Merger of dmalcolm/jit branch from git
authorDavid Malcolm <dmalcolm@gcc.gnu.org>
Tue, 11 Nov 2014 21:55:52 +0000 (21:55 +0000)
committerDavid Malcolm <dmalcolm@gcc.gnu.org>
Tue, 11 Nov 2014 21:55:52 +0000 (21:55 +0000)
ChangeLog:
* ChangeLog.jit: New.
* MAINTAINERS (Various Maintainers): Add myself as jit maintainer.

contrib/ChangeLog:
* ChangeLog.jit: New.
* jit-coverage-report.py: New file: a script to print crude
code-coverage information for the libgccjit API.

gcc/ChangeLog:
* ChangeLog.jit: New.
* Makefile.in (doc_build_sys): New variable, set to "sphinx" if
sphinx is installed, falling back to "texinfo" otherwise.
(FULL_DRIVER_NAME): New variable, adapted from the
install-driver target.  New target, a symlink within the builddir,
linked to "xgcc", for use when running the JIT library from the
builddir.
(MOSTLYCLEANFILES): Add FULL_DRIVER_NAME.
(install-driver): Use $(FULL_DRIVER_NAME) rather than spelling it
out.
* configure.ac (doc_build_sys): New variable, set to "sphinx" if
sphinx is installed, falling back to "texinfo" otherwise.
(GCC_DRIVER_NAME): Generate a gcc-driver-name.h file containing
GCC_DRIVER_NAME for the benefit of jit/internal-api.c.
* configure: Regenerate.
* doc/install.texi (--enable-host-shared): Specify that this is
required when building libgccjit.
(Tools/packages necessary for modifying GCC): Add Sphinx.
* timevar.def (TV_JIT_REPLAY): New.
(TV_ASSEMBLE): New.
(TV_LINK): New.
(TV_LOAD): New.

gcc/java/ChangeLog:
* gcc/ChangeLog.jit: New.

gcc/jit/ChangeLog:
* ChangeLog.jit: New.
* ChangeLog: New.
* Make-lang.in: New.
* TODO.rst: New.
* config-lang.in: New.
* docs/Makefile: New.
* docs/_build/texinfo/Makefile: New.
* docs/_build/texinfo/factorial.png: New.
* docs/_build/texinfo/libgccjit.texi: New.
* docs/_build/texinfo/sum-of-squares.png: New.
* docs/conf.py: New.
* docs/examples/tut01-hello-world.c: New.
* docs/examples/tut02-square.c: New.
* docs/examples/tut03-sum-of-squares.c: New.
* docs/examples/tut04-toyvm/Makefile: New.
* docs/examples/tut04-toyvm/factorial.toy: New.
* docs/examples/tut04-toyvm/fibonacci.toy: New.
* docs/examples/tut04-toyvm/toyvm.c: New.
* docs/index.rst: New.
* docs/internals/index.rst: New.
* docs/intro/factorial.png: New.
* docs/intro/index.rst: New.
* docs/intro/sum-of-squares.png: New.
* docs/intro/tutorial01.rst: New.
* docs/intro/tutorial02.rst: New.
* docs/intro/tutorial03.rst: New.
* docs/intro/tutorial04.rst: New.
* docs/topics/contexts.rst: New.
* docs/topics/expressions.rst: New.
* docs/topics/functions.rst: New.
* docs/topics/index.rst: New.
* docs/topics/locations.rst: New.
* docs/topics/objects.rst: New.
* docs/topics/results.rst: New.
* docs/topics/types.rst: New.
* dummy-frontend.c: New.
* jit-builtins.c: New.
* jit-builtins.h: New.
* jit-common.h: New.
* jit-playback.c: New.
* jit-playback.h: New.
* jit-recording.c: New.
* jit-recording.h: New.
* libgccjit++.h: New.
* libgccjit.c: New.
* libgccjit.h: New.
* libgccjit.map: New.
* notes.txt: New.

gcc/testsuite/ChangeLog:
* ChangeLog.jit: New.
* jit.dg/all-non-failing-tests.h: New.
* jit.dg/harness.h: New.
* jit.dg/jit.exp: New.
* jit.dg/test-accessing-struct.c: New.
* jit.dg/test-accessing-union.c: New.
* jit.dg/test-array-as-pointer.c: New.
* jit.dg/test-arrays.c: New.
* jit.dg/test-calling-external-function.c: New.
* jit.dg/test-calling-function-ptr.c: New.
* jit.dg/test-combination.c: New.
* jit.dg/test-dot-product.c: New.
* jit.dg/test-empty.c: New.
* jit.dg/test-error-accessing-field-in-other-struct.c: New.
* jit.dg/test-error-adding-to-terminated-block.c: New.
* jit.dg/test-error-array-as-pointer.c: New.
* jit.dg/test-error-bad-cast.c: New.
* jit.dg/test-error-block-in-wrong-function.c: New.
* jit.dg/test-error-call-through-ptr-with-mismatching-args.c: New.
* jit.dg/test-error-call-through-ptr-with-non-function.c: New.
* jit.dg/test-error-call-through-ptr-with-non-pointer.c: New.
* jit.dg/test-error-call-through-ptr-with-not-enough-args.c: New.
* jit.dg/test-error-call-through-ptr-with-too-many-args.c: New.
* jit.dg/test-error-call-with-mismatching-args.c: New.
* jit.dg/test-error-call-with-not-enough-args.c: New.
* jit.dg/test-error-call-with-too-many-args.c: New.
* jit.dg/test-error-dereference-field-of-non-pointer.c: New.
* jit.dg/test-error-dereference-read-of-non-pointer.c: New.
* jit.dg/test-error-get-type-bad-enum.c: New.
* jit.dg/test-error-index-not-a-numeric-type.c: New.
* jit.dg/test-error-mismatching-types-in-assignment.c: New.
* jit.dg/test-error-mismatching-types-in-call.c: New.
* jit.dg/test-error-missing-return.c: New.
* jit.dg/test-error-new-binary-op-bad-op.c: New.
* jit.dg/test-error-new-function-bad-kind.c: New.
* jit.dg/test-error-new-unary-op-bad-op.c: New.
* jit.dg/test-error-null-passed-to-api.c: New.
* jit.dg/test-error-return-within-void-function.c: New.
* jit.dg/test-error-unreachable-block.c: New.
* jit.dg/test-error-unterminated-block.c: New.
* jit.dg/test-error-value-not-a-numeric-type.c: New.
* jit.dg/test-expressions.c: New.
* jit.dg/test-factorial.c: New.
* jit.dg/test-fibonacci.c: New.
* jit.dg/test-functions.c: New.
* jit.dg/test-fuzzer.c: New.
* jit.dg/test-hello-world.c: New.
* jit.dg/test-linked-list.c: New.
* jit.dg/test-long-names.c: New.
* jit.dg/test-nested-contexts.c: New.
* jit.dg/test-nested-loops.c: New.
* jit.dg/test-operator-overloading.cc: New.
* jit.dg/test-quadratic.c: New.
* jit.dg/test-quadratic.cc: New.
* jit.dg/test-reading-struct.c: New.
* jit.dg/test-string-literal.c: New.
* jit.dg/test-sum-of-squares.c: New.
* jit.dg/test-threads.c: New.
* jit.dg/test-types.c: New.
* jit.dg/test-using-global.c: New.
* jit.dg/test-volatile.c: New.

include/ChangeLog:
* ChangeLog.jit: New.

libbacktrace/ChangeLog:
* ChangeLog.jit: New.

libcpp/ChangeLog:
* ChangeLog.jit: New.

libdecnumber/ChangeLog:
* ChangeLog.jit: New.

libiberty/ChangeLog:
* ChangeLog.jit: New.

zlib/ChangeLog:
* ChangeLog.jit: New.

From-SVN: r217374

136 files changed:
ChangeLog
ChangeLog.jit [new file with mode: 0644]
MAINTAINERS
contrib/ChangeLog
contrib/ChangeLog.jit [new file with mode: 0644]
contrib/jit-coverage-report.py [new file with mode: 0644]
gcc/ChangeLog
gcc/ChangeLog.jit [new file with mode: 0644]
gcc/Makefile.in
gcc/configure
gcc/configure.ac
gcc/doc/install.texi
gcc/java/ChangeLog
gcc/java/ChangeLog.jit [new file with mode: 0644]
gcc/jit/ChangeLog [new file with mode: 0644]
gcc/jit/ChangeLog.jit [new file with mode: 0644]
gcc/jit/Make-lang.in [new file with mode: 0644]
gcc/jit/TODO.rst [new file with mode: 0644]
gcc/jit/config-lang.in [new file with mode: 0644]
gcc/jit/docs/Makefile [new file with mode: 0644]
gcc/jit/docs/_build/texinfo/Makefile [new file with mode: 0644]
gcc/jit/docs/_build/texinfo/factorial.png [new file with mode: 0644]
gcc/jit/docs/_build/texinfo/libgccjit.texi [new file with mode: 0644]
gcc/jit/docs/_build/texinfo/sum-of-squares.png [new file with mode: 0644]
gcc/jit/docs/conf.py [new file with mode: 0644]
gcc/jit/docs/examples/tut01-hello-world.c [new file with mode: 0644]
gcc/jit/docs/examples/tut02-square.c [new file with mode: 0644]
gcc/jit/docs/examples/tut03-sum-of-squares.c [new file with mode: 0644]
gcc/jit/docs/examples/tut04-toyvm/Makefile [new file with mode: 0644]
gcc/jit/docs/examples/tut04-toyvm/factorial.toy [new file with mode: 0644]
gcc/jit/docs/examples/tut04-toyvm/fibonacci.toy [new file with mode: 0644]
gcc/jit/docs/examples/tut04-toyvm/toyvm.c [new file with mode: 0644]
gcc/jit/docs/index.rst [new file with mode: 0644]
gcc/jit/docs/internals/index.rst [new file with mode: 0644]
gcc/jit/docs/intro/factorial.png [new file with mode: 0644]
gcc/jit/docs/intro/index.rst [new file with mode: 0644]
gcc/jit/docs/intro/sum-of-squares.png [new file with mode: 0644]
gcc/jit/docs/intro/tutorial01.rst [new file with mode: 0644]
gcc/jit/docs/intro/tutorial02.rst [new file with mode: 0644]
gcc/jit/docs/intro/tutorial03.rst [new file with mode: 0644]
gcc/jit/docs/intro/tutorial04.rst [new file with mode: 0644]
gcc/jit/docs/topics/contexts.rst [new file with mode: 0644]
gcc/jit/docs/topics/expressions.rst [new file with mode: 0644]
gcc/jit/docs/topics/functions.rst [new file with mode: 0644]
gcc/jit/docs/topics/index.rst [new file with mode: 0644]
gcc/jit/docs/topics/locations.rst [new file with mode: 0644]
gcc/jit/docs/topics/objects.rst [new file with mode: 0644]
gcc/jit/docs/topics/results.rst [new file with mode: 0644]
gcc/jit/docs/topics/types.rst [new file with mode: 0644]
gcc/jit/dummy-frontend.c [new file with mode: 0644]
gcc/jit/jit-builtins.c [new file with mode: 0644]
gcc/jit/jit-builtins.h [new file with mode: 0644]
gcc/jit/jit-common.h [new file with mode: 0644]
gcc/jit/jit-playback.c [new file with mode: 0644]
gcc/jit/jit-playback.h [new file with mode: 0644]
gcc/jit/jit-recording.c [new file with mode: 0644]
gcc/jit/jit-recording.h [new file with mode: 0644]
gcc/jit/libgccjit++.h [new file with mode: 0644]
gcc/jit/libgccjit.c [new file with mode: 0644]
gcc/jit/libgccjit.h [new file with mode: 0644]
gcc/jit/libgccjit.map [new file with mode: 0644]
gcc/jit/notes.txt [new file with mode: 0644]
gcc/testsuite/ChangeLog
gcc/testsuite/ChangeLog.jit [new file with mode: 0644]
gcc/testsuite/jit.dg/all-non-failing-tests.h [new file with mode: 0644]
gcc/testsuite/jit.dg/harness.h [new file with mode: 0644]
gcc/testsuite/jit.dg/jit.exp [new file with mode: 0644]
gcc/testsuite/jit.dg/test-accessing-struct.c [new file with mode: 0644]
gcc/testsuite/jit.dg/test-accessing-union.c [new file with mode: 0644]
gcc/testsuite/jit.dg/test-array-as-pointer.c [new file with mode: 0644]
gcc/testsuite/jit.dg/test-arrays.c [new file with mode: 0644]
gcc/testsuite/jit.dg/test-calling-external-function.c [new file with mode: 0644]
gcc/testsuite/jit.dg/test-calling-function-ptr.c [new file with mode: 0644]
gcc/testsuite/jit.dg/test-combination.c [new file with mode: 0644]
gcc/testsuite/jit.dg/test-dot-product.c [new file with mode: 0644]
gcc/testsuite/jit.dg/test-empty.c [new file with mode: 0644]
gcc/testsuite/jit.dg/test-error-accessing-field-in-other-struct.c [new file with mode: 0644]
gcc/testsuite/jit.dg/test-error-adding-to-terminated-block.c [new file with mode: 0644]
gcc/testsuite/jit.dg/test-error-array-as-pointer.c [new file with mode: 0644]
gcc/testsuite/jit.dg/test-error-bad-cast.c [new file with mode: 0644]
gcc/testsuite/jit.dg/test-error-block-in-wrong-function.c [new file with mode: 0644]
gcc/testsuite/jit.dg/test-error-call-through-ptr-with-mismatching-args.c [new file with mode: 0644]
gcc/testsuite/jit.dg/test-error-call-through-ptr-with-non-function.c [new file with mode: 0644]
gcc/testsuite/jit.dg/test-error-call-through-ptr-with-non-pointer.c [new file with mode: 0644]
gcc/testsuite/jit.dg/test-error-call-through-ptr-with-not-enough-args.c [new file with mode: 0644]
gcc/testsuite/jit.dg/test-error-call-through-ptr-with-too-many-args.c [new file with mode: 0644]
gcc/testsuite/jit.dg/test-error-call-with-mismatching-args.c [new file with mode: 0644]
gcc/testsuite/jit.dg/test-error-call-with-not-enough-args.c [new file with mode: 0644]
gcc/testsuite/jit.dg/test-error-call-with-too-many-args.c [new file with mode: 0644]
gcc/testsuite/jit.dg/test-error-dereference-field-of-non-pointer.c [new file with mode: 0644]
gcc/testsuite/jit.dg/test-error-dereference-read-of-non-pointer.c [new file with mode: 0644]
gcc/testsuite/jit.dg/test-error-get-type-bad-enum.c [new file with mode: 0644]
gcc/testsuite/jit.dg/test-error-index-not-a-numeric-type.c [new file with mode: 0644]
gcc/testsuite/jit.dg/test-error-mismatching-types-in-assignment.c [new file with mode: 0644]
gcc/testsuite/jit.dg/test-error-mismatching-types-in-call.c [new file with mode: 0644]
gcc/testsuite/jit.dg/test-error-missing-return.c [new file with mode: 0644]
gcc/testsuite/jit.dg/test-error-new-binary-op-bad-op.c [new file with mode: 0644]
gcc/testsuite/jit.dg/test-error-new-function-bad-kind.c [new file with mode: 0644]
gcc/testsuite/jit.dg/test-error-new-unary-op-bad-op.c [new file with mode: 0644]
gcc/testsuite/jit.dg/test-error-null-passed-to-api.c [new file with mode: 0644]
gcc/testsuite/jit.dg/test-error-return-within-void-function.c [new file with mode: 0644]
gcc/testsuite/jit.dg/test-error-unreachable-block.c [new file with mode: 0644]
gcc/testsuite/jit.dg/test-error-unterminated-block.c [new file with mode: 0644]
gcc/testsuite/jit.dg/test-error-value-not-a-numeric-type.c [new file with mode: 0644]
gcc/testsuite/jit.dg/test-expressions.c [new file with mode: 0644]
gcc/testsuite/jit.dg/test-factorial.c [new file with mode: 0644]
gcc/testsuite/jit.dg/test-fibonacci.c [new file with mode: 0644]
gcc/testsuite/jit.dg/test-functions.c [new file with mode: 0644]
gcc/testsuite/jit.dg/test-fuzzer.c [new file with mode: 0644]
gcc/testsuite/jit.dg/test-hello-world.c [new file with mode: 0644]
gcc/testsuite/jit.dg/test-linked-list.c [new file with mode: 0644]
gcc/testsuite/jit.dg/test-long-names.c [new file with mode: 0644]
gcc/testsuite/jit.dg/test-nested-contexts.c [new file with mode: 0644]
gcc/testsuite/jit.dg/test-nested-loops.c [new file with mode: 0644]
gcc/testsuite/jit.dg/test-operator-overloading.cc [new file with mode: 0644]
gcc/testsuite/jit.dg/test-quadratic.c [new file with mode: 0644]
gcc/testsuite/jit.dg/test-quadratic.cc [new file with mode: 0644]
gcc/testsuite/jit.dg/test-reading-struct.c [new file with mode: 0644]
gcc/testsuite/jit.dg/test-string-literal.c [new file with mode: 0644]
gcc/testsuite/jit.dg/test-sum-of-squares.c [new file with mode: 0644]
gcc/testsuite/jit.dg/test-threads.c [new file with mode: 0644]
gcc/testsuite/jit.dg/test-types.c [new file with mode: 0644]
gcc/testsuite/jit.dg/test-using-global.c [new file with mode: 0644]
gcc/testsuite/jit.dg/test-volatile.c [new file with mode: 0644]
gcc/timevar.def
include/ChangeLog
include/ChangeLog.jit [new file with mode: 0644]
libbacktrace/ChangeLog
libbacktrace/ChangeLog.jit [new file with mode: 0644]
libcpp/ChangeLog
libcpp/ChangeLog.jit [new file with mode: 0644]
libdecnumber/ChangeLog
libdecnumber/ChangeLog.jit [new file with mode: 0644]
libiberty/ChangeLog
libiberty/ChangeLog.jit [new file with mode: 0644]
zlib/ChangeLog.jit [new file with mode: 0644]

index a2b3984cc3975036a24c74c668fffcd51fd40acc..4d45d9d8ed1f268f76633e9cd088a64f726a4a96 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2014-11-11  David Malcolm  <dmalcolm@redhat.com>
+
+       * ChangeLog.jit: New.
+       * MAINTAINERS (Various Maintainers): Add myself as jit maintainer.
+
 2014-11-11  Francois-Xavier Coudert  <fxcoudert@gcc.gnu.org>
 
        PR target/63610
diff --git a/ChangeLog.jit b/ChangeLog.jit
new file mode 100644 (file)
index 0000000..d4ba859
--- /dev/null
@@ -0,0 +1,23 @@
+2014-10-02  David Malcolm  <dmalcolm@redhat.com>
+
+       * MAINTAINERS: Update jit entry to match formatting change on
+       trunk: "Put all email addresses between '<' and '>'."
+
+2014-09-24  David Malcolm  <dmalcolm@redhat.com>
+
+       * ChangeLog.jit: Add copyright footer.
+
+2014-09-11  David Malcolm  <dmalcolm@redhat.com>
+
+       * MAINTAINERS (Various Maintainers): Add myself as jit maintainer.
+
+2013-10-03  David Malcolm  <dmalcolm@redhat.com>
+
+       * configure.ac: Add --enable-host-shared
+       * configure: Regenerate.
+\f
+Copyright (C) 2013-2014 Free Software Foundation, Inc.
+
+Copying and distribution of this file, with or without modification,
+are permitted in any medium without royalty provided the copyright
+notice and this notice are preserved.
index cdc2cdd27594d880a01a49da4fd9419803facec8..c7d45dfea24d9a5e55526bc3266d27a275eaf019 100644 (file)
@@ -260,6 +260,7 @@ testsuite           Janis Johnson           <janisjo@codesourcery.com>
 register allocation    Vladimir Makarov        <vmakarov@redhat.com>
 gdbhooks.py            David Malcolm           <dmalcolm@redhat.com>
 SLSR                   Bill Schmidt            <wschmidt@linux.vnet.ibm.com>
+jit                    David Malcolm           <dmalcolm@redhat.com>
 
 Note that individuals who maintain parts of the compiler need approval to
 check in changes outside of the parts of the compiler they maintain.
index d02e3fc8ddc96d42e397e17fe2c59ab9150dd3c9..2484d86e20d8a2d39f3c25795d3ac27494b4d9a7 100644 (file)
@@ -1,3 +1,9 @@
+2014-11-11  David Malcolm  <dmalcolm@redhat.com>
+
+       * ChangeLog.jit: New.
+       * jit-coverage-report.py: New file: a script to print crude
+       code-coverage information for the libgccjit API.
+
 2014-11-11  Marat Zakirov  <m.zakirov@samsung.com>
 
        * mklog: Symbol '}' stops search for changes.  
diff --git a/contrib/ChangeLog.jit b/contrib/ChangeLog.jit
new file mode 100644 (file)
index 0000000..38a315a
--- /dev/null
@@ -0,0 +1,14 @@
+2014-09-24  David Malcolm  <dmalcolm@redhat.com>
+
+       * ChangeLog.jit: Add copyright footer.
+
+2014-01-23  David Malcolm  <dmalcolm@redhat.com>
+
+       * jit-coverage-report.py: New file: a script to print crude
+       code-coverage information for the libgccjit API.
+\f
+Copyright (C) 2014 Free Software Foundation, Inc.
+
+Copying and distribution of this file, with or without modification,
+are permitted in any medium without royalty provided the copyright
+notice and this notice are preserved.
diff --git a/contrib/jit-coverage-report.py b/contrib/jit-coverage-report.py
new file mode 100644 (file)
index 0000000..529336f
--- /dev/null
@@ -0,0 +1,67 @@
+#! /usr/bin/python
+#
+# Print a report on which libgccjit.so symbols are used in which test
+# cases, and which lack test coverage.  Tested with Python 2.7 and 3.2
+# To be run from the root directory of the source tree.
+#
+# Copyright (C) 2014 Free Software Foundation, Inc.
+# Written by David Malcolm <dmalcolm@redhat.com>.
+#
+# This script is Free Software, and it can be copied, distributed and
+# modified as defined in the GNU General Public License.  A copy of
+# its license can be downloaded from http://www.gnu.org/copyleft/gpl.html
+
+from collections import Counter
+import glob
+import re
+import sys
+
+def parse_map_file(path):
+    """
+    Parse libgccjit.map, returning the symbols in the API as a list of str.
+    """
+    syms = []
+    with open(path) as f:
+        for line in f:
+            m = re.match('^\s+([a-z_]+);$', line)
+            if m:
+                syms.append(m.group(1))
+    return syms
+
+def parse_test_case(path):
+    """
+    Locate all symbol-like things in a C test case, yielding
+    them as a sequence of str.
+    """
+    with open(path) as f:
+        for line in f:
+            for m in re.finditer('([_A-Za-z][_A-Za-z0-9]*)', line):
+                yield m.group(1)
+
+def find_test_cases():
+    for path in glob.glob('gcc/testsuite/jit.dg/*.[ch]'):
+        yield path
+
+api_syms = parse_map_file('gcc/jit/libgccjit.map')
+
+syms_in_test_cases = {}
+for path in find_test_cases():
+    syms_in_test_cases[path] = list(parse_test_case(path))
+
+uses = Counter()
+for sym in sorted(api_syms):
+    print('symbol: %s' % sym)
+    uses[sym] = 0
+    for path in syms_in_test_cases:
+        count = syms_in_test_cases[path].count(sym)
+        uses[sym] += count
+        if count:
+            print('  uses in %s: %i' % (path, count))
+    if uses[sym] == 0:
+        print('  NEVER USED')
+    sys.stdout.write('\n')
+
+layout = '%40s  %5s  %s'
+print(layout % ('SYMBOL', 'USES', 'HISTOGRAM'))
+for sym, count in uses.most_common():
+    print(layout % (sym, count, '*' * count if count else 'UNUSED'))
index da2d3b5d68dd07ef4ec3bc26300339cc700f2507..951aa02b62d8273ddd36a519e9dc44b0fb6f7037 100644 (file)
@@ -1,3 +1,28 @@
+2014-11-11  David Malcolm  <dmalcolm@redhat.com>
+
+       * ChangeLog.jit: New.
+       * Makefile.in (doc_build_sys): New variable, set to "sphinx" if
+       sphinx is installed, falling back to "texinfo" otherwise.
+       (FULL_DRIVER_NAME): New variable, adapted from the
+       install-driver target.  New target, a symlink within the builddir,
+       linked to "xgcc", for use when running the JIT library from the
+       builddir.
+       (MOSTLYCLEANFILES): Add FULL_DRIVER_NAME.
+       (install-driver): Use $(FULL_DRIVER_NAME) rather than spelling it
+       out.
+       * configure.ac (doc_build_sys): New variable, set to "sphinx" if
+       sphinx is installed, falling back to "texinfo" otherwise.
+       (GCC_DRIVER_NAME): Generate a gcc-driver-name.h file containing
+       GCC_DRIVER_NAME for the benefit of jit/internal-api.c.
+       * configure: Regenerate.
+       * doc/install.texi (--enable-host-shared): Specify that this is
+       required when building libgccjit.
+       (Tools/packages necessary for modifying GCC): Add Sphinx.
+       * timevar.def (TV_JIT_REPLAY): New.
+       (TV_ASSEMBLE): New.
+       (TV_LINK): New.
+       (TV_LOAD): New.
+
 2014-11-11  Francois-Xavier Coudert  <fxcoudert@gcc.gnu.org>
 
        PR target/63610
diff --git a/gcc/ChangeLog.jit b/gcc/ChangeLog.jit
new file mode 100644 (file)
index 0000000..613084e
--- /dev/null
@@ -0,0 +1,360 @@
+2014-10-29  David Malcolm  <dmalcolm@redhat.com>
+
+       * doc/install.texi (Tools/packages necessary for modifying GCC):
+       Specify that Sphinx version 1.0 or later is required.  Wrap .rst
+       inside an @file command.
+
+2014-10-22  David Malcolm  <dmalcolm@redhat.com>
+
+       * cgraph.h: Drop now-redundant prototype of ipa_cp_c_finalize,
+       since trunk added this in ipa-prop.h.
+       * ipa-icf.c (ipa_icf_driver): Set optimizer to NULL when
+       done.
+
+2014-10-20  David Malcolm  <dmalcolm@redhat.com>
+
+       * doc/install.texi (Tools/packages necessary for modifying GCC):
+       Add Sphinx.
+
+2014-10-20  David Malcolm  <dmalcolm@redhat.com>
+
+       * Makefile.in (pkgconfigdir): Drop this.
+       (installdirs): Likewise.
+       * configure.ac (gcc_version): Don't AC_SUBST this.
+       * configure: Regenerate.
+
+2014-10-17  David Malcolm  <dmalcolm@redhat.com>
+
+       * Makefile.in (FULL_DRIVER_NAME): New variable, adapted from the
+       install-driver target.  New target, a symlink within the builddir,
+       linked to "xgcc", for use when running the JIT library from the
+       builddir.
+       (MOSTLYCLEANFILES): Add FULL_DRIVER_NAME.
+       (install-driver): Use $(FULL_DRIVER_NAME) rather than spelling it
+       out.
+       (site.exp): Don't set "bindir", as this is no longer needed when
+       running the jit testsuite.
+
+2014-10-13  David Malcolm  <dmalcolm@redhat.com>
+
+       * configure.ac: Update a reference to jit/internal-api.c to
+       jit/jit-playback.c.
+       * configure: Regenerate.
+
+2014-10-07  David Malcolm  <dmalcolm@redhat.com>
+
+       * Makefile.in (site.exp): When constructing site.exp, add a line
+       to set "bindir".
+       * configure.ac: Generate a gcc-driver-name.h file containing
+       GCC_DRIVER_NAME for the benefit of jit/internal-api.c.
+       * configure: Regenerate.
+
+2014-10-03  David Malcolm  <dmalcolm@redhat.com>
+
+       * diagnostic.c (diagnostic_finish): Free the memory for
+       context->classify_diagnostic and context->printer, running the
+       destructor for the latter.
+
+2014-10-02  David Malcolm  <dmalcolm@redhat.com>
+
+       * configure: Regenerate, after merger from trunk.
+
+2014-10-02  David Malcolm  <dmalcolm@redhat.com>
+
+       * configure.ac (doc_build_sys): New variable, set to "sphinx" if
+       sphinx is installed, falling back to "texinfo" otherwise.
+       * configure: Regenerate.
+       * Makefile.in (doc_build_sys): New.
+
+2014-09-24  David Malcolm  <dmalcolm@redhat.com>
+
+       * ChangeLog.jit: Add copyright footer.
+
+2014-09-24  David Malcolm  <dmalcolm@redhat.com>
+
+       * cgraph.h (cgraphbuild_c_finalize): Delete prototype of empty
+       function.
+       (ipa_c_finalize): Likewise.
+       (predict_c_finalize): Likewise.
+       (symtab_c_finalize): Likewise.
+       (varpool_c_finalize): Likewise.
+
+       * cgraph.c (cgraph_c_finalize): Add leading comment.  Put return
+       type on line before function name.
+       * cgraphunit.c (cgraphunit_c_finalize): Likewise.
+       * dwarf2out.c (dwarf2out_c_finalize): Likewise.
+       * gcse.c (gcse_c_finalize): Likewise.
+       * ipa-cp.c (ipa_cp_c_finalize): Likewise.
+       * ipa-reference.c (ipa_reference_c_finalize): Likewise.
+
+       * params.c (params_c_finalize): Update leading comment to match
+       format of the others mentioned above.
+
+       * cgraphbuild.c (cgraphbuild_c_finalize): Delete empty function.
+       * ipa.c (ipa_c_finalize): Likewise.
+       * predict.c (predict_c_finalize): Likewise.
+       * symtab.c (symtab_c_finalize): Likewise.
+       * varpool.c (varpool_c_finalize): Likewise.
+
+       * toplev.c (toplev::finalize): Remove calls to empty functions
+       cgraphbuild_c_finalize, ipa_c_finalize, predict_c_finalize,
+       symtab_c_finalize, varpool_c_finalize.
+
+2014-09-23  David Malcolm  <dmalcolm@redhat.com>
+
+       * passes.c (execute_ipa_summary_passes): Fix whitespace when
+       assigning to current_pass.
+       (ipa_write_summaries_2): Assign "pass" to "current_pass" global
+       before calling write_summary hook.
+       (ipa_write_optimization_summaries_1): Likewise when calling
+       write_optimization_summary hook.
+       (ipa_read_summaries_1): Likewise for read_summary hook.
+       (ipa_read_optimization_summaries_1): Likewise for
+       read_optimization_summary hook.
+       (execute_ipa_stmt_fixups): Likewise for stmt_fixup hook.
+
+2014-09-22  David Malcolm  <dmalcolm@redhat.com>
+
+       * cgraph.c (cgraph_c_finalize): Remove FIXME.
+       * timevar.c (timevar_init): Likewise.
+
+2014-09-18  David Malcolm  <dmalcolm@redhat.com>
+
+       * Makefile.in (pkgconfigdir): New.
+       (installdirs): Add creation of $(DESTDIR)$(pkgconfigdir).
+       * configure.ac (gcc_version): Expose this value for use via
+       AC_SUBST, since we need it within the new file libgccjit.pc.in.
+       * configure: Regenerate.
+
+2014-09-10  David Malcolm  <dmalcolm@redhat.com>
+
+       * cgraph.c (cgraph_c_finalize): Update to reflect the movement of
+       many globals into fields of the "symtab" object.
+       * cgraphunit.c (graphunit_c_finalize): Likewise.
+       * symtab.c (symtab_c_finalize): Likewise.
+
+       * toplev.c (initialize_rtl): Move static local "initialized_once"
+       into file scope, and rename to...
+       (rtl_initialized): New variable.
+       (toplev::finalize): Clear rtl_initialized and
+       this_target_rtl->target_specific_initialized so that RTL will be
+       reinitialized when the compiler is run more than once in-process.
+
+2014-07-14  David Malcolm  <dmalcolm@redhat.com>
+
+       * cgraph.h (ipa_cp_c_finalize): Add prototype.
+       * ipa-cp.c (ipa_cp_c_finalize): New.
+       * toplev.c (toplev::finalize): Add call to ipa_cp_c_finalize.
+
+2014-05-08  David Malcolm  <dmalcolm@redhat.com>
+
+       * params.c (global_init_params): Require that params_finished be
+       false, rather than being idempotent, in favor of purging all state
+       between toplev invocations, since in a release build
+       init_ggc_heuristics calls set_param_value_internal, and the
+       latter assumes that params_finished is true.
+       (params_c_finalize): New.
+       * params.h (params_c_finalize): New.
+       * toplev.c (toplev::finalize): Call params_c_finalize.
+
+2014-03-24  Tom Tromey  <tromey@redhat.com>
+
+       * toplev.c (general_init): Initialize input_location.
+       * input.c (input_location): Initialize to UNKNOWN_LOCATION.
+
+2014-03-19  Tom Tromey  <tromey@redhat.com>
+
+       * timevar.h (auto_timevar): New class.
+
+2014-03-19  Tom Tromey  <tromey@redhat.com>
+
+       * diagnostic.c (bt_stop): Use toplev::main.
+       * main.c (main): Update.
+       * toplev.c (do_compile): Remove argument.  Don't check
+       use_TV_TOTAL.
+       (toplev::toplev, toplev::~toplev, toplev::start_timevars): New
+       functions.
+       (toplev::main): Rename from toplev_main.  Update.
+       (toplev::finalize): Rename from toplev_finalize.  Update.
+       * toplev.h (class toplev): New.
+       (struct toplev_options): Remove.
+       (toplev_main, toplev_finalize): Don't declare.
+
+2014-03-11  David Malcolm  <dmalcolm@redhat.com>
+
+       * gcse.c (gcse_c_finalize): New, to clear test_insn between
+       in-process compiles.
+       * gcse.h (gcse_c_finalize): New.
+       * toplev.c: Include "gcse.h" so that we can...
+       (toplev_finalize): Call gcse_c_finalize.
+
+2014-03-11  David Malcolm  <dmalcolm@redhat.com>
+
+       * dwarf2out.c (dwarf2out_c_finalize): Release base_types.
+
+2014-03-10  David Malcolm  <dmalcolm@redhat.com>
+
+       * ipa-reference.c (ipa_init): Move static bool init_p from here
+       to...
+       (ipa_init_p): New file-scope variable, so that it can be reset
+       when repeatedly invoking the compiler within one process by...
+       (ipa_reference_c_finalize): New function.
+       * ipa-reference.h (ipa_reference_c_finalize): New.
+       * toplev.c (toplev_finalize): Invoke new function
+       ipa_reference_c_finalize.
+
+2014-01-24  David Malcolm  <dmalcolm@redhat.com>
+
+       * timevar.def: Replace TV_CLIENT_CALLBACK with TV_JIT_REPLAY.
+
+2013-10-11  David Malcolm  <dmalcolm@redhat.com>
+
+       * doc/install.texi (--enable-shared): Add note contrasting it
+       with...
+       (--enable-host-shared): New option.
+
+2013-10-11  David Malcolm  <dmalcolm@redhat.com>
+
+       * dumpfile.h (gcc::dump_manager): New class, to hold state
+       relating to dumpfile management.
+       (get_dump_file_name): Remove in favor of method of dump_manager.
+       (dump_initialized_p): Likewise.
+       (dump_start): Likewise.
+       (dump_finish): Likewise.
+       (dump_switch_p): Likewise.
+       (dump_register): Likewise.
+       (get_dump_file_info): Likewise.
+       * context.c (gcc::context::context): Construct the dump_manager
+       instance.
+       * context.h (gcc::context::get_dumps): New.
+       (gcc::context::m_dumps): New.
+       * coverage.c (coverage_init): Port to dump_manager API.
+       * dumpfile.c (extra_dump_files): Convert to field of
+       gcc::dump_manager.
+       (extra_dump_files_in_use): Likewise.
+       (extra_dump_files_alloced): Likewise.
+       (gcc::dump_manager::dump_manager): New.
+       (dump_register): Convert to...
+       (gcc::dump_manager::dump_register): ...method, replacing
+       function-static next_dump with m_next_dump field.
+       (get_dump_file_info): Convert to...
+       (gcc::dump_manager::get_dump_file_info): ...method.
+       (get_dump_file_name): Convert to...
+       (gcc::dump_manager::get_dump_file_name): ...method.
+       (dump_start): Convert to...
+       (gcc::dump_manager::dump_start): ...method.
+       (dump_finish): Convert to...
+       (gcc::dump_manager::dump_finish): ...method.
+       (dump_begin): Replace body with...
+       (gcc::dump_manager::dump_begin): ...new method.
+       (dump_phase_enabled_p): Convert to...
+       (gcc::dump_manager::dump_phase_enabled_p): ...method.
+       (dump_phase_enabled_p): Convert to...
+       (gcc::dump_manager::dump_phase_enabled_p): ...method.
+       (dump_initialized_p):  Convert to...
+       (gcc::dump_manager::dump_initialized_p): ...method.
+       (dump_flag_name): Replace body with...
+       (gcc::dump_manager::dump_flag_name): ...new method.
+       (dump_enable_all): Convert to...
+       (gcc::dump_manager::dump_enable_all): ...new method.
+       (opt_info_enable_passes): Convert to...
+       (gcc::dump_manager::opt_info_enable_passes): ...new method.
+       (dump_switch_p_1): Convert to...
+       (gcc::dump_manager::dump_switch_p_1): ...new method.
+       (dump_switch_p):  Convert to...
+       (gcc::dump_manager::dump_switch_p): ...new method.
+       (opt_info_switch_p): Port to dump_manager API.
+       (enable_rtl_dump_file): Likewise.
+       * opts-global.c (handle_common_deferred_options): Port to new
+       dump_manager API.
+       * passes.c (pass_manager::finish_optimization_passes): Likewise.
+       (pass_manager::register_one_dump_file): Likewise.
+       (pass_manager::register_pass): Likewise.
+       (pass_init_dump_file): Likewise.
+       (pass_fini_dump_file): Likewise.
+       * statistics.c (statistics_early_init): Likewise.
+
+2013-10-08  David Malcolm  <dmalcolm@redhat.com>
+
+       * ipa-inline.c (ipa_inline): Fix leak of "order" when
+       optimizations are disabled.
+
+2013-10-08  David Malcolm  <dmalcolm@redhat.com>
+
+       * coverage.c (coverage_finish): Fix leak of da_file_name.
+
+2013-10-07  David Malcolm  <dmalcolm@redhat.com>
+
+       * Makefile.in: Set PICFLAG from configure script; add it to
+       INTERNAL_CFLAGS.
+       * configure.ac (--enable-host-shared): Set up PICFLAG rather
+       than attempting to append -fPIC to CFLAGS, CXXFLAGS, LDFLAGS.
+       * configure: Regenerate.
+
+2013-10-03  David Malcolm  <dmalcolm@redhat.com>
+
+       * Makefile.in (LIBIBERTY): Use pic build of libiberty.a if
+       configured with --enable-host-shared.
+       (BUILD_LIBIBERTY): Likewise.
+       * cgraph.c (cgraph_c_finalize): New.
+       * cgraph.h (symtab_c_finalize): New declaration.
+       (cgraph_c_finalize): Likewise.
+       (cgraphunit_c_finalize): Likewise.
+       (cgraphbuild_c_finalize): Likewise.
+       (ipa_c_finalize): Likewise.
+       (predict_c_finalize): Likewise.
+       (varpool_c_finalize): Likewise.
+       * cgraphbuild.c (cgraphbuild_c_finalize): New.
+       * cgraphunit.c (first_analyzed): Move from analyze_functions
+       to file-scope.
+       (first_analyzed_var): Likewise.
+       (analyze_functions): Move static variables into file-scope.
+       (cgraphunit_c_finalize): New.
+       * configure.ac: Add --enable-host-shared, adding -fPIC.
+       * configure: Regenerate.
+       * dwarf2out.c (dwarf2out_c_finalize): New.
+       * dwarf2out.h (dwarf2out_c_finalize): Declare.
+       * ggc-page.c (init_ggc): Make idempotent.
+       * ipa-pure-const.c (function_insertion_hook_holder): Move to be
+       a field of class pass_ipa_pure_const.
+       (node_duplication_hook_holder): Likewise.
+       (node_removal_hook_holder): Likewise.
+       (register_hooks): Convert to method...
+       (pass_ipa_pure_const::register_hooks): ...here, converting
+       static variable init_p into...
+       (pass_ipa_pure_const::init_p): ...new field.
+       (pure_const_generate_summary): Update invocation of
+       register_hooks to invoke as a method of current_pass.
+       (pure_const_read_summary): Likewise.
+       (propagate): Convert to...
+       (pass_ipa_pure_const::execute): ...method.
+       * ipa.c (ipa_c_finalize): New.
+       * main.c (main): Update usage of toplev_main.
+       * params.c (global_init_params): Make idempotent.
+       * passes.c (execute_ipa_summary_passes): Set current_pass.
+       * predict.c (predict_c_finalize): New.
+       * stringpool.c (init_stringpool): Clean up if we're called more
+       than once.
+       * symtab.c (symtab_c_finalize): New.
+       * timevar.c (timevar_init): Ignore repeated calls.
+       * timevar.def (TV_CLIENT_CALLBACK): Add.
+       (TV_ASSEMBLE): Add.
+       (TV_LINK): Add.
+       (TV_LOAD): Add.
+       * toplev.c (do_compile) Add parameter (const toplev_options *);
+       use it to avoid starting/stopping/reporting timevar TV_TOTAL
+       for the case where toplev_main does not emcompass all timevars.
+       (toplev_main): Add parameter (const toplev_options *); pass it
+       to do_compile.
+       (toplev_finalize): New.
+       * toplev.h (struct toplev_options): New.
+       (toplev_main): Add parameter (const toplev_options *).
+       (toplev_finalize): New.
+       * varpool.c (varpool_c_finalize): New.
+
+\f
+Copyright (C) 2013-2014 Free Software Foundation, Inc.
+
+Copying and distribution of this file, with or without modification,
+are permitted in any medium without royalty provided the copyright
+notice and this notice are preserved.
index 4e856b16064105de7e09ef3f2a4e3285bcf2b7da..0ab3476d517b916ef1eef6178f26e4629a789cdc 100644 (file)
@@ -316,6 +316,11 @@ write_entries_to_file = $(shell rm -f $(2) || :) $(shell touch $(2)) \
                          $(shell expr $(range) + $(write_entries_to_file_split) - 1), $(1))" \
             | tr ' ' '\012' >> $(2)))
 
+# The jit documentation looks better if built with sphinx, but can be
+# built with texinfo if sphinx is not available.
+# configure sets "doc_build_sys" to "sphinx" or "texinfo" accordingly
+doc_build_sys=@doc_build_sys@
+
 # --------
 # UNSORTED
 # --------
@@ -1508,6 +1513,9 @@ BACKEND = libbackend.a main.o @TREEBROWSER@ libcommon-target.a libcommon.a \
 # front-end checking.
 TREECHECKING = @TREECHECKING@
 
+# The full name of the driver on installation
+FULL_DRIVER_NAME=$(target_noncanonical)-gcc-$(version)$(exeext)
+
 MOSTLYCLEANFILES = insn-flags.h insn-config.h insn-codes.h \
  insn-output.c insn-recog.c insn-emit.c insn-extract.c insn-peep.c \
  insn-attr.h insn-attr-common.h insn-attrtab.c insn-dfatab.c \
@@ -1515,7 +1523,7 @@ MOSTLYCLEANFILES = insn-flags.h insn-config.h insn-codes.h \
  tm-preds.h tm-constrs.h checksum-options gimple-match.c generic-match.c \
  tree-check.h min-insn-modes.c insn-modes.c insn-modes.h \
  genrtl.h gt-*.h gtype-*.h gtype-desc.c gtyp-input.list \
- xgcc$(exeext) cpp$(exeext) \
+ xgcc$(exeext) cpp$(exeext) $(FULL_DRIVER_NAME) \
  $(EXTRA_PROGRAMS) gcc-cross$(exeext) \
  $(SPECS) collect2$(exeext) gcc-ar$(exeext) gcc-nm$(exeext) \
  gcc-ranlib$(exeext) \
@@ -1524,6 +1532,12 @@ MOSTLYCLEANFILES = insn-flags.h insn-config.h insn-codes.h \
  gengtype$(exeext) *.[0-9][0-9].* *.[si] *-checksum.c libbackend.a \
  libcommon-target.a libcommon.a libgcc.mk
 
+# This symlink makes the full installation name of the driver be available
+# from within the *build* directory, for use when running the JIT library
+# from there (e.g. when running its testsuite).
+$(FULL_DRIVER_NAME): ./xgcc
+       $(LN) -s $< $@
+
 #\f
 # Language makefile fragments.
 
@@ -3287,9 +3301,9 @@ install-driver: installdirs xgcc$(exeext)
        -rm -f $(DESTDIR)$(bindir)/$(GCC_INSTALL_NAME)$(exeext)
        -$(INSTALL_PROGRAM) xgcc$(exeext) $(DESTDIR)$(bindir)/$(GCC_INSTALL_NAME)$(exeext)
        -if [ "$(GCC_INSTALL_NAME)" != "$(target_noncanonical)-gcc-$(version)" ]; then \
-         rm -f $(DESTDIR)$(bindir)/$(target_noncanonical)-gcc-$(version)$(exeext); \
+         rm -f $(DESTDIR)$(bindir)/$(FULL_DRIVER_NAME); \
          ( cd $(DESTDIR)$(bindir) && \
-           $(LN) $(GCC_INSTALL_NAME)$(exeext) $(target_noncanonical)-gcc-$(version)$(exeext) ); \
+           $(LN) $(GCC_INSTALL_NAME)$(exeext) $(FULL_DRIVER_NAME) ); \
        fi
        -if [ ! -f gcc-cross$(exeext) ] \
            && [ "$(GCC_INSTALL_NAME)" != "$(GCC_TARGET_INSTALL_NAME)" ]; then \
index 7c2654538fe3ae233b091d6b9014883176684b90..7f1f47d226a38cf3a88b4c099d0eac1542d6a73d 100755 (executable)
@@ -743,6 +743,7 @@ CXXDEPMODE
 DEPDIR
 am__leading_dot
 CXXCPP
+doc_build_sys
 AR
 NM
 BISON
@@ -8069,6 +8070,47 @@ fi
 
 fi
 
+# The jit documentation looks better if built with sphinx, but can be
+# built with texinfo if sphinx is not available.
+# Set "doc_build_sys" to "sphinx" or "texinfo" accordingly.
+# Extract the first word of "sphinx-build", so it can be a program name with args.
+set dummy sphinx-build; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_doc_build_sys+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$doc_build_sys"; then
+  ac_cv_prog_doc_build_sys="$doc_build_sys" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_doc_build_sys="sphinx"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  test -z "$ac_cv_prog_doc_build_sys" && ac_cv_prog_doc_build_sys="texinfo"
+fi
+fi
+doc_build_sys=$ac_cv_prog_doc_build_sys
+if test -n "$doc_build_sys"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $doc_build_sys" >&5
+$as_echo "$doc_build_sys" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
 
 # --------------------
 # Checks for C headers
@@ -18058,7 +18100,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 18061 "configure"
+#line 18103 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -18164,7 +18206,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 18167 "configure"
+#line 18209 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -28185,6 +28227,12 @@ _ACEOF
 
 fi
 
+# Generate gcc-driver-name.h containing GCC_DRIVER_NAME for the benefit
+# of jit/jit-playback.c.
+cat > gcc-driver-name.h <<EOF
+#define GCC_DRIVER_NAME "${target_noncanonical}-gcc-${gcc_BASEVER}${exeext}"
+EOF
+
 # Configure the subdirectories
 # AC_CONFIG_SUBDIRS($subdirs)
 
index dc14b457a5b169f1d853c1828d87643ae9d80f38..ecb75be101bef3aa8aaeea81acd74e3a0550565f 100644 (file)
@@ -971,6 +971,10 @@ else
   AC_CHECK_PROG(AR, ar, ar, ${CONFIG_SHELL-/bin/sh} ${srcdir}/../missing ar)
 fi
 
+# The jit documentation looks better if built with sphinx, but can be
+# built with texinfo if sphinx is not available.
+# Set "doc_build_sys" to "sphinx" or "texinfo" accordingly.
+AC_CHECK_PROG(doc_build_sys, sphinx-build, sphinx, texinfo)
 
 # --------------------
 # Checks for C headers
@@ -5604,6 +5608,12 @@ if test x"${LINKER_HASH_STYLE}" != x; then
                                          [The linker hash style])
 fi
 
+# Generate gcc-driver-name.h containing GCC_DRIVER_NAME for the benefit
+# of jit/jit-playback.c.
+cat > gcc-driver-name.h <<EOF
+#define GCC_DRIVER_NAME "${target_noncanonical}-gcc-${gcc_BASEVER}${exeext}"
+EOF
+
 # Configure the subdirectories
 # AC_CONFIG_SUBDIRS($subdirs)
 
index fa5fe6e2c97f5315f1514f263cfe5ef42988cb8a..9fbf853d3a38cb27aa4be0c4a95771cd19dff509 100644 (file)
@@ -476,6 +476,11 @@ Necessary for running @command{texi2dvi} and @command{texi2pdf}, which
 are used when running @command{make dvi} or @command{make pdf} to create
 DVI or PDF files, respectively.
 
+@item Sphinx version 1.0 (or later)
+
+Necessary to regenerate @file{jit/docs/_build/texinfo} from the @file{.rst}
+files in the directories below @file{jit/docs}.
+
 @item SVN (any version)
 @itemx SSH (any version)
 
@@ -939,7 +944,7 @@ Specify that the @emph{host} code should be built into position-independent
 machine code (with -fPIC), allowing it to be used within shared libraries,
 but yielding a slightly slower compiler.
 
-Currently this option is only of use to people developing GCC itself.
+This option is required when building the libgccjit.so library.
 
 Contrast with @option{--enable-shared}, which affects @emph{target}
 libraries.
index 4a027e26e72994b540f1bd1c08e9b09367d02f9f..267c3e1e0773a4f7ca2df7ab01baafb6eab84c53 100644 (file)
@@ -1,3 +1,7 @@
+2014-11-11  David Malcolm  <dmalcolm@redhat.com>
+
+       * gcc/ChangeLog.jit: New.
+
 2014-10-29  Richard Sandiford  <richard.sandiford@arm.com>
 
        * builtins.c, java-tree.h, typeck.c: Remove redundant enum from
diff --git a/gcc/java/ChangeLog.jit b/gcc/java/ChangeLog.jit
new file mode 100644 (file)
index 0000000..e5e7e27
--- /dev/null
@@ -0,0 +1,14 @@
+2014-09-24  David Malcolm  <dmalcolm@redhat.com>
+
+       * ChangeLog.jit: Add copyright footer.
+
+2013-10-11  David Malcolm  <dmalcolm@redhat.com>
+
+       * lang.c (java_handle_option): Update for introduction of
+       gcc::dump_manager.
+\f
+Copyright (C) 2013-2014 Free Software Foundation, Inc.
+
+Copying and distribution of this file, with or without modification,
+are permitted in any medium without royalty provided the copyright
+notice and this notice are preserved.
diff --git a/gcc/jit/ChangeLog b/gcc/jit/ChangeLog
new file mode 100644 (file)
index 0000000..23a7b13
--- /dev/null
@@ -0,0 +1,60 @@
+2014-11-11  David Malcolm  <dmalcolm@redhat.com>
+
+       * ChangeLog.jit: New.
+       * ChangeLog: New.
+       * Make-lang.in: New.
+       * TODO.rst: New.
+       * config-lang.in: New.
+       * docs/Makefile: New.
+       * docs/_build/texinfo/Makefile: New.
+       * docs/_build/texinfo/factorial.png: New.
+       * docs/_build/texinfo/libgccjit.texi: New.
+       * docs/_build/texinfo/sum-of-squares.png: New.
+       * docs/conf.py: New.
+       * docs/examples/tut01-hello-world.c: New.
+       * docs/examples/tut02-square.c: New.
+       * docs/examples/tut03-sum-of-squares.c: New.
+       * docs/examples/tut04-toyvm/Makefile: New.
+       * docs/examples/tut04-toyvm/factorial.toy: New.
+       * docs/examples/tut04-toyvm/fibonacci.toy: New.
+       * docs/examples/tut04-toyvm/toyvm.c: New.
+       * docs/index.rst: New.
+       * docs/internals/index.rst: New.
+       * docs/intro/factorial.png: New.
+       * docs/intro/index.rst: New.
+       * docs/intro/sum-of-squares.png: New.
+       * docs/intro/tutorial01.rst: New.
+       * docs/intro/tutorial02.rst: New.
+       * docs/intro/tutorial03.rst: New.
+       * docs/intro/tutorial04.rst: New.
+       * docs/topics/contexts.rst: New.
+       * docs/topics/expressions.rst: New.
+       * docs/topics/functions.rst: New.
+       * docs/topics/index.rst: New.
+       * docs/topics/locations.rst: New.
+       * docs/topics/objects.rst: New.
+       * docs/topics/results.rst: New.
+       * docs/topics/types.rst: New.
+       * dummy-frontend.c: New.
+       * jit-builtins.c: New.
+       * jit-builtins.h: New.
+       * jit-common.h: New.
+       * jit-playback.c: New.
+       * jit-playback.h: New.
+       * jit-recording.c: New.
+       * jit-recording.h: New.
+       * libgccjit++.h: New.
+       * libgccjit.c: New.
+       * libgccjit.h: New.
+       * libgccjit.map: New.
+       * notes.txt: New.
+
+2013-07-26  David Malcolm  <dmalcolm@redhat.com>
+
+       * Initial creation
+
+Copyright (C) 2013-2014 Free Software Foundation, Inc.
+
+Copying and distribution of this file, with or without modification,
+are permitted in any medium without royalty provided the copyright
+notice and this notice are preserved.
diff --git a/gcc/jit/ChangeLog.jit b/gcc/jit/ChangeLog.jit
new file mode 100644 (file)
index 0000000..f887e0f
--- /dev/null
@@ -0,0 +1,3498 @@
+2014-11-10  David Malcolm  <dmalcolm@redhat.com>
+
+       * docs/_build/texinfo/libgccjit.texi: Regenerate.
+
+2014-11-10  David Malcolm  <dmalcolm@redhat.com>
+
+       * dummy-frontend.c: Add includes now needed since r216805 by
+       cgraph.h: hash-map.h, is-a.h, plugin-api.h, vec.h, hashtab.h,
+       hash-set.h, machmode.h, tm.h, hard-reg-set.h, function.h,
+       ipa-ref.h, dumpfile.h.
+       * jit-playback.c: Likewise.
+
+2014-11-05  David Malcolm  <dmalcolm@redhat.com>
+
+       * jit-playback.c (gcc::jit::playback::context::handle_locations):
+       Drop the disabled debugging code.
+
+2014-11-05  David Malcolm  <dmalcolm@redhat.com>
+
+       * docs/topics/expressions.rst (Type-coercion): Casts between
+       pointer types are valid.
+       * libgccjit.c: Document that gcc_jit_context et al are actually
+       subclasses of the gcc::jit::recording classes.
+       (RETURN_VAL_IF_FAIL): Add top-level descriptive comment.
+       (RETURN_IF_NOT_VALID_BLOCK): Likewise.
+       (RETURN_NULL_IF_NOT_VALID_BLOCK): Likewise.
+       (jit_error): Likewise.
+       (compatible_types): Likewise.
+       (gcc_jit_context_acquire): Likewise.
+       (gcc_jit_context_release): Likewise.
+       (gcc_jit_context_new_child_context): Likewise.
+       (gcc_jit_context_new_location): Likewise.
+       (gcc_jit_location_as_object): Likewise.
+       (gcc_jit_type_as_object): Likewise.
+       (gcc_jit_context_get_type): Likewise.
+       (gcc_jit_context_get_int_type): Likewise.
+       (gcc_jit_type_get_pointer): Likewise.
+       (gcc_jit_type_get_const): Likewise.
+       (gcc_jit_type_get_volatile): Likewise.
+       (gcc_jit_context_new_array_type): Likewise.  Also document that
+       LOC can be NULL.  Fail with an error on negative size.
+       (gcc_jit_context_new_field): Add top-level descriptive comment and
+       document that LOC can be NULL.
+       (gcc_jit_field_as_object): Add top-level descriptive comment.
+       (gcc_jit_context_new_struct_type): Likewise.  Also document that
+       LOC can be NULL.
+       (gcc_jit_context_new_opaque_struct): Likewise.
+       (gcc_jit_struct_as_type): Add top-level descriptive comment.
+       (gcc_jit_struct_set_fields): Likewise.  Also document that LOC can
+       be NULL.
+       (gcc_jit_context_new_union_type): Likewise.
+       (gcc_jit_context_new_function_ptr_type): Likewise.
+       (gcc_jit_context_new_param): Likewise.
+       (gcc_jit_param_as_object): Add top-level descriptive comment.
+       (gcc_jit_param_as_lvalue): Likewise.
+       (gcc_jit_param_as_rvalue): Likewise.
+       (gcc_jit_context_new_function): Likewise.  Also document that LOC
+       can be NULL.
+       (gcc_jit_context_get_builtin_function): Add top-level descriptive
+       comment.
+       (gcc_jit_function_as_object): Likewise.
+       (gcc_jit_function_get_param): Likewise.
+       (gcc_jit_function_dump_to_dot): Likewise.
+       (gcc_jit_function_new_block): Likewise.
+       (gcc_jit_block_as_object): Likewise.
+       (gcc_jit_block_get_function): Likewise.
+       (gcc_jit_context_new_global): Likewise.  Also document that LOC
+       can be NULL.
+       (gcc_jit_lvalue_as_object): Add top-level descriptive comment.
+       (gcc_jit_lvalue_as_rvalue): Likewise.
+       (gcc_jit_rvalue_as_object): Likewise.
+       (gcc_jit_rvalue_get_type): Likewise.
+       (RETURN_NULL_IF_FAIL_NONNULL_NUMERIC_TYPE): Likewise.
+       (gcc_jit_context_new_rvalue_from_int): Likewise.
+       (gcc_jit_context_zero): Likewise.
+       (gcc_jit_context_one): Likewise.
+       (gcc_jit_context_new_rvalue_from_double): Likewise.
+       (gcc_jit_context_new_rvalue_from_ptr): Likewise.
+       (gcc_jit_context_null): Likewise.
+       (gcc_jit_context_new_string_literal): Likewise.
+       (gcc_jit_context_new_unary_op): Likewise.  Also document that LOC
+       can be NULL.
+       (gcc_jit_context_new_binary_op): Likewise.
+       (gcc_jit_context_new_comparison): Likewise.
+       (gcc_jit_context_new_call): Likewise.
+       (gcc_jit_context_new_call_through_ptr): Likewise.
+       (is_valid_cast): Add top-level descriptive comment.
+       (gcc_jit_context_new_cast): Likewise.  Also document that LOC can
+       be NULL.
+       (gcc_jit_context_new_array_access): Likewise.
+       (gcc_jit_object_get_context): Add top-level descriptive comment.
+       (gcc_jit_object_get_debug_string): Likewise.
+       (gcc_jit_lvalue_access_field): Likewise.  Also document that LOC can
+       be NULL.
+       (gcc_jit_rvalue_access_field): Likewise.
+       (gcc_jit_rvalue_dereference_field): Likewise.
+       (gcc_jit_rvalue_dereference): Likewise.
+       (gcc_jit_lvalue_get_address): Likewise.
+       (gcc_jit_function_new_local): Likewise.
+       (gcc_jit_block_add_eval): Likewise.
+       (gcc_jit_block_add_assignment): Likewise.
+       (gcc_jit_block_add_assignment_op): Likewise.
+       (is_bool): Add top-level descriptive comment.
+       (gcc_jit_block_end_with_conditional): Likewise.  Also document
+       that LOC can be NULL.
+       (gcc_jit_block_add_comment): Likewise.
+       (gcc_jit_block_end_with_jump): Likewise.
+       (gcc_jit_block_end_with_return): Likewise.
+       (gcc_jit_block_end_with_void_return): Likewise.
+       (gcc_jit_context_set_str_option): Add top-level descriptive
+       comment.
+       (gcc_jit_context_set_int_option): Likewise.
+       (gcc_jit_context_set_bool_option): Likewise.
+       (gcc_jit_context_compile): Likewise.
+       (gcc_jit_context_dump_to_file): Likewise.
+       (gcc_jit_context_get_first_error): Likewise.
+       (gcc_jit_result_get_code): Likewise.
+       (gcc_jit_result_release): Likewise.
+
+       * libgccjit.h (gcc_jit_context_acquire): Remove FIXME from
+       comment.
+       (gcc_jit_context_get_int_type): Add comment.
+       (gcc_jit_context_new_field): Likewise.
+       (gcc_jit_context_new_struct_type): Likewise.
+       (gcc_jit_context_new_opaque_struct): Likewise.
+       (gcc_jit_struct_as_type): Likewise.
+       (gcc_jit_context_new_param): Likewise.
+       (gcc_jit_param_as_lvalue): Likewise.
+       (gcc_jit_param_as_rvalue): Likewise.
+       (enum gcc_jit_function_kind): Likewise.
+       (gcc_jit_context_new_function): Likewise.
+       (gcc_jit_context_get_builtin_function): Likewise.
+       (gcc_jit_function_get_param): Likewise.
+
+2014-11-05  David Malcolm  <dmalcolm@redhat.com>
+
+       * libgccjit.c (gcc_jit_context_get_type): Verify that "type"
+       is valid immediately, rather than relying on called code.
+       (gcc_jit_context_new_function): Likewise for "kind".
+       (gcc_jit_context_new_unary_op): Likewise for "op".
+       (valid_binary_op_p): New.
+       (gcc_jit_context_new_binary_op): Verify that "op" is valid
+       immediately, rather than relying on called code.
+       (gcc_jit_context_new_comparison): Likewise.
+       (gcc_jit_block_add_assignment_op): Likewise.
+
+2014-11-05  David Malcolm  <dmalcolm@redhat.com>
+
+       * libgccjit.c: Include safe-ctype.h from libiberty.
+       (IS_ASCII_ALPHA): Delete.
+       (IS_ASCII_DIGIT): Delete.
+       (IS_ASCII_ALNUM): Delete.
+       (gcc_jit_context_new_function): Replace use of IS_ASCII_ALPHA and
+       IS_ASCII_ALNUM with ISALPHA and ISALNUM respectively, from
+       libiberty.
+
+2014-10-30  David Malcolm  <dmalcolm@redhat.com>
+
+       * dummy-frontend.c (jit_langhook_init): Remove some dead code.
+
+2014-10-27  David Malcolm  <dmalcolm@redhat.com>
+
+       * dummy-frontend.c: Drop includes of tree-iterator.h,
+       tree-ssa-alias.h, gimple-expr.h, gimple.h, gimple-pretty-print.h.
+       * jit-playback.c: Drop includes of debug.h, langhooks.h,
+       langhooks-def.h, tree-iterator.h, gimple-expr.h, tree-ssa-alias.h,
+       gimple.h, gimple-pretty-print.h, diagnostic-core.h, dumpfile.h.
+
+2014-10-21  David Malcolm  <dmalcolm@redhat.com>
+
+       * jit-recording.c: Include tm.h.  Don't include function.h.
+
+2014-10-21  David Malcolm  <dmalcolm@redhat.com>
+
+       * docs/_build/texinfo/libgccjit.texi: Regenerate.
+
+2014-10-21  David Malcolm  <dmalcolm@redhat.com>
+
+       * docs/intro/index.rst: Drop install.rst.  Add tutorial04.rst.
+       * docs/intro/install.rst: Rename to...
+       * docs/intro/tutorial01.rst: ...this, renaming old tutorial01.rst to...
+       * docs/intro/tutorial02.rst: ...this, renaming old tutorial02.rst to...
+       * docs/intro/tutorial03.rst: ...this, renaming old tutorial03.rst to...
+       * docs/intro/tutorial04.rst: ...this.
+       * docs/examples/install-hello-world.c: Rename to...
+       * docs/examples/tut01-hello-world.c: ...this.
+       * docs/examples/tut01-square.c: Rename to...
+       * docs/examples/tut02-square.c: ...this.
+       * docs/examples/tut02-sum-of-squares.c: Rename to...
+       * docs/examples/tut03-sum-of-squares.c: ...this.
+       * docs/examples/tut03-toyvm: Rename directory to...
+       * docs/examples/tut04-toyvm: ...this.
+       * docs/examples/tut04-toyvm/toyvm.c (PATH_TO_SCRIPTS): Update
+       for directory renaming.
+
+2014-10-21  David Malcolm  <dmalcolm@redhat.com>
+
+       * docs/intro/install.rst ("Installation via packages"): Drop
+       this section.
+       ("Installation from source"): Drop this section, moving parts
+       of it to https://gcc.gnu.org/wiki/JIT and some others to
+       docs/internals/index.rst.
+       ("Hello world"): This section becomes the only remaining part
+       of this file.  Eliminate references to pkg-config.
+
+       * docs/internals/index.rst
+       ("Using a working copy without installing every time"): Rewrite
+       as...
+       ("Working on the JIT library"): ...new section, aimed at
+       contributors (and myself) working from a build directory,
+       eliminating references to installation.  Add description
+       of pertinent configuration options.
+       ("Running the test suite"): Add setting of LIBRARY_PATH to
+       description of how to run a built binary outside of the test
+       suite.
+       ("Environment variables"): New section, describing pertinent
+       environment variables.
+
+2014-10-20  David Malcolm  <dmalcolm@redhat.com>
+
+       * jit-recording.c (gcc::jit::dump::dump): Handle fopen failures
+       by emitting an error on the context.
+       (gcc::jit::dump::~dump): Likewise for fclose failures.
+       (gcc::jit::dump::write): Don't attempt further work if the fopen
+       failed.  Handle fwrite failures by emitting an error on the
+       context.
+
+2014-10-20  David Malcolm  <dmalcolm@redhat.com>
+
+       * Make-lang.in (jit.install-common): Drop installation of
+       libgccjit.pc.
+       * config-lang.in (outputs): Drop jit/libgccjit.pc.
+       * libgccjit.pc.in: Delete.
+
+2014-10-17  David Malcolm  <dmalcolm@redhat.com>
+
+       * Make-lang.in (jit): Add $(FULL_DRIVER_NAME) as a dependency, so
+       that the symlink is created for testing.
+
+       * jit-playback.c (gcc::jit::playback::context::compile): Add
+       "-fno-use-linker-plugin" when invoking the driver.  Update error
+       messages to talk about the "gcc driver" rather than the
+       "gcc harness".  To ease troubleshooting, add error messages giving
+       the driver name and PATH to the error-handling code that fires
+       when the driver can't be found.
+
+2014-10-07  David Malcolm  <dmalcolm@redhat.com>
+
+       * docs/_build/texinfo/libgccjit.texi: Regenerate.
+
+2014-10-07  David Malcolm  <dmalcolm@redhat.com>
+
+       * docs/internals/index.rst (Overview of code structure): Directly
+       include the comment from jit-common.h as rst, rather than as a
+       quoted C++ comment.
+       * jit-common.h: Convert the summary format to valid reStructured
+       text for inclusion by docs/internals/index.rst.
+       * notes.txt: Clarify where libgccjit.c, jit-recording.c and
+       jit-playback.c fit into the high-level diagram.
+
+2014-10-07  David Malcolm  <dmalcolm@redhat.com>
+
+       * Make-lang.in (jit_OBJS): Drop jit/internal-api.o.
+       Add jit/jit-recording.o and jit/jit-playback.o.
+
+       * internal-api.c: Delete, moving content to new files jit-recording.c
+       and jit-playback.c.
+       * internal-api.h: Delete, moving content to new files
+       jit-common.h, jit-playback.h, jit-recording.h.
+       * jit-common.h: New file, containing the forward decls of classes
+       formerly in internal-api.h.
+       * jit-recording.c: New file, containing the gcc::jit::recording
+       code formerly in internal-api.c, and gcc::jit::dump.
+       * jit-recording.h: New file, containing the gcc::jit::recording
+       prototypes formerly in internal-api.h.
+       * jit-playback.c: New file, containing the gcc::jit::playback
+       code formerly in internal-api.c.
+       * jit-playback.h: New file, containing the gcc::jit::playback
+       prototypes formerly in internal-api.h.
+
+       * dummy-frontend.c: Don't include "internal-api.h".  Add includes
+       of jit-common.h and jit-playback.h.
+       * jit-builtins.h: Replace include of internal-api.h with
+       jit-common.h.
+       * jit-builtins.c: Replace include of internal-api.h with
+       jit-common.h.  Add include of jit-recording.h.
+       * libgccjit.c: Likewise.
+
+       * docs/internals/index.rst (Overview of code structure): Update
+       to reflect the above changes.
+
+2014-10-07  David Malcolm  <dmalcolm@redhat.com>
+
+       * docs/internals/index.rst
+       (Using a working copy without installing): Rename to...
+       (Using a working copy without installing every time): ...this, and
+       update to reflect the need to have installed the driver binary
+       when running directly from a build directory.
+       (Running the test suite): Add PATH setting to the example.
+       * docs/intro/install.rst ("Hello world"): Likewise.
+       * internal-api.c: Include new autogenerated header
+       "gcc-driver-name.h".
+       (gcc::jit::playback::context::compile): Rather than looking for a
+       "gcc" on the path, look for GCC_DRIVER_NAME from gcc-driver-name.h,
+       as created by the configure script, so that we are using one for
+       the correct target.
+
+2014-10-02  David Malcolm  <dmalcolm@redhat.com>
+
+       * Make-lang.in (jit.info): Implement.
+       (jit.install-info): Implement.
+       (jit.dvi): Implement.
+       (jit.pdf): Implement in terms of new target "jit.texinfo.pdf".
+       (jit.install-pdf): Likewise for new target
+       "jit.texinfo.install-pdf".
+       (jit.install-html): Implement in terms of
+       "jit.$(doc_build_sys).install-html" to redirect to new targets
+       "jit.sphinx.install-html" or "jit.texinfo.install-html".
+       (jit.html): Implement in terms of "jit.$(doc_build_sys).html" to
+       redirect to new targets "jit.sphinx.html" or "jit.texinfo.html".
+       (JIT_TEXI_FILES): New variable.
+       (jit.texinfo.html): New target.
+       (jit.texinfo.install-html): New target.
+       (jit.texinfo.pdf): New target.
+       (jit.texinfo.install-pdf): New target.
+       (SPHINX_BUILD_DIR): New variable.
+       (jit.sphinx.html): New target.
+       (jit_htmldir): New variable.
+       (jit.sphinx.install-html): New target.
+       (jit.sphinx.pdf): New target.
+
+2014-09-26  David Malcolm  <dmalcolm@redhat.com>
+
+       * internal-api.h (gcc::jit::recording::context): Convert field
+       "m_first_error_str" from a fixed-size buffer to a pointer, and add
+       a field "m_owns_first_error_str" to determine if we're responsible
+       for freeing it.
+       * internal-api.c (gcc::jit::recording::context::context): Update
+       initializations in ctor for above change.
+       (gcc::jit::recording::context::~context): Free m_first_error_str
+       if we own it.
+       (gcc::jit::recording::context::add_error_va): When capturing the
+       first error message on a context, rather than copying "errmsg" to
+       a fixed-size buffer and truncating if oversize, simply store the
+       pointer to the error message, and flag whether we need to free it.
+       (gcc::jit::recording::context::get_first_error): Update for change
+       of "m_first_error_str" from an internal buffer to a pointer.
+
+2014-09-25  David Malcolm  <dmalcolm@redhat.com>
+
+       * internal-api.c (gcc::jit::playback::context::compile): Use
+       pex_one rather than system when invoking "gcc" to go from a .s
+       file to a .so file.
+
+2014-09-25  David Malcolm  <dmalcolm@redhat.com>
+
+       * internal-api.c (make_tempdir_path_template): New.
+       (gcc::jit::playback::context::compile): Call
+       make_tempdir_path_template to make m_path_template, rather than
+       hardcoding "/tmp/" within "/tmp/libgccjit-XXXXXX".
+
+2014-09-24  David Malcolm  <dmalcolm@redhat.com>
+
+       * docs/internals/index.rst ("Overview of code structure"): Add
+       more descriptive text, including various fragments of
+       internal-api.h as appropriate.
+       * internal-api.h: Add marker comments for use by "literalinclude"
+       directives in docs/internals/index.rst.
+
+2014-09-24  David Malcolm  <dmalcolm@redhat.com>
+
+       * dummy-frontend.c (my_walker): Rename to...
+       (my_ggc_walker): ...this.
+       (my_root_tab): Rename to...
+       (jit_root_tab): ...this.
+       (jit_langhook_init): Update for renaming of "my_root_tab" to
+       "jit_root_tab".
+       * internal-api.c: Add descriptive API comments to functions
+       throughout.
+       (mutex): Rename to...
+       (jit_mutex): ...this.
+       (gcc::jit::recording::context::compile): Update for renaming of
+       "mutex" to "jit_mutex".
+       * internal-api.h: Add descriptive API comments to functions
+       throughout.  Add indentation to forward declarations of classes
+       to indicate inheritance.
+       * jit-builtins.c: Likewise.
+
+2014-09-24  David Malcolm  <dmalcolm@redhat.com>
+
+       * internal-api.c (gcc::jit::dump::write): Eliminate fixed-size
+       buffer "buf" by replacing call to vsnprintf with one to vasprintf
+       and a free, emitting an error on the dump's context if a malloc
+       failure occurs.
+       (gcc::jit::recording::context::add_error_va): Likewise, using
+       a precanned message if the malloc inside vasprinf fails.  Split
+       local "buf" into "malloced_msg" and "errmsg" to ensure that we
+       free the message iff we're using one malloc-ed by vasprintf.
+       (gcc::jit::recording::string::from_printf): Eliminate fixed-size
+       buffer "buf" by replacing call to vsnprintf with one to vasprintf
+       and a free, emitting an error on the relevant context if a malloc
+       failure occurs.
+
+2014-09-24  David Malcolm  <dmalcolm@redhat.com>
+
+       * dummy-frontend.c: Update copyright year.  Follow standard for
+       initial includes by removing redundant include of "ansidecl.h".
+       * internal-api.c: Follow standard for initial includes by removing
+       redundant include of "ansidecl.h".
+       * jit-builtins.c: Likewise.
+       * libgccjit.c: Likewise.
+
+2014-09-24  David Malcolm  <dmalcolm@redhat.com>
+
+       * ChangeLog.jit: Add copyright footer.
+       * Make-lang.in: Update copyright.
+       * config-lang.in: Update copyright.
+       * docs/examples/install-hello-world.c: Add copyright header.
+       * docs/examples/tut01-square.c: Likewise.
+       * docs/examples/tut02-sum-of-squares.c: Likewise.
+       * docs/examples/tut03-toyvm/toyvm.c: Likewise.
+       * internal-api.c: Likewise.
+       * internal-api.h: Likewise.
+       * libgccjit++.h: Likewise.
+       * libgccjit.c: Likewise.
+       * libgccjit.h: Likewise.
+       * libgccjit.map: Likewise.
+
+2014-09-23  David Malcolm  <dmalcolm@redhat.com>
+
+       * TODO.rst (API): Shift operators are done.
+       * docs/topics/expressions.rst (Binary): Add shift operators.
+       * internal-api.c (binary_op_strings): Likewise.
+       (gcc::jit::playback::context::new_binary_op): Likewise.
+       * libgccjit.h (enum gcc_jit_binary_op): Likewise.
+
+2014-09-23  David Malcolm  <dmalcolm@redhat.com>
+
+       * TODO.rst: Rename "Initial Release" section to "API", and
+       remove completed items: builtins, docs, pkgconfig file, fuzz
+       testing.  Move ability to name contexts and stmt_list per block
+       ideas to a new "Nice to have" section and note that it might be
+       better to go straight to gimple.
+       Move code coverage to "Test suite" section.
+       Add a "Probably not needed" section, moving some items to it.
+       Note that we're still missing shift operators.
+       Add idea that we could warn about unused objects in a context.
+
+2014-09-23  David Malcolm  <dmalcolm@redhat.com>
+
+       * docs/examples/tut03-toyvm/toyvm.c: Include <dejagnu.h>.
+       Add missing typedef of compilation_state.
+       (toyvm_function_parse): Add "name param.
+       (test): New.
+       (CHECK_NON_NULL): New, from harness.h
+       (CHECK_VALUE): Likewise.
+       (test_script): New.
+       (PATH_TO_SCRIPTS): New define.
+       (test_suite): New.
+       (main): If called with no args, run the test suite.
+
+2014-09-23  David Malcolm  <dmalcolm@redhat.com>
+
+       * docs/conf.py (__read_file): New helper function, for
+       extracting...
+       (gcc_BASEVER): New variable, read from "BASE-VER" in gcc src dir.
+       (gcc_DEVPHASE): Likewise, from file "DEV-PHASE".
+       (gcc_DATESTAMP): Likewise, from file "DATESTAMP".
+       (gcc_REVISION): Likewise, from file "REVISION" (if present).
+       (version): Rather than hardcoding this variable, extract from file
+       BASE-VER, via gcc_BASEVER local.
+       (release): Likewise, building it up from the files read above.
+       * docs/_build/texinfo/libgccjit.texi: Regenerate.
+
+2014-09-22  David Malcolm  <dmalcolm@redhat.com>
+
+       * docs/intro/tutorial01.rst: Remove stray "FIXME".
+       * docs/_build/texinfo/libgccjit.texi: Regenerate.
+
+2014-09-22  David Malcolm  <dmalcolm@redhat.com>
+
+       * docs/index.rst: Add internals/index.rst.
+       * docs/internals/index.rst: New.
+       * notes.txt: Update to reflect renaming of toplev_main to
+       toplev::main.
+
+2014-09-22  David Malcolm  <dmalcolm@redhat.com>
+
+       * docs/_build/texinfo/libgccjit.texi: Regenerate.
+       * docs/intro/install.rst: Reduce width of listing.
+       * docs/intro/tutorial01.rst: Use <libgccjit.h> rather than
+       "libgccjit.h" when including the header.
+       * docs/intro/tutorial02.rst: Likewise.
+       * docs/intro/tutorial03.rst: Clarify various sections; show
+       effect of reducing optimization level down from 3 to 2.
+       ("Putting it all together"): Move to above...
+       ("Behind the curtain: optimizing away stack manipulation"):
+       ...this, and rename this to...
+       ("Behind the curtain: How does our code get optimized?"): ...and
+       add more detail, and discussion of elimination of tail recursion.
+
+2014-09-19  David Malcolm  <dmalcolm@redhat.com>
+
+       * TODO.rst: Add detection of uninitialized variables, since
+       this bit me when developing "toyvm".
+
+       * docs/examples/tut03-toyvm/Makefile: New.
+       * docs/examples/tut03-toyvm/factorial.toy: New.
+       * docs/examples/tut03-toyvm/fibonacci.toy: New.
+       * docs/examples/tut03-toyvm/toyvm.c: New.
+
+       * docs/intro/index.rst: Add tutorial03.rst.
+       * docs/intro/tutorial01.rst: Fix example of how to dump
+       generated machine code.
+       * docs/intro/tutorial03.rst: New.
+       * docs/intro/factorial.png: New.
+
+       * docs/_build/texinfo/libgccjit.texi: Regenerate.
+       * docs/_build/texinfo/factorial.png: New (copied by sphinx from
+       docs/intro/factorial.png).
+
+2014-09-18  David Malcolm  <dmalcolm@redhat.com>
+
+       * Make-lang.in (jit.install-common): Install libgccjit.pc to
+       "$(DESTDIR)/$(libdir)/pkgconfig".
+       * config-lang.in (outputs): Define this, adding jit/libgccjit.pc
+       so that it makes it into AC_CONFIG_FILES and is thus generated from
+       jit/libgccjit.pc.in at configure time.
+       * docs/intro/install.rst ("Hello world"): Add discussion about the
+       use of pkg-config when building against an install in
+       a non-standard location.
+       * docs/_build/texinfo/libgccjit.texi: Regenerate.
+       * libgccjit.pc.in: New.
+
+2014-09-18  David Malcolm  <dmalcolm@redhat.com>
+
+       * docs/index.rst: Split index out into two new files...
+       * docs/intro/index.rst: New file.
+       * docs/topics/index.rst: New file.
+       * docs/_build/texinfo/libgccjit.texi: Regenerate.
+
+2014-09-18  David Malcolm  <dmalcolm@redhat.com>
+
+       * docs/_build/texinfo/Makefile: New file, generated by Sphinx, by
+       running "make texinfo" in docs directory.
+       * docs/_build/texinfo/libgccjit.texi: Likewise.
+       * docs/_build/texinfo/sum-of-squares.png: Likewise.
+
+2014-09-18  David Malcolm  <dmalcolm@redhat.com>
+
+       * docs/conf.py (Options for HTML output): Update html_theme from
+       "default" to "pyramid".
+
+2014-09-18  David Malcolm  <dmalcolm@redhat.com>
+
+       * docs/intro/install.rst: Markup fixes.
+       * docs/intro/tutorial01.rst: Likewise.
+       * docs/intro/tutorial02.rst: Likewise.
+       * docs/topics/contexts.rst: Likewise.
+       * docs/topics/expressions.rst: Likewise.
+       * docs/topics/functions.rst: Likewise.
+       * docs/topics/locations.rst: Likewise.
+       * docs/topics/types.rst: Likewise.
+
+2014-09-18  David Malcolm  <dmalcolm@redhat.com>
+
+       * docs/examples/install-hello-world.c (main): Fix missing
+       "return".
+       * docs/examples/tut01-square.c (main): Likewise.
+       * docs/examples/tut02-sum-of-squares.c (main): Likewise.
+
+2014-09-17  David Malcolm  <dmalcolm@redhat.com>
+
+       * docs/Makefile: New file.
+       * docs/conf.py: New file.
+       * docs/examples/install-hello-world.c: New file.
+       * docs/examples/tut01-square.c: New file.
+       * docs/examples/tut02-sum-of-squares.c: New file.
+       * docs/index.rst: New file.
+       * docs/intro/install.rst: New file.
+       * docs/intro/sum-of-squares.png: New file.
+       * docs/intro/tutorial01.rst: New file.
+       * docs/intro/tutorial02.rst: New file.
+       * docs/topics/contexts.rst: New file.
+       * docs/topics/expressions.rst: New file.
+       * docs/topics/functions.rst: New file.
+       * docs/topics/locations.rst: New file.
+       * docs/topics/objects.rst: New file.
+       * docs/topics/results.rst: New file.
+       * docs/topics/types.rst: New file.
+
+2014-09-11  David Malcolm  <dmalcolm@redhat.com>
+
+       * TODO.rst (Initial Release): Update for addition of myself as
+       maintainer.
+
+2014-09-10  David Malcolm  <dmalcolm@redhat.com>
+
+       * TODO.rst (Test suite): Multithreaded test is done.
+
+2014-09-10  David Malcolm  <dmalcolm@redhat.com>
+
+       * dummy-frontend.c: Fix up for the header file flattening on
+       trunk by adding includes of signop.h, tree-core.h, stor-layout.h,
+       tree-ssa-alias.h, gimple-expr.h.
+       (jit_langhook_write_globals): Update call to
+       finalize_compilation_unit to symtab->finalize_compilation_unit to
+       track change made on trunk in r214422.
+
+       * internal-api.c: Fix up for the header file flattening on trunk
+       by adding includes of gimple-expr.h, tree-ssa-alias.h,
+       stringpool.h, stor-layout.h, print-tree.h, gimplify.h.
+       (new_rvalue_from_int): Update call to real_from_integer.
+       (gcc::jit::playback::wrapper::operator new): Use
+       ggc_internal_cleared_alloc rather than
+       ggc_internal_cleared_alloc_stat.
+       (gcc::jit::playback::function::postprocess): Update call to
+       cgraph_finalize_function tocgraph_node::finalize_function.
+       (gcc::jit::playback::block::add_comment): Update call to
+       ggc_internal_alloc_stat to ggc_internal_alloc.
+
+2014-08-08  David Malcolm  <dmalcolm@redhat.com>
+
+       * libgccjit.h (gcc_jit_context_new_union_type): New entrypoint.
+       (gcc_jit_lvalue_access_field): Rename first param from "struct_"
+       to "struct_or_union".
+       (gcc_jit_rvalue_access_field): Likewise.
+
+       * libgccjit.c (gcc_jit_context_new_union_type): New entrypoint.
+
+       * libgccjit.map (gcc_jit_context_new_union_type): New entrypoint.
+
+       * internal-api.h (gcc::jit::recording::compound_type): New class
+       (gcc::jit::recording::union): New class.
+       (gcc::jit::playback::struct_): Rename this class to...
+       (gcc::jit::playback::compound_type): ...this.
+       (gcc::jit::recording::context::new_union_type): New method.
+       (gcc::jit::recording::context): Rename field "m_structs" to
+       "m_compound_types", generalizing from a vec <struct_ *> to a
+       vec<compound_type *>.
+       (gcc::jit::recording::field): Update field m_container from
+       struct * to container_type *.
+       (gcc::jit::recording::field::get_container): Generalize from
+       struct_ * to container_type *.
+       (gcc::jit::recording::field::set_container): Likewise.
+       (gcc::jit::recording::compound_type): New subclass of type, to
+       be a superclass of existing class struct_ and new class union_.
+       (gcc::jit::recording::struct_::get_name): Move to...
+       (gcc::jit::recording::compound_type::get_name): ...here.
+       (gcc::jit::recording::struct_::get_loc): Move to...
+       (gcc::jit::recording::compound_type::get_loc): ...here.
+       (gcc::jit::recording::struct_::set_fields): Move to...
+       (gcc::jit::recording::compound_type::set_fields): ...here.
+       (gcc::jit::recording::struct_::dereference): Move to...
+       (gcc::jit::recording::compound_type::dereference): ...here.
+       (gcc::jit::recording::struct_::is_int): Move to...
+       (gcc::jit::recording::compound_type::is_int): ...here.
+       (gcc::jit::recording::struct_::is_float): Move to...
+       (gcc::jit::recording::compound_type::is_float): ...here.
+       (gcc::jit::recording::struct_::is_bool): Move to...
+       (gcc::jit::recording::compound_type::is_bool): ...here.
+       (gcc::jit::recording::struct_::is_pointer): Move to...
+       (gcc::jit::recording::compound_type::is_pointer): ...here.
+       (gcc::jit::recording::struct_::is_array): Move to...
+       (gcc::jit::recording::compound_type::is_array): ...here.
+       (gcc::jit::recording::struct_::playback_struct): Move to...
+       (gcc::jit::recording::compound_type::playback_compound_type):
+       ...here, renaming and updating return type.
+       (gcc::jit::recording::struct_): Inherit from compound_type,
+       rather than just type.
+       (gcc::jit::recording::fields): Update to work on compound_type *
+       rather than struct_ *, renaming "m_struct" to "m_struct_or_union".
+       (gcc::jit::recording::union): New subclass of compound_type.
+       (gcc::jit::playback::context::new_struct_type): Generalize by
+       renaming to...
+       (gcc::jit::playback::context::new_compound_type): ...this, and
+       and an "is_struct" bool param.
+       (gcc::jit::playback::struct_): Generalize by renaming class to...
+       (gcc::jit::playback::compound_type): ...this.
+
+       * internal-api.c (gcc::jit::recording::context::context): Rename
+       field "m_structs" to "m_compound_types".
+       (gcc::jit::recording::context::new_struct_type): Likewise.
+       (gcc::jit::recording::context::new_union_type): New method.
+       (gcc::jit::recording::context::dump_to_file): Field "m_structs"
+       is renamed "m_compound_types" and changes type from struct_ *
+       to compound_type *.
+       (gcc::jit::recording::compound_type::compound_type): New ctor,
+       built from old body of gcc::jit::recording::struct_::struct_.
+       (gcc::jit::recording::struct_::set_fields): Move class to...
+       (gcc::jit::recording::compound_type::set_fields): ... here.
+       (gcc::jit::recording::struct_::dereference): Move class to...
+       (gcc::jit::recording::compound_type::dereference): ...here.
+       (gcc::jit::recording::struct_::struct_): Reimplement by calling
+       base class ctor.
+       (gcc::jit::recording::struct_::replay_into): The playback hook
+       is now "new_compound_type" and adds a bool, with true for
+       "is_struct" (vs a union).
+       (gcc::jit::recording::struct_::make_debug_string): "m_name" is
+       now moved to base class and private, so use an accessor.
+       (gcc::jit::recording::union_::union_): New function.
+       (gcc::jit::recording::union_::replay_into): New function.
+       (gcc::jit::recording::union_::make_debug_string): New function.
+       (gcc::jit::recording::fields::fields): Update first param from
+       struct_ * to compound_type *, and rename field "m_struct" to
+       "m_struct_or_union".
+       (gcc::jit::recording::fields::replay_into): "m_struct" is now
+       "m_struct_or_union" and has a playback_compound_type rather
+       than a playback_struct.
+       (gcc::jit::recording::fields::write_to_dump): Update for
+       renaming of m_struct to m_struct_or_union.
+       (gcc::jit::playback::context::new_struct_type): Rename method
+       to...
+       (gcc::jit::playback::context::new_compound_type): this,
+       generalizing so that it can make unions as well as structs; the
+       underlying playback type is now called "compound_type".
+       (gcc::jit::playback::struct_::set_fields): This method's class has
+       changed name, so this is now...
+       (gcc::jit::playback::compound_type::set_fields): ...this method.
+
+       * TODO.rst: Unions are done.
+
+2014-08-08  David Malcolm  <dmalcolm@redhat.com>
+
+       * TODO.rst: Function ptrs are done.
+       * internal-api.c
+       (gcc::jit::recording::context::new_function_ptr_type): New method.
+       (gcc::jit::recording::context::new_call_through_ptr): New method.
+       (gcc::jit::recording::memento_of_get_pointer::make_debug_string):
+       Add special-case handling of function pointer types.
+       (gcc::jit::recording::function_type::make_debug_string_with_ptr):
+       New method.
+       (gcc::jit::recording::function_type::make_debug_string):
+       Reimplement in terms of...
+       (gcc::jit::recording::function_type::make_debug_string_with): New
+       method, based on make_debug_string, but allowing for arbitrary
+       text between the return type and the parameters.
+       (gcc::jit::recording::call_through_ptr::call_through_ptr): New
+       method.
+       (gcc::jit::recording::call_through_ptr::replay_into): New method.
+       (gcc::jit::recording::call_through_ptr::make_debug_string): New
+       method.
+       (gcc::jit::playback::context::new_call): Reimplement in terms of...
+       (gcc::jit::playback::context::build_call): New method, using parts
+       of old implementation of new_call, so that we can share this
+       with...
+       (gcc::jit::playback::context::new_call_through_ptr): New method.
+       * internal-api.h
+       (gcc::jit::recording::context::new_function_ptr_type): New method.
+       (gcc::jit::recording::context::new_call_through_ptr): New method.
+       (gcc::jit::recording::type::dyn_cast_function_type): New method.
+       (gcc::jit::recording::function_type::dyn_cast_function_type): New
+       method.
+       (gcc::jit::recording::function_type::make_debug_string_with_ptr):
+       New method.
+       (gcc::jit::recording::function_type::make_debug_string_with): New
+       method.
+       (gcc::jit::recording::call_through_ptr): New subclass of rvalue.
+       (gcc::jit::playback::context::new_call_through_ptr): New method.
+       (gcc::jit::playback::context::build_call): New method.
+       * libgccjit.c (gcc_jit_context_new_function_ptr_type): New
+       function.
+       (gcc_jit_context_new_call_through_ptr): New function.
+       * libgccjit.h (gcc_jit_context_new_function_ptr_type): New
+       function.
+       (gcc_jit_context_new_call_through_ptr): New function.
+       * libgccjit.map (gcc_jit_context_new_call_through_ptr): New function.
+       (gcc_jit_context_new_function_ptr_type): New function.
+
+2014-07-25  David Malcolm  <dmalcolm@redhat.com>
+
+       * TODO.rst (error-checking): Remove various items that either
+       already were implemented, or are implemented by this commit.
+       * internal-api.h (gcc::jit::recording::type::is_numeric): New.
+       * libgccjit.c (RETURN_NULL_IF_FAIL_NONNULL_NUMERIC_TYPE): New macro.
+        (gcc_jit_context_new_rvalue_from_int): Verify that numeric_type is
+       indeed numeric.
+       (gcc_jit_context_zero): Likewise.
+       (gcc_jit_context_one): Likewise.
+       (gcc_jit_context_new_rvalue_from_double): Likewise.
+       (gcc_jit_context_new_array_access): Likewise for type of "index".
+
+2014-07-14  David Malcolm  <dmalcolm@redhat.com>
+
+       * internal-api.c (gcc::jit::recording::context::new_array_type):
+       Reject attempts to create an array of a struct if the fields of
+       the struct haven't yet been set.
+       * internal-api.h (gcc::jit::recording::type::dyn_cast_struct): New
+       virtual function.
+       (gcc::jit::recording::struct_::dyn_cast_struct): New, overriding
+       for this subclass.
+       (gcc::jit::recording::struct_::get_name): New.
+
+2014-05-07  David Malcolm  <dmalcolm@redhat.com>
+
+       * Make-lang.in (LIBGCCJIT_LINKER_NAME): New.
+       (LIBGCCJIT_VERSION_NUM): New.
+       (LIBGCCJIT_MINOR_NUM): New.
+       (LIBGCCJIT_RELEASE_NUM): New.
+       (LIBGCCJIT_SONAME): New.
+       (LIBGCCJIT_FILENAME): New.
+       (LIBGCCJIT_LINKER_NAME_SYMLINK): New.
+       (LIBGCCJIT_SONAME_SYMLINK): New.
+       (jit): Add symlink targets.
+       (libgccjit.so): Convert to...
+       (LIBGCCJIT_FILENAME): ...and add a soname.
+       (jit.install-common): Install the library with a soname, and
+       symlinks.  Install libgccjit++.h.
+
+2014-04-25  David Malcolm  <dmalcolm@redhat.com>
+
+       * internal-api.c (gcc::jit::playback::context::compile): Put
+       any output of dlerror through the add_error method, rather
+       than merely printing it to stderr, so that the error is also
+       recorded on the context.
+
+2014-03-19  Tom Tromey  <tromey@redhat.com>
+
+       * internal-api.c (compile): Use auto_timevar.
+
+2014-03-19  Tom Tromey  <tromey@redhat.com>
+
+       * internal-api.c (compile): Use toplev, not toplev_options.
+       Simplify.
+
+2014-03-19  David Malcolm  <dmalcolm@redhat.com>
+
+       * internal-api.c (gcc::jit::recording::context::add_error_va):
+       Rename local "progname" to "ctxt_progname" to avoid shadowing
+       the related global, for clarity.
+       (gcc::jit::playback::context::compile): Likewise.
+
+2014-03-19  David Malcolm  <dmalcolm@redhat.com>
+
+       * internal-api.c (gcc::jit::recording::memento_of_get_pointer::
+       accepts_writes_from): Accept writes from pointers, but not arrays.
+
+       * internal-api.h (gcc::jit::recording::type::is_pointer): New.
+       (gcc::jit::recording::type::is_array): New.
+       (gcc::jit::recording::memento_of_get_type::accepts_writes_from):
+       Allow (void *) to accept writes of pointers, but not arrays.
+       (gcc::jit::recording::memento_of_get_type::is_pointer): New.
+       (gcc::jit::recording::memento_of_get_type::is_array): New.
+       (gcc::jit::recording::memento_of_get_pointer::is_pointer): New.
+       (gcc::jit::recording::memento_of_get_pointer::is_array): New.
+       (gcc::jit::recording::memento_of_get_const::is_pointer): New.
+       (gcc::jit::recording::memento_of_get_const::is_array): New.
+       (gcc::jit::recording::memento_of_get_volatile::is_pointer): New.
+       (gcc::jit::recording::memento_of_get_volatile::is_array): New.
+       (gcc::jit::recording::array_type::is_pointer): New.
+       (gcc::jit::recording::array_type::is_array): New.
+       (gcc::jit::recording::function_type::is_pointer): New.
+       (gcc::jit::recording::function_type::is_array): New.
+       (gcc::jit::recording::struct_::is_pointer): New.
+       (gcc::jit::recording::struct_::is_array): New.
+
+       * libgccjit.c (gcc_jit_context_new_rvalue_from_ptr): Require the
+       pointer_type to be a pointer, not an array.
+       (gcc_jit_context_null): Likewise.
+       (is_valid_cast): Require pointer casts to be between pointer types,
+       not arrays.
+       (gcc_jit_context_new_array_access): Update error message from "not
+       a pointer" to "not a pointer or array".
+       (gcc_jit_rvalue_dereference_field): Require the pointer arg to be
+       of pointer type, not an array.
+       (gcc_jit_rvalue_dereference): Likewise.
+
+2014-03-14  David Malcolm  <dmalcolm@redhat.com>
+
+       * libgccjit.c (is_valid_cast): Permit casts between pointer types.
+
+       * internal-api.c (convert): Report more information if this ever
+       occurs, and make the error occur on the playback context, so that
+       it makes the gcc_jit_result be NULL.
+       (gcc::jit::playback::context::build_cast): Handle pointers.  Report
+       more information if an unhandlable cast reaches here.
+
+2014-03-13  David Malcolm  <dmalcolm@redhat.com>
+
+       * libgccjit.c (is_valid_cast): New.
+       (gcc_jit_context_new_cast): Check for compatible types.
+
+       * internal-api.c (gcc::jit::recording::memento_of_get_type::
+       is_int): New.
+       (gcc::jit::recording::memento_of_get_type::is_float): New.
+       (gcc::jit::recording::memento_of_get_type::is_bool): New.
+
+       * internal-api.h (gcc::jit::recording::type::is_int): New.
+       (gcc::jit::recording::type::is_float): New.
+       (gcc::jit::recording::type::is_bool): New.
+
+       (gcc::jit::recording::memento_of_get_type::is_int): New.
+       (gcc::jit::recording::memento_of_get_type::is_float): New.
+       (gcc::jit::recording::memento_of_get_type::is_bool): New.
+
+       (gcc::jit::recording::memento_of_get_pointer::is_int): New.
+       (gcc::jit::recording::memento_of_get_pointer::is_float): New.
+       (gcc::jit::recording::memento_of_get_pointer::is_bool): New.
+
+       (gcc::jit::recording::memento_of_get_const::is_int): New.
+       (gcc::jit::recording::memento_of_get_const::is_float): New.
+       (gcc::jit::recording::memento_of_get_const::is_bool): New.
+
+       (gcc::jit::recording::memento_of_get_volatile::is_int): New.
+       (gcc::jit::recording::memento_of_get_volatile::is_float): New.
+       (gcc::jit::recording::memento_of_get_volatile::is_bool): New.
+
+       (gcc::jit::recording::array_type::is_int): New.
+       (gcc::jit::recording::array_type::is_float): New.
+       (gcc::jit::recording::array_type::is_bool): New.
+
+       (gcc::jit::recording::function_type::is_int): New.
+       (gcc::jit::recording::function_type::is_float): New.
+       (gcc::jit::recording::function_type::is_bool): New.
+
+       (gcc::jit::recording::struct_::is_int): New.
+       (gcc::jit::recording::struct_::is_float): New.
+       (gcc::jit::recording::struct_::is_bool): New.
+
+2014-03-13  David Malcolm  <dmalcolm@redhat.com>
+
+       * internal-api.c (gcc::jit::recording::context::set_str_option):
+       Provide NULL recording::location to add_error.
+       (gcc::jit::recording::context::set_int_option): Likewise.
+       (gcc::jit::recording::context::set_bool_option): Likewise.
+       (gcc::jit::playback::context::compile): Likewise.
+       (gcc::jit::recording::context::add_error): Add recording::location
+       param.
+       (gcc::jit::recording::context::add_error_va): Likewise; print it
+       when present; add "error: " to stderr messages.
+       (gcc::jit::recording::location::replay_into): Provide
+       recording::location to the playback::location.
+
+       (gcc::jit::recording::function::validate): Add locations to the
+       add_error invocations.
+       (gcc::jit::recording::block::validate): Likewise.
+       (gcc::jit::playback::context::get_type): Likewise.
+       (gcc::jit::playback::context::new_unary_op): Likewise.
+       (gcc::jit::playback::context::new_binary_op): Likewise.
+       (gcc::jit::playback::context::new_comparison): Likewise.
+
+       (gcc::jit::recording::block::get_loc): New.
+       (gcc::jit::recording::block::get_first_statement): New.
+
+       (gcc::jit::playback::context::build_cast): Pass in higher-level
+       arguments in the hope of eventually providing better error
+       messages when a cast isn't possible.
+       (gcc::jit::playback::context::new_cast): As above.
+
+       (gcc::jit::playback::context::add_error): Add playback::location
+       parameter, using it to provide the corresponding
+       recording::location (if any) when reporting the error to the
+       recording::context.
+       (gcc::jit::playback::context::add_error_va): Likewise.
+       (gcc::jit::playback::context::new_location): Likewise.
+       (gcc::jit::playback::source_line::get_location): Likewise.
+       (gcc::jit::playback::location::location): Likewise.
+
+       * internal-api.h (gcc::jit::recording::context::add_error): Add
+       recording::location param.
+       (gcc::jit::recording::context::add_error_va): Likewise.
+
+       (gcc::jit::recording::context::errors_occurred): Also consider
+       errors that occur on a parent or ancestor context, recursively.
+
+       (gcc::jit::recording::block::get_loc): New.
+       (gcc::jit::recording::block::get_first_statement): New.
+       (gcc::jit::recording::statement::get_loc): New.
+
+       (gcc::jit::playback::context::new_location): Add recording::location
+       parameter.
+
+       (gcc::jit::playback::context::add_error): Add playback::location
+       parameter.
+       (gcc::jit::playback::context::add_error_va): Likewise.
+
+       (gcc::jit::playback::context::build_cast): Pass in higher-level
+       arguments in the hope of eventually providing better error
+       messages when a cast isn't possible.
+
+       (gcc::jit::playback::source_line::get_location): Add
+       recording::location parameter.
+       (gcc::jit::playback::location::location): Likewise.
+       (gcc::jit::playback::location::get_recording_loc): New.
+       (gcc::jit::playback::location::m_recording_loc): New.
+
+       * jit-builtins.c (gcc::jit::builtins_manager::get_builtin_function):
+       Provide NULL recording::location to add_error.
+       (gcc::jit::builtins_manager::make_primitive_type): Likewise.
+
+       * libgccjit.c (RETURN_VAL_IF_FAIL): Add location argument.
+       (RETURN_VAL_IF_FAIL_PRINTF1): Likewise.
+       (RETURN_VAL_IF_FAIL_PRINTF2): Likewise.
+       (RETURN_VAL_IF_FAIL_PRINTF3): Likewise.
+       (RETURN_VAL_IF_FAIL_PRINTF4): Likewise.
+       (RETURN_VAL_IF_FAIL_PRINTF6): Likewise.
+       (RETURN_NULL_IF_FAIL): Likewise.
+       (RETURN_NULL_IF_FAIL_PRINTF1): Likewise.
+       (RETURN_NULL_IF_FAIL_PRINTF2): Likewise.
+       (RETURN_NULL_IF_FAIL_PRINTF3): Likewise.
+       (RETURN_NULL_IF_FAIL_PRINTF4): Likewise.
+       (RETURN_NULL_IF_FAIL_PRINTF6): Likewise.
+       (RETURN_IF_FAIL): Likewise.
+       (RETURN_IF_FAIL_PRINTF1): Likewise.
+       (RETURN_IF_FAIL_PRINTF2): Likewise.
+       (RETURN_IF_FAIL_PRINTF4): Likewise.
+       (RETURN_IF_NOT_VALID_BLOCK): Likewise.
+       (RETURN_NULL_IF_NOT_VALID_BLOCK): Likewise.
+
+       (jit_error): Likewise.
+
+       (gcc_jit_location_as_object): Provided location argument to
+       error-handling macros.
+       (gcc_jit_type_as_object): Likewise.
+       (gcc_jit_context_get_type): Likewise.
+       (gcc_jit_context_get_int_type): Likewise.
+       (gcc_jit_type_get_pointer): Likewise.
+       (gcc_jit_type_get_const): Likewise.
+       (gcc_jit_type_get_volatile): Likewise.
+       (gcc_jit_context_new_array_type): Likewise.
+       (gcc_jit_context_new_field): Likewise.
+       (gcc_jit_context_new_struct_type): Likewise.
+       (gcc_jit_context_new_opaque_struct): Likewise.
+       (gcc_jit_struct_as_type): Likewise.
+       (gcc_jit_struct_set_fields): Likewise.
+       (gcc_jit_context_new_param): Likewise.
+       (gcc_jit_param_as_object): Likewise.
+       (gcc_jit_param_as_lvalue): Likewise.
+       (gcc_jit_param_as_rvalue): Likewise.
+       (gcc_jit_context_new_function): Likewise.
+       (gcc_jit_context_get_builtin_function): Likewise.
+       (gcc_jit_function_as_object): Likewise.
+       (gcc_jit_function_get_param): Likewise.
+       (gcc_jit_function_dump_to_dot): Likewise.
+       (gcc_jit_function_new_block): Likewise.
+       (gcc_jit_block_as_object): Likewise.
+       (gcc_jit_block_get_function): Likewise.
+       (gcc_jit_context_new_global): Likewise.
+       (gcc_jit_lvalue_as_object): Likewise.
+       (gcc_jit_lvalue_as_rvalue): Likewise.
+       (gcc_jit_rvalue_as_object): Likewise.
+       (gcc_jit_rvalue_get_type): Likewise.
+       (gcc_jit_context_new_rvalue_from_int): Likewise.
+       (gcc_jit_context_zero): Likewise.
+       (gcc_jit_context_one): Likewise.
+       (gcc_jit_context_new_rvalue_from_double): Likewise.
+       (gcc_jit_context_new_rvalue_from_ptr): Likewise.
+       (gcc_jit_context_null): Likewise.
+       (gcc_jit_context_new_string_literal): Likewise.
+       (gcc_jit_context_new_unary_op): Likewise.
+       (gcc_jit_context_new_binary_op): Likewise.
+       (gcc_jit_context_new_comparison): Likewise.
+       (gcc_jit_context_new_call): Likewise.
+       (gcc_jit_context_new_cast): Likewise.
+       (gcc_jit_context_new_array_access): Likewise.
+       (gcc_jit_object_get_context): Likewise.
+       (gcc_jit_object_get_debug_string): Likewise.
+       (gcc_jit_lvalue_access_field): Likewise.
+       (gcc_jit_rvalue_access_field): Likewise.
+       (gcc_jit_rvalue_dereference_field): Likewise.
+       (gcc_jit_rvalue_dereference_field): Likewise.
+       (gcc_jit_rvalue_dereference): Likewise.
+       (gcc_jit_lvalue_get_address): Likewise.
+       (gcc_jit_function_new_local): Likewise.
+       (gcc_jit_block_add_eval): Likewise.
+       (gcc_jit_block_add_assignment): Likewise.
+       (gcc_jit_block_add_assignment_op): Likewise.
+       (gcc_jit_block_end_with_conditional): Likewise.
+       (gcc_jit_block_add_comment): Likewise.
+       (gcc_jit_block_end_with_jump): Likewise.
+       (gcc_jit_block_end_with_return): Likewise.
+       (gcc_jit_block_end_with_void_return): Likewise.
+       (gcc_jit_context_set_str_option): Likewise.
+       (gcc_jit_context_set_int_option): Likewise.
+       (gcc_jit_context_set_bool_option): Likewise.
+       (gcc_jit_context_compile): Likewise.
+       (gcc_jit_context_dump_to_file): Likewise.
+       (gcc_jit_context_get_first_error): Likewise.
+       (gcc_jit_result_get_code): Likewise.
+       (gcc_jit_result_get_code): Likewise.
+       (gcc_jit_result_release): Likewise.
+
+2014-03-10  David Malcolm  <dmalcolm@redhat.com>
+
+       * libgccjit++.h (gccjit::context::new_rvalue): Make these
+       methods const.
+       (gccjit::context::zero): Likewise.
+       (gccjit::context::one): Likewise.
+       (gccjit::function::get_param): Likewise.
+
+2014-03-10  David Malcolm  <dmalcolm@redhat.com>
+
+       * libgccjit++.h (gccjit::error): New class, for exceptions.
+       (gccjit::context::get_inner_context): New accessor, so that we
+       can...
+       (gccjit::context::m_inner_ctxt): Make private.
+       (gccjit::context::context): Throw a gccjit::error if a NULL
+       context is passed in.
+       (gccjit::context::compile): Throw a gccjit::error if a NULL
+       result is returned from the C API, which indicates an error.
+       (gccjit::object::object): Throw a gccjit::error if a NULL
+       object is passed in, since that indicates that an error has
+       occurred.
+       (gccjit::location::location): In the default ctor, call the
+       base class default ctor rather than passing in a NULL to the
+       single-argument ctor, since the latter now indicates an error
+       has occurred at the C API level.
+       (gccjit::field::field): Likewise.
+       (gccjit::type::type): Likewise.
+       (gccjit::function::function): Likewise.
+       (gccjit::block::block): Likewise.
+       (gccjit::rvalue::rvalue): Likewise.
+
+2014-03-07  David Malcolm  <dmalcolm@redhat.com>
+
+       * libgccjit.h (enum gcc_jit_function_kind): Add
+       GCC_JIT_FUNCTION_ALWAYS_INLINE.
+       * internal-api.c (gcc::jit::recording::function::write_to_dump):
+       Handle GCC_JIT_FUNCTION_ALWAYS_INLINE.
+       (gcc::jit::playback::context::new_function): Likewise.
+       (gcc::jit::playback::context::postprocess): Handle
+       GCC_JIT_FUNCTION_INTERNAL and GCC_JIT_FUNCTION_ALWAYS_INLINE by
+       clearing DECL_EXTERNAL and TREE_PUBLIC.  Doing so fixes the
+       "undefined symbol" bug seen with GCC_JIT_FUNCTION_INTERNAL.
+       * TODO.rst: Update.
+
+2014-03-07  David Malcolm  <dmalcolm@redhat.com>
+
+       * libgccjit++.h (gccjit::context::new_global): New.
+
+2014-03-07  David Malcolm  <dmalcolm@redhat.com>
+
+       * internal-api.c (gcc::jit::playback::context::handle_locations):
+       Add a disabled call to line_table_dump, in case it's handy for
+       debugging in the future.
+       (gcc::jit::playback::context::set_tree_location): Assert that
+       the location is non-NULL.
+       (gcc::jit::playback::location::location): Initialize m_src_loc
+       to UNKNOWN_LOCATION.  This field should always be overwritten by
+       handle_locations before use, but given recent issues with bogus
+       locations it seems safer to initialize it.
+
+2014-03-06  David Malcolm  <dmalcolm@redhat.com>
+
+       * internal-api.c (gcc::jit::recording::context::
+       disassociate_from_playback): Recursively visit parent contexts.
+
+2014-03-05  David Malcolm  <dmalcolm@redhat.com>
+
+       * libgccjit.h (gcc_jit_function_dump_to_dot): New.
+       * libgccjit.map (gcc_jit_function_dump_to_dot): New.
+       * libgccjit++.h (gccjit::function::dump_to_dot): New.
+       * libgccjit.c (gcc_jit_function_dump_to_dot): New.
+       * internal-api.h (gcc::jit::recording::function::dump_to_dot): New.
+       (gcc::jit::recording::block::block): Add m_index member.
+       (gcc::jit::recording::block::dump_to_dot): New.
+       (gcc::jit::recording::block::dump_edges_to_dot): New.
+       * internal-api.c (gcc::jit::recording::function::new_block): Give
+       each block an index.
+       (gcc::jit::recording::function::dump_to_dot): New.
+       (gcc::jit::recording::block::dump_to_dot): New.
+       (gcc::jit::recording::block::dump_edges_to_dot): New.
+
+2014-03-04  David Malcolm  <dmalcolm@redhat.com>
+
+       * internal-api.c (gcc::jit::recording::memento_of_get_pointer::
+       accepts_writes_from): Avoid segfaulting when the argument is not
+       of pointer type.
+       * internal-api.h (gcc::jit::recording::accepts_writes_from): Add
+       an assertion.
+       * libgccjit.c (gcc_jit_context_new_comparison): Strip away const
+       and volatile when comparing input types.
+
+2014-03-04  David Malcolm  <dmalcolm@redhat.com>
+
+       * libgccjit.h (gcc_jit_type_get_volatile): New.
+       * libgccjit.map (gcc_jit_type_get_volatile): New.
+       * libgccjit.c (gcc_jit_type_get_volatile): New.
+       * libgccjit++.h (gccjit::type::get_volatile): New.
+       * internal-api.c (gcc::jit::recording::type::get_volatile): New.
+       (gcc::jit::recording::memento_of_get_volatile::replay_into): New.
+       (gcc::jit::recording::memento_of_get_volatile::make_debug_string): New.
+       * internal-api.h (gcc::jit::recording::type::get_volatile): New.
+       (gcc::jit::recording::type::accepts_writes_from): Strip off
+       qualifiers such as "const" and "volatile" from the source type.
+       (gcc::jit::recording::memento_of_get_volatile): New class.
+       (gcc::jit::playback::type::get_volatile): New.
+       * TODO.rst: Update.
+
+2014-03-03  David Malcolm  <dmalcolm@redhat.com>
+
+       * libgccjit++.h (gccjit::function::operator()): Add overload for
+       a call with 3 arguments.
+       (gccjit::block::add_call): Likewise for 4 arguments.
+       (gccjit::rvalue::cast_to): New method.
+       (gccjit::rvalue::operator[]): New methods.
+
+2014-02-28  David Malcolm  <dmalcolm@redhat.com>
+
+       * libgccjit.c (gcc_jit_context_new_binary_op): Check that the
+       operands have the same type.
+       (gcc_jit_context_new_comparison): Likewise.
+
+2014-02-28  David Malcolm  <dmalcolm@redhat.com>
+
+       * libgccjit.h (gcc_jit_context_new_cast): New.
+       * libgccjit.map (gcc_jit_context_new_cast): New.
+       * libgccjit++.h (gccjit::context::new_cast): New method.
+       * libgccjit.c (gcc_jit_context_new_cast): New.
+
+       * internal-api.h (gcc::jit::recording::context::new_cast): New method.
+       (gcc::jit::recording::cast): New subclass of rvalue.
+       (gcc::jit::playback::context::new_cast): New method.
+       (gcc::jit::playback::context::build_cast): New method.
+
+       * internal-api.c (convert): New.
+       (gcc::jit::recording::context::new_cast): New.
+       (gcc::jit::recording::cast::replay_into): New.
+       (gcc::jit::recording::cast::make_debug_string): New.
+       (gcc::jit::playback::context::build_cast): New.
+       (gcc::jit::playback::context::new_cast): New.
+
+       * TODO.rst: Update.
+
+2014-02-28  David Malcolm  <dmalcolm@redhat.com>
+
+       * libgccjit.h (gcc_jit_block_get_function): New.
+       * libgccjit.map (gcc_jit_block_get_function): New.
+       * libgccjit++.h (gccjit::block::get_function): New method.
+       * libgccjit.c (gcc_jit_block_get_function): New.
+
+2014-02-27  David Malcolm  <dmalcolm@redhat.com>
+
+       * libgccjit.h (gcc_jit_label): Delete in favor of...
+       (gcc_jit_block): New type.
+       (gcc_jit_loop): Delete.
+
+       (gcc_jit_function_new_forward_label): Delete in favor of...
+       (gcc_jit_function_new_block): New.
+
+       (gcc_jit_label_as_object): Delete in favor of...
+       (gcc_jit_block_as_object): New.
+
+       (gcc_jit_function_add_eval): Delete in favor of...
+       (gcc_jit_block_add_eval): New.
+
+       (gcc_jit_function_add_assignment): Delete in favor of...
+       (gcc_jit_block_add_assignment): New.
+
+       (gcc_jit_function_add_assignment_op): Delete in favor of...
+       (gcc_jit_block_add_assignment_op): New.
+
+       (gcc_jit_function_add_comment): Delete in favor of...
+       (gcc_jit_block_add_comment): New.
+
+       (gcc_jit_label_as_object): Delete in favor of...
+       (gcc_jit_block_as_object): New.
+
+       (gcc_jit_function_add_conditional): Delete in favor of...
+       (gcc_jit_block_end_with_conditional): New.
+
+       (gcc_jit_function_add_jump): Delete in favor of...
+       (gcc_jit_block_end_with_jump): New.
+
+       (gcc_jit_function_add_return): Delete in favor of...
+       (gcc_jit_block_end_with_return): New.
+
+       (gcc_jit_function_add_void_return): Delete in favor of...
+       (gcc_jit_block_end_with_void_return): New.
+
+       (gcc_jit_function_new_loop): Delete.
+       (gcc_jit_function_new_loop_over_range): Delete.
+       (gcc_jit_loop_as_object): Delete.
+       (gcc_jit_loop_end): Delete.
+
+       * libgccjit.map (gcc_jit_function_add_assignment): Delete in favor of...
+       (gcc_jit_block_add_assignment): New.
+
+       (gcc_jit_function_add_assignment_op): Delete in favor of...
+       (gcc_jit_block_add_assignment_op): New.
+
+       (gcc_jit_function_add_comment): Delete in favor of...
+       (gcc_jit_block_add_comment): New.
+
+       (gcc_jit_function_add_eval): Delete in favor of...
+       (gcc_jit_block_add_eval): New.
+
+       (gcc_jit_label_as_object): Delete in favor of...
+       (gcc_jit_block_as_object): New.
+
+       (gcc_jit_function_add_conditional): Delete in favor of...
+       (gcc_jit_block_end_with_conditional): New.
+
+       (gcc_jit_function_add_jump): Delete in favor of...
+       (gcc_jit_block_end_with_jump): New.
+
+       (gcc_jit_function_add_return): Delete in favor of...
+       (gcc_jit_block_end_with_return): New.
+
+       (gcc_jit_function_add_void_return): Delete in favor of...
+       (gcc_jit_block_end_with_void_return): New.
+
+       (gcc_jit_function_add_label): Delete in favor of...
+       (gcc_jit_function_new_block): New.
+       (gcc_jit_function_new_forward_label): Delete.
+       (gcc_jit_function_place_forward_label): Delete.
+
+       (gcc_jit_function_new_loop): Delete.
+       (gcc_jit_function_new_loop_over_range): Delete.
+       (gcc_jit_loop_as_object): Delete.
+       (gcc_jit_loop_end): Delete.
+
+       * libgccjit.c (gcc_jit_label): Delete in favor of...
+       (gcc_jit_block): New type.
+       (gcc_jit_loop): Delete.
+
+       (RETURN_IF_NOT_FUNC_DEFINITION): Delete in favor of...
+       (RETURN_IF_NOT_VALID_BLOCK): New macro.
+       (RETURN_NULL_IF_NOT_FUNC_DEFINITION): Delete in favor of...
+       (RETURN_NULL_IF_NOT_VALID_BLOCK): New macro.
+
+       (gcc_jit_function_new_forward_label): Delete in favor of...
+       (gcc_jit_function_new_block): New.
+
+       (gcc_jit_label_as_object): Delete in favor of...
+       (gcc_jit_block_as_object): New.
+
+       (gcc_jit_rvalue_dereference_field): Ensure that field has been
+       placed.
+
+       (gcc_jit_function_add_label): Delete
+       (gcc_jit_function_place_forward_label): Delete.
+
+       (gcc_jit_function_add_eval): Delete in favor of...
+       (gcc_jit_block_add_eval): New.
+
+       (gcc_jit_function_add_assignment): Delete in favor of...
+       (gcc_jit_block_add_assignment): New.
+
+       (gcc_jit_function_add_assignment_op): Delete in favor of...
+       (gcc_jit_block_add_assignment_op): New.
+
+       (gcc_jit_function_add_conditional): Delete in favor of...
+       (gcc_jit_block_end_with_conditional): New.
+
+       (gcc_jit_function_add_comment): Delete in favor of...
+       (gcc_jit_block_add_comment): New.
+
+       (gcc_jit_function_add_jump): Delete in favor of...
+       (gcc_jit_block_end_with_jump): New.
+
+       (gcc_jit_function_add_return): Delete in favor of...
+       (gcc_jit_block_end_with_return): New.
+
+       (gcc_jit_function_add_void_return): Delete in favor of...
+       (gcc_jit_block_end_with_void_return): New.
+
+       (gcc_jit_function_new_loop): Delete.
+       (gcc_jit_function_new_loop_over_range): Delete.
+       (gcc_jit_loop_as_object): Delete.
+       (gcc_jit_loop_end): Delete.
+
+       * internal-api.h (gcc::jit::recording::label): Delete class in
+       favor of...
+       (gcc::jit::recording::block): New class.
+       (gcc::jit::recording::loop): Delete class.
+       (gcc::jit::recording::loop_end): Delete class.
+
+       (gcc::jit::playback::label): Delete class in favor of...
+       (gcc::jit::playback::block): New class.
+
+       (gcc::jit::playback::loop): Delete class.
+
+       (gcc::jit::recording::playback_label): Delete function in favor of...
+       (gcc::jit::recording::playback_block): New function.
+
+       (gcc::jit::recording::context::validate): New.
+
+       (gcc::jit::recording::function::new_forward_label): Delete method.
+       (gcc::jit::recording::function::add_eval): Delete method in favor
+       of method of new gcc::jit::recording::block class.
+       (gcc::jit::recording::function::add_assignment): Likewise.
+       (gcc::jit::recording::function::add_assignment_op): Likewise.
+       (gcc::jit::recording::function::add_comment): Likewise.
+       (gcc::jit::recording::function::add_conditional): Likewise.
+       (gcc::jit::recording::function::place_forward_label): Likewise.
+       (gcc::jit::recording::function::add_jump): Likewise.
+       (gcc::jit::recording::function::add_return): Likewise.
+
+       (gcc::jit::recording::function::add_label): Delete method in favor of...
+       (gcc::jit::recording::function::new_block): New method.
+
+       (gcc::jit::recording::function::new_loop): Delete method.
+
+       (gcc::jit::recording::function::validate): New method.
+       (gcc::jit::recording::function::m_activity): Delete field in favor of...
+       (gcc::jit::recording::function::m_blocks): New field.
+
+       (gcc::jit::recording::statement::get_successor_blocks): New method.
+       (gcc::jit::recording::statement::write_to_dump): Make public.
+       (gcc::jit::recording::statement::statement): Accept a block rather
+       than a function.
+       (gcc::jit::recording::statement::playback_function): Delete.
+       (gcc::jit::recording::statement::get_block): New.
+       (gcc::jit::recording::statement::m_func): Delete in favor of...
+       (gcc::jit::recording::statement::m_block): ...this.
+
+       (gcc::jit::recording::eval::eval): Accept a block rather than a
+       function.
+       (gcc::jit::recording::assignment::assignment): Likewise.
+       (gcc::jit::recording::assignment_op::assignment_op): Likewise.
+       (gcc::jit::recording::comment::comment): Likewise.
+       (gcc::jit::recording::return::return): Likewise.
+       (gcc::jit::recording::conditional::conditional): Likewise; accept
+       blocks rather than labels.
+       (gcc::jit::recording::jump::jump): Likewise.
+       (gcc::jit::recording::conditional::get_successor_blocks): New.
+       (gcc::jit::recording::jump::get_successor_blocks): New.
+
+       (gcc::jit::playback::function::new_forward_label): Delete method
+       in favor of...
+       (gcc::jit::playback::function::new_block): New method.
+       (gcc::jit::playback::function::build_stmt_list): New method.
+       (gcc::jit::playback::function::m_blocks): New field.
+
+       * libgccjit++.h (gccjit::label): Delete class in favor of...
+       (gccjit::block): New class.
+       (gccjit::function::new_forward_label): Delete methods in favor of...
+       (gccjit::function::new_block): New methods.
+       (gccjit::function::add_comment): Delete methods in favor of methods
+       of new class gccjit::block.
+       (gccjit::function::add_conditional): Likewise.
+       (gccjit::function::add_label): Likewise.
+       (gccjit::function::place_forward_label): Likewise.
+       (gccjit::function::add_jump): Likewise.
+       (gccjit::function::add_return): Likewise.
+       (gccjit::function::add_call): Likewise.
+
+       * internal-api.c (gcc::jit::recording::playback_label): Delete in
+       favor of...
+       (gcc::jit::recording::playback_block): New.
+       (gcc::jit::recording::context::compile): Validate.
+       (gcc::jit::recording::context::validate): New.
+       (gcc::jit::recording::function::function): Update.
+       (gcc::jit::recording::function::new_forward_label): Delete.
+       (gcc::jit::recording::function::add_eval): Delete.
+       (gcc::jit::recording::function::add_assignment): Delete.
+       (gcc::jit::recording::function::add_assignment_op): Delete.
+       (gcc::jit::recording::function::new_block): New.
+       (gcc::jit::recording::function::add_comment): Delete.
+       (gcc::jit::ecording::function::add_conditional): Delete.
+       (gcc::jit::recording::function::add_label): Delete.
+       (gcc::jit::recording::function::place_forward_label): Delete.
+       (gcc::jit::recording::function::add_jump): Delete.
+       (gcc::jit::recording::function::add_return): Delete.
+       (gcc::jit::recording::function::new_loop): Delete.
+       (gcc::jit::recording::function::write_to_dump): Port to block-based
+       representation.
+       (gcc::jit::recording::function::validate): New.
+       (gcc::jit::recording::block::add_eval): New.
+       (gcc::jit::recording::block::add_assignment): New.
+       (gcc::jit::recording::label::replay_into): Delete.
+       (gcc::jit::recording::block::add_assignment_op): New.
+       (gcc::jit::recording::block::add_comment): New.
+       (gcc::jit::recording::block::end_with_conditional): New.
+       (gcc::jit::recording::block::end_with_jump): New.
+       (gcc::jit::recording::block::end_with_return): New.
+       (gcc::jit::recording::block::write_to_dump): New.
+       (gcc::jit::recording::block::validate): New.
+       (gcc::jit::recording::block::get_last_statement): New.
+       (gcc::jit::recording::block::get_successor_blocks): New.
+       (gcc::jit::recording::block::replay_into): New.
+       (gcc::jit::recording::label::make_debug_string): Delete.
+       (gcc::jit::recording::block::make_debug_string): New.
+       (gcc::jit::recording::statement::get_successor_blocks): New.
+       (gcc::jit::recording::eval::replay_into): Port to block-based
+       representation.
+       (gcc::jit::recording::assignment::replay_into): Likewise.
+       (gcc::jit::recording::assignment_op::replay_into): Likewise.
+       (gcc::jit::recording::comment::replay_into): Likewise.
+       (gcc::jit::recording::conditional::replay_into): Likewise.
+       (gcc::jit::recording::jump::replay_into): Likewise.
+       (gcc::jit::recording::return_::replay_into): Likewise.
+
+       (gcc::jit::recording::conditional::get_successor_blocks): New.
+       (gcc::jit::recording::place_label::place_label): Delete.
+       (gcc::jit::recording::place_label::replay_into): Delete.
+       (gcc::jit::recording::place_label::make_debug_string): Delete.
+       (gcc::jit::recording::place_label::write_to_dump): Delete.
+
+       (gcc::jit::recording::jump::get_successor_blocks): New.
+       (gcc::jit::recording::return_::get_successor_blocks): New.
+
+       (gcc::jit::recording::loop::replay_into): Delete.
+       (gcc::jit::recording::loop::make_debug_string): Delete.
+       (gcc::jit::recording::loop::end): Delete.
+       (gcc::jit::recording::loop_end::replay_into): Delete.
+       (gcc::jit::recording::loop_end::make_debug_string): Delete.
+
+       (gcc::jit::playback::function::new_forward_label): Delete.
+       (gcc::jit::playback::function::new_block): New.
+       (gcc::jit::playback::function::build_stmt_list): New.
+       (gcc::jit::playback::function::add_eval): Replace with...
+       (gcc::jit::playback::block::add_eval): New.
+       (gcc::jit::playback::function::add_assignment): Replace with...
+       (gcc::jit::playback::block::add_assignment): New.
+       (gcc::jit::playback::function::add_comment): Replace with...
+       (gcc::jit::playback::block::add_comment): New, reimplementing,
+       given that we no longer have labels.
+       (gcc::jit::playback::function::add_conditional): Replace with...
+       (gcc::jit::playback::block::add_conditional): New, reworking,
+       given that on_false can no longer be NULL.
+       (gcc::jit::playback::function::add_label): Delete.
+       (gcc::jit::playback::function::place_forward_label): Delete.
+       (gcc::jit::playback::function::add_jump): Replace with...
+       (gcc::jit::playback::block::add_jump): New.
+       (gcc::jit::playback::function::add_return): Replace with...
+       (gcc::jit::playback::block::add_return): New.
+       (gcc::jit::playback::function::new_loop): Delete.
+       (gcc::jit::playback::label::label): Replace with...
+       (gcc::jit::playback::block::block): ...this.
+
+       (gcc::jit::playback::loop::loop): Delete.
+       (gcc::jit::playback::loop::end): Delete.
+
+       (gcc::jit::playback::context::replay): Call each function's
+       build_stmt_list.
+
+       * TODO.rst: Update
+
+2014-02-25  David Malcolm  <dmalcolm@redhat.com>
+
+       * libgccjit.h (gcc_jit_function_add_void_return): New.
+       * libgccjit.map (gcc_jit_function_add_void_return): New.
+       * libgccjit.c (gcc_jit_function_add_void_return): New.
+       * libgccjit++.h (add_return): Add overloaded variant with no
+       rvalue, calling gcc_jit_function_add_void_return.
+
+       * internal-api.c (gcc::jit::recording::function::add_return): Add
+       comment that rvalue could be NULL.
+       (gcc::jit::playback::function::add_return): Support rvalue being
+       NULL.
+
+2014-02-25  David Malcolm  <dmalcolm@redhat.com>
+
+       * internal-api.h (gcc::jit::playback::function): Add field
+       m_inner_block.
+
+       * internal-api.c (gcc::jit::playback::function::function):
+       Create BLOCK here and link it to the BIND_EXPR.
+       (gcc::jit::playback::function::gt_ggc_mx): Walk m_inner_block.
+       (gcc::jit::playback::function::postprocess): Set up BLOCK_VARS on
+       the block, so that the local variables make it into the debuginfo.
+
+2014-02-24  Philip Herron <redbrain@gcc.gnu.org>
+
+       * Make-lang.in (jit.install-common): Implement.
+
+2014-02-21  David Malcolm  <dmalcolm@redhat.com>
+
+       * libgccjit.h (gcc_jit_context_dump_to_file): New.
+       * libgccjit.map (gcc_jit_context_dump_to_file): New.
+       * libgccjit.c (gcc_jit_context_dump_to_file): New.
+       * libgccjit++.h (gccjit::context::dump_to_file): New.
+
+       * internal-api.h (gcc::jit::dump): New class.
+       (gcc::jit::recording::playback_location): Add a replayer argument,
+       so that playback locations can be created before playback statements.
+       (gcc::jit::recording::location::playback_location): Likewise.
+       (gcc::jit::recording::statement::playback_location): Likewise.
+       (gcc::jit::recording::context::dump_to_file): New.
+       (gcc::jit::recording::context::m_structs): New field, for use by
+       dump_to_file.
+       (gcc::jit::recording::context::m_functions): Likewise.
+       (gcc::jit::recording::memento::write_to_dump): New virtual function.
+       (gcc::jit::recording::field::write_to_dump): New.
+       (gcc::jit::recording::fields::write_to_dump): New.
+       (gcc::jit::recording::function::write_to_dump): New.
+       (gcc::jit::recording::function::m_locals): New field for use by
+       write_to_dump.
+       (gcc::jit::recording::function::m_activity): Likewise.
+       (gcc::jit::recording::local::write_to_dump): New.
+       (gcc::jit::recording::statement::write_to_dump): New.
+       (gcc::jit::recording::place_label::write_to_dump): New.
+
+       * internal-api.c (gcc::jit::dump::dump): New.
+       (gcc::jit::dump::~dump): New.
+       (gcc::jit::dump::write): New.
+       (gcc::jit::dump::make_location): New.
+       (gcc::jit::recording::playback_location): Add a replayer argument,
+       so that playback locations can be created before playback statements.
+
+       (gcc::jit::recording::context::context): Initialize new fields.
+       (gcc::jit::recording::function::function): Likewise.
+
+       (gcc::jit::recording::context::new_struct_type): Add struct to the
+       context's m_structs vector.
+       (gcc::jit::recording::context::new_function): Add function to the
+       context's m_functions vector.
+       (gcc::jit::recording::context::dump_to_file): New.
+       (gcc::jit::recording::memento::write_to_dump): New.
+       (gcc::jit::recording::field::write_to_dump): New.
+       (gcc::jit::recording::fields::write_to_dump): New.
+       (gcc::jit::recording::function::write_to_dump): New.
+       (gcc::jit::recording::local::write_to_dump): New.
+       (gcc::jit::recording::statement::write_to_dump): New.
+       (gcc::jit::recording::place_label::write_to_dump): New.
+
+       (gcc::jit::recording::array_type::replay_into): Pass on replayer
+       to call to playback_location.
+       (gcc::jit::recording::field::replay_into): Likewise.
+       (gcc::jit::recording::struct_::replay_into): Likewise.
+       (gcc::jit::recording::param::replay_into): Likewise.
+       (gcc::jit::recording::function::replay_into): Likewise.
+       (gcc::jit::recording::global::replay_into): Likewise.
+       (gcc::jit::recording::unary_op::replay_into): Likewise.
+       (gcc::jit::recording::binary_op::replay_into): Likewise.
+       (gcc::jit::recording::comparison::replay_into): Likewise.
+       (gcc::jit::recording::call::replay_into): Likewise.
+       (gcc::jit::recording::array_access::replay_into): Likewise.
+       (gcc::jit::recording::access_field_of_lvalue::replay_into): Likewise.
+       (gcc::jit::recording::access_field_rvalue::replay_into): Likewise.
+       (gcc::jit::recording::dereference_field_rvalue::replay_into): Likewise.
+       (gcc::jit::recording::dereference_rvalue::replay_into): Likewise.
+       (gcc::jit::recording::get_address_of_lvalue::replay_into): Likewise.
+       (gcc::jit::recording::local::replay_into): Likewise.
+       (gcc::jit::recording::eval::replay_into): Likewise.
+       (gcc::jit::recording::assignment::replay_into): Likewise.
+       (gcc::jit::recording::assignment_op::replay_into): Likewise.
+       (gcc::jit::recording::comment::replay_into): Likewise.
+       (gcc::jit::recording::conditional::replay_into): Likewise.
+       (gcc::jit::recording::place_label::replay_into): Likewise.
+       (gcc::jit::recording::jump::replay_into): Likewise.
+       (gcc::jit::recording::return_::replay_into): Likewise.
+       (gcc::jit::recording::loop::replay_into): Likewise.
+       (gcc::jit::recording::loop_end::replay_into): Likewise.
+
+       (gcc::jit::recording::function::new_local): Add to the function's
+       vector of locals.
+       (gcc::jit::recording::function::add_eval): Add to the function's
+       m_activity field.
+       (gcc::jit::recording::function::add_assignment): Likewise.
+       (gcc::jit::recording::function::add_assignment_op): Likewise.
+       (gcc::jit::recording::function::add_comment): Likewise.
+       (gcc::jit::recording::function::add_conditional): Likewise.
+       (gcc::jit::recording::function::place_forward_label): Likewise.
+       (gcc::jit::recording::function::add_jump): Likewise.
+       (gcc::jit::recording::function::add_return): Likewise.
+       (gcc::jit::recording::function::new_loop): Likewise.
+
+       (gcc::jit::recording::conditional::make_debug_string): Add missing
+       semicolon.
+
+2014-02-19  David Malcolm  <dmalcolm@redhat.com>
+
+       * libgccjit.c (gcc_jit_context_new_rvalue_from_ptr): Verify that
+       pointer_type is indeed a pointer type.
+       (gcc_jit_context_null): Likewise.
+       (gcc_jit_context_new_array_access): Verify that ptr is indeed a
+       pointer.
+
+       * TODO.rst: Update
+
+2014-02-18  David Malcolm  <dmalcolm@redhat.com>
+
+       * libgccjit.h (gcc_jit_struct): New.
+       (gcc_jit_context_new_struct_type): Change return type from gcc_jit_type
+       to gcc_jit_struct.
+       (gcc_jit_context_new_opaque_struct): New.
+       (gcc_jit_struct_as_type): New.
+       (gcc_jit_struct_set_fields): New.
+       (gcc_jit_context_null): New.
+
+       * libgccjit.map (gcc_jit_context_new_opaque_struct): New.
+       (gcc_jit_context_null): New.
+       (gcc_jit_struct_as_type): New.
+       (gcc_jit_struct_set_fields): New.
+
+       * libgccjit++.h (gccjit::context::new_struct_type): Return a
+       struct_ rather than a type.
+       (gccjit::context::new_opaque_struct_type): New.
+       (gccjit::struct_): New subclass of type.
+
+       * libgccjit.c (gcc_jit_struct): New.
+       (RETURN_VAL_IF_FAIL_PRINTF1): New.
+       (RETURN_VAL_IF_FAIL_PRINTF2): New.
+       (RETURN_NULL_IF_FAIL_PRINTF1): New.
+       (RETURN_IF_FAIL_PRINTF1): New.
+       (RETURN_IF_FAIL_PRINTF2): New.
+       (gcc_jit_context_new_struct_type): Return a gcc_jit_struct rather
+       than a gcc_jit_type; implement by creating the struct, then
+       setting the fields in it.
+       (gcc_jit_context_new_opaque_struct): New.
+       (gcc_jit_struct_as_type): New.
+       (gcc_jit_struct_set_fields): New.
+       (gcc_jit_context_null): New.
+       (gcc_jit_lvalue_access_field): Use the struct's context when
+       reporting on a NULL field; verify that the field has been placed
+       in a struct.
+       (gcc_jit_rvalue_access_field): Likewise.
+       (is_bool): New.
+       (gcc_jit_function_add_conditional): Use the function's context
+       when reporting errors; verify that boolval's type is indeed
+       boolean.
+       (gcc_jit_function_new_loop): Likewise.
+
+       * internal-api.h (gcc::jit::recording::context::new_struct_type):
+       Don't accept fields, and return a struct_ rather than a type_, so
+       that fields can be set later.
+       (gcc::jit::recording::struct_::struct_): Store a (fields *) rather
+       than a vec of fields.
+       (gcc::jit::recording::struct_::as_type): New.
+       (gcc::jit::recording::struct_::get_fields): New.
+       (gcc::jit::recording::struct_::set_fields): New.
+       (gcc::jit::recording::struct_::playback_struct): New.
+       (gcc::jit::recording::fields): New class.
+       (gcc::jit::playback::context::new_struct_type): Don't accept
+       fields, and return a struct_ rather than a type_, so that fields
+       can be set later.
+       (gcc::jit::playback::struct_): New subclass of type.
+
+       * internal-api.c (gcc::jit::recording::context::get_type): With
+       nested contexts, create basic types within the ultimate parent
+       context, allowing for a fast check for the boolean type using
+       pointer equality.
+       (gcc::jit::recording::context::new_struct_type): Don't accept
+       fields, and return a struct_ rather than a type_, so that fields
+       can be set later.
+       (gcc::jit::recording::context::get_opaque_FILE_type): Update for
+       struct-creation changes.
+       (gcc::jit::recording::struct_::struct_): Store a (fields *) rather
+       than a vec of fields.
+       (gcc::jit::recording::struct_::set_fields): New.
+       (gcc::jit::recording::struct_::replay_into): Don't playback the
+       fields, as this is now done by a fields instance.
+       (gcc::jit::recording::fields::fields): New.
+       (gcc::jit::recording::fields::replay_into): New.
+       (gcc::jit::recording::fields::make_debug_string): New.
+       (gcc::jit:: playback::context::new_struct_type): Don't accept
+       fields, and return a struct_ rather than a type_, so that fields
+       can be set later.
+       (gcc::jit::playback::struct_::set_fields): New.
+
+       * TODO.rst: Update.
+
+2014-02-18  David Malcolm  <dmalcolm@redhat.com>
+
+       * libgccjit.c (gcc_jit_function_new_local): Use the context of the
+       function when reporting errors.
+       (gcc_jit_function_place_forward_label): Likewise.
+       (gcc_jit_function_add_eval): Likewise.
+       (gcc_jit_function_add_assignment_op): Likewise.
+       (gcc_jit_function_add_comment): Likewise.
+       (gcc_jit_function_add_jump): Likewise.
+
+2014-02-14  David Malcolm  <dmalcolm@redhat.com>
+
+       * libgccjit++.h (gccjit::type::zero): New method.
+       (gccjit::type::one): New method.
+       (gccjit::function::add_call): New family of overloaded methods.
+
+2014-02-13  David Malcolm  <dmalcolm@redhat.com>
+
+       * libgccjit.h (gcc_jit_context_get_builtin_function): New.
+       * libgccjit.map (gcc_jit_context_get_builtin_function): New.
+       * libgccjit++.h (gccjit::context::get_builtin_function): New method.
+
+       * Make-lang.in (jit_OBJS): Add jit/jit-builtins.o
+       * jit-builtins.c: New source file, for managing builtin functions
+       and their types.
+       * jit-builtins.h: Likewise.
+
+       * libgccjit.c (gcc_jit_context_new_function): Pass BUILT_IN_NONE for
+       the new argument of new_function
+       (gcc_jit_context_get_builtin_function): New.
+
+       * internal-api.h: Add idempotency guards.
+       (gcc::jit::recording::context::new_function): Add parameter
+       for builtin functions.
+       (gcc::jit::recording::context::get_builtin_function): New method.
+       (gcc::jit::recording::context::m_builtins_manager): New field.
+       (gcc::jit::recording::type::as_a_function_type): New virtual function.
+       (gcc::jit::recording::function_type): New subclass of type.
+       (gcc::jit::recording::function::function): Add parameter for
+       builtin functions.
+       (gcc::jit::recording::function::m_builtin_id): New field.
+       (gcc::jit::recording::function::new_function_type): New method.
+       (gcc::jit::playback::function::function):  Add parameter for
+       builtin functions.
+       * internal-api.c (gcc::jit::recording::context::context):
+       NULL-initialize new field m_builtins_manager.
+       (gcc::jit::recording::context::~context): Clean up the builtins
+       manager, if one has been created.
+       (gcc::jit::recording::context::new_function): Add parameter
+       (gcc::jit::recording::context::get_builtin_function): New method.
+       (gcc::jit::recording::function_type::function_type): Implement
+       constructor for new subclass.
+       (gcc::jit::recording::function_type::dereference): Implement
+       method for new subclass.
+       (gcc::jit::recording::function_type::replay_into): Likewise.
+       (gcc::jit::recording::function_type::make_debug_string): Likewise.
+       (gcc::jit::recording::function::function): Add parameter for
+       builtin functions.
+       (gcc::jit::recording::function::replay_into): Likewise for
+       creation of playback object.
+       (gcc::jit::recording::function::new_function_type): New method.
+       (gcc::jit::playback::function::new_function):  Add parameter for
+       builtin functions, using it to set up the fndecl accordingly.
+
+2014-02-11  David Malcolm  <dmalcolm@redhat.com>
+
+       * libgccjit.c (IS_ASCII_ALPHA): New macro.
+       (IS_ASCII_DIGIT): New macro.
+       (IS_ASCII_ALNUM): New macro.
+       (gcc_jit_context_new_function): Require that function names be valid
+       C identifiers for now, to avoid later problems in the assembler.
+
+2014-02-11  David Malcolm  <dmalcolm@redhat.com>
+
+       * libgccjit.h (enum gcc_jit_types): Add GCC_JIT_TYPE_BOOL.
+
+       * internal-api.h (gcc::jit::recording::comparison::comparison): Use
+       GCC_JIT_TYPE_BOOL as the types of comparisons, rather than
+       GCC_JIT_TYPE_INT.
+
+       * internal-api.c (gcc::jit::recording::memento_of_get_type::
+       dereference): Handle GCC_JIT_TYPE_BOOL (with an error).
+       (get_type_strings): Add GCC_JIT_TYPE_BOOL.
+       (get_tree_node_for_type): Handle GCC_JIT_TYPE_BOOL.
+
+2014-02-11  David Malcolm  <dmalcolm@redhat.com>
+
+       * internal-api.c (gcc::jit::recording::context::add_error_va): If
+       GCC_JIT_STR_OPTION_PROGNAME is NULL, use "libgccjit.so", as per
+       the comment in libgccjit.h
+       (gcc::jit::recording::label::replay_into): When reporting on an
+       unplaced label, include the name of the containing function in
+       the error message.
+       * libgccjit.c: Remove comment about "Functions for use within the
+       code factory", as this distinction went away in commit
+       96b218c9a1d5f39fb649e02c0e77586b180e8516.
+       (RETURN_VAL_IF_FAIL_PRINTF4): New.
+       (RETURN_NULL_IF_FAIL_PRINTF4): New.
+       (jit_error): Invoke vfprintf with the correct format string in
+       the NULL context case.
+       (gcc_jit_context_new_call): Check for NULL entries within the
+       array of arguments.
+
+2014-02-10  David Malcolm  <dmalcolm@redhat.com>
+
+       * libgccjit.h (gcc_jit_context_get_int_type): New.
+       * libgccjit.map (gcc_jit_context_get_int_type): New.
+       * libgccjit.c (gcc_jit_context_get_int_type): New.
+
+       * internal-api.h (gcc::jit::recording::context::get_int_type): New.
+       (gcc::jit::recording::context::get_int_type<T>): New template.
+       * internal-api.c (gcc::jit::recording::context::get_int_type): New.
+
+       * libgccjit++.h: Include <limits> so we can use std::numeric_limits.
+       (gccjit::context::get_int_type): New.
+       (gccjit::context::get_int_type<T>): New.
+
+2014-02-10  David Malcolm  <dmalcolm@redhat.com>
+
+       * libgccjit.h (gcc_jit_function_get_param): New.
+       * libgccjit.map (gcc_jit_function_get_param): New.
+       * libgccjit.c (gcc_jit_function_get_param): New.
+       * libgccjit++.h (gccjit::function::get_param): New.
+
+2014-02-10  David Malcolm  <dmalcolm@redhat.com>
+
+       * libgccjit++.h (gccjit::object::get_inner_object): Make const.
+       (gccjit::location::get_inner_location): Likewise.
+       (gccjit::field::get_inner_field): Likewise.
+       (gccjit::type::get_inner_type): Likewise.
+       (gccjit::function::get_inner_function): Likewise.
+       (gccjit::label::get_inner_label): Likewise.
+       (gccjit::rvalue::get_inner_rvalue): Likewise.
+       (gccjit::lvalue::get_inner_lvalue): Likewise.
+       (gccjit::param::get_inner_param): Likewise.
+
+2014-02-10  David Malcolm  <dmalcolm@redhat.com>
+
+       * libgccjit++.h (gccjit::object::get_context): New method.
+       (gccjit::function): Add overloaded operator () for various
+       numbers of arguments as a very terse way of creating function calls.
+       (gccjit::rvalue::get_type): New method.
+
+       (operator-): New overloaded unary op for rvalues.
+       (operator~): Likewise.
+       (operator!): Likewise.
+
+       (operator+): New overloaded binary op for rvalues.
+       (operator-): Likewise.
+       (operator*): Likewise.
+       (operator/): Likewise.
+       (operator%): Likewise.
+       (operator&): Likewise.
+       (operator^): Likewise.
+       (operator|): Likewise.
+       (operator&&): Likewise.
+       (operator||): Likewise.
+
+       (operator==): New overloaded comparison for rvalues.
+       (operator!=): Likewise.
+       (operator<): Likewise.
+       (operator<=): Likewise.
+       (operator>): Likewise.
+       (operator>=): Likewise.
+
+       (operator*): New overloaded operator for dereferencing an
+       rvalue representing a pointer.
+
+       * libgccjit.c (gcc_jit_rvalue_get_type): New.
+       * libgccjit.h (gcc_jit_rvalue_get_type): New.
+       * libgccjit.map (gcc_jit_rvalue_get_type): New.
+
+2014-02-10  David Malcolm  <dmalcolm@redhat.com>
+
+       * libgccjit++.h (gccjit::context::new_minus): New method,
+       providing a way to do a specific unary op with less typing.
+       (gccjit::context::new_bitwise_negate): Likewise.
+       (gccjit::context::new_logical_negate): Likewise.
+
+       (gccjit::context::new_plus): Likewise, for binary op.
+       (gccjit::context::new_minus): Likewise.
+       (gccjit::context::new_mult): Likewise.
+       (gccjit::context::new_divide): Likewise.
+       (gccjit::context::new_modulo): Likewise.
+       (gccjit::context::new_bitwise_and): Likewise.
+       (gccjit::context::new_bitwise_xor): Likewise.
+       (gccjit::context::new_bitwise_or): Likewise.
+       (gccjit::context::new_logical_and): Likewise.
+       (gccjit::context::new_logical_or): Likewise.
+
+       (gccjit::context::new_eq): Likewise, for comparison.
+       (gccjit::context::new_ne): Likewise.
+       (gccjit::context::new_lt): Likewise.
+       (gccjit::context::new_le): Likewise.
+       (gccjit::context::gccjit::context::new_gt): Likewise.
+       (gccjit::context::gccjit::context::new_ge): Likewise.
+
+       (gccjit::context::new_call): Add a series of overloaded methods
+       for specific numbers of args (from 0 - 6), to avoid the need for
+       client code to manually build a std::vector (or requiring C++11).
+
+2014-02-10  David Malcolm  <dmalcolm@redhat.com>
+
+       * libgccjit++.h (gccjit::context::new_struct_type): Pass std::vector
+       "fields" argument by reference rather than by value.
+       (gccjit::context::new_function): Likewise, for "params" arg.
+       (gccjit::context::new_call): Likewise, for "args" arg.
+
+2014-02-10  David Malcolm  <dmalcolm@redhat.com>
+
+       * libgccjit++.h (gccjit::context::new_location): Update filename
+       arg from a const char * to a const std::string &.
+       (gccjit::context::new_field): Likewise for "name" arg.
+       (gccjit::context::new_struct_type): Likewise.
+       (gccjit::context::new_param): Likewise.
+       (gccjit::context::new_function): Likewise.
+       (gccjit::function::new_local): Likewise.
+       (gccjit::context::new_rvalue): Likewise for "value" arg.
+       (gccjit::function::add_comment): Likewise for "text" arg.
+       (gccjit::function::new_forward_label): Likewise for "name" arg; add
+       variant taking no args for anonymous labels.
+       (gccjit::function::add_label): Likewise.
+
+2014-02-10  David Malcolm  <dmalcolm@redhat.com>
+
+       * libgccjit++.h (gccjit::object, gccjit::location): Move
+       these declarations to before that of gccjit::context so that
+       the various methods of context taking a location can have a
+       default location value.
+       (gccjit::context::new_array_type): Consolidate two methods,
+       one accepting a gccjit::location, the other without, by
+       providing a default argument (which thus has to be moved to the
+       end of the argument list).
+       (gccjit::context::new_field): Likewise.
+       (gccjit::context::new_struct_type): Likewise.
+       (gccjit::context::new_param): Likewise.
+       (gccjit::context::new_function): Likewise.
+       (gccjit::context::new_unary_op): Likewise.
+       (gccjit::context::new_binary_op): Likewise.
+       (gccjit::context::new_comparison): Likewise.
+       (gccjit::context::new_call): Likewise.
+       (gccjit::context::new_array_access): Likewise.
+       (gccjit::function::new_local): Likewise.
+       (gccjit::function::add_eval): Likewise.
+       (gccjit::function::add_assignment): Likewise.
+       (gccjit::function::add_assignment_op): Likewise.
+       (gccjit::function::add_comment): Likewise.
+       (gccjit::function::add_conditional): Likewise.
+       (gccjit::function::add_label): Likewise.
+       (gccjit::function::place_forward_label): Likewise.
+       (gccjit::function::add_jump): Likewise.
+       (gccjit::function::add_return): Likewise.
+       (gccjit::rvalue::access_field): Likewise.
+       (gccjit::rvalue::dereference_field): Likewise.
+       (gccjit::rvalue::dereference): Likewise.
+       (gccjit::lvalue::access_field): Likewise.
+       (gccjit::lvalue::get_address): Likewise.
+
+2014-02-10  David Malcolm  <dmalcolm@redhat.com>
+
+       * TODO.rst: Update.
+
+2014-02-06  David Malcolm  <dmalcolm@redhat.com>
+
+       * libgccjit++.h: Include <ostream> rather than <iostream>, since
+       the former gets us std::ostream, and the latter may introduce
+       startup-time overhead for constructing std::cout et al.
+       (gccjit::context::new_child_context): New.
+       (gccjit::context::release): New.
+       (gccjit::context::compile): New.
+       (gccjit::context::set_int_option): New.
+       (gccjit::context::set_bool_option): New.
+
+2014-02-03  David Malcolm  <dmalcolm@redhat.com>
+
+       * libgccjit.h (struct gcc_jit_object): New.
+       (gcc_jit_object_get_context): New.
+       (gcc_jit_object_get_debug_string): New.
+       (gcc_jit_location_as_object): New.
+       (gcc_jit_type_as_object): New.
+       (gcc_jit_field_as_object): New.
+       (gcc_jit_param_as_object): New.
+       (gcc_jit_function_as_object): New.
+       (gcc_jit_label_as_object): New.
+       (gcc_jit_lvalue_as_object): New.
+       (gcc_jit_rvalue_as_object): New.
+       (gcc_jit_loop_as_object): New.
+
+       * libgccjit.map (gcc_jit_field_as_object): New.
+       (gcc_jit_function_as_object): New.
+       (gcc_jit_label_as_object): New.
+       (gcc_jit_location_as_object): New.
+       (gcc_jit_loop_as_object): New.
+       (gcc_jit_lvalue_as_object): New.
+       (gcc_jit_object_get_context): New.
+       (gcc_jit_object_get_debug_string): New.
+       (gcc_jit_param_as_object): New.
+       (gcc_jit_rvalue_as_object): New.
+       (gcc_jit_type_as_object): New.
+
+       * libgccjit.c (struct gcc_jit_object): New.
+       (gcc_jit_location_as_object): New.
+       (gcc_jit_type_as_object): New.
+       (gcc_jit_field_as_object): New.
+       (gcc_jit_param_as_object): New.
+       (gcc_jit_function_as_object): New.
+       (gcc_jit_label_as_object): New.
+       (gcc_jit_lvalue_as_object): New.
+       (gcc_jit_rvalue_as_object): New.
+       (gcc_jit_object_get_context): New.
+       (gcc_jit_object_get_debug_string): New.
+       (gcc_jit_loop_as_object): New.
+       * internal-api.h (gcc::jit::recording::memento::get_context): New.
+       (gcc::jit::recording::memento::as_object): New.
+
+       * libgccjit++.h: Require iostream, for std::ostream.
+       (class object): New base class.
+       (operator << (std::ostream& stream, const object &obj)): New.
+       (location): Inherit from the new "object" base class.
+       (location::m_inner_loc): Remove, in favor of...
+       (location::get_inner_location): ...new method.
+       (field): Inherit from the new "object" base class.
+       (field::m_inner_field): Remove, in favor of...
+       (field::get_inner_field): ...new method.
+       (type): Inherit from the new "object" base class.
+       (type::m_inner_type): Remove, in favor of...
+       (type::get_inner_type): ...new method.
+       (function): Inherit from the new "object" base class.
+       (function::m_inner_func): Remove, in favor of...
+       (function::get_inner_function): ...new method.
+       (label): Inherit from the new "object" base class.
+       (label::m_inner_label): Remove, in favor of...
+       (label::get_inner_label): ...new method.
+       (rvalue) Inherit from the new "object" base class.
+       (rvalue::m_inner_rvalue): Remove, in favor of...
+       (rvalue::get_inner_rvalue): ...new method.
+
+       (context::new_field): Update for move of inner pointer to the
+       "object" base class.
+       (context::new_struct_type): Likewise.
+       (context::new_param): Likewise.
+       (context::new_function): Likewise.
+       (context::new_rvalue): Likewise.
+       (context::zero): Likewise.
+       (context::one): Likewise.
+       (context::new_rvalue): Likewise.
+       (context::new_rvalue): Likewise.
+       (context::new_unary_op): Likewise.
+       (context::new_binary_op): Likewise.
+       (context::new_comparison): Likewise.
+       (context::new_call): Likewise.
+
+       (object::get_debug_string): New.
+       (object::object): New.
+       (object::get_inner_object): New.
+       (operator << (std::ostream&, const object &)): New.
+
+       (location::location): Update for move of inner pointer to the
+       "object" base class.
+       (location::get_inner_location): New.
+
+       (field::field): Update for move of inner pointer to the
+       "object" base class.
+       (field::get_inner_field): New.
+
+       (type::type): Update for move of inner pointer to the
+       "object" base class.
+       (type::get_pointer): Likewise.
+       (type::get_inner_type): New.
+
+       (function::function): Update for move of inner pointer to the
+       "object" base class.
+       (function::new_forward_label): Likewise.
+       (function::new_local): Likewise.
+       (function::add_eval): Likewise.
+       (function::add_assignment): Likewise.
+       (function::add_assignment_op): Likewise.
+       (function::add_comment): Likewise.
+       (function::add_conditional): Likewise.
+       (function::add_label): Likewise.
+       (function::place_forward_label): Likewise.
+       (function::add_jump): Likewise.
+       (function::add_return): Likewise.
+       (function::get_inner_function): New.
+
+       (label::label): Update for move of inner pointer to the "object"
+       base class.
+       (label::get_inner_label): New
+
+       (rvalue::rvalue): Update for move of inner pointer to the "object"
+       base class.
+       (rvalue::get_inner_rvalue): New.
+       (rvalue::access_field): Likewise.
+       (rvalue::dereference_field): Likewise.
+       (rvalue::dereference): Likewise.
+
+       (lvalue::get_inner_lvalue): Update for move of inner pointer to
+       the "object" base class.
+       (lvalue::access_field): Likewise.
+       (lvalue::get_address): Likewise.
+
+2014-01-31  David Malcolm  <dmalcolm@redhat.com>
+
+       * libgccjit++.h: New file - a C++ wrapper for the libgccjit.h API.
+
+       * TODO.rst ("Test Suite"): New section, adding note about C++
+       tests.
+
+2014-01-31  David Malcolm  <dmalcolm@redhat.com>
+
+       * libgccjit.h (gcc_jit_context_new_rvalue_from_int): Give the type
+       parameter a more descriptive name.
+       (gcc_jit_context_zero): Likewise.
+       (gcc_jit_context_one): Likewise.
+       (gcc_jit_context_new_rvalue_from_double): Likewise.
+       (gcc_jit_context_new_rvalue_from_ptr): Likewise.
+
+       * libgccjit.c (gcc_jit_context_new_rvalue_from_int): Likewise.
+       (gcc_jit_context_zero): Likewise.
+       (gcc_jit_context_one): Likewise.
+       (gcc_jit_context_new_rvalue_from_double): Likewise.
+       (gcc_jit_context_new_rvalue_from_ptr): Likewise.
+
+       * internal-api.h (gcc::jit::recording::context::
+       new_rvalue_from_int): Likewise.
+       (gcc::jit::recording::context::
+       new_rvalue_from_double): Likewise.
+       (gcc::jit::recording::memento_of_new_rvalue_from_int::
+       memento_of_new_rvalue_from_int): Likewise.
+       (gcc::jit::recording::memento_of_new_rvalue_from_double::
+       memento_of_new_rvalue_from_double): Likewise.
+       (gcc::jit::recording::memento_of_new_rvalue_from_ptr::
+       memento_of_new_rvalue_from_ptr): Likewise.
+
+2014-01-30  David Malcolm  <dmalcolm@redhat.com>
+
+       * TODO.rst: Label-placement is now checked.
+
+       * internal-api.c (gcc::jit::recording::context::replay_into): Give
+       up if any errors occur during the playback.
+       (gcc::jit::recording::label::replay_into): Issue an error if the
+       label has not yet been placed (at playback time).
+       (gcc::jit::recording::place_label::place_label): Move this here
+       from internal-api.h.  Issue an error if the label has already
+       been placed (at recording time).
+
+       * internal-api.h (gcc::jit::recording::label): Add an
+       m_has_been_placed field, and make class place_label a friend so
+       it can set it.
+       (gcc::jit::recording::label::has_been_placed): New accessor.
+       (gcc::jit::recording::place_label::place_label): Move to
+       internal-api.c.
+
+       (gcc::jit::playback::context::errors_occurred): Make public, for
+       use by gcc::jit::recording::context::replay_into.
+
+2014-01-30  David Malcolm  <dmalcolm@redhat.com>
+
+       * internal-api.c (gcc::jit::recording::type::get_pointer):
+       Ensure that repeated calls yield the same type.
+       (gcc::jit::recording::memento_of_get_pointer::
+       accepts_writes_from): New.
+       (gcc::jit::recording::context::new_call): Move
+       the existing argument checking to...
+
+       * libgccjit.c (gcc_jit_context_new_call): ...here, and add
+       checking of the types of the arguments against the function.
+       (RETURN_VAL_IF_FAIL_PRINTF6): New.
+       (RETURN_NULL_IF_FAIL_PRINTF6): New.
+
+       * internal-api.h (gcc::jit::recording::type): New field
+       m_pointer_to_this_type, for use by get_pointer method.
+       (gcc::jit::recording::memento_of_get_pointer::
+       accepts_writes_from): New.
+       (gcc::jit::recording::function::get_param): New.
+
+       * TODO.rst (argument checking of gcc_jit_context_new_call): Done.
+
+2014-01-30  David Malcolm  <dmalcolm@redhat.com>
+
+       * TODO.rst: begin a list of error-checking we could do that this
+       commit *doesn't* cover.
+
+       * libgccjit.h (gcc_jit_field): Add note that fields can't be
+       shared between structs.
+       (GCC_JIT_BINARY_OP_MODULO): Fix typo in comment.
+
+       * libgccjit.c: (RETURN_VAL_IF_FAIL_PRINTF2): New.
+       (RETURN_VAL_IF_FAIL_PRINTF3): New.
+       (RETURN_NULL_IF_FAIL_PRINTF2): New.
+       (RETURN_NULL_IF_FAIL_PRINTF3): New.
+       (RETURN_IF_FAIL_PRINTF4): New.
+
+       (jit_error): Take a gcc::jit::recording::context rather than
+       a gcc_jit_context so that we pass in contexts from the inner
+       layer.
+
+       (compatible_types): New, for use in type-checking.
+
+       (gcc_jit_context_new_struct_type): Check each field to ensure that
+       it isn't already in use by another struct.
+
+       (gcc_jit_rvalue_dereference_field): Check that ptr is of a pointer
+       type and that the field is within the correct struct, using new
+       get_debug_string hooks to generate error messages.
+
+       (gcc_jit_rvalue_dereference): Check that rvalue is of a pointer
+       type.
+
+       (gcc_jit_function_add_assignment): Use the function's context when
+       reporting on NULL lvalue or rvalue.  Verify that the lvalue and
+       rvalue have compatible types.
+
+       (gcc_jit_function_add_return): Use the function's context when
+       reporting on NULL rvalue.  Verify that the rvalue is of an
+       appropriate type given the function's return type.
+
+       * internal-api.h (NUM_GCC_JIT_TYPES): New.
+       (gcc::jit::recording::context::record): Move from here to
+       internal-api.c.
+       (gcc::jit::recording::context::get_opaque_FILE_type): New.
+       (gcc::jit::recording::context::m_basic_types): New field.
+       (gcc::jit::recording::context::m_FILE_type): New field.
+
+       (gcc::jit::recording::memento::get_debug_string): New method.
+       (gcc::jit::recording::memento::memento): Initialize new field
+       m_debug_string, and verify context is non-NULL.
+       (gcc::jit::recording::memento::make_debug_string): New
+       pure-virtual function lazily used by get_debug_string.
+       (gcc::jit::recording::memento::m_debug_string): New field, for
+       get_debug_string to use as a cache.
+
+       (gcc::jit::recording::string): Rename field m_copy to m_buffer.
+       (gcc::jit::recording::from_printf): New factory function.
+       (gcc::jit::recording::make_debug_string): New.
+
+       (gcc::jit::recording::location::make_debug_string): New.
+
+       (gcc::jit::recording::type::dereference): New pure-virtual
+       function.
+       (gcc::jit::recording::type::accepts_writes_from): New virtual
+       function.
+       (gcc::jit::recording::type::unqualified): New virtual function.
+
+       (gcc::jit::recording::memento_of_get_type::dereference): New.
+       (gcc::jit::recording::memento_of_get_type::
+       accepts_writes_from): New.
+       (gcc::jit::recording::memento_of_get_type::make_debug_string):
+       New.
+
+       (gcc::jit::recording::memento_of_get_pointer::make_debug_string):
+       New.
+       (gcc::jit::recording::memento_of_get_pointer::dereference): New.
+       New.
+
+       (gcc::jit::recording::memento_of_get_const::make_debug_string):
+       New.
+       (gcc::jit::recording::memento_of_get_const::dereference): New.
+       New.
+       (gcc::jit::recording::memento_of_get_const::accepts_writes_from):
+       New.
+       (gcc::jit::recording::memento_of_get_const::unqualified): New.
+
+       (gcc::jit::recording::field): New field m_container, for the
+       containing struct (or union, if we implement that).
+       (gcc::jit::recording::field::get_type): New.
+       (gcc::jit::recording::field::get_container): New.
+       (gcc::jit::recording::field:set_container): New.
+       (gcc::jit::recording::field::make_debug_string): New.
+
+       (gcc::jit::recording::struct_::struct_): Move ctor implementation
+       from here into internal-api.c.
+       (gcc::jit::recording::struct_::dereference): New.
+       (gcc::jit::recording::struct_::make_debug_string): New.
+
+       (gcc::jit::recording::rvalue::m_type): New field.
+       (gcc::jit::recording::rvalue::rvalue): Require a non-NULL type for
+       new rvalue instances.
+       (gcc::jit::recording::rvalue::get_type): New accessor.
+
+       (gcc::jit::recording::lvalue): Eliminate field m_type in favor of
+       that within the rvalue base class.
+
+       (gcc::jit::recording::param::make_debug_string): New.
+
+       (gcc::jit::recording::function::get_return_type): New accessor.
+       (gcc::jit::recording::function::make_debug_string): New.
+
+       (gcc::jit::recording::label::make_debug_string): New.
+
+       (gcc::jit::recording::global): Eliminate field m_type in favor of
+       that within the rvalue ultimate base class (via lvalue).
+       (gcc::jit::recording::make_debug_string): New.
+
+       (gcc::jit::recording::memento_of_new_rvalue_from_int): Eliminate
+       field m_type in favor of that within the rvalue base class.
+       (gcc::jit::recording::memento_of_new_rvalue_from_int::
+       make_debug_string): New.
+
+       (gcc::jit::recording::memento_of_new_rvalue_from_double): Eliminate
+       field m_type in favor of that within the rvalue base class.
+       (gcc::jit::recording::memento_of_new_rvalue_from_double::
+       make_debug_string): New.
+
+       (gcc::jit::recording::memento_of_new_rvalue_from_ptr): Eliminate
+       field m_type in favor of that within the rvalue base class.
+       (gcc::jit::recording::memento_of_new_rvalue_from_ptr::
+       make_debug_string): New.
+
+       (gcc::jit::recording::memento_of_new_string_literal::
+       memento_of_new_string_literal): Initialize type.
+       (gcc::jit::recording::memento_of_new_string_literal::
+       make_debug_string): New.
+
+       (gcc::jit::recording::unary_op): Eliminate field m_result_type in
+       favor of m_type within the rvalue base class.
+       (gcc::jit::recording::unary_op::make_debug_string): New.
+
+       (gcc::jit::recording::binary_op): Eliminate field m_result_type in
+       favor of m_type within the rvalue base class.
+       (gcc::jit::recording::binary_op::make_debug_string): New.
+
+       (gcc::jit::recording::comparison): Eliminate field m_result_type
+       in favor of m_type within the rvalue base class.
+       (gcc::jit::recording::comparison::make_debug_string): New.
+
+       (gcc::jit::recording::make_debug_string): New.
+
+       (gcc::jit::recording::array_lookup::array_lookup): Initialize type
+       by dereferencing the type of the pointer.
+       (gcc::jit::recording::array_lookup::make_debug_string): New.
+
+       (gcc::jit::recording::access_field_of_lvalue::
+       access_field_of_lvalue): Initialize type from that of the field.
+       (gcc::jit::recording::access_field_of_lvalue::
+       make_debug_string): New.
+
+       (gcc::jit::recording::access_field_rvalue::
+       access_field_of_rvalue): Initialize type from that of the field.
+       (gcc::jit::recording::access_field_rvalue::make_debug_string):
+       New.
+
+       (gcc::jit::recording::dereference_field_rvalue::
+       dereference_field_rvalue): Initialize type from that of the field.
+       (gcc::jit::recording::dereference_field_rvalue::
+       make_debug_string): New.
+
+       (gcc::jit::recording::dereference_rvalue::dereference_rvalue):
+       Initialize type by dereferencing the type of the pointer.
+       (gcc::jit::recording::dereference_rvalue::make_debug_string): New.
+
+       (gcc::jit::recording::get_address_of_lvalue::
+       get_address_of_lvalue):  Initialize type by dereferencing the type
+       of the pointer.
+       (gcc::jit::recording::get_address_of_lvalue::make_debug_string):
+       New.
+
+       (gcc::jit::recording::local): Eliminate field m_type in favor of
+       that within the rvalue ultimate base class (via lvalue).
+       (gcc::jit::recording::make_debug_string): New.
+
+       (gcc::jit::recording::eval::make_debug_string): New.
+       (gcc::jit::recording::assignment::make_debug_string): New.
+       (gcc::jit::recording::assignment_op::make_debug_string): New.
+       (gcc::jit::recording::comment::make_debug_string): New.
+       (gcc::jit::recording::conditional::make_debug_string): New.
+       (gcc::jit::recording::place_label::make_debug_string): New.
+       (gcc::jit::recording::jump::make_debug_string): New.
+       (gcc::jit::recording::return_::make_debug_string): New.
+       (gcc::jit::recording::loop::make_debug_string): New.
+       (gcc::jit::recording::loop_end::make_debug_string): New.
+
+       * internal-api.c (gcc::jit::recording::context::context):
+       Initialize m_FILE_type and m_basic_types.
+       (gcc::jit::recording::context::record): Move here from
+       internal-api.h.
+       (gcc::jit::recording::context::replay_into): Add a disabled way to
+       log everything during a replay, exercising the stringification
+       machinery.
+       (gcc::jit::recording::context::get_type): Cache and reuse the
+       types, so that repeated calls on the context give the same object.
+       (gcc::jit::recording::context::get_opaque_FILE_type): New, for
+       the result of dereferencing (FILE*), mostly so that fuzz-testing
+       that tries this gets something sane back.
+       (gcc::jit::recording::memento::get_debug_string): New method,
+       giving a way to easily get a descriptive (const char *) for
+       an API entity.  Internally, it lazily calls the make_debug_string
+       virtual function, storing the result in m_debug_string.
+
+       (gcc::jit::recording::string::string): Rename field m_copy to m_buffer.
+       (gcc::jit::recording::string::~string): Likewise.
+       (gcc::jit::recording::string::from_printf): New factory function,
+       to make it easy to implement the make_debug_string hooks.
+
+       (gcc::jit::recording::string::make_debug_string): New.
+
+       (gcc::jit::recording::location::make_debug_string): New.
+
+       (gcc::jit::recording::memento_of_get_type::dereference): New.
+
+       (get_type_strings): New table of strings, for use by...
+       (gcc::jit::recording::memento_of_get_type::make_debug_string): New.
+
+       (gcc::jit::recording::memento_of_get_pointer::make_debug_string): New.
+
+       (gcc::jit::recording::memento_of_get_const::make_debug_string): New.
+
+       (gcc::jit::recording::field::make_debug_string): New.
+
+       (gcc::jit::recording::struct_::struct_): Move here from
+       internal-api.h.  Mark all fields as belonging to the new struct.
+
+       (gcc::jit::recording::struct_::dereference): New.
+       (gcc::jit::recording::struct_::make_debug_string): New.
+
+       (gcc::jit::recording::function::make_debug_string): New.
+
+       (gcc::jit::recording::label::make_debug_string): New.
+
+       (gcc::jit::recording::memento_of_new_rvalue_from_int::
+       make_debug_string): New.
+       (gcc::jit::recording::memento_of_new_rvalue_from_double::
+       make_debug_string): New.
+       (gcc::jit::recording::memento_of_new_rvalue_from_ptr::
+       make_debug_string): New.
+       (gcc::jit::recording::memento_of_new_string_literal::
+       make_debug_string): New.
+
+       (gcc::jit::recording::unary_op::replay_into): Use get_type ()
+       rather than the now-defunct m_result_type.
+       (gcc::jit::recording::binary_op::replay_into): Likewise.
+
+       (unary_op_strings): New table of strings for use by...
+       (gcc::jit::recording::unary_op::make_debug_string): New.
+
+       (binary_op_strings): New table of strings for use by...
+       (gcc::jit::recording::binary_op::make_debug_string): New.
+
+       (comparison_strings): New table of strings for use by...
+       (gcc::jit::recording::comparison::make_debug_string): New.
+
+       (gcc::jit::recording::call::call): Initialize the type.
+       (gcc::jit::recording::call::make_debug_string): New.
+
+       (gcc::jit::recording::array_lookup::make_debug_string): New.
+       (gcc::jit::recording::access_field_of_lvalue::
+       make_debug_string): New.
+       (gcc::jit::recording::access_field_rvalue::
+       make_debug_string): New.
+       (gcc::jit::recording::dereference_field_rvalue::
+       make_debug_string): New.
+       (gcc::jit::recording::dereference_rvalue::make_debug_string): New.
+       (gcc::jit::recording::get_address_of_lvalue::
+       make_debug_string): New.
+       (gcc::jit::recording::eval::make_debug_string): New.
+       (gcc::jit::recording::assignment::make_debug_string): New.
+       (gcc::jit::recording::assignment_op::make_debug_string): New.
+       (gcc::jit::recording::comment::make_debug_string): New.
+       (gcc::jit::recording::conditional::make_debug_string): New.
+       (gcc::jit::recording::place_label::make_debug_string): New.
+       (gcc::jit::recording::jump::make_debug_string): New.
+       (gcc::jit::recording::return_::make_debug_string): New.
+       (gcc::jit::recording::loop::make_debug_string): New.
+       (gcc::jit::recording::loop_end::make_debug_string): New.
+
+2014-01-29  David Malcolm  <dmalcolm@redhat.com>
+
+       * libgccjit.h (gcc_jit_lvalue_access_field): Require
+       a (gcc_jit_field *) rather than a field name.
+       (gcc_jit_rvalue_access_field): Likewise.
+       (gcc_jit_rvalue_dereference_field): Likewise.
+
+       * libgccjit.c (gcc_jit_lvalue_access_field): Require
+       a (gcc_jit_field *) rather than a field name.
+       (gcc_jit_rvalue_access_field): Likewise.
+       (gcc_jit_rvalue_dereference_field): Likewise.
+
+       * internal-api.c (gcc::jit::recording::rvalue::access_field):
+       Require a field rather than a fieldname string.
+       (gcc::jit::recording::rvalue::dereference_field): Likewise.
+       (gcc::jit::recording::lvalue::access_field): Likewise.
+
+       (gcc::jit::recording::access_field_of_lvalue::replay_into): Update
+       given that this now has a field, rather than a fieldname.
+       (gcc::jit::recording::access_field_rvalue::replay_into): Likewise.
+       (gcc::jit::recording::dereference_field_rvalue::replay_into): Likewise.
+
+       (get_field): Delete, as we no longer need to convert
+       from (struct, identifier) pairs to fields, instead directly using
+       fields.
+
+       (gcc::jit::playback::context::new_field_access): Require a field
+       rather than a fieldname, removing the need to look up the field by
+       name within the struct.
+
+       (gcc::jit::playback::lvalue::access_field): Likewise.
+       (gcc::jit::playback::rvalue::access_field): Likewise.
+       (gcc::jit::playback::rvalue::dereference_field): Likewise.
+
+       * internal-api.h (gcc::jit::recording::rvalue::access_field):
+       Require a field rather than a fieldname string.
+       (gcc::jit::recording::rvalue::dereference_field): Likewise.
+       (gcc::jit::recording::lvalue::access_field): Likewise.
+
+       (gcc::jit::recording::access_field_of_lvalue::access_field_of_lvalue):
+       Likewise.
+       (gcc::jit::recording::access_field_of_lvalue::m_fieldname): Drop
+       string field in favor of...
+       (gcc::jit::recording::access_field_of_lvalue::m_field):
+       ..."field" field, as it were.
+
+       (gcc::jit::recording::access_field_of_rvalue::access_field_of_rvalue):
+       Likewise.
+       (gcc::jit::recording::access_field_of_rvalue::m_fieldname): Drop
+       string field in favor of...
+       (gcc::jit::recording::access_field_of_rvalue::m_field):
+       ..."field" field.
+
+       (gcc::jit::recording::dereference_field_rvalue::
+       dereference_field_rvalue): Likewise.
+       (gcc::jit::recording::dereference_field_rvalue::m_fieldname): Drop
+       string field in favor of...
+       (gcc::jit::recording::dereference_field_rvalue::m_field):
+       ..."field" field.
+
+       (gcc::jit::playback::context::new_field_access): Require a field
+       rather than a fieldname string.
+       (gcc::jit::playback::context::access_field): Likewise.
+       (gcc::jit::playback::context::dereference_field): Likewise.
+       (gcc::jit::playback::rvalue::access_field):
+
+2014-01-28  David Malcolm  <dmalcolm@redhat.com>
+
+       * libgccjit.h (gcc_jit_context_new_child_context): New function.
+
+       * libgccjit.map (gcc_jit_context_new_child_context): New function.
+
+       * libgccjit.c (gcc_jit_context): Make the constructor explicit,
+       with a parent context as a parameter.
+       (gcc_jit_context_acquire): Create context with a NULL parent.
+       (gcc_jit_context_new_child_context): New function, creating a
+       context with the given parent.
+
+       * internal-api.h (gcc::jit::recording::context::context): New
+       explicit constructor, taking a parent context as a parameter.
+       (gcc::jit::recording::context::m_parent_ctxt): New field.
+
+       * internal-api.c (gcc::jit::recording::context::context): New
+       explicit constructor, taking a parent context as a parameter.
+       (gcc::jit::recording::context::replay_into): Replay parent contexts
+       before replaying the context itself.
+
+2014-01-27  David Malcolm  <dmalcolm@redhat.com>
+
+       * internal-api.c (gcc::jit::playback::context::compile): Removal
+       of the code-creation callback (96b218c9a1d5f39fb649e02c0e77586b180e8516)
+       accidentally removed the implementation of
+       GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE; reinstate it.
+
+2014-01-27  David Malcolm  <dmalcolm@redhat.com>
+
+       * internal-api (gcc::jit::recording::context::new_call): Verify
+       the argument count of the call against the parameter count of the
+       function, issuing an error if there's a mismatch.
+
+       * internal-api.h (gcc::jit::recording::function::get_name): New.
+       * (gcc::jit::recording::function::get_params): New.
+       * (gcc::jit::recording::function::is_variadic): New.
+
+2014-01-27  David Malcolm  <dmalcolm@redhat.com>
+
+       * libgccjit.h (enum gcc_jit_binary_op): Remove
+       GCC_JIT_BINARY_OP_FLOATING_DIVIDE, which I accidentally added
+       as part of a880c0d9c642730550f39d328f29a1d9935cb07e.
+
+2014-01-24  David Malcolm  <dmalcolm@redhat.com>
+
+       * libgccjit.h: Update comments to eliminate the code-creation
+       callback.  All "contextual" objects change from merely being
+       "alive" during the callback to having a lifetime equal to that
+       of the context they are created within, with automatic cleanup
+       when the context is released.
+       (gcc_jit_code_callback): Delete.
+       (gcc_jit_context_set_code_factory): Delete.
+
+       * libgccjit.map (gcc_jit_context_set_code_factory): Delete.
+
+       * dummy-frontend.c (my_walker): Update for rename of the singleton
+       reference-owning context.
+       (jit_langhook_parse_file): Rather than run a client-provided
+       callback, we now replay a recording of the client activity.
+
+       * internal-api.h (gcc::jit): Split the existing API into two
+       copies...
+       (gcc::jit::recording): ...a class hierarchy used to implement
+       the client-facing API, which records the API calls made to it
+       and...
+       (gcc::jit::playback): ...a class hierarchy used within the
+       dummy GCC frontend, which plays back the recorded API calls once
+       GCC is initialized.
+
+       * internal-api.c (gcc::jit::recording::playback_location): New
+       API, in which client API calls are recorded as a list of "memento"
+       objects, to be played back into GCC when the dummy frontend runs.
+       (gcc::jit::recording::playback_string): Likewise.
+       (gcc::jit::recording::playback_label): Likewise.
+       (gcc::jit::recording::context::~context): Likewise.
+       (gcc::jit::recording::context::replay_into): Likewise.
+       (gcc::jit::recording::context::disassociate_from_playback): Likewise.
+       (gcc::jit::recording::context::new_string): Likewise.
+       (gcc::jit::recording::context::new_location): Likewise.
+       (gcc::jit::recording::context::get_type): Likewise.
+       (gcc::jit::recording::context::new_field): Likewise.
+       (gcc::jit::recording::context::new_struct_type): Likewise.
+       (gcc::jit::recording::context::new_param): Likewise.
+       (gcc::jit::recording::context::new_function): Likewise.
+       (gcc::jit::recording::context::new_global): Likewise.
+       (gcc::jit::recording::context::new_rvalue_from_int): Likewise.
+       (gcc::jit::recording::context::new_rvalue_from_double): Likewise.
+       (gcc::jit::recording::context::new_rvalue_from_ptr): Likewise.
+       (gcc::jit::recording::context::new_string_literal): Likewise.
+       (gcc::jit::recording::context::new_unary_op): Likewise.
+       (gcc::jit::recording::context::new_binary_op): Likewise.
+       (gcc::jit::recording::context::new_comparison): Likewise.
+       (gcc::jit::recording::context::new_call): Likewise.
+       (gcc::jit::recording::context::new_array_lookup): Likewise.
+       (gcc::jit::recording::string::string): Likewise.
+       (gcc::jit::recording::string::~string): Likewise.
+       (gcc::jit::recording::location::replay_into): Likewise.
+       (gcc::jit::recording::type::get_pointer): Likewise.
+       (gcc::jit::recording::type::get_const): Likewise.
+       (gcc::jit::recording::memento_of_get_type::replay_into): Likewise.
+       (gcc::jit::recording::memento_of_get_pointer::replay_into): Likewise.
+       (gcc::jit::recording::memento_of_get_const::replay_into): Likewise.
+       (gcc::jit::recording::field::replay_into): Likewise.
+       (gcc::jit::recording::struct_::replay_into): Likewise.
+       (gcc::jit::recording::rvalue::access_field): Likewise.
+       (gcc::jit::recording::rvalue::dereference_field): Likewise.
+       (gcc::jit::recording::rvalue::dereference): Likewise.
+       (gcc::jit::recording::lvalue::access_field): Likewise.
+       (gcc::jit::recording::lvalue::get_address): Likewise.
+       (gcc::jit::recording::param::replay_into): Likewise.
+       (gcc::jit::recording::function::function): Likewise.
+       (gcc::jit::recording::function::replay_into): Likewise.
+       (gcc::jit::recording::function::new_local): Likewise.
+       (gcc::jit::recording::function::new_forward_label): Likewise.
+       (gcc::jit::recording::function::add_eval): Likewise.
+       (gcc::jit::recording::function::add_assignment): Likewise.
+       (gcc::jit::recording::function::add_assignment_op): Likewise.
+       (gcc::jit::recording::function::add_comment): Likewise.
+       (gcc::jit::recording::function::add_conditional): Likewise.
+       (gcc::jit::recording::function::add_label): Likewise.
+       (gcc::jit::recording::function::place_forward_label): Likewise.
+       (gcc::jit::recording::function::add_jump): Likewise.
+       (gcc::jit::recording::function::add_return): Likewise.
+       (gcc::jit::recording::function::new_loop): Likewise.
+       (gcc::jit::recording::label::replay_into): Likewise.
+       (gcc::jit::recording::global::replay_into): Likewise.
+       (gcc::jit::recording::memento_of_new_rvalue_from_int::replay_into):
+       Likewise.
+       (gcc::jit::recording::memento_of_new_rvalue_from_double::replay_into):
+       Likewise.
+       (gcc::jit::recording::memento_of_new_rvalue_from_ptr::replay_into):
+       Likewise.
+       (gcc::jit::recording::memento_of_new_string_literal::replay_into):
+       Likewise.
+       (gcc::jit::recording::unary_op::replay_into): Likewise.
+       (gcc::jit::recording::binary_op::replay_into): Likewise.
+       (gcc::jit::recording::comparison::replay_into): Likewise.
+       (gcc::jit::recording::call::call): Likewise.
+       (gcc::jit::recording::call::replay_into): Likewise.
+       (gcc::jit::recording::array_lookup::replay_into): Likewise.
+       (gcc::jit::recording::access_field_of_lvalue::replay_into): Likewise.
+       (gcc::jit::recording::access_field_rvalue::replay_into): Likewise.
+       (gcc::jit::recording::dereference_field_rvalue::replay_into): Likewise.
+       (gcc::jit::recording::dereference_rvalue::replay_into): Likewise.
+       (gcc::jit::recording::get_address_of_lvalue::replay_into): Likewise.
+       (gcc::jit::recording::local::replay_into): Likewise.
+       (gcc::jit::recording::eval::replay_into): Likewise.
+       (gcc::jit::recording::assignment::replay_into): Likewise.
+       (gcc::jit::recording::assignment_op::replay_into): Likewise.
+       (gcc::jit::recording::comment::replay_into): Likewise.
+       (gcc::jit::recording::conditional::replay_into): Likewise.
+       (gcc::jit::recording::place_label::replay_into): Likewise.
+       (gcc::jit::recording::jump::replay_into): Likewise.
+       (gcc::jit::recording::return_::replay_into): Likewise.
+       (gcc::jit::recording::loop::replay_into): Likewise.
+       (gcc::jit::recording::loop::end): Likewise.
+       (gcc::jit::recording::loop_end::replay_into): Likewise.
+
+       (gcc::jit::recording::context::set_str_option): Likewise.
+       Option setting and error-handling is now "owned" by the recording
+       context; the playback context delegates to the recording context
+       for these aspects.
+       (gcc::jit::recording::context::set_int_option): Likewise.
+       (gcc::jit::recording::context::set_bool_option): Likewise.
+       (gcc::jit::recording::context::compile): Likewise.
+       (gcc::jit::recording::context::add_error): Likewise.
+       (gcc::jit::recording::context::add_error_va): Likewise.
+       (gcc::jit::recording::context::get_first_error): Likewise.
+
+       (gcc::jit::context::context): Rename to...
+       (gcc::jit::playback::context::context): ...this.
+       (gcc::jit::context::~context): Rename to...
+       (gcc::jit::playback::context::~context): ...this.
+       (gcc::jit::context::gt_ggc_mx): Rename to...
+       (gcc::jit::playback::context::gt_ggc_mx): ...this.
+
+       (gcc::jit::context::set_code_factory): Eliminate.
+
+       (gcc::jit::context::get_type): Rename to...
+       (gcc::jit::playback::context::get_type): ...this.
+       (gcc::jit::context::new_field): Rename to...
+       (gcc::jit::playback::context::new_field): ...this.
+       (gcc::jit::context::new_struct_type): Rename to...
+       (gcc::jit::playback::context::new_struct_type): ...this, and
+       update to require a vec<field *>.
+       (gcc::jit::context::new_param): Rename to...
+       (gcc::jit::playback::context::new_param): ...this.
+       (gcc::jit::context::new_function): Rename to...
+       (gcc::jit::playback::context::new_function): ...this, and update
+       to require a vec<param *>.
+       (gcc::jit::context::new_global): Rename to...
+       (gcc::jit::playback::context::new_global): ...this.
+       (gcc::jit::context::new_rvalue_from_int): Rename to...
+       (gcc::jit::playback::context::new_rvalue_from_int): ...this.
+       (gcc::jit::context::new_rvalue_from_double): Rename to...
+       (gcc::jit::playback::context::new_rvalue_from_double): ...this.
+       (gcc::jit::context::new_rvalue_from_ptr): Rename to...
+       (gcc::jit::playback::context::new_rvalue_from_ptr): ...this.
+       (gcc::jit::context::new_string_literal): Rename to...
+       (gcc::jit::playback::context::new_string_literal): ...this.
+       (gcc::jit::context::as_truth_value): Rename to...
+       (gcc::jit::playback::context::as_truth_value): ...this.
+       (gcc::jit::context::new_unary_op): Rename to...
+       (gcc::jit::playback::context::new_unary_op): ...this.
+       (gcc::jit::context::new_binary_op): Rename to...
+       (gcc::jit::playback::context::new_binary_op): ...this.
+       (gcc::jit::context::new_comparison): Rename to...
+       (gcc::jit::playback::context::new_comparison): ...this.
+       (gcc::jit::context::new_call): Rename to...
+       (gcc::jit::playback::context::new_call): ...this, and update
+       to require a vec<rvalue *>.
+       (gcc::jit::context::new_array_lookup): Rename to...
+       (gcc::jit::playback::context::new_array_lookup): ...this.
+       (gcc::jit::context::new_field_access): Rename to...
+       (gcc::jit::playback::context::new_field_access): ...this.
+       (gcc::jit::context::new_dereference): Rename to...
+       (gcc::jit::playback::context::new_dereference): ...this.
+
+       (gcc::jit::lvalue::access_field): Rename to...
+       (gcc::jit::playback::lvalue::access_field): ...this.
+       (gcc::jit::lvalue::get_address): Rename to...
+       (gcc::jit::playback::lvalue::get_address): ...this.
+
+       (gcc::jit::rvalue::dereference_field): Rename to...
+       (gcc::jit::playback::rvalue::dereference_field): ...this.
+
+       (gcc::jit::rvalue::dereference): Rename to...
+       (gcc::jit::playback::rvalue::dereference): ...this.
+
+       (gcc::jit::wrapper::operator new): Rename to...
+       (gcc::jit::playback::wrapper::operator new): ...this.
+
+       (gcc::jit::function::function): Rename to...
+       (gcc::jit::playback::function::function): ...this.
+       (gcc::jit::function::gt_ggc_mx): Rename to...
+       (gcc::jit::playback::function::gt_ggc_mx): ...this.
+       (gcc::jit::function::get_return_type_as_tree): Rename to...
+       (gcc::jit::playback::function::get_return_type_as_tree): ...this.
+       (gcc::jit::function::new_local): Rename to...
+       (gcc::jit::playback::function::new_local): ...this.
+       (gcc::jit::function::new_forward_label): Rename to...
+       (gcc::jit::playback::function::new_forward_label): ...this.
+       (gcc::jit::function::postprocess): Rename to...
+       (gcc::jit::playback::function::postprocess): ...this.
+       (gcc::jit::function::add_eval): Rename to...
+       (gcc::jit::playback::function::add_eval): ...this.
+       (gcc::jit::function::add_assignment): Rename to...
+       (gcc::jit::playback::function::add_assignment): ...this.
+       (gcc::jit::function::add_comment): Rename to...
+       (gcc::jit::playback::function::add_comment): ...this.
+       (gcc::jit::function::add_conditional): Rename to...
+       (gcc::jit::playback::function::add_conditional): ...this.
+       (gcc::jit::function::add_label): Rename to...
+       (gcc::jit::playback::function::add_label): ...this.
+       (gcc::jit::function::place_forward_label): Rename to...
+       (gcc::jit::playback::function::place_forward_label): ...this.
+       (gcc::jit::function::add_jump): Rename to...
+       (gcc::jit::playback::function::add_jump): ...this.
+       (gcc::jit::function::add_return): Rename to...
+       (gcc::jit::playback::function::add_return): ...this.
+       (gcc::jit::function::new_loop): Rename to...
+       (gcc::jit::playback::function::new_loop): ...this.
+
+       (gcc::jit::label::label): Rename to...
+       (gcc::jit::playback::label::label): ...this.
+
+       (gcc::jit::loop::loop): Rename to...
+       (gc::jit::playback::loop::loop): ...this.
+       (gcc::jit::loop::end): Rename to...
+       (gcc::jit::playback::loop): ...this.
+
+       (gcc::jit::active_jit_ctxt): Eliminate in favor of...
+       (gcc::jit::active_playback_ctxt): ...this.
+
+       (gcc::jit::context::compile): Rename to...
+       (gcc::jit::playback::context::compile): ...this, and eliminate the
+       mutex handling; this is done for us by the caller.
+
+       (gcc::jit::context::invoke_code_factory): Rename to...
+       (gcc::jit::playback::context::replay): this.  Rather than call
+       a client-provided callback, instead replay the recorded API
+       calls.
+
+       (gcc::jit::context::dump_generated_code): Rename to...
+       (gcc::jit::playback::context::dump_generated_code): ...this.
+
+       (location_comparator): Update for renamed types.
+
+       (gcc::jit::context::handle_locations): Rename to...
+       (gcc::jit::playback::context::handle_locations): ...this.
+
+       (gcc::jit::context::add_error): Rename to...
+       (gcc::jit::playback::context::add_error): this, and delegate to
+       the recording context's add_error_va.
+
+       (gcc::jit::context::add_error_va): Rename to...
+       (gcc::jit::playback::context::add_error_va): this, and delegate
+       to the recording context.
+
+       (gcc::jit::context::new_location): Rename to...
+       (gcc::jit::playback::context::new_location): ...this.
+       (gcc::jit::context::set_tree_location): Rename to...
+       (gcc::jit::playback::context::set_tree_location): ...this.
+       (gcc::jit::context::get_source_file): Rename to...
+       (gcc::jit::playback::context::get_source_file): ...this.
+       (gcc::jit::source_file::source_file): Rename to...
+       (gcc::jit::playback::source_file::source_file): ...this.
+       (gcc::jit::source_file::get_source_line): Rename to...
+       (gcc::jit::playback::source_file::get_source_line): ...this.
+       (gcc::jit::source_line::source_line): Rename to...
+       (gcc::jit::playback::source_line::source_line): ...this.
+       (gcc::jit::source_line::get_location): Rename to...
+       (gcc::jit::playback::source_line::get_location): ...this.
+
+       (gcc::jit::location::location): Rename to...
+       (gcc::jit::playback::location::location): ...this.
+
+       * libgccjit.c: Update classes to derive from the "jit::recording"
+       class hierarchy.
+       (RETURN_IF_NOT_INITIAL_CTXT): Eliminate, as it relates to
+       code-creation callbacks.
+       (RETURN_NULL_IF_NOT_INITIAL_CTXT): Likewise.
+       (RETURN_NULL_IF_NOT_CALLBACK_CTXT): Likewise.
+       (jit_error): There isn't an "active jit context" anymore, except
+       during actual compilation, so simplify the logic here.
+       (gcc_jit_context_set_code_factory): Delete.
+
+       (gcc_jit_context_new_location): Update preconditions now that we
+       don't have code-creation callbacks.
+       (gcc_jit_context_get_type): Likewise.
+       (gcc_jit_type_get_pointer): Likewise.
+       (gcc_jit_type_get_const): Likewise.
+       (gcc_jit_context_new_field): Likewise.
+       (gcc_jit_context_new_struct_type): Likewise.
+       (gcc_jit_context_new_param): Likewise.
+       (gcc_jit_param_as_lvalue): Likewise.
+       (gcc_jit_param_as_rvalue): Likewise.
+       (gcc_jit_context_new_function): Likewise.
+       (gcc_jit_context_new_function): Likewise.
+       (gcc_jit_function_new_forward_label): Likewise.
+       (gcc_jit_context_new_global): Likewise.
+       (gcc_jit_lvalue_as_rvalue): Likewise.
+       (gcc_jit_context_new_rvalue_from_int): Likewise.
+       (gcc_jit_context_zero): Likewise.
+       (gcc_jit_context_one): Likewise.
+       (gcc_jit_context_new_rvalue_from_double): Likewise.
+       (gcc_jit_context_new_rvalue_from_ptr): Likewise.
+       (gcc_jit_context_new_string_literal): Likewise.
+       (gcc_jit_context_new_unary_op): Likewise.
+       (gcc_jit_context_new_binary_op): Likewise.
+       (gcc_jit_context_new_comparison): Likewise.
+       (gcc_jit_context_new_call): Likewise.
+       (gcc_jit_context_new_call): Likewise.
+       (gcc_jit_context_new_array_lookup): Likewise.
+       (gcc_jit_context_set_str_option): Likewise.
+       (gcc_jit_context_set_int_option): Likewise.
+       (gcc_jit_context_set_bool_option): Likewise.
+       (gcc_jit_context_compile): Likewise.
+       (gcc_jit_function_add_assignment_op): Likewise.  Also,
+       reimplement as a separate kind of recording, since we can't know
+       the type of the lvalue at recording-time.
+
+       * notes.txt: Update diagram to reflect the new implementation.
+
+2014-01-24  David Malcolm  <dmalcolm@redhat.com>
+
+       * libgccjit.h (enum gcc_jit_binary_op): We will use the result
+       type to determine if GCC_JIT_BINARY_OP_DIVIDE should
+       truncate towards zero, or be floating-point division.
+
+       * internal-api.c (gcc::jit::context::new_binary_op): Likewise.
+
+2014-01-24  David Malcolm  <dmalcolm@redhat.com>
+
+       * internal-api.h (gcc::jit::context::get_str_option): New access
+       method.
+       (gcc::jit::context::get_int_option): Likewise.
+
+       * internal-api.c (gcc::jit::context::~context): Use access methods
+       for options, rather than direct field access.
+       (gcc::jit::context::compile): Likewise.
+
+2014-01-23  David Malcolm  <dmalcolm@redhat.com>
+
+       * libgccjit.h (enum gcc_jit_bool_option): New value:
+       GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE.
+
+       * internal-api.c (gcc::jit::context::compile): Call
+       dump_generated_code if the user has requested it.
+       (gcc::jit::context::dump_generated_code): New, copying
+       from the .s file to stderr.
+
+       * internal-api.h (gcc::jit::context::dump_generated_code): New.
+
+2014-01-23  David Malcolm  <dmalcolm@redhat.com>
+
+       * internal-api.h (gcc::jit::function): Add field
+       "m_inner_bind_expr".
+       * internal-api.c (gcc::jit::function::function): Create a BIND_EXPR
+       for all non-imported functions, and put the statement list within
+       it.
+       (gcc::jit::function::gt_ggc_mx): Visit m_inner_bind_expr.
+       (gcc::jit::function::new_local): Set the DECL_CONTEXT of the new
+       local to be the function's BIND_EXPR, and prepend the new local
+       to said BIND_EXPR's BIND_EXPR_VARS chain.
+       (gcc::jit::function::postprocess): Set the DECL_SAVED_TREE of the
+       FUNCTION_DECL to be the BIND_EXPR, rather than the statement list.
+       The latter is now contained within the former.
+
+2014-01-23  David Malcolm  <dmalcolm@redhat.com>
+
+       * internal-api.h (gcc::jit::function::add_stmt): New.
+
+       * internal-api.c (gcc::jit::function::add_eval): Replace use of
+       tsi_link_stmt with call to add_stmt.
+       (gcc::jit::function::add_assignment): Likewise.
+       (gcc::jit::function::add_conditional): Likewise.
+       (gcc::jit::function::place_forward_label): Likewise.
+       (gcc::jit::function::add_jump): Likewise.
+       (gcc::jit::function::add_return): Likewise.
+
+2014-01-21  David Malcolm  <dmalcolm@redhat.com>
+
+       * internal-api.c (gcc::jit::function::add_comment): New.
+       * internal-api.h (gcc::jit::function::add_comment): New.
+       * libgccjit.c (gcc_jit_function_add_comment): New.
+       * libgccjit.h (gcc_jit_function_add_comment): New.
+       * libgccjit.map: Add gcc_jit_function_add_comment.
+
+2013-10-24  David Malcolm  <dmalcolm@redhat.com>
+
+       * internal-api.c (gcc::jit::function::add_eval): Handle non-NULL
+       locations.
+       (gcc::jit::context::handle_locations): Fix test for the various
+       kinds of declarations, replacing use of DECL_MINIMAL_CHECK,
+       which aborts on failure (such as if we saw a type).
+       * libgccjit.h (GCC_JIT_BOOL_OPTION_DEBUGINFO): Fix out-of-date
+       comment.
+
+2013-10-23  David Malcolm  <dmalcolm@redhat.com>
+
+       * internal-api.c: Update for rename of tree-flow.h to tree-cfg.h
+       in r203320, for declaration of dump_function_to_file.
+       * TODO.rst ("segfault seen in libbacktrace"): Remove - this was
+       fixed by Ian in r203810.
+
+2013-10-23  David Malcolm  <dmalcolm@redhat.com>
+
+       * internal-api.c: Add missing include of diagnostic-core.h
+
+2013-10-22  David Malcolm  <dmalcolm@redhat.com>
+
+       * internal-api.c (gcc::jit::context::add_error_va): Record the
+       first error that occurs on a context.
+       (gcc::jit::context::get_first_error): New.
+       * internal-api.h (gcc::jit::context::get_first_error): New.
+       (gcc::jit::context::m_first_error_str): New.
+       * libgccjit.c (gcc_jit_context_get_first_error): New.
+       * libgccjit.h (gcc_jit_context_get_first_error): New.
+       * libgccjit.map (gcc_jit_context_get_first_error): New.
+
+2013-10-21  David Malcolm  <dmalcolm@redhat.com>
+
+       * internal-api.c (gcc::jit::context::compile): Correctly cleanup
+       timevars in error-handling, preventing an issue where an error
+       on a context left timevar.c in an unstopped state, leading to an
+       assertion failure when restarting timevars in the next compile.
+       Found via fuzz-testing.
+
+2013-10-21  David Malcolm  <dmalcolm@redhat.com>
+
+       * internal-api.c (gcc::jit::context::postprocess): Show source
+       line numbers (if any) in gimple dump.
+
+2013-10-21  David Malcolm  <dmalcolm@redhat.com>
+
+       * libgccjit.c (gcc_jit_function_new_local): Use a more clear
+       error message for the case where someone tries to add a local
+       to a function imported from elsewhere.
+
+2013-10-21  David Malcolm  <dmalcolm@redhat.com>
+
+       * TODO.rst ("the C unary prefix "&" operator"): Remove completed item.
+       * internal-api.c (gcc::jit::lvalue::get_address): New.
+       * internal-api.h (gcc::jit::lvalue::get_address): New.
+       * libgccjit.c (gcc_jit_lvalue_get_address): New.
+       * libgccjit.h (gcc_jit_lvalue_get_address): New.
+       * libgccjit.map (gcc_jit_lvalue_get_address): New.
+
+2013-10-18  David Malcolm  <dmalcolm@redhat.com>
+
+       * internal-api.c (gcc::jit::context::new_param): Add context
+       argument to ctor for rvalue and its subclasses.
+       (gcc::jit::context::new_global): Likewise.
+       (gcc::jit::context::new_rvalue_from_int): Likewise.
+       (gcc::jit::context::new_rvalue_from_double): Likewise.
+       (gcc::jit::context::new_rvalue_from_ptr): Likewise.
+       (gcc::jit::context::new_string_literal): Likewise.
+       (gcc::jit::context::new_call): Likewise.
+       (gcc::jit::context::new_array_lookup): Likewise.
+       (gcc::jit::function::new_local): Likewise.
+       (gcc::jit::context::new_binary_op): Likewise; add new
+       operations.
+       (gcc::jit::context::new_comparison): Likewise; add new
+       comparisons.
+       (gcc::jit::context::as_truth_value): New.
+       (gcc::jit::context::new_unary_op): New.
+       (gcc::jit::context::new_field_access): Convert to a helper
+       method for use by the access_fields methods.
+       (gcc::jit::context::new_dereference): New.
+       (gcc::jit::lvalue::access_field): New.
+       (gcc::jit::rvalue::access_field): New.
+       (gcc::jit::rvalue::dereference_field): New.
+       (gcc::jit::rvalue::dereference): New.
+       * internal-api.h (gcc::jit::context::new_unary_op): New.
+       (gcc::jit::context::new_field_access): Work
+       (gcc::jit::context::new_dereference): New.
+       (gcc::jit::context::as_truth_value): New.
+       (gcc::jit::rvalue): Add a context field.
+       (gcc::jit::rvalue::access_field): New.
+       (gcc::jit::rvalue::dereference_field): New.
+       (gcc::jit::rvalue::dereference): New.
+       (gcc::jit::lvalue::lvalue): Add context to ctor.
+       (gcc::jit::lvalue::access_field): New.
+       (gcc::jit::param::param): Add context to ctor.
+       * libgccjit.c (gcc_jit_context_new_unary_op): New.
+       (gcc_jit_context_new_field_access): Remove.
+       (gcc_jit_lvalue_access_field): New.
+       (gcc_jit_rvalue_access_field): New.
+       (gcc_jit_rvalue_dereference_field): New.
+       (gcc_jit_rvalue_dereference): New.
+       *libgccjit.h (enum gcc_jit_unary_op): New.
+       (gcc_jit_context_new_unary_op): New.
+       (enum gcc_jit_binary_op): Document values, and add...
+       (GCC_JIT_BINARY_OP_DIVIDE): New.
+       (GCC_JIT_BINARY_OP_MODULO): New.
+       (GCC_JIT_BINARY_OP_BITWISE_AND): New.
+       (GCC_JIT_BINARY_OP_BITWISE_XOR): New.
+       (GCC_JIT_BINARY_OP_BITWISE_OR): New.
+       (GCC_JIT_BINARY_OP_LOGICAL_AND): New.
+       (GCC_JIT_BINARY_OP_LOGICAL_OR): New.
+       (enum gcc_jit_comparison): Document values, and add...
+       (GCC_JIT_COMPARISON_EQ): New.
+       (GCC_JIT_COMPARISON_NE): New.
+       (GCC_JIT_COMPARISON_LE): New.
+       (GCC_JIT_COMPARISON_GT): New.
+       (GCC_JIT_COMPARISON_GE): New.
+       (gcc_jit_context_new_field_access): Remove.
+       (gcc_jit_lvalue_access_field): New.
+       (gcc_jit_rvalue_access_field): New.
+       (gcc_jit_rvalue_dereference_field): New.
+       (gcc_jit_rvalue_dereference): New.
+       * libgccjit.map (gcc_jit_context_new_field_access): Remove.
+       (gcc_jit_lvalue_access_field): New.
+       (gcc_jit_rvalue_access_field): New.
+       (gcc_jit_rvalue_dereference_field): New.
+       (gcc_jit_rvalue_dereference): New.
+       * TODO.rst: Update
+
+2013-10-18  David Malcolm  <dmalcolm@redhat.com>
+
+       * internal-api.c (gcc::jit::context::get_type): Improve error
+       message, and report the bogus value.
+       (gcc::jit::context::new_binary_op): Likewise.
+       (gcc::jit::context::new_comparison): Likewise.
+       (gcc::jit::context::set_str_option): Likewise.
+       (gcc::jit::context::set_int_option): Likewise.
+       (gcc::jit::context::set_bool_option): Likewise.
+       (gcc::jit::context::compile): Likewise, and make the errors
+       block the creation of result, rather than just the return
+       value of the client callback.
+       (gcc::jit::context::add_error): Add varargs and provide
+       implementation, calling into...
+       (gcc::jit::context::add_error_va): New.
+       * internal-api.h (GNU_PRINTF): New.
+       (gcc::jit::context::add_error): Add varargs and GNU_PRINTF
+       attribute macro.
+       (gcc::jit::context::add_error_va): New.
+       (gcc::jit::context::errors_occurred): New.
+       (gcc::jit::context::m_error_count): New.
+       (gcc::jit::function::get_kind): New.
+       * libgccjit.c (JIT_BEGIN_STMT): New.
+       (JIT_END_STMT): New.
+       (RETURN_VAL_IF_FAIL): New.
+       (RETURN_NULL_IF_FAIL): New.
+       (RETURN_IF_FAIL): New.
+       (RETURN_IF_NOT_INITIAL_CTXT): New.
+       (RETURN_NULL_IF_NOT_INITIAL_CTXT): New.
+       (RETURN_NULL_IF_NOT_CALLBACK_CTXT): New.
+       (RETURN_IF_NOT_FUNC_DEFINITION): New.
+       (RETURN_NULL_IF_NOT_FUNC_DEFINITION): New.
+       (jit_error): New.
+       (gcc_jit_context_set_code_factory): Use new error-checking
+       macros.
+       (ASSERT_WITHIN_CALLBACK): Remove.
+       (ASSERT_NOT_WITHIN_CALLBACK): Remove.
+       (gcc_jit_context_new_location): Use new error-checking macros.
+       (gcc_jit_context_get_type): Likewise.
+       (gcc_jit_type_get_pointer): Likewise.
+       (gcc_jit_type_get_const): Likewise.
+       (gcc_jit_context_new_field): Likewise.
+       (gcc_jit_context_new_struct_type): Likewise.
+       (gcc_jit_context_new_param): Likewise.
+       (gcc_jit_param_as_lvalue): Likewise.
+       (gcc_jit_param_as_rvalue): Likewise.
+       (gcc_jit_context_new_function): Likewise.
+       (gcc_jit_function_new_forward_label): Likewise.
+       (gcc_jit_context_new_global): Likewise.
+       (gcc_jit_lvalue_as_rvalue): Likewise.
+       (gcc_jit_context_new_rvalue_from_int): Likewise.
+       (gcc_jit_context_zero): Likewise.
+       (gcc_jit_context_one): Likewise.
+       (gcc_jit_context_new_rvalue_from_double): Likewise.
+       (gcc_jit_context_new_rvalue_from_ptr): Likewise.
+       (gcc_jit_context_new_string_literal): Likewise.
+       (gcc_jit_context_new_binary_op): Likewise.
+       (gcc_jit_context_new_comparison): Likewise.
+       (gcc_jit_context_new_call): Likewise.
+       (gcc_jit_context_new_array_lookup): Likewise.
+       (gcc_jit_context_new_field_access): Likewise.
+       (gcc_jit_function_new_local): Likewise.
+       (gcc_jit_function_add_label): Likewise.
+       (gcc_jit_function_place_forward_label): Likewise.
+       (gcc_jit_function_add_eval): Likewise.
+       (gcc_jit_function_add_assignment): Likewise.
+       (gcc_jit_function_add_assignment_op): Likewise.
+       (gcc_jit_function_add_conditional): Likewise.
+       (gcc_jit_function_add_jump): Likewise.
+       (gcc_jit_function_add_return): Likewise.
+       (gcc_jit_function_new_loop): Likewise.
+       (gcc_jit_loop_end): Likewise.
+       (gcc_jit_context_set_str_option): Likewise.
+       (gcc_jit_context_set_int_option): Likewise.
+       (gcc_jit_context_set_bool_option): Likewise.
+       (gcc_jit_context_compile): Likewise.
+       (gcc_jit_result_get_code): Likewise.
+       (gcc_jit_result_release): Likewise.
+       * libgccjit.h (gcc_jit_function_new_forward_label): Clarify
+       behavior.
+       (gcc_jit_function_add_label): Likewise.
+
+2013-10-17  David Malcolm  <dmalcolm@redhat.com>
+
+       * internal-api.c (gcc::jit::context::get_void_type): Remove.
+       (gcc::jit::context::get_char_type): Remove.
+       (gcc::jit::context::get_int_type): Remove.
+       (gcc::jit::context::get_float_type): Remove.
+       (gcc::jit::context::get_double_type): Remove.
+       (get_tree_node_for_type): New.
+       (gcc::jit::context::get_type): New.
+       (gcc::jit::context::new_rvalue_from_double): New.
+       (gcc::jit::context::new_rvalue_from_ptr): New.
+       * internal-api.h (gcc::jit::context::get_void_type): Remove.
+       (gcc::jit::context::get_char_type): Remove.
+       (gcc::jit::context::get_int_type): Remove.
+       (gcc::jit::context::get_float_type): Remove.
+       (gcc::jit::context::get_double_type): Remove.
+       (gcc::jit::context::get_type): New.
+       (gcc::jit::context::new_rvalue_from_double): New.
+       (gcc::jit::context::new_rvalue_from_ptr): New.
+       * libgccjit.c (gcc_jit_context_get_void_type): Remove.
+       (gcc_jit_context_get_char_type): Remove.
+       (gcc_jit_context_get_int_type): Remove.
+       (gcc_jit_context_get_float_type): Remove.
+       (gcc_jit_context_get_double_type): Remove.
+       (gcc_jit_context_get_type): New.
+       (gcc_jit_context_new_rvalue_from_double): New.
+       (gcc_jit_context_new_rvalue_from_ptr): New.
+       * libgccjit.h (gcc_jit_context_get_void_type): Remove.
+       (gcc_jit_context_get_char_type): Remove.
+       (gcc_jit_context_get_int_type): Remove.
+       (gcc_jit_context_get_float_type): Remove.
+       (gcc_jit_context_get_double_type): Remove.
+       (enum gcc_jit_types): New.
+       (gcc_jit_context_get_type): New.
+       (gcc_jit_context_new_rvalue_from_double): New.
+       (gcc_jit_context_new_rvalue_from_ptr): New.
+       * libgccjit.map (gcc_jit_context_get_void_type): Remove.
+       (gcc_jit_context_get_char_type): Remove.
+       (gcc_jit_context_get_int_type): Remove.
+       (gcc_jit_context_get_float_type): Remove.
+       (gcc_jit_context_get_double_type): Remove.
+       (enum gcc_jit_types): New.
+       (gcc_jit_context_get_type): New.
+       (gcc_jit_context_new_rvalue_from_double): New.
+       (gcc_jit_context_new_rvalue_from_ptr): New.
+       * TODO.rst ("access to more primitive types"): Remove
+       completed item.
+
+2013-10-17  David Malcolm  <dmalcolm@redhat.com>
+
+       * libgccjit.h: Add and reword comments throughout.
+
+2013-10-17  David Malcolm  <dmalcolm@redhat.com>
+
+       * TODO.rst: Update.
+
+2013-10-16  David Malcolm  <dmalcolm@redhat.com>
+
+       * TODO.rst (gcc_jit_context_new_local): Remove completed item.
+       * internal-api.c (gcc::jit::context::new_local): Replace with...
+       (gcc::jit::function::new_local): ...this, and change return type
+       from (local*) to (lvalue*).
+       * internal-api.h (gcc::jit::local): Eliminate.
+       (gcc::jit::context::new_local): Replace with...
+       (gcc::jit::function::new_local): ...this, and change return type
+       from (local*) to (lvalue*).
+       * libgccjit.c (gcc_jit_local): Eliminate.
+       (gcc_jit_context_new_local): Replace with...
+       (gcc_jit_function_new_local): ...this, and change return type
+       from (gcc_jit_local*) to (gcc_jit_lvalue*).
+       (gcc_jit_local_as_lvalue): Remove.
+       (gcc_jit_local_as_rvalue): Remove.
+       * libgccjit.h (gcc_jit_local): Remove.
+       (gcc_jit_context_new_local): Replace with...
+       (gcc_jit_function_new_local): ...this, and change return type
+       from (gcc_jit_local*) to (gcc_jit_lvalue*).
+       (gcc_jit_local_as_lvalue): Remove.
+       (gcc_jit_local_as_rvalue): Remove.
+       * libgccjit.map (gcc_jit_context_new_local): Replace with...
+       (gcc_jit_function_new_local): ...this.
+       (gcc_jit_local_as_lvalue): Remove.
+       (gcc_jit_local_as_rvalue): Remove.
+
+2013-10-15  David Malcolm  <dmalcolm@redhat.com>
+
+       * libgccjit.h (gcc_jit_location): Rewrite comment to reflect
+       that this part of the API is now implemented.
+       ("Functions for use within the code factory."): Add notes on
+       memory-management and lifetimes.
+       * notes.txt: Update diagram to show handle_locations.
+
+2013-10-15  David Malcolm  <dmalcolm@redhat.com>
+
+       * TODO.rst: Update.
+
+2013-10-14  David Malcolm  <dmalcolm@redhat.com>
+
+       * libgccjit.map: Alphabetize the exported symbols.
+
+2013-10-14  David Malcolm  <dmalcolm@redhat.com>
+
+       * internal-api.c (gcc::jit::context::new_field): Implement
+       location support, by calling set_tree_location.
+       (gcc::jit::context::new_struct_type): Likewise.
+       (gcc::jit::context::new_param): Likewise.
+       (gcc::jit::context::new_function): Likewise.
+       (gcc::jit::context::new_global): Likewise.
+       (gcc::jit::context::new_local): Likewise.
+       (gcc::jit::context::new_binary_op): Likewise.
+       (gcc::jit::context::new_comparison): Likewise.
+       (gcc::jit::context::new_call): Likewise.
+       (gcc::jit::context::new_array_lookup): Likewise.
+       (gcc::jit::context::new_field_access): Likewise.
+       (gcc::jit::context::add_assignment): Likewise.
+       (gcc::jit::context::add_conditional): Likewise.
+       (gcc::jit::function::add_label): Likewise.
+       (gcc::jit::function::add_jump): Likewise.
+       (gcc::jit::function::add_return): Likewise.
+       (gcc::jit::function::place_forward_label): Likewise, adding
+       location parameter.
+       (gcc::jit::loop::loop): Add loc arg to place_forward_label.
+       (gcc::jit::loop::end): Likewise.
+       (gcc::jit::context::invoke_code_factory): Call handle_locations
+       after the client callback is done, before any GC can run.
+       (line_comparator): New.
+       (location_comparator): New.
+       (gcc::jit::context::handle_locations): New.
+       (gcc::jit::context::new_location): New.
+       (gcc::jit::context::set_tree_location): New.
+       (gcc::jit::context::get_source_file): New.
+       (gcc::jit::source_file::source_file): New.
+       (gcc::jit::source_file::get_source_line): New.
+       (gcc::jit::source_line::source_line): New.
+       (gcc::jit::source_line::get_location): New.
+       (gcc::jit::location::location): New.
+       * internal-api.h (gcc::jit::context::new_location): New.
+       (gcc::jit::context::set_tree_location): New.
+       (gcc::jit::context::handle_locations): New.
+       (gcc::jit::context::get_source_file): New.
+       (gcc::jit::context::m_source_files): New field.
+       (gcc::jit::context::m_cached_locations: New field.
+       (gcc::jit::function::place_forward_label): Add location
+       parameter.
+       (gcc::jit::function::set_tree_location): New.
+       (gcc::jit::source_file): New class.
+       (gcc::jit::source_line): New class.
+       (gcc::jit::location): New class.
+       * libgccjit.c (gcc_jit_context_new_location): New.
+       (gcc_jit_function_place_forward_label): Add location parameter,
+       changing public API.
+       * libgccjit.h (gcc_jit_context_new_location): New.
+       (gcc_jit_function_place_forward_label): Add location parameter,
+       changing public API.
+       * libgccjit.map (gcc_jit_context_new_location): New.
+       (main): Remove obsolete export.
+       (called_function): Likewise.
+
+2013-10-11  David Malcolm  <dmalcolm@redhat.com>
+
+       * internal-api.c: Update includes to reflect move of decl of
+       dump_function_to_file from tree-dump.h to tree-flow.h in
+       r203320.
+
+2013-10-10  David Malcolm  <dmalcolm@redhat.com>
+
+       * libgccjit.h (GCC_JIT_BOOL_OPTION_DUMP_SUMMARY): New.
+       * internal-api.c ((gcc::jit::context::compile): Implement
+       GCC_JIT_BOOL_OPTION_DUMP_SUMMARY.
+
+2013-10-10  David Malcolm  <dmalcolm@redhat.com>
+
+       * libgccjit.h (GCC_JIT_BOOL_OPTION_SELFCHECK_GC): Improve
+       documentation.
+       (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE): Likewise.
+
+2013-10-10  David Malcolm  <dmalcolm@redhat.com>
+
+       * libgccjit.h: Clarify the separation of the API into "outside
+       the callback" and "within the callback" entrypoints, moving the
+       latter to the bottom of the header.
+
+2013-10-10  David Malcolm  <dmalcolm@redhat.com>
+
+       * libgccjit.h: Add comments throughout.
+
+2013-10-09  David Malcolm  <dmalcolm@redhat.com>
+
+       * internal-api.c (gcc::jit::context::~context): Fix indentation;
+       clean up memory allocations when using
+       GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES.
+
+2013-10-09  David Malcolm  <dmalcolm@redhat.com>
+
+       * libgccjit.h (enum gcc_jit_bool_option): Add
+       GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING.
+       * internal-api.c (gcc::jit::context::compile): Implement
+       GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING.
+
+2013-10-09  David Malcolm  <dmalcolm@redhat.com>
+
+       * libgccjit.h (enum gcc_jit_bool_option): Add
+       GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES.
+       * internal-api.c (gcc::jit::context::~context): Implement
+       GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES.
+
+2013-10-08  David Malcolm  <dmalcolm@redhat.com>
+
+       * internal-api.c (gcc::jit::context::compile): Use mkdtemp to
+       create a temporary directory and create the .s and .so files
+       there, rather than writing to "fake.s" and then reading it to
+       make "fake.so", then using it, fixing various possible race
+       attacks by processes that can write to the process' current
+       working directory.
+       (gcc::jit::context::~context): Clean up tempfiles and path
+       buffers.
+       * internal-api.h (gcc::jit::context): Add fields
+       m_path_template, m_path_tempdir, m_path_c_file, m_path_s_file,
+       m_path_so_file.
+
+2013-10-08  David Malcolm  <dmalcolm@redhat.com>
+
+       * internal-api.c (gcc::jit::context::new_function): Fix leak of
+       arg_types.
+
+2013-10-08  David Malcolm  <dmalcolm@redhat.com>
+
+       * internal-api.c (gcc::jit::context::~context): New.
+       * internal-api.h (gcc::jit::context::~context): New.
+
+2013-10-07  David Malcolm  <dmalcolm@redhat.com>
+
+       * internal-api.c (gcc::jit::context::compile): Implement
+       GCC_JIT_BOOL_OPTION_SELFCHECK_GC.
+
+       * libgccjit.h (enum gcc_jit_bool_option): Add
+       GCC_JIT_BOOL_OPTION_SELFCHECK_GC.
+
+2013-10-07  David Malcolm  <dmalcolm@redhat.com>
+
+       * Make-lang.in: Rename JIT_OBJS to jit_OBJS.  Delete manual
+       dependencies.
+
+2013-10-04  David Malcolm  <dmalcolm@redhat.com>
+
+       * internal-api.c (gcc::jit::context::new_global): New.
+       * internal-api.h (gcc::jit::context::new_global): New.
+       * libgccjit.c (gcc_jit_context_new_global) New.
+       * libgccjit.h (gcc_jit_context_new_global) New.
+       * libgccjit.map: Add gcc_jit_context_new_global.
+
+2013-10-03  David Malcolm  <dmalcolm@redhat.com>
+
+       * libgccjit.c (gcc_jit_param_as_lvalue): New.
+       * libgccjit.h (gcc_jit_param_as_lvalue): New.
+       * libgccjit.map: Add gcc_jit_param_as_lvalue.
+
+2013-10-03  David Malcolm  <dmalcolm@redhat.com>
+
+       * internal-api.c (gcc::jit::function::postprocess): Dump gimple
+       using dump_function_to_file rather than debug_gimple_seq so that
+       we also get the declaration.
+
+2013-10-03  David Malcolm  <dmalcolm@redhat.com>
+
+       * Make-lang.in: New.
+       * TODO.rst: New.
+       * config-lang.in: New.
+       * dummy-frontend.c: New.
+       * internal-api.c: New.
+       * internal-api.h: New.
+       * libgccjit.c: New.
+       * libgccjit.h: New.
+       * libgccjit.map: New.
+       * notes.txt: New.
+\f
+Copyright (C) 2013-2014 Free Software Foundation, Inc.
+
+Copying and distribution of this file, with or without modification,
+are permitted in any medium without royalty provided the copyright
+notice and this notice are preserved.
diff --git a/gcc/jit/Make-lang.in b/gcc/jit/Make-lang.in
new file mode 100644 (file)
index 0000000..167fcad
--- /dev/null
@@ -0,0 +1,298 @@
+# Top level -*- makefile -*- fragment for libgccjit.so.
+#   Copyright (C) 2013-2014 Free Software Foundation, Inc.
+
+#This file is part of GCC.
+
+#GCC is free software; you can redistribute it and/or modify
+#it under the terms of the GNU General Public License as published by
+#the Free Software Foundation; either version 3, or (at your option)
+#any later version.
+
+#GCC is distributed in the hope that it will be useful,
+#but WITHOUT ANY WARRANTY; without even the implied warranty of
+#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+# This file provides the language dependent support in the main Makefile.
+# Each language makefile fragment must provide the following targets:
+#
+# foo.all.cross, foo.start.encap, foo.rest.encap,
+# foo.install-common, foo.install-man, foo.install-info, foo.install-pdf,
+# foo.install-html, foo.info, foo.dvi, foo.pdf, foo.html, foo.uninstall,
+# foo.mostlyclean, foo.clean, foo.distclean,
+# foo.maintainer-clean, foo.stage1, foo.stage2, foo.stage3, foo.stage4
+#
+# where `foo' is the name of the language.
+#
+# It should also provide rules for:
+#
+# - making any compiler driver (eg: g++)
+# - the compiler proper (eg: cc1plus)
+# - define the names for selecting the language in LANGUAGES.
+
+#\f
+# Define the names for selecting jit in LANGUAGES.
+# Note that it would be nice to move the dependency on g++
+# into the jit rule, but that needs a little bit of work
+# to do the right thing within all.cross.
+
+LIBGCCJIT_LINKER_NAME = libgccjit.so
+LIBGCCJIT_VERSION_NUM = 0
+LIBGCCJIT_MINOR_NUM = 0
+LIBGCCJIT_RELEASE_NUM = 1
+LIBGCCJIT_SONAME = $(LIBGCCJIT_LINKER_NAME).$(LIBGCCJIT_VERSION_NUM)
+LIBGCCJIT_FILENAME = \
+  $(LIBGCCJIT_SONAME).$(LIBGCCJIT_MINOR_NUM).$(LIBGCCJIT_RELEASE_NUM)
+
+LIBGCCJIT_LINKER_NAME_SYMLINK = $(LIBGCCJIT_LINKER_NAME)
+LIBGCCJIT_SONAME_SYMLINK = $(LIBGCCJIT_SONAME)
+
+jit: $(LIBGCCJIT_FILENAME) \
+       $(LIBGCCJIT_SYMLINK) \
+       $(LIBGCCJIT_LINKER_NAME_SYMLINK) \
+       $(FULL_DRIVER_NAME)
+
+# Tell GNU make to ignore these if they exist.
+.PHONY: jit
+
+jit_OBJS = attribs.o \
+       jit/dummy-frontend.o \
+       jit/libgccjit.o \
+       jit/jit-recording.o \
+       jit/jit-playback.o \
+       jit/jit-builtins.o
+
+# Use strict warnings for this front end.
+jit-warn = $(STRICT_WARN)
+
+# We avoid using $(BACKEND) from Makefile.in in order to avoid pulling
+# in main.o
+$(LIBGCCJIT_FILENAME): $(jit_OBJS) \
+       libbackend.a libcommon-target.a libcommon.a \
+       $(CPPLIB) $(LIBDECNUMBER) \
+       $(LIBDEPS) $(srcdir)/jit/libgccjit.map
+       +$(LLINKER) $(ALL_LINKERFLAGS) $(LDFLAGS) -o $@ -shared \
+            $(jit_OBJS) libbackend.a libcommon-target.a libcommon.a \
+            $(CPPLIB) $(LIBDECNUMBER) $(LIBS) $(BACKENDLIBS) \
+            -Wl,--version-script=$(srcdir)/jit/libgccjit.map \
+            -Wl,-soname,$(LIBGCCJIT_SONAME)
+
+$(LIBGCCJIT_SONAME_SYMLINK): $(LIBGCCJIT_FILENAME)
+       ln -sf $(LIBGCCJIT_FILENAME) $(LIBGCCJIT_SONAME_SYMLINK)
+
+$(LIBGCCJIT_LINKER_NAME_SYMLINK): $(LIBGCCJIT_SONAME_SYMLINK)
+       ln -sf $(LIBGCCJIT_SONAME_SYMLINK) $(LIBGCCJIT_LINKER_NAME_SYMLINK)
+
+#\f
+# Build hooks:
+
+jit.all.cross:
+jit.start.encap:
+jit.rest.encap:
+
+# Documentation build hooks.
+#
+# The documentation can be built using the texinfo toolchain, or
+# the sphinx toolchain
+#
+# The jit documentation is authored using Sphinx, which has numerous
+# advantages over Texinfo, including:
+#
+#   * much faster
+#
+#   * use of CSS and JS to provide less of a 1990s feel in the generated
+#     HTML.
+#
+#   * sane, stable HTML page and anchor names
+#
+#   * sane HTML navigation: ability to move forward and back in the HTML
+#     at every node to read the HTML like a book
+#
+#   * syntax-coloring of examples
+#
+#   * the ability to "include" fragments of code inline.  This is used
+#     heavily by the jit docs, so that the example code is shared by both
+#     the test suite and the documentation to ensure that the examples
+#     appearing in the docs actually compile and work
+#
+# Sphinx is not a "blessed" dependency, and so a prebuilt libgccjit.texinfo
+# file built by Sphinx is checked into the source tree to avoid requiring
+# everyone to have Sphinx installed.
+#
+# This prebuilt libgccjit.texinfo has the "include" fragments "baked in",
+# and so contains the content from the sphinx toolchain, but lacks the
+# syntax-coloring, and the generated HTML is (IMHO) greatly inferior to
+# that generated by Sphinx.
+
+# These targets redirect HTML creation and installation to either
+# jit.sphinx.(install-)html or jit.texinfo.(install-)html.
+jit.html: jit.$(doc_build_sys).html
+jit.install-html: jit.$(doc_build_sys).install-html
+
+# For now, use texinfo for pdf, since the sphinx latex toolchain currently
+# fails for me deep inside pdflatex (see notes below)
+jit.pdf: jit.texinfo.pdf
+jit.install-pdf: jit.texinfo.install-pdf
+
+# Hooks for building docs using texinfo
+JIT_TEXI_FILES = $(srcdir)/jit/docs/_build/texinfo/libgccjit.texi
+
+jit.info: doc/libgccjit.info
+doc/libgccjit.info: $(JIT_TEXI_FILES)
+       if test "x$(BUILD_INFO)" = xinfo; then \
+         rm -f doc/libgccjit.info*; \
+         $(MAKEINFO) $(MAKEINFOFLAGS) -I $(gcc_docdir) \
+               -I $(gcc_docdir)/include -o $@ $<; \
+       else true; fi
+
+jit.install-info: $(DESTDIR)$(infodir)/libgccjit.info
+
+jit.dvi: doc/libgccjit.dvi
+doc/libgccjit.dvi: $(JIT_TEXI_FILES)
+       $(TEXI2DVI) -I $(abs_docdir) -I $(abs_docdir)/include -o $@ $<
+
+jit.texinfo.html: $(build_htmldir)/jit/index.html
+
+$(build_htmldir)/jit/index.html: $(srcdir)/jit/docs/_build/texinfo/libgccjit.texi
+       $(mkinstalldirs) $(@D)
+       rm -f $(@D)/*
+       $(TEXI2HTML) -I $(gcc_docdir)/include -I $(srcdir)/jit -o $(@D) $<
+
+jit.texinfo.install-html: jit.texinfo.html
+       @$(NORMAL_INSTALL)
+       test -z "$(htmldir)" || $(mkinstalldirs) "$(DESTDIR)$(htmldir)"
+       @for p in $(build_htmldir)/jit; do \
+         if test -f "$$p" || test -d "$$p"; then d=""; else d="$(srcdir)/"; fi; \
+         f=$(html__strip_dir) \
+         if test -d "$$d$$p"; then \
+           echo " $(mkinstalldirs) '$(DESTDIR)$(htmldir)/$$f'"; \
+           $(mkinstalldirs) "$(DESTDIR)$(htmldir)/$$f" || exit 1; \
+           echo " $(INSTALL_DATA) '$$d$$p'/* '$(DESTDIR)$(htmldir)/$$f'"; \
+           $(INSTALL_DATA) "$$d$$p"/* "$(DESTDIR)$(htmldir)/$$f"; \
+         else \
+           echo " $(INSTALL_DATA) '$$d$$p' '$(DESTDIR)$(htmldir)/$$f'"; \
+           $(INSTALL_DATA) "$$d$$p" "$(DESTDIR)$(htmldir)/$$f"; \
+         fi; \
+       done
+
+jit.texinfo.pdf: doc/libgccjit.pdf
+
+doc/libgccjit.pdf: $(JIT_TEXI_FILES)
+       $(TEXI2PDF) -I $(abs_docdir) -I $(abs_docdir)/include -o $@ $<
+
+jit.texinfo.install-pdf: doc/libgccjit.pdf
+       @$(NORMAL_INSTALL)
+       test -z "$(pdfdir)" || $(mkinstalldirs) "$(DESTDIR)$(pdfdir)/gcc"
+       @for p in doc/libgccjit.pdf; do \
+         if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+         f=$(pdf__strip_dir) \
+         echo " $(INSTALL_DATA) '$$d$$p' '$(DESTDIR)$(pdfdir)/gcc/$$f'"; \
+         $(INSTALL_DATA) "$$d$$p" "$(DESTDIR)$(pdfdir)/gcc/$$f"; \
+       done
+
+# Hooks for building docs using the Sphinx toolchain:
+
+SPHINX_BUILD_DIR=jit/sphinx-build
+
+jit.sphinx.html:
+       mkdir -p $(SPHINX_BUILD_DIR)
+       (cd $(srcdir)/jit/docs && \
+         make html BUILDDIR=$(PWD)/$(SPHINX_BUILD_DIR) )
+
+jit_htmldir=$(htmldir)/jit
+
+jit.sphinx.install-html: jit.sphinx.html
+       @$(NORMAL_INSTALL)
+       test -z "$(jit_htmldir)" || $(mkinstalldirs) "$(DESTDIR)$(jit_htmldir)"
+       @for f in $(shell cd $(SPHINX_BUILD_DIR)/html && find) ; do \
+         if test -f $(SPHINX_BUILD_DIR)/html/"$$f"; then \
+            $(INSTALL_DATA) $(SPHINX_BUILD_DIR)/html/"$$f" $(DESTDIR)$(jit_htmldir)/"$$f"; \
+         else \
+            mkdir $(DESTDIR)$(jit_htmldir)/"$$f"; \
+         fi; \
+       done
+
+# (This one is currently failing deep inside pdflatex for me;
+# see https://bugzilla.redhat.com/show_bug.cgi?id=1148845 )
+jit.sphinx.pdf: $(SPHINX_BUILD_DIR)/latex/libgccjit.pdf
+$(SPHINX_BUILD_DIR)/latex/libgccjit.pdf:
+       mkdir -p $(SPHINX_BUILD_DIR)
+       (cd $(srcdir)/jit/docs && \
+         make latexpdf BUILDDIR=$(PWD)/$(SPHINX_BUILD_DIR) )
+
+jit.sphinx.install-pdf: $(SPHINX_BUILD_DIR)/latex/libgccjit.pdf
+       @$(NORMAL_INSTALL)
+       test -z "$(pdfdir)" || $(mkinstalldirs) "$(DESTDIR)$(pdfdir)/gcc"
+       @for p in $(SPHINX_BUILD_DIR)/latex/libgccjit.pdf; do \
+         if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+         f=$(pdf__strip_dir) \
+         echo " $(INSTALL_DATA) '$$d$$p' '$(DESTDIR)$(pdfdir)/gcc/$$f'"; \
+         $(INSTALL_DATA) "$$d$$p" "$(DESTDIR)$(pdfdir)/gcc/$$f"; \
+       done
+
+jit.srcinfo:
+jit.srcextra:
+
+jit.tags:
+
+jit.man:
+
+jit.srcman:
+
+lang_checks += check-jit
+
+#\f
+# Install hooks:
+jit.install-common: installdirs
+       $(INSTALL_PROGRAM) $(LIBGCCJIT_FILENAME) \
+         $(DESTDIR)/$(libdir)/$(LIBGCCJIT_FILENAME)
+       ln -sf \
+         $(LIBGCCJIT_FILENAME) \
+         $(DESTDIR)/$(libdir)/$(LIBGCCJIT_SONAME_SYMLINK)
+       ln -sf \
+         $(LIBGCCJIT_SONAME_SYMLINK)\
+         $(DESTDIR)/$(libdir)/$(LIBGCCJIT_LINKER_NAME_SYMLINK)
+       $(INSTALL_PROGRAM) $(srcdir)/jit/libgccjit.h \
+         $(DESTDIR)/$(includedir)/libgccjit.h
+       $(INSTALL_PROGRAM) $(srcdir)/jit/libgccjit++.h \
+         $(DESTDIR)/$(includedir)/libgccjit++.h
+
+jit.install-man:
+
+jit.install-plugin:
+
+jit.uninstall:
+
+#\f
+# Clean hooks:
+# A lot of the ancillary files are deleted by the main makefile.
+# We just have to delete files specific to us.
+
+jit.mostlyclean:
+
+jit.clean:
+
+jit.distclean:
+
+jit.maintainer-clean:
+
+#\f
+# Stage hooks:
+# The main makefile has already created stage?/jit.
+
+jit.stage1: stage1-start
+       -mv jit/*$(objext) stage1/jit
+jit.stage2: stage2-start
+       -mv jit/*$(objext) stage2/jit
+jit.stage3: stage3-start
+       -mv jit/*$(objext) stage3/jit
+jit.stage4: stage4-start
+       -mv jit/*$(objext) stage4/jit
+jit.stageprofile: stageprofile-start
+       -mv jit/*$(objext) stageprofile/jit
+jit.stagefeedback: stagefeedback-start
+       -mv jit/*$(objext) stagefeedback/jit
diff --git a/gcc/jit/TODO.rst b/gcc/jit/TODO.rst
new file mode 100644 (file)
index 0000000..09c4d9d
--- /dev/null
@@ -0,0 +1,119 @@
+TODOs
+-----
+
+API
+===
+* error-handling:
+    * have a client-provided error-handling callback for the context, and
+      call it, rather than asserting/crashing etc, to make the API resilient and helpful
+
+* probably should turn off signal handlers and backtracing, leaving that to
+  the client code
+
+* enums and ABI: give enums specific numbers, in ranges, to make it
+  possible to maintain a logical ordering whilst preserving ABI.
+
+* expose the statements in the API? (mostly so they can be stringified?)
+
+* support more arithmetic ops and comparison modes
+
+* access to a function by address::
+
+    extern gcc_jit_function *
+    gcc_jit_context_get_function (ctxt,
+                                  void *); /* need type information */
+
+  so you can access "static" fns in your code.
+
+* ability to turn a function into a function pointer::
+
+    gcc_jit_function_as_rvalue ()
+
+* expressing branch probabilies (like __builtin_expect)::
+
+    extern gcc_jit_rvalue *
+    gcc_jit_rvalue_likely (gcc_jit_rvalue *rvalue,
+                           int is_likely);
+
+  though would:
+
+    extern void
+    gcc_jit_block_set_likelihood (gcc_jit_block *block,
+                                  int hotness);
+
+  be better?  (for expressing how hot the current location is)
+
+* add a SONAME to the library (and potentially version the symbols?)
+
+* do we need alternative forms of division (floor vs rounding)?
+
+* are we missing any ops?
+
+* error-checking:
+
+    * gcc_jit_context_new_unary_op: various checks needed
+
+    * gcc_jit_context_new_binary_op: various checks needed
+
+    * gcc_jit_context_new_comparison: must be numeric or pointer types
+
+    * gcc_jit_context_new_array_access: "index" must be of numeric type.
+
+    * gcc_jit_lvalue_access_field: must be field of correct struct
+
+    * gcc_jit_rvalue_access_field: must be field of correct struct
+
+    * gcc_jit_block_add_assignment_op: check the types
+
+* Implement more kinds of casts e.g. pointers
+
+Bugs
+====
+* fixing all the state issues: make it work repeatedly with optimization
+  turned up to full.
+
+* make the dirty dirty hacks less egregious...
+
+* test under valgrind; fix memory leaks
+
+* re-architect gcc so we don't have to reinitialize everything every time
+  a context is compiled
+
+Test suite
+==========
+* get DejaGnu to build and run C++ testcases
+
+* measure code coverage in testing of libgccjit.so
+
+Future milestones
+=================
+* try porting llvmpipe to gcc
+
+* inline assembler?
+
+* Detect and issue warnings/errors about uses of uninitialized variables
+
+* Warn about unused objects in a context (e.g. rvalues/lvalues)?  (e.g.
+  for gcc_jit_context_new_call vs gcc_jit_block_add_eval)
+
+Nice to have
+============
+* Currently each function has a single stmt_list, which is built in
+  postprocessing by walking the list of blocks.  Presumably we could
+  have each block have its own stmt_list, avoiding the need for this
+  traversal, and having the block structure show up within tree dumps.
+  Alternatively, could we skip tree and go straight to gimple?
+
+* ability to give contexts names, for ease of debugging?
+
+
+Probably not needed
+===================
+* "switch" and "case" ?
+
+* sizeof (should this be an API hook?)  do we even need it? presumably
+  client code can just do the sizeof() in its own code.
+
+* do we need unary plus?
+
+etc etc
diff --git a/gcc/jit/config-lang.in b/gcc/jit/config-lang.in
new file mode 100644 (file)
index 0000000..7a32afe
--- /dev/null
@@ -0,0 +1,38 @@
+# Top level configure fragment for libgccjit.so.
+#   Copyright (C) 2013-2014 Free Software Foundation, Inc.
+
+#This file is part of GCC.
+
+#GCC is free software; you can redistribute it and/or modify
+#it under the terms of the GNU General Public License as published by
+#the Free Software Foundation; either version 3, or (at your option)
+#any later version.
+
+#GCC is distributed in the hope that it will be useful,
+#but WITHOUT ANY WARRANTY; without even the implied warranty of
+#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+# Configure looks for the existence of this file to auto-config each language.
+# We define several parameters used by configure:
+#
+# language     - name of language as it would appear in $(LANGUAGES)
+# compilers    - value to add to $(COMPILERS)
+
+language="jit"
+
+compilers="libgccjit.so"
+
+target_libs=""
+
+gtfiles="\$(srcdir)/jit/dummy-frontend.c"
+
+# The configuration requires --enable-host-shared
+# for jit to be supported.
+# Hence to get the jit, one must configure with:
+#   --enable-host-shared --enable-languages=jit
+build_by_default="no"
diff --git a/gcc/jit/docs/Makefile b/gcc/jit/docs/Makefile
new file mode 100644 (file)
index 0000000..7d20702
--- /dev/null
@@ -0,0 +1,153 @@
+# Makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS    =
+SPHINXBUILD   = sphinx-build
+PAPER         =
+BUILDDIR      = _build
+
+# Internal variables.
+PAPEROPT_a4     = -D latex_paper_size=a4
+PAPEROPT_letter = -D latex_paper_size=letter
+ALLSPHINXOPTS   = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+# the i18n builder cannot share the environment and doctrees with the others
+I18NSPHINXOPTS  = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+
+.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
+
+help:
+       @echo "Please use \`make <target>' where <target> is one of"
+       @echo "  html       to make standalone HTML files"
+       @echo "  dirhtml    to make HTML files named index.html in directories"
+       @echo "  singlehtml to make a single large HTML file"
+       @echo "  pickle     to make pickle files"
+       @echo "  json       to make JSON files"
+       @echo "  htmlhelp   to make HTML files and a HTML help project"
+       @echo "  qthelp     to make HTML files and a qthelp project"
+       @echo "  devhelp    to make HTML files and a Devhelp project"
+       @echo "  epub       to make an epub"
+       @echo "  latex      to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
+       @echo "  latexpdf   to make LaTeX files and run them through pdflatex"
+       @echo "  text       to make text files"
+       @echo "  man        to make manual pages"
+       @echo "  texinfo    to make Texinfo files"
+       @echo "  info       to make Texinfo files and run them through makeinfo"
+       @echo "  gettext    to make PO message catalogs"
+       @echo "  changes    to make an overview of all changed/added/deprecated items"
+       @echo "  linkcheck  to check all external links for integrity"
+       @echo "  doctest    to run all doctests embedded in the documentation (if enabled)"
+
+clean:
+       -rm -rf $(BUILDDIR)/*
+
+html:
+       $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
+       @echo
+       @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
+
+dirhtml:
+       $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
+       @echo
+       @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
+
+singlehtml:
+       $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
+       @echo
+       @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
+
+pickle:
+       $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
+       @echo
+       @echo "Build finished; now you can process the pickle files."
+
+json:
+       $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
+       @echo
+       @echo "Build finished; now you can process the JSON files."
+
+htmlhelp:
+       $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
+       @echo
+       @echo "Build finished; now you can run HTML Help Workshop with the" \
+             ".hhp project file in $(BUILDDIR)/htmlhelp."
+
+qthelp:
+       $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
+       @echo
+       @echo "Build finished; now you can run "qcollectiongenerator" with the" \
+             ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
+       @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/libgccjit.qhcp"
+       @echo "To view the help file:"
+       @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/libgccjit.qhc"
+
+devhelp:
+       $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
+       @echo
+       @echo "Build finished."
+       @echo "To view the help file:"
+       @echo "# mkdir -p $$HOME/.local/share/devhelp/libgccjit"
+       @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/libgccjit"
+       @echo "# devhelp"
+
+epub:
+       $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
+       @echo
+       @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
+
+latex:
+       $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+       @echo
+       @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
+       @echo "Run \`make' in that directory to run these through (pdf)latex" \
+             "(use \`make latexpdf' here to do that automatically)."
+
+latexpdf:
+       $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+       @echo "Running LaTeX files through pdflatex..."
+       $(MAKE) -C $(BUILDDIR)/latex all-pdf
+       @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
+
+text:
+       $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
+       @echo
+       @echo "Build finished. The text files are in $(BUILDDIR)/text."
+
+man:
+       $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
+       @echo
+       @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
+
+texinfo:
+       $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+       @echo
+       @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
+       @echo "Run \`make' in that directory to run these through makeinfo" \
+             "(use \`make info' here to do that automatically)."
+
+info:
+       $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+       @echo "Running Texinfo files through makeinfo..."
+       make -C $(BUILDDIR)/texinfo info
+       @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
+
+gettext:
+       $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
+       @echo
+       @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
+
+changes:
+       $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
+       @echo
+       @echo "The overview file is in $(BUILDDIR)/changes."
+
+linkcheck:
+       $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
+       @echo
+       @echo "Link check complete; look for any errors in the above output " \
+             "or in $(BUILDDIR)/linkcheck/output.txt."
+
+doctest:
+       $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
+       @echo "Testing of doctests in the sources finished, look at the " \
+             "results in $(BUILDDIR)/doctest/output.txt."
diff --git a/gcc/jit/docs/_build/texinfo/Makefile b/gcc/jit/docs/_build/texinfo/Makefile
new file mode 100644 (file)
index 0000000..87e3048
--- /dev/null
@@ -0,0 +1,50 @@
+# Makefile for Sphinx Texinfo output
+
+infodir ?= /usr/share/info
+
+MAKEINFO = makeinfo --no-split
+MAKEINFO_html = makeinfo --no-split --html
+MAKEINFO_plaintext = makeinfo --no-split --plaintext
+TEXI2PDF = texi2pdf --batch --expand
+INSTALL_INFO = install-info
+
+ALLDOCS = $(basename $(wildcard *.texi))
+
+all: info
+info: $(addsuffix .info,$(ALLDOCS))
+plaintext: $(addsuffix .txt,$(ALLDOCS))
+html: $(addsuffix .html,$(ALLDOCS))
+pdf: $(addsuffix .pdf,$(ALLDOCS))
+
+install-info: info
+       for f in *.info; do \
+         cp -t $(infodir) "$$f" && \
+         $(INSTALL_INFO) --info-dir=$(infodir) "$$f" ; \
+       done
+
+uninstall-info: info
+       for f in *.info; do \
+         rm -f "$(infodir)/$$f"  ; \
+         $(INSTALL_INFO) --delete --info-dir=$(infodir) "$$f" ; \
+       done
+
+%.info: %.texi
+       $(MAKEINFO) -o '$@' '$<'
+
+%.txt: %.texi
+       $(MAKEINFO_plaintext) -o '$@' '$<'
+
+%.html: %.texi
+       $(MAKEINFO_html) -o '$@' '$<'
+
+%.pdf: %.texi
+       -$(TEXI2PDF) '$<'
+       -$(TEXI2PDF) '$<'
+       -$(TEXI2PDF) '$<'
+
+clean:
+       -rm -f *.info *.pdf *.txt *.html
+       -rm -f *.log *.ind *.aux *.toc *.syn *.idx *.out *.ilg *.pla *.ky *.pg
+       -rm -f *.vr *.tp *.fn *.fns *.def *.defs *.cp *.cps *.ge *.ges *.mo
+
+.PHONY: all info plaintext html pdf install-info uninstall-info clean
diff --git a/gcc/jit/docs/_build/texinfo/factorial.png b/gcc/jit/docs/_build/texinfo/factorial.png
new file mode 100644 (file)
index 0000000..dff47ce
Binary files /dev/null and b/gcc/jit/docs/_build/texinfo/factorial.png differ
diff --git a/gcc/jit/docs/_build/texinfo/libgccjit.texi b/gcc/jit/docs/_build/texinfo/libgccjit.texi
new file mode 100644 (file)
index 0000000..58ba150
--- /dev/null
@@ -0,0 +1,6537 @@
+\input texinfo   @c -*-texinfo-*-
+@c %**start of header
+@setfilename libgccjit.info
+@documentencoding UTF-8
+@ifinfo
+@*Generated by Sphinx 1.1.3.@*
+@end ifinfo
+@settitle libgccjit Documentation
+@defindex ge
+@paragraphindent 2
+@exampleindent 4
+@afourlatex
+@dircategory Miscellaneous
+@direntry
+* libgccjit: (libgccjit.info). One line description of project.
+@end direntry
+
+@c %**end of header
+
+@copying
+@quotation
+libgccjit 5.0.0 (experimental 20141110), November 10, 2014
+
+David Malcolm
+
+Copyright @copyright{} 2014, Free Software Foundation
+@end quotation
+
+@end copying
+
+@titlepage
+@title libgccjit Documentation
+@insertcopying
+@end titlepage
+@contents
+
+@c %** start of user preamble
+
+@c %** end of user preamble
+
+@ifnottex
+@node Top
+@top libgccjit Documentation
+@insertcopying
+@end ifnottex
+
+@c %**start of body
+@anchor{index doc}@anchor{0}
+@c Copyright (C) 2014 Free Software Foundation, Inc.
+@c Originally contributed by David Malcolm <dmalcolm@redhat.com>
+@c 
+@c This is free software: you can redistribute it and/or modify it
+@c under the terms of the GNU General Public License as published by
+@c the Free Software Foundation, either version 3 of the License, or
+@c (at your option) any later version.
+@c 
+@c This program is distributed in the hope that it will be useful, but
+@c WITHOUT ANY WARRANTY; without even the implied warranty of
+@c MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+@c General Public License for more details.
+@c 
+@c You should have received a copy of the GNU General Public License
+@c along with this program.  If not, see
+@c <http://www.gnu.org/licenses/>.
+
+Contents:
+
+@c Copyright (C) 2014 Free Software Foundation, Inc.
+@c Originally contributed by David Malcolm <dmalcolm@redhat.com>
+@c 
+@c This is free software: you can redistribute it and/or modify it
+@c under the terms of the GNU General Public License as published by
+@c the Free Software Foundation, either version 3 of the License, or
+@c (at your option) any later version.
+@c 
+@c This program is distributed in the hope that it will be useful, but
+@c WITHOUT ANY WARRANTY; without even the implied warranty of
+@c MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+@c General Public License for more details.
+@c 
+@c You should have received a copy of the GNU General Public License
+@c along with this program.  If not, see
+@c <http://www.gnu.org/licenses/>.
+
+@menu
+* Tutorial:: 
+* Topic Reference:: 
+* Internals:: 
+* Indices and tables:: 
+* Index:: 
+
+@detailmenu
+ --- The Detailed Node Listing ---
+
+Tutorial
+
+* Tutorial part 1; "Hello world": Tutorial part 1 "Hello world". 
+* Tutorial part 2; Creating a trivial machine code function: Tutorial part 2 Creating a trivial machine code function. 
+* Tutorial part 3; Loops and variables: Tutorial part 3 Loops and variables. 
+* Tutorial part 4; Adding JIT-compilation to a toy interpreter: Tutorial part 4 Adding JIT-compilation to a toy interpreter. 
+
+Tutorial part 2: Creating a trivial machine code function
+
+* Options:: 
+* Full example:: 
+
+Tutorial part 3: Loops and variables
+
+* Expressions; lvalues and rvalues: Expressions lvalues and rvalues. 
+* Control flow:: 
+* Visualizing the control flow graph:: 
+* Full example: Full example<2>. 
+
+Tutorial part 4: Adding JIT-compilation to a toy interpreter
+
+* Our toy interpreter:: 
+* Compiling to machine code:: 
+* Setting things up:: 
+* Populating the function:: 
+* Verifying the control flow graph:: 
+* Compiling the context:: 
+* Single-stepping through the generated code:: 
+* Examining the generated code:: 
+* Putting it all together:: 
+* Behind the curtain; How does our code get optimized?: Behind the curtain How does our code get optimized?. 
+
+Behind the curtain: How does our code get optimized?
+
+* Optimizing away stack manipulation:: 
+* Elimination of tail recursion:: 
+
+Topic Reference
+
+* Compilation contexts:: 
+* Objects:: 
+* Types:: 
+* Expressions:: 
+* Creating and using functions:: 
+* Source Locations:: 
+* Compilation results:: 
+
+Compilation contexts
+
+* Lifetime-management:: 
+* Thread-safety:: 
+* Error-handling:: 
+* Debugging:: 
+* Options: Options<2>. 
+
+Options
+
+* String Options:: 
+* Boolean options:: 
+* Integer options:: 
+
+Types
+
+* Standard types:: 
+* Pointers@comma{} const@comma{} and volatile: Pointers const and volatile. 
+* Structures and unions:: 
+
+Expressions
+
+* Rvalues:: 
+* Lvalues:: 
+* Working with pointers@comma{} structs and unions: Working with pointers structs and unions. 
+
+Rvalues
+
+* Simple expressions:: 
+* Unary Operations:: 
+* Binary Operations:: 
+* Comparisons:: 
+* Function calls:: 
+* Type-coercion:: 
+
+Lvalues
+
+* Global variables:: 
+
+Creating and using functions
+
+* Params:: 
+* Functions:: 
+* Blocks:: 
+* Statements:: 
+
+Source Locations
+
+* Faking it:: 
+
+Internals
+
+* Working on the JIT library:: 
+* Running the test suite:: 
+* Environment variables:: 
+* Overview of code structure:: 
+
+@end detailmenu
+@end menu
+
+
+@node Tutorial,Topic Reference,Top,Top
+@anchor{intro/index libgccjit}@anchor{1}@anchor{intro/index doc}@anchor{2}@anchor{intro/index tutorial}@anchor{3}
+@chapter Tutorial
+
+
+@c Copyright (C) 2014 Free Software Foundation, Inc.
+@c Originally contributed by David Malcolm <dmalcolm@redhat.com>
+@c 
+@c This is free software: you can redistribute it and/or modify it
+@c under the terms of the GNU General Public License as published by
+@c the Free Software Foundation, either version 3 of the License, or
+@c (at your option) any later version.
+@c 
+@c This program is distributed in the hope that it will be useful, but
+@c WITHOUT ANY WARRANTY; without even the implied warranty of
+@c MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+@c General Public License for more details.
+@c 
+@c You should have received a copy of the GNU General Public License
+@c along with this program.  If not, see
+@c <http://www.gnu.org/licenses/>.
+
+@menu
+* Tutorial part 1; "Hello world": Tutorial part 1 "Hello world". 
+* Tutorial part 2; Creating a trivial machine code function: Tutorial part 2 Creating a trivial machine code function. 
+* Tutorial part 3; Loops and variables: Tutorial part 3 Loops and variables. 
+* Tutorial part 4; Adding JIT-compilation to a toy interpreter: Tutorial part 4 Adding JIT-compilation to a toy interpreter. 
+
+@end menu
+
+@node Tutorial part 1 "Hello world",Tutorial part 2 Creating a trivial machine code function,,Tutorial
+@anchor{intro/tutorial01 doc}@anchor{4}@anchor{intro/tutorial01 tutorial-part-1-hello-world}@anchor{5}
+@section Tutorial part 1: "Hello world"
+
+
+Before we look at the details of the API, let's look at building and
+running programs that use the library.
+
+Here's a toy "hello world" program that uses the library to synthesize
+a call to @cite{printf} and uses it to write a message to stdout.
+
+Don't worry about the content of the program for now; we'll cover
+the details in later parts of this tutorial.
+
+@quotation
+
+@example
+/* Smoketest example for libgccjit.so
+   Copyright (C) 2014 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include <libgccjit.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+
+static void
+create_code (gcc_jit_context *ctxt)
+@{
+  /* Let's try to inject the equivalent of:
+     void
+     greet (const char *name)
+     @{
+        printf ("hello %s\n", name);
+     @}
+  */
+  gcc_jit_type *void_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+  gcc_jit_type *const_char_ptr_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_CONST_CHAR_PTR);
+  gcc_jit_param *param_name =
+    gcc_jit_context_new_param (ctxt, NULL, const_char_ptr_type, "name");
+  gcc_jit_function *func =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                  GCC_JIT_FUNCTION_EXPORTED,
+                                  void_type,
+                                  "greet",
+                                  1, &param_name,
+                                  0);
+
+  gcc_jit_param *param_format =
+    gcc_jit_context_new_param (ctxt, NULL, const_char_ptr_type, "format");
+  gcc_jit_function *printf_func =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                 GCC_JIT_FUNCTION_IMPORTED,
+                                 gcc_jit_context_get_type (
+                                    ctxt, GCC_JIT_TYPE_INT),
+                                 "printf",
+                                 1, &param_format,
+                                 1);
+  gcc_jit_rvalue *args[2];
+  args[0] = gcc_jit_context_new_string_literal (ctxt, "hello %s\n");
+  args[1] = gcc_jit_param_as_rvalue (param_name);
+
+  gcc_jit_block *block = gcc_jit_function_new_block (func, NULL);
+
+  gcc_jit_block_add_eval (
+    block, NULL,
+    gcc_jit_context_new_call (ctxt,
+                              NULL,
+                              printf_func,
+                              2, args));
+  gcc_jit_block_end_with_void_return (block, NULL);
+@}
+
+int
+main (int argc, char **argv)
+@{
+  gcc_jit_context *ctxt;
+  gcc_jit_result *result;
+
+  /* Get a "context" object for working with the library.  */
+  ctxt = gcc_jit_context_acquire ();
+  if (!ctxt)
+    @{
+      fprintf (stderr, "NULL ctxt");
+      exit (1);
+    @}
+
+  /* Set some options on the context.
+     Let's see the code being generated, in assembler form.  */
+  gcc_jit_context_set_bool_option (
+    ctxt,
+    GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE,
+    0);
+
+  /* Populate the context.  */
+  create_code (ctxt);
+
+  /* Compile the code.  */
+  result = gcc_jit_context_compile (ctxt);
+  if (!result)
+    @{
+      fprintf (stderr, "NULL result");
+      exit (1);
+    @}
+
+  /* Extract the generated code from "result".  */
+  typedef void (*fn_type) (const char *);
+  fn_type greet =
+    (fn_type)gcc_jit_result_get_code (result, "greet");
+  if (!greet)
+    @{
+      fprintf (stderr, "NULL greet");
+      exit (1);
+    @}
+
+  /* Now call the generated function: */
+  greet ("world");
+  fflush (stdout);
+
+  gcc_jit_context_release (ctxt);
+  gcc_jit_result_release (result);
+  return 0;
+@}
+
+@end example
+
+@noindent
+@end quotation
+
+Copy the above to @cite{tut01-hello-world.c}.
+
+Assuming you have the jit library installed, build the test program
+using:
+
+@example
+$ gcc \
+    tut01-hello-world.c \
+    -o tut01-hello-world \
+    -lgccjit
+@end example
+
+@noindent
+
+You should then be able to run the built program:
+
+@example
+$ ./tut01-hello-world
+hello world
+@end example
+
+@noindent
+
+@c Copyright (C) 2014 Free Software Foundation, Inc.
+@c Originally contributed by David Malcolm <dmalcolm@redhat.com>
+@c 
+@c This is free software: you can redistribute it and/or modify it
+@c under the terms of the GNU General Public License as published by
+@c the Free Software Foundation, either version 3 of the License, or
+@c (at your option) any later version.
+@c 
+@c This program is distributed in the hope that it will be useful, but
+@c WITHOUT ANY WARRANTY; without even the implied warranty of
+@c MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+@c General Public License for more details.
+@c 
+@c You should have received a copy of the GNU General Public License
+@c along with this program.  If not, see
+@c <http://www.gnu.org/licenses/>.
+
+@node Tutorial part 2 Creating a trivial machine code function,Tutorial part 3 Loops and variables,Tutorial part 1 "Hello world",Tutorial
+@anchor{intro/tutorial02 doc}@anchor{6}@anchor{intro/tutorial02 tutorial-part-2-creating-a-trivial-machine-code-function}@anchor{7}
+@section Tutorial part 2: Creating a trivial machine code function
+
+
+Consider this C function:
+
+@example
+int square (int i)
+@{
+  return i * i;
+@}
+@end example
+
+@noindent
+
+How can we construct this at run-time using libgccjit?
+
+First we need to include the relevant header:
+
+@example
+#include <libgccjit.h>
+@end example
+
+@noindent
+
+All state associated with compilation is associated with a
+@pxref{8,,gcc_jit_context *}.
+
+Create one using @pxref{9,,gcc_jit_context_acquire()}:
+
+@example
+gcc_jit_context *ctxt;
+ctxt = gcc_jit_context_acquire ();
+@end example
+
+@noindent
+
+The JIT library has a system of types.  It is statically-typed: every
+expression is of a specific type, fixed at compile-time.  In our example,
+all of the expressions are of the C @cite{int} type, so let's obtain this from
+the context, as a @pxref{a,,gcc_jit_type *}, using
+@pxref{b,,gcc_jit_context_get_type()}:
+
+@example
+gcc_jit_type *int_type =
+  gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+@end example
+
+@noindent
+
+@pxref{a,,gcc_jit_type *} is an example of a "contextual" object: every
+entity in the API is associated with a @pxref{8,,gcc_jit_context *}.
+
+Memory management is easy: all such "contextual" objects are automatically
+cleaned up for you when the context is released, using
+@pxref{c,,gcc_jit_context_release()}:
+
+@example
+gcc_jit_context_release (ctxt);
+@end example
+
+@noindent
+
+so you don't need to manually track and cleanup all objects, just the
+contexts.
+
+Although the API is C-based, there is a form of class hierarchy, which
+looks like this:
+
+@example
++- gcc_jit_object
+    +- gcc_jit_location
+    +- gcc_jit_type
+       +- gcc_jit_struct
+    +- gcc_jit_field
+    +- gcc_jit_function
+    +- gcc_jit_block
+    +- gcc_jit_rvalue
+        +- gcc_jit_lvalue
+           +- gcc_jit_param
+@end example
+
+@noindent
+
+There are casting methods for upcasting from subclasses to parent classes.
+For example, @pxref{d,,gcc_jit_type_as_object()}:
+
+@example
+gcc_jit_object *obj = gcc_jit_type_as_object (int_type);
+@end example
+
+@noindent
+
+One thing you can do with a @pxref{e,,gcc_jit_object *} is
+to ask it for a human-readable description, using
+@pxref{f,,gcc_jit_object_get_debug_string()}:
+
+@example
+printf ("obj: %s\n", gcc_jit_object_get_debug_string (obj));
+@end example
+
+@noindent
+
+giving this text on stdout:
+
+@example
+obj: int
+@end example
+
+@noindent
+
+This is invaluable when debugging.
+
+Let's create the function.  To do so, we first need to construct
+its single parameter, specifying its type and giving it a name,
+using @pxref{10,,gcc_jit_context_new_param()}:
+
+@example
+gcc_jit_param *param_i =
+  gcc_jit_context_new_param (ctxt, NULL, int_type, "i");
+@end example
+
+@noindent
+
+Now we can create the function, using
+@pxref{11,,gcc_jit_context_new_function()}:
+
+@example
+gcc_jit_function *func =
+  gcc_jit_context_new_function (ctxt, NULL,
+                                GCC_JIT_FUNCTION_EXPORTED,
+                                int_type,
+                                "square",
+                                1, &param_i,
+                                0);
+@end example
+
+@noindent
+
+To define the code within the function, we must create basic blocks
+containing statements.
+
+Every basic block contains a list of statements, eventually terminated
+by a statement that either returns, or jumps to another basic block.
+
+Our function has no control-flow, so we just need one basic block:
+
+@example
+gcc_jit_block *block = gcc_jit_function_new_block (func, NULL);
+@end example
+
+@noindent
+
+Our basic block is relatively simple: it immediately terminates by
+returning the value of an expression.
+
+We can build the expression using @pxref{12,,gcc_jit_context_new_binary_op()}:
+
+@example
+gcc_jit_rvalue *expr =
+  gcc_jit_context_new_binary_op (
+    ctxt, NULL,
+    GCC_JIT_BINARY_OP_MULT, int_type,
+    gcc_jit_param_as_rvalue (param_i),
+    gcc_jit_param_as_rvalue (param_i));
+@end example
+
+@noindent
+
+A @pxref{13,,gcc_jit_rvalue *} is another example of a
+@pxref{e,,gcc_jit_object *} subclass.  We can upcast it using
+@pxref{14,,gcc_jit_rvalue_as_object()} and as before print it with
+@pxref{f,,gcc_jit_object_get_debug_string()}.
+
+@example
+printf ("expr: %s\n",
+        gcc_jit_object_get_debug_string (
+          gcc_jit_rvalue_as_object (expr)));
+@end example
+
+@noindent
+
+giving this output:
+
+@example
+expr: i * i
+@end example
+
+@noindent
+
+Creating the expression in itself doesn't do anything; we have to add
+this expression to a statement within the block.  In this case, we use it
+to build a return statement, which terminates the basic block:
+
+@example
+gcc_jit_block_end_with_return (block, NULL, expr);
+@end example
+
+@noindent
+
+OK, we've populated the context.  We can now compile it using
+@pxref{15,,gcc_jit_context_compile()}:
+
+@example
+gcc_jit_result *result;
+result = gcc_jit_context_compile (ctxt);
+@end example
+
+@noindent
+
+and get a @pxref{16,,gcc_jit_result *}.
+
+We can now use @pxref{17,,gcc_jit_result_get_code()} to look up a specific
+machine code routine within the result, in this case, the function we
+created above.
+
+@example
+void *fn_ptr = gcc_jit_result_get_code (result, "square");
+if (!fn_ptr)
+  @{
+    fprintf (stderr, "NULL fn_ptr");
+    goto error;
+  @}
+@end example
+
+@noindent
+
+We can now cast the pointer to an appropriate function pointer type, and
+then call it:
+
+@example
+typedef int (*fn_type) (int);
+fn_type square = (fn_type)fn_ptr;
+printf ("result: %d", square (5));
+@end example
+
+@noindent
+
+@example
+result: 25
+@end example
+
+@noindent
+
+@menu
+* Options:: 
+* Full example:: 
+
+@end menu
+
+@node Options,Full example,,Tutorial part 2 Creating a trivial machine code function
+@anchor{intro/tutorial02 options}@anchor{18}
+@subsection Options
+
+
+To get more information on what's going on, you can set debugging flags
+on the context using @pxref{19,,gcc_jit_context_set_bool_option()}.
+
+@c (I'm deliberately not mentioning
+@c :c:macro:`GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE` here since I think
+@c it's probably more of use to implementors than to users)
+
+Setting @pxref{1a,,GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE} will dump a
+C-like representation to stderr when you compile (GCC's "GIMPLE"
+representation):
+
+@example
+gcc_jit_context_set_bool_option (
+  ctxt,
+  GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE,
+  1);
+result = gcc_jit_context_compile (ctxt);
+@end example
+
+@noindent
+
+@example
+square (signed int i)
+@{
+  signed int D.260;
+
+  entry:
+  D.260 = i * i;
+  return D.260;
+@}
+@end example
+
+@noindent
+
+We can see the generated machine code in assembler form (on stderr) by
+setting @pxref{1b,,GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE} on the context
+before compiling:
+
+@example
+gcc_jit_context_set_bool_option (
+  ctxt,
+  GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE,
+  1);
+result = gcc_jit_context_compile (ctxt);
+@end example
+
+@noindent
+
+@example
+      .file   "fake.c"
+      .text
+      .globl  square
+      .type   square, @@function
+square:
+.LFB6:
+      .cfi_startproc
+      pushq   %rbp
+      .cfi_def_cfa_offset 16
+      .cfi_offset 6, -16
+      movq    %rsp, %rbp
+      .cfi_def_cfa_register 6
+      movl    %edi, -4(%rbp)
+.L14:
+      movl    -4(%rbp), %eax
+      imull   -4(%rbp), %eax
+      popq    %rbp
+      .cfi_def_cfa 7, 8
+      ret
+      .cfi_endproc
+.LFE6:
+      .size   square, .-square
+      .ident  "GCC: (GNU) 4.9.0 20131023 (Red Hat 0.2-0.5.1920c315ff984892399893b380305ab36e07b455.fc20)"
+      .section       .note.GNU-stack,"",@@progbits
+@end example
+
+@noindent
+
+By default, no optimizations are performed, the equivalent of GCC's
+@cite{-O0} option.  We can turn things up to e.g. @cite{-O3} by calling
+@pxref{1c,,gcc_jit_context_set_int_option()} with
+@pxref{1d,,GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL}:
+
+@example
+gcc_jit_context_set_int_option (
+  ctxt,
+  GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL,
+  3);
+@end example
+
+@noindent
+
+@example
+      .file   "fake.c"
+      .text
+      .p2align 4,,15
+      .globl  square
+      .type   square, @@function
+square:
+.LFB7:
+      .cfi_startproc
+.L16:
+      movl    %edi, %eax
+      imull   %edi, %eax
+      ret
+      .cfi_endproc
+.LFE7:
+      .size   square, .-square
+      .ident  "GCC: (GNU) 4.9.0 20131023 (Red Hat 0.2-0.5.1920c315ff984892399893b380305ab36e07b455.fc20)"
+      .section        .note.GNU-stack,"",@@progbits
+@end example
+
+@noindent
+
+Naturally this has only a small effect on such a trivial function.
+
+@node Full example,,Options,Tutorial part 2 Creating a trivial machine code function
+@anchor{intro/tutorial02 full-example}@anchor{1e}
+@subsection Full example
+
+
+Here's what the above looks like as a complete program:
+
+@quotation
+
+@example
+/* Usage example for libgccjit.so
+   Copyright (C) 2014 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include <libgccjit.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+
+void
+create_code (gcc_jit_context *ctxt)
+@{
+  /* Let's try to inject the equivalent of:
+
+      int square (int i)
+      @{
+        return i * i;
+      @}
+  */
+  gcc_jit_type *int_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+  gcc_jit_param *param_i =
+    gcc_jit_context_new_param (ctxt, NULL, int_type, "i");
+  gcc_jit_function *func =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                  GCC_JIT_FUNCTION_EXPORTED,
+                                  int_type,
+                                  "square",
+                                  1, &param_i,
+                                  0);
+
+  gcc_jit_block *block = gcc_jit_function_new_block (func, NULL);
+
+  gcc_jit_rvalue *expr =
+    gcc_jit_context_new_binary_op (
+      ctxt, NULL,
+      GCC_JIT_BINARY_OP_MULT, int_type,
+      gcc_jit_param_as_rvalue (param_i),
+      gcc_jit_param_as_rvalue (param_i));
+
+   gcc_jit_block_end_with_return (block, NULL, expr);
+@}
+
+int
+main (int argc, char **argv)
+@{
+  gcc_jit_context *ctxt = NULL;
+  gcc_jit_result *result = NULL;
+
+  /* Get a "context" object for working with the library.  */
+  ctxt = gcc_jit_context_acquire ();
+  if (!ctxt)
+    @{
+      fprintf (stderr, "NULL ctxt");
+      goto error;
+    @}
+
+  /* Set some options on the context.
+     Let's see the code being generated, in assembler form.  */
+  gcc_jit_context_set_bool_option (
+    ctxt,
+    GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE,
+    0);
+
+  /* Populate the context.  */
+  create_code (ctxt);
+
+  /* Compile the code.  */
+  result = gcc_jit_context_compile (ctxt);
+  if (!result)
+    @{
+      fprintf (stderr, "NULL result");
+      goto error;
+    @}
+
+  /* Extract the generated code from "result".  */
+  void *fn_ptr = gcc_jit_result_get_code (result, "square");
+  if (!fn_ptr)
+     @{
+       fprintf (stderr, "NULL fn_ptr");
+       goto error;
+     @}
+
+  typedef int (*fn_type) (int);
+  fn_type square = (fn_type)fn_ptr;
+  printf ("result: %d", square (5));
+
+ error:
+  gcc_jit_context_release (ctxt);
+  gcc_jit_result_release (result);
+  return 0;
+@}
+
+@end example
+
+@noindent
+@end quotation
+
+Building and running it:
+
+@example
+$ gcc \
+    tut02-square.c \
+    -o tut02-square \
+    -lgccjit
+
+# Run the built program:
+$ ./tut02-square
+result: 25
+@end example
+
+@noindent
+
+@c Copyright (C) 2014 Free Software Foundation, Inc.
+@c Originally contributed by David Malcolm <dmalcolm@redhat.com>
+@c 
+@c This is free software: you can redistribute it and/or modify it
+@c under the terms of the GNU General Public License as published by
+@c the Free Software Foundation, either version 3 of the License, or
+@c (at your option) any later version.
+@c 
+@c This program is distributed in the hope that it will be useful, but
+@c WITHOUT ANY WARRANTY; without even the implied warranty of
+@c MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+@c General Public License for more details.
+@c 
+@c You should have received a copy of the GNU General Public License
+@c along with this program.  If not, see
+@c <http://www.gnu.org/licenses/>.
+
+@node Tutorial part 3 Loops and variables,Tutorial part 4 Adding JIT-compilation to a toy interpreter,Tutorial part 2 Creating a trivial machine code function,Tutorial
+@anchor{intro/tutorial03 tutorial-part-3-loops-and-variables}@anchor{1f}@anchor{intro/tutorial03 doc}@anchor{20}
+@section Tutorial part 3: Loops and variables
+
+
+Consider this C function:
+
+@quotation
+
+@example
+int loop_test (int n)
+@{
+  int sum = 0;
+  for (int i = 0; i < n; i++)
+    sum += i * i;
+  return sum;
+@}
+@end example
+
+@noindent
+@end quotation
+
+This example demonstrates some more features of libgccjit, with local
+variables and a loop.
+
+To break this down into libgccjit terms, it's usually easier to reword
+the @cite{for} loop as a @cite{while} loop, giving:
+
+@quotation
+
+@example
+int loop_test (int n)
+@{
+  int sum = 0;
+  int i = 0;
+  while (i < n)
+  @{
+    sum += i * i;
+    i++;
+  @}
+  return sum;
+@}
+@end example
+
+@noindent
+@end quotation
+
+Here's what the final control flow graph will look like:
+
+@quotation
+
+
+@float Figure
+
+@image{sum-of-squares,,,image of a control flow graph,png}
+
+@end float
+
+@end quotation
+
+As before, we include the libgccjit header and make a
+@pxref{8,,gcc_jit_context *}.
+
+@example
+#include <libgccjit.h>
+
+void test (void)
+@{
+  gcc_jit_context *ctxt;
+  ctxt = gcc_jit_context_acquire ();
+@end example
+
+@noindent
+
+The function works with the C @cite{int} type:
+
+@example
+gcc_jit_type *the_type =
+  gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+gcc_jit_type *return_type = the_type;
+@end example
+
+@noindent
+
+though we could equally well make it work on, say, @cite{double}:
+
+@example
+gcc_jit_type *the_type =
+  gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_DOUBLE);
+@end example
+
+@noindent
+
+Let's build the function:
+
+@example
+gcc_jit_param *n =
+  gcc_jit_context_new_param (ctxt, NULL, the_type, "n");
+gcc_jit_param *params[1] = @{n@};
+gcc_jit_function *func =
+  gcc_jit_context_new_function (ctxt, NULL,
+                                GCC_JIT_FUNCTION_EXPORTED,
+                                return_type,
+                                "loop_test",
+                                1, params, 0);
+@end example
+
+@noindent
+
+@menu
+* Expressions; lvalues and rvalues: Expressions lvalues and rvalues. 
+* Control flow:: 
+* Visualizing the control flow graph:: 
+* Full example: Full example<2>. 
+
+@end menu
+
+@node Expressions lvalues and rvalues,Control flow,,Tutorial part 3 Loops and variables
+@anchor{intro/tutorial03 expressions-lvalues-and-rvalues}@anchor{21}
+@subsection Expressions: lvalues and rvalues
+
+
+The base class of expression is the @pxref{13,,gcc_jit_rvalue *},
+representing an expression that can be on the @emph{right}-hand side of
+an assignment: a value that can be computed somehow, and assigned
+@emph{to} a storage area (such as a variable).  It has a specific
+@pxref{a,,gcc_jit_type *}.
+
+Anothe important class is @pxref{22,,gcc_jit_lvalue *}.
+A @pxref{22,,gcc_jit_lvalue *}. is something that can of the @emph{left}-hand
+side of an assignment: a storage area (such as a variable).
+
+In other words, every assignment can be thought of as:
+
+@example
+LVALUE = RVALUE;
+@end example
+
+@noindent
+
+Note that @pxref{22,,gcc_jit_lvalue *} is a subclass of
+@pxref{13,,gcc_jit_rvalue *}, where in an assignment of the form:
+
+@example
+LVALUE_A = LVALUE_B;
+@end example
+
+@noindent
+
+the @cite{LVALUE_B} implies reading the current value of that storage
+area, assigning it into the @cite{LVALUE_A}.
+
+So far the only expressions we've seen are @cite{i * i}:
+
+@example
+gcc_jit_rvalue *expr =
+  gcc_jit_context_new_binary_op (
+    ctxt, NULL,
+    GCC_JIT_BINARY_OP_MULT, int_type,
+    gcc_jit_param_as_rvalue (param_i),
+    gcc_jit_param_as_rvalue (param_i));
+@end example
+
+@noindent
+
+which is a @pxref{13,,gcc_jit_rvalue *}, and the various function
+parameters: @cite{param_i} and @cite{param_n}, instances of
+@pxref{23,,gcc_jit_param *}, which is a subclass of
+@pxref{22,,gcc_jit_lvalue *} (and, in turn, of @pxref{13,,gcc_jit_rvalue *}):
+we can both read from and write to function parameters within the
+body of a function.
+
+Our new example has a couple of local variables.  We create them by
+calling @pxref{24,,gcc_jit_function_new_local()}, supplying a type and a
+name:
+
+@example
+/* Build locals:  */
+gcc_jit_lvalue *i =
+  gcc_jit_function_new_local (func, NULL, the_type, "i");
+gcc_jit_lvalue *sum =
+  gcc_jit_function_new_local (func, NULL, the_type, "sum");
+@end example
+
+@noindent
+
+These are instances of @pxref{22,,gcc_jit_lvalue *} - they can be read from
+and written to.
+
+Note that there is no precanned way to create @emph{and} initialize a variable
+like in C:
+
+@example
+int i = 0;
+@end example
+
+@noindent
+
+Instead, having added the local to the function, we have to separately add
+an assignment of @cite{0} to @cite{local_i} at the beginning of the function.
+
+@node Control flow,Visualizing the control flow graph,Expressions lvalues and rvalues,Tutorial part 3 Loops and variables
+@anchor{intro/tutorial03 control-flow}@anchor{25}
+@subsection Control flow
+
+
+This function has a loop, so we need to build some basic blocks to
+handle the control flow.  In this case, we need 4 blocks:
+
+
+@enumerate 
+
+@item 
+before the loop (initializing the locals)
+
+@item 
+the conditional at the top of the loop (comparing @cite{i < n})
+
+@item 
+the body of the loop
+
+@item 
+after the loop terminates (@cite{return sum})
+@end enumerate
+
+so we create these as @pxref{26,,gcc_jit_block *} instances within the
+@pxref{27,,gcc_jit_function *}:
+
+@example
+gcc_jit_block *b_initial =
+  gcc_jit_function_new_block (func, "initial");
+gcc_jit_block *b_loop_cond =
+  gcc_jit_function_new_block (func, "loop_cond");
+gcc_jit_block *b_loop_body =
+  gcc_jit_function_new_block (func, "loop_body");
+gcc_jit_block *b_after_loop =
+  gcc_jit_function_new_block (func, "after_loop");
+@end example
+
+@noindent
+
+We now populate each block with statements.
+
+The entry block @cite{b_initial} consists of initializations followed by a jump
+to the conditional.  We assign @cite{0} to @cite{i} and to @cite{sum}, using
+@pxref{28,,gcc_jit_block_add_assignment()} to add
+an assignment statement, and using @pxref{29,,gcc_jit_context_zero()} to get
+the constant value @cite{0} for the relevant type for the right-hand side of
+the assignment:
+
+@example
+/* sum = 0; */
+gcc_jit_block_add_assignment (
+  b_initial, NULL,
+  sum,
+  gcc_jit_context_zero (ctxt, the_type));
+
+/* i = 0; */
+gcc_jit_block_add_assignment (
+  b_initial, NULL,
+  i,
+  gcc_jit_context_zero (ctxt, the_type));
+@end example
+
+@noindent
+
+We can then terminate the entry block by jumping to the conditional:
+
+@example
+gcc_jit_block_end_with_jump (b_initial, NULL, b_loop_cond);
+@end example
+
+@noindent
+
+The conditional block is equivalent to the line @cite{while (i < n)} from our
+C example. It contains a single statement: a conditional, which jumps to
+one of two destination blocks depending on a boolean
+@pxref{13,,gcc_jit_rvalue *}, in this case the comparison of @cite{i} and @cite{n}.
+We build the comparison using @pxref{2a,,gcc_jit_context_new_comparison()}:
+
+@example
+gcc_jit_rvalue *guard =
+  gcc_jit_context_new_comparison (
+    ctxt, NULL,
+    GCC_JIT_COMPARISON_GE,
+    gcc_jit_lvalue_as_rvalue (i),
+    gcc_jit_param_as_rvalue (n));
+@end example
+
+@noindent
+
+and can then use this to add @cite{b_loop_cond}'s sole statement, via
+@pxref{2b,,gcc_jit_block_end_with_conditional()}:
+
+@example
+gcc_jit_block_end_with_conditional (b_loop_cond, NULL, guard);
+@end example
+
+@noindent
+
+Next, we populate the body of the loop.
+
+The C statement @cite{sum += i * i;} is an assignment operation, where an
+lvalue is modified "in-place".  We use
+@pxref{2c,,gcc_jit_block_add_assignment_op()} to handle these operations:
+
+@example
+/* sum += i * i */
+gcc_jit_block_add_assignment_op (
+  b_loop_body, NULL,
+  sum,
+  GCC_JIT_BINARY_OP_PLUS,
+  gcc_jit_context_new_binary_op (
+    ctxt, NULL,
+    GCC_JIT_BINARY_OP_MULT, the_type,
+    gcc_jit_lvalue_as_rvalue (i),
+    gcc_jit_lvalue_as_rvalue (i)));
+@end example
+
+@noindent
+
+The @cite{i++} can be thought of as @cite{i += 1}, and can thus be handled in
+a similar way.  We use @pxref{2d,,gcc_jit_context_one()} to get the constant
+value @cite{1} (for the relevant type) for the right-hand side
+of the assignment.
+
+@example
+/* i++ */
+gcc_jit_block_add_assignment_op (
+  b_loop_body, NULL,
+  i,
+  GCC_JIT_BINARY_OP_PLUS,
+  gcc_jit_context_one (ctxt, the_type));
+@end example
+
+@noindent
+
+@cartouche
+@quotation Note 
+For numeric constants other than 0 or 1, we could use
+@pxref{2e,,gcc_jit_context_new_rvalue_from_int()} and
+@pxref{2f,,gcc_jit_context_new_rvalue_from_double()}.
+@end quotation
+@end cartouche
+
+The loop body completes by jumping back to the conditional:
+
+@example
+gcc_jit_block_end_with_jump (b_loop_body, NULL, b_loop_cond);
+@end example
+
+@noindent
+
+Finally, we populate the @cite{b_after_loop} block, reached when the loop
+conditional is false.  We want to generate the equivalent of:
+
+@example
+return sum;
+@end example
+
+@noindent
+
+so the block is just one statement:
+
+@example
+/* return sum */
+gcc_jit_block_end_with_return (
+  b_after_loop,
+  NULL,
+  gcc_jit_lvalue_as_rvalue (sum));
+@end example
+
+@noindent
+
+@cartouche
+@quotation Note 
+You can intermingle block creation with statement creation,
+but given that the terminator statements generally include references
+to other blocks, I find it's clearer to create all the blocks,
+@emph{then} all the statements.
+@end quotation
+@end cartouche
+
+We've finished populating the function.  As before, we can now compile it
+to machine code:
+
+@example
+gcc_jit_result *result;
+result = gcc_jit_context_compile (ctxt);
+
+typedef int (*loop_test_fn_type) (int);
+loop_test_fn_type loop_test =
+ (loop_test_fn_type)gcc_jit_result_get_code (result, "loop_test");
+if (!loop_test)
+  goto error;
+printf ("result: %d", loop_test (10));
+@end example
+
+@noindent
+
+@example
+result: 285
+@end example
+
+@noindent
+
+@node Visualizing the control flow graph,Full example<2>,Control flow,Tutorial part 3 Loops and variables
+@anchor{intro/tutorial03 visualizing-the-control-flow-graph}@anchor{30}
+@subsection Visualizing the control flow graph
+
+
+You can see the control flow graph of a function using
+@pxref{31,,gcc_jit_function_dump_to_dot()}:
+
+@example
+gcc_jit_function_dump_to_dot (func, "/tmp/sum-of-squares.dot");
+@end example
+
+@noindent
+
+giving a .dot file in GraphViz format.
+
+You can convert this to an image using @cite{dot}:
+
+@example
+$ dot -Tpng /tmp/sum-of-squares.dot -o /tmp/sum-of-squares.png
+@end example
+
+@noindent
+
+or use a viewer (my preferred one is xdot.py; see
+@indicateurl{https://github.com/jrfonseca/xdot.py}; on Fedora you can
+install it with @cite{yum install python-xdot}):
+
+@quotation
+
+
+@float Figure
+
+@image{sum-of-squares,,,image of a control flow graph,png}
+
+@end float
+
+@end quotation
+
+@node Full example<2>,,Visualizing the control flow graph,Tutorial part 3 Loops and variables
+@anchor{intro/tutorial03 full-example}@anchor{32}
+@subsection Full example
+
+
+@quotation
+
+@example
+/* Usage example for libgccjit.so
+   Copyright (C) 2014 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include <libgccjit.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+
+void
+create_code (gcc_jit_context *ctxt)
+@{
+  /*
+    Simple sum-of-squares, to test conditionals and looping
+
+    int loop_test (int n)
+    @{
+      int i;
+      int sum = 0;
+      for (i = 0; i < n ; i ++)
+      @{
+       sum += i * i;
+      @}
+      return sum;
+   */
+  gcc_jit_type *the_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+  gcc_jit_type *return_type = the_type;
+
+  gcc_jit_param *n =
+    gcc_jit_context_new_param (ctxt, NULL, the_type, "n");
+  gcc_jit_param *params[1] = @{n@};
+  gcc_jit_function *func =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                 GCC_JIT_FUNCTION_EXPORTED,
+                                 return_type,
+                                 "loop_test",
+                                 1, params, 0);
+
+  /* Build locals:  */
+  gcc_jit_lvalue *i =
+    gcc_jit_function_new_local (func, NULL, the_type, "i");
+  gcc_jit_lvalue *sum =
+    gcc_jit_function_new_local (func, NULL, the_type, "sum");
+
+  gcc_jit_block *b_initial =
+    gcc_jit_function_new_block (func, "initial");
+  gcc_jit_block *b_loop_cond =
+    gcc_jit_function_new_block (func, "loop_cond");
+  gcc_jit_block *b_loop_body =
+    gcc_jit_function_new_block (func, "loop_body");
+  gcc_jit_block *b_after_loop =
+    gcc_jit_function_new_block (func, "after_loop");
+
+  /* sum = 0; */
+  gcc_jit_block_add_assignment (
+    b_initial, NULL,
+    sum,
+    gcc_jit_context_zero (ctxt, the_type));
+
+  /* i = 0; */
+  gcc_jit_block_add_assignment (
+    b_initial, NULL,
+    i,
+    gcc_jit_context_zero (ctxt, the_type));
+
+  gcc_jit_block_end_with_jump (b_initial, NULL, b_loop_cond);
+
+  /* if (i >= n) */
+  gcc_jit_block_end_with_conditional (
+    b_loop_cond, NULL,
+    gcc_jit_context_new_comparison (
+       ctxt, NULL,
+       GCC_JIT_COMPARISON_GE,
+       gcc_jit_lvalue_as_rvalue (i),
+       gcc_jit_param_as_rvalue (n)),
+    b_after_loop,
+    b_loop_body);
+
+  /* sum += i * i */
+  gcc_jit_block_add_assignment_op (
+    b_loop_body, NULL,
+    sum,
+    GCC_JIT_BINARY_OP_PLUS,
+    gcc_jit_context_new_binary_op (
+      ctxt, NULL,
+      GCC_JIT_BINARY_OP_MULT, the_type,
+      gcc_jit_lvalue_as_rvalue (i),
+      gcc_jit_lvalue_as_rvalue (i)));
+
+  /* i++ */
+  gcc_jit_block_add_assignment_op (
+    b_loop_body, NULL,
+    i,
+    GCC_JIT_BINARY_OP_PLUS,
+    gcc_jit_context_one (ctxt, the_type));
+
+  gcc_jit_block_end_with_jump (b_loop_body, NULL, b_loop_cond);
+
+  /* return sum */
+  gcc_jit_block_end_with_return (
+    b_after_loop,
+    NULL,
+    gcc_jit_lvalue_as_rvalue (sum));
+@}
+
+int
+main (int argc, char **argv)
+@{
+  gcc_jit_context *ctxt = NULL;
+  gcc_jit_result *result = NULL;
+
+  /* Get a "context" object for working with the library.  */
+  ctxt = gcc_jit_context_acquire ();
+  if (!ctxt)
+    @{
+      fprintf (stderr, "NULL ctxt");
+      goto error;
+    @}
+
+  /* Set some options on the context.
+     Let's see the code being generated, in assembler form.  */
+  gcc_jit_context_set_bool_option (
+    ctxt,
+    GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE,
+    0);
+
+  /* Populate the context.  */
+  create_code (ctxt);
+
+  /* Compile the code.  */
+  result = gcc_jit_context_compile (ctxt);
+  if (!result)
+    @{
+      fprintf (stderr, "NULL result");
+      goto error;
+    @}
+
+  /* Extract the generated code from "result".  */
+  typedef int (*loop_test_fn_type) (int);
+  loop_test_fn_type loop_test =
+    (loop_test_fn_type)gcc_jit_result_get_code (result, "loop_test");
+  if (!loop_test)
+    @{
+      fprintf (stderr, "NULL loop_test");
+      goto error;
+    @}
+
+  /* Run the generated code.  */
+  int val = loop_test (10);
+  printf("loop_test returned: %d\n", val);
+
+ error:
+  gcc_jit_context_release (ctxt);
+  gcc_jit_result_release (result);
+  return 0;
+@}
+
+@end example
+
+@noindent
+@end quotation
+
+Building and running it:
+
+@example
+$ gcc \
+    tut03-sum-of-squares.c \
+    -o tut03-sum-of-squares \
+    -lgccjit
+
+# Run the built program:
+$ ./tut03-sum-of-squares
+loop_test returned: 285
+@end example
+
+@noindent
+
+@c Copyright (C) 2014 Free Software Foundation, Inc.
+@c Originally contributed by David Malcolm <dmalcolm@redhat.com>
+@c 
+@c This is free software: you can redistribute it and/or modify it
+@c under the terms of the GNU General Public License as published by
+@c the Free Software Foundation, either version 3 of the License, or
+@c (at your option) any later version.
+@c 
+@c This program is distributed in the hope that it will be useful, but
+@c WITHOUT ANY WARRANTY; without even the implied warranty of
+@c MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+@c General Public License for more details.
+@c 
+@c You should have received a copy of the GNU General Public License
+@c along with this program.  If not, see
+@c <http://www.gnu.org/licenses/>.
+
+@node Tutorial part 4 Adding JIT-compilation to a toy interpreter,,Tutorial part 3 Loops and variables,Tutorial
+@anchor{intro/tutorial04 tutorial-part-4-adding-jit-compilation-to-a-toy-interpreter}@anchor{33}@anchor{intro/tutorial04 doc}@anchor{34}
+@section Tutorial part 4: Adding JIT-compilation to a toy interpreter
+
+
+In this example we construct a "toy" interpreter, and add JIT-compilation
+to it.
+
+@menu
+* Our toy interpreter:: 
+* Compiling to machine code:: 
+* Setting things up:: 
+* Populating the function:: 
+* Verifying the control flow graph:: 
+* Compiling the context:: 
+* Single-stepping through the generated code:: 
+* Examining the generated code:: 
+* Putting it all together:: 
+* Behind the curtain; How does our code get optimized?: Behind the curtain How does our code get optimized?. 
+
+@end menu
+
+@node Our toy interpreter,Compiling to machine code,,Tutorial part 4 Adding JIT-compilation to a toy interpreter
+@anchor{intro/tutorial04 our-toy-interpreter}@anchor{35}
+@subsection Our toy interpreter
+
+
+It's a stack-based interpreter, and is intended as a (very simple) example
+of the kind of bytecode interpreter seen in dynamic languages such as
+Python, Ruby etc.
+
+For the sake of simplicity, our toy virtual machine is very limited:
+
+@quotation
+
+
+@itemize *
+
+@item 
+The only data type is @cite{int}
+
+@item 
+It can only work on one function at a time (so that the only
+function call that can be made is to recurse).
+
+@item 
+Functions can only take one parameter.
+
+@item 
+Functions have a stack of @cite{int} values.
+
+@item 
+We'll implement function call within the interpreter by calling a
+function in our implementation, rather than implementing our own
+frame stack.
+
+@item 
+The parser is only good enough to get the examples to work.
+@end itemize
+@end quotation
+
+Naturally, a real interpreter would be much more complicated that this.
+
+The following operations are supported:
+
+
+@multitable {xxxxxxxxxxxxxxxxxxxxxxxx} {xxxxxxxxxxxxxxxxxxxxxxxxxx} {xxxxxxxxxxxxxxxxx} {xxxxxxxxxxxxxxxxxx} 
+@headitem
+
+Operation
+
+@tab
+
+Meaning
+
+@tab
+
+Old Stack
+
+@tab
+
+New Stack
+
+@item
+
+DUP
+
+@tab
+
+Duplicate top of stack.
+
+@tab
+
+@code{[..., x]}
+
+@tab
+
+@code{[..., x, x]}
+
+@item
+
+ROT
+
+@tab
+
+Swap top two elements
+of stack.
+
+@tab
+
+@code{[..., x, y]}
+
+@tab
+
+@code{[..., y, x]}
+
+@item
+
+BINARY_ADD
+
+@tab
+
+Add the top two elements
+on the stack.
+
+@tab
+
+@code{[..., x, y]}
+
+@tab
+
+@code{[..., (x+y)]}
+
+@item
+
+BINARY_SUBTRACT
+
+@tab
+
+Likewise, but subtract.
+
+@tab
+
+@code{[..., x, y]}
+
+@tab
+
+@code{[..., (x-y)]}
+
+@item
+
+BINARY_MULT
+
+@tab
+
+Likewise, but multiply.
+
+@tab
+
+@code{[..., x, y]}
+
+@tab
+
+@code{[..., (x*y)]}
+
+@item
+
+BINARY_COMPARE_LT
+
+@tab
+
+Compare the top two
+elements on the stack
+and push a nonzero/zero
+if (x<y).
+
+@tab
+
+@code{[..., x, y]}
+
+@tab
+
+@code{[..., (x<y)]}
+
+@item
+
+RECURSE
+
+@tab
+
+Recurse, passing the top
+of the stack, and
+popping the result.
+
+@tab
+
+@code{[..., x]}
+
+@tab
+
+@code{[..., fn(x)]}
+
+@item
+
+RETURN
+
+@tab
+
+Return the top of the
+stack.
+
+@tab
+
+@code{[x]}
+
+@tab
+
+@code{[]}
+
+@item
+
+PUSH_CONST @cite{arg}
+
+@tab
+
+Push an int const.
+
+@tab
+
+@code{[...]}
+
+@tab
+
+@code{[..., arg]}
+
+@item
+
+JUMP_ABS_IF_TRUE @cite{arg}
+
+@tab
+
+Pop; if top of stack was
+nonzero, jump to
+@code{arg}.
+
+@tab
+
+@code{[..., x]}
+
+@tab
+
+@code{[...]}
+
+@end multitable
+
+
+Programs can be interpreted, disassembled, and compiled to machine code.
+
+The interpreter reads @code{.toy} scripts.  Here's what a simple recursive
+factorial program looks like, the script @code{factorial.toy}.
+The parser ignores lines beginning with a @cite{#}.
+
+@quotation
+
+@example
+# Simple recursive factorial implementation, roughly equivalent to:
+#
+#  int factorial (int arg)
+#  @{
+#     if (arg < 2)
+#       return arg
+#     return arg * factorial (arg - 1)
+#  @}
+
+# Initial state:
+# stack: [arg]
+
+# 0:
+DUP
+# stack: [arg, arg]
+
+# 1:
+PUSH_CONST 2
+# stack: [arg, arg, 2]
+
+# 2:
+BINARY_COMPARE_LT
+# stack: [arg, (arg < 2)]
+
+# 3:
+JUMP_ABS_IF_TRUE 9
+# stack: [arg]
+
+# 4:
+DUP
+# stack: [arg, arg]
+
+# 5:
+PUSH_CONST 1
+# stack: [arg, arg, 1]
+
+# 6:
+BINARY_SUBTRACT
+# stack: [arg,  (arg - 1)
+
+# 7:
+RECURSE
+# stack: [arg, factorial(arg - 1)]
+
+# 8:
+BINARY_MULT
+# stack: [arg * factorial(arg - 1)]
+
+# 9:
+RETURN
+
+@end example
+
+@noindent
+@end quotation
+
+The interpreter is a simple infinite loop with a big @code{switch} statement
+based on what the next opcode is:
+
+@quotation
+
+@example
+
+static int
+toyvm_function_interpret (toyvm_function *fn, int arg, FILE *trace)
+@{
+  toyvm_frame frame;
+#define PUSH(ARG) (toyvm_frame_push (&frame, (ARG)))
+#define POP(ARG) (toyvm_frame_pop (&frame))
+
+  frame.frm_function = fn;
+  frame.frm_pc = 0;
+  frame.frm_cur_depth = 0;
+
+  PUSH (arg);
+
+  while (1)
+    @{
+      toyvm_op *op;
+      int x, y;
+      assert (frame.frm_pc < fn->fn_num_ops);
+      op = &fn->fn_ops[frame.frm_pc++];
+
+      if (trace)
+       @{
+         toyvm_frame_dump_stack (&frame, trace);
+         toyvm_function_disassemble_op (fn, op, frame.frm_pc, trace);
+       @}
+
+      switch (op->op_opcode)
+       @{
+         /* Ops taking no operand.  */
+       case DUP:
+         x = POP ();
+         PUSH (x);
+         PUSH (x);
+         break;
+
+       case ROT:
+         y = POP ();
+         x = POP ();
+         PUSH (y);
+         PUSH (x);
+         break;
+
+       case BINARY_ADD:
+         y = POP ();
+         x = POP ();
+         PUSH (x + y);
+         break;
+
+       case BINARY_SUBTRACT:
+         y = POP ();
+         x = POP ();
+         PUSH (x - y);
+         break;
+
+       case BINARY_MULT:
+         y = POP ();
+         x = POP ();
+         PUSH (x * y);
+         break;
+
+       case BINARY_COMPARE_LT:
+         y = POP ();
+         x = POP ();
+         PUSH (x < y);
+         break;
+
+       case RECURSE:
+         x = POP ();
+         x = toyvm_function_interpret (fn, x, trace);
+         PUSH (x);
+         break;
+
+       case RETURN:
+         return POP ();
+
+         /* Ops taking an operand.  */
+       case PUSH_CONST:
+         PUSH (op->op_operand);
+         break;
+
+       case JUMP_ABS_IF_TRUE:
+         x = POP ();
+         if (x)
+           frame.frm_pc = op->op_operand;
+         break;
+
+       default:
+         assert (0); /* unknown opcode */
+
+       @} /* end of switch on opcode */
+    @} /* end of while loop */
+
+#undef PUSH
+#undef POP
+@}
+
+
+@end example
+
+@noindent
+@end quotation
+
+@node Compiling to machine code,Setting things up,Our toy interpreter,Tutorial part 4 Adding JIT-compilation to a toy interpreter
+@anchor{intro/tutorial04 compiling-to-machine-code}@anchor{36}
+@subsection Compiling to machine code
+
+
+We want to generate machine code that can be cast to this type and
+then directly executed in-process:
+
+@quotation
+
+@example
+typedef int (*toyvm_compiled_func) (int);
+
+
+@end example
+
+@noindent
+@end quotation
+
+Our compiler isn't very sophisticated; it takes the implementation of
+each opcode above, and maps it directly to the operations supported by
+the libgccjit API.
+
+How should we handle the stack?  In theory we could calculate what the
+stack depth will be at each opcode, and optimize away the stack
+manipulation "by hand".  We'll see below that libgccjit is able to do
+this for us, so we'll implement stack manipulation
+in a direct way, by creating a @code{stack} array and @code{stack_depth}
+variables, local within the generated function, equivalent to this C code:
+
+@example
+int stack_depth;
+int stack[MAX_STACK_DEPTH];
+@end example
+
+@noindent
+
+We'll also have local variables @code{x} and @code{y} for use when implementing
+the opcodes, equivalent to this:
+
+@example
+int x;
+int y;
+@end example
+
+@noindent
+
+This means our compiler has the following state:
+
+@quotation
+
+@example
+
+struct compilation_state
+@{
+  gcc_jit_context *ctxt;
+
+  gcc_jit_type *int_type;
+  gcc_jit_type *bool_type;
+  gcc_jit_type *stack_type; /* int[MAX_STACK_DEPTH] */
+
+  gcc_jit_rvalue *const_one;
+
+  gcc_jit_function *fn;
+  gcc_jit_param *param_arg;
+  gcc_jit_lvalue *stack;
+  gcc_jit_lvalue *stack_depth;
+  gcc_jit_lvalue *x;
+  gcc_jit_lvalue *y;
+
+  gcc_jit_location *op_locs[MAX_OPS];
+  gcc_jit_block *initial_block;
+  gcc_jit_block *op_blocks[MAX_OPS];
+
+@};
+
+
+@end example
+
+@noindent
+@end quotation
+
+@node Setting things up,Populating the function,Compiling to machine code,Tutorial part 4 Adding JIT-compilation to a toy interpreter
+@anchor{intro/tutorial04 setting-things-up}@anchor{37}
+@subsection Setting things up
+
+
+First we create our types:
+
+@quotation
+
+@example
+  state.int_type =
+    gcc_jit_context_get_type (state.ctxt, GCC_JIT_TYPE_INT);
+  state.bool_type =
+    gcc_jit_context_get_type (state.ctxt, GCC_JIT_TYPE_BOOL);
+  state.stack_type =
+    gcc_jit_context_new_array_type (state.ctxt, NULL,
+                                   state.int_type, MAX_STACK_DEPTH);
+
+
+@end example
+
+@noindent
+@end quotation
+
+along with extracting a useful @cite{int} constant:
+
+@quotation
+
+@example
+  state.const_one = gcc_jit_context_one (state.ctxt, state.int_type);
+
+
+@end example
+
+@noindent
+@end quotation
+
+We'll implement push and pop in terms of the @code{stack} array and
+@code{stack_depth}.  Here are helper functions for adding statements to
+a block, implementing pushing and popping values:
+
+@quotation
+
+@example
+
+static void
+add_push (compilation_state *state,
+         gcc_jit_block *block,
+         gcc_jit_rvalue *rvalue,
+         gcc_jit_location *loc)
+@{
+  /* stack[stack_depth] = RVALUE */
+  gcc_jit_block_add_assignment (
+    block,
+    loc,
+    /* stack[stack_depth] */
+    gcc_jit_context_new_array_access (
+      state->ctxt,
+      loc,
+      gcc_jit_lvalue_as_rvalue (state->stack),
+      gcc_jit_lvalue_as_rvalue (state->stack_depth)),
+    rvalue);
+
+  /* "stack_depth++;".  */
+  gcc_jit_block_add_assignment_op (
+    block,
+    loc,
+    state->stack_depth,
+    GCC_JIT_BINARY_OP_PLUS,
+    state->const_one);
+@}
+
+static void
+add_pop (compilation_state *state,
+        gcc_jit_block *block,
+        gcc_jit_lvalue *lvalue,
+        gcc_jit_location *loc)
+@{
+  /* "--stack_depth;".  */
+  gcc_jit_block_add_assignment_op (
+    block,
+    loc,
+    state->stack_depth,
+    GCC_JIT_BINARY_OP_MINUS,
+    state->const_one);
+
+  /* "LVALUE = stack[stack_depth];".  */
+  gcc_jit_block_add_assignment (
+    block,
+    loc,
+    lvalue,
+    /* stack[stack_depth] */
+    gcc_jit_lvalue_as_rvalue (
+      gcc_jit_context_new_array_access (
+       state->ctxt,
+       loc,
+       gcc_jit_lvalue_as_rvalue (state->stack),
+       gcc_jit_lvalue_as_rvalue (state->stack_depth))));
+@}
+
+
+@end example
+
+@noindent
+@end quotation
+
+We will support single-stepping through the generated code in the
+debugger, so we need to create @pxref{38,,gcc_jit_location} instances, one
+per operation in the source code.  These will reference the lines of
+e.g. @code{factorial.toy}.
+
+@quotation
+
+@example
+  for (pc = 0; pc < fn->fn_num_ops; pc++)
+    @{
+      toyvm_op *op = &fn->fn_ops[pc];
+
+      state.op_locs[pc] = gcc_jit_context_new_location (state.ctxt,
+                                                       fn->fn_filename,
+                                                       op->op_linenum,
+                                                       0); /* column */
+    @}
+
+
+@end example
+
+@noindent
+@end quotation
+
+Let's create the function itself.  As usual, we create its parameter
+first, then use the parameter to create the function:
+
+@quotation
+
+@example
+  state.param_arg =
+    gcc_jit_context_new_param (state.ctxt, state.op_locs[0],
+                              state.int_type, "arg");
+  state.fn =
+    gcc_jit_context_new_function (state.ctxt,
+                                 state.op_locs[0],
+                                 GCC_JIT_FUNCTION_EXPORTED,
+                                 state.int_type,
+                                 funcname,
+                                 1, &state.param_arg, 0);
+
+
+@end example
+
+@noindent
+@end quotation
+
+We create the locals within the function.
+
+@quotation
+
+@example
+  state.stack =
+    gcc_jit_function_new_local (state.fn, NULL,
+                               state.stack_type, "stack");
+  state.stack_depth =
+    gcc_jit_function_new_local (state.fn, NULL,
+                               state.int_type, "stack_depth");
+  state.x =
+    gcc_jit_function_new_local (state.fn, NULL,
+                               state.int_type, "x");
+  state.y =
+    gcc_jit_function_new_local (state.fn, NULL,
+                               state.int_type, "y");
+
+
+@end example
+
+@noindent
+@end quotation
+
+@node Populating the function,Verifying the control flow graph,Setting things up,Tutorial part 4 Adding JIT-compilation to a toy interpreter
+@anchor{intro/tutorial04 populating-the-function}@anchor{39}
+@subsection Populating the function
+
+
+There's some one-time initialization, and the API treats the first block
+you create as the entrypoint of the function, so we need to create that
+block first:
+
+@quotation
+
+@example
+  state.initial_block = gcc_jit_function_new_block (state.fn, "initial");
+
+
+@end example
+
+@noindent
+@end quotation
+
+We can now create blocks for each of the operations.  Most of these will
+be consolidated into larger blocks when the optimizer runs.
+
+@quotation
+
+@example
+  for (pc = 0; pc < fn->fn_num_ops; pc++)
+    @{
+      char buf[16];
+      sprintf (buf, "instr%i", pc);
+      state.op_blocks[pc] = gcc_jit_function_new_block (state.fn, buf);
+    @}
+
+
+@end example
+
+@noindent
+@end quotation
+
+Now that we have a block it can jump to when it's done, we can populate
+the initial block:
+
+@quotation
+
+@example
+
+  /* "stack_depth = 0;".  */
+  gcc_jit_block_add_assignment (
+    state.initial_block,
+    state.op_locs[0],
+    state.stack_depth,
+    gcc_jit_context_zero (state.ctxt, state.int_type));
+
+  /* "PUSH (arg);".  */
+  add_push (&state,
+           state.initial_block,
+           gcc_jit_param_as_rvalue (state.param_arg),
+           state.op_locs[0]);
+
+  /* ...and jump to insn 0.  */
+  gcc_jit_block_end_with_jump (state.initial_block,
+                              state.op_locs[0],
+                              state.op_blocks[0]);
+
+
+@end example
+
+@noindent
+@end quotation
+
+We can now populate the blocks for the individual operations.  We loop
+through them, adding instructions to their blocks:
+
+@quotation
+
+@example
+  for (pc = 0; pc < fn->fn_num_ops; pc++)
+    @{
+      gcc_jit_location *loc = state.op_locs[pc];
+
+      gcc_jit_block *block = state.op_blocks[pc];
+      gcc_jit_block *next_block = (pc < fn->fn_num_ops
+                                  ? state.op_blocks[pc + 1]
+                                  : NULL);
+
+      toyvm_op *op;
+      op = &fn->fn_ops[pc];
+
+
+@end example
+
+@noindent
+@end quotation
+
+We're going to have another big @code{switch} statement for implementing
+the opcodes, this time for compiling them, rather than interpreting
+them.  It's helpful to have macros for implementing push and pop, so that
+we can make the @code{switch} statement that's coming up look as much as
+possible like the one above within the interpreter:
+
+@example
+
+#define X_EQUALS_POP()\
+      add_pop (&state, block, state.x, loc)
+#define Y_EQUALS_POP()\
+      add_pop (&state, block, state.y, loc)
+#define PUSH_RVALUE(RVALUE)\
+      add_push (&state, block, (RVALUE), loc)
+#define PUSH_X()\
+      PUSH_RVALUE (gcc_jit_lvalue_as_rvalue (state.x))
+#define PUSH_Y() \
+      PUSH_RVALUE (gcc_jit_lvalue_as_rvalue (state.y))
+
+
+@end example
+
+@noindent
+
+@cartouche
+@quotation Note 
+A particularly clever implementation would have an @emph{identical}
+@code{switch} statement shared by the interpreter and the compiler, with
+some preprocessor "magic".  We're not doing that here, for the sake
+of simplicity.
+@end quotation
+@end cartouche
+
+When I first implemented this compiler, I accidentally missed an edit
+when copying and pasting the @code{Y_EQUALS_POP} macro, so that popping the
+stack into @code{y} instead erroneously assigned it to @code{x}, leaving @code{y}
+uninitialized.
+
+To track this kind of thing down, we can use
+@pxref{3a,,gcc_jit_block_add_comment()} to add descriptive comments
+to the internal representation.  This is invaluable when looking through
+the generated IR for, say @code{factorial}:
+
+@quotation
+
+@example
+
+      gcc_jit_block_add_comment (block, loc, opcode_names[op->op_opcode]);
+
+
+@end example
+
+@noindent
+@end quotation
+
+We can now write the big @code{switch} statement that implements the
+individual opcodes, populating the relevant block with statements:
+
+@quotation
+
+@example
+
+      switch (op->op_opcode)
+       @{
+       case DUP:
+         X_EQUALS_POP ();
+         PUSH_X ();
+         PUSH_X ();
+         break;
+
+       case ROT:
+         Y_EQUALS_POP ();
+         X_EQUALS_POP ();
+         PUSH_Y ();
+         PUSH_X ();
+         break;
+
+       case BINARY_ADD:
+         Y_EQUALS_POP ();
+         X_EQUALS_POP ();
+         PUSH_RVALUE (
+          gcc_jit_context_new_binary_op (
+            state.ctxt,
+            loc,
+            GCC_JIT_BINARY_OP_PLUS,
+            state.int_type,
+            gcc_jit_lvalue_as_rvalue (state.x),
+            gcc_jit_lvalue_as_rvalue (state.y)));
+         break;
+
+       case BINARY_SUBTRACT:
+         Y_EQUALS_POP ();
+         X_EQUALS_POP ();
+         PUSH_RVALUE (
+          gcc_jit_context_new_binary_op (
+            state.ctxt,
+            loc,
+            GCC_JIT_BINARY_OP_MINUS,
+            state.int_type,
+            gcc_jit_lvalue_as_rvalue (state.x),
+            gcc_jit_lvalue_as_rvalue (state.y)));
+         break;
+
+       case BINARY_MULT:
+         Y_EQUALS_POP ();
+         X_EQUALS_POP ();
+         PUSH_RVALUE (
+          gcc_jit_context_new_binary_op (
+            state.ctxt,
+            loc,
+            GCC_JIT_BINARY_OP_MULT,
+            state.int_type,
+            gcc_jit_lvalue_as_rvalue (state.x),
+            gcc_jit_lvalue_as_rvalue (state.y)));
+         break;
+
+       case BINARY_COMPARE_LT:
+         Y_EQUALS_POP ();
+         X_EQUALS_POP ();
+         PUSH_RVALUE (
+            /* cast of bool to int */
+            gcc_jit_context_new_cast (
+              state.ctxt,
+              loc,
+              /* (x < y) as a bool */
+              gcc_jit_context_new_comparison (
+                state.ctxt,
+                loc,
+                GCC_JIT_COMPARISON_LT,
+                gcc_jit_lvalue_as_rvalue (state.x),
+                gcc_jit_lvalue_as_rvalue (state.y)),
+              state.int_type));
+         break;
+
+       case RECURSE:
+         @{
+           X_EQUALS_POP ();
+           gcc_jit_rvalue *arg = gcc_jit_lvalue_as_rvalue (state.x);
+           PUSH_RVALUE (
+             gcc_jit_context_new_call (
+               state.ctxt,
+               loc,
+               state.fn,
+               1, &arg));
+           break;
+         @}
+
+       case RETURN:
+         X_EQUALS_POP ();
+         gcc_jit_block_end_with_return (
+           block,
+           loc,
+           gcc_jit_lvalue_as_rvalue (state.x));
+         break;
+
+         /* Ops taking an operand.  */
+       case PUSH_CONST:
+         PUSH_RVALUE (
+           gcc_jit_context_new_rvalue_from_int (
+             state.ctxt,
+             state.int_type,
+             op->op_operand));
+         break;
+
+       case JUMP_ABS_IF_TRUE:
+         X_EQUALS_POP ();
+         gcc_jit_block_end_with_conditional (
+           block,
+           loc,
+           /* "(bool)x".  */
+           gcc_jit_context_new_cast (
+             state.ctxt,
+             loc,
+             gcc_jit_lvalue_as_rvalue (state.x),
+             state.bool_type),
+           state.op_blocks[op->op_operand], /* on_true */
+           next_block); /* on_false */
+         break;
+
+       default:
+         assert(0);
+       @} /* end of switch on opcode */
+
+
+@end example
+
+@noindent
+@end quotation
+
+Every block must be terminated, via a call to one of the
+@code{gcc_jit_block_end_with_} entrypoints.  This has been done for two
+of the opcodes, but we need to do it for the other ones, by jumping
+to the next block.
+
+@quotation
+
+@example
+      if (op->op_opcode != JUMP_ABS_IF_TRUE
+         && op->op_opcode != RETURN)
+       gcc_jit_block_end_with_jump (
+         block,
+         loc,
+         next_block);
+
+
+@end example
+
+@noindent
+@end quotation
+
+This is analogous to simply incrementing the program counter.
+
+@node Verifying the control flow graph,Compiling the context,Populating the function,Tutorial part 4 Adding JIT-compilation to a toy interpreter
+@anchor{intro/tutorial04 verifying-the-control-flow-graph}@anchor{3b}
+@subsection Verifying the control flow graph
+
+
+Having finished looping over the blocks, the context is complete.
+
+As before, we can verify that the control flow and statements are sane by
+using @pxref{31,,gcc_jit_function_dump_to_dot()}:
+
+@example
+gcc_jit_function_dump_to_dot (state.fn, "/tmp/factorial.dot");
+@end example
+
+@noindent
+
+and viewing the result.  Note how the label names, comments, and
+variable names show up in the dump, to make it easier to spot
+errors in our compiler.
+
+@quotation
+
+
+@float Figure
+
+@image{factorial,,,image of a control flow graph,png}
+
+@end float
+
+@end quotation
+
+@node Compiling the context,Single-stepping through the generated code,Verifying the control flow graph,Tutorial part 4 Adding JIT-compilation to a toy interpreter
+@anchor{intro/tutorial04 compiling-the-context}@anchor{3c}
+@subsection Compiling the context
+
+
+Having finished looping over the blocks and populating them with
+statements, the context is complete.
+
+We can now compile it, and extract machine code from the result:
+
+@quotation
+
+@example
+  gcc_jit_result *result = gcc_jit_context_compile (state.ctxt);
+  gcc_jit_context_release (state.ctxt);
+
+  return (toyvm_compiled_func)gcc_jit_result_get_code (result,
+                                                      funcname);
+
+@end example
+
+@noindent
+@end quotation
+
+We can now run the result:
+
+@quotation
+
+@example
+  toyvm_compiled_func code = toyvm_function_compile (fn);
+  printf ("compiler result: %d\n",
+         code (atoi (argv[2])));
+
+
+@end example
+
+@noindent
+@end quotation
+
+@node Single-stepping through the generated code,Examining the generated code,Compiling the context,Tutorial part 4 Adding JIT-compilation to a toy interpreter
+@anchor{intro/tutorial04 single-stepping-through-the-generated-code}@anchor{3d}
+@subsection Single-stepping through the generated code
+
+
+It's possible to debug the generated code.  To do this we need to both:
+
+@quotation
+
+
+@itemize *
+
+@item 
+Set up source code locations for our statements, so that we can
+meaningfully step through the code.  We did this above by
+calling @pxref{3e,,gcc_jit_context_new_location()} and using the
+results.
+
+@item 
+Enable the generation of debugging information, by setting
+@pxref{3f,,GCC_JIT_BOOL_OPTION_DEBUGINFO} on the
+@pxref{8,,gcc_jit_context} via
+@pxref{19,,gcc_jit_context_set_bool_option()}:
+
+@example
+gcc_jit_context_set_bool_option (
+  ctxt,
+  GCC_JIT_BOOL_OPTION_DEBUGINFO,
+  1);
+@end example
+
+@noindent
+@end itemize
+@end quotation
+
+Having done this, we can put a breakpoint on the generated function:
+
+@example
+$ gdb --args ./toyvm factorial.toy 10
+(gdb) break factorial
+Function "factorial" not defined.
+Make breakpoint pending on future shared library load? (y or [n]) y
+Breakpoint 1 (factorial) pending.
+(gdb) run
+Breakpoint 1, factorial (arg=10) at factorial.toy:14
+14    DUP
+@end example
+
+@noindent
+
+We've set up location information, which references @code{factorial.toy}.
+This allows us to use e.g. @code{list} to see where we are in the script:
+
+@example
+(gdb) list
+9
+10    # Initial state:
+11    # stack: [arg]
+12
+13    # 0:
+14    DUP
+15    # stack: [arg, arg]
+16
+17    # 1:
+18    PUSH_CONST 2
+@end example
+
+@noindent
+
+and to step through the function, examining the data:
+
+@example
+(gdb) n
+18    PUSH_CONST 2
+(gdb) n
+22    BINARY_COMPARE_LT
+(gdb) print stack
+$5 = @{10, 10, 2, 0, -7152, 32767, 0, 0@}
+(gdb) print stack_depth
+$6 = 3
+@end example
+
+@noindent
+
+You'll see that the parts of the @code{stack} array that haven't been
+touched yet are uninitialized.
+
+@cartouche
+@quotation Note 
+Turning on optimizations may lead to unpredictable results when
+stepping through the generated code: the execution may appear to
+"jump around" the source code.  This is analogous to turning up the
+optimization level in a regular compiler.
+@end quotation
+@end cartouche
+
+@node Examining the generated code,Putting it all together,Single-stepping through the generated code,Tutorial part 4 Adding JIT-compilation to a toy interpreter
+@anchor{intro/tutorial04 examining-the-generated-code}@anchor{40}
+@subsection Examining the generated code
+
+
+How good is the optimized code?
+
+We can turn up optimizations, by calling
+@pxref{1c,,gcc_jit_context_set_int_option()} with
+@pxref{1d,,GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL}:
+
+@example
+gcc_jit_context_set_int_option (
+  ctxt,
+  GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL,
+  3);
+@end example
+
+@noindent
+
+One of GCC's internal representations is called "gimple".  A dump of the
+initial gimple representation of the code can be seen by setting:
+
+@example
+gcc_jit_context_set_bool_option (ctxt,
+                                 GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE,
+                                 1);
+@end example
+
+@noindent
+
+With optimization on and source locations displayed, this gives:
+
+@c We'll use "c" for gimple dumps
+
+@example
+factorial (signed int arg)
+@{
+  <unnamed type> D.80;
+  signed int D.81;
+  signed int D.82;
+  signed int D.83;
+  signed int D.84;
+  signed int D.85;
+  signed int y;
+  signed int x;
+  signed int stack_depth;
+  signed int stack[8];
+
+  try
+    @{
+      initial:
+      stack_depth = 0;
+      stack[stack_depth] = arg;
+      stack_depth = stack_depth + 1;
+      goto instr0;
+      instr0:
+      /* DUP */:
+      stack_depth = stack_depth + -1;
+      x = stack[stack_depth];
+      stack[stack_depth] = x;
+      stack_depth = stack_depth + 1;
+      stack[stack_depth] = x;
+      stack_depth = stack_depth + 1;
+      goto instr1;
+      instr1:
+      /* PUSH_CONST */:
+      stack[stack_depth] = 2;
+      stack_depth = stack_depth + 1;
+      goto instr2;
+
+      /* etc */
+@end example
+
+@noindent
+
+You can see the generated machine code in assembly form via:
+
+@example
+gcc_jit_context_set_bool_option (
+  ctxt,
+  GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE,
+  1);
+result = gcc_jit_context_compile (ctxt);
+@end example
+
+@noindent
+
+which shows that (on this x86_64 box) the compiler has unrolled the loop
+and is using MMX instructions to perform several multiplications
+simultaneously:
+
+@example
+        .file   "fake.c"
+        .text
+.Ltext0:
+        .p2align 4,,15
+        .globl  factorial
+        .type   factorial, @@function
+factorial:
+.LFB0:
+        .file 1 "factorial.toy"
+        .loc 1 14 0
+        .cfi_startproc
+.LVL0:
+.L2:
+        .loc 1 26 0
+        cmpl    $1, %edi
+        jle     .L13
+        leal    -1(%rdi), %edx
+        movl    %edx, %ecx
+        shrl    $2, %ecx
+        leal    0(,%rcx,4), %esi
+        testl   %esi, %esi
+        je      .L14
+        cmpl    $9, %edx
+        jbe     .L14
+        leal    -2(%rdi), %eax
+        movl    %eax, -16(%rsp)
+        leal    -3(%rdi), %eax
+        movd    -16(%rsp), %xmm0
+        movl    %edi, -16(%rsp)
+        movl    %eax, -12(%rsp)
+        movd    -16(%rsp), %xmm1
+        xorl    %eax, %eax
+        movl    %edx, -16(%rsp)
+        movd    -12(%rsp), %xmm4
+        movd    -16(%rsp), %xmm6
+        punpckldq       %xmm4, %xmm0
+        movdqa  .LC1(%rip), %xmm4
+        punpckldq       %xmm6, %xmm1
+        punpcklqdq      %xmm0, %xmm1
+        movdqa  .LC0(%rip), %xmm0
+        jmp     .L5
+        # etc - edited for brevity
+@end example
+
+@noindent
+
+This is clearly overkill for a function that will likely overflow the
+@code{int} type before the vectorization is worthwhile - but then again, this
+is a toy example.
+
+Turning down the optimization level to 2:
+
+@example
+gcc_jit_context_set_int_option (
+  ctxt,
+  GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL,
+  3);
+@end example
+
+@noindent
+
+yields this code, which is simple enough to quote in its entirety:
+
+@example
+        .file   "fake.c"
+        .text
+        .p2align 4,,15
+        .globl  factorial
+        .type   factorial, @@function
+factorial:
+.LFB0:
+        .cfi_startproc
+.L2:
+        cmpl    $1, %edi
+        jle     .L8
+        movl    $1, %edx
+        jmp     .L4
+        .p2align 4,,10
+        .p2align 3
+.L6:
+        movl    %eax, %edi
+.L4:
+.L5:
+        leal    -1(%rdi), %eax
+        imull   %edi, %edx
+        cmpl    $1, %eax
+        jne     .L6
+.L3:
+.L7:
+        imull   %edx, %eax
+        ret
+.L8:
+        movl    %edi, %eax
+        movl    $1, %edx
+        jmp     .L7
+        .cfi_endproc
+.LFE0:
+        .size   factorial, .-factorial
+        .ident  "GCC: (GNU) 4.9.0 20131023 (Red Hat 0.2-%@{gcc_release@})"
+        .section        .note.GNU-stack,"",@@progbits
+@end example
+
+@noindent
+
+Note that the stack pushing and popping have been eliminated, as has the
+recursive call (in favor of an iteration).
+
+@node Putting it all together,Behind the curtain How does our code get optimized?,Examining the generated code,Tutorial part 4 Adding JIT-compilation to a toy interpreter
+@anchor{intro/tutorial04 putting-it-all-together}@anchor{41}
+@subsection Putting it all together
+
+
+The complete example can be seen in the source tree at
+@code{gcc/jit/docs/examples/tut04-toyvm/toyvm.c}
+
+along with a Makefile and a couple of sample .toy scripts:
+
+@example
+$ ls -al
+drwxrwxr-x. 2 david david   4096 Sep 19 17:46 .
+drwxrwxr-x. 3 david david   4096 Sep 19 15:26 ..
+-rw-rw-r--. 1 david david    615 Sep 19 12:43 factorial.toy
+-rw-rw-r--. 1 david david    834 Sep 19 13:08 fibonacci.toy
+-rw-rw-r--. 1 david david    238 Sep 19 14:22 Makefile
+-rw-rw-r--. 1 david david  16457 Sep 19 17:07 toyvm.c
+
+$ make toyvm
+g++ -Wall -g -o toyvm toyvm.c -lgccjit
+
+$ ./toyvm factorial.toy 10
+interpreter result: 3628800
+compiler result: 3628800
+
+$ ./toyvm fibonacci.toy 10
+interpreter result: 55
+compiler result: 55
+@end example
+
+@noindent
+
+@node Behind the curtain How does our code get optimized?,,Putting it all together,Tutorial part 4 Adding JIT-compilation to a toy interpreter
+@anchor{intro/tutorial04 behind-the-curtain-how-does-our-code-get-optimized}@anchor{42}
+@subsection Behind the curtain: How does our code get optimized?
+
+
+Our example is done, but you may be wondering about exactly how the
+compiler turned what we gave it into the machine code seen above.
+
+We can examine what the compiler is doing in detail by setting:
+
+@example
+gcc_jit_context_set_bool_option (state.ctxt,
+                                 GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING,
+                                 1);
+gcc_jit_context_set_bool_option (state.ctxt,
+                                 GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES,
+                                 1);
+@end example
+
+@noindent
+
+This will dump detailed information about the compiler's state to a
+directory under @code{/tmp}, and keep it from being cleaned up.
+
+The precise names and their formats of these files is subject to change.
+Higher optimization levels lead to more files.
+Here's what I saw (edited for brevity; there were almost 200 files):
+
+@example
+intermediate files written to /tmp/libgccjit-KPQbGw
+$ ls /tmp/libgccjit-KPQbGw/
+fake.c.000i.cgraph
+fake.c.000i.type-inheritance
+fake.c.004t.gimple
+fake.c.007t.omplower
+fake.c.008t.lower
+fake.c.011t.eh
+fake.c.012t.cfg
+fake.c.014i.visibility
+fake.c.015i.early_local_cleanups
+fake.c.016t.ssa
+# etc
+@end example
+
+@noindent
+
+The gimple code is converted into Static Single Assignment form,
+with annotations for use when generating the debuginfo:
+
+@example
+$ less /tmp/libgccjit-KPQbGw/fake.c.016t.ssa
+@end example
+
+@noindent
+
+@example
+;; Function factorial (factorial, funcdef_no=0, decl_uid=53, symbol_order=0)
+
+factorial (signed int arg)
+@{
+  signed int stack[8];
+  signed int stack_depth;
+  signed int x;
+  signed int y;
+  <unnamed type> _20;
+  signed int _21;
+  signed int _38;
+  signed int _44;
+  signed int _51;
+  signed int _56;
+
+initial:
+  stack_depth_3 = 0;
+  # DEBUG stack_depth => stack_depth_3
+  stack[stack_depth_3] = arg_5(D);
+  stack_depth_7 = stack_depth_3 + 1;
+  # DEBUG stack_depth => stack_depth_7
+  # DEBUG instr0 => NULL
+  # DEBUG /* DUP */ => NULL
+  stack_depth_8 = stack_depth_7 + -1;
+  # DEBUG stack_depth => stack_depth_8
+  x_9 = stack[stack_depth_8];
+  # DEBUG x => x_9
+  stack[stack_depth_8] = x_9;
+  stack_depth_11 = stack_depth_8 + 1;
+  # DEBUG stack_depth => stack_depth_11
+  stack[stack_depth_11] = x_9;
+  stack_depth_13 = stack_depth_11 + 1;
+  # DEBUG stack_depth => stack_depth_13
+  # DEBUG instr1 => NULL
+  # DEBUG /* PUSH_CONST */ => NULL
+  stack[stack_depth_13] = 2;
+
+  /* etc; edited for brevity */
+@end example
+
+@noindent
+
+We can perhaps better see the code by turning off
+@pxref{3f,,GCC_JIT_BOOL_OPTION_DEBUGINFO} to suppress all those @code{DEBUG}
+statements, giving:
+
+@example
+$ less /tmp/libgccjit-1Hywc0/fake.c.016t.ssa
+@end example
+
+@noindent
+
+@example
+;; Function factorial (factorial, funcdef_no=0, decl_uid=53, symbol_order=0)
+
+factorial (signed int arg)
+@{
+  signed int stack[8];
+  signed int stack_depth;
+  signed int x;
+  signed int y;
+  <unnamed type> _20;
+  signed int _21;
+  signed int _38;
+  signed int _44;
+  signed int _51;
+  signed int _56;
+
+initial:
+  stack_depth_3 = 0;
+  stack[stack_depth_3] = arg_5(D);
+  stack_depth_7 = stack_depth_3 + 1;
+  stack_depth_8 = stack_depth_7 + -1;
+  x_9 = stack[stack_depth_8];
+  stack[stack_depth_8] = x_9;
+  stack_depth_11 = stack_depth_8 + 1;
+  stack[stack_depth_11] = x_9;
+  stack_depth_13 = stack_depth_11 + 1;
+  stack[stack_depth_13] = 2;
+  stack_depth_15 = stack_depth_13 + 1;
+  stack_depth_16 = stack_depth_15 + -1;
+  y_17 = stack[stack_depth_16];
+  stack_depth_18 = stack_depth_16 + -1;
+  x_19 = stack[stack_depth_18];
+  _20 = x_19 < y_17;
+  _21 = (signed int) _20;
+  stack[stack_depth_18] = _21;
+  stack_depth_23 = stack_depth_18 + 1;
+  stack_depth_24 = stack_depth_23 + -1;
+  x_25 = stack[stack_depth_24];
+  if (x_25 != 0)
+    goto <bb 4> (instr9);
+  else
+    goto <bb 3> (instr4);
+
+instr4:
+/* DUP */:
+  stack_depth_26 = stack_depth_24 + -1;
+  x_27 = stack[stack_depth_26];
+  stack[stack_depth_26] = x_27;
+  stack_depth_29 = stack_depth_26 + 1;
+  stack[stack_depth_29] = x_27;
+  stack_depth_31 = stack_depth_29 + 1;
+  stack[stack_depth_31] = 1;
+  stack_depth_33 = stack_depth_31 + 1;
+  stack_depth_34 = stack_depth_33 + -1;
+  y_35 = stack[stack_depth_34];
+  stack_depth_36 = stack_depth_34 + -1;
+  x_37 = stack[stack_depth_36];
+  _38 = x_37 - y_35;
+  stack[stack_depth_36] = _38;
+  stack_depth_40 = stack_depth_36 + 1;
+  stack_depth_41 = stack_depth_40 + -1;
+  x_42 = stack[stack_depth_41];
+  _44 = factorial (x_42);
+  stack[stack_depth_41] = _44;
+  stack_depth_46 = stack_depth_41 + 1;
+  stack_depth_47 = stack_depth_46 + -1;
+  y_48 = stack[stack_depth_47];
+  stack_depth_49 = stack_depth_47 + -1;
+  x_50 = stack[stack_depth_49];
+  _51 = x_50 * y_48;
+  stack[stack_depth_49] = _51;
+  stack_depth_53 = stack_depth_49 + 1;
+
+  # stack_depth_1 = PHI <stack_depth_24(2), stack_depth_53(3)>
+instr9:
+/* RETURN */:
+  stack_depth_54 = stack_depth_1 + -1;
+  x_55 = stack[stack_depth_54];
+  _56 = x_55;
+  stack =@{v@} @{CLOBBER@};
+  return _56;
+
+@}
+@end example
+
+@noindent
+
+Note in the above how all the @pxref{26,,gcc_jit_block} instances we
+created have been consolidated into just 3 blocks in GCC's internal
+representation: @code{initial}, @code{instr4} and @code{instr9}.
+
+@menu
+* Optimizing away stack manipulation:: 
+* Elimination of tail recursion:: 
+
+@end menu
+
+@node Optimizing away stack manipulation,Elimination of tail recursion,,Behind the curtain How does our code get optimized?
+@anchor{intro/tutorial04 optimizing-away-stack-manipulation}@anchor{43}
+@subsubsection Optimizing away stack manipulation
+
+
+Recall our simple implementation of stack operations.  Let's examine
+how the stack operations are optimized away.
+
+After a pass of constant-propagation, the depth of the stack at each
+opcode can be determined at compile-time:
+
+@example
+$ less /tmp/libgccjit-1Hywc0/fake.c.021t.ccp1
+@end example
+
+@noindent
+
+@example
+;; Function factorial (factorial, funcdef_no=0, decl_uid=53, symbol_order=0)
+
+factorial (signed int arg)
+@{
+  signed int stack[8];
+  signed int stack_depth;
+  signed int x;
+  signed int y;
+  <unnamed type> _20;
+  signed int _21;
+  signed int _38;
+  signed int _44;
+  signed int _51;
+
+initial:
+  stack[0] = arg_5(D);
+  x_9 = stack[0];
+  stack[0] = x_9;
+  stack[1] = x_9;
+  stack[2] = 2;
+  y_17 = stack[2];
+  x_19 = stack[1];
+  _20 = x_19 < y_17;
+  _21 = (signed int) _20;
+  stack[1] = _21;
+  x_25 = stack[1];
+  if (x_25 != 0)
+    goto <bb 4> (instr9);
+  else
+    goto <bb 3> (instr4);
+
+instr4:
+/* DUP */:
+  x_27 = stack[0];
+  stack[0] = x_27;
+  stack[1] = x_27;
+  stack[2] = 1;
+  y_35 = stack[2];
+  x_37 = stack[1];
+  _38 = x_37 - y_35;
+  stack[1] = _38;
+  x_42 = stack[1];
+  _44 = factorial (x_42);
+  stack[1] = _44;
+  y_48 = stack[1];
+  x_50 = stack[0];
+  _51 = x_50 * y_48;
+  stack[0] = _51;
+
+instr9:
+/* RETURN */:
+  x_55 = stack[0];
+  x_56 = x_55;
+  stack =@{v@} @{CLOBBER@};
+  return x_56;
+
+@}
+@end example
+
+@noindent
+
+Note how, in the above, all those @code{stack_depth} values are now just
+constants: we're accessing specific stack locations at each opcode.
+
+The "esra" pass ("Early Scalar Replacement of Aggregates") breaks
+out our "stack" array into individual elements:
+
+@example
+$ less /tmp/libgccjit-1Hywc0/fake.c.024t.esra
+@end example
+
+@noindent
+
+@example
+;; Function factorial (factorial, funcdef_no=0, decl_uid=53, symbol_order=0)
+
+Created a replacement for stack offset: 0, size: 32: stack$0
+Created a replacement for stack offset: 32, size: 32: stack$1
+Created a replacement for stack offset: 64, size: 32: stack$2
+
+Symbols to be put in SSA form
+@{ D.89 D.90 D.91 @}
+Incremental SSA update started at block: 0
+Number of blocks in CFG: 5
+Number of blocks to update: 4 ( 80%)
+
+
+factorial (signed int arg)
+@{
+  signed int stack$2;
+  signed int stack$1;
+  signed int stack$0;
+  signed int stack[8];
+  signed int stack_depth;
+  signed int x;
+  signed int y;
+  <unnamed type> _20;
+  signed int _21;
+  signed int _38;
+  signed int _44;
+  signed int _51;
+
+initial:
+  stack$0_45 = arg_5(D);
+  x_9 = stack$0_45;
+  stack$0_39 = x_9;
+  stack$1_32 = x_9;
+  stack$2_30 = 2;
+  y_17 = stack$2_30;
+  x_19 = stack$1_32;
+  _20 = x_19 < y_17;
+  _21 = (signed int) _20;
+  stack$1_28 = _21;
+  x_25 = stack$1_28;
+  if (x_25 != 0)
+    goto <bb 4> (instr9);
+  else
+    goto <bb 3> (instr4);
+
+instr4:
+/* DUP */:
+  x_27 = stack$0_39;
+  stack$0_22 = x_27;
+  stack$1_14 = x_27;
+  stack$2_12 = 1;
+  y_35 = stack$2_12;
+  x_37 = stack$1_14;
+  _38 = x_37 - y_35;
+  stack$1_10 = _38;
+  x_42 = stack$1_10;
+  _44 = factorial (x_42);
+  stack$1_6 = _44;
+  y_48 = stack$1_6;
+  x_50 = stack$0_22;
+  _51 = x_50 * y_48;
+  stack$0_1 = _51;
+
+  # stack$0_52 = PHI <stack$0_39(2), stack$0_1(3)>
+instr9:
+/* RETURN */:
+  x_55 = stack$0_52;
+  x_56 = x_55;
+  stack =@{v@} @{CLOBBER@};
+  return x_56;
+
+@}
+@end example
+
+@noindent
+
+Hence at this point, all those pushes and pops of the stack are now
+simply assignments to specific temporary variables.
+
+After some copy propagation, the stack manipulation has been completely
+optimized away:
+
+@example
+$ less /tmp/libgccjit-1Hywc0/fake.c.026t.copyprop1
+@end example
+
+@noindent
+
+@example
+;; Function factorial (factorial, funcdef_no=0, decl_uid=53, symbol_order=0)
+
+factorial (signed int arg)
+@{
+  signed int stack$2;
+  signed int stack$1;
+  signed int stack$0;
+  signed int stack[8];
+  signed int stack_depth;
+  signed int x;
+  signed int y;
+  <unnamed type> _20;
+  signed int _21;
+  signed int _38;
+  signed int _44;
+  signed int _51;
+
+initial:
+  stack$0_39 = arg_5(D);
+  _20 = arg_5(D) <= 1;
+  _21 = (signed int) _20;
+  if (_21 != 0)
+    goto <bb 4> (instr9);
+  else
+    goto <bb 3> (instr4);
+
+instr4:
+/* DUP */:
+  _38 = arg_5(D) + -1;
+  _44 = factorial (_38);
+  _51 = arg_5(D) * _44;
+  stack$0_1 = _51;
+
+  # stack$0_52 = PHI <arg_5(D)(2), _51(3)>
+instr9:
+/* RETURN */:
+  stack =@{v@} @{CLOBBER@};
+  return stack$0_52;
+
+@}
+@end example
+
+@noindent
+
+Later on, another pass finally eliminated @code{stack_depth} local and the
+unused parts of the @cite{stack`} array altogether:
+
+@example
+$ less /tmp/libgccjit-1Hywc0/fake.c.036t.release_ssa
+@end example
+
+@noindent
+
+@example
+;; Function factorial (factorial, funcdef_no=0, decl_uid=53, symbol_order=0)
+
+Released 44 names, 314.29%, removed 44 holes
+factorial (signed int arg)
+@{
+  signed int stack$0;
+  signed int mult_acc_1;
+  <unnamed type> _5;
+  signed int _6;
+  signed int _7;
+  signed int mul_tmp_10;
+  signed int mult_acc_11;
+  signed int mult_acc_13;
+
+  # arg_9 = PHI <arg_8(D)(0)>
+  # mult_acc_13 = PHI <1(0)>
+initial:
+
+  <bb 5>:
+  # arg_4 = PHI <arg_9(2), _7(3)>
+  # mult_acc_1 = PHI <mult_acc_13(2), mult_acc_11(3)>
+  _5 = arg_4 <= 1;
+  _6 = (signed int) _5;
+  if (_6 != 0)
+    goto <bb 4> (instr9);
+  else
+    goto <bb 3> (instr4);
+
+instr4:
+/* DUP */:
+  _7 = arg_4 + -1;
+  mult_acc_11 = mult_acc_1 * arg_4;
+  goto <bb 5>;
+
+  # stack$0_12 = PHI <arg_4(5)>
+instr9:
+/* RETURN */:
+  mul_tmp_10 = mult_acc_1 * stack$0_12;
+  return mul_tmp_10;
+
+@}
+@end example
+
+@noindent
+
+@node Elimination of tail recursion,,Optimizing away stack manipulation,Behind the curtain How does our code get optimized?
+@anchor{intro/tutorial04 elimination-of-tail-recursion}@anchor{44}
+@subsubsection Elimination of tail recursion
+
+
+Another significant optimization is the detection that the call to
+@code{factorial} is tail recursion, which can be eliminated in favor of
+an iteration:
+
+@example
+$ less /tmp/libgccjit-1Hywc0/fake.c.030t.tailr1
+@end example
+
+@noindent
+
+@example
+;; Function factorial (factorial, funcdef_no=0, decl_uid=53, symbol_order=0)
+
+
+Symbols to be put in SSA form
+@{ D.88 @}
+Incremental SSA update started at block: 0
+Number of blocks in CFG: 5
+Number of blocks to update: 4 ( 80%)
+
+
+factorial (signed int arg)
+@{
+  signed int stack$2;
+  signed int stack$1;
+  signed int stack$0;
+  signed int stack[8];
+  signed int stack_depth;
+  signed int x;
+  signed int y;
+  signed int mult_acc_1;
+  <unnamed type> _20;
+  signed int _21;
+  signed int _38;
+  signed int mul_tmp_44;
+  signed int mult_acc_51;
+
+  # arg_5 = PHI <arg_39(D)(0), _38(3)>
+  # mult_acc_1 = PHI <1(0), mult_acc_51(3)>
+initial:
+  _20 = arg_5 <= 1;
+  _21 = (signed int) _20;
+  if (_21 != 0)
+    goto <bb 4> (instr9);
+  else
+    goto <bb 3> (instr4);
+
+instr4:
+/* DUP */:
+  _38 = arg_5 + -1;
+  mult_acc_51 = mult_acc_1 * arg_5;
+  goto <bb 2> (initial);
+
+  # stack$0_52 = PHI <arg_5(2)>
+instr9:
+/* RETURN */:
+  stack =@{v@} @{CLOBBER@};
+  mul_tmp_44 = mult_acc_1 * stack$0_52;
+  return mul_tmp_44;
+
+@}
+@end example
+
+@noindent
+
+@c Copyright (C) 2014 Free Software Foundation, Inc.
+@c Originally contributed by David Malcolm <dmalcolm@redhat.com>
+@c 
+@c This is free software: you can redistribute it and/or modify it
+@c under the terms of the GNU General Public License as published by
+@c the Free Software Foundation, either version 3 of the License, or
+@c (at your option) any later version.
+@c 
+@c This program is distributed in the hope that it will be useful, but
+@c WITHOUT ANY WARRANTY; without even the implied warranty of
+@c MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+@c General Public License for more details.
+@c 
+@c You should have received a copy of the GNU General Public License
+@c along with this program.  If not, see
+@c <http://www.gnu.org/licenses/>.
+
+@node Topic Reference,Internals,Tutorial,Top
+@anchor{topics/index doc}@anchor{45}@anchor{topics/index topic-reference}@anchor{46}
+@chapter Topic Reference
+
+
+@c Copyright (C) 2014 Free Software Foundation, Inc.
+@c Originally contributed by David Malcolm <dmalcolm@redhat.com>
+@c 
+@c This is free software: you can redistribute it and/or modify it
+@c under the terms of the GNU General Public License as published by
+@c the Free Software Foundation, either version 3 of the License, or
+@c (at your option) any later version.
+@c 
+@c This program is distributed in the hope that it will be useful, but
+@c WITHOUT ANY WARRANTY; without even the implied warranty of
+@c MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+@c General Public License for more details.
+@c 
+@c You should have received a copy of the GNU General Public License
+@c along with this program.  If not, see
+@c <http://www.gnu.org/licenses/>.
+
+@menu
+* Compilation contexts:: 
+* Objects:: 
+* Types:: 
+* Expressions:: 
+* Creating and using functions:: 
+* Source Locations:: 
+* Compilation results:: 
+
+Compilation contexts
+
+* Lifetime-management:: 
+* Thread-safety:: 
+* Error-handling:: 
+* Debugging:: 
+* Options: Options<2>. 
+
+Options
+
+* String Options:: 
+* Boolean options:: 
+* Integer options:: 
+
+Types
+
+* Standard types:: 
+* Pointers@comma{} const@comma{} and volatile: Pointers const and volatile. 
+* Structures and unions:: 
+
+Expressions
+
+* Rvalues:: 
+* Lvalues:: 
+* Working with pointers@comma{} structs and unions: Working with pointers structs and unions. 
+
+Rvalues
+
+* Simple expressions:: 
+* Unary Operations:: 
+* Binary Operations:: 
+* Comparisons:: 
+* Function calls:: 
+* Type-coercion:: 
+
+Lvalues
+
+* Global variables:: 
+
+Creating and using functions
+
+* Params:: 
+* Functions:: 
+* Blocks:: 
+* Statements:: 
+
+Source Locations
+
+* Faking it:: 
+
+@end menu
+
+
+@node Compilation contexts,Objects,,Topic Reference
+@anchor{topics/contexts compilation-contexts}@anchor{47}@anchor{topics/contexts doc}@anchor{48}
+@section Compilation contexts
+
+
+@geindex gcc_jit_context (C type)
+@anchor{topics/contexts gcc_jit_context}@anchor{8}
+@deffn {C Type} gcc_jit_context
+@end deffn
+
+The top-level of the API is the @pxref{8,,gcc_jit_context} type.
+
+A @pxref{8,,gcc_jit_context} instance encapsulates the state of a
+compilation.
+
+You can set up options on it, and add types, functions and code.
+Invoking @pxref{15,,gcc_jit_context_compile()} on it gives you a
+@pxref{16,,gcc_jit_result}.
+
+@menu
+* Lifetime-management:: 
+* Thread-safety:: 
+* Error-handling:: 
+* Debugging:: 
+* Options: Options<2>. 
+
+@end menu
+
+@node Lifetime-management,Thread-safety,,Compilation contexts
+@anchor{topics/contexts lifetime-management}@anchor{49}
+@subsection Lifetime-management
+
+
+Contexts are the unit of lifetime-management within the API: objects
+have their lifetime bounded by the context they are created within, and
+cleanup of such objects is done for you when the context is released.
+
+@geindex gcc_jit_context_acquire (C function)
+@anchor{topics/contexts gcc_jit_context_acquire}@anchor{9}
+@deffn {C Function} gcc_jit_context *gcc_jit_context_acquire (void)
+
+This function acquires a new @pxref{e,,gcc_jit_object *} instance,
+which is independent of any others that may be present within this
+process.
+@end deffn
+
+@geindex gcc_jit_context_release (C function)
+@anchor{topics/contexts gcc_jit_context_release}@anchor{c}
+@deffn {C Function} void gcc_jit_context_release (gcc_jit_context@w{ }*ctxt)
+
+This function releases all resources associated with the given context.
+Both the context itself and all of its @pxref{e,,gcc_jit_object *}
+instances are cleaned up.  It should be called exactly once on a given
+context.
+
+It is invalid to use the context or any of its "contextual" objects
+after calling this.
+
+@example
+gcc_jit_context_release (ctxt);
+@end example
+
+@noindent
+@end deffn
+
+@geindex gcc_jit_context_new_child_context (C function)
+@anchor{topics/contexts gcc_jit_context_new_child_context}@anchor{4a}
+@deffn {C Function} gcc_jit_context * gcc_jit_context_new_child_context (gcc_jit_context@w{ }*parent_ctxt)
+
+Given an existing JIT context, create a child context.
+
+The child inherits a copy of all option-settings from the parent.
+
+The child can reference objects created within the parent, but not
+vice-versa.
+
+The lifetime of the child context must be bounded by that of the
+parent: you should release a child context before releasing the parent
+context.
+
+If you use a function from a parent context within a child context,
+you have to compile the parent context before you can compile the
+child context, and the gcc_jit_result of the parent context must
+outlive the gcc_jit_result of the child context.
+
+This allows caching of shared initializations.  For example, you could
+create types and declarations of global functions in a parent context
+once within a process, and then create child contexts whenever a
+function or loop becomes hot. Each such child context can be used for
+JIT-compiling just one function or loop, but can reference types
+and helper functions created within the parent context.
+
+Contexts can be arbitrarily nested, provided the above rules are
+followed, but it's probably not worth going above 2 or 3 levels, and
+there will likely be a performance hit for such nesting.
+@end deffn
+
+@node Thread-safety,Error-handling,Lifetime-management,Compilation contexts
+@anchor{topics/contexts thread-safety}@anchor{4b}
+@subsection Thread-safety
+
+
+Instances of @pxref{e,,gcc_jit_object *} created via
+@pxref{9,,gcc_jit_context_acquire()} are independent from each other:
+only one thread may use a given context at once, but multiple threads
+could each have their own contexts without needing locks.
+
+Contexts created via @pxref{4a,,gcc_jit_context_new_child_context()} are
+related to their parent context.  They can be partitioned by their
+ultimate ancestor into independent "family trees".   Only one thread
+within a process may use a given "family tree" of such contexts at once,
+and if you're using multiple threads you should provide your own locking
+around entire such context partitions.
+
+@node Error-handling,Debugging,Thread-safety,Compilation contexts
+@anchor{topics/contexts error-handling}@anchor{4c}
+@subsection Error-handling
+
+
+You can only compile and get code from a context if no errors occur.
+
+In general, if an error occurs when using an API entrypoint, it returns
+NULL.  You don't have to check everywhere for NULL results, since the
+API gracefully handles a NULL being passed in for any argument.
+
+Errors are printed on stderr and can be queried using
+@pxref{4d,,gcc_jit_context_get_first_error()}.
+
+@geindex gcc_jit_context_get_first_error (C function)
+@anchor{topics/contexts gcc_jit_context_get_first_error}@anchor{4d}
+@deffn {C Function} const char *           gcc_jit_context_get_first_error (gcc_jit_context@w{ }*ctxt)
+
+Returns the first error message that occurred on the context.
+
+The returned string is valid for the rest of the lifetime of the
+context.
+
+If no errors occurred, this will be NULL.
+@end deffn
+
+@node Debugging,Options<2>,Error-handling,Compilation contexts
+@anchor{topics/contexts debugging}@anchor{4e}
+@subsection Debugging
+
+
+@geindex gcc_jit_context_dump_to_file (C function)
+@anchor{topics/contexts gcc_jit_context_dump_to_file}@anchor{4f}
+@deffn {C Function} void           gcc_jit_context_dump_to_file (gcc_jit_context@w{ }*ctxt, const char@w{ }*path, int@w{ }update_locations)
+
+To help with debugging: dump a C-like representation to the given path,
+describing what's been set up on the context.
+
+If "update_locations" is true, then also set up @pxref{38,,gcc_jit_location}
+information throughout the context, pointing at the dump file as if it
+were a source file.  This may be of use in conjunction with
+@pxref{3f,,GCC_JIT_BOOL_OPTION_DEBUGINFO} to allow stepping through the
+code in a debugger.
+@end deffn
+
+@node Options<2>,,Debugging,Compilation contexts
+@anchor{topics/contexts options}@anchor{50}
+@subsection Options
+
+
+@menu
+* String Options:: 
+* Boolean options:: 
+* Integer options:: 
+
+@end menu
+
+@node String Options,Boolean options,,Options<2>
+@anchor{topics/contexts string-options}@anchor{51}
+@subsubsection String Options
+
+
+@geindex gcc_jit_context_set_str_option (C function)
+@anchor{topics/contexts gcc_jit_context_set_str_option}@anchor{52}
+@deffn {C Function} void gcc_jit_context_set_str_option (gcc_jit_context@w{ }*ctxt, enum gcc_jit_str_option@w{ }opt, const char@w{ }*value)
+
+Set a string option of the context.
+
+@geindex gcc_jit_str_option (C type)
+@anchor{topics/contexts gcc_jit_str_option}@anchor{53}
+@deffn {C Type} enum gcc_jit_str_option
+@end deffn
+
+There is currently just one string option:
+
+@geindex GCC_JIT_STR_OPTION_PROGNAME (C macro)
+@anchor{topics/contexts GCC_JIT_STR_OPTION_PROGNAME}@anchor{54}
+@deffn {C Macro} GCC_JIT_STR_OPTION_PROGNAME
+
+The name of the program, for use as a prefix when printing error
+messages to stderr.  If @cite{NULL}, or default, "libgccjit.so" is used.
+@end deffn
+@end deffn
+
+@node Boolean options,Integer options,String Options,Options<2>
+@anchor{topics/contexts boolean-options}@anchor{55}
+@subsubsection Boolean options
+
+
+@geindex gcc_jit_context_set_bool_option (C function)
+@anchor{topics/contexts gcc_jit_context_set_bool_option}@anchor{19}
+@deffn {C Function} void gcc_jit_context_set_bool_option (gcc_jit_context@w{ }*ctxt, enum gcc_jit_bool_option@w{ }opt, int@w{ }value)
+
+Set a boolean option of the context.
+Zero is "false" (the default), non-zero is "true".
+
+@geindex gcc_jit_bool_option (C type)
+@anchor{topics/contexts gcc_jit_bool_option}@anchor{56}
+@deffn {C Type} enum gcc_jit_bool_option
+@end deffn
+
+@geindex GCC_JIT_BOOL_OPTION_DEBUGINFO (C macro)
+@anchor{topics/contexts GCC_JIT_BOOL_OPTION_DEBUGINFO}@anchor{3f}
+@deffn {C Macro} GCC_JIT_BOOL_OPTION_DEBUGINFO
+
+If true, @pxref{15,,gcc_jit_context_compile()} will attempt to do the right
+thing so that if you attach a debugger to the process, it will
+be able to inspect variables and step through your code.
+
+Note that you can't step through code unless you set up source
+location information for the code (by creating and passing in
+@pxref{38,,gcc_jit_location} instances).
+@end deffn
+
+@geindex GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE (C macro)
+@anchor{topics/contexts GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE}@anchor{57}
+@deffn {C Macro} GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE
+
+If true, @pxref{15,,gcc_jit_context_compile()} will dump its initial
+"tree" representation of your code to stderr (before any
+optimizations).
+
+Here's some sample output (from the @cite{square} example):
+
+@example
+<statement_list 0x7f4875a62cc0
+   type <void_type 0x7f4875a64bd0 VOID
+       align 8 symtab 0 alias set -1 canonical type 0x7f4875a64bd0
+       pointer_to_this <pointer_type 0x7f4875a64c78>>
+   side-effects head 0x7f4875a761e0 tail 0x7f4875a761f8 stmts 0x7f4875a62d20 0x7f4875a62d00
+
+   stmt <label_expr 0x7f4875a62d20 type <void_type 0x7f4875a64bd0>
+       side-effects
+       arg 0 <label_decl 0x7f4875a79080 entry type <void_type 0x7f4875a64bd0>
+           VOID file (null) line 0 col 0
+           align 1 context <function_decl 0x7f4875a77500 square>>>
+   stmt <return_expr 0x7f4875a62d00
+       type <integer_type 0x7f4875a645e8 public SI
+           size <integer_cst 0x7f4875a623a0 constant 32>
+           unit size <integer_cst 0x7f4875a623c0 constant 4>
+           align 32 symtab 0 alias set -1 canonical type 0x7f4875a645e8 precision 32 min <integer_cst 0x7f4875a62340 -2147483648> max <integer_cst 0x7f4875a62360 2147483647>
+           pointer_to_this <pointer_type 0x7f4875a6b348>>
+       side-effects
+       arg 0 <modify_expr 0x7f4875a72a78 type <integer_type 0x7f4875a645e8>
+           side-effects arg 0 <result_decl 0x7f4875a7a000 D.54>
+           arg 1 <mult_expr 0x7f4875a72a50 type <integer_type 0x7f4875a645e8>
+               arg 0 <parm_decl 0x7f4875a79000 i> arg 1 <parm_decl 0x7f4875a79000 i>>>>>
+@end example
+
+@noindent
+@end deffn
+
+@geindex GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE (C macro)
+@anchor{topics/contexts GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE}@anchor{1a}
+@deffn {C Macro} GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE
+
+If true, @pxref{15,,gcc_jit_context_compile()} will dump the "gimple"
+representation of your code to stderr, before any optimizations
+are performed.  The dump resembles C code:
+
+@example
+square (signed int i)
+@{
+  signed int D.56;
+
+  entry:
+  D.56 = i * i;
+  return D.56;
+@}
+@end example
+
+@noindent
+@end deffn
+
+@geindex GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE (C macro)
+@anchor{topics/contexts GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE}@anchor{1b}
+@deffn {C Macro} GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE
+
+If true, @pxref{15,,gcc_jit_context_compile()} will dump the final
+generated code to stderr, in the form of assembly language:
+
+@example
+    .file    "fake.c"
+    .text
+    .globl    square
+    .type    square, @@function
+square:
+.LFB0:
+    .cfi_startproc
+    pushq    %rbp
+    .cfi_def_cfa_offset 16
+    .cfi_offset 6, -16
+    movq    %rsp, %rbp
+    .cfi_def_cfa_register 6
+    movl    %edi, -4(%rbp)
+.L2:
+    movl    -4(%rbp), %eax
+    imull    -4(%rbp), %eax
+    popq    %rbp
+    .cfi_def_cfa 7, 8
+    ret
+    .cfi_endproc
+.LFE0:
+    .size    square, .-square
+    .ident    "GCC: (GNU) 4.9.0 20131023 (Red Hat 0.1-%@{gcc_release@})"
+    .section    .note.GNU-stack,"",@@progbits
+@end example
+
+@noindent
+@end deffn
+
+@geindex GCC_JIT_BOOL_OPTION_DUMP_SUMMARY (C macro)
+@anchor{topics/contexts GCC_JIT_BOOL_OPTION_DUMP_SUMMARY}@anchor{58}
+@deffn {C Macro} GCC_JIT_BOOL_OPTION_DUMP_SUMMARY
+
+If true, @pxref{15,,gcc_jit_context_compile()} will print information to stderr
+on the actions it is performing, followed by a profile showing
+the time taken and memory usage of each phase.
+@end deffn
+
+@geindex GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING (C macro)
+@anchor{topics/contexts GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING}@anchor{59}
+@deffn {C Macro} GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING
+
+If true, @pxref{15,,gcc_jit_context_compile()} will dump copious
+amount of information on what it's doing to various
+files within a temporary directory.  Use
+@pxref{5a,,GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES} (see below) to
+see the results.  The files are intended to be human-readable,
+but the exact files and their formats are subject to change.
+@end deffn
+
+@geindex GCC_JIT_BOOL_OPTION_SELFCHECK_GC (C macro)
+@anchor{topics/contexts GCC_JIT_BOOL_OPTION_SELFCHECK_GC}@anchor{5b}
+@deffn {C Macro} GCC_JIT_BOOL_OPTION_SELFCHECK_GC
+
+If true, libgccjit will aggressively run its garbage collector, to
+shake out bugs (greatly slowing down the compile).  This is likely
+to only be of interest to developers @emph{of} the library.  It is
+used when running the selftest suite.
+@end deffn
+
+@geindex GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES (C macro)
+@anchor{topics/contexts GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES}@anchor{5a}
+@deffn {C Macro} GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES
+
+If true, the @pxref{8,,gcc_jit_context} will not clean up intermediate files
+written to the filesystem, and will display their location on stderr.
+@end deffn
+@end deffn
+
+@node Integer options,,Boolean options,Options<2>
+@anchor{topics/contexts integer-options}@anchor{5c}
+@subsubsection Integer options
+
+
+@geindex gcc_jit_context_set_int_option (C function)
+@anchor{topics/contexts gcc_jit_context_set_int_option}@anchor{1c}
+@deffn {C Function} void gcc_jit_context_set_int_option (gcc_jit_context@w{ }*ctxt, enum gcc_jit_int_option@w{ }opt, int@w{ }value)
+
+Set an integer option of the context.
+
+@geindex gcc_jit_int_option (C type)
+@anchor{topics/contexts gcc_jit_int_option}@anchor{5d}
+@deffn {C Type} enum gcc_jit_int_option
+@end deffn
+
+There is currently just one integer option:
+
+@geindex GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL (C macro)
+@anchor{topics/contexts GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL}@anchor{1d}
+@deffn {C Macro} GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL
+
+How much to optimize the code.
+
+Valid values are 0-3, corresponding to GCC's command-line options
+-O0 through -O3.
+
+The default value is 0 (unoptimized).
+@end deffn
+@end deffn
+
+@c Copyright (C) 2014 Free Software Foundation, Inc.
+@c Originally contributed by David Malcolm <dmalcolm@redhat.com>
+@c 
+@c This is free software: you can redistribute it and/or modify it
+@c under the terms of the GNU General Public License as published by
+@c the Free Software Foundation, either version 3 of the License, or
+@c (at your option) any later version.
+@c 
+@c This program is distributed in the hope that it will be useful, but
+@c WITHOUT ANY WARRANTY; without even the implied warranty of
+@c MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+@c General Public License for more details.
+@c 
+@c You should have received a copy of the GNU General Public License
+@c along with this program.  If not, see
+@c <http://www.gnu.org/licenses/>.
+
+@node Objects,Types,Compilation contexts,Topic Reference
+@anchor{topics/objects objects}@anchor{5e}@anchor{topics/objects doc}@anchor{5f}
+@section Objects
+
+
+@geindex gcc_jit_object (C type)
+@anchor{topics/objects gcc_jit_object}@anchor{e}
+@deffn {C Type} gcc_jit_object
+@end deffn
+
+Almost every entity in the API (with the exception of
+@pxref{8,,gcc_jit_context *} and @pxref{16,,gcc_jit_result *}) is a
+"contextual" object, a @pxref{e,,gcc_jit_object *}
+
+A JIT object:
+
+@quotation
+
+
+@itemize *
+
+@item 
+is associated with a @pxref{8,,gcc_jit_context *}.
+
+@item 
+is automatically cleaned up for you when its context is released so
+you don't need to manually track and cleanup all objects, just the
+contexts.
+@end itemize
+@end quotation
+
+Although the API is C-based, there is a form of class hierarchy, which
+looks like this:
+
+@example
++- gcc_jit_object
+    +- gcc_jit_location
+    +- gcc_jit_type
+       +- gcc_jit_struct
+    +- gcc_jit_field
+    +- gcc_jit_function
+    +- gcc_jit_block
+    +- gcc_jit_rvalue
+        +- gcc_jit_lvalue
+           +- gcc_jit_param
+@end example
+
+@noindent
+
+There are casting methods for upcasting from subclasses to parent classes.
+For example, @pxref{d,,gcc_jit_type_as_object()}:
+
+@example
+gcc_jit_object *obj = gcc_jit_type_as_object (int_type);
+@end example
+
+@noindent
+
+The object "base class" has the following operations:
+
+@geindex gcc_jit_object_get_context (C function)
+@anchor{topics/objects gcc_jit_object_get_context}@anchor{60}
+@deffn {C Function} gcc_jit_context *gcc_jit_object_get_context (gcc_jit_object@w{ }*obj)
+
+Which context is "obj" within?
+@end deffn
+
+@geindex gcc_jit_object_get_debug_string (C function)
+@anchor{topics/objects gcc_jit_object_get_debug_string}@anchor{f}
+@deffn {C Function} const char *gcc_jit_object_get_debug_string (gcc_jit_object@w{ }*obj)
+
+Generate a human-readable description for the given object.
+
+For example,
+
+@example
+printf ("obj: %s\n", gcc_jit_object_get_debug_string (obj));
+@end example
+
+@noindent
+
+might give this text on stdout:
+
+@example
+obj: 4.0 * (float)i
+@end example
+
+@noindent
+
+@cartouche
+@quotation Note 
+If you call this on an object, the @cite{const char *} buffer is allocated
+and generated on the first call for that object, and the buffer will
+have the same lifetime as the object  i.e. it will exist until the
+object's context is released.
+@end quotation
+@end cartouche
+@end deffn
+
+@c Copyright (C) 2014 Free Software Foundation, Inc.
+@c Originally contributed by David Malcolm <dmalcolm@redhat.com>
+@c 
+@c This is free software: you can redistribute it and/or modify it
+@c under the terms of the GNU General Public License as published by
+@c the Free Software Foundation, either version 3 of the License, or
+@c (at your option) any later version.
+@c 
+@c This program is distributed in the hope that it will be useful, but
+@c WITHOUT ANY WARRANTY; without even the implied warranty of
+@c MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+@c General Public License for more details.
+@c 
+@c You should have received a copy of the GNU General Public License
+@c along with this program.  If not, see
+@c <http://www.gnu.org/licenses/>.
+
+@node Types,Expressions,Objects,Topic Reference
+@anchor{topics/types doc}@anchor{61}@anchor{topics/types types}@anchor{62}
+@section Types
+
+
+@geindex gcc_jit_type (C type)
+@anchor{topics/types gcc_jit_type}@anchor{a}
+@deffn {C Type} gcc_jit_type
+
+gcc_jit_type represents a type within the library.
+@end deffn
+
+@geindex gcc_jit_type_as_object (C function)
+@anchor{topics/types gcc_jit_type_as_object}@anchor{d}
+@deffn {C Function} gcc_jit_object *gcc_jit_type_as_object (gcc_jit_type@w{ }*type)
+
+Upcast a type to an object.
+@end deffn
+
+Types can be created in several ways:
+
+
+@itemize *
+
+@item 
+fundamental types can be accessed using
+@pxref{b,,gcc_jit_context_get_type()}:
+
+@example
+gcc_jit_type *int_type = gcc_jit_context_get_type (GCC_JIT_TYPE_INT);
+@end example
+
+@noindent
+
+See @pxref{b,,gcc_jit_context_get_type()} for the available types.
+
+@item 
+derived types can be accessed by using functions such as
+@pxref{63,,gcc_jit_type_get_pointer()} and @pxref{64,,gcc_jit_type_get_const()}:
+
+@example
+gcc_jit_type *const_int_star = gcc_jit_type_get_pointer (gcc_jit_type_get_const (int_type));
+gcc_jit_type *int_const_star = gcc_jit_type_get_const (gcc_jit_type_get_pointer (int_type));
+@end example
+
+@noindent
+
+@item 
+by creating structures (see below).
+@end itemize
+
+@menu
+* Standard types:: 
+* Pointers@comma{} const@comma{} and volatile: Pointers const and volatile. 
+* Structures and unions:: 
+
+@end menu
+
+@node Standard types,Pointers const and volatile,,Types
+@anchor{topics/types standard-types}@anchor{65}
+@subsection Standard types
+
+
+@geindex gcc_jit_context_get_type (C function)
+@anchor{topics/types gcc_jit_context_get_type}@anchor{b}
+@deffn {C Function} gcc_jit_type *gcc_jit_context_get_type (gcc_jit_context@w{ }*ctxt, enum gcc_jit_types@w{ }type_)
+
+Access a specific type.  The available types are:
+
+
+@multitable {xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx} {xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx} 
+@headitem
+
+@cite{enum gcc_jit_types} value
+
+@tab
+
+Meaning
+
+@item
+
+@code{GCC_JIT_TYPE_VOID}
+
+@tab
+
+C's @code{void} type.
+
+@item
+
+@code{GCC_JIT_TYPE_VOID_PTR}
+
+@tab
+
+C's @code{void *}.
+
+@item
+
+@code{GCC_JIT_TYPE_BOOL}
+
+@tab
+
+C++'s @code{bool} type; also C99's
+@code{_Bool} type, aka @code{bool} if
+using stdbool.h.
+
+@item
+
+@code{GCC_JIT_TYPE_CHAR}
+
+@tab
+
+C's @code{char} (of some signedness)
+
+@item
+
+@code{GCC_JIT_TYPE_SIGNED_CHAR}
+
+@tab
+
+C's @code{signed char}
+
+@item
+
+@code{GCC_JIT_TYPE_UNSIGNED_CHAR}
+
+@tab
+
+C's @code{unsigned char}
+
+@item
+
+@code{GCC_JIT_TYPE_SHORT}
+
+@tab
+
+C's @code{short} (signed)
+
+@item
+
+@code{GCC_JIT_TYPE_UNSIGNED_SHORT}
+
+@tab
+
+C's @code{unsigned short}
+
+@item
+
+@code{GCC_JIT_TYPE_INT}
+
+@tab
+
+C's @code{int} (signed)
+
+@item
+
+@code{GCC_JIT_TYPE_UNSIGNED_INT}
+
+@tab
+
+C's @code{unsigned int}
+
+@item
+
+@code{GCC_JIT_TYPE_LONG}
+
+@tab
+
+C's @code{long} (signed)
+
+@item
+
+@code{GCC_JIT_TYPE_UNSIGNED_LONG}
+
+@tab
+
+C's @code{unsigned long}
+
+@item
+
+@code{GCC_JIT_TYPE_LONG_LONG}
+
+@tab
+
+C99's @code{long long} (signed)
+
+@item
+
+@code{GCC_JIT_TYPE_UNSIGNED_LONG_LONG}
+
+@tab
+
+C99's @code{unsigned long long}
+
+@item
+
+@code{GCC_JIT_TYPE_FLOAT}
+
+@tab
+
+@item
+
+@code{GCC_JIT_TYPE_DOUBLE}
+
+@tab
+
+@item
+
+@code{GCC_JIT_TYPE_LONG_DOUBLE}
+
+@tab
+
+@item
+
+@code{GCC_JIT_TYPE_CONST_CHAR_PTR}
+
+@tab
+
+C type: @code{(const char *)}
+
+@item
+
+@code{GCC_JIT_TYPE_SIZE_T}
+
+@tab
+
+C's @code{size_t} type
+
+@item
+
+@code{GCC_JIT_TYPE_FILE_PTR}
+
+@tab
+
+C type: @code{(FILE *)}
+
+@end multitable
+
+@end deffn
+
+@geindex gcc_jit_context_get_int_type (C function)
+@anchor{topics/types gcc_jit_context_get_int_type}@anchor{66}
+@deffn {C Function} gcc_jit_type *           gcc_jit_context_get_int_type (gcc_jit_context@w{ }*ctxt, int@w{ }num_bytes, int@w{ }is_signed)
+
+Access the integer type of the given size.
+@end deffn
+
+@node Pointers const and volatile,Structures and unions,Standard types,Types
+@anchor{topics/types pointers-const-and-volatile}@anchor{67}
+@subsection Pointers, @cite{const}, and @cite{volatile}
+
+
+@geindex gcc_jit_type_get_pointer (C function)
+@anchor{topics/types gcc_jit_type_get_pointer}@anchor{63}
+@deffn {C Function} gcc_jit_type *gcc_jit_type_get_pointer (gcc_jit_type@w{ }*type)
+
+Given type "T", get type "T*".
+@end deffn
+
+@geindex gcc_jit_type_get_const (C function)
+@anchor{topics/types gcc_jit_type_get_const}@anchor{64}
+@deffn {C Function} gcc_jit_type *gcc_jit_type_get_const (gcc_jit_type@w{ }*type)
+
+Given type "T", get type "const T".
+@end deffn
+
+@geindex gcc_jit_type_get_volatile (C function)
+@anchor{topics/types gcc_jit_type_get_volatile}@anchor{68}
+@deffn {C Function} gcc_jit_type *gcc_jit_type_get_volatile (gcc_jit_type@w{ }*type)
+
+Given type "T", get type "volatile T".
+@end deffn
+
+@geindex gcc_jit_context_new_array_type (C function)
+@anchor{topics/types gcc_jit_context_new_array_type}@anchor{69}
+@deffn {C Function} gcc_jit_type *            gcc_jit_context_new_array_type (gcc_jit_context@w{ }*ctxt, gcc_jit_location@w{ }*loc, gcc_jit_type@w{ }*element_type, int@w{ }num_elements)
+
+Given type "T", get type "T[N]" (for a constant N).
+@end deffn
+
+@node Structures and unions,,Pointers const and volatile,Types
+@anchor{topics/types structures-and-unions}@anchor{6a}
+@subsection Structures and unions
+
+
+@geindex gcc_jit_struct (C type)
+@anchor{topics/types gcc_jit_struct}@anchor{6b}
+@deffn {C Type} gcc_jit_struct
+@end deffn
+
+A compound type analagous to a C @cite{struct}.
+
+@geindex gcc_jit_field (C type)
+@anchor{topics/types gcc_jit_field}@anchor{6c}
+@deffn {C Type} gcc_jit_field
+@end deffn
+
+A field within a @pxref{6b,,gcc_jit_struct}.
+
+You can model C @cite{struct} types by creating @pxref{6b,,gcc_jit_struct *} and
+@pxref{6c,,gcc_jit_field} instances, in either order:
+
+
+@itemize *
+
+@item 
+by creating the fields, then the structure.  For example, to model:
+
+@example
+struct coord @{double x; double y; @};
+@end example
+
+@noindent
+
+you could call:
+
+@example
+gcc_jit_field *field_x =
+  gcc_jit_context_new_field (ctxt, NULL, double_type, "x");
+gcc_jit_field *field_y =
+  gcc_jit_context_new_field (ctxt, NULL, double_type, "y");
+gcc_jit_field *fields[2] = @{field_x, field_y@};
+gcc_jit_struct *coord =
+  gcc_jit_context_new_struct_type (ctxt, NULL, "coord", 2, fields);
+@end example
+
+@noindent
+
+@item 
+by creating the structure, then populating it with fields, typically
+to allow modelling self-referential structs such as:
+
+@example
+struct node @{ int m_hash; struct node *m_next; @};
+@end example
+
+@noindent
+
+like this:
+
+@example
+gcc_jit_type *node =
+  gcc_jit_context_new_opaque_struct (ctxt, NULL, "node");
+gcc_jit_type *node_ptr =
+  gcc_jit_type_get_pointer (node);
+gcc_jit_field *field_hash =
+  gcc_jit_context_new_field (ctxt, NULL, int_type, "m_hash");
+gcc_jit_field *field_next =
+  gcc_jit_context_new_field (ctxt, NULL, node_ptr, "m_next");
+gcc_jit_field *fields[2] = @{field_hash, field_next@};
+gcc_jit_struct_set_fields (node, NULL, 2, fields);
+@end example
+
+@noindent
+@end itemize
+
+@geindex gcc_jit_context_new_field (C function)
+@anchor{topics/types gcc_jit_context_new_field}@anchor{6d}
+@deffn {C Function} gcc_jit_field *           gcc_jit_context_new_field (gcc_jit_context@w{ }*ctxt, gcc_jit_location@w{ }*loc, gcc_jit_type@w{ }*type, const char@w{ }*name)
+
+Construct a new field, with the given type and name.
+@end deffn
+
+@geindex gcc_jit_field_as_object (C function)
+@anchor{topics/types gcc_jit_field_as_object}@anchor{6e}
+@deffn {C Function} gcc_jit_object *           gcc_jit_field_as_object (gcc_jit_field@w{ }*field)
+
+Upcast from field to object.
+@end deffn
+
+@geindex gcc_jit_context_new_struct_type (C function)
+@anchor{topics/types gcc_jit_context_new_struct_type}@anchor{6f}
+@deffn {C Function} gcc_jit_struct *gcc_jit_context_new_struct_type (gcc_jit_context@w{ }*ctxt, gcc_jit_location@w{ }*loc, const char@w{ }*name, int@w{ }num_fields, gcc_jit_field@w{ }**fields)
+
+@quotation
+
+Construct a new struct type, with the given name and fields.
+@end quotation
+@end deffn
+
+@geindex gcc_jit_context_new_opaque_struct (C function)
+@anchor{topics/types gcc_jit_context_new_opaque_struct}@anchor{70}
+@deffn {C Function} gcc_jit_struct *         gcc_jit_context_new_opaque_struct (gcc_jit_context@w{ }*ctxt, gcc_jit_location@w{ }*loc, const char@w{ }*name)
+
+Construct a new struct type, with the given name, but without
+specifying the fields.   The fields can be omitted (in which case the
+size of the struct is not known), or later specified using
+@pxref{71,,gcc_jit_struct_set_fields()}.
+@end deffn
+
+@geindex gcc_jit_struct_as_type (C function)
+@anchor{topics/types gcc_jit_struct_as_type}@anchor{72}
+@deffn {C Function} gcc_jit_type *           gcc_jit_struct_as_type (gcc_jit_struct@w{ }*struct_type)
+
+Upcast from struct to type.
+@end deffn
+
+@geindex gcc_jit_struct_set_fields (C function)
+@anchor{topics/types gcc_jit_struct_set_fields}@anchor{71}
+@deffn {C Function} void           gcc_jit_struct_set_fields (gcc_jit_struct@w{ }*struct_type, gcc_jit_location@w{ }*loc, int@w{ }num_fields, gcc_jit_field@w{ }**fields)
+
+Populate the fields of a formerly-opaque struct type.
+
+This can only be called once on a given struct type.
+@end deffn
+
+@c Copyright (C) 2014 Free Software Foundation, Inc.
+@c Originally contributed by David Malcolm <dmalcolm@redhat.com>
+@c 
+@c This is free software: you can redistribute it and/or modify it
+@c under the terms of the GNU General Public License as published by
+@c the Free Software Foundation, either version 3 of the License, or
+@c (at your option) any later version.
+@c 
+@c This program is distributed in the hope that it will be useful, but
+@c WITHOUT ANY WARRANTY; without even the implied warranty of
+@c MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+@c General Public License for more details.
+@c 
+@c You should have received a copy of the GNU General Public License
+@c along with this program.  If not, see
+@c <http://www.gnu.org/licenses/>.
+
+@node Expressions,Creating and using functions,Types,Topic Reference
+@anchor{topics/expressions expressions}@anchor{73}@anchor{topics/expressions doc}@anchor{74}
+@section Expressions
+
+
+@menu
+* Rvalues:: 
+* Lvalues:: 
+* Working with pointers@comma{} structs and unions: Working with pointers structs and unions. 
+
+Rvalues
+
+* Simple expressions:: 
+* Unary Operations:: 
+* Binary Operations:: 
+* Comparisons:: 
+* Function calls:: 
+* Type-coercion:: 
+
+Lvalues
+
+* Global variables:: 
+
+@end menu
+
+
+@node Rvalues,Lvalues,,Expressions
+@anchor{topics/expressions rvalues}@anchor{75}
+@subsection Rvalues
+
+
+@geindex gcc_jit_rvalue (C type)
+@anchor{topics/expressions gcc_jit_rvalue}@anchor{13}
+@deffn {C Type} gcc_jit_rvalue
+@end deffn
+
+A @pxref{13,,gcc_jit_rvalue *} is an expression that can be computed.
+
+It can be simple, e.g.:
+
+@quotation
+
+
+@itemize *
+
+@item 
+an integer value e.g. @cite{0} or @cite{42}
+
+@item 
+a string literal e.g. @cite{"Hello world"}
+
+@item 
+a variable e.g. @cite{i}.  These are also lvalues (see below).
+@end itemize
+@end quotation
+
+or compound e.g.:
+
+@quotation
+
+
+@itemize *
+
+@item 
+a unary expression e.g. @cite{!cond}
+
+@item 
+a binary expression e.g. @cite{(a + b)}
+
+@item 
+a function call e.g. @cite{get_distance (&player_ship@comma{} &target)}
+
+@item 
+etc.
+@end itemize
+@end quotation
+
+Every rvalue has an associated type, and the API will check to ensure
+that types match up correctly (otherwise the context will emit an error).
+
+@geindex gcc_jit_rvalue_get_type (C function)
+@anchor{topics/expressions gcc_jit_rvalue_get_type}@anchor{76}
+@deffn {C Function} gcc_jit_type *gcc_jit_rvalue_get_type (gcc_jit_rvalue@w{ }*rvalue)
+
+Get the type of this rvalue.
+@end deffn
+
+@geindex gcc_jit_rvalue_as_object (C function)
+@anchor{topics/expressions gcc_jit_rvalue_as_object}@anchor{14}
+@deffn {C Function} gcc_jit_object *gcc_jit_rvalue_as_object (gcc_jit_rvalue@w{ }*rvalue)
+
+Upcast the given rvalue to be an object.
+@end deffn
+
+@menu
+* Simple expressions:: 
+* Unary Operations:: 
+* Binary Operations:: 
+* Comparisons:: 
+* Function calls:: 
+* Type-coercion:: 
+
+@end menu
+
+@node Simple expressions,Unary Operations,,Rvalues
+@anchor{topics/expressions simple-expressions}@anchor{77}
+@subsubsection Simple expressions
+
+
+@geindex gcc_jit_context_new_rvalue_from_int (C function)
+@anchor{topics/expressions gcc_jit_context_new_rvalue_from_int}@anchor{2e}
+@deffn {C Function} gcc_jit_rvalue *           gcc_jit_context_new_rvalue_from_int (gcc_jit_context@w{ }*ctxt, gcc_jit_type@w{ }*numeric_type, int@w{ }value)
+
+Given a numeric type (integer or floating point), build an rvalue for
+the given constant value.
+@end deffn
+
+@geindex gcc_jit_context_zero (C function)
+@anchor{topics/expressions gcc_jit_context_zero}@anchor{29}
+@deffn {C Function} gcc_jit_rvalue *gcc_jit_context_zero (gcc_jit_context@w{ }*ctxt, gcc_jit_type@w{ }*numeric_type)
+
+Given a numeric type (integer or floating point), get the rvalue for
+zero.  Essentially this is just a shortcut for:
+
+@example
+gcc_jit_context_new_rvalue_from_int (ctxt, numeric_type, 0)
+@end example
+
+@noindent
+@end deffn
+
+@geindex gcc_jit_context_one (C function)
+@anchor{topics/expressions gcc_jit_context_one}@anchor{2d}
+@deffn {C Function} gcc_jit_rvalue *gcc_jit_context_one (gcc_jit_context@w{ }*ctxt, gcc_jit_type@w{ }*numeric_type)
+
+Given a numeric type (integer or floating point), get the rvalue for
+zero.  Essentially this is just a shortcut for:
+
+@example
+gcc_jit_context_new_rvalue_from_int (ctxt, numeric_type, 1)
+@end example
+
+@noindent
+@end deffn
+
+@geindex gcc_jit_context_new_rvalue_from_double (C function)
+@anchor{topics/expressions gcc_jit_context_new_rvalue_from_double}@anchor{2f}
+@deffn {C Function} gcc_jit_rvalue *            gcc_jit_context_new_rvalue_from_double (gcc_jit_context@w{ }*ctxt, gcc_jit_type@w{ }*numeric_type, double@w{ }value)
+
+Given a numeric type (integer or floating point), build an rvalue for
+the given constant value.
+@end deffn
+
+@geindex gcc_jit_context_new_rvalue_from_ptr (C function)
+@anchor{topics/expressions gcc_jit_context_new_rvalue_from_ptr}@anchor{78}
+@deffn {C Function} gcc_jit_rvalue *           gcc_jit_context_new_rvalue_from_ptr (gcc_jit_context@w{ }*ctxt, gcc_jit_type@w{ }*pointer_type, void@w{ }*value)
+
+Given a pointer type, build an rvalue for the given address.
+@end deffn
+
+@geindex gcc_jit_context_null (C function)
+@anchor{topics/expressions gcc_jit_context_null}@anchor{79}
+@deffn {C Function} gcc_jit_rvalue *gcc_jit_context_null (gcc_jit_context@w{ }*ctxt, gcc_jit_type@w{ }*pointer_type)
+
+Given a pointer type, build an rvalue for @code{NULL}.  Essentially this
+is just a shortcut for:
+
+@example
+gcc_jit_context_new_rvalue_from_ptr (ctxt, pointer_type, NULL)
+@end example
+
+@noindent
+@end deffn
+
+@geindex gcc_jit_context_new_string_literal (C function)
+@anchor{topics/expressions gcc_jit_context_new_string_literal}@anchor{7a}
+@deffn {C Function} gcc_jit_rvalue *           gcc_jit_context_new_string_literal (gcc_jit_context@w{ }*ctxt, const char@w{ }*value)
+
+Generate an rvalue for the given NIL-terminated string, of type
+@code{GCC_JIT_TYPE_CONST_CHAR_PTR}.
+@end deffn
+
+@node Unary Operations,Binary Operations,Simple expressions,Rvalues
+@anchor{topics/expressions unary-operations}@anchor{7b}
+@subsubsection Unary Operations
+
+
+@geindex gcc_jit_context_new_unary_op (C function)
+@anchor{topics/expressions gcc_jit_context_new_unary_op}@anchor{7c}
+@deffn {C Function} gcc_jit_rvalue *            gcc_jit_context_new_unary_op (gcc_jit_context@w{ }*ctxt, gcc_jit_location@w{ }*loc, enum gcc_jit_unary_op@w{ }op, gcc_jit_type@w{ }*result_type, gcc_jit_rvalue@w{ }*rvalue)
+
+Build a unary operation out of an input rvalue.
+@end deffn
+
+@geindex gcc_jit_unary_op (C type)
+@anchor{topics/expressions gcc_jit_unary_op}@anchor{7d}
+@deffn {C Type} enum gcc_jit_unary_op
+@end deffn
+
+The available unary operations are:
+
+
+@multitable {xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx} {xxxxxxxxxxxxxx} 
+@headitem
+
+Unary Operation
+
+@tab
+
+C equivalent
+
+@item
+
+@pxref{7e,,GCC_JIT_UNARY_OP_MINUS}
+
+@tab
+
+@cite{-(EXPR)}
+
+@item
+
+@pxref{7f,,GCC_JIT_UNARY_OP_BITWISE_NEGATE}
+
+@tab
+
+@cite{~(EXPR)}
+
+@item
+
+@pxref{80,,GCC_JIT_UNARY_OP_LOGICAL_NEGATE}
+
+@tab
+
+@cite{!(EXPR)}
+
+@end multitable
+
+
+@geindex GCC_JIT_UNARY_OP_MINUS (C macro)
+@anchor{topics/expressions GCC_JIT_UNARY_OP_MINUS}@anchor{7e}
+@deffn {C Macro} GCC_JIT_UNARY_OP_MINUS
+
+Negate an arithmetic value; analogous to:
+
+@example
+-(EXPR)
+@end example
+
+@noindent
+
+in C.
+@end deffn
+
+@geindex GCC_JIT_UNARY_OP_BITWISE_NEGATE (C macro)
+@anchor{topics/expressions GCC_JIT_UNARY_OP_BITWISE_NEGATE}@anchor{7f}
+@deffn {C Macro} GCC_JIT_UNARY_OP_BITWISE_NEGATE
+
+Bitwise negation of an integer value (one's complement); analogous
+to:
+
+@example
+~(EXPR)
+@end example
+
+@noindent
+
+in C.
+@end deffn
+
+@geindex GCC_JIT_UNARY_OP_LOGICAL_NEGATE (C macro)
+@anchor{topics/expressions GCC_JIT_UNARY_OP_LOGICAL_NEGATE}@anchor{80}
+@deffn {C Macro} GCC_JIT_UNARY_OP_LOGICAL_NEGATE
+
+Logical negation of an arithmetic or pointer value; analogous to:
+
+@example
+!(EXPR)
+@end example
+
+@noindent
+
+in C.
+@end deffn
+
+@node Binary Operations,Comparisons,Unary Operations,Rvalues
+@anchor{topics/expressions binary-operations}@anchor{81}
+@subsubsection Binary Operations
+
+
+@geindex gcc_jit_context_new_binary_op (C function)
+@anchor{topics/expressions gcc_jit_context_new_binary_op}@anchor{12}
+@deffn {C Function} gcc_jit_rvalue *gcc_jit_context_new_binary_op (gcc_jit_context@w{ }*ctxt, gcc_jit_location@w{ }*loc, enum gcc_jit_binary_op@w{ }op, gcc_jit_type@w{ }*result_type, gcc_jit_rvalue@w{ }*a, gcc_jit_rvalue@w{ }*b)
+
+Build a binary operation out of two constituent rvalues.
+@end deffn
+
+@geindex gcc_jit_binary_op (C type)
+@anchor{topics/expressions gcc_jit_binary_op}@anchor{82}
+@deffn {C Type} enum gcc_jit_binary_op
+@end deffn
+
+The available binary operations are:
+
+
+@multitable {xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx} {xxxxxxxxxxxxxx} 
+@headitem
+
+Binary Operation
+
+@tab
+
+C equivalent
+
+@item
+
+@pxref{83,,GCC_JIT_BINARY_OP_PLUS}
+
+@tab
+
+@cite{x + y}
+
+@item
+
+@code{GCC_JIT_BINARY_OP_MINUS}
+
+@tab
+
+@cite{x - y}
+
+@item
+
+@pxref{84,,GCC_JIT_BINARY_OP_MULT}
+
+@tab
+
+@cite{x * y}
+
+@item
+
+@pxref{85,,GCC_JIT_BINARY_OP_DIVIDE}
+
+@tab
+
+@cite{x / y}
+
+@item
+
+@pxref{86,,GCC_JIT_BINARY_OP_MODULO}
+
+@tab
+
+@cite{x % y}
+
+@item
+
+@pxref{87,,GCC_JIT_BINARY_OP_BITWISE_AND}
+
+@tab
+
+@cite{x & y}
+
+@item
+
+@pxref{88,,GCC_JIT_BINARY_OP_BITWISE_XOR}
+
+@tab
+
+@cite{x ^ y}
+
+@item
+
+@pxref{89,,GCC_JIT_BINARY_OP_BITWISE_OR}
+
+@tab
+
+@cite{x | y}
+
+@item
+
+@pxref{8a,,GCC_JIT_BINARY_OP_LOGICAL_AND}
+
+@tab
+
+@cite{x && y}
+
+@item
+
+@pxref{8b,,GCC_JIT_BINARY_OP_LOGICAL_OR}
+
+@tab
+
+@cite{x || y}
+
+@item
+
+@pxref{8c,,GCC_JIT_BINARY_OP_LSHIFT}
+
+@tab
+
+@cite{x << y}
+
+@item
+
+@pxref{8d,,GCC_JIT_BINARY_OP_RSHIFT}
+
+@tab
+
+@cite{x >> y}
+
+@end multitable
+
+
+@geindex GCC_JIT_BINARY_OP_PLUS (C macro)
+@anchor{topics/expressions GCC_JIT_BINARY_OP_PLUS}@anchor{83}
+@deffn {C Macro} GCC_JIT_BINARY_OP_PLUS
+
+Addition of arithmetic values; analogous to:
+
+@example
+(EXPR_A) + (EXPR_B)
+@end example
+
+@noindent
+
+in C.
+
+For pointer addition, use @pxref{8e,,gcc_jit_context_new_array_access()}.
+@end deffn
+
+
+@deffn {C Macro} GCC_JIT_BINARY_OP_MINUS`
+
+Subtraction of arithmetic values; analogous to:
+
+@example
+(EXPR_A) - (EXPR_B)
+@end example
+
+@noindent
+
+in C.
+@end deffn
+
+@geindex GCC_JIT_BINARY_OP_MULT (C macro)
+@anchor{topics/expressions GCC_JIT_BINARY_OP_MULT}@anchor{84}
+@deffn {C Macro} GCC_JIT_BINARY_OP_MULT
+
+Multiplication of a pair of arithmetic values; analogous to:
+
+@example
+(EXPR_A) * (EXPR_B)
+@end example
+
+@noindent
+
+in C.
+@end deffn
+
+@geindex GCC_JIT_BINARY_OP_DIVIDE (C macro)
+@anchor{topics/expressions GCC_JIT_BINARY_OP_DIVIDE}@anchor{85}
+@deffn {C Macro} GCC_JIT_BINARY_OP_DIVIDE
+
+Quotient of division of arithmetic values; analogous to:
+
+@example
+(EXPR_A) / (EXPR_B)
+@end example
+
+@noindent
+
+in C.
+
+The result type affects the kind of division: if the result type is
+integer-based, then the result is truncated towards zero, whereas
+a floating-point result type indicates floating-point division.
+@end deffn
+
+@geindex GCC_JIT_BINARY_OP_MODULO (C macro)
+@anchor{topics/expressions GCC_JIT_BINARY_OP_MODULO}@anchor{86}
+@deffn {C Macro} GCC_JIT_BINARY_OP_MODULO
+
+Remainder of division of arithmetic values; analogous to:
+
+@example
+(EXPR_A) % (EXPR_B)
+@end example
+
+@noindent
+
+in C.
+@end deffn
+
+@geindex GCC_JIT_BINARY_OP_BITWISE_AND (C macro)
+@anchor{topics/expressions GCC_JIT_BINARY_OP_BITWISE_AND}@anchor{87}
+@deffn {C Macro} GCC_JIT_BINARY_OP_BITWISE_AND
+
+Bitwise AND; analogous to:
+
+@example
+(EXPR_A) & (EXPR_B)
+@end example
+
+@noindent
+
+in C.
+@end deffn
+
+@geindex GCC_JIT_BINARY_OP_BITWISE_XOR (C macro)
+@anchor{topics/expressions GCC_JIT_BINARY_OP_BITWISE_XOR}@anchor{88}
+@deffn {C Macro} GCC_JIT_BINARY_OP_BITWISE_XOR
+
+Bitwise exclusive OR; analogous to:
+
+@example
+(EXPR_A) ^ (EXPR_B)
+@end example
+
+@noindent
+
+in C.
+@end deffn
+
+@geindex GCC_JIT_BINARY_OP_BITWISE_OR (C macro)
+@anchor{topics/expressions GCC_JIT_BINARY_OP_BITWISE_OR}@anchor{89}
+@deffn {C Macro} GCC_JIT_BINARY_OP_BITWISE_OR
+
+Bitwise inclusive OR; analogous to:
+
+@example
+(EXPR_A) | (EXPR_B)
+@end example
+
+@noindent
+
+in C.
+@end deffn
+
+@geindex GCC_JIT_BINARY_OP_LOGICAL_AND (C macro)
+@anchor{topics/expressions GCC_JIT_BINARY_OP_LOGICAL_AND}@anchor{8a}
+@deffn {C Macro} GCC_JIT_BINARY_OP_LOGICAL_AND
+
+Logical AND; analogous to:
+
+@example
+(EXPR_A) && (EXPR_B)
+@end example
+
+@noindent
+
+in C.
+@end deffn
+
+@geindex GCC_JIT_BINARY_OP_LOGICAL_OR (C macro)
+@anchor{topics/expressions GCC_JIT_BINARY_OP_LOGICAL_OR}@anchor{8b}
+@deffn {C Macro} GCC_JIT_BINARY_OP_LOGICAL_OR
+
+Logical OR; analogous to:
+
+@example
+(EXPR_A) || (EXPR_B)
+@end example
+
+@noindent
+
+in C.
+@end deffn
+
+@geindex GCC_JIT_BINARY_OP_LSHIFT (C macro)
+@anchor{topics/expressions GCC_JIT_BINARY_OP_LSHIFT}@anchor{8c}
+@deffn {C Macro} GCC_JIT_BINARY_OP_LSHIFT
+
+Left shift; analogous to:
+
+@example
+(EXPR_A) << (EXPR_B)
+@end example
+
+@noindent
+
+in C.
+@end deffn
+
+@geindex GCC_JIT_BINARY_OP_RSHIFT (C macro)
+@anchor{topics/expressions GCC_JIT_BINARY_OP_RSHIFT}@anchor{8d}
+@deffn {C Macro} GCC_JIT_BINARY_OP_RSHIFT
+
+Right shift; analogous to:
+
+@example
+(EXPR_A) >> (EXPR_B)
+@end example
+
+@noindent
+
+in C.
+@end deffn
+
+@node Comparisons,Function calls,Binary Operations,Rvalues
+@anchor{topics/expressions comparisons}@anchor{8f}
+@subsubsection Comparisons
+
+
+@geindex gcc_jit_context_new_comparison (C function)
+@anchor{topics/expressions gcc_jit_context_new_comparison}@anchor{2a}
+@deffn {C Function} gcc_jit_rvalue *           gcc_jit_context_new_comparison (gcc_jit_context@w{ }*ctxt, gcc_jit_location@w{ }*loc, enum gcc_jit_comparison@w{ }op, gcc_jit_rvalue@w{ }*a, gcc_jit_rvalue@w{ }*b)
+
+Build a boolean rvalue out of the comparison of two other rvalues.
+@end deffn
+
+@geindex gcc_jit_comparison (C type)
+@anchor{topics/expressions gcc_jit_comparison}@anchor{90}
+@deffn {C Type} enum gcc_jit_comparison
+@end deffn
+
+
+@multitable {xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx} {xxxxxxxxxxxxxx} 
+@headitem
+
+Comparison
+
+@tab
+
+C equivalent
+
+@item
+
+@code{GCC_JIT_COMPARISON_EQ}
+
+@tab
+
+@cite{x == y}
+
+@item
+
+@code{GCC_JIT_COMPARISON_NE}
+
+@tab
+
+@cite{x != y}
+
+@item
+
+@code{GCC_JIT_COMPARISON_LT}
+
+@tab
+
+@cite{x < y}
+
+@item
+
+@code{GCC_JIT_COMPARISON_LE}
+
+@tab
+
+@cite{x <= y}
+
+@item
+
+@code{GCC_JIT_COMPARISON_GT}
+
+@tab
+
+@cite{x > y}
+
+@item
+
+@code{GCC_JIT_COMPARISON_GE}
+
+@tab
+
+@cite{x >= y}
+
+@end multitable
+
+
+@node Function calls,Type-coercion,Comparisons,Rvalues
+@anchor{topics/expressions function-calls}@anchor{91}
+@subsubsection Function calls
+
+
+@geindex gcc_jit_context_new_call (C function)
+@anchor{topics/expressions gcc_jit_context_new_call}@anchor{92}
+@deffn {C Function} gcc_jit_rvalue *           gcc_jit_context_new_call (gcc_jit_context@w{ }*ctxt, gcc_jit_location@w{ }*loc, gcc_jit_function@w{ }*func, int@w{ }numargs, gcc_jit_rvalue@w{ }**args)
+
+Given a function and the given table of argument rvalues, construct a
+call to the function, with the result as an rvalue.
+
+@cartouche
+@quotation Note 
+@pxref{92,,gcc_jit_context_new_call()} merely builds a
+@pxref{13,,gcc_jit_rvalue} i.e. an expression that can be evaluated,
+perhaps as part of a more complicated expression.
+The call @emph{won't} happen unless you add a statement to a function
+that evaluates the expression.
+
+For example, if you want to call a function and discard the result
+(or to call a function with @code{void} return type), use
+@pxref{93,,gcc_jit_block_add_eval()}:
+
+@example
+/* Add "(void)printf (arg0, arg1);".  */
+gcc_jit_block_add_eval (
+  block, NULL,
+  gcc_jit_context_new_call (
+    ctxt,
+    NULL,
+    printf_func,
+    2, args));
+@end example
+
+@noindent
+@end quotation
+@end cartouche
+@end deffn
+
+@node Type-coercion,,Function calls,Rvalues
+@anchor{topics/expressions type-coercion}@anchor{94}
+@subsubsection Type-coercion
+
+
+@geindex gcc_jit_context_new_cast (C function)
+@anchor{topics/expressions gcc_jit_context_new_cast}@anchor{95}
+@deffn {C Function} gcc_jit_rvalue *           gcc_jit_context_new_cast (gcc_jit_context@w{ }*ctxt, gcc_jit_location@w{ }*loc, gcc_jit_rvalue@w{ }*rvalue, gcc_jit_type@w{ }*type)
+
+Given an rvalue of T, construct another rvalue of another type.
+
+Currently only a limited set of conversions are possible:
+
+@quotation
+
+
+@itemize *
+
+@item 
+int <-> float
+
+@item 
+int <-> bool
+
+@item 
+P*  <-> Q*, for pointer types P and Q
+@end itemize
+@end quotation
+@end deffn
+
+@node Lvalues,Working with pointers structs and unions,Rvalues,Expressions
+@anchor{topics/expressions lvalues}@anchor{96}
+@subsection Lvalues
+
+
+@geindex gcc_jit_lvalue (C type)
+@anchor{topics/expressions gcc_jit_lvalue}@anchor{22}
+@deffn {C Type} gcc_jit_lvalue
+@end deffn
+
+An lvalue is something that can of the @emph{left}-hand side of an assignment:
+a storage area (such as a variable).  It is also usable as an rvalue,
+where the rvalue is computed by reading from the storage area.
+
+@geindex gcc_jit_lvalue_as_object (C function)
+@anchor{topics/expressions gcc_jit_lvalue_as_object}@anchor{97}
+@deffn {C Function} gcc_jit_object *           gcc_jit_lvalue_as_object (gcc_jit_lvalue@w{ }*lvalue)
+
+Upcast an lvalue to be an object.
+@end deffn
+
+@geindex gcc_jit_lvalue_as_rvalue (C function)
+@anchor{topics/expressions gcc_jit_lvalue_as_rvalue}@anchor{98}
+@deffn {C Function} gcc_jit_rvalue *           gcc_jit_lvalue_as_rvalue (gcc_jit_lvalue@w{ }*lvalue)
+
+Upcast an lvalue to be an rvalue.
+@end deffn
+
+@geindex gcc_jit_lvalue_get_address (C function)
+@anchor{topics/expressions gcc_jit_lvalue_get_address}@anchor{99}
+@deffn {C Function} gcc_jit_rvalue *           gcc_jit_lvalue_get_address (gcc_jit_lvalue@w{ }*lvalue, gcc_jit_location@w{ }*loc)
+
+Take the address of an lvalue; analogous to:
+
+@example
+&(EXPR)
+@end example
+
+@noindent
+
+in C.
+@end deffn
+
+@menu
+* Global variables:: 
+
+@end menu
+
+@node Global variables,,,Lvalues
+@anchor{topics/expressions global-variables}@anchor{9a}
+@subsubsection Global variables
+
+
+@geindex gcc_jit_context_new_global (C function)
+@anchor{topics/expressions gcc_jit_context_new_global}@anchor{9b}
+@deffn {C Function} gcc_jit_lvalue *           gcc_jit_context_new_global (gcc_jit_context@w{ }*ctxt, gcc_jit_location@w{ }*loc, gcc_jit_type@w{ }*type, const char@w{ }*name)
+
+Add a new global variable of the given type and name to the context.
+@end deffn
+
+@node Working with pointers structs and unions,,Lvalues,Expressions
+@anchor{topics/expressions working-with-pointers-structs-and-unions}@anchor{9c}
+@subsection Working with pointers, structs and unions
+
+
+@geindex gcc_jit_rvalue_dereference (C function)
+@anchor{topics/expressions gcc_jit_rvalue_dereference}@anchor{9d}
+@deffn {C Function} gcc_jit_lvalue *           gcc_jit_rvalue_dereference (gcc_jit_rvalue@w{ }*rvalue, gcc_jit_location@w{ }*loc)
+
+Given an rvalue of pointer type @code{T *}, dereferencing the pointer,
+getting an lvalue of type @code{T}.  Analogous to:
+
+@example
+*(EXPR)
+@end example
+
+@noindent
+
+in C.
+@end deffn
+
+Field access is provided separately for both lvalues and rvalues.
+
+@geindex gcc_jit_lvalue_access_field (C function)
+@anchor{topics/expressions gcc_jit_lvalue_access_field}@anchor{9e}
+@deffn {C Function} gcc_jit_lvalue *           gcc_jit_lvalue_access_field (gcc_jit_lvalue@w{ }*struct_, gcc_jit_location@w{ }*loc, gcc_jit_field@w{ }*field)
+
+Given an lvalue of struct or union type, access the given field,
+getting an lvalue of the field's type.  Analogous to:
+
+@example
+(EXPR).field = ...;
+@end example
+
+@noindent
+
+in C.
+@end deffn
+
+@geindex gcc_jit_rvalue_access_field (C function)
+@anchor{topics/expressions gcc_jit_rvalue_access_field}@anchor{9f}
+@deffn {C Function} gcc_jit_rvalue *           gcc_jit_rvalue_access_field (gcc_jit_rvalue@w{ }*struct_, gcc_jit_location@w{ }*loc, gcc_jit_field@w{ }*field)
+
+Given an rvalue of struct or union type, access the given field
+as an rvalue.  Analogous to:
+
+@example
+(EXPR).field
+@end example
+
+@noindent
+
+in C.
+@end deffn
+
+@geindex gcc_jit_rvalue_dereference_field (C function)
+@anchor{topics/expressions gcc_jit_rvalue_dereference_field}@anchor{a0}
+@deffn {C Function} gcc_jit_lvalue *           gcc_jit_rvalue_dereference_field (gcc_jit_rvalue@w{ }*ptr, gcc_jit_location@w{ }*loc, gcc_jit_field@w{ }*field)
+
+Given an rvalue of pointer type @code{T *} where T is of struct or union
+type, access the given field as an lvalue.  Analogous to:
+
+@example
+(EXPR)->field
+@end example
+
+@noindent
+
+in C, itself equivalent to @code{(*EXPR).FIELD}.
+@end deffn
+
+@geindex gcc_jit_context_new_array_access (C function)
+@anchor{topics/expressions gcc_jit_context_new_array_access}@anchor{8e}
+@deffn {C Function} gcc_jit_lvalue *           gcc_jit_context_new_array_access (gcc_jit_context@w{ }*ctxt, gcc_jit_location@w{ }*loc, gcc_jit_rvalue@w{ }*ptr, gcc_jit_rvalue@w{ }*index)
+
+Given an rvalue of pointer type @code{T *}, get at the element @cite{T} at
+the given index, using standard C array indexing rules i.e. each
+increment of @code{index} corresponds to @code{sizeof(T)} bytes.
+Analogous to:
+
+@example
+PTR[INDEX]
+@end example
+
+@noindent
+
+in C (or, indeed, to @code{PTR + INDEX}).
+@end deffn
+
+@c Copyright (C) 2014 Free Software Foundation, Inc.
+@c Originally contributed by David Malcolm <dmalcolm@redhat.com>
+@c 
+@c This is free software: you can redistribute it and/or modify it
+@c under the terms of the GNU General Public License as published by
+@c the Free Software Foundation, either version 3 of the License, or
+@c (at your option) any later version.
+@c 
+@c This program is distributed in the hope that it will be useful, but
+@c WITHOUT ANY WARRANTY; without even the implied warranty of
+@c MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+@c General Public License for more details.
+@c 
+@c You should have received a copy of the GNU General Public License
+@c along with this program.  If not, see
+@c <http://www.gnu.org/licenses/>.
+
+@node Creating and using functions,Source Locations,Expressions,Topic Reference
+@anchor{topics/functions doc}@anchor{a1}@anchor{topics/functions creating-and-using-functions}@anchor{a2}
+@section Creating and using functions
+
+
+@menu
+* Params:: 
+* Functions:: 
+* Blocks:: 
+* Statements:: 
+
+@end menu
+
+@node Params,Functions,,Creating and using functions
+@anchor{topics/functions params}@anchor{a3}
+@subsection Params
+
+
+@geindex gcc_jit_param (C type)
+@anchor{topics/functions gcc_jit_param}@anchor{23}
+@deffn {C Type} gcc_jit_param
+
+A @cite{gcc_jit_param} represents a parameter to a function.
+@end deffn
+
+@geindex gcc_jit_context_new_param (C function)
+@anchor{topics/functions gcc_jit_context_new_param}@anchor{10}
+@deffn {C Function} gcc_jit_param *           gcc_jit_context_new_param (gcc_jit_context@w{ }*ctxt, gcc_jit_location@w{ }*loc, gcc_jit_type@w{ }*type, const char@w{ }*name)
+
+In preparation for creating a function, create a new parameter of the
+given type and name.
+@end deffn
+
+Parameters are lvalues, and thus are also rvalues (and objects), so the
+following upcasts are available:
+
+@geindex gcc_jit_param_as_lvalue (C function)
+@anchor{topics/functions gcc_jit_param_as_lvalue}@anchor{a4}
+@deffn {C Function} gcc_jit_lvalue *            gcc_jit_param_as_lvalue (gcc_jit_param@w{ }*param)
+
+Upcasting from param to lvalue.
+@end deffn
+
+@geindex gcc_jit_param_as_rvalue (C function)
+@anchor{topics/functions gcc_jit_param_as_rvalue}@anchor{a5}
+@deffn {C Function} gcc_jit_rvalue *            gcc_jit_param_as_rvalue (gcc_jit_param@w{ }*param)
+
+Upcasting from param to rvalue.
+@end deffn
+
+@geindex gcc_jit_param_as_object (C function)
+@anchor{topics/functions gcc_jit_param_as_object}@anchor{a6}
+@deffn {C Function} gcc_jit_object *            gcc_jit_param_as_object (gcc_jit_param@w{ }*param)
+
+Upcasting from param to object.
+@end deffn
+
+@node Functions,Blocks,Params,Creating and using functions
+@anchor{topics/functions functions}@anchor{a7}
+@subsection Functions
+
+
+@geindex gcc_jit_function (C type)
+@anchor{topics/functions gcc_jit_function}@anchor{27}
+@deffn {C Type} gcc_jit_function
+
+A @cite{gcc_jit_function} represents a function - either one that we're
+creating ourselves, or one that we're referencing.
+@end deffn
+
+@geindex gcc_jit_context_new_function (C function)
+@anchor{topics/functions gcc_jit_context_new_function}@anchor{11}
+@deffn {C Function} gcc_jit_function *            gcc_jit_context_new_function (gcc_jit_context@w{ }*ctxt, gcc_jit_location@w{ }*loc, enum gcc_jit_function_kind@w{ }kind, gcc_jit_type@w{ }*return_type, const char@w{ }*name, int@w{ }num_params, gcc_jit_param@w{ }**params, int@w{ }is_variadic)
+
+Create a gcc_jit_function with the given name and parameters.
+
+@geindex gcc_jit_function_kind (C type)
+@anchor{topics/functions gcc_jit_function_kind}@anchor{a8}
+@deffn {C Type} enum gcc_jit_function_kind
+@end deffn
+
+This enum controls the kind of function created, and has the following
+values:
+
+@quotation
+
+@geindex GCC_JIT_FUNCTION_EXPORTED (C macro)
+@anchor{topics/functions GCC_JIT_FUNCTION_EXPORTED}@anchor{a9}
+@deffn {C Macro} GCC_JIT_FUNCTION_EXPORTED
+
+Function is defined by the client code and visible
+by name outside of the JIT.
+@end deffn
+
+@geindex GCC_JIT_FUNCTION_INTERNAL (C macro)
+@anchor{topics/functions GCC_JIT_FUNCTION_INTERNAL}@anchor{aa}
+@deffn {C Macro} GCC_JIT_FUNCTION_INTERNAL
+
+Function is defined by the client code, but is invisible
+outside of the JIT.  Analogous to a "static" function.
+@end deffn
+
+@geindex GCC_JIT_FUNCTION_IMPORTED (C macro)
+@anchor{topics/functions GCC_JIT_FUNCTION_IMPORTED}@anchor{ab}
+@deffn {C Macro} GCC_JIT_FUNCTION_IMPORTED
+
+Function is not defined by the client code; we're merely
+referring to it.  Analogous to using an "extern" function from a
+header file.
+@end deffn
+
+@geindex GCC_JIT_FUNCTION_ALWAYS_INLINE (C macro)
+@anchor{topics/functions GCC_JIT_FUNCTION_ALWAYS_INLINE}@anchor{ac}
+@deffn {C Macro} GCC_JIT_FUNCTION_ALWAYS_INLINE
+
+Function is only ever inlined into other functions, and is
+invisible outside of the JIT.
+
+Analogous to prefixing with @code{inline} and adding
+@code{__attribute__((always_inline))}
+
+Inlining will only occur when the optimization level is
+above 0; when optimization is off, this is essentially the
+same as GCC_JIT_FUNCTION_INTERNAL.
+@end deffn
+@end quotation
+@end deffn
+
+@geindex gcc_jit_context_get_builtin_function (C function)
+@anchor{topics/functions gcc_jit_context_get_builtin_function}@anchor{ad}
+@deffn {C Function} gcc_jit_function *gcc_jit_context_get_builtin_function (gcc_jit_context@w{ }*ctxt, const char@w{ }*name)
+@end deffn
+
+@geindex gcc_jit_function_as_object (C function)
+@anchor{topics/functions gcc_jit_function_as_object}@anchor{ae}
+@deffn {C Function} gcc_jit_object *           gcc_jit_function_as_object (gcc_jit_function@w{ }*func)
+
+Upcasting from function to object.
+@end deffn
+
+@geindex gcc_jit_function_get_param (C function)
+@anchor{topics/functions gcc_jit_function_get_param}@anchor{af}
+@deffn {C Function} gcc_jit_param *            gcc_jit_function_get_param (gcc_jit_function@w{ }*func, int@w{ }index)
+
+Get the param of the given index (0-based).
+@end deffn
+
+@geindex gcc_jit_function_dump_to_dot (C function)
+@anchor{topics/functions gcc_jit_function_dump_to_dot}@anchor{31}
+@deffn {C Function} void             gcc_jit_function_dump_to_dot (gcc_jit_function@w{ }*func, const char@w{ }*path)
+
+Emit the function in graphviz format to the given path.
+@end deffn
+
+@geindex gcc_jit_function_new_local (C function)
+@anchor{topics/functions gcc_jit_function_new_local}@anchor{24}
+@deffn {C Function} gcc_jit_lvalue *           gcc_jit_function_new_local (gcc_jit_function@w{ }*func, gcc_jit_location@w{ }*loc, gcc_jit_type@w{ }*type, const char@w{ }*name)
+
+Create a new local variable within the function, of the given type and
+name.
+@end deffn
+
+@node Blocks,Statements,Functions,Creating and using functions
+@anchor{topics/functions blocks}@anchor{b0}
+@subsection Blocks
+
+
+@geindex gcc_jit_block (C type)
+@anchor{topics/functions gcc_jit_block}@anchor{26}
+@deffn {C Type} gcc_jit_block
+
+A @cite{gcc_jit_block} represents a basic block within a function  i.e. a
+sequence of statements with a single entry point and a single exit
+point.
+
+The first basic block that you create within a function will
+be the entrypoint.
+
+Each basic block that you create within a function must be
+terminated, either with a conditional, a jump, or a return.
+
+It's legal to have multiple basic blocks that return within
+one function.
+@end deffn
+
+@geindex gcc_jit_function_new_block (C function)
+@anchor{topics/functions gcc_jit_function_new_block}@anchor{b1}
+@deffn {C Function} gcc_jit_block *            gcc_jit_function_new_block (gcc_jit_function@w{ }*func, const char@w{ }*name)
+
+Create a basic block of the given name.  The name may be NULL, but
+providing meaningful names is often helpful when debugging: it may
+show up in dumps of the internal representation, and in error
+messages.
+@end deffn
+
+@geindex gcc_jit_block_as_object (C function)
+@anchor{topics/functions gcc_jit_block_as_object}@anchor{b2}
+@deffn {C Function} gcc_jit_object *            gcc_jit_block_as_object (gcc_jit_block@w{ }*block)
+
+Upcast from block to object.
+@end deffn
+
+@geindex gcc_jit_block_get_function (C function)
+@anchor{topics/functions gcc_jit_block_get_function}@anchor{b3}
+@deffn {C Function} gcc_jit_function *            gcc_jit_block_get_function (gcc_jit_block@w{ }*block)
+
+Which function is this block within?
+@end deffn
+
+@node Statements,,Blocks,Creating and using functions
+@anchor{topics/functions statements}@anchor{b4}
+@subsection Statements
+
+
+@geindex gcc_jit_block_add_eval (C function)
+@anchor{topics/functions gcc_jit_block_add_eval}@anchor{93}
+@deffn {C Function} void           gcc_jit_block_add_eval (gcc_jit_block@w{ }*block, gcc_jit_location@w{ }*loc, gcc_jit_rvalue@w{ }*rvalue)
+
+Add evaluation of an rvalue, discarding the result
+(e.g. a function call that "returns" void).
+
+This is equivalent to this C code:
+
+@example
+(void)expression;
+@end example
+
+@noindent
+@end deffn
+
+@geindex gcc_jit_block_add_assignment (C function)
+@anchor{topics/functions gcc_jit_block_add_assignment}@anchor{28}
+@deffn {C Function} void           gcc_jit_block_add_assignment (gcc_jit_block@w{ }*block, gcc_jit_location@w{ }*loc, gcc_jit_lvalue@w{ }*lvalue, gcc_jit_rvalue@w{ }*rvalue)
+
+Add evaluation of an rvalue, assigning the result to the given
+lvalue.
+
+This is roughly equivalent to this C code:
+
+@example
+lvalue = rvalue;
+@end example
+
+@noindent
+@end deffn
+
+@geindex gcc_jit_block_add_assignment_op (C function)
+@anchor{topics/functions gcc_jit_block_add_assignment_op}@anchor{2c}
+@deffn {C Function} void           gcc_jit_block_add_assignment_op (gcc_jit_block@w{ }*block, gcc_jit_location@w{ }*loc, gcc_jit_lvalue@w{ }*lvalue, enum gcc_jit_binary_op@w{ }op, gcc_jit_rvalue@w{ }*rvalue)
+
+Add evaluation of an rvalue, using the result to modify an
+lvalue.
+
+This is analogous to "+=" and friends:
+
+@example
+lvalue += rvalue;
+lvalue *= rvalue;
+lvalue /= rvalue;
+@end example
+
+@noindent
+
+etc.  For example:
+
+@example
+/* "i++" */
+gcc_jit_block_add_assignment_op (
+  loop_body, NULL,
+  i,
+  GCC_JIT_BINARY_OP_PLUS,
+  gcc_jit_context_one (ctxt, int_type));
+@end example
+
+@noindent
+@end deffn
+
+@geindex gcc_jit_block_add_comment (C function)
+@anchor{topics/functions gcc_jit_block_add_comment}@anchor{3a}
+@deffn {C Function} void           gcc_jit_block_add_comment (gcc_jit_block@w{ }*block, gcc_jit_location@w{ }*loc, const char@w{ }*text)
+
+Add a no-op textual comment to the internal representation of the
+code.  It will be optimized away, but will be visible in the dumps
+seen via @pxref{57,,GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE}
+and @pxref{1a,,GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE},
+and thus may be of use when debugging how your project's internal
+representation gets converted to the libgccjit IR.
+@end deffn
+
+@geindex gcc_jit_block_end_with_conditional (C function)
+@anchor{topics/functions gcc_jit_block_end_with_conditional}@anchor{2b}
+@deffn {C Function} void           gcc_jit_block_end_with_conditional (gcc_jit_block@w{ }*block, gcc_jit_location@w{ }*loc, gcc_jit_rvalue@w{ }*boolval, gcc_jit_block@w{ }*on_true, gcc_jit_block@w{ }*on_false)
+
+Terminate a block by adding evaluation of an rvalue, branching on the
+result to the appropriate successor block.
+
+This is roughly equivalent to this C code:
+
+@example
+if (boolval)
+  goto on_true;
+else
+  goto on_false;
+@end example
+
+@noindent
+
+block, boolval, on_true, and on_false must be non-NULL.
+@end deffn
+
+@geindex gcc_jit_block_end_with_jump (C function)
+@anchor{topics/functions gcc_jit_block_end_with_jump}@anchor{b5}
+@deffn {C Function} void           gcc_jit_block_end_with_jump (gcc_jit_block@w{ }*block, gcc_jit_location@w{ }*loc, gcc_jit_block@w{ }*target)
+
+Terminate a block by adding a jump to the given target block.
+
+This is roughly equivalent to this C code:
+
+@example
+goto target;
+@end example
+
+@noindent
+@end deffn
+
+@geindex gcc_jit_block_end_with_return (C function)
+@anchor{topics/functions gcc_jit_block_end_with_return}@anchor{b6}
+@deffn {C Function} void           gcc_jit_block_end_with_return (gcc_jit_block@w{ }*block, gcc_jit_location@w{ }*loc, gcc_jit_rvalue@w{ }*rvalue)
+
+Terminate a block by adding evaluation of an rvalue, returning the value.
+
+This is roughly equivalent to this C code:
+
+@example
+return expression;
+@end example
+
+@noindent
+@end deffn
+
+@geindex gcc_jit_block_end_with_void_return (C function)
+@anchor{topics/functions gcc_jit_block_end_with_void_return}@anchor{b7}
+@deffn {C Function} void           gcc_jit_block_end_with_void_return (gcc_jit_block@w{ }*block, gcc_jit_location@w{ }*loc)
+
+Terminate a block by adding a valueless return, for use within a function
+with "void" return type.
+
+This is equivalent to this C code:
+
+@example
+return;
+@end example
+
+@noindent
+@end deffn
+
+@c Copyright (C) 2014 Free Software Foundation, Inc.
+@c Originally contributed by David Malcolm <dmalcolm@redhat.com>
+@c 
+@c This is free software: you can redistribute it and/or modify it
+@c under the terms of the GNU General Public License as published by
+@c the Free Software Foundation, either version 3 of the License, or
+@c (at your option) any later version.
+@c 
+@c This program is distributed in the hope that it will be useful, but
+@c WITHOUT ANY WARRANTY; without even the implied warranty of
+@c MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+@c General Public License for more details.
+@c 
+@c You should have received a copy of the GNU General Public License
+@c along with this program.  If not, see
+@c <http://www.gnu.org/licenses/>.
+
+@node Source Locations,Compilation results,Creating and using functions,Topic Reference
+@anchor{topics/locations source-locations}@anchor{b8}@anchor{topics/locations doc}@anchor{b9}
+@section Source Locations
+
+
+@geindex gcc_jit_location (C type)
+@anchor{topics/locations gcc_jit_location}@anchor{38}
+@deffn {C Type} gcc_jit_location
+
+A @cite{gcc_jit_location} encapsulates a source code location, so that
+you can (optionally) associate locations in your language with
+statements in the JIT-compiled code, allowing the debugger to
+single-step through your language.
+
+@cite{gcc_jit_location} instances are optional: you can always pass NULL to
+any API entrypoint accepting one.
+
+You can construct them using @pxref{3e,,gcc_jit_context_new_location()}.
+
+You need to enable @pxref{3f,,GCC_JIT_BOOL_OPTION_DEBUGINFO} on the
+@pxref{8,,gcc_jit_context} for these locations to actually be usable by
+the debugger:
+
+@example
+gcc_jit_context_set_bool_option (
+  ctxt,
+  GCC_JIT_BOOL_OPTION_DEBUGINFO,
+  1);
+@end example
+
+@noindent
+@end deffn
+
+@geindex gcc_jit_context_new_location (C function)
+@anchor{topics/locations gcc_jit_context_new_location}@anchor{3e}
+@deffn {C Function} gcc_jit_location *           gcc_jit_context_new_location (gcc_jit_context@w{ }*ctxt, const char@w{ }*filename, int@w{ }line, int@w{ }column)
+
+Create a @cite{gcc_jit_location} instance representing the given source
+location.
+@end deffn
+
+@menu
+* Faking it:: 
+
+@end menu
+
+@node Faking it,,,Source Locations
+@anchor{topics/locations faking-it}@anchor{ba}
+@subsection Faking it
+
+
+If you don't have source code for your internal representation, but need
+to debug, you can generate a C-like representation of the functions in
+your context using @pxref{4f,,gcc_jit_context_dump_to_file()}:
+
+@example
+gcc_jit_context_dump_to_file (ctxt, "/tmp/something.c",
+                              1 /* update_locations */);
+@end example
+
+@noindent
+
+This will dump C-like code to the given path.  If the @cite{update_locations}
+argument is true, this will also set up @cite{gcc_jit_location} information
+throughout the context, pointing at the dump file as if it were a source
+file, giving you @emph{something} you can step through in the debugger.
+
+@c Copyright (C) 2014 Free Software Foundation, Inc.
+@c Originally contributed by David Malcolm <dmalcolm@redhat.com>
+@c 
+@c This is free software: you can redistribute it and/or modify it
+@c under the terms of the GNU General Public License as published by
+@c the Free Software Foundation, either version 3 of the License, or
+@c (at your option) any later version.
+@c 
+@c This program is distributed in the hope that it will be useful, but
+@c WITHOUT ANY WARRANTY; without even the implied warranty of
+@c MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+@c General Public License for more details.
+@c 
+@c You should have received a copy of the GNU General Public License
+@c along with this program.  If not, see
+@c <http://www.gnu.org/licenses/>.
+
+@node Compilation results,,Source Locations,Topic Reference
+@anchor{topics/results compilation-results}@anchor{bb}@anchor{topics/results doc}@anchor{bc}
+@section Compilation results
+
+
+@geindex gcc_jit_result (C type)
+@anchor{topics/results gcc_jit_result}@anchor{16}
+@deffn {C Type} gcc_jit_result
+
+A @cite{gcc_jit_result} encapsulates the result of compiling a context.
+@end deffn
+
+@geindex gcc_jit_context_compile (C function)
+@anchor{topics/results gcc_jit_context_compile}@anchor{15}
+@deffn {C Function} gcc_jit_result *           gcc_jit_context_compile (gcc_jit_context@w{ }*ctxt)
+
+This calls into GCC and builds the code, returning a
+@cite{gcc_jit_result *}.
+@end deffn
+
+@geindex gcc_jit_result_get_code (C function)
+@anchor{topics/results gcc_jit_result_get_code}@anchor{17}
+@deffn {C Function} void *           gcc_jit_result_get_code (gcc_jit_result@w{ }*result, const char@w{ }*funcname)
+
+Locate a given function within the built machine code.
+This will need to be cast to a function pointer of the
+correct type before it can be called.
+@end deffn
+
+@geindex gcc_jit_result_release (C function)
+@anchor{topics/results gcc_jit_result_release}@anchor{bd}
+@deffn {C Function} void           gcc_jit_result_release (gcc_jit_result@w{ }*result)
+
+Once we're done with the code, this unloads the built .so file.
+This cleans up the result; after calling this, it's no longer
+valid to use the result.
+@end deffn
+
+@c Copyright (C) 2014 Free Software Foundation, Inc.
+@c Originally contributed by David Malcolm <dmalcolm@redhat.com>
+@c 
+@c This is free software: you can redistribute it and/or modify it
+@c under the terms of the GNU General Public License as published by
+@c the Free Software Foundation, either version 3 of the License, or
+@c (at your option) any later version.
+@c 
+@c This program is distributed in the hope that it will be useful, but
+@c WITHOUT ANY WARRANTY; without even the implied warranty of
+@c MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+@c General Public License for more details.
+@c 
+@c You should have received a copy of the GNU General Public License
+@c along with this program.  If not, see
+@c <http://www.gnu.org/licenses/>.
+
+@node Internals,Indices and tables,Topic Reference,Top
+@anchor{internals/index internals}@anchor{be}@anchor{internals/index doc}@anchor{bf}
+@chapter Internals
+
+
+@menu
+* Working on the JIT library:: 
+* Running the test suite:: 
+* Environment variables:: 
+* Overview of code structure:: 
+
+@end menu
+
+@node Working on the JIT library,Running the test suite,,Internals
+@anchor{internals/index working-on-the-jit-library}@anchor{c0}
+@section Working on the JIT library
+
+
+Having checked out the source code (to "src"), you can configure and build
+the JIT library like this:
+
+@example
+mkdir build
+mkdir install
+PREFIX=$(pwd)/install
+cd build
+../src/configure \
+   --enable-host-shared \
+   --enable-languages=jit \
+   --disable-bootstrap \
+   --enable-checking=release \
+   --prefix=$PREFIX
+nice make -j4 # altering the "4" to however many cores you have
+@end example
+
+@noindent
+
+This should build a libgccjit.so within jit/build/gcc:
+
+@example
+[build] $ file gcc/libgccjit.so*
+gcc/libgccjit.so:       symbolic link to `libgccjit.so.0'
+gcc/libgccjit.so.0:     symbolic link to `libgccjit.so.0.0.1'
+gcc/libgccjit.so.0.0.1: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, not stripped
+@end example
+
+@noindent
+
+Here's what those configuration options mean:
+
+@geindex command line option; --enable-host-shared
+@anchor{internals/index cmdoption--enable-host-shared}@anchor{c1}
+@deffn {Option} --enable-host-shared
+
+Configuring with this option means that the compiler is built as
+position-independent code, which incurs a slight performance hit,
+but it necessary for a shared library.
+@end deffn
+
+@geindex command line option; --enable-languages=jit
+@anchor{internals/index cmdoption--enable-languages}@anchor{c2}
+@deffn {Option} --enable-languages=jit
+
+This specifies which frontends to build.  The JIT library looks like
+a frontend to the rest of the code.
+@end deffn
+
+@geindex command line option; --disable-bootstrap
+@anchor{internals/index cmdoption--disable-bootstrap}@anchor{c3}
+@deffn {Option} --disable-bootstrap
+
+For hacking on the "jit" subdirectory, performing a full
+bootstrap can be overkill, since it's unused by a bootstrap.  However,
+when submitting patches, you should remove this option, to ensure that
+the compiler can still bootstrap itself.
+@end deffn
+
+@geindex command line option; --enable-checking=release
+@anchor{internals/index cmdoption--enable-checking}@anchor{c4}
+@deffn {Option} --enable-checking=release
+
+The compile can perform extensive self-checking as it runs, useful when
+debugging, but slowing things down.
+
+For maximum speed, configure with @code{--enable-checking=release} to
+disable this self-checking.
+@end deffn
+
+@node Running the test suite,Environment variables,Working on the JIT library,Internals
+@anchor{internals/index running-the-test-suite}@anchor{c5}
+@section Running the test suite
+
+
+@example
+[build] $ cd gcc
+[gcc] $ make check-jit RUNTESTFLAGS="-v -v -v"
+@end example
+
+@noindent
+
+A summary of the tests can then be seen in:
+
+@example
+jit/build/gcc/testsuite/jit/jit.sum
+@end example
+
+@noindent
+
+and detailed logs in:
+
+@example
+jit/build/gcc/testsuite/jit/jit.log
+@end example
+
+@noindent
+
+The test executables can be seen as:
+
+@example
+jit/build/gcc/testsuite/jit/*.exe
+@end example
+
+@noindent
+
+which can be run independently.
+
+You can compile and run individual tests by passing "jit.exp=TESTNAME" to RUNTESTFLAGS e.g.:
+
+@example
+[gcc] $ make check-jit RUNTESTFLAGS="-v -v -v jit.exp=test-factorial.c"
+@end example
+
+@noindent
+
+and once a test has been compiled, you can debug it directly:
+
+@example
+[gcc] $ PATH=.:$PATH \
+        LD_LIBRARY_PATH=. \
+        LIBRARY_PATH=. \
+          gdb --args \
+            testsuite/jit/test-factorial.exe
+@end example
+
+@noindent
+
+@node Environment variables,Overview of code structure,Running the test suite,Internals
+@anchor{internals/index environment-variables}@anchor{c6}
+@section Environment variables
+
+
+When running client code against a locally-built libgccjit, three
+environment variables need to be set up:
+
+@geindex environment variable; LD_LIBRARY_PATH
+@anchor{internals/index envvar-LD_LIBRARY_PATH}@anchor{c7}
+@deffn {Environment Variable} LD_LIBRARY_PATH
+
+@quotation
+
+@cite{libgccjit.so} is dynamically linked into client code, so if running
+against a locally-built library, @code{LD_LIBRARY_PATH} needs to be set
+up appropriately.  The library can be found within the "gcc"
+subdirectory of the build tree:
+@end quotation
+
+@example
+$ file libgccjit.so*
+libgccjit.so:       symbolic link to `libgccjit.so.0'
+libgccjit.so.0:     symbolic link to `libgccjit.so.0.0.1'
+libgccjit.so.0.0.1: ELF 64-bit LSB shared object, x86-64, version 1 (GNU/Linux), dynamically linked, not stripped
+@end example
+
+@noindent
+@end deffn
+
+@geindex environment variable; PATH
+@anchor{internals/index envvar-PATH}@anchor{c8}
+@deffn {Environment Variable} PATH
+
+The library uses a driver executable for converting from .s assembler
+files to .so shared libraries.  Specifically, it looks for a name
+expanded from
+@code{$@{target_noncanonical@}-gcc-$@{gcc_BASEVER@}$@{exeext@}}
+such as @code{x86_64-unknown-linux-gnu-gcc-5.0.0}.
+
+Hence @code{PATH} needs to include a directory where the library can
+locate this executable.
+
+The executable is normally installed to the installation bindir
+(e.g. /usr/bin), but a copy is also created within the "gcc"
+subdirectory of the build tree for running the testsuite, and for ease
+of development.
+@end deffn
+
+@geindex environment variable; LIBRARY_PATH
+@anchor{internals/index envvar-LIBRARY_PATH}@anchor{c9}
+@deffn {Environment Variable} LIBRARY_PATH
+
+The driver executable invokes the linker, and the latter needs to locate
+support libraries needed by the generated code, or you will see errors
+like:
+
+@example
+ld: cannot find crtbeginS.o: No such file or directory
+ld: cannot find -lgcc
+ld: cannot find -lgcc_s
+@end example
+
+@noindent
+
+Hence if running directly from a locally-built copy (without installing),
+@code{LIBRARY_PATH} needs to contain the "gcc" subdirectory of the build
+tree.
+@end deffn
+
+For example, to run a binary that uses the library against a non-installed
+build of the library in LIBGCCJIT_BUILD_DIR you need an invocation of the
+client code like this, to preprend the dir to each of the environment
+variables:
+
+@example
+$ LD_LIBRARY_PATH=$(LIBGCCJIT_BUILD_DIR):$(LD_LIBRARY_PATH) \
+  PATH=$(LIBGCCJIT_BUILD_DIR):$(PATH) \
+  LIBRARY_PATH=$(LIBGCCJIT_BUILD_DIR):$(LIBRARY_PATH) \
+    ./jit-hello-world
+hello world
+@end example
+
+@noindent
+
+@node Overview of code structure,,Environment variables,Internals
+@anchor{internals/index overview-of-code-structure}@anchor{ca}
+@section Overview of code structure
+
+
+
+@itemize *
+
+@item 
+@code{libgccjit.c} implements the API entrypoints.  It performs error
+checking, then calls into classes of the gcc::jit::recording namespace
+within @code{jit-recording.c} and @code{jit-recording.h}.
+
+@item 
+The gcc::jit::recording classes (within @code{jit-recording.c} and
+@code{jit-recording.h}) record the API calls that are made:
+
+@quotation
+
+@example
+
+  /* Indentation indicates inheritance: */
+  class context;
+  class builtins_manager; // declared within jit-builtins.h
+  class memento;
+    class string;
+    class location;
+    class type;
+      class function_type;
+      class compound_type;
+        class struct_;
+       class union_;
+    class field;
+    class fields;
+    class function;
+    class block;
+    class rvalue;
+      class lvalue;
+        class local;
+       class global;
+        class param;
+    class statement;
+
+
+@end example
+
+@noindent
+@end quotation
+
+@item 
+When the context is compiled, the gcc::jit::playback classes (within
+@code{jit-playback.c} and @code{jit-playback.h}) replay the API calls
+within langhook:parse_file:
+
+@quotation
+
+@example
+
+  /* Indentation indicates inheritance: */
+  class context;
+  class wrapper;
+    class type;
+      class compound_type;
+    class field;
+    class function;
+    class block;
+    class rvalue;
+      class lvalue;
+        class param;
+    class source_file;
+    class source_line;
+    class location;
+
+
+@end example
+
+@noindent
+
+@example
+Client Code   . Generated .            libgccjit.so
+              . code      .
+              .           . JIT API  . JIT "Frontend". (libbackend.a)
+....................................................................................
+   â”‚          .           .          .               .
+    â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€>      .               .
+              .           .    â”‚     .               .
+              .           .    V     .               .
+              .           .    â”€â”€> libgccjit.c       .
+              .           .        â”‚ (error-checking).
+              .           .        â”‚                 .
+              .           .        â”€â”€> jit-recording.c
+              .           .              (record API calls)
+              .           .    <───────              .
+              .           .    â”‚     .               .
+   <───────────────────────────      .               .
+   â”‚          .           .          .               .
+   â”‚          .           .          .               .
+   V          .           .  gcc_jit_context_compile .
+    â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€>      .               .
+              .           .    â”‚     .               .
+              .           .    â”‚ ACQUIRE MUTEX       .
+              .           .    â”‚     .               .
+              .           .    V───────────────────────> toplev::main (for now)
+              .           .          .               .       â”‚
+              .           .          .               .   (various code)
+              .           .          .               .       â”‚
+              .           .          .               .       V
+              .           .          .    <───────────────── langhook:parse_file
+              .           .          .    â”‚          .
+              .           .          .    â”‚ (jit_langhook_parse_file)
+              .           .          .    â”‚          .
+..........................................│..................VVVVVVVVVVVVV...
+              .           .          .    â”‚          .       No GC in here
+              .           .          .    â”‚ jit-playback.c
+              .           .          .    â”‚   (playback of API calls)
+              .           .          .    â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€> creation of functions,
+              .           .          .               .     types, expression trees
+              .           .          .    <──────────────── etc
+              .           .          .    â”‚(handle_locations: add locations to
+              .           .          .    â”‚ linemap and associate them with trees)
+              .           .          .    â”‚          .
+              .           .          .    â”‚          .       No GC in here
+..........................................│..................AAAAAAAAAAAAA...
+              .           .          .    â”‚ for each function
+              .           .          .    â”€â”€> postprocess
+              .           .          .        â”‚      .
+              .           .          .        â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€> cgraph_finalize_function
+              .           .          .        <────────────
+              .           .          .     <──       .
+              .           .          .    â”‚          .
+              .           .          .    â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€> (end of
+              .           .          .               .       â”‚ langhook_parse_file)
+              .           .          .               .       â”‚
+              .           .          .               .   (various code)
+              .           .          .               .       â”‚
+              .           .          .               .       â†“
+              .           .          .    <───────────────── langhook:write_globals
+              .           .          .    â”‚          .
+              .           .          .    â”‚ (jit_langhook_write_globals)
+              .           .          .    â”‚          .
+              .           .          .    â”‚          .
+              .           .          .    â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€> finalize_compilation_unit
+              .           .          .               .       â”‚
+              .           .          .               .   (the middle─end and backend)
+              .           .          .               .       â†“
+              .           .    <───────────────────────────── end of toplev::main
+              .           .    â”‚ RELEASE MUTEX       .
+              .           .    â”‚     .               .
+              .           .    â”‚ Convert assembler to DSO
+              .           .    â”‚     .               .
+              .           .    â”‚ Load DSO            .
+   <───────────────────────────      .               .
+   â”‚          .           .          .               .
+   Get (void*).           .          .               .
+   â”‚          .           .          .               .
+   â”‚ Call it  .           .          .               .
+   â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€>       .          .               .
+              .    â”‚      .          .               .
+              .    â”‚      .          .               .
+   <───────────────       .          .               .
+   â”‚          .           .          .               .
+   â”‚          .           .          .               .
+etc
+
+@end example
+
+@noindent
+@end quotation
+@end itemize
+
+Here is a high-level summary from @code{jit-common.h}:
+
+@quotation
+
+In order to allow jit objects to be usable outside of a compile
+whilst working with the existing structure of GCC's code the
+C API is implemented in terms of a gcc::jit::recording::context,
+which records the calls made to it.
+
+When a gcc_jit_context is compiled, the recording context creates a
+playback context.  The playback context invokes the bulk of the GCC
+code, and within the "frontend" parsing hook, plays back the recorded
+API calls, creating GCC tree objects.
+
+So there are two parallel families of classes: those relating to
+recording, and those relating to playback:
+
+
+@itemize *
+
+@item 
+Visibility: recording objects are exposed back to client code,
+whereas playback objects are internal to the library.
+
+@item 
+Lifetime: recording objects have a lifetime equal to that of the
+recording context that created them, whereas playback objects only
+exist within the frontend hook.
+
+@item 
+Memory allocation: recording objects are allocated by the recording
+context, and automatically freed by it when the context is released,
+whereas playback objects are allocated within the GC heap, and
+garbage-collected; they can own GC-references.
+
+@item 
+Integration with rest of GCC: recording objects are unrelated to the
+rest of GCC, whereas playback objects are wrappers around "tree"
+instances.  Hence you can't ask a recording rvalue or lvalue what its
+type is, whereas you can for a playback rvalue of lvalue (since it
+can work with the underlying GCC tree nodes).
+
+@item 
+Instancing: There can be multiple recording contexts "alive" at once
+(albeit it only one compiling at once), whereas there can only be one
+playback context alive at one time (since it interacts with the GC).
+@end itemize
+
+Ultimately if GCC could support multiple GC heaps and contexts, and
+finer-grained initialization, then this recording vs playback
+distinction could be eliminated.
+
+During a playback, we associate objects from the recording with
+their counterparts during this playback.  For simplicity, we store this
+within the recording objects, as @code{void *m_playback_obj}, casting it to
+the appropriate playback object subclass.  For these casts to make
+sense, the two class hierarchies need to have the same structure.
+
+Note that the playback objects that @code{m_playback_obj} points to are
+GC-allocated, but the recording objects don't own references:
+these associations only exist within a part of the code where
+the GC doesn't collect, and are set back to NULL before the GC can
+run.
+@end quotation
+
+This document describes libgccjit@footnote{http://gcc.gnu.org/wiki/JIT}, an API
+for embedding GCC inside programs and libraries.
+
+Note that libgccjit is currently of "Alpha" quality;
+the APIs are not yet set in stone, and they shouldn't be used in
+production yet.
+
+@node Indices and tables,Index,Internals,Top
+@anchor{index indices-and-tables}@anchor{cb}
+@unnumbered Indices and tables
+
+
+
+@itemize *
+
+@item 
+@emph{genindex}
+
+@item 
+@emph{modindex}
+
+@item 
+@emph{search}
+@end itemize
+
+@c Some notes:
+@c 
+@c The Sphinx C domain appears to lack explicit support for enum values,
+@c so I've been using :c:macro: for them.
+@c 
+@c See http://sphinx-doc.org/domains.html#the-c-domain
+
+@node Index,,Indices and tables,Top
+@unnumbered Index
+
+
+@printindex ge
+
+@c %**end of body
+@bye
diff --git a/gcc/jit/docs/_build/texinfo/sum-of-squares.png b/gcc/jit/docs/_build/texinfo/sum-of-squares.png
new file mode 100644 (file)
index 0000000..7a3b4af
Binary files /dev/null and b/gcc/jit/docs/_build/texinfo/sum-of-squares.png differ
diff --git a/gcc/jit/docs/conf.py b/gcc/jit/docs/conf.py
new file mode 100644 (file)
index 0000000..c300339
--- /dev/null
@@ -0,0 +1,258 @@
+# -*- coding: utf-8 -*-
+#
+# libgccjit documentation build configuration file, created by
+# sphinx-quickstart on Wed Jul 30 13:39:01 2014.
+#
+# This file is execfile()d with the current directory set to its containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+import sys, os
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#sys.path.insert(0, os.path.abspath('.'))
+
+# -- General configuration -----------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+#needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be extensions
+# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
+extensions = []
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The encoding of source files.
+#source_encoding = 'utf-8-sig'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'libgccjit'
+copyright = u'2014, Free Software Foundation'
+
+# GCC-specific: extract version information from "gcc" src subdir for
+# use in "version" and "release" below.
+def __read_file(name):
+    gcc_srcdir = '../..'
+    path = os.path.join(gcc_srcdir, name)
+    if os.path.exists(path):
+        return open(path).read().strip()
+    else:
+        return ''
+gcc_BASEVER = __read_file('BASE-VER')
+gcc_DEVPHASE = __read_file('DEV-PHASE')
+gcc_DATESTAMP = __read_file('DATESTAMP')
+gcc_REVISION = __read_file('REVISION')
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+version = gcc_BASEVER
+# The full version, including alpha/beta/rc tags.
+release = ('%s (%s %s%s)'
+           % (gcc_BASEVER, gcc_DEVPHASE, gcc_DATESTAMP,
+              (' %s' % gcc_REVISION) if gcc_REVISION else ''))
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#language = None
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+#today_fmt = '%B %d, %Y'
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+exclude_patterns = ['_build']
+
+# The reST default role (used for this markup: `text`) to use for all documents.
+#default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+# A list of ignored prefixes for module index sorting.
+#modindex_common_prefix = []
+
+
+# -- Options for HTML output ---------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages.  See the documentation for
+# a list of builtin themes.
+html_theme = 'pyramid'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further.  For a list of options available for each theme, see the
+# documentation.
+#html_theme_options = {}
+
+# Add any paths that contain custom themes here, relative to this directory.
+#html_theme_path = []
+
+# The name for this set of Sphinx documents.  If None, it defaults to
+# "<project> v<release> documentation".
+#html_title = None
+
+# A shorter title for the navigation bar.  Default is the same as html_title.
+#html_short_title = None
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+#html_logo = None
+
+# The name of an image file (within the static path) to use as favicon of the
+# docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+#html_favicon = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['_static']
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+#html_last_updated_fmt = '%b %d, %Y'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+#html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+#html_sidebars = {}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+#html_additional_pages = {}
+
+# If false, no module index is generated.
+#html_domain_indices = True
+
+# If false, no index is generated.
+#html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+#html_split_index = False
+
+# If true, links to the reST sources are added to the pages.
+#html_show_sourcelink = True
+
+# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
+#html_show_sphinx = True
+
+# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
+#html_show_copyright = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it.  The value of this option must be the
+# base URL from which the finished HTML is served.
+#html_use_opensearch = ''
+
+# This is the file name suffix for HTML files (e.g. ".xhtml").
+#html_file_suffix = None
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'libgccjitdoc'
+
+
+# -- Options for LaTeX output --------------------------------------------------
+
+latex_elements = {
+# The paper size ('letterpaper' or 'a4paper').
+#'papersize': 'letterpaper',
+
+# The font size ('10pt', '11pt' or '12pt').
+#'pointsize': '10pt',
+
+# Additional stuff for the LaTeX preamble.
+#'preamble': '',
+}
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title, author, documentclass [howto/manual]).
+latex_documents = [
+  ('index', 'libgccjit.tex', u'libgccjit Documentation',
+   u'David Malcolm', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+#latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#latex_use_parts = False
+
+# If true, show page references after internal links.
+#latex_show_pagerefs = False
+
+# If true, show URL addresses after external links.
+#latex_show_urls = False
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_domain_indices = True
+
+
+# -- Options for manual page output --------------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+    ('index', 'libgccjit', u'libgccjit Documentation',
+     [u'David Malcolm'], 1)
+]
+
+# If true, show URL addresses after external links.
+#man_show_urls = False
+
+
+# -- Options for Texinfo output ------------------------------------------------
+
+# Grouping the document tree into Texinfo files. List of tuples
+# (source start file, target name, title, author,
+#  dir menu entry, description, category)
+texinfo_documents = [
+  ('index', 'libgccjit', u'libgccjit Documentation',
+   u'David Malcolm', 'libgccjit', 'One line description of project.',
+   'Miscellaneous'),
+]
+
+# Documents to append as an appendix to all manuals.
+#texinfo_appendices = []
+
+# If false, no module index is generated.
+#texinfo_domain_indices = True
+
+# How to display URL addresses: 'footnote', 'no', or 'inline'.
+#texinfo_show_urls = 'footnote'
diff --git a/gcc/jit/docs/examples/tut01-hello-world.c b/gcc/jit/docs/examples/tut01-hello-world.c
new file mode 100644 (file)
index 0000000..49c9651
--- /dev/null
@@ -0,0 +1,123 @@
+/* Smoketest example for libgccjit.so
+   Copyright (C) 2014 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include <libgccjit.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+
+static void
+create_code (gcc_jit_context *ctxt)
+{
+  /* Let's try to inject the equivalent of:
+     void
+     greet (const char *name)
+     {
+        printf ("hello %s\n", name);
+     }
+  */
+  gcc_jit_type *void_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+  gcc_jit_type *const_char_ptr_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_CONST_CHAR_PTR);
+  gcc_jit_param *param_name =
+    gcc_jit_context_new_param (ctxt, NULL, const_char_ptr_type, "name");
+  gcc_jit_function *func =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                  GCC_JIT_FUNCTION_EXPORTED,
+                                  void_type,
+                                  "greet",
+                                  1, &param_name,
+                                  0);
+
+  gcc_jit_param *param_format =
+    gcc_jit_context_new_param (ctxt, NULL, const_char_ptr_type, "format");
+  gcc_jit_function *printf_func =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                 GCC_JIT_FUNCTION_IMPORTED,
+                                 gcc_jit_context_get_type (
+                                    ctxt, GCC_JIT_TYPE_INT),
+                                 "printf",
+                                 1, &param_format,
+                                 1);
+  gcc_jit_rvalue *args[2];
+  args[0] = gcc_jit_context_new_string_literal (ctxt, "hello %s\n");
+  args[1] = gcc_jit_param_as_rvalue (param_name);
+
+  gcc_jit_block *block = gcc_jit_function_new_block (func, NULL);
+
+  gcc_jit_block_add_eval (
+    block, NULL,
+    gcc_jit_context_new_call (ctxt,
+                              NULL,
+                              printf_func,
+                              2, args));
+  gcc_jit_block_end_with_void_return (block, NULL);
+}
+
+int
+main (int argc, char **argv)
+{
+  gcc_jit_context *ctxt;
+  gcc_jit_result *result;
+
+  /* Get a "context" object for working with the library.  */
+  ctxt = gcc_jit_context_acquire ();
+  if (!ctxt)
+    {
+      fprintf (stderr, "NULL ctxt");
+      exit (1);
+    }
+
+  /* Set some options on the context.
+     Let's see the code being generated, in assembler form.  */
+  gcc_jit_context_set_bool_option (
+    ctxt,
+    GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE,
+    0);
+
+  /* Populate the context.  */
+  create_code (ctxt);
+
+  /* Compile the code.  */
+  result = gcc_jit_context_compile (ctxt);
+  if (!result)
+    {
+      fprintf (stderr, "NULL result");
+      exit (1);
+    }
+
+  /* Extract the generated code from "result".  */
+  typedef void (*fn_type) (const char *);
+  fn_type greet =
+    (fn_type)gcc_jit_result_get_code (result, "greet");
+  if (!greet)
+    {
+      fprintf (stderr, "NULL greet");
+      exit (1);
+    }
+
+  /* Now call the generated function: */
+  greet ("world");
+  fflush (stdout);
+
+  gcc_jit_context_release (ctxt);
+  gcc_jit_result_release (result);
+  return 0;
+}
diff --git a/gcc/jit/docs/examples/tut02-square.c b/gcc/jit/docs/examples/tut02-square.c
new file mode 100644 (file)
index 0000000..5eae179
--- /dev/null
@@ -0,0 +1,107 @@
+/* Usage example for libgccjit.so
+   Copyright (C) 2014 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include <libgccjit.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+
+void
+create_code (gcc_jit_context *ctxt)
+{
+  /* Let's try to inject the equivalent of:
+
+      int square (int i)
+      {
+        return i * i;
+      }
+  */
+  gcc_jit_type *int_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+  gcc_jit_param *param_i =
+    gcc_jit_context_new_param (ctxt, NULL, int_type, "i");
+  gcc_jit_function *func =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                  GCC_JIT_FUNCTION_EXPORTED,
+                                  int_type,
+                                  "square",
+                                  1, &param_i,
+                                  0);
+
+  gcc_jit_block *block = gcc_jit_function_new_block (func, NULL);
+
+  gcc_jit_rvalue *expr =
+    gcc_jit_context_new_binary_op (
+      ctxt, NULL,
+      GCC_JIT_BINARY_OP_MULT, int_type,
+      gcc_jit_param_as_rvalue (param_i),
+      gcc_jit_param_as_rvalue (param_i));
+
+   gcc_jit_block_end_with_return (block, NULL, expr);
+}
+
+int
+main (int argc, char **argv)
+{
+  gcc_jit_context *ctxt = NULL;
+  gcc_jit_result *result = NULL;
+
+  /* Get a "context" object for working with the library.  */
+  ctxt = gcc_jit_context_acquire ();
+  if (!ctxt)
+    {
+      fprintf (stderr, "NULL ctxt");
+      goto error;
+    }
+
+  /* Set some options on the context.
+     Let's see the code being generated, in assembler form.  */
+  gcc_jit_context_set_bool_option (
+    ctxt,
+    GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE,
+    0);
+
+  /* Populate the context.  */
+  create_code (ctxt);
+
+  /* Compile the code.  */
+  result = gcc_jit_context_compile (ctxt);
+  if (!result)
+    {
+      fprintf (stderr, "NULL result");
+      goto error;
+    }
+
+  /* Extract the generated code from "result".  */
+  void *fn_ptr = gcc_jit_result_get_code (result, "square");
+  if (!fn_ptr)
+     {
+       fprintf (stderr, "NULL fn_ptr");
+       goto error;
+     }
+
+  typedef int (*fn_type) (int);
+  fn_type square = (fn_type)fn_ptr;
+  printf ("result: %d", square (5));
+
+ error:
+  gcc_jit_context_release (ctxt);
+  gcc_jit_result_release (result);
+  return 0;
+}
diff --git a/gcc/jit/docs/examples/tut03-sum-of-squares.c b/gcc/jit/docs/examples/tut03-sum-of-squares.c
new file mode 100644 (file)
index 0000000..594230b
--- /dev/null
@@ -0,0 +1,172 @@
+/* Usage example for libgccjit.so
+   Copyright (C) 2014 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include <libgccjit.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+
+void
+create_code (gcc_jit_context *ctxt)
+{
+  /*
+    Simple sum-of-squares, to test conditionals and looping
+
+    int loop_test (int n)
+    {
+      int i;
+      int sum = 0;
+      for (i = 0; i < n ; i ++)
+      {
+       sum += i * i;
+      }
+      return sum;
+   */
+  gcc_jit_type *the_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+  gcc_jit_type *return_type = the_type;
+
+  gcc_jit_param *n =
+    gcc_jit_context_new_param (ctxt, NULL, the_type, "n");
+  gcc_jit_param *params[1] = {n};
+  gcc_jit_function *func =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                 GCC_JIT_FUNCTION_EXPORTED,
+                                 return_type,
+                                 "loop_test",
+                                 1, params, 0);
+
+  /* Build locals:  */
+  gcc_jit_lvalue *i =
+    gcc_jit_function_new_local (func, NULL, the_type, "i");
+  gcc_jit_lvalue *sum =
+    gcc_jit_function_new_local (func, NULL, the_type, "sum");
+
+  gcc_jit_block *b_initial =
+    gcc_jit_function_new_block (func, "initial");
+  gcc_jit_block *b_loop_cond =
+    gcc_jit_function_new_block (func, "loop_cond");
+  gcc_jit_block *b_loop_body =
+    gcc_jit_function_new_block (func, "loop_body");
+  gcc_jit_block *b_after_loop =
+    gcc_jit_function_new_block (func, "after_loop");
+
+  /* sum = 0; */
+  gcc_jit_block_add_assignment (
+    b_initial, NULL,
+    sum,
+    gcc_jit_context_zero (ctxt, the_type));
+
+  /* i = 0; */
+  gcc_jit_block_add_assignment (
+    b_initial, NULL,
+    i,
+    gcc_jit_context_zero (ctxt, the_type));
+
+  gcc_jit_block_end_with_jump (b_initial, NULL, b_loop_cond);
+
+  /* if (i >= n) */
+  gcc_jit_block_end_with_conditional (
+    b_loop_cond, NULL,
+    gcc_jit_context_new_comparison (
+       ctxt, NULL,
+       GCC_JIT_COMPARISON_GE,
+       gcc_jit_lvalue_as_rvalue (i),
+       gcc_jit_param_as_rvalue (n)),
+    b_after_loop,
+    b_loop_body);
+
+  /* sum += i * i */
+  gcc_jit_block_add_assignment_op (
+    b_loop_body, NULL,
+    sum,
+    GCC_JIT_BINARY_OP_PLUS,
+    gcc_jit_context_new_binary_op (
+      ctxt, NULL,
+      GCC_JIT_BINARY_OP_MULT, the_type,
+      gcc_jit_lvalue_as_rvalue (i),
+      gcc_jit_lvalue_as_rvalue (i)));
+
+  /* i++ */
+  gcc_jit_block_add_assignment_op (
+    b_loop_body, NULL,
+    i,
+    GCC_JIT_BINARY_OP_PLUS,
+    gcc_jit_context_one (ctxt, the_type));
+
+  gcc_jit_block_end_with_jump (b_loop_body, NULL, b_loop_cond);
+
+  /* return sum */
+  gcc_jit_block_end_with_return (
+    b_after_loop,
+    NULL,
+    gcc_jit_lvalue_as_rvalue (sum));
+}
+
+int
+main (int argc, char **argv)
+{
+  gcc_jit_context *ctxt = NULL;
+  gcc_jit_result *result = NULL;
+
+  /* Get a "context" object for working with the library.  */
+  ctxt = gcc_jit_context_acquire ();
+  if (!ctxt)
+    {
+      fprintf (stderr, "NULL ctxt");
+      goto error;
+    }
+
+  /* Set some options on the context.
+     Let's see the code being generated, in assembler form.  */
+  gcc_jit_context_set_bool_option (
+    ctxt,
+    GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE,
+    0);
+
+  /* Populate the context.  */
+  create_code (ctxt);
+
+  /* Compile the code.  */
+  result = gcc_jit_context_compile (ctxt);
+  if (!result)
+    {
+      fprintf (stderr, "NULL result");
+      goto error;
+    }
+
+  /* Extract the generated code from "result".  */
+  typedef int (*loop_test_fn_type) (int);
+  loop_test_fn_type loop_test =
+    (loop_test_fn_type)gcc_jit_result_get_code (result, "loop_test");
+  if (!loop_test)
+    {
+      fprintf (stderr, "NULL loop_test");
+      goto error;
+    }
+
+  /* Run the generated code.  */
+  int val = loop_test (10);
+  printf("loop_test returned: %d\n", val);
+
+ error:
+  gcc_jit_context_release (ctxt);
+  gcc_jit_result_release (result);
+  return 0;
+}
diff --git a/gcc/jit/docs/examples/tut04-toyvm/Makefile b/gcc/jit/docs/examples/tut04-toyvm/Makefile
new file mode 100644 (file)
index 0000000..1b45c8d
--- /dev/null
@@ -0,0 +1,11 @@
+factorial: toyvm
+       ./toyvm factorial.toy 10
+
+fibonacci: toyvm
+       ./toyvm fibonacci.toy 8
+
+toyvm: toyvm.c Makefile
+       g++ -Wall -g -o $@ $< $(shell pkg-config --cflags --libs libgccjit)
+
+clean:
+       rm -f *.o toyvm
diff --git a/gcc/jit/docs/examples/tut04-toyvm/factorial.toy b/gcc/jit/docs/examples/tut04-toyvm/factorial.toy
new file mode 100644 (file)
index 0000000..48e4034
--- /dev/null
@@ -0,0 +1,50 @@
+# Simple recursive factorial implementation, roughly equivalent to:
+#
+#  int factorial (int arg)
+#  {
+#     if (arg < 2)
+#       return arg
+#     return arg * factorial (arg - 1)
+#  }
+
+# Initial state:
+# stack: [arg]
+
+# 0:
+DUP
+# stack: [arg, arg]
+
+# 1:
+PUSH_CONST 2
+# stack: [arg, arg, 2]
+
+# 2:
+BINARY_COMPARE_LT
+# stack: [arg, (arg < 2)]
+
+# 3:
+JUMP_ABS_IF_TRUE 9
+# stack: [arg]
+
+# 4:
+DUP
+# stack: [arg, arg]
+
+# 5:
+PUSH_CONST 1
+# stack: [arg, arg, 1]
+
+# 6:
+BINARY_SUBTRACT
+# stack: [arg,  (arg - 1)
+
+# 7:
+RECURSE
+# stack: [arg, factorial(arg - 1)]
+
+# 8:
+BINARY_MULT
+# stack: [arg * factorial(arg - 1)]
+
+# 9:
+RETURN
diff --git a/gcc/jit/docs/examples/tut04-toyvm/fibonacci.toy b/gcc/jit/docs/examples/tut04-toyvm/fibonacci.toy
new file mode 100644 (file)
index 0000000..5ae0a40
--- /dev/null
@@ -0,0 +1,66 @@
+# Simple recursive fibonacci implementation, roughly equivalent to:
+#
+#  int fibonacci (int arg)
+#  {
+#     if (arg < 2)
+#       return arg
+#     return fibonacci (arg-1) + fibonacci (arg-2)
+#  }
+
+# Initial state:
+# stack: [arg]
+
+# 0:
+DUP
+# stack: [arg, arg]
+
+# 1:
+PUSH_CONST 2
+# stack: [arg, arg, 2]
+
+# 2:
+BINARY_COMPARE_LT
+# stack: [arg, (arg < 2)]
+
+# 3:
+JUMP_ABS_IF_TRUE 13
+# stack: [arg]
+
+# 4:
+DUP
+# stack: [arg, arg]
+
+# 5:
+PUSH_CONST  1
+# stack: [arg, arg, 1]
+
+# 6:
+BINARY_SUBTRACT
+# stack: [arg,  (arg - 1)
+
+# 7:
+RECURSE
+# stack: [arg, fib(arg - 1)]
+
+# 8:
+ROT
+# stack: [fib(arg - 1), arg]
+
+# 9:
+PUSH_CONST  2
+# stack: [fib(arg - 1), arg, 2]
+
+# 10:
+BINARY_SUBTRACT
+# stack: [fib(arg - 1), arg,  (arg - 2)
+
+# 11:
+RECURSE
+# stack: [fib(arg - 1), fib(arg - 1)]
+
+# 12:
+BINARY_ADD
+# stack: [fib(arg - 1) + fib(arg - 1)]
+
+# 13:
+RETURN
diff --git a/gcc/jit/docs/examples/tut04-toyvm/toyvm.c b/gcc/jit/docs/examples/tut04-toyvm/toyvm.c
new file mode 100644 (file)
index 0000000..666bf2e
--- /dev/null
@@ -0,0 +1,861 @@
+/* A simple stack-based virtual machine to demonstrate
+   JIT-compilation.
+   Copyright (C) 2014 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <dejagnu.h>
+
+#include <libgccjit.h>
+
+/* Typedefs.  */
+typedef struct toyvm_op toyvm_op;
+typedef struct toyvm_function toyvm_function;
+typedef struct toyvm_frame toyvm_frame;
+typedef struct compilation_state compilation_state;
+
+/* Functions are compiled to this function ptr type.  */
+typedef int (*toyvm_compiled_func) (int);
+
+enum opcode {
+  /* Ops taking no operand.  */
+  DUP,
+  ROT,
+  BINARY_ADD,
+  BINARY_SUBTRACT,
+  BINARY_MULT,
+  BINARY_COMPARE_LT,
+  RECURSE,
+  RETURN,
+
+  /* Ops taking an operand.  */
+  PUSH_CONST,
+  JUMP_ABS_IF_TRUE
+};
+
+#define FIRST_UNARY_OPCODE (PUSH_CONST)
+
+const char * const opcode_names[] = {
+  "DUP",
+  "ROT",
+  "BINARY_ADD",
+  "BINARY_SUBTRACT",
+  "BINARY_MULT",
+  "BINARY_COMPARE_LT",
+  "RECURSE",
+  "RETURN",
+
+  "PUSH_CONST",
+  "JUMP_ABS_IF_TRUE",
+};
+
+struct toyvm_op
+{
+  /* Which operation.  */
+  enum opcode op_opcode;
+
+  /* Some opcodes take an argument.  */
+  int op_operand;
+
+  /* The line number of the operation within the source file.  */
+  int op_linenum;
+};
+
+#define MAX_OPS  (64)
+
+struct toyvm_function
+{
+  const char *fn_filename;
+  int         fn_num_ops;
+  toyvm_op    fn_ops[MAX_OPS];
+};
+
+#define MAX_STACK_DEPTH (8)
+
+struct toyvm_frame
+{
+  toyvm_function *frm_function;
+  int             frm_pc;
+  int             frm_stack[MAX_STACK_DEPTH];
+  int             frm_cur_depth;
+};
+
+static void
+add_op (toyvm_function *fn, enum opcode opcode,
+       int operand, int linenum)
+{
+  toyvm_op *op;
+  assert (fn->fn_num_ops < MAX_OPS);
+  op = &fn->fn_ops[fn->fn_num_ops++];
+  op->op_opcode = opcode;
+  op->op_operand = operand;
+  op->op_linenum = linenum;
+}
+
+static void
+add_unary_op (toyvm_function *fn, enum opcode opcode,
+             const char *rest_of_line, int linenum)
+{
+  int operand = atoi (rest_of_line);
+  add_op (fn, opcode, operand, linenum);
+}
+
+static toyvm_function *
+toyvm_function_parse (const char *filename, const char *name)
+{
+  FILE *f = NULL;
+  toyvm_function *fn = NULL;
+  char *line = NULL;
+  ssize_t linelen;
+  size_t bufsize;
+  int linenum = 0;
+
+  assert (filename);
+  assert (name);
+
+  f = fopen (filename, "r");
+  if (!f)
+    {
+      fprintf (stderr,
+              "cannot open file %s: %s\n",
+              filename, strerror (errno));
+      goto error;
+    }
+
+  fn = (toyvm_function *)calloc (1, sizeof (toyvm_function));
+  if (!fn)
+    {
+      fprintf (stderr, "out of memory allocating toyvm_function\n");
+      goto error;
+    }
+  fn->fn_filename = name;
+
+  /* Read the lines of the file.  */
+  while ((linelen = getline (&line, &bufsize, f)) != -1)
+    {
+      /* Note that this is a terrible parser, but it avoids the need to
+        bring in lex/yacc as a dependency.  */
+      linenum++;
+
+      if (0)
+       fprintf (stdout, "%3d: %s", linenum, line);
+
+      /* Lines beginning with # are comments.  */
+      if (line[0] == '#')
+       continue;
+
+      /* Skip blank lines.  */
+      if (line[0] == '\n')
+       continue;
+
+#define LINE_MATCHES(OPCODE) (0 == strncmp ((OPCODE), line, strlen (OPCODE)))
+      if (LINE_MATCHES ("DUP\n"))
+       add_op (fn, DUP, 0, linenum);
+      else if (LINE_MATCHES ("ROT\n"))
+       add_op (fn, ROT, 0, linenum);
+      else if (LINE_MATCHES ("BINARY_ADD\n"))
+       add_op (fn, BINARY_ADD, 0, linenum);
+      else if (LINE_MATCHES ("BINARY_SUBTRACT\n"))
+       add_op (fn, BINARY_SUBTRACT, 0, linenum);
+      else if (LINE_MATCHES ("BINARY_MULT\n"))
+       add_op (fn, BINARY_MULT, 0, linenum);
+      else if (LINE_MATCHES ("BINARY_COMPARE_LT\n"))
+       add_op (fn, BINARY_COMPARE_LT, 0, linenum);
+      else if (LINE_MATCHES ("RECURSE\n"))
+       add_op (fn, RECURSE, 0, linenum);
+      else if (LINE_MATCHES ("RETURN\n"))
+       add_op (fn, RETURN, 0, linenum);
+      else if (LINE_MATCHES ("PUSH_CONST "))
+       add_unary_op (fn, PUSH_CONST,
+                     line + strlen ("PUSH_CONST "), linenum);
+      else if (LINE_MATCHES ("JUMP_ABS_IF_TRUE "))
+       add_unary_op (fn, JUMP_ABS_IF_TRUE,
+                     line + strlen("JUMP_ABS_IF_TRUE "), linenum);
+      else
+       {
+         fprintf (stderr, "%s:%d: parse error\n", filename, linenum);
+         free (fn);
+         fn = NULL;
+         goto error;
+       }
+#undef LINE_MATCHES
+    }
+  free (line);
+  fclose (f);
+
+  return fn;
+
+ error:
+  free (line);
+  fclose (f);
+  free (fn);
+  return NULL;
+}
+
+static void
+toyvm_function_disassemble_op (toyvm_function *fn, toyvm_op *op, int index, FILE *out)
+{
+  fprintf (out, "%s:%d: index %d: %s",
+          fn->fn_filename, op->op_linenum, index,
+          opcode_names[op->op_opcode]);
+  if (op->op_opcode >= FIRST_UNARY_OPCODE)
+    fprintf (out, " %d", op->op_operand);
+  fprintf (out, "\n");
+}
+
+static void
+toyvm_function_disassemble (toyvm_function *fn, FILE *out)
+{
+  int i;
+  for (i = 0; i < fn->fn_num_ops; i++)
+    {
+      toyvm_op *op = &fn->fn_ops[i];
+      toyvm_function_disassemble_op (fn, op, i, out);
+    }
+}
+
+static void
+toyvm_frame_push (toyvm_frame *frame, int arg)
+{
+  assert (frame->frm_cur_depth < MAX_STACK_DEPTH);
+  frame->frm_stack[frame->frm_cur_depth++] = arg;
+}
+
+static int
+toyvm_frame_pop (toyvm_frame *frame)
+{
+  assert (frame->frm_cur_depth > 0);
+  return frame->frm_stack[--frame->frm_cur_depth];
+}
+
+static void
+toyvm_frame_dump_stack (toyvm_frame *frame, FILE *out)
+{
+  int i;
+  fprintf (out, "stack:");
+  for (i = 0; i < frame->frm_cur_depth; i++)
+    {
+      fprintf (out, " %d", frame->frm_stack[i]);
+    }
+  fprintf (out, "\n");
+}
+
+/* Execute the given function.  */
+
+static int
+toyvm_function_interpret (toyvm_function *fn, int arg, FILE *trace)
+{
+  toyvm_frame frame;
+#define PUSH(ARG) (toyvm_frame_push (&frame, (ARG)))
+#define POP(ARG) (toyvm_frame_pop (&frame))
+
+  frame.frm_function = fn;
+  frame.frm_pc = 0;
+  frame.frm_cur_depth = 0;
+
+  PUSH (arg);
+
+  while (1)
+    {
+      toyvm_op *op;
+      int x, y;
+      assert (frame.frm_pc < fn->fn_num_ops);
+      op = &fn->fn_ops[frame.frm_pc++];
+
+      if (trace)
+       {
+         toyvm_frame_dump_stack (&frame, trace);
+         toyvm_function_disassemble_op (fn, op, frame.frm_pc, trace);
+       }
+
+      switch (op->op_opcode)
+       {
+         /* Ops taking no operand.  */
+       case DUP:
+         x = POP ();
+         PUSH (x);
+         PUSH (x);
+         break;
+
+       case ROT:
+         y = POP ();
+         x = POP ();
+         PUSH (y);
+         PUSH (x);
+         break;
+
+       case BINARY_ADD:
+         y = POP ();
+         x = POP ();
+         PUSH (x + y);
+         break;
+
+       case BINARY_SUBTRACT:
+         y = POP ();
+         x = POP ();
+         PUSH (x - y);
+         break;
+
+       case BINARY_MULT:
+         y = POP ();
+         x = POP ();
+         PUSH (x * y);
+         break;
+
+       case BINARY_COMPARE_LT:
+         y = POP ();
+         x = POP ();
+         PUSH (x < y);
+         break;
+
+       case RECURSE:
+         x = POP ();
+         x = toyvm_function_interpret (fn, x, trace);
+         PUSH (x);
+         break;
+
+       case RETURN:
+         return POP ();
+
+         /* Ops taking an operand.  */
+       case PUSH_CONST:
+         PUSH (op->op_operand);
+         break;
+
+       case JUMP_ABS_IF_TRUE:
+         x = POP ();
+         if (x)
+           frame.frm_pc = op->op_operand;
+         break;
+
+       default:
+         assert (0); /* unknown opcode */
+
+       } /* end of switch on opcode */
+    } /* end of while loop */
+
+#undef PUSH
+#undef POP
+}
+
+/* JIT compilation.  */
+
+struct compilation_state
+{
+  gcc_jit_context *ctxt;
+
+  gcc_jit_type *int_type;
+  gcc_jit_type *bool_type;
+  gcc_jit_type *stack_type; /* int[MAX_STACK_DEPTH] */
+
+  gcc_jit_rvalue *const_one;
+
+  gcc_jit_function *fn;
+  gcc_jit_param *param_arg;
+  gcc_jit_lvalue *stack;
+  gcc_jit_lvalue *stack_depth;
+  gcc_jit_lvalue *x;
+  gcc_jit_lvalue *y;
+
+  gcc_jit_location *op_locs[MAX_OPS];
+  gcc_jit_block *initial_block;
+  gcc_jit_block *op_blocks[MAX_OPS];
+
+};
+
+/* Stack manipulation.  */
+
+static void
+add_push (compilation_state *state,
+         gcc_jit_block *block,
+         gcc_jit_rvalue *rvalue,
+         gcc_jit_location *loc)
+{
+  /* stack[stack_depth] = RVALUE */
+  gcc_jit_block_add_assignment (
+    block,
+    loc,
+    /* stack[stack_depth] */
+    gcc_jit_context_new_array_access (
+      state->ctxt,
+      loc,
+      gcc_jit_lvalue_as_rvalue (state->stack),
+      gcc_jit_lvalue_as_rvalue (state->stack_depth)),
+    rvalue);
+
+  /* "stack_depth++;".  */
+  gcc_jit_block_add_assignment_op (
+    block,
+    loc,
+    state->stack_depth,
+    GCC_JIT_BINARY_OP_PLUS,
+    state->const_one);
+}
+
+static void
+add_pop (compilation_state *state,
+        gcc_jit_block *block,
+        gcc_jit_lvalue *lvalue,
+        gcc_jit_location *loc)
+{
+  /* "--stack_depth;".  */
+  gcc_jit_block_add_assignment_op (
+    block,
+    loc,
+    state->stack_depth,
+    GCC_JIT_BINARY_OP_MINUS,
+    state->const_one);
+
+  /* "LVALUE = stack[stack_depth];".  */
+  gcc_jit_block_add_assignment (
+    block,
+    loc,
+    lvalue,
+    /* stack[stack_depth] */
+    gcc_jit_lvalue_as_rvalue (
+      gcc_jit_context_new_array_access (
+       state->ctxt,
+       loc,
+       gcc_jit_lvalue_as_rvalue (state->stack),
+       gcc_jit_lvalue_as_rvalue (state->stack_depth))));
+}
+
+/* The main compilation hook.  */
+
+static toyvm_compiled_func
+toyvm_function_compile (toyvm_function *fn)
+{
+  compilation_state state;
+  int pc;
+  char *funcname;
+
+  memset (&state, 0, sizeof (state));
+
+  /* Copy filename to funcname.  */
+  funcname = (char *)malloc (strlen (fn->fn_filename) + 1);
+  strcpy (funcname, fn->fn_filename);
+
+  /* Convert "." to NIL terminator.  */
+  *(strchr (funcname, '.')) = '\0';
+
+  state.ctxt = gcc_jit_context_acquire ();
+
+  gcc_jit_context_set_bool_option (state.ctxt,
+                                  GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE,
+                                  0);
+  gcc_jit_context_set_bool_option (state.ctxt,
+                                  GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE,
+                                  0);
+  gcc_jit_context_set_int_option (state.ctxt,
+                                 GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL,
+                                 3);
+  gcc_jit_context_set_bool_option (state.ctxt,
+                                  GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES,
+                                  0);
+  gcc_jit_context_set_bool_option (state.ctxt,
+                                  GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING,
+                                  0);
+  gcc_jit_context_set_bool_option (state.ctxt,
+                                  GCC_JIT_BOOL_OPTION_DEBUGINFO,
+                                  1);
+
+  /* Create types.  */
+  state.int_type =
+    gcc_jit_context_get_type (state.ctxt, GCC_JIT_TYPE_INT);
+  state.bool_type =
+    gcc_jit_context_get_type (state.ctxt, GCC_JIT_TYPE_BOOL);
+  state.stack_type =
+    gcc_jit_context_new_array_type (state.ctxt, NULL,
+                                   state.int_type, MAX_STACK_DEPTH);
+
+  /* The constant value 1.  */
+  state.const_one = gcc_jit_context_one (state.ctxt, state.int_type);
+
+  /* Create locations.  */
+  for (pc = 0; pc < fn->fn_num_ops; pc++)
+    {
+      toyvm_op *op = &fn->fn_ops[pc];
+
+      state.op_locs[pc] = gcc_jit_context_new_location (state.ctxt,
+                                                       fn->fn_filename,
+                                                       op->op_linenum,
+                                                       0); /* column */
+    }
+
+  /* Creating the function.  */
+  state.param_arg =
+    gcc_jit_context_new_param (state.ctxt, state.op_locs[0],
+                              state.int_type, "arg");
+  state.fn =
+    gcc_jit_context_new_function (state.ctxt,
+                                 state.op_locs[0],
+                                 GCC_JIT_FUNCTION_EXPORTED,
+                                 state.int_type,
+                                 funcname,
+                                 1, &state.param_arg, 0);
+
+  /* Create stack lvalues.  */
+  state.stack =
+    gcc_jit_function_new_local (state.fn, NULL,
+                               state.stack_type, "stack");
+  state.stack_depth =
+    gcc_jit_function_new_local (state.fn, NULL,
+                               state.int_type, "stack_depth");
+  state.x =
+    gcc_jit_function_new_local (state.fn, NULL,
+                               state.int_type, "x");
+  state.y =
+    gcc_jit_function_new_local (state.fn, NULL,
+                               state.int_type, "y");
+
+  /* 1st pass: create blocks, one per opcode. */
+
+  /* We need an entry block to do one-time initialization, so create that
+     first.  */
+  state.initial_block = gcc_jit_function_new_block (state.fn, "initial");
+
+  /* Create a block per operation.  */
+  for (pc = 0; pc < fn->fn_num_ops; pc++)
+    {
+      char buf[16];
+      sprintf (buf, "instr%i", pc);
+      state.op_blocks[pc] = gcc_jit_function_new_block (state.fn, buf);
+    }
+
+  /* Populate the initial block.  */
+
+  /* "stack_depth = 0;".  */
+  gcc_jit_block_add_assignment (
+    state.initial_block,
+    state.op_locs[0],
+    state.stack_depth,
+    gcc_jit_context_zero (state.ctxt, state.int_type));
+
+  /* "PUSH (arg);".  */
+  add_push (&state,
+           state.initial_block,
+           gcc_jit_param_as_rvalue (state.param_arg),
+           state.op_locs[0]);
+
+  /* ...and jump to insn 0.  */
+  gcc_jit_block_end_with_jump (state.initial_block,
+                              state.op_locs[0],
+                              state.op_blocks[0]);
+
+  /* 2nd pass: fill in instructions.  */
+  for (pc = 0; pc < fn->fn_num_ops; pc++)
+    {
+      gcc_jit_location *loc = state.op_locs[pc];
+
+      gcc_jit_block *block = state.op_blocks[pc];
+      gcc_jit_block *next_block = (pc < fn->fn_num_ops
+                                  ? state.op_blocks[pc + 1]
+                                  : NULL);
+
+      toyvm_op *op;
+      op = &fn->fn_ops[pc];
+
+      /* Helper macros.  */
+
+#define X_EQUALS_POP()\
+      add_pop (&state, block, state.x, loc)
+#define Y_EQUALS_POP()\
+      add_pop (&state, block, state.y, loc)
+#define PUSH_RVALUE(RVALUE)\
+      add_push (&state, block, (RVALUE), loc)
+#define PUSH_X()\
+      PUSH_RVALUE (gcc_jit_lvalue_as_rvalue (state.x))
+#define PUSH_Y() \
+      PUSH_RVALUE (gcc_jit_lvalue_as_rvalue (state.y))
+
+      gcc_jit_block_add_comment (block, loc, opcode_names[op->op_opcode]);
+
+      /* Handle the individual opcodes.  */
+
+      switch (op->op_opcode)
+       {
+       case DUP:
+         X_EQUALS_POP ();
+         PUSH_X ();
+         PUSH_X ();
+         break;
+
+       case ROT:
+         Y_EQUALS_POP ();
+         X_EQUALS_POP ();
+         PUSH_Y ();
+         PUSH_X ();
+         break;
+
+       case BINARY_ADD:
+         Y_EQUALS_POP ();
+         X_EQUALS_POP ();
+         PUSH_RVALUE (
+          gcc_jit_context_new_binary_op (
+            state.ctxt,
+            loc,
+            GCC_JIT_BINARY_OP_PLUS,
+            state.int_type,
+            gcc_jit_lvalue_as_rvalue (state.x),
+            gcc_jit_lvalue_as_rvalue (state.y)));
+         break;
+
+       case BINARY_SUBTRACT:
+         Y_EQUALS_POP ();
+         X_EQUALS_POP ();
+         PUSH_RVALUE (
+          gcc_jit_context_new_binary_op (
+            state.ctxt,
+            loc,
+            GCC_JIT_BINARY_OP_MINUS,
+            state.int_type,
+            gcc_jit_lvalue_as_rvalue (state.x),
+            gcc_jit_lvalue_as_rvalue (state.y)));
+         break;
+
+       case BINARY_MULT:
+         Y_EQUALS_POP ();
+         X_EQUALS_POP ();
+         PUSH_RVALUE (
+          gcc_jit_context_new_binary_op (
+            state.ctxt,
+            loc,
+            GCC_JIT_BINARY_OP_MULT,
+            state.int_type,
+            gcc_jit_lvalue_as_rvalue (state.x),
+            gcc_jit_lvalue_as_rvalue (state.y)));
+         break;
+
+       case BINARY_COMPARE_LT:
+         Y_EQUALS_POP ();
+         X_EQUALS_POP ();
+         PUSH_RVALUE (
+            /* cast of bool to int */
+            gcc_jit_context_new_cast (
+              state.ctxt,
+              loc,
+              /* (x < y) as a bool */
+              gcc_jit_context_new_comparison (
+                state.ctxt,
+                loc,
+                GCC_JIT_COMPARISON_LT,
+                gcc_jit_lvalue_as_rvalue (state.x),
+                gcc_jit_lvalue_as_rvalue (state.y)),
+              state.int_type));
+         break;
+
+       case RECURSE:
+         {
+           X_EQUALS_POP ();
+           gcc_jit_rvalue *arg = gcc_jit_lvalue_as_rvalue (state.x);
+           PUSH_RVALUE (
+             gcc_jit_context_new_call (
+               state.ctxt,
+               loc,
+               state.fn,
+               1, &arg));
+           break;
+         }
+
+       case RETURN:
+         X_EQUALS_POP ();
+         gcc_jit_block_end_with_return (
+           block,
+           loc,
+           gcc_jit_lvalue_as_rvalue (state.x));
+         break;
+
+         /* Ops taking an operand.  */
+       case PUSH_CONST:
+         PUSH_RVALUE (
+           gcc_jit_context_new_rvalue_from_int (
+             state.ctxt,
+             state.int_type,
+             op->op_operand));
+         break;
+
+       case JUMP_ABS_IF_TRUE:
+         X_EQUALS_POP ();
+         gcc_jit_block_end_with_conditional (
+           block,
+           loc,
+           /* "(bool)x".  */
+           gcc_jit_context_new_cast (
+             state.ctxt,
+             loc,
+             gcc_jit_lvalue_as_rvalue (state.x),
+             state.bool_type),
+           state.op_blocks[op->op_operand], /* on_true */
+           next_block); /* on_false */
+         break;
+
+       default:
+         assert(0);
+       } /* end of switch on opcode */
+
+      /* Go to the next block.  */
+      if (op->op_opcode != JUMP_ABS_IF_TRUE
+         && op->op_opcode != RETURN)
+       gcc_jit_block_end_with_jump (
+         block,
+         loc,
+         next_block);
+
+    } /* end of loop on PC locations.  */
+
+  /* We've now finished populating the context.  Compile it.  */
+  gcc_jit_result *result = gcc_jit_context_compile (state.ctxt);
+  gcc_jit_context_release (state.ctxt);
+
+  return (toyvm_compiled_func)gcc_jit_result_get_code (result,
+                                                      funcname);
+  /* (this leaks "result" and "funcname") */
+}
+
+char test[1024];
+
+#define CHECK_NON_NULL(PTR) \
+  do {                                       \
+    if ((PTR) != NULL)                       \
+      {                                      \
+       pass ("%s: %s is non-null", test, #PTR); \
+      }                                      \
+    else                                     \
+      {                                      \
+       fail ("%s: %s is NULL", test, #PTR); \
+       abort ();                            \
+    }                                        \
+  } while (0)
+
+#define CHECK_VALUE(ACTUAL, EXPECTED) \
+  do {                                       \
+    if ((ACTUAL) == (EXPECTED))              \
+      {                                      \
+       pass ("%s: actual: %s == expected: %s", test, #ACTUAL, #EXPECTED); \
+      }                                      \
+    else                                     \
+      {                                        \
+       fail ("%s: actual: %s != expected: %s", test, #ACTUAL, #EXPECTED); \
+       fprintf (stderr, "incorrect value\n"); \
+       abort ();                              \
+    }                                        \
+  } while (0)
+
+static void
+test_script (const char *scripts_dir, const char *script_name, int input,
+            int expected_result)
+{
+  char *script_path;
+  toyvm_function *fn;
+  int interpreted_result;
+  toyvm_compiled_func code;
+  int compiled_result;
+
+  snprintf (test, sizeof (test), "toyvm.c: %s", script_name);
+
+  script_path = (char *)malloc (strlen (scripts_dir)
+                               + strlen (script_name) + 1);
+  CHECK_NON_NULL (script_path);
+  sprintf (script_path, "%s%s", scripts_dir, script_name);
+
+  fn = toyvm_function_parse (script_path, script_name);
+  CHECK_NON_NULL (fn);
+
+  interpreted_result = toyvm_function_interpret (fn, input, NULL);
+  CHECK_VALUE (interpreted_result, expected_result);
+
+  code = toyvm_function_compile (fn);
+  CHECK_NON_NULL (code);
+
+  compiled_result = code (input);
+  CHECK_VALUE (compiled_result, expected_result);
+
+  free (script_path);
+}
+
+#define PATH_TO_SCRIPTS  ("/jit/docs/examples/tut04-toyvm/")
+
+static void
+test_suite (void)
+{
+  const char *srcdir;
+  char *scripts_dir;
+
+  snprintf (test, sizeof (test), "toyvm.c");
+
+  /* We need to locate the test scripts.
+     Rely on "srcdir" being set in the environment.  */
+
+  srcdir = getenv ("srcdir");
+  CHECK_NON_NULL (srcdir);
+
+  scripts_dir = (char *)malloc (strlen (srcdir) + strlen(PATH_TO_SCRIPTS)
+                               + 1);
+  CHECK_NON_NULL (scripts_dir);
+  sprintf (scripts_dir, "%s%s", srcdir, PATH_TO_SCRIPTS);
+
+  test_script (scripts_dir, "factorial.toy", 10, 3628800);
+  test_script (scripts_dir, "fibonacci.toy", 10, 55);
+
+  free (scripts_dir);
+}
+
+int
+main (int argc, char **argv)
+{
+  const char *filename = NULL;
+  toyvm_function *fn = NULL;
+
+  /* If called with no args, assume we're being run by the test suite.  */
+  if (argc < 3)
+    {
+      test_suite ();
+      return 0;
+    }
+
+  if (argc != 3)
+    {
+      fprintf (stdout,
+       "%s FILENAME INPUT: Parse and run a .toy file\n",
+       argv[0]);
+      exit (1);
+    }
+
+  filename = argv[1];
+  fn = toyvm_function_parse (filename, filename);
+  if (!fn)
+    exit (1);
+
+  if (0)
+    toyvm_function_disassemble (fn, stdout);
+
+  printf ("interpreter result: %d\n",
+         toyvm_function_interpret (fn, atoi (argv[2]), NULL));
+
+  /* JIT-compilation.  */
+  toyvm_compiled_func code = toyvm_function_compile (fn);
+  printf ("compiler result: %d\n",
+         code (atoi (argv[2])));
+
+ return 0;
+}
diff --git a/gcc/jit/docs/index.rst b/gcc/jit/docs/index.rst
new file mode 100644 (file)
index 0000000..ed75e36
--- /dev/null
@@ -0,0 +1,50 @@
+.. Copyright (C) 2014 Free Software Foundation, Inc.
+   Originally contributed by David Malcolm <dmalcolm@redhat.com>
+
+   This is free software: you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see
+   <http://www.gnu.org/licenses/>.
+
+libgccjit
+=========
+
+Contents:
+
+.. toctree::
+   :maxdepth: 2
+
+   intro/index.rst
+   topics/index.rst
+   internals/index.rst
+
+This document describes `libgccjit <http://gcc.gnu.org/wiki/JIT>`_, an API
+for embedding GCC inside programs and libraries.
+
+Note that libgccjit is currently of "Alpha" quality;
+the APIs are not yet set in stone, and they shouldn't be used in
+production yet.
+
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
+
+.. Some notes:
+
+   The Sphinx C domain appears to lack explicit support for enum values,
+   so I've been using :c:macro: for them.
+
+   See http://sphinx-doc.org/domains.html#the-c-domain
diff --git a/gcc/jit/docs/internals/index.rst b/gcc/jit/docs/internals/index.rst
new file mode 100644 (file)
index 0000000..80626e4
--- /dev/null
@@ -0,0 +1,216 @@
+.. Copyright (C) 2014 Free Software Foundation, Inc.
+   Originally contributed by David Malcolm <dmalcolm@redhat.com>
+
+   This is free software: you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see
+   <http://www.gnu.org/licenses/>.
+
+Internals
+=========
+
+Working on the JIT library
+--------------------------
+Having checked out the source code (to "src"), you can configure and build
+the JIT library like this:
+
+.. code-block:: bash
+
+  mkdir build
+  mkdir install
+  PREFIX=$(pwd)/install
+  cd build
+  ../src/configure \
+     --enable-host-shared \
+     --enable-languages=jit \
+     --disable-bootstrap \
+     --enable-checking=release \
+     --prefix=$PREFIX
+  nice make -j4 # altering the "4" to however many cores you have
+
+This should build a libgccjit.so within jit/build/gcc:
+
+.. code-block:: console
+
+ [build] $ file gcc/libgccjit.so*
+ gcc/libgccjit.so:       symbolic link to `libgccjit.so.0'
+ gcc/libgccjit.so.0:     symbolic link to `libgccjit.so.0.0.1'
+ gcc/libgccjit.so.0.0.1: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, not stripped
+
+Here's what those configuration options mean:
+
+.. option:: --enable-host-shared
+
+  Configuring with this option means that the compiler is built as
+  position-independent code, which incurs a slight performance hit,
+  but it necessary for a shared library.
+
+.. option:: --enable-languages=jit
+
+  This specifies which frontends to build.  The JIT library looks like
+  a frontend to the rest of the code.
+
+.. option:: --disable-bootstrap
+
+  For hacking on the "jit" subdirectory, performing a full
+  bootstrap can be overkill, since it's unused by a bootstrap.  However,
+  when submitting patches, you should remove this option, to ensure that
+  the compiler can still bootstrap itself.
+
+.. option:: --enable-checking=release
+
+  The compile can perform extensive self-checking as it runs, useful when
+  debugging, but slowing things down.
+
+  For maximum speed, configure with ``--enable-checking=release`` to
+  disable this self-checking.
+
+Running the test suite
+----------------------
+
+.. code-block:: console
+
+  [build] $ cd gcc
+  [gcc] $ make check-jit RUNTESTFLAGS="-v -v -v"
+
+A summary of the tests can then be seen in:
+
+.. code-block:: console
+
+  jit/build/gcc/testsuite/jit/jit.sum
+
+and detailed logs in:
+
+.. code-block:: console
+
+  jit/build/gcc/testsuite/jit/jit.log
+
+The test executables can be seen as:
+
+.. code-block:: console
+
+  jit/build/gcc/testsuite/jit/*.exe
+
+which can be run independently.
+
+You can compile and run individual tests by passing "jit.exp=TESTNAME" to RUNTESTFLAGS e.g.:
+
+.. code-block:: console
+
+   [gcc] $ make check-jit RUNTESTFLAGS="-v -v -v jit.exp=test-factorial.c"
+
+and once a test has been compiled, you can debug it directly:
+
+.. code-block:: console
+
+   [gcc] $ PATH=.:$PATH \
+           LD_LIBRARY_PATH=. \
+           LIBRARY_PATH=. \
+             gdb --args \
+               testsuite/jit/test-factorial.exe
+
+Environment variables
+---------------------
+When running client code against a locally-built libgccjit, three
+environment variables need to be set up:
+
+.. envvar:: LD_LIBRARY_PATH
+
+   `libgccjit.so` is dynamically linked into client code, so if running
+   against a locally-built library, ``LD_LIBRARY_PATH`` needs to be set
+   up appropriately.  The library can be found within the "gcc"
+   subdirectory of the build tree:
+
+  .. code-block:: console
+
+    $ file libgccjit.so*
+    libgccjit.so:       symbolic link to `libgccjit.so.0'
+    libgccjit.so.0:     symbolic link to `libgccjit.so.0.0.1'
+    libgccjit.so.0.0.1: ELF 64-bit LSB shared object, x86-64, version 1 (GNU/Linux), dynamically linked, not stripped
+
+.. envvar:: PATH
+
+  The library uses a driver executable for converting from .s assembler
+  files to .so shared libraries.  Specifically, it looks for a name
+  expanded from
+  ``${target_noncanonical}-gcc-${gcc_BASEVER}${exeext}``
+  such as ``x86_64-unknown-linux-gnu-gcc-5.0.0``.
+
+  Hence ``PATH`` needs to include a directory where the library can
+  locate this executable.
+
+  The executable is normally installed to the installation bindir
+  (e.g. /usr/bin), but a copy is also created within the "gcc"
+  subdirectory of the build tree for running the testsuite, and for ease
+  of development.
+
+.. envvar:: LIBRARY_PATH
+
+  The driver executable invokes the linker, and the latter needs to locate
+  support libraries needed by the generated code, or you will see errors
+  like:
+
+  .. code-block:: console
+
+    ld: cannot find crtbeginS.o: No such file or directory
+    ld: cannot find -lgcc
+    ld: cannot find -lgcc_s
+
+  Hence if running directly from a locally-built copy (without installing),
+  ``LIBRARY_PATH`` needs to contain the "gcc" subdirectory of the build
+  tree.
+
+For example, to run a binary that uses the library against a non-installed
+build of the library in LIBGCCJIT_BUILD_DIR you need an invocation of the
+client code like this, to preprend the dir to each of the environment
+variables:
+
+.. code-block:: console
+
+  $ LD_LIBRARY_PATH=$(LIBGCCJIT_BUILD_DIR):$(LD_LIBRARY_PATH) \
+    PATH=$(LIBGCCJIT_BUILD_DIR):$(PATH) \
+    LIBRARY_PATH=$(LIBGCCJIT_BUILD_DIR):$(LIBRARY_PATH) \
+      ./jit-hello-world
+  hello world
+
+Overview of code structure
+--------------------------
+
+* ``libgccjit.c`` implements the API entrypoints.  It performs error
+  checking, then calls into classes of the gcc::jit::recording namespace
+  within ``jit-recording.c`` and ``jit-recording.h``.
+
+* The gcc::jit::recording classes (within ``jit-recording.c`` and
+  ``jit-recording.h``) record the API calls that are made:
+
+   .. literalinclude:: ../../jit-common.h
+    :start-after: /* Recording types.  */
+    :end-before: /* End of recording types. */
+    :language: c++
+
+* When the context is compiled, the gcc::jit::playback classes (within
+  ``jit-playback.c`` and ``jit-playback.h``) replay the API calls
+  within langhook:parse_file:
+
+   .. literalinclude:: ../../jit-common.h
+    :start-after: /* Playback types.  */
+    :end-before: /* End of playback types. */
+    :language: c++
+
+   .. literalinclude:: ../../notes.txt
+    :lines: 1-
+
+Here is a high-level summary from ``jit-common.h``:
+
+.. include:: ../../jit-common.h
+  :start-after: This comment is included by the docs.
+  :end-before: End of comment for inclusion in the docs.  */
diff --git a/gcc/jit/docs/intro/factorial.png b/gcc/jit/docs/intro/factorial.png
new file mode 100644 (file)
index 0000000..dff47ce
Binary files /dev/null and b/gcc/jit/docs/intro/factorial.png differ
diff --git a/gcc/jit/docs/intro/index.rst b/gcc/jit/docs/intro/index.rst
new file mode 100644 (file)
index 0000000..d3bcec9
--- /dev/null
@@ -0,0 +1,27 @@
+.. Copyright (C) 2014 Free Software Foundation, Inc.
+   Originally contributed by David Malcolm <dmalcolm@redhat.com>
+
+   This is free software: you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see
+   <http://www.gnu.org/licenses/>.
+
+Tutorial
+========
+
+.. toctree::
+   :maxdepth: 2
+
+   tutorial01.rst
+   tutorial02.rst
+   tutorial03.rst
+   tutorial04.rst
diff --git a/gcc/jit/docs/intro/sum-of-squares.png b/gcc/jit/docs/intro/sum-of-squares.png
new file mode 100644 (file)
index 0000000..7a3b4af
Binary files /dev/null and b/gcc/jit/docs/intro/sum-of-squares.png differ
diff --git a/gcc/jit/docs/intro/tutorial01.rst b/gcc/jit/docs/intro/tutorial01.rst
new file mode 100644 (file)
index 0000000..b1a5128
--- /dev/null
@@ -0,0 +1,52 @@
+.. Copyright (C) 2014 Free Software Foundation, Inc.
+   Originally contributed by David Malcolm <dmalcolm@redhat.com>
+
+   This is free software: you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see
+   <http://www.gnu.org/licenses/>.
+
+.. default-domain:: c
+
+Tutorial part 1: "Hello world"
+==============================
+
+Before we look at the details of the API, let's look at building and
+running programs that use the library.
+
+Here's a toy "hello world" program that uses the library to synthesize
+a call to `printf` and uses it to write a message to stdout.
+
+Don't worry about the content of the program for now; we'll cover
+the details in later parts of this tutorial.
+
+   .. literalinclude:: ../examples/tut01-hello-world.c
+    :language: c
+
+Copy the above to `tut01-hello-world.c`.
+
+Assuming you have the jit library installed, build the test program
+using:
+
+.. code-block:: console
+
+  $ gcc \
+      tut01-hello-world.c \
+      -o tut01-hello-world \
+      -lgccjit
+
+You should then be able to run the built program:
+
+.. code-block:: console
+
+  $ ./tut01-hello-world
+  hello world
diff --git a/gcc/jit/docs/intro/tutorial02.rst b/gcc/jit/docs/intro/tutorial02.rst
new file mode 100644 (file)
index 0000000..f52499e
--- /dev/null
@@ -0,0 +1,349 @@
+.. Copyright (C) 2014 Free Software Foundation, Inc.
+   Originally contributed by David Malcolm <dmalcolm@redhat.com>
+
+   This is free software: you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see
+   <http://www.gnu.org/licenses/>.
+
+.. default-domain:: c
+
+Tutorial part 2: Creating a trivial machine code function
+---------------------------------------------------------
+
+Consider this C function:
+
+.. code-block:: c
+
+   int square (int i)
+   {
+     return i * i;
+   }
+
+How can we construct this at run-time using libgccjit?
+
+First we need to include the relevant header:
+
+.. code-block:: c
+
+  #include <libgccjit.h>
+
+All state associated with compilation is associated with a
+:c:type:`gcc_jit_context *`.
+
+Create one using :c:func:`gcc_jit_context_acquire`:
+
+.. code-block:: c
+
+  gcc_jit_context *ctxt;
+  ctxt = gcc_jit_context_acquire ();
+
+The JIT library has a system of types.  It is statically-typed: every
+expression is of a specific type, fixed at compile-time.  In our example,
+all of the expressions are of the C `int` type, so let's obtain this from
+the context, as a :c:type:`gcc_jit_type *`, using
+:c:func:`gcc_jit_context_get_type`:
+
+.. code-block:: c
+
+  gcc_jit_type *int_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+:c:type:`gcc_jit_type *` is an example of a "contextual" object: every
+entity in the API is associated with a :c:type:`gcc_jit_context *`.
+
+Memory management is easy: all such "contextual" objects are automatically
+cleaned up for you when the context is released, using
+:c:func:`gcc_jit_context_release`:
+
+.. code-block:: c
+
+  gcc_jit_context_release (ctxt);
+
+so you don't need to manually track and cleanup all objects, just the
+contexts.
+
+Although the API is C-based, there is a form of class hierarchy, which
+looks like this::
+
+  +- gcc_jit_object
+      +- gcc_jit_location
+      +- gcc_jit_type
+         +- gcc_jit_struct
+      +- gcc_jit_field
+      +- gcc_jit_function
+      +- gcc_jit_block
+      +- gcc_jit_rvalue
+          +- gcc_jit_lvalue
+             +- gcc_jit_param
+
+There are casting methods for upcasting from subclasses to parent classes.
+For example, :c:func:`gcc_jit_type_as_object`:
+
+.. code-block:: c
+
+   gcc_jit_object *obj = gcc_jit_type_as_object (int_type);
+
+One thing you can do with a :c:type:`gcc_jit_object *` is
+to ask it for a human-readable description, using
+:c:func:`gcc_jit_object_get_debug_string`:
+
+.. code-block:: c
+
+   printf ("obj: %s\n", gcc_jit_object_get_debug_string (obj));
+
+giving this text on stdout:
+
+.. code-block:: bash
+
+   obj: int
+
+This is invaluable when debugging.
+
+Let's create the function.  To do so, we first need to construct
+its single parameter, specifying its type and giving it a name,
+using :c:func:`gcc_jit_context_new_param`:
+
+.. code-block:: c
+
+  gcc_jit_param *param_i =
+    gcc_jit_context_new_param (ctxt, NULL, int_type, "i");
+
+Now we can create the function, using
+:c:func:`gcc_jit_context_new_function`:
+
+.. code-block:: c
+
+  gcc_jit_function *func =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                  GCC_JIT_FUNCTION_EXPORTED,
+                                  int_type,
+                                  "square",
+                                  1, &param_i,
+                                  0);
+
+To define the code within the function, we must create basic blocks
+containing statements.
+
+Every basic block contains a list of statements, eventually terminated
+by a statement that either returns, or jumps to another basic block.
+
+Our function has no control-flow, so we just need one basic block:
+
+.. code-block:: c
+
+  gcc_jit_block *block = gcc_jit_function_new_block (func, NULL);
+
+Our basic block is relatively simple: it immediately terminates by
+returning the value of an expression.
+
+We can build the expression using :c:func:`gcc_jit_context_new_binary_op`:
+
+.. code-block:: c
+
+   gcc_jit_rvalue *expr =
+     gcc_jit_context_new_binary_op (
+       ctxt, NULL,
+       GCC_JIT_BINARY_OP_MULT, int_type,
+       gcc_jit_param_as_rvalue (param_i),
+       gcc_jit_param_as_rvalue (param_i));
+
+A :c:type:`gcc_jit_rvalue *` is another example of a
+:c:type:`gcc_jit_object *` subclass.  We can upcast it using
+:c:func:`gcc_jit_rvalue_as_object` and as before print it with
+:c:func:`gcc_jit_object_get_debug_string`.
+
+.. code-block:: c
+
+   printf ("expr: %s\n",
+           gcc_jit_object_get_debug_string (
+             gcc_jit_rvalue_as_object (expr)));
+
+giving this output:
+
+.. code-block:: bash
+
+   expr: i * i
+
+Creating the expression in itself doesn't do anything; we have to add
+this expression to a statement within the block.  In this case, we use it
+to build a return statement, which terminates the basic block:
+
+.. code-block:: c
+
+  gcc_jit_block_end_with_return (block, NULL, expr);
+
+OK, we've populated the context.  We can now compile it using
+:c:func:`gcc_jit_context_compile`:
+
+.. code-block:: c
+
+   gcc_jit_result *result;
+   result = gcc_jit_context_compile (ctxt);
+
+and get a :c:type:`gcc_jit_result *`.
+
+We can now use :c:func:`gcc_jit_result_get_code` to look up a specific
+machine code routine within the result, in this case, the function we
+created above.
+
+.. code-block:: c
+
+   void *fn_ptr = gcc_jit_result_get_code (result, "square");
+   if (!fn_ptr)
+     {
+       fprintf (stderr, "NULL fn_ptr");
+       goto error;
+     }
+
+We can now cast the pointer to an appropriate function pointer type, and
+then call it:
+
+.. code-block:: c
+
+  typedef int (*fn_type) (int);
+  fn_type square = (fn_type)fn_ptr;
+  printf ("result: %d", square (5));
+
+.. code-block:: bash
+
+  result: 25
+
+
+Options
+*******
+
+To get more information on what's going on, you can set debugging flags
+on the context using :c:func:`gcc_jit_context_set_bool_option`.
+
+.. (I'm deliberately not mentioning
+    :c:macro:`GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE` here since I think
+    it's probably more of use to implementors than to users)
+
+Setting :c:macro:`GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE` will dump a
+C-like representation to stderr when you compile (GCC's "GIMPLE"
+representation):
+
+.. code-block:: c
+
+   gcc_jit_context_set_bool_option (
+     ctxt,
+     GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE,
+     1);
+   result = gcc_jit_context_compile (ctxt);
+
+.. code-block:: c
+
+  square (signed int i)
+  {
+    signed int D.260;
+
+    entry:
+    D.260 = i * i;
+    return D.260;
+  }
+
+We can see the generated machine code in assembler form (on stderr) by
+setting :c:macro:`GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE` on the context
+before compiling:
+
+.. code-block:: c
+
+  gcc_jit_context_set_bool_option (
+    ctxt,
+    GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE,
+    1);
+  result = gcc_jit_context_compile (ctxt);
+
+.. code-block:: gas
+
+        .file   "fake.c"
+        .text
+        .globl  square
+        .type   square, @function
+  square:
+  .LFB6:
+        .cfi_startproc
+        pushq   %rbp
+        .cfi_def_cfa_offset 16
+        .cfi_offset 6, -16
+        movq    %rsp, %rbp
+        .cfi_def_cfa_register 6
+        movl    %edi, -4(%rbp)
+  .L14:
+        movl    -4(%rbp), %eax
+        imull   -4(%rbp), %eax
+        popq    %rbp
+        .cfi_def_cfa 7, 8
+        ret
+        .cfi_endproc
+  .LFE6:
+        .size   square, .-square
+        .ident  "GCC: (GNU) 4.9.0 20131023 (Red Hat 0.2-0.5.1920c315ff984892399893b380305ab36e07b455.fc20)"
+        .section       .note.GNU-stack,"",@progbits
+
+By default, no optimizations are performed, the equivalent of GCC's
+`-O0` option.  We can turn things up to e.g. `-O3` by calling
+:c:func:`gcc_jit_context_set_int_option` with
+:c:macro:`GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL`:
+
+.. code-block:: c
+
+  gcc_jit_context_set_int_option (
+    ctxt,
+    GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL,
+    3);
+
+.. code-block:: gas
+
+        .file   "fake.c"
+        .text
+        .p2align 4,,15
+        .globl  square
+        .type   square, @function
+  square:
+  .LFB7:
+        .cfi_startproc
+  .L16:
+        movl    %edi, %eax
+        imull   %edi, %eax
+        ret
+        .cfi_endproc
+  .LFE7:
+        .size   square, .-square
+        .ident  "GCC: (GNU) 4.9.0 20131023 (Red Hat 0.2-0.5.1920c315ff984892399893b380305ab36e07b455.fc20)"
+        .section        .note.GNU-stack,"",@progbits
+
+Naturally this has only a small effect on such a trivial function.
+
+
+Full example
+************
+
+Here's what the above looks like as a complete program:
+
+   .. literalinclude:: ../examples/tut02-square.c
+    :lines: 1-
+    :language: c
+
+Building and running it:
+
+.. code-block:: console
+
+  $ gcc \
+      tut02-square.c \
+      -o tut02-square \
+      -lgccjit
+
+  # Run the built program:
+  $ ./tut02-square
+  result: 25
diff --git a/gcc/jit/docs/intro/tutorial03.rst b/gcc/jit/docs/intro/tutorial03.rst
new file mode 100644 (file)
index 0000000..0845150
--- /dev/null
@@ -0,0 +1,378 @@
+.. Copyright (C) 2014 Free Software Foundation, Inc.
+   Originally contributed by David Malcolm <dmalcolm@redhat.com>
+
+   This is free software: you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see
+   <http://www.gnu.org/licenses/>.
+
+Tutorial part 3: Loops and variables
+------------------------------------
+Consider this C function:
+
+ .. code-block:: c
+
+  int loop_test (int n)
+  {
+    int sum = 0;
+    for (int i = 0; i < n; i++)
+      sum += i * i;
+    return sum;
+  }
+
+This example demonstrates some more features of libgccjit, with local
+variables and a loop.
+
+To break this down into libgccjit terms, it's usually easier to reword
+the `for` loop as a `while` loop, giving:
+
+ .. code-block:: c
+
+  int loop_test (int n)
+  {
+    int sum = 0;
+    int i = 0;
+    while (i < n)
+    {
+      sum += i * i;
+      i++;
+    }
+    return sum;
+  }
+
+Here's what the final control flow graph will look like:
+
+    .. figure:: sum-of-squares.png
+      :alt: image of a control flow graph
+
+As before, we include the libgccjit header and make a
+:c:type:`gcc_jit_context *`.
+
+.. code-block:: c
+
+  #include <libgccjit.h>
+
+  void test (void)
+  {
+    gcc_jit_context *ctxt;
+    ctxt = gcc_jit_context_acquire ();
+
+The function works with the C `int` type:
+
+.. code-block:: c
+
+  gcc_jit_type *the_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+  gcc_jit_type *return_type = the_type;
+
+though we could equally well make it work on, say, `double`:
+
+.. code-block:: c
+
+  gcc_jit_type *the_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_DOUBLE);
+
+Let's build the function:
+
+.. code-block:: c
+
+  gcc_jit_param *n =
+    gcc_jit_context_new_param (ctxt, NULL, the_type, "n");
+  gcc_jit_param *params[1] = {n};
+  gcc_jit_function *func =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                 GCC_JIT_FUNCTION_EXPORTED,
+                                 return_type,
+                                 "loop_test",
+                                 1, params, 0);
+
+Expressions: lvalues and rvalues
+********************************
+
+The base class of expression is the :c:type:`gcc_jit_rvalue *`,
+representing an expression that can be on the *right*-hand side of
+an assignment: a value that can be computed somehow, and assigned
+*to* a storage area (such as a variable).  It has a specific
+:c:type:`gcc_jit_type *`.
+
+Anothe important class is :c:type:`gcc_jit_lvalue *`.
+A :c:type:`gcc_jit_lvalue *`. is something that can of the *left*-hand
+side of an assignment: a storage area (such as a variable).
+
+In other words, every assignment can be thought of as:
+
+.. code-block:: c
+
+   LVALUE = RVALUE;
+
+Note that :c:type:`gcc_jit_lvalue *` is a subclass of
+:c:type:`gcc_jit_rvalue *`, where in an assignment of the form:
+
+.. code-block:: c
+
+   LVALUE_A = LVALUE_B;
+
+the `LVALUE_B` implies reading the current value of that storage
+area, assigning it into the `LVALUE_A`.
+
+So far the only expressions we've seen are `i * i`:
+
+.. code-block:: c
+
+   gcc_jit_rvalue *expr =
+     gcc_jit_context_new_binary_op (
+       ctxt, NULL,
+       GCC_JIT_BINARY_OP_MULT, int_type,
+       gcc_jit_param_as_rvalue (param_i),
+       gcc_jit_param_as_rvalue (param_i));
+
+which is a :c:type:`gcc_jit_rvalue *`, and the various function
+parameters: `param_i` and `param_n`, instances of
+:c:type:`gcc_jit_param *`, which is a subclass of
+:c:type:`gcc_jit_lvalue *` (and, in turn, of :c:type:`gcc_jit_rvalue *`):
+we can both read from and write to function parameters within the
+body of a function.
+
+Our new example has a couple of local variables.  We create them by
+calling :c:func:`gcc_jit_function_new_local`, supplying a type and a
+name:
+
+.. code-block:: c
+
+  /* Build locals:  */
+  gcc_jit_lvalue *i =
+    gcc_jit_function_new_local (func, NULL, the_type, "i");
+  gcc_jit_lvalue *sum =
+    gcc_jit_function_new_local (func, NULL, the_type, "sum");
+
+These are instances of :c:type:`gcc_jit_lvalue *` - they can be read from
+and written to.
+
+Note that there is no precanned way to create *and* initialize a variable
+like in C:
+
+.. code-block:: c
+
+   int i = 0;
+
+Instead, having added the local to the function, we have to separately add
+an assignment of `0` to `local_i` at the beginning of the function.
+
+Control flow
+************
+
+This function has a loop, so we need to build some basic blocks to
+handle the control flow.  In this case, we need 4 blocks:
+
+1. before the loop (initializing the locals)
+2. the conditional at the top of the loop (comparing `i < n`)
+3. the body of the loop
+4. after the loop terminates (`return sum`)
+
+so we create these as :c:type:`gcc_jit_block *` instances within the
+:c:type:`gcc_jit_function *`:
+
+.. code-block:: c
+
+  gcc_jit_block *b_initial =
+    gcc_jit_function_new_block (func, "initial");
+  gcc_jit_block *b_loop_cond =
+    gcc_jit_function_new_block (func, "loop_cond");
+  gcc_jit_block *b_loop_body =
+    gcc_jit_function_new_block (func, "loop_body");
+  gcc_jit_block *b_after_loop =
+    gcc_jit_function_new_block (func, "after_loop");
+
+We now populate each block with statements.
+
+The entry block `b_initial` consists of initializations followed by a jump
+to the conditional.  We assign `0` to `i` and to `sum`, using
+:c:func:`gcc_jit_block_add_assignment` to add
+an assignment statement, and using :c:func:`gcc_jit_context_zero` to get
+the constant value `0` for the relevant type for the right-hand side of
+the assignment:
+
+.. code-block:: c
+
+  /* sum = 0; */
+  gcc_jit_block_add_assignment (
+    b_initial, NULL,
+    sum,
+    gcc_jit_context_zero (ctxt, the_type));
+
+  /* i = 0; */
+  gcc_jit_block_add_assignment (
+    b_initial, NULL,
+    i,
+    gcc_jit_context_zero (ctxt, the_type));
+
+We can then terminate the entry block by jumping to the conditional:
+
+.. code-block:: c
+
+  gcc_jit_block_end_with_jump (b_initial, NULL, b_loop_cond);
+
+The conditional block is equivalent to the line `while (i < n)` from our
+C example. It contains a single statement: a conditional, which jumps to
+one of two destination blocks depending on a boolean
+:c:type:`gcc_jit_rvalue *`, in this case the comparison of `i` and `n`.
+We build the comparison using :c:func:`gcc_jit_context_new_comparison`:
+
+.. code-block:: c
+
+   gcc_jit_rvalue *guard =
+     gcc_jit_context_new_comparison (
+       ctxt, NULL,
+       GCC_JIT_COMPARISON_GE,
+       gcc_jit_lvalue_as_rvalue (i),
+       gcc_jit_param_as_rvalue (n));
+
+and can then use this to add `b_loop_cond`'s sole statement, via
+:c:func:`gcc_jit_block_end_with_conditional`:
+
+.. code-block:: c
+
+  gcc_jit_block_end_with_conditional (b_loop_cond, NULL, guard);
+
+Next, we populate the body of the loop.
+
+The C statement `sum += i * i;` is an assignment operation, where an
+lvalue is modified "in-place".  We use
+:c:func:`gcc_jit_block_add_assignment_op` to handle these operations:
+
+.. code-block:: c
+
+  /* sum += i * i */
+  gcc_jit_block_add_assignment_op (
+    b_loop_body, NULL,
+    sum,
+    GCC_JIT_BINARY_OP_PLUS,
+    gcc_jit_context_new_binary_op (
+      ctxt, NULL,
+      GCC_JIT_BINARY_OP_MULT, the_type,
+      gcc_jit_lvalue_as_rvalue (i),
+      gcc_jit_lvalue_as_rvalue (i)));
+
+The `i++` can be thought of as `i += 1`, and can thus be handled in
+a similar way.  We use :c:func:`gcc_jit_context_one` to get the constant
+value `1` (for the relevant type) for the right-hand side
+of the assignment.
+
+.. code-block:: c
+
+  /* i++ */
+  gcc_jit_block_add_assignment_op (
+    b_loop_body, NULL,
+    i,
+    GCC_JIT_BINARY_OP_PLUS,
+    gcc_jit_context_one (ctxt, the_type));
+
+.. note::
+
+  For numeric constants other than 0 or 1, we could use
+  :c:func:`gcc_jit_context_new_rvalue_from_int` and
+  :c:func:`gcc_jit_context_new_rvalue_from_double`.
+
+The loop body completes by jumping back to the conditional:
+
+.. code-block:: c
+
+  gcc_jit_block_end_with_jump (b_loop_body, NULL, b_loop_cond);
+
+Finally, we populate the `b_after_loop` block, reached when the loop
+conditional is false.  We want to generate the equivalent of:
+
+.. code-block:: c
+
+   return sum;
+
+so the block is just one statement:
+
+.. code-block:: c
+
+  /* return sum */
+  gcc_jit_block_end_with_return (
+    b_after_loop,
+    NULL,
+    gcc_jit_lvalue_as_rvalue (sum));
+
+.. note::
+
+   You can intermingle block creation with statement creation,
+   but given that the terminator statements generally include references
+   to other blocks, I find it's clearer to create all the blocks,
+   *then* all the statements.
+
+We've finished populating the function.  As before, we can now compile it
+to machine code:
+
+.. code-block:: c
+
+   gcc_jit_result *result;
+   result = gcc_jit_context_compile (ctxt);
+
+   typedef int (*loop_test_fn_type) (int);
+   loop_test_fn_type loop_test =
+    (loop_test_fn_type)gcc_jit_result_get_code (result, "loop_test");
+   if (!loop_test)
+     goto error;
+   printf ("result: %d", loop_test (10));
+
+.. code-block:: bash
+
+   result: 285
+
+
+Visualizing the control flow graph
+**********************************
+
+You can see the control flow graph of a function using
+:c:func:`gcc_jit_function_dump_to_dot`:
+
+.. code-block:: c
+
+  gcc_jit_function_dump_to_dot (func, "/tmp/sum-of-squares.dot");
+
+giving a .dot file in GraphViz format.
+
+You can convert this to an image using `dot`:
+
+.. code-block:: bash
+
+   $ dot -Tpng /tmp/sum-of-squares.dot -o /tmp/sum-of-squares.png
+
+or use a viewer (my preferred one is xdot.py; see
+https://github.com/jrfonseca/xdot.py; on Fedora you can
+install it with `yum install python-xdot`):
+
+    .. figure:: sum-of-squares.png
+      :alt: image of a control flow graph
+
+Full example
+************
+
+   .. literalinclude:: ../examples/tut03-sum-of-squares.c
+    :lines: 1-
+    :language: c
+
+Building and running it:
+
+.. code-block:: console
+
+  $ gcc \
+      tut03-sum-of-squares.c \
+      -o tut03-sum-of-squares \
+      -lgccjit
+
+  # Run the built program:
+  $ ./tut03-sum-of-squares
+  loop_test returned: 285
diff --git a/gcc/jit/docs/intro/tutorial04.rst b/gcc/jit/docs/intro/tutorial04.rst
new file mode 100644 (file)
index 0000000..cafdddb
--- /dev/null
@@ -0,0 +1,1108 @@
+.. Copyright (C) 2014 Free Software Foundation, Inc.
+   Originally contributed by David Malcolm <dmalcolm@redhat.com>
+
+   This is free software: you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see
+   <http://www.gnu.org/licenses/>.
+
+Tutorial part 4: Adding JIT-compilation to a toy interpreter
+------------------------------------------------------------
+In this example we construct a "toy" interpreter, and add JIT-compilation
+to it.
+
+Our toy interpreter
+*******************
+
+It's a stack-based interpreter, and is intended as a (very simple) example
+of the kind of bytecode interpreter seen in dynamic languages such as
+Python, Ruby etc.
+
+For the sake of simplicity, our toy virtual machine is very limited:
+
+  * The only data type is `int`
+
+  * It can only work on one function at a time (so that the only
+    function call that can be made is to recurse).
+
+  * Functions can only take one parameter.
+
+  * Functions have a stack of `int` values.
+
+  * We'll implement function call within the interpreter by calling a
+    function in our implementation, rather than implementing our own
+    frame stack.
+
+  * The parser is only good enough to get the examples to work.
+
+Naturally, a real interpreter would be much more complicated that this.
+
+The following operations are supported:
+
+====================== ======================== =============== ==============
+Operation              Meaning                  Old Stack       New Stack
+====================== ======================== =============== ==============
+DUP                    Duplicate top of stack.  ``[..., x]``    ``[..., x, x]``
+ROT                    Swap top two elements    ``[..., x, y]`` ``[..., y, x]``
+                       of stack.
+BINARY_ADD             Add the top two elements ``[..., x, y]`` ``[..., (x+y)]``
+                       on the stack.
+BINARY_SUBTRACT        Likewise, but subtract.  ``[..., x, y]`` ``[..., (x-y)]``
+BINARY_MULT            Likewise, but multiply.  ``[..., x, y]`` ``[..., (x*y)]``
+BINARY_COMPARE_LT      Compare the top two      ``[..., x, y]`` ``[..., (x<y)]``
+                       elements on the stack
+                       and push a nonzero/zero
+                       if (x<y).
+RECURSE                Recurse, passing the top ``[..., x]``    ``[..., fn(x)]``
+                       of the stack, and
+                       popping the result.
+RETURN                 Return the top of the    ``[x]``         ``[]``
+                       stack.
+PUSH_CONST `arg`       Push an int const.       ``[...]``       ``[..., arg]``
+JUMP_ABS_IF_TRUE `arg` Pop; if top of stack was ``[..., x]``    ``[...]``
+                       nonzero, jump to
+                       ``arg``.
+====================== ======================== =============== ==============
+
+Programs can be interpreted, disassembled, and compiled to machine code.
+
+The interpreter reads ``.toy`` scripts.  Here's what a simple recursive
+factorial program looks like, the script ``factorial.toy``.
+The parser ignores lines beginning with a `#`.
+
+   .. literalinclude:: ../examples/tut04-toyvm/factorial.toy
+    :lines: 1-
+    :language: c
+
+The interpreter is a simple infinite loop with a big ``switch`` statement
+based on what the next opcode is:
+
+   .. literalinclude:: ../examples/tut04-toyvm/toyvm.c
+    :start-after: /* Execute the given function.  */
+    :end-before: /* JIT compilation.  */
+    :language: c
+
+Compiling to machine code
+*************************
+We want to generate machine code that can be cast to this type and
+then directly executed in-process:
+
+   .. literalinclude:: ../examples/tut04-toyvm/toyvm.c
+    :start-after: /* Functions are compiled to this function ptr type.  */
+    :end-before: enum opcode
+    :language: c
+
+Our compiler isn't very sophisticated; it takes the implementation of
+each opcode above, and maps it directly to the operations supported by
+the libgccjit API.
+
+How should we handle the stack?  In theory we could calculate what the
+stack depth will be at each opcode, and optimize away the stack
+manipulation "by hand".  We'll see below that libgccjit is able to do
+this for us, so we'll implement stack manipulation
+in a direct way, by creating a ``stack`` array and ``stack_depth``
+variables, local within the generated function, equivalent to this C code:
+
+.. code-block:: c
+
+  int stack_depth;
+  int stack[MAX_STACK_DEPTH];
+
+We'll also have local variables ``x`` and ``y`` for use when implementing
+the opcodes, equivalent to this:
+
+.. code-block:: c
+
+  int x;
+  int y;
+
+This means our compiler has the following state:
+
+   .. literalinclude:: ../examples/tut04-toyvm/toyvm.c
+    :start-after: /* JIT compilation.  */
+    :end-before: /* Stack manipulation.  */
+    :language: c
+
+Setting things up
+*****************
+
+First we create our types:
+
+   .. literalinclude:: ../examples/tut04-toyvm/toyvm.c
+    :start-after: /* Create types.  */
+    :end-before: /* The constant value 1.  */
+    :language: c
+
+along with extracting a useful `int` constant:
+
+   .. literalinclude:: ../examples/tut04-toyvm/toyvm.c
+    :start-after: /* The constant value 1.  */
+    :end-before: /* Create locations.  */
+    :language: c
+
+We'll implement push and pop in terms of the ``stack`` array and
+``stack_depth``.  Here are helper functions for adding statements to
+a block, implementing pushing and popping values:
+
+   .. literalinclude:: ../examples/tut04-toyvm/toyvm.c
+    :start-after: /* Stack manipulation.  */
+    :end-before: /* The main compilation hook.  */
+    :language: c
+
+We will support single-stepping through the generated code in the
+debugger, so we need to create :c:type:`gcc_jit_location` instances, one
+per operation in the source code.  These will reference the lines of
+e.g. ``factorial.toy``.
+
+   .. literalinclude:: ../examples/tut04-toyvm/toyvm.c
+    :start-after: /* Create locations.  */
+    :end-before: /* Creating the function.  */
+    :language: c
+
+Let's create the function itself.  As usual, we create its parameter
+first, then use the parameter to create the function:
+
+   .. literalinclude:: ../examples/tut04-toyvm/toyvm.c
+    :start-after: /* Creating the function.  */
+    :end-before: /* Create stack lvalues.  */
+    :language: c
+
+We create the locals within the function.
+
+   .. literalinclude:: ../examples/tut04-toyvm/toyvm.c
+    :start-after: /* Create stack lvalues.  */
+    :end-before: /* 1st pass: create blocks, one per opcode.
+    :language: c
+
+Populating the function
+***********************
+
+There's some one-time initialization, and the API treats the first block
+you create as the entrypoint of the function, so we need to create that
+block first:
+
+   .. literalinclude:: ../examples/tut04-toyvm/toyvm.c
+    :start-after: first.  */
+    :end-before: /* Create a block per operation.  */
+    :language: c
+
+We can now create blocks for each of the operations.  Most of these will
+be consolidated into larger blocks when the optimizer runs.
+
+   .. literalinclude:: ../examples/tut04-toyvm/toyvm.c
+    :start-after: /* Create a block per operation.  */
+    :end-before: /* Populate the initial block.  */
+    :language: c
+
+Now that we have a block it can jump to when it's done, we can populate
+the initial block:
+
+   .. literalinclude:: ../examples/tut04-toyvm/toyvm.c
+    :start-after: /* Populate the initial block.  */
+    :end-before: /* 2nd pass: fill in instructions.  */
+    :language: c
+
+We can now populate the blocks for the individual operations.  We loop
+through them, adding instructions to their blocks:
+
+   .. literalinclude:: ../examples/tut04-toyvm/toyvm.c
+    :start-after: /* 2nd pass: fill in instructions.  */
+    :end-before: /* Helper macros.  */
+    :language: c
+
+We're going to have another big ``switch`` statement for implementing
+the opcodes, this time for compiling them, rather than interpreting
+them.  It's helpful to have macros for implementing push and pop, so that
+we can make the ``switch`` statement that's coming up look as much as
+possible like the one above within the interpreter:
+
+.. literalinclude:: ../examples/tut04-toyvm/toyvm.c
+    :start-after: /* Helper macros.  */
+    :end-before: gcc_jit_block_add_comment
+    :language: c
+
+.. note::
+
+   A particularly clever implementation would have an *identical*
+   ``switch`` statement shared by the interpreter and the compiler, with
+   some preprocessor "magic".  We're not doing that here, for the sake
+   of simplicity.
+
+When I first implemented this compiler, I accidentally missed an edit
+when copying and pasting the ``Y_EQUALS_POP`` macro, so that popping the
+stack into ``y`` instead erroneously assigned it to ``x``, leaving ``y``
+uninitialized.
+
+To track this kind of thing down, we can use
+:c:func:`gcc_jit_block_add_comment` to add descriptive comments
+to the internal representation.  This is invaluable when looking through
+the generated IR for, say ``factorial``:
+
+   .. literalinclude:: ../examples/tut04-toyvm/toyvm.c
+    :start-after: PUSH_RVALUE (gcc_jit_lvalue_as_rvalue (state.y))
+    :end-before: /* Handle the individual opcodes.  */
+    :language: c
+
+We can now write the big ``switch`` statement that implements the
+individual opcodes, populating the relevant block with statements:
+
+   .. literalinclude:: ../examples/tut04-toyvm/toyvm.c
+    :start-after: /* Handle the individual opcodes.  */
+    :end-before: /* Go to the next block.  */
+    :language: c
+
+Every block must be terminated, via a call to one of the
+``gcc_jit_block_end_with_`` entrypoints.  This has been done for two
+of the opcodes, but we need to do it for the other ones, by jumping
+to the next block.
+
+   .. literalinclude:: ../examples/tut04-toyvm/toyvm.c
+    :start-after: /* Go to the next block.  */
+    :end-before: /* end of loop on PC locations.  */
+    :language: c
+
+This is analogous to simply incrementing the program counter.
+
+Verifying the control flow graph
+********************************
+Having finished looping over the blocks, the context is complete.
+
+As before, we can verify that the control flow and statements are sane by
+using :c:func:`gcc_jit_function_dump_to_dot`:
+
+.. code-block:: c
+
+  gcc_jit_function_dump_to_dot (state.fn, "/tmp/factorial.dot");
+
+and viewing the result.  Note how the label names, comments, and
+variable names show up in the dump, to make it easier to spot
+errors in our compiler.
+
+  .. figure:: factorial.png
+    :alt: image of a control flow graph
+
+Compiling the context
+*********************
+Having finished looping over the blocks and populating them with
+statements, the context is complete.
+
+We can now compile it, and extract machine code from the result:
+
+   .. literalinclude:: ../examples/tut04-toyvm/toyvm.c
+    :start-after: /* We've now finished populating the context.  Compile it.  */
+    :end-before: /* (this leaks "result" and "funcname") */
+    :language: c
+
+We can now run the result:
+
+   .. literalinclude:: ../examples/tut04-toyvm/toyvm.c
+    :start-after: /* JIT-compilation.  */
+    :end-before: return 0;
+    :language: c
+
+Single-stepping through the generated code
+******************************************
+
+It's possible to debug the generated code.  To do this we need to both:
+
+  * Set up source code locations for our statements, so that we can
+    meaningfully step through the code.  We did this above by
+    calling :c:func:`gcc_jit_context_new_location` and using the
+    results.
+
+  * Enable the generation of debugging information, by setting
+    :c:macro:`GCC_JIT_BOOL_OPTION_DEBUGINFO` on the
+    :c:type:`gcc_jit_context` via
+    :c:func:`gcc_jit_context_set_bool_option`:
+
+    .. code-block:: c
+
+     gcc_jit_context_set_bool_option (
+       ctxt,
+       GCC_JIT_BOOL_OPTION_DEBUGINFO,
+       1);
+
+Having done this, we can put a breakpoint on the generated function:
+
+.. code-block:: console
+
+  $ gdb --args ./toyvm factorial.toy 10
+  (gdb) break factorial
+  Function "factorial" not defined.
+  Make breakpoint pending on future shared library load? (y or [n]) y
+  Breakpoint 1 (factorial) pending.
+  (gdb) run
+  Breakpoint 1, factorial (arg=10) at factorial.toy:14
+  14   DUP
+
+We've set up location information, which references ``factorial.toy``.
+This allows us to use e.g. ``list`` to see where we are in the script:
+
+.. code-block:: console
+
+  (gdb) list
+  9
+  10    # Initial state:
+  11    # stack: [arg]
+  12
+  13    # 0:
+  14    DUP
+  15    # stack: [arg, arg]
+  16
+  17    # 1:
+  18    PUSH_CONST 2
+
+and to step through the function, examining the data:
+
+.. code-block:: console
+
+  (gdb) n
+  18    PUSH_CONST 2
+  (gdb) n
+  22    BINARY_COMPARE_LT
+  (gdb) print stack
+  $5 = {10, 10, 2, 0, -7152, 32767, 0, 0}
+  (gdb) print stack_depth
+  $6 = 3
+
+You'll see that the parts of the ``stack`` array that haven't been
+touched yet are uninitialized.
+
+.. note::
+
+   Turning on optimizations may lead to unpredictable results when
+   stepping through the generated code: the execution may appear to
+   "jump around" the source code.  This is analogous to turning up the
+   optimization level in a regular compiler.
+
+Examining the generated code
+****************************
+
+How good is the optimized code?
+
+We can turn up optimizations, by calling
+:c:func:`gcc_jit_context_set_int_option` with
+:c:macro:`GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL`:
+
+.. code-block:: c
+
+  gcc_jit_context_set_int_option (
+    ctxt,
+    GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL,
+    3);
+
+One of GCC's internal representations is called "gimple".  A dump of the
+initial gimple representation of the code can be seen by setting:
+
+.. code-block:: c
+
+  gcc_jit_context_set_bool_option (ctxt,
+                                   GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE,
+                                   1);
+
+With optimization on and source locations displayed, this gives:
+
+.. We'll use "c" for gimple dumps
+
+.. code-block:: c
+
+  factorial (signed int arg)
+  {
+    <unnamed type> D.80;
+    signed int D.81;
+    signed int D.82;
+    signed int D.83;
+    signed int D.84;
+    signed int D.85;
+    signed int y;
+    signed int x;
+    signed int stack_depth;
+    signed int stack[8];
+
+    try
+      {
+        initial:
+        stack_depth = 0;
+        stack[stack_depth] = arg;
+        stack_depth = stack_depth + 1;
+        goto instr0;
+        instr0:
+        /* DUP */:
+        stack_depth = stack_depth + -1;
+        x = stack[stack_depth];
+        stack[stack_depth] = x;
+        stack_depth = stack_depth + 1;
+        stack[stack_depth] = x;
+        stack_depth = stack_depth + 1;
+        goto instr1;
+        instr1:
+        /* PUSH_CONST */:
+        stack[stack_depth] = 2;
+        stack_depth = stack_depth + 1;
+        goto instr2;
+
+        /* etc */
+
+You can see the generated machine code in assembly form via:
+
+.. code-block:: c
+
+  gcc_jit_context_set_bool_option (
+    ctxt,
+    GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE,
+    1);
+  result = gcc_jit_context_compile (ctxt);
+
+which shows that (on this x86_64 box) the compiler has unrolled the loop
+and is using MMX instructions to perform several multiplications
+simultaneously:
+
+.. code-block:: gas
+
+          .file   "fake.c"
+          .text
+  .Ltext0:
+          .p2align 4,,15
+          .globl  factorial
+          .type   factorial, @function
+  factorial:
+  .LFB0:
+          .file 1 "factorial.toy"
+          .loc 1 14 0
+          .cfi_startproc
+  .LVL0:
+  .L2:
+          .loc 1 26 0
+          cmpl    $1, %edi
+          jle     .L13
+          leal    -1(%rdi), %edx
+          movl    %edx, %ecx
+          shrl    $2, %ecx
+          leal    0(,%rcx,4), %esi
+          testl   %esi, %esi
+          je      .L14
+          cmpl    $9, %edx
+          jbe     .L14
+          leal    -2(%rdi), %eax
+          movl    %eax, -16(%rsp)
+          leal    -3(%rdi), %eax
+          movd    -16(%rsp), %xmm0
+          movl    %edi, -16(%rsp)
+          movl    %eax, -12(%rsp)
+          movd    -16(%rsp), %xmm1
+          xorl    %eax, %eax
+          movl    %edx, -16(%rsp)
+          movd    -12(%rsp), %xmm4
+          movd    -16(%rsp), %xmm6
+          punpckldq       %xmm4, %xmm0
+          movdqa  .LC1(%rip), %xmm4
+          punpckldq       %xmm6, %xmm1
+          punpcklqdq      %xmm0, %xmm1
+          movdqa  .LC0(%rip), %xmm0
+          jmp     .L5
+          # etc - edited for brevity
+
+This is clearly overkill for a function that will likely overflow the
+``int`` type before the vectorization is worthwhile - but then again, this
+is a toy example.
+
+Turning down the optimization level to 2:
+
+.. code-block:: c
+
+  gcc_jit_context_set_int_option (
+    ctxt,
+    GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL,
+    3);
+
+yields this code, which is simple enough to quote in its entirety:
+
+.. code-block:: gas
+
+          .file   "fake.c"
+          .text
+          .p2align 4,,15
+          .globl  factorial
+          .type   factorial, @function
+  factorial:
+  .LFB0:
+          .cfi_startproc
+  .L2:
+          cmpl    $1, %edi
+          jle     .L8
+          movl    $1, %edx
+          jmp     .L4
+          .p2align 4,,10
+          .p2align 3
+  .L6:
+          movl    %eax, %edi
+  .L4:
+  .L5:
+          leal    -1(%rdi), %eax
+          imull   %edi, %edx
+          cmpl    $1, %eax
+          jne     .L6
+  .L3:
+  .L7:
+          imull   %edx, %eax
+          ret
+  .L8:
+          movl    %edi, %eax
+          movl    $1, %edx
+          jmp     .L7
+          .cfi_endproc
+  .LFE0:
+          .size   factorial, .-factorial
+          .ident  "GCC: (GNU) 4.9.0 20131023 (Red Hat 0.2-%{gcc_release})"
+          .section        .note.GNU-stack,"",@progbits
+
+Note that the stack pushing and popping have been eliminated, as has the
+recursive call (in favor of an iteration).
+
+Putting it all together
+***********************
+
+The complete example can be seen in the source tree at
+``gcc/jit/docs/examples/tut04-toyvm/toyvm.c``
+
+along with a Makefile and a couple of sample .toy scripts:
+
+.. code-block:: console
+
+  $ ls -al
+  drwxrwxr-x. 2 david david   4096 Sep 19 17:46 .
+  drwxrwxr-x. 3 david david   4096 Sep 19 15:26 ..
+  -rw-rw-r--. 1 david david    615 Sep 19 12:43 factorial.toy
+  -rw-rw-r--. 1 david david    834 Sep 19 13:08 fibonacci.toy
+  -rw-rw-r--. 1 david david    238 Sep 19 14:22 Makefile
+  -rw-rw-r--. 1 david david  16457 Sep 19 17:07 toyvm.c
+
+  $ make toyvm
+  g++ -Wall -g -o toyvm toyvm.c -lgccjit
+
+  $ ./toyvm factorial.toy 10
+  interpreter result: 3628800
+  compiler result: 3628800
+
+  $ ./toyvm fibonacci.toy 10
+  interpreter result: 55
+  compiler result: 55
+
+Behind the curtain: How does our code get optimized?
+****************************************************
+
+Our example is done, but you may be wondering about exactly how the
+compiler turned what we gave it into the machine code seen above.
+
+We can examine what the compiler is doing in detail by setting:
+
+.. code-block:: c
+
+  gcc_jit_context_set_bool_option (state.ctxt,
+                                   GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING,
+                                   1);
+  gcc_jit_context_set_bool_option (state.ctxt,
+                                   GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES,
+                                   1);
+
+This will dump detailed information about the compiler's state to a
+directory under ``/tmp``, and keep it from being cleaned up.
+
+The precise names and their formats of these files is subject to change.
+Higher optimization levels lead to more files.
+Here's what I saw (edited for brevity; there were almost 200 files):
+
+.. code-block:: console
+
+  intermediate files written to /tmp/libgccjit-KPQbGw
+  $ ls /tmp/libgccjit-KPQbGw/
+  fake.c.000i.cgraph
+  fake.c.000i.type-inheritance
+  fake.c.004t.gimple
+  fake.c.007t.omplower
+  fake.c.008t.lower
+  fake.c.011t.eh
+  fake.c.012t.cfg
+  fake.c.014i.visibility
+  fake.c.015i.early_local_cleanups
+  fake.c.016t.ssa
+  # etc
+
+The gimple code is converted into Static Single Assignment form,
+with annotations for use when generating the debuginfo:
+
+.. code-block:: console
+
+  $ less /tmp/libgccjit-KPQbGw/fake.c.016t.ssa
+
+.. code-block:: c
+
+  ;; Function factorial (factorial, funcdef_no=0, decl_uid=53, symbol_order=0)
+
+  factorial (signed int arg)
+  {
+    signed int stack[8];
+    signed int stack_depth;
+    signed int x;
+    signed int y;
+    <unnamed type> _20;
+    signed int _21;
+    signed int _38;
+    signed int _44;
+    signed int _51;
+    signed int _56;
+
+  initial:
+    stack_depth_3 = 0;
+    # DEBUG stack_depth => stack_depth_3
+    stack[stack_depth_3] = arg_5(D);
+    stack_depth_7 = stack_depth_3 + 1;
+    # DEBUG stack_depth => stack_depth_7
+    # DEBUG instr0 => NULL
+    # DEBUG /* DUP */ => NULL
+    stack_depth_8 = stack_depth_7 + -1;
+    # DEBUG stack_depth => stack_depth_8
+    x_9 = stack[stack_depth_8];
+    # DEBUG x => x_9
+    stack[stack_depth_8] = x_9;
+    stack_depth_11 = stack_depth_8 + 1;
+    # DEBUG stack_depth => stack_depth_11
+    stack[stack_depth_11] = x_9;
+    stack_depth_13 = stack_depth_11 + 1;
+    # DEBUG stack_depth => stack_depth_13
+    # DEBUG instr1 => NULL
+    # DEBUG /* PUSH_CONST */ => NULL
+    stack[stack_depth_13] = 2;
+
+    /* etc; edited for brevity */
+
+We can perhaps better see the code by turning off
+:c:macro:`GCC_JIT_BOOL_OPTION_DEBUGINFO` to suppress all those ``DEBUG``
+statements, giving:
+
+.. code-block:: console
+
+  $ less /tmp/libgccjit-1Hywc0/fake.c.016t.ssa
+
+.. code-block:: c
+
+  ;; Function factorial (factorial, funcdef_no=0, decl_uid=53, symbol_order=0)
+
+  factorial (signed int arg)
+  {
+    signed int stack[8];
+    signed int stack_depth;
+    signed int x;
+    signed int y;
+    <unnamed type> _20;
+    signed int _21;
+    signed int _38;
+    signed int _44;
+    signed int _51;
+    signed int _56;
+
+  initial:
+    stack_depth_3 = 0;
+    stack[stack_depth_3] = arg_5(D);
+    stack_depth_7 = stack_depth_3 + 1;
+    stack_depth_8 = stack_depth_7 + -1;
+    x_9 = stack[stack_depth_8];
+    stack[stack_depth_8] = x_9;
+    stack_depth_11 = stack_depth_8 + 1;
+    stack[stack_depth_11] = x_9;
+    stack_depth_13 = stack_depth_11 + 1;
+    stack[stack_depth_13] = 2;
+    stack_depth_15 = stack_depth_13 + 1;
+    stack_depth_16 = stack_depth_15 + -1;
+    y_17 = stack[stack_depth_16];
+    stack_depth_18 = stack_depth_16 + -1;
+    x_19 = stack[stack_depth_18];
+    _20 = x_19 < y_17;
+    _21 = (signed int) _20;
+    stack[stack_depth_18] = _21;
+    stack_depth_23 = stack_depth_18 + 1;
+    stack_depth_24 = stack_depth_23 + -1;
+    x_25 = stack[stack_depth_24];
+    if (x_25 != 0)
+      goto <bb 4> (instr9);
+    else
+      goto <bb 3> (instr4);
+
+  instr4:
+  /* DUP */:
+    stack_depth_26 = stack_depth_24 + -1;
+    x_27 = stack[stack_depth_26];
+    stack[stack_depth_26] = x_27;
+    stack_depth_29 = stack_depth_26 + 1;
+    stack[stack_depth_29] = x_27;
+    stack_depth_31 = stack_depth_29 + 1;
+    stack[stack_depth_31] = 1;
+    stack_depth_33 = stack_depth_31 + 1;
+    stack_depth_34 = stack_depth_33 + -1;
+    y_35 = stack[stack_depth_34];
+    stack_depth_36 = stack_depth_34 + -1;
+    x_37 = stack[stack_depth_36];
+    _38 = x_37 - y_35;
+    stack[stack_depth_36] = _38;
+    stack_depth_40 = stack_depth_36 + 1;
+    stack_depth_41 = stack_depth_40 + -1;
+    x_42 = stack[stack_depth_41];
+    _44 = factorial (x_42);
+    stack[stack_depth_41] = _44;
+    stack_depth_46 = stack_depth_41 + 1;
+    stack_depth_47 = stack_depth_46 + -1;
+    y_48 = stack[stack_depth_47];
+    stack_depth_49 = stack_depth_47 + -1;
+    x_50 = stack[stack_depth_49];
+    _51 = x_50 * y_48;
+    stack[stack_depth_49] = _51;
+    stack_depth_53 = stack_depth_49 + 1;
+
+    # stack_depth_1 = PHI <stack_depth_24(2), stack_depth_53(3)>
+  instr9:
+  /* RETURN */:
+    stack_depth_54 = stack_depth_1 + -1;
+    x_55 = stack[stack_depth_54];
+    _56 = x_55;
+    stack ={v} {CLOBBER};
+    return _56;
+
+  }
+
+Note in the above how all the :c:type:`gcc_jit_block` instances we
+created have been consolidated into just 3 blocks in GCC's internal
+representation: ``initial``, ``instr4`` and ``instr9``.
+
+Optimizing away stack manipulation
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Recall our simple implementation of stack operations.  Let's examine
+how the stack operations are optimized away.
+
+After a pass of constant-propagation, the depth of the stack at each
+opcode can be determined at compile-time:
+
+.. code-block:: console
+
+  $ less /tmp/libgccjit-1Hywc0/fake.c.021t.ccp1
+
+.. code-block:: c
+
+  ;; Function factorial (factorial, funcdef_no=0, decl_uid=53, symbol_order=0)
+
+  factorial (signed int arg)
+  {
+    signed int stack[8];
+    signed int stack_depth;
+    signed int x;
+    signed int y;
+    <unnamed type> _20;
+    signed int _21;
+    signed int _38;
+    signed int _44;
+    signed int _51;
+
+  initial:
+    stack[0] = arg_5(D);
+    x_9 = stack[0];
+    stack[0] = x_9;
+    stack[1] = x_9;
+    stack[2] = 2;
+    y_17 = stack[2];
+    x_19 = stack[1];
+    _20 = x_19 < y_17;
+    _21 = (signed int) _20;
+    stack[1] = _21;
+    x_25 = stack[1];
+    if (x_25 != 0)
+      goto <bb 4> (instr9);
+    else
+      goto <bb 3> (instr4);
+
+  instr4:
+  /* DUP */:
+    x_27 = stack[0];
+    stack[0] = x_27;
+    stack[1] = x_27;
+    stack[2] = 1;
+    y_35 = stack[2];
+    x_37 = stack[1];
+    _38 = x_37 - y_35;
+    stack[1] = _38;
+    x_42 = stack[1];
+    _44 = factorial (x_42);
+    stack[1] = _44;
+    y_48 = stack[1];
+    x_50 = stack[0];
+    _51 = x_50 * y_48;
+    stack[0] = _51;
+
+  instr9:
+  /* RETURN */:
+    x_55 = stack[0];
+    x_56 = x_55;
+    stack ={v} {CLOBBER};
+    return x_56;
+
+  }
+
+Note how, in the above, all those ``stack_depth`` values are now just
+constants: we're accessing specific stack locations at each opcode.
+
+The "esra" pass ("Early Scalar Replacement of Aggregates") breaks
+out our "stack" array into individual elements:
+
+.. code-block:: console
+
+  $ less /tmp/libgccjit-1Hywc0/fake.c.024t.esra
+
+.. code-block:: c
+
+  ;; Function factorial (factorial, funcdef_no=0, decl_uid=53, symbol_order=0)
+
+  Created a replacement for stack offset: 0, size: 32: stack$0
+  Created a replacement for stack offset: 32, size: 32: stack$1
+  Created a replacement for stack offset: 64, size: 32: stack$2
+
+  Symbols to be put in SSA form
+  { D.89 D.90 D.91 }
+  Incremental SSA update started at block: 0
+  Number of blocks in CFG: 5
+  Number of blocks to update: 4 ( 80%)
+
+
+  factorial (signed int arg)
+  {
+    signed int stack$2;
+    signed int stack$1;
+    signed int stack$0;
+    signed int stack[8];
+    signed int stack_depth;
+    signed int x;
+    signed int y;
+    <unnamed type> _20;
+    signed int _21;
+    signed int _38;
+    signed int _44;
+    signed int _51;
+
+  initial:
+    stack$0_45 = arg_5(D);
+    x_9 = stack$0_45;
+    stack$0_39 = x_9;
+    stack$1_32 = x_9;
+    stack$2_30 = 2;
+    y_17 = stack$2_30;
+    x_19 = stack$1_32;
+    _20 = x_19 < y_17;
+    _21 = (signed int) _20;
+    stack$1_28 = _21;
+    x_25 = stack$1_28;
+    if (x_25 != 0)
+      goto <bb 4> (instr9);
+    else
+      goto <bb 3> (instr4);
+
+  instr4:
+  /* DUP */:
+    x_27 = stack$0_39;
+    stack$0_22 = x_27;
+    stack$1_14 = x_27;
+    stack$2_12 = 1;
+    y_35 = stack$2_12;
+    x_37 = stack$1_14;
+    _38 = x_37 - y_35;
+    stack$1_10 = _38;
+    x_42 = stack$1_10;
+    _44 = factorial (x_42);
+    stack$1_6 = _44;
+    y_48 = stack$1_6;
+    x_50 = stack$0_22;
+    _51 = x_50 * y_48;
+    stack$0_1 = _51;
+
+    # stack$0_52 = PHI <stack$0_39(2), stack$0_1(3)>
+  instr9:
+  /* RETURN */:
+    x_55 = stack$0_52;
+    x_56 = x_55;
+    stack ={v} {CLOBBER};
+    return x_56;
+
+  }
+
+Hence at this point, all those pushes and pops of the stack are now
+simply assignments to specific temporary variables.
+
+After some copy propagation, the stack manipulation has been completely
+optimized away:
+
+.. code-block:: console
+
+  $ less /tmp/libgccjit-1Hywc0/fake.c.026t.copyprop1
+
+.. code-block:: c
+
+  ;; Function factorial (factorial, funcdef_no=0, decl_uid=53, symbol_order=0)
+
+  factorial (signed int arg)
+  {
+    signed int stack$2;
+    signed int stack$1;
+    signed int stack$0;
+    signed int stack[8];
+    signed int stack_depth;
+    signed int x;
+    signed int y;
+    <unnamed type> _20;
+    signed int _21;
+    signed int _38;
+    signed int _44;
+    signed int _51;
+
+  initial:
+    stack$0_39 = arg_5(D);
+    _20 = arg_5(D) <= 1;
+    _21 = (signed int) _20;
+    if (_21 != 0)
+      goto <bb 4> (instr9);
+    else
+      goto <bb 3> (instr4);
+
+  instr4:
+  /* DUP */:
+    _38 = arg_5(D) + -1;
+    _44 = factorial (_38);
+    _51 = arg_5(D) * _44;
+    stack$0_1 = _51;
+
+    # stack$0_52 = PHI <arg_5(D)(2), _51(3)>
+  instr9:
+  /* RETURN */:
+    stack ={v} {CLOBBER};
+    return stack$0_52;
+
+  }
+
+Later on, another pass finally eliminated ``stack_depth`` local and the
+unused parts of the `stack`` array altogether:
+
+.. code-block:: console
+
+  $ less /tmp/libgccjit-1Hywc0/fake.c.036t.release_ssa
+
+.. code-block:: c
+
+  ;; Function factorial (factorial, funcdef_no=0, decl_uid=53, symbol_order=0)
+
+  Released 44 names, 314.29%, removed 44 holes
+  factorial (signed int arg)
+  {
+    signed int stack$0;
+    signed int mult_acc_1;
+    <unnamed type> _5;
+    signed int _6;
+    signed int _7;
+    signed int mul_tmp_10;
+    signed int mult_acc_11;
+    signed int mult_acc_13;
+
+    # arg_9 = PHI <arg_8(D)(0)>
+    # mult_acc_13 = PHI <1(0)>
+  initial:
+
+    <bb 5>:
+    # arg_4 = PHI <arg_9(2), _7(3)>
+    # mult_acc_1 = PHI <mult_acc_13(2), mult_acc_11(3)>
+    _5 = arg_4 <= 1;
+    _6 = (signed int) _5;
+    if (_6 != 0)
+      goto <bb 4> (instr9);
+    else
+      goto <bb 3> (instr4);
+
+  instr4:
+  /* DUP */:
+    _7 = arg_4 + -1;
+    mult_acc_11 = mult_acc_1 * arg_4;
+    goto <bb 5>;
+
+    # stack$0_12 = PHI <arg_4(5)>
+  instr9:
+  /* RETURN */:
+    mul_tmp_10 = mult_acc_1 * stack$0_12;
+    return mul_tmp_10;
+
+  }
+
+
+Elimination of tail recursion
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Another significant optimization is the detection that the call to
+``factorial`` is tail recursion, which can be eliminated in favor of
+an iteration:
+
+.. code-block:: console
+
+  $ less /tmp/libgccjit-1Hywc0/fake.c.030t.tailr1
+
+.. code-block:: c
+
+  ;; Function factorial (factorial, funcdef_no=0, decl_uid=53, symbol_order=0)
+
+
+  Symbols to be put in SSA form
+  { D.88 }
+  Incremental SSA update started at block: 0
+  Number of blocks in CFG: 5
+  Number of blocks to update: 4 ( 80%)
+
+
+  factorial (signed int arg)
+  {
+    signed int stack$2;
+    signed int stack$1;
+    signed int stack$0;
+    signed int stack[8];
+    signed int stack_depth;
+    signed int x;
+    signed int y;
+    signed int mult_acc_1;
+    <unnamed type> _20;
+    signed int _21;
+    signed int _38;
+    signed int mul_tmp_44;
+    signed int mult_acc_51;
+
+    # arg_5 = PHI <arg_39(D)(0), _38(3)>
+    # mult_acc_1 = PHI <1(0), mult_acc_51(3)>
+  initial:
+    _20 = arg_5 <= 1;
+    _21 = (signed int) _20;
+    if (_21 != 0)
+      goto <bb 4> (instr9);
+    else
+      goto <bb 3> (instr4);
+
+  instr4:
+  /* DUP */:
+    _38 = arg_5 + -1;
+    mult_acc_51 = mult_acc_1 * arg_5;
+    goto <bb 2> (initial);
+
+    # stack$0_52 = PHI <arg_5(2)>
+  instr9:
+  /* RETURN */:
+    stack ={v} {CLOBBER};
+    mul_tmp_44 = mult_acc_1 * stack$0_52;
+    return mul_tmp_44;
+
+  }
diff --git a/gcc/jit/docs/topics/contexts.rst b/gcc/jit/docs/topics/contexts.rst
new file mode 100644 (file)
index 0000000..d8dd4f8
--- /dev/null
@@ -0,0 +1,315 @@
+.. Copyright (C) 2014 Free Software Foundation, Inc.
+   Originally contributed by David Malcolm <dmalcolm@redhat.com>
+
+   This is free software: you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see
+   <http://www.gnu.org/licenses/>.
+
+.. default-domain:: c
+
+Compilation contexts
+====================
+
+.. type:: gcc_jit_context
+
+The top-level of the API is the :c:type:`gcc_jit_context` type.
+
+A :c:type:`gcc_jit_context` instance encapsulates the state of a
+compilation.
+
+You can set up options on it, and add types, functions and code.
+Invoking :c:func:`gcc_jit_context_compile` on it gives you a
+:c:type:`gcc_jit_result`.
+
+Lifetime-management
+-------------------
+Contexts are the unit of lifetime-management within the API: objects
+have their lifetime bounded by the context they are created within, and
+cleanup of such objects is done for you when the context is released.
+
+.. function:: gcc_jit_context *gcc_jit_context_acquire (void)
+
+  This function acquires a new :c:type:`gcc_jit_object *` instance,
+  which is independent of any others that may be present within this
+  process.
+
+.. function:: void gcc_jit_context_release (gcc_jit_context *ctxt)
+
+  This function releases all resources associated with the given context.
+  Both the context itself and all of its :c:type:`gcc_jit_object *`
+  instances are cleaned up.  It should be called exactly once on a given
+  context.
+
+  It is invalid to use the context or any of its "contextual" objects
+  after calling this.
+
+  .. code-block:: c
+
+    gcc_jit_context_release (ctxt);
+
+.. function:: gcc_jit_context * gcc_jit_context_new_child_context (gcc_jit_context *parent_ctxt)
+
+   Given an existing JIT context, create a child context.
+
+   The child inherits a copy of all option-settings from the parent.
+
+   The child can reference objects created within the parent, but not
+   vice-versa.
+
+   The lifetime of the child context must be bounded by that of the
+   parent: you should release a child context before releasing the parent
+   context.
+
+   If you use a function from a parent context within a child context,
+   you have to compile the parent context before you can compile the
+   child context, and the gcc_jit_result of the parent context must
+   outlive the gcc_jit_result of the child context.
+
+   This allows caching of shared initializations.  For example, you could
+   create types and declarations of global functions in a parent context
+   once within a process, and then create child contexts whenever a
+   function or loop becomes hot. Each such child context can be used for
+   JIT-compiling just one function or loop, but can reference types
+   and helper functions created within the parent context.
+
+   Contexts can be arbitrarily nested, provided the above rules are
+   followed, but it's probably not worth going above 2 or 3 levels, and
+   there will likely be a performance hit for such nesting.
+
+
+Thread-safety
+-------------
+Instances of :c:type:`gcc_jit_object *` created via
+:c:func:`gcc_jit_context_acquire` are independent from each other:
+only one thread may use a given context at once, but multiple threads
+could each have their own contexts without needing locks.
+
+Contexts created via :c:func:`gcc_jit_context_new_child_context` are
+related to their parent context.  They can be partitioned by their
+ultimate ancestor into independent "family trees".   Only one thread
+within a process may use a given "family tree" of such contexts at once,
+and if you're using multiple threads you should provide your own locking
+around entire such context partitions.
+
+
+Error-handling
+--------------
+You can only compile and get code from a context if no errors occur.
+
+In general, if an error occurs when using an API entrypoint, it returns
+NULL.  You don't have to check everywhere for NULL results, since the
+API gracefully handles a NULL being passed in for any argument.
+
+Errors are printed on stderr and can be queried using
+:c:func:`gcc_jit_context_get_first_error`.
+
+.. function:: const char *\
+              gcc_jit_context_get_first_error (gcc_jit_context *ctxt)
+
+   Returns the first error message that occurred on the context.
+
+   The returned string is valid for the rest of the lifetime of the
+   context.
+
+   If no errors occurred, this will be NULL.
+
+Debugging
+---------
+
+.. function:: void\
+              gcc_jit_context_dump_to_file (gcc_jit_context *ctxt,\
+                                            const char *path,\
+                                            int update_locations)
+
+   To help with debugging: dump a C-like representation to the given path,
+   describing what's been set up on the context.
+
+   If "update_locations" is true, then also set up :type:`gcc_jit_location`
+   information throughout the context, pointing at the dump file as if it
+   were a source file.  This may be of use in conjunction with
+   :macro:`GCC_JIT_BOOL_OPTION_DEBUGINFO` to allow stepping through the
+   code in a debugger.
+
+
+Options
+-------
+
+String Options
+**************
+
+.. function:: void gcc_jit_context_set_str_option(gcc_jit_context *ctxt, \
+                                                  enum gcc_jit_str_option opt, \
+                                                  const char *value)
+
+   Set a string option of the context.
+
+   .. type:: enum gcc_jit_str_option
+
+   There is currently just one string option:
+
+   .. macro:: GCC_JIT_STR_OPTION_PROGNAME
+
+      The name of the program, for use as a prefix when printing error
+      messages to stderr.  If `NULL`, or default, "libgccjit.so" is used.
+
+Boolean options
+***************
+
+.. function:: void gcc_jit_context_set_bool_option(gcc_jit_context *ctxt, \
+                                                  enum gcc_jit_bool_option opt, \
+                                                  int value)
+
+  Set a boolean option of the context.
+  Zero is "false" (the default), non-zero is "true".
+
+  .. type:: enum gcc_jit_bool_option
+
+  .. macro:: GCC_JIT_BOOL_OPTION_DEBUGINFO
+
+     If true, :func:`gcc_jit_context_compile` will attempt to do the right
+     thing so that if you attach a debugger to the process, it will
+     be able to inspect variables and step through your code.
+
+     Note that you can't step through code unless you set up source
+     location information for the code (by creating and passing in
+     :type:`gcc_jit_location` instances).
+
+  .. macro:: GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE
+
+     If true, :func:`gcc_jit_context_compile` will dump its initial
+     "tree" representation of your code to stderr (before any
+     optimizations).
+
+     Here's some sample output (from the `square` example)::
+
+        <statement_list 0x7f4875a62cc0
+           type <void_type 0x7f4875a64bd0 VOID
+               align 8 symtab 0 alias set -1 canonical type 0x7f4875a64bd0
+               pointer_to_this <pointer_type 0x7f4875a64c78>>
+           side-effects head 0x7f4875a761e0 tail 0x7f4875a761f8 stmts 0x7f4875a62d20 0x7f4875a62d00
+
+           stmt <label_expr 0x7f4875a62d20 type <void_type 0x7f4875a64bd0>
+               side-effects
+               arg 0 <label_decl 0x7f4875a79080 entry type <void_type 0x7f4875a64bd0>
+                   VOID file (null) line 0 col 0
+                   align 1 context <function_decl 0x7f4875a77500 square>>>
+           stmt <return_expr 0x7f4875a62d00
+               type <integer_type 0x7f4875a645e8 public SI
+                   size <integer_cst 0x7f4875a623a0 constant 32>
+                   unit size <integer_cst 0x7f4875a623c0 constant 4>
+                   align 32 symtab 0 alias set -1 canonical type 0x7f4875a645e8 precision 32 min <integer_cst 0x7f4875a62340 -2147483648> max <integer_cst 0x7f4875a62360 2147483647>
+                   pointer_to_this <pointer_type 0x7f4875a6b348>>
+               side-effects
+               arg 0 <modify_expr 0x7f4875a72a78 type <integer_type 0x7f4875a645e8>
+                   side-effects arg 0 <result_decl 0x7f4875a7a000 D.54>
+                   arg 1 <mult_expr 0x7f4875a72a50 type <integer_type 0x7f4875a645e8>
+                       arg 0 <parm_decl 0x7f4875a79000 i> arg 1 <parm_decl 0x7f4875a79000 i>>>>>
+
+  .. macro:: GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE
+
+     If true, :func:`gcc_jit_context_compile` will dump the "gimple"
+     representation of your code to stderr, before any optimizations
+     are performed.  The dump resembles C code:
+
+     .. code-block:: c
+
+       square (signed int i)
+       {
+         signed int D.56;
+
+         entry:
+         D.56 = i * i;
+         return D.56;
+       }
+
+  .. macro:: GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE
+
+     If true, :func:`gcc_jit_context_compile` will dump the final
+     generated code to stderr, in the form of assembly language:
+
+     .. code-block:: gas
+
+           .file    "fake.c"
+           .text
+           .globl    square
+           .type    square, @function
+       square:
+       .LFB0:
+           .cfi_startproc
+           pushq    %rbp
+           .cfi_def_cfa_offset 16
+           .cfi_offset 6, -16
+           movq    %rsp, %rbp
+           .cfi_def_cfa_register 6
+           movl    %edi, -4(%rbp)
+       .L2:
+           movl    -4(%rbp), %eax
+           imull    -4(%rbp), %eax
+           popq    %rbp
+           .cfi_def_cfa 7, 8
+           ret
+           .cfi_endproc
+       .LFE0:
+           .size    square, .-square
+           .ident    "GCC: (GNU) 4.9.0 20131023 (Red Hat 0.1-%{gcc_release})"
+           .section    .note.GNU-stack,"",@progbits
+
+
+  .. macro:: GCC_JIT_BOOL_OPTION_DUMP_SUMMARY
+
+     If true, :func:`gcc_jit_context_compile` will print information to stderr
+     on the actions it is performing, followed by a profile showing
+     the time taken and memory usage of each phase.
+
+  .. macro:: GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING
+
+     If true, :func:`gcc_jit_context_compile` will dump copious
+     amount of information on what it's doing to various
+     files within a temporary directory.  Use
+     :macro:`GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES` (see below) to
+     see the results.  The files are intended to be human-readable,
+     but the exact files and their formats are subject to change.
+
+  .. macro:: GCC_JIT_BOOL_OPTION_SELFCHECK_GC
+
+     If true, libgccjit will aggressively run its garbage collector, to
+     shake out bugs (greatly slowing down the compile).  This is likely
+     to only be of interest to developers *of* the library.  It is
+     used when running the selftest suite.
+
+  .. macro:: GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES
+
+     If true, the :type:`gcc_jit_context` will not clean up intermediate files
+     written to the filesystem, and will display their location on stderr.
+
+Integer options
+***************
+
+.. function:: void gcc_jit_context_set_int_option (gcc_jit_context *ctxt, \
+                                                  enum gcc_jit_int_option opt, \
+                                                  int value)
+
+  Set an integer option of the context.
+
+  .. type:: enum gcc_jit_int_option
+
+  There is currently just one integer option:
+
+  .. macro:: GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL
+
+     How much to optimize the code.
+
+     Valid values are 0-3, corresponding to GCC's command-line options
+     -O0 through -O3.
+
+     The default value is 0 (unoptimized).
diff --git a/gcc/jit/docs/topics/expressions.rst b/gcc/jit/docs/topics/expressions.rst
new file mode 100644 (file)
index 0000000..1cf9641
--- /dev/null
@@ -0,0 +1,525 @@
+.. Copyright (C) 2014 Free Software Foundation, Inc.
+   Originally contributed by David Malcolm <dmalcolm@redhat.com>
+
+   This is free software: you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see
+   <http://www.gnu.org/licenses/>.
+
+.. default-domain:: c
+
+Expressions
+===========
+
+Rvalues
+-------
+.. type:: gcc_jit_rvalue
+
+A :c:type:`gcc_jit_rvalue *` is an expression that can be computed.
+
+It can be simple, e.g.:
+
+  * an integer value e.g. `0` or `42`
+  * a string literal e.g. `"Hello world"`
+  * a variable e.g. `i`.  These are also lvalues (see below).
+
+or compound e.g.:
+
+  * a unary expression e.g. `!cond`
+  * a binary expression e.g. `(a + b)`
+  * a function call e.g. `get_distance (&player_ship, &target)`
+  * etc.
+
+Every rvalue has an associated type, and the API will check to ensure
+that types match up correctly (otherwise the context will emit an error).
+
+.. function:: gcc_jit_type *gcc_jit_rvalue_get_type (gcc_jit_rvalue *rvalue)
+
+  Get the type of this rvalue.
+
+.. function:: gcc_jit_object *gcc_jit_rvalue_as_object (gcc_jit_rvalue *rvalue)
+
+  Upcast the given rvalue to be an object.
+
+
+Simple expressions
+******************
+
+.. function:: gcc_jit_rvalue *\
+              gcc_jit_context_new_rvalue_from_int (gcc_jit_context *ctxt, \
+                                                   gcc_jit_type *numeric_type, \
+                                                   int value)
+
+   Given a numeric type (integer or floating point), build an rvalue for
+   the given constant value.
+
+.. function::  gcc_jit_rvalue *gcc_jit_context_zero (gcc_jit_context *ctxt, \
+                                                     gcc_jit_type *numeric_type)
+
+   Given a numeric type (integer or floating point), get the rvalue for
+   zero.  Essentially this is just a shortcut for:
+
+   .. code-block:: c
+
+      gcc_jit_context_new_rvalue_from_int (ctxt, numeric_type, 0)
+
+.. function::  gcc_jit_rvalue *gcc_jit_context_one (gcc_jit_context *ctxt, \
+                                                    gcc_jit_type *numeric_type)
+
+   Given a numeric type (integer or floating point), get the rvalue for
+   zero.  Essentially this is just a shortcut for:
+
+   .. code-block:: c
+
+      gcc_jit_context_new_rvalue_from_int (ctxt, numeric_type, 1)
+
+.. function::  gcc_jit_rvalue *\
+               gcc_jit_context_new_rvalue_from_double (gcc_jit_context *ctxt, \
+                                                       gcc_jit_type *numeric_type, \
+                                                       double value)
+
+   Given a numeric type (integer or floating point), build an rvalue for
+   the given constant value.
+
+.. function:: gcc_jit_rvalue *\
+              gcc_jit_context_new_rvalue_from_ptr (gcc_jit_context *ctxt, \
+                                                   gcc_jit_type *pointer_type, \
+                                                   void *value)
+
+   Given a pointer type, build an rvalue for the given address.
+
+.. function:: gcc_jit_rvalue *gcc_jit_context_null (gcc_jit_context *ctxt, \
+                                                    gcc_jit_type *pointer_type)
+
+   Given a pointer type, build an rvalue for ``NULL``.  Essentially this
+   is just a shortcut for:
+
+   .. code-block:: c
+
+      gcc_jit_context_new_rvalue_from_ptr (ctxt, pointer_type, NULL)
+
+.. function:: gcc_jit_rvalue *\
+              gcc_jit_context_new_string_literal (gcc_jit_context *ctxt, \
+                                                  const char *value)
+
+   Generate an rvalue for the given NIL-terminated string, of type
+   :c:data:`GCC_JIT_TYPE_CONST_CHAR_PTR`.
+
+
+Unary Operations
+****************
+
+.. function:: gcc_jit_rvalue * \
+              gcc_jit_context_new_unary_op (gcc_jit_context *ctxt, \
+                                            gcc_jit_location *loc, \
+                                            enum gcc_jit_unary_op op, \
+                                            gcc_jit_type *result_type, \
+                                            gcc_jit_rvalue *rvalue)
+
+   Build a unary operation out of an input rvalue.
+
+.. type:: enum gcc_jit_unary_op
+
+The available unary operations are:
+
+==========================================  ============
+Unary Operation                             C equivalent
+==========================================  ============
+:c:macro:`GCC_JIT_UNARY_OP_MINUS`           `-(EXPR)`
+:c:macro:`GCC_JIT_UNARY_OP_BITWISE_NEGATE`  `~(EXPR)`
+:c:macro:`GCC_JIT_UNARY_OP_LOGICAL_NEGATE`  `!(EXPR)`
+==========================================  ============
+
+.. c:macro:: GCC_JIT_UNARY_OP_MINUS
+
+    Negate an arithmetic value; analogous to:
+
+    .. code-block:: c
+
+       -(EXPR)
+
+    in C.
+
+.. c:macro:: GCC_JIT_UNARY_OP_BITWISE_NEGATE
+
+    Bitwise negation of an integer value (one's complement); analogous
+    to:
+
+    .. code-block:: c
+
+       ~(EXPR)
+
+    in C.
+
+.. c:macro:: GCC_JIT_UNARY_OP_LOGICAL_NEGATE
+
+    Logical negation of an arithmetic or pointer value; analogous to:
+
+    .. code-block:: c
+
+       !(EXPR)
+
+    in C.
+
+Binary Operations
+*****************
+
+.. function:: gcc_jit_rvalue *gcc_jit_context_new_binary_op (gcc_jit_context *ctxt, \
+                                                             gcc_jit_location *loc, \
+                                                             enum gcc_jit_binary_op op, \
+                                                             gcc_jit_type *result_type, \
+                                                             gcc_jit_rvalue *a, gcc_jit_rvalue *b)
+
+   Build a binary operation out of two constituent rvalues.
+
+.. type:: enum gcc_jit_binary_op
+
+The available binary operations are:
+
+========================================  ============
+Binary Operation                          C equivalent
+========================================  ============
+:c:macro:`GCC_JIT_BINARY_OP_PLUS`         `x + y`
+:c:macro:`GCC_JIT_BINARY_OP_MINUS`        `x - y`
+:c:macro:`GCC_JIT_BINARY_OP_MULT`         `x * y`
+:c:macro:`GCC_JIT_BINARY_OP_DIVIDE`       `x / y`
+:c:macro:`GCC_JIT_BINARY_OP_MODULO`       `x % y`
+:c:macro:`GCC_JIT_BINARY_OP_BITWISE_AND`  `x & y`
+:c:macro:`GCC_JIT_BINARY_OP_BITWISE_XOR`  `x ^ y`
+:c:macro:`GCC_JIT_BINARY_OP_BITWISE_OR`   `x | y`
+:c:macro:`GCC_JIT_BINARY_OP_LOGICAL_AND`  `x && y`
+:c:macro:`GCC_JIT_BINARY_OP_LOGICAL_OR`   `x || y`
+:c:macro:`GCC_JIT_BINARY_OP_LSHIFT`       `x << y`
+:c:macro:`GCC_JIT_BINARY_OP_RSHIFT`       `x >> y`
+========================================  ============
+
+.. c:macro:: GCC_JIT_BINARY_OP_PLUS
+
+   Addition of arithmetic values; analogous to:
+
+   .. code-block:: c
+
+     (EXPR_A) + (EXPR_B)
+
+   in C.
+
+   For pointer addition, use :c:func:`gcc_jit_context_new_array_access`.
+
+.. c:macro:: GCC_JIT_BINARY_OP_MINUS`
+
+   Subtraction of arithmetic values; analogous to:
+
+   .. code-block:: c
+
+     (EXPR_A) - (EXPR_B)
+
+   in C.
+
+.. c:macro:: GCC_JIT_BINARY_OP_MULT
+
+   Multiplication of a pair of arithmetic values; analogous to:
+
+   .. code-block:: c
+
+     (EXPR_A) * (EXPR_B)
+
+   in C.
+
+.. c:macro:: GCC_JIT_BINARY_OP_DIVIDE
+
+   Quotient of division of arithmetic values; analogous to:
+
+   .. code-block:: c
+
+     (EXPR_A) / (EXPR_B)
+
+   in C.
+
+   The result type affects the kind of division: if the result type is
+   integer-based, then the result is truncated towards zero, whereas
+   a floating-point result type indicates floating-point division.
+
+.. c:macro:: GCC_JIT_BINARY_OP_MODULO
+
+   Remainder of division of arithmetic values; analogous to:
+
+   .. code-block:: c
+
+     (EXPR_A) % (EXPR_B)
+
+   in C.
+
+.. c:macro:: GCC_JIT_BINARY_OP_BITWISE_AND
+
+   Bitwise AND; analogous to:
+
+   .. code-block:: c
+
+     (EXPR_A) & (EXPR_B)
+
+   in C.
+
+.. c:macro:: GCC_JIT_BINARY_OP_BITWISE_XOR
+
+   Bitwise exclusive OR; analogous to:
+
+   .. code-block:: c
+
+      (EXPR_A) ^ (EXPR_B)
+
+   in C.
+
+.. c:macro:: GCC_JIT_BINARY_OP_BITWISE_OR
+
+   Bitwise inclusive OR; analogous to:
+
+   .. code-block:: c
+
+     (EXPR_A) | (EXPR_B)
+
+   in C.
+
+.. c:macro:: GCC_JIT_BINARY_OP_LOGICAL_AND
+
+   Logical AND; analogous to:
+
+   .. code-block:: c
+
+     (EXPR_A) && (EXPR_B)
+
+   in C.
+
+.. c:macro:: GCC_JIT_BINARY_OP_LOGICAL_OR
+
+   Logical OR; analogous to:
+
+   .. code-block:: c
+
+     (EXPR_A) || (EXPR_B)
+
+   in C.
+
+.. c:macro:: GCC_JIT_BINARY_OP_LSHIFT
+
+   Left shift; analogous to:
+
+   .. code-block:: c
+
+     (EXPR_A) << (EXPR_B)
+
+   in C.
+
+.. c:macro:: GCC_JIT_BINARY_OP_RSHIFT
+
+   Right shift; analogous to:
+
+   .. code-block:: c
+
+     (EXPR_A) >> (EXPR_B)
+
+   in C.
+
+Comparisons
+***********
+
+.. function:: gcc_jit_rvalue *\
+              gcc_jit_context_new_comparison (gcc_jit_context *ctxt,\
+                                              gcc_jit_location *loc,\
+                                              enum gcc_jit_comparison op,\
+                                              gcc_jit_rvalue *a, gcc_jit_rvalue *b)
+
+   Build a boolean rvalue out of the comparison of two other rvalues.
+
+.. type:: enum gcc_jit_comparison
+
+=======================================  ============
+Comparison                               C equivalent
+=======================================  ============
+:c:macro:`GCC_JIT_COMPARISON_EQ`         `x == y`
+:c:macro:`GCC_JIT_COMPARISON_NE`         `x != y`
+:c:macro:`GCC_JIT_COMPARISON_LT`         `x < y`
+:c:macro:`GCC_JIT_COMPARISON_LE`         `x <= y`
+:c:macro:`GCC_JIT_COMPARISON_GT`         `x > y`
+:c:macro:`GCC_JIT_COMPARISON_GE`         `x >= y`
+=======================================  ============
+
+
+Function calls
+**************
+.. function:: gcc_jit_rvalue *\
+              gcc_jit_context_new_call (gcc_jit_context *ctxt,\
+                                        gcc_jit_location *loc,\
+                                        gcc_jit_function *func,\
+                                        int numargs , gcc_jit_rvalue **args)
+
+   Given a function and the given table of argument rvalues, construct a
+   call to the function, with the result as an rvalue.
+
+   .. note::
+
+      :c:func:`gcc_jit_context_new_call` merely builds a
+      :c:type:`gcc_jit_rvalue` i.e. an expression that can be evaluated,
+      perhaps as part of a more complicated expression.
+      The call *won't* happen unless you add a statement to a function
+      that evaluates the expression.
+
+      For example, if you want to call a function and discard the result
+      (or to call a function with ``void`` return type), use
+      :c:func:`gcc_jit_block_add_eval`:
+
+      .. code-block:: c
+
+         /* Add "(void)printf (arg0, arg1);".  */
+         gcc_jit_block_add_eval (
+           block, NULL,
+           gcc_jit_context_new_call (
+             ctxt,
+             NULL,
+             printf_func,
+             2, args));
+
+Type-coercion
+*************
+
+.. function:: gcc_jit_rvalue *\
+              gcc_jit_context_new_cast (gcc_jit_context *ctxt,\
+                                        gcc_jit_location *loc,\
+                                        gcc_jit_rvalue *rvalue,\
+                                        gcc_jit_type *type)
+
+   Given an rvalue of T, construct another rvalue of another type.
+
+   Currently only a limited set of conversions are possible:
+
+     * int <-> float
+     * int <-> bool
+     * P*  <-> Q*, for pointer types P and Q
+
+Lvalues
+-------
+
+.. type:: gcc_jit_lvalue
+
+An lvalue is something that can of the *left*-hand side of an assignment:
+a storage area (such as a variable).  It is also usable as an rvalue,
+where the rvalue is computed by reading from the storage area.
+
+.. function:: gcc_jit_object *\
+              gcc_jit_lvalue_as_object (gcc_jit_lvalue *lvalue)
+
+   Upcast an lvalue to be an object.
+
+.. function:: gcc_jit_rvalue *\
+              gcc_jit_lvalue_as_rvalue (gcc_jit_lvalue *lvalue)
+
+   Upcast an lvalue to be an rvalue.
+
+.. function:: gcc_jit_rvalue *\
+              gcc_jit_lvalue_get_address (gcc_jit_lvalue *lvalue,\
+                                          gcc_jit_location *loc)
+
+   Take the address of an lvalue; analogous to:
+
+   .. code-block:: c
+
+     &(EXPR)
+
+   in C.
+
+Global variables
+****************
+
+.. function:: gcc_jit_lvalue *\
+              gcc_jit_context_new_global (gcc_jit_context *ctxt,\
+                                          gcc_jit_location *loc,\
+                                          gcc_jit_type *type,\
+                                          const char *name)
+
+   Add a new global variable of the given type and name to the context.
+
+
+Working with pointers, structs and unions
+-----------------------------------------
+
+.. function:: gcc_jit_lvalue *\
+              gcc_jit_rvalue_dereference (gcc_jit_rvalue *rvalue,\
+                                          gcc_jit_location *loc)
+
+   Given an rvalue of pointer type ``T *``, dereferencing the pointer,
+   getting an lvalue of type ``T``.  Analogous to:
+
+   .. code-block:: c
+
+     *(EXPR)
+
+   in C.
+
+Field access is provided separately for both lvalues and rvalues.
+
+.. function:: gcc_jit_lvalue *\
+              gcc_jit_lvalue_access_field (gcc_jit_lvalue *struct_,\
+                                           gcc_jit_location *loc,\
+                                           gcc_jit_field *field)
+
+   Given an lvalue of struct or union type, access the given field,
+   getting an lvalue of the field's type.  Analogous to:
+
+   .. code-block:: c
+
+      (EXPR).field = ...;
+
+   in C.
+
+.. function:: gcc_jit_rvalue *\
+              gcc_jit_rvalue_access_field (gcc_jit_rvalue *struct_,\
+                                           gcc_jit_location *loc,\
+                                           gcc_jit_field *field)
+
+   Given an rvalue of struct or union type, access the given field
+   as an rvalue.  Analogous to:
+
+   .. code-block:: c
+
+      (EXPR).field
+
+   in C.
+
+.. function:: gcc_jit_lvalue *\
+              gcc_jit_rvalue_dereference_field (gcc_jit_rvalue *ptr,\
+                                                gcc_jit_location *loc,\
+                                                gcc_jit_field *field)
+
+   Given an rvalue of pointer type ``T *`` where T is of struct or union
+   type, access the given field as an lvalue.  Analogous to:
+
+   .. code-block:: c
+
+      (EXPR)->field
+
+   in C, itself equivalent to ``(*EXPR).FIELD``.
+
+.. function:: gcc_jit_lvalue *\
+              gcc_jit_context_new_array_access (gcc_jit_context *ctxt,\
+                                                gcc_jit_location *loc,\
+                                                gcc_jit_rvalue *ptr,\
+                                                gcc_jit_rvalue *index)
+
+   Given an rvalue of pointer type ``T *``, get at the element `T` at
+   the given index, using standard C array indexing rules i.e. each
+   increment of ``index`` corresponds to ``sizeof(T)`` bytes.
+   Analogous to:
+
+   .. code-block:: c
+
+      PTR[INDEX]
+
+   in C (or, indeed, to ``PTR + INDEX``).
diff --git a/gcc/jit/docs/topics/functions.rst b/gcc/jit/docs/topics/functions.rst
new file mode 100644 (file)
index 0000000..aa0c069
--- /dev/null
@@ -0,0 +1,311 @@
+.. Copyright (C) 2014 Free Software Foundation, Inc.
+   Originally contributed by David Malcolm <dmalcolm@redhat.com>
+
+   This is free software: you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see
+   <http://www.gnu.org/licenses/>.
+
+.. default-domain:: c
+
+Creating and using functions
+============================
+
+Params
+------
+.. type:: gcc_jit_param
+
+   A `gcc_jit_param` represents a parameter to a function.
+
+.. function:: gcc_jit_param *\
+              gcc_jit_context_new_param (gcc_jit_context *ctxt,\
+                                         gcc_jit_location *loc,\
+                                         gcc_jit_type *type,\
+                                         const char *name)
+
+   In preparation for creating a function, create a new parameter of the
+   given type and name.
+
+Parameters are lvalues, and thus are also rvalues (and objects), so the
+following upcasts are available:
+
+.. function::  gcc_jit_lvalue *\
+               gcc_jit_param_as_lvalue (gcc_jit_param *param)
+
+   Upcasting from param to lvalue.
+
+.. function::  gcc_jit_rvalue *\
+               gcc_jit_param_as_rvalue (gcc_jit_param *param)
+
+   Upcasting from param to rvalue.
+
+.. function::  gcc_jit_object *\
+               gcc_jit_param_as_object (gcc_jit_param *param)
+
+   Upcasting from param to object.
+
+
+Functions
+---------
+
+.. type:: gcc_jit_function
+
+   A `gcc_jit_function` represents a function - either one that we're
+   creating ourselves, or one that we're referencing.
+
+.. function::  gcc_jit_function *\
+               gcc_jit_context_new_function (gcc_jit_context *ctxt,\
+                                             gcc_jit_location *loc,\
+                                             enum gcc_jit_function_kind kind,\
+                                             gcc_jit_type *return_type,\
+                                             const char *name,\
+                                             int num_params,\
+                                             gcc_jit_param **params,\
+                                             int is_variadic)
+
+   Create a gcc_jit_function with the given name and parameters.
+
+   .. type:: enum gcc_jit_function_kind
+
+   This enum controls the kind of function created, and has the following
+   values:
+
+      .. macro:: GCC_JIT_FUNCTION_EXPORTED
+
+         Function is defined by the client code and visible
+         by name outside of the JIT.
+
+      .. macro::   GCC_JIT_FUNCTION_INTERNAL
+
+         Function is defined by the client code, but is invisible
+         outside of the JIT.  Analogous to a "static" function.
+
+      .. macro::   GCC_JIT_FUNCTION_IMPORTED
+
+         Function is not defined by the client code; we're merely
+         referring to it.  Analogous to using an "extern" function from a
+         header file.
+
+      .. macro::   GCC_JIT_FUNCTION_ALWAYS_INLINE
+
+         Function is only ever inlined into other functions, and is
+         invisible outside of the JIT.
+
+         Analogous to prefixing with ``inline`` and adding
+         ``__attribute__((always_inline))``
+
+         Inlining will only occur when the optimization level is
+         above 0; when optimization is off, this is essentially the
+         same as GCC_JIT_FUNCTION_INTERNAL.
+
+.. function::  gcc_jit_function *\
+               gcc_jit_context_get_builtin_function (gcc_jit_context *ctxt,\
+                                                     const char *name)
+
+.. function::  gcc_jit_object *\
+               gcc_jit_function_as_object (gcc_jit_function *func)
+
+    Upcasting from function to object.
+
+.. function::  gcc_jit_param *\
+               gcc_jit_function_get_param (gcc_jit_function *func, int index)
+
+   Get the param of the given index (0-based).
+
+.. function::  void \
+               gcc_jit_function_dump_to_dot (gcc_jit_function *func,\
+                                             const char *path)
+
+   Emit the function in graphviz format to the given path.
+
+.. function:: gcc_jit_lvalue *\
+              gcc_jit_function_new_local (gcc_jit_function *func,\
+                                          gcc_jit_location *loc,\
+                                          gcc_jit_type *type,\
+                                          const char *name)
+
+   Create a new local variable within the function, of the given type and
+   name.
+
+
+Blocks
+------
+.. type:: gcc_jit_block
+
+   A `gcc_jit_block` represents a basic block within a function  i.e. a
+   sequence of statements with a single entry point and a single exit
+   point.
+
+   The first basic block that you create within a function will
+   be the entrypoint.
+
+   Each basic block that you create within a function must be
+   terminated, either with a conditional, a jump, or a return.
+
+   It's legal to have multiple basic blocks that return within
+   one function.
+
+.. function::  gcc_jit_block *\
+               gcc_jit_function_new_block (gcc_jit_function *func,\
+                                           const char *name)
+
+   Create a basic block of the given name.  The name may be NULL, but
+   providing meaningful names is often helpful when debugging: it may
+   show up in dumps of the internal representation, and in error
+   messages.
+
+.. function::  gcc_jit_object *\
+               gcc_jit_block_as_object (gcc_jit_block *block)
+
+   Upcast from block to object.
+
+.. function::  gcc_jit_function *\
+               gcc_jit_block_get_function (gcc_jit_block *block)
+
+   Which function is this block within?
+
+
+Statements
+----------
+
+.. function:: void\
+              gcc_jit_block_add_eval (gcc_jit_block *block,\
+                                      gcc_jit_location *loc,\
+                                      gcc_jit_rvalue *rvalue)
+
+   Add evaluation of an rvalue, discarding the result
+   (e.g. a function call that "returns" void).
+
+   This is equivalent to this C code:
+
+   .. code-block:: c
+
+     (void)expression;
+
+.. function:: void\
+              gcc_jit_block_add_assignment (gcc_jit_block *block,\
+                                            gcc_jit_location *loc,\
+                                            gcc_jit_lvalue *lvalue,\
+                                            gcc_jit_rvalue *rvalue)
+
+   Add evaluation of an rvalue, assigning the result to the given
+   lvalue.
+
+   This is roughly equivalent to this C code:
+
+   .. code-block:: c
+
+     lvalue = rvalue;
+
+.. function:: void\
+              gcc_jit_block_add_assignment_op (gcc_jit_block *block,\
+                                 gcc_jit_location *loc,\
+                                 gcc_jit_lvalue *lvalue,\
+                                 enum gcc_jit_binary_op op,\
+                                 gcc_jit_rvalue *rvalue)
+
+   Add evaluation of an rvalue, using the result to modify an
+   lvalue.
+
+   This is analogous to "+=" and friends:
+
+   .. code-block:: c
+
+     lvalue += rvalue;
+     lvalue *= rvalue;
+     lvalue /= rvalue;
+
+   etc.  For example:
+
+   .. code-block:: c
+
+     /* "i++" */
+     gcc_jit_block_add_assignment_op (
+       loop_body, NULL,
+       i,
+       GCC_JIT_BINARY_OP_PLUS,
+       gcc_jit_context_one (ctxt, int_type));
+
+.. function:: void\
+              gcc_jit_block_add_comment (gcc_jit_block *block,\
+                                         gcc_jit_location *loc,\
+                                         const char *text)
+
+   Add a no-op textual comment to the internal representation of the
+   code.  It will be optimized away, but will be visible in the dumps
+   seen via :macro:`GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE`
+   and :macro:`GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE`,
+   and thus may be of use when debugging how your project's internal
+   representation gets converted to the libgccjit IR.
+
+.. function:: void\
+              gcc_jit_block_end_with_conditional (gcc_jit_block *block,\
+                                                  gcc_jit_location *loc,\
+                                                  gcc_jit_rvalue *boolval,\
+                                                  gcc_jit_block *on_true,\
+                                                  gcc_jit_block *on_false)
+
+   Terminate a block by adding evaluation of an rvalue, branching on the
+   result to the appropriate successor block.
+
+   This is roughly equivalent to this C code:
+
+   .. code-block:: c
+
+     if (boolval)
+       goto on_true;
+     else
+       goto on_false;
+
+   block, boolval, on_true, and on_false must be non-NULL.
+
+.. function:: void\
+              gcc_jit_block_end_with_jump (gcc_jit_block *block,\
+                                           gcc_jit_location *loc,\
+                                           gcc_jit_block *target)
+
+
+   Terminate a block by adding a jump to the given target block.
+
+   This is roughly equivalent to this C code:
+
+   .. code-block:: c
+
+      goto target;
+
+.. function:: void\
+              gcc_jit_block_end_with_return (gcc_jit_block *block,\
+                                             gcc_jit_location *loc,\
+                                             gcc_jit_rvalue *rvalue)
+
+
+   Terminate a block by adding evaluation of an rvalue, returning the value.
+
+   This is roughly equivalent to this C code:
+
+   .. code-block:: c
+
+      return expression;
+
+.. function:: void\
+              gcc_jit_block_end_with_void_return (gcc_jit_block *block,\
+                                                  gcc_jit_location *loc)
+
+
+   Terminate a block by adding a valueless return, for use within a function
+   with "void" return type.
+
+   This is equivalent to this C code:
+
+   .. code-block:: c
+
+      return;
diff --git a/gcc/jit/docs/topics/index.rst b/gcc/jit/docs/topics/index.rst
new file mode 100644 (file)
index 0000000..a129137
--- /dev/null
@@ -0,0 +1,30 @@
+.. Copyright (C) 2014 Free Software Foundation, Inc.
+   Originally contributed by David Malcolm <dmalcolm@redhat.com>
+
+   This is free software: you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see
+   <http://www.gnu.org/licenses/>.
+
+Topic Reference
+===============
+
+.. toctree::
+   :maxdepth: 2
+
+   contexts.rst
+   objects.rst
+   types.rst
+   expressions.rst
+   functions.rst
+   locations.rst
+   results.rst
diff --git a/gcc/jit/docs/topics/locations.rst b/gcc/jit/docs/topics/locations.rst
new file mode 100644 (file)
index 0000000..d1db974
--- /dev/null
@@ -0,0 +1,69 @@
+.. Copyright (C) 2014 Free Software Foundation, Inc.
+   Originally contributed by David Malcolm <dmalcolm@redhat.com>
+
+   This is free software: you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see
+   <http://www.gnu.org/licenses/>.
+
+.. default-domain:: c
+
+Source Locations
+================
+
+.. type:: gcc_jit_location
+
+   A `gcc_jit_location` encapsulates a source code location, so that
+   you can (optionally) associate locations in your language with
+   statements in the JIT-compiled code, allowing the debugger to
+   single-step through your language.
+
+   `gcc_jit_location` instances are optional: you can always pass NULL to
+   any API entrypoint accepting one.
+
+   You can construct them using :c:func:`gcc_jit_context_new_location`.
+
+   You need to enable :c:macro:`GCC_JIT_BOOL_OPTION_DEBUGINFO` on the
+   :c:type:`gcc_jit_context` for these locations to actually be usable by
+   the debugger:
+
+   .. code-block:: c
+
+     gcc_jit_context_set_bool_option (
+       ctxt,
+       GCC_JIT_BOOL_OPTION_DEBUGINFO,
+       1);
+
+.. function:: gcc_jit_location *\
+              gcc_jit_context_new_location (gcc_jit_context *ctxt,\
+                                            const char *filename,\
+                                            int line,\
+                                            int column)
+
+   Create a `gcc_jit_location` instance representing the given source
+   location.
+
+Faking it
+---------
+If you don't have source code for your internal representation, but need
+to debug, you can generate a C-like representation of the functions in
+your context using :c:func:`gcc_jit_context_dump_to_file()`:
+
+.. code-block:: c
+
+  gcc_jit_context_dump_to_file (ctxt, "/tmp/something.c",
+                                1 /* update_locations */);
+
+This will dump C-like code to the given path.  If the `update_locations`
+argument is true, this will also set up `gcc_jit_location` information
+throughout the context, pointing at the dump file as if it were a source
+file, giving you *something* you can step through in the debugger.
diff --git a/gcc/jit/docs/topics/objects.rst b/gcc/jit/docs/topics/objects.rst
new file mode 100644 (file)
index 0000000..b05888d
--- /dev/null
@@ -0,0 +1,86 @@
+.. Copyright (C) 2014 Free Software Foundation, Inc.
+   Originally contributed by David Malcolm <dmalcolm@redhat.com>
+
+   This is free software: you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see
+   <http://www.gnu.org/licenses/>.
+
+.. default-domain:: c
+
+Objects
+=======
+
+.. type:: gcc_jit_object
+
+Almost every entity in the API (with the exception of
+:c:type:`gcc_jit_context *` and :c:type:`gcc_jit_result *`) is a
+"contextual" object, a :c:type:`gcc_jit_object *`
+
+A JIT object:
+
+  * is associated with a :c:type:`gcc_jit_context *`.
+
+  * is automatically cleaned up for you when its context is released so
+    you don't need to manually track and cleanup all objects, just the
+    contexts.
+
+Although the API is C-based, there is a form of class hierarchy, which
+looks like this::
+
+  +- gcc_jit_object
+      +- gcc_jit_location
+      +- gcc_jit_type
+         +- gcc_jit_struct
+      +- gcc_jit_field
+      +- gcc_jit_function
+      +- gcc_jit_block
+      +- gcc_jit_rvalue
+          +- gcc_jit_lvalue
+             +- gcc_jit_param
+
+There are casting methods for upcasting from subclasses to parent classes.
+For example, :c:func:`gcc_jit_type_as_object`:
+
+.. code-block:: c
+
+   gcc_jit_object *obj = gcc_jit_type_as_object (int_type);
+
+The object "base class" has the following operations:
+
+.. function:: gcc_jit_context *gcc_jit_object_get_context (gcc_jit_object *obj)
+
+  Which context is "obj" within?
+
+
+.. function:: const char *gcc_jit_object_get_debug_string (gcc_jit_object *obj)
+
+  Generate a human-readable description for the given object.
+
+  For example,
+
+  .. code-block:: c
+
+     printf ("obj: %s\n", gcc_jit_object_get_debug_string (obj));
+
+  might give this text on stdout:
+
+  .. code-block:: bash
+
+     obj: 4.0 * (float)i
+
+  .. note::
+
+     If you call this on an object, the `const char *` buffer is allocated
+     and generated on the first call for that object, and the buffer will
+     have the same lifetime as the object  i.e. it will exist until the
+     object's context is released.
diff --git a/gcc/jit/docs/topics/results.rst b/gcc/jit/docs/topics/results.rst
new file mode 100644 (file)
index 0000000..10dc94f
--- /dev/null
@@ -0,0 +1,48 @@
+.. Copyright (C) 2014 Free Software Foundation, Inc.
+   Originally contributed by David Malcolm <dmalcolm@redhat.com>
+
+   This is free software: you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see
+   <http://www.gnu.org/licenses/>.
+
+.. default-domain:: c
+
+Compilation results
+===================
+
+.. type:: gcc_jit_result
+
+  A `gcc_jit_result` encapsulates the result of compiling a context.
+
+.. function:: gcc_jit_result *\
+              gcc_jit_context_compile (gcc_jit_context *ctxt)
+
+   This calls into GCC and builds the code, returning a
+   `gcc_jit_result *`.
+
+
+.. function:: void *\
+              gcc_jit_result_get_code (gcc_jit_result *result,\
+                                       const char *funcname)
+
+   Locate a given function within the built machine code.
+   This will need to be cast to a function pointer of the
+   correct type before it can be called.
+
+
+.. function:: void\
+              gcc_jit_result_release (gcc_jit_result *result)
+
+   Once we're done with the code, this unloads the built .so file.
+   This cleans up the result; after calling this, it's no longer
+   valid to use the result.
diff --git a/gcc/jit/docs/topics/types.rst b/gcc/jit/docs/topics/types.rst
new file mode 100644 (file)
index 0000000..6770eca
--- /dev/null
@@ -0,0 +1,217 @@
+.. Copyright (C) 2014 Free Software Foundation, Inc.
+   Originally contributed by David Malcolm <dmalcolm@redhat.com>
+
+   This is free software: you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see
+   <http://www.gnu.org/licenses/>.
+
+.. default-domain:: c
+
+Types
+=====
+
+.. c:type:: gcc_jit_type
+
+   gcc_jit_type represents a type within the library.
+
+.. function:: gcc_jit_object *gcc_jit_type_as_object (gcc_jit_type *type)
+
+   Upcast a type to an object.
+
+Types can be created in several ways:
+
+* fundamental types can be accessed using
+  :func:`gcc_jit_context_get_type`:
+
+  .. code-block:: c
+
+      gcc_jit_type *int_type = gcc_jit_context_get_type (GCC_JIT_TYPE_INT);
+
+  See :func:`gcc_jit_context_get_type` for the available types.
+
+* derived types can be accessed by using functions such as
+  :func:`gcc_jit_type_get_pointer` and :func:`gcc_jit_type_get_const`:
+
+  .. code-block:: c
+
+    gcc_jit_type *const_int_star = gcc_jit_type_get_pointer (gcc_jit_type_get_const (int_type));
+    gcc_jit_type *int_const_star = gcc_jit_type_get_const (gcc_jit_type_get_pointer (int_type));
+
+* by creating structures (see below).
+
+Standard types
+--------------
+
+.. function:: gcc_jit_type *gcc_jit_context_get_type (gcc_jit_context *ctxt, \
+                                                      enum gcc_jit_types type_)
+
+   Access a specific type.  The available types are:
+
+   =========================================  ================================
+   `enum gcc_jit_types` value                 Meaning
+   =========================================  ================================
+   :c:data:`GCC_JIT_TYPE_VOID`                C's ``void`` type.
+   :c:data:`GCC_JIT_TYPE_VOID_PTR`            C's ``void *``.
+   :c:data:`GCC_JIT_TYPE_BOOL`                C++'s ``bool`` type; also C99's
+                                              ``_Bool`` type, aka ``bool`` if
+                                              using stdbool.h.
+   :c:data:`GCC_JIT_TYPE_CHAR`                C's ``char`` (of some signedness)
+   :c:data:`GCC_JIT_TYPE_SIGNED_CHAR`         C's ``signed char``
+   :c:data:`GCC_JIT_TYPE_UNSIGNED_CHAR`       C's ``unsigned char``
+   :c:data:`GCC_JIT_TYPE_SHORT`               C's ``short`` (signed)
+   :c:data:`GCC_JIT_TYPE_UNSIGNED_SHORT`      C's ``unsigned short``
+   :c:data:`GCC_JIT_TYPE_INT`                 C's ``int`` (signed)
+   :c:data:`GCC_JIT_TYPE_UNSIGNED_INT`        C's ``unsigned int``
+   :c:data:`GCC_JIT_TYPE_LONG`                C's ``long`` (signed)
+   :c:data:`GCC_JIT_TYPE_UNSIGNED_LONG`       C's ``unsigned long``
+   :c:data:`GCC_JIT_TYPE_LONG_LONG`           C99's ``long long`` (signed)
+   :c:data:`GCC_JIT_TYPE_UNSIGNED_LONG_LONG`  C99's ``unsigned long long``
+   :c:data:`GCC_JIT_TYPE_FLOAT`
+   :c:data:`GCC_JIT_TYPE_DOUBLE`
+   :c:data:`GCC_JIT_TYPE_LONG_DOUBLE`
+   :c:data:`GCC_JIT_TYPE_CONST_CHAR_PTR`      C type: ``(const char *)``
+   :c:data:`GCC_JIT_TYPE_SIZE_T`              C's ``size_t`` type
+   :c:data:`GCC_JIT_TYPE_FILE_PTR`            C type: ``(FILE *)``
+   =========================================  ================================
+
+.. function:: gcc_jit_type *\
+              gcc_jit_context_get_int_type (gcc_jit_context *ctxt, \
+                                            int num_bytes, int is_signed)
+
+   Access the integer type of the given size.
+
+
+Pointers, `const`, and `volatile`
+---------------------------------
+
+.. function::  gcc_jit_type *gcc_jit_type_get_pointer (gcc_jit_type *type)
+
+   Given type "T", get type "T*".
+
+.. function::  gcc_jit_type *gcc_jit_type_get_const (gcc_jit_type *type)
+
+   Given type "T", get type "const T".
+
+.. function::  gcc_jit_type *gcc_jit_type_get_volatile (gcc_jit_type *type)
+
+   Given type "T", get type "volatile T".
+
+.. function::  gcc_jit_type *\
+               gcc_jit_context_new_array_type (gcc_jit_context *ctxt, \
+                                               gcc_jit_location *loc, \
+                                               gcc_jit_type *element_type, \
+                                               int num_elements)
+
+   Given type "T", get type "T[N]" (for a constant N).
+
+
+Structures and unions
+---------------------
+
+.. c:type:: gcc_jit_struct
+
+A compound type analagous to a C `struct`.
+
+.. c:type:: gcc_jit_field
+
+A field within a :c:type:`gcc_jit_struct`.
+
+You can model C `struct` types by creating :c:type:`gcc_jit_struct *` and
+:c:type:`gcc_jit_field` instances, in either order:
+
+* by creating the fields, then the structure.  For example, to model:
+
+  .. code-block:: c
+
+    struct coord {double x; double y; };
+
+  you could call:
+
+  .. code-block:: c
+
+    gcc_jit_field *field_x =
+      gcc_jit_context_new_field (ctxt, NULL, double_type, "x");
+    gcc_jit_field *field_y =
+      gcc_jit_context_new_field (ctxt, NULL, double_type, "y");
+    gcc_jit_field *fields[2] = {field_x, field_y};
+    gcc_jit_struct *coord =
+      gcc_jit_context_new_struct_type (ctxt, NULL, "coord", 2, fields);
+
+* by creating the structure, then populating it with fields, typically
+  to allow modelling self-referential structs such as:
+
+  .. code-block:: c
+
+    struct node { int m_hash; struct node *m_next; };
+
+  like this:
+
+  .. code-block:: c
+
+    gcc_jit_type *node =
+      gcc_jit_context_new_opaque_struct (ctxt, NULL, "node");
+    gcc_jit_type *node_ptr =
+      gcc_jit_type_get_pointer (node);
+    gcc_jit_field *field_hash =
+      gcc_jit_context_new_field (ctxt, NULL, int_type, "m_hash");
+    gcc_jit_field *field_next =
+      gcc_jit_context_new_field (ctxt, NULL, node_ptr, "m_next");
+    gcc_jit_field *fields[2] = {field_hash, field_next};
+    gcc_jit_struct_set_fields (node, NULL, 2, fields);
+
+.. function:: gcc_jit_field *\
+              gcc_jit_context_new_field (gcc_jit_context *ctxt,\
+                                         gcc_jit_location *loc,\
+                                         gcc_jit_type *type,\
+                                         const char *name)
+
+   Construct a new field, with the given type and name.
+
+.. function:: gcc_jit_object *\
+              gcc_jit_field_as_object (gcc_jit_field *field)
+
+   Upcast from field to object.
+
+.. function:: gcc_jit_struct *\
+   gcc_jit_context_new_struct_type (gcc_jit_context *ctxt,\
+                                    gcc_jit_location *loc,\
+                                    const char *name,\
+                                    int num_fields,\
+                                    gcc_jit_field **fields)
+
+     Construct a new struct type, with the given name and fields.
+
+.. function:: gcc_jit_struct *\
+              gcc_jit_context_new_opaque_struct (gcc_jit_context *ctxt,\
+                                                 gcc_jit_location *loc,\
+                                                 const char *name)
+
+     Construct a new struct type, with the given name, but without
+     specifying the fields.   The fields can be omitted (in which case the
+     size of the struct is not known), or later specified using
+     :c:func:`gcc_jit_struct_set_fields`.
+
+.. function:: gcc_jit_type *\
+              gcc_jit_struct_as_type (gcc_jit_struct *struct_type)
+
+   Upcast from struct to type.
+
+.. function:: void\
+              gcc_jit_struct_set_fields (gcc_jit_struct *struct_type,\
+                                         gcc_jit_location *loc,\
+                                         int num_fields,\
+                                         gcc_jit_field **fields)
+
+   Populate the fields of a formerly-opaque struct type.
+
+   This can only be called once on a given struct type.
diff --git a/gcc/jit/dummy-frontend.c b/gcc/jit/dummy-frontend.c
new file mode 100644 (file)
index 0000000..7e3abda
--- /dev/null
@@ -0,0 +1,252 @@
+/* jit.c -- Dummy "frontend" for use during JIT-compilation.
+   Copyright (C) 2013-2014 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "opts.h"
+#include "signop.h"
+#include "tree-core.h"
+#include "stor-layout.h"
+#include "tree.h"
+#include "debug.h"
+#include "langhooks.h"
+#include "langhooks-def.h"
+#include "hash-map.h"
+#include "is-a.h"
+#include "plugin-api.h"
+#include "vec.h"
+#include "hashtab.h"
+#include "hash-set.h"
+#include "machmode.h"
+#include "tm.h"
+#include "hard-reg-set.h"
+#include "function.h"
+#include "ipa-ref.h"
+#include "dumpfile.h"
+#include "cgraph.h"
+
+#include "jit-common.h"
+#include "jit-playback.h"
+
+#include <mpfr.h>
+
+/* Language-dependent contents of a type.  */
+
+struct GTY(()) lang_type
+{
+  char dummy;
+};
+
+/* Language-dependent contents of a decl.  */
+
+struct GTY((variable_size)) lang_decl
+{
+  char dummy;
+};
+
+/* Language-dependent contents of an identifier.  This must include a
+   tree_identifier.  */
+
+struct GTY(()) lang_identifier
+{
+  struct tree_identifier common;
+};
+
+/* The resulting tree type.  */
+
+union GTY((desc ("TREE_CODE (&%h.generic) == IDENTIFIER_NODE"),
+          chain_next ("CODE_CONTAINS_STRUCT (TREE_CODE (&%h.generic), TS_COMMON) ? ((union lang_tree_node *) TREE_CHAIN (&%h.generic)) : NULL")))
+lang_tree_node
+{
+  union tree_node GTY((tag ("0"),
+                      desc ("tree_node_structure (&%h)"))) generic;
+  struct lang_identifier GTY((tag ("1"))) identifier;
+};
+
+/* We don't use language_function.  */
+
+struct GTY(()) language_function
+{
+  int dummy;
+};
+
+/* GC-marking callback for use from jit_root_tab.
+
+   If there's an active playback context, call its marking method
+   so that it can mark any pointers it references.  */
+
+static void my_ggc_walker (void *)
+{
+  if (gcc::jit::active_playback_ctxt)
+    gcc::jit::active_playback_ctxt->gt_ggc_mx ();
+}
+
+const char *dummy;
+
+struct ggc_root_tab jit_root_tab[] =
+  {
+    {
+      &dummy, 1, 0, my_ggc_walker, NULL
+    },
+    LAST_GGC_ROOT_TAB
+  };
+
+/* Language hooks.  */
+
+static bool
+jit_langhook_init (void)
+{
+  static bool registered_root_tab = false;
+  if (!registered_root_tab)
+    {
+      ggc_register_root_tab (jit_root_tab);
+      registered_root_tab = true;
+    }
+
+  build_common_tree_nodes (false, false);
+
+  /* I don't know why this has to be done explicitly.  */
+  void_list_node = build_tree_list (NULL_TREE, void_type_node);
+
+  build_common_builtin_nodes ();
+
+  /* The default precision for floating point numbers.  This is used
+     for floating point constants with abstract type.  This may
+     eventually be controllable by a command line option.  */
+  mpfr_set_default_prec (256);
+
+  return true;
+}
+
+static void
+jit_langhook_parse_file (void)
+{
+  /* Replay the activity by the client, recorded on the context.  */
+  gcc_assert (gcc::jit::active_playback_ctxt);
+  gcc::jit::active_playback_ctxt->replay ();
+}
+
+static tree
+jit_langhook_type_for_mode (enum machine_mode mode, int unsignedp)
+{
+  if (mode == TYPE_MODE (float_type_node))
+    return float_type_node;
+
+  if (mode == TYPE_MODE (double_type_node))
+    return double_type_node;
+
+  if (mode == TYPE_MODE (integer_type_node))
+    return unsignedp ? unsigned_type_node : integer_type_node;
+
+  if (mode == TYPE_MODE (long_integer_type_node))
+    return unsignedp ? long_unsigned_type_node : long_integer_type_node;
+
+  if (COMPLEX_MODE_P (mode))
+    {
+      if (mode == TYPE_MODE (complex_float_type_node))
+       return complex_float_type_node;
+      if (mode == TYPE_MODE (complex_double_type_node))
+       return complex_double_type_node;
+      if (mode == TYPE_MODE (complex_long_double_type_node))
+       return complex_long_double_type_node;
+      if (mode == TYPE_MODE (complex_integer_type_node) && !unsignedp)
+       return complex_integer_type_node;
+    }
+
+  /* gcc_unreachable */
+  return NULL;
+}
+
+static tree
+jit_langhook_type_for_size (unsigned int bits ATTRIBUTE_UNUSED,
+                           int unsignedp ATTRIBUTE_UNUSED)
+{
+  gcc_unreachable ();
+  return NULL;
+}
+
+/* Record a builtin function.  We just ignore builtin functions.  */
+
+static tree
+jit_langhook_builtin_function (tree decl)
+{
+  return decl;
+}
+
+static bool
+jit_langhook_global_bindings_p (void)
+{
+  gcc_unreachable ();
+  return true;
+}
+
+static tree
+jit_langhook_pushdecl (tree decl ATTRIBUTE_UNUSED)
+{
+  gcc_unreachable ();
+}
+
+static tree
+jit_langhook_getdecls (void)
+{
+  return NULL;
+}
+
+static void
+jit_langhook_write_globals (void)
+{
+  /* This is the hook that runs the middle and backends: */
+  symtab->finalize_compilation_unit ();
+}
+
+#undef LANG_HOOKS_NAME
+#define LANG_HOOKS_NAME                "libgccjit"
+
+#undef LANG_HOOKS_INIT
+#define LANG_HOOKS_INIT                jit_langhook_init
+
+#undef LANG_HOOKS_PARSE_FILE
+#define LANG_HOOKS_PARSE_FILE          jit_langhook_parse_file
+
+#undef LANG_HOOKS_TYPE_FOR_MODE
+#define LANG_HOOKS_TYPE_FOR_MODE       jit_langhook_type_for_mode
+
+#undef LANG_HOOKS_TYPE_FOR_SIZE
+#define LANG_HOOKS_TYPE_FOR_SIZE       jit_langhook_type_for_size
+
+#undef LANG_HOOKS_BUILTIN_FUNCTION
+#define LANG_HOOKS_BUILTIN_FUNCTION    jit_langhook_builtin_function
+
+#undef LANG_HOOKS_GLOBAL_BINDINGS_P
+#define LANG_HOOKS_GLOBAL_BINDINGS_P   jit_langhook_global_bindings_p
+
+#undef LANG_HOOKS_PUSHDECL
+#define LANG_HOOKS_PUSHDECL            jit_langhook_pushdecl
+
+#undef LANG_HOOKS_GETDECLS
+#define LANG_HOOKS_GETDECLS            jit_langhook_getdecls
+
+#undef LANG_HOOKS_WRITE_GLOBALS
+#define LANG_HOOKS_WRITE_GLOBALS       jit_langhook_write_globals
+
+struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER;
+
+#include "gt-jit-dummy-frontend.h"
+#include "gtype-jit.h"
diff --git a/gcc/jit/jit-builtins.c b/gcc/jit/jit-builtins.c
new file mode 100644 (file)
index 0000000..07902e8
--- /dev/null
@@ -0,0 +1,424 @@
+/* jit-builtins.c -- Handling of builtin functions during JIT-compilation.
+   Copyright (C) 2014 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "opts.h"
+#include "tree.h"
+#include "target.h"
+
+#include "jit-common.h"
+#include "jit-builtins.h"
+#include "jit-recording.h"
+
+namespace gcc {
+
+namespace jit {
+
+namespace recording {
+
+const char *const prefix = "__builtin_";
+const size_t prefix_len = strlen (prefix);
+
+/* Create "builtin_data", a const table of the data within builtins.def.  */
+struct builtin_data
+{
+  const char *name;
+  enum jit_builtin_type type;
+  bool both_p;
+  bool fallback_p;
+
+  const char *get_asm_name () const
+  {
+    if (both_p && fallback_p)
+      return name + prefix_len;
+    else
+      return name;
+  }
+};
+
+#define DEF_BUILTIN(X, NAME, C, TYPE, LT, BOTH_P, FALLBACK_P, NA, AT, IM, COND)\
+  {NAME, TYPE, BOTH_P, FALLBACK_P},
+static const struct builtin_data builtin_data[] =
+{
+#include "builtins.def"
+};
+#undef DEF_BUILTIN
+
+/* Helper function for find_builtin_by_name.  */
+
+static bool
+matches_builtin (const char *in_name,
+                const struct builtin_data& bd)
+{
+  const bool debug = 0;
+  gcc_assert (bd.name);
+
+  if (debug)
+    fprintf (stderr, "seen builtin: %s\n", bd.name);
+
+  if (0 == strcmp (bd.name, in_name))
+    {
+      return true;
+    }
+
+  if (bd.both_p)
+    {
+      /* Then the macros in builtins.def gave a "__builtin_"
+        prefix to bd.name, but we should also recognize the form
+        without the prefix.  */
+      gcc_assert (0 == strncmp (bd.name, prefix, prefix_len));
+      if (debug)
+       fprintf (stderr, "testing without prefix as: %s\n",
+                bd.name + prefix_len);
+      if (0 == strcmp (bd.name + prefix_len, in_name))
+       {
+         return true;
+       }
+    }
+
+  return false;
+}
+
+/* Locate the built-in function that matches name IN_NAME,
+   writing the result to OUT_ID and returning true if found,
+   or returning false if not found.  */
+
+static bool
+find_builtin_by_name (const char *in_name,
+                     enum built_in_function *out_id)
+{
+  /* Locate builtin.  This currently works by performing repeated
+     strcmp against every possible candidate, which is likely to
+     inefficient.
+
+     We start at index 1 to skip the initial entry (BUILT_IN_NONE), which
+     has a NULL name.  */
+  for (unsigned int i = 1;
+       i < sizeof (builtin_data) / sizeof (builtin_data[0]);
+       i++)
+    {
+      const struct builtin_data& bd = builtin_data[i];
+      if (matches_builtin (in_name, bd))
+       {
+         /* Found a match.  */
+         *out_id = static_cast<enum built_in_function> (i);
+         return true;
+       }
+    }
+
+  /* Not found.  */
+  return false;
+}
+
+// class builtins_manager
+
+/* Constructor for gcc::jit::recording::builtins_manager.  */
+
+builtins_manager::builtins_manager (context *ctxt)
+  : m_ctxt (ctxt)
+{
+  memset (m_types, 0, sizeof (m_types));
+  memset (m_builtin_functions, 0, sizeof (m_builtin_functions));
+}
+
+/* Locate a builtin function by name.
+   Create a recording::function of the appropriate type, reusing them
+   if they've already been seen.  */
+
+function *
+builtins_manager::get_builtin_function (const char *name)
+{
+  enum built_in_function builtin_id;
+  if (!find_builtin_by_name (name, &builtin_id))
+    {
+      m_ctxt->add_error (NULL, "builtin \"%s\" not found", name);
+      return NULL;
+    }
+
+  gcc_assert (builtin_id >= 0);
+  gcc_assert (builtin_id < END_BUILTINS);
+
+  /* Lazily build the functions, caching them so that repeated calls for
+     the same id on a context give back the same object.  */
+  if (!m_builtin_functions[builtin_id])
+    {
+      m_builtin_functions[builtin_id] = make_builtin_function (builtin_id);
+      m_ctxt->record (m_builtin_functions[builtin_id]);
+    }
+
+  return m_builtin_functions[builtin_id];
+}
+
+/* Create the recording::function for a given builtin function, by ID.  */
+
+function *
+builtins_manager::make_builtin_function (enum built_in_function builtin_id)
+{
+  const struct builtin_data& bd = builtin_data[builtin_id];
+  enum jit_builtin_type type_id = bd.type;
+  function_type *func_type = get_type (type_id)->as_a_function_type ();
+  if (!func_type)
+    return NULL;
+
+  vec<type *> param_types = func_type->get_param_types ();
+  recording::param **params = new recording::param *[param_types.length ()];
+
+  int i;
+  type *param_type;
+  FOR_EACH_VEC_ELT (param_types, i, param_type)
+    {
+      char buf[16];
+      snprintf (buf, 16, "arg%d", i);
+      params[i] = m_ctxt->new_param (NULL,
+                                    param_type,
+                                    buf);
+    }
+  const char *asm_name = bd.get_asm_name ();
+  function *result =
+    new function (m_ctxt,
+                 NULL,
+                 GCC_JIT_FUNCTION_IMPORTED, // FIXME
+                 func_type->get_return_type (),
+                 m_ctxt->new_string (asm_name),
+                 param_types.length (),
+                 params,
+                 func_type->is_variadic (),
+                 builtin_id);
+  delete[] params;
+  return result;
+}
+
+/* Get the recording::type for a given type of builtin function,
+   by ID, creating it if it doesn't already exist.  */
+
+type *
+builtins_manager::get_type (enum jit_builtin_type type_id)
+{
+  if (!m_types[type_id])
+    m_types[type_id] = make_type (type_id);
+  return m_types[type_id];
+}
+
+/* Create the recording::type for a given type of builtin function.  */
+
+type *
+builtins_manager::make_type (enum jit_builtin_type type_id)
+{
+  /* Use builtin-types.def to construct a switch statement, with each
+     case deferring to one of the methods below:
+       - DEF_PRIMITIVE_TYPE is handled as a call to make_primitive_type.
+       - the various DEF_FUNCTION_TYPE_n are handled by variadic calls
+        to make_fn_type.
+       - similarly for DEF_FUNCTION_TYPE_VAR_n, but setting the
+       "is_variadic" argument.
+       - DEF_POINTER_TYPE is handled by make_ptr_type.
+     That should handle everything, but just in case we also suppy a
+     gcc_unreachable default clause.  */
+  switch (type_id)
+    {
+#define DEF_PRIMITIVE_TYPE(ENUM, VALUE) \
+      case ENUM: return make_primitive_type (ENUM);
+#define DEF_FUNCTION_TYPE_0(ENUM, RETURN) \
+      case ENUM: return make_fn_type (ENUM, RETURN, 0, 0);
+#define DEF_FUNCTION_TYPE_1(ENUM, RETURN, ARG1) \
+      case ENUM: return make_fn_type (ENUM, RETURN, 0, 1, ARG1);
+#define DEF_FUNCTION_TYPE_2(ENUM, RETURN, ARG1, ARG2) \
+      case ENUM: return make_fn_type (ENUM, RETURN, 0, 2, ARG1, ARG2);
+#define DEF_FUNCTION_TYPE_3(ENUM, RETURN, ARG1, ARG2, ARG3) \
+      case ENUM: return make_fn_type (ENUM, RETURN, 0, 3, ARG1, ARG2, ARG3);
+#define DEF_FUNCTION_TYPE_4(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4) \
+      case ENUM: return make_fn_type (ENUM, RETURN, 0, 4, ARG1, ARG2, ARG3, ARG4);
+#define DEF_FUNCTION_TYPE_5(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5)        \
+      case ENUM: return make_fn_type (ENUM, RETURN, 0, 5, ARG1, ARG2, ARG3, ARG4, ARG5);
+#define DEF_FUNCTION_TYPE_6(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
+                           ARG6)                                       \
+      case ENUM: return make_fn_type (ENUM, RETURN, 0, 6, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6);
+#define DEF_FUNCTION_TYPE_7(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
+                           ARG6, ARG7)                                 \
+      case ENUM: return make_fn_type (ENUM, RETURN, 0, 7, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7);
+#define DEF_FUNCTION_TYPE_8(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
+                           ARG6, ARG7, ARG8)                           \
+      case ENUM: return make_fn_type (ENUM, RETURN, 0, 8, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, \
+                                     ARG7, ARG8);
+#define DEF_FUNCTION_TYPE_VAR_0(ENUM, RETURN) \
+      case ENUM: return make_fn_type (ENUM, RETURN, 1, 0);
+#define DEF_FUNCTION_TYPE_VAR_1(ENUM, RETURN, ARG1) \
+      case ENUM: return make_fn_type (ENUM, RETURN, 1, 1, ARG1);
+#define DEF_FUNCTION_TYPE_VAR_2(ENUM, RETURN, ARG1, ARG2) \
+      case ENUM: return make_fn_type (ENUM, RETURN, 1, 2, ARG1, ARG2);
+#define DEF_FUNCTION_TYPE_VAR_3(ENUM, RETURN, ARG1, ARG2, ARG3) \
+      case ENUM: return make_fn_type (ENUM, RETURN, 1, 3, ARG1, ARG2, ARG3);
+#define DEF_FUNCTION_TYPE_VAR_4(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4) \
+      case ENUM: return make_fn_type (ENUM, RETURN, 1, 4, ARG1, ARG2, ARG3, ARG4);
+#define DEF_FUNCTION_TYPE_VAR_5(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) \
+      case ENUM: return make_fn_type (ENUM, RETURN, 1, 5, ARG1, ARG2, ARG3, ARG4, ARG5);
+#define DEF_POINTER_TYPE(ENUM, TYPE) \
+      case ENUM: return make_ptr_type (ENUM, TYPE);
+
+#include "builtin-types.def"
+
+#undef DEF_PRIMITIVE_TYPE
+#undef DEF_FUNCTION_TYPE_1
+#undef DEF_FUNCTION_TYPE_2
+#undef DEF_FUNCTION_TYPE_3
+#undef DEF_FUNCTION_TYPE_4
+#undef DEF_FUNCTION_TYPE_5
+#undef DEF_FUNCTION_TYPE_6
+#undef DEF_FUNCTION_TYPE_VAR_0
+#undef DEF_FUNCTION_TYPE_VAR_1
+#undef DEF_FUNCTION_TYPE_VAR_2
+#undef DEF_FUNCTION_TYPE_VAR_3
+#undef DEF_FUNCTION_TYPE_VAR_4
+#undef DEF_FUNCTION_TYPE_VAR_5
+#undef DEF_POINTER_TYPE
+
+    default:
+      gcc_unreachable ();
+    }
+}
+
+/* Create the recording::type for a given primitive type within the
+   builtin system.
+
+   Only some types are currently supported.  */
+
+type*
+builtins_manager::make_primitive_type (enum jit_builtin_type type_id)
+{
+  switch (type_id)
+    {
+    default:
+      // only some of these types are implemented so far:
+      m_ctxt->add_error (NULL,
+                        "unimplemented primitive type for builtin: %d", type_id);
+      return NULL;
+
+    case BT_VOID: return m_ctxt->get_type (GCC_JIT_TYPE_VOID);
+    case BT_BOOL: return m_ctxt->get_type (GCC_JIT_TYPE_BOOL);
+    case BT_INT: return m_ctxt->get_type (GCC_JIT_TYPE_INT);
+    case BT_UINT: return m_ctxt->get_type (GCC_JIT_TYPE_UNSIGNED_INT);
+    case BT_LONG: return m_ctxt->get_type (GCC_JIT_TYPE_LONG);
+    case BT_ULONG: return m_ctxt->get_type (GCC_JIT_TYPE_UNSIGNED_LONG);
+    case BT_LONGLONG: return m_ctxt->get_type (GCC_JIT_TYPE_LONG_LONG);
+    case BT_ULONGLONG:
+      return m_ctxt->get_type (GCC_JIT_TYPE_UNSIGNED_LONG_LONG);
+    // case BT_INT128:
+    // case BT_UINT128:
+    // case BT_INTMAX:
+    // case BT_UINTMAX:
+    case BT_UINT16: return m_ctxt->get_int_type (2, false);
+    case BT_UINT32: return m_ctxt->get_int_type (4, false);
+    case BT_UINT64: return m_ctxt->get_int_type (8, false);
+    // case BT_WORD:
+    // case BT_UNWINDWORD:
+    case BT_FLOAT: return m_ctxt->get_type (GCC_JIT_TYPE_FLOAT);
+    case BT_DOUBLE: return m_ctxt->get_type (GCC_JIT_TYPE_DOUBLE);
+    case BT_LONGDOUBLE: return m_ctxt->get_type (GCC_JIT_TYPE_LONG_DOUBLE);
+    // case BT_COMPLEX_FLOAT:
+    // case BT_COMPLEX_DOUBLE:
+    // case BT_COMPLEX_LONGDOUBLE:
+    case BT_PTR: return m_ctxt->get_type (GCC_JIT_TYPE_VOID_PTR);
+    case BT_FILEPTR: return m_ctxt->get_type (GCC_JIT_TYPE_FILE_PTR);
+    // case BT_CONST:
+    // case BT_VOLATILE_PTR:
+    // case BT_CONST_VOLATILE_PTR:
+    // case BT_PTRMODE:
+    // case BT_INT_PTR:
+    // case BT_FLOAT_PTR:
+    // case BT_DOUBLE_PTR:
+    // case BT_CONST_DOUBLE_PTR:
+    // case BT_LONGDOUBLE_PTR:
+    // case BT_PID:
+    // case BT_SIZE:
+    // case BT_SSIZE:
+    // case BT_WINT:
+    // case BT_STRING:
+    case BT_CONST_STRING: return m_ctxt->get_type (GCC_JIT_TYPE_CONST_CHAR_PTR);
+    // case BT_DFLOAT32:
+    // case BT_DFLOAT64:
+    // case BT_DFLOAT128:
+    // case BT_DFLOAT32_PTR:
+    // case BT_DFLOAT64_PTR:
+    // case BT_DFLOAT128_PTR:
+    // case BT_VALIST_REF:
+    // case BT_VALIST_ARG:
+    // case BT_I1:
+    // case BT_I2:
+    // case BT_I4:
+    // case BT_I8:
+    // case BT_I16:
+    }
+}
+
+/* Create the recording::function_type for a given function type
+   signature.  */
+
+function_type *
+builtins_manager::make_fn_type (enum jit_builtin_type,
+                               enum jit_builtin_type return_type_id,
+                               bool is_variadic,
+                               int num_args, ...)
+{
+  va_list list;
+  int i;
+  type **param_types = new type *[num_args];
+  type *return_type = NULL;
+  function_type *result = NULL;
+
+  va_start (list, num_args);
+  for (i = 0; i < num_args; ++i)
+    {
+      enum jit_builtin_type arg_type_id =
+       (enum jit_builtin_type) va_arg (list, int);
+      param_types[i] = get_type (arg_type_id);
+      if (!param_types[i])
+       goto error;
+    }
+  va_end (list);
+
+  return_type = get_type (return_type_id);
+  if (!return_type)
+    goto error;
+
+  result = new function_type (m_ctxt,
+                             return_type,
+                             num_args,
+                             param_types,
+                             is_variadic);
+
+ error:
+  delete[] param_types;
+  return result;
+}
+
+/* Handler for DEF_POINTER_TYPE within builtins_manager::make_type.  */
+
+type *
+builtins_manager::make_ptr_type (enum jit_builtin_type,
+                                enum jit_builtin_type other_type_id)
+{
+  type *base_type = get_type (other_type_id);
+  return base_type->get_pointer ();
+}
+
+} // namespace recording
+} // namespace jit
+} // namespace gcc
diff --git a/gcc/jit/jit-builtins.h b/gcc/jit/jit-builtins.h
new file mode 100644 (file)
index 0000000..7c46bfd
--- /dev/null
@@ -0,0 +1,114 @@
+/* jit-builtins.h -- Handling of builtin functions during JIT-compilation.
+   Copyright (C) 2014 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef JIT_BUILTINS_H
+#define JIT_BUILTINS_H
+
+#include "jit-common.h"
+
+namespace gcc {
+
+namespace jit {
+
+namespace recording {
+
+/* Create an enum of the builtin types.  */
+
+enum jit_builtin_type
+{
+#define DEF_PRIMITIVE_TYPE(NAME, VALUE) NAME,
+#define DEF_FUNCTION_TYPE_0(NAME, RETURN) NAME,
+#define DEF_FUNCTION_TYPE_1(NAME, RETURN, ARG1) NAME,
+#define DEF_FUNCTION_TYPE_2(NAME, RETURN, ARG1, ARG2) NAME,
+#define DEF_FUNCTION_TYPE_3(NAME, RETURN, ARG1, ARG2, ARG3) NAME,
+#define DEF_FUNCTION_TYPE_4(NAME, RETURN, ARG1, ARG2, ARG3, ARG4) NAME,
+#define DEF_FUNCTION_TYPE_5(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) NAME,
+#define DEF_FUNCTION_TYPE_6(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6) NAME,
+#define DEF_FUNCTION_TYPE_7(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7) NAME,
+#define DEF_FUNCTION_TYPE_8(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7, ARG8) NAME,
+#define DEF_FUNCTION_TYPE_VAR_0(NAME, RETURN) NAME,
+#define DEF_FUNCTION_TYPE_VAR_1(NAME, RETURN, ARG1) NAME,
+#define DEF_FUNCTION_TYPE_VAR_2(NAME, RETURN, ARG1, ARG2) NAME,
+#define DEF_FUNCTION_TYPE_VAR_3(NAME, RETURN, ARG1, ARG2, ARG3) NAME,
+#define DEF_FUNCTION_TYPE_VAR_4(NAME, RETURN, ARG1, ARG2, ARG3, ARG4) NAME,
+#define DEF_FUNCTION_TYPE_VAR_5(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG6) \
+  NAME,
+#define DEF_POINTER_TYPE(NAME, TYPE) NAME,
+#include "builtin-types.def"
+#undef DEF_PRIMITIVE_TYPE
+#undef DEF_FUNCTION_TYPE_0
+#undef DEF_FUNCTION_TYPE_1
+#undef DEF_FUNCTION_TYPE_2
+#undef DEF_FUNCTION_TYPE_3
+#undef DEF_FUNCTION_TYPE_4
+#undef DEF_FUNCTION_TYPE_5
+#undef DEF_FUNCTION_TYPE_6
+#undef DEF_FUNCTION_TYPE_7
+#undef DEF_FUNCTION_TYPE_8
+#undef DEF_FUNCTION_TYPE_VAR_0
+#undef DEF_FUNCTION_TYPE_VAR_1
+#undef DEF_FUNCTION_TYPE_VAR_2
+#undef DEF_FUNCTION_TYPE_VAR_3
+#undef DEF_FUNCTION_TYPE_VAR_4
+#undef DEF_FUNCTION_TYPE_VAR_5
+#undef DEF_POINTER_TYPE
+  BT_LAST
+}; /* enum jit_builtin_type */
+
+/***********************************************************************/
+
+class builtins_manager
+{
+public:
+  builtins_manager (context *ctxt);
+
+  function *
+  get_builtin_function (const char *name);
+
+private:
+  function *make_builtin_function (enum built_in_function builtin_id);
+
+  type *get_type (enum jit_builtin_type type_id);
+
+  type *make_type (enum jit_builtin_type type_id);
+
+  type*
+  make_primitive_type (enum jit_builtin_type type_id);
+
+  function_type*
+  make_fn_type (enum jit_builtin_type type_id,
+               enum jit_builtin_type return_type_id,
+               bool is_variadic,
+               int num_args, ...);
+
+  type*
+  make_ptr_type (enum jit_builtin_type type_id,
+                enum jit_builtin_type other_type_id);
+
+private:
+  context *m_ctxt;
+  type *m_types[BT_LAST];
+  function *m_builtin_functions[END_BUILTINS];
+};
+
+} // namespace recording
+} // namespace jit
+} // namespace gcc
+
+#endif /* JIT_BUILTINS_H */
diff --git a/gcc/jit/jit-common.h b/gcc/jit/jit-common.h
new file mode 100644 (file)
index 0000000..58e4a8c
--- /dev/null
@@ -0,0 +1,182 @@
+/* Core of implementation of libgccjit.so
+   Copyright (C) 2013-2014 Free Software Foundation, Inc.
+   Contributed by David Malcolm <dmalcolm@redhat.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef JIT_COMMON_H
+#define JIT_COMMON_H
+
+#include "libgccjit.h"
+
+#include "tree.h"
+#include "tree-iterator.h"
+
+#ifdef GCC_VERSION
+#if GCC_VERSION >= 4001
+#define GNU_PRINTF(M, N) __attribute__ ((format (gnu_printf, (M), (N))))
+#else
+#define GNU_PRINTF(M, N)
+#endif
+#endif
+
+const int NUM_GCC_JIT_TYPES = GCC_JIT_TYPE_FILE_PTR + 1;
+
+/* This comment is included by the docs.
+
+   In order to allow jit objects to be usable outside of a compile
+   whilst working with the existing structure of GCC's code the
+   C API is implemented in terms of a gcc::jit::recording::context,
+   which records the calls made to it.
+
+   When a gcc_jit_context is compiled, the recording context creates a
+   playback context.  The playback context invokes the bulk of the GCC
+   code, and within the "frontend" parsing hook, plays back the recorded
+   API calls, creating GCC tree objects.
+
+   So there are two parallel families of classes: those relating to
+   recording, and those relating to playback:
+
+   * Visibility: recording objects are exposed back to client code,
+     whereas playback objects are internal to the library.
+
+   * Lifetime: recording objects have a lifetime equal to that of the
+     recording context that created them, whereas playback objects only
+     exist within the frontend hook.
+
+   * Memory allocation: recording objects are allocated by the recording
+     context, and automatically freed by it when the context is released,
+     whereas playback objects are allocated within the GC heap, and
+     garbage-collected; they can own GC-references.
+
+   * Integration with rest of GCC: recording objects are unrelated to the
+     rest of GCC, whereas playback objects are wrappers around "tree"
+     instances.  Hence you can't ask a recording rvalue or lvalue what its
+     type is, whereas you can for a playback rvalue of lvalue (since it
+     can work with the underlying GCC tree nodes).
+
+   * Instancing: There can be multiple recording contexts "alive" at once
+     (albeit it only one compiling at once), whereas there can only be one
+     playback context alive at one time (since it interacts with the GC).
+
+   Ultimately if GCC could support multiple GC heaps and contexts, and
+   finer-grained initialization, then this recording vs playback
+   distinction could be eliminated.
+
+   During a playback, we associate objects from the recording with
+   their counterparts during this playback.  For simplicity, we store this
+   within the recording objects, as ``void *m_playback_obj``, casting it to
+   the appropriate playback object subclass.  For these casts to make
+   sense, the two class hierarchies need to have the same structure.
+
+   Note that the playback objects that ``m_playback_obj`` points to are
+   GC-allocated, but the recording objects don't own references:
+   these associations only exist within a part of the code where
+   the GC doesn't collect, and are set back to NULL before the GC can
+   run.
+
+   End of comment for inclusion in the docs.  */
+
+namespace gcc {
+
+namespace jit {
+
+class result;
+class dump;
+
+namespace recording {
+
+  /* Recording types.  */
+
+  /* Indentation indicates inheritance: */
+  class context;
+  class builtins_manager; // declared within jit-builtins.h
+  class memento;
+    class string;
+    class location;
+    class type;
+      class function_type;
+      class compound_type;
+        class struct_;
+       class union_;
+    class field;
+    class fields;
+    class function;
+    class block;
+    class rvalue;
+      class lvalue;
+        class local;
+       class global;
+        class param;
+    class statement;
+
+  /* End of recording types. */
+}
+
+namespace playback {
+  /* Playback types.  */
+
+  /* Indentation indicates inheritance: */
+  class context;
+  class wrapper;
+    class type;
+      class compound_type;
+    class field;
+    class function;
+    class block;
+    class rvalue;
+      class lvalue;
+        class param;
+    class source_file;
+    class source_line;
+    class location;
+
+  /* End of playback types. */
+}
+
+typedef playback::context replayer;
+
+class dump
+{
+public:
+  dump (recording::context &ctxt,
+       const char *filename,
+       bool update_locations);
+  ~dump ();
+
+  void write (const char *fmt, ...)
+    GNU_PRINTF(2, 3);
+
+  bool update_locations () const { return m_update_locations; }
+
+  recording::location *
+  make_location () const;
+
+private:
+  recording::context &m_ctxt;
+  const char *m_filename;
+  bool m_update_locations;
+  int m_line;
+  int m_column;
+  FILE *m_file;
+};
+
+} // namespace gcc::jit
+
+} // namespace gcc
+
+#endif /* JIT_COMMON_H */
diff --git a/gcc/jit/jit-playback.c b/gcc/jit/jit-playback.c
new file mode 100644 (file)
index 0000000..285a3ef
--- /dev/null
@@ -0,0 +1,2100 @@
+/* Internals of libgccjit: classes for playing back recorded API calls.
+   Copyright (C) 2013-2014 Free Software Foundation, Inc.
+   Contributed by David Malcolm <dmalcolm@redhat.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "opts.h"
+#include "tree.h"
+#include "hash-map.h"
+#include "is-a.h"
+#include "plugin-api.h"
+#include "vec.h"
+#include "hashtab.h"
+#include "hash-set.h"
+#include "machmode.h"
+#include "tm.h"
+#include "hard-reg-set.h"
+#include "function.h"
+#include "ipa-ref.h"
+#include "dumpfile.h"
+#include "cgraph.h"
+#include "toplev.h"
+#include "timevar.h"
+#include "tree-cfg.h"
+#include "target.h"
+#include "convert.h"
+#include "stringpool.h"
+#include "stor-layout.h"
+#include "print-tree.h"
+#include "gimplify.h"
+#include "gcc-driver-name.h"
+
+#include "jit-common.h"
+#include "jit-playback.h"
+
+
+/* gcc::jit::playback::context::build_cast uses the convert.h API,
+   which in turn requires the frontend to provide a "convert"
+   function, apparently as a fallback.
+
+   Hence we provide this dummy one, with the requirement that any casts
+   are handled before reaching this.  */
+extern tree convert (tree type, tree expr);
+
+tree
+convert (tree dst_type, tree expr)
+{
+  gcc_assert (gcc::jit::active_playback_ctxt);
+  gcc::jit::active_playback_ctxt->add_error (NULL, "unhandled conversion");
+  fprintf (stderr, "input expression:\n");
+  debug_tree (expr);
+  fprintf (stderr, "requested type:\n");
+  debug_tree (dst_type);
+  return error_mark_node;
+}
+
+namespace gcc {
+namespace jit {
+
+/**********************************************************************
+ Playback.
+ **********************************************************************/
+
+/* The constructor for gcc::jit::playback::context.  */
+
+playback::context::context (recording::context *ctxt)
+  : m_recording_ctxt (ctxt),
+    m_char_array_type_node (NULL),
+    m_const_char_ptr (NULL)
+{
+  m_functions.create (0);
+  m_source_files.create (0);
+  m_cached_locations.create (0);
+}
+
+/* The destructor for gcc::jit::playback::context.  */
+
+playback::context::~context ()
+{
+  if (get_bool_option (GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES))
+    fprintf (stderr, "intermediate files written to %s\n", m_path_tempdir);
+  else
+    {
+      /* Clean up .s/.so and tempdir. */
+      if (m_path_s_file)
+        unlink (m_path_s_file);
+      if (m_path_so_file)
+        unlink (m_path_so_file);
+      if (m_path_tempdir)
+        rmdir (m_path_tempdir);
+    }
+
+  free (m_path_template);
+  /* m_path_tempdir aliases m_path_template, or is NULL, so don't
+     attempt to free it .  */
+  free (m_path_c_file);
+  free (m_path_s_file);
+  free (m_path_so_file);
+  m_functions.release ();
+}
+
+/* A playback::context can reference GC-managed pointers.  Mark them
+   ("by hand", rather than by gengtype).
+
+   This is called on the active playback context (if any) by the
+   my_ggc_walker hook in the jit_root_table in dummy-frontend.c.  */
+
+void
+playback::context::
+gt_ggc_mx ()
+{
+  int i;
+  function *func;
+  FOR_EACH_VEC_ELT (m_functions, i, func)
+    {
+      if (ggc_test_and_set_mark (func))
+       func->gt_ggc_mx ();
+    }
+}
+
+/* Given an enum gcc_jit_types value, get a "tree" type.  */
+
+static tree
+get_tree_node_for_type (enum gcc_jit_types type_)
+{
+  switch (type_)
+    {
+    case GCC_JIT_TYPE_VOID:
+      return void_type_node;
+
+    case GCC_JIT_TYPE_VOID_PTR:
+      return ptr_type_node;
+
+    case GCC_JIT_TYPE_BOOL:
+      return boolean_type_node;
+
+    case GCC_JIT_TYPE_CHAR:
+      return char_type_node;
+    case GCC_JIT_TYPE_SIGNED_CHAR:
+      return signed_char_type_node;
+    case GCC_JIT_TYPE_UNSIGNED_CHAR:
+      return unsigned_char_type_node;
+
+    case GCC_JIT_TYPE_SHORT:
+      return short_integer_type_node;
+    case GCC_JIT_TYPE_UNSIGNED_SHORT:
+      return short_unsigned_type_node;
+
+    case GCC_JIT_TYPE_CONST_CHAR_PTR:
+      {
+       tree const_char = build_qualified_type (char_type_node,
+                                               TYPE_QUAL_CONST);
+       return build_pointer_type (const_char);
+      }
+
+    case GCC_JIT_TYPE_INT:
+      return integer_type_node;
+    case GCC_JIT_TYPE_UNSIGNED_INT:
+      return unsigned_type_node;
+
+    case GCC_JIT_TYPE_LONG:
+      return long_integer_type_node;
+    case GCC_JIT_TYPE_UNSIGNED_LONG:
+      return long_unsigned_type_node;
+
+    case GCC_JIT_TYPE_LONG_LONG:
+      return long_long_integer_type_node;
+    case GCC_JIT_TYPE_UNSIGNED_LONG_LONG:
+      return long_long_unsigned_type_node;
+
+    case GCC_JIT_TYPE_FLOAT:
+      return float_type_node;
+    case GCC_JIT_TYPE_DOUBLE:
+      return double_type_node;
+    case GCC_JIT_TYPE_LONG_DOUBLE:
+      return long_double_type_node;
+
+    case GCC_JIT_TYPE_SIZE_T:
+      return size_type_node;
+
+    case GCC_JIT_TYPE_FILE_PTR:
+      return fileptr_type_node;
+    }
+
+  return NULL;
+}
+
+/* Construct a playback::type instance (wrapping a tree) for the given
+   enum value.  */
+
+playback::type *
+playback::context::
+get_type (enum gcc_jit_types type_)
+{
+  tree type_node = get_tree_node_for_type (type_);
+  if (NULL == type_node)
+    {
+      add_error (NULL,
+                "unrecognized (enum gcc_jit_types) value: %i", type_);
+      return NULL;
+    }
+
+  return new type (type_node);
+}
+
+/* Construct a playback::type instance (wrapping a tree) for the given
+   array type.  */
+
+playback::type *
+playback::context::
+new_array_type (playback::location *loc,
+               playback::type *element_type,
+               int num_elements)
+{
+  gcc_assert (element_type);
+
+  tree t = build_array_type_nelts (element_type->as_tree (),
+                                  num_elements);
+  layout_type (t);
+
+  if (loc)
+    set_tree_location (t, loc);
+
+  return new type (t);
+}
+
+/* Construct a playback::field instance (wrapping a tree).  */
+
+playback::field *
+playback::context::
+new_field (location *loc,
+          type *type,
+          const char *name)
+{
+  gcc_assert (type);
+  gcc_assert (name);
+
+  /* compare with c/c-decl.c:grokfield and grokdeclarator.  */
+  tree decl = build_decl (UNKNOWN_LOCATION, FIELD_DECL,
+                         get_identifier (name), type->as_tree ());
+
+  if (loc)
+    set_tree_location (decl, loc);
+
+  return new field (decl);
+}
+
+/* Construct a playback::compound_type instance (wrapping a tree).  */
+
+playback::compound_type *
+playback::context::
+new_compound_type (location *loc,
+                  const char *name,
+                  bool is_struct) /* else is union */
+{
+  gcc_assert (name);
+
+  /* Compare with c/c-decl.c: start_struct. */
+
+  tree t = make_node (is_struct ? RECORD_TYPE : UNION_TYPE);
+  TYPE_NAME (t) = get_identifier (name);
+  TYPE_SIZE (t) = 0;
+
+  if (loc)
+    set_tree_location (t, loc);
+
+  return new compound_type (t);
+}
+
+void
+playback::compound_type::set_fields (const vec<playback::field *> &fields)
+{
+  /* Compare with c/c-decl.c: finish_struct. */
+  tree t = as_tree ();
+
+  tree fieldlist = NULL;
+  for (unsigned i = 0; i < fields.length (); i++)
+    {
+      field *f = fields[i];
+      DECL_CONTEXT (f->as_tree ()) = t;
+      fieldlist = chainon (f->as_tree (), fieldlist);
+    }
+  fieldlist = nreverse (fieldlist);
+  TYPE_FIELDS (t) = fieldlist;
+
+  layout_type (t);
+}
+
+/* Construct a playback::type instance (wrapping a tree) for a function
+   type.  */
+
+playback::type *
+playback::context::
+new_function_type (type *return_type,
+                  vec<type *> *param_types,
+                  int is_variadic)
+{
+  int i;
+  type *param_type;
+
+  tree *arg_types = (tree *)xcalloc(param_types->length (), sizeof(tree*));
+
+  FOR_EACH_VEC_ELT (*param_types, i, param_type)
+    arg_types[i] = param_type->as_tree ();
+
+  tree fn_type;
+  if (is_variadic)
+    fn_type =
+      build_varargs_function_type_array (return_type->as_tree (),
+                                        param_types->length (),
+                                        arg_types);
+  else
+    fn_type = build_function_type_array (return_type->as_tree (),
+                                        param_types->length (),
+                                        arg_types);
+  free (arg_types);
+
+  return new type (fn_type);
+}
+
+/* Construct a playback::param instance (wrapping a tree).  */
+
+playback::param *
+playback::context::
+new_param (location *loc,
+          type *type,
+          const char *name)
+{
+  gcc_assert (type);
+  gcc_assert (name);
+  tree inner = build_decl (UNKNOWN_LOCATION, PARM_DECL,
+                          get_identifier (name), type->as_tree ());
+  if (loc)
+    set_tree_location (inner, loc);
+
+  return new param (this, inner);
+}
+
+/* Construct a playback::function instance.  */
+
+playback::function *
+playback::context::
+new_function (location *loc,
+             enum gcc_jit_function_kind kind,
+             type *return_type,
+             const char *name,
+             vec<param *> *params,
+             int is_variadic,
+             enum built_in_function builtin_id)
+{
+  int i;
+  param *param;
+
+  //can return_type be NULL?
+  gcc_assert (name);
+
+  tree *arg_types = (tree *)xcalloc(params->length (), sizeof(tree*));
+  FOR_EACH_VEC_ELT (*params, i, param)
+    arg_types[i] = TREE_TYPE (param->as_tree ());
+
+  tree fn_type;
+  if (is_variadic)
+    fn_type = build_varargs_function_type_array (return_type->as_tree (),
+                                                params->length (), arg_types);
+  else
+    fn_type = build_function_type_array (return_type->as_tree (),
+                                        params->length (), arg_types);
+  free (arg_types);
+
+  /* FIXME: this uses input_location: */
+  tree fndecl = build_fn_decl (name, fn_type);
+
+  if (loc)
+    set_tree_location (fndecl, loc);
+
+  tree resdecl = build_decl (UNKNOWN_LOCATION, RESULT_DECL,
+                            NULL_TREE, return_type->as_tree ());
+  DECL_ARTIFICIAL (resdecl) = 1;
+  DECL_IGNORED_P (resdecl) = 1;
+  DECL_RESULT (fndecl) = resdecl;
+
+  if (builtin_id)
+    {
+      DECL_BUILT_IN_CLASS (fndecl) = BUILT_IN_NORMAL;
+      DECL_FUNCTION_CODE (fndecl) = builtin_id;
+      gcc_assert (loc == NULL);
+      DECL_SOURCE_LOCATION (fndecl) = BUILTINS_LOCATION;
+    }
+
+  if (kind != GCC_JIT_FUNCTION_IMPORTED)
+    {
+      tree param_decl_list = NULL;
+      FOR_EACH_VEC_ELT (*params, i, param)
+       {
+         param_decl_list = chainon (param->as_tree (), param_decl_list);
+       }
+
+      /* The param list was created in reverse order; fix it: */
+      param_decl_list = nreverse (param_decl_list);
+
+      tree t;
+      for (t = param_decl_list; t; t = DECL_CHAIN (t))
+       {
+         DECL_CONTEXT (t) = fndecl;
+         DECL_ARG_TYPE (t) = TREE_TYPE (t);
+       }
+
+      /* Set it up on DECL_ARGUMENTS */
+      DECL_ARGUMENTS(fndecl) = param_decl_list;
+    }
+
+  if (kind == GCC_JIT_FUNCTION_ALWAYS_INLINE)
+    {
+      DECL_DECLARED_INLINE_P (fndecl) = 1;
+
+      /* Add attribute "always_inline": */
+      DECL_ATTRIBUTES (fndecl) =
+       tree_cons (get_identifier ("always_inline"),
+                  NULL,
+                  DECL_ATTRIBUTES (fndecl));
+    }
+
+  function *func = new function (this, fndecl, kind);
+  m_functions.safe_push (func);
+  return func;
+}
+
+/* Construct a playback::lvalue instance (wrapping a tree).  */
+
+playback::lvalue *
+playback::context::
+new_global (location *loc,
+            type *type,
+            const char *name)
+{
+  gcc_assert (type);
+  gcc_assert (name);
+  tree inner = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+                          get_identifier (name),
+                          type->as_tree ());
+  TREE_PUBLIC (inner) = 1;
+  DECL_COMMON (inner) = 1;
+  DECL_EXTERNAL (inner) = 1;
+
+  if (loc)
+    set_tree_location (inner, loc);
+
+  return new lvalue (this, inner);
+}
+
+/* Construct a playback::rvalue instance (wrapping a tree).  */
+
+playback::rvalue *
+playback::context::
+new_rvalue_from_int (type *type,
+                    int value)
+{
+  // FIXME: type-checking, or coercion?
+  tree inner_type = type->as_tree ();
+  if (INTEGRAL_TYPE_P (inner_type))
+    {
+      tree inner = build_int_cst (inner_type, value);
+      return new rvalue (this, inner);
+    }
+  else
+    {
+      REAL_VALUE_TYPE real_value;
+      real_from_integer (&real_value, VOIDmode, value, SIGNED);
+      tree inner = build_real (inner_type, real_value);
+      return new rvalue (this, inner);
+    }
+}
+
+/* Construct a playback::rvalue instance (wrapping a tree).  */
+
+playback::rvalue *
+playback::context::
+new_rvalue_from_double (type *type,
+                       double value)
+{
+  // FIXME: type-checking, or coercion?
+  tree inner_type = type->as_tree ();
+
+  /* We have a "double", we want a REAL_VALUE_TYPE.
+
+     real.c:real_from_target appears to require the representation to be
+     split into 32-bit values, and then sent as an pair of host long
+     ints.  */
+  REAL_VALUE_TYPE real_value;
+  union
+  {
+    double as_double;
+    uint32_t as_uint32s[2];
+  } u;
+  u.as_double = value;
+  long int as_long_ints[2];
+  as_long_ints[0] = u.as_uint32s[0];
+  as_long_ints[1] = u.as_uint32s[1];
+  real_from_target (&real_value, as_long_ints, DFmode);
+  tree inner = build_real (inner_type, real_value);
+  return new rvalue (this, inner);
+}
+
+/* Construct a playback::rvalue instance (wrapping a tree).  */
+
+playback::rvalue *
+playback::context::
+new_rvalue_from_ptr (type *type,
+                    void *value)
+{
+  tree inner_type = type->as_tree ();
+  /* FIXME: how to ensure we have a wide enough type?  */
+  tree inner = build_int_cstu (inner_type, (unsigned HOST_WIDE_INT)value);
+  return new rvalue (this, inner);
+}
+
+/* Construct a playback::rvalue instance (wrapping a tree).  */
+
+playback::rvalue *
+playback::context::
+new_string_literal (const char *value)
+{
+  tree t_str = build_string (strlen (value), value);
+  gcc_assert (m_char_array_type_node);
+  TREE_TYPE (t_str) = m_char_array_type_node;
+
+  /* Convert to (const char*), loosely based on
+     c/c-typeck.c: array_to_pointer_conversion,
+     by taking address of start of string.  */
+  tree t_addr = build1 (ADDR_EXPR, m_const_char_ptr, t_str);
+
+  return new rvalue (this, t_addr);
+}
+
+/* Coerce a tree expression into a boolean tree expression.  */
+
+tree
+playback::context::
+as_truth_value (tree expr, location *loc)
+{
+  /* Compare to c-typeck.c:c_objc_common_truthvalue_conversion */
+  tree typed_zero = fold_build1 (CONVERT_EXPR,
+                                TREE_TYPE (expr),
+                                integer_zero_node);
+  if (loc)
+    set_tree_location (typed_zero, loc);
+
+  expr = build2 (NE_EXPR, integer_type_node, expr, typed_zero);
+  if (loc)
+    set_tree_location (expr, loc);
+
+  return expr;
+}
+
+/* Construct a playback::rvalue instance (wrapping a tree) for a
+   unary op.  */
+
+playback::rvalue *
+playback::context::
+new_unary_op (location *loc,
+             enum gcc_jit_unary_op op,
+             type *result_type,
+             rvalue *a)
+{
+  // FIXME: type-checking, or coercion?
+  enum tree_code inner_op;
+
+  gcc_assert (result_type);
+  gcc_assert (a);
+
+  tree node = a->as_tree ();
+  tree inner_result = NULL;
+
+  switch (op)
+    {
+    default:
+      add_error (loc, "unrecognized (enum gcc_jit_unary_op) value: %i", op);
+      return NULL;
+
+    case GCC_JIT_UNARY_OP_MINUS:
+      inner_op = NEGATE_EXPR;
+      break;
+
+    case GCC_JIT_UNARY_OP_BITWISE_NEGATE:
+      inner_op = BIT_NOT_EXPR;
+      break;
+
+    case GCC_JIT_UNARY_OP_LOGICAL_NEGATE:
+      node = as_truth_value (node, loc);
+      inner_result = invert_truthvalue (node);
+      if (loc)
+       set_tree_location (inner_result, loc);
+      return new rvalue (this, inner_result);
+    }
+
+  inner_result = build1 (inner_op,
+                        result_type->as_tree (),
+                        node);
+  if (loc)
+    set_tree_location (inner_result, loc);
+
+  return new rvalue (this, inner_result);
+}
+
+/* Construct a playback::rvalue instance (wrapping a tree) for a
+   binary op.  */
+
+playback::rvalue *
+playback::context::
+new_binary_op (location *loc,
+              enum gcc_jit_binary_op op,
+              type *result_type,
+              rvalue *a, rvalue *b)
+{
+  // FIXME: type-checking, or coercion?
+  enum tree_code inner_op;
+
+  gcc_assert (result_type);
+  gcc_assert (a);
+  gcc_assert (b);
+
+  tree node_a = a->as_tree ();
+  tree node_b = b->as_tree ();
+
+  switch (op)
+    {
+    default:
+      add_error (loc, "unrecognized (enum gcc_jit_binary_op) value: %i", op);
+      return NULL;
+
+    case GCC_JIT_BINARY_OP_PLUS:
+      inner_op = PLUS_EXPR;
+      break;
+
+    case GCC_JIT_BINARY_OP_MINUS:
+      inner_op = MINUS_EXPR;
+      break;
+
+    case GCC_JIT_BINARY_OP_MULT:
+      inner_op = MULT_EXPR;
+      break;
+
+    case GCC_JIT_BINARY_OP_DIVIDE:
+      if (FLOAT_TYPE_P (result_type->as_tree ()))
+       /* Floating-point division: */
+       inner_op = RDIV_EXPR;
+      else
+       /* Truncating to zero: */
+       inner_op = TRUNC_DIV_EXPR;
+      break;
+
+    case GCC_JIT_BINARY_OP_MODULO:
+      inner_op = TRUNC_MOD_EXPR;
+      break;
+
+    case GCC_JIT_BINARY_OP_BITWISE_AND:
+      inner_op = BIT_AND_EXPR;
+      break;
+
+    case GCC_JIT_BINARY_OP_BITWISE_XOR:
+      inner_op = BIT_XOR_EXPR;
+      break;
+
+    case GCC_JIT_BINARY_OP_BITWISE_OR:
+      inner_op = BIT_IOR_EXPR;
+      break;
+
+    case GCC_JIT_BINARY_OP_LOGICAL_AND:
+      node_a = as_truth_value (node_a, loc);
+      node_b = as_truth_value (node_b, loc);
+      inner_op = TRUTH_ANDIF_EXPR;
+      break;
+
+    case GCC_JIT_BINARY_OP_LOGICAL_OR:
+      node_a = as_truth_value (node_a, loc);
+      node_b = as_truth_value (node_b, loc);
+      inner_op = TRUTH_ORIF_EXPR;
+      break;
+
+    case GCC_JIT_BINARY_OP_LSHIFT:
+      inner_op = LSHIFT_EXPR;
+      break;
+
+    case GCC_JIT_BINARY_OP_RSHIFT:
+      inner_op = RSHIFT_EXPR;
+      break;
+    }
+
+  tree inner_expr = build2 (inner_op,
+                           result_type->as_tree (),
+                           node_a,
+                           node_b);
+  if (loc)
+    set_tree_location (inner_expr, loc);
+
+  return new rvalue (this, inner_expr);
+}
+
+/* Construct a playback::rvalue instance (wrapping a tree) for a
+   comparison.  */
+
+playback::rvalue *
+playback::context::
+new_comparison (location *loc,
+               enum gcc_jit_comparison op,
+               rvalue *a, rvalue *b)
+{
+  // FIXME: type-checking, or coercion?
+  enum tree_code inner_op;
+
+  gcc_assert (a);
+  gcc_assert (b);
+
+  switch (op)
+    {
+    default:
+      add_error (loc, "unrecognized (enum gcc_jit_comparison) value: %i", op);
+      return NULL;
+
+    case GCC_JIT_COMPARISON_EQ:
+      inner_op = EQ_EXPR;
+      break;
+    case GCC_JIT_COMPARISON_NE:
+      inner_op = NE_EXPR;
+      break;
+    case GCC_JIT_COMPARISON_LT:
+      inner_op = LT_EXPR;
+      break;
+    case GCC_JIT_COMPARISON_LE:
+      inner_op = LE_EXPR;
+      break;
+    case GCC_JIT_COMPARISON_GT:
+      inner_op = GT_EXPR;
+      break;
+    case GCC_JIT_COMPARISON_GE:
+      inner_op = GE_EXPR;
+      break;
+    }
+
+  tree inner_expr = build2 (inner_op,
+                           boolean_type_node,
+                           a->as_tree (),
+                           b->as_tree ());
+  if (loc)
+    set_tree_location (inner_expr, loc);
+  return new rvalue (this, inner_expr);
+}
+
+/* Construct a playback::rvalue instance (wrapping a tree) for a
+   function call.  */
+
+playback::rvalue *
+playback::context::
+build_call (location *loc,
+           tree fn_ptr,
+           vec<rvalue *> args)
+{
+  vec<tree, va_gc> *tree_args;
+  vec_alloc (tree_args, args.length ());
+  for (unsigned i = 0; i < args.length (); i++)
+    tree_args->quick_push (args[i]->as_tree ());
+
+  if (loc)
+    set_tree_location (fn_ptr, loc);
+
+  tree fn = TREE_TYPE (fn_ptr);
+  tree fn_type = TREE_TYPE (fn);
+  tree return_type = TREE_TYPE (fn_type);
+
+  return new rvalue (this,
+                    build_call_vec (return_type,
+                                    fn_ptr, tree_args));
+
+  /* see c-typeck.c: build_function_call
+     which calls build_function_call_vec
+
+     which does lots of checking, then:
+    result = build_call_array_loc (loc, TREE_TYPE (fntype),
+                                  function, nargs, argarray);
+    which is in tree.c
+    (see also build_call_vec)
+   */
+}
+
+/* Construct a playback::rvalue instance (wrapping a tree) for a
+   call to a specific function.  */
+
+playback::rvalue *
+playback::context::
+new_call (location *loc,
+         function *func,
+         vec<rvalue *> args)
+{
+  tree fndecl;
+
+  gcc_assert (func);
+
+  fndecl = func->as_fndecl ();
+
+  tree fntype = TREE_TYPE (fndecl);
+
+  tree fn = build1 (ADDR_EXPR, build_pointer_type (fntype), fndecl);
+
+  return build_call (loc, fn, args);
+}
+
+/* Construct a playback::rvalue instance (wrapping a tree) for a
+   call through a function pointer.  */
+
+playback::rvalue *
+playback::context::
+new_call_through_ptr (location *loc,
+                     rvalue *fn_ptr,
+                     vec<rvalue *> args)
+{
+  gcc_assert (fn_ptr);
+  tree t_fn_ptr = fn_ptr->as_tree ();
+
+  return build_call (loc, t_fn_ptr, args);
+}
+
+/* Construct a tree for a cast.  */
+
+tree
+playback::context::build_cast (playback::location *loc,
+                              playback::rvalue *expr,
+                              playback::type *type_)
+{
+  /* For comparison, see:
+     - c/c-typeck.c:build_c_cast
+     - c/c-convert.c: convert
+     - convert.h
+
+     Only some kinds of cast are currently supported here.  */
+  tree t_expr = expr->as_tree ();
+  tree t_dst_type = type_->as_tree ();
+  tree t_ret = NULL;
+  t_ret = targetm.convert_to_type (t_dst_type, t_expr);
+  if (t_ret)
+      return t_ret;
+  enum tree_code dst_code = TREE_CODE (t_dst_type);
+  switch (dst_code)
+    {
+    case INTEGER_TYPE:
+    case ENUMERAL_TYPE:
+      t_ret = convert_to_integer (t_dst_type, t_expr);
+      goto maybe_fold;
+
+    case BOOLEAN_TYPE:
+      /* Compare with c_objc_common_truthvalue_conversion and
+        c_common_truthvalue_conversion. */
+      /* For now, convert to: (t_expr != 0)  */
+      t_ret = build2 (NE_EXPR, t_dst_type,
+                     t_expr, integer_zero_node);
+      goto maybe_fold;
+
+    case REAL_TYPE:
+      t_ret = convert_to_real (t_dst_type, t_expr);
+      goto maybe_fold;
+
+    case POINTER_TYPE:
+      t_ret = build1 (NOP_EXPR, t_dst_type, t_expr);
+      goto maybe_fold;
+
+    default:
+      add_error (loc, "couldn't handle cast during playback");
+      fprintf (stderr, "input expression:\n");
+      debug_tree (t_expr);
+      fprintf (stderr, "requested type:\n");
+      debug_tree (t_dst_type);
+      return error_mark_node;
+
+    maybe_fold:
+      if (TREE_CODE (t_ret) != C_MAYBE_CONST_EXPR)
+       t_ret = fold (t_ret);
+      return t_ret;
+    }
+}
+
+/* Construct a playback::rvalue instance (wrapping a tree) for a
+   cast.  */
+
+playback::rvalue *
+playback::context::
+new_cast (playback::location *loc,
+         playback::rvalue *expr,
+         playback::type *type_)
+{
+
+  tree t_cast = build_cast (loc, expr, type_);
+  if (loc)
+    set_tree_location (t_cast, loc);
+  return new rvalue (this, t_cast);
+}
+
+/* Construct a playback::lvalue instance (wrapping a tree) for an
+   array access.  */
+
+playback::lvalue *
+playback::context::
+new_array_access (location *loc,
+                 rvalue *ptr,
+                 rvalue *index)
+{
+  gcc_assert (ptr);
+  gcc_assert (index);
+
+  /* For comparison, see:
+       c/c-typeck.c: build_array_ref
+       c-family/c-common.c: pointer_int_sum
+  */
+  tree t_ptr = ptr->as_tree ();
+  tree t_index = index->as_tree ();
+  tree t_type_ptr = TREE_TYPE (t_ptr);
+  tree t_type_star_ptr = TREE_TYPE (t_type_ptr);
+
+  if (TREE_CODE (t_type_ptr) == ARRAY_TYPE)
+    {
+      tree t_result = build4 (ARRAY_REF, t_type_star_ptr, t_ptr, t_index,
+                             NULL_TREE, NULL_TREE);
+      if (loc)
+        set_tree_location (t_result, loc);
+      return new lvalue (this, t_result);
+    }
+  else
+    {
+      /* Convert index to an offset in bytes.  */
+      tree t_sizeof = size_in_bytes (t_type_star_ptr);
+      t_index = fold_build1 (CONVERT_EXPR, sizetype, t_index);
+      tree t_offset = build2 (MULT_EXPR, sizetype, t_index, t_sizeof);
+
+      /* Locate (ptr + offset).  */
+      tree t_address = build2 (POINTER_PLUS_EXPR, t_type_ptr, t_ptr, t_offset);
+
+      tree t_indirection = build1 (INDIRECT_REF, t_type_star_ptr, t_address);
+      if (loc)
+        {
+          set_tree_location (t_sizeof, loc);
+          set_tree_location (t_offset, loc);
+          set_tree_location (t_address, loc);
+          set_tree_location (t_indirection, loc);
+        }
+
+      return new lvalue (this, t_indirection);
+    }
+}
+
+/* Construct a tree for a field access.  */
+
+tree
+playback::context::
+new_field_access (location *loc,
+                 tree datum,
+                 field *field)
+{
+  gcc_assert (datum);
+  gcc_assert (field);
+
+  /* Compare with c/c-typeck.c:lookup_field, build_indirect_ref, and
+     build_component_ref. */
+  tree type = TREE_TYPE (datum);
+  gcc_assert (type);
+  gcc_assert (TREE_CODE (type) != POINTER_TYPE);
+
+ tree t_field = field->as_tree ();
+ tree ref = build3 (COMPONENT_REF, TREE_TYPE (t_field), datum,
+                    t_field, NULL_TREE);
+  if (loc)
+    set_tree_location (ref, loc);
+  return ref;
+}
+
+/* Construct a tree for a dereference.  */
+
+tree
+playback::context::
+new_dereference (tree ptr,
+                location *loc)
+{
+  gcc_assert (ptr);
+
+  tree type = TREE_TYPE (TREE_TYPE(ptr));
+  tree datum = build1 (INDIRECT_REF, type, ptr);
+  if (loc)
+    set_tree_location (datum, loc);
+  return datum;
+}
+
+/* Construct a playback::lvalue instance (wrapping a tree) for a
+   field access.  */
+
+playback::lvalue *
+playback::lvalue::
+access_field (location *loc,
+             field *field)
+{
+  tree datum = as_tree ();
+  tree ref = get_context ()->new_field_access (loc, datum, field);
+  if (!ref)
+    return NULL;
+  return new lvalue (get_context (), ref);
+}
+
+/* Construct a playback::rvalue instance (wrapping a tree) for a
+   field access.  */
+
+playback::rvalue *
+playback::rvalue::
+access_field (location *loc,
+             field *field)
+{
+  tree datum = as_tree ();
+  tree ref = get_context ()->new_field_access (loc, datum, field);
+  if (!ref)
+    return NULL;
+  return new rvalue (get_context (), ref);
+}
+
+/* Construct a playback::lvalue instance (wrapping a tree) for a
+   dereferenced field access.  */
+
+playback::lvalue *
+playback::rvalue::
+dereference_field (location *loc,
+                  field *field)
+{
+  tree ptr = as_tree ();
+  tree datum = get_context ()->new_dereference (ptr, loc);
+  if (!datum)
+    return NULL;
+  tree ref = get_context ()->new_field_access (loc, datum, field);
+  if (!ref)
+    return NULL;
+  return new lvalue (get_context (), ref);
+}
+
+/* Construct a playback::lvalue instance (wrapping a tree) for a
+   dereference.  */
+
+playback::lvalue *
+playback::rvalue::
+dereference (location *loc)
+{
+  tree ptr = as_tree ();
+  tree datum = get_context ()->new_dereference (ptr, loc);
+  return new lvalue (get_context (), datum);
+}
+
+/* Construct a playback::rvalue instance (wrapping a tree) for an
+   address-lookup.  */
+
+playback::rvalue *
+playback::lvalue::
+get_address (location *loc)
+{
+  tree t_lvalue = as_tree ();
+  tree t_thistype = TREE_TYPE (t_lvalue);
+  tree t_ptrtype = build_pointer_type (t_thistype);
+  tree ptr = build1 (ADDR_EXPR, t_ptrtype, t_lvalue);
+  if (loc)
+    get_context ()->set_tree_location (ptr, loc);
+  return new rvalue (get_context (), ptr);
+}
+
+/* gcc::jit::playback::wrapper subclasses are GC-managed:
+   allocate them using ggc_internal_cleared_alloc.  */
+
+void *
+playback::wrapper::
+operator new (size_t sz)
+{
+  return ggc_internal_cleared_alloc (sz MEM_STAT_INFO);
+}
+
+/* Constructor for gcc:jit::playback::function.  */
+
+playback::function::
+function (context *ctxt,
+         tree fndecl,
+         enum gcc_jit_function_kind kind)
+: m_ctxt(ctxt),
+  m_inner_fndecl (fndecl),
+  m_inner_bind_expr (NULL),
+  m_kind (kind)
+{
+  if (m_kind != GCC_JIT_FUNCTION_IMPORTED)
+    {
+      /* Create a BIND_EXPR, and within it, a statement list.  */
+      m_stmt_list = alloc_stmt_list ();
+      m_stmt_iter = tsi_start (m_stmt_list);
+      m_inner_block = make_node (BLOCK);
+      m_inner_bind_expr =
+       build3 (BIND_EXPR, void_type_node, NULL, m_stmt_list, m_inner_block);
+    }
+  else
+    {
+      m_inner_block = NULL;
+      m_stmt_list = NULL;
+    }
+}
+
+/* Hand-written GC-marking hook for playback functions.  */
+
+void
+playback::function::
+gt_ggc_mx ()
+{
+  gt_ggc_m_9tree_node (m_inner_fndecl);
+  gt_ggc_m_9tree_node (m_inner_bind_expr);
+  gt_ggc_m_9tree_node (m_stmt_list);
+  gt_ggc_m_9tree_node (m_inner_block);
+}
+
+/* Get the return type of a playback function, in tree form.  */
+
+tree
+playback::function::
+get_return_type_as_tree () const
+{
+  return TREE_TYPE (TREE_TYPE(m_inner_fndecl));
+}
+
+/* Construct a new local within this playback::function.  */
+
+playback::lvalue *
+playback::function::
+new_local (location *loc,
+          type *type,
+          const char *name)
+{
+  gcc_assert (type);
+  gcc_assert (name);
+  tree inner = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+                          get_identifier (name),
+                          type->as_tree ());
+  DECL_CONTEXT (inner) = this->m_inner_fndecl;
+
+  /* Prepend to BIND_EXPR_VARS: */
+  DECL_CHAIN (inner) = BIND_EXPR_VARS (m_inner_bind_expr);
+  BIND_EXPR_VARS (m_inner_bind_expr) = inner;
+
+  if (loc)
+    set_tree_location (inner, loc);
+  return new lvalue (m_ctxt, inner);
+}
+
+/* Construct a new block within this playback::function.  */
+
+playback::block *
+playback::function::
+new_block (const char *name)
+{
+  gcc_assert (m_kind != GCC_JIT_FUNCTION_IMPORTED);
+
+  block *result = new playback::block (this, name);
+  m_blocks.safe_push (result);
+  return result;
+}
+
+/* Build a statement list for the function as a whole out of the
+   lists of statements for the individual blocks, building labels
+   for each block.  */
+
+void
+playback::function::
+build_stmt_list ()
+{
+  int i;
+  block *b;
+
+  FOR_EACH_VEC_ELT (m_blocks, i, b)
+    {
+      int j;
+      tree stmt;
+
+      b->m_label_expr = build1 (LABEL_EXPR,
+                               void_type_node,
+                               b->as_label_decl ());
+      tsi_link_after (&m_stmt_iter, b->m_label_expr, TSI_CONTINUE_LINKING);
+
+      FOR_EACH_VEC_ELT (b->m_stmts, j, stmt)
+       tsi_link_after (&m_stmt_iter, stmt, TSI_CONTINUE_LINKING);
+    }
+}
+
+/* Finish compiling the given function, potentially running the
+   garbage-collector.
+   The function will have a statement list by now.
+   Amongst other things, this gimplifies the statement list,
+   and calls cgraph_node::finalize_function on the function.  */
+
+void
+playback::function::
+postprocess ()
+{
+  if (m_ctxt->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE))
+    debug_tree (m_stmt_list);
+
+  /* Do we need this to force cgraphunit.c to output the function? */
+  if (m_kind == GCC_JIT_FUNCTION_EXPORTED)
+    {
+      DECL_EXTERNAL (m_inner_fndecl) = 0;
+      DECL_PRESERVE_P (m_inner_fndecl) = 1;
+    }
+
+  if (m_kind == GCC_JIT_FUNCTION_INTERNAL
+      ||m_kind == GCC_JIT_FUNCTION_ALWAYS_INLINE)
+    {
+      DECL_EXTERNAL (m_inner_fndecl) = 0;
+      TREE_PUBLIC (m_inner_fndecl) = 0;
+    }
+
+  if (m_kind != GCC_JIT_FUNCTION_IMPORTED)
+    {
+      /* Seem to need this in gimple-low.c: */
+      gcc_assert (m_inner_block);
+      DECL_INITIAL (m_inner_fndecl) = m_inner_block;
+
+      /* how to add to function? the following appears to be how to
+        set the body of a m_inner_fndecl: */
+      DECL_SAVED_TREE(m_inner_fndecl) = m_inner_bind_expr;
+
+      /* Ensure that locals appear in the debuginfo.  */
+      BLOCK_VARS (m_inner_block) = BIND_EXPR_VARS (m_inner_bind_expr);
+
+      //debug_tree (m_inner_fndecl);
+
+      /* Convert to gimple: */
+      //printf("about to gimplify_function_tree\n");
+      gimplify_function_tree (m_inner_fndecl);
+      //printf("finished gimplify_function_tree\n");
+
+      current_function_decl = m_inner_fndecl;
+      if (m_ctxt->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE))
+       dump_function_to_file (m_inner_fndecl, stderr, TDF_VOPS|TDF_MEMSYMS|TDF_LINENO);
+      //debug_tree (m_inner_fndecl);
+
+      //printf("about to add to cgraph\n");
+      /* Add to cgraph: */
+      cgraph_node::finalize_function (m_inner_fndecl, false);
+      /* This can trigger a collection, so we need to have all of
+        the funcs as roots.  */
+
+      current_function_decl = NULL;
+    }
+}
+
+/* Add an eval of the rvalue to the function's statement list.  */
+
+void
+playback::block::
+add_eval (location *loc,
+         rvalue *rvalue)
+{
+  gcc_assert (rvalue);
+
+  if (loc)
+    set_tree_location (rvalue->as_tree (), loc);
+
+  add_stmt (rvalue->as_tree ());
+}
+
+/* Add an assignment to the function's statement list.  */
+
+void
+playback::block::
+add_assignment (location *loc,
+               lvalue *lvalue,
+               rvalue *rvalue)
+{
+  gcc_assert (lvalue);
+  gcc_assert (rvalue);
+
+  tree t_lvalue = lvalue->as_tree ();
+  tree t_rvalue = rvalue->as_tree ();
+  if (TREE_TYPE (t_rvalue) != TREE_TYPE (t_lvalue))
+    {
+      t_rvalue = build1 (CONVERT_EXPR,
+                        TREE_TYPE (t_lvalue),
+                        t_rvalue);
+      if (loc)
+       set_tree_location (t_rvalue, loc);
+    }
+
+  tree stmt =
+    build2 (MODIFY_EXPR, TREE_TYPE (t_lvalue),
+           t_lvalue, t_rvalue);
+  if (loc)
+    set_tree_location (stmt, loc);
+  add_stmt (stmt);
+}
+
+/* Add a comment to the function's statement list.
+   For now this is done by adding a dummy label.  */
+
+void
+playback::block::
+add_comment (location *loc,
+            const char *text)
+{
+  /* Wrap the text in C-style comment delimiters.  */
+  size_t sz =
+    (3 /* opening delim */
+     + strlen (text)
+     + 3 /* closing delim */
+     + 1 /* terminator */);
+  char *wrapped = (char *)ggc_internal_alloc (sz);
+  snprintf (wrapped, sz, "/* %s */", text);
+
+  /* For now we simply implement this by adding a dummy label with a name
+     containing the given text.  */
+  tree identifier = get_identifier (wrapped);
+  tree label_decl = build_decl (UNKNOWN_LOCATION, LABEL_DECL,
+                               identifier, void_type_node);
+  DECL_CONTEXT (label_decl) = m_func->as_fndecl ();
+
+  tree label_expr = build1 (LABEL_EXPR, void_type_node, label_decl);
+  if (loc)
+    set_tree_location (label_expr, loc);
+  add_stmt (label_expr);
+}
+
+/* Add a conditional jump statement to the function's statement list.  */
+
+void
+playback::block::
+add_conditional (location *loc,
+                rvalue *boolval,
+                block *on_true,
+                block *on_false)
+{
+  gcc_assert (boolval);
+  gcc_assert (on_true);
+  gcc_assert (on_false);
+
+  /* COND_EXPR wants statement lists for the true/false operands, but we
+     want labels.
+     Shim it by creating jumps to the labels */
+  tree true_jump = build1 (GOTO_EXPR, void_type_node,
+                          on_true->as_label_decl ());
+  if (loc)
+    set_tree_location (true_jump, loc);
+
+  tree false_jump = build1 (GOTO_EXPR, void_type_node,
+                           on_false->as_label_decl ());
+  if (loc)
+    set_tree_location (false_jump, loc);
+
+  tree stmt =
+    build3 (COND_EXPR, void_type_node, boolval->as_tree (),
+           true_jump, false_jump);
+  if (loc)
+    set_tree_location (stmt, loc);
+  add_stmt (stmt);
+}
+
+/* Add an unconditional jump statement to the function's statement list.  */
+
+void
+playback::block::
+add_jump (location *loc,
+         block *target)
+{
+  gcc_assert (target);
+
+  // see c_finish_loop
+  //tree top = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
+  //add_stmt (top);
+
+  //tree stmt = build_and_jump (&LABEL_EXPR_LABEL (target->label_));
+  TREE_USED (target->as_label_decl ()) = 1;
+  tree stmt = build1 (GOTO_EXPR, void_type_node, target->as_label_decl ());
+  if (loc)
+    set_tree_location (stmt, loc);
+  add_stmt (stmt);
+
+  /*
+  from c-typeck.c:
+tree
+c_finish_goto_label (location_t loc, tree label)
+{
+  tree decl = lookup_label_for_goto (loc, label);
+  if (!decl)
+    return NULL_TREE;
+  TREE_USED (decl) = 1;
+  {
+    tree t = build1 (GOTO_EXPR, void_type_node, decl);
+    SET_EXPR_LOCATION (t, loc);
+    return add_stmt (t);
+  }
+}
+  */
+
+}
+
+/* Add a return statement to the function's statement list.  */
+
+void
+playback::block::
+add_return (location *loc,
+           rvalue *rvalue)
+{
+  tree modify_retval = NULL;
+  tree return_type = m_func->get_return_type_as_tree ();
+  if (rvalue)
+    {
+      tree t_lvalue = DECL_RESULT (m_func->as_fndecl ());
+      tree t_rvalue = rvalue->as_tree ();
+      if (TREE_TYPE (t_rvalue) != TREE_TYPE (t_lvalue))
+       t_rvalue = build1 (CONVERT_EXPR,
+                          TREE_TYPE (t_lvalue),
+                          t_rvalue);
+      modify_retval = build2 (MODIFY_EXPR, return_type,
+                             t_lvalue, t_rvalue);
+      if (loc)
+       set_tree_location (modify_retval, loc);
+    }
+  tree return_stmt = build1 (RETURN_EXPR, return_type,
+                            modify_retval);
+  if (loc)
+    set_tree_location (return_stmt, loc);
+
+  add_stmt (return_stmt);
+}
+
+/* Constructor for gcc::jit::playback::block.  */
+
+playback::block::
+block (function *func,
+       const char *name)
+: m_func (func),
+  m_stmts ()
+{
+  tree identifier;
+
+  gcc_assert (func);
+  // name can be NULL
+  if (name)
+    identifier = get_identifier (name);
+  else
+    identifier = NULL;
+  m_label_decl = build_decl (UNKNOWN_LOCATION, LABEL_DECL,
+                           identifier, void_type_node);
+  DECL_CONTEXT (m_label_decl) = func->as_fndecl ();
+  m_label_expr = NULL;
+}
+
+/* Construct a tempdir path template suitable for use by mkdtemp
+   e.g. "/tmp/libgccjit-XXXXXX", but respecting the rules in
+   libiberty's choose_tempdir rather than hardcoding "/tmp/".
+
+   The memory is allocated using malloc and must be freed.
+   Aborts the process if allocation fails. */
+
+static char *
+make_tempdir_path_template ()
+{
+  const char *tmpdir_buf;
+  size_t tmpdir_len;
+  const char *file_template_buf;
+  size_t file_template_len;
+  char *result;
+
+  /* The result of choose_tmpdir is a cached buffer within libiberty, so
+     we must *not* free it.  */
+  tmpdir_buf = choose_tmpdir ();
+
+  /* choose_tmpdir aborts on malloc failure.  */
+  gcc_assert (tmpdir_buf);
+
+  tmpdir_len = strlen (tmpdir_buf);
+  /* tmpdir_buf should now have a dir separator as the final byte.  */
+  gcc_assert (tmpdir_len > 0);
+  gcc_assert (tmpdir_buf[tmpdir_len - 1] == DIR_SEPARATOR);
+
+  file_template_buf = "libgccjit-XXXXXX";
+  file_template_len = strlen (file_template_buf);
+
+  result = XNEWVEC (char, tmpdir_len + file_template_len + 1);
+  strcpy (result, tmpdir_buf);
+  strcpy (result + tmpdir_len, file_template_buf);
+
+  return result;
+}
+
+/* Compile a playback::context:
+
+   - Use the context's options to cconstruct command-line options, and
+     call into the rest of GCC (toplev::main).
+   - Assuming it succeeds, we have a .s file; we want a .so file.
+     Invoke another gcc to convert the .s file to a .so file.
+   - dlopen the .so file
+   - Wrap the result up as a playback::result and return it.  */
+
+result *
+playback::context::
+compile ()
+{
+  void *handle = NULL;
+  const char *ctxt_progname;
+  result *result_obj = NULL;
+  const char *fake_args[20];
+  unsigned int num_args;
+
+  m_path_template = make_tempdir_path_template ();
+  if (!m_path_template)
+    return NULL;
+
+  /* Create tempdir using mkdtemp.  This is created with 0700 perms and
+     is unique.  Hence no other (non-root) users should have access to
+     the paths within it.  */
+  m_path_tempdir = mkdtemp (m_path_template);
+  if (!m_path_tempdir)
+    return NULL;
+  m_path_c_file = concat (m_path_tempdir, "/fake.c", NULL);
+  m_path_s_file = concat (m_path_tempdir, "/fake.s", NULL);
+  m_path_so_file = concat (m_path_tempdir, "/fake.so", NULL);
+
+  /* Call into the rest of gcc.
+     For now, we have to assemble command-line options to pass into
+     toplev::main, so that they can be parsed. */
+
+  /* Pass in user-provided program name as argv0, if any, so that it
+     makes it into GCC's "progname" global, used in various diagnostics. */
+  ctxt_progname = get_str_option (GCC_JIT_STR_OPTION_PROGNAME);
+  fake_args[0] =
+    (ctxt_progname ? ctxt_progname : "libgccjit.so");
+
+  fake_args[1] = m_path_c_file;
+  num_args = 2;
+
+#define ADD_ARG(arg) \
+  do \
+    { \
+      gcc_assert(num_args < sizeof(fake_args)/sizeof(char*)); \
+      fake_args[num_args++] = arg; \
+    } \
+  while (0)
+
+  ADD_ARG ("-fPIC");
+
+  /* Handle int options: */
+  switch (get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL))
+    {
+    default:
+      add_error (NULL,
+                "unrecognized optimization level: %i",
+                get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL));
+      return NULL;
+
+    case 0:
+      ADD_ARG ("-O0");
+      break;
+
+    case 1:
+      ADD_ARG ("-O1");
+      break;
+
+    case 2:
+      ADD_ARG ("-O2");
+      break;
+
+    case 3:
+      ADD_ARG ("-O3");
+      break;
+    }
+  /* What about -Os? */
+
+  /* Handle bool options: */
+  if (get_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO))
+    ADD_ARG ("-g");
+
+  /* Suppress timing (and other) info.  */
+  if (!get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_SUMMARY))
+    {
+      ADD_ARG ("-quiet");
+      quiet_flag = 1;
+    }
+
+  /* Aggressively garbage-collect, to shake out bugs: */
+  if (get_bool_option (GCC_JIT_BOOL_OPTION_SELFCHECK_GC))
+    {
+      ADD_ARG ("--param");
+      ADD_ARG ("ggc-min-expand=0");
+      ADD_ARG ("--param");
+      ADD_ARG ("ggc-min-heapsize=0");
+    }
+
+  if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING))
+    {
+      ADD_ARG ("-fdump-tree-all");
+      ADD_ARG ("-fdump-rtl-all");
+      ADD_ARG ("-fdump-ipa-all");
+    }
+
+  toplev toplev (false);
+
+  toplev.main (num_args, const_cast <char **> (fake_args));
+  toplev.finalize ();
+
+  active_playback_ctxt = NULL;
+
+  if (errors_occurred ())
+    return NULL;
+
+  if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE))
+   dump_generated_code ();
+
+  /* Gross hacks follow:
+     We have a .s file; we want a .so file.
+     We could reuse parts of gcc/gcc.c to do this.
+     For now, just use the driver binary from the install, as
+     named in gcc-driver-name.h
+     e.g. "x86_64-unknown-linux-gnu-gcc-5.0.0".
+   */
+  {
+    auto_timevar assemble_timevar (TV_ASSEMBLE);
+    const char *errmsg;
+    const char *argv[7];
+    int exit_status = 0;
+    int err = 0;
+    const char *gcc_driver_name = GCC_DRIVER_NAME;
+
+    argv[0] = gcc_driver_name;
+    argv[1] = "-shared";
+    /* The input: assembler.  */
+    argv[2] = m_path_s_file;
+    /* The output: shared library.  */
+    argv[3] = "-o";
+    argv[4] = m_path_so_file;
+
+    /* Don't use the linker plugin.
+       If running with just a "make" and not a "make install", then we'd
+       run into
+          "fatal error: -fuse-linker-plugin, but liblto_plugin.so not found"
+       libto_plugin is a .la at build time, with it becoming installed with
+       ".so" suffix: i.e. it doesn't exist with a .so suffix until install
+       time.  */
+    argv[5] = "-fno-use-linker-plugin";
+
+    /* pex argv arrays are NULL-terminated.  */
+    argv[6] = NULL;
+
+    errmsg = pex_one (PEX_SEARCH, /* int flags, */
+                     gcc_driver_name,
+                     const_cast<char * const *> (argv),
+                     ctxt_progname, /* const char *pname */
+                     NULL, /* const char *outname */
+                     NULL, /* const char *errname */
+                     &exit_status, /* int *status */
+                     &err); /* int *err*/
+    if (errmsg)
+      {
+       add_error (NULL, "error invoking gcc driver: %s", errmsg);
+       return NULL;
+      }
+
+    /* pex_one can return a NULL errmsg when the executable wasn't
+       found (or doesn't exist), so trap these cases also.  */
+    if (exit_status || err)
+      {
+       add_error (NULL,
+                  "error invoking gcc driver: exit_status: %i err: %i",
+                  exit_status, err);
+       add_error (NULL,
+                  "whilst attempting to run a driver named: %s",
+                  gcc_driver_name);
+       add_error (NULL,
+                  "PATH was: %s",
+                  getenv ("PATH"));
+       return NULL;
+      }
+  }
+
+  // TODO: split out assembles vs linker
+
+  /* dlopen the .so file. */
+  {
+    auto_timevar load_timevar (TV_LOAD);
+
+    const char *error;
+
+    /* Clear any existing error.  */
+    dlerror ();
+
+    handle = dlopen (m_path_so_file, RTLD_NOW | RTLD_LOCAL);
+    if ((error = dlerror()) != NULL)  {
+      add_error (NULL, "%s", error);
+    }
+    if (handle)
+      result_obj = new result (handle);
+    else
+      result_obj = NULL;
+  }
+
+  return result_obj;
+}
+
+/* Top-level hook for playing back a recording context.
+
+   This plays back m_recording_ctxt, and, if no errors
+   occurred builds statement lists for and then postprocesses
+   every function in the result.  */
+
+void
+playback::context::
+replay ()
+{
+  /* Adapted from c-common.c:c_common_nodes_and_builtins.  */
+  tree array_domain_type = build_index_type (size_int (200));
+  m_char_array_type_node
+    = build_array_type (char_type_node, array_domain_type);
+
+  m_const_char_ptr
+    = build_pointer_type (build_qualified_type (char_type_node,
+                                               TYPE_QUAL_CONST));
+
+  /* Replay the recorded events:  */
+  timevar_push (TV_JIT_REPLAY);
+
+  m_recording_ctxt->replay_into (this);
+
+  /* Clean away the temporary references from recording objects
+     to playback objects.  We have to do this now since the
+     latter are GC-allocated, but the former don't mark these
+     refs.  Hence we must stop using them before the GC can run.  */
+  m_recording_ctxt->disassociate_from_playback ();
+
+  timevar_pop (TV_JIT_REPLAY);
+
+  if (!errors_occurred ())
+    {
+      int i;
+      function *func;
+
+      /* No GC can happen yet; process the cached source locations.  */
+      handle_locations ();
+
+      /* We've now created tree nodes for the stmts in the various blocks
+        in each function, but we haven't built each function's single stmt
+        list yet.  Do so now.  */
+      FOR_EACH_VEC_ELT (m_functions, i, func)
+       func->build_stmt_list ();
+
+      /* No GC can have happened yet.  */
+
+      /* Postprocess the functions.  This could trigger GC.  */
+      FOR_EACH_VEC_ELT (m_functions, i, func)
+       {
+         gcc_assert (func);
+         func->postprocess ();
+       }
+    }
+}
+
+/* Dump the generated .s file to stderr.  */
+
+void
+playback::context::
+dump_generated_code ()
+{
+  char buf[4096];
+  size_t sz;
+  FILE *f_in = fopen (m_path_s_file, "r");
+  if (!f_in)
+    return;
+
+  while ( (sz = fread (buf, 1, sizeof (buf), f_in)) )
+    fwrite (buf, 1, sz, stderr);
+
+  fclose (f_in);
+}
+
+/* qsort comparator for comparing pairs of playback::source_line *,
+   ordering them by line number.  */
+
+static int
+line_comparator (const void *lhs, const void *rhs)
+{
+  const playback::source_line *line_lhs = \
+    *static_cast<const playback::source_line * const*> (lhs);
+  const playback::source_line *line_rhs = \
+    *static_cast<const playback::source_line * const*> (rhs);
+  return line_lhs->get_line_num () - line_rhs->get_line_num ();
+}
+
+/* qsort comparator for comparing pairs of playback::location *,
+   ordering them by column number.  */
+
+static int
+location_comparator (const void *lhs, const void *rhs)
+{
+  const playback::location *loc_lhs = \
+    *static_cast<const playback::location * const *> (lhs);
+  const playback::location *loc_rhs = \
+    *static_cast<const playback::location * const *> (rhs);
+  return loc_lhs->get_column_num () - loc_rhs->get_column_num ();
+}
+
+/* Our API allows locations to be created in arbitrary orders, but the
+   linemap API requires locations to be created in ascending order
+   as if we were tokenizing files.
+
+   This hook sorts all of the the locations that have been created, and
+   calls into the linemap API, creating linemap entries in sorted order
+   for our locations.  */
+
+void
+playback::context::
+handle_locations ()
+{
+  /* Create the source code locations, following the ordering rules
+     imposed by the linemap API.
+
+     line_table is a global.  */
+  int i;
+  source_file *file;
+
+  FOR_EACH_VEC_ELT (m_source_files, i, file)
+    {
+      linemap_add (line_table, LC_ENTER, false, file->get_filename (), 0);
+
+      /* Sort lines by ascending line numbers.  */
+      file->m_source_lines.qsort (&line_comparator);
+
+      int j;
+      source_line *line;
+      FOR_EACH_VEC_ELT (file->m_source_lines, j, line)
+       {
+         int k;
+         location *loc;
+
+         /* Sort locations in line by ascending column numbers.  */
+         line->m_locations.qsort (&location_comparator);
+
+         /* Determine maximum column within this line.  */
+         gcc_assert (line->m_locations.length () > 0);
+         location *final_column =
+           line->m_locations[line->m_locations.length () - 1];
+         int max_col = final_column->get_column_num ();
+
+         linemap_line_start (line_table, line->get_line_num (), max_col);
+         FOR_EACH_VEC_ELT (line->m_locations, k, loc)
+           {
+             loc->m_srcloc =                                      \
+               linemap_position_for_column (line_table, loc->get_column_num ());
+           }
+       }
+
+      linemap_add (line_table, LC_LEAVE, false, NULL, 0);
+    }
+
+  /* line_table should now be populated; every playback::location should
+     now have an m_srcloc.  */
+
+  /* Now assign them to tree nodes as appropriate.  */
+  std::pair<tree, location *> *cached_location;
+
+  FOR_EACH_VEC_ELT (m_cached_locations, i, cached_location)
+    {
+      tree t = cached_location->first;
+      source_location srcloc = cached_location->second->m_srcloc;
+
+      /* This covers expressions: */
+      if (CAN_HAVE_LOCATION_P (t))
+       SET_EXPR_LOCATION (t, srcloc);
+      else if (CODE_CONTAINS_STRUCT(TREE_CODE(t), TS_DECL_MINIMAL))
+       DECL_SOURCE_LOCATION (t) = srcloc;
+      else
+       {
+         /* Don't know how to set location on this node.  */
+       }
+    }
+}
+
+/* We handle errors on a playback::context by adding them to the
+   corresponding recording::context.  */
+
+void
+playback::context::
+add_error (location *loc, const char *fmt, ...)
+{
+  va_list ap;
+  va_start (ap, fmt);
+  m_recording_ctxt->add_error_va (loc ? loc->get_recording_loc () : NULL,
+                                 fmt, ap);
+  va_end (ap);
+}
+
+/* We handle errors on a playback::context by adding them to the
+   corresponding recording::context.  */
+
+void
+playback::context::
+add_error_va (location *loc, const char *fmt, va_list ap)
+{
+  m_recording_ctxt->add_error_va (loc ? loc->get_recording_loc () : NULL,
+                                 fmt, ap);
+}
+
+/* Constructor for gcc::jit::playback::result.  */
+
+result::
+result(void *dso_handle)
+  : m_dso_handle(dso_handle)
+{
+}
+
+/* gcc::jit::playback::result's destructor.
+
+   Called implicitly by gcc_jit_result_release.  */
+
+result::~result()
+{
+  dlclose (m_dso_handle);
+}
+
+/* Attempt to locate the given function by name within the
+   playback::result, using dlsym.
+
+   Implements the post-error-checking part of
+   gcc_jit_result_get_code.  */
+
+void *
+result::
+get_code (const char *funcname)
+{
+  void *code;
+  const char *error;
+
+  /* Clear any existing error.  */
+  dlerror ();
+
+  code = dlsym (m_dso_handle, funcname);
+
+  if ((error = dlerror()) != NULL)  {
+    fprintf(stderr, "%s\n", error);
+  }
+
+  return code;
+}
+
+/* Dealing with the linemap API.  */
+
+/* Construct a playback::location for a recording::location, if it
+   doesn't exist already.  */
+
+playback::location *
+playback::context::
+new_location (recording::location *rloc,
+             const char *filename,
+             int line,
+             int column)
+{
+  /* Get the source_file for filename, creating if necessary.  */
+  source_file *src_file = get_source_file (filename);
+  /* Likewise for the line within the file.  */
+  source_line *src_line = src_file->get_source_line (line);
+  /* Likewise for the column within the line.  */
+  location *loc = src_line->get_location (rloc, column);
+  return loc;
+}
+
+/* Deferred setting of the location for a given tree, by adding the
+   (tree, playback::location) pair to a list of deferred associations.
+   We will actually set the location on the tree later on once
+   the source_location for the playback::location exists.  */
+
+void
+playback::context::
+set_tree_location (tree t, location *loc)
+{
+  gcc_assert (loc);
+  m_cached_locations.safe_push (std::make_pair (t, loc));
+}
+
+
+/* Construct a playback::source_file for the given source
+   filename, if it doesn't exist already.  */
+
+playback::source_file *
+playback::context::
+get_source_file (const char *filename)
+{
+  /* Locate the file.
+     For simplicitly, this is currently a linear search.
+     Replace with a hash if this shows up in the profile.  */
+  int i;
+  source_file *file;
+  tree ident_filename = get_identifier (filename);
+
+  FOR_EACH_VEC_ELT (m_source_files, i, file)
+    if (file->filename_as_tree () == ident_filename)
+      return file;
+
+  /* Not found.  */
+  file = new source_file (ident_filename);
+  m_source_files.safe_push (file);
+  return file;
+}
+
+/* Constructor for gcc::jit::playback::source_file.  */
+
+playback::source_file::source_file (tree filename) :
+  m_source_lines (),
+  m_filename (filename)
+{
+}
+
+/* Construct a playback::source_line for the given line
+   within this source file, if one doesn't exist already.  */
+
+playback::source_line *
+playback::source_file::
+get_source_line (int line_num)
+{
+  /* Locate the line.
+     For simplicitly, this is currently a linear search.
+     Replace with a hash if this shows up in the profile.  */
+  int i;
+  source_line *line;
+
+  FOR_EACH_VEC_ELT (m_source_lines, i, line)
+    if (line->get_line_num () == line_num)
+      return line;
+
+  /* Not found.  */
+  line = new source_line (this, line_num);
+  m_source_lines.safe_push (line);
+  return line;
+}
+
+/* Constructor for gcc::jit::playback::source_line.  */
+
+playback::source_line::source_line (source_file *file, int line_num) :
+  m_locations (),
+  m_source_file (file),
+  m_line_num (line_num)
+{
+}
+
+/* Construct a playback::location for the given column
+   within this line of a specific source file, if one doesn't exist
+   already.  */
+
+playback::location *
+playback::source_line::
+get_location (recording::location *rloc, int column_num)
+{
+  int i;
+  location *loc;
+
+  /* Another linear search that probably should be a hash table.  */
+  FOR_EACH_VEC_ELT (m_locations, i, loc)
+    if (loc->get_column_num () == column_num)
+      return loc;
+
+  /* Not found.  */
+  loc = new location (rloc, this, column_num);
+  m_locations.safe_push (loc);
+  return loc;
+}
+
+/* Constructor for gcc::jit::playback::location.  */
+
+playback::location::location (recording::location *loc,
+                             source_line *line,
+                             int column_num) :
+  m_srcloc (UNKNOWN_LOCATION),
+  m_recording_loc (loc),
+  m_line (line),
+  m_column_num(column_num)
+{
+}
+
+/* The active gcc::jit::playback::context instance.  This is a singleton,
+   guarded by jit_mutex.  */
+
+playback::context *active_playback_ctxt;
+
+} // namespace gcc::jit
+
+} // namespace gcc
diff --git a/gcc/jit/jit-playback.h b/gcc/jit/jit-playback.h
new file mode 100644 (file)
index 0000000..dcb19bf
--- /dev/null
@@ -0,0 +1,564 @@
+/* Internals of libgccjit: classes for playing back recorded API calls.
+   Copyright (C) 2013-2014 Free Software Foundation, Inc.
+   Contributed by David Malcolm <dmalcolm@redhat.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef JIT_PLAYBACK_H
+#define JIT_PLAYBACK_H
+
+#include <utility> // for std::pair
+
+#include "jit-recording.h"
+
+namespace gcc {
+
+namespace jit {
+
+/**********************************************************************
+ Playback.
+ **********************************************************************/
+
+namespace playback {
+
+class context
+{
+public:
+  context (::gcc::jit::recording::context *ctxt);
+  ~context ();
+
+  void gt_ggc_mx ();
+
+  void replay ();
+
+  location *
+  new_location (recording::location *rloc,
+               const char *filename,
+               int line,
+               int column);
+
+  type *
+  get_type (enum gcc_jit_types type);
+
+  type *
+  new_array_type (location *loc,
+                 type *element_type,
+                 int num_elements);
+
+  field *
+  new_field (location *loc,
+            type *type,
+            const char *name);
+
+  compound_type *
+  new_compound_type (location *loc,
+                    const char *name,
+                    bool is_struct); /* else is union */
+
+  type *
+  new_function_type (type *return_type,
+                    vec<type *> *param_types,
+                    int is_variadic);
+
+  param *
+  new_param (location *loc,
+            type *type,
+            const char *name);
+
+  function *
+  new_function (location *loc,
+               enum gcc_jit_function_kind kind,
+               type *return_type,
+               const char *name,
+               vec<param *> *params,
+               int is_variadic,
+               enum built_in_function builtin_id);
+
+  lvalue *
+  new_global (location *loc,
+             type *type,
+             const char *name);
+
+  rvalue *
+  new_rvalue_from_int (type *type,
+                      int value);
+
+  rvalue *
+  new_rvalue_from_double (type *type,
+                         double value);
+
+  rvalue *
+  new_rvalue_from_ptr (type *type,
+                      void *value);
+
+  rvalue *
+  new_string_literal (const char *value);
+
+  rvalue *
+  new_unary_op (location *loc,
+               enum gcc_jit_unary_op op,
+               type *result_type,
+               rvalue *a);
+
+  rvalue *
+  new_binary_op (location *loc,
+                enum gcc_jit_binary_op op,
+                type *result_type,
+                rvalue *a, rvalue *b);
+
+  rvalue *
+  new_comparison (location *loc,
+                 enum gcc_jit_comparison op,
+                 rvalue *a, rvalue *b);
+
+  rvalue *
+  new_call (location *loc,
+           function *func,
+           vec<rvalue *> args);
+
+  rvalue *
+  new_call_through_ptr (location *loc,
+                       rvalue *fn_ptr,
+                       vec<rvalue *> args);
+
+  rvalue *
+  new_cast (location *loc,
+           rvalue *expr,
+           type *type_);
+
+  lvalue *
+  new_array_access (location *loc,
+                   rvalue *ptr,
+                   rvalue *index);
+
+  void
+  set_str_option (enum gcc_jit_str_option opt,
+                 const char *value);
+
+  void
+  set_int_option (enum gcc_jit_int_option opt,
+                 int value);
+
+  void
+  set_bool_option (enum gcc_jit_bool_option opt,
+                  int value);
+
+  const char *
+  get_str_option (enum gcc_jit_str_option opt) const
+  {
+    return m_recording_ctxt->get_str_option (opt);
+  }
+
+  int
+  get_int_option (enum gcc_jit_int_option opt) const
+  {
+    return m_recording_ctxt->get_int_option (opt);
+  }
+
+  int
+  get_bool_option (enum gcc_jit_bool_option opt) const
+  {
+    return m_recording_ctxt->get_bool_option (opt);
+  }
+
+  result *
+  compile ();
+
+  void
+  add_error (location *loc, const char *fmt, ...)
+      GNU_PRINTF(3, 4);
+
+  void
+  add_error_va (location *loc, const char *fmt, va_list ap)
+      GNU_PRINTF(3, 0);
+
+  const char *
+  get_first_error () const;
+
+  void
+  set_tree_location (tree t, location *loc);
+
+  tree
+  new_field_access (location *loc,
+                   tree datum,
+                   field *field);
+
+  tree
+  new_dereference (tree ptr, location *loc);
+
+  tree
+  as_truth_value (tree expr, location *loc);
+
+  bool errors_occurred () const
+  {
+    return m_recording_ctxt->errors_occurred ();
+  }
+
+private:
+  void dump_generated_code ();
+
+  rvalue *
+  build_call (location *loc,
+             tree fn_ptr,
+             vec<rvalue *> args);
+
+  tree
+  build_cast (location *loc,
+             rvalue *expr,
+             type *type_);
+
+  source_file *
+  get_source_file (const char *filename);
+
+  void handle_locations ();
+
+private:
+  ::gcc::jit::recording::context *m_recording_ctxt;
+
+  /* Allocated using xmalloc (by xstrdup).  */
+  char *m_path_template;
+
+  /* This either aliases m_path_template, or is NULL.  */
+  char *m_path_tempdir;
+
+  /* The following are allocated using xmalloc.  */
+  char *m_path_c_file;
+  char *m_path_s_file;
+  char *m_path_so_file;
+
+  vec<function *> m_functions;
+  tree m_char_array_type_node;
+  tree m_const_char_ptr;
+
+  /* Source location handling.  */
+  vec<source_file *> m_source_files;
+
+  vec<std::pair<tree, location *> > m_cached_locations;
+};
+
+/* A temporary wrapper object.
+   These objects are (mostly) only valid during replay.
+   We allocate them on the GC heap, so that they will be cleaned
+   the next time the GC collects.
+   The exception is the "function" class, which is tracked and marked by
+   the jit::context, since it needs to stay alive during post-processing
+   (when the GC could run). */
+class wrapper
+{
+public:
+  /* Allocate in the GC heap.  */
+  void *operator new (size_t sz);
+
+};
+
+class type : public wrapper
+{
+public:
+  type (tree inner)
+    : m_inner(inner)
+  {}
+
+  tree as_tree () const { return m_inner; }
+
+  type *get_pointer () const { return new type (build_pointer_type (m_inner)); }
+
+  type *get_const () const
+  {
+    return new type (build_qualified_type (m_inner, TYPE_QUAL_CONST));
+  }
+
+  type *get_volatile () const
+  {
+    return new type (build_qualified_type (m_inner, TYPE_QUAL_VOLATILE));
+  }
+
+private:
+  tree m_inner;
+};
+
+class compound_type : public type
+{
+public:
+  compound_type (tree inner)
+    : type (inner)
+  {}
+
+  void set_fields (const vec<field *> &fields);
+};
+
+class field : public wrapper
+{
+public:
+  field (tree inner)
+    : m_inner(inner)
+  {}
+
+  tree as_tree () const { return m_inner; }
+
+private:
+  tree m_inner;
+};
+
+class function : public wrapper
+{
+public:
+  function(context *ctxt, tree fndecl, enum gcc_jit_function_kind kind);
+
+  void gt_ggc_mx ();
+
+  tree get_return_type_as_tree () const;
+
+  tree as_fndecl () const { return m_inner_fndecl; }
+
+  enum gcc_jit_function_kind get_kind () const { return m_kind; }
+
+  lvalue *
+  new_local (location *loc,
+            type *type,
+            const char *name);
+
+  block*
+  new_block (const char *name);
+
+  void
+  build_stmt_list ();
+
+  void
+  postprocess ();
+
+public:
+  context *m_ctxt;
+
+public:
+  void
+  set_tree_location (tree t, location *loc)
+  {
+    m_ctxt->set_tree_location (t, loc);
+  }
+
+private:
+  tree m_inner_fndecl;
+  tree m_inner_block;
+  tree m_inner_bind_expr;
+  enum gcc_jit_function_kind m_kind;
+  tree m_stmt_list;
+  tree_stmt_iterator m_stmt_iter;
+  vec<block *> m_blocks;
+};
+
+class block : public wrapper
+{
+public:
+  block (function *func,
+        const char *name);
+
+  tree as_label_decl () const { return m_label_decl; }
+
+  void
+  add_eval (location *loc,
+           rvalue *rvalue);
+
+  void
+  add_assignment (location *loc,
+                 lvalue *lvalue,
+                 rvalue *rvalue);
+
+  void
+  add_comment (location *loc,
+              const char *text);
+
+  void
+  add_conditional (location *loc,
+                  rvalue *boolval,
+                  block *on_true,
+                  block *on_false);
+
+  block *
+  add_block (location *loc,
+            const char *name);
+
+  void
+  add_jump (location *loc,
+           block *target);
+
+  void
+  add_return (location *loc,
+             rvalue *rvalue);
+
+private:
+  void
+  set_tree_location (tree t, location *loc)
+  {
+    m_func->set_tree_location (t, loc);
+  }
+
+  void add_stmt (tree stmt)
+  {
+    /* TODO: use one stmt_list per block.  */
+    m_stmts.safe_push (stmt);
+  }
+
+private:
+  function *m_func;
+  tree m_label_decl;
+  vec<tree> m_stmts;
+
+public: // for now
+  tree m_label_expr;
+
+  friend class function;
+};
+
+class rvalue : public wrapper
+{
+public:
+  rvalue (context *ctxt, tree inner)
+    : m_ctxt (ctxt),
+      m_inner (inner)
+  {}
+
+  rvalue *
+  as_rvalue () { return this; }
+
+  tree as_tree () const { return m_inner; }
+
+  context *get_context () const { return m_ctxt; }
+
+  type *
+  get_type () { return new type (TREE_TYPE (m_inner)); }
+
+  rvalue *
+  access_field (location *loc,
+               field *field);
+
+  lvalue *
+  dereference_field (location *loc,
+                    field *field);
+
+  lvalue *
+  dereference (location *loc);
+
+private:
+  context *m_ctxt;
+  tree m_inner;
+};
+
+class lvalue : public rvalue
+{
+public:
+  lvalue (context *ctxt, tree inner)
+    : rvalue(ctxt, inner)
+  {}
+
+  lvalue *
+  as_lvalue () { return this; }
+
+  lvalue *
+  access_field (location *loc,
+               field *field);
+
+  rvalue *
+  get_address (location *loc);
+
+};
+
+class param : public lvalue
+{
+public:
+  param (context *ctxt, tree inner)
+    : lvalue(ctxt, inner)
+  {}
+};
+
+/* Dealing with the linemap API.
+
+   It appears that libcpp requires locations to be created as if by
+   a tokenizer, creating them by filename, in ascending order of
+   line/column, whereas our API doesn't impose any such constraints:
+   we allow client code to create locations in arbitrary orders.
+
+   To square this circle, we need to cache all location creation,
+   grouping things up by filename/line, and then creating the linemap
+   entries in a post-processing phase.  */
+
+/* A set of locations, all sharing a filename */
+class source_file : public wrapper
+{
+public:
+  source_file (tree filename);
+
+  source_line *
+  get_source_line (int line_num);
+
+  tree filename_as_tree () const { return m_filename; }
+
+  const char*
+  get_filename () const { return IDENTIFIER_POINTER (m_filename); }
+
+  vec<source_line *> m_source_lines;
+
+private:
+  tree m_filename;
+};
+
+/* A source line, with one or more locations of interest.  */
+class source_line : public wrapper
+{
+public:
+  source_line (source_file *file, int line_num);
+
+  location *
+  get_location (recording::location *rloc, int column_num);
+
+  int get_line_num () const { return m_line_num; }
+
+  vec<location *> m_locations;
+
+private:
+  source_file *m_source_file;
+  int m_line_num;
+};
+
+/* A specific location on a source line.  This is what we expose
+   to the client API.  */
+class location : public wrapper
+{
+public:
+  location (recording::location *loc, source_line *line, int column_num);
+
+  int get_column_num () const { return m_column_num; }
+
+  recording::location *get_recording_loc () const { return m_recording_loc; }
+
+  source_location m_srcloc;
+
+private:
+  recording::location *m_recording_loc;
+  source_line *m_line;
+  int m_column_num;
+};
+
+} // namespace gcc::jit::playback
+
+extern playback::context *active_playback_ctxt;
+
+} // namespace gcc::jit
+
+} // namespace gcc
+
+#endif /* JIT_PLAYBACK_H */
+
diff --git a/gcc/jit/jit-recording.c b/gcc/jit/jit-recording.c
new file mode 100644 (file)
index 0000000..8daa8f2
--- /dev/null
@@ -0,0 +1,3434 @@
+/* Internals of libgccjit: classes for recording calls made to the JIT API.
+   Copyright (C) 2013-2014 Free Software Foundation, Inc.
+   Contributed by David Malcolm <dmalcolm@redhat.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "opts.h"
+#include "tree.h"
+#include "pretty-print.h"
+
+#include <pthread.h>
+
+#include "jit-common.h"
+#include "jit-builtins.h"
+#include "jit-recording.h"
+#include "jit-playback.h"
+
+namespace gcc {
+namespace jit {
+
+// class dump
+
+dump::dump (recording::context &ctxt,
+           const char *filename,
+           bool update_locations)
+: m_ctxt (ctxt),
+  m_filename (filename),
+  m_update_locations (update_locations),
+  m_line (0),
+  m_column (0)
+{
+  m_file = fopen (filename, "w");
+  if (!m_file)
+    ctxt.add_error (NULL,
+                   "error opening dump file %s for writing: %s",
+                   filename,
+                   xstrerror (errno));
+}
+
+dump::~dump ()
+{
+  if (m_file)
+    {
+      int err = fclose (m_file);
+      if (err)
+       m_ctxt.add_error (NULL,
+                         "error closing dump file %s: %s",
+                         m_filename,
+                         xstrerror (errno));
+    }
+}
+
+/* Write the given message to the dump, using printf-formatting
+   conventions, updating the line/column within the dump.
+
+   Emit an error on the context if a failure occurs.  */
+
+void
+dump::write (const char *fmt, ...)
+{
+  va_list ap;
+  char *buf = NULL;
+
+  /* If there was an error opening the file, we've already reported it.
+     Don't attempt further work.  */
+  if (!m_file)
+    return;
+
+  va_start (ap, fmt);
+  vasprintf (&buf, fmt, ap);
+  va_end (ap);
+
+  if (!buf)
+    {
+      m_ctxt.add_error (NULL, "malloc failure writing to dumpfile %s",
+                       m_filename);
+      return;
+    }
+
+  if (fwrite (buf, strlen (buf), 1, m_file) != 1)
+    m_ctxt.add_error (NULL, "error writing to dump file %s",
+                     m_filename);
+
+  /* Update line/column: */
+  for (const char *ptr = buf; *ptr; ptr++)
+    {
+      if ('\n' == *ptr)
+       {
+         m_line++;
+         m_column = 0;
+       }
+      else
+       m_column++;
+    }
+
+  free (buf);
+}
+
+/* Construct a gcc::jit::recording::location instance for the current
+   location within the dump.  */
+
+recording::location *
+dump::make_location () const
+{
+  return m_ctxt.new_location (m_filename, m_line, m_column);
+}
+
+/**********************************************************************
+ Recording.
+ **********************************************************************/
+
+/* Get the playback::location for the given recording::location,
+   handling a NULL input with a NULL output.  */
+
+playback::location *
+recording::playback_location (replayer *r, recording::location *loc)
+{
+  if (loc)
+    return loc->playback_location (r);
+  else
+    return NULL;
+}
+
+/* Get a const char * for the given recording::string
+   handling a NULL input with a NULL output.  */
+
+const char *
+recording::playback_string (recording::string *str)
+{
+  if (str)
+    return str->c_str ();
+  else
+    return NULL;
+}
+
+/* Get the playback::block for the given recording::block,
+   handling a NULL input with a NULL output.  */
+
+playback::block *
+recording::playback_block (recording::block *b)
+{
+  if (b)
+    return b->playback_block ();
+  else
+    return NULL;
+}
+
+/* Methods of cc::jit::recording::context.  */
+
+/* The constructor for gcc::jit::recording::context, used by
+   gcc_jit_context_acquire and gcc_jit_context_new_child_context.  */
+
+recording::context::context (context *parent_ctxt)
+  : m_parent_ctxt (parent_ctxt),
+    m_error_count (0),
+    m_first_error_str (NULL),
+    m_owns_first_error_str (false),
+    m_mementos (),
+    m_compound_types (),
+    m_functions (),
+    m_FILE_type (NULL),
+    m_builtins_manager(NULL)
+{
+  if (parent_ctxt)
+    {
+      /* Inherit options from parent.
+         Note that the first memcpy means copying pointers to strings.  */
+      memcpy (m_str_options,
+              parent_ctxt->m_str_options,
+              sizeof (m_str_options));
+      memcpy (m_int_options,
+              parent_ctxt->m_int_options,
+              sizeof (m_int_options));
+      memcpy (m_bool_options,
+              parent_ctxt->m_bool_options,
+              sizeof (m_bool_options));
+    }
+  else
+    {
+      memset (m_str_options, 0, sizeof (m_str_options));
+      memset (m_int_options, 0, sizeof (m_int_options));
+      memset (m_bool_options, 0, sizeof (m_bool_options));
+    }
+
+  memset (m_basic_types, 0, sizeof (m_basic_types));
+}
+
+/* The destructor for gcc::jit::recording::context, implicitly used by
+   gcc_jit_context_release.  */
+
+recording::context::~context ()
+{
+  int i;
+  memento *m;
+  FOR_EACH_VEC_ELT (m_mementos, i, m)
+    {
+      delete m;
+    }
+
+  if (m_builtins_manager)
+    delete m_builtins_manager;
+
+  if (m_owns_first_error_str)
+    free (m_first_error_str);
+}
+
+/* Add the given mememto to the list of those tracked by this
+   gcc::jit::recording::context, so that e.g. it can be deleted
+   when this context is released.  */
+
+void
+recording::context::record (memento *m)
+{
+  gcc_assert (m);
+
+  m_mementos.safe_push (m);
+}
+
+/* Replay this context (and any parents) into the given replayer.  */
+
+void
+recording::context::replay_into (replayer *r)
+{
+  int i;
+  memento *m;
+
+  /* If we have a parent context, we must replay it.  This will
+     recursively walk backwards up the historical tree, then replay things
+     forwards "in historical order", starting with the ultimate parent
+     context, until we reach the "this" context.
+
+     Note that we fully replay the parent, then fully replay the child,
+     which means that inter-context references can only exist from child
+     to parent, not the other way around.
+
+     All of this replaying is suboptimal - it would be better to do the
+     work for the parent context *once*, rather than replaying the parent
+     every time we replay each child.  However, fixing this requires deep
+     surgery to lifetime-management: we'd need every context family tree
+     to have its own GC heap, and to initialize the GCC code to use that
+     heap (with a mutex on such a heap).  */
+  if (m_parent_ctxt)
+    m_parent_ctxt->replay_into (r);
+
+  if (r->errors_occurred ())
+    return;
+
+  /* Replay this context's saved operations into r.  */
+  FOR_EACH_VEC_ELT (m_mementos, i, m)
+    {
+      /* Disabled low-level debugging, here if we need it: print what
+        we're replaying.
+        Note that the calls to get_debug_string might lead to more
+        mementos being created for the strings.
+        This can also be used to exercise the debug_string
+        machinery.  */
+      if (0)
+       printf ("context %p replaying (%p): %s\n",
+               (void *)this, (void *)m, m->get_debug_string ());
+
+      m->replay_into (r);
+
+      if (r->errors_occurred ())
+       return;
+    }
+}
+
+/* During a playback, we associate objects from the recording with
+   their counterparts during this playback.
+
+   For simplicity, we store this within the recording objects.
+
+   The following method cleans away these associations, to ensure that
+   we never have out-of-date associations lingering on subsequent
+   playbacks (the objects pointed to are GC-managed, but the
+   recording objects don't own refs to them).  */
+
+void
+recording::context::disassociate_from_playback ()
+{
+  int i;
+  memento *m;
+
+  if (m_parent_ctxt)
+    m_parent_ctxt->disassociate_from_playback ();
+
+  FOR_EACH_VEC_ELT (m_mementos, i, m)
+    {
+      m->set_playback_obj (NULL);
+    }
+}
+
+/* Create a recording::string instance and add it to this context's list
+   of mementos.
+
+   This creates a fresh copy of the given 0-terminated buffer.  */
+
+recording::string *
+recording::context::new_string (const char *text)
+{
+  if (!text)
+    return NULL;
+
+  recording::string *result = new string (this, text);
+  record (result);
+  return result;
+}
+
+/* Create a recording::location instance and add it to this context's
+   list of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_new_location.  */
+
+recording::location *
+recording::context::new_location (const char *filename,
+                                int line,
+                                int column)
+{
+  recording::location *result =
+    new recording::location (this,
+                           new_string (filename),
+                           line, column);
+  record (result);
+  return result;
+}
+
+/* If we haven't seen this enum value yet, create a recording::type
+   instance and add it to this context's list of mementos.
+
+   If we have seen it before, reuse our cached value, so that repeated
+   calls on the context give the same object.
+
+   If we have a parent context, the cache is within the ultimate
+   ancestor context.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_get_type.  */
+
+recording::type *
+recording::context::get_type (enum gcc_jit_types kind)
+{
+  if (!m_basic_types[kind])
+    {
+      if (m_parent_ctxt)
+       m_basic_types[kind] = m_parent_ctxt->get_type (kind);
+      else
+       {
+         recording::type *result = new memento_of_get_type (this, kind);
+         record (result);
+         m_basic_types[kind] = result;
+       }
+    }
+
+  return m_basic_types[kind];
+}
+
+/* Get a recording::type instance for the given size and signedness.
+   This is implemented in terms of recording::context::get_type
+   above.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_get_int_type.  */
+
+recording::type *
+recording::context::get_int_type (int num_bytes, int is_signed)
+{
+  /* We can't use a switch here since some of the values are macros affected
+     by options; e.g. i386.h has
+       #define LONG_TYPE_SIZE (TARGET_X32 ? 32 : BITS_PER_WORD)
+     Compare with tree.c's make_or_reuse_type.  Note that the _SIZE macros
+     are in bits, rather than bytes.
+  */
+  const int num_bits = num_bytes * 8;
+  if (num_bits == INT_TYPE_SIZE)
+    return get_type (is_signed
+                    ? GCC_JIT_TYPE_INT
+                    : GCC_JIT_TYPE_UNSIGNED_INT);
+  if (num_bits == CHAR_TYPE_SIZE)
+    return get_type (is_signed
+                    ? GCC_JIT_TYPE_SIGNED_CHAR
+                    : GCC_JIT_TYPE_UNSIGNED_CHAR);
+  if (num_bits == SHORT_TYPE_SIZE)
+    return get_type (is_signed
+                    ? GCC_JIT_TYPE_SHORT
+                    : GCC_JIT_TYPE_UNSIGNED_SHORT);
+  if (num_bits == LONG_TYPE_SIZE)
+    return get_type (is_signed
+                    ? GCC_JIT_TYPE_LONG
+                    : GCC_JIT_TYPE_UNSIGNED_LONG);
+  if (num_bits == LONG_LONG_TYPE_SIZE)
+    return get_type (is_signed
+                    ? GCC_JIT_TYPE_LONG_LONG
+                    : GCC_JIT_TYPE_UNSIGNED_LONG_LONG);
+
+  /* Some other size, not corresponding to the C int types.  */
+  /* To be written: support arbitrary other sizes, sharing by
+     memoizing at the recording::context level?  */
+  gcc_unreachable ();
+}
+
+/* Create a recording::type instance and add it to this context's list
+   of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_new_array_type.  */
+
+recording::type *
+recording::context::new_array_type (recording::location *loc,
+                                   recording::type *element_type,
+                                   int num_elements)
+{
+  if (struct_ *s = element_type->dyn_cast_struct ())
+    if (!s->get_fields ())
+      {
+       add_error (NULL,
+                  "cannot create an array of type %s"
+                  " until the fields have been set",
+                  s->get_name ()->c_str ());
+       return NULL;
+      }
+  recording::type *result =
+    new recording::array_type (this, loc, element_type, num_elements);
+  record (result);
+  return result;
+}
+
+/* Create a recording::field instance and add it to this context's list
+   of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_new_field.  */
+
+recording::field *
+recording::context::new_field (recording::location *loc,
+                              recording::type *type,
+                              const char *name)
+{
+  recording::field *result =
+    new recording::field (this, loc, type, new_string (name));
+  record (result);
+  return result;
+}
+
+/* Create a recording::struct_ instance and add it to this context's
+   list of mementos and list of compound types.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_new_struct_type.  */
+
+recording::struct_ *
+recording::context::new_struct_type (recording::location *loc,
+                                    const char *name)
+{
+  recording::struct_ *result = new struct_ (this, loc, new_string (name));
+  record (result);
+  m_compound_types.safe_push (result);
+  return result;
+}
+
+/* Create a recording::union_ instance and add it to this context's
+   list of mementos and list of compound types.
+
+   Implements the first post-error-checking part of
+   gcc_jit_context_new_union_type.  */
+
+recording::union_ *
+recording::context::new_union_type (recording::location *loc,
+                                   const char *name)
+{
+  recording::union_ *result = new union_ (this, loc, new_string (name));
+  record (result);
+  m_compound_types.safe_push (result);
+  return result;
+}
+
+/* Create a recording::type instance and add it to this context's list
+   of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_new_function_ptr_type.  */
+
+recording::type *
+recording::context::new_function_ptr_type (recording::location *, /* unused loc */
+                                          recording::type *return_type,
+                                          int num_params,
+                                          recording::type **param_types,
+                                          int is_variadic)
+{
+  recording::function_type *fn_type =
+    new function_type (this,
+                      return_type,
+                      num_params,
+                      param_types,
+                      is_variadic);
+  record (fn_type);
+
+  /* Return a pointer-type to the the function type.  */
+  return fn_type->get_pointer ();
+}
+
+/* Create a recording::param instance and add it to this context's list
+   of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_new_param.  */
+
+recording::param *
+recording::context::new_param (recording::location *loc,
+                              recording::type *type,
+                              const char *name)
+{
+  recording::param *result = new recording::param (this, loc, type, new_string (name));
+  record (result);
+  return result;
+}
+
+/* Create a recording::function instance and add it to this context's list
+   of mementos and list of functions.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_new_function.  */
+
+recording::function *
+recording::context::new_function (recording::location *loc,
+                                 enum gcc_jit_function_kind kind,
+                                 recording::type *return_type,
+                                 const char *name,
+                                 int num_params,
+                                 recording::param **params,
+                                 int is_variadic,
+                                 enum built_in_function builtin_id)
+{
+  recording::function *result =
+    new recording::function (this,
+                            loc, kind, return_type,
+                            new_string (name),
+                            num_params, params, is_variadic,
+                            builtin_id);
+  record (result);
+  m_functions.safe_push (result);
+
+  return result;
+}
+
+/* Get a recording::function instance, which is lazily-created and added
+   to the context's lists of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_get_builtin_function.  */
+
+recording::function *
+recording::context::get_builtin_function (const char *name)
+{
+  if (!m_builtins_manager)
+    m_builtins_manager = new builtins_manager (this);
+  return m_builtins_manager->get_builtin_function (name);
+}
+
+/* Create a recording::global instance and add it to this context's list
+   of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_new_global.  */
+
+recording::lvalue *
+recording::context::new_global (recording::location *loc,
+                               recording::type *type,
+                               const char *name)
+{
+  recording::lvalue *result =
+    new recording::global (this, loc, type, new_string (name));
+  record (result);
+  return result;
+}
+
+/* Create a recording::memento_of_new_rvalue_from_int instance and add
+   it to this context's list of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_new_rvalue_from_int.  */
+
+recording::rvalue *
+recording::context::new_rvalue_from_int (recording::type *type,
+                                        int value)
+{
+  recording::rvalue *result =
+    new memento_of_new_rvalue_from_int (this, NULL, type, value);
+  record (result);
+  return result;
+}
+
+/* Create a recording::memento_of_new_rvalue_from_double instance and
+   add it to this context's list of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_new_rvalue_from_double.  */
+
+recording::rvalue *
+recording::context::new_rvalue_from_double (recording::type *type,
+                                           double value)
+{
+  recording::rvalue *result =
+    new memento_of_new_rvalue_from_double (this, NULL, type, value);
+  record (result);
+  return result;
+}
+
+/* Create a recording::memento_of_new_rvalue_from_ptr instance and add
+   it to this context's list of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_new_rvalue_from_ptr.  */
+
+recording::rvalue *
+recording::context::new_rvalue_from_ptr (recording::type *type,
+                                        void *value)
+{
+  recording::rvalue *result =
+    new memento_of_new_rvalue_from_ptr (this, NULL, type, value);
+  record (result);
+  return result;
+}
+
+/* Create a recording::memento_of_new_string_literal instance and add it
+   to this context's list of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_new_string_literal.  */
+
+recording::rvalue *
+recording::context::new_string_literal (const char *value)
+{
+  recording::rvalue *result =
+    new memento_of_new_string_literal (this, NULL, new_string (value));
+  record (result);
+  return result;
+}
+
+/* Create a recording::unary_op instance and add it to this context's
+   list of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_new_unary_op.  */
+
+recording::rvalue *
+recording::context::new_unary_op (recording::location *loc,
+                                 enum gcc_jit_unary_op op,
+                                 recording::type *result_type,
+                                 recording::rvalue *a)
+{
+  recording::rvalue *result =
+    new unary_op (this, loc, op, result_type, a);
+  record (result);
+  return result;
+}
+
+/* Create a recording::binary_op instance and add it to this context's
+   list of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_new_binary_op.  */
+
+recording::rvalue *
+recording::context::new_binary_op (recording::location *loc,
+                                  enum gcc_jit_binary_op op,
+                                  recording::type *result_type,
+                                  recording::rvalue *a,
+                                  recording::rvalue *b)
+{
+  recording::rvalue *result =
+    new binary_op (this, loc, op, result_type, a, b);
+  record (result);
+  return result;
+}
+
+/* Create a recording::comparison instance and add it to this context's
+   list of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_new_comparison.  */
+
+recording::rvalue *
+recording::context::new_comparison (recording::location *loc,
+                                   enum gcc_jit_comparison op,
+                                   recording::rvalue *a,
+                                   recording::rvalue *b)
+{
+  recording::rvalue *result = new comparison (this, loc, op, a, b);
+  record (result);
+  return result;
+}
+
+/* Create a recording::cast instance and add it to this context's list
+   of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_new_cast.  */
+
+recording::rvalue *
+recording::context::new_cast (recording::location *loc,
+                             recording::rvalue *expr,
+                             recording::type *type_)
+{
+  recording::rvalue *result = new cast (this, loc, expr, type_);
+  record (result);
+  return result;
+}
+
+/* Create a recording::call instance and add it to this context's list
+   of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_new_call.  */
+
+recording::rvalue *
+recording::context::new_call (recording::location *loc,
+                             function *func,
+                             int numargs , recording::rvalue **args)
+{
+  recording::rvalue *result = new call (this, loc, func, numargs, args);
+  record (result);
+  return result;
+}
+
+/* Create a recording::call_through_ptr instance and add it to this
+   context's list of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_new_call_through_ptr.  */
+
+recording::rvalue *
+recording::context::new_call_through_ptr (recording::location *loc,
+                                         recording::rvalue *fn_ptr,
+                                         int numargs,
+                                         recording::rvalue **args)
+  {
+  recording::rvalue *result = new call_through_ptr (this, loc, fn_ptr, numargs, args);
+  record (result);
+  return result;
+}
+
+/* Create a recording::array_access instance and add it to this context's list
+   of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_new_array_access.  */
+
+recording::lvalue *
+recording::context::new_array_access (recording::location *loc,
+                                     recording::rvalue *ptr,
+                                     recording::rvalue *index)
+{
+  recording::lvalue *result = new array_access (this, loc, ptr, index);
+  record (result);
+  return result;
+}
+
+/* Set the given string option for this context, or add an error if
+   it's not recognized.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_set_str_option.  */
+
+void
+recording::context::set_str_option (enum gcc_jit_str_option opt,
+                                   const char *value)
+{
+  if (opt < 0 || opt >= GCC_JIT_NUM_STR_OPTIONS)
+    {
+      add_error (NULL,
+                "unrecognized (enum gcc_jit_str_option) value: %i", opt);
+      return;
+    }
+  m_str_options[opt] = value;
+}
+
+/* Set the given integer option for this context, or add an error if
+   it's not recognized.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_set_int_option.  */
+
+void
+recording::context::set_int_option (enum gcc_jit_int_option opt,
+                                   int value)
+{
+  if (opt < 0 || opt >= GCC_JIT_NUM_INT_OPTIONS)
+    {
+      add_error (NULL,
+                "unrecognized (enum gcc_jit_int_option) value: %i", opt);
+      return;
+    }
+  m_int_options[opt] = value;
+}
+
+/* Set the given boolean option for this context, or add an error if
+   it's not recognized.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_set_bool_option.  */
+
+void
+recording::context::set_bool_option (enum gcc_jit_bool_option opt,
+                                    int value)
+{
+  if (opt < 0 || opt >= GCC_JIT_NUM_BOOL_OPTIONS)
+    {
+      add_error (NULL,
+                "unrecognized (enum gcc_jit_bool_option) value: %i", opt);
+      return;
+    }
+  m_bool_options[opt] = value ? true : false;
+}
+
+/* This mutex guards gcc::jit::recording::context::compile, so that only
+   one thread can be accessing the bulk of GCC's state at once.  */
+
+static pthread_mutex_t jit_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+/* Validate this context, and if it passes, compile it within a
+   mutex.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_compile.  */
+
+result *
+recording::context::compile ()
+{
+  validate ();
+
+  if (errors_occurred ())
+    return NULL;
+
+  /* Acquire the big GCC mutex. */
+  pthread_mutex_lock (&jit_mutex);
+  gcc_assert (NULL == ::gcc::jit::active_playback_ctxt);
+
+  /* Set up a playback context.  */
+  ::gcc::jit::playback::context replayer (this);
+  ::gcc::jit::active_playback_ctxt = &replayer;
+
+  result *result_obj = replayer.compile ();
+
+  /* Release the big GCC mutex. */
+  ::gcc::jit::active_playback_ctxt = NULL;
+  pthread_mutex_unlock (&jit_mutex);
+
+  return result_obj;
+}
+
+/* Format the given error using printf's conventions, print
+   it to stderr, and add it to the context.  */
+
+void
+recording::context::add_error (location *loc, const char *fmt, ...)
+{
+  va_list ap;
+  va_start (ap, fmt);
+  add_error_va (loc, fmt, ap);
+  va_end (ap);
+}
+
+/* Format the given error using printf's conventions, print
+   it to stderr, and add it to the context.  */
+
+void
+recording::context::add_error_va (location *loc, const char *fmt, va_list ap)
+{
+  char *malloced_msg;
+  const char *errmsg;
+  bool has_ownership;
+
+  vasprintf (&malloced_msg, fmt, ap);
+  if (malloced_msg)
+    {
+      errmsg = malloced_msg;
+      has_ownership = true;
+    }
+  else
+    {
+      errmsg = "out of memory generating error message";
+      has_ownership = false;
+    }
+
+  const char *ctxt_progname =
+    get_str_option (GCC_JIT_STR_OPTION_PROGNAME);
+  if (!ctxt_progname)
+    ctxt_progname = "libgccjit.so";
+
+  if (loc)
+    fprintf (stderr, "%s: %s: error: %s\n",
+            ctxt_progname,
+            loc->get_debug_string (),
+            errmsg);
+  else
+    fprintf (stderr, "%s: error: %s\n",
+            ctxt_progname,
+            errmsg);
+
+  if (!m_error_count)
+    {
+      m_first_error_str = const_cast <char *> (errmsg);
+      m_owns_first_error_str = has_ownership;
+    }
+  else
+    if (has_ownership)
+      free (malloced_msg);
+
+  m_error_count++;
+}
+
+/* Get the message for the first error that occurred on this context, or
+   NULL if no errors have occurred on it.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_get_first_error.  */
+
+const char *
+recording::context::get_first_error () const
+{
+  return m_first_error_str;
+}
+
+/* Lazily generate and record a recording::type representing an opaque
+   struct named "FILE".
+
+   For use if client code tries to dereference the result of
+   get_type (GCC_JIT_TYPE_FILE_PTR).  */
+
+recording::type *
+recording::context::get_opaque_FILE_type ()
+{
+  if (!m_FILE_type)
+    m_FILE_type = new_struct_type (NULL, "FILE");
+  return m_FILE_type;
+}
+
+/* Dump a C-like representation of the given context to the given path.
+   If UPDATE_LOCATIONS is true, update the locations within the
+   context's mementos to point to the dumpfile.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_dump_to_file.  */
+
+void
+recording::context::dump_to_file (const char *path, bool update_locations)
+{
+  int i;
+  dump d (*this, path, update_locations);
+
+  /* Forward declaration of structs and unions.  */
+  compound_type *st;
+  FOR_EACH_VEC_ELT (m_compound_types, i, st)
+    {
+      d.write ("%s;\n\n", st->get_debug_string ());
+    }
+
+  /* Content of structs, where set.  */
+  FOR_EACH_VEC_ELT (m_compound_types, i, st)
+    if (st->get_fields ())
+      {
+       st->get_fields ()->write_to_dump (d);
+       d.write ("\n");
+      }
+
+  function *fn;
+  FOR_EACH_VEC_ELT (m_functions, i, fn)
+    {
+      fn->write_to_dump (d);
+    }
+}
+
+/* This is a pre-compilation check for the context (and any parents).
+
+   Detect errors within the context, adding errors if any are found.  */
+
+void
+recording::context::validate ()
+{
+  if (m_parent_ctxt)
+    m_parent_ctxt->validate ();
+
+  int i;
+  function *fn;
+  FOR_EACH_VEC_ELT (m_functions, i, fn)
+    fn->validate ();
+}
+
+/* The implementation of class gcc::jit::recording::memento.  */
+
+/* Get a (const char *) debug description of the given memento, by
+   calling the pure-virtual make_debug_string hook, caching the
+   result.
+
+   It is intended that this should only be called in debugging and
+   error-handling paths, so this doesn't need to be particularly
+   optimized.  */
+
+const char *
+recording::memento::get_debug_string ()
+{
+  if (!m_debug_string)
+    m_debug_string = make_debug_string ();
+  return m_debug_string->c_str ();
+}
+
+/* Default implementation of recording::memento::write_to_dump, writing
+   an indented form of the memento's debug string to the dump.  */
+
+void
+recording::memento::write_to_dump (dump &d)
+{
+  d.write("  %s\n", get_debug_string ());
+}
+
+/* The implementation of class gcc::jit::recording::string.  */
+
+/* Constructor for gcc::jit::recording::string::string, allocating a
+   copy of the given text using new char[].  */
+
+recording::string::string (context *ctxt, const char *text)
+  : memento (ctxt)
+{
+  m_len = strlen (text);
+  m_buffer = new char[m_len + 1];
+  strcpy (m_buffer, text);
+}
+
+/* Destructor for gcc::jit::recording::string::string.  */
+
+recording::string::~string ()
+{
+  delete[] m_buffer;
+}
+
+/* Function for making gcc::jit::recording::string instances on a
+   context via printf-style formatting.
+
+   It is intended that this should only be called in debugging and
+   error-handling paths, so this doesn't need to be particularly
+   optimized, hence the double-copy of the string is acceptable.  */
+
+recording::string *
+recording::string::from_printf (context *ctxt, const char *fmt, ...)
+{
+  va_list ap;
+  char *buf = NULL;
+  recording::string *result;
+
+  va_start (ap, fmt);
+  vasprintf (&buf, fmt, ap);
+  va_end (ap);
+
+  if (!buf)
+    {
+      ctxt->add_error (NULL, "malloc failure");
+      return NULL;
+    }
+
+  result = ctxt->new_string (buf);
+  free (buf);
+  return result;
+}
+
+/* Implementation of recording::memento::make_debug_string for strings,
+   wrapping the given string in quotes and escaping as necessary.  */
+
+recording::string *
+recording::string::make_debug_string ()
+{
+  /* Hack to avoid infinite recursion into strings when logging all
+     mementos: don't re-escape strings:  */
+  if (m_buffer[0] == '"')
+    return this;
+
+  /* Wrap in quotes and do escaping etc */
+
+  size_t sz = (1 /* opening quote */
+              + (m_len * 2) /* each char might get escaped */
+              + 1 /* closing quote */
+              + 1); /* nil termintator */
+  char *tmp = new char[sz];
+  size_t len = 0;
+
+#define APPEND(CH)  do { gcc_assert (len < sz); tmp[len++] = (CH); } while (0)
+  APPEND('"'); /* opening quote */
+  for (size_t i = 0; i < m_len ; i++)
+    {
+      char ch = m_buffer[i];
+      if (ch == '\t' || ch == '\n' || ch == '\\' || ch == '"')
+       APPEND('\\');
+      APPEND(ch);
+    }
+  APPEND('"'); /* closing quote */
+#undef APPEND
+  tmp[len] = '\0'; /* nil termintator */
+
+  string *result = m_ctxt->new_string (tmp);
+
+  delete[] tmp;
+  return result;
+}
+
+/* The implementation of class gcc::jit::recording::location.  */
+
+/* Implementation of recording::memento::replay_into for locations.
+
+   Create a new playback::location and store it into the
+   recording::location's m_playback_obj field.  */
+
+void
+recording::location::replay_into (replayer *r)
+{
+  m_playback_obj = r->new_location (this,
+                                   m_filename->c_str (),
+                                   m_line,
+                                   m_column);
+}
+
+/* Implementation of recording::memento::make_debug_string for locations,
+   turning them into the usual form:
+     FILENAME:LINE:COLUMN
+   like we do when emitting diagnostics.  */
+
+recording::string *
+recording::location::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+                             "%s:%i:%i",
+                             m_filename->c_str (), m_line, m_column);
+}
+
+/* The implementation of class gcc::jit::recording::type.  */
+
+/* Given a type T, get the type T*.
+
+   If this doesn't already exist, generate a new memento_of_get_pointer
+   instance and add it to this type's context's list of mementos.
+
+   Otherwise, use the cached type.
+
+   Implements the post-error-checking part of
+   gcc_jit_type_get_pointer.  */
+
+recording::type *
+recording::type::get_pointer ()
+{
+  if (!m_pointer_to_this_type)
+    {
+      m_pointer_to_this_type = new memento_of_get_pointer (this);
+      m_ctxt->record (m_pointer_to_this_type);
+    }
+  return m_pointer_to_this_type;
+}
+
+/* Given a type T, get the type const T.
+
+   Implements the post-error-checking part of
+   gcc_jit_type_get_const.  */
+
+recording::type *
+recording::type::get_const ()
+{
+  recording::type *result = new memento_of_get_const (this);
+  m_ctxt->record (result);
+  return result;
+}
+
+/* Given a type T, get the type volatile T.
+
+   Implements the post-error-checking part of
+   gcc_jit_type_get_volatile.  */
+
+recording::type *
+recording::type::get_volatile ()
+{
+  recording::type *result = new memento_of_get_volatile (this);
+  m_ctxt->record (result);
+  return result;
+}
+
+/* Implementation of pure virtual hook recording::type::dereference for
+   recording::memento_of_get_type.  */
+
+recording::type *
+recording::memento_of_get_type::dereference ()
+{
+  switch (m_kind)
+    {
+    default: gcc_unreachable ();
+
+    case GCC_JIT_TYPE_VOID:
+      return NULL;
+
+    case GCC_JIT_TYPE_VOID_PTR:
+      return m_ctxt->get_type (GCC_JIT_TYPE_VOID);
+
+    case GCC_JIT_TYPE_BOOL:
+    case GCC_JIT_TYPE_CHAR:
+    case GCC_JIT_TYPE_SIGNED_CHAR:
+    case GCC_JIT_TYPE_UNSIGNED_CHAR:
+    case GCC_JIT_TYPE_SHORT:
+    case GCC_JIT_TYPE_UNSIGNED_SHORT:
+    case GCC_JIT_TYPE_INT:
+    case GCC_JIT_TYPE_UNSIGNED_INT:
+    case GCC_JIT_TYPE_LONG:
+    case GCC_JIT_TYPE_UNSIGNED_LONG:
+    case GCC_JIT_TYPE_LONG_LONG:
+    case GCC_JIT_TYPE_UNSIGNED_LONG_LONG:
+    case GCC_JIT_TYPE_FLOAT:
+    case GCC_JIT_TYPE_DOUBLE:
+    case GCC_JIT_TYPE_LONG_DOUBLE:
+      /* Not a pointer: */
+      return NULL;
+
+    case GCC_JIT_TYPE_CONST_CHAR_PTR:
+      return m_ctxt->get_type (GCC_JIT_TYPE_CHAR)->get_const ();
+
+    case GCC_JIT_TYPE_SIZE_T:
+      /* Not a pointer: */
+      return NULL;
+
+    case GCC_JIT_TYPE_FILE_PTR:
+      /* Give the client code back an opaque "struct FILE".  */
+      return m_ctxt->get_opaque_FILE_type ();
+    }
+}
+
+/* Implementation of pure virtual hook recording::type::is_int for
+   recording::memento_of_get_type.  */
+
+bool
+recording::memento_of_get_type::is_int () const
+{
+  switch (m_kind)
+    {
+    default: gcc_unreachable ();
+
+    case GCC_JIT_TYPE_VOID:
+      return false;
+
+    case GCC_JIT_TYPE_VOID_PTR:
+      return false;
+
+    case GCC_JIT_TYPE_BOOL:
+      return false;
+
+    case GCC_JIT_TYPE_CHAR:
+    case GCC_JIT_TYPE_SIGNED_CHAR:
+    case GCC_JIT_TYPE_UNSIGNED_CHAR:
+    case GCC_JIT_TYPE_SHORT:
+    case GCC_JIT_TYPE_UNSIGNED_SHORT:
+    case GCC_JIT_TYPE_INT:
+    case GCC_JIT_TYPE_UNSIGNED_INT:
+    case GCC_JIT_TYPE_LONG:
+    case GCC_JIT_TYPE_UNSIGNED_LONG:
+    case GCC_JIT_TYPE_LONG_LONG:
+    case GCC_JIT_TYPE_UNSIGNED_LONG_LONG:
+      return true;
+
+    case GCC_JIT_TYPE_FLOAT:
+    case GCC_JIT_TYPE_DOUBLE:
+    case GCC_JIT_TYPE_LONG_DOUBLE:
+      return false;
+
+    case GCC_JIT_TYPE_CONST_CHAR_PTR:
+      return false;
+
+    case GCC_JIT_TYPE_SIZE_T:
+      return true;
+
+    case GCC_JIT_TYPE_FILE_PTR:
+      return false;
+    }
+}
+
+/* Implementation of pure virtual hook recording::type::is_float for
+   recording::memento_of_get_type.  */
+
+bool
+recording::memento_of_get_type::is_float () const
+{
+  switch (m_kind)
+    {
+    default: gcc_unreachable ();
+
+    case GCC_JIT_TYPE_VOID:
+      return false;
+
+    case GCC_JIT_TYPE_VOID_PTR:
+      return false;
+
+    case GCC_JIT_TYPE_BOOL:
+      return false;
+
+    case GCC_JIT_TYPE_CHAR:
+    case GCC_JIT_TYPE_SIGNED_CHAR:
+    case GCC_JIT_TYPE_UNSIGNED_CHAR:
+    case GCC_JIT_TYPE_SHORT:
+    case GCC_JIT_TYPE_UNSIGNED_SHORT:
+    case GCC_JIT_TYPE_INT:
+    case GCC_JIT_TYPE_UNSIGNED_INT:
+    case GCC_JIT_TYPE_LONG:
+    case GCC_JIT_TYPE_UNSIGNED_LONG:
+    case GCC_JIT_TYPE_LONG_LONG:
+    case GCC_JIT_TYPE_UNSIGNED_LONG_LONG:
+      return false;
+
+    case GCC_JIT_TYPE_FLOAT:
+    case GCC_JIT_TYPE_DOUBLE:
+    case GCC_JIT_TYPE_LONG_DOUBLE:
+      return true;
+
+    case GCC_JIT_TYPE_CONST_CHAR_PTR:
+      return false;
+
+    case GCC_JIT_TYPE_SIZE_T:
+      return false;
+
+    case GCC_JIT_TYPE_FILE_PTR:
+      return false;
+    }
+}
+
+/* Implementation of pure virtual hook recording::type::is_bool for
+   recording::memento_of_get_type.  */
+
+bool
+recording::memento_of_get_type::is_bool () const
+{
+  switch (m_kind)
+    {
+    default: gcc_unreachable ();
+
+    case GCC_JIT_TYPE_VOID:
+      return false;
+
+    case GCC_JIT_TYPE_VOID_PTR:
+      return false;
+
+    case GCC_JIT_TYPE_BOOL:
+      return true;
+
+    case GCC_JIT_TYPE_CHAR:
+    case GCC_JIT_TYPE_SIGNED_CHAR:
+    case GCC_JIT_TYPE_UNSIGNED_CHAR:
+    case GCC_JIT_TYPE_SHORT:
+    case GCC_JIT_TYPE_UNSIGNED_SHORT:
+    case GCC_JIT_TYPE_INT:
+    case GCC_JIT_TYPE_UNSIGNED_INT:
+    case GCC_JIT_TYPE_LONG:
+    case GCC_JIT_TYPE_UNSIGNED_LONG:
+    case GCC_JIT_TYPE_LONG_LONG:
+    case GCC_JIT_TYPE_UNSIGNED_LONG_LONG:
+      return false;
+
+    case GCC_JIT_TYPE_FLOAT:
+    case GCC_JIT_TYPE_DOUBLE:
+    case GCC_JIT_TYPE_LONG_DOUBLE:
+      return false;
+
+    case GCC_JIT_TYPE_CONST_CHAR_PTR:
+      return false;
+
+    case GCC_JIT_TYPE_SIZE_T:
+      return false;
+
+    case GCC_JIT_TYPE_FILE_PTR:
+      return false;
+    }
+}
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::memento_of_get_type.  */
+
+void
+recording::memento_of_get_type::replay_into (replayer *r)
+{
+  set_playback_obj (r->get_type (m_kind));
+}
+
+/* The implementation of class gcc::jit::recording::memento_of_get_type.  */
+
+/* Descriptive strings for each of enum gcc_jit_types.  */
+
+static const char * const get_type_strings[] = {
+  "void",    /* GCC_JIT_TYPE_VOID */
+  "void *",  /* GCC_JIT_TYPE_VOID_PTR */
+
+  "bool",  /* GCC_JIT_TYPE_BOOL */
+
+  "char",           /* GCC_JIT_TYPE_CHAR */
+  "signed char",    /* GCC_JIT_TYPE_SIGNED_CHAR */
+  "unsigned char",  /* GCC_JIT_TYPE_UNSIGNED_CHAR */
+
+  "short",           /* GCC_JIT_TYPE_SHORT */
+  "unsigned short",  /* GCC_JIT_TYPE_UNSIGNED_SHORT */
+
+  "int",           /* GCC_JIT_TYPE_INT */
+  "unsigned int",  /* GCC_JIT_TYPE_UNSIGNED_INT */
+
+  "long",           /* GCC_JIT_TYPE_LONG  */
+  "unsigned long",  /* GCC_JIT_TYPE_UNSIGNED_LONG, */
+
+  "long long",           /* GCC_JIT_TYPE_LONG_LONG */
+  "unsigned long long",  /* GCC_JIT_TYPE_UNSIGNED_LONG_LONG */
+
+  "float",        /* GCC_JIT_TYPE_FLOAT */
+  "double",       /* GCC_JIT_TYPE_DOUBLE */
+  "long double",  /* GCC_JIT_TYPE_LONG_DOUBLE */
+
+  "const char *",  /* GCC_JIT_TYPE_CONST_CHAR_PTR */
+
+  "size_t",  /* GCC_JIT_TYPE_SIZE_T */
+
+  "FILE *"  /* GCC_JIT_TYPE_FILE_PTR */
+
+};
+
+/* Implementation of recording::memento::make_debug_string for
+   results of get_type, using a simple table of type names.  */
+
+recording::string *
+recording::memento_of_get_type::make_debug_string ()
+{
+  return m_ctxt->new_string (get_type_strings[m_kind]);
+}
+
+/* The implementation of class gcc::jit::recording::memento_of_get_pointer.  */
+
+/* Override of default implementation of
+   recording::type::accepts_writes_from for get_pointer.
+
+   Require a pointer type, and allowing writes to
+   (const T *) from a (T*), but not the other way around.  */
+
+bool
+recording::memento_of_get_pointer::accepts_writes_from (type *rtype)
+{
+  /* Must be a pointer type: */
+  type *rtype_points_to = rtype->is_pointer ();
+  if (!rtype_points_to)
+    return false;
+
+  /* It's OK to assign to a (const T *) from a (T *).  */
+  return m_other_type->unqualified ()
+    ->accepts_writes_from (rtype_points_to);
+}
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::memento_of_get_pointer.  */
+
+void
+recording::memento_of_get_pointer::replay_into (replayer *)
+{
+  set_playback_obj (m_other_type->playback_type ()->get_pointer ());
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   results of get_pointer, adding " *" to the underlying type,
+   with special-casing to handle function pointer types.  */
+
+recording::string *
+recording::memento_of_get_pointer::make_debug_string ()
+{
+  /* Special-case function pointer types, to put the "*" in parens between
+     the return type and the params (for one level of dereferencing, at
+     least).  */
+  if (function_type *fn_type = m_other_type->dyn_cast_function_type ())
+    return fn_type->make_debug_string_with_ptr ();
+
+  return string::from_printf (m_ctxt,
+                             "%s *", m_other_type->get_debug_string ());
+}
+
+/* The implementation of class gcc::jit::recording::memento_of_get_const.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::memento_of_get_const.  */
+
+void
+recording::memento_of_get_const::replay_into (replayer *)
+{
+  set_playback_obj (m_other_type->playback_type ()->get_const ());
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   results of get_const, prepending "const ".  */
+
+recording::string *
+recording::memento_of_get_const::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+                             "const %s", m_other_type->get_debug_string ());
+}
+
+/* The implementation of class gcc::jit::recording::memento_of_get_volatile.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::memento_of_get_volatile.  */
+
+void
+recording::memento_of_get_volatile::replay_into (replayer *)
+{
+  set_playback_obj (m_other_type->playback_type ()->get_volatile ());
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   results of get_volatile, prepending "volatile ".  */
+
+recording::string *
+recording::memento_of_get_volatile::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+                             "volatile %s", m_other_type->get_debug_string ());
+}
+
+/* The implementation of class gcc::jit::recording::array_type */
+
+/* Implementation of pure virtual hook recording::type::dereference for
+   recording::array_type.  */
+
+recording::type *
+recording::array_type::dereference ()
+{
+  return m_element_type;
+}
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::array_type.  */
+
+void
+recording::array_type::replay_into (replayer *r)
+{
+  set_playback_obj (r->new_array_type (playback_location (r, m_loc),
+                                      m_element_type->playback_type (),
+                                      m_num_elements));
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   results of new_array_type.  */
+
+recording::string *
+recording::array_type::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+                             "%s[%d]",
+                             m_element_type->get_debug_string (),
+                             m_num_elements);
+}
+
+/* The implementation of class gcc::jit::recording::function_type */
+
+/* Constructor for gcc::jit::recording::function_type.  */
+
+recording::function_type::function_type (context *ctxt,
+                                        type *return_type,
+                                        int num_params,
+                                        type **param_types,
+                                        int is_variadic)
+: type (ctxt),
+  m_return_type (return_type),
+  m_param_types (),
+  m_is_variadic (is_variadic)
+{
+  for (int i = 0; i< num_params; i++)
+    m_param_types.safe_push (param_types[i]);
+}
+
+/* Implementation of pure virtual hook recording::type::dereference for
+   recording::function_type.  */
+
+recording::type *
+recording::function_type::dereference ()
+{
+  return NULL;
+}
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::function_type.  */
+
+void
+recording::function_type::replay_into (replayer *r)
+{
+  /* Convert m_param_types to a vec of playback type.  */
+  vec <playback::type *> param_types;
+  int i;
+  recording::type *type;
+  param_types.create (m_param_types.length ());
+  FOR_EACH_VEC_ELT (m_param_types, i, type)
+    param_types.safe_push (type->playback_type ());
+
+  set_playback_obj (r->new_function_type (m_return_type->playback_type (),
+                                         &param_types,
+                                         m_is_variadic));
+}
+
+/* Special-casing for make_debug_string for get_pointer results for
+   handling (one level) of pointers to functions.  */
+
+recording::string *
+recording::function_type::make_debug_string_with_ptr ()
+{
+  return make_debug_string_with ("(*) ");
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   results of new_function_type.  */
+
+recording::string *
+recording::function_type::make_debug_string ()
+{
+  return make_debug_string_with ("");
+}
+
+/* Build a debug string representation of the form:
+
+     RESULT_TYPE INSERT (PARAM_TYPES)
+
+   for use when handling 0 and 1 level of indirection to this
+   function type.  */
+
+recording::string *
+recording::function_type::make_debug_string_with (const char *insert)
+{
+  /* First, build a buffer for the arguments.  */
+  /* Calculate length of said buffer.  */
+  size_t sz = 1; /* nil terminator */
+  for (unsigned i = 0; i< m_param_types.length (); i++)
+    {
+      sz += strlen (m_param_types[i]->get_debug_string ());
+      sz += 2; /* ", " separator */
+    }
+  if (m_is_variadic)
+    sz += 5; /* ", ..." separator and ellipsis */
+
+  /* Now allocate and populate the buffer.  */
+  char *argbuf = new char[sz];
+  size_t len = 0;
+
+  for (unsigned i = 0; i< m_param_types.length (); i++)
+    {
+      strcpy (argbuf + len, m_param_types[i]->get_debug_string ());
+      len += strlen (m_param_types[i]->get_debug_string ());
+      if (i + 1 < m_param_types.length ())
+       {
+         strcpy (argbuf + len, ", ");
+         len += 2;
+       }
+    }
+  if (m_is_variadic)
+    {
+      if (m_param_types.length ())
+       {
+         strcpy (argbuf + len, ", ");
+         len += 2;
+       }
+      strcpy (argbuf + len, "...");
+      len += 3;
+    }
+  argbuf[len] = '\0';
+
+  /* ...and use it to get the string for the call as a whole.  */
+  string *result = string::from_printf (m_ctxt,
+                                       "%s %s(%s)",
+                                       m_return_type->get_debug_string (),
+                                       insert,
+                                       argbuf);
+
+  delete[] argbuf;
+
+  return result;
+}
+
+/* The implementation of class gcc::jit::recording::field.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::field.  */
+
+void
+recording::field::replay_into (replayer *r)
+{
+  set_playback_obj (r->new_field (playback_location (r, m_loc),
+                                 m_type->playback_type (),
+                                 playback_string (m_name)));
+}
+
+/* Override the default implementation of
+   recording::memento::write_to_dump.  Dump each field
+   by dumping a line of the form:
+      TYPE NAME;
+   so that we can build up a struct/union field-byfield.  */
+
+void
+recording::field::write_to_dump (dump &d)
+{
+  d.write ("  %s %s;\n",
+          m_type->get_debug_string (),
+          m_name->c_str ());
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   results of new_field.  */
+
+recording::string *
+recording::field::make_debug_string ()
+{
+  return m_name;
+}
+
+/* The implementation of class gcc::jit::recording::compound_type */
+
+/* The constructor for gcc::jit::recording::compound_type.  */
+
+recording::compound_type::compound_type (context *ctxt,
+                                        location *loc,
+                                        string *name)
+: type (ctxt),
+  m_loc (loc),
+  m_name (name),
+  m_fields (NULL)
+{
+}
+
+/* Set the fields of a compound type.
+
+   Implements the post-error-checking part of
+   gcc_jit_struct_set_fields, and is also used by
+   gcc_jit_context_new_union_type.  */
+
+void
+recording::compound_type::set_fields (location *loc,
+                                     int num_fields,
+                                     field **field_array)
+{
+  m_loc = loc;
+  gcc_assert (NULL == m_fields);
+
+  m_fields = new fields (this, num_fields, field_array);
+  m_ctxt->record (m_fields);
+}
+
+/* Implementation of pure virtual hook recording::type::dereference for
+   recording::compound_type.  */
+
+recording::type *
+recording::compound_type::dereference ()
+{
+  return NULL; /* not a pointer */
+}
+
+/* The implementation of class gcc::jit::recording::struct_.  */
+
+/* The constructor for gcc::jit::recording::struct_.  */
+
+recording::struct_::struct_ (context *ctxt,
+                            location *loc,
+                            string *name)
+: compound_type (ctxt, loc, name)
+{
+}
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::struct_.  */
+
+void
+recording::struct_::replay_into (replayer *r)
+{
+  set_playback_obj (
+    r->new_compound_type (playback_location (r, get_loc ()),
+                         get_name ()->c_str (),
+                         true /* is_struct */));
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   structs.  */
+
+recording::string *
+recording::struct_::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+                             "struct %s", get_name ()->c_str ());
+}
+
+/* The implementation of class gcc::jit::recording::union_.  */
+
+/* The constructor for gcc::jit::recording::union_.  */
+
+recording::union_::union_ (context *ctxt,
+                          location *loc,
+                          string *name)
+: compound_type (ctxt, loc, name)
+{
+}
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::union_.  */
+
+void
+recording::union_::replay_into (replayer *r)
+{
+  set_playback_obj (
+    r->new_compound_type (playback_location (r, get_loc ()),
+                         get_name ()->c_str (),
+                         false /* is_struct */));
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   unions.  */
+
+recording::string *
+recording::union_::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+                             "union %s", get_name ()->c_str ());
+}
+
+/* The implementation of class gcc::jit::recording::fields.  */
+
+/* The constructor for gcc::jit::recording::fields.  */
+
+recording::fields::fields (compound_type *struct_or_union,
+                          int num_fields,
+                          field **fields)
+: memento (struct_or_union->m_ctxt),
+  m_struct_or_union (struct_or_union),
+  m_fields ()
+{
+  for (int i = 0; i < num_fields; i++)
+    {
+      gcc_assert (fields[i]->get_container () == NULL);
+      fields[i]->set_container (m_struct_or_union);
+      m_fields.safe_push (fields[i]);
+    }
+}
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::fields.  */
+
+void
+recording::fields::replay_into (replayer *)
+{
+  vec<playback::field *> playback_fields;
+  playback_fields.create (m_fields.length ());
+  for (unsigned i = 0; i < m_fields.length (); i++)
+    playback_fields.safe_push (m_fields[i]->playback_field ());
+  m_struct_or_union->playback_compound_type ()->set_fields (playback_fields);
+}
+
+/* Override the default implementation of
+   recording::memento::write_to_dump by writing a union/struct
+   declaration of this form:
+
+      struct/union NAME {
+        TYPE_1 NAME_1;
+        TYPE_2 NAME_2;
+       ....
+        TYPE_N NAME_N;
+      };
+
+    to the dump.  */
+
+void
+recording::fields::write_to_dump (dump &d)
+{
+  int i;
+  field *f;
+
+  d.write ("%s\n{\n", m_struct_or_union->get_debug_string ());
+  FOR_EACH_VEC_ELT (m_fields, i, f)
+    f->write_to_dump (d);
+  d.write ("};\n");
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   field tables.  */
+
+recording::string *
+recording::fields::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+                             "fields");
+}
+
+/* The implementation of class gcc::jit::recording::rvalue.  */
+
+/* Create a recording::access_field_rvalue instance and add it to
+   the rvalue's context's list of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_rvalue_access_field.  */
+
+recording::rvalue *
+recording::rvalue::access_field (recording::location *loc,
+                                field *field)
+{
+  recording::rvalue *result =
+    new access_field_rvalue (m_ctxt, loc, this, field);
+  m_ctxt->record (result);
+  return result;
+}
+
+/* Create a recording::dereference_field_rvalue instance and add it to
+   the rvalue's context's list of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_rvalue_dereference_field.  */
+
+recording::lvalue *
+recording::rvalue::dereference_field (recording::location *loc,
+                                     field *field)
+{
+  recording::lvalue *result =
+    new dereference_field_rvalue (m_ctxt, loc, this, field);
+  m_ctxt->record (result);
+  return result;
+}
+
+/* Create a recording::dereference_rvalue instance and add it to the
+   rvalue's context's list of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_rvalue_dereference.  */
+
+recording::lvalue *
+recording::rvalue::dereference (recording::location *loc)
+{
+  recording::lvalue *result =
+    new dereference_rvalue (m_ctxt, loc, this);
+  m_ctxt->record (result);
+  return result;
+}
+
+/* The implementation of class gcc::jit::recording::lvalue.  */
+
+/* Create a recording::new_access_field_of_lvalue instance and add it to
+   the lvalue's context's list of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_lvalue_access_field.  */
+
+recording::lvalue *
+recording::lvalue::access_field (recording::location *loc,
+                                field *field)
+{
+  recording::lvalue *result =
+    new access_field_of_lvalue (m_ctxt, loc, this, field);
+  m_ctxt->record (result);
+  return result;
+}
+
+/* Create a recording::get_address_of_lvalue instance and add it to
+   the lvalue's context's list of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_lvalue_get_address.  */
+
+recording::rvalue *
+recording::lvalue::get_address (recording::location *loc)
+{
+  recording::rvalue *result =
+    new get_address_of_lvalue (m_ctxt, loc, this);
+  m_ctxt->record (result);
+  return result;
+}
+
+/* The implementation of class gcc::jit::recording::param.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::param.  */
+
+void
+recording::param::replay_into (replayer *r)
+{
+  set_playback_obj (r->new_param (playback_location (r, m_loc),
+                                 m_type->playback_type (),
+                                 m_name->c_str ()));
+}
+
+
+/* The implementation of class gcc::jit::recording::function.  */
+
+/* gcc::jit::recording::function's constructor.  */
+
+recording::function::function (context *ctxt,
+                              recording::location *loc,
+                              enum gcc_jit_function_kind kind,
+                              type *return_type,
+                              recording::string *name,
+                              int num_params,
+                              recording::param **params,
+                              int is_variadic,
+                              enum built_in_function builtin_id)
+: memento (ctxt),
+  m_loc (loc),
+  m_kind (kind),
+  m_return_type (return_type),
+  m_name (name),
+  m_params (),
+  m_is_variadic (is_variadic),
+  m_builtin_id (builtin_id),
+  m_locals (),
+  m_blocks ()
+{
+  for (int i = 0; i< num_params; i++)
+    m_params.safe_push (params[i]);
+}
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::function.  */
+
+void
+recording::function::replay_into (replayer *r)
+{
+  /* Convert m_params to a vec of playback param.  */
+  vec <playback::param *> params;
+  int i;
+  recording::param *param;
+  params.create (m_params.length ());
+  FOR_EACH_VEC_ELT (m_params, i, param)
+    params.safe_push (param->playback_param ());
+
+  set_playback_obj (r->new_function (playback_location (r, m_loc),
+                                    m_kind,
+                                    m_return_type->playback_type (),
+                                    m_name->c_str (),
+                                    &params,
+                                    m_is_variadic,
+                                    m_builtin_id));
+}
+
+/* Create a recording::local instance and add it to
+   the functions's context's list of mementos, and to the function's
+   list of locals.
+
+   Implements the post-error-checking part of
+   gcc_jit_function_new_local.  */
+
+recording::lvalue *
+recording::function::new_local (recording::location *loc,
+                               type *type,
+                               const char *name)
+{
+  local *result = new local (this, loc, type, new_string (name));
+  m_ctxt->record (result);
+  m_locals.safe_push (result);
+  return result;
+}
+
+/* Create a recording::block instance and add it to
+   the functions's context's list of mementos, and to the function's
+   list of blocks.
+
+   Implements the post-error-checking part of
+   gcc_jit_function_new_block.  */
+
+recording::block*
+recording::function::new_block (const char *name)
+{
+  gcc_assert (m_kind != GCC_JIT_FUNCTION_IMPORTED);
+
+  recording::block *result =
+    new recording::block (this, m_blocks.length (), new_string (name));
+  m_ctxt->record (result);
+  m_blocks.safe_push (result);
+  return result;
+}
+
+/* Override the default implementation of
+   recording::memento::write_to_dump by dumping a C-like
+   representation of the function; either like a prototype
+   for GCC_JIT_FUNCTION_IMPORTED, or like a full definition for
+   all other kinds of function.  */
+
+void
+recording::function::write_to_dump (dump &d)
+{
+  switch (m_kind)
+    {
+    default: gcc_unreachable ();
+    case GCC_JIT_FUNCTION_EXPORTED:
+    case GCC_JIT_FUNCTION_IMPORTED:
+      d.write ("extern ");
+      break;
+    case GCC_JIT_FUNCTION_INTERNAL:
+      d.write ("static ");
+      break;
+    case GCC_JIT_FUNCTION_ALWAYS_INLINE:
+      d.write ("static inline ");
+      break;
+     }
+  d.write ("%s\n", m_return_type->get_debug_string ());
+
+  if (d.update_locations ())
+    m_loc = d.make_location ();
+
+  d.write ("%s (", get_debug_string ());
+
+  int i;
+  recording::param *param;
+  FOR_EACH_VEC_ELT (m_params, i, param)
+    {
+      if (i > 0)
+       d.write (", ");
+      d.write ("%s %s",
+              param->get_type ()->get_debug_string (),
+              param->get_debug_string ());
+    }
+  d.write (")");
+  if (m_kind == GCC_JIT_FUNCTION_IMPORTED)
+    {
+      d.write ("; /* (imported) */\n\n");
+    }
+  else
+    {
+      int i;
+      local *var = NULL;
+      block *b;
+      d.write ("\n{\n");
+
+      /* Write locals: */
+      FOR_EACH_VEC_ELT (m_locals, i, var)
+       var->write_to_dump (d);
+      if (m_locals.length ())
+       d.write ("\n");
+
+      /* Write each block: */
+      FOR_EACH_VEC_ELT (m_blocks, i, b)
+       {
+         if (i > 0)
+           d.write ("\n");
+         b->write_to_dump (d);
+       }
+
+      d.write ("}\n\n");
+    }
+}
+
+/* Pre-compilation validation of a function, for those things we can't
+   check until the context is (supposedly) fully-populated.  */
+
+void
+recording::function::validate ()
+{
+  /* Complain about empty functions with non-void return type.  */
+  if (m_kind != GCC_JIT_FUNCTION_IMPORTED
+      && m_return_type != m_ctxt->get_type (GCC_JIT_TYPE_VOID))
+    if (0 == m_blocks.length ())
+      m_ctxt->add_error (m_loc,
+                        "function %s returns non-void (type: %s)"
+                        " but has no blocks",
+                        get_debug_string (),
+                        m_return_type->get_debug_string ());
+
+  /* Check that all blocks are terminated.  */
+  int num_invalid_blocks = 0;
+  {
+    int i;
+    block *b;
+
+    FOR_EACH_VEC_ELT (m_blocks, i, b)
+      if (!b->validate ())
+       num_invalid_blocks++;
+  }
+
+  /* Check that all blocks are reachable.  */
+  if (m_blocks.length () > 0 && 0 == num_invalid_blocks)
+    {
+      /* Iteratively walk the graph of blocks, marking their "m_is_reachable"
+        flag, starting at the initial block.  */
+      vec<block *> worklist;
+      worklist.create (m_blocks.length ());
+      worklist.safe_push (m_blocks[0]);
+      while (worklist.length () > 0)
+       {
+         block *b = worklist.pop ();
+         b->m_is_reachable = true;
+
+         /* Add successor blocks that aren't yet marked to the worklist.  */
+         /* We checked that each block has a terminating statement above .  */
+         block *next1, *next2;
+         int n = b->get_successor_blocks (&next1, &next2);
+         switch (n)
+           {
+           default:
+             gcc_unreachable ();
+           case 2:
+             if (!next2->m_is_reachable)
+               worklist.safe_push (next2);
+             /* fallthrough */
+           case 1:
+             if (!next1->m_is_reachable)
+               worklist.safe_push (next1);
+             break;
+           case 0:
+             break;
+           }
+       }
+
+      /* Now complain about any blocks that haven't been marked.  */
+      {
+       int i;
+       block *b;
+       FOR_EACH_VEC_ELT (m_blocks, i, b)
+         if (!b->m_is_reachable)
+           m_ctxt->add_error (b->get_loc (),
+                              "unreachable block: %s",
+                              b->get_debug_string ());
+      }
+    }
+}
+
+/* Implements the post-error-checking part of
+   gcc_jit_function_dump_to_dot.  */
+
+void
+recording::function::dump_to_dot (const char *path)
+{
+  FILE *fp  = fopen (path, "w");
+  if (!fp)
+    return;
+
+  pretty_printer the_pp;
+  the_pp.buffer->stream = fp;
+
+  pretty_printer *pp = &the_pp;
+
+  pp_printf (pp,
+            "digraph %s {\n", get_debug_string ());
+
+  /* Blocks: */
+  {
+    int i;
+    block *b;
+    FOR_EACH_VEC_ELT (m_blocks, i, b)
+      b->dump_to_dot (pp);
+  }
+
+  /* Edges: */
+  {
+    int i;
+    block *b;
+    FOR_EACH_VEC_ELT (m_blocks, i, b)
+      b->dump_edges_to_dot (pp);
+  }
+
+  pp_printf (pp, "}\n");
+  pp_flush (pp);
+  fclose (fp);
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   functions.  */
+
+recording::string *
+recording::function::make_debug_string ()
+{
+  return m_name;
+}
+
+/* The implementation of class gcc::jit::recording::block.  */
+
+/* Create a recording::eval instance and add it to
+   the block's context's list of mementos, and to the block's
+   list of statements.
+
+   Implements the post-error-checking part of
+   gcc_jit_block_add_eval.  */
+
+void
+recording::block::add_eval (recording::location *loc,
+                           recording::rvalue *rvalue)
+{
+  statement *result = new eval (this, loc, rvalue);
+  m_ctxt->record (result);
+  m_statements.safe_push (result);
+}
+
+/* Create a recording::assignment instance and add it to
+   the block's context's list of mementos, and to the block's
+   list of statements.
+
+   Implements the post-error-checking part of
+   gcc_jit_block_add_assignment.  */
+
+void
+recording::block::add_assignment (recording::location *loc,
+                                 recording::lvalue *lvalue,
+                                 recording::rvalue *rvalue)
+{
+  statement *result = new assignment (this, loc, lvalue, rvalue);
+  m_ctxt->record (result);
+  m_statements.safe_push (result);
+}
+
+/* Create a recording::assignment_op instance and add it to
+   the block's context's list of mementos, and to the block's
+   list of statements.
+
+   Implements the post-error-checking part of
+   gcc_jit_block_add_assignment_op.  */
+
+void
+recording::block::add_assignment_op (recording::location *loc,
+                                    recording::lvalue *lvalue,
+                                    enum gcc_jit_binary_op op,
+                                    recording::rvalue *rvalue)
+{
+  statement *result = new assignment_op (this, loc, lvalue, op, rvalue);
+  m_ctxt->record (result);
+  m_statements.safe_push (result);
+}
+
+/* Create a recording::comment instance and add it to
+   the block's context's list of mementos, and to the block's
+   list of statements.
+
+   Implements the post-error-checking part of
+   gcc_jit_block_add_comment.  */
+
+void
+recording::block::add_comment (recording::location *loc,
+                              const char *text)
+{
+  statement *result = new comment (this, loc, new_string (text));
+  m_ctxt->record (result);
+  m_statements.safe_push (result);
+}
+
+/* Create a recording::end_with_conditional instance and add it to
+   the block's context's list of mementos, and to the block's
+   list of statements.
+
+   Implements the post-error-checking part of
+   gcc_jit_block_end_with_conditional.  */
+
+void
+recording::block::end_with_conditional (recording::location *loc,
+                                       recording::rvalue *boolval,
+                                       recording::block *on_true,
+                                       recording::block *on_false)
+{
+  statement *result = new conditional (this, loc, boolval, on_true, on_false);
+  m_ctxt->record (result);
+  m_statements.safe_push (result);
+  m_has_been_terminated = true;
+}
+
+/* Create a recording::end_with_jump instance and add it to
+   the block's context's list of mementos, and to the block's
+   list of statements.
+
+   Implements the post-error-checking part of
+   gcc_jit_block_end_with_jump.  */
+
+void
+recording::block::end_with_jump (recording::location *loc,
+                                recording::block *target)
+{
+  statement *result = new jump (this, loc, target);
+  m_ctxt->record (result);
+  m_statements.safe_push (result);
+  m_has_been_terminated = true;
+}
+
+/* Create a recording::end_with_return instance and add it to
+   the block's context's list of mementos, and to the block's
+   list of statements.
+
+   Implements the post-error-checking parts of
+   gcc_jit_block_end_with_return and
+   gcc_jit_block_end_with_void_return.  */
+
+void
+recording::block::end_with_return (recording::location *loc,
+                                  recording::rvalue *rvalue)
+{
+  /* This is used by both gcc_jit_function_add_return and
+     gcc_jit_function_add_void_return; rvalue will be non-NULL for
+     the former and NULL for the latter.  */
+  statement *result = new return_ (this, loc, rvalue);
+  m_ctxt->record (result);
+  m_statements.safe_push (result);
+  m_has_been_terminated = true;
+}
+
+/* Override the default implementation of
+   recording::memento::write_to_dump for blocks by writing
+   an unindented block name as a label, followed by the indented
+   statements:
+
+    BLOCK_NAME:
+      STATEMENT_1;
+      STATEMENT_2;
+      ...
+      STATEMENT_N;  */
+
+void
+recording::block::write_to_dump (dump &d)
+{
+  d.write ("%s:\n", get_debug_string ());
+
+  int i;
+  statement *s;
+  FOR_EACH_VEC_ELT (m_statements, i, s)
+    s->write_to_dump (d);
+}
+
+/* Validate a block by ensuring that it has been terminated.  */
+
+bool
+recording::block::validate ()
+{
+  if (!has_been_terminated ())
+    {
+      statement *stmt = get_last_statement ();
+      location *loc = stmt ? stmt->get_loc () : NULL;
+      m_func->get_context ()->add_error (loc,
+                                        "unterminated block in %s: %s",
+                                        m_func->get_debug_string (),
+                                        get_debug_string ());
+      return false;
+    }
+
+  return true;
+}
+
+/* Get the source-location of a block by using that of the first
+   statement within it, if any.  */
+
+recording::location *
+recording::block::get_loc () const
+{
+  recording::statement *stmt = get_first_statement ();
+  if (stmt)
+    return stmt->get_loc ();
+  else
+    return NULL;
+}
+
+/* Get the first statement within a block, if any.  */
+
+recording::statement *
+recording::block::get_first_statement () const
+{
+  if (m_statements.length ())
+    return m_statements[0];
+  else
+    return NULL;
+}
+
+/* Get the last statement within a block, if any.  */
+
+recording::statement *
+recording::block::get_last_statement () const
+{
+  if (m_statements.length ())
+    return m_statements[m_statements.length () - 1];
+  else
+    return NULL;
+}
+
+/* Assuming that this block has been terminated, get the number of
+   successor blocks, which will be 0, 1 or 2, for return, unconditional
+   jump, and conditional jump respectively.
+   NEXT1 and NEXT2 must be non-NULL.  The first successor block (if any)
+   is written to NEXT1, and the second (if any) to NEXT2.
+
+   Used when validating functions, and when dumping dot representations
+   of them.  */
+
+int
+recording::block::get_successor_blocks (block **next1, block **next2) const
+{
+  gcc_assert (m_has_been_terminated);
+  gcc_assert (next1);
+  gcc_assert (next2);
+  statement *last_statement = get_last_statement ();
+  gcc_assert (last_statement);
+  return last_statement->get_successor_blocks (next1, next2);
+}
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::block.  */
+
+void
+recording::block::replay_into (replayer *)
+{
+  set_playback_obj (m_func->playback_function ()
+                     ->new_block (playback_string (m_name)));
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   blocks.  */
+
+recording::string *
+recording::block::make_debug_string ()
+{
+  if (m_name)
+    return m_name;
+  else
+    return string::from_printf (m_ctxt,
+                               "<UNNAMED BLOCK %p>",
+                               (void *)this);
+}
+
+/* Dump a block in graphviz form into PP, capturing the block name (if
+   any) and the statements.  */
+
+void
+recording::block::dump_to_dot (pretty_printer *pp)
+{
+  pp_printf (pp,
+            ("\tblock_%d "
+             "[shape=record,style=filled,fillcolor=white,label=\"{"),
+            m_index);
+  pp_write_text_to_stream (pp);
+  if (m_name)
+    {
+      pp_string (pp, m_name->c_str ());
+      pp_string (pp, ":");
+      pp_newline (pp);
+      pp_write_text_as_dot_label_to_stream (pp, true /*for_record*/);
+    }
+
+  int i;
+  statement *s;
+  FOR_EACH_VEC_ELT (m_statements, i, s)
+    {
+      pp_string (pp, s->get_debug_string ());
+      pp_newline (pp);
+      pp_write_text_as_dot_label_to_stream (pp, true /*for_record*/);
+    }
+
+  pp_printf (pp,
+            "}\"];\n\n");
+  pp_flush (pp);
+}
+
+/* Dump the out-edges of the block in graphviz form into PP.  */
+
+void
+recording::block::dump_edges_to_dot (pretty_printer *pp)
+{
+  block *next[2];
+  int num_succs = get_successor_blocks (&next[0], &next[1]);
+  for (int i = 0; i < num_succs; i++)
+    pp_printf (pp,
+              "\tblock_%d:s -> block_%d:n;\n",
+              m_index, next[i]->m_index);
+}
+
+/* The implementation of class gcc::jit::recording::global.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::global.  */
+
+void
+recording::global::replay_into (replayer *r)
+{
+  set_playback_obj (r->new_global (playback_location (r, m_loc),
+                                  m_type->playback_type (),
+                                  playback_string (m_name)));
+}
+
+/* The implementation of class gcc::jit::recording::memento_of_new_rvalue_from_int.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::memento_of_new_rvalue_from_int.  */
+
+void
+recording::memento_of_new_rvalue_from_int::replay_into (replayer *r)
+{
+  set_playback_obj (r->new_rvalue_from_int (m_type->playback_type (),
+                                           m_value));
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   rvalue_from_int, rendering it as
+     (TYPE)LITERAL
+   e.g.
+     "(int)42".  */
+
+recording::string *
+recording::memento_of_new_rvalue_from_int::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+                             "(%s)%i",
+                             m_type->get_debug_string (),
+                             m_value);
+}
+
+/* The implementation of class gcc::jit::recording::memento_of_new_rvalue_from_double.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::memento_of_new_rvalue_from_double.  */
+
+void
+recording::memento_of_new_rvalue_from_double::replay_into (replayer *r)
+{
+  set_playback_obj (r->new_rvalue_from_double (m_type->playback_type (),
+                                              m_value));
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   rvalue_from_double, rendering it as
+     (TYPE)LITERAL
+   e.g.
+     "(float)42.0".  */
+
+recording::string *
+recording::memento_of_new_rvalue_from_double::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+                             "(%s)%f",
+                             m_type->get_debug_string (),
+                             m_value);
+}
+
+/* The implementation of class gcc::jit::recording::memento_of_new_rvalue_from_ptr.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::memento_of_new_rvalue_from_ptr.  */
+
+void
+recording::memento_of_new_rvalue_from_ptr::replay_into (replayer *r)
+{
+  set_playback_obj (r->new_rvalue_from_ptr (m_type->playback_type (),
+                                           m_value));
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   rvalue_from_ptr, rendering it as
+     (TYPE)HEX
+   e.g.
+     "(int *)0xdeadbeef"
+
+   Zero is rendered as NULL e.g.
+     "(int *)NULL".  */
+
+recording::string *
+recording::memento_of_new_rvalue_from_ptr::make_debug_string ()
+{
+  if (m_value != NULL)
+    return string::from_printf (m_ctxt,
+                               "(%s)%p",
+                               m_type->get_debug_string (), m_value);
+  else
+    return string::from_printf (m_ctxt,
+                               "(%s)NULL",
+                               m_type->get_debug_string ());
+}
+
+/* The implementation of class gcc::jit::recording::memento_of_new_string_literal.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::memento_of_new_string_literal.  */
+
+void
+recording::memento_of_new_string_literal::replay_into (replayer *r)
+{
+  set_playback_obj (r->new_string_literal (m_value->c_str ()));
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   string literals.  */
+
+recording::string *
+recording::memento_of_new_string_literal::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+                             m_value->get_debug_string ());
+}
+
+/* The implementation of class gcc::jit::recording::unary_op.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::unary_op.  */
+
+void
+recording::unary_op::replay_into (replayer *r)
+{
+  set_playback_obj (r->new_unary_op (playback_location (r, m_loc),
+                                    m_op,
+                                    get_type ()->playback_type (),
+                                    m_a->playback_rvalue ()));
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   unary ops.  */
+
+static const char * const unary_op_strings[] = {
+  "-", /* GCC_JIT_UNARY_OP_MINUS */
+  "~", /* GCC_JIT_UNARY_OP_BITWISE_NEGATE */
+  "!", /* GCC_JIT_UNARY_OP_LOGICAL_NEGATE */
+};
+
+recording::string *
+recording::unary_op::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+                             "%s(%s)",
+                             unary_op_strings[m_op],
+                             m_a->get_debug_string ());
+}
+
+/* The implementation of class gcc::jit::recording::binary_op.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::binary_op.  */
+
+void
+recording::binary_op::replay_into (replayer *r)
+{
+  set_playback_obj (r->new_binary_op (playback_location (r, m_loc),
+                                     m_op,
+                                     get_type ()->playback_type (),
+                                     m_a->playback_rvalue (),
+                                     m_b->playback_rvalue ()));
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   binary ops.  */
+
+static const char * const binary_op_strings[] = {
+  "+", /* GCC_JIT_BINARY_OP_PLUS */
+  "-", /* GCC_JIT_BINARY_OP_MINUS */
+  "*", /* GCC_JIT_BINARY_OP_MULT */
+  "/", /* GCC_JIT_BINARY_OP_DIVIDE */
+  "%", /* GCC_JIT_BINARY_OP_MODULO */
+  "&", /* GCC_JIT_BINARY_OP_BITWISE_AND */
+  "^", /* GCC_JIT_BINARY_OP_BITWISE_XOR */
+  "|", /* GCC_JIT_BINARY_OP_BITWISE_OR */
+  "&&", /* GCC_JIT_BINARY_OP_LOGICAL_AND */
+  "||", /* GCC_JIT_BINARY_OP_LOGICAL_OR */
+  "<<", /* GCC_JIT_BINARY_OP_LSHIFT */
+  ">>", /* GCC_JIT_BINARY_OP_RSHIFT */
+};
+
+recording::string *
+recording::binary_op::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+                             "%s %s %s",
+                             m_a->get_debug_string (),
+                             binary_op_strings[m_op],
+                             m_b->get_debug_string ());
+}
+
+/* The implementation of class gcc::jit::recording::comparison.  */
+
+/* Implementation of recording::memento::make_debug_string for
+   comparisons.  */
+
+static const char * const comparison_strings[] =
+{
+  "==", /* GCC_JIT_COMPARISON_EQ */
+  "!=", /* GCC_JIT_COMPARISON_NE */
+  "<",  /* GCC_JIT_COMPARISON_LT */
+  "<=", /* GCC_JIT_COMPARISON_LE */
+  ">",  /* GCC_JIT_COMPARISON_GT */
+  ">=", /* GCC_JIT_COMPARISON_GE */
+};
+
+recording::string *
+recording::comparison::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+                             "%s %s %s",
+                             m_a->get_debug_string (),
+                             comparison_strings[m_op],
+                             m_b->get_debug_string ());
+}
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::comparison.  */
+
+void
+recording::comparison::replay_into (replayer *r)
+{
+  set_playback_obj (r->new_comparison (playback_location (r, m_loc),
+                                      m_op,
+                                      m_a->playback_rvalue (),
+                                      m_b->playback_rvalue ()));
+}
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::cast.  */
+
+void
+recording::cast::replay_into (replayer *r)
+{
+  set_playback_obj (r->new_cast (playback_location (r, m_loc),
+                                m_rvalue->playback_rvalue (),
+                                get_type ()->playback_type ()));
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   casts.  */
+
+recording::string *
+recording::cast::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+                             "(%s)%s",
+                             get_type ()->get_debug_string (),
+                             m_rvalue->get_debug_string ());
+}
+
+/* The implementation of class gcc::jit::recording::call.  */
+
+/* The constructor for gcc::jit::recording::call.  */
+
+recording::call::call (recording::context *ctxt,
+                      recording::location *loc,
+                      recording::function *func,
+                      int numargs,
+                      rvalue **args)
+: rvalue (ctxt, loc, func->get_return_type ()),
+  m_func (func),
+  m_args ()
+{
+  for (int i = 0; i< numargs; i++)
+    m_args.safe_push (args[i]);
+}
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::call.  */
+
+void
+recording::call::replay_into (replayer *r)
+{
+  vec<playback::rvalue *> playback_args;
+  playback_args.create (m_args.length ());
+  for (unsigned i = 0; i< m_args.length (); i++)
+    playback_args.safe_push (m_args[i]->playback_rvalue ());
+
+  set_playback_obj (r->new_call (playback_location (r, m_loc),
+                                m_func->playback_function (),
+                                playback_args));
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   function calls.  */
+
+recording::string *
+recording::call::make_debug_string ()
+{
+  /* First, build a buffer for the arguments.  */
+  /* Calculate length of said buffer.  */
+  size_t sz = 1; /* nil terminator */
+  for (unsigned i = 0; i< m_args.length (); i++)
+    {
+      sz += strlen (m_args[i]->get_debug_string ());
+      sz += 2; /* ", " separator */
+    }
+
+  /* Now allocate and populate the buffer.  */
+  char *argbuf = new char[sz];
+  size_t len = 0;
+
+  for (unsigned i = 0; i< m_args.length (); i++)
+    {
+      strcpy (argbuf + len, m_args[i]->get_debug_string ());
+      len += strlen (m_args[i]->get_debug_string ());
+      if (i + 1 < m_args.length ())
+       {
+         strcpy (argbuf + len, ", ");
+         len += 2;
+       }
+    }
+  argbuf[len] = '\0';
+
+  /* ...and use it to get the string for the call as a whole.  */
+  string *result = string::from_printf (m_ctxt,
+                                       "%s (%s)",
+                                       m_func->get_debug_string (),
+                                       argbuf);
+
+  delete[] argbuf;
+
+  return result;
+}
+
+/* The implementation of class gcc::jit::recording::call_through_ptr.  */
+
+/* The constructor for recording::call_through_ptr. */
+
+recording::call_through_ptr::call_through_ptr (recording::context *ctxt,
+                                              recording::location *loc,
+                                              recording::rvalue *fn_ptr,
+                                              int numargs,
+                                              rvalue **args)
+: rvalue (ctxt, loc,
+         fn_ptr->get_type ()->dereference ()
+           ->as_a_function_type ()->get_return_type ()),
+  m_fn_ptr (fn_ptr),
+  m_args ()
+{
+  for (int i = 0; i< numargs; i++)
+    m_args.safe_push (args[i]);
+}
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::call_through_ptr.  */
+
+void
+recording::call_through_ptr::replay_into (replayer *r)
+{
+  vec<playback::rvalue *> playback_args;
+  playback_args.create (m_args.length ());
+  for (unsigned i = 0; i< m_args.length (); i++)
+    playback_args.safe_push (m_args[i]->playback_rvalue ());
+
+  set_playback_obj (r->new_call_through_ptr (playback_location (r, m_loc),
+                                            m_fn_ptr->playback_rvalue (),
+                                            playback_args));
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   calls through function ptrs.  */
+
+recording::string *
+recording::call_through_ptr::make_debug_string ()
+{
+  /* First, build a buffer for the arguments.  */
+  /* Calculate length of said buffer.  */
+  size_t sz = 1; /* nil terminator */
+  for (unsigned i = 0; i< m_args.length (); i++)
+    {
+      sz += strlen (m_args[i]->get_debug_string ());
+      sz += 2; /* ", " separator */
+    }
+
+  /* Now allocate and populate the buffer.  */
+  char *argbuf = new char[sz];
+  size_t len = 0;
+
+  for (unsigned i = 0; i< m_args.length (); i++)
+    {
+      strcpy (argbuf + len, m_args[i]->get_debug_string ());
+      len += strlen (m_args[i]->get_debug_string ());
+      if (i + 1 < m_args.length ())
+       {
+         strcpy (argbuf + len, ", ");
+         len += 2;
+       }
+    }
+  argbuf[len] = '\0';
+
+  /* ...and use it to get the string for the call as a whole.  */
+  string *result = string::from_printf (m_ctxt,
+                                       "%s (%s)",
+                                       m_fn_ptr->get_debug_string (),
+                                       argbuf);
+
+  delete[] argbuf;
+
+  return result;
+}
+
+/* The implementation of class gcc::jit::recording::array_access.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::array_access.  */
+
+void
+recording::array_access::replay_into (replayer *r)
+{
+  set_playback_obj (
+    r->new_array_access (playback_location (r, m_loc),
+                        m_ptr->playback_rvalue (),
+                        m_index->playback_rvalue ()));
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   array accesses.  */
+
+recording::string *
+recording::array_access::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+                             "%s[%s]",
+                             m_ptr->get_debug_string (),
+                             m_index->get_debug_string ());
+}
+
+/* The implementation of class gcc::jit::recording::access_field_of_lvalue.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::access_field_of_lvalue.  */
+
+void
+recording::access_field_of_lvalue::replay_into (replayer *r)
+{
+  set_playback_obj (
+    m_lvalue->playback_lvalue ()
+      ->access_field (playback_location (r, m_loc),
+                     m_field->playback_field ()));
+
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   accessing a field of an lvalue.  */
+
+recording::string *
+recording::access_field_of_lvalue::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+                             "%s.%s",
+                             m_lvalue->get_debug_string (),
+                             m_field->get_debug_string ());
+}
+
+/* The implementation of class gcc::jit::recording::access_field_rvalue.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::access_field_rvalue.  */
+
+void
+recording::access_field_rvalue::replay_into (replayer *r)
+{
+  set_playback_obj (
+    m_rvalue->playback_rvalue ()
+      ->access_field (playback_location (r, m_loc),
+                     m_field->playback_field ()));
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   accessing a field of an rvalue.  */
+
+recording::string *
+recording::access_field_rvalue::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+                             "%s.%s",
+                             m_rvalue->get_debug_string (),
+                             m_field->get_debug_string ());
+}
+
+/* The implementation of class
+   gcc::jit::recording::dereference_field_rvalue.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::dereference_field_rvalue.  */
+
+void
+recording::dereference_field_rvalue::replay_into (replayer *r)
+{
+  set_playback_obj (
+    m_rvalue->playback_rvalue ()->
+      dereference_field (playback_location (r, m_loc),
+                        m_field->playback_field ()));
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   dereferencing a field of an rvalue.  */
+
+recording::string *
+recording::dereference_field_rvalue::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+                             "%s->%s",
+                             m_rvalue->get_debug_string (),
+                             m_field->get_debug_string ());
+}
+
+/* The implementation of class gcc::jit::recording::dereference_rvalue.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::dereference_rvalue.  */
+
+void
+recording::dereference_rvalue::replay_into (replayer *r)
+{
+  set_playback_obj (
+    m_rvalue->playback_rvalue ()->
+      dereference (playback_location (r, m_loc)));
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   dereferencing an rvalue.  */
+
+recording::string *
+recording::dereference_rvalue::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+                             "*%s",
+                             m_rvalue->get_debug_string ());
+}
+
+/* The implementation of class gcc::jit::recording::get_address_of_lvalue.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::get_address_of_lvalue.  */
+
+void
+recording::get_address_of_lvalue::replay_into (replayer *r)
+{
+  set_playback_obj (
+    m_lvalue->playback_lvalue ()->
+      get_address (playback_location (r, m_loc)));
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   getting the address of an lvalue.  */
+
+recording::string *
+recording::get_address_of_lvalue::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+                             "&%s",
+                             m_lvalue->get_debug_string ());
+}
+
+/* The implementation of class gcc::jit::recording::local.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::local.  */
+
+void
+recording::local::replay_into (replayer *r)
+{
+  set_playback_obj (
+    m_func->playback_function ()
+      ->new_local (playback_location (r, m_loc),
+                  m_type->playback_type (),
+                  playback_string (m_name)));
+}
+
+/* Override the default implementation of
+   recording::memento::write_to_dump for locals by writing
+      TYPE NAME;
+   for use at the top of the function body as if it were a
+   declaration.  */
+
+void
+recording::local::write_to_dump (dump &d)
+{
+  if (d.update_locations ())
+    m_loc = d.make_location ();
+  d.write("  %s %s;\n",
+         m_type->get_debug_string (),
+         get_debug_string ());
+}
+
+/* The implementation of class gcc::jit::recording::statement.  */
+
+/* We poison the default implementation of
+   gcc::jit::recording::statement::get_successor_blocks
+   since this vfunc must only ever be called on terminator
+   statements.  */
+
+int
+recording::statement::get_successor_blocks (block **/*out_next1*/,
+                                           block **/*out_next2*/) const
+{
+  /* The base class implementation is for non-terminating statements,
+     and thus should never be called.  */
+  gcc_unreachable ();
+  return 0;
+}
+
+/* Extend the default implementation of
+   recording::memento::write_to_dump for statements by (if requested)
+   updating the location of the statement to the current location in
+   the dumpfile.  */
+
+void
+recording::statement::write_to_dump (dump &d)
+{
+  memento::write_to_dump (d);
+  if (d.update_locations ())
+    m_loc = d.make_location ();
+}
+
+/* The implementation of class gcc::jit::recording::eval.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::eval.  */
+
+void
+recording::eval::replay_into (replayer *r)
+{
+  playback_block (get_block ())
+    ->add_eval (playback_location (r),
+               m_rvalue->playback_rvalue ());
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   an eval statement.  */
+
+recording::string *
+recording::eval::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+                             "(void)%s;",
+                             m_rvalue->get_debug_string ());
+}
+
+/* The implementation of class gcc::jit::recording::assignment.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::assignment.  */
+
+void
+recording::assignment::replay_into (replayer *r)
+{
+  playback_block (get_block ())
+    ->add_assignment (playback_location (r),
+                     m_lvalue->playback_lvalue (),
+                     m_rvalue->playback_rvalue ());
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   an assignment statement.  */
+
+recording::string *
+recording::assignment::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+                             "%s = %s;",
+                             m_lvalue->get_debug_string (),
+                             m_rvalue->get_debug_string ());
+}
+
+/* The implementation of class gcc::jit::recording::assignment_op.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::assignment_op.  */
+
+void
+recording::assignment_op::replay_into (replayer *r)
+{
+  playback::type *result_type =
+    m_lvalue->playback_lvalue ()->get_type ();
+
+  playback::rvalue *binary_op =
+    r->new_binary_op (playback_location (r),
+                     m_op,
+                     result_type,
+                     m_lvalue->playback_rvalue (),
+                     m_rvalue->playback_rvalue ());
+
+  playback_block (get_block ())
+    ->add_assignment (playback_location (r),
+                     m_lvalue->playback_lvalue (),
+                     binary_op);
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   an assignment_op statement.  */
+
+recording::string *
+recording::assignment_op::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+                             "%s %s= %s;",
+                             m_lvalue->get_debug_string (),
+                             binary_op_strings[m_op],
+                             m_rvalue->get_debug_string ());
+}
+
+/* The implementation of class gcc::jit::recording::comment.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::comment.  */
+
+void
+recording::comment::replay_into (replayer *r)
+{
+  playback_block (get_block ())
+    ->add_comment (playback_location (r),
+                  m_text->c_str ());
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   a comment "statement".  */
+
+recording::string *
+recording::comment::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+                             "/* %s */",
+                             m_text->c_str ());
+}
+
+/* The implementation of class gcc::jit::recording::conditional.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::conditional.  */
+
+void
+recording::conditional::replay_into (replayer *r)
+{
+  playback_block (get_block ())
+    ->add_conditional (playback_location (r),
+                      m_boolval->playback_rvalue (),
+                      playback_block (m_on_true),
+                      playback_block (m_on_false));
+}
+
+/* Override the poisoned default implementation of
+   gcc::jit::recording::statement::get_successor_blocks
+
+   A conditional jump has 2 successor blocks.  */
+
+int
+recording::conditional::get_successor_blocks (block **out_next1,
+                                             block **out_next2) const
+{
+  *out_next1 = m_on_true;
+  *out_next2 = m_on_false;
+  return 2;
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   a conditional jump statement.  */
+
+recording::string *
+recording::conditional::make_debug_string ()
+{
+  if (m_on_false)
+    return string::from_printf (m_ctxt,
+                               "if (%s) goto %s; else goto %s;",
+                               m_boolval->get_debug_string (),
+                               m_on_true->get_debug_string (),
+                               m_on_false->get_debug_string ());
+  else
+    return string::from_printf (m_ctxt,
+                               "if (%s) goto %s;",
+                               m_boolval->get_debug_string (),
+                               m_on_true->get_debug_string ());
+}
+
+/* The implementation of class gcc::jit::recording::jump.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::jump.  */
+
+void
+recording::jump::replay_into (replayer *r)
+{
+  playback_block (get_block ())
+    ->add_jump (playback_location (r),
+               m_target->playback_block ());
+}
+
+/* Override the poisoned default implementation of
+   gcc::jit::recording::statement::get_successor_blocks
+
+   An unconditional jump has 1 successor block.  */
+
+int
+recording::jump::get_successor_blocks (block **out_next1,
+                                      block **/*out_next2*/) const
+{
+  *out_next1 = m_target;
+  return 1;
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   a unconditional jump statement.  */
+
+recording::string *
+recording::jump::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+                             "goto %s;",
+                             m_target->get_debug_string ());
+}
+
+/* The implementation of class gcc::jit::recording::return_.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::return_.  */
+
+void
+recording::return_::replay_into (replayer *r)
+{
+  playback_block (get_block ())
+    ->add_return (playback_location (r),
+                 m_rvalue ? m_rvalue->playback_rvalue () : NULL);
+}
+
+/* Override the poisoned default implementation of
+   gcc::jit::recording::statement::get_successor_blocks
+
+   A return statement has no successor block.  */
+
+int
+recording::return_::get_successor_blocks (block **/*out_next1*/,
+                                         block **/*out_next2*/) const
+{
+  return 0;
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   a return statement (covers both those with and without rvalues).  */
+
+recording::string *
+recording::return_::make_debug_string ()
+{
+  if (m_rvalue)
+    return string::from_printf (m_ctxt,
+                               "return %s;",
+                               m_rvalue->get_debug_string ());
+  else
+    return string::from_printf (m_ctxt,
+                               "return;");
+}
+
+} // namespace gcc::jit
+
+} // namespace gcc
diff --git a/gcc/jit/jit-recording.h b/gcc/jit/jit-recording.h
new file mode 100644 (file)
index 0000000..bb1a2ee
--- /dev/null
@@ -0,0 +1,1593 @@
+/* Internals of libgccjit: classes for recording calls made to the JIT API.
+   Copyright (C) 2013-2014 Free Software Foundation, Inc.
+   Contributed by David Malcolm <dmalcolm@redhat.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef JIT_RECORDING_H
+#define JIT_RECORDING_H
+
+#include "jit-common.h"
+
+namespace gcc {
+
+namespace jit {
+
+class result;
+class dump;
+
+/**********************************************************************
+ Recording.
+ **********************************************************************/
+
+namespace recording {
+
+playback::location *
+playback_location (replayer *r, location *loc);
+
+const char *
+playback_string (string *str);
+
+playback::block *
+playback_block (block *b);
+
+/* A JIT-compilation context.  */
+class context
+{
+public:
+  context (context *parent_ctxt);
+  ~context ();
+
+  void record (memento *m);
+  void replay_into (replayer *r);
+  void disassociate_from_playback ();
+
+  string *
+  new_string (const char *text);
+
+  location *
+  new_location (const char *filename,
+               int line,
+               int column);
+
+  type *
+  get_type (enum gcc_jit_types type);
+
+  type *
+  get_int_type (int num_bytes, int is_signed);
+
+  type *
+  new_array_type (location *loc,
+                 type *element_type,
+                 int num_elements);
+
+  field *
+  new_field (location *loc,
+            type *type,
+            const char *name);
+
+  struct_ *
+  new_struct_type (location *loc,
+                  const char *name);
+
+  union_ *
+  new_union_type (location *loc,
+                 const char *name);
+
+  type *
+  new_function_ptr_type (location *loc,
+                        type *return_type,
+                        int num_params,
+                        type **param_types,
+                        int is_variadic);
+
+  param *
+  new_param (location *loc,
+            type *type,
+            const char *name);
+
+  function *
+  new_function (location *loc,
+               enum gcc_jit_function_kind kind,
+               type *return_type,
+               const char *name,
+               int num_params,
+               param **params,
+               int is_variadic,
+               enum built_in_function builtin_id);
+
+  function *
+  get_builtin_function (const char *name);
+
+  lvalue *
+  new_global (location *loc,
+             type *type,
+             const char *name);
+
+  rvalue *
+  new_rvalue_from_int (type *numeric_type,
+                      int value);
+
+  rvalue *
+  new_rvalue_from_double (type *numeric_type,
+                         double value);
+
+  rvalue *
+  new_rvalue_from_ptr (type *pointer_type,
+                      void *value);
+
+  rvalue *
+  new_string_literal (const char *value);
+
+  rvalue *
+  new_unary_op (location *loc,
+               enum gcc_jit_unary_op op,
+               type *result_type,
+               rvalue *a);
+
+  rvalue *
+  new_binary_op (location *loc,
+                enum gcc_jit_binary_op op,
+                type *result_type,
+                rvalue *a, rvalue *b);
+
+  rvalue *
+  new_comparison (location *loc,
+                 enum gcc_jit_comparison op,
+                 rvalue *a, rvalue *b);
+
+  rvalue *
+  new_call (location *loc,
+           function *func,
+           int numargs, rvalue **args);
+
+  rvalue *
+  new_call_through_ptr (location *loc,
+                       rvalue *fn_ptr,
+                       int numargs, rvalue **args);
+
+  rvalue *
+  new_cast (location *loc,
+           rvalue *expr,
+           type *type_);
+
+  lvalue *
+  new_array_access (location *loc,
+                   rvalue *ptr,
+                   rvalue *index);
+
+  void
+  set_str_option (enum gcc_jit_str_option opt,
+                 const char *value);
+
+  void
+  set_int_option (enum gcc_jit_int_option opt,
+                 int value);
+
+  void
+  set_bool_option (enum gcc_jit_bool_option opt,
+                  int value);
+
+  const char *
+  get_str_option (enum gcc_jit_str_option opt) const
+  {
+    return m_str_options[opt];
+  }
+
+  int
+  get_int_option (enum gcc_jit_int_option opt) const
+  {
+    return m_int_options[opt];
+  }
+
+  int
+  get_bool_option (enum gcc_jit_bool_option opt) const
+  {
+    return m_bool_options[opt];
+  }
+
+  result *
+  compile ();
+
+  void
+  add_error (location *loc, const char *fmt, ...)
+      GNU_PRINTF(3, 4);
+
+  void
+  add_error_va (location *loc, const char *fmt, va_list ap)
+      GNU_PRINTF(3, 0);
+
+  const char *
+  get_first_error () const;
+
+  bool errors_occurred () const
+  {
+    if (m_parent_ctxt)
+      if (m_parent_ctxt->errors_occurred ())
+       return true;
+    return m_error_count;
+  }
+
+  type *get_opaque_FILE_type ();
+
+  void dump_to_file (const char *path, bool update_locations);
+
+private:
+  void validate ();
+
+private:
+  context *m_parent_ctxt;
+
+  int m_error_count;
+
+  char *m_first_error_str;
+  bool m_owns_first_error_str;
+
+  const char *m_str_options[GCC_JIT_NUM_STR_OPTIONS];
+  int m_int_options[GCC_JIT_NUM_INT_OPTIONS];
+  bool m_bool_options[GCC_JIT_NUM_BOOL_OPTIONS];
+
+  /* Recorded API usage.  */
+  vec<memento *> m_mementos;
+
+  /* Specific recordings, for use by dump_to_file.  */
+  vec<compound_type *> m_compound_types;
+  vec<function *> m_functions;
+
+  type *m_basic_types[NUM_GCC_JIT_TYPES];
+  type *m_FILE_type;
+
+  builtins_manager *m_builtins_manager; // lazily created
+};
+
+
+/* An object with lifetime managed by the context i.e.
+   it lives until the context is released, at which
+   point it itself is cleaned up.  */
+
+class memento
+{
+public:
+  virtual ~memento () {}
+
+  /* Hook for replaying this.  */
+  virtual void replay_into (replayer *r) = 0;
+
+  void set_playback_obj (void *obj) { m_playback_obj = obj; }
+
+
+  /* Get the context that owns this object.
+
+     Implements the post-error-checking part of
+     gcc_jit_object_get_context.  */
+  context *get_context () { return m_ctxt; }
+
+  memento *
+  as_object () { return this; }
+
+  /* Debugging hook, for use in generating error messages etc.
+     Implements the post-error-checking part of
+     gcc_jit_object_get_debug_string.  */
+  const char *
+  get_debug_string ();
+
+  virtual void write_to_dump (dump &d);
+
+protected:
+  memento (context *ctxt)
+  : m_ctxt (ctxt),
+    m_playback_obj (NULL),
+    m_debug_string (NULL)
+  {
+    gcc_assert (ctxt);
+  }
+
+  string *new_string (const char *text) { return m_ctxt->new_string (text); }
+
+private:
+  virtual string * make_debug_string () = 0;
+
+public:
+  context *m_ctxt;
+
+protected:
+  void *m_playback_obj;
+
+private:
+  string *m_debug_string;
+};
+
+/* or just use std::string? */
+class string : public memento
+{
+public:
+  string (context *ctxt, const char *text);
+  ~string ();
+
+  const char *c_str () { return m_buffer; }
+
+  static string * from_printf (context *ctxt, const char *fmt, ...)
+    GNU_PRINTF(2, 3);
+
+  void replay_into (replayer *) {}
+
+private:
+  string * make_debug_string ();
+
+private:
+  size_t m_len;
+  char *m_buffer;
+};
+
+class location : public memento
+{
+public:
+  location (context *ctxt, string *filename, int line, int column)
+  : memento (ctxt),
+    m_filename (filename),
+    m_line (line),
+    m_column (column)
+ {}
+
+  void replay_into (replayer *r);
+
+  playback::location *
+  playback_location (replayer *r)
+  {
+    /* Normally during playback, we can walk forwards through the list of
+       recording objects, playing them back.  The ordering of recording
+       ensures that everything that a recording object refers to has
+       already been played back, so we can simply look up the relevant
+       m_playback_obj.
+
+       Locations are an exception, due to the "write_to_dump" method of
+       recording::statement.  This method can set a new location on a
+       statement after the statement is created, and thus the location
+       appears in the context's memento list *after* the statement that
+       refers to it.
+
+       In such circumstances, the statement is replayed *before* the location,
+       when the latter doesn't yet have a playback object.
+
+       Hence we need to ensure that locations have playback objects.  */
+    if (!m_playback_obj)
+      {
+       replay_into (r);
+      }
+    gcc_assert (m_playback_obj);
+    return static_cast <playback::location *> (m_playback_obj);
+  }
+
+private:
+  string * make_debug_string ();
+
+private:
+  string *m_filename;
+  int m_line;
+  int m_column;
+};
+
+class type : public memento
+{
+public:
+  type *get_pointer ();
+  type *get_const ();
+  type *get_volatile ();
+
+  /* Get the type obtained when dereferencing this type.
+
+     This will return NULL if it's not valid to dereference this type.
+     The caller is responsible for setting an error.  */
+  virtual type *dereference () = 0;
+
+  /* Dynamic casts.  */
+  virtual function_type *dyn_cast_function_type () { return NULL; }
+  virtual function_type *as_a_function_type() { gcc_unreachable (); return NULL; }
+  virtual struct_ *dyn_cast_struct () { return NULL; }
+
+  /* Is it typesafe to copy to this type from rtype?  */
+  virtual bool accepts_writes_from (type *rtype)
+  {
+    gcc_assert (rtype);
+    return this == rtype->unqualified ();
+  }
+
+  /* Strip off "const" etc */
+  virtual type *unqualified ()
+  {
+    return this;
+  }
+
+  virtual bool is_int () const = 0;
+  virtual bool is_float () const = 0;
+  virtual bool is_bool () const = 0;
+  virtual type *is_pointer () = 0;
+  virtual type *is_array () = 0;
+
+  bool is_numeric () const
+  {
+    return is_int () || is_float () || is_bool ();
+  }
+
+  playback::type *
+  playback_type ()
+  {
+    return static_cast <playback::type *> (m_playback_obj);
+  }
+
+protected:
+  type (context *ctxt)
+    : memento (ctxt),
+    m_pointer_to_this_type (NULL)
+  {}
+
+private:
+  type *m_pointer_to_this_type;
+};
+
+/* Result of "gcc_jit_type_get_type".  */
+class memento_of_get_type : public type
+{
+public:
+  memento_of_get_type (context *ctxt,
+                      enum gcc_jit_types kind)
+  : type (ctxt),
+    m_kind (kind) {}
+
+  type *dereference ();
+
+  bool accepts_writes_from (type *rtype)
+  {
+    if (m_kind == GCC_JIT_TYPE_VOID_PTR)
+      if (rtype->is_pointer ())
+       {
+         /* LHS (this) is type (void *), and the RHS is a pointer:
+            accept it:  */
+         return true;
+       }
+
+    return type::accepts_writes_from (rtype);
+  }
+
+  bool is_int () const;
+  bool is_float () const;
+  bool is_bool () const;
+  type *is_pointer () { return dereference (); }
+  type *is_array () { return NULL; }
+
+public:
+  void replay_into (replayer *r);
+
+private:
+  string * make_debug_string ();
+
+private:
+  enum gcc_jit_types m_kind;
+};
+
+/* Result of "gcc_jit_type_get_pointer".  */
+class memento_of_get_pointer : public type
+{
+public:
+  memento_of_get_pointer (type *other_type)
+  : type (other_type->m_ctxt),
+    m_other_type (other_type) {}
+
+  type *dereference () { return m_other_type; }
+
+  bool accepts_writes_from (type *rtype);
+
+  void replay_into (replayer *r);
+
+  bool is_int () const { return false; }
+  bool is_float () const { return false; }
+  bool is_bool () const { return false; }
+  type *is_pointer () { return m_other_type; }
+  type *is_array () { return NULL; }
+
+private:
+  string * make_debug_string ();
+
+private:
+  type *m_other_type;
+};
+
+/* Result of "gcc_jit_type_get_const".  */
+class memento_of_get_const : public type
+{
+public:
+  memento_of_get_const (type *other_type)
+  : type (other_type->m_ctxt),
+    m_other_type (other_type) {}
+
+  type *dereference () { return m_other_type->dereference (); }
+
+  bool accepts_writes_from (type */*rtype*/)
+  {
+    /* Can't write to a "const".  */
+    return false;
+  }
+
+  /* Strip off the "const", giving the underlying type.  */
+  type *unqualified () { return m_other_type; }
+
+  bool is_int () const { return m_other_type->is_int (); }
+  bool is_float () const { return m_other_type->is_float (); }
+  bool is_bool () const { return m_other_type->is_bool (); }
+  type *is_pointer () { return m_other_type->is_pointer (); }
+  type *is_array () { return m_other_type->is_array (); }
+
+  void replay_into (replayer *);
+
+private:
+  string * make_debug_string ();
+
+private:
+  type *m_other_type;
+};
+
+/* Result of "gcc_jit_type_get_volatile".  */
+class memento_of_get_volatile : public type
+{
+public:
+  memento_of_get_volatile (type *other_type)
+  : type (other_type->m_ctxt),
+    m_other_type (other_type) {}
+
+  type *dereference () { return m_other_type->dereference (); }
+
+  /* Strip off the "volatile", giving the underlying type.  */
+  type *unqualified () { return m_other_type; }
+
+  bool is_int () const { return m_other_type->is_int (); }
+  bool is_float () const { return m_other_type->is_float (); }
+  bool is_bool () const { return m_other_type->is_bool (); }
+  type *is_pointer () { return m_other_type->is_pointer (); }
+  type *is_array () { return m_other_type->is_array (); }
+
+  void replay_into (replayer *);
+
+private:
+  string * make_debug_string ();
+
+private:
+  type *m_other_type;
+};
+
+class array_type : public type
+{
+ public:
+  array_type (context *ctxt,
+             location *loc,
+             type *element_type,
+             int num_elements)
+  : type (ctxt),
+    m_loc (loc),
+    m_element_type (element_type),
+    m_num_elements (num_elements)
+  {}
+
+  type *dereference ();
+
+  bool is_int () const { return false; }
+  bool is_float () const { return false; }
+  bool is_bool () const { return false; }
+  type *is_pointer () { return NULL; }
+  type *is_array () { return m_element_type; }
+
+  void replay_into (replayer *);
+
+ private:
+  string * make_debug_string ();
+
+ private:
+  location *m_loc;
+  type *m_element_type;
+  int m_num_elements;
+};
+
+class function_type : public type
+{
+public:
+  function_type (context *ctxt,
+                type *return_type,
+                int num_params,
+                type **param_types,
+                int is_variadic);
+
+  type *dereference ();
+  function_type *dyn_cast_function_type () { return this; }
+  function_type *as_a_function_type () { return this; }
+
+  bool is_int () const { return false; }
+  bool is_float () const { return false; }
+  bool is_bool () const { return false; }
+  type *is_pointer () { return NULL; }
+  type *is_array () { return NULL; }
+
+  void replay_into (replayer *);
+
+  type * get_return_type () const { return m_return_type; }
+  vec<type *> get_param_types () const { return m_param_types; }
+  int is_variadic () const { return m_is_variadic; }
+
+  string * make_debug_string_with_ptr ();
+
+ private:
+  string * make_debug_string ();
+  string * make_debug_string_with (const char *);
+
+private:
+  type *m_return_type;
+  vec<type *> m_param_types;
+  int m_is_variadic;
+};
+
+class field : public memento
+{
+public:
+  field (context *ctxt,
+        location *loc,
+        type *type,
+        string *name)
+  : memento (ctxt),
+    m_loc (loc),
+    m_type (type),
+    m_name (name),
+    m_container (NULL)
+  {}
+
+  type * get_type () const { return m_type; }
+
+  compound_type * get_container () const { return m_container; }
+  void set_container (compound_type *c) { m_container = c; }
+
+  void replay_into (replayer *);
+
+  void write_to_dump (dump &d);
+
+  playback::field *
+  playback_field () const
+  {
+    return static_cast <playback::field *> (m_playback_obj);
+  }
+
+private:
+  string * make_debug_string ();
+
+private:
+  location *m_loc;
+  type *m_type;
+  string *m_name;
+  compound_type *m_container;
+};
+
+/* Base class for struct_ and union_ */
+class compound_type : public type
+{
+public:
+  compound_type (context *ctxt,
+                location *loc,
+                string *name);
+
+  string *get_name () const { return m_name; }
+  location *get_loc () const { return m_loc; }
+  fields * get_fields () { return m_fields; }
+
+  void
+  set_fields (location *loc,
+             int num_fields,
+             field **fields);
+
+  type *dereference ();
+
+  bool is_int () const { return false; }
+  bool is_float () const { return false; }
+  bool is_bool () const { return false; }
+  type *is_pointer () { return NULL; }
+  type *is_array () { return NULL; }
+
+  playback::compound_type *
+  playback_compound_type ()
+  {
+    return static_cast <playback::compound_type *> (m_playback_obj);
+  }
+
+private:
+  location *m_loc;
+  string *m_name;
+  fields *m_fields;
+};
+
+class struct_ : public compound_type
+{
+public:
+  struct_ (context *ctxt,
+          location *loc,
+          string *name);
+
+  struct_ *dyn_cast_struct () { return this; }
+
+  type *
+  as_type () { return this; }
+
+  void replay_into (replayer *r);
+
+private:
+  string * make_debug_string ();
+
+};
+
+// memento of struct_::set_fields
+class fields : public memento
+{
+public:
+  fields (compound_type *struct_or_union,
+         int num_fields,
+         field **fields);
+
+  void replay_into (replayer *r);
+
+  void write_to_dump (dump &d);
+
+private:
+  string * make_debug_string ();
+
+private:
+  compound_type *m_struct_or_union;
+  vec<field *> m_fields;
+};
+
+class union_ : public compound_type
+{
+public:
+  union_ (context *ctxt,
+         location *loc,
+         string *name);
+
+  void replay_into (replayer *r);
+
+private:
+  string * make_debug_string ();
+
+private:
+  location *m_loc;
+  string *m_name;
+  fields *m_fields;
+};
+
+class rvalue : public memento
+{
+public:
+  rvalue (context *ctxt,
+         location *loc,
+         type *type_)
+  : memento (ctxt),
+    m_loc (loc),
+    m_type (type_)
+  {
+    gcc_assert (type_);
+  }
+
+  /* Get the recording::type of this rvalue.
+
+     Implements the post-error-checking part of
+     gcc_jit_rvalue_get_type.  */
+  type * get_type () const { return m_type; }
+
+  playback::rvalue *
+  playback_rvalue () const
+  {
+    return static_cast <playback::rvalue *> (m_playback_obj);
+  }
+  rvalue *
+  access_field (location *loc,
+               field *field);
+
+  lvalue *
+  dereference_field (location *loc,
+                    field *field);
+
+  lvalue *
+  dereference (location *loc);
+
+protected:
+  location *m_loc;
+  type *m_type;
+};
+
+class lvalue : public rvalue
+{
+public:
+  lvalue (context *ctxt,
+         location *loc,
+         type *type_)
+    : rvalue (ctxt, loc, type_)
+    {}
+
+  playback::lvalue *
+  playback_lvalue () const
+  {
+    return static_cast <playback::lvalue *> (m_playback_obj);
+  }
+
+  lvalue *
+  access_field (location *loc,
+               field *field);
+
+  rvalue *
+  get_address (location *loc);
+
+  rvalue *
+  as_rvalue () { return this; }
+};
+
+class param : public lvalue
+{
+public:
+  param (context *ctxt,
+        location *loc,
+        type *type,
+        string *name)
+    : lvalue (ctxt, loc, type),
+    m_name (name) {}
+
+  lvalue *
+  as_lvalue () { return this; }
+
+  void replay_into (replayer *r);
+
+  playback::param *
+  playback_param () const
+  {
+    return static_cast <playback::param *> (m_playback_obj);
+  }
+
+private:
+  string * make_debug_string () { return m_name; }
+
+private:
+  string *m_name;
+};
+
+class function : public memento
+{
+public:
+  function (context *ctxt,
+           location *loc,
+           enum gcc_jit_function_kind kind,
+           type *return_type,
+           string *name,
+           int num_params,
+           param **params,
+           int is_variadic,
+           enum built_in_function builtin_id);
+
+  void replay_into (replayer *r);
+
+  playback::function *
+  playback_function () const
+  {
+    return static_cast <playback::function *> (m_playback_obj);
+  }
+
+  enum gcc_jit_function_kind get_kind () const { return m_kind; }
+
+  lvalue *
+  new_local (location *loc,
+            type *type,
+            const char *name);
+
+  block*
+  new_block (const char *name);
+
+  type *get_return_type () const { return m_return_type; }
+  string * get_name () const { return m_name; }
+  vec<param *> get_params () const { return m_params; }
+
+  /* Get the given param by index.
+     Implements the post-error-checking part of
+     gcc_jit_function_get_param.  */
+  param *get_param (int i) const { return m_params[i]; }
+
+  bool is_variadic () const { return m_is_variadic; }
+
+  void write_to_dump (dump &d);
+
+  void validate ();
+
+  void dump_to_dot (const char *path);
+
+private:
+  string * make_debug_string ();
+
+private:
+  location *m_loc;
+  enum gcc_jit_function_kind m_kind;
+  type *m_return_type;
+  string *m_name;
+  vec<param *> m_params;
+  int m_is_variadic;
+  enum built_in_function m_builtin_id;
+  vec<local *> m_locals;
+  vec<block *> m_blocks;
+};
+
+class block : public memento
+{
+public:
+  block (function *func, int index, string *name)
+  : memento (func->m_ctxt),
+    m_func (func),
+    m_index (index),
+    m_name (name),
+    m_statements (),
+    m_has_been_terminated (false),
+    m_is_reachable (false)
+  {
+  }
+
+  /* Get the recording::function containing this block.
+     Implements the post-error-checking part of
+     gcc_jit_block_get_function.  */
+  function *get_function () { return m_func; }
+
+  bool has_been_terminated () { return m_has_been_terminated; }
+  bool is_reachable () { return m_is_reachable; }
+
+  void
+  add_eval (location *loc,
+           rvalue *rvalue);
+
+  void
+  add_assignment (location *loc,
+                 lvalue *lvalue,
+                 rvalue *rvalue);
+
+  void
+  add_assignment_op (location *loc,
+                    lvalue *lvalue,
+                    enum gcc_jit_binary_op op,
+                    rvalue *rvalue);
+
+  void
+  add_comment (location *loc,
+              const char *text);
+
+  void
+  end_with_conditional (location *loc,
+                       rvalue *boolval,
+                       block *on_true,
+                       block *on_false);
+
+  void
+  end_with_jump (location *loc,
+                block *target);
+
+  void
+  end_with_return (location *loc,
+                  rvalue *rvalue);
+
+  playback::block *
+  playback_block () const
+  {
+    return static_cast <playback::block *> (m_playback_obj);
+  }
+
+  void write_to_dump (dump &d);
+
+  bool validate ();
+
+  location *get_loc () const;
+
+  statement *get_first_statement () const;
+  statement *get_last_statement () const;
+
+  int get_successor_blocks (block **next1, block **next2) const;
+
+private:
+  string * make_debug_string ();
+
+  void replay_into (replayer *r);
+
+  void dump_to_dot (pretty_printer *pp);
+  void dump_edges_to_dot (pretty_printer *pp);
+
+private:
+  function *m_func;
+  int m_index;
+  string *m_name;
+  vec<statement *> m_statements;
+  bool m_has_been_terminated;
+  bool m_is_reachable;
+
+  friend class function;
+};
+
+class global : public lvalue
+{
+public:
+  global (context *ctxt,
+         location *loc,
+         type *type,
+         string *name)
+  : lvalue (ctxt, loc, type),
+    m_name (name)
+  {}
+
+  void replay_into (replayer *);
+
+private:
+  string * make_debug_string () { return m_name; }
+
+private:
+  string *m_name;
+};
+
+class memento_of_new_rvalue_from_int : public rvalue
+{
+public:
+  memento_of_new_rvalue_from_int (context *ctxt,
+                                 location *loc,
+                                 type *numeric_type,
+                                 int value)
+  : rvalue (ctxt, loc, numeric_type),
+    m_value (value) {}
+
+  void replay_into (replayer *r);
+
+private:
+  string * make_debug_string ();
+
+private:
+  int m_value;
+};
+
+class memento_of_new_rvalue_from_double : public rvalue
+{
+public:
+  memento_of_new_rvalue_from_double (context *ctxt,
+                                    location *loc,
+                                    type *numeric_type,
+                                    double value)
+  : rvalue (ctxt, loc, numeric_type),
+    m_value (value)
+  {}
+
+  void replay_into (replayer *);
+
+private:
+  string * make_debug_string ();
+
+private:
+  double m_value;
+};
+
+class memento_of_new_rvalue_from_ptr : public rvalue
+{
+public:
+  memento_of_new_rvalue_from_ptr (context *ctxt,
+                                 location *loc,
+                                 type *pointer_type,
+                                 void *value)
+  : rvalue (ctxt, loc, pointer_type),
+    m_value (value)
+  {}
+
+  void replay_into (replayer *);
+
+private:
+  string * make_debug_string ();
+
+private:
+  void *m_value;
+};
+
+class memento_of_new_string_literal : public rvalue
+{
+public:
+  memento_of_new_string_literal (context *ctxt,
+                                location *loc,
+                                string *value)
+  : rvalue (ctxt, loc, ctxt->get_type (GCC_JIT_TYPE_CONST_CHAR_PTR)),
+    m_value (value) {}
+
+  void replay_into (replayer *r);
+
+private:
+  string * make_debug_string ();
+
+private:
+  string *m_value;
+};
+
+class unary_op : public rvalue
+{
+public:
+  unary_op (context *ctxt,
+           location *loc,
+           enum gcc_jit_unary_op op,
+           type *result_type,
+           rvalue *a)
+  : rvalue (ctxt, loc, result_type),
+    m_op (op),
+    m_a (a)
+  {}
+
+  void replay_into (replayer *r);
+
+private:
+  string * make_debug_string ();
+
+private:
+  enum gcc_jit_unary_op m_op;
+  rvalue *m_a;
+};
+
+class binary_op : public rvalue
+{
+public:
+  binary_op (context *ctxt,
+            location *loc,
+            enum gcc_jit_binary_op op,
+            type *result_type,
+            rvalue *a, rvalue *b)
+  : rvalue (ctxt, loc, result_type),
+    m_op (op),
+    m_a (a),
+    m_b (b) {}
+
+  void replay_into (replayer *r);
+
+private:
+  string * make_debug_string ();
+
+private:
+  enum gcc_jit_binary_op m_op;
+  rvalue *m_a;
+  rvalue *m_b;
+};
+
+class comparison : public rvalue
+{
+public:
+  comparison (context *ctxt,
+             location *loc,
+             enum gcc_jit_comparison op,
+             rvalue *a, rvalue *b)
+  : rvalue (ctxt, loc, ctxt->get_type (GCC_JIT_TYPE_BOOL)),
+    m_op (op),
+    m_a (a),
+    m_b (b)
+  {}
+
+  void replay_into (replayer *r);
+
+private:
+  string * make_debug_string ();
+
+private:
+  enum gcc_jit_comparison m_op;
+  rvalue *m_a;
+  rvalue *m_b;
+};
+
+class cast : public rvalue
+{
+public:
+  cast (context *ctxt,
+       location *loc,
+       rvalue *a,
+       type *type_)
+  : rvalue (ctxt, loc, type_),
+    m_rvalue (a)
+  {}
+
+  void replay_into (replayer *r);
+
+private:
+  string * make_debug_string ();
+
+private:
+  rvalue *m_rvalue;
+};
+
+class call : public rvalue
+{
+public:
+  call (context *ctxt,
+       location *loc,
+       function *func,
+       int numargs,
+       rvalue **args);
+
+  void replay_into (replayer *r);
+
+private:
+  string * make_debug_string ();
+
+private:
+  function *m_func;
+  vec<rvalue *> m_args;
+};
+
+class call_through_ptr : public rvalue
+{
+public:
+  call_through_ptr (context *ctxt,
+                   location *loc,
+                   rvalue *fn_ptr,
+                   int numargs,
+                   rvalue **args);
+
+  void replay_into (replayer *r);
+
+private:
+  string * make_debug_string ();
+
+private:
+  rvalue *m_fn_ptr;
+  vec<rvalue *> m_args;
+};
+
+class array_access : public lvalue
+{
+public:
+  array_access (context *ctxt,
+               location *loc,
+               rvalue *ptr,
+               rvalue *index)
+  : lvalue (ctxt, loc, ptr->get_type ()->dereference ()),
+    m_ptr (ptr),
+    m_index (index)
+  {}
+
+  void replay_into (replayer *r);
+
+private:
+  string * make_debug_string ();
+
+private:
+  rvalue *m_ptr;
+  rvalue *m_index;
+};
+
+class access_field_of_lvalue : public lvalue
+{
+public:
+  access_field_of_lvalue (context *ctxt,
+                         location *loc,
+                         lvalue *val,
+                         field *field)
+  : lvalue (ctxt, loc, field->get_type ()),
+    m_lvalue (val),
+    m_field (field)
+  {}
+
+  void replay_into (replayer *r);
+
+private:
+  string * make_debug_string ();
+
+private:
+  lvalue *m_lvalue;
+  field *m_field;
+};
+
+class access_field_rvalue : public rvalue
+{
+public:
+  access_field_rvalue (context *ctxt,
+                      location *loc,
+                      rvalue *val,
+                      field *field)
+  : rvalue (ctxt, loc, field->get_type ()),
+    m_rvalue (val),
+    m_field (field)
+  {}
+
+  void replay_into (replayer *r);
+
+private:
+  string * make_debug_string ();
+
+private:
+  rvalue *m_rvalue;
+  field *m_field;
+};
+
+class dereference_field_rvalue : public lvalue
+{
+public:
+  dereference_field_rvalue (context *ctxt,
+                           location *loc,
+                           rvalue *val,
+                           field *field)
+  : lvalue (ctxt, loc, field->get_type ()),
+    m_rvalue (val),
+    m_field (field)
+  {}
+
+  void replay_into (replayer *r);
+
+private:
+  string * make_debug_string ();
+
+private:
+  rvalue *m_rvalue;
+  field *m_field;
+};
+
+class dereference_rvalue : public lvalue
+{
+public:
+  dereference_rvalue (context *ctxt,
+                     location *loc,
+                     rvalue *val)
+  : lvalue (ctxt, loc, val->get_type ()->dereference ()),
+    m_rvalue (val) {}
+
+  void replay_into (replayer *r);
+
+private:
+  string * make_debug_string ();
+
+private:
+  rvalue *m_rvalue;
+};
+
+class get_address_of_lvalue : public rvalue
+{
+public:
+  get_address_of_lvalue (context *ctxt,
+                        location *loc,
+                        lvalue *val)
+  : rvalue (ctxt, loc, val->get_type ()->get_pointer ()),
+    m_lvalue (val)
+  {}
+
+  void replay_into (replayer *r);
+
+private:
+  string * make_debug_string ();
+
+private:
+  lvalue *m_lvalue;
+};
+
+class local : public lvalue
+{
+public:
+  local (function *func, location *loc, type *type_, string *name)
+    : lvalue (func->m_ctxt, loc, type_),
+    m_func (func),
+    m_name (name) {}
+
+  void replay_into (replayer *r);
+
+  void write_to_dump (dump &d);
+
+private:
+  string * make_debug_string () { return m_name; }
+
+private:
+  function *m_func;
+  string *m_name;
+};
+
+class statement : public memento
+{
+public:
+  virtual int get_successor_blocks (block **out_next1,
+                                   block **out_next2) const;
+
+  void write_to_dump (dump &d);
+
+  location *get_loc () const { return m_loc; }
+
+protected:
+  statement (block *b, location *loc)
+  : memento (b->m_ctxt),
+    m_block (b),
+    m_loc (loc) {}
+
+  block *get_block () const { return m_block; }
+
+  playback::location *
+  playback_location (replayer *r) const
+  {
+    return ::gcc::jit::recording::playback_location (r, m_loc);
+  }
+
+private:
+  block *m_block;
+  location *m_loc;
+};
+
+class eval : public statement
+{
+public:
+  eval (block *b,
+       location *loc,
+       rvalue *rvalue)
+  : statement (b, loc),
+    m_rvalue (rvalue) {}
+
+  void replay_into (replayer *r);
+
+private:
+  string * make_debug_string ();
+
+private:
+  rvalue *m_rvalue;
+};
+
+class assignment : public statement
+{
+public:
+  assignment (block *b,
+             location *loc,
+             lvalue *lvalue,
+             rvalue *rvalue)
+  : statement (b, loc),
+    m_lvalue (lvalue),
+    m_rvalue (rvalue) {}
+
+  void replay_into (replayer *r);
+
+private:
+  string * make_debug_string ();
+
+private:
+  lvalue *m_lvalue;
+  rvalue *m_rvalue;
+};
+
+class assignment_op : public statement
+{
+public:
+  assignment_op (block *b,
+                location *loc,
+                lvalue *lvalue,
+                enum gcc_jit_binary_op op,
+                rvalue *rvalue)
+  : statement (b, loc),
+    m_lvalue (lvalue),
+    m_op (op),
+    m_rvalue (rvalue) {}
+
+  void replay_into (replayer *r);
+
+private:
+  string * make_debug_string ();
+
+private:
+  lvalue *m_lvalue;
+  enum gcc_jit_binary_op m_op;
+  rvalue *m_rvalue;
+};
+
+class comment : public statement
+{
+public:
+  comment (block *b,
+          location *loc,
+          string *text)
+  : statement (b, loc),
+    m_text (text) {}
+
+  void replay_into (replayer *r);
+
+private:
+  string * make_debug_string ();
+
+private:
+  string *m_text;
+};
+
+class conditional : public statement
+{
+public:
+  conditional (block *b,
+              location *loc,
+              rvalue *boolval,
+              block *on_true,
+              block *on_false)
+  : statement (b, loc),
+    m_boolval (boolval),
+    m_on_true (on_true),
+    m_on_false (on_false) {}
+
+  void replay_into (replayer *r);
+
+  int get_successor_blocks (block **out_next1,
+                           block **out_next2) const;
+
+private:
+  string * make_debug_string ();
+
+private:
+  rvalue *m_boolval;
+  block *m_on_true;
+  block *m_on_false;
+};
+
+class jump : public statement
+{
+public:
+  jump (block *b,
+       location *loc,
+       block *target)
+  : statement (b, loc),
+    m_target (target) {}
+
+  void replay_into (replayer *r);
+
+  int get_successor_blocks (block **out_next1,
+                           block **out_next2) const;
+
+private:
+  string * make_debug_string ();
+
+private:
+  block *m_target;
+};
+
+class return_ : public statement
+{
+public:
+  return_ (block *b,
+          location *loc,
+          rvalue *rvalue)
+  : statement (b, loc),
+    m_rvalue (rvalue) {}
+
+  void replay_into (replayer *r);
+
+  int get_successor_blocks (block **out_next1,
+                           block **out_next2) const;
+
+private:
+  string * make_debug_string ();
+
+private:
+  rvalue *m_rvalue;
+};
+
+} // namespace gcc::jit::recording
+
+/* The result of JIT-compilation.  */
+class result
+{
+public:
+  result(void *dso_handle);
+
+  virtual ~result();
+
+  void *
+  get_code (const char *funcname);
+
+private:
+  void *m_dso_handle;
+};
+
+} // namespace gcc::jit
+
+} // namespace gcc
+
+#endif /* JIT_RECORDING_H */
+
diff --git a/gcc/jit/libgccjit++.h b/gcc/jit/libgccjit++.h
new file mode 100644 (file)
index 0000000..67ed5d5
--- /dev/null
@@ -0,0 +1,1574 @@
+/* A C++ API for libgccjit, purely as inline wrapper functions.
+   Copyright (C) 2014 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef LIBGCCJIT_PLUS_PLUS_H
+#define LIBGCCJIT_PLUS_PLUS_H
+
+#include "libgccjit.h"
+
+#include <limits>
+#include <ostream>
+#include <vector>
+
+/****************************************************************************
+ C++ API
+ ****************************************************************************/
+
+namespace gccjit
+{
+  class context;
+  class location;
+  class field;
+  class type;
+  class struct_;
+  class param;
+  class function;
+  class block;
+  class rvalue;
+  class lvalue;
+
+  /* Errors within the API become C++ exceptions of this class.  */
+  class error
+  {
+  };
+
+  class object
+  {
+  public:
+    context get_context () const;
+
+    std::string get_debug_string () const;
+
+  protected:
+    object ();
+    object (gcc_jit_object *obj);
+
+    gcc_jit_object *get_inner_object () const;
+
+  private:
+    gcc_jit_object *m_inner_obj;
+  };
+
+  inline std::ostream& operator << (std::ostream& stream, const object &obj);
+
+  /* Some client code will want to supply source code locations, others
+     won't.  To avoid doubling the number of entrypoints, everything
+     accepting a location also has a default argument.  To do this, the
+     other classes need to see that "location" has a default constructor,
+     hence we need to declare it first.  */
+  class location : public object
+  {
+  public:
+    location ();
+    location (gcc_jit_location *loc);
+
+    gcc_jit_location *get_inner_location () const;
+  };
+
+  class context
+  {
+  public:
+    static context acquire ();
+    context ();
+    context (gcc_jit_context *ctxt);
+
+    gccjit::context new_child_context ();
+
+    gcc_jit_context *get_inner_context () { return m_inner_ctxt; }
+
+    void release ();
+
+    gcc_jit_result *compile ();
+
+    void dump_to_file (const std::string &path,
+                      bool update_locations);
+
+    void set_int_option (enum gcc_jit_int_option opt,
+                        int value);
+
+    void set_bool_option (enum gcc_jit_bool_option opt,
+                         int value);
+
+    location
+    new_location (const std::string &filename,
+                 int line,
+                 int column);
+
+    type get_type (enum gcc_jit_types kind);
+    type get_int_type (size_t num_bytes, int is_signed);
+
+    /* A way to map a specific int type, using the compiler to
+       get the details automatically e.g.:
+         gccjit::type type = get_int_type <my_int_type_t> ();  */
+    template <typename T>
+    type get_int_type ();
+
+    type new_array_type (type element_type, int num_elements,
+                        location loc = location ());
+
+    field new_field (type type_, const std::string &name,
+                    location loc = location ());
+
+    struct_ new_struct_type (const std::string &name,
+                            std::vector<field> &fields,
+                            location loc = location ());
+
+    struct_ new_opaque_struct_type (const std::string &name,
+                                   location loc = location ());
+
+    param new_param (type type_,
+                    const std::string &name,
+                    location loc = location ());
+
+    function new_function (enum gcc_jit_function_kind kind,
+                          type return_type,
+                          const std::string &name,
+                          std::vector<param> &params,
+                          int is_variadic,
+                          location loc = location ());
+
+    function get_builtin_function (const std::string &name);
+
+    lvalue new_global (type type_,
+                      const std::string &name,
+                      location loc = location ());
+
+    rvalue new_rvalue (type numeric_type,
+                      int value) const;
+    rvalue zero (type numeric_type) const;
+    rvalue one (type numeric_type) const;
+    rvalue new_rvalue (type numeric_type,
+                      double value) const;
+    rvalue new_rvalue (type pointer_type,
+                      void *value) const;
+    rvalue new_rvalue (const std::string &value) const;
+
+    /* Generic unary operations...  */
+    rvalue new_unary_op (enum gcc_jit_unary_op op,
+                        type result_type,
+                        rvalue a,
+                        location loc = location ());
+
+    /* ...and shorter ways to spell the various specific kinds of
+       unary op.  */
+    rvalue new_minus (type result_type,
+                     rvalue a,
+                     location loc = location ());
+    rvalue new_bitwise_negate (type result_type,
+                              rvalue a,
+                              location loc = location ());
+    rvalue new_logical_negate (type result_type,
+                              rvalue a,
+                              location loc = location ());
+
+    /* Generic binary operations...  */
+    rvalue new_binary_op (enum gcc_jit_binary_op op,
+                         type result_type,
+                         rvalue a, rvalue b,
+                         location loc = location ());
+
+    /* ...and shorter ways to spell the various specific kinds of
+       binary op.  */
+    rvalue new_plus (type result_type,
+                    rvalue a, rvalue b,
+                    location loc = location ());
+    rvalue new_minus (type result_type,
+                     rvalue a, rvalue b,
+                     location loc = location ());
+    rvalue new_mult (type result_type,
+                    rvalue a, rvalue b,
+                    location loc = location ());
+    rvalue new_divide (type result_type,
+                      rvalue a, rvalue b,
+                      location loc = location ());
+    rvalue new_modulo (type result_type,
+                      rvalue a, rvalue b,
+                      location loc = location ());
+    rvalue new_bitwise_and (type result_type,
+                           rvalue a, rvalue b,
+                           location loc = location ());
+    rvalue new_bitwise_xor (type result_type,
+                           rvalue a, rvalue b,
+                           location loc = location ());
+    rvalue new_bitwise_or (type result_type,
+                          rvalue a, rvalue b,
+                          location loc = location ());
+    rvalue new_logical_and (type result_type,
+                           rvalue a, rvalue b,
+                           location loc = location ());
+    rvalue new_logical_or (type result_type,
+                          rvalue a, rvalue b,
+                          location loc = location ());
+
+    /* Generic comparisons...  */
+    rvalue new_comparison (enum gcc_jit_comparison op,
+                          rvalue a, rvalue b,
+                          location loc = location ());
+    /* ...and shorter ways to spell the various specific kinds of
+       comparison.  */
+    rvalue new_eq (rvalue a, rvalue b,
+                  location loc = location ());
+    rvalue new_ne (rvalue a, rvalue b,
+                  location loc = location ());
+    rvalue new_lt (rvalue a, rvalue b,
+                  location loc = location ());
+    rvalue new_le (rvalue a, rvalue b,
+                  location loc = location ());
+    rvalue new_gt (rvalue a, rvalue b,
+                  location loc = location ());
+    rvalue new_ge (rvalue a, rvalue b,
+                  location loc = location ());
+
+    /* The most general way of creating a function call.  */
+    rvalue new_call (function func,
+                    std::vector<rvalue> &args,
+                    location loc = location ());
+
+    /* In addition, we provide a series of overloaded "new_call" methods
+       for specific numbers of args (from 0 - 6), to avoid the need for
+       client code to manually build a vector.  */
+    rvalue new_call (function func,
+                    location loc = location ());
+    rvalue new_call (function func,
+                    rvalue arg0,
+                    location loc = location ());
+    rvalue new_call (function func,
+                    rvalue arg0, rvalue arg1,
+                    location loc = location ());
+    rvalue new_call (function func,
+                    rvalue arg0, rvalue arg1, rvalue arg2,
+                    location loc = location ());
+    rvalue new_call (function func,
+                    rvalue arg0, rvalue arg1, rvalue arg2,
+                    rvalue arg3,
+                    location loc = location ());
+    rvalue new_call (function func,
+                    rvalue arg0, rvalue arg1, rvalue arg2,
+                    rvalue arg3, rvalue arg4,
+                    location loc = location ());
+    rvalue new_call (function func,
+                    rvalue arg0, rvalue arg1, rvalue arg2,
+                    rvalue arg3, rvalue arg4, rvalue arg5,
+                    location loc = location ());
+
+    rvalue new_cast (rvalue expr,
+                    type type_,
+                    location loc = location ());
+
+    lvalue new_array_access (rvalue ptr,
+                            rvalue index,
+                            location loc = location ());
+
+  private:
+    gcc_jit_context *m_inner_ctxt;
+  };
+
+  class field : public object
+  {
+  public:
+    field ();
+    field (gcc_jit_field *inner);
+
+    gcc_jit_field *get_inner_field () const;
+  };
+
+  class type : public object
+  {
+  public:
+    type ();
+    type (gcc_jit_type *inner);
+
+    gcc_jit_type *get_inner_type () const;
+
+    type get_pointer ();
+    type get_volatile ();
+
+    // Shortcuts for getting values of numeric types:
+    rvalue zero ();
+    rvalue one ();
+ };
+
+  class struct_ : public type
+  {
+  public:
+    struct_ ();
+    struct_ (gcc_jit_struct *inner);
+
+    gcc_jit_struct *get_inner_struct () const;
+  };
+
+  class function : public object
+  {
+  public:
+    function ();
+    function (gcc_jit_function *func);
+
+    gcc_jit_function *get_inner_function () const;
+
+    void dump_to_dot (const std::string &path);
+
+    param get_param (int index) const;
+
+    block new_block ();
+    block new_block (const std::string &name);
+
+    lvalue new_local (type type_,
+                     const std::string &name,
+                     location loc = location ());
+
+    /* A series of overloaded operator () with various numbers of arguments
+       for a very terse way of creating a call to this function.  The call
+       is created within the same context as the function itself, which may
+       not be what you want.  */
+    rvalue operator() (location loc = location ());
+    rvalue operator() (rvalue arg0,
+                      location loc = location ());
+    rvalue operator() (rvalue arg0, rvalue arg1,
+                      location loc = location ());
+    rvalue operator() (rvalue arg0, rvalue arg1, rvalue arg2,
+                      location loc = location ());
+  };
+
+  class block : public object
+  {
+  public:
+    block ();
+    block (gcc_jit_block *inner);
+
+    gcc_jit_block *get_inner_block () const;
+
+    function get_function () const;
+
+    void add_eval (rvalue rvalue,
+                  location loc = location ());
+
+    void add_assignment (lvalue lvalue,
+                        rvalue rvalue,
+                        location loc = location ());
+
+    void add_assignment_op (lvalue lvalue,
+                           enum gcc_jit_binary_op op,
+                           rvalue rvalue,
+                           location loc = location ());
+
+    /* A way to add a function call to the body of a function being
+       defined, with various numbers of args.  */
+    rvalue add_call (function other,
+                    location loc = location ());
+    rvalue add_call (function other,
+                    rvalue arg0,
+                    location loc = location ());
+    rvalue add_call (function other,
+                    rvalue arg0, rvalue arg1,
+                    location loc = location ());
+    rvalue add_call (function other,
+                    rvalue arg0, rvalue arg1, rvalue arg2,
+                    location loc = location ());
+    rvalue add_call (function other,
+                    rvalue arg0, rvalue arg1, rvalue arg2, rvalue arg3,
+                    location loc = location ());
+
+    void add_comment (const std::string &text,
+                     location loc = location ());
+
+    void end_with_conditional (rvalue boolval,
+                              block on_true,
+                              block on_false,
+                              location loc = location ());
+
+    void end_with_jump (block target,
+                       location loc = location ());
+
+    void end_with_return (rvalue rvalue,
+                         location loc = location ());
+    void end_with_return (location loc = location ());
+
+  };
+
+  class rvalue : public object
+  {
+  public:
+    rvalue ();
+    rvalue (gcc_jit_rvalue *inner);
+    gcc_jit_rvalue *get_inner_rvalue () const;
+
+    type get_type ();
+
+    rvalue access_field (field field,
+                        location loc = location ());
+
+    lvalue dereference_field (field field,
+                             location loc = location ());
+
+    lvalue dereference (location loc = location ());
+
+    rvalue cast_to (type type_,
+                   location loc = location ());
+
+    /* Array access.  */
+    lvalue operator[] (rvalue index);
+    lvalue operator[] (int index);
+  };
+
+  class lvalue : public rvalue
+  {
+  public:
+    lvalue ();
+    lvalue (gcc_jit_lvalue *inner);
+
+    gcc_jit_lvalue *get_inner_lvalue () const;
+
+    lvalue access_field (field field,
+                        location loc = location ());
+
+    rvalue get_address (location loc = location ());
+  };
+
+  class param : public lvalue
+  {
+  public:
+    param ();
+    param (gcc_jit_param *inner);
+
+    gcc_jit_param *get_inner_param () const;
+  };
+
+
+  /* Overloaded operators, for those who want the most terse API
+     (at the possible risk of being a little too magical).
+
+     In each case, the first parameter is used to determine which context
+     owns the resulting expression, and, where appropriate,  what the
+     latter's type is. */
+
+  /* Unary operators.  */
+  rvalue operator- (rvalue a); // unary minus
+  rvalue operator~ (rvalue a); // unary bitwise negate
+  rvalue operator! (rvalue a); // unary logical negate
+
+  /* Binary operators.  */
+  rvalue operator+ (rvalue a, rvalue b);
+  rvalue operator- (rvalue a, rvalue b);
+  rvalue operator* (rvalue a, rvalue b);
+  rvalue operator/ (rvalue a, rvalue b);
+  rvalue operator% (rvalue a, rvalue b);
+  rvalue operator& (rvalue a, rvalue b); //  bitwise and
+  rvalue operator^ (rvalue a, rvalue b); // bitwise_xor
+  rvalue operator| (rvalue a, rvalue b); // bitwise_or
+  rvalue operator&& (rvalue a, rvalue b); // logical_and
+  rvalue operator|| (rvalue a, rvalue b); // logical_or
+
+  /* Comparisons.  */
+  rvalue operator== (rvalue a, rvalue b);
+  rvalue operator!= (rvalue a, rvalue b);
+  rvalue operator< (rvalue a, rvalue b);
+  rvalue operator<= (rvalue a, rvalue b);
+  rvalue operator> (rvalue a, rvalue b);
+  rvalue operator>= (rvalue a, rvalue b);
+
+  /* Dereferencing. */
+  lvalue operator* (rvalue ptr);
+}
+
+/****************************************************************************
+ Implementation of the API
+ ****************************************************************************/
+namespace gccjit {
+
+// class context
+inline context context::acquire ()
+{
+  return context (gcc_jit_context_acquire ());
+}
+inline context::context () : m_inner_ctxt (NULL) {}
+inline context::context (gcc_jit_context *inner) : m_inner_ctxt (inner)
+{
+  if (!inner)
+    throw error ();
+}
+
+inline gccjit::context
+context::new_child_context ()
+{
+  return context (gcc_jit_context_new_child_context (m_inner_ctxt));
+}
+
+inline void
+context::release ()
+{
+  gcc_jit_context_release (m_inner_ctxt);
+  m_inner_ctxt = NULL;
+}
+
+inline gcc_jit_result *
+context::compile ()
+{
+  gcc_jit_result *result = gcc_jit_context_compile (m_inner_ctxt);
+  if (!result)
+    throw error ();
+  return result;
+}
+
+inline void
+context::dump_to_file (const std::string &path,
+                      bool update_locations)
+{
+  gcc_jit_context_dump_to_file (m_inner_ctxt,
+                               path.c_str (),
+                               update_locations);
+}
+
+inline void
+context::set_int_option (enum gcc_jit_int_option opt,
+                        int value)
+{
+  gcc_jit_context_set_int_option (m_inner_ctxt, opt, value);
+
+}
+
+inline void
+context::set_bool_option (enum gcc_jit_bool_option opt,
+                         int value)
+{
+  gcc_jit_context_set_bool_option (m_inner_ctxt, opt, value);
+
+}
+
+inline location
+context::new_location (const std::string &filename,
+                      int line,
+                      int column)
+{
+  return location (gcc_jit_context_new_location (m_inner_ctxt,
+                                                filename.c_str (),
+                                                line,
+                                                column));
+}
+
+inline type
+context::get_type (enum gcc_jit_types kind)
+{
+  return type (gcc_jit_context_get_type (m_inner_ctxt, kind));
+}
+
+inline type
+context::get_int_type (size_t num_bytes, int is_signed)
+{
+  return type (gcc_jit_context_get_int_type (m_inner_ctxt,
+                                            num_bytes,
+                                            is_signed));
+}
+
+template <typename T>
+inline type
+context::get_int_type ()
+{
+  return get_int_type (sizeof (T), std::numeric_limits<T>::is_signed);
+}
+
+inline type
+context::new_array_type (type element_type, int num_elements, location loc)
+{
+  return type (gcc_jit_context_new_array_type (
+                m_inner_ctxt,
+                loc.get_inner_location (),
+                element_type.get_inner_type (),
+                num_elements));
+}
+
+inline field
+context::new_field (type type_, const std::string &name, location loc)
+{
+  return field (gcc_jit_context_new_field (m_inner_ctxt,
+                                          loc.get_inner_location (),
+                                          type_.get_inner_type (),
+                                          name.c_str ()));
+}
+
+inline struct_
+context::new_struct_type (const std::string &name,
+                         std::vector<field> &fields,
+                         location loc)
+{
+  /* Treat std::vector as an array, relying on it not being resized: */
+  field *as_array_of_wrappers = &fields[0];
+
+  /* Treat the array as being of the underlying pointers, relying on
+     the wrapper type being such a pointer internally. */
+  gcc_jit_field **as_array_of_ptrs =
+    reinterpret_cast<gcc_jit_field **> (as_array_of_wrappers);
+
+  return struct_ (gcc_jit_context_new_struct_type (m_inner_ctxt,
+                                                  loc.get_inner_location (),
+                                                  name.c_str (),
+                                                  fields.size (),
+                                                  as_array_of_ptrs));
+}
+
+inline struct_
+context::new_opaque_struct_type (const std::string &name,
+                                location loc)
+{
+  return struct_ (gcc_jit_context_new_opaque_struct (
+                   m_inner_ctxt,
+                   loc.get_inner_location (),
+                   name.c_str ()));
+}
+
+inline param
+context::new_param (type type_,
+                   const std::string &name,
+                   location loc)
+{
+  return param (gcc_jit_context_new_param (m_inner_ctxt,
+                                          loc.get_inner_location (),
+                                          type_.get_inner_type (),
+                                          name.c_str ()));
+}
+
+inline function
+context::new_function (enum gcc_jit_function_kind kind,
+                      type return_type,
+                      const std::string &name,
+                      std::vector<param> &params,
+                      int is_variadic,
+                      location loc)
+{
+  /* Treat std::vector as an array, relying on it not being resized: */
+  param *as_array_of_wrappers = &params[0];
+
+  /* Treat the array as being of the underlying pointers, relying on
+     the wrapper type being such a pointer internally. */
+  gcc_jit_param **as_array_of_ptrs =
+    reinterpret_cast<gcc_jit_param **> (as_array_of_wrappers);
+
+  return function (gcc_jit_context_new_function (m_inner_ctxt,
+                                                loc.get_inner_location (),
+                                                kind,
+                                                return_type.get_inner_type (),
+                                                name.c_str (),
+                                                params.size (),
+                                                as_array_of_ptrs,
+                                                is_variadic));
+}
+
+inline function
+context::get_builtin_function (const std::string &name)
+{
+  return function (gcc_jit_context_get_builtin_function (m_inner_ctxt,
+                                                        name.c_str ()));
+}
+
+inline lvalue
+context::new_global (type type_,
+                    const std::string &name,
+                    location loc)
+{
+  return lvalue (gcc_jit_context_new_global (m_inner_ctxt,
+                                            loc.get_inner_location (),
+                                            type_.get_inner_type (),
+                                            name.c_str ()));
+}
+
+inline rvalue
+context::new_rvalue (type numeric_type,
+                    int value) const
+{
+  return rvalue (
+    gcc_jit_context_new_rvalue_from_int (m_inner_ctxt,
+                                        numeric_type.get_inner_type (),
+                                        value));
+}
+
+inline rvalue
+context::zero (type numeric_type) const
+{
+  return rvalue (gcc_jit_context_zero (m_inner_ctxt,
+                                      numeric_type.get_inner_type ()));
+}
+
+inline rvalue
+context::one (type numeric_type) const
+{
+  return rvalue (gcc_jit_context_one (m_inner_ctxt,
+                                      numeric_type.get_inner_type ()));
+}
+
+inline rvalue
+context::new_rvalue (type numeric_type,
+                    double value) const
+{
+  return rvalue (
+    gcc_jit_context_new_rvalue_from_double (m_inner_ctxt,
+                                           numeric_type.get_inner_type (),
+                                           value));
+}
+
+inline rvalue
+context::new_rvalue (type pointer_type,
+                    void *value) const
+{
+  return rvalue (
+    gcc_jit_context_new_rvalue_from_ptr (m_inner_ctxt,
+                                        pointer_type.get_inner_type (),
+                                        value));
+}
+
+inline rvalue
+context::new_rvalue (const std::string &value) const
+{
+  return rvalue (
+    gcc_jit_context_new_string_literal (m_inner_ctxt, value.c_str ()));
+}
+
+inline rvalue
+context::new_unary_op (enum gcc_jit_unary_op op,
+                      type result_type,
+                      rvalue a,
+                      location loc)
+{
+  return rvalue (gcc_jit_context_new_unary_op (m_inner_ctxt,
+                                              loc.get_inner_location (),
+                                              op,
+                                              result_type.get_inner_type (),
+                                              a.get_inner_rvalue ()));
+}
+inline rvalue
+context::new_minus (type result_type,
+                   rvalue a,
+                   location loc)
+{
+  return rvalue (new_unary_op (GCC_JIT_UNARY_OP_MINUS,
+                              result_type, a, loc));
+}
+inline rvalue
+context::new_bitwise_negate (type result_type,
+                            rvalue a,
+                            location loc)
+{
+  return rvalue (new_unary_op (GCC_JIT_UNARY_OP_BITWISE_NEGATE,
+                              result_type, a, loc));
+}
+inline rvalue
+context::new_logical_negate (type result_type,
+                            rvalue a,
+                            location loc)
+{
+  return rvalue (new_unary_op (GCC_JIT_UNARY_OP_LOGICAL_NEGATE,
+                              result_type, a, loc));
+}
+
+inline rvalue
+context::new_binary_op (enum gcc_jit_binary_op op,
+                       type result_type,
+                       rvalue a, rvalue b,
+                       location loc)
+{
+  return rvalue (gcc_jit_context_new_binary_op (m_inner_ctxt,
+                                               loc.get_inner_location (),
+                                               op,
+                                               result_type.get_inner_type (),
+                                               a.get_inner_rvalue (),
+                                               b.get_inner_rvalue ()));
+}
+inline rvalue
+context::new_plus (type result_type,
+                  rvalue a, rvalue b,
+                  location loc)
+{
+  return new_binary_op (GCC_JIT_BINARY_OP_PLUS,
+                       result_type, a, b, loc);
+}
+inline rvalue
+context::new_minus (type result_type,
+                   rvalue a, rvalue b,
+                   location loc)
+{
+  return new_binary_op (GCC_JIT_BINARY_OP_MINUS,
+                       result_type, a, b, loc);
+}
+inline rvalue
+context::new_mult (type result_type,
+                  rvalue a, rvalue b,
+                  location loc)
+{
+  return new_binary_op (GCC_JIT_BINARY_OP_MULT,
+                       result_type, a, b, loc);
+}
+inline rvalue
+context::new_divide (type result_type,
+                    rvalue a, rvalue b,
+                    location loc)
+{
+  return new_binary_op (GCC_JIT_BINARY_OP_DIVIDE,
+                       result_type, a, b, loc);
+}
+inline rvalue
+context::new_modulo (type result_type,
+                    rvalue a, rvalue b,
+                    location loc)
+{
+  return new_binary_op (GCC_JIT_BINARY_OP_MODULO,
+                       result_type, a, b, loc);
+}
+inline rvalue
+context::new_bitwise_and (type result_type,
+                         rvalue a, rvalue b,
+                         location loc)
+{
+  return new_binary_op (GCC_JIT_BINARY_OP_BITWISE_AND,
+                       result_type, a, b, loc);
+}
+inline rvalue
+context::new_bitwise_xor (type result_type,
+                         rvalue a, rvalue b,
+                         location loc)
+{
+  return new_binary_op (GCC_JIT_BINARY_OP_BITWISE_XOR,
+                       result_type, a, b, loc);
+}
+inline rvalue
+context::new_bitwise_or (type result_type,
+                        rvalue a, rvalue b,
+                        location loc)
+{
+  return new_binary_op (GCC_JIT_BINARY_OP_BITWISE_OR,
+                       result_type, a, b, loc);
+}
+inline rvalue
+context::new_logical_and (type result_type,
+                         rvalue a, rvalue b,
+                         location loc)
+{
+  return new_binary_op (GCC_JIT_BINARY_OP_LOGICAL_AND,
+                       result_type, a, b, loc);
+}
+inline rvalue
+context::new_logical_or (type result_type,
+                        rvalue a, rvalue b,
+                        location loc)
+{
+  return new_binary_op (GCC_JIT_BINARY_OP_LOGICAL_OR,
+                       result_type, a, b, loc);
+}
+
+inline rvalue
+context::new_comparison (enum gcc_jit_comparison op,
+                        rvalue a, rvalue b,
+                        location loc)
+{
+  return rvalue (gcc_jit_context_new_comparison (m_inner_ctxt,
+                                                loc.get_inner_location (),
+                                                op,
+                                                a.get_inner_rvalue (),
+                                                b.get_inner_rvalue ()));
+}
+inline rvalue
+context::new_eq (rvalue a, rvalue b,
+                location loc)
+{
+  return new_comparison (GCC_JIT_COMPARISON_EQ,
+                        a, b, loc);
+}
+inline rvalue
+context::new_ne (rvalue a, rvalue b,
+                location loc)
+{
+  return new_comparison (GCC_JIT_COMPARISON_NE,
+                        a, b, loc);
+}
+inline rvalue
+context::new_lt (rvalue a, rvalue b,
+                location loc)
+{
+  return new_comparison (GCC_JIT_COMPARISON_LT,
+                        a, b, loc);
+}
+inline rvalue
+context::new_le (rvalue a, rvalue b,
+                location loc)
+{
+  return new_comparison (GCC_JIT_COMPARISON_LE,
+                        a, b, loc);
+}
+inline rvalue
+context::new_gt (rvalue a, rvalue b,
+                location loc)
+{
+  return new_comparison (GCC_JIT_COMPARISON_GT,
+                        a, b, loc);
+}
+inline rvalue
+context::new_ge (rvalue a, rvalue b,
+                location loc)
+{
+  return new_comparison (GCC_JIT_COMPARISON_GE,
+                        a, b, loc);
+}
+
+inline rvalue
+context::new_call (function func,
+                  std::vector<rvalue> &args,
+                  location loc)
+{
+  /* Treat std::vector as an array, relying on it not being resized: */
+  rvalue *as_array_of_wrappers = &args[0];
+
+  /* Treat the array as being of the underlying pointers, relying on
+     the wrapper type being such a pointer internally. */
+  gcc_jit_rvalue **as_array_of_ptrs =
+    reinterpret_cast<gcc_jit_rvalue **> (as_array_of_wrappers);
+  return gcc_jit_context_new_call (m_inner_ctxt,
+                                  loc.get_inner_location (),
+                                  func.get_inner_function (),
+                                  args.size (),
+                                  as_array_of_ptrs);
+}
+inline rvalue
+context::new_call (function func,
+                  location loc)
+{
+  std::vector<rvalue> args;
+  return new_call (func, args, loc);
+}
+
+inline rvalue
+context::new_call (function func,
+                  rvalue arg0,
+                  location loc)
+{
+  std::vector<rvalue> args(1);
+  args[0] = arg0;
+  return new_call (func, args, loc);
+}
+inline rvalue
+context::new_call (function func,
+                  rvalue arg0, rvalue arg1,
+                  location loc)
+{
+  std::vector<rvalue> args(2);
+  args[0] = arg0;
+  args[1] = arg1;
+  return new_call (func, args, loc);
+}
+inline rvalue
+context::new_call (function func,
+                  rvalue arg0, rvalue arg1, rvalue arg2,
+                  location loc)
+{
+  std::vector<rvalue> args(3);
+  args[0] = arg0;
+  args[1] = arg1;
+  args[2] = arg2;
+  return new_call (func, args, loc);
+}
+inline rvalue
+context::new_call (function func,
+                  rvalue arg0, rvalue arg1, rvalue arg2,
+                  rvalue arg3,
+                  location loc)
+{
+  std::vector<rvalue> args(4);
+  args[0] = arg0;
+  args[1] = arg1;
+  args[2] = arg2;
+  args[3] = arg3;
+  return new_call (func, args, loc);
+}
+inline rvalue
+context::new_call (function func,
+                  rvalue arg0, rvalue arg1, rvalue arg2,
+                  rvalue arg3, rvalue arg4,
+                  location loc)
+{
+  std::vector<rvalue> args(5);
+  args[0] = arg0;
+  args[1] = arg1;
+  args[2] = arg2;
+  args[3] = arg3;
+  args[4] = arg4;
+  return new_call (func, args, loc);
+}
+inline rvalue
+context::new_call (function func,
+                  rvalue arg0, rvalue arg1, rvalue arg2,
+                  rvalue arg3, rvalue arg4, rvalue arg5,
+                  location loc)
+{
+  std::vector<rvalue> args(6);
+  args[0] = arg0;
+  args[1] = arg1;
+  args[2] = arg2;
+  args[3] = arg3;
+  args[4] = arg4;
+  args[5] = arg5;
+  return new_call (func, args, loc);
+}
+
+inline rvalue
+context::new_cast (rvalue expr,
+                  type type_,
+                  location loc)
+{
+  return rvalue (gcc_jit_context_new_cast (m_inner_ctxt,
+                                          loc.get_inner_location (),
+                                          expr.get_inner_rvalue (),
+                                          type_.get_inner_type ()));
+}
+
+inline lvalue
+context::new_array_access (rvalue ptr,
+                          rvalue index,
+                          location loc)
+{
+  return lvalue (gcc_jit_context_new_array_access (m_inner_ctxt,
+                                                  loc.get_inner_location (),
+                                                  ptr.get_inner_rvalue (),
+                                                  index.get_inner_rvalue ()));
+}
+
+// class object
+inline context
+object::get_context () const
+{
+  return context (gcc_jit_object_get_context (m_inner_obj));
+}
+
+inline std::string
+object::get_debug_string () const
+{
+  return gcc_jit_object_get_debug_string (m_inner_obj);
+}
+
+inline object::object () : m_inner_obj (NULL) {}
+inline object::object (gcc_jit_object *obj) : m_inner_obj (obj)
+{
+  if (!obj)
+    throw error ();
+}
+
+inline gcc_jit_object *
+object::get_inner_object () const
+{
+  return m_inner_obj;
+}
+
+inline std::ostream&
+operator << (std::ostream& stream, const object &obj)
+{
+  return stream << obj.get_debug_string ();
+}
+
+// class location
+inline location::location () : object () {}
+inline location::location (gcc_jit_location *loc)
+  : object (gcc_jit_location_as_object (loc))
+{}
+
+inline gcc_jit_location *
+location::get_inner_location () const
+{
+  /* Manual downcast: */
+  return reinterpret_cast<gcc_jit_location *> (get_inner_object ());
+}
+
+// class field
+inline field::field () : object () {}
+inline field::field (gcc_jit_field *inner)
+  : object (gcc_jit_field_as_object (inner))
+{}
+
+inline gcc_jit_field *
+field::get_inner_field () const
+{
+  /* Manual downcast: */
+  return reinterpret_cast<gcc_jit_field *> (get_inner_object ());
+}
+
+// class type
+inline type::type () : object () {}
+inline type::type (gcc_jit_type *inner)
+  : object (gcc_jit_type_as_object (inner))
+{}
+
+inline gcc_jit_type *
+type::get_inner_type () const
+{
+  /* Manual downcast: */
+  return reinterpret_cast<gcc_jit_type *> (get_inner_object ());
+}
+
+inline type
+type::get_pointer ()
+{
+  return type (gcc_jit_type_get_pointer (get_inner_type ()));
+}
+
+inline type
+type::get_volatile ()
+{
+  return type (gcc_jit_type_get_volatile (get_inner_type ()));
+}
+
+inline rvalue
+type::zero ()
+{
+  return get_context ().new_rvalue (*this, 0);
+}
+
+inline rvalue
+type::one ()
+{
+  return get_context ().new_rvalue (*this, 1);
+}
+
+// class struct_
+inline struct_::struct_ () : type (NULL) {}
+inline struct_::struct_ (gcc_jit_struct *inner) :
+  type (gcc_jit_struct_as_type (inner))
+{
+}
+
+inline gcc_jit_struct *
+struct_::get_inner_struct () const
+{
+  /* Manual downcast: */
+  return reinterpret_cast<gcc_jit_struct *> (get_inner_object ());
+}
+
+// class function
+inline function::function () : object () {}
+inline function::function (gcc_jit_function *inner)
+  : object (gcc_jit_function_as_object (inner))
+{}
+
+inline gcc_jit_function *
+function::get_inner_function () const
+{
+  /* Manual downcast: */
+  return reinterpret_cast<gcc_jit_function *> (get_inner_object ());
+}
+
+inline void
+function::dump_to_dot (const std::string &path)
+{
+  gcc_jit_function_dump_to_dot (get_inner_function (),
+                               path.c_str ());
+}
+
+inline param
+function::get_param (int index) const
+{
+  return param (gcc_jit_function_get_param (get_inner_function (),
+                                           index));
+}
+
+inline block
+function::new_block ()
+{
+  return block (gcc_jit_function_new_block (get_inner_function (),
+                                           NULL));
+}
+
+inline block
+function::new_block (const std::string &name)
+{
+  return block (gcc_jit_function_new_block (get_inner_function (),
+                                           name.c_str ()));
+}
+
+inline lvalue
+function::new_local (type type_,
+                    const std::string &name,
+                    location loc)
+{
+  return lvalue (gcc_jit_function_new_local (get_inner_function (),
+                                            loc.get_inner_location (),
+                                            type_.get_inner_type (),
+                                            name.c_str ()));
+}
+
+inline function
+block::get_function () const
+{
+  return function (gcc_jit_block_get_function ( get_inner_block ()));
+}
+
+inline void
+block::add_eval (rvalue rvalue,
+                location loc)
+{
+  gcc_jit_block_add_eval (get_inner_block (),
+                         loc.get_inner_location (),
+                         rvalue.get_inner_rvalue ());
+}
+
+inline void
+block::add_assignment (lvalue lvalue,
+                      rvalue rvalue,
+                      location loc)
+{
+  gcc_jit_block_add_assignment (get_inner_block (),
+                               loc.get_inner_location (),
+                               lvalue.get_inner_lvalue (),
+                               rvalue.get_inner_rvalue ());
+}
+
+inline void
+block::add_assignment_op (lvalue lvalue,
+                         enum gcc_jit_binary_op op,
+                         rvalue rvalue,
+                         location loc)
+{
+  gcc_jit_block_add_assignment_op (get_inner_block (),
+                                  loc.get_inner_location (),
+                                  lvalue.get_inner_lvalue (),
+                                  op,
+                                  rvalue.get_inner_rvalue ());
+}
+
+inline void
+block::add_comment (const std::string &text,
+                   location loc)
+{
+  gcc_jit_block_add_comment (get_inner_block (),
+                            loc.get_inner_location (),
+                            text.c_str ());
+}
+
+inline void
+block::end_with_conditional (rvalue boolval,
+                            block on_true,
+                            block on_false,
+                            location loc)
+{
+  gcc_jit_block_end_with_conditional (get_inner_block (),
+                                     loc.get_inner_location (),
+                                     boolval.get_inner_rvalue (),
+                                     on_true.get_inner_block (),
+                                     on_false.get_inner_block ());
+}
+
+inline void
+block::end_with_jump (block target,
+                     location loc)
+{
+  gcc_jit_block_end_with_jump (get_inner_block (),
+                              loc.get_inner_location (),
+                              target.get_inner_block ());
+}
+
+inline void
+block::end_with_return (rvalue rvalue,
+                       location loc)
+{
+  gcc_jit_block_end_with_return (get_inner_block (),
+                                loc.get_inner_location (),
+                                rvalue.get_inner_rvalue ());
+}
+
+inline void
+block::end_with_return (location loc)
+{
+  gcc_jit_block_end_with_void_return (get_inner_block (),
+                                     loc.get_inner_location ());
+}
+
+inline rvalue
+block::add_call (function other,
+                location loc)
+{
+  rvalue c = get_context ().new_call (other, loc);
+  add_eval (c);
+  return c;
+}
+inline rvalue
+block::add_call (function other,
+                rvalue arg0,
+                location loc)
+{
+  rvalue c = get_context ().new_call (other, arg0, loc);
+  add_eval (c);
+  return c;
+}
+inline rvalue
+block::add_call (function other,
+                rvalue arg0, rvalue arg1,
+                location loc)
+{
+  rvalue c = get_context ().new_call (other, arg0, arg1, loc);
+  add_eval (c);
+  return c;
+}
+inline rvalue
+block::add_call (function other,
+                rvalue arg0, rvalue arg1, rvalue arg2,
+                location loc)
+{
+  rvalue c = get_context ().new_call (other, arg0, arg1, arg2, loc);
+  add_eval (c);
+  return c;
+}
+
+inline rvalue
+block::add_call (function other,
+                rvalue arg0, rvalue arg1, rvalue arg2, rvalue arg3,
+                location loc)
+{
+  rvalue c = get_context ().new_call (other, arg0, arg1, arg2, arg3, loc);
+  add_eval (c);
+  return c;
+}
+
+inline rvalue
+function::operator() (location loc)
+{
+  return get_context ().new_call (*this, loc);
+}
+inline rvalue
+function::operator() (rvalue arg0,
+                     location loc)
+{
+  return get_context ().new_call (*this,
+                                 arg0,
+                                 loc);
+}
+inline rvalue
+function::operator() (rvalue arg0, rvalue arg1,
+                     location loc)
+{
+  return get_context ().new_call (*this,
+                                 arg0, arg1,
+                                 loc);
+}
+inline rvalue
+function::operator() (rvalue arg0, rvalue arg1, rvalue arg2,
+                     location loc)
+{
+  return get_context ().new_call (*this,
+                                 arg0, arg1, arg2,
+                                 loc);
+}
+
+// class block
+inline block::block () : object () {}
+inline block::block (gcc_jit_block *inner)
+  : object (gcc_jit_block_as_object (inner))
+{}
+
+inline gcc_jit_block *
+block::get_inner_block () const
+{
+  /* Manual downcast: */
+  return reinterpret_cast<gcc_jit_block *> (get_inner_object ());
+}
+
+//  class rvalue
+inline rvalue::rvalue () : object () {}
+inline rvalue::rvalue (gcc_jit_rvalue *inner)
+  : object (gcc_jit_rvalue_as_object (inner))
+{}
+
+inline gcc_jit_rvalue *
+rvalue::get_inner_rvalue () const
+{
+  /* Manual downcast: */
+  return reinterpret_cast<gcc_jit_rvalue *> (get_inner_object ());
+}
+
+inline type
+rvalue::get_type ()
+{
+  return type (gcc_jit_rvalue_get_type (get_inner_rvalue ()));
+}
+
+inline rvalue
+rvalue::access_field (field field,
+                     location loc)
+{
+  return rvalue (gcc_jit_rvalue_access_field (get_inner_rvalue (),
+                                             loc.get_inner_location (),
+                                             field.get_inner_field ()));
+}
+
+inline lvalue
+rvalue::dereference_field (field field,
+                          location loc)
+{
+  return lvalue (gcc_jit_rvalue_dereference_field (get_inner_rvalue (),
+                                                  loc.get_inner_location (),
+                                                  field.get_inner_field ()));
+}
+
+inline lvalue
+rvalue::dereference (location loc)
+{
+  return lvalue (gcc_jit_rvalue_dereference (get_inner_rvalue (),
+                                            loc.get_inner_location ()));
+}
+
+inline rvalue
+rvalue::cast_to (type type_,
+                location loc)
+{
+  return get_context ().new_cast (*this, type_, loc);
+}
+
+inline lvalue
+rvalue::operator[] (rvalue index)
+{
+  return get_context ().new_array_access (*this, index);
+}
+
+inline lvalue
+rvalue::operator[] (int index)
+{
+  context ctxt = get_context ();
+  type int_t = ctxt.get_int_type <int> ();
+  return ctxt.new_array_access (*this,
+                               ctxt.new_rvalue (int_t,
+                                                index));
+}
+
+// class lvalue : public rvalue
+inline lvalue::lvalue () : rvalue () {}
+inline lvalue::lvalue (gcc_jit_lvalue *inner)
+  : rvalue (gcc_jit_lvalue_as_rvalue (inner))
+{}
+
+inline gcc_jit_lvalue *
+lvalue::get_inner_lvalue () const
+{
+  /* Manual downcast: */
+  return reinterpret_cast<gcc_jit_lvalue *> (get_inner_object ());
+}
+
+inline lvalue
+lvalue::access_field (field field, location loc)
+{
+  return lvalue (gcc_jit_lvalue_access_field (get_inner_lvalue (),
+                                             loc.get_inner_location (),
+                                             field.get_inner_field ()));
+}
+
+inline rvalue
+lvalue::get_address (location loc)
+{
+  return rvalue (gcc_jit_lvalue_get_address (get_inner_lvalue (),
+                                            loc.get_inner_location ()));
+}
+
+// class param : public lvalue
+inline param::param () : lvalue () {}
+inline param::param (gcc_jit_param *inner)
+  : lvalue (gcc_jit_param_as_lvalue (inner))
+{}
+
+/* Overloaded operators.  */
+// Unary operators
+inline rvalue operator- (rvalue a)
+{
+  return a.get_context ().new_minus (a.get_type (), a);
+}
+inline rvalue operator~ (rvalue a)
+{
+  return a.get_context ().new_bitwise_negate (a.get_type (), a);
+}
+inline rvalue operator! (rvalue a)
+{
+  return a.get_context ().new_logical_negate (a.get_type (), a);
+}
+
+// Binary operators
+inline rvalue operator+ (rvalue a, rvalue b)
+{
+  return a.get_context ().new_plus (a.get_type (), a, b);
+}
+inline rvalue operator- (rvalue a, rvalue b)
+{
+  return a.get_context ().new_minus (a.get_type (), a, b);
+}
+inline rvalue operator* (rvalue a, rvalue b)
+{
+  return a.get_context ().new_mult (a.get_type (), a, b);
+}
+inline rvalue operator/ (rvalue a, rvalue b)
+{
+  return a.get_context ().new_divide (a.get_type (), a, b);
+}
+inline rvalue operator% (rvalue a, rvalue b)
+{
+  return a.get_context ().new_modulo (a.get_type (), a, b);
+}
+inline rvalue operator& (rvalue a, rvalue b)
+{
+  return a.get_context ().new_bitwise_and (a.get_type (), a, b);
+}
+inline rvalue operator^ (rvalue a, rvalue b)
+{
+  return a.get_context ().new_bitwise_xor (a.get_type (), a, b);
+}
+inline rvalue operator| (rvalue a, rvalue b)
+{
+  return a.get_context ().new_bitwise_or (a.get_type (), a, b);
+}
+inline rvalue operator&& (rvalue a, rvalue b)
+{
+  return a.get_context ().new_logical_and (a.get_type (), a, b);
+}
+inline rvalue operator|| (rvalue a, rvalue b)
+{
+  return a.get_context ().new_logical_or (a.get_type (), a, b);
+}
+
+/* Comparisons.  */
+inline rvalue operator== (rvalue a, rvalue b)
+{
+  return a.get_context ().new_eq (a, b);
+}
+inline rvalue operator!= (rvalue a, rvalue b)
+{
+  return a.get_context ().new_ne (a, b);
+}
+inline rvalue operator< (rvalue a, rvalue b)
+{
+  return a.get_context ().new_lt (a, b);
+}
+inline rvalue operator<= (rvalue a, rvalue b)
+{
+  return a.get_context ().new_le (a, b);
+}
+inline rvalue operator> (rvalue a, rvalue b)
+{
+  return a.get_context ().new_gt (a, b);
+}
+inline rvalue operator>= (rvalue a, rvalue b)
+{
+  return a.get_context ().new_ge (a, b);
+}
+
+/* Dereferencing. */
+inline lvalue operator* (rvalue ptr)
+{
+  return ptr.dereference ();
+}
+
+} // namespace gccjit
+
+#endif /* #ifndef LIBGCCJIT_PLUS_PLUS_H */
diff --git a/gcc/jit/libgccjit.c b/gcc/jit/libgccjit.c
new file mode 100644 (file)
index 0000000..7bc9209
--- /dev/null
@@ -0,0 +1,2074 @@
+/* Implementation of the C API; all wrappers into the internal C++ API
+   Copyright (C) 2013-2014 Free Software Foundation, Inc.
+   Contributed by David Malcolm <dmalcolm@redhat.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "opts.h"
+#include "safe-ctype.h"
+
+#include "libgccjit.h"
+#include "jit-common.h"
+#include "jit-recording.h"
+
+/* The opaque types used by the public API are actually subclasses
+   of the gcc::jit::recording classes.  */
+
+struct gcc_jit_context : public gcc::jit::recording::context
+{
+  gcc_jit_context (gcc_jit_context *parent_ctxt) :
+    context (parent_ctxt)
+  {}
+};
+
+struct gcc_jit_result : public gcc::jit::result
+{
+};
+
+struct gcc_jit_object : public gcc::jit::recording::memento
+{
+};
+
+struct gcc_jit_location : public gcc::jit::recording::location
+{
+};
+
+struct gcc_jit_type : public gcc::jit::recording::type
+{
+};
+
+struct gcc_jit_struct : public gcc::jit::recording::struct_
+{
+};
+
+struct gcc_jit_field : public gcc::jit::recording::field
+{
+};
+
+struct gcc_jit_function : public gcc::jit::recording::function
+{
+};
+
+struct gcc_jit_block : public gcc::jit::recording::block
+{
+};
+
+struct gcc_jit_rvalue : public gcc::jit::recording::rvalue
+{
+};
+
+struct gcc_jit_lvalue : public gcc::jit::recording::lvalue
+{
+};
+
+struct gcc_jit_param : public gcc::jit::recording::param
+{
+};
+
+/**********************************************************************
+ Error-handling.
+
+ We try to gracefully handle API usage errors by being defensive
+ at the API boundary.
+ **********************************************************************/
+
+#define JIT_BEGIN_STMT do {
+#define JIT_END_STMT   } while(0)
+
+/* Each of these error-handling macros determines if TEST_EXPR holds.
+
+   If TEXT_EXPR fails to hold we return from the enclosing function and
+   print an error, either via adding an error on the given context CTXT
+   if CTXT is non-NULL, falling back to simply printing to stderr if CTXT
+   is NULL.
+
+   They have to be macros since they inject their "return" into the
+   function they are placed in.
+
+   The variant macros express:
+
+     (A) whether or not we need to return a value:
+           RETURN_VAL_IF_FAIL* vs
+           RETURN_IF_FAIL*,
+        with the former returning RETURN_EXPR, and
+           RETURN_NULL_IF_FAIL*
+        for the common case where a NULL value is to be returned on
+        error, and
+
+     (B) whether the error message is to be directly printed:
+          RETURN_*IF_FAIL
+        or is a format string with some number of arguments:
+          RETURN_*IF_FAIL_PRINTF*
+
+   They all use JIT_BEGIN_STMT/JIT_END_STMT so they can be written with
+   trailing semicolons.
+*/
+
+#define RETURN_VAL_IF_FAIL(TEST_EXPR, RETURN_EXPR, CTXT, LOC, ERR_MSG) \
+  JIT_BEGIN_STMT                                                       \
+    if (!(TEST_EXPR))                                                  \
+      {                                                                \
+       jit_error ((CTXT), (LOC), "%s: %s", __func__, (ERR_MSG));       \
+       return (RETURN_EXPR);                                           \
+      }                                                                \
+  JIT_END_STMT
+
+#define RETURN_VAL_IF_FAIL_PRINTF1(TEST_EXPR, RETURN_EXPR, CTXT, LOC, ERR_FMT, A0) \
+  JIT_BEGIN_STMT                                                       \
+    if (!(TEST_EXPR))                                                  \
+      {                                                                \
+       jit_error ((CTXT), (LOC), "%s: " ERR_FMT,                       \
+                  __func__, (A0));                             \
+       return (RETURN_EXPR);                                           \
+      }                                                                \
+  JIT_END_STMT
+
+#define RETURN_VAL_IF_FAIL_PRINTF2(TEST_EXPR, RETURN_EXPR, CTXT, LOC, ERR_FMT, A0, A1) \
+  JIT_BEGIN_STMT                                                       \
+    if (!(TEST_EXPR))                                                  \
+      {                                                                \
+       jit_error ((CTXT), (LOC), "%s: " ERR_FMT,                               \
+                  __func__, (A0), (A1));                               \
+       return (RETURN_EXPR);                                           \
+      }                                                                \
+  JIT_END_STMT
+
+#define RETURN_VAL_IF_FAIL_PRINTF3(TEST_EXPR, RETURN_EXPR, CTXT, LOC, ERR_FMT, A0, A1, A2) \
+  JIT_BEGIN_STMT                                                       \
+    if (!(TEST_EXPR))                                                  \
+      {                                                                \
+       jit_error ((CTXT), (LOC), "%s: " ERR_FMT,                               \
+                  __func__, (A0), (A1), (A2));                 \
+       return (RETURN_EXPR);                                           \
+      }                                                                \
+  JIT_END_STMT
+
+#define RETURN_VAL_IF_FAIL_PRINTF4(TEST_EXPR, RETURN_EXPR, CTXT, LOC, ERR_FMT, A0, A1, A2, A3) \
+  JIT_BEGIN_STMT                                                       \
+    if (!(TEST_EXPR))                                                  \
+      {                                                                \
+       jit_error ((CTXT), (LOC), "%s: " ERR_FMT,                               \
+                  __func__, (A0), (A1), (A2), (A3));                   \
+       return (RETURN_EXPR);                                           \
+      }                                                                \
+  JIT_END_STMT
+
+#define RETURN_VAL_IF_FAIL_PRINTF6(TEST_EXPR, RETURN_EXPR, CTXT, LOC, ERR_FMT, A0, A1, A2, A3, A4, A5) \
+  JIT_BEGIN_STMT                                                       \
+    if (!(TEST_EXPR))                                                  \
+      {                                                                \
+       jit_error ((CTXT), (LOC), "%s: " ERR_FMT,                               \
+                  __func__, (A0), (A1), (A2), (A3), (A4), (A5));       \
+       return (RETURN_EXPR);                                           \
+      }                                                                \
+  JIT_END_STMT
+
+#define RETURN_NULL_IF_FAIL(TEST_EXPR, CTXT, LOC, ERR_MSG) \
+  RETURN_VAL_IF_FAIL ((TEST_EXPR), NULL, (CTXT), (LOC), (ERR_MSG))
+
+#define RETURN_NULL_IF_FAIL_PRINTF1(TEST_EXPR, CTXT, LOC, ERR_FMT, A0) \
+  RETURN_VAL_IF_FAIL_PRINTF1 (TEST_EXPR, NULL, CTXT, LOC, ERR_FMT, A0)
+
+#define RETURN_NULL_IF_FAIL_PRINTF2(TEST_EXPR, CTXT, LOC, ERR_FMT, A0, A1) \
+  RETURN_VAL_IF_FAIL_PRINTF2 (TEST_EXPR, NULL, CTXT, LOC, ERR_FMT, A0, A1)
+
+#define RETURN_NULL_IF_FAIL_PRINTF3(TEST_EXPR, CTXT, LOC, ERR_FMT, A0, A1, A2) \
+  RETURN_VAL_IF_FAIL_PRINTF3 (TEST_EXPR, NULL, CTXT, LOC, ERR_FMT, A0, A1, A2)
+
+#define RETURN_NULL_IF_FAIL_PRINTF4(TEST_EXPR, CTXT, LOC, ERR_FMT, A0, A1, A2, A3) \
+  RETURN_VAL_IF_FAIL_PRINTF4 (TEST_EXPR, NULL, CTXT, LOC, ERR_FMT, A0, A1, A2, A3)
+
+#define RETURN_NULL_IF_FAIL_PRINTF6(TEST_EXPR, CTXT, LOC, ERR_FMT, A0, A1, A2, A3, A4, A5) \
+  RETURN_VAL_IF_FAIL_PRINTF6 (TEST_EXPR, NULL, CTXT, LOC, ERR_FMT, A0, A1, A2, A3, A4, A5)
+
+#define RETURN_IF_FAIL(TEST_EXPR, CTXT, LOC, ERR_MSG)                  \
+  JIT_BEGIN_STMT                                                       \
+    if (!(TEST_EXPR))                                                  \
+      {                                                                \
+       jit_error ((CTXT), (LOC), "%s: %s", __func__, (ERR_MSG));               \
+       return;                                                 \
+      }                                                                \
+  JIT_END_STMT
+
+#define RETURN_IF_FAIL_PRINTF1(TEST_EXPR, CTXT, LOC, ERR_FMT, A0) \
+  JIT_BEGIN_STMT                                                       \
+    if (!(TEST_EXPR))                                                  \
+      {                                                                \
+       jit_error ((CTXT), (LOC), "%s: " ERR_FMT,                               \
+                  __func__, (A0));                                     \
+       return;                                                 \
+      }                                                                \
+  JIT_END_STMT
+
+#define RETURN_IF_FAIL_PRINTF2(TEST_EXPR, CTXT, LOC, ERR_FMT, A0, A1) \
+  JIT_BEGIN_STMT                                                       \
+    if (!(TEST_EXPR))                                                  \
+      {                                                                \
+       jit_error ((CTXT), (LOC), "%s: " ERR_FMT,                               \
+                  __func__, (A0), (A1));                               \
+       return;                                                 \
+      }                                                                \
+  JIT_END_STMT
+
+#define RETURN_IF_FAIL_PRINTF4(TEST_EXPR, CTXT, LOC, ERR_FMT, A0, A1, A2, A3) \
+  JIT_BEGIN_STMT                                                       \
+    if (!(TEST_EXPR))                                                  \
+      {                                                                \
+       jit_error ((CTXT), (LOC), "%s: " ERR_FMT,                               \
+                  __func__, (A0), (A1), (A2), (A3));                   \
+       return;                                                 \
+      }                                                                \
+  JIT_END_STMT
+
+/* Check that BLOCK is non-NULL, and that it's OK to add statements to
+   it.  This will fail if BLOCK has already been terminated by some
+   kind of jump or a return.  */
+#define RETURN_IF_NOT_VALID_BLOCK(BLOCK, LOC)                          \
+  JIT_BEGIN_STMT                                                       \
+    RETURN_IF_FAIL ((BLOCK), NULL, (LOC), "NULL block");               \
+    RETURN_IF_FAIL_PRINTF2 (                                           \
+      !(BLOCK)->has_been_terminated (),                                \
+      (BLOCK)->get_context (),                                         \
+      (LOC),                                                           \
+      "adding to terminated block: %s (already terminated by: %s)",    \
+      (BLOCK)->get_debug_string (),                                    \
+      (BLOCK)->get_last_statement ()->get_debug_string ());            \
+  JIT_END_STMT
+
+/* As RETURN_IF_NOT_VALID_BLOCK, but injecting a "return NULL;" if it
+   fails.  */
+#define RETURN_NULL_IF_NOT_VALID_BLOCK(BLOCK, LOC)                     \
+  JIT_BEGIN_STMT                                                       \
+    RETURN_NULL_IF_FAIL ((BLOCK), NULL, (LOC), "NULL block");          \
+    RETURN_NULL_IF_FAIL_PRINTF2 (                                      \
+      !(BLOCK)->has_been_terminated (),                                \
+      (BLOCK)->get_context (),                                         \
+      (LOC),                                                           \
+      "adding to terminated block: %s (already terminated by: %s)",    \
+      (BLOCK)->get_debug_string (),                                    \
+      (BLOCK)->get_last_statement ()->get_debug_string ());            \
+  JIT_END_STMT
+
+/* Format the given string, and report it as an error, either on CTXT
+   if non-NULL, or by printing to stderr if we have a NULL context.
+   LOC gives the source location where the error occcurred, and can be
+   NULL.  */
+
+static void
+jit_error (gcc::jit::recording::context *ctxt,
+          gcc_jit_location *loc,
+          const char *fmt, ...)
+  GNU_PRINTF(3, 4);
+
+static void
+jit_error (gcc::jit::recording::context *ctxt,
+          gcc_jit_location *loc,
+          const char *fmt, ...)
+{
+  va_list ap;
+  va_start (ap, fmt);
+
+  if (ctxt)
+    ctxt->add_error_va (loc, fmt, ap);
+  else
+    {
+      /* No context?  Send to stderr.  */
+      vfprintf (stderr, fmt, ap);
+      fprintf (stderr, "\n");
+    }
+
+  va_end (ap);
+}
+
+/* Determine whether or not we can write to lvalues of type LTYPE from
+   rvalues of type RTYPE, detecting type errors such as attempting to
+   write to an int with a string literal (without an explicit cast).
+
+   This is implemented by calling the
+   gcc::jit::recording::type::accepts_writes_from virtual function on
+   LTYPE.  */
+
+static bool
+compatible_types (gcc::jit::recording::type *ltype,
+                 gcc::jit::recording::type *rtype)
+{
+  return ltype->accepts_writes_from (rtype);
+}
+
+/* Public entrypoint for acquiring a gcc_jit_context.
+   Note that this creates a new top-level context; contrast with
+   gcc_jit_context_new_child_context below.
+
+   The real work is done in the constructor for
+   gcc::jit::recording::context in jit-recording.c. */
+
+gcc_jit_context *
+gcc_jit_context_acquire (void)
+{
+  return new gcc_jit_context (NULL);
+}
+
+/* Public entrypoint for releasing a gcc_jit_context.
+   The real work is done in the destructor for
+   gcc::jit::recording::context in jit-recording.c.  */
+
+void
+gcc_jit_context_release (gcc_jit_context *ctxt)
+{
+  delete ctxt;
+}
+
+/* Public entrypoint for creating a child context within
+   PARENT_CTXT.  See description in libgccjit.h.
+
+   The real work is done in the constructor for
+   gcc::jit::recording::context in jit-recording.c. */
+
+gcc_jit_context *
+gcc_jit_context_new_child_context (gcc_jit_context *parent_ctxt)
+{
+  return new gcc_jit_context (parent_ctxt);
+}
+
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, the real work is done by the
+     gcc::jit::recording::context::new_location
+   method in jit-recording.c.  */
+
+gcc_jit_location *
+gcc_jit_context_new_location (gcc_jit_context *ctxt,
+                             const char *filename,
+                             int line,
+                             int column)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+
+  return (gcc_jit_location *)ctxt->new_location (filename, line, column);
+}
+
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, this calls the trivial
+   gcc::jit::recording::memento::as_object method (a location is a
+   memento), in jit-recording.h.  */
+
+gcc_jit_object *
+gcc_jit_location_as_object (gcc_jit_location *loc)
+{
+  RETURN_NULL_IF_FAIL (loc, NULL, NULL, "NULL location");
+
+  return static_cast <gcc_jit_object *> (loc->as_object ());
+}
+
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, this calls the trivial
+   gcc::jit::recording::memento::as_object method (a type is a
+   memento), in jit-recording.h.  */
+
+gcc_jit_object *
+gcc_jit_type_as_object (gcc_jit_type *type)
+{
+  RETURN_NULL_IF_FAIL (type, NULL, NULL, "NULL type");
+
+  return static_cast <gcc_jit_object *> (type->as_object ());
+}
+
+/* Public entrypoint for getting a specific type from a context.
+
+   After error-checking, the real work is done by the
+   gcc::jit::recording::context::get_type method, in
+   jit-recording.c  */
+
+gcc_jit_type *
+gcc_jit_context_get_type (gcc_jit_context *ctxt,
+                         enum gcc_jit_types type)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+  RETURN_NULL_IF_FAIL_PRINTF1 (
+    (type >= GCC_JIT_TYPE_VOID
+     && type <= GCC_JIT_TYPE_FILE_PTR),
+    ctxt, NULL,
+    "unrecognized value for enum gcc_jit_types: %i", type);
+
+  return (gcc_jit_type *)ctxt->get_type (type);
+}
+
+/* Public entrypoint for getting the integer type of the given size and
+   signedness.
+
+   After error-checking, the real work is done by the
+   gcc::jit::recording::context::get_int_type method,
+   in jit-recording.c.  */
+
+gcc_jit_type *
+gcc_jit_context_get_int_type (gcc_jit_context *ctxt,
+                             int num_bytes, int is_signed)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+  RETURN_NULL_IF_FAIL (num_bytes >= 0, ctxt, NULL, "negative size");
+
+  return (gcc_jit_type *)ctxt->get_int_type (num_bytes, is_signed);
+}
+
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, the real work is done by the
+   gcc::jit::recording::type::get_pointer method, in
+   jit-recording.c  */
+
+gcc_jit_type *
+gcc_jit_type_get_pointer (gcc_jit_type *type)
+{
+  RETURN_NULL_IF_FAIL (type, NULL, NULL, "NULL type");
+
+  return (gcc_jit_type *)type->get_pointer ();
+}
+
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, the real work is done by the
+   gcc::jit::recording::type::get_const method, in
+   jit-recording.c.  */
+
+gcc_jit_type *
+gcc_jit_type_get_const (gcc_jit_type *type)
+{
+  RETURN_NULL_IF_FAIL (type, NULL, NULL, "NULL type");
+
+  return (gcc_jit_type *)type->get_const ();
+}
+
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, the real work is done by the
+   gcc::jit::recording::type::get_volatile method, in
+   jit-recording.c.  */
+
+gcc_jit_type *
+gcc_jit_type_get_volatile (gcc_jit_type *type)
+{
+  RETURN_NULL_IF_FAIL (type, NULL, NULL, "NULL type");
+
+  return (gcc_jit_type *)type->get_volatile ();
+}
+
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, the real work is done by the
+   gcc::jit::recording::context::new_array_type method, in
+   jit-recording.c.  */
+
+gcc_jit_type *
+gcc_jit_context_new_array_type (gcc_jit_context *ctxt,
+                               gcc_jit_location *loc,
+                               gcc_jit_type *element_type,
+                               int num_elements)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL context");
+  /* LOC can be NULL.  */
+  RETURN_NULL_IF_FAIL (element_type, ctxt, loc, "NULL type");
+  RETURN_NULL_IF_FAIL (num_elements >= 0, ctxt, NULL, "negative size");
+
+  return (gcc_jit_type *)ctxt->new_array_type (loc,
+                                              element_type,
+                                              num_elements);
+}
+
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, the real work is done by the
+   gcc::jit::recording::context::new_field method, in
+   jit-recording.c.  */
+
+gcc_jit_field *
+gcc_jit_context_new_field (gcc_jit_context *ctxt,
+                          gcc_jit_location *loc,
+                          gcc_jit_type *type,
+                          const char *name)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+  /* LOC can be NULL.  */
+  RETURN_NULL_IF_FAIL (type, ctxt, loc, "NULL type");
+  RETURN_NULL_IF_FAIL (name, ctxt, loc, "NULL name");
+
+  return (gcc_jit_field *)ctxt->new_field (loc, type, name);
+}
+
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, this calls the trivial
+   gcc::jit::recording::memento::as_object method (a field is a
+   memento), in jit-recording.h.  */
+
+gcc_jit_object *
+gcc_jit_field_as_object (gcc_jit_field *field)
+{
+  RETURN_NULL_IF_FAIL (field, NULL, NULL, "NULL field");
+
+  return static_cast <gcc_jit_object *> (field->as_object ());
+}
+
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, the real work is done by the
+   gcc::jit::recording::context::new_struct_type method,
+   immediately followed by a "set_fields" call on the resulting
+   gcc::jit::recording::compound_type *, both in jit-recording.c  */
+
+gcc_jit_struct *
+gcc_jit_context_new_struct_type (gcc_jit_context *ctxt,
+                                gcc_jit_location *loc,
+                                const char *name,
+                                int num_fields,
+                                gcc_jit_field **fields)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+  /* LOC can be NULL.  */
+  RETURN_NULL_IF_FAIL (name, ctxt, loc, "NULL name");
+  if (num_fields)
+    RETURN_NULL_IF_FAIL (fields, ctxt, loc, "NULL fields ptr");
+  for (int i = 0; i < num_fields; i++)
+    {
+      RETURN_NULL_IF_FAIL (fields[i], ctxt, loc, "NULL field ptr");
+      RETURN_NULL_IF_FAIL_PRINTF2 (
+       NULL == fields[i]->get_container (),
+       ctxt, loc,
+       "%s is already a field of %s",
+       fields[i]->get_debug_string (),
+       fields[i]->get_container ()->get_debug_string ());
+    }
+
+  gcc::jit::recording::struct_ *result =
+    ctxt->new_struct_type (loc, name);
+  result->set_fields (loc,
+                     num_fields,
+                     (gcc::jit::recording::field **)fields);
+  return static_cast<gcc_jit_struct *> (result);
+}
+
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, the real work is done by the
+   gcc::jit::recording::context::new_struct_type method in
+   jit-recording.c.  */
+
+gcc_jit_struct *
+gcc_jit_context_new_opaque_struct (gcc_jit_context *ctxt,
+                                  gcc_jit_location *loc,
+                                  const char *name)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL context");
+  /* LOC can be NULL.  */
+  RETURN_NULL_IF_FAIL (name, ctxt, loc, "NULL name");
+
+  return (gcc_jit_struct *)ctxt->new_struct_type (loc, name);
+}
+
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, this calls the trivial
+   gcc::jit::recording::struct_::as_object method in
+   jit-recording.h.  */
+
+gcc_jit_type *
+gcc_jit_struct_as_type (gcc_jit_struct *struct_type)
+{
+  RETURN_NULL_IF_FAIL (struct_type, NULL, NULL, "NULL struct_type");
+
+  return static_cast <gcc_jit_type *> (struct_type->as_type ());
+}
+
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, the real work is done by the
+   gcc::jit::recording::compound_type::set_fields method in
+   jit-recording.c.  */
+
+void
+gcc_jit_struct_set_fields (gcc_jit_struct *struct_type,
+                          gcc_jit_location *loc,
+                          int num_fields,
+                          gcc_jit_field **fields)
+{
+  RETURN_IF_FAIL (struct_type, NULL, loc, "NULL struct_type");
+  /* LOC can be NULL.  */
+  gcc::jit::recording::context *ctxt = struct_type->m_ctxt;
+  RETURN_IF_FAIL_PRINTF1 (
+    NULL == struct_type->get_fields (), ctxt, loc,
+    "%s already has had fields set",
+    struct_type->get_debug_string ());
+  if (num_fields)
+    RETURN_IF_FAIL (fields, ctxt, loc, "NULL fields ptr");
+  for (int i = 0; i < num_fields; i++)
+    {
+      RETURN_IF_FAIL (fields[i], ctxt, loc, "NULL field ptr");
+      RETURN_IF_FAIL_PRINTF2 (
+       NULL == fields[i]->get_container (),
+       ctxt, loc,
+       "%s is already a field of %s",
+       fields[i]->get_debug_string (),
+       fields[i]->get_container ()->get_debug_string ());
+    }
+
+  struct_type->set_fields (loc, num_fields,
+                          (gcc::jit::recording::field **)fields);
+}
+
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, the real work is done by the
+   gcc::jit::recording::context::new_union_type method,
+   immediately followed by a "set_fields" call on the resulting
+   gcc::jit::recording::compound_type *, both in jit-recording.c  */
+
+gcc_jit_type *
+gcc_jit_context_new_union_type (gcc_jit_context *ctxt,
+                               gcc_jit_location *loc,
+                               const char *name,
+                               int num_fields,
+                               gcc_jit_field **fields)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+  /* LOC can be NULL.  */
+  RETURN_NULL_IF_FAIL (name, ctxt, loc, "NULL name");
+  if (num_fields)
+    RETURN_NULL_IF_FAIL (fields, ctxt, loc, "NULL fields ptr");
+  for (int i = 0; i < num_fields; i++)
+    {
+      RETURN_NULL_IF_FAIL (fields[i], ctxt, loc, "NULL field ptr");
+      RETURN_NULL_IF_FAIL_PRINTF2 (
+       NULL == fields[i]->get_container (),
+       ctxt, loc,
+       "%s is already a field of %s",
+       fields[i]->get_debug_string (),
+       fields[i]->get_container ()->get_debug_string ());
+    }
+
+  gcc::jit::recording::union_ *result =
+    ctxt->new_union_type (loc, name);
+  result->set_fields (loc,
+                     num_fields,
+                     (gcc::jit::recording::field **)fields);
+  return (gcc_jit_type *) (result);
+}
+
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, the real work is done by the
+   gcc::jit::recording::context::new_function_ptr_type method,
+   in jit-recording.c  */
+
+gcc_jit_type *
+gcc_jit_context_new_function_ptr_type (gcc_jit_context *ctxt,
+                                      gcc_jit_location *loc,
+                                      gcc_jit_type *return_type,
+                                      int num_params,
+                                      gcc_jit_type **param_types,
+                                      int is_variadic)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL context");
+  /* LOC can be NULL.  */
+  RETURN_NULL_IF_FAIL (return_type, ctxt, loc, "NULL return_type");
+  RETURN_NULL_IF_FAIL (
+    (num_params == 0) || param_types,
+    ctxt, loc,
+    "NULL param_types creating function pointer type");
+  for (int i = 0; i < num_params; i++)
+    RETURN_NULL_IF_FAIL_PRINTF1 (
+      param_types[i],
+      ctxt, loc,
+      "NULL parameter type %i creating function pointer type", i);
+
+  return (gcc_jit_type*)
+    ctxt->new_function_ptr_type (loc, return_type,
+                                num_params,
+                                (gcc::jit::recording::type **)param_types,
+                                is_variadic);
+}
+
+/* Constructing functions.  */
+
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, the real work is done by the
+   gcc::jit::recording::context::new_param method, in jit-recording.c  */
+
+gcc_jit_param *
+gcc_jit_context_new_param (gcc_jit_context *ctxt,
+                          gcc_jit_location *loc,
+                          gcc_jit_type *type,
+                          const char *name)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL context");
+  /* LOC can be NULL.  */
+  RETURN_NULL_IF_FAIL (type, ctxt, loc, "NULL type");
+  RETURN_NULL_IF_FAIL (name, ctxt, loc, "NULL name");
+
+  return (gcc_jit_param *)ctxt->new_param (loc, type, name);
+}
+
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, this calls the trivial
+   gcc::jit::recording::memento::as_object method (a param is a memento),
+   in jit-recording.h.  */
+
+gcc_jit_object *
+gcc_jit_param_as_object (gcc_jit_param *param)
+{
+  RETURN_NULL_IF_FAIL (param, NULL, NULL, "NULL param");
+
+  return static_cast <gcc_jit_object *> (param->as_object ());
+}
+
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, this calls the trivial
+   gcc::jit::recording::param::as_lvalue method in jit-recording.h.  */
+
+gcc_jit_lvalue *
+gcc_jit_param_as_lvalue (gcc_jit_param *param)
+{
+  RETURN_NULL_IF_FAIL (param, NULL, NULL, "NULL param");
+
+  return (gcc_jit_lvalue *)param->as_lvalue ();
+}
+
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, this calls the trivial
+   gcc::jit::recording::lvalue::as_rvalue method (a param is an rvalue),
+   in jit-recording.h.  */
+
+gcc_jit_rvalue *
+gcc_jit_param_as_rvalue (gcc_jit_param *param)
+{
+  RETURN_NULL_IF_FAIL (param, NULL, NULL, "NULL param");
+
+  return (gcc_jit_rvalue *)param->as_rvalue ();
+}
+
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, the real work is done by the
+   gcc::jit::recording::context::new_function method, in
+   jit-recording.c.  */
+
+gcc_jit_function *
+gcc_jit_context_new_function (gcc_jit_context *ctxt,
+                             gcc_jit_location *loc,
+                             enum gcc_jit_function_kind kind,
+                             gcc_jit_type *return_type,
+                             const char *name,
+                             int num_params,
+                             gcc_jit_param **params,
+                             int is_variadic)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL context");
+  /* LOC can be NULL.  */
+  RETURN_NULL_IF_FAIL_PRINTF1 (
+    ((kind >= GCC_JIT_FUNCTION_EXPORTED)
+     && (kind <= GCC_JIT_FUNCTION_ALWAYS_INLINE)),
+    ctxt, loc,
+    "unrecognized value for enum gcc_jit_function_kind: %i",
+    kind);
+  RETURN_NULL_IF_FAIL (return_type, ctxt, loc, "NULL return_type");
+  RETURN_NULL_IF_FAIL (name, ctxt, loc, "NULL name");
+  /* The assembler can only handle certain names, so for now, enforce
+     C's rules for identiers upon the name, using ISALPHA and ISALNUM
+     from safe-ctype.h to ignore the current locale.
+     Eventually we'll need some way to interact with e.g. C++ name
+     mangling.  */
+  {
+    /* Leading char: */
+    char ch = *name;
+    RETURN_NULL_IF_FAIL_PRINTF2 (
+       ISALPHA (ch) || ch == '_',
+       ctxt, loc,
+       "name \"%s\" contains invalid character: '%c'",
+       name, ch);
+    /* Subsequent chars: */
+    for (const char *ptr = name + 1; (ch = *ptr); ptr++)
+      {
+       RETURN_NULL_IF_FAIL_PRINTF2 (
+         ISALNUM (ch) || ch == '_',
+         ctxt, loc,
+         "name \"%s\" contains invalid character: '%c'",
+         name, ch);
+      }
+  }
+  RETURN_NULL_IF_FAIL_PRINTF1 (
+    (num_params == 0) || params,
+    ctxt, loc,
+    "NULL params creating function %s", name);
+  for (int i = 0; i < num_params; i++)
+    RETURN_NULL_IF_FAIL_PRINTF2 (
+      params[i],
+      ctxt, loc,
+      "NULL parameter %i creating function %s", i, name);
+
+  return (gcc_jit_function*)
+    ctxt->new_function (loc, kind, return_type, name,
+                       num_params,
+                       (gcc::jit::recording::param **)params,
+                       is_variadic,
+                       BUILT_IN_NONE);
+}
+
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, the real work is done by the
+   gcc::jit::recording::context::get_builtin_function method, in
+   jit-recording.c.  */
+
+gcc_jit_function *
+gcc_jit_context_get_builtin_function (gcc_jit_context *ctxt,
+                                     const char *name)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+  RETURN_NULL_IF_FAIL (name, ctxt, NULL, "NULL name");
+
+  return static_cast <gcc_jit_function *> (ctxt->get_builtin_function (name));
+}
+
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, this calls the trivial
+   gcc::jit::recording::memento::as_object method (a function is a
+   memento), in jit-recording.h.  */
+
+gcc_jit_object *
+gcc_jit_function_as_object (gcc_jit_function *func)
+{
+  RETURN_NULL_IF_FAIL (func, NULL, NULL, "NULL function");
+
+  return static_cast <gcc_jit_object *> (func->as_object ());
+}
+
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, the real work is done by the
+   gcc::jit::recording::function::get_param method, in
+   jit-recording.h.  */
+
+gcc_jit_param *
+gcc_jit_function_get_param (gcc_jit_function *func, int index)
+{
+  RETURN_NULL_IF_FAIL (func, NULL, NULL, "NULL function");
+  gcc::jit::recording::context *ctxt = func->m_ctxt;
+  RETURN_NULL_IF_FAIL (index >= 0, ctxt, NULL, "negative index");
+  int num_params = func->get_params ().length ();
+  RETURN_NULL_IF_FAIL_PRINTF3 (index < num_params,
+                              ctxt, NULL,
+                              "index of %d is too large (%s has %d params)",
+                              index,
+                              func->get_debug_string (),
+                              num_params);
+
+  return static_cast <gcc_jit_param *> (func->get_param (index));
+}
+
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, the real work is done by the
+   gcc::jit::recording::function::dump_to_dot method, in
+   jit-recording.c.  */
+
+void
+gcc_jit_function_dump_to_dot (gcc_jit_function *func,
+                             const char *path)
+{
+  RETURN_IF_FAIL (func, NULL, NULL, "NULL function");
+  gcc::jit::recording::context *ctxt = func->m_ctxt;
+  RETURN_IF_FAIL (path, ctxt, NULL, "NULL path");
+
+  func->dump_to_dot (path);
+}
+
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, the real work is done by the
+   gcc::jit::recording::function::new_block method, in
+   jit-recording.c.  */
+
+gcc_jit_block*
+gcc_jit_function_new_block (gcc_jit_function *func,
+                           const char *name)
+{
+  RETURN_NULL_IF_FAIL (func, NULL, NULL, "NULL function");
+  RETURN_NULL_IF_FAIL (func->get_kind () != GCC_JIT_FUNCTION_IMPORTED,
+                      func->get_context (), NULL,
+                      "cannot add block to an imported function");
+  /* name can be NULL.  */
+
+  return (gcc_jit_block *)func->new_block (name);
+}
+
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, this calls the trivial
+   gcc::jit::recording::memento::as_object method (a block is a
+   memento), in jit-recording.h.  */
+
+gcc_jit_object *
+gcc_jit_block_as_object (gcc_jit_block *block)
+{
+  RETURN_NULL_IF_FAIL (block, NULL, NULL, "NULL block");
+
+  return static_cast <gcc_jit_object *> (block->as_object ());
+}
+
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, the real work is done by the
+   gcc::jit::recording::block::get_function method, in
+   jit-recording.h.  */
+
+gcc_jit_function *
+gcc_jit_block_get_function (gcc_jit_block *block)
+{
+  RETURN_NULL_IF_FAIL (block, NULL, NULL, "NULL block");
+
+  return static_cast <gcc_jit_function *> (block->get_function ());
+}
+
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, the real work is done by the
+   gcc::jit::recording::context::new_global method, in
+   jit-recording.c.  */
+
+gcc_jit_lvalue *
+gcc_jit_context_new_global (gcc_jit_context *ctxt,
+                           gcc_jit_location *loc,
+                           gcc_jit_type *type,
+                           const char *name)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL context");
+  /* LOC can be NULL.  */
+  RETURN_NULL_IF_FAIL (type, ctxt, loc, "NULL type");
+  RETURN_NULL_IF_FAIL (name, ctxt, loc, "NULL name");
+
+  return (gcc_jit_lvalue *)ctxt->new_global (loc, type, name);
+}
+
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, this calls the trivial
+   gcc::jit::recording::memento::as_object method (an lvalue is a
+   memento), in jit-recording.h.  */
+
+gcc_jit_object *
+gcc_jit_lvalue_as_object (gcc_jit_lvalue *lvalue)
+{
+  RETURN_NULL_IF_FAIL (lvalue, NULL, NULL, "NULL lvalue");
+
+  return static_cast <gcc_jit_object *> (lvalue->as_object ());
+}
+
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, this calls the trivial
+   gcc::jit::recording::lvalue::as_rvalue method in jit-recording.h.  */
+
+gcc_jit_rvalue *
+gcc_jit_lvalue_as_rvalue (gcc_jit_lvalue *lvalue)
+{
+  RETURN_NULL_IF_FAIL (lvalue, NULL, NULL, "NULL lvalue");
+
+  return (gcc_jit_rvalue *)lvalue->as_rvalue ();
+}
+
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, this calls the trivial
+   gcc::jit::recording::memento::as_object method (an rvalue is a
+   memento), in jit-recording.h.  */
+
+gcc_jit_object *
+gcc_jit_rvalue_as_object (gcc_jit_rvalue *rvalue)
+{
+  RETURN_NULL_IF_FAIL (rvalue, NULL, NULL, "NULL rvalue");
+
+  return static_cast <gcc_jit_object *> (rvalue->as_object ());
+}
+
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, the real work is done by the
+   gcc::jit::recording::rvalue::get_type method, in
+   jit-recording.h.  */
+
+gcc_jit_type *
+gcc_jit_rvalue_get_type (gcc_jit_rvalue *rvalue)
+{
+  RETURN_NULL_IF_FAIL (rvalue, NULL, NULL, "NULL rvalue");
+
+  return static_cast <gcc_jit_type *> (rvalue->get_type ());
+}
+
+/* Verify that NUMERIC_TYPE is non-NULL, and that it is a "numeric"
+   type i.e. it satisfies gcc::jit::type::is_numeric (), such as the
+   result of gcc_jit_context_get_type (GCC_JIT_TYPE_INT).  */
+
+#define RETURN_NULL_IF_FAIL_NONNULL_NUMERIC_TYPE(CTXT, NUMERIC_TYPE) \
+  RETURN_NULL_IF_FAIL (NUMERIC_TYPE, CTXT, NULL, "NULL type"); \
+  RETURN_NULL_IF_FAIL_PRINTF1 (                                \
+    NUMERIC_TYPE->is_numeric (), ctxt, NULL,                   \
+    "not a numeric type: %s",                                  \
+    NUMERIC_TYPE->get_debug_string ());
+
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, the real work is done by the
+   gcc::jit::recording::context::new_rvalue_from_int method in
+   jit-recording.c.  */
+
+gcc_jit_rvalue *
+gcc_jit_context_new_rvalue_from_int (gcc_jit_context *ctxt,
+                                    gcc_jit_type *numeric_type,
+                                    int value)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+  RETURN_NULL_IF_FAIL_NONNULL_NUMERIC_TYPE (ctxt, numeric_type);
+
+  return (gcc_jit_rvalue *)ctxt->new_rvalue_from_int (numeric_type, value);
+}
+
+/* Public entrypoint.  See description in libgccjit.h.
+
+   This is essentially equivalent to:
+      gcc_jit_context_new_rvalue_from_int (ctxt, numeric_type, 0);
+   albeit with slightly different error messages if an error occurs.  */
+
+gcc_jit_rvalue *
+gcc_jit_context_zero (gcc_jit_context *ctxt,
+                     gcc_jit_type *numeric_type)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+  RETURN_NULL_IF_FAIL_NONNULL_NUMERIC_TYPE (ctxt, numeric_type);
+
+  return gcc_jit_context_new_rvalue_from_int (ctxt, numeric_type, 0);
+}
+
+/* Public entrypoint.  See description in libgccjit.h.
+
+   This is essentially equivalent to:
+      gcc_jit_context_new_rvalue_from_int (ctxt, numeric_type, 1);
+   albeit with slightly different error messages if an error occurs.  */
+
+gcc_jit_rvalue *
+gcc_jit_context_one (gcc_jit_context *ctxt,
+                    gcc_jit_type *numeric_type)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+  RETURN_NULL_IF_FAIL_NONNULL_NUMERIC_TYPE (ctxt, numeric_type);
+
+  return gcc_jit_context_new_rvalue_from_int (ctxt, numeric_type, 1);
+}
+
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, the real work is done by the
+   gcc::jit::recording::context::new_rvalue_from_double method in
+   jit-recording.c.  */
+
+gcc_jit_rvalue *
+gcc_jit_context_new_rvalue_from_double (gcc_jit_context *ctxt,
+                                       gcc_jit_type *numeric_type,
+                                       double value)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+  RETURN_NULL_IF_FAIL_NONNULL_NUMERIC_TYPE (ctxt, numeric_type);
+
+  return (gcc_jit_rvalue *)ctxt->new_rvalue_from_double (numeric_type, value);
+}
+
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, the real work is done by the
+   gcc::jit::recording::context::new_rvalue_from_ptr method in
+   jit-recording.c.  */
+
+gcc_jit_rvalue *
+gcc_jit_context_new_rvalue_from_ptr (gcc_jit_context *ctxt,
+                                    gcc_jit_type *pointer_type,
+                                    void *value)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+  RETURN_NULL_IF_FAIL (pointer_type, ctxt, NULL, "NULL type");
+  RETURN_NULL_IF_FAIL_PRINTF1 (
+    pointer_type->is_pointer (),
+    ctxt, NULL,
+    "not a pointer type (type: %s)",
+    pointer_type->get_debug_string ());
+
+  return (gcc_jit_rvalue *)ctxt->new_rvalue_from_ptr (pointer_type, value);
+}
+
+/* Public entrypoint.  See description in libgccjit.h.
+
+   This is essentially equivalent to:
+      gcc_jit_context_new_rvalue_from_ptr (ctxt, pointer_type, NULL);
+   albeit with slightly different error messages if an error occurs.  */
+
+gcc_jit_rvalue *
+gcc_jit_context_null (gcc_jit_context *ctxt,
+                     gcc_jit_type *pointer_type)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+  RETURN_NULL_IF_FAIL (pointer_type, ctxt, NULL, "NULL type");
+  RETURN_NULL_IF_FAIL_PRINTF1 (
+    pointer_type->is_pointer (),
+    ctxt, NULL,
+    "not a pointer type (type: %s)",
+    pointer_type->get_debug_string ());
+
+  return gcc_jit_context_new_rvalue_from_ptr (ctxt, pointer_type, NULL);
+}
+
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, the real work is done by the
+   gcc::jit::recording::context::new_string_literal method in
+   jit-recording.c.  */
+
+gcc_jit_rvalue *
+gcc_jit_context_new_string_literal (gcc_jit_context *ctxt,
+                                   const char *value)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+  RETURN_NULL_IF_FAIL (value, ctxt, NULL, "NULL value");
+
+  return (gcc_jit_rvalue *)ctxt->new_string_literal (value);
+}
+
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, the real work is done by the
+   gcc::jit::recording::context::new_unary_op method in
+   jit-recording.c.  */
+
+gcc_jit_rvalue *
+gcc_jit_context_new_unary_op (gcc_jit_context *ctxt,
+                             gcc_jit_location *loc,
+                             enum gcc_jit_unary_op op,
+                             gcc_jit_type *result_type,
+                             gcc_jit_rvalue *rvalue)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL context");
+  /* LOC can be NULL.  */
+  RETURN_NULL_IF_FAIL_PRINTF1 (
+    (op >= GCC_JIT_UNARY_OP_MINUS
+     && op <= GCC_JIT_UNARY_OP_LOGICAL_NEGATE),
+    ctxt, loc,
+    "unrecognized value for enum gcc_jit_unary_op: %i",
+    op);
+  RETURN_NULL_IF_FAIL (result_type, ctxt, loc, "NULL result_type");
+  RETURN_NULL_IF_FAIL (rvalue, ctxt, loc, "NULL rvalue");
+
+  return (gcc_jit_rvalue *)ctxt->new_unary_op (loc, op, result_type, rvalue);
+}
+
+/* Determine if OP is a valid value for enum gcc_jit_binary_op.
+   For use by both gcc_jit_context_new_binary_op and
+   gcc_jit_block_add_assignment_op.  */
+
+static bool
+valid_binary_op_p (enum gcc_jit_binary_op op)
+{
+  return (op >= GCC_JIT_BINARY_OP_PLUS
+         && op <= GCC_JIT_BINARY_OP_RSHIFT);
+}
+
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, the real work is done by the
+   gcc::jit::recording::context::new_binary_op method in
+   jit-recording.c.  */
+
+gcc_jit_rvalue *
+gcc_jit_context_new_binary_op (gcc_jit_context *ctxt,
+                              gcc_jit_location *loc,
+                              enum gcc_jit_binary_op op,
+                              gcc_jit_type *result_type,
+                              gcc_jit_rvalue *a, gcc_jit_rvalue *b)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL context");
+  /* LOC can be NULL.  */
+  RETURN_NULL_IF_FAIL_PRINTF1 (
+    valid_binary_op_p (op),
+    ctxt, loc,
+    "unrecognized value for enum gcc_jit_binary_op: %i",
+    op);
+  RETURN_NULL_IF_FAIL (result_type, ctxt, loc, "NULL result_type");
+  RETURN_NULL_IF_FAIL (a, ctxt, loc, "NULL a");
+  RETURN_NULL_IF_FAIL (b, ctxt, loc, "NULL b");
+  RETURN_NULL_IF_FAIL_PRINTF4 (
+    a->get_type () == b->get_type (),
+    ctxt, loc,
+    "mismatching types for binary op:"
+    " a: %s (type: %s) b: %s (type: %s)",
+    a->get_debug_string (),
+    a->get_type ()->get_debug_string (),
+    b->get_debug_string (),
+    b->get_type ()->get_debug_string ());
+
+  return (gcc_jit_rvalue *)ctxt->new_binary_op (loc, op, result_type, a, b);
+}
+
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, the real work is done by the
+   gcc::jit::recording::context::new_comparison method in
+   jit-recording.c.  */
+
+gcc_jit_rvalue *
+gcc_jit_context_new_comparison (gcc_jit_context *ctxt,
+                               gcc_jit_location *loc,
+                               enum gcc_jit_comparison op,
+                               gcc_jit_rvalue *a, gcc_jit_rvalue *b)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL context");
+  /* LOC can be NULL.  */
+  RETURN_NULL_IF_FAIL_PRINTF1 (
+    (op >= GCC_JIT_COMPARISON_EQ
+     && op <= GCC_JIT_COMPARISON_GE),
+    ctxt, loc,
+    "unrecognized value for enum gcc_jit_comparison: %i",
+    op);
+  RETURN_NULL_IF_FAIL (a, ctxt, loc, "NULL a");
+  RETURN_NULL_IF_FAIL (b, ctxt, loc, "NULL b");
+  RETURN_NULL_IF_FAIL_PRINTF4 (
+    a->get_type ()->unqualified () == b->get_type ()->unqualified (),
+    ctxt, loc,
+    "mismatching types for comparison:"
+    " a: %s (type: %s) b: %s (type: %s)",
+    a->get_debug_string (),
+    a->get_type ()->get_debug_string (),
+    b->get_debug_string (),
+    b->get_type ()->get_debug_string ());
+
+  return (gcc_jit_rvalue *)ctxt->new_comparison (loc, op, a, b);
+}
+
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, the real work is done by the
+   gcc::jit::recording::context::new_call method in
+   jit-recording.c.  */
+
+gcc_jit_rvalue *
+gcc_jit_context_new_call (gcc_jit_context *ctxt,
+                         gcc_jit_location *loc,
+                         gcc_jit_function *func,
+                         int numargs , gcc_jit_rvalue **args)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL context");
+  /* LOC can be NULL.  */
+  RETURN_NULL_IF_FAIL (func, ctxt, loc, "NULL function");
+  if (numargs)
+    RETURN_NULL_IF_FAIL (args, ctxt, loc, "NULL args");
+
+  int min_num_params = func->get_params ().length ();
+  bool is_variadic = func->is_variadic ();
+
+  RETURN_NULL_IF_FAIL_PRINTF3 (
+    numargs >= min_num_params,
+    ctxt, loc,
+    "not enough arguments to function \"%s\""
+    " (got %i args, expected %i)",
+    func->get_name ()->c_str (),
+    numargs, min_num_params);
+
+  RETURN_NULL_IF_FAIL_PRINTF3 (
+    (numargs == min_num_params || is_variadic),
+    ctxt, loc,
+    "too many arguments to function \"%s\""
+    " (got %i args, expected %i)",
+    func->get_name ()->c_str (),
+    numargs, min_num_params);
+
+  for (int i = 0; i < min_num_params; i++)
+    {
+      gcc::jit::recording::param *param = func->get_param (i);
+      gcc_jit_rvalue *arg = args[i];
+
+      RETURN_NULL_IF_FAIL_PRINTF4 (
+       arg,
+       ctxt, loc,
+       "NULL argument %i to function \"%s\":"
+       " param %s (type: %s)",
+       i + 1,
+       func->get_name ()->c_str (),
+       param->get_debug_string (),
+       param->get_type ()->get_debug_string ());
+
+      RETURN_NULL_IF_FAIL_PRINTF6 (
+       compatible_types (param->get_type (),
+                         arg->get_type ()),
+       ctxt, loc,
+       "mismatching types for argument %d of function \"%s\":"
+       " assignment to param %s (type: %s) from %s (type: %s)",
+       i + 1,
+       func->get_name ()->c_str (),
+       param->get_debug_string (),
+       param->get_type ()->get_debug_string (),
+       arg->get_debug_string (),
+       arg->get_type ()->get_debug_string ());
+    }
+
+  return (gcc_jit_rvalue *)ctxt->new_call (loc,
+                                          func,
+                                          numargs,
+                                          (gcc::jit::recording::rvalue **)args);
+}
+
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, the real work is done by the
+   gcc::jit::recording::context::new_call_through_ptr method in
+   jit-recording.c.  */
+
+gcc_jit_rvalue *
+gcc_jit_context_new_call_through_ptr (gcc_jit_context *ctxt,
+                                     gcc_jit_location *loc,
+                                     gcc_jit_rvalue *fn_ptr,
+                                     int numargs, gcc_jit_rvalue **args)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL context");
+  /* LOC can be NULL.  */
+  RETURN_NULL_IF_FAIL (fn_ptr, ctxt, loc, "NULL fn_ptr");
+  if (numargs)
+    RETURN_NULL_IF_FAIL (args, ctxt, loc, "NULL args");
+
+  gcc::jit::recording::type *ptr_type = fn_ptr->get_type ()->dereference ();
+  RETURN_NULL_IF_FAIL_PRINTF2 (
+    ptr_type, ctxt, loc,
+    "fn_ptr is not a ptr: %s"
+    " type: %s",
+    fn_ptr->get_debug_string (),
+    fn_ptr->get_type ()->get_debug_string ());
+
+  gcc::jit::recording::function_type *fn_type =
+    ptr_type->dyn_cast_function_type();
+  RETURN_NULL_IF_FAIL_PRINTF2 (
+    fn_type, ctxt, loc,
+    "fn_ptr is not a function ptr: %s"
+    " type: %s",
+    fn_ptr->get_debug_string (),
+    fn_ptr->get_type ()->get_debug_string ());
+
+  int min_num_params = fn_type->get_param_types ().length ();
+  bool is_variadic = fn_type->is_variadic ();
+
+  RETURN_NULL_IF_FAIL_PRINTF3 (
+    numargs >= min_num_params,
+    ctxt, loc,
+    "not enough arguments to fn_ptr: %s"
+    " (got %i args, expected %i)",
+    fn_ptr->get_debug_string (),
+    numargs, min_num_params);
+
+  RETURN_NULL_IF_FAIL_PRINTF3 (
+    (numargs == min_num_params || is_variadic),
+    ctxt, loc,
+    "too many arguments to fn_ptr: %s"
+    " (got %i args, expected %i)",
+    fn_ptr->get_debug_string (),
+    numargs, min_num_params);
+
+  for (int i = 0; i < min_num_params; i++)
+    {
+      gcc::jit::recording::type *param_type = fn_type->get_param_types ()[i];
+      gcc_jit_rvalue *arg = args[i];
+
+      RETURN_NULL_IF_FAIL_PRINTF3 (
+       arg,
+       ctxt, loc,
+       "NULL argument %i to fn_ptr: %s"
+       " (type: %s)",
+       i + 1,
+       fn_ptr->get_debug_string (),
+       param_type->get_debug_string ());
+
+      RETURN_NULL_IF_FAIL_PRINTF6 (
+       compatible_types (param_type,
+                         arg->get_type ()),
+       ctxt, loc,
+       "mismatching types for argument %d of fn_ptr: %s:"
+       " assignment to param %d (type: %s) from %s (type: %s)",
+       i + 1,
+       fn_ptr->get_debug_string (),
+       i + 1,
+       param_type->get_debug_string (),
+       arg->get_debug_string (),
+       arg->get_type ()->get_debug_string ());
+    }
+
+  return (gcc_jit_rvalue *)(
+           ctxt->new_call_through_ptr (loc,
+                                       fn_ptr,
+                                       numargs,
+                                       (gcc::jit::recording::rvalue **)args));
+}
+
+/* Helper function for determining if we can cast an rvalue from SRC_TYPE
+   to DST_TYPE, for use by gcc_jit_context_new_cast.
+
+   We only permit these kinds of cast:
+
+     int <-> float
+     int <-> bool
+     P*  <-> Q*   for pointer types P and Q.  */
+
+static bool
+is_valid_cast (gcc::jit::recording::type *src_type,
+              gcc_jit_type *dst_type)
+{
+  bool src_is_int = src_type->is_int ();
+  bool dst_is_int = dst_type->is_int ();
+  bool src_is_float = src_type->is_float ();
+  bool dst_is_float = dst_type->is_float ();
+  bool src_is_bool = src_type->is_bool ();
+  bool dst_is_bool = dst_type->is_bool ();
+
+  if (src_is_int)
+    if (dst_is_int || dst_is_float || dst_is_bool)
+      return true;
+
+  if (src_is_float)
+    if (dst_is_int || dst_is_float)
+      return true;
+
+  if (src_is_bool)
+    if (dst_is_int || dst_is_bool)
+      return true;
+
+  /* Permit casts between pointer types.  */
+  gcc::jit::recording::type *deref_src_type = src_type->is_pointer ();
+  gcc::jit::recording::type *deref_dst_type = dst_type->is_pointer ();
+  if (deref_src_type && deref_dst_type)
+    return true;
+
+  return false;
+}
+
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, the real work is done by the
+   gcc::jit::recording::context::new_cast method in jit-recording.c.  */
+
+gcc_jit_rvalue *
+gcc_jit_context_new_cast (gcc_jit_context *ctxt,
+                         gcc_jit_location *loc,
+                         gcc_jit_rvalue *rvalue,
+                         gcc_jit_type *type)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL context");
+  /* LOC can be NULL.  */
+  RETURN_NULL_IF_FAIL (rvalue, ctxt, loc, "NULL rvalue");
+  RETURN_NULL_IF_FAIL (type, ctxt, loc, "NULL type");
+  RETURN_NULL_IF_FAIL_PRINTF3 (
+    is_valid_cast (rvalue->get_type (), type),
+    ctxt, loc,
+    "cannot cast %s from type: %s to type: %s",
+    rvalue->get_debug_string (),
+    rvalue->get_type ()->get_debug_string (),
+    type->get_debug_string ());
+
+  return static_cast <gcc_jit_rvalue *> (ctxt->new_cast (loc, rvalue, type));
+}
+
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, the real work is done by the
+   gcc::jit::recording::context::new_array_access method in
+   jit-recording.c.  */
+
+extern gcc_jit_lvalue *
+gcc_jit_context_new_array_access (gcc_jit_context *ctxt,
+                                 gcc_jit_location *loc,
+                                 gcc_jit_rvalue *ptr,
+                                 gcc_jit_rvalue *index)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL context");
+  /* LOC can be NULL.  */
+  RETURN_NULL_IF_FAIL (ptr, ctxt, loc, "NULL ptr");
+  RETURN_NULL_IF_FAIL (index, ctxt, loc, "NULL index");
+  RETURN_NULL_IF_FAIL_PRINTF2 (
+    ptr->get_type ()->dereference (),
+    ctxt, loc,
+    "ptr: %s (type: %s) is not a pointer or array",
+    ptr->get_debug_string (),
+    ptr->get_type ()->get_debug_string ());
+  RETURN_NULL_IF_FAIL_PRINTF2 (
+    index->get_type ()->is_numeric (),
+    ctxt, loc,
+    "index: %s (type: %s) is not of numeric type",
+    index->get_debug_string (),
+    index->get_type ()->get_debug_string ());
+
+  return (gcc_jit_lvalue *)ctxt->new_array_access (loc, ptr, index);
+}
+
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, the real work is done by the
+   gcc::jit::recording::memento::get_context method in
+   jit-recording.h.  */
+
+gcc_jit_context *
+gcc_jit_object_get_context (gcc_jit_object *obj)
+{
+  RETURN_NULL_IF_FAIL (obj, NULL, NULL, "NULL object");
+
+  return static_cast <gcc_jit_context *> (obj->get_context ());
+}
+
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, the real work is done by the
+   gcc::jit::recording::memento::get_debug_string method in
+   jit-recording.c.  */
+
+const char *
+gcc_jit_object_get_debug_string (gcc_jit_object *obj)
+{
+  RETURN_NULL_IF_FAIL (obj, NULL, NULL, "NULL object");
+
+  return obj->get_debug_string ();
+}
+
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, the real work is done by the
+   gcc::jit::recording::lvalue::access_field method in
+   jit-recording.c.  */
+
+gcc_jit_lvalue *
+gcc_jit_lvalue_access_field (gcc_jit_lvalue *struct_,
+                            gcc_jit_location *loc,
+                            gcc_jit_field *field)
+{
+  RETURN_NULL_IF_FAIL (struct_, NULL, loc, "NULL struct");
+  /* LOC can be NULL.  */
+  gcc::jit::recording::context *ctxt = struct_->m_ctxt;
+  RETURN_NULL_IF_FAIL (field, ctxt, loc, "NULL field");
+  RETURN_NULL_IF_FAIL_PRINTF1 (field->get_container (), field->m_ctxt, loc,
+                              "field %s has not been placed in a struct",
+                              field->get_debug_string ());
+
+  return (gcc_jit_lvalue *)struct_->access_field (loc, field);
+}
+
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, the real work is done by the
+   gcc::jit::recording::rvalue::access_field method in
+   jit-recording.c.  */
+
+gcc_jit_rvalue *
+gcc_jit_rvalue_access_field (gcc_jit_rvalue *struct_,
+                            gcc_jit_location *loc,
+                            gcc_jit_field *field)
+{
+  RETURN_NULL_IF_FAIL (struct_, NULL, loc, "NULL struct");
+  /* LOC can be NULL.  */
+  gcc::jit::recording::context *ctxt = struct_->m_ctxt;
+  RETURN_NULL_IF_FAIL (field, ctxt, loc, "NULL field");
+  RETURN_NULL_IF_FAIL_PRINTF1 (field->get_container (), field->m_ctxt, loc,
+                              "field %s has not been placed in a struct",
+                              field->get_debug_string ());
+
+  return (gcc_jit_rvalue *)struct_->access_field (loc, field);
+}
+
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, the real work is done by the
+   gcc::jit::recording::rvalue::deference_field method in
+   jit-recording.c.  */
+
+gcc_jit_lvalue *
+gcc_jit_rvalue_dereference_field (gcc_jit_rvalue *ptr,
+                                 gcc_jit_location *loc,
+                                 gcc_jit_field *field)
+{
+  RETURN_NULL_IF_FAIL (ptr, NULL, loc, "NULL ptr");
+  /* LOC can be NULL.  */
+  RETURN_NULL_IF_FAIL (field, NULL, loc, "NULL field");
+  gcc::jit::recording::type *underlying_type =
+    ptr->get_type ()->is_pointer ();
+  RETURN_NULL_IF_FAIL_PRINTF1 (field->get_container (), field->m_ctxt, loc,
+                              "field %s has not been placed in a struct",
+                              field->get_debug_string ());
+  RETURN_NULL_IF_FAIL_PRINTF3 (
+    underlying_type,
+    ptr->m_ctxt, loc,
+    "dereference of non-pointer %s (type: %s) when accessing ->%s",
+    ptr->get_debug_string (),
+    ptr->get_type ()->get_debug_string (),
+    field->get_debug_string ());
+  RETURN_NULL_IF_FAIL_PRINTF2 (
+    (field->get_container ()->unqualified ()
+     == underlying_type->unqualified ()),
+    ptr->m_ctxt, loc,
+    "%s is not a field of %s",
+    field->get_debug_string (),
+    underlying_type->get_debug_string ());
+
+  return (gcc_jit_lvalue *)ptr->dereference_field (loc, field);
+}
+
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, the real work is done by the
+   gcc::jit::recording::rvalue::deference method in
+   jit-recording.c.  */
+
+gcc_jit_lvalue *
+gcc_jit_rvalue_dereference (gcc_jit_rvalue *rvalue,
+                           gcc_jit_location *loc)
+{
+  RETURN_NULL_IF_FAIL (rvalue, NULL, loc, "NULL rvalue");
+  /* LOC can be NULL.  */
+
+  gcc::jit::recording::type *underlying_type =
+    rvalue->get_type ()->is_pointer ();
+
+  RETURN_NULL_IF_FAIL_PRINTF2 (
+    underlying_type,
+    rvalue->m_ctxt, loc,
+    "dereference of non-pointer %s (type: %s)",
+    rvalue->get_debug_string (),
+    rvalue->get_type ()->get_debug_string ());
+
+  return (gcc_jit_lvalue *)rvalue->dereference (loc);
+}
+
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, the real work is done by the
+   gcc::jit::recording::lvalue::get_address method in jit-recording.c.  */
+
+gcc_jit_rvalue *
+gcc_jit_lvalue_get_address (gcc_jit_lvalue *lvalue,
+                           gcc_jit_location *loc)
+{
+  RETURN_NULL_IF_FAIL (lvalue, NULL, loc, "NULL lvalue");
+  /* LOC can be NULL.  */
+
+  return (gcc_jit_rvalue *)lvalue->get_address (loc);
+}
+
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, the real work is done by the
+   gcc::jit::recording::function::new_local method in jit-recording.c.  */
+
+gcc_jit_lvalue *
+gcc_jit_function_new_local (gcc_jit_function *func,
+                           gcc_jit_location *loc,
+                           gcc_jit_type *type,
+                           const char *name)
+{
+  RETURN_NULL_IF_FAIL (func, NULL, loc, "NULL function");
+  /* LOC can be NULL.  */
+  gcc::jit::recording::context *ctxt = func->m_ctxt;
+  RETURN_NULL_IF_FAIL (func->get_kind () != GCC_JIT_FUNCTION_IMPORTED,
+                      ctxt, loc,
+                      "Cannot add locals to an imported function");
+  RETURN_NULL_IF_FAIL (type, ctxt, loc, "NULL type");
+  RETURN_NULL_IF_FAIL (name, ctxt, loc, "NULL name");
+
+  return (gcc_jit_lvalue *)func->new_local (loc, type, name);
+}
+
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, the real work is done by the
+   gcc::jit::recording::block::add_eval method in jit-recording.c.  */
+
+void
+gcc_jit_block_add_eval (gcc_jit_block *block,
+                       gcc_jit_location *loc,
+                       gcc_jit_rvalue *rvalue)
+{
+  RETURN_IF_NOT_VALID_BLOCK (block, loc);
+  /* LOC can be NULL.  */
+  gcc::jit::recording::context *ctxt = block->get_context ();
+  RETURN_IF_FAIL (rvalue, ctxt, loc, "NULL rvalue");
+
+  return block->add_eval (loc, rvalue);
+}
+
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, the real work is done by the
+   gcc::jit::recording::block::add_assignment method in
+   jit-recording.c.  */
+
+void
+gcc_jit_block_add_assignment (gcc_jit_block *block,
+                             gcc_jit_location *loc,
+                             gcc_jit_lvalue *lvalue,
+                             gcc_jit_rvalue *rvalue)
+{
+  RETURN_IF_NOT_VALID_BLOCK (block, loc);
+  /* LOC can be NULL.  */
+  gcc::jit::recording::context *ctxt = block->get_context ();
+  RETURN_IF_FAIL (lvalue, ctxt, loc, "NULL lvalue");
+  RETURN_IF_FAIL (rvalue, ctxt, loc, "NULL rvalue");
+  RETURN_IF_FAIL_PRINTF4 (
+    compatible_types (lvalue->get_type (),
+                     rvalue->get_type ()),
+    ctxt, loc,
+    "mismatching types:"
+    " assignment to %s (type: %s) from %s (type: %s)",
+    lvalue->get_debug_string (),
+    lvalue->get_type ()->get_debug_string (),
+    rvalue->get_debug_string (),
+    rvalue->get_type ()->get_debug_string ());
+
+  return block->add_assignment (loc, lvalue, rvalue);
+}
+
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, the real work is done by the
+   gcc::jit::recording::block::add_assignment_op method in
+   jit-recording.c.  */
+
+void
+gcc_jit_block_add_assignment_op (gcc_jit_block *block,
+                                gcc_jit_location *loc,
+                                gcc_jit_lvalue *lvalue,
+                                enum gcc_jit_binary_op op,
+                                gcc_jit_rvalue *rvalue)
+{
+  RETURN_IF_NOT_VALID_BLOCK (block, loc);
+  /* LOC can be NULL.  */
+  gcc::jit::recording::context *ctxt = block->get_context ();
+  RETURN_IF_FAIL (lvalue, ctxt, loc, "NULL lvalue");
+  RETURN_IF_FAIL_PRINTF1 (
+    valid_binary_op_p (op),
+    ctxt, loc,
+    "unrecognized value for enum gcc_jit_binary_op: %i",
+    op);
+  RETURN_IF_FAIL (rvalue, ctxt, loc, "NULL rvalue");
+
+  return block->add_assignment_op (loc, lvalue, op, rvalue);
+}
+
+/* Internal helper function for determining if rvalue BOOLVAL is of
+   boolean type.  For use by gcc_jit_block_end_with_conditional.  */
+
+static bool
+is_bool (gcc_jit_rvalue *boolval)
+{
+  gcc::jit::recording::type *actual_type = boolval->get_type ();
+  gcc::jit::recording::type *bool_type =
+    boolval->m_ctxt->get_type (GCC_JIT_TYPE_BOOL);
+  return actual_type == bool_type;
+}
+
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, the real work is done by the
+   gcc::jit::recording::block::end_with_conditional method in
+   jit-recording.c.  */
+
+void
+gcc_jit_block_end_with_conditional (gcc_jit_block *block,
+                                   gcc_jit_location *loc,
+                                   gcc_jit_rvalue *boolval,
+                                   gcc_jit_block *on_true,
+                                   gcc_jit_block *on_false)
+{
+  RETURN_IF_NOT_VALID_BLOCK (block, loc);
+  /* LOC can be NULL.  */
+  gcc::jit::recording::context *ctxt = block->get_context ();
+  RETURN_IF_FAIL (boolval, ctxt, loc, "NULL boolval");
+  RETURN_IF_FAIL_PRINTF2 (
+   is_bool (boolval), ctxt, loc,
+   "%s (type: %s) is not of boolean type ",
+   boolval->get_debug_string (),
+   boolval->get_type ()->get_debug_string ());
+  RETURN_IF_FAIL (on_true, ctxt, loc, "NULL on_true");
+  RETURN_IF_FAIL (on_true, ctxt, loc, "NULL on_false");
+  RETURN_IF_FAIL_PRINTF4 (
+    block->get_function () == on_true->get_function (),
+    ctxt, loc,
+    "\"on_true\" block is not in same function:"
+    " source block %s is in function %s"
+    " whereas target block %s is in function %s",
+    block->get_debug_string (),
+    block->get_function ()->get_debug_string (),
+    on_true->get_debug_string (),
+    on_true->get_function ()->get_debug_string ());
+  RETURN_IF_FAIL_PRINTF4 (
+    block->get_function () == on_false->get_function (),
+    ctxt, loc,
+    "\"on_false\" block is not in same function:"
+    " source block %s is in function %s"
+    " whereas target block %s is in function %s",
+    block->get_debug_string (),
+    block->get_function ()->get_debug_string (),
+    on_false->get_debug_string (),
+    on_false->get_function ()->get_debug_string ());
+
+  return block->end_with_conditional (loc, boolval, on_true, on_false);
+}
+
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, the real work is done by the
+   gcc::jit::recording::block::add_comment method in
+   jit-recording.c.  */
+
+void
+gcc_jit_block_add_comment (gcc_jit_block *block,
+                          gcc_jit_location *loc,
+                          const char *text)
+{
+  RETURN_IF_NOT_VALID_BLOCK (block, loc);
+  /* LOC can be NULL.  */
+  gcc::jit::recording::context *ctxt = block->get_context ();
+  RETURN_IF_FAIL (text, ctxt, loc, "NULL text");
+
+  block->add_comment (loc, text);
+}
+
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, the real work is done by the
+   gcc::jit::recording::block::end_with_jump method in
+   jit-recording.c.  */
+
+void
+gcc_jit_block_end_with_jump (gcc_jit_block *block,
+                            gcc_jit_location *loc,
+                            gcc_jit_block *target)
+{
+  RETURN_IF_NOT_VALID_BLOCK (block, loc);
+  /* LOC can be NULL.  */
+  gcc::jit::recording::context *ctxt = block->get_context ();
+  RETURN_IF_FAIL (target, ctxt, loc, "NULL target");
+  RETURN_IF_FAIL_PRINTF4 (
+    block->get_function () == target->get_function (),
+    ctxt, loc,
+    "target block is not in same function:"
+    " source block %s is in function %s"
+    " whereas target block %s is in function %s",
+    block->get_debug_string (),
+    block->get_function ()->get_debug_string (),
+    target->get_debug_string (),
+    target->get_function ()->get_debug_string ());
+
+  block->end_with_jump (loc, target);
+}
+
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, the real work is done by the
+   gcc::jit::recording::block::end_with_return method in
+   jit-recording.c.  */
+
+void
+gcc_jit_block_end_with_return (gcc_jit_block *block,
+                              gcc_jit_location *loc,
+                              gcc_jit_rvalue *rvalue)
+{
+  RETURN_IF_NOT_VALID_BLOCK (block, loc);
+  /* LOC can be NULL.  */
+  gcc::jit::recording::context *ctxt = block->get_context ();
+  gcc::jit::recording::function *func = block->get_function ();
+  RETURN_IF_FAIL (rvalue, ctxt, loc, "NULL rvalue");
+  RETURN_IF_FAIL_PRINTF4 (
+    compatible_types (
+      func->get_return_type (),
+      rvalue->get_type ()),
+    ctxt, loc,
+    "mismatching types:"
+    " return of %s (type: %s) in function %s (return type: %s)",
+    rvalue->get_debug_string (),
+    rvalue->get_type ()->get_debug_string (),
+    func->get_debug_string (),
+    func->get_return_type ()->get_debug_string ());
+
+  return block->end_with_return (loc, rvalue);
+}
+
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, the real work is done by the
+   gcc::jit::recording::block::end_with_return method in
+   jit-recording.c.  */
+
+void
+gcc_jit_block_end_with_void_return (gcc_jit_block *block,
+                                   gcc_jit_location *loc)
+{
+  RETURN_IF_NOT_VALID_BLOCK (block, loc);
+  /* LOC can be NULL.  */
+  gcc::jit::recording::context *ctxt = block->get_context ();
+  gcc::jit::recording::function *func = block->get_function ();
+  RETURN_IF_FAIL_PRINTF2 (
+    func->get_return_type () == ctxt->get_type (GCC_JIT_TYPE_VOID),
+    ctxt, loc,
+    "mismatching types:"
+    " void return in function %s (return type: %s)",
+    func->get_debug_string (),
+    func->get_return_type ()->get_debug_string ());
+
+  return block->end_with_return (loc, NULL);
+}
+
+/**********************************************************************
+ Option-management
+ **********************************************************************/
+
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, the real work is done by the
+   gcc::jit::recording::context::set_str_option method in
+   jit-recording.c.  */
+
+void
+gcc_jit_context_set_str_option (gcc_jit_context *ctxt,
+                               enum gcc_jit_str_option opt,
+                               const char *value)
+{
+  RETURN_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+  /* opt is checked by the inner function.
+     value can be NULL.  */
+
+  ctxt->set_str_option (opt, value);
+}
+
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, the real work is done by the
+   gcc::jit::recording::context::set_int_option method in
+   jit-recording.c.  */
+
+void
+gcc_jit_context_set_int_option (gcc_jit_context *ctxt,
+                               enum gcc_jit_int_option opt,
+                               int value)
+{
+  RETURN_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+  /* opt is checked by the inner function.  */
+
+  ctxt->set_int_option (opt, value);
+}
+
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, the real work is done by the
+   gcc::jit::recording::context::set_bool_option method in
+   jit-recording.c.  */
+
+void
+gcc_jit_context_set_bool_option (gcc_jit_context *ctxt,
+                                enum gcc_jit_bool_option opt,
+                                int value)
+{
+  RETURN_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+  /* opt is checked by the inner function.  */
+
+  ctxt->set_bool_option (opt, value);
+}
+
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, the real work is done by the
+   gcc::jit::recording::context::compile method in
+   jit-recording.c.  */
+
+gcc_jit_result *
+gcc_jit_context_compile (gcc_jit_context *ctxt)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+
+  return (gcc_jit_result *)ctxt->compile ();
+}
+
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, the real work is done by the
+   gcc::jit::recording::context::dump_to_file method in
+   jit-recording.c.  */
+
+void
+gcc_jit_context_dump_to_file (gcc_jit_context *ctxt,
+                             const char *path,
+                             int update_locations)
+{
+  RETURN_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+  RETURN_IF_FAIL (path, ctxt, NULL, "NULL path");
+  ctxt->dump_to_file (path, update_locations);
+}
+
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, the real work is done by the
+   gcc::jit::recording::context::get_first_error method in
+   jit-recording.c.  */
+
+const char *
+gcc_jit_context_get_first_error (gcc_jit_context *ctxt)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+
+  return ctxt->get_first_error ();
+}
+
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, the real work is done by the
+   gcc::jit::playback::result::get_code method in
+   jit-playback.c.  */
+
+void *
+gcc_jit_result_get_code (gcc_jit_result *result,
+                        const char *fnname)
+{
+  RETURN_NULL_IF_FAIL (result, NULL, NULL, "NULL result");
+  RETURN_NULL_IF_FAIL (fnname, NULL, NULL, "NULL fnname");
+
+  return result->get_code (fnname);
+}
+
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, this is essentially a wrapper around the
+   destructor for gcc::jit::playback::result in jit-playback.c.  */
+
+void
+gcc_jit_result_release (gcc_jit_result *result)
+{
+  RETURN_IF_FAIL (result, NULL, NULL, "NULL result");
+
+  delete result;
+}
diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h
new file mode 100644 (file)
index 0000000..e07002d
--- /dev/null
@@ -0,0 +1,986 @@
+/* A pure C API to enable client code to embed GCC as a JIT-compiler.
+   Copyright (C) 2013-2014 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef LIBGCCJIT_H
+#define LIBGCCJIT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/**********************************************************************
+ Data structures.
+ **********************************************************************/
+/* All structs within the API are opaque. */
+
+/* A gcc_jit_context encapsulates the state of a compilation.  It goes
+   through two states:
+
+   (1) "initial", during which you can set up options on it, and add
+       types, functions and code, using the API below.
+       Invoking gcc_jit_context_compile on it transitions it to the
+       "after compilation" state.
+
+   (2) "after compilation", when you can call gcc_jit_context_release to
+       clean up.  */
+typedef struct gcc_jit_context gcc_jit_context;
+
+/* A gcc_jit_result encapsulates the result of a compilation.  */
+typedef struct gcc_jit_result gcc_jit_result;
+
+/* An object created within a context.  Such objects are automatically
+   cleaned up when the context is released.
+
+   The class hierarchy looks like this:
+
+     +- gcc_jit_object
+         +- gcc_jit_location
+         +- gcc_jit_type
+           +- gcc_jit_struct
+         +- gcc_jit_field
+         +- gcc_jit_function
+         +- gcc_jit_block
+         +- gcc_jit_rvalue
+             +- gcc_jit_lvalue
+                 +- gcc_jit_param
+*/
+typedef struct gcc_jit_object gcc_jit_object;
+
+/* A gcc_jit_location encapsulates a source code location, so that
+   you can (optionally) associate locations in your language with
+   statements in the JIT-compiled code, allowing the debugger to
+   single-step through your language.
+
+   Note that to do so, you also need to enable
+     GCC_JIT_BOOL_OPTION_DEBUGINFO
+   on the gcc_jit_context.
+
+   gcc_jit_location instances are optional; you can always pass
+   NULL.  */
+typedef struct gcc_jit_location gcc_jit_location;
+
+/* A gcc_jit_type encapsulates a type e.g. "int" or a "struct foo*".  */
+typedef struct gcc_jit_type gcc_jit_type;
+
+/* A gcc_jit_field encapsulates a field within a struct; it is used
+   when creating a struct type (using gcc_jit_context_new_struct_type).
+   Fields cannot be shared between structs.  */
+typedef struct gcc_jit_field gcc_jit_field;
+
+/* A gcc_jit_struct encapsulates a struct type, either one that we have
+   the layout for, or an opaque type.  */
+typedef struct gcc_jit_struct gcc_jit_struct;
+
+/* A gcc_jit_function encapsulates a function: either one that you're
+   creating yourself, or a reference to one that you're dynamically
+   linking to within the rest of the process.  */
+typedef struct gcc_jit_function gcc_jit_function;
+
+/* A gcc_jit_block encapsulates a "basic block" of statements within a
+   function (i.e. with one entry point and one exit point).
+
+   Every block within a function must be terminated with a conditional,
+   a branch, or a return.
+
+   The blocks within a function form a directed graph.
+
+   The entrypoint to the function is the first block created within
+   it.
+
+   All of the blocks in a function must be reachable via some path from
+   the first block.
+
+   It's OK to have more than one "return" from a function (i.e. multiple
+   blocks that terminate by returning).  */
+typedef struct gcc_jit_block gcc_jit_block;
+
+/* A gcc_jit_rvalue is an expression within your code, with some type.  */
+typedef struct gcc_jit_rvalue gcc_jit_rvalue;
+
+/* A gcc_jit_lvalue is a storage location within your code (e.g. a
+   variable, a parameter, etc).  It is also a gcc_jit_rvalue; use
+   gcc_jit_lvalue_as_rvalue to cast.  */
+typedef struct gcc_jit_lvalue gcc_jit_lvalue;
+
+/* A gcc_jit_param is a function parameter, used when creating a
+   gcc_jit_function.  It is also a gcc_jit_lvalue (and thus also an
+   rvalue); use gcc_jit_param_as_lvalue to convert.  */
+typedef struct gcc_jit_param gcc_jit_param;
+
+/* Acquire a JIT-compilation context.  */
+extern gcc_jit_context *
+gcc_jit_context_acquire (void);
+
+/* Release the context.  After this call, it's no longer valid to use
+   the ctxt.  */
+extern void
+gcc_jit_context_release (gcc_jit_context *ctxt);
+
+/* Options taking string values. */
+enum gcc_jit_str_option
+{
+  /* The name of the program, for use as a prefix when printing error
+     messages to stderr.  If NULL, or default, "libgccjit.so" is used.  */
+  GCC_JIT_STR_OPTION_PROGNAME,
+
+  GCC_JIT_NUM_STR_OPTIONS
+};
+
+/* Options taking int values. */
+enum gcc_jit_int_option
+{
+  /* How much to optimize the code.
+     Valid values are 0-3, corresponding to GCC's command-line options
+     -O0 through -O3.
+
+     The default value is 0 (unoptimized).  */
+  GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL,
+
+  GCC_JIT_NUM_INT_OPTIONS
+};
+
+/* Options taking boolean values.
+   These all default to "false".  */
+enum gcc_jit_bool_option
+{
+  /* If true, gcc_jit_context_compile will attempt to do the right
+     thing so that if you attach a debugger to the process, it will
+     be able to inspect variables and step through your code.
+
+     Note that you can't step through code unless you set up source
+     location information for the code (by creating and passing in
+     gcc_jit_location instances).  */
+  GCC_JIT_BOOL_OPTION_DEBUGINFO,
+
+  /* If true, gcc_jit_context_compile will dump its initial "tree"
+     representation of your code to stderr (before any
+     optimizations).  */
+  GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE,
+
+  /* If true, gcc_jit_context_compile will dump the "gimple"
+     representation of your code to stderr, before any optimizations
+     are performed.  The dump resembles C code.  */
+  GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE,
+
+  /* If true, gcc_jit_context_compile will dump the final
+     generated code to stderr, in the form of assembly language.  */
+  GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE,
+
+  /* If true, gcc_jit_context_compile will print information to stderr
+     on the actions it is performing, followed by a profile showing
+     the time taken and memory usage of each phase.
+   */
+  GCC_JIT_BOOL_OPTION_DUMP_SUMMARY,
+
+  /* If true, gcc_jit_context_compile will dump copious
+     amount of information on what it's doing to various
+     files within a temporary directory.  Use
+     GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES (see below) to
+     see the results.  The files are intended to be human-readable,
+     but the exact files and their formats are subject to change.
+  */
+  GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING,
+
+  /* If true, libgccjit will aggressively run its garbage collector, to
+     shake out bugs (greatly slowing down the compile).  This is likely
+     to only be of interest to developers *of* the library.  It is
+     used when running the selftest suite.  */
+  GCC_JIT_BOOL_OPTION_SELFCHECK_GC,
+
+  /* If true, gcc_jit_context_release will not clean up
+     intermediate files written to the filesystem, and will display
+     their location on stderr.  */
+  GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES,
+
+  GCC_JIT_NUM_BOOL_OPTIONS
+};
+
+/* Set a string option on the given context.
+
+   The context directly stores the (const char *), so the passed string
+   must outlive the context.  */
+extern void
+gcc_jit_context_set_str_option (gcc_jit_context *ctxt,
+                               enum gcc_jit_str_option opt,
+                               const char *value);
+
+/* Set an int option on the given context.  */
+extern void
+gcc_jit_context_set_int_option (gcc_jit_context *ctxt,
+                               enum gcc_jit_int_option opt,
+                               int value);
+
+/* Set a boolean option on the given context.
+
+   Zero is "false" (the default), non-zero is "true".  */
+extern void
+gcc_jit_context_set_bool_option (gcc_jit_context *ctxt,
+                                enum gcc_jit_bool_option opt,
+                                int value);
+
+/* This actually calls into GCC and runs the build, all
+   in a mutex for now.  The result is a wrapper around a .so file.
+   It can only be called once on a given context.  */
+extern gcc_jit_result *
+gcc_jit_context_compile (gcc_jit_context *ctxt);
+
+/* To help with debugging: dump a C-like representation to the given path,
+   describing what's been set up on the context.
+
+   If "update_locations" is true, then also set up gcc_jit_location
+   information throughout the context, pointing at the dump file as if it
+   were a source file.  This may be of use in conjunction with
+   GCC_JIT_BOOL_OPTION_DEBUGINFO to allow stepping through the code in a
+   debugger.  */
+extern void
+gcc_jit_context_dump_to_file (gcc_jit_context *ctxt,
+                             const char *path,
+                             int update_locations);
+
+/* To be called after a compile, this gives the first error message
+   that occurred on the context.
+
+   The returned string is valid for the rest of the lifetime of the
+   context.
+
+   If no errors occurred, this will be NULL.  */
+extern const char *
+gcc_jit_context_get_first_error (gcc_jit_context *ctxt);
+
+/* Locate a given function within the built machine code.
+   This will need to be cast to a function pointer of the
+   correct type before it can be called. */
+extern void *
+gcc_jit_result_get_code (gcc_jit_result *result,
+                        const char *funcname);
+
+/* Once we're done with the code, this unloads the built .so file.
+   This cleans up the result; after calling this, it's no longer
+   valid to use the result.  */
+extern void
+gcc_jit_result_release (gcc_jit_result *result);
+
+
+/**********************************************************************
+ Functions for creating "contextual" objects.
+
+ All objects created by these functions share the lifetime of the context
+ they are created within, and are automatically cleaned up for you when
+ you call gcc_jit_context_release on the context.
+
+ Note that this means you can't use references to them after you've
+ released their context.
+
+ All (const char *) string arguments passed to these functions are
+ copied, so you don't need to keep them around.  Note that this *isn't*
+ the case for other parts of the API.
+
+ You create code by adding a sequence of statements to blocks.
+**********************************************************************/
+
+/**********************************************************************
+ The base class of "contextual" object.
+ **********************************************************************/
+/* Which context is "obj" within?  */
+extern gcc_jit_context *
+gcc_jit_object_get_context (gcc_jit_object *obj);
+
+/* Get a human-readable description of this object.
+   The string buffer is created the first time this is called on a given
+   object, and persists until the object's context is released.  */
+extern const char *
+gcc_jit_object_get_debug_string (gcc_jit_object *obj);
+
+/**********************************************************************
+ Debugging information.
+ **********************************************************************/
+
+/* Creating source code locations for use by the debugger.
+   Line and column numbers are 1-based.  */
+extern gcc_jit_location *
+gcc_jit_context_new_location (gcc_jit_context *ctxt,
+                             const char *filename,
+                             int line,
+                             int column);
+
+/* Upcasting from location to object.  */
+extern gcc_jit_object *
+gcc_jit_location_as_object (gcc_jit_location *loc);
+
+
+/**********************************************************************
+ Types.
+ **********************************************************************/
+
+/* Upcasting from type to object.  */
+extern gcc_jit_object *
+gcc_jit_type_as_object (gcc_jit_type *type);
+
+/* Access to specific types.  */
+enum gcc_jit_types
+{
+  /* C's "void" type.  */
+  GCC_JIT_TYPE_VOID,
+
+  /* "void *".  */
+  GCC_JIT_TYPE_VOID_PTR,
+
+  /* C++'s bool type; also C99's "_Bool" type, aka "bool" if using
+     stdbool.h.  */
+  GCC_JIT_TYPE_BOOL,
+
+  /* Various integer types.  */
+
+  /* C's "char" (of some signedness) and the variants where the
+     signedness is specified.  */
+  GCC_JIT_TYPE_CHAR,
+  GCC_JIT_TYPE_SIGNED_CHAR,
+  GCC_JIT_TYPE_UNSIGNED_CHAR,
+
+  /* C's "short" and "unsigned short".  */
+  GCC_JIT_TYPE_SHORT, /* signed */
+  GCC_JIT_TYPE_UNSIGNED_SHORT,
+
+  /* C's "int" and "unsigned int".  */
+  GCC_JIT_TYPE_INT, /* signed */
+  GCC_JIT_TYPE_UNSIGNED_INT,
+
+  /* C's "long" and "unsigned long".  */
+  GCC_JIT_TYPE_LONG, /* signed */
+  GCC_JIT_TYPE_UNSIGNED_LONG,
+
+  /* C99's "long long" and "unsigned long long".  */
+  GCC_JIT_TYPE_LONG_LONG, /* signed */
+  GCC_JIT_TYPE_UNSIGNED_LONG_LONG,
+
+  /* Floating-point types  */
+
+  GCC_JIT_TYPE_FLOAT,
+  GCC_JIT_TYPE_DOUBLE,
+  GCC_JIT_TYPE_LONG_DOUBLE,
+
+  /* C type: (const char *).  */
+  GCC_JIT_TYPE_CONST_CHAR_PTR,
+
+ /* The C "size_t" type.  */
+  GCC_JIT_TYPE_SIZE_T,
+
+ /* C type: (FILE *)  */
+  GCC_JIT_TYPE_FILE_PTR
+};
+
+extern gcc_jit_type *
+gcc_jit_context_get_type (gcc_jit_context *ctxt,
+                         enum gcc_jit_types type_);
+
+/* Get the integer type of the given size and signedness.  */
+extern gcc_jit_type *
+gcc_jit_context_get_int_type (gcc_jit_context *ctxt,
+                             int num_bytes, int is_signed);
+
+/* Constructing new types. */
+
+/* Given type "T", get type "T*".  */
+extern gcc_jit_type *
+gcc_jit_type_get_pointer (gcc_jit_type *type);
+
+/* Given type "T", get type "const T".  */
+extern gcc_jit_type *
+gcc_jit_type_get_const (gcc_jit_type *type);
+
+/* Given type "T", get type "volatile T".  */
+extern gcc_jit_type *
+gcc_jit_type_get_volatile (gcc_jit_type *type);
+
+/* Given type "T", get type "T[N]" (for a constant N).  */
+extern gcc_jit_type *
+gcc_jit_context_new_array_type (gcc_jit_context *ctxt,
+                               gcc_jit_location *loc,
+                               gcc_jit_type *element_type,
+                               int num_elements);
+
+/* Struct-handling.  */
+
+/* Create a field, for use within a struct or union.  */
+extern gcc_jit_field *
+gcc_jit_context_new_field (gcc_jit_context *ctxt,
+                          gcc_jit_location *loc,
+                          gcc_jit_type *type,
+                          const char *name);
+
+/* Upcasting from field to object.  */
+extern gcc_jit_object *
+gcc_jit_field_as_object (gcc_jit_field *field);
+
+/* Create a struct type from an array of fields.  */
+extern gcc_jit_struct *
+gcc_jit_context_new_struct_type (gcc_jit_context *ctxt,
+                                gcc_jit_location *loc,
+                                const char *name,
+                                int num_fields,
+                                gcc_jit_field **fields);
+
+/* Create an opaque struct type.  */
+extern gcc_jit_struct *
+gcc_jit_context_new_opaque_struct (gcc_jit_context *ctxt,
+                                  gcc_jit_location *loc,
+                                  const char *name);
+
+/* Upcast a struct to a type.  */
+extern gcc_jit_type *
+gcc_jit_struct_as_type (gcc_jit_struct *struct_type);
+
+/* Populating the fields of a formerly-opaque struct type.
+   This can only be called once on a given struct type.  */
+extern void
+gcc_jit_struct_set_fields (gcc_jit_struct *struct_type,
+                          gcc_jit_location *loc,
+                          int num_fields,
+                          gcc_jit_field **fields);
+
+/* Unions work similarly to structs.  */
+extern gcc_jit_type *
+gcc_jit_context_new_union_type (gcc_jit_context *ctxt,
+                               gcc_jit_location *loc,
+                               const char *name,
+                               int num_fields,
+                               gcc_jit_field **fields);
+
+/* Function pointers. */
+
+extern gcc_jit_type *
+gcc_jit_context_new_function_ptr_type (gcc_jit_context *ctxt,
+                                      gcc_jit_location *loc,
+                                      gcc_jit_type *return_type,
+                                      int num_params,
+                                      gcc_jit_type **param_types,
+                                      int is_variadic);
+
+/**********************************************************************
+ Constructing functions.
+ **********************************************************************/
+/* Create a function param.  */
+extern gcc_jit_param *
+gcc_jit_context_new_param (gcc_jit_context *ctxt,
+                          gcc_jit_location *loc,
+                          gcc_jit_type *type,
+                          const char *name);
+
+/* Upcasting from param to object.  */
+extern gcc_jit_object *
+gcc_jit_param_as_object (gcc_jit_param *param);
+
+/* Upcasting from param to lvalue.  */
+extern gcc_jit_lvalue *
+gcc_jit_param_as_lvalue (gcc_jit_param *param);
+
+/* Upcasting from param to rvalue.  */
+extern gcc_jit_rvalue *
+gcc_jit_param_as_rvalue (gcc_jit_param *param);
+
+/* Kinds of function.  */
+enum gcc_jit_function_kind
+{
+  /* Function is defined by the client code and visible
+     by name outside of the JIT.  */
+  GCC_JIT_FUNCTION_EXPORTED,
+
+  /* Function is defined by the client code, but is invisible
+     outside of the JIT.  Analogous to a "static" function.  */
+  GCC_JIT_FUNCTION_INTERNAL,
+
+  /* Function is not defined by the client code; we're merely
+     referring to it.  Analogous to using an "extern" function from a
+     header file.  */
+  GCC_JIT_FUNCTION_IMPORTED,
+
+  /* Function is only ever inlined into other functions, and is
+     invisible outside of the JIT.
+
+     Analogous to prefixing with "inline" and adding
+     __attribute__((always_inline)).
+
+     Inlining will only occur when the optimization level is
+     above 0; when optimization is off, this is essentially the
+     same as GCC_JIT_FUNCTION_INTERNAL.  */
+  GCC_JIT_FUNCTION_ALWAYS_INLINE
+};
+
+/* Create a function.  */
+extern gcc_jit_function *
+gcc_jit_context_new_function (gcc_jit_context *ctxt,
+                             gcc_jit_location *loc,
+                             enum gcc_jit_function_kind kind,
+                             gcc_jit_type *return_type,
+                             const char *name,
+                             int num_params,
+                             gcc_jit_param **params,
+                             int is_variadic);
+
+/* Create a reference to a builtin function (sometimes called
+   intrinsic functions).  */
+extern gcc_jit_function *
+gcc_jit_context_get_builtin_function (gcc_jit_context *ctxt,
+                                     const char *name);
+
+/* Upcasting from function to object.  */
+extern gcc_jit_object *
+gcc_jit_function_as_object (gcc_jit_function *func);
+
+/* Get a specific param of a function by index.  */
+extern gcc_jit_param *
+gcc_jit_function_get_param (gcc_jit_function *func, int index);
+
+/* Emit the function in graphviz format.  */
+extern void
+gcc_jit_function_dump_to_dot (gcc_jit_function *func,
+                             const char *path);
+
+/* Create a block.
+
+   The name can be NULL, or you can give it a meaningful name, which
+   may show up in dumps of the internal representation, and in error
+   messages.  */
+extern gcc_jit_block *
+gcc_jit_function_new_block (gcc_jit_function *func,
+                           const char *name);
+
+/* Upcasting from block to object.  */
+extern gcc_jit_object *
+gcc_jit_block_as_object (gcc_jit_block *block);
+
+/* Which function is this block within?  */
+extern gcc_jit_function *
+gcc_jit_block_get_function (gcc_jit_block *block);
+
+/**********************************************************************
+ lvalues, rvalues and expressions.
+ **********************************************************************/
+
+extern gcc_jit_lvalue *
+gcc_jit_context_new_global (gcc_jit_context *ctxt,
+                           gcc_jit_location *loc,
+                           gcc_jit_type *type,
+                           const char *name);
+
+/* Upcasting.  */
+extern gcc_jit_object *
+gcc_jit_lvalue_as_object (gcc_jit_lvalue *lvalue);
+
+extern gcc_jit_rvalue *
+gcc_jit_lvalue_as_rvalue (gcc_jit_lvalue *lvalue);
+
+extern gcc_jit_object *
+gcc_jit_rvalue_as_object (gcc_jit_rvalue *rvalue);
+
+extern gcc_jit_type *
+gcc_jit_rvalue_get_type (gcc_jit_rvalue *rvalue);
+
+/* Integer constants. */
+extern gcc_jit_rvalue *
+gcc_jit_context_new_rvalue_from_int (gcc_jit_context *ctxt,
+                                    gcc_jit_type *numeric_type,
+                                    int value);
+
+extern gcc_jit_rvalue *
+gcc_jit_context_zero (gcc_jit_context *ctxt,
+                     gcc_jit_type *numeric_type);
+
+extern gcc_jit_rvalue *
+gcc_jit_context_one (gcc_jit_context *ctxt,
+                    gcc_jit_type *numeric_type);
+
+/* Floating-point constants.  */
+extern gcc_jit_rvalue *
+gcc_jit_context_new_rvalue_from_double (gcc_jit_context *ctxt,
+                                       gcc_jit_type *numeric_type,
+                                       double value);
+
+/* Pointers.  */
+extern gcc_jit_rvalue *
+gcc_jit_context_new_rvalue_from_ptr (gcc_jit_context *ctxt,
+                                    gcc_jit_type *pointer_type,
+                                    void *value);
+
+extern gcc_jit_rvalue *
+gcc_jit_context_null (gcc_jit_context *ctxt,
+                     gcc_jit_type *pointer_type);
+
+/* String literals. */
+extern gcc_jit_rvalue *
+gcc_jit_context_new_string_literal (gcc_jit_context *ctxt,
+                                   const char *value);
+
+enum gcc_jit_unary_op
+{
+  /* Negate an arithmetic value; analogous to:
+       -(EXPR)
+     in C.  */
+  GCC_JIT_UNARY_OP_MINUS,
+
+  /* Bitwise negation of an integer value (one's complement); analogous
+     to:
+       ~(EXPR)
+     in C.  */
+  GCC_JIT_UNARY_OP_BITWISE_NEGATE,
+
+  /* Logical negation of an arithmetic or pointer value; analogous to:
+       !(EXPR)
+     in C.  */
+  GCC_JIT_UNARY_OP_LOGICAL_NEGATE
+};
+
+extern gcc_jit_rvalue *
+gcc_jit_context_new_unary_op (gcc_jit_context *ctxt,
+                             gcc_jit_location *loc,
+                             enum gcc_jit_unary_op op,
+                             gcc_jit_type *result_type,
+                             gcc_jit_rvalue *rvalue);
+
+enum gcc_jit_binary_op
+{
+  /* Addition of arithmetic values; analogous to:
+       (EXPR_A) + (EXPR_B)
+     in C.
+     For pointer addition, use gcc_jit_context_new_array_access.  */
+  GCC_JIT_BINARY_OP_PLUS,
+
+  /* Subtraction of arithmetic values; analogous to:
+       (EXPR_A) - (EXPR_B)
+     in C.  */
+  GCC_JIT_BINARY_OP_MINUS,
+
+  /* Multiplication of a pair of arithmetic values; analogous to:
+       (EXPR_A) * (EXPR_B)
+     in C.  */
+  GCC_JIT_BINARY_OP_MULT,
+
+  /* Quotient of division of arithmetic values; analogous to:
+       (EXPR_A) / (EXPR_B)
+     in C.
+     The result type affects the kind of division: if the result type is
+     integer-based, then the result is truncated towards zero, whereas
+     a floating-point result type indicates floating-point division.  */
+  GCC_JIT_BINARY_OP_DIVIDE,
+
+  /* Remainder of division of arithmetic values; analogous to:
+       (EXPR_A) % (EXPR_B)
+     in C.  */
+  GCC_JIT_BINARY_OP_MODULO,
+
+  /* Bitwise AND; analogous to:
+       (EXPR_A) & (EXPR_B)
+     in C.  */
+  GCC_JIT_BINARY_OP_BITWISE_AND,
+
+  /* Bitwise exclusive OR; analogous to:
+       (EXPR_A) ^ (EXPR_B)
+     in C.  */
+  GCC_JIT_BINARY_OP_BITWISE_XOR,
+
+  /* Bitwise inclusive OR; analogous to:
+       (EXPR_A) | (EXPR_B)
+     in C.  */
+  GCC_JIT_BINARY_OP_BITWISE_OR,
+
+  /* Logical AND; analogous to:
+       (EXPR_A) && (EXPR_B)
+     in C.  */
+  GCC_JIT_BINARY_OP_LOGICAL_AND,
+
+  /* Logical OR; analogous to:
+       (EXPR_A) || (EXPR_B)
+     in C.  */
+  GCC_JIT_BINARY_OP_LOGICAL_OR,
+
+  /* Left shift; analogous to:
+       (EXPR_A) << (EXPR_B)
+     in C.  */
+  GCC_JIT_BINARY_OP_LSHIFT,
+
+  /* Right shift; analogous to:
+       (EXPR_A) >> (EXPR_B)
+     in C.  */
+  GCC_JIT_BINARY_OP_RSHIFT
+};
+
+extern gcc_jit_rvalue *
+gcc_jit_context_new_binary_op (gcc_jit_context *ctxt,
+                              gcc_jit_location *loc,
+                              enum gcc_jit_binary_op op,
+                              gcc_jit_type *result_type,
+                              gcc_jit_rvalue *a, gcc_jit_rvalue *b);
+
+/* (Comparisons are treated as separate from "binary_op" to save
+   you having to specify the result_type).  */
+
+enum gcc_jit_comparison
+{
+  /* (EXPR_A) == (EXPR_B).  */
+  GCC_JIT_COMPARISON_EQ,
+
+  /* (EXPR_A) != (EXPR_B).  */
+  GCC_JIT_COMPARISON_NE,
+
+  /* (EXPR_A) < (EXPR_B).  */
+  GCC_JIT_COMPARISON_LT,
+
+  /* (EXPR_A) <=(EXPR_B).  */
+  GCC_JIT_COMPARISON_LE,
+
+  /* (EXPR_A) > (EXPR_B).  */
+  GCC_JIT_COMPARISON_GT,
+
+  /* (EXPR_A) >= (EXPR_B).  */
+  GCC_JIT_COMPARISON_GE
+};
+
+extern gcc_jit_rvalue *
+gcc_jit_context_new_comparison (gcc_jit_context *ctxt,
+                               gcc_jit_location *loc,
+                               enum gcc_jit_comparison op,
+                               gcc_jit_rvalue *a, gcc_jit_rvalue *b);
+
+/* Function calls.  */
+
+/* Call of a specific function.  */
+extern gcc_jit_rvalue *
+gcc_jit_context_new_call (gcc_jit_context *ctxt,
+                         gcc_jit_location *loc,
+                         gcc_jit_function *func,
+                         int numargs , gcc_jit_rvalue **args);
+
+/* Call through a function pointer.  */
+extern gcc_jit_rvalue *
+gcc_jit_context_new_call_through_ptr (gcc_jit_context *ctxt,
+                                     gcc_jit_location *loc,
+                                     gcc_jit_rvalue *fn_ptr,
+                                     int numargs, gcc_jit_rvalue **args);
+
+/* Type-coercion.
+
+   Currently only a limited set of conversions are possible:
+     int <-> float
+     int <-> bool  */
+extern gcc_jit_rvalue *
+gcc_jit_context_new_cast (gcc_jit_context *ctxt,
+                         gcc_jit_location *loc,
+                         gcc_jit_rvalue *rvalue,
+                         gcc_jit_type *type);
+
+extern gcc_jit_lvalue *
+gcc_jit_context_new_array_access (gcc_jit_context *ctxt,
+                                 gcc_jit_location *loc,
+                                 gcc_jit_rvalue *ptr,
+                                 gcc_jit_rvalue *index);
+
+/* Field access is provided separately for both lvalues and rvalues.  */
+
+/* Accessing a field of an lvalue of struct type, analogous to:
+      (EXPR).field = ...;
+   in C.  */
+extern gcc_jit_lvalue *
+gcc_jit_lvalue_access_field (gcc_jit_lvalue *struct_or_union,
+                            gcc_jit_location *loc,
+                            gcc_jit_field *field);
+
+/* Accessing a field of an rvalue of struct type, analogous to:
+      (EXPR).field
+   in C.  */
+extern gcc_jit_rvalue *
+gcc_jit_rvalue_access_field (gcc_jit_rvalue *struct_or_union,
+                            gcc_jit_location *loc,
+                            gcc_jit_field *field);
+
+/* Accessing a field of an rvalue of pointer type, analogous to:
+      (EXPR)->field
+   in C, itself equivalent to (*EXPR).FIELD  */
+extern gcc_jit_lvalue *
+gcc_jit_rvalue_dereference_field (gcc_jit_rvalue *ptr,
+                                 gcc_jit_location *loc,
+                                 gcc_jit_field *field);
+
+/* Dereferencing a pointer; analogous to:
+     *(EXPR)
+*/
+extern gcc_jit_lvalue *
+gcc_jit_rvalue_dereference (gcc_jit_rvalue *rvalue,
+                           gcc_jit_location *loc);
+
+/* Taking the address of an lvalue; analogous to:
+     &(EXPR)
+   in C.  */
+extern gcc_jit_rvalue *
+gcc_jit_lvalue_get_address (gcc_jit_lvalue *lvalue,
+                           gcc_jit_location *loc);
+
+extern gcc_jit_lvalue *
+gcc_jit_function_new_local (gcc_jit_function *func,
+                           gcc_jit_location *loc,
+                           gcc_jit_type *type,
+                           const char *name);
+
+/**********************************************************************
+ Statement-creation.
+ **********************************************************************/
+
+/* Add evaluation of an rvalue, discarding the result
+   (e.g. a function call that "returns" void).
+
+   This is equivalent to this C code:
+
+     (void)expression;
+*/
+extern void
+gcc_jit_block_add_eval (gcc_jit_block *block,
+                       gcc_jit_location *loc,
+                       gcc_jit_rvalue *rvalue);
+
+/* Add evaluation of an rvalue, assigning the result to the given
+   lvalue.
+
+   This is roughly equivalent to this C code:
+
+     lvalue = rvalue;
+*/
+extern void
+gcc_jit_block_add_assignment (gcc_jit_block *block,
+                             gcc_jit_location *loc,
+                             gcc_jit_lvalue *lvalue,
+                             gcc_jit_rvalue *rvalue);
+
+/* Add evaluation of an rvalue, using the result to modify an
+   lvalue.
+
+   This is analogous to "+=" and friends:
+
+     lvalue += rvalue;
+     lvalue *= rvalue;
+     lvalue /= rvalue;
+   etc  */
+extern void
+gcc_jit_block_add_assignment_op (gcc_jit_block *block,
+                                gcc_jit_location *loc,
+                                gcc_jit_lvalue *lvalue,
+                                enum gcc_jit_binary_op op,
+                                gcc_jit_rvalue *rvalue);
+
+/* Add a no-op textual comment to the internal representation of the
+   code.  It will be optimized away, but will be visible in the dumps
+   seen via
+     GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE
+   and
+     GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE,
+   and thus may be of use when debugging how your project's internal
+   representation gets converted to the libgccjit IR.  */
+extern void
+gcc_jit_block_add_comment (gcc_jit_block *block,
+                          gcc_jit_location *loc,
+                          const char *text);
+
+/* Terminate a block by adding evaluation of an rvalue, branching on the
+   result to the appropriate successor block.
+
+   This is roughly equivalent to this C code:
+
+     if (boolval)
+       goto on_true;
+     else
+       goto on_false;
+
+   block, boolval, on_true, and on_false must be non-NULL.  */
+extern void
+gcc_jit_block_end_with_conditional (gcc_jit_block *block,
+                                   gcc_jit_location *loc,
+                                   gcc_jit_rvalue *boolval,
+                                   gcc_jit_block *on_true,
+                                   gcc_jit_block *on_false);
+
+/* Terminate a block by adding a jump to the given target block.
+
+   This is roughly equivalent to this C code:
+
+      goto target;
+*/
+extern void
+gcc_jit_block_end_with_jump (gcc_jit_block *block,
+                            gcc_jit_location *loc,
+                            gcc_jit_block *target);
+
+/* Terminate a block by adding evaluation of an rvalue, returning the value.
+
+   This is roughly equivalent to this C code:
+
+      return expression;
+*/
+extern void
+gcc_jit_block_end_with_return (gcc_jit_block *block,
+                              gcc_jit_location *loc,
+                              gcc_jit_rvalue *rvalue);
+
+/* Terminate a block by adding a valueless return, for use within a function
+   with "void" return type.
+
+   This is equivalent to this C code:
+
+      return;
+*/
+extern void
+gcc_jit_block_end_with_void_return (gcc_jit_block *block,
+                                   gcc_jit_location *loc);
+
+/**********************************************************************
+ Nested contexts.
+ **********************************************************************/
+
+/* Given an existing JIT context, create a child context.
+
+   The child inherits a copy of all option-settings from the parent.
+
+   The child can reference objects created within the parent, but not
+   vice-versa.
+
+   The lifetime of the child context must be bounded by that of the
+   parent: you should release a child context before releasing the parent
+   context.
+
+   If you use a function from a parent context within a child context,
+   you have to compile the parent context before you can compile the
+   child context, and the gcc_jit_result of the parent context must
+   outlive the gcc_jit_result of the child context.
+
+   This allows caching of shared initializations.  For example, you could
+   create types and declarations of global functions in a parent context
+   once within a process, and then create child contexts whenever a
+   function or loop becomes hot. Each such child context can be used for
+   JIT-compiling just one function or loop, but can reference types
+   and helper functions created within the parent context.
+
+   Contexts can be arbitrarily nested, provided the above rules are
+   followed, but it's probably not worth going above 2 or 3 levels, and
+   there will likely be a performance hit for such nesting.  */
+
+extern gcc_jit_context *
+gcc_jit_context_new_child_context (gcc_jit_context *parent_ctxt);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif  /* LIBGCCJIT_H  */
diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map
new file mode 100644 (file)
index 0000000..d4ba7b6
--- /dev/null
@@ -0,0 +1,100 @@
+# Linker script for libgccjit.so
+#   Copyright (C) 2013-2014 Free Software Foundation, Inc.
+#   Contributed by David Malcolm <dmalcolm@redhat.com>.
+#
+# This file is part of GCC.
+#
+# GCC is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GCC is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.  */
+{
+  global:
+    # Keep this list sorted alphabetically:
+    gcc_jit_block_add_assignment;
+    gcc_jit_block_add_assignment_op;
+    gcc_jit_block_add_comment;
+    gcc_jit_block_add_eval;
+    gcc_jit_block_as_object;
+    gcc_jit_block_end_with_conditional;
+    gcc_jit_block_end_with_jump;
+    gcc_jit_block_end_with_return;
+    gcc_jit_block_end_with_void_return;
+    gcc_jit_block_get_function;
+    gcc_jit_context_acquire;
+    gcc_jit_context_compile;
+    gcc_jit_context_dump_to_file;
+    gcc_jit_context_get_builtin_function;
+    gcc_jit_context_get_first_error;
+    gcc_jit_context_get_type;
+    gcc_jit_context_get_int_type;
+    gcc_jit_context_new_array_access;
+    gcc_jit_context_new_array_type;
+    gcc_jit_context_new_binary_op;
+    gcc_jit_context_new_call;
+    gcc_jit_context_new_call_through_ptr;
+    gcc_jit_context_new_cast;
+    gcc_jit_context_new_child_context;
+    gcc_jit_context_new_comparison;
+    gcc_jit_context_new_field;
+    gcc_jit_context_new_function;
+    gcc_jit_context_new_function_ptr_type;
+    gcc_jit_context_new_global;
+    gcc_jit_context_new_location;
+    gcc_jit_context_new_opaque_struct;
+    gcc_jit_context_new_param;
+    gcc_jit_context_new_rvalue_from_double;
+    gcc_jit_context_new_rvalue_from_int;
+    gcc_jit_context_new_rvalue_from_ptr;
+    gcc_jit_context_new_string_literal;
+    gcc_jit_context_new_struct_type;
+    gcc_jit_context_new_unary_op;
+    gcc_jit_context_new_union_type;
+    gcc_jit_context_null;
+    gcc_jit_context_one;
+    gcc_jit_context_release;
+    gcc_jit_context_set_bool_option;
+    gcc_jit_context_set_int_option;
+    gcc_jit_context_set_str_option;
+    gcc_jit_context_zero;
+    gcc_jit_field_as_object;
+    gcc_jit_function_as_object;
+    gcc_jit_function_dump_to_dot;
+    gcc_jit_function_get_param;
+    gcc_jit_function_new_block;
+    gcc_jit_function_new_local;
+    gcc_jit_location_as_object;
+    gcc_jit_lvalue_as_object;
+    gcc_jit_lvalue_as_rvalue;
+    gcc_jit_lvalue_access_field;
+    gcc_jit_lvalue_get_address;
+    gcc_jit_object_get_context;
+    gcc_jit_object_get_debug_string;
+    gcc_jit_param_as_lvalue;
+    gcc_jit_param_as_object;
+    gcc_jit_param_as_rvalue;
+    gcc_jit_result_get_code;
+    gcc_jit_result_release;
+    gcc_jit_rvalue_access_field;
+    gcc_jit_rvalue_as_object;
+    gcc_jit_rvalue_dereference;
+    gcc_jit_rvalue_dereference_field;
+    gcc_jit_rvalue_get_type;
+    gcc_jit_struct_as_type;
+    gcc_jit_struct_set_fields;
+    gcc_jit_type_as_object;
+    gcc_jit_type_get_const;
+    gcc_jit_type_get_pointer;
+    gcc_jit_type_get_volatile;
+
+  local: *;
+};
\ No newline at end of file
diff --git a/gcc/jit/notes.txt b/gcc/jit/notes.txt
new file mode 100644 (file)
index 0000000..d337cb4
--- /dev/null
@@ -0,0 +1,84 @@
+Client Code   . Generated .            libgccjit.so
+              . code      .
+              .           . JIT API  . JIT "Frontend". (libbackend.a)
+....................................................................................
+   â”‚          .           .          .               .
+    â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€>      .               .
+              .           .    â”‚     .               .
+              .           .    V     .               .
+              .           .    â”€â”€> libgccjit.c       .
+              .           .        â”‚ (error-checking).
+              .           .        â”‚                 .
+              .           .        â”€â”€> jit-recording.c
+              .           .              (record API calls)
+              .           .    <───────              .
+              .           .    â”‚     .               .
+   <───────────────────────────      .               .
+   â”‚          .           .          .               .
+   â”‚          .           .          .               .
+   V          .           .  gcc_jit_context_compile .
+    â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€>      .               .
+              .           .    â”‚     .               .
+              .           .    â”‚ ACQUIRE MUTEX       .
+              .           .    â”‚     .               .
+              .           .    V───────────────────────> toplev::main (for now)
+              .           .          .               .       â”‚
+              .           .          .               .   (various code)
+              .           .          .               .       â”‚
+              .           .          .               .       V
+              .           .          .    <───────────────── langhook:parse_file
+              .           .          .    â”‚          .
+              .           .          .    â”‚ (jit_langhook_parse_file)
+              .           .          .    â”‚          .
+..........................................│..................VVVVVVVVVVVVV...
+              .           .          .    â”‚          .       No GC in here
+              .           .          .    â”‚ jit-playback.c
+              .           .          .    â”‚   (playback of API calls)
+              .           .          .    â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€> creation of functions,
+              .           .          .               .     types, expression trees
+              .           .          .    <──────────────── etc
+              .           .          .    â”‚(handle_locations: add locations to
+              .           .          .    â”‚ linemap and associate them with trees)
+              .           .          .    â”‚          .
+              .           .          .    â”‚          .       No GC in here
+..........................................│..................AAAAAAAAAAAAA...
+              .           .          .    â”‚ for each function
+              .           .          .    â”€â”€> postprocess
+              .           .          .        â”‚      .
+              .           .          .        â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€> cgraph_finalize_function
+              .           .          .        <────────────
+              .           .          .     <──       .
+              .           .          .    â”‚          .
+              .           .          .    â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€> (end of
+              .           .          .               .       â”‚ langhook_parse_file)
+              .           .          .               .       â”‚
+              .           .          .               .   (various code)
+              .           .          .               .       â”‚
+              .           .          .               .       â†“
+              .           .          .    <───────────────── langhook:write_globals
+              .           .          .    â”‚          .
+              .           .          .    â”‚ (jit_langhook_write_globals)
+              .           .          .    â”‚          .
+              .           .          .    â”‚          .
+              .           .          .    â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€> finalize_compilation_unit
+              .           .          .               .       â”‚
+              .           .          .               .   (the middle─end and backend)
+              .           .          .               .       â†“
+              .           .    <───────────────────────────── end of toplev::main
+              .           .    â”‚ RELEASE MUTEX       .
+              .           .    â”‚     .               .
+              .           .    â”‚ Convert assembler to DSO
+              .           .    â”‚     .               .
+              .           .    â”‚ Load DSO            .
+   <───────────────────────────      .               .
+   â”‚          .           .          .               .
+   Get (void*).           .          .               .
+   â”‚          .           .          .               .
+   â”‚ Call it  .           .          .               .
+   â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€>       .          .               .
+              .    â”‚      .          .               .
+              .    â”‚      .          .               .
+   <───────────────       .          .               .
+   â”‚          .           .          .               .
+   â”‚          .           .          .               .
+etc
index ae73a1013d199a31168d619c52a451a99c396477..905a51ade3619b69bf2a58eaae275db46ae0c1bc 100644 (file)
@@ -1,3 +1,67 @@
+2014-11-11  David Malcolm  <dmalcolm@redhat.com>
+
+       * ChangeLog.jit: New.
+       * jit.dg/all-non-failing-tests.h: New.
+       * jit.dg/harness.h: New.
+       * jit.dg/jit.exp: New.
+       * jit.dg/test-accessing-struct.c: New.
+       * jit.dg/test-accessing-union.c: New.
+       * jit.dg/test-array-as-pointer.c: New.
+       * jit.dg/test-arrays.c: New.
+       * jit.dg/test-calling-external-function.c: New.
+       * jit.dg/test-calling-function-ptr.c: New.
+       * jit.dg/test-combination.c: New.
+       * jit.dg/test-dot-product.c: New.
+       * jit.dg/test-empty.c: New.
+       * jit.dg/test-error-accessing-field-in-other-struct.c: New.
+       * jit.dg/test-error-adding-to-terminated-block.c: New.
+       * jit.dg/test-error-array-as-pointer.c: New.
+       * jit.dg/test-error-bad-cast.c: New.
+       * jit.dg/test-error-block-in-wrong-function.c: New.
+       * jit.dg/test-error-call-through-ptr-with-mismatching-args.c: New.
+       * jit.dg/test-error-call-through-ptr-with-non-function.c: New.
+       * jit.dg/test-error-call-through-ptr-with-non-pointer.c: New.
+       * jit.dg/test-error-call-through-ptr-with-not-enough-args.c: New.
+       * jit.dg/test-error-call-through-ptr-with-too-many-args.c: New.
+       * jit.dg/test-error-call-with-mismatching-args.c: New.
+       * jit.dg/test-error-call-with-not-enough-args.c: New.
+       * jit.dg/test-error-call-with-too-many-args.c: New.
+       * jit.dg/test-error-dereference-field-of-non-pointer.c: New.
+       * jit.dg/test-error-dereference-read-of-non-pointer.c: New.
+       * jit.dg/test-error-get-type-bad-enum.c: New.
+       * jit.dg/test-error-index-not-a-numeric-type.c: New.
+       * jit.dg/test-error-mismatching-types-in-assignment.c: New.
+       * jit.dg/test-error-mismatching-types-in-call.c: New.
+       * jit.dg/test-error-missing-return.c: New.
+       * jit.dg/test-error-new-binary-op-bad-op.c: New.
+       * jit.dg/test-error-new-function-bad-kind.c: New.
+       * jit.dg/test-error-new-unary-op-bad-op.c: New.
+       * jit.dg/test-error-null-passed-to-api.c: New.
+       * jit.dg/test-error-return-within-void-function.c: New.
+       * jit.dg/test-error-unreachable-block.c: New.
+       * jit.dg/test-error-unterminated-block.c: New.
+       * jit.dg/test-error-value-not-a-numeric-type.c: New.
+       * jit.dg/test-expressions.c: New.
+       * jit.dg/test-factorial.c: New.
+       * jit.dg/test-fibonacci.c: New.
+       * jit.dg/test-functions.c: New.
+       * jit.dg/test-fuzzer.c: New.
+       * jit.dg/test-hello-world.c: New.
+       * jit.dg/test-linked-list.c: New.
+       * jit.dg/test-long-names.c: New.
+       * jit.dg/test-nested-contexts.c: New.
+       * jit.dg/test-nested-loops.c: New.
+       * jit.dg/test-operator-overloading.cc: New.
+       * jit.dg/test-quadratic.c: New.
+       * jit.dg/test-quadratic.cc: New.
+       * jit.dg/test-reading-struct.c: New.
+       * jit.dg/test-string-literal.c: New.
+       * jit.dg/test-sum-of-squares.c: New.
+       * jit.dg/test-threads.c: New.
+       * jit.dg/test-types.c: New.
+       * jit.dg/test-using-global.c: New.
+       * jit.dg/test-volatile.c: New.
+
 2014-11-11  James Greenhalgh  <james.greenhalgh@arm.com>
 
        * gcc.target/aarch64/vbslq_f64_1.c: New.
diff --git a/gcc/testsuite/ChangeLog.jit b/gcc/testsuite/ChangeLog.jit
new file mode 100644 (file)
index 0000000..a850c6f
--- /dev/null
@@ -0,0 +1,626 @@
+2014-11-05  David Malcolm  <dmalcolm@redhat.com>
+
+       * jit.dg/test-error-get-type-bad-enum.c: New test case.
+       * jit.dg/test-error-new-binary-op-bad-op.c: Likewise.
+       * jit.dg/test-error-new-function-bad-kind.c: Likewise.
+       * jit.dg/test-error-new-unary-op-bad-op.c: Likewise.
+
+2014-10-22  David Malcolm  <dmalcolm@redhat.com>
+
+       * jit.dg/jit.exp (DEFAULT_CFLAGS): Add -fgnu89-inline since
+       dejagnu.h assumes this.
+
+2014-10-17  David Malcolm  <dmalcolm@redhat.com>
+
+       * jit.dg/jit.exp (get_path_of_driver): New procedure.
+       (jit-dg-test): Don't unsetenv GCC_EXEC_PREFIX, since jit-playback.c
+       now adds -fno-use-linker-plugin to the driver cmdline sidestepping
+       the builddir/installdir libtto_plugin naming issue.
+       When setting up PATH so that the JIT library can invoke the driver
+       by installation name, don't use the installation "bindir".
+       Instead, simply use the location of xgcc as detected
+       get_path_of_driver.  In addition, set up LIBRARY_PATH so that the
+       linker run from inside the JIT library can locate libgcc etc when
+       building the .so, pointing it at the same directory.
+
+2014-10-13  David Malcolm  <dmalcolm@redhat.com>
+
+       * jit.dg/jit.exp (fixed_host_execute): New function, taken from
+       "host_execute" in DejaGnu's dejagnu.exp, with one line removed.
+       (jit-dg-test): Use fixed_host_execute, rathern than host_execute.
+
+2014-10-13  David Malcolm  <dmalcolm@redhat.com>
+
+       * jit.dg/harness.h [MAKE_DEJAGNU_H_THREADSAFE] (note): Redefine
+       "note" from dejagnu.h to new function dejagnu_note so that we can
+       make "note" be threadsafe.
+       (set_options): Don't enable GCC_JIT_BOOL_OPTION_DUMP_SUMMARY,
+       since it can generate large amounts of output that could overwhelm
+       expect's buffer.
+       * jit.dg/test-dot-product.c (verify_code): Use "note" rather than
+       "printf", to give DejaGnu more chances to parse this log data,
+       rather than overflowing its buffer.
+       * jit.dg/test-factorial.c (verify_code): Likewise.
+       * jit.dg/test-fibonacci.c (verify_code): Likewise.
+       * jit.dg/test-fuzzer.c (main): Likewise.
+       * jit.dg/test-nested-loops.c (verify_code): Likewise.
+       * jit.dg/test-sum-of-squares.c (verify_code): Likewise.
+       * jit.dg/test-threads.c (note): New function, adding thread-safety
+       on top of "dejagnu_note", the latter being the implementation
+       found in dejagnu.h.
+       (run_threaded_test): Use "note" rather than "printf".
+
+2014-10-07  David Malcolm  <dmalcolm@redhat.com>
+
+       * jit.dg/jit.exp (jit-dg-test): Prepend the installed bindir to
+       the PATH before invoking built binaries using the library, so that
+       the library can find the driver.  Restore the PATH immediately
+       afterwards.
+
+2014-09-24  David Malcolm  <dmalcolm@redhat.com>
+
+       * ChangeLog.jit: Add copyright footer.
+
+2014-09-23  David Malcolm  <dmalcolm@redhat.com>
+
+       * jit.dg/test-expressions.c (make_tests_of_binary_ops): Add
+       shift operators.
+       (verify_binary_ops): Likewise.
+
+2014-09-18  David Malcolm  <dmalcolm@redhat.com>
+
+       * jit.dg/jit.exp: When constructing "tests", add the example files
+       from the documentation, to ensure that they compile.
+
+2014-09-10  David Malcolm  <dmalcolm@redhat.com>
+
+       * jit.dg/jit.exp: Load target-supports.exp.
+
+2014-09-09  David Malcolm  <dmalcolm@redhat.com>
+
+       * jit.dg/test-nested-loops.c: New test case.
+       * jit.dg/all-non-failing-tests.h: Add test-nested-loops.c.
+       * jit.dg/test-combination.c (create_code): Likewise.
+       (verify_code): Likewise.
+       * jit.dg/test-threads.c (const): Add test-nested-loops.c.
+
+2014-08-11  David Malcolm  <dmalcolm@redhat.com>
+
+       * jit.dg/test-threads.c: New test case, running all of the
+       individual test cases in separate threads.
+       * jit.dg/test-combination.c: Move inclusion of the various
+       individual testcases into...
+       * jit.dg/all-non-failing-tests.h: ...this new file, and rename
+       TEST_COMBINATION to COMBINED_TEST.
+       * jit.dg/harness.h: Respond to new macro MAKE_DEJAGNU_H_THREADSAFE
+       by hacking up <dejagnu.h> to be threadsafe.  Rename
+       TEST_COMBINATION to COMBINED_TEST.
+       * jit.dg/jit.exp (proc jit-dg-test): Add "-lpthread" when building
+       test-threads.exe.
+
+2014-08-08  David Malcolm  <dmalcolm@redhat.com>
+
+       * jit.dg/test-accessing-union.c: New test case.
+       * jit.dg/test-combination.c: Add test-accessing-union.c.
+
+2014-08-08  David Malcolm  <dmalcolm@redhat.com>
+
+       * jit.dg/test-combination.c (create_code): Add missing calls to
+       create_code_quadratic and create_code_reading_struct.
+       (verify_code): Add missing calls to verify_code_quadratic and
+       verify_code_reading_struct.
+
+2014-08-08  David Malcolm  <dmalcolm@redhat.com>
+
+       * jit.dg/test-calling-function-ptr.c: New test case.
+       * jit.dg/test-combination.c: Add test-calling-function-ptr.c.
+       * jit.dg/test-error-call-through-ptr-with-mismatching-args.c: New
+       test case.
+       * jit.dg/test-error-call-through-ptr-with-non-function.c: New test
+       case.
+       * jit.dg/test-error-call-through-ptr-with-non-pointer.c: New test
+       case.
+       * jit.dg/test-error-call-through-ptr-with-not-enough-args.c: New
+       test case.
+
+2014-07-25  David Malcolm  <dmalcolm@redhat.com>
+
+       * jit.dg/test-error-index-not-a-numeric-type.c: New test case.
+       * jit.dg/test-error-value-not-a-numeric-type.c: New test case.
+
+2014-03-19  David Malcolm  <dmalcolm@redhat.com>
+
+       * jit.dg/test-array-as-pointer.c: New test case, verifying that
+       there's a way to treat arrays as pointers.
+       * jit.dg/test-combination.c: Add test-array-as-pointer.c...
+       (create_code): ...here and...
+       (verify_code): ...here.
+
+       * jit.dg/test-error-array-as-pointer.c: New test case, verifying
+       that bogus casts from array to pointer are caught by the type
+       system, rather than leading to ICEs seen in:
+       https://github.com/davidmalcolm/pygccjit/pull/3#issuecomment-37883129
+
+2014-03-18  David Malcolm  <dmalcolm@redhat.com>
+
+       * jit.dg/test-combination.c: Add test-arrays.c and test-volatile.c.
+       Add comment about test-error-*.c.  Remove comment about
+       test-failure.c, which was removed in
+       96b218c9a1d5f39fb649e02c0e77586b180e8516.
+       (create_code): Call into test-arrays.c and test-volatile.c.
+       (verify_code): Likewise.
+
+2014-03-14  David Malcolm  <dmalcolm@redhat.com>
+
+       * jit.dg/test-expressions.c (called_pointer_checking_function): New.
+       (make_tests_of_casts): Add test of casting from array to pointer.
+       (verify_casts): Likewise.
+
+2014-03-13  David Malcolm  <dmalcolm@redhat.com>
+
+       * jit.dg/test-error-bad-cast.c: New test case.
+
+2014-03-11  David Malcolm  <dmalcolm@redhat.com>
+
+       * jit.dg/harness.h (set_options): Increase optimization level from
+       0 to 3.
+
+2014-03-07  David Malcolm  <dmalcolm@redhat.com>
+
+       * jit.dg/test-functions.c (create_test_of_hidden_function): New,
+       adding test coverage for GCC_JIT_FUNCTION_ALWAYS_INLINE and
+       GCC_JIT_FUNCTION_INTERNAL.
+       (create_tests_of_hidden_functions): Likewise.
+       (verify_hidden_functions): Likewise.
+       (create_code): Add call to create_tests_of_hidden_functions.
+       (verify_code): Add call to verify_hidden_functions.
+       * jit.dg/test-quadratic.c (make_calc_discriminant): Convert
+       from GCC_JIT_FUNCTION_EXPORTED to GCC_JIT_FUNCTION_INTERNAL.
+
+2014-03-07  David Malcolm  <dmalcolm@redhat.com>
+
+       * jit.dg/test-functions.c: Reorder function definitions, grouping
+       them by subject-matter rather than by create-vs-verify phase.
+
+2014-03-06  David Malcolm  <dmalcolm@redhat.com>
+
+       * jit.dg/test-nested-contexts.c (main): Dump the contexts to
+       files, setting up source locations, and adding test coverage for
+       gcc_jit_context_dump_to_file.
+
+2014-03-04  David Malcolm  <dmalcolm@redhat.com>
+
+       * jit.dg/test-error-mismatching-types-in-call.c: New test case,
+       to ensure that a (struct foo *) vs (struct foo) type error is
+       gracefully handled.
+
+2014-03-04  David Malcolm  <dmalcolm@redhat.com>
+
+       * jit.dg/test-volatile.c: New testcase, to exercise
+       gcc_jit_type_get_volatile, and show a way to work with pre-existing
+       global variables.
+
+2014-02-28  David Malcolm  <dmalcolm@redhat.com>
+
+       * jit.dg/test-expressions.c (make_test_of_cast): New, to test new
+       entrypoint gcc_jit_context_new_cast.
+       (make_tests_of_casts): New.
+       (create_code): Add call to make_tests_of_casts.
+       (verify_code): Add call to verify_casts.
+
+2014-02-27  David Malcolm  <dmalcolm@redhat.com>
+
+       * jit.dg/test-accessing-struct.c (create_code): Port to
+       block-based API.
+       * jit.dg/test-calling-external-function.c (create_code): Likewise.
+       * jit.dg/test-error-accessing-field-in-other-struct.c (create_code):
+       Likewise.
+       * jit.dg/test-error-call-with-mismatching-args.c (create_code):
+       Likewise.
+       * jit.dg/test-error-call-with-not-enough-args.c (create_code):
+       Likewise.
+       * jit.dg/test-error-call-with-too-many-args.c (create_code):
+       Likewise.
+       * jit.dg/test-error-dereference-field-of-non-pointer.c (create_code):
+       Likewise.
+       * jit.dg/test-error-dereference-read: Likewise.
+       * jit.dg/test-error-mismatching-types-in-assignment.c: Likewise.
+       * jit.dg/test-error-return-within-void-function.c: Likewise.
+       * jit.dg/test-expressions.c: Likewise.
+       * jit.dg/test-factorial.c: Likewise.
+       * jit.dg/test-functions.c: Likewise.
+       * jit.dg/test-fuzzer.c: Likewise.
+       * jit.dg/test-hello-world.c (create_code): Likewise.
+       * jit.dg/test-nested-contexts.c: Likewise.
+       * jit.dg/test-operator-overloading.cc: Likewise.
+       * jit.dg/test-quadratic.c: Likewise.
+       * jit.dg/test-quadratic.cc: Likewise.
+       * jit.dg/test-reading-struct.c (create_code): Likewise.
+       * jit.dg/test-string-literal.c (create_code): Likewise.
+       * jit.dg/test-sum-of-squares.c (create_code): Likewise.
+       * jit.dg/test-types.c (create_code): Likewise.
+       * jit.dg/test-using-global.c (create_code): Likewise.
+
+       * jit.dg/test-arrays.c (create_code): Likewise, eliminating use of
+       loop API.
+       * jit.dg/test-dot-product.c (create_code): Likewise.
+       * jit.dg/test-linked-list.c (create_code): Likewise.
+
+       * jit.dg/test-error-adding-to-terminated-block.c: New testcase.
+       * jit.dg/test-error-block-in-wrong-function.c: Likewise.
+       * jit.dg/test-error-missing-return.c: Likewise.
+       * jit.dg/test-error-unreachable-block.c: Likewise.
+       * jit.dg/test-error-unterminated-block.c: Likewise.
+
+       * jit.dg/test-error-label-already-placed.c: Delete obsolete testcase.
+       * jit.dg/test-error-unplaced-label.c: Likewise.
+
+2014-02-25  David Malcolm  <dmalcolm@redhat.com>
+
+       * jit.dg/test-functions.c (create_use_of_void_return): New, to add
+       test coverage for gcc_jit_function_add_void_return.
+       (verify_void_return): Likewise.
+       (create_code): Add call to create_use_of_void_return.
+       (verify_code): Add call to verify_void_return.
+
+2014-02-18  David Malcolm  <dmalcolm@redhat.com>
+
+       * jit.dg/test-accessing-struct.c (create_code): Update for change to
+       return type of gcc_jit_context_new_struct_type.
+       * jit.dg/test-arrays.c (create_code): Likewise.
+       * jit.dg/test-error-accessing-field-in-other-struct.c (create_code):
+       Likewise.
+       * jit.dg/test-error-dereference-field-of-non-pointer.c (create_code):
+       Likewise.
+       * jit.dg/test-fuzzer.c (make_random_type): Likewise.
+       * jit.dg/test-nested-contexts.c (make_types): Likewise.
+       * jit.dg/test-quadratic.c (make_types): Likewise.
+       * jit.dg/test-reading-struct.c (create_code): Likewise.
+       * jit.dg/test-types.c (create_code): Likewise.
+
+       * jit.dg/test-linked-list.c: New selftest, exercising
+       gcc_jit_context_new_opaque_struct, gcc_jit_type_get_pointer, and
+       gcc_jit_context_null.
+       * jit.dg/test-combination.c: Add test-linked-list.c
+
+2014-02-14  David Malcolm  <dmalcolm@redhat.com>
+
+       * jit.dg/test-operator-overloading.cc (make_test_quadratic): Use
+       the new "zero" and "one" methods of gccjit::type.
+       * jit.dg/test-quadratic.cc (make_test_quadratic): Use the new
+       "add_call" method of gccjit::function.
+
+2014-02-13  David Malcolm  <dmalcolm@redhat.com>
+
+       * jit.dg/harness.h (CHECK_DOUBLE_VALUE): New macro.
+       (CHECK): New macro.
+       * jit.dg/test-functions.c: New testcase, exercising
+       gcc_jit_context_get_builtin_function.
+       * jit.dg/test-combination.c: Add test-functions.c to the combined
+       test.
+
+2014-02-11  David Malcolm  <dmalcolm@redhat.com>
+
+       * jit.dg/test-types.c: Add test coverage for getting type
+       GCC_JIT_TYPE_BOOL.
+       * jit.dg/test-expressions.c (make_test_of_comparison): Convert
+       return type from int to bool.
+       (verify_comparisons): Likewise.
+
+2014-02-11  David Malcolm  <dmalcolm@redhat.com>
+
+       * jit.dg/test-error-unplaced-label.c (verify_code): Update
+       expected error message to reflect commit
+       6cd4f82c5237cc328aea229cdaaa428ff09d6e98.
+
+2014-02-10  David Malcolm  <dmalcolm@redhat.com>
+
+       * jit.dg/test-types.c (struct zoo): Add field m_sized_int_type,
+       to be populated by...
+       (create_code): Use gcc_jit_context_get_int_type.
+       (verify_code): Verify that type from gcc_jit_context_get_int_type
+       works properly.
+       * jit.dg/test-operator-overloading.cc (make_types): Use the
+       template form of get_int_type.
+       * jit.dg/test-quadratic.cc (make_types): Likewise.
+
+2014-02-10  David Malcolm  <dmalcolm@redhat.com>
+
+       * jit.dg/test-operator-overloading.cc: New testcase, a
+       rewrite of test-quadratic.cc to use operator overloading.
+
+2014-02-10  David Malcolm  <dmalcolm@redhat.com>
+
+       * jit.dg/test-quadratic.cc (make_calc_discriminant): Make use of
+       new methods of the C++ wrapper API to shorten the example code.
+       (make_test_quadratic): Likewise.
+
+2014-02-10  David Malcolm  <dmalcolm@redhat.com>
+
+       * jit.dg/test-quadratic.cc (make_test_quadratic): Update for
+       change to gccjit::context::new_call to pass args by reference
+       rather than by value.
+
+2014-02-03  David Malcolm  <dmalcolm@redhat.com>
+
+       * jit.dg/harness.h (check_string_value): Add a forward declaration,
+       so that we can use CHECK_STRING_VALUE from within tests used by
+       test-combination.c.
+
+       * jit.dg/test-expressions.c (make_test_of_unary_op): Return a debug
+       stringification of the operation so that it be sanity-checked.
+       (make_test_of_binary_op): Likewise.
+       (make_test_of_comparison): Likewise.
+       (make_tests_of_unary_ops): Verify that said stringifications are
+       indeed sane.
+       (make_tests_of_binary_ops): Likewise.
+       (make_tests_of_comparisons): Likewise.
+
+       * jit.dg/test-quadratic.cc (make_types): Verify that the
+       get_debug_string method works.
+       (make_test_quadratic): Likewise, also, verify that the <<
+       operator works.
+
+2014-01-31  David Malcolm  <dmalcolm@redhat.com>
+
+       * jit.dg/test-quadratic.cc: New file - a translation of
+       test-quadratic.c to the libgccjit++.h C++ API.
+
+2014-01-30  David Malcolm  <dmalcolm@redhat.com>
+
+       * jit.dg/test-error-label-already-placed.c: New test case.
+       * jit.dg/test-error-unplaced-label.c: New test case.
+
+2014-01-30  David Malcolm  <dmalcolm@redhat.com>
+
+       * jit.dg/test-error-call-with-mismatching-args.c: New test case.
+
+2014-01-30  David Malcolm  <dmalcolm@redhat.com>
+
+       * jit.dg/test-error-accessing-field-in-other-struct.c: New test
+       case.
+       * jit.dg/test-error-dereference-field-of-non-pointer.c: Likewise.
+       * jit.dg/test-error-dereference-read-of-non-pointer.c: Likewise.
+       * jit.dg/test-error-mismatching-types-in-assignment.c: Likewise.
+       * jit.dg/test-error-return-within-void-function.c: Likewise.
+
+2014-01-29  David Malcolm  <dmalcolm@redhat.com>
+
+       * jit.dg/test-accessing-struct.c (create_code): Update for API change
+       for accessing fields in terms of gcc_jit_field pointers rather than
+       by name.
+       * jit.dg/test-nested-contexts.c (make_calc_discriminant): Likewise.
+       (make_test_quadratic): Likewise.
+       * jit.dg/test-quadratic.c (make_calc_discriminant): Likewise.
+       (make_test_quadratic): Likewise.
+       * jit.dg/test-reading-struct.c (create_code): Likewise.
+       * jit.dg/test-types.c: Likewise.
+
+2014-01-28  David Malcolm  <dmalcolm@redhat.com>
+
+       * jit.dg/harness.h (test_jit): Add the possibility of turning off
+       this function, if the newly-coined "TEST_ESCHEWS_TEST_JIT" is
+       defined, for use by...
+       * jit.dg/test-nested-contexts.c: New test case, adapting
+       test-quadratic.c, but splitting it into a 3-deep arrangement of
+       nested contexts, to test the implementation of child contexts.
+
+2014-01-28  David Malcolm  <dmalcolm@redhat.com>
+
+       * jit.dg/harness.h (test_jit): Move the various calls to set up
+       options on the context into...
+       (set_options): ...this new function.
+
+2014-01-27  David Malcolm  <dmalcolm@redhat.com>
+
+       * jit.dg/test-error-call-with-not-enough-args.c: New test case.
+       * jit.dg/test-error-call-with-too-many-args.c: New test case.
+       * jit.dg/test-null-passed-to-api.c: Rename to...
+       * jit.dg/test-error-null-passed-to-api.c: ...this, so that
+       error-handling test cases are consistently named.
+
+2014-01-24  David Malcolm  <dmalcolm@redhat.com>
+
+       * jit.dg/test-empty.c: New test case.
+
+2014-01-24  David Malcolm  <dmalcolm@redhat.com>
+
+       * jit.dg/harness.h (code_making_callback): Rename to...
+       (create_code): ...this, and eliminate the returned
+       error-handling value: test cases will simply call into the
+       gcc_jit_ API, without needing to be run from a callback.
+       (test_jit): Don't register a callback, simply call the
+       "create_code" function for the testcase before compiling the
+       context.
+
+       * jit.dg/test-accessing-struct.c: Rename "code_making_callback"
+       to "create_code" and eliminate the return code.
+       * jit.dg/test-calling-external-function.c: Likewise.
+       * jit.dg/test-combination.c: Likewise.
+       * jit.dg/test-dot-product.c: Likewise.
+       * jit.dg/test-expressions.c: Likewise.
+       * jit.dg/test-factorial.c: Likewise.
+       * jit.dg/test-fibonacci.c: Likewise.
+       * jit.dg/test-fuzzer.c: Likewise.
+       * jit.dg/test-hello-world.c: Likewise.
+       * jit.dg/test-null-passed-to-api.c: Likewise.
+       * jit.dg/test-quadratic.c: Likewise.
+       * jit.dg/test-reading-struct.c: Likewise.
+       * jit.dg/test-string-literal.c: Likewise.
+       * jit.dg/test-sum-of-squares.c: Likewise.
+       * jit.dg/test-types.c: Likewise.
+       * jit.dg/test-using-global.c: Likewise.
+
+       * jit.dg/test-failure.c: Remove this test case, since it was
+       specifically for testing the now-defunct callback-based API.
+
+2014-01-23  David Malcolm  <dmalcolm@redhat.com>
+
+       * jit.dg/test-quadratic.c: New test case, written to achieve test
+       coverage of gcc_jit_rvalue_access_field, but also exercising
+       division of doubles.
+
+       * jit.dg/test-combination.c: Add test-quadratic.c
+
+       * jit.dg/test-expressions.c: Add TODOs.
+
+2014-01-23  David Malcolm  <dmalcolm@redhat.com>
+
+       * jit.dg/test-reading-struct.c: New test, to provide test coverage
+       of gcc_jit_type_get_const and gcc_jit_lvalue_access_field, in the
+       process uncovering bugs in how locals were handled.
+       * jit.dg/test-combination.c: Add usage of test-reading-struct.c.
+
+2014-01-21  David Malcolm  <dmalcolm@redhat.com>
+
+       * jit.dg/test-hello-world.c (code_making_callback): Add usage of
+       gcc_jit_function_add_comment.
+
+2013-10-24  David Malcolm  <dmalcolm@redhat.com>
+
+       * jit.dg/harness.h (main): Wrap with #ifndef TEST_PROVIDES_MAIN
+       * jit.dg/test-fuzzer.c: New.
+
+2013-10-22  David Malcolm  <dmalcolm@redhat.com>
+
+       * jit.dg/harness.h (verify_code): Add context param so that
+       test cases of failure can query errors on it.
+       (CHECK_STRING_VALUE): New.
+       (check_string_value): New.
+       (test_jit): Add user_data param and pass it to the code factory.
+       Pass context to verify_code, calling it before releasing said
+       context.
+       (main): Add NULL user_data to test_jit call.
+       * jit.dg/test-accessing-struct.c (verify_code): Add context
+       param.
+       * jit.dg/test-calling-external-function.c (verify_code):
+       Likewise.
+       * jit.dg/test-combination.c (verify_code): Likewise.
+       * jit.dg/test-dot-product.c (verify_code): Likewise.
+       * jit.dg/test-expressions.c (verify_code): Likewise.
+       * jit.dg/test-factorial.c (verify_code): Likewise.
+       * jit.dg/test-failure.c (verify_code): Likewise.
+       * jit.dg/test-fibonacci.c (verify_code): Likewise.
+       * jit.dg/test-hello-world.c (verify_code): Likewise.
+       * jit.dg/test-string-literal.c (verify_code): Likewise.
+       * jit.dg/test-sum-of-squares.c (verify_code): Likewise.
+       * jit.dg/test-types.c (verify_code): Likewise.
+       * jit.dg/test-using-global.c (verify_code): Likewise.
+       * jit.dg/test-null-passed-to-api.c (verify_code): Likewise;
+       use context to verify that the library provides a sane error
+       message to the client code.
+
+2013-10-21  David Malcolm  <dmalcolm@redhat.com>
+
+       * jit.dg/test-expressions.c (test_global): New.
+       (make_test_of_get_address): New.
+       (verify_get_address): New.
+       (code_making_callback): Add call to make_test_of_get_address.
+       (verify_code): Add call to verify_get_address.
+
+2013-10-18  David Malcolm  <dmalcolm@redhat.com>
+
+       * jit.dg/test-expressions.c: New.
+       * jit.dg/test-combination.c: Add usage of test-expressions.c
+       * jit.dg/test-accessing-struct.c (code_making_callback): Update
+       for changes to field-access API.
+       * jit.dg/test-types.c (code_making_callback): Likewise.
+
+2013-10-18  David Malcolm  <dmalcolm@redhat.com>
+
+       * jit.dg/test-null-passed-to-api.c: New.
+
+2013-10-17  David Malcolm  <dmalcolm@redhat.com>
+
+       * jit.dg/test-accessing-struct.c (code_making_callback): Update
+       for changes to type API.
+       * jit.dg/test-calling-external-function.c (code_making_callback):
+       Likewise.
+       * jit.dg/test-dot-product.c (code_making_callback): Likewise.
+       * jit.dg/test-factorial.c (code_making_callback): Likewise.
+       * jit.dg/test-fibonacci.c (code_making_callback): Likewise.
+       * jit.dg/test-hello-world.c (code_making_callback): Likewise.
+       * jit.dg/test-string-literal.c (code_making_callback): Likewise.
+       * jit.dg/test-sum-of-squares.c (code_making_callback): Likewise.
+       * jit.dg/test-using-globals.c (code_making_callback): Likewise.
+       * jit.dg/test-types.c: New.
+       * jit.dg/test-combination.c (code_making_callback): Use code
+       from test-types.c.
+       (verify_code): ...and verify it.
+
+2013-10-16  David Malcolm  <dmalcolm@redhat.com>
+
+       * jit.dg/test-dot-product.c (code_making_callback): Update for
+       API changes to locals.
+       * jit.dg/test-sum-of-squares.c (code_making_callback): Likewise.
+
+2013-10-14  David Malcolm  <dmalcolm@redhat.com>
+
+       * jit.dg/jit.exp (jit-dg-test): Detect compilation errors and
+       make them be test failures.
+
+2013-10-14  David Malcolm  <dmalcolm@redhat.com>
+
+       * jit.dg/test-factorial.c (code_making_callback): Update
+       for change to gcc_jit_function_place_forward_label.
+       * jit.dg/test-fibonacci.c (code_making_callback): Add line
+       numbering to comment, and set up source locations throughout)
+       allowing stepping throught the comment in the debugger.
+       * jit.dg/test-sum-of-squares.c (code_making_callback): Update
+       for change to gcc_jit_function_place_forward_label.
+
+2013-10-10  David Malcolm  <dmalcolm@redhat.com>
+
+       * jit.dg/harness.h: Set GCC_JIT_BOOL_OPTION_DUMP_SUMMARY when
+       running selftests.
+
+2013-10-08  David Malcolm  <dmalcolm@redhat.com>
+
+       * jit.dg/harness.h: Wrap parts of harness within a
+       #ifndef TEST_COMBINATION so that it can be included multiple
+       times.
+       * jit.dg/test-accessing-struct.c (code_making_callback): Rename
+       the generated function from test_fn to test_access to avoid a
+       naming collision in the combined test.
+       (verify_code): Likewise.
+       * jit.dg/test-calling-external-function.c (code_making_callback):
+       Rename the generated function from test_fn to test_caller.
+       (verify_code): Likewise.
+       * jit.dg/test-combination.c: New.
+       * jit.dg/test-string-literal.c (code_making_callback): Rename
+       the generated function from test_fn to test_string_literal.
+       (verify_code): Likewise.
+       * jit.dg/test-using-global.c (code_making_callback): Rename
+       the generated function from test_fn to test_using_global.
+       (verify_code): Likewise.
+
+2013-10-07  David Malcolm  <dmalcolm@redhat.com>
+
+       * jit.dg/harness.h (test_jit): Set
+       GCC_JIT_BOOL_OPTION_SELFCHECK_GC when running selftests.
+
+2013-10-04  David Malcolm  <dmalcolm@redhat.com>
+
+       * jit.dg/test-using-global.c: New.
+
+2013-10-03  David Malcolm  <dmalcolm@redhat.com>
+
+       * jit.dg: New subdirectory
+       * jit.dg/harness.h: New.
+       * jit.dg/jit.exp: New.
+       * jit.dg/test-accessing-struct.c: New.
+       * jit.dg/test-calling-external-function.c: New.
+       * jit.dg/test-dot-product.c: New.
+       * jit.dg/test-factorial.c: New.
+       * jit.dg/test-failure.c: New.
+       * jit.dg/test-fibonacci.c: New.
+       * jit.dg/test-hello-world.c: New.
+       * jit.dg/test-string-literal.c: New.
+       * jit.dg/test-sum-of-squares.c: New.
+
+\f
+Copyright (C) 2013-2014 Free Software Foundation, Inc.
+
+Copying and distribution of this file, with or without modification,
+are permitted in any medium without royalty provided the copyright
+notice and this notice are preserved.
diff --git a/gcc/testsuite/jit.dg/all-non-failing-tests.h b/gcc/testsuite/jit.dg/all-non-failing-tests.h
new file mode 100644 (file)
index 0000000..10d7199
--- /dev/null
@@ -0,0 +1,166 @@
+/* This file is used by test-combination.c and test-threads.c to
+   bring all of the non-failing test cases into one source file,
+   renaming each "create_code" and "verify_code" hook so that they
+   each have unique name.  */
+
+/* Include various other test cases, defining COMBINED_TEST so that
+   harness.h doesn't duplicate copes of e.g. main, and renaming the
+   hooks provided by each test case.  */
+#define COMBINED_TEST
+
+/* test-accessing-struct.c */
+#define create_code create_code_accessing_struct
+#define verify_code verify_code_accessing_struct
+#include "test-accessing-struct.c"
+#undef create_code
+#undef verify_code
+
+/* test-accessing-union.c */
+#define create_code create_code_accessing_union
+#define verify_code verify_code_accessing_union
+#include "test-accessing-union.c"
+#undef create_code
+#undef verify_code
+
+/* test-array-as-pointer.c */
+#define create_code create_code_array_as_pointer
+#define verify_code verify_code_array_as_pointer
+#include "test-array-as-pointer.c"
+#undef create_code
+#undef verify_code
+
+/* test-arrays.c */
+#define create_code create_code_arrays
+#define verify_code verify_code_arrays
+#include "test-arrays.c"
+#undef create_code
+#undef verify_code
+
+/* test-calling-external-function.c */
+#define create_code create_code_calling_external_function
+#define verify_code verify_code_calling_external_function
+#include "test-calling-external-function.c"
+#undef create_code
+#undef verify_code
+
+/* test-calling-function-ptr.c */
+#define create_code create_code_calling_function_ptr
+#define verify_code verify_code_calling_function_ptr
+#include "test-calling-function-ptr.c"
+#undef create_code
+#undef verify_code
+
+/* test-dot-product.c */
+#define create_code create_code_dot_product
+#define verify_code verify_code_dot_product
+#include "test-dot-product.c"
+#undef create_code
+#undef verify_code
+
+/* test-error-*.c: We don't use these test cases, since they deliberately
+   introduce errors, which we don't want here.  */
+
+/* test-expressions.c */
+#define create_code create_code_expressions
+#define verify_code verify_code_expressions
+#include "test-expressions.c"
+#undef create_code
+#undef verify_code
+
+/* test-factorial.c */
+#define create_code create_code_factorial
+#define verify_code verify_code_factorial
+#include "test-factorial.c"
+#undef create_code
+#undef verify_code
+
+/* test-fibonacci.c */
+#define create_code create_code_fibonacci
+#define verify_code verify_code_fibonacci
+#include "test-fibonacci.c"
+#undef create_code
+#undef verify_code
+
+/* test-functions.c */
+#define create_code create_code_functions
+#define verify_code verify_code_functions
+#include "test-functions.c"
+#undef create_code
+#undef verify_code
+
+/* test-hello-world.c */
+#define create_code create_code_hello_world
+#define verify_code verify_code_hello_world
+#include "test-hello-world.c"
+#undef create_code
+#undef verify_code
+
+/* test-linked-list.c */
+#define create_code create_code_linked_list
+#define verify_code verify_code_linked_list
+#include "test-linked-list.c"
+#undef create_code
+#undef verify_code
+
+/* test-long-names.c */
+#define create_code create_code_long_names
+#define verify_code verify_code_long_names
+#include "test-long-names.c"
+#undef create_code
+#undef verify_code
+
+/* test-quadratic.c */
+#define create_code create_code_quadratic
+#define verify_code verify_code_quadratic
+#include "test-quadratic.c"
+#undef create_code
+#undef verify_code
+
+/* test-nested-loops.c */
+#define create_code create_code_nested_loop
+#define verify_code verify_code_nested_loop
+#include "test-nested-loops.c"
+#undef create_code
+#undef verify_code
+
+/* test-reading-struct.c */
+#define create_code create_code_reading_struct
+#define verify_code verify_code_reading_struct
+#include "test-reading-struct.c"
+#undef create_code
+#undef verify_code
+
+/* test-string-literal.c */
+#define create_code create_code_string_literal
+#define verify_code verify_code_string_literal
+#include "test-string-literal.c"
+#undef create_code
+#undef verify_code
+
+/* test-sum-of-squares.c */
+#define create_code create_code_sum_of_squares
+#define verify_code verify_code_sum_of_squares
+#include "test-sum-of-squares.c"
+#undef create_code
+#undef verify_code
+
+/* test-types.c */
+#define create_code create_code_types
+#define verify_code verify_code_types
+#include "test-types.c"
+#undef create_code
+#undef verify_code
+
+/* test-using-global.c */
+#define create_code create_code_using_global
+#define verify_code verify_code_using_global
+#include "test-using-global.c"
+#undef create_code
+#undef verify_code
+
+/* test-volatile.c */
+#define create_code create_code_volatile
+#define verify_code verify_code_volatile
+#include "test-volatile.c"
+#undef create_code
+#undef verify_code
diff --git a/gcc/testsuite/jit.dg/harness.h b/gcc/testsuite/jit.dg/harness.h
new file mode 100644 (file)
index 0000000..f326891
--- /dev/null
@@ -0,0 +1,242 @@
+/*
+  Code shared between multiple testcases.
+
+  This file contains "main" and support code.
+  Each testcase should implement the following hooks:
+
+    extern void
+    create_code (gcc_jit_context *ctxt, void * user_data);
+
+    extern void
+    verify_code (gcc_jit_context *ctxt, gcc_jit_result *result);
+
+ */
+#include <stdlib.h>
+#include <stdio.h>
+
+/* test-threads.c use threads, but dejagnu.h isn't thread-safe; there's a
+   shared "buffer", and the counts of passed/failed etc are globals.
+
+   The solution is to use macros to rename "pass" and "fail", replacing them
+   with mutex-guarded alternatives.  */
+#ifdef MAKE_DEJAGNU_H_THREADSAFE
+#define pass dejagnu_pass
+#define fail dejagnu_fail
+#define note dejagnu_note
+#endif
+
+#include <dejagnu.h>
+
+#ifdef MAKE_DEJAGNU_H_THREADSAFE
+#undef pass
+#undef fail
+#undef note
+#endif
+
+static char test[1024];
+
+#define CHECK_NON_NULL(PTR) \
+  do {                                       \
+    if ((PTR) != NULL)                       \
+      {                                      \
+       pass ("%s: %s is non-null", test, #PTR); \
+      }                                      \
+    else                                     \
+      {                                      \
+       fail ("%s: %s is NULL", test, #PTR); \
+       abort ();                            \
+    }                                        \
+  } while (0)
+
+#define CHECK_VALUE(ACTUAL, EXPECTED) \
+  do {                                       \
+    if ((ACTUAL) == (EXPECTED))              \
+      {                                      \
+       pass ("%s: actual: %s == expected: %s", test, #ACTUAL, #EXPECTED); \
+      }                                      \
+    else                                     \
+      {                                        \
+       fail ("%s: actual: %s != expected: %s", test, #ACTUAL, #EXPECTED); \
+       fprintf (stderr, "incorrect value\n"); \
+       abort ();                              \
+    }                                        \
+  } while (0)
+
+#define CHECK_DOUBLE_VALUE(ACTUAL, EXPECTED) \
+  do {                                       \
+    double expected = (EXPECTED);           \
+    double actual = (ACTUAL);               \
+    if (abs (actual - expected) < 0.00001)   \
+      {                                      \
+       pass ("%s: actual: %s == expected: %s", test, #ACTUAL, #EXPECTED); \
+      }                                      \
+    else                                     \
+      {                                      \
+       fail ("%s: actual: %s != expected: %s", test, #ACTUAL, #EXPECTED); \
+       fprintf (stderr, "incorrect value: %f\n", actual); \
+       abort ();                            \
+    }                                        \
+  } while (0)
+
+#define CHECK_STRING_VALUE(ACTUAL, EXPECTED) \
+  check_string_value ((ACTUAL), (EXPECTED));
+
+#define CHECK(COND) \
+  do {                                 \
+    if (COND)                          \
+      {                                \
+       pass ("%s: %s", test, #COND);   \
+      }                                \
+    else                               \
+      {                                \
+       fail ("%s: %s", test, #COND);   \
+       abort ();                       \
+      }                                \
+  } while (0)
+
+/* Hooks that testcases should provide.  */
+extern void
+create_code (gcc_jit_context *ctxt, void * user_data);
+
+extern void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result);
+
+extern void check_string_value (const char *actual, const char *expected);
+
+/* Implement framework needed for turning the testcase hooks into an
+   executable.  test-combination.c and test-threads.c each combine multiple
+   testcases into larger testcases, so we have COMBINED_TEST as a way of
+   temporarily turning off this part of harness.h.  */
+#ifndef COMBINED_TEST
+
+void check_string_value (const char *actual, const char *expected)
+{
+  if (actual && !expected)
+    {
+      fail ("%s: actual: \"%s\" != expected: NULL", test, actual);
+       fprintf (stderr, "incorrect value\n");
+       abort ();
+    }
+    if (expected && !actual)
+      {
+       fail ("%s: actual: NULL != expected: \"%s\"", test, expected);
+       fprintf (stderr, "incorrect value\n");
+       abort ();
+      }
+    if (actual && expected)
+      {
+       if (strcmp (actual, expected))
+         {
+           fail ("%s: actual: \"%s\" != expected: \"%s\"", test, actual, expected);
+           fprintf (stderr, "incorrect valuen");
+           abort ();
+         }
+       pass ("%s: actual: \"%s\" == expected: \"%s\"", test, actual, expected);
+      }
+    else
+      pass ("%s: actual: NULL == expected: NULL");
+}
+
+static void set_options (gcc_jit_context *ctxt, const char *argv0)
+{
+  /* Set up options.  */
+  gcc_jit_context_set_str_option (
+    ctxt,
+    GCC_JIT_STR_OPTION_PROGNAME,
+    argv0);
+  gcc_jit_context_set_int_option (
+    ctxt,
+    GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL,
+    3);
+  gcc_jit_context_set_bool_option (
+    ctxt,
+    GCC_JIT_BOOL_OPTION_DEBUGINFO,
+    1);
+  gcc_jit_context_set_bool_option (
+    ctxt,
+    GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE,
+    0);
+  gcc_jit_context_set_bool_option (
+    ctxt,
+    GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE,
+    0);
+  gcc_jit_context_set_bool_option (
+    ctxt,
+    GCC_JIT_BOOL_OPTION_SELFCHECK_GC,
+    1);
+  gcc_jit_context_set_bool_option (
+    ctxt,
+    GCC_JIT_BOOL_OPTION_DUMP_SUMMARY,
+    0);
+}
+
+#ifndef TEST_ESCHEWS_TEST_JIT
+/* Run one iteration of the test.  */
+static void
+test_jit (const char *argv0, void *user_data)
+{
+  gcc_jit_context *ctxt;
+  gcc_jit_result *result;
+
+  ctxt = gcc_jit_context_acquire ();
+     /* FIXME: error-handling */
+
+  set_options (ctxt, argv0);
+
+  create_code (ctxt, user_data);
+
+  /* This actually calls into GCC and runs the build, all
+     in a mutex for now.  */
+  result = gcc_jit_context_compile (ctxt);
+
+  verify_code (ctxt, result);
+
+  gcc_jit_context_release (ctxt);
+
+  /* Once we're done with the code, this unloads the built .so file: */
+  gcc_jit_result_release (result);
+}
+#endif /* #ifndef TEST_ESCHEWS_TEST_JIT */
+
+/* We want to prefix all unit test results with the test, but dejagnu.exp's
+   host_execute appears to get confused by the leading "./" of argv0,
+   leading to all tests simply reporting as a single period character ".".
+
+   Hence strip out the final component of the path to the program name,
+   so that we can use that in unittest reports.  */
+const char*
+extract_progname (const char *argv0)
+{
+  const char *p;
+
+  p = argv0 + strlen (argv0);
+  while (p != argv0 && p[-1] != '/')
+    --p;
+  return p;
+}
+
+#ifndef TEST_PROVIDES_MAIN
+int
+main (int argc, char **argv)
+{
+  int i;
+
+  for (i = 1; i <= 5; i++)
+    {
+      snprintf (test, sizeof (test),
+               "%s iteration %d of %d",
+                extract_progname (argv[0]),
+                i, 5);
+
+      //printf ("ITERATION %d\n", i);
+      test_jit (argv[0], NULL);
+      //printf ("\n");
+    }
+
+  totals ();
+
+  return 0;
+}
+#endif /* #ifndef TEST_PROVIDES_MAIN */
+
+#endif /* #ifndef COMBINED_TEST */
diff --git a/gcc/testsuite/jit.dg/jit.exp b/gcc/testsuite/jit.dg/jit.exp
new file mode 100644 (file)
index 0000000..531e929
--- /dev/null
@@ -0,0 +1,293 @@
+# Test code for libgccjit.so
+#
+# We will compile each of jit.dg/test-*.c into an executable
+# dynamically linked against libgccjit.so, and then run each
+# such executable.
+#
+# These executables call into the libgccjit.so API to create
+# code, compile it, and run it, verifying that the results
+# are as expected.  See harness.h for shared code used by all
+# such executables.
+#
+# The executables call into DejaGnu's unit testing C API to
+# report PASS/FAIL results, which this script gathers back
+# up into the Tcl world, reporting a summary of all results
+# across all of the executables.
+
+load_lib dg.exp
+load_lib prune.exp
+load_lib target-supports.exp
+load_lib gcc-defs.exp
+load_lib timeout.exp
+load_lib target-libpath.exp
+load_lib gcc.exp
+load_lib dejagnu.exp
+
+# This is host_execute from dejagnu.exp commit
+#   126a089777158a7891ff975473939f08c0e31a1c
+# with the following patch applied, and renaming to "fixed_host_execute".
+# See the discussion at
+#  http://lists.gnu.org/archive/html/dejagnu/2014-10/msg00000.html
+#
+#  --- /usr/share/dejagnu/dejagnu.exp.old  2014-10-08 13:38:57.274068541 -0400
+#  +++ /usr/share/dejagnu/dejagnu.exp      2014-10-10 12:27:51.113813659 -0400
+#  @@ -113,8 +113,6 @@ proc host_execute {args} {
+#       set timetol 0
+#       set arguments ""
+#   
+#  -    expect_before buffer_full { perror "Buffer full" }
+#  -
+#       if { [llength $args] == 0} {
+#          set executable $args
+#       } else {
+
+
+# Execute the executable file, and anaylyse the output for the
+# test state keywords.
+#    Returns:
+#      A "" (empty) string if everything worked, or an error message
+#      if there was a problem.
+#
+proc fixed_host_execute {args} {
+    global text
+    global spawn_id
+
+    set timeoutmsg "Timed out: Never got started, "
+    set timeout 100
+    set file all
+    set timetol 0
+    set arguments ""
+
+    if { [llength $args] == 0} {
+       set executable $args
+    } else {
+       set executable [string trimleft [lindex [split $args " "] 0] "\{"]
+       set params [string trimleft [lindex [split $args " "] 1] "\{"]
+       set params [string trimright $params "\}"]
+    }
+
+    verbose "The executable is $executable" 2
+    if {![file exists ${executable}]} {
+       perror "The executable, \"$executable\" is missing" 0
+       return "No source file found"
+    }
+
+    # spawn the executable and look for the DejaGnu output messages from the
+    # test case.
+    # spawn -noecho -open [open "|./${executable}" "r"]
+    spawn -noecho "./${executable}" ${params}
+    expect_after full_buffer { error "got full_buffer" }
+
+    set prefix "\[^\r\n\]*"
+    expect {
+       -re "^$prefix\[0-9\]\[0-9\]:..:..:${text}*\r\n" {
+           regsub "\[\n\r\t\]*NOTE: $text\r\n" $expect_out(0,string) "" output
+           verbose "$output" 3
+           set timetol 0
+           exp_continue
+       }
+       -re "^$prefix\tNOTE:${text}*" {
+           regsub "\[\n\r\t\]*NOTE: $text\r\n" $expect_out(0,string) "" output
+           set output [string range $output 6 end]
+           verbose "$output" 2
+           set timetol 0
+           exp_continue
+       }
+       -re "^$prefix\tPASSED:${text}*" {
+           regsub "\[\n\r\t\]*PASSED: $text\r\n" $expect_out(0,string) "" output
+           set output [string range $output 8 end]
+           pass "$output"
+           set timetol 0
+           exp_continue
+       }
+       -re "^$prefix\tFAILED:${text}*" {
+           regsub "\[\n\r\t\]*FAILED: $text\r\n" $expect_out(0,string) "" output
+           set output [string range $output 8 end]
+           fail "$output"
+           set timetol 0
+           exp_continue
+       }
+       -re "^$prefix\tUNTESTED:${text}*" {
+           regsub "\[\n\r\t\]*TESTED: $text\r\n" $expect_out(0,string) "" output
+           set output [string range $output 8 end]
+           untested "$output"
+           set timetol 0
+           exp_continue
+       }
+       -re "^$prefix\tUNRESOLVED:${text}*" {
+           regsub "\[\n\r\t\]*UNRESOLVED: $text\r\n" $expect_out(0,string) "" output
+           set output [string range $output 8 end]
+           unresolved "$output"
+           set timetol 0
+           exp_continue
+       }
+       -re "^Totals" {
+           verbose "All done" 2
+       }
+       eof {
+           #       unresolved "${executable} died prematurely"
+           #       catch close
+           #       return "${executable} died prematurely"
+       }
+       timeout {
+           warning "Timed out executing test case"
+           if { $timetol <= 2 } {
+               incr timetol
+               exp_continue
+           } else {
+               -               catch close
+               return "Timed out executing test case"
+           }
+       }
+       -re "^$prefix\r\n" {
+           exp_continue
+       }
+    }
+
+    # force a close of the executable to be safe.
+    catch close
+
+    return ""
+}
+
+# (end of code from dejagnu.exp)
+
+# GCC_UNDER_TEST is needed by gcc_target_compile
+global GCC_UNDER_TEST
+if ![info exists GCC_UNDER_TEST] {
+    set GCC_UNDER_TEST "[find_gcc]"
+}
+
+# Initialize dg.
+dg-init
+
+# Gather a list of all tests.
+
+# Tests within the testsuite: gcc/testsuite/jit.dg/test-*.c
+set tests [lsort [find $srcdir/$subdir test-*.c]]
+
+# We also test the examples within the documentation, to ensure that
+# they compile:
+set tests [lsort [concat $tests [find $srcdir/../jit/docs/examples *.c]]]
+
+verbose "tests: $tests"
+
+# libgloss has found the driver (as "xgcc" or "gcc) and stored
+# its full path as GCC_UNDER_TEST.
+proc get_path_of_driver {} {
+    global GCC_UNDER_TEST
+
+    verbose "GCC_UNDER_TEST: $GCC_UNDER_TEST"
+    set binary [lindex $GCC_UNDER_TEST 0]
+    verbose "binary: $binary"
+
+    return [file dirname $binary]
+}
+
+proc jit-dg-test { prog do_what extra_tool_flags } {
+    verbose "within jit-dg-test..."
+    verbose "  prog: $prog"
+    verbose "  do_what: $do_what"
+    verbose "  extra_tool_flags: $extra_tool_flags"
+
+    # test-threads.c needs to be linked against pthreads
+    if {[string match "*test-threads.c" $prog]} {
+       append extra_tool_flags " -lpthread"
+    }
+
+    # Determine what to name the built executable.
+    set output_file "[file rootname [file tail $prog]].exe"
+    verbose "output_file: $output_file"
+
+    # Create the test executable:
+    set comp_output [gcc_target_compile $prog $output_file $do_what \
+                       "{additional_flags=$extra_tool_flags}"]
+    if ![jit_check_compile "$prog" "initial compilation" \
+           $output_file $comp_output] then {
+      return
+    }
+
+    # Run the test executable, capturing the PASS/FAIL textual output
+    # from the C API, converting it into the Tcl API.
+
+    # We need to set LD_LIBRARY_PATH so that the test files can find
+    # libgccjit.so
+    # Do this using set_ld_library_path_env_vars from target-libpath.exp
+    global ld_library_path
+    global base_dir
+    set ld_library_path "$base_dir/../../"
+    set_ld_library_path_env_vars
+
+    # libgccjit uses the driver to convert .s files to .so libraries
+    # via its *installed* name, FULL_DRIVER_NAME
+    #   ${target_noncanonical}-gcc-${gcc_BASEVER}${exeext}
+    # e.g. "x86_64-unknown-linux-gnu-gcc-5.0.0"
+    # looking for it on PATH.  Hence we need to prepend the location of
+    # that executable to PATH when running the tests
+    set dir_containing_driver [get_path_of_driver ]
+    verbose "dir_containing_driver: $dir_containing_driver"
+    global env
+    set old_path $env(PATH)
+    setenv "PATH" $dir_containing_driver:$old_path
+    verbose -log "PATH=[getenv PATH]"
+
+    # We have:
+    #   test-executables
+    #     linked to -> libgccjit.so
+    #                    -> invokes driver:
+    #                         -> invokes the assembler
+    #                         -> invokes the linker
+    # We want to be able to run this from the builddir without installing
+    # but the linker needs to be able to locate various libraries, or we
+    # get:
+    #   ld: cannot find crtbeginS.o: No such file or directory
+    #   ld: cannot find -lgcc
+    #   ld: cannot find -lgcc_s
+    # These can be found in the "gcc" subdir of the build.
+    # Hence to be able to run the testsuite without installing, we need
+    # to set or prepend the "gcc" subdir of the build to LIBRARY_PATH:
+    if { [info exists env(LIBRARY_PATH) ] } {
+       set old_library_path $env(LIBRARY_PATH)
+       setenv "LIBRARY_PATH" $dir_containing_driver:$old_library_path
+    } else {
+       setenv "LIBRARY_PATH" $dir_containing_driver
+    }
+    verbose -log "LIBRARY_PATH=[getenv LIBRARY_PATH]"
+
+    # dejagnu.exp's host_execute has code to scrape out test results
+    # from the DejaGnu C API and bring back into the tcl world, so we
+    # use that to invoke the built code.
+    # However, it appears to be buggy; see:
+    #  http://lists.gnu.org/archive/html/dejagnu/2014-10/msg00000.html
+    # We instead call a patched local copy, "fixed_host_execute", defined
+    # above.
+    set result [fixed_host_execute $output_file]
+    verbose "result: $result"
+
+    # Restore PATH
+    setenv "PATH" $old_path
+
+    # Restore LIBRARY_PATH
+    if { [info exists old_library_path] } {
+       setenv "LIBRARY_PATH" $old_library_path
+    } else {
+       unsetenv "LIBRARY_PATH"
+    }
+
+    restore_ld_library_path_env_vars
+}
+
+# We need to link with --export-dynamic for test-calling-external-function.c
+# so that the JIT-built code can call into functions from the main program.
+set DEFAULT_CFLAGS "-I$srcdir/../jit -lgccjit -g -Wall -Werror -Wl,--export-dynamic"
+
+# <dejagnu.h> assumes -fgnu89-inline
+# See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63613
+# and http://lists.gnu.org/archive/html/dejagnu/2014-10/msg00011.html
+append DEFAULT_CFLAGS " -fgnu89-inline"
+
+# Main loop.  This will invoke jig-dg-test on each test-*.c file.
+dg-runtest $tests "" $DEFAULT_CFLAGS
+
+# All done.
+dg-finish
diff --git a/gcc/testsuite/jit.dg/test-accessing-struct.c b/gcc/testsuite/jit.dg/test-accessing-struct.c
new file mode 100644 (file)
index 0000000..109a0d7
--- /dev/null
@@ -0,0 +1,112 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+struct foo
+{
+  int x;
+  int y;
+  int z;
+};
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  /* Let's try to inject the equivalent of:
+     void
+     test_access (struct foo *f)
+     {
+        f->z = f->x * f->y;
+     }
+  */
+  gcc_jit_type *void_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+  gcc_jit_type *int_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+  gcc_jit_field *x =
+    gcc_jit_context_new_field (ctxt,
+                               NULL,
+                               int_type,
+                               "x");
+  gcc_jit_field *y =
+    gcc_jit_context_new_field (ctxt,
+                               NULL,
+                               int_type,
+                               "y");
+  gcc_jit_field *z =
+    gcc_jit_context_new_field (ctxt,
+                               NULL,
+                               int_type,
+                               "z");
+  gcc_jit_field *fields[] = {x, y, z};
+  gcc_jit_struct *struct_type =
+    gcc_jit_context_new_struct_type (ctxt, NULL, "foo", 3, fields);
+  gcc_jit_type *ptr_type =
+    gcc_jit_type_get_pointer (gcc_jit_struct_as_type (struct_type));
+
+  /* Build the test function.  */
+  gcc_jit_param *param_f =
+    gcc_jit_context_new_param (ctxt, NULL, ptr_type, "f");
+  gcc_jit_function *test_fn =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                  GCC_JIT_FUNCTION_EXPORTED,
+                                  void_type,
+                                  "test_access",
+                                  1, &param_f,
+                                  0);
+
+  /* f->x * f->y */
+  gcc_jit_rvalue *sum =
+    gcc_jit_context_new_binary_op (
+      ctxt, NULL,
+      GCC_JIT_BINARY_OP_MULT,
+      int_type,
+      gcc_jit_lvalue_as_rvalue (
+       gcc_jit_rvalue_dereference_field (
+         gcc_jit_param_as_rvalue (param_f),
+         NULL,
+         x)),
+      gcc_jit_lvalue_as_rvalue (
+       gcc_jit_rvalue_dereference_field (
+       gcc_jit_param_as_rvalue (param_f),
+       NULL,
+       y)));
+
+  /* f->z = ... */
+  gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
+  gcc_jit_block_add_assignment (
+    block,
+    NULL,
+    gcc_jit_rvalue_dereference_field (
+      gcc_jit_param_as_rvalue (param_f),
+      NULL,
+      z),
+    sum);
+  gcc_jit_block_end_with_void_return (block, NULL);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  typedef void (*fn_type) (struct foo *);
+  CHECK_NON_NULL (result);
+
+  fn_type test_access =
+    (fn_type)gcc_jit_result_get_code (result, "test_access");
+  CHECK_NON_NULL (test_access);
+
+  struct foo tmp;
+  tmp.x = 5;
+  tmp.y = 7;
+  tmp.z = 0;
+
+  /* Call the JIT-generated function.  */
+  test_access (&tmp);
+
+  /* Verify that the code correctly modified the field "z".  */
+  CHECK_VALUE (tmp.z, 35);
+}
+
diff --git a/gcc/testsuite/jit.dg/test-accessing-union.c b/gcc/testsuite/jit.dg/test-accessing-union.c
new file mode 100644 (file)
index 0000000..658d1bc
--- /dev/null
@@ -0,0 +1,97 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+union int_or_float
+{
+  int as_int;
+  float as_float;
+};
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  /* Let's try to inject the equivalent of:
+     float
+     test_union (int i)
+     {
+        union int_or_float u;
+       u.as_int = i;
+       return u.as_float;
+     }
+  */
+  gcc_jit_type *int_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+  gcc_jit_type *float_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_FLOAT);
+  gcc_jit_field *as_int =
+    gcc_jit_context_new_field (ctxt,
+                               NULL,
+                               int_type,
+                               "as_int");
+  gcc_jit_field *as_float =
+    gcc_jit_context_new_field (ctxt,
+                               NULL,
+                               float_type,
+                               "as_float");
+  gcc_jit_field *fields[] = {as_int, as_float};
+  gcc_jit_type *union_type =
+    gcc_jit_context_new_union_type (ctxt, NULL,
+                                   "int_or_float", 2, fields);
+
+  /* Build the test function.  */
+  gcc_jit_param *param_i =
+    gcc_jit_context_new_param (ctxt, NULL, int_type, "i");
+  gcc_jit_function *test_fn =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                  GCC_JIT_FUNCTION_EXPORTED,
+                                  float_type,
+                                  "test_union",
+                                  1, &param_i,
+                                  0);
+
+  gcc_jit_lvalue *u =
+    gcc_jit_function_new_local (test_fn, NULL,
+                               union_type, "u");
+
+  gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
+
+  /* u.as_int = i; */
+  gcc_jit_block_add_assignment (
+    block,
+    NULL,
+    /* "u.as_int = ..." */
+    gcc_jit_lvalue_access_field (u,
+                                NULL,
+                                as_int),
+    gcc_jit_param_as_rvalue (param_i));
+
+  /* return u.as_float; */
+  gcc_jit_block_end_with_return (
+    block, NULL,
+    gcc_jit_rvalue_access_field (gcc_jit_lvalue_as_rvalue (u),
+                                NULL,
+                                as_float));
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  typedef float (*fn_type) (int i);
+  CHECK_NON_NULL (result);
+
+  fn_type test_union =
+    (fn_type)gcc_jit_result_get_code (result, "test_union");
+  CHECK_NON_NULL (test_union);
+
+  /* Call the JIT-generated function.  */
+  float f_result = test_union (42);
+
+  union int_or_float u;
+  u.as_float = f_result;
+
+  CHECK_VALUE (u.as_int, 42);
+}
diff --git a/gcc/testsuite/jit.dg/test-array-as-pointer.c b/gcc/testsuite/jit.dg/test-array-as-pointer.c
new file mode 100644 (file)
index 0000000..1a240ac
--- /dev/null
@@ -0,0 +1,101 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <stddef.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+#define BUFFER_SIZE (1024)
+
+char test_buffer[1024];
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  /* Let's try to inject the equivalent of:
+        void test_of_array_as_pointer (const char *name)
+        {
+            snprintf (test_buffer, sizeof (test_buffer),
+                     "hello %s", name);
+        }
+    */
+  gcc_jit_type *void_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+  gcc_jit_type *const_char_ptr_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_CONST_CHAR_PTR);
+  gcc_jit_type *char_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_CHAR);
+  gcc_jit_type *char_ptr_type =
+    gcc_jit_type_get_pointer (char_type);
+  gcc_jit_type *int_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+  gcc_jit_type *size_t_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_SIZE_T);
+  gcc_jit_type *buf_type =
+    gcc_jit_context_new_array_type (ctxt, NULL, char_type, BUFFER_SIZE);
+
+  /* extern int snprintf(char *str, size_t size, const char *format, ...); */
+  gcc_jit_param *param_s =
+    gcc_jit_context_new_param (ctxt, NULL, char_ptr_type, "s");
+  gcc_jit_param *param_n =
+    gcc_jit_context_new_param (ctxt, NULL, size_t_type, "n");
+  gcc_jit_param *param_format =
+    gcc_jit_context_new_param (ctxt, NULL, const_char_ptr_type, "format");
+  gcc_jit_param *snprintf_params[3] = {param_s, param_n, param_format};
+  gcc_jit_function *snprintf =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                 GCC_JIT_FUNCTION_IMPORTED,
+                                 int_type,
+                                 "snprintf",
+                                 3, snprintf_params,
+                                 1);
+
+  gcc_jit_param *param_name =
+    gcc_jit_context_new_param (ctxt, NULL, const_char_ptr_type, "name");
+  gcc_jit_function *test_fn =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                 GCC_JIT_FUNCTION_EXPORTED,
+                                 void_type,
+                                 "test_of_array_as_pointer",
+                                 1, &param_name,
+                                 0);
+
+  gcc_jit_lvalue *buffer =
+    gcc_jit_context_new_global (ctxt, NULL, buf_type, "test_buffer");
+
+  gcc_jit_block *block = gcc_jit_function_new_block(test_fn, "entry");
+
+  /* snprintf(buffer, sizeof(buffer), "hello %s", name); */
+  gcc_jit_rvalue *args[4];
+  args[0] = gcc_jit_context_new_cast (
+    ctxt, NULL,
+    /* Here's the difference with test-error-array-as-pointer.c: */
+    gcc_jit_lvalue_get_address (buffer,
+                               NULL),
+    char_ptr_type);
+  args[1] = gcc_jit_context_new_rvalue_from_int (ctxt,
+                                                size_t_type,
+                                                BUFFER_SIZE);
+  args[2] = gcc_jit_context_new_string_literal (ctxt, "hello %s");
+  args[3] = gcc_jit_param_as_rvalue (param_name);
+
+  gcc_jit_block_add_eval (
+    block, NULL,
+    gcc_jit_context_new_call (ctxt, NULL, snprintf, 4, args));
+  gcc_jit_block_end_with_void_return (block, NULL);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  CHECK_NON_NULL (result);
+
+  typedef void (*fn_type) (const char *);
+  fn_type test_of_array_as_pointer =
+    (fn_type)gcc_jit_result_get_code (result, "test_of_array_as_pointer");
+  CHECK_NON_NULL (test_of_array_as_pointer);
+
+  test_of_array_as_pointer ("world");
+  CHECK_STRING_VALUE (test_buffer, "hello world");
+}
diff --git a/gcc/testsuite/jit.dg/test-arrays.c b/gcc/testsuite/jit.dg/test-arrays.c
new file mode 100644 (file)
index 0000000..378a2a3
--- /dev/null
@@ -0,0 +1,165 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <stddef.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+#define ARRAY_SIZE (4)
+
+/* Verify that struct layout works properly when adding an array field.  */
+struct array_holder
+{
+  float m_before;
+  int m_ints[ARRAY_SIZE];
+  float m_after;
+};
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  /* Let's try to inject the equivalent of:
+
+     void
+     test_array (struct array_holder *ah)
+     {
+       ah->m_before = 4.0f;
+       for i in 0 to (ARRAY_SIZE - 1):
+         ah->m_ints[i] = (i * i);
+       ah->m_after = 2.0f;
+     }
+  */
+  gcc_jit_type *void_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+  gcc_jit_type *float_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_FLOAT);
+  gcc_jit_type *int_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+  gcc_jit_field *field_m_before =
+    gcc_jit_context_new_field (ctxt, NULL, float_type, "m_before");
+  gcc_jit_field *field_m_ints =
+    gcc_jit_context_new_field (
+    ctxt, NULL,
+    gcc_jit_context_new_array_type (ctxt, NULL, int_type, ARRAY_SIZE),
+    "m_ints");
+  gcc_jit_field *field_m_after =
+    gcc_jit_context_new_field (ctxt, NULL, float_type, "m_after");
+
+  gcc_jit_field *fields[] = {
+    field_m_before,
+    field_m_ints,
+    field_m_after,
+  };
+
+  gcc_jit_struct *struct_type =
+    gcc_jit_context_new_struct_type (
+      ctxt,
+      NULL,
+      "array_holder",
+      3, fields);
+
+  gcc_jit_type *struct_ptr_type =
+    gcc_jit_type_get_pointer (gcc_jit_struct_as_type (struct_type));
+
+  /* Build the test_fn.  */
+  gcc_jit_param *param_ah =
+    gcc_jit_context_new_param (ctxt, NULL, struct_ptr_type, "ah");
+  gcc_jit_function *func =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                 GCC_JIT_FUNCTION_EXPORTED,
+                                 void_type,
+                                 "test_array",
+                                 1, &param_ah,
+                                 0);
+
+  gcc_jit_block *initial = gcc_jit_function_new_block (func, "initial");
+  gcc_jit_block *loop_test = gcc_jit_function_new_block (func, "loop_test");
+  gcc_jit_block *loop_body = gcc_jit_function_new_block (func, "loop_body");
+  gcc_jit_block *final = gcc_jit_function_new_block (func, "final");
+
+  /* "ah->m_before = 4.0f;" */
+  gcc_jit_block_add_assignment (
+    initial, NULL,
+    gcc_jit_rvalue_dereference_field (
+      gcc_jit_param_as_rvalue (param_ah), NULL, field_m_before),
+    gcc_jit_context_new_rvalue_from_int (ctxt, float_type, 4));
+
+  gcc_jit_block_add_comment (initial, NULL,
+                            "for i in 0 to (ARRAY_SIZE - 1):");
+  gcc_jit_lvalue *i =
+    gcc_jit_function_new_local (func, NULL, int_type, "i");
+  gcc_jit_block_add_assignment (initial, NULL,
+      i,
+      gcc_jit_context_zero (ctxt, int_type));
+
+  gcc_jit_block_end_with_jump (initial, NULL, loop_test);
+
+  gcc_jit_block_end_with_conditional (loop_test, NULL,
+    gcc_jit_context_new_comparison (
+      ctxt, NULL,
+      GCC_JIT_COMPARISON_LT,
+      gcc_jit_lvalue_as_rvalue (i),
+      gcc_jit_context_new_rvalue_from_int (ctxt, int_type, ARRAY_SIZE)),
+    loop_body,
+    final);
+
+  gcc_jit_block_add_comment (loop_body, NULL, "ah->m_ints[i] = (i * i);");
+  gcc_jit_block_add_assignment (
+    loop_body, NULL,
+    gcc_jit_context_new_array_access (
+      ctxt, NULL,
+      gcc_jit_lvalue_as_rvalue (gcc_jit_rvalue_dereference_field (
+       gcc_jit_param_as_rvalue (param_ah),
+       NULL,
+       field_m_ints)),
+      gcc_jit_lvalue_as_rvalue (i)),
+    gcc_jit_context_new_binary_op (
+      ctxt, NULL,
+      GCC_JIT_BINARY_OP_MULT,
+      int_type,
+      gcc_jit_lvalue_as_rvalue (i),
+      gcc_jit_lvalue_as_rvalue (i)));
+
+  /* "i++" */
+  gcc_jit_block_add_assignment_op (
+    loop_body, NULL,
+    i,
+    GCC_JIT_BINARY_OP_PLUS,
+    gcc_jit_context_one (ctxt, int_type));
+
+  gcc_jit_block_end_with_jump (loop_body, NULL, loop_test);
+
+ /* ah->m_after = 2.0f; */
+  gcc_jit_block_add_assignment (
+    final, NULL,
+    gcc_jit_rvalue_dereference_field (
+      gcc_jit_param_as_rvalue (param_ah), NULL, field_m_after),
+    gcc_jit_context_new_rvalue_from_int (ctxt, float_type, 2));
+  gcc_jit_block_end_with_void_return (final, NULL);
+
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  typedef void (*fn_type) (struct array_holder *ah);
+
+  CHECK_NON_NULL (result);
+  fn_type test_array =
+    (fn_type)gcc_jit_result_get_code (result, "test_array");
+  CHECK_NON_NULL (test_array);
+
+  struct array_holder ah;
+  memset (&ah, 0xf0, sizeof (ah));
+
+  test_array (&ah);
+  CHECK_VALUE (ah.m_before, 4.0f);
+  CHECK_VALUE (ah.m_ints[0], 0);
+  CHECK_VALUE (ah.m_ints[1], 1);
+  CHECK_VALUE (ah.m_ints[2], 4);
+  CHECK_VALUE (ah.m_ints[3], 9);
+  CHECK_VALUE (ah.m_after, 2.0f);
+
+}
diff --git a/gcc/testsuite/jit.dg/test-calling-external-function.c b/gcc/testsuite/jit.dg/test-calling-external-function.c
new file mode 100644 (file)
index 0000000..177f329
--- /dev/null
@@ -0,0 +1,118 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+  extern void
+  called_function (int i, int j, int k);
+
+#ifdef __cplusplus
+}
+#endif
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  /* Let's try to inject the equivalent of:
+     extern void called_function (int i, int j, int k);
+
+     void
+     test_caller (int a)
+     {
+        called_function (a * 3, a * 4, a * 5);
+     }
+  */
+  int i;
+  gcc_jit_type *void_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+  gcc_jit_type *int_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+  /* Declare the imported function.  */
+  gcc_jit_param *params[3];
+  params[0] =
+    gcc_jit_context_new_param (ctxt, NULL, int_type, "i");
+  params[1] =
+    gcc_jit_context_new_param (ctxt, NULL, int_type, "j");
+  params[2] =
+    gcc_jit_context_new_param (ctxt, NULL, int_type, "k");
+  gcc_jit_function *called_fn =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                  GCC_JIT_FUNCTION_IMPORTED,
+                                  void_type,
+                                  "called_function",
+                                  3, params,
+                                  0);
+
+  /* Build the test_fn.  */
+  gcc_jit_param *param_a =
+    gcc_jit_context_new_param (ctxt, NULL, int_type, "a");
+  gcc_jit_function *test_fn =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                  GCC_JIT_FUNCTION_EXPORTED,
+                                  void_type,
+                                  "test_caller",
+                                  1, &param_a,
+                                  0);
+  /* "a * 3, a * 4, a * 5"  */
+  gcc_jit_rvalue *args[3];
+  for (i = 0; i < 3; i++)
+    args[i] =
+      gcc_jit_context_new_binary_op (
+        ctxt, NULL,
+        GCC_JIT_BINARY_OP_MULT,
+        int_type,
+        gcc_jit_param_as_rvalue (param_a),
+        gcc_jit_context_new_rvalue_from_int (
+          ctxt,
+          int_type,
+          (i + 3) ));
+  gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
+  gcc_jit_block_add_eval (
+    block, NULL,
+    gcc_jit_context_new_call (ctxt,
+                              NULL,
+                              called_fn,
+                              3, args));
+  gcc_jit_block_end_with_void_return (block, NULL);
+}
+
+static int called_with[3];
+
+extern void
+called_function (int i, int j, int k)
+{
+  called_with[0] = i;
+  called_with[1] = j;
+  called_with[2] = k;
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  typedef void (*fn_type) (int);
+  CHECK_NON_NULL (result);
+
+  fn_type test_caller =
+    (fn_type)gcc_jit_result_get_code (result, "test_caller");
+  CHECK_NON_NULL (test_caller);
+
+  called_with[0] = 0;
+  called_with[1] = 0;
+  called_with[2] = 0;
+
+  /* Call the JIT-generated function.  */
+  test_caller (5);
+
+  /* Verify that it correctly called "called_function".  */
+  CHECK_VALUE (called_with[0], 15);
+  CHECK_VALUE (called_with[1], 20);
+  CHECK_VALUE (called_with[2], 25);
+}
+
diff --git a/gcc/testsuite/jit.dg/test-calling-function-ptr.c b/gcc/testsuite/jit.dg/test-calling-function-ptr.c
new file mode 100644 (file)
index 0000000..e21bd15
--- /dev/null
@@ -0,0 +1,118 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  /* Let's try to inject the equivalent of:
+
+     void
+     test_calling_function_ptr (void (*fn_ptr) (int, int, int) fn_ptr,
+                                int a)
+     {
+        fn_ptr (a * 3, a * 4, a * 5);
+     }
+  */
+
+  int i;
+  gcc_jit_type *void_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+  gcc_jit_type *int_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+  /* Build the function ptr type.  */
+  gcc_jit_type *param_types[3];
+  param_types[0] = int_type;
+  param_types[1] = int_type;
+  param_types[2] = int_type;
+
+  gcc_jit_type *fn_ptr_type =
+    gcc_jit_context_new_function_ptr_type (ctxt, NULL,
+                                          void_type,
+                                          3, param_types, 0);
+
+  /* Ensure that function ptr types have sane debug strings.  */
+
+  CHECK_STRING_VALUE (
+    gcc_jit_object_get_debug_string (gcc_jit_type_as_object (fn_ptr_type)),
+    "void (*) (int, int, int)");
+
+  /* Build the test_fn.  */
+  gcc_jit_param *param_fn_ptr =
+    gcc_jit_context_new_param (ctxt, NULL, fn_ptr_type, "fn_ptr");
+  gcc_jit_param *param_a =
+    gcc_jit_context_new_param (ctxt, NULL, int_type, "a");
+
+  gcc_jit_param *params[2];
+  params[0] = param_fn_ptr;
+  params[1] = param_a;
+
+  gcc_jit_function *test_fn =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                  GCC_JIT_FUNCTION_EXPORTED,
+                                  void_type,
+                                  "test_calling_function_ptr",
+                                  2, params,
+                                  0);
+  /* "a * 3, a * 4, a * 5"  */
+  gcc_jit_rvalue *args[3];
+  for (i = 0; i < 3; i++)
+    args[i] =
+      gcc_jit_context_new_binary_op (
+        ctxt, NULL,
+        GCC_JIT_BINARY_OP_MULT,
+        int_type,
+        gcc_jit_param_as_rvalue (param_a),
+        gcc_jit_context_new_rvalue_from_int (
+          ctxt,
+          int_type,
+          (i + 3) ));
+  gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
+  gcc_jit_block_add_eval (
+    block, NULL,
+    gcc_jit_context_new_call_through_ptr (
+      ctxt,
+      NULL,
+      gcc_jit_param_as_rvalue (param_fn_ptr),
+      3, args));
+  gcc_jit_block_end_with_void_return (block, NULL);
+}
+
+static int called_through_ptr_with[3];
+
+static void
+function_called_through_fn_ptr (int i, int j, int k)
+{
+  called_through_ptr_with[0] = i;
+  called_through_ptr_with[1] = j;
+  called_through_ptr_with[2] = k;
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  typedef void (*fn_type) (void (*fn_ptr) (int, int, int),
+                          int);
+  CHECK_NON_NULL (result);
+
+  fn_type test_caller =
+    (fn_type)gcc_jit_result_get_code (result, "test_calling_function_ptr");
+  CHECK_NON_NULL (test_caller);
+
+  called_through_ptr_with[0] = 0;
+  called_through_ptr_with[1] = 0;
+  called_through_ptr_with[2] = 0;
+
+  /* Call the JIT-generated function.  */
+  test_caller (function_called_through_fn_ptr, 5);
+
+  /* Verify that it correctly called "function_called_through_fn_ptr".  */
+  CHECK_VALUE (called_through_ptr_with[0], 15);
+  CHECK_VALUE (called_through_ptr_with[1], 20);
+  CHECK_VALUE (called_through_ptr_with[2], 25);
+}
+
diff --git a/gcc/testsuite/jit.dg/test-combination.c b/gcc/testsuite/jit.dg/test-combination.c
new file mode 100644 (file)
index 0000000..06ba902
--- /dev/null
@@ -0,0 +1,67 @@
+/* Construct a test case by combining other test cases, to try to shake
+   out state issues: all of the test cases are run in one process, inside
+   one gcc_jit_context (per iteration).  */
+
+#include "all-non-failing-tests.h"
+
+/* Now construct a test case from all the other test cases.
+
+   We undefine COMBINED_TEST so that we can now include harness.h
+   "for real".  */
+#undef COMBINED_TEST
+#include "harness.h"
+
+/* Our testing hooks are the combination of the other test cases.  */
+void
+create_code (gcc_jit_context *ctxt, void * user_data)
+{
+  create_code_accessing_struct (ctxt, user_data);
+  create_code_accessing_union (ctxt, user_data);
+  create_code_array_as_pointer (ctxt, user_data);
+  create_code_arrays (ctxt, user_data);
+  create_code_calling_external_function (ctxt, user_data);
+  create_code_calling_function_ptr (ctxt, user_data);
+  create_code_dot_product (ctxt, user_data);
+  create_code_expressions (ctxt, user_data);
+  create_code_factorial (ctxt, user_data);
+  create_code_fibonacci (ctxt, user_data);
+  create_code_functions (ctxt, user_data);
+  create_code_hello_world (ctxt, user_data);
+  create_code_linked_list (ctxt, user_data);
+  create_code_long_names (ctxt, user_data);
+  create_code_quadratic (ctxt, user_data);
+  create_code_nested_loop (ctxt, user_data);
+  create_code_reading_struct  (ctxt, user_data);
+  create_code_string_literal (ctxt, user_data);
+  create_code_sum_of_squares (ctxt, user_data);
+  create_code_types (ctxt, user_data);
+  create_code_using_global (ctxt, user_data);
+  create_code_volatile (ctxt, user_data);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  verify_code_accessing_struct (ctxt, result);
+  verify_code_accessing_union (ctxt, result);
+  verify_code_array_as_pointer (ctxt, result);
+  verify_code_arrays (ctxt, result);
+  verify_code_calling_external_function (ctxt, result);
+  verify_code_calling_function_ptr (ctxt, result);
+  verify_code_dot_product (ctxt, result);
+  verify_code_expressions (ctxt, result);
+  verify_code_factorial (ctxt, result);
+  verify_code_fibonacci (ctxt, result);
+  verify_code_functions (ctxt, result);
+  verify_code_hello_world (ctxt, result);
+  verify_code_linked_list (ctxt, result);
+  verify_code_long_names (ctxt, result);
+  verify_code_quadratic (ctxt, result);
+  verify_code_nested_loop (ctxt, result);
+  verify_code_reading_struct (ctxt, result);
+  verify_code_string_literal (ctxt, result);
+  verify_code_sum_of_squares (ctxt, result);
+  verify_code_types (ctxt, result);
+  verify_code_using_global (ctxt, result);
+  verify_code_volatile (ctxt, result);
+}
diff --git a/gcc/testsuite/jit.dg/test-dot-product.c b/gcc/testsuite/jit.dg/test-dot-product.c
new file mode 100644 (file)
index 0000000..a41109a
--- /dev/null
@@ -0,0 +1,129 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  /* Let's try to inject the equivalent of:
+
+       double
+       my_dot_product (int n, double *a, double *b)
+       {
+         double result = 0.;
+         for (int i = 0; i < n; i++)
+           result += a[i] * b[i];
+         return result
+       }
+
+     and see what the optimizer can do.  */
+  gcc_jit_type *val_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_DOUBLE);
+  gcc_jit_type *ptr_type = gcc_jit_type_get_pointer (val_type);
+  gcc_jit_type *int_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+  gcc_jit_type *return_type = val_type;
+  gcc_jit_param *param_n =
+    gcc_jit_context_new_param (ctxt, NULL, int_type, "n");
+  gcc_jit_param *param_a =
+    gcc_jit_context_new_param (ctxt, NULL, ptr_type, "a");
+  gcc_jit_param *param_b =
+    gcc_jit_context_new_param (ctxt, NULL, ptr_type, "b");
+  gcc_jit_param *params[3] = {param_n, param_a, param_b};
+  gcc_jit_function *func =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                 GCC_JIT_FUNCTION_EXPORTED,
+                                 return_type,
+                                 "my_dot_product",
+                                 3, params, 0);
+
+  gcc_jit_block *initial = gcc_jit_function_new_block (func, "initial");
+  gcc_jit_block *loop_test = gcc_jit_function_new_block (func, "loop_test");
+  gcc_jit_block *loop_body = gcc_jit_function_new_block (func, "loop_body");
+  gcc_jit_block *final = gcc_jit_function_new_block (func, "final");
+
+  /* Build: "double result = 0.;" */
+  gcc_jit_lvalue *result =
+    gcc_jit_function_new_local (func, NULL, val_type, "result");
+
+  gcc_jit_block_add_assignment (initial, NULL,
+    result, gcc_jit_context_zero (ctxt, val_type));
+
+  /* Build: "for (int i = 0; i < n; i++)" */
+  gcc_jit_lvalue *i =
+    gcc_jit_function_new_local (func, NULL, int_type, "i");
+  gcc_jit_block_add_assignment (initial, NULL,
+    i, gcc_jit_context_zero (ctxt, int_type));
+
+  gcc_jit_block_end_with_jump (initial, NULL, loop_test);
+
+  gcc_jit_block_end_with_conditional (
+    loop_test, NULL,
+
+    /* (i < n) */
+    gcc_jit_context_new_comparison (
+      ctxt, NULL,
+      GCC_JIT_COMPARISON_LT,
+      gcc_jit_lvalue_as_rvalue (i),
+      gcc_jit_param_as_rvalue (param_n)),
+
+    loop_body,
+    final);
+
+  /* Build: "result += a[i] * b[i];" */
+  gcc_jit_block_add_assignment_op (
+    loop_body, NULL,
+    result,
+    GCC_JIT_BINARY_OP_PLUS,
+    gcc_jit_context_new_binary_op (
+      ctxt, NULL,
+      GCC_JIT_BINARY_OP_MULT,
+      val_type,
+      gcc_jit_lvalue_as_rvalue (
+       gcc_jit_context_new_array_access (
+          ctxt, NULL,
+         gcc_jit_param_as_rvalue (param_a),
+         gcc_jit_lvalue_as_rvalue (i))),
+      gcc_jit_lvalue_as_rvalue (
+       gcc_jit_context_new_array_access (
+          ctxt, NULL,
+         gcc_jit_param_as_rvalue (param_b),
+         gcc_jit_lvalue_as_rvalue (i)))));
+
+  /* Build: "i++" */
+  gcc_jit_block_add_assignment_op (
+    loop_body, NULL,
+    i,
+    GCC_JIT_BINARY_OP_PLUS,
+    gcc_jit_context_one (ctxt, int_type));
+
+  gcc_jit_block_end_with_jump (loop_body, NULL, loop_test);
+
+  /* Build: "return result;" */
+  gcc_jit_block_end_with_return (
+    final,
+    NULL,
+    gcc_jit_lvalue_as_rvalue (result));
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  typedef double (*my_dot_product_fn_type) (int n, double *a, double *b);
+  CHECK_NON_NULL (result);
+
+  my_dot_product_fn_type my_dot_product =
+    (my_dot_product_fn_type)gcc_jit_result_get_code (result,
+                                                    "my_dot_product");
+  CHECK_NON_NULL (my_dot_product);
+  double test_array[] = {1., 2., 3., 4., 5., 6., 7., 8., 9., 10.};
+  double val = my_dot_product (10, test_array, test_array);
+  note ("my_dot_product returned: %f", val);
+  CHECK_VALUE (val, 385.0);
+}
+
diff --git a/gcc/testsuite/jit.dg/test-empty.c b/gcc/testsuite/jit.dg/test-empty.c
new file mode 100644 (file)
index 0000000..820f232
--- /dev/null
@@ -0,0 +1,20 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  /* Do nothing.  */
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  /* We should have a non-NULL result, albeit one with nothing in it.  */
+  CHECK_NON_NULL (result);
+}
+
diff --git a/gcc/testsuite/jit.dg/test-error-accessing-field-in-other-struct.c b/gcc/testsuite/jit.dg/test-error-accessing-field-in-other-struct.c
new file mode 100644 (file)
index 0000000..f10954b
--- /dev/null
@@ -0,0 +1,114 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+struct foo
+{
+  int x;
+  int y;
+};
+
+struct bar
+{
+  int p;
+  int q;
+};
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  /* Let's try to inject the equivalent of:
+     void
+     test_bogus_access (struct foo *f)
+     {
+        f->p = f->q;
+     }
+     i.e. using the wrong struct.
+  */
+  gcc_jit_type *void_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+  gcc_jit_type *int_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+  /* Map "struct foo".  */
+  gcc_jit_field *x =
+    gcc_jit_context_new_field (ctxt,
+                               NULL,
+                               int_type,
+                               "x");
+  gcc_jit_field *y =
+    gcc_jit_context_new_field (ctxt,
+                               NULL,
+                               int_type,
+                               "y");
+  gcc_jit_field *foo_fields[] = {x, y};
+  gcc_jit_struct *struct_foo =
+    gcc_jit_context_new_struct_type (ctxt, NULL, "foo", 2, foo_fields);
+
+  /* Map "struct bar".  */
+  gcc_jit_field *p =
+    gcc_jit_context_new_field (ctxt,
+                               NULL,
+                               int_type,
+                               "p");
+  gcc_jit_field *q =
+    gcc_jit_context_new_field (ctxt,
+                               NULL,
+                               int_type,
+                               "q");
+  /* We don't actually need a gcc_jit_type for "struct bar" for the test.  */
+  gcc_jit_field *bar_fields[] = {p, q};
+  (void)gcc_jit_context_new_struct_type (ctxt, NULL, "foo", 2, bar_fields);
+
+  gcc_jit_type *foo_ptr =
+    gcc_jit_type_get_pointer (gcc_jit_struct_as_type (struct_foo));
+
+  /* Build the test function.  */
+  gcc_jit_param *param_f =
+    gcc_jit_context_new_param (ctxt, NULL, foo_ptr, "f");
+  gcc_jit_function *test_fn =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                  GCC_JIT_FUNCTION_EXPORTED,
+                                  void_type,
+                                  "test_bogus_access",
+                                  1, &param_f,
+                                  0);
+
+  /* Erroneous: f->p = ... */
+  gcc_jit_lvalue *lvalue =
+    gcc_jit_rvalue_dereference_field (
+      gcc_jit_param_as_rvalue (param_f),
+      NULL,
+      p);
+
+  /* Erroneous: ... = f->q; */
+  gcc_jit_rvalue *rvalue =
+    gcc_jit_lvalue_as_rvalue (
+      gcc_jit_rvalue_dereference_field (
+       gcc_jit_param_as_rvalue (param_f),
+       NULL,
+       q));
+
+  gcc_jit_block *block =
+    gcc_jit_function_new_block (test_fn, NULL);
+  gcc_jit_block_add_assignment (
+    block,
+    NULL,
+    lvalue, rvalue);
+  gcc_jit_block_end_with_void_return (block, NULL);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  CHECK_VALUE (result, NULL);
+
+  /* Verify that the correct error message was emitted.  */
+  CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+                     "gcc_jit_rvalue_dereference_field:"
+                     " p is not a field of struct foo");
+}
+
diff --git a/gcc/testsuite/jit.dg/test-error-adding-to-terminated-block.c b/gcc/testsuite/jit.dg/test-error-adding-to-terminated-block.c
new file mode 100644 (file)
index 0000000..9c39dd6
--- /dev/null
@@ -0,0 +1,48 @@
+#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  /* Let's try to inject the equivalent of:
+       void
+       test_fn ()
+       {
+        return;
+        return;
+       }
+  */
+  gcc_jit_type *void_t =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+
+  /* Build the test_fn.  */
+  gcc_jit_function *test_fn =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                  GCC_JIT_FUNCTION_EXPORTED,
+                                  void_t,
+                                  "test_fn",
+                                  0, NULL,
+                                  0);
+  gcc_jit_block *initial =
+    gcc_jit_function_new_block (test_fn, "initial");
+
+  gcc_jit_block_end_with_void_return (initial, NULL);
+  /* Error: "initial" has already been terminated.  */
+  gcc_jit_block_end_with_void_return (initial, NULL);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  CHECK_VALUE (result, NULL);
+
+  CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+                     "gcc_jit_block_end_with_void_return:"
+                     " adding to terminated block:"
+                     " initial (already terminated by: return;)");
+}
diff --git a/gcc/testsuite/jit.dg/test-error-array-as-pointer.c b/gcc/testsuite/jit.dg/test-error-array-as-pointer.c
new file mode 100644 (file)
index 0000000..cd2b7f8
--- /dev/null
@@ -0,0 +1,99 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <stddef.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+#define BUFFER_SIZE (1024)
+
+char test_buffer[1024];
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  /* Let's try to inject the equivalent of:
+        void test_of_array_as_pointer (const char *name)
+        {
+            snprintf (test_buffer, sizeof (test_buffer),
+                     "hello %s", name);
+        }
+    */
+  gcc_jit_type *void_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+  gcc_jit_type *const_char_ptr_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_CONST_CHAR_PTR);
+  gcc_jit_type *char_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_CHAR);
+  gcc_jit_type *char_ptr_type =
+    gcc_jit_type_get_pointer (char_type);
+  gcc_jit_type *int_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+  gcc_jit_type *size_t_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_SIZE_T);
+  gcc_jit_type *buf_type =
+    gcc_jit_context_new_array_type (ctxt, NULL, char_type, BUFFER_SIZE);
+
+  /* extern int snprintf(char *str, size_t size, const char *format, ...); */
+  gcc_jit_param *param_s =
+    gcc_jit_context_new_param (ctxt, NULL, char_ptr_type, "s");
+  gcc_jit_param *param_n =
+    gcc_jit_context_new_param (ctxt, NULL, size_t_type, "n");
+  gcc_jit_param *param_format =
+    gcc_jit_context_new_param (ctxt, NULL, const_char_ptr_type, "format");
+  gcc_jit_param *snprintf_params[3] = {param_s, param_n, param_format};
+  gcc_jit_function *snprintf =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                 GCC_JIT_FUNCTION_IMPORTED,
+                                 int_type,
+                                 "snprintf",
+                                 3, snprintf_params,
+                                 1);
+
+  gcc_jit_param *param_name =
+    gcc_jit_context_new_param (ctxt, NULL, const_char_ptr_type, "name");
+  gcc_jit_function *test_fn =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                 GCC_JIT_FUNCTION_EXPORTED,
+                                 void_type,
+                                 "test_of_array_as_pointer",
+                                 1, &param_name,
+                                 0);
+
+  gcc_jit_lvalue *buffer =
+    gcc_jit_context_new_global (ctxt, NULL, buf_type, "test_buffer");
+
+  gcc_jit_block *block = gcc_jit_function_new_block(test_fn, "entry");
+
+  /* snprintf(buffer, sizeof(buffer), "hello %s", name); */
+  gcc_jit_rvalue *args[4];
+  args[0] = gcc_jit_context_new_cast (
+    ctxt, NULL,
+    /* Here's the difference with test-array-as-pointer.c: */
+    gcc_jit_lvalue_as_rvalue (buffer),
+    char_ptr_type);
+  args[1] = gcc_jit_context_new_rvalue_from_int (ctxt,
+                                                size_t_type,
+                                                BUFFER_SIZE);
+  args[2] = gcc_jit_context_new_string_literal (ctxt, "hello %s");
+  args[3] = gcc_jit_param_as_rvalue (param_name);
+
+  gcc_jit_block_add_eval (
+    block, NULL,
+    gcc_jit_context_new_call (ctxt, NULL, snprintf, 4, args));
+  gcc_jit_block_end_with_void_return (block, NULL);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  CHECK_VALUE (result, NULL);
+
+  /* Verify that the correct error message was emitted.  */
+  CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+                     "gcc_jit_context_new_cast:"
+                     " cannot cast test_buffer"
+                     " from type: char[1024]"
+                     " to type: char *");
+}
diff --git a/gcc/testsuite/jit.dg/test-error-bad-cast.c b/gcc/testsuite/jit.dg/test-error-bad-cast.c
new file mode 100644 (file)
index 0000000..a0ab413
--- /dev/null
@@ -0,0 +1,63 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  /* Let's try to inject the equivalent of:
+
+     int
+     test_fn ()
+     {
+       struct foo f;
+       return (int)f;
+     }
+
+     and verify that the API complains about the bad cast.
+  */
+  gcc_jit_type *int_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+
+  gcc_jit_struct *struct_foo =
+    gcc_jit_context_new_struct_type (ctxt, NULL, "foo",
+                                    0, NULL);
+
+  gcc_jit_function *test_fn =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                  GCC_JIT_FUNCTION_EXPORTED,
+                                  int_type,
+                                  "test_fn",
+                                  0, NULL,
+                                  0);
+  gcc_jit_lvalue *f =
+    gcc_jit_function_new_local (
+      test_fn,
+      NULL,
+      gcc_jit_struct_as_type (struct_foo), "f");
+
+  gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
+
+  gcc_jit_block_end_with_return (
+    block, NULL,
+    gcc_jit_context_new_cast (ctxt, NULL,
+                             gcc_jit_lvalue_as_rvalue (f),
+                             int_type));
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  CHECK_VALUE (result, NULL);
+
+  /* Verify that the correct error message was emitted.  */
+  CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+                     "gcc_jit_context_new_cast:"
+                     " cannot cast f from type: struct foo"
+                     " to type: int");
+}
+
diff --git a/gcc/testsuite/jit.dg/test-error-block-in-wrong-function.c b/gcc/testsuite/jit.dg/test-error-block-in-wrong-function.c
new file mode 100644 (file)
index 0000000..b7342a3
--- /dev/null
@@ -0,0 +1,65 @@
+#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  /* Let's try to inject the equivalent of:
+       void
+       test_fn ()
+       {
+        goto label;
+       }
+
+       void
+       other_fn ()
+       {
+         label:
+       };
+     where the destination block is in another function.
+  */
+  gcc_jit_type *void_t =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+
+  /* Build the test_fn.  */
+  gcc_jit_function *test_fn =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                  GCC_JIT_FUNCTION_EXPORTED,
+                                  void_t,
+                                  "test_fn",
+                                  0, NULL,
+                                  0);
+  /* Build the other_fn.  */
+  gcc_jit_function *other_fn =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                  GCC_JIT_FUNCTION_EXPORTED,
+                                  void_t,
+                                  "other_fn",
+                                  0, NULL,
+                                  0);
+
+  gcc_jit_block *initial =
+    gcc_jit_function_new_block (test_fn, "initial");
+  gcc_jit_block *block_within_other_fn =
+    gcc_jit_function_new_block (other_fn, "block_within_other_fn");
+
+  gcc_jit_block_end_with_jump (initial, NULL, block_within_other_fn);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  CHECK_VALUE (result, NULL);
+
+  CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+                     "gcc_jit_block_end_with_jump:"
+                     " target block is not in same function:"
+                     " source block initial is in function test_fn"
+                     " whereas target block block_within_other_fn"
+                     " is in function other_fn");
+}
diff --git a/gcc/testsuite/jit.dg/test-error-call-through-ptr-with-mismatching-args.c b/gcc/testsuite/jit.dg/test-error-call-through-ptr-with-mismatching-args.c
new file mode 100644 (file)
index 0000000..afe5a7c
--- /dev/null
@@ -0,0 +1,74 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  /* Let's try to inject the equivalent of:
+
+     void
+     test_fn (void (*some_fn_ptr) (void *))
+     {
+        some_fn_ptr (42);
+     }
+
+     and verify that the API complains about the mismatching argument
+     type ("int" vs "void *").  */
+  gcc_jit_type *void_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+  gcc_jit_type *void_ptr_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID_PTR);
+  gcc_jit_type *int_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+  /* Build the function ptr type.  */
+  gcc_jit_type *fn_ptr_type =
+    gcc_jit_context_new_function_ptr_type (ctxt, NULL,
+                                          void_type,
+                                          1, &void_ptr_type, 0);
+
+  /* Build the test_fn.  */
+  gcc_jit_param *param_fn_ptr =
+    gcc_jit_context_new_param (ctxt, NULL, fn_ptr_type, "some_fn_ptr");
+
+  gcc_jit_function *test_fn =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                  GCC_JIT_FUNCTION_EXPORTED,
+                                  void_type,
+                                  "test_fn",
+                                  1, &param_fn_ptr,
+                                  0);
+  /* some_fn_ptr (42); */
+  gcc_jit_rvalue *arg =
+    gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 42);
+
+  gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
+  gcc_jit_block_add_eval (
+    block, NULL,
+    gcc_jit_context_new_call_through_ptr (
+      ctxt,
+      NULL,
+      gcc_jit_param_as_rvalue (param_fn_ptr),
+      1, &arg));
+  /* the above has the wrong type for argument 1.  */
+  gcc_jit_block_end_with_void_return (block, NULL);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  CHECK_VALUE (result, NULL);
+
+  /* Verify that the correct error message was emitted.  */
+  CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+                     ("gcc_jit_context_new_call_through_ptr:"
+                      " mismatching types for argument 1 of fn_ptr:"
+                      " some_fn_ptr:"
+                      " assignment to param 1 (type: void *)"
+                      " from (int)42 (type: int)"));
+}
+
diff --git a/gcc/testsuite/jit.dg/test-error-call-through-ptr-with-non-function.c b/gcc/testsuite/jit.dg/test-error-call-through-ptr-with-non-function.c
new file mode 100644 (file)
index 0000000..513e3d3
--- /dev/null
@@ -0,0 +1,65 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  /* Let's try to inject the equivalent of:
+
+     void
+     test_fn (void *some_ptr)
+     {
+        ((some_unspecified_fn_ptr_type)some_ptr) (42);
+     }
+
+     and verify that the API complains about the 42 not being a
+     function pointer.  */
+  gcc_jit_type *void_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+  gcc_jit_type *void_ptr_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID_PTR);
+  gcc_jit_type *int_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+  /* Build the test_fn.  */
+  gcc_jit_param *some_ptr =
+    gcc_jit_context_new_param (ctxt, NULL, void_ptr_type, "some_ptr");
+
+  gcc_jit_function *test_fn =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                  GCC_JIT_FUNCTION_EXPORTED,
+                                  void_type,
+                                  "test_fn",
+                                  1, &some_ptr,
+                                  0);
+  gcc_jit_rvalue *arg =
+    gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 42);
+
+  /* ((some_unspecified_fn_ptr_type)some_ptr) (42); */
+  gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
+  gcc_jit_block_add_eval (
+    block, NULL,
+    gcc_jit_context_new_call_through_ptr (
+      ctxt,
+      NULL,
+      /* This is not a function pointer.  */
+      gcc_jit_param_as_rvalue (some_ptr),
+      1, &arg));
+  gcc_jit_block_end_with_void_return (block, NULL);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  CHECK_VALUE (result, NULL);
+
+  /* Verify that the correct error message was emitted.  */
+  CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+                     ("gcc_jit_context_new_call_through_ptr:"
+                      " fn_ptr is not a function ptr: some_ptr type: void *"));
+}
+
diff --git a/gcc/testsuite/jit.dg/test-error-call-through-ptr-with-non-pointer.c b/gcc/testsuite/jit.dg/test-error-call-through-ptr-with-non-pointer.c
new file mode 100644 (file)
index 0000000..8bb50d9
--- /dev/null
@@ -0,0 +1,62 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  /* Let's try to inject the equivalent of:
+
+     void
+     test_fn ()
+     {
+        ((some_unspecified_fn_ptr_type)42) (43);
+     }
+
+     and verify that the API complains about the 42 not being a
+     function pointer.  */
+  gcc_jit_type *void_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+  gcc_jit_type *int_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+  /* Build the test_fn.  */
+  gcc_jit_function *test_fn =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                  GCC_JIT_FUNCTION_EXPORTED,
+                                  void_type,
+                                  "test_fn",
+                                  0, NULL,
+                                  0);
+  gcc_jit_rvalue *not_a_function =
+    gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 42);
+  gcc_jit_rvalue *arg =
+    gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 43);
+
+  /* ((some_unspecified_fn_ptr_type)42) (43); */
+  gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
+  gcc_jit_block_add_eval (
+    block, NULL,
+    gcc_jit_context_new_call_through_ptr (
+      ctxt,
+      NULL,
+      /* This is not even a pointer, let alone a function pointer.  */
+      not_a_function,
+      1, &arg));
+  gcc_jit_block_end_with_void_return (block, NULL);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  CHECK_VALUE (result, NULL);
+
+  /* Verify that the correct error message was emitted.  */
+  CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+                     ("gcc_jit_context_new_call_through_ptr:"
+                      " fn_ptr is not a ptr: (int)42 type: int"));
+}
+
diff --git a/gcc/testsuite/jit.dg/test-error-call-through-ptr-with-not-enough-args.c b/gcc/testsuite/jit.dg/test-error-call-through-ptr-with-not-enough-args.c
new file mode 100644 (file)
index 0000000..3e160f4
--- /dev/null
@@ -0,0 +1,70 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  /* Let's try to inject the equivalent of:
+
+     void
+     test_caller (void (*some_fn_ptr) (int p))
+     {
+        called_function (); // missing arg
+     }
+
+     and verify that the API complains about the missing argument.
+  */
+  gcc_jit_type *void_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+  gcc_jit_type *int_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+  /* Build the function ptr type.  */
+  gcc_jit_type *fn_ptr_type =
+    gcc_jit_context_new_function_ptr_type (ctxt, NULL,
+                                          void_type,
+                                          1, &int_type, 0);
+
+  /* Build the test_fn.  */
+  gcc_jit_param *param_fn_ptr =
+    gcc_jit_context_new_param (ctxt, NULL, fn_ptr_type, "some_fn_ptr");
+
+  gcc_jit_function *test_fn =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                  GCC_JIT_FUNCTION_EXPORTED,
+                                  void_type,
+                                  "test_caller",
+                                  1, &param_fn_ptr,
+                                  0);
+
+  gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
+  /* called_function ();  */
+  gcc_jit_block_add_eval (
+    block, NULL,
+    gcc_jit_context_new_call_through_ptr (
+      ctxt,
+      NULL,
+      gcc_jit_param_as_rvalue (param_fn_ptr),
+      0, NULL));
+  /* the above has not enough args.  */
+  gcc_jit_block_end_with_void_return (block, NULL);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  /* Ensure that mismatching arg count leads to the API giving a NULL
+     result back.  */
+  CHECK_VALUE (result, NULL);
+
+  /* Verify that the correct error message was emitted.  */
+  CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+                     ("gcc_jit_context_new_call_through_ptr:"
+                      " not enough arguments to fn_ptr: some_fn_ptr"
+                      " (got 0 args, expected 1)"));
+}
+
diff --git a/gcc/testsuite/jit.dg/test-error-call-through-ptr-with-too-many-args.c b/gcc/testsuite/jit.dg/test-error-call-through-ptr-with-too-many-args.c
new file mode 100644 (file)
index 0000000..b8cb2f4
--- /dev/null
@@ -0,0 +1,87 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+  extern void
+  called_function (void);
+
+#ifdef __cplusplus
+}
+#endif
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  /* Let's try to inject the equivalent of:
+     void
+     test_caller (void (*some_fn_ptr) (void), int a)
+     {
+        some_fn_ptr (a);
+     }
+
+     and verify that the API complains about the mismatching arg
+     counts.
+  */
+  gcc_jit_type *void_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+  gcc_jit_type *int_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+  /* Build the function ptr type.  */
+  gcc_jit_type *fn_ptr_type =
+    gcc_jit_context_new_function_ptr_type (ctxt, NULL,
+                                          void_type,
+                                          0, NULL, 0);
+
+  /* Build the test_fn.  */
+  gcc_jit_param *param_fn_ptr =
+    gcc_jit_context_new_param (ctxt, NULL, fn_ptr_type, "some_fn_ptr");
+  gcc_jit_param *param_a =
+    gcc_jit_context_new_param (ctxt, NULL, int_type, "a");
+  gcc_jit_param *params[2];
+  params[0] = param_fn_ptr;
+  params[1] = param_a;
+
+  gcc_jit_function *test_fn =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                  GCC_JIT_FUNCTION_EXPORTED,
+                                  void_type,
+                                  "test_caller",
+                                  2, params,
+                                  0);
+  gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
+
+  /* some_fn_ptr (a); */
+  gcc_jit_rvalue *arg = gcc_jit_param_as_rvalue (param_a);
+  gcc_jit_block_add_eval (
+    block, NULL,
+    gcc_jit_context_new_call_through_ptr (
+      ctxt,
+      NULL,
+      gcc_jit_param_as_rvalue (param_fn_ptr),
+      1, &arg));
+  /* the above has too many args.  */
+  gcc_jit_block_end_with_void_return (block, NULL);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  /* Ensure that mismatching arg count leads to the API giving a NULL
+     result back.  */
+  CHECK_VALUE (result, NULL);
+
+  /* Verify that the correct error message was emitted.  */
+  CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+                     "gcc_jit_context_new_call_through_ptr:"
+                     " too many arguments to fn_ptr:"
+                     " some_fn_ptr (got 1 args, expected 0)");
+}
+
diff --git a/gcc/testsuite/jit.dg/test-error-call-with-mismatching-args.c b/gcc/testsuite/jit.dg/test-error-call-with-mismatching-args.c
new file mode 100644 (file)
index 0000000..7306ffd
--- /dev/null
@@ -0,0 +1,87 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+  extern void
+  called_function (void *ptr);
+
+#ifdef __cplusplus
+}
+#endif
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  /* Let's try to inject the equivalent of:
+     extern void called_function (void *ptr);
+
+     void
+     test_fn ()
+     {
+        called_function (42);
+     }
+
+     and verify that the API complains about the mismatching argument
+     type ("int" vs "void *").  */
+  gcc_jit_type *void_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+  gcc_jit_type *void_ptr_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID_PTR);
+  gcc_jit_type *int_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+  /* Declare the imported function.  */
+  gcc_jit_param *param =
+    gcc_jit_context_new_param (ctxt, NULL, void_ptr_type, "ptr");
+  gcc_jit_function *called_fn =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                  GCC_JIT_FUNCTION_IMPORTED,
+                                  void_type,
+                                  "called_function",
+                                  1, &param,
+                                  0);
+
+  /* Build the test_fn.  */
+  gcc_jit_function *test_fn =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                  GCC_JIT_FUNCTION_EXPORTED,
+                                  void_type,
+                                  "test_fn",
+                                  0, NULL,
+                                  0);
+  /* called_function (42);  */
+  gcc_jit_rvalue *arg =
+    gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 42);
+
+  gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
+  gcc_jit_block_add_eval (
+    block, NULL,
+    gcc_jit_context_new_call (ctxt,
+                              NULL,
+                              called_fn,
+                              1, &arg));
+  /* the above has the wrong type for argument 1.  */
+  gcc_jit_block_end_with_void_return (block, NULL);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  CHECK_VALUE (result, NULL);
+
+  /* Verify that the correct error message was emitted.  */
+  CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+                     ("gcc_jit_context_new_call:"
+                      " mismatching types for argument 1"
+                      " of function \"called_function\":"
+                      " assignment to param ptr (type: void *)"
+                      " from (int)42 (type: int)"));
+}
+
diff --git a/gcc/testsuite/jit.dg/test-error-call-with-not-enough-args.c b/gcc/testsuite/jit.dg/test-error-call-with-not-enough-args.c
new file mode 100644 (file)
index 0000000..1e8dbbc
--- /dev/null
@@ -0,0 +1,87 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+  extern void
+  called_function (void);
+
+#ifdef __cplusplus
+}
+#endif
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  /* Let's try to inject the equivalent of:
+     extern void called_function (int p);
+
+     void
+     test_caller ()
+     {
+        called_function (); // missing arg
+     }
+
+     and verify that the API complains about the missing argument.
+  */
+  gcc_jit_type *void_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+  gcc_jit_type *int_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+  /* Declare the imported function.  */
+  gcc_jit_param *param_p =
+    gcc_jit_context_new_param (ctxt, NULL, int_type, "p");
+  gcc_jit_function *called_fn =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                  GCC_JIT_FUNCTION_IMPORTED,
+                                  void_type,
+                                  "called_function",
+                                  1, &param_p,
+                                  0);
+
+  /* Build the test_fn.  */
+  gcc_jit_function *test_fn =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                  GCC_JIT_FUNCTION_EXPORTED,
+                                  void_type,
+                                  "test_caller",
+                                  0, NULL,
+                                  0);
+  gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
+  /* called_function ();  */
+  gcc_jit_block_add_eval (
+    block, NULL,
+    gcc_jit_context_new_call (ctxt,
+                              NULL,
+                              called_fn,
+                              0, NULL));
+  /* the above has the wrong arg count.  */
+  gcc_jit_block_end_with_void_return (block, NULL);
+}
+
+extern void
+called_function (void)
+{
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  /* Ensure that mismatching arg count leads to the API giving a NULL
+     result back.  */
+  CHECK_VALUE (result, NULL);
+
+  /* Verify that the correct error message was emitted.  */
+  CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+                     ("gcc_jit_context_new_call:"
+                      " not enough arguments to function \"called_function\""
+                      " (got 0 args, expected 1)"));
+}
+
diff --git a/gcc/testsuite/jit.dg/test-error-call-with-too-many-args.c b/gcc/testsuite/jit.dg/test-error-call-with-too-many-args.c
new file mode 100644 (file)
index 0000000..a50fc97
--- /dev/null
@@ -0,0 +1,89 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+  extern void
+  called_function (void);
+
+#ifdef __cplusplus
+}
+#endif
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  /* Let's try to inject the equivalent of:
+     extern void called_function ();
+
+     void
+     test_caller (int a)
+     {
+        called_function (a);
+     }
+
+     and verify that the API complains about the mismatching arg
+     counts.
+  */
+  gcc_jit_type *void_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+  gcc_jit_type *int_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+  /* Declare the imported function.  */
+  gcc_jit_function *called_fn =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                  GCC_JIT_FUNCTION_IMPORTED,
+                                  void_type,
+                                  "called_function",
+                                  0, NULL,
+                                  0);
+
+  /* Build the test_fn.  */
+  gcc_jit_param *param_a =
+    gcc_jit_context_new_param (ctxt, NULL, int_type, "a");
+  gcc_jit_function *test_fn =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                  GCC_JIT_FUNCTION_EXPORTED,
+                                  void_type,
+                                  "test_caller",
+                                  1, &param_a,
+                                  0);
+  gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
+  /* called_function (a);  */
+  gcc_jit_rvalue *arg = gcc_jit_param_as_rvalue (param_a);
+  gcc_jit_block_add_eval (
+    block, NULL,
+    gcc_jit_context_new_call (ctxt,
+                              NULL,
+                              called_fn,
+                              1, &arg));
+  /* the above has the wrong arg count.  */
+  gcc_jit_block_end_with_void_return (block, NULL);
+}
+
+extern void
+called_function (void)
+{
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  /* Ensure that mismatching arg count leads to the API giving a NULL
+     result back.  */
+  CHECK_VALUE (result, NULL);
+
+  /* Verify that the correct error message was emitted.  */
+  CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+                     ("gcc_jit_context_new_call:"
+                      " too many arguments to function \"called_function\""
+                      " (got 1 args, expected 0)"));
+}
+
diff --git a/gcc/testsuite/jit.dg/test-error-dereference-field-of-non-pointer.c b/gcc/testsuite/jit.dg/test-error-dereference-field-of-non-pointer.c
new file mode 100644 (file)
index 0000000..75171d7
--- /dev/null
@@ -0,0 +1,95 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+struct foo
+{
+  int x;
+  int y;
+};
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  /* Let's try to inject the equivalent of:
+     void
+     test_bogus_dereference ()
+     {
+        struct foo tmp;
+        tmp->x = tmp->y;
+     }
+     i.e. where tmp is *not* a pointer.
+  */
+  gcc_jit_type *void_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+  gcc_jit_type *int_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+  /* Map "struct foo".  */
+  gcc_jit_field *x =
+    gcc_jit_context_new_field (ctxt,
+                               NULL,
+                               int_type,
+                               "x");
+  gcc_jit_field *y =
+    gcc_jit_context_new_field (ctxt,
+                               NULL,
+                               int_type,
+                               "y");
+  gcc_jit_field *foo_fields[] = {x, y};
+  gcc_jit_struct *struct_foo =
+    gcc_jit_context_new_struct_type (ctxt, NULL, "foo", 2, foo_fields);
+
+  /* Build the test function.  */
+  gcc_jit_function *test_fn =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                  GCC_JIT_FUNCTION_EXPORTED,
+                                  void_type,
+                                  "test_bogus_dereference",
+                                  0, NULL,
+                                  0);
+  gcc_jit_lvalue *tmp =
+    gcc_jit_function_new_local (test_fn, NULL,
+                               gcc_jit_struct_as_type (struct_foo),
+                               "tmp");
+
+  gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
+
+  /* Erroneous: tmp->x = ... */
+  gcc_jit_lvalue *lvalue =
+    gcc_jit_rvalue_dereference_field (
+      gcc_jit_lvalue_as_rvalue (tmp),
+      NULL,
+      x);
+
+  /* Erroneous: ... = tmp->y; */
+  gcc_jit_rvalue *rvalue =
+    gcc_jit_lvalue_as_rvalue (
+      gcc_jit_rvalue_dereference_field (
+       gcc_jit_lvalue_as_rvalue (tmp),
+       NULL,
+       y));
+
+  gcc_jit_block_add_assignment (
+    block,
+    NULL,
+    lvalue, rvalue);
+
+  gcc_jit_block_end_with_void_return (block, NULL);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  CHECK_VALUE (result, NULL);
+
+  /* Verify that the correct error message was emitted.  */
+  CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+                     ("gcc_jit_rvalue_dereference_field:"
+                      " dereference of non-pointer tmp (type: struct foo)"
+                      " when accessing ->x"));
+}
+
diff --git a/gcc/testsuite/jit.dg/test-error-dereference-read-of-non-pointer.c b/gcc/testsuite/jit.dg/test-error-dereference-read-of-non-pointer.c
new file mode 100644 (file)
index 0000000..7b97ab1
--- /dev/null
@@ -0,0 +1,55 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  /* Let's try to inject the equivalent of:
+       void
+       int test_bogus_dereference_read (int i)
+       {
+        return *i;
+       }
+     i.e. where i is *not* a pointer.
+  */
+  gcc_jit_type *void_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+  gcc_jit_type *int_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+  /* Build the test function.  */
+  gcc_jit_param *param_i =
+      gcc_jit_context_new_param (ctxt, NULL, int_type, "i");
+  gcc_jit_function *test_fn =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                  GCC_JIT_FUNCTION_EXPORTED,
+                                  void_type,
+                                  "test_bogus_dereference_read",
+                                  1, &param_i,
+                                  0);
+  gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
+  /* Erroneous: "return *i;" */
+  gcc_jit_block_end_with_return (
+    block,
+    NULL,
+    gcc_jit_lvalue_as_rvalue (
+      gcc_jit_rvalue_dereference (
+        gcc_jit_param_as_rvalue (param_i),
+       NULL)));
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  CHECK_VALUE (result, NULL);
+
+  /* Verify that the correct error message was emitted.  */
+  CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+                     ("gcc_jit_rvalue_dereference:"
+                      " dereference of non-pointer i (type: int)"));
+}
+
diff --git a/gcc/testsuite/jit.dg/test-error-get-type-bad-enum.c b/gcc/testsuite/jit.dg/test-error-get-type-bad-enum.c
new file mode 100644 (file)
index 0000000..67b712e
--- /dev/null
@@ -0,0 +1,27 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  /* Trigger an API error by passing bad data.  */
+  gcc_jit_context_get_type (ctxt, 42);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  /* Ensure that the bad API usage prevents the API giving a bogus
+     result back.  */
+  CHECK_VALUE (result, NULL);
+
+  /* Verify that the correct error message was emitted.  */
+  CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+                     ("gcc_jit_context_get_type:"
+                      " unrecognized value for enum gcc_jit_types: 42"));
+}
+
diff --git a/gcc/testsuite/jit.dg/test-error-index-not-a-numeric-type.c b/gcc/testsuite/jit.dg/test-error-index-not-a-numeric-type.c
new file mode 100644 (file)
index 0000000..a3540b2
--- /dev/null
@@ -0,0 +1,34 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  /* Let's try to access an array at an index that isn't of a numeric
+     type and verify that the API complains about the bad type.
+  */
+  gcc_jit_rvalue *string =
+    gcc_jit_context_new_string_literal (ctxt,
+                                       "hello world");
+
+  (void)gcc_jit_context_new_array_access (
+    ctxt, NULL,
+    string, /* ptr */
+    string /* index, not of numeric type */);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  CHECK_VALUE (result, NULL);
+
+  /* Verify that the correct error message was emitted.  */
+  CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+                     "gcc_jit_context_new_array_access:"
+                     " index: \"hello world\" (type: const char *)"
+                     " is not of numeric type");
+}
diff --git a/gcc/testsuite/jit.dg/test-error-mismatching-types-in-assignment.c b/gcc/testsuite/jit.dg/test-error-mismatching-types-in-assignment.c
new file mode 100644 (file)
index 0000000..83d212d
--- /dev/null
@@ -0,0 +1,61 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  /* Let's try to inject the equivalent of:
+
+     void
+     test_fn ()
+     {
+        int i;
+        i = "this is not an int";
+     }
+
+     and verify that the API complains about the mismatching types
+     in the assignment.
+  */
+  gcc_jit_type *void_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+  gcc_jit_type *int_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+  gcc_jit_function *test_fn =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                  GCC_JIT_FUNCTION_EXPORTED,
+                                  void_type,
+                                  "test_fn",
+                                  0, NULL,
+                                  0);
+  gcc_jit_lvalue *i =
+    gcc_jit_function_new_local (
+      test_fn, NULL, int_type, "i");
+
+  gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
+
+  gcc_jit_block_add_assignment (
+    block, NULL,
+    i, /* of type int */
+    gcc_jit_context_new_string_literal (
+      ctxt, "this is not an int"));
+  gcc_jit_block_end_with_void_return (block, NULL);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  CHECK_VALUE (result, NULL);
+
+  /* Verify that the correct error message was emitted.  */
+  CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+                     "gcc_jit_block_add_assignment:"
+                     " mismatching types:"
+                     " assignment to i (type: int)"
+                     " from \"this is not an int\" (type: const char *)");
+}
+
diff --git a/gcc/testsuite/jit.dg/test-error-mismatching-types-in-call.c b/gcc/testsuite/jit.dg/test-error-mismatching-types-in-call.c
new file mode 100644 (file)
index 0000000..203c4ca
--- /dev/null
@@ -0,0 +1,80 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  /* Let's try to inject the equivalent of:
+
+       struct foo;
+
+       extern void called_function (struct foo *ptr);
+
+       void
+       test_fn ()
+       {
+         struct foo f;
+        called_function (f);
+     }
+
+     and verify that we get a type error (foo * vs foo).
+  */
+  gcc_jit_type *void_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+  gcc_jit_struct *struct_foo =
+    gcc_jit_context_new_opaque_struct (ctxt, NULL, "foo");
+  gcc_jit_type *foo_ptr =
+    gcc_jit_type_get_pointer (gcc_jit_struct_as_type (struct_foo));
+  gcc_jit_param *param =
+    gcc_jit_context_new_param (ctxt, NULL, foo_ptr, "ptr");
+
+  gcc_jit_function *called_function =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                  GCC_JIT_FUNCTION_IMPORTED,
+                                  void_type,
+                                  "called_function",
+                                  1, &param,
+                                  0);
+
+  gcc_jit_function *test_fn =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                  GCC_JIT_FUNCTION_EXPORTED,
+                                  void_type,
+                                  "test_fn",
+                                  0, NULL,
+                                  0);
+  gcc_jit_lvalue *f =
+    gcc_jit_function_new_local (
+      test_fn, NULL, gcc_jit_struct_as_type (struct_foo), "f");
+
+  gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
+
+  gcc_jit_rvalue *arg = gcc_jit_lvalue_as_rvalue (f);
+
+  gcc_jit_block_add_eval (
+    block, NULL,
+    gcc_jit_context_new_call (
+      ctxt, NULL,
+      called_function,
+      1, &arg));
+  gcc_jit_block_end_with_void_return (block, NULL);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  CHECK_VALUE (result, NULL);
+
+  /* Verify that the correct error message was emitted.  */
+  CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+                     "gcc_jit_context_new_call:"
+                     " mismatching types for argument 1"
+                     " of function \"called_function\":"
+                     " assignment to param ptr (type: struct foo *)"
+                     " from f (type: struct foo)");
+}
+
diff --git a/gcc/testsuite/jit.dg/test-error-missing-return.c b/gcc/testsuite/jit.dg/test-error-missing-return.c
new file mode 100644 (file)
index 0000000..5e24346
--- /dev/null
@@ -0,0 +1,40 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  /* Let's try to inject the equivalent of:
+       int
+       test_fn ()
+       {
+       }
+     and verify that the API complains about the lack of
+     a returned value.
+  */
+  gcc_jit_type *int_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+  (void)gcc_jit_context_new_function (ctxt, NULL,
+                                     GCC_JIT_FUNCTION_EXPORTED,
+                                     int_type,
+                                     "test_fn",
+                                     0, NULL,
+                                     0);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  CHECK_VALUE (result, NULL);
+
+  /* Verify that the correct error message was emitted.  */
+  CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+                     "function test_fn returns non-void (type: int)"
+                     " but has no blocks");
+}
+
diff --git a/gcc/testsuite/jit.dg/test-error-new-binary-op-bad-op.c b/gcc/testsuite/jit.dg/test-error-new-binary-op-bad-op.c
new file mode 100644 (file)
index 0000000..0592f55
--- /dev/null
@@ -0,0 +1,37 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  /* Trigger an API error by passing bad data.  */
+  (void)gcc_jit_context_new_binary_op (
+         ctxt,
+         NULL,
+
+         /* Non-valid enum value: */
+         (enum gcc_jit_binary_op) 42,
+
+         /* These aren't valid either: */
+         NULL, /* gcc_jit_type *result_type, */
+         NULL, NULL); /* gcc_jit_rvalue *a, gcc_jit_rvalue *b */
+
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  /* Ensure that the bad API usage prevents the API giving a bogus
+     result back.  */
+  CHECK_VALUE (result, NULL);
+
+  /* Verify that the correct error message was emitted.  */
+  CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+                     ("gcc_jit_context_new_binary_op:"
+                      " unrecognized value for enum gcc_jit_binary_op: 42"));
+}
+
diff --git a/gcc/testsuite/jit.dg/test-error-new-function-bad-kind.c b/gcc/testsuite/jit.dg/test-error-new-function-bad-kind.c
new file mode 100644 (file)
index 0000000..f9772de
--- /dev/null
@@ -0,0 +1,41 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  gcc_jit_type *int_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+  /* Trigger an API error by passing bad data.  */
+  (void)gcc_jit_context_new_function (
+         ctxt,
+         NULL,
+
+         /* Non-valid enum value: */
+         (enum gcc_jit_function_kind)42,
+
+         int_type, /* gcc_jit_type *return_type, */
+         "foo", /* const char *name, */
+         0, /* int num_params, */
+         NULL, /* gcc_jit_param **params, */
+         0); /* int is_variadic */
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  /* Ensure that the bad API usage prevents the API giving a bogus
+     result back.  */
+  CHECK_VALUE (result, NULL);
+
+  /* Verify that the correct error message was emitted.  */
+  CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+                     ("gcc_jit_context_new_function:"
+                      " unrecognized value for enum gcc_jit_function_kind: 42"));
+}
+
diff --git a/gcc/testsuite/jit.dg/test-error-new-unary-op-bad-op.c b/gcc/testsuite/jit.dg/test-error-new-unary-op-bad-op.c
new file mode 100644 (file)
index 0000000..faab139
--- /dev/null
@@ -0,0 +1,36 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  /* Trigger an API error by passing bad data.  */
+  (void)gcc_jit_context_new_unary_op (
+         ctxt,
+         NULL,
+
+         /* Non-valid enum value: */
+         (enum gcc_jit_unary_op) 42,
+
+         /* These aren't valid either: */
+         NULL, /* gcc_jit_type *result_type, */
+         NULL); /* gcc_jit_rvalue *rvalue */
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  /* Ensure that the bad API usage prevents the API giving a bogus
+     result back.  */
+  CHECK_VALUE (result, NULL);
+
+  /* Verify that the correct error message was emitted.  */
+  CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+                     ("gcc_jit_context_new_unary_op:"
+                      " unrecognized value for enum gcc_jit_unary_op: 42"));
+}
+
diff --git a/gcc/testsuite/jit.dg/test-error-null-passed-to-api.c b/gcc/testsuite/jit.dg/test-error-null-passed-to-api.c
new file mode 100644 (file)
index 0000000..ea4390b
--- /dev/null
@@ -0,0 +1,31 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  /* Trigger an API error by passing bad data.  */
+  gcc_jit_context_new_function (ctxt, NULL,
+                                GCC_JIT_FUNCTION_EXPORTED,
+                                NULL, /* error: this must be non-NULL */
+                                "hello_world",
+                                0, NULL,
+                                0);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  /* Ensure that the bad API usage prevents the API giving a bogus
+     result back.  */
+  CHECK_VALUE (result, NULL);
+
+  /* Verify that the correct error message was emitted.  */
+  CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+                     "gcc_jit_context_new_function: NULL return_type");
+}
+
diff --git a/gcc/testsuite/jit.dg/test-error-return-within-void-function.c b/gcc/testsuite/jit.dg/test-error-return-within-void-function.c
new file mode 100644 (file)
index 0000000..1b0e9c8
--- /dev/null
@@ -0,0 +1,54 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  /* Let's try to inject the equivalent of:
+     void
+     test_fn ()
+     {
+        return 42;
+     }
+
+     and verify that the API complains about the return
+     of a value within a function with "void" return.
+  */
+  gcc_jit_type *void_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+  gcc_jit_type *int_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+  gcc_jit_function *test_fn =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                  GCC_JIT_FUNCTION_EXPORTED,
+                                  void_type, /* "void" return */
+                                  "test_fn",
+                                  0, NULL,
+                                  0);
+  gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
+
+  /* "return 42;"  (i.e. non-void) */
+  gcc_jit_block_end_with_return (
+    block, NULL,
+    gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 42));
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  /* Ensure that the "return 42" leads to the API giving a NULL
+     result back.  */
+  CHECK_VALUE (result, NULL);
+
+  /* Verify that the correct error message was emitted.  */
+  CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+                     "gcc_jit_block_end_with_return:"
+                     " mismatching types: return of (int)42 (type: int)"
+                     " in function test_fn (return type: void)");
+}
+
diff --git a/gcc/testsuite/jit.dg/test-error-unreachable-block.c b/gcc/testsuite/jit.dg/test-error-unreachable-block.c
new file mode 100644 (file)
index 0000000..10806bd
--- /dev/null
@@ -0,0 +1,50 @@
+#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  /* Let's try to inject the equivalent of:
+       void
+       test_fn ()
+       {
+        return;
+
+        return;
+       }
+     where the second block is unreachable.
+  */
+  gcc_jit_type *void_t =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+
+  /* Build the test_fn.  */
+  gcc_jit_function *test_fn =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                  GCC_JIT_FUNCTION_EXPORTED,
+                                  void_t,
+                                  "test_fn",
+                                  0, NULL,
+                                  0);
+  gcc_jit_block *initial =
+    gcc_jit_function_new_block (test_fn, "a");
+  gcc_jit_block *unreachable =
+    gcc_jit_function_new_block (test_fn, "b");
+
+  gcc_jit_block_end_with_void_return (initial, NULL);
+
+  gcc_jit_block_end_with_void_return (unreachable, NULL);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  CHECK_VALUE (result, NULL);
+
+  CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+                     "unreachable block: b");
+}
diff --git a/gcc/testsuite/jit.dg/test-error-unterminated-block.c b/gcc/testsuite/jit.dg/test-error-unterminated-block.c
new file mode 100644 (file)
index 0000000..491f09f
--- /dev/null
@@ -0,0 +1,42 @@
+#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  /* Let's try to inject the equivalent of:
+       void
+       test_fn ()
+       {
+         initial:
+       }
+     with an unterminated block.
+  */
+  gcc_jit_type *void_t =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+
+  /* Build the test_fn.  */
+  gcc_jit_function *test_fn =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                  GCC_JIT_FUNCTION_EXPORTED,
+                                  void_t,
+                                  "test_fn",
+                                  0, NULL,
+                                  0);
+  (void)gcc_jit_function_new_block (test_fn, "initial");
+  /* Error: the above block isn't terminated.  */
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  CHECK_VALUE (result, NULL);
+
+  CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+                     "unterminated block in test_fn: initial");
+}
diff --git a/gcc/testsuite/jit.dg/test-error-value-not-a-numeric-type.c b/gcc/testsuite/jit.dg/test-error-value-not-a-numeric-type.c
new file mode 100644 (file)
index 0000000..46f4f48
--- /dev/null
@@ -0,0 +1,29 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  /* Let's try to build an rvalue from a double with a non-numeric type
+     and verify that the API complains about the bad type.
+  */
+  gcc_jit_type *void_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+
+  (void)gcc_jit_context_new_rvalue_from_double (ctxt, void_type, 42.0);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  CHECK_VALUE (result, NULL);
+
+  /* Verify that the correct error message was emitted.  */
+  CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+                     "gcc_jit_context_new_rvalue_from_double:"
+                     " not a numeric type: void");
+}
diff --git a/gcc/testsuite/jit.dg/test-expressions.c b/gcc/testsuite/jit.dg/test-expressions.c
new file mode 100644 (file)
index 0000000..eb986f3
--- /dev/null
@@ -0,0 +1,896 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <stdbool.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+/**********************************************************************
+ Unary ops
+ **********************************************************************/
+
+static const char *
+make_test_of_unary_op (gcc_jit_context *ctxt,
+                      gcc_jit_type *type,
+                      enum gcc_jit_unary_op op,
+                      const char *funcname)
+{
+  /* Make a test function of the form:
+       T test_unary_op (T a)
+       {
+         return OP a;
+       }
+     and return a debug dump of the OP so that
+     the caller can sanity-check the debug dump implementation.
+  */
+  gcc_jit_param *param_a =
+    gcc_jit_context_new_param (ctxt, NULL, type, "a");
+  gcc_jit_function *test_fn =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                 GCC_JIT_FUNCTION_EXPORTED,
+                                 type,
+                                 funcname,
+                                 1, &param_a,
+                                 0);
+  gcc_jit_rvalue *unary_op = gcc_jit_context_new_unary_op (
+    ctxt,
+    NULL,
+    op,
+    type,
+    gcc_jit_param_as_rvalue (param_a));
+
+  gcc_jit_block *initial = gcc_jit_function_new_block (test_fn, "initial");
+  gcc_jit_block_end_with_return (initial, NULL, unary_op);
+
+  return gcc_jit_object_get_debug_string (
+    gcc_jit_rvalue_as_object (unary_op));
+}
+
+
+static void
+make_tests_of_unary_ops (gcc_jit_context *ctxt)
+{
+  gcc_jit_type *int_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+  CHECK_STRING_VALUE (
+    make_test_of_unary_op (ctxt,
+                          int_type,
+                          GCC_JIT_UNARY_OP_MINUS,
+                          "test_UNARY_OP_MINUS_on_int"),
+    "-(a)");
+  CHECK_STRING_VALUE (
+    make_test_of_unary_op (ctxt,
+                          int_type,
+                          GCC_JIT_UNARY_OP_BITWISE_NEGATE,
+                          "test_UNARY_OP_BITWISE_NEGATE_on_int"),
+    "~(a)");
+  CHECK_STRING_VALUE (
+    make_test_of_unary_op (ctxt,
+                          int_type,
+                          GCC_JIT_UNARY_OP_LOGICAL_NEGATE,
+                          "test_UNARY_OP_LOGICAL_NEGATE_on_int"),
+    "!(a)");
+}
+
+static void
+verify_unary_ops (gcc_jit_result *result)
+{
+  typedef int (*test_fn) (int);
+
+  test_fn test_UNARY_OP_MINUS_on_int =
+    (test_fn)gcc_jit_result_get_code (result,
+                                     "test_UNARY_OP_MINUS_on_int");
+  CHECK_NON_NULL (test_UNARY_OP_MINUS_on_int);
+  CHECK_VALUE (test_UNARY_OP_MINUS_on_int (0), 0);
+  CHECK_VALUE (test_UNARY_OP_MINUS_on_int (42), -42);
+  CHECK_VALUE (test_UNARY_OP_MINUS_on_int (-5), 5);
+
+  test_fn test_UNARY_OP_BITWISE_NEGATE_on_int =
+    (test_fn)gcc_jit_result_get_code (result,
+                                     "test_UNARY_OP_BITWISE_NEGATE_on_int");
+  CHECK_NON_NULL (test_UNARY_OP_BITWISE_NEGATE_on_int);
+  CHECK_VALUE (test_UNARY_OP_BITWISE_NEGATE_on_int (0), ~0);
+  CHECK_VALUE (test_UNARY_OP_BITWISE_NEGATE_on_int (42), ~42);
+  CHECK_VALUE (test_UNARY_OP_BITWISE_NEGATE_on_int (-5), ~-5);
+
+  test_fn test_UNARY_OP_LOGICAL_NEGATE_on_int =
+    (test_fn)gcc_jit_result_get_code (result,
+                                     "test_UNARY_OP_LOGICAL_NEGATE_on_int");
+  CHECK_NON_NULL (test_UNARY_OP_LOGICAL_NEGATE_on_int);
+  CHECK_VALUE (test_UNARY_OP_LOGICAL_NEGATE_on_int (0), 1);
+  CHECK_VALUE (test_UNARY_OP_LOGICAL_NEGATE_on_int (42), 0);
+  CHECK_VALUE (test_UNARY_OP_LOGICAL_NEGATE_on_int (-5), 0);
+
+}
+
+/**********************************************************************
+ Binary ops
+ **********************************************************************/
+
+static const char *
+make_test_of_binary_op (gcc_jit_context *ctxt,
+                       gcc_jit_type *type,
+                       enum gcc_jit_binary_op op,
+                       const char *funcname)
+{
+  /* Make a test function of the form:
+       T test_binary_op (T a, T b)
+       {
+         return a OP b;
+       }
+  */
+  gcc_jit_param *param_a =
+    gcc_jit_context_new_param (ctxt, NULL, type, "a");
+  gcc_jit_param *param_b =
+    gcc_jit_context_new_param (ctxt, NULL, type, "b");
+  gcc_jit_param *params[] = {param_a, param_b};
+  gcc_jit_function *test_fn =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                 GCC_JIT_FUNCTION_EXPORTED,
+                                 type,
+                                 funcname,
+                                 2, params,
+                                 0);
+  gcc_jit_rvalue *binary_op =
+    gcc_jit_context_new_binary_op (
+      ctxt,
+      NULL,
+      op,
+      type,
+      gcc_jit_param_as_rvalue (param_a),
+      gcc_jit_param_as_rvalue (param_b));
+
+  gcc_jit_block *initial = gcc_jit_function_new_block (test_fn, "initial");
+  gcc_jit_block_end_with_return (initial, NULL, binary_op);
+
+  return gcc_jit_object_get_debug_string (
+    gcc_jit_rvalue_as_object (binary_op));
+}
+
+
+static void
+make_tests_of_binary_ops (gcc_jit_context *ctxt)
+{
+  gcc_jit_type *int_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+  /* Test binary ops.  */
+  CHECK_STRING_VALUE (
+    make_test_of_binary_op (ctxt,
+                           int_type,
+                           GCC_JIT_BINARY_OP_PLUS,
+                           "test_BINARY_OP_PLUS_on_int"),
+    "a + b");
+  CHECK_STRING_VALUE (
+    make_test_of_binary_op (ctxt,
+                           int_type,
+                           GCC_JIT_BINARY_OP_MINUS,
+                           "test_BINARY_OP_MINUS_on_int"),
+    "a - b");
+  CHECK_STRING_VALUE (
+    make_test_of_binary_op (ctxt,
+                           int_type,
+                           GCC_JIT_BINARY_OP_MULT,
+                           "test_BINARY_OP_MULT_on_int"),
+    "a * b");
+  CHECK_STRING_VALUE (
+    make_test_of_binary_op (ctxt,
+                           int_type,
+                           GCC_JIT_BINARY_OP_DIVIDE,
+                           "test_BINARY_OP_DIVIDE_on_int"),
+    "a / b");
+  /* TODO: test for DIVIDE on float or double */
+  CHECK_STRING_VALUE (
+    make_test_of_binary_op (ctxt,
+                           int_type,
+                           GCC_JIT_BINARY_OP_MODULO,
+                           "test_BINARY_OP_MODULO_on_int"),
+    "a % b");
+  CHECK_STRING_VALUE (
+    make_test_of_binary_op (ctxt,
+                           int_type,
+                           GCC_JIT_BINARY_OP_BITWISE_AND,
+                           "test_BINARY_OP_BITWISE_AND_on_int"),
+    "a & b");
+  CHECK_STRING_VALUE (
+    make_test_of_binary_op (ctxt,
+                           int_type,
+                           GCC_JIT_BINARY_OP_BITWISE_XOR,
+                           "test_BINARY_OP_BITWISE_XOR_on_int"),
+    "a ^ b");
+  CHECK_STRING_VALUE (
+    make_test_of_binary_op (ctxt,
+                           int_type,
+                           GCC_JIT_BINARY_OP_BITWISE_OR,
+                           "test_BINARY_OP_BITWISE_OR_on_int"),
+    "a | b");
+  CHECK_STRING_VALUE (
+    make_test_of_binary_op (ctxt,
+                           int_type,
+                           GCC_JIT_BINARY_OP_LOGICAL_AND,
+                           "test_BINARY_OP_LOGICAL_AND_on_int"),
+    "a && b");
+  CHECK_STRING_VALUE (
+    make_test_of_binary_op (ctxt,
+                           int_type,
+                           GCC_JIT_BINARY_OP_LOGICAL_OR,
+                           "test_BINARY_OP_LOGICAL_OR_on_int"),
+    "a || b");
+  CHECK_STRING_VALUE (
+    make_test_of_binary_op (ctxt,
+                           int_type,
+                           GCC_JIT_BINARY_OP_LSHIFT,
+                           "test_BINARY_OP_LSHIFT_on_int"),
+    "a << b");
+  CHECK_STRING_VALUE (
+    make_test_of_binary_op (ctxt,
+                           int_type,
+                           GCC_JIT_BINARY_OP_RSHIFT,
+                           "test_BINARY_OP_RSHIFT_on_int"),
+    "a >> b");
+}
+
+static void
+verify_binary_ops (gcc_jit_result *result)
+{
+  typedef int (*test_fn) (int, int);
+
+  test_fn test_BINARY_OP_PLUS_on_int =
+    (test_fn)gcc_jit_result_get_code (result,
+                                     "test_BINARY_OP_PLUS_on_int");
+  CHECK_NON_NULL (test_BINARY_OP_PLUS_on_int);
+  CHECK_VALUE (test_BINARY_OP_PLUS_on_int (0, 0), 0);
+  CHECK_VALUE (test_BINARY_OP_PLUS_on_int (1, 2), 3);
+  CHECK_VALUE (test_BINARY_OP_PLUS_on_int (100, -1), 99);
+  CHECK_VALUE (test_BINARY_OP_PLUS_on_int (-1, -4), -5);
+
+  test_fn test_BINARY_OP_MINUS_on_int =
+    (test_fn)gcc_jit_result_get_code (result,
+                                     "test_BINARY_OP_MINUS_on_int");
+  CHECK_NON_NULL (test_BINARY_OP_MINUS_on_int);
+  CHECK_VALUE (test_BINARY_OP_MINUS_on_int (0, 0), 0);
+  CHECK_VALUE (test_BINARY_OP_MINUS_on_int (1, 2), -1);
+  CHECK_VALUE (test_BINARY_OP_MINUS_on_int (100, -1), 101);
+  CHECK_VALUE (test_BINARY_OP_MINUS_on_int (-1, -4), 3);
+
+  test_fn test_BINARY_OP_MULT_on_int =
+    (test_fn)gcc_jit_result_get_code (result,
+                                     "test_BINARY_OP_MULT_on_int");
+  CHECK_NON_NULL (test_BINARY_OP_MULT_on_int);
+  CHECK_VALUE (test_BINARY_OP_MULT_on_int (0, 0), 0);
+  CHECK_VALUE (test_BINARY_OP_MULT_on_int (1, 2), 2);
+  CHECK_VALUE (test_BINARY_OP_MULT_on_int (100, -1), -100);
+  CHECK_VALUE (test_BINARY_OP_MULT_on_int (-1, -4), 4);
+  CHECK_VALUE (test_BINARY_OP_MULT_on_int (7, 10), 70);
+
+  test_fn test_BINARY_OP_DIVIDE_on_int =
+    (test_fn)gcc_jit_result_get_code (result,
+                                     "test_BINARY_OP_DIVIDE_on_int");
+  CHECK_NON_NULL (test_BINARY_OP_DIVIDE_on_int);
+  CHECK_VALUE (test_BINARY_OP_DIVIDE_on_int (7, 2), 3);
+  CHECK_VALUE (test_BINARY_OP_DIVIDE_on_int (100, -1), (100 / -1));
+  CHECK_VALUE (test_BINARY_OP_DIVIDE_on_int (-1, -4), (-1 / -4));
+  CHECK_VALUE (test_BINARY_OP_DIVIDE_on_int (60, 5), 12);
+
+  /* TODO: test for DIVIDE on float or double */
+
+  test_fn test_BINARY_OP_MODULO_on_int =
+    (test_fn)gcc_jit_result_get_code (result,
+                                     "test_BINARY_OP_MODULO_on_int");
+  CHECK_NON_NULL (test_BINARY_OP_MODULO_on_int);
+  CHECK_VALUE (test_BINARY_OP_MODULO_on_int (7, 2), 1);
+  CHECK_VALUE (test_BINARY_OP_MODULO_on_int (100, -1), (100 % -1));
+  CHECK_VALUE (test_BINARY_OP_MODULO_on_int (-1, -4), (-1 % -4));
+  CHECK_VALUE (test_BINARY_OP_MODULO_on_int (60, 5), 0);
+
+  test_fn test_BINARY_OP_BITWISE_AND_on_int =
+    (test_fn)gcc_jit_result_get_code (result,
+                                     "test_BINARY_OP_BITWISE_AND_on_int");
+  CHECK_NON_NULL (test_BINARY_OP_BITWISE_AND_on_int);
+  CHECK_VALUE (test_BINARY_OP_BITWISE_AND_on_int (0xf0f0, 0x7777), 0x7070);
+
+  test_fn test_BINARY_OP_BITWISE_XOR_on_int =
+    (test_fn)gcc_jit_result_get_code (result,
+                                     "test_BINARY_OP_BITWISE_XOR_on_int");
+  CHECK_NON_NULL (test_BINARY_OP_BITWISE_XOR_on_int);
+  CHECK_VALUE (test_BINARY_OP_BITWISE_XOR_on_int (0xf0f0, 0x7777), 0x8787);
+
+  test_fn test_BINARY_OP_BITWISE_OR_on_int =
+    (test_fn)gcc_jit_result_get_code (result,
+                                     "test_BINARY_OP_BITWISE_OR_on_int");
+  CHECK_NON_NULL (test_BINARY_OP_BITWISE_OR_on_int);
+  CHECK_VALUE (test_BINARY_OP_BITWISE_OR_on_int (0xf0f0, 0x7777), 0xf7f7);
+
+  test_fn test_BINARY_OP_LOGICAL_AND_on_int =
+    (test_fn)gcc_jit_result_get_code (result,
+                                     "test_BINARY_OP_LOGICAL_AND_on_int");
+  CHECK_NON_NULL (test_BINARY_OP_LOGICAL_AND_on_int);
+  CHECK_VALUE (test_BINARY_OP_LOGICAL_AND_on_int (0, 0), 0);
+  CHECK_VALUE (test_BINARY_OP_LOGICAL_AND_on_int (42, 0), 0);
+  CHECK_VALUE (test_BINARY_OP_LOGICAL_AND_on_int (0, -13), 0);
+  CHECK_VALUE (test_BINARY_OP_LOGICAL_AND_on_int (1997, 1998), 1);
+
+  test_fn test_BINARY_OP_LOGICAL_OR_on_int =
+    (test_fn)gcc_jit_result_get_code (result,
+                                     "test_BINARY_OP_LOGICAL_OR_on_int");
+  CHECK_NON_NULL (test_BINARY_OP_LOGICAL_OR_on_int);
+  CHECK_VALUE (test_BINARY_OP_LOGICAL_OR_on_int (0, 0), 0);
+  CHECK_VALUE (test_BINARY_OP_LOGICAL_OR_on_int (42, 0), 1);
+  CHECK_VALUE (test_BINARY_OP_LOGICAL_OR_on_int (0, -13), 1);
+  CHECK_VALUE (test_BINARY_OP_LOGICAL_OR_on_int (1997, 1998), 1);
+
+  test_fn test_BINARY_OP_LSHIFT_on_int =
+    (test_fn)gcc_jit_result_get_code (result,
+                                     "test_BINARY_OP_LSHIFT_on_int");
+  CHECK_NON_NULL (test_BINARY_OP_LSHIFT_on_int);
+  CHECK_VALUE (test_BINARY_OP_LSHIFT_on_int (0, 0), 0);
+  CHECK_VALUE (test_BINARY_OP_LSHIFT_on_int (0, 1), 0);
+  CHECK_VALUE (test_BINARY_OP_LSHIFT_on_int (0, 2), 0);
+  CHECK_VALUE (test_BINARY_OP_LSHIFT_on_int (1, 0), 1);
+  CHECK_VALUE (test_BINARY_OP_LSHIFT_on_int (1, 1), 2);
+  CHECK_VALUE (test_BINARY_OP_LSHIFT_on_int (1, 2), 4);
+  CHECK_VALUE (test_BINARY_OP_LSHIFT_on_int (1, 3), 8);
+  CHECK_VALUE (test_BINARY_OP_LSHIFT_on_int (3, 0), 3);
+  CHECK_VALUE (test_BINARY_OP_LSHIFT_on_int (3, 1), 6);
+  CHECK_VALUE (test_BINARY_OP_LSHIFT_on_int (3, 5), 3 * 32);
+  CHECK_VALUE (test_BINARY_OP_LSHIFT_on_int (42, 0), 42);
+  CHECK_VALUE (test_BINARY_OP_LSHIFT_on_int (42, 1), 84);
+
+  test_fn test_BINARY_OP_RSHIFT_on_int =
+    (test_fn)gcc_jit_result_get_code (result,
+                                     "test_BINARY_OP_RSHIFT_on_int");
+  CHECK_NON_NULL (test_BINARY_OP_RSHIFT_on_int);
+  CHECK_VALUE (test_BINARY_OP_RSHIFT_on_int (0, 0), 0);
+  CHECK_VALUE (test_BINARY_OP_RSHIFT_on_int (42, 0), 42);
+  CHECK_VALUE (test_BINARY_OP_RSHIFT_on_int (42, 1), 21);
+  CHECK_VALUE (test_BINARY_OP_RSHIFT_on_int (42, 2), 10);
+}
+
+/**********************************************************************
+ Comparisons
+ **********************************************************************/
+
+static const char *
+make_test_of_comparison (gcc_jit_context *ctxt,
+                        gcc_jit_type *type,
+                        enum gcc_jit_comparison op,
+                        const char *funcname)
+{
+  /* Make a test function of the form:
+       bool test_comparison_op (T a, T b)
+       {
+         return a OP b;
+       }
+  */
+  gcc_jit_param *param_a =
+    gcc_jit_context_new_param (ctxt, NULL, type, "a");
+  gcc_jit_param *param_b =
+    gcc_jit_context_new_param (ctxt, NULL, type, "b");
+  gcc_jit_param *params[] = {param_a, param_b};
+  gcc_jit_type *bool_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_BOOL);
+  gcc_jit_function *test_fn =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                 GCC_JIT_FUNCTION_EXPORTED,
+                                 bool_type,
+                                 funcname,
+                                 2, params,
+                                 0);
+  gcc_jit_rvalue *comparison =
+    gcc_jit_context_new_comparison (
+      ctxt,
+      NULL,
+      op,
+      gcc_jit_param_as_rvalue (param_a),
+      gcc_jit_param_as_rvalue (param_b));
+
+  gcc_jit_block *initial = gcc_jit_function_new_block (test_fn, "initial");
+  gcc_jit_block_end_with_return (initial, NULL, comparison);
+
+  return gcc_jit_object_get_debug_string (
+    gcc_jit_rvalue_as_object (comparison));
+}
+
+static void
+make_tests_of_comparisons (gcc_jit_context *ctxt)
+{
+  gcc_jit_type *int_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+  CHECK_STRING_VALUE (
+    make_test_of_comparison (ctxt,
+                            int_type,
+                            GCC_JIT_COMPARISON_EQ,
+                            "test_COMPARISON_EQ_on_int"),
+    "a == b");
+  CHECK_STRING_VALUE (
+    make_test_of_comparison (ctxt,
+                            int_type,
+                            GCC_JIT_COMPARISON_NE,
+                            "test_COMPARISON_NE_on_int"),
+    "a != b");
+  CHECK_STRING_VALUE (
+    make_test_of_comparison (ctxt,
+                            int_type,
+                            GCC_JIT_COMPARISON_LT,
+                            "test_COMPARISON_LT_on_int"),
+    "a < b");
+  CHECK_STRING_VALUE (
+    make_test_of_comparison (ctxt,
+                            int_type,
+                            GCC_JIT_COMPARISON_LE,
+                            "test_COMPARISON_LE_on_int"),
+    "a <= b");
+  CHECK_STRING_VALUE (
+    make_test_of_comparison (ctxt,
+                            int_type,
+                            GCC_JIT_COMPARISON_GT,
+                            "test_COMPARISON_GT_on_int"),
+    "a > b");
+  CHECK_STRING_VALUE (
+    make_test_of_comparison (ctxt,
+                            int_type,
+                            GCC_JIT_COMPARISON_GE,
+                            "test_COMPARISON_GE_on_int"),
+    "a >= b");
+}
+
+static void
+verify_comparisons (gcc_jit_result *result)
+{
+  typedef bool (*test_fn) (int, int);
+
+  test_fn test_COMPARISON_EQ_on_int =
+    (test_fn)gcc_jit_result_get_code (result,
+                                     "test_COMPARISON_EQ_on_int");
+  CHECK_NON_NULL (test_COMPARISON_EQ_on_int);
+  CHECK_VALUE (test_COMPARISON_EQ_on_int (0, 0), 1);
+  CHECK_VALUE (test_COMPARISON_EQ_on_int (1, 2), 0);
+
+  test_fn test_COMPARISON_NE_on_int =
+    (test_fn)gcc_jit_result_get_code (result,
+                                     "test_COMPARISON_NE_on_int");
+  CHECK_NON_NULL (test_COMPARISON_NE_on_int);
+  CHECK_VALUE (test_COMPARISON_NE_on_int (0, 0), 0);
+  CHECK_VALUE (test_COMPARISON_NE_on_int (1, 2), 1);
+
+  test_fn test_COMPARISON_LT_on_int =
+    (test_fn)gcc_jit_result_get_code (result,
+                                     "test_COMPARISON_LT_on_int");
+  CHECK_NON_NULL (test_COMPARISON_LT_on_int);
+  CHECK_VALUE (test_COMPARISON_LT_on_int (0, 0), 0);
+  CHECK_VALUE (test_COMPARISON_LT_on_int (1, 2), 1);
+  CHECK_VALUE (test_COMPARISON_LT_on_int (2, 1), 0);
+  CHECK_VALUE (test_COMPARISON_LT_on_int (-2, 1), 1);
+
+  test_fn test_COMPARISON_LE_on_int =
+    (test_fn)gcc_jit_result_get_code (result,
+                                     "test_COMPARISON_LE_on_int");
+  CHECK_NON_NULL (test_COMPARISON_LE_on_int);
+  CHECK_VALUE (test_COMPARISON_LE_on_int (0, 0), 1);
+  CHECK_VALUE (test_COMPARISON_LE_on_int (1, 2), 1);
+  CHECK_VALUE (test_COMPARISON_LE_on_int (2, 1), 0);
+
+  test_fn test_COMPARISON_GT_on_int =
+    (test_fn)gcc_jit_result_get_code (result,
+                                     "test_COMPARISON_GT_on_int");
+  CHECK_NON_NULL (test_COMPARISON_GT_on_int);
+  CHECK_VALUE (test_COMPARISON_GT_on_int (0, 0), 0);
+  CHECK_VALUE (test_COMPARISON_GT_on_int (1, 2), 0);
+  CHECK_VALUE (test_COMPARISON_GT_on_int (2, 1), 1);
+
+  test_fn test_COMPARISON_GE_on_int =
+    (test_fn)gcc_jit_result_get_code (result,
+                                     "test_COMPARISON_GE_on_int");
+  CHECK_NON_NULL (test_COMPARISON_GE_on_int);
+  CHECK_VALUE (test_COMPARISON_GE_on_int (0, 0), 1);
+  CHECK_VALUE (test_COMPARISON_GE_on_int (1, 2), 0);
+  CHECK_VALUE (test_COMPARISON_GE_on_int (2, 1), 1);
+}
+
+/**********************************************************************
+ Casts
+ **********************************************************************/
+
+static const char*
+make_test_of_cast (gcc_jit_context *ctxt,
+                  gcc_jit_type *input_type,
+                  gcc_jit_type *output_type,
+                  const char *funcname)
+{
+  /* Make a test function of the form:
+       OUTPUT_TYPE test_cast_* (INPUT_TYPE a)
+       {
+          return (OUTPUT_TYPE)a;
+       }
+  */
+  gcc_jit_param *param_a =
+    gcc_jit_context_new_param (ctxt, NULL, input_type, "a");
+  gcc_jit_param *params[] = {param_a};
+  gcc_jit_function *test_fn =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                 GCC_JIT_FUNCTION_EXPORTED,
+                                 output_type,
+                                 funcname,
+                                 1, params,
+                                 0);
+  gcc_jit_rvalue *cast =
+    gcc_jit_context_new_cast (
+      ctxt,
+      NULL,
+      gcc_jit_param_as_rvalue (param_a),
+      output_type);
+  gcc_jit_block *initial = gcc_jit_function_new_block (test_fn, "initial");
+  gcc_jit_block_end_with_return (initial, NULL, cast);
+
+  return gcc_jit_object_get_debug_string (
+    gcc_jit_rvalue_as_object (cast));
+}
+
+/* For use by test_cast_from_array_of_ints_to_int_ptr.  */
+extern int called_pointer_checking_function (int *ints)
+{
+  CHECK_VALUE (ints[0], 10);
+  CHECK_VALUE (ints[1], 4);
+  return ints[0] * ints[1];
+}
+
+static void
+make_tests_of_casts (gcc_jit_context *ctxt)
+{
+  gcc_jit_type *int_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+  gcc_jit_type *float_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_FLOAT);
+  gcc_jit_type *bool_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_BOOL);
+  gcc_jit_type *array_int_type =
+    gcc_jit_context_new_array_type (ctxt, NULL,
+                                   int_type,
+                                   2);
+  gcc_jit_type *int_ptr_type =
+    gcc_jit_type_get_pointer (int_type);
+
+  /* float/int conversions */
+  CHECK_STRING_VALUE (
+    make_test_of_cast (ctxt,
+                      float_type,
+                      int_type,
+                      "test_cast_from_float_to_int"),
+    "(int)a");
+  CHECK_STRING_VALUE (
+    make_test_of_cast (ctxt,
+                      int_type,
+                      float_type,
+                      "test_cast_from_int_to_float"),
+    "(float)a");
+
+  /* bool/int conversions */
+  CHECK_STRING_VALUE (
+    make_test_of_cast (ctxt,
+                      bool_type,
+                      int_type,
+                      "test_cast_from_bool_to_int"),
+    "(int)a");
+  CHECK_STRING_VALUE (
+    make_test_of_cast (ctxt,
+                      int_type,
+                      bool_type,
+                      "test_cast_from_int_to_bool"),
+    "(bool)a");
+
+  /* array/ptr conversions */
+  {
+    gcc_jit_function *test_fn =
+      gcc_jit_context_new_function (
+       ctxt, NULL,
+       GCC_JIT_FUNCTION_EXPORTED,
+       int_type,
+       "test_cast_from_array_of_ints_to_int_ptr",
+       0, NULL,
+       0);
+    /* Equivalent to:
+          int test_cast_from_array_of_ints_to_int_ptr (void)
+         {
+           int array[2];
+           array[0] = 10;
+           array[1] = 4;
+           return called_pointer_checking_function (array);
+         }
+    */
+
+    gcc_jit_param *param_ints =
+      gcc_jit_context_new_param (ctxt, NULL, int_ptr_type, "ints");
+    gcc_jit_function *called_fn =
+      gcc_jit_context_new_function (
+       ctxt, NULL,
+       GCC_JIT_FUNCTION_IMPORTED,
+       int_type,
+       "called_pointer_checking_function",
+       1, &param_ints,
+       0);
+
+    gcc_jit_lvalue *array =
+      gcc_jit_function_new_local (test_fn, NULL,
+                                 array_int_type,
+                                 "array");
+    gcc_jit_block *block =
+      gcc_jit_function_new_block (test_fn, "block");
+    /* array[0] = 10; */
+    gcc_jit_block_add_assignment (
+      block, NULL,
+      gcc_jit_context_new_array_access (
+       ctxt, NULL,
+       gcc_jit_lvalue_as_rvalue (array),
+       gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 0)),
+      gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 10));
+    /* array[1] = 4; */
+    gcc_jit_block_add_assignment (
+      block, NULL,
+      gcc_jit_context_new_array_access (
+       ctxt, NULL,
+       gcc_jit_lvalue_as_rvalue (array),
+       gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 1)),
+      gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 4));
+    gcc_jit_rvalue *cast =
+      gcc_jit_context_new_cast (
+       ctxt,
+       NULL,
+       /* We need a get_address here.  */
+       gcc_jit_lvalue_get_address (array, NULL),
+       int_ptr_type);
+    gcc_jit_block_end_with_return (
+      block, NULL,
+      gcc_jit_context_new_call (
+       ctxt, NULL,
+       called_fn,
+       1, &cast));
+
+    CHECK_STRING_VALUE (
+      gcc_jit_object_get_debug_string (
+       gcc_jit_rvalue_as_object (cast)),
+      "(int *)&array");
+  }
+}
+
+static void
+verify_casts (gcc_jit_result *result)
+{
+  /* float to int */
+  {
+    typedef int (*fn_type) (float);
+    fn_type test_cast_from_float_to_int =
+      (fn_type)gcc_jit_result_get_code (result,
+                                       "test_cast_from_float_to_int");
+    CHECK_NON_NULL (test_cast_from_float_to_int);
+    CHECK_VALUE (test_cast_from_float_to_int (4.2), 4);
+  }
+
+  /* int to float */
+  {
+    typedef float (*fn_type) (int);
+    fn_type test_cast_from_int_to_float =
+      (fn_type)gcc_jit_result_get_code (result,
+                                       "test_cast_from_int_to_float");
+    CHECK_NON_NULL (test_cast_from_int_to_float);
+    CHECK_VALUE (test_cast_from_int_to_float (4), 4.0);
+  }
+
+  /* bool to int */
+  {
+    typedef int (*fn_type) (bool);
+    fn_type test_cast_from_bool_to_int =
+      (fn_type)gcc_jit_result_get_code (result,
+                                       "test_cast_from_bool_to_int");
+    CHECK_NON_NULL (test_cast_from_bool_to_int);
+    CHECK_VALUE (test_cast_from_bool_to_int (0), 0);
+    CHECK_VALUE (test_cast_from_bool_to_int (1), 1);
+  }
+
+  /* int to bool */
+  {
+    typedef bool (*fn_type) (int);
+    fn_type test_cast_from_int_to_bool =
+      (fn_type)gcc_jit_result_get_code (result,
+                                       "test_cast_from_int_to_bool");
+    CHECK_NON_NULL (test_cast_from_int_to_bool);
+    CHECK_VALUE (test_cast_from_int_to_bool (0), 0);
+    CHECK_VALUE (test_cast_from_int_to_bool (1), 1);
+  }
+
+  /* array to ptr */
+  {
+    typedef int (*fn_type) (void);
+    fn_type test_cast_from_array_of_ints_to_int_ptr =
+      (fn_type)gcc_jit_result_get_code (
+       result,
+       "test_cast_from_array_of_ints_to_int_ptr");
+    CHECK_NON_NULL (test_cast_from_array_of_ints_to_int_ptr);
+    CHECK_VALUE (test_cast_from_array_of_ints_to_int_ptr (), 40);
+  }
+}
+
+/**********************************************************************
+ Dereferences
+ **********************************************************************/
+
+static void
+make_tests_of_dereferences (gcc_jit_context *ctxt)
+{
+  /*
+       int test_dereference_read (int *ptr)
+       {
+        return *ptr;
+       }
+       void test_dereference_write (int *ptr, int i)
+       {
+        *ptr = i;
+       }
+  */
+  gcc_jit_type *void_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+  gcc_jit_type *int_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+  gcc_jit_type *int_ptr_type =
+    gcc_jit_type_get_pointer (int_type);
+  {
+    gcc_jit_param *param_ptr =
+      gcc_jit_context_new_param (ctxt, NULL, int_ptr_type, "ptr");
+    gcc_jit_function *test_dereference_read =
+      gcc_jit_context_new_function (ctxt, NULL,
+                                   GCC_JIT_FUNCTION_EXPORTED,
+                                   int_type,
+                                   "test_dereference_read",
+                                   1, &param_ptr,
+                                   0);
+    gcc_jit_block *initial =
+      gcc_jit_function_new_block (test_dereference_read, "initial");
+    gcc_jit_block_end_with_return (
+      initial,
+      NULL,
+      gcc_jit_lvalue_as_rvalue (
+       gcc_jit_rvalue_dereference (
+         gcc_jit_param_as_rvalue (param_ptr),
+         NULL)));
+  }
+
+  {
+    gcc_jit_param *param_ptr =
+      gcc_jit_context_new_param (ctxt, NULL, int_ptr_type, "ptr");
+    gcc_jit_param *param_i =
+      gcc_jit_context_new_param (ctxt, NULL, int_type, "i");
+    gcc_jit_param *params[] = {param_ptr, param_i};
+    gcc_jit_function *test_dereference_write =
+      gcc_jit_context_new_function (ctxt, NULL,
+                                   GCC_JIT_FUNCTION_EXPORTED,
+                                   void_type,
+                                   "test_dereference_write",
+                                   2, params,
+                                   0);
+    gcc_jit_block *initial =
+      gcc_jit_function_new_block (test_dereference_write, "initial");
+    gcc_jit_block_add_assignment (
+      initial,
+      NULL,
+      gcc_jit_rvalue_dereference (
+       gcc_jit_param_as_rvalue (param_ptr),
+       NULL),
+      gcc_jit_param_as_rvalue (param_i));
+    gcc_jit_block_end_with_void_return (initial, NULL);
+  }
+}
+
+static void
+verify_dereferences (gcc_jit_result *result)
+{
+  int a = 42;
+  int b = -99;
+
+  {
+    typedef int (*test_read) (int *);
+    test_read test_dereference_read =
+      (test_read)gcc_jit_result_get_code (result,
+                                         "test_dereference_read");
+    CHECK_NON_NULL (test_dereference_read);
+    CHECK_VALUE (test_dereference_read (&a), 42);
+    CHECK_VALUE (test_dereference_read (&b), -99);
+  }
+
+ {
+    typedef void (*test_write) (int *, int);
+    test_write test_dereference_write =
+      (test_write)gcc_jit_result_get_code (result,
+                                         "test_dereference_write");
+    CHECK_NON_NULL (test_dereference_write);
+    test_dereference_write (&a, -55);
+    CHECK_VALUE (a, -55);
+
+    test_dereference_write (&b, 404);
+    CHECK_VALUE (b, 404);
+  }
+}
+
+/**********************************************************************
+ gcc_jit_lvalue_get_address
+ **********************************************************************/
+
+int test_global;
+static void
+make_test_of_get_address (gcc_jit_context *ctxt)
+{
+  /*
+     void *test_get_address (void)
+     {
+       return &test_global;
+     }
+  */
+  gcc_jit_type *int_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+  gcc_jit_lvalue *test_global =
+    gcc_jit_context_new_global (
+      ctxt,
+      NULL,
+      int_type,
+      "test_global");
+
+ gcc_jit_type *void_ptr_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID_PTR);
+
+  gcc_jit_function *test_get_address =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                 GCC_JIT_FUNCTION_EXPORTED,
+                                 void_ptr_type,
+                                 "test_get_address",
+                                 0, NULL,
+                                 0);
+  gcc_jit_block *initial =
+    gcc_jit_function_new_block (test_get_address, "initial");
+  gcc_jit_block_end_with_return (
+    initial,
+    NULL,
+    gcc_jit_lvalue_get_address (
+      test_global,
+      NULL));
+}
+
+static void
+verify_get_address (gcc_jit_result *result)
+{
+  typedef void *(*test_fn) (void);
+    test_fn test_get_address =
+      (test_fn)gcc_jit_result_get_code (result,
+                                       "test_get_address");
+  CHECK_NON_NULL (test_get_address);
+  CHECK_VALUE (test_get_address (), &test_global);
+}
+
+/**********************************************************************
+ Code for harness
+ **********************************************************************/
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  make_tests_of_unary_ops (ctxt);
+  make_tests_of_binary_ops (ctxt);
+  make_tests_of_comparisons (ctxt);
+  make_tests_of_casts (ctxt);
+  make_tests_of_dereferences (ctxt);
+  make_test_of_get_address (ctxt);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  CHECK_NON_NULL (result);
+
+  verify_unary_ops (result);
+  verify_binary_ops (result);
+  verify_comparisons (result);
+  verify_casts (result);
+  verify_dereferences (result);
+  verify_get_address (result);
+}
diff --git a/gcc/testsuite/jit.dg/test-factorial.c b/gcc/testsuite/jit.dg/test-factorial.c
new file mode 100644 (file)
index 0000000..b2aaece
--- /dev/null
@@ -0,0 +1,103 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  /* Let's try to inject the equivalent of:
+
+      int
+      my_factorial (int x)
+      {
+        if (x < 2)
+          return x;
+        else
+          return x * my_factorial (x - 1);
+      }
+
+     and see if the optimizer eliminates the recursion (it does).
+   */
+  gcc_jit_type *the_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+  gcc_jit_type *return_type = the_type;
+
+  gcc_jit_param *x =
+    gcc_jit_context_new_param (ctxt, NULL, the_type, "x");
+  gcc_jit_param *params[1] = {x};
+  gcc_jit_function *func =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                 GCC_JIT_FUNCTION_EXPORTED,
+                                 return_type,
+                                 "my_factorial",
+                                 1, params, 0);
+
+  gcc_jit_block *initial =
+    gcc_jit_function_new_block (func, "initial");
+  gcc_jit_block *on_true =
+    gcc_jit_function_new_block (func, "on_true");
+  gcc_jit_block *on_false =
+    gcc_jit_function_new_block (func, "on_false");
+
+ /* if (x < 2) */
+  gcc_jit_block_end_with_conditional (
+    initial, NULL,
+    gcc_jit_context_new_comparison (
+      ctxt, NULL,
+      GCC_JIT_COMPARISON_LT,
+      gcc_jit_param_as_rvalue (x),
+      gcc_jit_context_new_rvalue_from_int (
+       ctxt,
+       the_type,
+       2)),
+    on_true,
+    on_false);
+
+  /* true branch: */
+  /* return x */
+  gcc_jit_block_end_with_return (
+    on_true,
+    NULL,
+    gcc_jit_param_as_rvalue (x));
+
+  /* false branch: */
+  gcc_jit_rvalue *x_minus_1 =
+    gcc_jit_context_new_binary_op (
+      ctxt, NULL,
+      GCC_JIT_BINARY_OP_MINUS, the_type,
+      gcc_jit_param_as_rvalue (x),
+      gcc_jit_context_new_rvalue_from_int (
+       ctxt,
+       the_type,
+       1));
+  gcc_jit_block_end_with_return (
+    on_false,
+    NULL,
+    gcc_jit_context_new_binary_op (
+      ctxt, NULL,
+      GCC_JIT_BINARY_OP_MULT, the_type,
+      gcc_jit_param_as_rvalue (x),
+      /* my_factorial (x - 1) */
+      gcc_jit_context_new_call (
+        ctxt, NULL,
+        func,
+        1, &x_minus_1)));
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  typedef int (*my_factorial_fn_type) (int);
+  CHECK_NON_NULL (result);
+  my_factorial_fn_type my_factorial =
+    (my_factorial_fn_type)gcc_jit_result_get_code (result, "my_factorial");
+  CHECK_NON_NULL (my_factorial);
+  int val = my_factorial (10);
+  note ("my_factorial returned: %d", val);
+  CHECK_VALUE (val, 3628800);
+}
+
diff --git a/gcc/testsuite/jit.dg/test-fibonacci.c b/gcc/testsuite/jit.dg/test-fibonacci.c
new file mode 100644 (file)
index 0000000..607bd56
--- /dev/null
@@ -0,0 +1,136 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  const int FIRST_LINE = __LINE__ + 4;
+  /* Let's try to inject the equivalent of:
+0000000001111111111222222222233333333334444444444555555555566666666667
+1234567890123456789012345678901234567890123456789012345678901234567890
+FIRST_LINE + 0: int
+FIRST_LINE + 1: my_fibonacci (int x)
+FIRST_LINE + 2: {
+FIRST_LINE + 3:   if (x < 2)
+FIRST_LINE + 4:     return x;
+FIRST_LINE + 5:   else
+FIRST_LINE + 6:     return my_fibonacci (x - 1) + my_fibonacci (x - 2);
+FIRST_LINE + 7: }
+0000000001111111111222222222233333333334444444444555555555566666666667
+1234567890123456789012345678901234567890123456789012345678901234567890
+
+     where the source locations are set up to point to the commented-out
+     code above.
+     It should therefore be possible to step through the generated code
+     in the debugger, stepping through the above commented-out code
+     fragement.
+   */
+  gcc_jit_type *the_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+  gcc_jit_type *return_type = the_type;
+
+  gcc_jit_param *x =
+    gcc_jit_context_new_param (
+      ctxt,
+      gcc_jit_context_new_location (
+       ctxt, __FILE__, FIRST_LINE + 1, 35),
+      the_type, "x");
+  gcc_jit_param *params[1] = {x};
+  gcc_jit_function *func =
+    gcc_jit_context_new_function (ctxt,
+                                 gcc_jit_context_new_location (
+                                   ctxt, __FILE__, FIRST_LINE, 17),
+                                 GCC_JIT_FUNCTION_EXPORTED,
+                                 return_type,
+                                 "my_fibonacci",
+                                 1, params, 0);
+
+  gcc_jit_block *initial =
+    gcc_jit_function_new_block (func, "initial");
+  gcc_jit_block *on_true =
+    gcc_jit_function_new_block (func, "on_true");
+  gcc_jit_block *on_false =
+    gcc_jit_function_new_block (func, "on_false");
+
+  /* if (x < 2) */
+  gcc_jit_block_end_with_conditional (
+    initial,
+    gcc_jit_context_new_location (ctxt, __FILE__, FIRST_LINE + 3, 19),
+    gcc_jit_context_new_comparison (
+      ctxt,
+      gcc_jit_context_new_location (ctxt, __FILE__, FIRST_LINE + 3, 25),
+      GCC_JIT_COMPARISON_LT,
+      gcc_jit_param_as_rvalue (x),
+      gcc_jit_context_new_rvalue_from_int (
+       ctxt,
+       the_type,
+       2)),
+    on_true,
+    on_false);
+
+  /* true branch: */
+  /* return x */
+  gcc_jit_block_end_with_return (
+    on_true,
+    gcc_jit_context_new_location (ctxt, __FILE__, FIRST_LINE + 4, 21),
+    gcc_jit_param_as_rvalue (x));
+
+  /* false branch: */
+  gcc_jit_rvalue *x_minus_1 =
+    gcc_jit_context_new_binary_op (
+      ctxt,
+      gcc_jit_context_new_location (ctxt, __FILE__, FIRST_LINE + 6, 44),
+      GCC_JIT_BINARY_OP_MINUS, the_type,
+      gcc_jit_param_as_rvalue (x),
+      gcc_jit_context_new_rvalue_from_int (
+       ctxt,
+       the_type,
+       1));
+  gcc_jit_rvalue *x_minus_2 =
+    gcc_jit_context_new_binary_op (
+      ctxt,
+      gcc_jit_context_new_location (ctxt, __FILE__, FIRST_LINE + 6, 67),
+      GCC_JIT_BINARY_OP_MINUS, the_type,
+      gcc_jit_param_as_rvalue (x),
+      gcc_jit_context_new_rvalue_from_int (
+       ctxt,
+       the_type,
+       2));
+  gcc_jit_block_end_with_return (
+    on_false,
+    gcc_jit_context_new_location (ctxt, __FILE__, FIRST_LINE + 6, 21),
+    gcc_jit_context_new_binary_op (
+      ctxt,
+      gcc_jit_context_new_location (ctxt, __FILE__, FIRST_LINE + 6, 49),
+      GCC_JIT_BINARY_OP_PLUS, the_type,
+      /* my_fibonacci (x - 1) */
+      gcc_jit_context_new_call (
+       ctxt,
+       gcc_jit_context_new_location (ctxt, __FILE__, FIRST_LINE + 6, 28),
+       func,
+       1, &x_minus_1),
+      /* my_fibonacci (x - 2) */
+      gcc_jit_context_new_call (
+       ctxt,
+       gcc_jit_context_new_location (ctxt, __FILE__, FIRST_LINE + 6, 51),
+       func,
+       1, &x_minus_2)));
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  typedef int (*my_fibonacci_fn_type) (int);
+  CHECK_NON_NULL (result);
+  my_fibonacci_fn_type my_fibonacci =
+    (my_fibonacci_fn_type)gcc_jit_result_get_code (result, "my_fibonacci");
+  CHECK_NON_NULL (my_fibonacci);
+  int val = my_fibonacci (10);
+  note ("my_fibonacci returned: %d", val);
+  CHECK_VALUE (val, 55);
+}
diff --git a/gcc/testsuite/jit.dg/test-functions.c b/gcc/testsuite/jit.dg/test-functions.c
new file mode 100644 (file)
index 0000000..3d03ada
--- /dev/null
@@ -0,0 +1,356 @@
+#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+/**********************************************************************
+ GCC_JIT_FUNCTION_ALWAYS_INLINE and GCC_JIT_FUNCTION_INTERNAL
+ **********************************************************************/
+static void
+create_test_of_hidden_function (gcc_jit_context *ctxt,
+                               enum gcc_jit_function_kind hidden_kind,
+                               const char *hidden_func_name,
+                               const char *visible_func_name)
+{
+  /* Let's try to inject the equivalent of:
+     static double hidden_mult (double a, double b)
+     {
+       return x * x;
+     }
+     double my_square (double x)
+     {
+       return my_mult (x, x);
+     }
+
+     where hidden_mult can potentially be
+       inline  __attribute__((always_inline)).  */
+  gcc_jit_type *double_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_DOUBLE);
+
+  /* Create "my_mult" */
+  gcc_jit_param *param_a =
+    gcc_jit_context_new_param (ctxt, NULL, double_type, "a");
+  gcc_jit_param *param_b =
+    gcc_jit_context_new_param (ctxt, NULL, double_type, "b");
+  gcc_jit_param *params[2] = {param_a, param_b};
+  gcc_jit_function *my_mult =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                 hidden_kind,
+                                  double_type,
+                                  hidden_func_name,
+                                  2, params,
+                                  0);
+  gcc_jit_block *body_of_my_mult =
+    gcc_jit_function_new_block (my_mult, NULL);
+  gcc_jit_block_end_with_return (
+    body_of_my_mult, NULL,
+    gcc_jit_context_new_binary_op (
+      ctxt, NULL,
+      GCC_JIT_BINARY_OP_MULT,
+      double_type,
+      gcc_jit_param_as_rvalue (param_a),
+      gcc_jit_param_as_rvalue (param_b)));
+
+  /* Create "my_square" */
+  gcc_jit_param *param_x =
+    gcc_jit_context_new_param (ctxt, NULL, double_type, "x");
+  gcc_jit_function *my_square =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                  GCC_JIT_FUNCTION_EXPORTED,
+                                  double_type,
+                                  visible_func_name,
+                                  1, &param_x,
+                                  0);
+  gcc_jit_block *body_of_my_square =
+    gcc_jit_function_new_block (my_square, NULL);
+  gcc_jit_rvalue *args[2] = {gcc_jit_param_as_rvalue (param_x),
+                            gcc_jit_param_as_rvalue (param_x)};
+  gcc_jit_block_end_with_return (
+    body_of_my_square, NULL,
+    gcc_jit_context_new_call (
+      ctxt, NULL,
+      my_mult,
+      2, args));
+}
+
+static void
+create_tests_of_hidden_functions (gcc_jit_context *ctxt)
+{
+  create_test_of_hidden_function (ctxt,
+                                 GCC_JIT_FUNCTION_INTERNAL,
+                                 "my_internal_mult",
+                                 "my_square_with_internal");
+  create_test_of_hidden_function (ctxt,
+                                 GCC_JIT_FUNCTION_ALWAYS_INLINE,
+                                 "my_always_inline_mult",
+                                 "my_square_with_always_inline");
+}
+
+static void
+verify_hidden_functions (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  CHECK_NON_NULL (result);
+
+  /* GCC_JIT_FUNCTION_INTERNAL and GCC_JIT_FUNCTION_ALWAYS_INLINE
+     functions should not be accessible in the result.  */
+  CHECK_VALUE (NULL, gcc_jit_result_get_code (result, "my_internal_mult"));
+  CHECK_VALUE (NULL, gcc_jit_result_get_code (result, "my_always_inline_mult"));
+
+  typedef double (*fn_type) (double);
+  fn_type my_square_with_internal =
+    (fn_type)gcc_jit_result_get_code (result, "my_square_with_internal");
+  CHECK_NON_NULL (my_square_with_internal);
+  CHECK_VALUE (my_square_with_internal (5.0), 25.0);
+
+  fn_type my_square_with_always_inline =
+    (fn_type)gcc_jit_result_get_code (result, "my_square_with_always_inline");
+  CHECK_NON_NULL (my_square_with_always_inline);
+  CHECK_VALUE (my_square_with_always_inline (5.0), 25.0);
+}
+
+/**********************************************************************
+ Builtin functions
+ **********************************************************************/
+
+static void
+create_test_of_builtin_strcmp (gcc_jit_context *ctxt)
+{
+  /* Let's try to inject the equivalent of:
+       int
+       test_of_builtin_strcmp (const char *a, const char *b)
+       {
+         return __builtin_strcmp (a, b);
+       }
+  */
+  gcc_jit_type *int_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+  gcc_jit_type *const_char_ptr_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_CONST_CHAR_PTR);
+
+  /* Get the built-in function.  */
+  gcc_jit_function *builtin_fn =
+    gcc_jit_context_get_builtin_function (ctxt, "strcmp");
+
+  CHECK_STRING_VALUE (
+    gcc_jit_object_get_debug_string (gcc_jit_function_as_object (builtin_fn)),
+    "strcmp");
+
+  /* Build the test_fn.  */
+  gcc_jit_param *param_a =
+    gcc_jit_context_new_param (ctxt, NULL, const_char_ptr_type, "a");
+  gcc_jit_param *param_b =
+    gcc_jit_context_new_param (ctxt, NULL, const_char_ptr_type, "b");
+  gcc_jit_param *params[2] = {param_a, param_b};
+  gcc_jit_function *test_fn =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                  GCC_JIT_FUNCTION_EXPORTED,
+                                  int_type,
+                                  "test_of_builtin_strcmp",
+                                  2, params,
+                                  0);
+  gcc_jit_rvalue *args[2] = {gcc_jit_param_as_rvalue (param_a),
+                            gcc_jit_param_as_rvalue (param_b)};
+  gcc_jit_rvalue *call =
+    gcc_jit_context_new_call (ctxt,
+                              NULL,
+                              builtin_fn,
+                              2, args);
+  CHECK_STRING_VALUE (
+    gcc_jit_object_get_debug_string (gcc_jit_rvalue_as_object (call)),
+    "strcmp (a, b)");
+
+  gcc_jit_block *initial =
+    gcc_jit_function_new_block (test_fn, "initial");
+  gcc_jit_block_end_with_return (initial, NULL, call);
+}
+
+static void
+create_test_of_builtin_trig (gcc_jit_context *ctxt)
+{
+  /* Let's try to inject the equivalent of:
+       int
+       test_of_builtin_trig (double theta)
+       {
+         return 2 * sin (theta) * cos (theta);
+       }
+       (in theory, optimizable to sin (2 * theta))
+  */
+  gcc_jit_type *double_t =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_DOUBLE);
+
+  /* Get the built-in functions.  */
+  gcc_jit_function *builtin_sin =
+    gcc_jit_context_get_builtin_function (ctxt, "sin");
+  gcc_jit_function *builtin_cos =
+    gcc_jit_context_get_builtin_function (ctxt, "cos");
+
+  /* Build the test_fn.  */
+  gcc_jit_param *param_theta =
+    gcc_jit_context_new_param (ctxt, NULL, double_t, "theta");
+  gcc_jit_function *test_fn =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                  GCC_JIT_FUNCTION_EXPORTED,
+                                  double_t,
+                                  "test_of_builtin_trig",
+                                  1, &param_theta,
+                                  0);
+  gcc_jit_rvalue *args[1] = {gcc_jit_param_as_rvalue (param_theta)};
+  gcc_jit_rvalue *two =
+    gcc_jit_context_new_rvalue_from_int (ctxt, double_t, 2);
+  gcc_jit_rvalue *ret =
+    gcc_jit_context_new_binary_op (
+      ctxt, NULL,
+      GCC_JIT_BINARY_OP_MULT,
+      double_t,
+      two,
+      gcc_jit_context_new_binary_op (
+        ctxt, NULL,
+       GCC_JIT_BINARY_OP_MULT,
+       double_t,
+       gcc_jit_context_new_call (ctxt, NULL,
+                                 builtin_sin,
+                                 1, args),
+       gcc_jit_context_new_call (ctxt, NULL,
+                                 builtin_cos,
+                                 1, args)));
+  CHECK_STRING_VALUE (
+    gcc_jit_object_get_debug_string (gcc_jit_rvalue_as_object (ret)),
+    "(double)2 * sin (theta) * cos (theta)");
+
+  gcc_jit_block *initial =
+    gcc_jit_function_new_block (test_fn, "initial");
+  gcc_jit_block_end_with_return (initial, NULL, ret);
+}
+
+static void
+create_use_of_builtins (gcc_jit_context *ctxt)
+{
+  create_test_of_builtin_strcmp (ctxt);
+  create_test_of_builtin_trig (ctxt);
+}
+
+static void
+verify_test_of_builtin_strcmp (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  typedef int (*fn_type) (const char *, const char *);
+  CHECK_NON_NULL (result);
+
+  fn_type test_of_builtin_strcmp =
+    (fn_type)gcc_jit_result_get_code (result, "test_of_builtin_strcmp");
+  CHECK_NON_NULL (test_of_builtin_strcmp);
+
+  /* Verify that it correctly called strcmp.  */
+  CHECK_VALUE (test_of_builtin_strcmp ("foo", "foo"), 0);
+  CHECK (test_of_builtin_strcmp ("foo", "bar") > 0);
+  CHECK (test_of_builtin_strcmp ("bar", "foo") < 0);
+}
+
+static void
+verify_test_of_builtin_trig (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  typedef double (*fn_type) (double);
+  CHECK_NON_NULL (result);
+
+  fn_type test_of_builtin_trig =
+    (fn_type)gcc_jit_result_get_code (result, "test_of_builtin_trig");
+  CHECK_NON_NULL (test_of_builtin_trig);
+
+  /* Verify that it correctly computes
+        sin (2 * theta)
+     (perhaps calling sin and cos). */
+  CHECK_DOUBLE_VALUE (test_of_builtin_trig (0.0         ),  0.0);
+  CHECK_DOUBLE_VALUE (test_of_builtin_trig (M_PI_4      ),  1.0);
+  CHECK_DOUBLE_VALUE (test_of_builtin_trig (M_PI_2      ),  0.0);
+  CHECK_DOUBLE_VALUE (test_of_builtin_trig (M_PI_4 * 3.0), -1.0);
+  CHECK_DOUBLE_VALUE (test_of_builtin_trig (M_PI        ),  0.0);
+}
+
+static void
+verify_use_of_builtins (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  verify_test_of_builtin_strcmp (ctxt, result);
+  verify_test_of_builtin_trig (ctxt, result);
+}
+
+/**********************************************************************
+ "void" return
+ **********************************************************************/
+
+static void
+create_use_of_void_return (gcc_jit_context *ctxt)
+{
+  /* Let's try to inject the equivalent of:
+       void
+       test_of_void_return (int *out)
+       {
+         *out = 1;
+        return;
+       }
+  */
+  gcc_jit_type *void_t =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+  gcc_jit_type *int_t =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+  gcc_jit_type *int_ptr_t =
+    gcc_jit_type_get_pointer (int_t);
+
+  /* Build the test_fn.  */
+  gcc_jit_param *param_out =
+    gcc_jit_context_new_param (ctxt, NULL, int_ptr_t, "out");
+  gcc_jit_function *test_fn =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                  GCC_JIT_FUNCTION_EXPORTED,
+                                  void_t,
+                                  "test_of_void_return",
+                                  1, &param_out,
+                                  0);
+  gcc_jit_block *initial =
+    gcc_jit_function_new_block (test_fn, "initial");
+
+  gcc_jit_block_add_assignment (
+    initial, NULL,
+    /* "*out = ..." */
+    gcc_jit_rvalue_dereference (gcc_jit_param_as_rvalue (param_out),
+                               NULL),
+    gcc_jit_context_one (ctxt, int_t));
+  gcc_jit_block_end_with_void_return (initial, NULL);
+}
+
+static void
+verify_void_return (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  typedef void (*fn_type) (int *);
+  CHECK_NON_NULL (result);
+
+  fn_type test_of_void_return =
+    (fn_type)gcc_jit_result_get_code (result, "test_of_void_return");
+  CHECK_NON_NULL (test_of_void_return);
+
+  int i;
+  test_of_void_return (&i);
+  CHECK_VALUE (i, 1); /* ensure correct value was written back */
+}
+
+/**********************************************************************
+ Code for harness
+ **********************************************************************/
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  create_tests_of_hidden_functions (ctxt);
+  create_use_of_builtins (ctxt);
+  create_use_of_void_return (ctxt);
+}
+
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  verify_hidden_functions (ctxt, result);
+  verify_use_of_builtins (ctxt, result);
+  verify_void_return (ctxt, result);
+}
diff --git a/gcc/testsuite/jit.dg/test-fuzzer.c b/gcc/testsuite/jit.dg/test-fuzzer.c
new file mode 100644 (file)
index 0000000..f363f8f
--- /dev/null
@@ -0,0 +1,462 @@
+/* Fuzz-testing of libgccjit API.
+   Currently this triggers internal compiler errors, typically due to type
+   mismatches.  */
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+
+#include "libgccjit.h"
+
+#define TEST_PROVIDES_MAIN
+#include "harness.h"
+
+typedef struct fuzzer
+{
+  gcc_jit_context *ctxt;
+
+  unsigned int seed;
+
+  int num_types;
+  gcc_jit_type **types;
+
+  int num_globals;
+  gcc_jit_lvalue **globals;
+
+  int num_funcs;
+  gcc_jit_function **funcs;
+
+} fuzzer;
+
+static void
+fuzzer_init (fuzzer *f, gcc_jit_context *ctxt, unsigned int seed);
+
+static int
+fuzzer_randrange (fuzzer *f, int min, int max);
+
+static gcc_jit_location *
+get_random_location (fuzzer *f);
+
+static gcc_jit_type *
+get_random_type (fuzzer *f);
+
+static gcc_jit_type *
+make_random_type (fuzzer *f);
+
+static gcc_jit_lvalue *
+make_random_global (fuzzer *f);
+
+static gcc_jit_function *
+make_random_function (fuzzer *f);
+
+typedef struct function_fuzzer
+{
+  fuzzer *f;
+
+  int num_params;
+  gcc_jit_param **params;
+
+  gcc_jit_function *fn;
+
+  int num_locals;
+  gcc_jit_lvalue **locals;
+
+  gcc_jit_block *block;
+
+} function_fuzzer;
+
+static void
+function_fuzzer_add_stmt (function_fuzzer *ff);
+
+static gcc_jit_lvalue *
+get_random_lvalue (function_fuzzer *ff, int max_depth);
+
+static gcc_jit_rvalue *
+get_random_rvalue (function_fuzzer *ff, int max_depth);
+
+/* fuzzer defns.  */
+
+static void
+fuzzer_init (fuzzer *f, gcc_jit_context *ctxt, unsigned int seed)
+{
+  int i;
+  memset (f, 0, sizeof (*f));
+  f->ctxt = ctxt;
+  f->seed = seed;
+
+  int num_types = fuzzer_randrange (f, 5, 10);
+  f->types = malloc (num_types * sizeof (gcc_jit_type *));
+
+  int num_funcs = fuzzer_randrange (f, 3, 5);
+  f->funcs = malloc (num_funcs * sizeof (gcc_jit_function *));
+
+  int num_globals = fuzzer_randrange (f, 5, 10);
+  f->globals = malloc (num_globals * sizeof (gcc_jit_lvalue *));
+
+  for (i = 0; i < num_types; i++)
+    {
+      gcc_jit_type *type = make_random_type (f);
+      assert (type);
+      f->types[f->num_types++] = type;
+    }
+
+  for (i = 0; i < num_globals; i++)
+    f->globals[f->num_globals++] = make_random_global (f);
+
+  for (i = 0; i < num_funcs; i++)
+    f->funcs[f->num_funcs++] = make_random_function (f);
+}
+
+/* Get random int in inclusive range [min, max].  */
+
+static int fuzzer_randrange (fuzzer *f, int min, int max)
+{
+  assert (min <= max);
+  int i = rand_r (&f->seed);
+  int result = (i % (max + 1 - min)) + min;
+  assert (result >= min);
+  assert (result <= max);
+  return result;
+}
+
+static gcc_jit_location *
+get_random_location (fuzzer *f)
+{
+  const char *filename = NULL;
+
+  if (fuzzer_randrange (f, 0, 1))
+    return NULL;
+
+  switch (fuzzer_randrange (f, 1, 2))
+    {
+    case 1:
+      filename = "foo.c";
+      break;
+    case 2:
+      filename = "bar.c";
+      break;
+    }
+
+  return gcc_jit_context_new_location (f->ctxt,
+                                      filename,
+                                      fuzzer_randrange (f, 1, 1000),
+                                      fuzzer_randrange (f, 1, 1000));
+}
+
+const enum gcc_jit_types types[] = {
+  GCC_JIT_TYPE_VOID,
+
+  GCC_JIT_TYPE_VOID_PTR,
+
+  GCC_JIT_TYPE_CHAR,
+  GCC_JIT_TYPE_SIGNED_CHAR,
+  GCC_JIT_TYPE_UNSIGNED_CHAR,
+
+  GCC_JIT_TYPE_SHORT,
+  GCC_JIT_TYPE_UNSIGNED_SHORT,
+
+  GCC_JIT_TYPE_INT,
+  GCC_JIT_TYPE_UNSIGNED_INT,
+
+  GCC_JIT_TYPE_LONG,
+  GCC_JIT_TYPE_UNSIGNED_LONG,
+
+  GCC_JIT_TYPE_LONG_LONG,
+  GCC_JIT_TYPE_UNSIGNED_LONG_LONG,
+
+  GCC_JIT_TYPE_FLOAT,
+  GCC_JIT_TYPE_DOUBLE,
+  GCC_JIT_TYPE_LONG_DOUBLE,
+
+  GCC_JIT_TYPE_CONST_CHAR_PTR,
+
+  GCC_JIT_TYPE_SIZE_T,
+
+  GCC_JIT_TYPE_FILE_PTR
+};
+#define NUM_TYPES (sizeof(types)/sizeof(types[0]))
+
+static gcc_jit_type *
+get_random_type (fuzzer *f)
+{
+  int i = fuzzer_randrange (f, 0, (NUM_TYPES - 1) + f->num_types);
+  if (i < NUM_TYPES)
+    return gcc_jit_context_get_type (f->ctxt, types[i]);
+  assert ((i - NUM_TYPES) < f->num_types);
+  assert (f->types[i - NUM_TYPES]);
+  return f->types[i - NUM_TYPES];
+}
+
+static gcc_jit_type *
+make_random_type (fuzzer *f)
+{
+  switch (fuzzer_randrange (f, 0, 5))
+    {
+    case 0:
+      return gcc_jit_type_get_pointer (get_random_type (f));
+    case 1:
+      return gcc_jit_type_get_const (get_random_type (f));
+    default:
+      {
+       /* Create a struct.  */
+       int num_fields = fuzzer_randrange (f, 0, 10);
+       gcc_jit_field **fields = \
+         malloc (num_fields * sizeof (gcc_jit_field *));
+       int i;
+       for (i = 0; i < num_fields ; i++)
+         {
+           char field_name[256];
+           sprintf (field_name, "field%i", i);
+           fields[i] = gcc_jit_context_new_field (f->ctxt,
+                                                  get_random_location (f),
+                                                  get_random_type (f),
+                                                  field_name);
+         }
+       char struct_name[256];
+       sprintf (struct_name, "s%i", f->num_types);
+       gcc_jit_struct *struct_ = \
+         gcc_jit_context_new_struct_type (f->ctxt,
+                                          get_random_location (f),
+                                          struct_name,
+                                          num_fields,
+                                          fields);
+       free (fields);
+       return gcc_jit_struct_as_type (struct_);
+      }
+    }
+}
+
+static gcc_jit_lvalue *
+make_random_global (fuzzer *f)
+{
+  char global_name[256];
+  sprintf (global_name, "g%i", f->num_globals);
+  return gcc_jit_context_new_global (f->ctxt,
+                                    get_random_location (f),
+                                    get_random_type (f),
+                                    global_name);
+}
+
+static gcc_jit_function *
+make_random_function (fuzzer *f)
+{
+  char func_name[256];
+  sprintf (func_name, "fn%i", f->num_funcs);
+
+  function_fuzzer *ff = malloc (sizeof (function_fuzzer));
+  memset (ff, 0, sizeof (*ff));
+
+  ff->f = f;
+
+  ff->num_params = fuzzer_randrange (f, 0, 10);
+  ff->params = malloc (ff->num_params * sizeof (gcc_jit_param *));
+  int i;
+  for (i = 0; i < ff->num_params; i++)
+    {
+      char param_name[256];
+      sprintf (param_name, "param%i", i);
+      ff->params[i] = \
+       gcc_jit_context_new_param (f->ctxt,
+                                  get_random_location (f),
+                                  get_random_type (f),
+                                  param_name);
+    }
+
+  enum gcc_jit_function_kind kind =
+    ((enum gcc_jit_function_kind)
+     fuzzer_randrange (f, 0, GCC_JIT_FUNCTION_IMPORTED));
+
+  ff->fn = \
+    gcc_jit_context_new_function (
+      f->ctxt,
+      get_random_location (f),
+      kind,
+      get_random_type (f),
+      func_name,
+      ff->num_params,
+      ff->params,
+      fuzzer_randrange (f, 0, 1));
+  ff->block = gcc_jit_function_new_block (ff->fn, NULL);
+
+  /* Create locals.  */
+  if (kind != GCC_JIT_FUNCTION_IMPORTED)
+    {
+      ff->num_locals = fuzzer_randrange (f, 0, 10);
+      ff->locals = malloc (ff->num_locals * sizeof (gcc_jit_lvalue *));
+      for (i = 0; i < ff->num_locals; i++)
+       {
+         char local_name[256];
+         sprintf (local_name, "local%i", i);
+         ff->locals[i] =
+           gcc_jit_function_new_local (ff->fn,
+                                       get_random_location (f),
+                                       get_random_type (f),
+                                       local_name);
+       }
+    }
+  /* TODO: use locals.  */
+
+  if (kind != GCC_JIT_FUNCTION_IMPORTED)
+    {
+      /* TODO: create body */
+      int num_stmts = fuzzer_randrange (f, 0, 10);
+      for (i = 0; i < num_stmts; i++)
+       function_fuzzer_add_stmt (ff);
+    }
+
+  gcc_jit_block_end_with_return (ff->block, NULL, get_random_rvalue (ff, 3));
+
+
+  gcc_jit_function *result = ff->fn;
+
+  free (ff->params);
+  free (ff);
+
+  return result;
+}
+
+/* function_fuzzer defns.  */
+
+static void function_fuzzer_add_stmt (function_fuzzer *ff)
+{
+  gcc_jit_block_add_eval (ff->block,
+                         get_random_location (ff->f),
+                         get_random_rvalue (ff, 4));
+  gcc_jit_block_add_assignment (ff->block,
+                               get_random_location (ff->f),
+                               get_random_lvalue (ff, 4),
+                               get_random_rvalue (ff, 4));
+  /* TODO: place more kinds of statement */
+  /* TODO: labels  */
+}
+
+static gcc_jit_lvalue *get_random_lvalue (function_fuzzer *ff, int max_depth)
+{
+  int choice = fuzzer_randrange (ff->f, 0,
+                                ff->num_params
+                                + ff->num_locals
+                                + ff->f->num_globals - 1);
+  if (choice < ff->num_params)
+    return gcc_jit_param_as_lvalue (ff->params[choice]);
+  choice -= ff->num_params;
+
+  if (choice < ff->num_locals)
+    return ff->locals[choice];
+  choice -= ff->num_locals;
+
+  assert (choice < ff->f->num_globals);
+  return ff->f->globals[choice];
+}
+
+static gcc_jit_rvalue *get_random_rvalue (function_fuzzer *ff, int max_depth)
+{
+  int use_lvalue = fuzzer_randrange (ff->f, 0, 1);
+  if (use_lvalue)
+    return gcc_jit_lvalue_as_rvalue (get_random_lvalue (ff, max_depth));
+
+  int choice = fuzzer_randrange (ff->f, 0, 1);
+
+  /* Compound op: */
+  switch (choice)
+    {
+    case 0:
+      return gcc_jit_context_new_string_literal (ff->f->ctxt, "hello");
+    case 1:
+      return gcc_jit_context_new_rvalue_from_int (
+       ff->f->ctxt,
+       get_random_type (ff->f),
+       fuzzer_randrange (ff->f, 0, INT_MAX));
+    case 2:
+      return gcc_jit_context_new_rvalue_from_double (
+       ff->f->ctxt,
+       get_random_type (ff->f),
+       ((double)fuzzer_randrange (ff->f, 0, INT_MAX))
+        / (double)fuzzer_randrange (ff->f, 0, INT_MAX));
+    case 3:
+      return gcc_jit_context_new_unary_op (
+       ff->f->ctxt,
+       get_random_location (ff->f),
+       ((enum gcc_jit_unary_op)
+        fuzzer_randrange (ff->f, 0, GCC_JIT_UNARY_OP_LOGICAL_NEGATE)),
+       get_random_type (ff->f),
+       get_random_rvalue (ff, max_depth - 1));
+    case 4:
+      return gcc_jit_context_new_binary_op (
+       ff->f->ctxt,
+       get_random_location (ff->f),
+       ((enum gcc_jit_binary_op)
+        fuzzer_randrange (ff->f, 0, GCC_JIT_BINARY_OP_LOGICAL_OR)),
+       get_random_type (ff->f),
+       get_random_rvalue (ff, max_depth - 1),
+       get_random_rvalue (ff, max_depth - 1));
+    case 5:
+      return gcc_jit_lvalue_get_address (
+       get_random_lvalue (ff, max_depth - 1),
+       get_random_location (ff->f));
+
+      /* TODO:
+        - comparisons
+        - calls
+        - array lookup
+        - fields
+        - dereferencing */
+    }
+  return NULL;
+}
+
+
+/* Top-level defns for use by harness. */
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  fuzzer f;
+  int seed = *(int*)user_data;
+
+  fuzzer_init (&f, ctxt, seed);
+}
+
+static int num_completed_compilations = 0;
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  /* We can make no guarantees about whether we built something
+     valid or not, and the result might have an infinite loop,
+     so we can't execute it.
+
+     If we survive to reach here, note the fact for DejaGnu.  */
+  pass ("%s: survived compilation", test);
+  if (result)
+    num_completed_compilations++;
+}
+
+static void
+test_fuzzer (const char *argv0, int seed)
+{
+  test_jit (argv0, &seed);
+}
+
+int
+main (int argc, char **argv)
+{
+  int i, seed;
+  const int NUM_ITERATIONS = 2;
+  const int NUM_SEEDS = 100;
+  for (i = 1; i <= NUM_ITERATIONS; i++)
+    {
+      for (seed = 0; seed < NUM_SEEDS ; seed++)
+       {
+         snprintf (test, sizeof (test),
+                   "%s iteration %d of %d; seed %d of %d",
+                   extract_progname (argv[0]),
+                   i, NUM_ITERATIONS, seed, NUM_SEEDS);
+         test_fuzzer (argv[0], seed);
+       }
+    }
+  pass ("%s: survived running all tests", extract_progname (argv[0]));
+  note ("%s: num completed compilations: %d", extract_progname (argv[0]),
+       num_completed_compilations);
+  totals ();
+
+  return 0;
+}
diff --git a/gcc/testsuite/jit.dg/test-hello-world.c b/gcc/testsuite/jit.dg/test-hello-world.c
new file mode 100644 (file)
index 0000000..93f737b
--- /dev/null
@@ -0,0 +1,72 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  /* Let's try to inject the equivalent of:
+     void
+     hello_world (const char *name)
+     {
+        // a test comment
+        printf ("hello %s\n", name);
+     }
+  */
+  gcc_jit_type *void_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+  gcc_jit_type *const_char_ptr_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_CONST_CHAR_PTR);
+  gcc_jit_param *param_name =
+    gcc_jit_context_new_param (ctxt, NULL, const_char_ptr_type, "name");
+  gcc_jit_function *func =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                  GCC_JIT_FUNCTION_EXPORTED,
+                                  void_type,
+                                  "hello_world",
+                                  1, &param_name,
+                                  0);
+
+  gcc_jit_param *param_format =
+    gcc_jit_context_new_param (ctxt, NULL, const_char_ptr_type, "format");
+  gcc_jit_function *printf_func =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                 GCC_JIT_FUNCTION_IMPORTED,
+                                 gcc_jit_context_get_type (
+                                    ctxt, GCC_JIT_TYPE_INT),
+                                 "printf",
+                                 1, &param_format,
+                                 1);
+  gcc_jit_rvalue *args[2];
+  args[0] = gcc_jit_context_new_string_literal (ctxt, "hello %s\n");
+  args[1] = gcc_jit_param_as_rvalue (param_name);
+
+  gcc_jit_block *block = gcc_jit_function_new_block (func, NULL);
+
+  gcc_jit_block_add_comment (
+    block, NULL,
+    "a test comment");
+
+  gcc_jit_block_add_eval (
+    block, NULL,
+    gcc_jit_context_new_call (ctxt,
+                              NULL,
+                              printf_func,
+                              2, args));
+  gcc_jit_block_end_with_void_return (block, NULL);
+}
+
+extern void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  typedef void (*fn_type) (const char *);
+  CHECK_NON_NULL (result);
+  fn_type hello_world =
+    (fn_type)gcc_jit_result_get_code (result, "hello_world");
+  CHECK_NON_NULL (hello_world);
+  hello_world ("world");
+  fflush (stdout);
+}
diff --git a/gcc/testsuite/jit.dg/test-linked-list.c b/gcc/testsuite/jit.dg/test-linked-list.c
new file mode 100644 (file)
index 0000000..28871d9
--- /dev/null
@@ -0,0 +1,141 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+/* A doubly-linked list, to ensure that the JIT API can cope with
+   self-referential types.  */
+struct node
+{
+  struct node *prev;
+  struct node *next;
+  int value;
+};
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  /* Let's try to inject the equivalent of:
+     int
+     test_linked_list (struct node *n)
+     {
+       int total = 0;
+       while (n)
+         {
+           total += n->value;
+           n = n->next;
+         }
+       return total;
+     }
+  */
+  gcc_jit_type *t_int =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+  gcc_jit_struct *t_node =
+    gcc_jit_context_new_opaque_struct (ctxt, NULL, "node");
+  gcc_jit_type *t_node_ptr =
+    gcc_jit_type_get_pointer (gcc_jit_struct_as_type (t_node));
+
+  gcc_jit_field *f_prev =
+    gcc_jit_context_new_field (ctxt, NULL, t_node_ptr, "prev");
+  gcc_jit_field *f_next =
+    gcc_jit_context_new_field (ctxt, NULL, t_node_ptr, "next");
+  gcc_jit_field *f_value =
+    gcc_jit_context_new_field (ctxt, NULL, t_int, "value");
+  gcc_jit_field *fields[] = {f_prev, f_next, f_value};
+  gcc_jit_struct_set_fields (t_node, NULL, 3, fields);
+
+  /* Build the test function.  */
+  gcc_jit_param *param_n =
+    gcc_jit_context_new_param (ctxt, NULL, t_node_ptr, "n");
+  gcc_jit_function *fn =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                 GCC_JIT_FUNCTION_EXPORTED,
+                                 t_int,
+                                 "test_linked_list",
+                                 1, &param_n,
+                                 0);
+  /* int total; */
+  gcc_jit_lvalue *total =
+    gcc_jit_function_new_local (fn, NULL, t_int, "total");
+
+  gcc_jit_block *initial = gcc_jit_function_new_block (fn, "initial");
+  gcc_jit_block *loop_test = gcc_jit_function_new_block (fn, "loop_test");
+  gcc_jit_block *loop_body = gcc_jit_function_new_block (fn, "loop_body");
+  gcc_jit_block *final = gcc_jit_function_new_block (fn, "final");
+
+  /* total = 0; */
+  gcc_jit_block_add_assignment (
+    initial, NULL,
+    total,
+    gcc_jit_context_zero (ctxt, t_int));
+  gcc_jit_block_end_with_jump (initial, NULL, loop_test);
+
+  /* while (n) */
+  gcc_jit_block_end_with_conditional (
+    loop_test, NULL,
+    gcc_jit_context_new_comparison (ctxt, NULL,
+                                   GCC_JIT_COMPARISON_NE,
+                                   gcc_jit_param_as_rvalue (param_n),
+                                   gcc_jit_context_null (ctxt, t_node_ptr)),
+    loop_body,
+    final);
+
+  /* total += n->value; */
+  gcc_jit_block_add_assignment_op (
+    loop_body, NULL,
+    total,
+    GCC_JIT_BINARY_OP_PLUS,
+    gcc_jit_lvalue_as_rvalue (
+      gcc_jit_rvalue_dereference_field (
+       gcc_jit_param_as_rvalue (param_n),
+       NULL,
+       f_value)));
+
+  /* n = n->next; */
+  gcc_jit_block_add_assignment (
+    loop_body, NULL,
+    gcc_jit_param_as_lvalue (param_n),
+    gcc_jit_lvalue_as_rvalue (
+      gcc_jit_rvalue_dereference_field (
+       gcc_jit_param_as_rvalue (param_n),
+       NULL,
+       f_next)));
+
+  gcc_jit_block_end_with_jump (loop_body, NULL, loop_test);
+
+  /* return total; */
+  gcc_jit_block_end_with_return (
+    final, NULL, gcc_jit_lvalue_as_rvalue (total));
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  struct node a, b, c;
+  typedef int (*fn_type) (struct node *n);
+  CHECK_NON_NULL (result);
+
+  fn_type test_linked_list =
+    (fn_type)gcc_jit_result_get_code (result, "test_linked_list");
+  CHECK_NON_NULL (test_linked_list);
+
+  /* Construct a simple linked-list on the stack: a->b->c: */
+  a.prev = NULL;
+  a.next = &b;
+  a.value = 5;
+
+  b.prev = &a;
+  b.next = &c;
+  b.value = 3;
+
+  c.prev = &b;
+  c.next = NULL;
+  c.value = 7;
+
+  CHECK_VALUE (test_linked_list (NULL), 0);
+  CHECK_VALUE (test_linked_list (&a), 15);
+  CHECK_VALUE (test_linked_list (&b), 10);
+  CHECK_VALUE (test_linked_list (&c), 7);
+}
diff --git a/gcc/testsuite/jit.dg/test-long-names.c b/gcc/testsuite/jit.dg/test-long-names.c
new file mode 100644 (file)
index 0000000..0fc7e67
--- /dev/null
@@ -0,0 +1,112 @@
+/* Test of using the API with very long names.  */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+/* 65KB */
+#define NAME_LENGTH (65 * 1024)
+
+static struct long_names
+{
+  char struct_name[NAME_LENGTH];
+  char fn_name[NAME_LENGTH];
+  char local_name[NAME_LENGTH];
+  char block_name[NAME_LENGTH];
+} long_names;
+
+static void
+populate_name (const char *prefix, char *buffer)
+{
+  int i;
+
+  /* Begin with the given prefix: */
+  sprintf (buffer, prefix);
+
+  /* Populate the rest of the buffer with 0123456789 repeatedly: */
+  for (i = strlen (prefix); i < NAME_LENGTH - 1; i++)
+    buffer[i] = '0' + (i % 10);
+
+  /* NIL-terminate the buffer: */
+  buffer[NAME_LENGTH - 1] = '\0';
+}
+
+static void
+populate_names (void)
+{
+  populate_name ("struct_", long_names.struct_name);
+  populate_name ("test_fn_", long_names.fn_name);
+  populate_name ("local_", long_names.local_name);
+  populate_name ("block_", long_names.block_name);
+}
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  /* Where "ETC" is a very long suffix, let's try to inject the
+     equivalent of:
+
+       struct struct_ETC;
+
+       int
+       test_fn_ETC ()
+       {
+         int local_ETC;
+         local_ETC = 42;
+         return local_ETC;
+       }
+
+     to verify that the API copes with such long names.  */
+
+  populate_names ();
+
+  gcc_jit_type *int_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+  /* We don't yet use this struct.  */
+  (void)gcc_jit_context_new_opaque_struct (ctxt, NULL,
+                                          long_names.struct_name);
+
+  gcc_jit_function *test_fn =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                 GCC_JIT_FUNCTION_EXPORTED,
+                                 int_type,
+                                 long_names.fn_name,
+                                 0, NULL,
+                                 0);
+  gcc_jit_lvalue *local =
+    gcc_jit_function_new_local (test_fn,
+                               NULL,
+                               int_type,
+                               long_names.local_name);
+
+  gcc_jit_block *block =
+    gcc_jit_function_new_block (test_fn, long_names.block_name);
+
+  gcc_jit_block_add_assignment (
+    block,
+    NULL,
+    local,
+    gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 42));
+
+  gcc_jit_block_end_with_return (
+    block, NULL,
+    gcc_jit_lvalue_as_rvalue (local));
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  CHECK_NON_NULL (result);
+
+  typedef int (*my_fn_type) (void);
+  CHECK_NON_NULL (result);
+  my_fn_type my_fn =
+    (my_fn_type)gcc_jit_result_get_code (result, long_names.fn_name);
+  CHECK_NON_NULL (my_fn);
+  int val = my_fn ();
+  CHECK_VALUE (val, 42);
+}
diff --git a/gcc/testsuite/jit.dg/test-nested-contexts.c b/gcc/testsuite/jit.dg/test-nested-contexts.c
new file mode 100644 (file)
index 0000000..16bc63f
--- /dev/null
@@ -0,0 +1,641 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#define TEST_ESCHEWS_TEST_JIT
+#define TEST_PROVIDES_MAIN
+#include "harness.h"
+
+struct quadratic
+{
+  double a;
+  double b;
+  double c;
+  double discriminant;
+};
+
+/* This is an adapted version of test-quadratic.c
+
+   Like that test, we'll try to inject the following code, but we'll
+   split it up into some nested contexts, in 3 levels, to test
+   how nested contexts work.
+
+   ***** In top-level context: *****
+
+     (shared type declarations, for int, double, struct quadratic);
+     extern double sqrt (double);
+
+   ***** In mid-level context: *****
+
+     void
+     calc_discriminant (struct quadratic *q)
+     {
+       // (b^2 - 4ac)
+       q->discriminant = (q->b * q->b) - (4 * q->a * q->c);
+     }
+
+   ***** In bottom context: *****
+
+     int
+     test_quadratic (double a, double b, double c, double *r1, double *r2)
+     {
+       struct quadratic q;
+       q.a = a;
+       q.b = b;
+       q.c = c;
+       calc_discriminant (&q);
+       if (q.discriminant > 0)
+        {
+           double s = sqrt (q.discriminant);
+           *r1 = (-b + s) / (2 * a);
+           *r2 = (-b - s) / (2 * a);
+           return 2;
+        }
+       else if (q.discriminant == 0)
+        {
+           *r1 = -b / (2 * a);
+           return 1;
+        }
+        else return 0;
+     }
+*/
+
+struct top_level
+{
+  gcc_jit_context *ctxt;
+
+  /* "double" and "(double *)".  */
+  gcc_jit_type *numeric_type;
+  gcc_jit_type *numeric_type_ptr;
+
+  /* The value (double)0.  */
+  gcc_jit_rvalue *zero;
+
+  gcc_jit_type *int_type;
+  gcc_jit_type *void_type;
+
+  /* "struct quadratic" */
+  gcc_jit_type *struct_quadratic;
+  gcc_jit_field *a;
+  gcc_jit_field *b;
+  gcc_jit_field *c;
+  gcc_jit_field *discriminant;
+
+  /* "(struct quadratic *)" */
+  gcc_jit_type *quadratic_ptr;
+
+  gcc_jit_function *sqrt;
+};
+
+struct middle_level
+{
+  gcc_jit_context *ctxt;
+  gcc_jit_function *calc_discriminant;
+};
+
+struct bottom_level
+{
+  gcc_jit_context *ctxt;
+};
+
+static void
+make_types (struct top_level *top_level)
+{
+  top_level->numeric_type =
+    gcc_jit_context_get_type (top_level->ctxt, GCC_JIT_TYPE_DOUBLE);
+  top_level->numeric_type_ptr =
+    gcc_jit_type_get_pointer (top_level->numeric_type);
+  top_level->zero =
+    gcc_jit_context_zero (top_level->ctxt, top_level->numeric_type);
+
+  top_level->int_type =
+    gcc_jit_context_get_type (top_level->ctxt, GCC_JIT_TYPE_INT);
+  top_level->void_type =
+    gcc_jit_context_get_type (top_level->ctxt, GCC_JIT_TYPE_VOID);
+
+  top_level->a =
+    gcc_jit_context_new_field (top_level->ctxt,
+                              NULL,
+                              top_level->numeric_type,
+                              "a");
+  top_level->b =
+    gcc_jit_context_new_field (top_level->ctxt,
+                              NULL,
+                              top_level->numeric_type,
+                              "b");
+  top_level->c =
+    gcc_jit_context_new_field (top_level->ctxt,
+                              NULL,
+                              top_level->numeric_type,
+                              "c");
+  top_level->discriminant =
+    gcc_jit_context_new_field (top_level->ctxt,
+                              NULL,
+                              top_level->numeric_type,
+                              "discriminant");
+  gcc_jit_field *fields[] = {top_level->a,
+                            top_level->b,
+                            top_level->c,
+                            top_level->discriminant};
+  top_level->struct_quadratic =
+    gcc_jit_struct_as_type (
+      gcc_jit_context_new_struct_type (top_level->ctxt, NULL,
+                                      "quadratic", 4, fields));
+  top_level->quadratic_ptr =
+    gcc_jit_type_get_pointer (top_level->struct_quadratic);
+}
+
+static void
+make_sqrt (struct top_level *top_level)
+{
+  gcc_jit_param *param_x =
+    gcc_jit_context_new_param (top_level->ctxt, NULL,
+                              top_level->numeric_type, "x");
+  top_level->sqrt =
+    gcc_jit_context_new_function (top_level->ctxt, NULL,
+                                 GCC_JIT_FUNCTION_IMPORTED,
+                                 top_level->numeric_type,
+                                 "sqrt",
+                                 1, &param_x,
+                                 0);
+}
+
+static void
+make_calc_discriminant (struct top_level *top_level,
+                       struct middle_level *middle_level)
+{
+  /* Build "calc_discriminant".  */
+  gcc_jit_param *param_q =
+    gcc_jit_context_new_param (middle_level->ctxt, NULL,
+                              top_level->quadratic_ptr, "q");
+  middle_level->calc_discriminant =
+    gcc_jit_context_new_function (middle_level->ctxt, NULL,
+                                 GCC_JIT_FUNCTION_EXPORTED,
+                                 top_level->void_type,
+                                 "calc_discriminant",
+                                 1, &param_q,
+                                 0);
+  gcc_jit_block *blk =
+    gcc_jit_function_new_block (middle_level->calc_discriminant, NULL);
+  gcc_jit_block_add_comment (
+    blk, NULL,
+    "(b^2 - 4ac)");
+
+  gcc_jit_rvalue *q_a =
+    gcc_jit_lvalue_as_rvalue (
+       gcc_jit_rvalue_dereference_field (
+         gcc_jit_param_as_rvalue (param_q),
+         NULL, top_level->a));
+  gcc_jit_rvalue *q_b =
+    gcc_jit_lvalue_as_rvalue (
+       gcc_jit_rvalue_dereference_field (
+         gcc_jit_param_as_rvalue (param_q),
+         NULL, top_level->b));
+  gcc_jit_rvalue *q_c =
+    gcc_jit_lvalue_as_rvalue (
+       gcc_jit_rvalue_dereference_field (
+         gcc_jit_param_as_rvalue (param_q),
+         NULL, top_level->c));
+
+  gcc_jit_block_add_assignment (
+    blk, NULL,
+
+    /* q->discriminant =...  */
+    gcc_jit_rvalue_dereference_field (
+      gcc_jit_param_as_rvalue (param_q),
+      NULL,
+      top_level->discriminant),
+
+    /* (q->b * q->b) - (4 * q->a * q->c) */
+    gcc_jit_context_new_binary_op (
+      middle_level->ctxt, NULL,
+      GCC_JIT_BINARY_OP_MINUS,
+      top_level->numeric_type,
+
+      /* (q->b * q->b) */
+      gcc_jit_context_new_binary_op (
+       middle_level->ctxt, NULL,
+       GCC_JIT_BINARY_OP_MULT,
+       top_level->numeric_type,
+       q_b, q_b),
+
+      /* (4 * (q->a * q->c)) */
+      gcc_jit_context_new_binary_op (
+       middle_level->ctxt, NULL,
+       GCC_JIT_BINARY_OP_MULT,
+       top_level->numeric_type,
+       /* 4.0 */
+       gcc_jit_context_new_rvalue_from_int (
+         middle_level->ctxt,
+         top_level->numeric_type,
+         4),
+       /* (q->a * q->c) */
+       gcc_jit_context_new_binary_op (
+         middle_level->ctxt, NULL,
+         GCC_JIT_BINARY_OP_MULT,
+         top_level->numeric_type,
+         q_a, q_c)))); /* end of gcc_jit_function_add_assignment call.  */
+
+  gcc_jit_block_end_with_void_return (blk, NULL);
+}
+
+static void
+make_test_quadratic (struct top_level *top_level,
+                    struct middle_level *middle_level,
+                    struct bottom_level *bottom_level)
+{
+  gcc_jit_param *a =
+    gcc_jit_context_new_param (bottom_level->ctxt, NULL,
+                              top_level->numeric_type, "a");
+  gcc_jit_param *b =
+    gcc_jit_context_new_param (bottom_level->ctxt, NULL,
+                              top_level->numeric_type, "b");
+  gcc_jit_param *c =
+    gcc_jit_context_new_param (bottom_level->ctxt, NULL,
+                              top_level->numeric_type, "c");
+  gcc_jit_param *r1 =
+    gcc_jit_context_new_param (bottom_level->ctxt, NULL,
+                              top_level->numeric_type_ptr, "r1");
+  gcc_jit_param *r2 =
+    gcc_jit_context_new_param (bottom_level->ctxt, NULL,
+                              top_level->numeric_type_ptr, "r2");
+  gcc_jit_param *params[] = {a, b, c, r1, r2};
+  gcc_jit_function *test_quadratic =
+    gcc_jit_context_new_function (bottom_level->ctxt, NULL,
+                                 GCC_JIT_FUNCTION_EXPORTED,
+                                 top_level->int_type,
+                                 "test_quadratic",
+                                 5, params,
+                                 0);
+
+  /* struct quadratic q; */
+  gcc_jit_lvalue *q =
+    gcc_jit_function_new_local (
+      test_quadratic, NULL,
+      top_level->struct_quadratic,
+      "q");
+
+  gcc_jit_block *initial =
+    gcc_jit_function_new_block (test_quadratic,
+                               "initial");
+  gcc_jit_block *on_positive_discriminant
+    = gcc_jit_function_new_block (test_quadratic,
+                                 "positive_discriminant");
+
+  gcc_jit_block *on_nonpositive_discriminant
+    = gcc_jit_function_new_block (test_quadratic,
+                                 "nonpositive_discriminant");
+
+  gcc_jit_block *on_zero_discriminant
+    = gcc_jit_function_new_block (test_quadratic,
+                                 "zero_discriminant");
+
+  gcc_jit_block *on_negative_discriminant
+    = gcc_jit_function_new_block (test_quadratic,
+                                 "negative_discriminant");
+
+  /* Initial block.  */
+  /* q.a = a; */
+  gcc_jit_block_add_assignment (
+    initial, NULL,
+    gcc_jit_lvalue_access_field (q, NULL, top_level->a),
+    gcc_jit_param_as_rvalue (a));
+  /* q.b = b; */
+  gcc_jit_block_add_assignment (
+    initial, NULL,
+    gcc_jit_lvalue_access_field (q, NULL, top_level->b),
+    gcc_jit_param_as_rvalue (b));
+  /* q.c = c; */
+  gcc_jit_block_add_assignment (
+    initial, NULL,
+    gcc_jit_lvalue_access_field (q, NULL, top_level->c),
+    gcc_jit_param_as_rvalue (c));
+  /* calc_discriminant (&q); */
+  gcc_jit_rvalue *address_of_q = gcc_jit_lvalue_get_address (q, NULL);
+  gcc_jit_block_add_eval (
+    initial, NULL,
+    gcc_jit_context_new_call (
+      bottom_level->ctxt, NULL,
+      middle_level->calc_discriminant,
+      1, &address_of_q));
+
+  gcc_jit_block_add_comment (
+    initial, NULL,
+    "if (q.discriminant > 0)");
+  gcc_jit_block_end_with_conditional (
+    initial, NULL,
+    gcc_jit_context_new_comparison (
+      bottom_level->ctxt, NULL,
+      GCC_JIT_COMPARISON_GT,
+      gcc_jit_rvalue_access_field (
+       gcc_jit_lvalue_as_rvalue (q),
+       NULL,
+       top_level->discriminant),
+      top_level->zero),
+    on_positive_discriminant,
+    on_nonpositive_discriminant);
+
+  /* Block: "on_positive_discriminant" */
+  /* double s = sqrt (q.discriminant); */
+  gcc_jit_lvalue *s = gcc_jit_function_new_local (
+    test_quadratic, NULL,
+    top_level->numeric_type,
+    "s");
+  gcc_jit_rvalue *discriminant_of_q =
+    gcc_jit_rvalue_access_field (gcc_jit_lvalue_as_rvalue (q),
+                                NULL,
+                                top_level->discriminant);
+  gcc_jit_block_add_assignment (
+    on_positive_discriminant, NULL,
+    s,
+    gcc_jit_context_new_call (
+      bottom_level->ctxt, NULL,
+      top_level->sqrt,
+      1, &discriminant_of_q));
+
+  gcc_jit_rvalue *minus_b =
+    gcc_jit_context_new_unary_op (
+      bottom_level->ctxt, NULL,
+      GCC_JIT_UNARY_OP_MINUS,
+      top_level->numeric_type,
+      gcc_jit_param_as_rvalue (b));
+  gcc_jit_rvalue *two_a =
+    gcc_jit_context_new_binary_op (
+      bottom_level->ctxt, NULL,
+      GCC_JIT_BINARY_OP_MULT,
+      top_level->numeric_type,
+      gcc_jit_context_new_rvalue_from_int (
+       bottom_level->ctxt,
+       top_level->numeric_type,
+       2),
+      gcc_jit_param_as_rvalue (a));
+
+  gcc_jit_block_add_comment (
+    on_positive_discriminant, NULL,
+    "*r1 = (-b + s) / (2 * a);");
+  gcc_jit_block_add_assignment (
+    on_positive_discriminant, NULL,
+
+    /* "*r1 = ..." */
+    gcc_jit_rvalue_dereference (
+      gcc_jit_param_as_rvalue (r1), NULL),
+
+    /* (-b + s) / (2 * a) */
+    gcc_jit_context_new_binary_op (
+      bottom_level->ctxt, NULL,
+      GCC_JIT_BINARY_OP_DIVIDE,
+      top_level->numeric_type,
+      gcc_jit_context_new_binary_op (
+       bottom_level->ctxt, NULL,
+       GCC_JIT_BINARY_OP_PLUS,
+       top_level->numeric_type,
+       minus_b,
+       gcc_jit_lvalue_as_rvalue (s)),
+      two_a));
+
+  gcc_jit_block_add_comment (
+    on_positive_discriminant, NULL,
+    "*r2 = (-b - s) / (2 * a)");
+  gcc_jit_block_add_assignment (
+    on_positive_discriminant, NULL,
+
+    /* "*r2 = ..." */
+    gcc_jit_rvalue_dereference (
+      gcc_jit_param_as_rvalue (r2), NULL),
+
+    /* (-b - s) / (2 * a) */
+    gcc_jit_context_new_binary_op (
+      bottom_level->ctxt, NULL,
+      GCC_JIT_BINARY_OP_DIVIDE,
+      top_level->numeric_type,
+      gcc_jit_context_new_binary_op (
+       bottom_level->ctxt, NULL,
+       GCC_JIT_BINARY_OP_MINUS,
+       top_level->numeric_type,
+       minus_b,
+       gcc_jit_lvalue_as_rvalue (s)),
+      two_a));
+
+  /* "return 2;" */
+  gcc_jit_block_end_with_return (
+    on_positive_discriminant, NULL,
+    gcc_jit_context_new_rvalue_from_int (
+      bottom_level->ctxt,
+      top_level->int_type,
+      2));
+
+  /* Block: "on_nonpositive_discriminant" */
+  gcc_jit_block_add_comment (
+    on_nonpositive_discriminant, NULL,
+    "else if (q.discriminant == 0)");
+  gcc_jit_block_end_with_conditional (
+    on_nonpositive_discriminant, NULL,
+    gcc_jit_context_new_comparison (
+      bottom_level->ctxt, NULL,
+      GCC_JIT_COMPARISON_EQ,
+      gcc_jit_rvalue_access_field (
+       gcc_jit_lvalue_as_rvalue (q),
+       NULL,
+       top_level->discriminant),
+      top_level->zero),
+    on_zero_discriminant,
+    on_negative_discriminant);
+
+  /* Block: "on_zero_discriminant" */
+  gcc_jit_block_add_comment (
+    on_zero_discriminant, NULL,
+    "*r1 = -b / (2 * a);");
+  gcc_jit_block_add_assignment (
+    on_zero_discriminant, NULL,
+
+    /* "*r1 = ..." */
+    gcc_jit_rvalue_dereference (
+      gcc_jit_param_as_rvalue (r1), NULL),
+
+    /* -b / (2 * a) */
+    gcc_jit_context_new_binary_op (
+      bottom_level->ctxt, NULL,
+      GCC_JIT_BINARY_OP_DIVIDE,
+      top_level->numeric_type,
+      minus_b,
+      two_a));
+
+  /* "return 1;" */
+  gcc_jit_block_end_with_return (
+    on_zero_discriminant, NULL,
+      gcc_jit_context_one (bottom_level->ctxt, top_level->int_type));
+
+  /* Block: "on_negative_discriminant" */
+  gcc_jit_block_end_with_return (
+    /* else return 0; */
+    on_negative_discriminant, NULL,
+    gcc_jit_context_zero (bottom_level->ctxt, top_level->int_type));
+}
+
+void
+verify_middle_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  struct quadratic q;
+
+  typedef void (*fn_type) (struct quadratic *q);
+  fn_type calc_discriminant =
+    (fn_type)gcc_jit_result_get_code (result,
+                                     "calc_discriminant");
+  CHECK_NON_NULL (calc_discriminant);
+
+  q.a = 3;
+  q.b = 5;
+  q.c = 7;
+  q.discriminant = 0;
+  calc_discriminant (&q);
+
+  CHECK_VALUE (q.discriminant, -59);
+}
+
+void
+verify_bottom_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  typedef int (*fn_type) (double a, double b, double c,
+                         double *r1, double *r2);
+
+  CHECK_NON_NULL (result);
+
+  fn_type test_quadratic =
+    (fn_type)gcc_jit_result_get_code (result, "test_quadratic");
+  CHECK_NON_NULL (test_quadratic);
+
+  /* Verify that the code correctly solves quadratic equations.  */
+  double r1, r2;
+
+  /* This one has two solutions: */
+  CHECK_VALUE (test_quadratic (1, 3, -4, &r1, &r2), 2);
+  CHECK_VALUE (r1, 1);
+  CHECK_VALUE (r2, -4);
+
+  /* This one has one solution: */
+  CHECK_VALUE (test_quadratic (4, 4, 1, &r1, &r2), 1);
+  CHECK_VALUE (r1, -0.5);
+
+  /* This one has no real solutions: */
+  CHECK_VALUE (test_quadratic (4, 1, 1, &r1, &r2), 0);
+}
+
+int
+main (int argc, char **argv)
+{
+  int i, j, k;
+  const int NUM_TOP_ITERATIONS = 2;
+  const int NUM_MIDDLE_ITERATIONS = 2;
+  const int NUM_BOTTOM_ITERATIONS = 2;
+
+  /* We do the whole thing multiple times to shake out state-management
+     issues in the underlying code.  */
+
+  for (i = 1; i <= NUM_TOP_ITERATIONS; i++)
+    {
+      /* Create the top-level context.  */
+      snprintf (test, sizeof (test),
+               "%s iteration %d of %d of top level",
+               extract_progname (argv[0]),
+               i, NUM_TOP_ITERATIONS);
+
+      struct top_level top_level;
+      memset (&top_level, 0, sizeof (top_level));
+
+      top_level.ctxt = gcc_jit_context_acquire ();
+      set_options (top_level.ctxt, argv[0]);
+
+      make_types (&top_level);
+      make_sqrt (&top_level);
+
+      /* No errors should have occurred.  */
+      CHECK_VALUE (gcc_jit_context_get_first_error (top_level.ctxt), NULL);
+
+      gcc_jit_context_dump_to_file (top_level.ctxt,
+                                   "dump-of-test-nested-contexts-top.c",
+                                   1);
+
+      for (j = 1; j <= NUM_MIDDLE_ITERATIONS; j++)
+       {
+         /* Create and populate the middle-level context, using
+            objects from the top-level context.  */
+         snprintf (test, sizeof (test),
+                   ("%s iteration %d of %d of top level;"
+                    " %d of %d of middle level"),
+                   extract_progname (argv[0]),
+                   i, NUM_TOP_ITERATIONS,
+                   j, NUM_MIDDLE_ITERATIONS);
+
+         struct middle_level middle_level;
+         memset (&middle_level, 0, sizeof (middle_level));
+
+         middle_level.ctxt =
+           gcc_jit_context_new_child_context (top_level.ctxt);
+         make_calc_discriminant (&top_level,
+                                 &middle_level);
+
+         /* No errors should have occurred.  */
+         CHECK_VALUE (gcc_jit_context_get_first_error (middle_level.ctxt),
+                      NULL);
+
+         gcc_jit_context_dump_to_file (middle_level.ctxt,
+                                       "dump-of-test-nested-contexts-middle.c",
+                                       1);
+
+         gcc_jit_result *middle_result =
+           gcc_jit_context_compile (middle_level.ctxt);
+         CHECK_NON_NULL (middle_result);
+
+         verify_middle_code (middle_level.ctxt, middle_result);
+
+         for (k = 1; k <= NUM_BOTTOM_ITERATIONS; k++)
+           {
+             /* Create and populate the innermost context, using
+                objects from the top-level and middle-level contexts.  */
+             snprintf (test, sizeof (test),
+                       ("%s iteration %d of %d of top level;"
+                        " %d of %d of middle level;"
+                        " %d of %d of bottom level"),
+                       extract_progname (argv[0]),
+                       i, NUM_TOP_ITERATIONS,
+                       j, NUM_MIDDLE_ITERATIONS,
+                       k, NUM_BOTTOM_ITERATIONS);
+
+             struct bottom_level bottom_level;
+             memset (&bottom_level, 0, sizeof (bottom_level));
+
+             bottom_level.ctxt =
+               gcc_jit_context_new_child_context (middle_level.ctxt);
+             make_test_quadratic (&top_level,
+                                  &middle_level,
+                                  &bottom_level);
+
+             /* No errors should have occurred.  */
+             CHECK_VALUE (gcc_jit_context_get_first_error (bottom_level.ctxt),
+                          NULL);
+
+             gcc_jit_context_dump_to_file (bottom_level.ctxt,
+                                           "dump-of-test-nested-contexts-bottom.c",
+                                           1);
+
+             gcc_jit_result *bottom_result =
+               gcc_jit_context_compile (bottom_level.ctxt);
+             verify_bottom_code (bottom_level.ctxt, bottom_result);
+             gcc_jit_result_release (bottom_result);
+             gcc_jit_context_release (bottom_level.ctxt);
+
+           }
+
+         gcc_jit_result_release (middle_result);
+         gcc_jit_context_release (middle_level.ctxt);
+
+       }
+
+      gcc_jit_context_release (top_level.ctxt);
+   }
+
+  totals ();
+
+  return 0;
+}
diff --git a/gcc/testsuite/jit.dg/test-nested-loops.c b/gcc/testsuite/jit.dg/test-nested-loops.c
new file mode 100644 (file)
index 0000000..1d1a2ba
--- /dev/null
@@ -0,0 +1,179 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  /* Let's try to inject the equivalent of:
+
+       double
+       test_nested_loops (int n, double *a, double *b)
+       {
+         double result = 0.;
+         for (int i = 0; i < n; i++)
+           for (int j = 0; j < n; j++)
+             result += a[i] * b[j];
+         return result
+       }
+  */
+  gcc_jit_type *val_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_DOUBLE);
+  gcc_jit_type *ptr_type = gcc_jit_type_get_pointer (val_type);
+  gcc_jit_type *int_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+  gcc_jit_type *return_type = val_type;
+  gcc_jit_param *param_n =
+    gcc_jit_context_new_param (ctxt, NULL, int_type, "n");
+  gcc_jit_param *param_a =
+    gcc_jit_context_new_param (ctxt, NULL, ptr_type, "a");
+  gcc_jit_param *param_b =
+    gcc_jit_context_new_param (ctxt, NULL, ptr_type, "b");
+  gcc_jit_param *params[3] = {param_n, param_a, param_b};
+  gcc_jit_function *func =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                 GCC_JIT_FUNCTION_EXPORTED,
+                                 return_type,
+                                 "test_nested_loops",
+                                 3, params, 0);
+
+  /* Create locals. */
+  gcc_jit_lvalue *result =
+    gcc_jit_function_new_local (func, NULL, val_type, "result");
+  gcc_jit_lvalue *i =
+    gcc_jit_function_new_local (func, NULL, int_type, "i");
+  gcc_jit_lvalue *j =
+    gcc_jit_function_new_local (func, NULL, int_type, "j");
+
+  /* Create basic blocks. */
+  gcc_jit_block *b_entry =
+    gcc_jit_function_new_block (func, "b_entry");
+  gcc_jit_block *b_outer_loop_cond =
+    gcc_jit_function_new_block (func, "b_outer_loop_cond");
+  gcc_jit_block *b_outer_loop_head =
+    gcc_jit_function_new_block (func, "b_outer_loop_head");
+  gcc_jit_block *b_outer_loop_tail =
+    gcc_jit_function_new_block (func, "b_outer_loop_tail");
+  gcc_jit_block *b_inner_loop_cond =
+    gcc_jit_function_new_block (func, "b_inner_loop_cond");
+  gcc_jit_block *b_inner_loop_body =
+    gcc_jit_function_new_block (func, "b_inner_loop_body");
+  gcc_jit_block *b_exit =
+    gcc_jit_function_new_block (func, "b_exit");
+
+
+  /* Populate b_entry. */
+
+  /* "result = 0.;" */
+  gcc_jit_block_add_assignment (
+    b_entry, NULL,
+    result,
+    gcc_jit_context_zero (ctxt, val_type));
+  /* "i = 0;" */
+  gcc_jit_block_add_assignment (
+    b_entry, NULL,
+    i,
+    gcc_jit_context_zero (ctxt, int_type));
+  gcc_jit_block_end_with_jump (b_entry, NULL, b_outer_loop_cond);
+
+  /* Populate b_outer_loop_cond. */
+  gcc_jit_block_end_with_conditional (
+    b_outer_loop_cond,
+    NULL,
+    /* (i < n) */
+    gcc_jit_context_new_comparison (
+      ctxt, NULL,
+      GCC_JIT_COMPARISON_LT,
+      gcc_jit_lvalue_as_rvalue (i),
+      gcc_jit_param_as_rvalue (param_n)),
+    b_outer_loop_head,
+    b_exit);
+
+  /* Populate b_outer_loop_head. */
+  /* j = 0; */
+  gcc_jit_block_add_assignment (
+    b_outer_loop_head, NULL,
+    j,
+    gcc_jit_context_zero (ctxt, int_type));
+  gcc_jit_block_end_with_jump (b_outer_loop_head, NULL, b_inner_loop_cond);
+
+  /* Populate b_inner_loop_cond. */
+  gcc_jit_block_end_with_conditional (
+    b_inner_loop_cond,
+    NULL,
+    /* (j < n) */
+    gcc_jit_context_new_comparison (
+      ctxt, NULL,
+      GCC_JIT_COMPARISON_LT,
+      gcc_jit_lvalue_as_rvalue (j),
+      gcc_jit_param_as_rvalue (param_n)),
+    b_inner_loop_body,
+    b_outer_loop_tail);
+
+  /* Populate b_inner_loop_body. */
+  /* "result += a[i] * b[j];" */
+  gcc_jit_block_add_assignment_op (
+    b_inner_loop_body, NULL,
+    result,
+    GCC_JIT_BINARY_OP_PLUS,
+    gcc_jit_context_new_binary_op (
+      ctxt, NULL,
+      GCC_JIT_BINARY_OP_MULT,
+      val_type,
+      gcc_jit_lvalue_as_rvalue (
+        gcc_jit_context_new_array_access(
+          ctxt, NULL,
+          gcc_jit_param_as_rvalue (param_a),
+          gcc_jit_lvalue_as_rvalue (i))),
+      gcc_jit_lvalue_as_rvalue (
+        gcc_jit_context_new_array_access(
+          ctxt, NULL,
+          gcc_jit_param_as_rvalue (param_b),
+          gcc_jit_lvalue_as_rvalue (j)))));
+  /* "j++" */
+  gcc_jit_block_add_assignment_op (
+    b_inner_loop_body, NULL,
+    j,
+    GCC_JIT_BINARY_OP_PLUS,
+    gcc_jit_context_one (ctxt, int_type));
+
+  gcc_jit_block_end_with_jump (b_inner_loop_body, NULL, b_inner_loop_cond);
+
+  /* Populate b_outer_loop_tail. */
+  /* "i++" */
+  gcc_jit_block_add_assignment_op (
+    b_outer_loop_tail, NULL,
+    i,
+    GCC_JIT_BINARY_OP_PLUS,
+    gcc_jit_context_one (ctxt, int_type));
+  gcc_jit_block_end_with_jump (b_outer_loop_tail, NULL, b_outer_loop_cond);
+
+  /* Populate b_exit. */
+  /* "return result;" */
+  gcc_jit_block_end_with_return (
+    b_exit,
+    NULL,
+    gcc_jit_lvalue_as_rvalue (result));
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  typedef double (*test_nested_loops_fn_type) (int n, double *a, double *b);
+  CHECK_NON_NULL (result);
+
+  test_nested_loops_fn_type test_nested_loops =
+    (test_nested_loops_fn_type)gcc_jit_result_get_code (result,
+                                                    "test_nested_loops");
+  CHECK_NON_NULL (test_nested_loops);
+  double test_a[] = {1., 2., 3., 4., 5., 6., 7., 8., 9., 10.};
+  double test_b[] = {5., 6., 7., 8., 9., 10., 1., 2., 3., 4.};
+  double val = test_nested_loops (10, test_a, test_b);
+  note ("test_nested_loops returned: %f", val);
+  CHECK_VALUE (val, 3025.0);
+}
diff --git a/gcc/testsuite/jit.dg/test-operator-overloading.cc b/gcc/testsuite/jit.dg/test-operator-overloading.cc
new file mode 100644 (file)
index 0000000..cbb1e98
--- /dev/null
@@ -0,0 +1,310 @@
+/* Test of C++ API.  */
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit++.h"
+
+#include <sstream>
+
+#include "harness.h"
+
+struct quadratic
+{
+  double a;
+  double b;
+  double c;
+  double discriminant;
+};
+
+/* As per test-quadratic.cc, let's try to inject the equivalent of:
+
+     extern double sqrt (double);
+
+     void
+     calc_discriminant (struct quadratic *q)
+     {
+       // (b^2 - 4ac)
+       q->discriminant = (q->b * q->b) - (4 * q->a * q->c);
+     }
+
+     int
+     test_quadratic (double a, double b, double c, double *r1, double *r2)
+     {
+       struct quadratic q;
+       q.a = a;
+       q.b = b;
+       q.c = c;
+       calc_discriminant (&q);
+       if (q.discriminant > 0)
+        {
+           double s = sqrt (q.discriminant);
+           *r1 = (-b + s) / (2 * a);
+           *r2 = (-b - s) / (2 * a);
+           return 2;
+        }
+       else if (q.discriminant == 0)
+        {
+           *r1 = -b / (2 * a);
+           return 1;
+        }
+        else return 0;
+     }
+
+  However, we'll use operator overloading for maxium brevity, at the
+  risk of perhaps being too "magical".
+*/
+
+/****************************************************************************
+ Test case
+ ****************************************************************************/
+
+struct quadratic_test
+{
+  gccjit::context ctxt;
+
+  /* "double" and "(double *)".  */
+  gccjit::type numeric_type;
+  gccjit::type numeric_type_ptr;
+
+  /* The value (double)0.  */
+  gccjit::rvalue zero;
+
+  gccjit::type int_type;
+  gccjit::type void_type;
+
+  /* "struct quadratic" */
+  gccjit::type quadratic;
+  gccjit::field a;
+  gccjit::field b;
+  gccjit::field c;
+  gccjit::field discriminant;
+
+  /* "(struct quadratic *)" */
+  gccjit::type quadratic_ptr;
+
+  gccjit::function calc_discriminant;
+
+  gccjit::function sqrt;
+
+};
+
+static void
+make_types (quadratic_test &testcase)
+{
+  testcase.numeric_type = testcase.ctxt.get_type (GCC_JIT_TYPE_DOUBLE);
+  testcase.numeric_type_ptr = testcase.numeric_type.get_pointer ();
+  testcase.zero = testcase.ctxt.zero (testcase.numeric_type);
+
+  testcase.int_type = testcase.ctxt.get_int_type <int> ();
+  testcase.void_type = testcase.ctxt.get_type (GCC_JIT_TYPE_VOID);
+
+  testcase.a = testcase.ctxt.new_field (testcase.numeric_type, "a");
+  testcase.b = testcase.ctxt.new_field (testcase.numeric_type, "b");
+  testcase.c = testcase.ctxt.new_field (testcase.numeric_type, "c");
+  testcase.discriminant =
+    testcase.ctxt.new_field (testcase.numeric_type, "discriminant");
+  CHECK_STRING_VALUE (testcase.discriminant.get_debug_string ().c_str (),
+                      "discriminant");
+  std::vector<gccjit::field> fields (4);
+  fields[0] = testcase.a;
+  fields[1] = testcase.b;
+  fields[2] = testcase.c;
+  fields[3] = testcase.discriminant;
+  testcase.quadratic =
+    testcase.ctxt.new_struct_type (
+      "quadratic",
+      fields);
+  testcase.quadratic_ptr = testcase.quadratic.get_pointer ();
+}
+
+static void
+make_sqrt (quadratic_test &testcase)
+{
+  std::vector<gccjit::param> params (1);
+  params[0] =
+    testcase.ctxt.new_param (testcase.numeric_type, "x");
+  testcase.sqrt =
+    testcase.ctxt.new_function (GCC_JIT_FUNCTION_IMPORTED,
+                               testcase.numeric_type,
+                               "sqrt",
+                               params,
+                               0);
+}
+
+static void
+make_calc_discriminant (quadratic_test &testcase)
+{
+  /* Build "calc_discriminant".  */
+  gccjit::param param_q =
+    testcase.ctxt.new_param (testcase.quadratic_ptr, "q");
+  std::vector <gccjit::param> params (1);
+  params[0] = param_q;
+  testcase.calc_discriminant =
+    testcase.ctxt.new_function (GCC_JIT_FUNCTION_EXPORTED,
+                               testcase.void_type,
+                               "calc_discriminant",
+                               params,
+                               0);
+  gccjit::block block = testcase.calc_discriminant.new_block ();
+  block.add_comment ("(b^2 - 4ac)");
+
+  gccjit::rvalue q_a = param_q.dereference_field (testcase.a);
+  gccjit::rvalue q_b = param_q.dereference_field (testcase.b);
+  gccjit::rvalue q_c = param_q.dereference_field (testcase.c);
+
+  gccjit::rvalue four =
+    testcase.ctxt.new_rvalue (testcase.numeric_type, 4);
+
+  block.add_assignment (
+    /* q->discriminant =...  */
+    param_q.dereference_field (testcase.discriminant),
+    /* (q->b * q->b) - (4 * q->a * q->c) */
+    (q_b * q_b) - (four * q_a * q_c));
+  block.end_with_return ();
+}
+
+static void
+make_test_quadratic (quadratic_test &testcase)
+{
+  gccjit::param a = testcase.ctxt.new_param (testcase.numeric_type, "a");
+  gccjit::param b = testcase.ctxt.new_param (testcase.numeric_type, "b");
+  gccjit::param c = testcase.ctxt.new_param (testcase.numeric_type, "c");
+  gccjit::param r1 =
+    testcase.ctxt.new_param (testcase.numeric_type_ptr, "r1");
+  gccjit::param r2 =
+    testcase.ctxt.new_param (testcase.numeric_type_ptr, "r2");
+
+  std::vector<gccjit::param> params (5);
+  params[0] = a;
+  params[1] = b;
+  params[2] = c;
+  params[3] = r1;
+  params[4] = r2;
+
+  gccjit::function test_quadratic =
+    testcase.ctxt.new_function (GCC_JIT_FUNCTION_EXPORTED,
+                               testcase.int_type,
+                               "test_quadratic",
+                               params,
+                               0);
+
+  /* struct quadratic q; */
+  gccjit::lvalue q = test_quadratic.new_local (testcase.quadratic, "q");
+
+  gccjit::block initial = test_quadratic.new_block ("initial");
+  gccjit::block on_positive_discriminant
+    = test_quadratic.new_block ("positive_discriminant");
+  gccjit::block on_nonpositive_discriminant
+    = test_quadratic.new_block ("nonpositive_discriminant");
+  gccjit::block on_zero_discriminant
+    = test_quadratic.new_block ("zero_discriminant");
+  gccjit::block on_negative_discriminant
+    = test_quadratic.new_block ("negative_discriminant");
+
+  CHECK_STRING_VALUE (on_zero_discriminant.get_debug_string ().c_str (),
+                      "zero_discriminant");
+
+  /* q.a = a; */
+  initial.add_assignment (q.access_field (testcase.a), a);
+  /* q.b = b; */
+  initial.add_assignment (q.access_field (testcase.b), b);
+  /* q.c = c; */
+  initial.add_assignment (q.access_field (testcase.c), c);
+  /* calc_discriminant (&q); */
+  gccjit::rvalue address_of_q = q.get_address ();
+  initial.add_eval (testcase.calc_discriminant (address_of_q));
+
+  initial.add_comment ("if (q.discriminant > 0)");
+  initial.end_with_conditional (
+    q.access_field (testcase.discriminant) > testcase.zero,
+    on_positive_discriminant,
+    on_nonpositive_discriminant);
+
+  /* Block: "on_positive_discriminant" */
+  /* double s = sqrt (q.discriminant); */
+  gccjit::lvalue s = test_quadratic.new_local (testcase.numeric_type, "s");
+  gccjit::rvalue discriminant_of_q = q.access_field (testcase.discriminant);
+  on_positive_discriminant.add_assignment (s, testcase.sqrt (discriminant_of_q));
+
+  gccjit::rvalue minus_b = -b;
+  gccjit::rvalue two =
+    testcase.ctxt.new_rvalue (testcase.numeric_type, 2);
+  gccjit::rvalue two_a = two * a;
+  CHECK_STRING_VALUE (two_a.get_debug_string ().c_str (),
+                      "(double)2 * a");
+
+  on_positive_discriminant.add_comment ("*r1 = (-b + s) / (2 * a);");
+  on_positive_discriminant.add_assignment (*r1, (minus_b + s) / two_a);
+
+  on_positive_discriminant.add_comment ("*r2 = (-b - s) / (2 * a)");
+  on_positive_discriminant.add_assignment (*r2, (minus_b - s) / two_a);
+
+  /* "return 2;" */
+  on_positive_discriminant.end_with_return (
+    testcase.ctxt.new_rvalue (testcase.int_type, 2));
+
+  /* Block: "on_nonpositive_discriminant" */
+  /* "else if (q.discriminant == 0)" */
+  on_nonpositive_discriminant.add_comment ("else if (q.discriminant == 0)");
+  on_nonpositive_discriminant.end_with_conditional (
+    q.access_field (testcase.discriminant) == testcase.zero,
+    on_zero_discriminant,
+    on_negative_discriminant);
+
+  /* Block: "on_zero_discriminant" */
+  /* if (q.discriminant == 0) */
+  on_zero_discriminant.add_comment ("*r1 = -b / (2 * a);");
+  on_zero_discriminant.add_assignment (*r1, minus_b / two_a);
+
+  /* "return 1;" */
+  on_zero_discriminant.end_with_return (testcase.int_type.one ());
+
+  /* Block: "on_negative_discriminant" */
+  /* else return 0; */
+  on_negative_discriminant.end_with_return (testcase.int_type.zero ());
+
+  /* Verify that output stream operator << works.  */
+  std::ostringstream os;
+  os << "streamed output: " << address_of_q;
+  CHECK_STRING_VALUE (os.str ().c_str (), "streamed output: &q");
+}
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  struct quadratic_test testcase;
+  memset (&testcase, 0, sizeof (testcase));
+  testcase.ctxt = ctxt;
+  make_types (testcase);
+  make_sqrt (testcase);
+  make_calc_discriminant (testcase);
+  make_test_quadratic (testcase);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  typedef int (*fn_type) (double a, double b, double c,
+                         double *r1, double *r2);
+
+  CHECK_NON_NULL (result);
+
+  fn_type test_quadratic =
+    (fn_type)gcc_jit_result_get_code (result, "test_quadratic");
+  CHECK_NON_NULL (test_quadratic);
+
+  /* Verify that the code correctly solves quadratic equations.  */
+  double r1, r2;
+
+  /* This one has two solutions: */
+  CHECK_VALUE (test_quadratic (1, 3, -4, &r1, &r2), 2);
+  CHECK_VALUE (r1, 1);
+  CHECK_VALUE (r2, -4);
+
+  /* This one has one solution: */
+  CHECK_VALUE (test_quadratic (4, 4, 1, &r1, &r2), 1);
+  CHECK_VALUE (r1, -0.5);
+
+  /* This one has no real solutions: */
+  CHECK_VALUE (test_quadratic (4, 1, 1, &r1, &r2), 0);
+}
diff --git a/gcc/testsuite/jit.dg/test-quadratic.c b/gcc/testsuite/jit.dg/test-quadratic.c
new file mode 100644 (file)
index 0000000..715174c
--- /dev/null
@@ -0,0 +1,488 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+struct quadratic
+{
+  double a;
+  double b;
+  double c;
+  double discriminant;
+};
+
+/* Let's try to inject the equivalent of:
+
+     extern double sqrt (double);
+
+     static void
+     calc_discriminant (struct quadratic *q)
+     {
+       // (b^2 - 4ac)
+       q->discriminant = (q->b * q->b) - (4 * q->a * q->c);
+     }
+
+     int
+     test_quadratic (double a, double b, double c, double *r1, double *r2)
+     {
+       struct quadratic q;
+       q.a = a;
+       q.b = b;
+       q.c = c;
+       calc_discriminant (&q);
+       if (q.discriminant > 0)
+        {
+           double s = sqrt (q.discriminant);
+           *r1 = (-b + s) / (2 * a);
+           *r2 = (-b - s) / (2 * a);
+           return 2;
+        }
+       else if (q.discriminant == 0)
+        {
+           *r1 = -b / (2 * a);
+           return 1;
+        }
+        else return 0;
+     }
+*/
+
+struct quadratic_test
+{
+  gcc_jit_context *ctxt;
+
+  /* "double" and "(double *)".  */
+  gcc_jit_type *numeric_type;
+  gcc_jit_type *numeric_type_ptr;
+
+  /* The value (double)0.  */
+  gcc_jit_rvalue *zero;
+
+  gcc_jit_type *int_type;
+  gcc_jit_type *void_type;
+
+  /* "struct quadratic" */
+  gcc_jit_type *quadratic;
+  gcc_jit_field *a;
+  gcc_jit_field *b;
+  gcc_jit_field *c;
+  gcc_jit_field *discriminant;
+
+  /* "(struct quadratic *)" */
+  gcc_jit_type *quadratic_ptr;
+
+  gcc_jit_function *calc_discriminant;
+
+  gcc_jit_function *sqrt;
+
+};
+
+static void
+make_types (struct quadratic_test *testcase)
+{
+  testcase->numeric_type =
+    gcc_jit_context_get_type (testcase->ctxt, GCC_JIT_TYPE_DOUBLE);
+  testcase->numeric_type_ptr =
+    gcc_jit_type_get_pointer (testcase->numeric_type);
+  testcase->zero =
+    gcc_jit_context_zero (testcase->ctxt, testcase->numeric_type);
+
+  testcase->int_type =
+    gcc_jit_context_get_type (testcase->ctxt, GCC_JIT_TYPE_INT);
+
+  testcase->void_type =
+    gcc_jit_context_get_type (testcase->ctxt, GCC_JIT_TYPE_VOID);
+
+  testcase->a =
+    gcc_jit_context_new_field (testcase->ctxt,
+                              NULL,
+                              testcase->numeric_type,
+                              "a");
+  testcase->b =
+    gcc_jit_context_new_field (testcase->ctxt,
+                              NULL,
+                              testcase->numeric_type,
+                              "b");
+  testcase->c =
+    gcc_jit_context_new_field (testcase->ctxt,
+                              NULL,
+                              testcase->numeric_type,
+                              "c");
+  testcase->discriminant =
+    gcc_jit_context_new_field (testcase->ctxt,
+                              NULL,
+                              testcase->numeric_type,
+                              "discriminant");
+  gcc_jit_field *fields[] = {testcase->a,
+                            testcase->b,
+                            testcase->c,
+                            testcase->discriminant};
+  testcase->quadratic =
+    gcc_jit_struct_as_type (
+      gcc_jit_context_new_struct_type (testcase->ctxt, NULL,
+                                      "quadratic", 4, fields));
+  testcase->quadratic_ptr = gcc_jit_type_get_pointer (testcase->quadratic);
+}
+
+static void
+make_sqrt (struct quadratic_test *testcase)
+{
+  gcc_jit_param *param_x =
+    gcc_jit_context_new_param (testcase->ctxt, NULL,
+                              testcase->numeric_type, "x");
+  testcase->sqrt =
+    gcc_jit_context_new_function (testcase->ctxt, NULL,
+                                 GCC_JIT_FUNCTION_IMPORTED,
+                                 testcase->numeric_type,
+                                 "sqrt",
+                                 1, &param_x,
+                                 0);
+}
+
+static void
+make_calc_discriminant (struct quadratic_test *testcase)
+{
+  /* Build "calc_discriminant".  */
+  gcc_jit_param *param_q =
+    gcc_jit_context_new_param (testcase->ctxt, NULL,
+                              testcase->quadratic_ptr, "q");
+  testcase->calc_discriminant =
+    gcc_jit_context_new_function (testcase->ctxt, NULL,
+                                 GCC_JIT_FUNCTION_INTERNAL,
+                                 testcase->void_type,
+                                 "calc_discriminant",
+                                 1, &param_q,
+                                 0);
+  gcc_jit_block *blk =
+    gcc_jit_function_new_block (testcase->calc_discriminant, NULL);
+  gcc_jit_block_add_comment (
+    blk, NULL,
+    "(b^2 - 4ac)");
+
+  gcc_jit_rvalue *q_a =
+    gcc_jit_lvalue_as_rvalue (
+       gcc_jit_rvalue_dereference_field (
+         gcc_jit_param_as_rvalue (param_q),
+         NULL, testcase->a));
+  gcc_jit_rvalue *q_b =
+    gcc_jit_lvalue_as_rvalue (
+       gcc_jit_rvalue_dereference_field (
+         gcc_jit_param_as_rvalue (param_q),
+         NULL, testcase->b));
+  gcc_jit_rvalue *q_c =
+    gcc_jit_lvalue_as_rvalue (
+       gcc_jit_rvalue_dereference_field (
+         gcc_jit_param_as_rvalue (param_q),
+         NULL, testcase->c));
+
+  gcc_jit_block_add_assignment (
+    blk, NULL,
+
+    /* q->discriminant =...  */
+    gcc_jit_rvalue_dereference_field (
+      gcc_jit_param_as_rvalue (param_q),
+      NULL,
+      testcase->discriminant),
+
+    /* (q->b * q->b) - (4 * q->a * q->c) */
+    gcc_jit_context_new_binary_op (
+      testcase->ctxt, NULL,
+      GCC_JIT_BINARY_OP_MINUS,
+      testcase->numeric_type,
+
+      /* (q->b * q->b) */
+      gcc_jit_context_new_binary_op (
+       testcase->ctxt, NULL,
+       GCC_JIT_BINARY_OP_MULT,
+       testcase->numeric_type,
+       q_b, q_b),
+
+      /* (4 * (q->a * q->c)) */
+      gcc_jit_context_new_binary_op (
+       testcase->ctxt, NULL,
+       GCC_JIT_BINARY_OP_MULT,
+       testcase->numeric_type,
+       /* 4.0 */
+       gcc_jit_context_new_rvalue_from_int (
+         testcase->ctxt,
+         testcase->numeric_type,
+         4),
+       /* (q->a * q->c) */
+       gcc_jit_context_new_binary_op (
+         testcase->ctxt, NULL,
+         GCC_JIT_BINARY_OP_MULT,
+         testcase->numeric_type,
+         q_a, q_c)))); /* end of gcc_jit_function_add_assignment call.  */
+
+  gcc_jit_block_end_with_void_return (blk, NULL);
+}
+
+static void
+make_test_quadratic (struct quadratic_test *testcase)
+{
+  gcc_jit_param *a =
+    gcc_jit_context_new_param (testcase->ctxt, NULL,
+                              testcase->numeric_type, "a");
+  gcc_jit_param *b =
+    gcc_jit_context_new_param (testcase->ctxt, NULL,
+                              testcase->numeric_type, "b");
+  gcc_jit_param *c =
+    gcc_jit_context_new_param (testcase->ctxt, NULL,
+                              testcase->numeric_type, "c");
+  gcc_jit_param *r1 =
+    gcc_jit_context_new_param (testcase->ctxt, NULL,
+                              testcase->numeric_type_ptr, "r1");
+  gcc_jit_param *r2 =
+    gcc_jit_context_new_param (testcase->ctxt, NULL,
+                              testcase->numeric_type_ptr, "r2");
+  gcc_jit_param *params[] = {a, b, c, r1, r2};
+  gcc_jit_function *test_quadratic =
+    gcc_jit_context_new_function (testcase->ctxt, NULL,
+                                 GCC_JIT_FUNCTION_EXPORTED,
+                                 testcase->int_type,
+                                 "test_quadratic",
+                                 5, params,
+                                 0);
+  /* struct quadratic q; */
+  gcc_jit_lvalue *q =
+    gcc_jit_function_new_local (
+      test_quadratic, NULL,
+      testcase->quadratic,
+      "q");
+
+  gcc_jit_block *initial =
+    gcc_jit_function_new_block (test_quadratic,
+                               "initial");
+  gcc_jit_block *on_positive_discriminant
+    = gcc_jit_function_new_block (test_quadratic,
+                                 "positive_discriminant");
+
+  gcc_jit_block *on_nonpositive_discriminant
+    = gcc_jit_function_new_block (test_quadratic,
+                                 "nonpositive_discriminant");
+
+  gcc_jit_block *on_zero_discriminant
+    = gcc_jit_function_new_block (test_quadratic,
+                                 "zero_discriminant");
+
+  gcc_jit_block *on_negative_discriminant
+    = gcc_jit_function_new_block (test_quadratic,
+                                 "negative_discriminant");
+
+  /* Initial block.  */
+  /* q.a = a; */
+  gcc_jit_block_add_assignment (
+    initial, NULL,
+    gcc_jit_lvalue_access_field (q, NULL, testcase->a),
+    gcc_jit_param_as_rvalue (a));
+  /* q.b = b; */
+  gcc_jit_block_add_assignment (
+    initial, NULL,
+    gcc_jit_lvalue_access_field (q, NULL, testcase->b),
+    gcc_jit_param_as_rvalue (b));
+  /* q.c = c; */
+  gcc_jit_block_add_assignment (
+    initial, NULL,
+    gcc_jit_lvalue_access_field (q, NULL, testcase->c),
+    gcc_jit_param_as_rvalue (c));
+  /* calc_discriminant (&q); */
+  gcc_jit_rvalue *address_of_q = gcc_jit_lvalue_get_address (q, NULL);
+  gcc_jit_block_add_eval (
+    initial, NULL,
+    gcc_jit_context_new_call (
+      testcase->ctxt, NULL,
+      testcase->calc_discriminant,
+      1, &address_of_q));
+
+  gcc_jit_block_add_comment (
+    initial, NULL,
+    "if (q.discriminant > 0)");
+  gcc_jit_block_end_with_conditional (
+    initial, NULL,
+    gcc_jit_context_new_comparison (
+      testcase->ctxt, NULL,
+      GCC_JIT_COMPARISON_GT,
+      gcc_jit_rvalue_access_field (
+       gcc_jit_lvalue_as_rvalue (q),
+       NULL,
+       testcase->discriminant),
+      testcase->zero),
+    on_positive_discriminant,
+    on_nonpositive_discriminant);
+
+  /* Block: "on_positive_discriminant" */
+  /* double s = sqrt (q.discriminant); */
+  gcc_jit_lvalue *s = gcc_jit_function_new_local (
+    test_quadratic, NULL,
+    testcase->numeric_type,
+    "s");
+  gcc_jit_rvalue *discriminant_of_q =
+    gcc_jit_rvalue_access_field (gcc_jit_lvalue_as_rvalue (q),
+                                NULL,
+                                testcase->discriminant);
+  gcc_jit_block_add_assignment (
+    on_positive_discriminant, NULL,
+    s,
+    gcc_jit_context_new_call (
+      testcase->ctxt, NULL,
+      testcase->sqrt,
+      1, &discriminant_of_q));
+
+  gcc_jit_rvalue *minus_b =
+    gcc_jit_context_new_unary_op (
+      testcase->ctxt, NULL,
+      GCC_JIT_UNARY_OP_MINUS,
+      testcase->numeric_type,
+      gcc_jit_param_as_rvalue (b));
+  gcc_jit_rvalue *two_a =
+    gcc_jit_context_new_binary_op (
+      testcase->ctxt, NULL,
+      GCC_JIT_BINARY_OP_MULT,
+      testcase->numeric_type,
+      gcc_jit_context_new_rvalue_from_int (
+       testcase->ctxt,
+       testcase->numeric_type,
+       2),
+      gcc_jit_param_as_rvalue (a));
+
+  gcc_jit_block_add_comment (
+    on_positive_discriminant, NULL,
+    "*r1 = (-b + s) / (2 * a);");
+  gcc_jit_block_add_assignment (
+    on_positive_discriminant, NULL,
+
+    /* "*r1 = ..." */
+    gcc_jit_rvalue_dereference (
+      gcc_jit_param_as_rvalue (r1), NULL),
+
+    /* (-b + s) / (2 * a) */
+    gcc_jit_context_new_binary_op (
+      testcase->ctxt, NULL,
+      GCC_JIT_BINARY_OP_DIVIDE,
+      testcase->numeric_type,
+      gcc_jit_context_new_binary_op (
+       testcase->ctxt, NULL,
+       GCC_JIT_BINARY_OP_PLUS,
+       testcase->numeric_type,
+       minus_b,
+       gcc_jit_lvalue_as_rvalue (s)),
+      two_a));
+
+  gcc_jit_block_add_comment (
+    on_positive_discriminant, NULL,
+    "*r2 = (-b - s) / (2 * a)");
+  gcc_jit_block_add_assignment (
+    on_positive_discriminant, NULL,
+
+    /* "*r2 = ..." */
+    gcc_jit_rvalue_dereference (
+      gcc_jit_param_as_rvalue (r2), NULL),
+
+    /* (-b - s) / (2 * a) */
+    gcc_jit_context_new_binary_op (
+      testcase->ctxt, NULL,
+      GCC_JIT_BINARY_OP_DIVIDE,
+      testcase->numeric_type,
+      gcc_jit_context_new_binary_op (
+       testcase->ctxt, NULL,
+       GCC_JIT_BINARY_OP_MINUS,
+       testcase->numeric_type,
+       minus_b,
+       gcc_jit_lvalue_as_rvalue (s)),
+      two_a));
+
+  /* "return 2;" */
+  gcc_jit_block_end_with_return (
+    on_positive_discriminant, NULL,
+    gcc_jit_context_new_rvalue_from_int (
+      testcase->ctxt,
+      testcase->int_type,
+      2));
+
+  /* Block: "on_nonpositive_discriminant" */
+  gcc_jit_block_add_comment (
+    on_nonpositive_discriminant, NULL,
+    "else if (q.discriminant == 0)");
+  gcc_jit_block_end_with_conditional (
+    on_nonpositive_discriminant, NULL,
+    gcc_jit_context_new_comparison (
+      testcase->ctxt, NULL,
+      GCC_JIT_COMPARISON_EQ,
+      gcc_jit_rvalue_access_field (
+       gcc_jit_lvalue_as_rvalue (q),
+       NULL,
+       testcase->discriminant),
+      testcase->zero),
+    on_zero_discriminant,
+    on_negative_discriminant);
+
+  /* Block: "on_zero_discriminant" */
+  gcc_jit_block_add_comment (
+    on_zero_discriminant, NULL,
+    "*r1 = -b / (2 * a);");
+  gcc_jit_block_add_assignment (
+    on_zero_discriminant, NULL,
+
+    /* "*r1 = ..." */
+    gcc_jit_rvalue_dereference (
+      gcc_jit_param_as_rvalue (r1), NULL),
+
+    /* -b / (2 * a) */
+    gcc_jit_context_new_binary_op (
+      testcase->ctxt, NULL,
+      GCC_JIT_BINARY_OP_DIVIDE,
+      testcase->numeric_type,
+      minus_b,
+      two_a));
+  gcc_jit_block_end_with_return (
+    /* "return 1;" */
+    on_zero_discriminant, NULL,
+      gcc_jit_context_one (testcase->ctxt, testcase->int_type));
+
+  /* Block: "on_negative_discriminant" */
+  gcc_jit_block_end_with_return (
+    /* "else return 0;" */
+    on_negative_discriminant, NULL,
+    gcc_jit_context_zero (testcase->ctxt, testcase->int_type));
+}
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  struct quadratic_test testcase;
+  memset (&testcase, 0, sizeof (testcase));
+  testcase.ctxt = ctxt;
+  make_types (&testcase);
+  make_sqrt (&testcase);
+  make_calc_discriminant (&testcase);
+  make_test_quadratic (&testcase);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  typedef int (*fn_type) (double a, double b, double c,
+                         double *r1, double *r2);
+
+  CHECK_NON_NULL (result);
+
+  fn_type test_quadratic =
+    (fn_type)gcc_jit_result_get_code (result, "test_quadratic");
+  CHECK_NON_NULL (test_quadratic);
+
+  /* Verify that the code correctly solves quadratic equations.  */
+  double r1, r2;
+
+  /* This one has two solutions: */
+  CHECK_VALUE (test_quadratic (1, 3, -4, &r1, &r2), 2);
+  CHECK_VALUE (r1, 1);
+  CHECK_VALUE (r2, -4);
+
+  /* This one has one solution: */
+  CHECK_VALUE (test_quadratic (4, 4, 1, &r1, &r2), 1);
+  CHECK_VALUE (r1, -0.5);
+
+  /* This one has no real solutions: */
+  CHECK_VALUE (test_quadratic (4, 1, 1, &r1, &r2), 0);
+}
diff --git a/gcc/testsuite/jit.dg/test-quadratic.cc b/gcc/testsuite/jit.dg/test-quadratic.cc
new file mode 100644 (file)
index 0000000..f347669
--- /dev/null
@@ -0,0 +1,366 @@
+/* Test of C++ API.  */
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit++.h"
+
+#include <sstream>
+
+#include "harness.h"
+
+struct quadratic
+{
+  double a;
+  double b;
+  double c;
+  double discriminant;
+};
+
+/* As per test-quadratic.c, let's try to inject the equivalent of:
+
+     extern double sqrt (double);
+
+     void
+     calc_discriminant (struct quadratic *q)
+     {
+       // (b^2 - 4ac)
+       q->discriminant = (q->b * q->b) - (4 * q->a * q->c);
+     }
+
+     int
+     test_quadratic (double a, double b, double c, double *r1, double *r2)
+     {
+       struct quadratic q;
+       q.a = a;
+       q.b = b;
+       q.c = c;
+       calc_discriminant (&q);
+       if (q.discriminant > 0)
+        {
+           double s = sqrt (q.discriminant);
+           *r1 = (-b + s) / (2 * a);
+           *r2 = (-b - s) / (2 * a);
+           return 2;
+        }
+       else if (q.discriminant == 0)
+        {
+           *r1 = -b / (2 * a);
+           return 1;
+        }
+        else return 0;
+     }
+
+  However, we'll use the C++ bindings.
+*/
+
+/****************************************************************************
+ Test case
+ ****************************************************************************/
+
+struct quadratic_test
+{
+  gccjit::context ctxt;
+
+  /* "double" and "(double *)".  */
+  gccjit::type numeric_type;
+  gccjit::type numeric_type_ptr;
+
+  /* The value (double)0.  */
+  gccjit::rvalue zero;
+
+  gccjit::type int_type;
+  gccjit::type void_type;
+
+  /* "struct quadratic" */
+  gccjit::type quadratic;
+  gccjit::field a;
+  gccjit::field b;
+  gccjit::field c;
+  gccjit::field discriminant;
+
+  /* "(struct quadratic *)" */
+  gccjit::type quadratic_ptr;
+
+  gccjit::function calc_discriminant;
+
+  gccjit::function sqrt;
+
+};
+
+static void
+make_types (quadratic_test &testcase)
+{
+  testcase.numeric_type = testcase.ctxt.get_type (GCC_JIT_TYPE_DOUBLE);
+  testcase.numeric_type_ptr = testcase.numeric_type.get_pointer ();
+  testcase.zero = testcase.ctxt.zero (testcase.numeric_type);
+
+  testcase.int_type = testcase.ctxt.get_int_type <int> ();
+  testcase.void_type = testcase.ctxt.get_type (GCC_JIT_TYPE_VOID);
+
+  testcase.a = testcase.ctxt.new_field (testcase.numeric_type, "a");
+  testcase.b = testcase.ctxt.new_field (testcase.numeric_type, "b");
+  testcase.c = testcase.ctxt.new_field (testcase.numeric_type, "c");
+  testcase.discriminant =
+    testcase.ctxt.new_field (testcase.numeric_type, "discriminant");
+  CHECK_STRING_VALUE (testcase.discriminant.get_debug_string ().c_str (),
+                      "discriminant");
+  std::vector<gccjit::field> fields (4);
+  fields[0] = testcase.a;
+  fields[1] = testcase.b;
+  fields[2] = testcase.c;
+  fields[3] = testcase.discriminant;
+  testcase.quadratic =
+    testcase.ctxt.new_struct_type (
+      "quadratic",
+      fields);
+  testcase.quadratic_ptr = testcase.quadratic.get_pointer ();
+}
+
+static void
+make_sqrt (quadratic_test &testcase)
+{
+  std::vector<gccjit::param> params (1);
+  params[0] =
+    testcase.ctxt.new_param (testcase.numeric_type, "x");
+  testcase.sqrt =
+    testcase.ctxt.new_function (GCC_JIT_FUNCTION_IMPORTED,
+                               testcase.numeric_type,
+                               "sqrt",
+                               params,
+                               0);
+}
+
+static void
+make_calc_discriminant (quadratic_test &testcase)
+{
+  /* Build "calc_discriminant".  */
+  gccjit::param param_q =
+    testcase.ctxt.new_param (testcase.quadratic_ptr, "q");
+  std::vector <gccjit::param> params (1);
+  params[0] = param_q;
+  testcase.calc_discriminant =
+    testcase.ctxt.new_function (GCC_JIT_FUNCTION_EXPORTED,
+                               testcase.void_type,
+                               "calc_discriminant",
+                               params,
+                               0);
+  gccjit::block block = testcase.calc_discriminant.new_block ();
+  block.add_comment ("(b^2 - 4ac)");
+
+  gccjit::rvalue q_a = param_q.dereference_field (testcase.a);
+  gccjit::rvalue q_b = param_q.dereference_field (testcase.b);
+  gccjit::rvalue q_c = param_q.dereference_field (testcase.c);
+
+  block.add_assignment (
+    /* q->discriminant =...  */
+    param_q.dereference_field (testcase.discriminant),
+    /* (q->b * q->b) - (4 * q->a * q->c) */
+    testcase.ctxt.new_minus (
+      testcase.numeric_type,
+
+      /* (q->b * q->b) */
+      testcase.ctxt.new_mult (
+       testcase.numeric_type,
+       q_b, q_b),
+
+      /* (4 * (q->a * q->c)) */
+      testcase.ctxt.new_mult (
+       testcase.numeric_type,
+       /* 4.0 */
+       testcase.ctxt.new_rvalue (
+         testcase.numeric_type,
+         4),
+       /* (q->a * q->c) */
+       testcase.ctxt.new_mult (
+         testcase.numeric_type,
+         q_a, q_c)))); /* end of add_assignment call.  */
+  block.end_with_return ();
+}
+
+static void
+make_test_quadratic (quadratic_test &testcase)
+{
+  gccjit::param a = testcase.ctxt.new_param (testcase.numeric_type, "a");
+  gccjit::param b = testcase.ctxt.new_param (testcase.numeric_type, "b");
+  gccjit::param c = testcase.ctxt.new_param (testcase.numeric_type, "c");
+  gccjit::param r1 =
+    testcase.ctxt.new_param (testcase.numeric_type_ptr, "r1");
+  gccjit::param r2 =
+    testcase.ctxt.new_param (testcase.numeric_type_ptr, "r2");
+
+  std::vector<gccjit::param> params (5);
+  params[0] = a;
+  params[1] = b;
+  params[2] = c;
+  params[3] = r1;
+  params[4] = r2;
+
+  gccjit::function test_quadratic =
+    testcase.ctxt.new_function (GCC_JIT_FUNCTION_EXPORTED,
+                               testcase.int_type,
+                               "test_quadratic",
+                               params,
+                               0);
+
+  /* struct quadratic q; */
+  gccjit::lvalue q = test_quadratic.new_local (testcase.quadratic, "q");
+
+  gccjit::block initial = test_quadratic.new_block ("initial");
+  gccjit::block on_positive_discriminant
+    = test_quadratic.new_block ("positive_discriminant");
+  gccjit::block on_nonpositive_discriminant
+    = test_quadratic.new_block ("nonpositive_discriminant");
+  gccjit::block on_zero_discriminant
+    = test_quadratic.new_block ("zero_discriminant");
+  gccjit::block on_negative_discriminant
+    = test_quadratic.new_block ("negative_discriminant");
+
+  CHECK_STRING_VALUE (on_zero_discriminant.get_debug_string ().c_str (),
+                      "zero_discriminant");
+
+  /* q.a = a; */
+  initial.add_assignment (q.access_field (testcase.a), a);
+  /* q.b = b; */
+  initial.add_assignment (q.access_field (testcase.b), b);
+  /* q.c = c; */
+  initial.add_assignment (q.access_field (testcase.c), c);
+  /* calc_discriminant (&q); */
+  gccjit::rvalue address_of_q = q.get_address ();
+  initial.add_call (testcase.calc_discriminant, address_of_q);
+
+  initial.add_comment ("if (q.discriminant > 0)");
+  initial.end_with_conditional (
+    testcase.ctxt.new_gt (
+      q.access_field (testcase.discriminant),
+      testcase.zero),
+    on_positive_discriminant,
+    on_nonpositive_discriminant);
+
+  /* Block: "on_positive_discriminant" */
+  /* double s = sqrt (q.discriminant); */
+  gccjit::lvalue s = test_quadratic.new_local (testcase.numeric_type, "s");
+  gccjit::rvalue discriminant_of_q = q.access_field (testcase.discriminant);
+  on_positive_discriminant.add_assignment (
+    s,
+    testcase.ctxt.new_call (testcase.sqrt, discriminant_of_q));
+
+  gccjit::rvalue minus_b =
+    testcase.ctxt.new_minus (
+      testcase.numeric_type,
+      b);
+  gccjit::rvalue two_a =
+    testcase.ctxt.new_mult (
+      testcase.numeric_type,
+      testcase.ctxt.new_rvalue (testcase.numeric_type, 2),
+      a);
+  CHECK_STRING_VALUE (two_a.get_debug_string ().c_str (),
+                      "(double)2 * a");
+
+  on_positive_discriminant.add_comment ("*r1 = (-b + s) / (2 * a);");
+  on_positive_discriminant.add_assignment (
+    /* "*r1 = ..." */
+    r1.dereference (),
+
+    /* (-b + s) / (2 * a) */
+    testcase.ctxt.new_divide (
+      testcase.numeric_type,
+      testcase.ctxt.new_plus (
+       testcase.numeric_type,
+       minus_b,
+       s),
+      two_a));
+
+  on_positive_discriminant.add_comment ("*r2 = (-b - s) / (2 * a)");
+  on_positive_discriminant.add_assignment (
+    /* "*r2 = ..." */
+    r2.dereference (),
+
+    /* (-b - s) / (2 * a) */
+    testcase.ctxt.new_divide (
+      testcase.numeric_type,
+      testcase.ctxt.new_minus (
+       testcase.numeric_type,
+       minus_b,
+       s),
+      two_a));
+
+  /* "return 2;" */
+  on_positive_discriminant.end_with_return (
+    testcase.ctxt.new_rvalue (testcase.int_type, 2));
+
+  /* Block: "on_nonpositive_discriminant" */
+  on_nonpositive_discriminant.add_comment ("else if (q.discriminant == 0)");
+  on_nonpositive_discriminant.end_with_conditional (
+    testcase.ctxt.new_eq (
+      q.access_field (testcase.discriminant),
+      testcase.zero),
+    on_zero_discriminant,
+    on_negative_discriminant);
+
+  /* Block: "on_zero_discriminant" */
+  /* if (q.discriminant == 0) */
+  on_zero_discriminant.add_comment ("*r1 = -b / (2 * a);");
+  on_zero_discriminant.add_assignment (
+    /* "*r1 = ..." */
+    r1.dereference (),
+
+    /* -b / (2 * a) */
+    testcase.ctxt.new_divide (
+      testcase.numeric_type,
+      minus_b,
+      two_a));
+
+  /* "return 1;" */
+  on_zero_discriminant.end_with_return (
+    testcase.ctxt.one (testcase.int_type));
+
+  /* Block: "on_negative_discriminant" */
+  /* else return 0; */
+  on_negative_discriminant.end_with_return (
+    testcase.ctxt.zero (testcase.int_type));
+
+  /* Verify that output stream operator << works.  */
+  std::ostringstream os;
+  os << "streamed output: " << address_of_q;
+  CHECK_STRING_VALUE (os.str ().c_str (), "streamed output: &q");
+}
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  struct quadratic_test testcase;
+  memset (&testcase, 0, sizeof (testcase));
+  testcase.ctxt = ctxt;
+  make_types (testcase);
+  make_sqrt (testcase);
+  make_calc_discriminant (testcase);
+  make_test_quadratic (testcase);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  typedef int (*fn_type) (double a, double b, double c,
+                         double *r1, double *r2);
+
+  CHECK_NON_NULL (result);
+
+  fn_type test_quadratic =
+    (fn_type)gcc_jit_result_get_code (result, "test_quadratic");
+  CHECK_NON_NULL (test_quadratic);
+
+  /* Verify that the code correctly solves quadratic equations.  */
+  double r1, r2;
+
+  /* This one has two solutions: */
+  CHECK_VALUE (test_quadratic (1, 3, -4, &r1, &r2), 2);
+  CHECK_VALUE (r1, 1);
+  CHECK_VALUE (r2, -4);
+
+  /* This one has one solution: */
+  CHECK_VALUE (test_quadratic (4, 4, 1, &r1, &r2), 1);
+  CHECK_VALUE (r1, -0.5);
+
+  /* This one has no real solutions: */
+  CHECK_VALUE (test_quadratic (4, 1, 1, &r1, &r2), 0);
+}
diff --git a/gcc/testsuite/jit.dg/test-reading-struct.c b/gcc/testsuite/jit.dg/test-reading-struct.c
new file mode 100644 (file)
index 0000000..a090ba9
--- /dev/null
@@ -0,0 +1,135 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+struct bar
+{
+  int x;
+  int y;
+};
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  /* Let's try to inject the equivalent of:
+
+     int
+     test_reading (const struct bar *f)
+     {
+       return f->x * f->y;
+     }
+
+     int
+     test_writing ()
+     {
+       struct bar tmp;
+       tmp.x = 5;
+       tmp.y = 7;
+       return test_reading (&tmp);
+     }
+  */
+  gcc_jit_type *int_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+  gcc_jit_field *x =
+    gcc_jit_context_new_field (ctxt,
+                               NULL,
+                               int_type,
+                               "x");
+  gcc_jit_field *y =
+    gcc_jit_context_new_field (ctxt,
+                               NULL,
+                               int_type,
+                               "y");
+  gcc_jit_field *fields[] = {x, y};
+  gcc_jit_type *struct_type =
+    gcc_jit_struct_as_type (
+      gcc_jit_context_new_struct_type (ctxt, NULL, "bar", 2, fields));
+  gcc_jit_type *const_struct_type = gcc_jit_type_get_const (struct_type);
+  gcc_jit_type *ptr_type = gcc_jit_type_get_pointer (const_struct_type);
+
+  /* Build "test_reading".  */
+  gcc_jit_param *param_f =
+    gcc_jit_context_new_param (ctxt, NULL, ptr_type, "f");
+  gcc_jit_function *fn_test_reading =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                  GCC_JIT_FUNCTION_EXPORTED,
+                                  int_type,
+                                  "test_reading",
+                                  1, &param_f,
+                                  0);
+
+  /* return f->x * f->y; */
+  gcc_jit_block *reading_block = gcc_jit_function_new_block (fn_test_reading, NULL);
+  gcc_jit_block_end_with_return (
+    reading_block,
+    NULL,
+    gcc_jit_context_new_binary_op (
+      ctxt, NULL,
+      GCC_JIT_BINARY_OP_MULT,
+      int_type,
+      gcc_jit_lvalue_as_rvalue (
+       gcc_jit_rvalue_dereference_field (
+         gcc_jit_param_as_rvalue (param_f),
+         NULL,
+         x)),
+      gcc_jit_lvalue_as_rvalue (
+       gcc_jit_rvalue_dereference_field (
+       gcc_jit_param_as_rvalue (param_f),
+       NULL,
+       y))));
+
+  /* Build "test_writing".  */
+  gcc_jit_function *fn_test_writing =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                  GCC_JIT_FUNCTION_EXPORTED,
+                                  int_type,
+                                  "test_writing",
+                                  0, NULL,
+                                  0);
+
+  /* struct bar tmp; */
+  gcc_jit_lvalue *local_tmp =
+    gcc_jit_function_new_local (fn_test_writing, NULL,
+                               struct_type,
+                               "tmp");
+  /* tmp.x = 5; */
+  gcc_jit_block *writing_block = gcc_jit_function_new_block (fn_test_writing, NULL);
+  gcc_jit_block_add_assignment (
+    writing_block, NULL,
+    gcc_jit_lvalue_access_field (local_tmp, NULL, x),
+    gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 5));
+
+  /* tmp.y = 7; */
+  gcc_jit_block_add_assignment (
+    writing_block, NULL,
+    gcc_jit_lvalue_access_field (local_tmp, NULL, y),
+    gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 7));
+
+  /* return test_reading (&tmp); */
+  gcc_jit_rvalue *arg = gcc_jit_lvalue_get_address (local_tmp, NULL);
+  gcc_jit_block_end_with_return (
+    writing_block,
+    NULL,
+    gcc_jit_context_new_call (
+      ctxt, NULL,
+      fn_test_reading,
+      1, &arg));
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  typedef int (*fn_type) (void);
+  CHECK_NON_NULL (result);
+
+  fn_type test_writing =
+    (fn_type)gcc_jit_result_get_code (result, "test_writing");
+  CHECK_NON_NULL (test_writing);
+
+  /* Verify that the code correctly returns the product of the fields.  */
+  CHECK_VALUE (test_writing (), 35);
+}
+
diff --git a/gcc/testsuite/jit.dg/test-string-literal.c b/gcc/testsuite/jit.dg/test-string-literal.c
new file mode 100644 (file)
index 0000000..097830d
--- /dev/null
@@ -0,0 +1,52 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  /* Let's try to inject the equivalent of:
+
+     const char *
+     test_string_literal (void)
+     {
+        return "hello world";
+     }
+  */
+  gcc_jit_type *const_char_ptr_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_CONST_CHAR_PTR);
+
+  /* Build the test_fn.  */
+  gcc_jit_function *test_fn =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                  GCC_JIT_FUNCTION_EXPORTED,
+                                  const_char_ptr_type,
+                                  "test_string_literal",
+                                  0, NULL,
+                                  0);
+  gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
+
+  gcc_jit_block_end_with_return (
+    block, NULL,
+    gcc_jit_context_new_string_literal (ctxt, "hello world"));
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  typedef const char *(*fn_type) (void);
+  CHECK_NON_NULL (result);
+  fn_type test_string_literal =
+    (fn_type)gcc_jit_result_get_code (result, "test_string_literal");
+  CHECK_NON_NULL (test_string_literal);
+
+  /* Call the JIT-generated function.  */
+  const char *str = test_string_literal ();
+  CHECK_NON_NULL (str);
+  CHECK_VALUE (strcmp (str, "hello world"), 0);
+}
+
diff --git a/gcc/testsuite/jit.dg/test-sum-of-squares.c b/gcc/testsuite/jit.dg/test-sum-of-squares.c
new file mode 100644 (file)
index 0000000..d6fdcf6
--- /dev/null
@@ -0,0 +1,126 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  /*
+    Simple sum-of-squares, to test conditionals and looping
+
+    int loop_test (int n)
+    {
+      int i;
+      int sum = 0;
+      for (i = 0; i < n ; i ++)
+      {
+       sum += i * i;
+      }
+      return sum;
+   */
+  gcc_jit_type *the_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+  gcc_jit_type *return_type = the_type;
+
+  gcc_jit_param *n =
+    gcc_jit_context_new_param (ctxt, NULL, the_type, "n");
+  gcc_jit_param *params[1] = {n};
+  gcc_jit_function *func =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                 GCC_JIT_FUNCTION_EXPORTED,
+                                 return_type,
+                                 "loop_test",
+                                 1, params, 0);
+
+  /* Build locals:  */
+  gcc_jit_lvalue *i =
+    gcc_jit_function_new_local (func, NULL, the_type, "i");
+  gcc_jit_lvalue *sum =
+    gcc_jit_function_new_local (func, NULL, the_type, "sum");
+
+  gcc_jit_block *initial =
+    gcc_jit_function_new_block (func, "initial");
+  gcc_jit_block *loop_cond =
+    gcc_jit_function_new_block (func, "loop_cond");
+  gcc_jit_block *loop_body =
+    gcc_jit_function_new_block (func, "loop_body");
+  gcc_jit_block *after_loop =
+    gcc_jit_function_new_block (func, "after_loop");
+
+  /* sum = 0; */
+  gcc_jit_block_add_assignment (
+    initial, NULL,
+    sum,
+    gcc_jit_context_new_rvalue_from_int (ctxt, the_type, 0));
+
+  /* i = 0; */
+  gcc_jit_block_add_assignment (
+    initial, NULL,
+    i,
+    gcc_jit_context_new_rvalue_from_int (ctxt, the_type, 0));
+
+  gcc_jit_block_end_with_jump (initial, NULL, loop_cond);
+
+  /* if (i >= n) */
+  gcc_jit_block_end_with_conditional (
+    loop_cond, NULL,
+    gcc_jit_context_new_comparison (
+       ctxt, NULL,
+       GCC_JIT_COMPARISON_GE,
+       gcc_jit_lvalue_as_rvalue (i),
+       gcc_jit_param_as_rvalue (n)),
+    after_loop,
+    loop_body);
+
+  /* sum += i * i */
+  gcc_jit_block_add_assignment (
+    loop_body, NULL,
+    sum,
+    gcc_jit_context_new_binary_op (
+      ctxt, NULL,
+      GCC_JIT_BINARY_OP_PLUS, the_type,
+      gcc_jit_lvalue_as_rvalue (sum),
+      gcc_jit_context_new_binary_op (
+        ctxt, NULL,
+        GCC_JIT_BINARY_OP_MULT, the_type,
+        gcc_jit_lvalue_as_rvalue (i),
+        gcc_jit_lvalue_as_rvalue (i))));
+
+  /* i++ */
+  gcc_jit_block_add_assignment (
+    loop_body, NULL,
+    i,
+    gcc_jit_context_new_binary_op (
+      ctxt, NULL,
+      GCC_JIT_BINARY_OP_PLUS, the_type,
+      gcc_jit_lvalue_as_rvalue (i),
+      gcc_jit_context_new_rvalue_from_int (
+       ctxt,
+       the_type,
+       1)));
+
+  gcc_jit_block_end_with_jump (loop_body, NULL, loop_cond);
+
+  /* return sum */
+  gcc_jit_block_end_with_return (
+    after_loop,
+    NULL,
+    gcc_jit_lvalue_as_rvalue (sum));
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  typedef int (*loop_test_fn_type) (int);
+  CHECK_NON_NULL (result);
+  loop_test_fn_type loop_test =
+    (loop_test_fn_type)gcc_jit_result_get_code (result, "loop_test");
+  CHECK_NON_NULL (loop_test);
+  int val = loop_test (10);
+  note ("loop_test returned: %d", val);
+  CHECK_VALUE (val, 285);
+}
diff --git a/gcc/testsuite/jit.dg/test-threads.c b/gcc/testsuite/jit.dg/test-threads.c
new file mode 100644 (file)
index 0000000..7c248cc
--- /dev/null
@@ -0,0 +1,252 @@
+/* test-threads.c
+
+   As per test-combination.c, construct a test case by combining other test
+   cases, to try to shake out state issues.  However each test runs in a
+   separate thread.  */
+
+#include <pthread.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+/* dejagnu.h isn't thread-safe; there's a shared "buffer", and the counts
+   of "passed"/"failed" etc are globals.
+
+   We get around this by putting a mutex around pass/fail calls.
+ */
+
+static pthread_mutex_t dg_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+/* By defining MAKE_DEJAGNU_H_THREADSAFE before we include harness.h,
+   harness.h injects macros before including <dejagnu.h> so that the
+   pass/fail functions become "dejagnu_pass"/"dejagnu_fail" etc.  */
+
+void dejagnu_pass (const char* fmt, ...);
+void dejagnu_fail (const char* fmt, ...);
+void dejagnu_note (const char* fmt, ...);
+
+/* We now provide our own implementations of "pass"/"fail"/"note", which
+   call the underlying dejagnu implementations, but with a mutex.  */
+
+inline void
+pass (const char* fmt, ...)
+{
+  va_list ap;
+  char buffer[512];
+
+  va_start (ap, fmt);
+  vsnprintf (buffer, sizeof (buffer), fmt, ap);
+  va_end (ap);
+
+  pthread_mutex_lock (&dg_mutex);
+  dejagnu_pass (buffer);
+  pthread_mutex_unlock (&dg_mutex);
+}
+
+inline void
+fail (const char* fmt, ...)
+{
+  va_list ap;
+  char buffer[512];
+
+  va_start (ap, fmt);
+  vsnprintf (buffer, sizeof (buffer), fmt, ap);
+  va_end (ap);
+
+  pthread_mutex_lock (&dg_mutex);
+  dejagnu_fail (buffer);
+  pthread_mutex_unlock (&dg_mutex);
+}
+
+inline void
+note (const char* fmt, ...)
+{
+  va_list ap;
+  char buffer[512];
+
+  va_start (ap, fmt);
+  vsnprintf (buffer, sizeof (buffer), fmt, ap);
+  va_end (ap);
+
+  pthread_mutex_lock (&dg_mutex);
+  dejagnu_note (buffer);
+  pthread_mutex_unlock (&dg_mutex);
+}
+
+#define MAKE_DEJAGNU_H_THREADSAFE
+
+/* We also need to provide our own version of TEST_NAME.  */
+#define TEST_NAME
+
+/* We can now include all of the relevant selftests.  */
+
+#include "all-non-failing-tests.h"
+
+#define TEST_PROVIDES_MAIN
+#define TEST_ESCHEWS_TEST_JIT
+
+/* Now construct a test case from all the other test cases.
+
+   We undefine COMBINED_TEST so that we can now include harness.h
+   "for real".  */
+#undef COMBINED_TEST
+#include "harness.h"
+
+struct testcase
+{
+  const char *m_name;
+  void (*m_hook_to_create_code) (gcc_jit_context *ctxt,
+                                void * user_data);
+  void (*m_hook_to_verify_code) (gcc_jit_context *ctxt,
+                                gcc_jit_result *result);
+};
+
+const struct testcase testcases[] = {
+  {"accessing_struct",
+   create_code_accessing_struct,
+   verify_code_accessing_struct},
+  {"accessing_union",
+   create_code_accessing_union,
+   verify_code_accessing_union},
+  {"array_as_pointer",
+   create_code_array_as_pointer,
+   verify_code_array_as_pointer},
+  {"arrays",
+   create_code_arrays,
+   verify_code_arrays},
+  {"calling_external_function",
+   create_code_calling_external_function,
+   verify_code_calling_external_function},
+  {"calling_function_ptr",
+   create_code_calling_function_ptr,
+   verify_code_calling_function_ptr},
+  {"dot_product",
+   create_code_dot_product,
+   verify_code_dot_product},
+  {"expressions",
+   create_code_expressions,
+   verify_code_expressions},
+  {"factorial",
+   create_code_factorial,
+   verify_code_factorial},
+  {"fibonacci",
+   create_code_fibonacci,
+   verify_code_fibonacci},
+  {"functions",
+   create_code_functions,
+   verify_code_functions},
+  {"hello_world",
+   create_code_hello_world,
+   verify_code_hello_world},
+  {"linked_list",
+   create_code_linked_list,
+   verify_code_linked_list},
+  {"long_names",
+   create_code_long_names,
+   verify_code_long_names},
+  {"quadratic",
+   create_code_quadratic,
+   verify_code_quadratic},
+  {"nested_loop",
+   create_code_nested_loop,
+   verify_code_nested_loop},
+  {"reading_struct ",
+   create_code_reading_struct ,
+   verify_code_reading_struct },
+  {"string_literal",
+   create_code_string_literal,
+   verify_code_string_literal},
+  {"sum_of_squares",
+   create_code_sum_of_squares,
+   verify_code_sum_of_squares},
+  {"types",
+   create_code_types,
+   verify_code_types},
+  {"using_global",
+   create_code_using_global,
+   verify_code_using_global},
+  {"volatile",
+   create_code_volatile,
+   verify_code_volatile}
+};
+
+const int num_testcases = (sizeof (testcases) / sizeof (testcases[0]));
+
+struct thread_data
+{
+  pthread_t m_tid;
+  const struct testcase *m_testcase;
+};
+
+static const char *argv0;
+
+void *
+run_threaded_test (void *data)
+{
+  struct thread_data *thread = (struct thread_data *)data;
+  int i;
+
+  for (i = 0; i < 5; i++)
+    {
+      gcc_jit_context *ctxt;
+      gcc_jit_result *result;
+
+      note ("run_threaded_test: %s iteration: %d",
+           thread->m_testcase->m_name, i);
+
+      ctxt = gcc_jit_context_acquire ();
+
+      set_options (ctxt, argv0);
+
+      thread->m_testcase->m_hook_to_create_code (ctxt, NULL);
+
+      result = gcc_jit_context_compile (ctxt);
+
+      thread->m_testcase->m_hook_to_verify_code (ctxt, result);
+
+      gcc_jit_context_release (ctxt);
+
+      /* Once we're done with the code, this unloads the built .so file: */
+      gcc_jit_result_release (result);
+    }
+
+  return NULL;
+}
+
+int
+main (int argc, char **argv)
+{
+  int i;
+
+  snprintf (test, sizeof (test),
+           "%s",
+           extract_progname (argv[0]));
+
+  argv0 = argv[0];
+
+  /* The individual testcases are not thread-safe (some have their own
+     global variables), so we have one thread per test-case.  */
+  struct thread_data *threads =
+    calloc (num_testcases, sizeof (struct thread_data));
+
+  /* Start a thread per test-case.  */
+  for (i = 0; i < num_testcases; i++)
+    {
+      struct thread_data *thread = &threads[i];
+      thread->m_testcase = &testcases[i];
+      pthread_create (&thread->m_tid,
+                     NULL,
+                     run_threaded_test,
+                     thread);
+    }
+
+  /* Wait for all the threads to be done.  */
+  for (i = 0; i < num_testcases; i++)
+    {
+      struct thread_data *thread = &threads[i];
+      (void)pthread_join (thread->m_tid, NULL);
+    }
+
+  totals ();
+
+  return 0;
+}
diff --git a/gcc/testsuite/jit.dg/test-types.c b/gcc/testsuite/jit.dg/test-types.c
new file mode 100644 (file)
index 0000000..8debcd7
--- /dev/null
@@ -0,0 +1,361 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <stdbool.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+struct zoo
+{
+  void *m_void_ptr;
+
+  bool m_bool;
+
+  char m_char;
+  signed char m_signed_char;
+  unsigned char m_unsigned_char;
+
+  short m_short;
+  unsigned short m_unsigned_short;
+
+  int m_int;
+  unsigned int m_unsigned_int;
+
+  long m_long;
+  unsigned long m_unsigned_long;
+
+  long long m_long_long;
+  unsigned long long m_unsigned_long_long;
+
+  int m_sized_int_type;
+
+  float m_float;
+  double m_double;
+  long double m_long_double;
+
+  const char *m_const_char_ptr;
+
+  size_t m_size_t;
+
+  FILE *m_FILE_ptr;
+};
+
+int test_int = 42;
+int *test_ptr = &test_int;
+
+const char *test_string = "test_string";
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  /* Let's try to inject the equivalent of:
+
+     void
+     test_caller (struct zoo *z)
+     {
+       for each fields "m_field":
+         z->m_field = ...some data;
+     }
+  */
+  gcc_jit_type *void_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+
+#define CREATE_FIELD(TYPE, NAME) \
+  gcc_jit_context_new_field ( \
+       ctxt, NULL, \
+       gcc_jit_context_get_type (ctxt, TYPE), \
+       NAME)
+
+  gcc_jit_field *field_m_void_ptr =
+    CREATE_FIELD (GCC_JIT_TYPE_VOID_PTR, "m_void_ptr");
+
+  gcc_jit_field *field_m_bool =
+    CREATE_FIELD (GCC_JIT_TYPE_BOOL, "m_bool");
+
+  gcc_jit_field *field_m_char =
+    CREATE_FIELD (GCC_JIT_TYPE_CHAR, "m_char");
+  gcc_jit_field *field_m_signed_char =
+    CREATE_FIELD (GCC_JIT_TYPE_SIGNED_CHAR, "m_signed_char");
+  gcc_jit_field *field_m_unsigned_char =
+    CREATE_FIELD (GCC_JIT_TYPE_UNSIGNED_CHAR, "m_unsigned_char");
+
+  gcc_jit_field *field_m_short =
+    CREATE_FIELD (GCC_JIT_TYPE_SHORT, "m_short");
+  gcc_jit_field *field_m_unsigned_short =
+    CREATE_FIELD (GCC_JIT_TYPE_UNSIGNED_SHORT, "m_unsigned_short");
+
+  gcc_jit_field *field_m_int =
+    CREATE_FIELD (GCC_JIT_TYPE_INT, "m_int");
+  gcc_jit_field *field_m_unsigned_int =
+    CREATE_FIELD (GCC_JIT_TYPE_UNSIGNED_INT, "m_unsigned_int");
+
+  gcc_jit_field *field_m_long =
+    CREATE_FIELD (GCC_JIT_TYPE_LONG, "m_long");
+  gcc_jit_field *field_m_unsigned_long =
+    CREATE_FIELD (GCC_JIT_TYPE_UNSIGNED_LONG, "m_unsigned_long");
+
+  gcc_jit_field *field_m_long_long =
+    CREATE_FIELD (GCC_JIT_TYPE_LONG_LONG, "m_long_long");
+  gcc_jit_field *field_m_unsigned_long_long =
+    CREATE_FIELD (GCC_JIT_TYPE_UNSIGNED_LONG_LONG, "m_unsigned_long_long");
+
+  /* Signed int type with sizeof (int): */
+  gcc_jit_type *sized_int_type =
+    gcc_jit_context_get_int_type (ctxt, sizeof (int), 1);
+  gcc_jit_field *field_m_sized_int_type =
+    gcc_jit_context_new_field (
+      ctxt, NULL, sized_int_type, "m_sized_int_type");
+
+  gcc_jit_field *field_m_float =
+    CREATE_FIELD (GCC_JIT_TYPE_FLOAT, "m_float");
+  gcc_jit_field *field_m_double =
+    CREATE_FIELD (GCC_JIT_TYPE_DOUBLE, "m_double");
+  gcc_jit_field *field_m_long_double =
+    CREATE_FIELD (GCC_JIT_TYPE_LONG_DOUBLE, "m_long_double");
+
+  gcc_jit_field *field_m_const_char_ptr =
+    CREATE_FIELD (GCC_JIT_TYPE_CONST_CHAR_PTR, "m_const_char_ptr");
+
+  gcc_jit_field *field_m_size_t =
+    CREATE_FIELD (GCC_JIT_TYPE_SIZE_T, "m_size_t");
+
+  gcc_jit_field *field_m_FILE_ptr =
+    CREATE_FIELD (GCC_JIT_TYPE_FILE_PTR, "m_FILE_ptr");
+
+#undef CREATE_FIELD
+
+  gcc_jit_field *zoo_fields[] = {
+    field_m_void_ptr,
+
+    field_m_bool,
+
+    field_m_char,
+    field_m_signed_char,
+    field_m_unsigned_char,
+
+    field_m_short,
+    field_m_unsigned_short,
+
+    field_m_int,
+    field_m_unsigned_int,
+
+    field_m_long,
+    field_m_unsigned_long,
+
+    field_m_long_long,
+    field_m_unsigned_long_long,
+
+    field_m_sized_int_type,
+
+    field_m_float,
+    field_m_double,
+    field_m_long_double,
+
+    field_m_const_char_ptr,
+
+    field_m_size_t,
+
+    field_m_FILE_ptr
+  };
+
+  gcc_jit_type *zoo_type =
+    gcc_jit_struct_as_type (
+      gcc_jit_context_new_struct_type (
+        ctxt,
+       NULL,
+       "zoo",
+       sizeof (zoo_fields) / sizeof (zoo_fields[0]),
+       zoo_fields));
+
+  gcc_jit_type *zoo_ptr_type =
+    gcc_jit_type_get_pointer (zoo_type);
+
+  /* Build the test_fn.         */
+  gcc_jit_param *param_z =
+    gcc_jit_context_new_param (ctxt, NULL, zoo_ptr_type, "z");
+  gcc_jit_function *test_fn =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                 GCC_JIT_FUNCTION_EXPORTED,
+                                 void_type,
+                                 "test_types",
+                                 1, &param_z,
+                                 0);
+  gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
+
+  /* Write to the various fields of param "z". */
+#define ASSIGN(FIELD, EXPR) \
+  gcc_jit_block_add_assignment (               \
+    block, NULL,                               \
+    gcc_jit_rvalue_dereference_field (         \
+      gcc_jit_param_as_rvalue (param_z),       \
+      NULL,                                    \
+      (FIELD)),                                \
+    (EXPR));
+
+  ASSIGN(
+    field_m_void_ptr,
+    gcc_jit_context_new_rvalue_from_ptr (
+      ctxt,
+      gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID_PTR),
+      test_ptr))
+
+  ASSIGN(field_m_bool,
+    gcc_jit_context_new_rvalue_from_int (
+      ctxt,
+      gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_BOOL), 1))
+
+  ASSIGN(field_m_char,
+    gcc_jit_context_new_rvalue_from_int (
+      ctxt,
+      gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_CHAR),
+      'V'))
+  ASSIGN(field_m_signed_char,
+    gcc_jit_context_new_rvalue_from_int (
+      ctxt,
+      gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_SIGNED_CHAR),
+      -37))
+  ASSIGN(field_m_unsigned_char,
+    gcc_jit_context_new_rvalue_from_int (
+      ctxt,
+      gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_UNSIGNED_CHAR),
+      200))
+
+  ASSIGN(field_m_short,
+    gcc_jit_context_new_rvalue_from_int (
+      ctxt,
+      gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_SHORT),
+      -900))
+  ASSIGN(field_m_unsigned_short,
+    gcc_jit_context_new_rvalue_from_int (
+      ctxt,
+      gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_UNSIGNED_SHORT),
+      0x3000))
+
+  ASSIGN(field_m_int,
+    gcc_jit_context_new_rvalue_from_int (
+      ctxt,
+      gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT),
+      -0x2000))
+  ASSIGN(field_m_unsigned_int,
+    gcc_jit_context_new_rvalue_from_int (
+      ctxt,
+      gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_UNSIGNED_INT),
+      1234567))
+
+  ASSIGN(field_m_long,
+    gcc_jit_context_new_rvalue_from_int (
+      ctxt,
+      gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_LONG),
+      -5))
+  ASSIGN(field_m_unsigned_long,
+    gcc_jit_context_new_rvalue_from_int (
+      ctxt,
+      gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_UNSIGNED_LONG),
+      12345678))
+
+  ASSIGN(field_m_long_long,
+    gcc_jit_context_new_rvalue_from_int (
+      ctxt,
+      gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_LONG_LONG),
+      -42))
+  ASSIGN(field_m_unsigned_long_long,
+    gcc_jit_context_new_rvalue_from_int (
+      ctxt,
+      gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_UNSIGNED_LONG_LONG),
+      123456789))
+
+  ASSIGN(field_m_sized_int_type,
+    gcc_jit_context_new_rvalue_from_int (
+      ctxt,
+      sized_int_type, 500))
+
+  ASSIGN(field_m_float,
+    gcc_jit_context_new_rvalue_from_double (
+      ctxt,
+      gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_FLOAT),
+      3.141))
+  ASSIGN(field_m_double,
+    gcc_jit_context_new_rvalue_from_double (
+      ctxt,
+      gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_DOUBLE),
+      3.141))
+  ASSIGN(field_m_long_double,
+    gcc_jit_context_new_rvalue_from_double (
+      ctxt,
+      gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_LONG_DOUBLE),
+      3.141))
+
+  ASSIGN(field_m_const_char_ptr,
+    gcc_jit_context_new_rvalue_from_ptr (
+      ctxt,
+      gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_CONST_CHAR_PTR),
+      (char *)test_string))
+
+  ASSIGN(field_m_size_t,
+    gcc_jit_context_new_rvalue_from_int (
+      ctxt,
+      gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_SIZE_T),
+      sizeof (struct zoo)))
+
+  ASSIGN(field_m_FILE_ptr,
+    gcc_jit_context_new_rvalue_from_ptr (
+      ctxt,
+      gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_FILE_PTR),
+      stderr))
+
+#undef ASSIGN
+
+  gcc_jit_block_end_with_void_return (block, NULL);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  typedef void (*fn_type) (struct zoo *);
+  CHECK_NON_NULL (result);
+
+  fn_type test_types =
+    (fn_type)gcc_jit_result_get_code (result, "test_types");
+  CHECK_NON_NULL (test_types);
+
+  struct zoo z;
+  memset (&z, 0xf0, sizeof (z));
+
+  /* Call the JIT-generated function.  */
+  test_types (&z);
+
+  /* Verify that it correctly wrote to the various fields.  */
+  CHECK_VALUE (z.m_void_ptr, test_ptr);
+
+  CHECK_VALUE (z.m_bool, true);
+
+  CHECK_VALUE (z.m_char, 'V');
+  CHECK_VALUE (z.m_signed_char, -37);
+  CHECK_VALUE (z.m_unsigned_char, 200);
+
+  CHECK_VALUE (z.m_short, -900);
+  CHECK_VALUE (z.m_unsigned_short, 0x3000);
+
+  CHECK_VALUE (z.m_int, -0x2000);
+  CHECK_VALUE (z.m_unsigned_int, 1234567);
+
+  CHECK_VALUE (z.m_long, -5);
+  CHECK_VALUE (z.m_unsigned_long, 12345678);
+
+  CHECK_VALUE (z.m_long_long, -42);
+  CHECK_VALUE (z.m_unsigned_long_long, 123456789);
+
+  CHECK_VALUE (z.m_sized_int_type, 500);
+
+  CHECK_VALUE (z.m_float, 3.141f);
+  CHECK_VALUE (z.m_double, 3.141);
+  CHECK_VALUE (z.m_long_double, 3.141);
+
+  CHECK_VALUE (z.m_const_char_ptr, test_string);
+
+  CHECK_VALUE (z.m_size_t, sizeof (struct zoo));
+
+  CHECK_VALUE (z.m_FILE_ptr, stderr);
+}
diff --git a/gcc/testsuite/jit.dg/test-using-global.c b/gcc/testsuite/jit.dg/test-using-global.c
new file mode 100644 (file)
index 0000000..3ec949f
--- /dev/null
@@ -0,0 +1,73 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+  extern int the_global;
+
+#ifdef __cplusplus
+}
+#endif
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  /* Let's try to inject the equivalent of:
+     extern int the_global;
+
+     void
+     test_using_global (void)
+     {
+       the_global += 1;
+     }
+  */
+  gcc_jit_type *void_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+  gcc_jit_type *int_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+  /* Build the test_fn.  */
+  gcc_jit_function *test_fn =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                 GCC_JIT_FUNCTION_EXPORTED,
+                                 void_type,
+                                 "test_using_global",
+                                 0, NULL,
+                                 0);
+  gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
+
+  gcc_jit_block_add_assignment_op (
+    block, NULL,
+    gcc_jit_context_new_global (ctxt, NULL, int_type, "the_global"),
+    GCC_JIT_BINARY_OP_PLUS,
+    gcc_jit_context_one (ctxt, int_type));
+  gcc_jit_block_end_with_void_return (block, NULL);
+}
+
+int the_global;
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  typedef void (*fn_type) (void);
+  CHECK_NON_NULL (result);
+
+  fn_type test_using_global =
+    (fn_type)gcc_jit_result_get_code (result, "test_using_global");
+  CHECK_NON_NULL (test_using_global);
+
+  the_global = 42;
+
+  /* Call the JIT-generated function.  */
+  test_using_global ();
+
+  /* Verify that it correctly modified the_global.  */
+  CHECK_VALUE (the_global, 43);
+}
+
diff --git a/gcc/testsuite/jit.dg/test-volatile.c b/gcc/testsuite/jit.dg/test-volatile.c
new file mode 100644 (file)
index 0000000..3ef3ca5
--- /dev/null
@@ -0,0 +1,66 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+volatile int the_volatile;
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  /* Let's try to inject the equivalent of:
+     extern volatile int the_volatile;
+
+     int
+     test_using_volatile (void)
+     {
+       return the_volatile;
+     }
+  */
+  gcc_jit_type *int_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+  gcc_jit_type *volatile_int_type =
+    gcc_jit_type_get_volatile (int_type);
+
+  /* Build the test_fn.  */
+  gcc_jit_function *test_fn =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                 GCC_JIT_FUNCTION_EXPORTED,
+                                 int_type,
+                                 "test_using_volatile",
+                                 0, NULL,
+                                 0);
+  gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
+  gcc_jit_lvalue *read_of_the_volatile =
+    gcc_jit_rvalue_dereference (
+      gcc_jit_context_new_rvalue_from_ptr (
+        ctxt,
+       gcc_jit_type_get_pointer (volatile_int_type),
+       (void *)&the_volatile),
+      NULL);
+
+  gcc_jit_block_end_with_return (
+    block, NULL,
+    gcc_jit_lvalue_as_rvalue (read_of_the_volatile));
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  typedef int (*fn_type) (void);
+  CHECK_NON_NULL (result);
+
+  fn_type test_using_volatile =
+    (fn_type)gcc_jit_result_get_code (result, "test_using_volatile");
+  CHECK_NON_NULL (test_using_volatile);
+
+  the_volatile = 42;
+
+  /* Call the JIT-generated function.  */
+  test_using_volatile ();
+
+  CHECK_VALUE (test_using_volatile (), 42);
+}
+
index b74cbb0bca730fcf341f055cb9acd17f8ba67c2b..f3e7b8890696dadf2d4b7868cf1f45e05e58c6af 100644 (file)
@@ -280,3 +280,9 @@ DEFTIMEVAR (TV_VERIFY_LOOP_CLOSED    , "verify loop closed")
 DEFTIMEVAR (TV_VERIFY_RTL_SHARING    , "verify RTL sharing")
 DEFTIMEVAR (TV_REBUILD_FREQUENCIES   , "rebuild frequencies")
 DEFTIMEVAR (TV_REPAIR_LOOPS         , "repair loop structures")
+
+/* Stuff used by libgccjit.so.  */
+DEFTIMEVAR (TV_JIT_REPLAY           , "replay of JIT client activity")
+DEFTIMEVAR (TV_ASSEMBLE             , "assemble JIT code")
+DEFTIMEVAR (TV_LINK                 , "link JIT code")
+DEFTIMEVAR (TV_LOAD                 , "load JIT result")
index e48268296bfab1c177acdb177247741753305f4e..093bc14a510b6bc7272a34beb8d9dcbb8900183d 100644 (file)
@@ -1,3 +1,7 @@
+2014-11-11  David Malcolm  <dmalcolm@redhat.com>
+
+       * ChangeLog.jit: New.
+
 2014-10-28  Richard Henderson  <rth@redhat.com>
 
        * longlong.h [__alpha] (umul_ppmm): Disable for c++.
diff --git a/include/ChangeLog.jit b/include/ChangeLog.jit
new file mode 100644 (file)
index 0000000..84acd33
--- /dev/null
@@ -0,0 +1,11 @@
+2014-09-25  David Malcolm  <dmalcolm@redhat.com>
+
+       * libiberty.h (choose_tmpdir): New prototype.
+       * ChangeLog.jit: New.
+
+\f
+Copyright (C) 2014 Free Software Foundation, Inc.
+
+Copying and distribution of this file, with or without modification,
+are permitted in any medium without royalty provided the copyright
+notice and this notice are preserved.
index 2530d19b96aa6ed84800e9be53f22e7e2799f1e3..ec6fbc3494d7463d5122fe0e810129e875fc5290 100644 (file)
@@ -1,3 +1,7 @@
+2014-11-11  David Malcolm  <dmalcolm@redhat.com>
+
+       * ChangeLog.jit: New.
+
 2014-11-11  Francois-Xavier Coudert  <fxcoudert@gcc.gnu.org>
 
        PR target/63610
diff --git a/libbacktrace/ChangeLog.jit b/libbacktrace/ChangeLog.jit
new file mode 100644 (file)
index 0000000..6b60e3b
--- /dev/null
@@ -0,0 +1,14 @@
+2014-09-24  David Malcolm  <dmalcolm@redhat.com>
+
+       * ChangeLog.jit: Add copyright footer.
+
+2013-10-03  David Malcolm  <dmalcolm@redhat.com>
+
+       * configure.ac: Add --enable-host-shared.
+       * configure: Regenerate.
+\f
+Copyright (C) 2013-2014 Free Software Foundation, Inc.
+
+Copying and distribution of this file, with or without modification,
+are permitted in any medium without royalty provided the copyright
+notice and this notice are preserved.
index 331a82dcd63bbab5ff1cbc6d5d489507b14bb47a..aa860b5ff1f7f37fe72c6a14b7a180868e19a455 100644 (file)
@@ -1,3 +1,7 @@
+2014-11-11  David Malcolm  <dmalcolm@redhat.com>
+
+       * ChangeLog.jit: New.
+
 2014-11-10  Edward Smith-Rowland  <3dw4rd@verizon.net>
 
        * include/cpplib.h (cpp_callbacks): Add has_attribute.
diff --git a/libcpp/ChangeLog.jit b/libcpp/ChangeLog.jit
new file mode 100644 (file)
index 0000000..5182b9c
--- /dev/null
@@ -0,0 +1,22 @@
+2014-09-24  David Malcolm  <dmalcolm@redhat.com>
+
+       * ChangeLog.jit: Add copyright footer.
+
+2013-10-07  David Malcolm  <dmalcolm@redhat.com>
+
+       * Makefile.in: Set PICFLAG from configure script; add it to
+       ALL_CFLAGS.
+       * configure.ac (--enable-host-shared): Set up PICFLAG rather
+       than attempting to append -fPIC to CFLAGS, CXXFLAGS, LDFLAGS.
+       * configure: Regenerate.
+
+2013-10-03  David Malcolm  <dmalcolm@redhat.com>
+
+       * configure.ac: Add --enable-host-shared.
+       * configure: Regenerate.
+\f
+Copyright (C) 2013-2014 Free Software Foundation, Inc.
+
+Copying and distribution of this file, with or without modification,
+are permitted in any medium without royalty provided the copyright
+notice and this notice are preserved.
index 14df41c99ea4334173c0f0b907f33a31bcdd7053..d3244b65a3690994cc9a335807fd8f510c55049e 100644 (file)
@@ -1,3 +1,7 @@
+2014-11-11  David Malcolm  <dmalcolm@redhat.com>
+
+       * ChangeLog.jit: New.
+
 2014-01-23  Marek Polacek  <polacek@redhat.com>
 
        PR c/59871
diff --git a/libdecnumber/ChangeLog.jit b/libdecnumber/ChangeLog.jit
new file mode 100644 (file)
index 0000000..5182b9c
--- /dev/null
@@ -0,0 +1,22 @@
+2014-09-24  David Malcolm  <dmalcolm@redhat.com>
+
+       * ChangeLog.jit: Add copyright footer.
+
+2013-10-07  David Malcolm  <dmalcolm@redhat.com>
+
+       * Makefile.in: Set PICFLAG from configure script; add it to
+       ALL_CFLAGS.
+       * configure.ac (--enable-host-shared): Set up PICFLAG rather
+       than attempting to append -fPIC to CFLAGS, CXXFLAGS, LDFLAGS.
+       * configure: Regenerate.
+
+2013-10-03  David Malcolm  <dmalcolm@redhat.com>
+
+       * configure.ac: Add --enable-host-shared.
+       * configure: Regenerate.
+\f
+Copyright (C) 2013-2014 Free Software Foundation, Inc.
+
+Copying and distribution of this file, with or without modification,
+are permitted in any medium without royalty provided the copyright
+notice and this notice are preserved.
index ff06b184aaa6e77150519fe3ab808cc4c334b22f..d82cce914897c177c2cd18eea22a30b15948f915 100644 (file)
@@ -1,3 +1,7 @@
+2014-11-11  David Malcolm  <dmalcolm@redhat.com>
+
+       * ChangeLog.jit: New.
+
 2014-11-05  Rainer Orth  <ro@CeBiTec.Uni-Bielefeld.DE>
 
        * sigsetmask.c (_POSIX_SOURCE): Remove.
diff --git a/libiberty/ChangeLog.jit b/libiberty/ChangeLog.jit
new file mode 100644 (file)
index 0000000..5b64f80
--- /dev/null
@@ -0,0 +1,23 @@
+2014-09-25  David Malcolm  <dmalcolm@redhat.com>
+
+       * choose-temp.c (choose_tmpdir): Remove now-redundant local
+       copy of prototype.
+       * functions.texi: Regenerate.
+       * make-temp-file.c (choose_tmpdir): Convert return type from
+       char * to const char * - given that this returns a pointer to
+       a memoized allocation, the caller must not touch it.
+
+2014-09-24  David Malcolm  <dmalcolm@redhat.com>
+
+       * ChangeLog.jit: Add copyright footer.
+
+2013-10-03  David Malcolm  <dmalcolm@redhat.com>
+
+       * configure.ac: If --enable-host-shared, use -fPIC.
+       * configure: Regenerate.
+\f
+Copyright (C) 2013-2014 Free Software Foundation, Inc.
+
+Copying and distribution of this file, with or without modification,
+are permitted in any medium without royalty provided the copyright
+notice and this notice are preserved.
diff --git a/zlib/ChangeLog.jit b/zlib/ChangeLog.jit
new file mode 100644 (file)
index 0000000..64ba6e1
--- /dev/null
@@ -0,0 +1,22 @@
+2014-09-24  David Malcolm  <dmalcolm@redhat.com>
+
+       * ChangeLog.jit: Add copyright footer.
+
+2013-10-07  David Malcolm  <dmalcolm@redhat.com>
+
+       * Makefile.am: Add PICFLAG to libz_a_CFLAGS.
+       * configure.ac (--enable-host-shared): Set up PICFLAG rather
+       than attempting to append -fPIC to CFLAGS.
+       * Makefile.in: Regenerate.
+       * configure: Regenerate.
+
+2013-10-03  David Malcolm  <dmalcolm@redhat.com>
+
+       * configure.ac: Add --enable-host-shared.
+       * configure: Regenerate.
+\f
+Copyright (C) 2013-2014 Free Software Foundation, Inc.
+
+Copying and distribution of this file, with or without modification,
+are permitted in any medium without royalty provided the copyright
+notice and this notice are preserved.