public inbox for jit@gcc.gnu.org
 help / color / mirror / Atom feed
* Re: Stage 3 RFC: using "jit" for ahead-of-time compilation
  2015-01-01  0:00 Stage 3 RFC: using "jit" for ahead-of-time compilation David Malcolm
  2015-01-01  0:00 ` Richard Biener
@ 2015-01-01  0:00 ` Jakub Jelinek
  1 sibling, 0 replies; 6+ messages in thread
From: Jakub Jelinek @ 2015-01-01  0:00 UTC (permalink / raw)
  To: David Malcolm; +Cc: jit, gcc-patches, Richard Biener, Joseph Myers

On Thu, Jan 15, 2015 at 03:05:59PM -0500, David Malcolm wrote:
> Release managers: given that this only touches the jit, and that the jit
> is off by default, any objections if I go ahead and commit this?
> It's a late-breaking feature, but the jit as a whole is new, and
> I think the following is a big win, so I'd like to proceed with this in
> stage 3 (i.e. in the next 24 hours).  There are docs and testcases.

Ok with me.

	Jakub

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] Re: Stage 3 RFC: using "jit" for ahead-of-time compilation
  2015-01-01  0:00     ` Richard Biener
@ 2015-01-01  0:00       ` David Malcolm
  0 siblings, 0 replies; 6+ messages in thread
From: David Malcolm @ 2015-01-01  0:00 UTC (permalink / raw)
  To: Richard Biener; +Cc: jit, GCC Patches, Jakub Jelinek, Joseph Myers

On Mon, 2015-01-19 at 10:51 +0100, Richard Biener wrote:
> On Fri, Jan 16, 2015 at 7:47 PM, David Malcolm <dmalcolm@redhat.com> wrote:
> > On Thu, 2015-01-15 at 22:50 +0100, Richard Biener wrote:
> >> On January 15, 2015 9:05:59 PM CET, David Malcolm <dmalcolm@redhat.com> wrote:
> >> >Release managers: given that this only touches the jit, and that the
> >> >jit
> >> >is off by default, any objections if I go ahead and commit this?
> >> >It's a late-breaking feature, but the jit as a whole is new, and
> >> >I think the following is a big win, so I'd like to proceed with this in
> >> >stage 3 (i.e. in the next 24 hours).  There are docs and testcases.
> >> >
> >> >New jit API entrypoint: gcc_jit_context_compile_to_file
> >> >
> >> >This patch adds a way to use libgccjit for ahead-of-time compilation.
> >> >I noticed that given the postprocessing steps the jit has to take to
> >> >turn the .s file into in-memory code (invoke driver to convert to
> >> >a .so and then dlopen), that it's not much of a leap to support
> >> >compiling the .s file into objects, dynamic libraries, and executables.
> >> >
> >> >Doing so seems like a big win from a feature standpoint: people with
> >> >pre-existing frontend code who want a backend can then plug in
> >> >libgccjit
> >> >and have a compiler, without needing to write it as a GCC frontend, or
> >> >use LLVM.
> >>
> >> Note that you should make them aware of our runtime license with
> >> respect to the eligible compilation process.  Which means this is not
> >> a way to implement proprietary front ends.
> >>
> >> Richard.
> >
> > IANAL, but as I understand things, the runtime license is an additional
> > grant of rights that covers certain components of GCC that bear the GCC
> > Runtime Library Exception, allowing them to be used in certain
> > additional ways beyond regular GPLv3-compliance.
> >
> > libgccjit doesn't have that exception; it's GPLv3.
> >
> > Perhaps an argument could be made for libgccjit to have the exception,
> > if the FSF think that that would better serve the FSF's mission; right
> > now, I'm merely trying to provide a technical means to modularity.
> >
> > Assuming the above is correct, anything linked against it needs to be
> > GPLv3-compatible.  Hence any such frontend linked against libgccjit
> > would need to be GPLv3-compatible.
> >
> > Attached is a patch (on top of the proposed one below), to clarify the
> > wording in the new tutorial a little, to remind people that such linking
> > needs to be license-compatible (without actually spelling out what the
> > license is, though it's visible at the top of the public header file,
> > libgccjit.h, as GPLv3 or later without the runtime library exception).
> >
> > Are the combined patches OK by you?
> 
> Yes.
> 
> Thanks,
> Richard.

Thanks.  I've committed the combination of the two patches to trunk as
r219876.  Sorry about the lateness of this feature.

With this commit, gcc now has a brainf*** frontend (albeit one hidden
deep in the jit examples dir, and not using the regular frontend
machinery).

Dave

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Stage 3 RFC: using "jit" for ahead-of-time compilation
  2015-01-01  0:00 Stage 3 RFC: using "jit" for ahead-of-time compilation David Malcolm
@ 2015-01-01  0:00 ` Richard Biener
  2015-01-01  0:00   ` [PATCH] " David Malcolm
  2015-01-01  0:00 ` Jakub Jelinek
  1 sibling, 1 reply; 6+ messages in thread
From: Richard Biener @ 2015-01-01  0:00 UTC (permalink / raw)
  To: David Malcolm, jit, gcc-patches, Jakub Jelinek, Joseph Myers

On January 15, 2015 9:05:59 PM CET, David Malcolm <dmalcolm@redhat.com> wrote:
>Release managers: given that this only touches the jit, and that the
>jit
>is off by default, any objections if I go ahead and commit this?
>It's a late-breaking feature, but the jit as a whole is new, and
>I think the following is a big win, so I'd like to proceed with this in
>stage 3 (i.e. in the next 24 hours).  There are docs and testcases.
>
>New jit API entrypoint: gcc_jit_context_compile_to_file
>
>This patch adds a way to use libgccjit for ahead-of-time compilation.
>I noticed that given the postprocessing steps the jit has to take to
>turn the .s file into in-memory code (invoke driver to convert to
>a .so and then dlopen), that it's not much of a leap to support
>compiling the .s file into objects, dynamic libraries, and executables.
>
>Doing so seems like a big win from a feature standpoint: people with
>pre-existing frontend code who want a backend can then plug in
>libgccjit
>and have a compiler, without needing to write it as a GCC frontend, or
>use LLVM.

Note that you should make them aware of our runtime license with respect to the eligible compilation process.  Which means this is not a way to implement proprietary front ends.

Richard.

>"jit" becomes something of a misnomer for this use-case.
>
>As an experiment, I used this technique to add a compiler for the
>language I'll refer to as "brainf" (ahem), and wrote this up for the
>libgccjit tutorial (it's all in the patch); prebuilt HTML can be seen
>at:
>https://dmalcolm.fedorapeople.org/gcc/libgccjit-api-docs-wip/intro/tutorial05.html
>
>The main things that are missing are:
> * specifying libraries to link against (Uli had some ideas about this)
>  * cross-compilation support (needs some deeper work, especially the
>    test suite, so deferrable to gcc 6, I guess)
>but the feature is useful with the patch as-is.
>
>The new test cases take jit.sum's # of expected passes
>from 7514 to 7571.
>
>gcc/jit/ChangeLog:
>	* docs/cp/topics/results.rst: Rename to...
>	* docs/cp/topics/compilation.rst: ...this, and add section on
>	ahead-of-time compilation.
>	* docs/cp/topics/index.rst: Update for renaming of results.rst
>	to compilation.rst.
>	* docs/examples/emit-alphabet.bf: New file, a sample "brainf"
>	script.
>	* docs/examples/tut05-bf.c: New file, implementing a compiler
>	for "brainf".
>	* docs/internals/test-hello-world.exe.log.txt: Update to reflect
>	changes to logger output.
>	* docs/intro/index.rst: Add tutorial05.rst
>	* docs/intro/tutorial05.rst: New file.
>	* docs/topics/results.rst: Rename to...
>	* docs/topics/compilation.rst: ...this, and add section on
>	ahead-of-time compilation.
>	* docs/topics/index.rst: Update for renaming of results.rst to
>	compilation.rst.
>	* jit-playback.c (gcc::jit::playback::context::compile): Convert
>	return type from result * to void.  Move the code to convert to
>	dso and dlopen the result to a new pure virtual "postprocess"
>	method.
>	(gcc::jit::playback::compile_to_memory::compile_to_memory): New
>	function.
>	(gcc::jit::playback::compile_to_memory::postprocess): New
>	function, based on playback::context::compile.
>	(gcc::jit::playback::compile_to_file::compile_to_file): New
>	function.
>	(gcc::jit::playback::compile_to_file::postprocess): New function.
>	(gcc::jit::playback::compile_to_file::copy_file): New function.
>	(gcc::jit::playback::context::convert_to_dso): Move internals
>	to...
>	(gcc::jit::playback::context::invoke_driver): New method.  Add
>	"-shared" and "-c" options to driver's argv as needed.
>	* jit-playback.h: Include "timevar.h".
>	(gcc::jit::playback::context::compile): Convert return type from
>	result * to void.
>	(gcc::jit::playback::context::postprocess): New pure virtual
>	function, making this an abstract base class.
>	(gcc::jit::playback::context::get_tempdir): New accessor.
>	(gcc::jit::playback::context::invoke_driver): New function.
>	(class gcc::jit::playback::compile_to_memory): New subclass of
>	playback::context.
>	(class gcc::jit::playback::compile_to_file): Likewise.
>	* jit-recording.c (gcc::jit::recording::context::compile): Use a
>	playback::compile_to_memory, and extract its result.
>	(gcc::jit::recording::context::compile_to_file): New function.
>	* jit-recording.h (gcc::jit::recording::context::compile_to_file):
>	New function.
>	* libgccjit++.h (gccjit::context::compile_to_file): New method.
>	* libgccjit.c (gcc_jit_context_compile): Update log message to
>	clarify that this is an in-memory compile.
>	(gcc_jit_context_compile_to_file): New function.
>	* libgccjit.h (gcc_jit_context): Clarify that you can compile
>	a context more than once, and that you can compile to a file
>	as well as to memory.
>	(gcc_jit_result): Clarify that this is the result of an
>	in-memory compilation.
>	(gcc_jit_context_compile): Clarify that you can compile, and that
>	this is an in-memory compilation.
>	(enum gcc_jit_output_kind): New enum.
>	(gcc_jit_context_compile_to_file): New function.
>	(gcc_jit_context_enable_dump): Clarify comment to cover both forms
>	of compilation.
>	* libgccjit.map (gcc_jit_context_compile_to_file): New API
>	entrypoint.
>	* notes.txt: Update to show the playback::context::postprocess
>	virtual function.
>
>gcc/testsuite/ChangeLog:
>	* jit.dg/harness.h: Include <unistd.h>.
>	(CHECK_NO_ERRORS): New.
>	(verify_code): Wrap prototype in #ifndef TEST_COMPILING_TO_FILE.
>	(test_jit): Support new macro TEST_COMPILING_TO_FILE for exercising
>	gcc_jit_context_compile_to_file.
>	* jit.dg/jit.exp (fixed_host_execute): Fix the code for passing on
>	args to the spawned executable.
>	(jit-expand-vars): New function.
>	(jit-exe-params): New variable.
>	(dg-jit-set-exe-params): New function.
>	(jit-dg-test): Detect testcases that use
>	jit-verify-compile-to-file and call jit-setup-compile-to-file.
>	Set arguments of spawned process to jit-exe-params.
>	(jit-get-output-filename): New function.
>	(jit-setup-compile-to-file): New function.
>	(jit-verify-compile-to-file): New function.
>	(jit-run-executable): New function.
>	(jit-verify-executable): New function.
>	* jit.dg/test-compile-to-assembler.c: New testcase.
>	* jit.dg/test-compile-to-dynamic-library.c: New testcase.
>	* jit.dg/test-compile-to-executable.c: New testcase.
>	* jit.dg/test-compile-to-object.c: New testcase.
>---
> gcc/jit/docs/cp/topics/compilation.rst             |  58 +++
> gcc/jit/docs/cp/topics/index.rst                   |   4 +-
> gcc/jit/docs/cp/topics/results.rst                 |  48 ---
> gcc/jit/docs/examples/emit-alphabet.bf             |  17 +
>gcc/jit/docs/examples/tut05-bf.c                   | 446
>+++++++++++++++++++++
> .../docs/internals/test-hello-world.exe.log.txt    |  48 ++-
> gcc/jit/docs/intro/index.rst                       |   3 +-
> gcc/jit/docs/intro/tutorial05.rst                  | 253 ++++++++++++
> gcc/jit/docs/topics/compilation.rst                | 199 +++++++++
> gcc/jit/docs/topics/index.rst                      |   4 +-
> gcc/jit/docs/topics/results.rst                    | 127 ------
>gcc/jit/jit-playback.c                             | 308 +++++++++++++-
> gcc/jit/jit-playback.h                             |  54 ++-
> gcc/jit/jit-recording.c                            |  40 +-
> gcc/jit/jit-recording.h                            |   4 +
> gcc/jit/libgccjit++.h                              |  12 +
> gcc/jit/libgccjit.c                                |  31 +-
> gcc/jit/libgccjit.h                                |  58 ++-
> gcc/jit/libgccjit.map                              |   1 +
> gcc/jit/notes.txt                                  |  13 +-
> gcc/testsuite/jit.dg/harness.h                     |  29 +-
> gcc/testsuite/jit.dg/jit.exp                       | 209 +++++++++-
> gcc/testsuite/jit.dg/test-compile-to-assembler.c   |  65 +++
> .../jit.dg/test-compile-to-dynamic-library.c       |  65 +++
> gcc/testsuite/jit.dg/test-compile-to-executable.c  | 110 +++++
> gcc/testsuite/jit.dg/test-compile-to-object.c      |  65 +++
> 26 files changed, 2026 insertions(+), 245 deletions(-)
> create mode 100644 gcc/jit/docs/cp/topics/compilation.rst
> delete mode 100644 gcc/jit/docs/cp/topics/results.rst
> create mode 100644 gcc/jit/docs/examples/emit-alphabet.bf
> create mode 100644 gcc/jit/docs/examples/tut05-bf.c
> create mode 100644 gcc/jit/docs/intro/tutorial05.rst
> create mode 100644 gcc/jit/docs/topics/compilation.rst
> delete mode 100644 gcc/jit/docs/topics/results.rst
> create mode 100644 gcc/testsuite/jit.dg/test-compile-to-assembler.c
>create mode 100644
>gcc/testsuite/jit.dg/test-compile-to-dynamic-library.c
> create mode 100644 gcc/testsuite/jit.dg/test-compile-to-executable.c
> create mode 100644 gcc/testsuite/jit.dg/test-compile-to-object.c
>
>diff --git a/gcc/jit/docs/cp/topics/compilation.rst
>b/gcc/jit/docs/cp/topics/compilation.rst
>new file mode 100644
>index 0000000..05917e8
>--- /dev/null
>+++ b/gcc/jit/docs/cp/topics/compilation.rst
>@@ -0,0 +1,58 @@
>+.. Copyright (C) 2014-2015 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:: cpp
>+
>+Compiling a context
>+===================
>+
>+Once populated, a :class:`gccjit::context` can be compiled to
>+machine code, either in-memory via :func:`gccjit::context::compile` or
>+to disk via :func:`gccjit::context::compile_to_file`.
>+
>+You can compile a context multiple times (using either form of
>+compilation), although any errors that occur on the context will
>+prevent any future compilation of that context.
>+
>+In-memory compilation
>+*********************
>+
>+.. function:: gcc_jit_result *\
>+              gccjit::context::compile ()
>+
>+   This calls into GCC and builds the code, returning a
>+   `gcc_jit_result *`.
>+
>+   This is a thin wrapper around the
>+   :c:func:`gcc_jit_context_compile` API entrypoint.
>+
>+Ahead-of-time compilation
>+*************************
>+
>+Although libgccjit is primarily aimed at just-in-time compilation, it
>+can also be used for implementing more traditional ahead-of-time
>+compilers, via the :func:`gccjit::context::compile_to_file` method.
>+
>+.. function:: void \
>+              gccjit::context::compile_to_file (enum
>gcc_jit_output_kind,\
>+                                                const char
>*output_path)
>+
>+   Compile the :class:`gccjit::context` to a file of the given
>+   kind.
>+
>+   This is a thin wrapper around the
>+   :c:func:`gcc_jit_context_compile_to_file` API entrypoint.
>diff --git a/gcc/jit/docs/cp/topics/index.rst
>b/gcc/jit/docs/cp/topics/index.rst
>index a129137..4ebb623 100644
>--- a/gcc/jit/docs/cp/topics/index.rst
>+++ b/gcc/jit/docs/cp/topics/index.rst
>@@ -1,4 +1,4 @@
>-.. Copyright (C) 2014 Free Software Foundation, Inc.
>+.. Copyright (C) 2014-2015 Free Software Foundation, Inc.
>    Originally contributed by David Malcolm <dmalcolm@redhat.com>
> 
>    This is free software: you can redistribute it and/or modify it
>@@ -27,4 +27,4 @@ Topic Reference
>    expressions.rst
>    functions.rst
>    locations.rst
>-   results.rst
>+   compilation.rst
>diff --git a/gcc/jit/docs/cp/topics/results.rst
>b/gcc/jit/docs/cp/topics/results.rst
>deleted file mode 100644
>index 18200ac..0000000
>--- a/gcc/jit/docs/cp/topics/results.rst
>+++ /dev/null
>@@ -1,48 +0,0 @@
>-.. 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:: cpp
>-
>-Compilation results
>-===================
>-
>-.. type:: gcc_jit_result
>-
>-  A `gcc_jit_result` encapsulates the result of compiling a context.
>-
>-.. function:: gcc_jit_result *\
>-              gccjit::context::compile ()
>-
>-   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/examples/emit-alphabet.bf
>b/gcc/jit/docs/examples/emit-alphabet.bf
>new file mode 100644
>index 0000000..6863273
>--- /dev/null
>+++ b/gcc/jit/docs/examples/emit-alphabet.bf
>@@ -0,0 +1,17 @@
>+[
>+  Emit the uppercase alphabet
>+]
>+
>+cell 0 = 26
>+++++++++++++++++++++++++++
>+
>+cell 1 = 65
>+>+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++<
>+
>+while cell#0 != 0
>+[
>+ >
>+ .      emit cell#1
>+ +      increment cell@1
>+ <-     decrement cell@0
>+]
>diff --git a/gcc/jit/docs/examples/tut05-bf.c
>b/gcc/jit/docs/examples/tut05-bf.c
>new file mode 100644
>index 0000000..f948ede
>--- /dev/null
>+++ b/gcc/jit/docs/examples/tut05-bf.c
>@@ -0,0 +1,446 @@
>+/* A compiler for the "bf" language.  */
>+
>+#include <stdlib.h>
>+#include <string.h>
>+#include <errno.h>
>+
>+#include "libgccjit.h"
>+
>+/* Make "main" function:
>+     int
>+     main (int argc, char **argv)
>+     {
>+       ...
>+     }
>+*/
>+static gcc_jit_function *
>+make_main (gcc_jit_context *ctxt)
>+{
>+  gcc_jit_type *int_type =
>+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
>+  gcc_jit_param *param_argc =
>+    gcc_jit_context_new_param (ctxt, NULL, int_type, "argc");
>+  gcc_jit_type *char_ptr_ptr_type =
>+    gcc_jit_type_get_pointer (
>+      gcc_jit_type_get_pointer (
>+	gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_CHAR)));
>+  gcc_jit_param *param_argv =
>+    gcc_jit_context_new_param (ctxt, NULL, char_ptr_ptr_type, "argv");
>+  gcc_jit_param *params[2] = {param_argc, param_argv};
>+  gcc_jit_function *func_main =
>+    gcc_jit_context_new_function (ctxt, NULL,
>+				  GCC_JIT_FUNCTION_EXPORTED,
>+				  int_type,
>+				  "main",
>+				  2, params,
>+				  0);
>+  return func_main;
>+}
>+
>+#define MAX_OPEN_PARENS 16
>+
>+typedef struct bf_compiler
>+{
>+  const char *filename;
>+  int line;
>+  int column;
>+
>+  gcc_jit_context *ctxt;
>+
>+  gcc_jit_type *void_type;
>+  gcc_jit_type *int_type;
>+  gcc_jit_type *byte_type;
>+  gcc_jit_type *array_type;
>+
>+  gcc_jit_function *func_getchar;
>+  gcc_jit_function *func_putchar;
>+
>+  gcc_jit_function *func;
>+  gcc_jit_block *curblock;
>+
>+  gcc_jit_rvalue *int_zero;
>+  gcc_jit_rvalue *int_one;
>+  gcc_jit_rvalue *byte_zero;
>+  gcc_jit_rvalue *byte_one;
>+  gcc_jit_lvalue *data_cells;
>+  gcc_jit_lvalue *idx;
>+
>+  int num_open_parens;
>+  gcc_jit_block *paren_test[MAX_OPEN_PARENS];
>+  gcc_jit_block *paren_body[MAX_OPEN_PARENS];
>+  gcc_jit_block *paren_after[MAX_OPEN_PARENS];
>+
>+} bf_compiler;
>+
>+/* Bail out, with a message on stderr.  */
>+
>+static void
>+fatal_error (bf_compiler *bfc, const char *msg)
>+{
>+  fprintf (stderr,
>+	   "%s:%i:%i: %s",
>+	   bfc->filename, bfc->line, bfc->column, msg);
>+  abort ();
>+}
>+
>+/* Get "data_cells[idx]" as an lvalue.  */
>+
>+static gcc_jit_lvalue *
>+bf_get_current_data (bf_compiler *bfc, gcc_jit_location *loc)
>+{
>+  return gcc_jit_context_new_array_access (
>+    bfc->ctxt,
>+    loc,
>+    gcc_jit_lvalue_as_rvalue (bfc->data_cells),
>+    gcc_jit_lvalue_as_rvalue (bfc->idx));
>+}
>+
>+/* Get "data_cells[idx] == 0" as a boolean rvalue.  */
>+
>+static gcc_jit_rvalue *
>+bf_current_data_is_zero (bf_compiler *bfc, gcc_jit_location *loc)
>+{
>+  return gcc_jit_context_new_comparison (
>+    bfc->ctxt,
>+    loc,
>+    GCC_JIT_COMPARISON_EQ,
>+    gcc_jit_lvalue_as_rvalue (bf_get_current_data (bfc, loc)),
>+    bfc->byte_zero);
>+}
>+
>+/* Compile one bf character.  */
>+
>+static void
>+bf_compile_char (bf_compiler *bfc,
>+		 unsigned char ch)
>+{
>+  gcc_jit_location *loc =
>+    gcc_jit_context_new_location (bfc->ctxt,
>+				  bfc->filename,
>+				  bfc->line,
>+				  bfc->column);
>+
>+  /* Turn this on to trace execution, by injecting putchar ()
>+     of each source char. */
>+  if (0)
>+    {
>+      gcc_jit_rvalue *arg =
>+	gcc_jit_context_new_rvalue_from_int (
>+					     bfc->ctxt,
>+					     bfc->int_type,
>+					     ch);
>+      gcc_jit_rvalue *call =
>+	gcc_jit_context_new_call (bfc->ctxt,
>+				  loc,
>+				  bfc->func_putchar,
>+				  1, &arg);
>+      gcc_jit_block_add_eval (bfc->curblock,
>+			      loc,
>+			      call);
>+    }
>+
>+  switch (ch)
>+    {
>+      case '>':
>+	gcc_jit_block_add_comment (bfc->curblock,
>+				   loc,
>+				   "'>': idx += 1;");
>+	gcc_jit_block_add_assignment_op (bfc->curblock,
>+					 loc,
>+					 bfc->idx,
>+					 GCC_JIT_BINARY_OP_PLUS,
>+					 bfc->int_one);
>+	break;
>+
>+      case '<':
>+	gcc_jit_block_add_comment (bfc->curblock,
>+				   loc,
>+				   "'<': idx -= 1;");
>+	gcc_jit_block_add_assignment_op (bfc->curblock,
>+					 loc,
>+					 bfc->idx,
>+					 GCC_JIT_BINARY_OP_MINUS,
>+					 bfc->int_one);
>+	break;
>+
>+      case '+':
>+	gcc_jit_block_add_comment (bfc->curblock,
>+				   loc,
>+				   "'+': data[idx] += 1;");
>+	gcc_jit_block_add_assignment_op (bfc->curblock,
>+					 loc,
>+					 bf_get_current_data (bfc, loc),
>+					 GCC_JIT_BINARY_OP_PLUS,
>+					 bfc->byte_one);
>+	break;
>+
>+      case '-':
>+	gcc_jit_block_add_comment (bfc->curblock,
>+				   loc,
>+				   "'-': data[idx] -= 1;");
>+	gcc_jit_block_add_assignment_op (bfc->curblock,
>+					 loc,
>+					 bf_get_current_data (bfc, loc),
>+					 GCC_JIT_BINARY_OP_MINUS,
>+					 bfc->byte_one);
>+	break;
>+
>+      case '.':
>+	{
>+	  gcc_jit_rvalue *arg =
>+	    gcc_jit_context_new_cast (
>+	      bfc->ctxt,
>+	      loc,
>+	      gcc_jit_lvalue_as_rvalue (bf_get_current_data (bfc, loc)),
>+	      bfc->int_type);
>+	  gcc_jit_rvalue *call =
>+	    gcc_jit_context_new_call (bfc->ctxt,
>+				      loc,
>+				      bfc->func_putchar,
>+				      1, &arg);
>+	  gcc_jit_block_add_comment (bfc->curblock,
>+				     loc,
>+				     "'.': putchar ((int)data[idx]);");
>+	  gcc_jit_block_add_eval (bfc->curblock,
>+				  loc,
>+				  call);
>+	}
>+	break;
>+
>+      case ',':
>+	{
>+	  gcc_jit_rvalue *call =
>+	    gcc_jit_context_new_call (bfc->ctxt,
>+				      loc,
>+				      bfc->func_getchar,
>+				      0, NULL);
>+	  gcc_jit_block_add_comment (
>+	    bfc->curblock,
>+	    loc,
>+	    "',': data[idx] = (unsigned char)getchar ();");
>+	  gcc_jit_block_add_assignment (bfc->curblock,
>+					loc,
>+					bf_get_current_data (bfc, loc),
>+					gcc_jit_context_new_cast (
>+					  bfc->ctxt,
>+					  loc,
>+					  call,
>+					  bfc->byte_type));
>+	}
>+	break;
>+
>+      case '[':
>+	{
>+	  gcc_jit_block *loop_test =
>+	    gcc_jit_function_new_block (bfc->func, NULL);
>+	  gcc_jit_block *on_zero =
>+	    gcc_jit_function_new_block (bfc->func, NULL);
>+	  gcc_jit_block *on_non_zero =
>+	    gcc_jit_function_new_block (bfc->func, NULL);
>+
>+	  if (bfc->num_open_parens == MAX_OPEN_PARENS)
>+	    fatal_error (bfc, "too many open parens");
>+
>+	  gcc_jit_block_end_with_jump (
>+	    bfc->curblock,
>+	    loc,
>+	    loop_test);
>+
>+	  gcc_jit_block_add_comment (
>+	    loop_test,
>+	    loc,
>+	    "'['");
>+	  gcc_jit_block_end_with_conditional (
>+	    loop_test,
>+	    loc,
>+	    bf_current_data_is_zero (bfc, loc),
>+	    on_zero,
>+	    on_non_zero);
>+	  bfc->paren_test[bfc->num_open_parens] = loop_test;
>+	  bfc->paren_body[bfc->num_open_parens] = on_non_zero;
>+	  bfc->paren_after[bfc->num_open_parens] = on_zero;
>+	  bfc->num_open_parens += 1;
>+	  bfc->curblock = on_non_zero;
>+	}
>+	break;
>+
>+      case ']':
>+	{
>+	  gcc_jit_block_add_comment (
>+	    bfc->curblock,
>+	    loc,
>+	    "']'");
>+
>+	  if (bfc->num_open_parens == 0)
>+	    fatal_error (bfc, "mismatching parens");
>+	  bfc->num_open_parens -= 1;
>+	  gcc_jit_block_end_with_jump (
>+	    bfc->curblock,
>+	    loc,
>+	    bfc->paren_test[bfc->num_open_parens]);
>+	  bfc->curblock = bfc->paren_after[bfc->num_open_parens];
>+	}
>+	break;
>+
>+    case '\n':
>+      bfc->line +=1;
>+      bfc->column = 0;
>+      break;
>+    }
>+
>+  if (ch != '\n')
>+    bfc->column += 1;
>+}
>+
>+/* Compile the given .bf file into a gcc_jit_context, containing a
>+   single "main" function suitable for compiling into an executable. 
>*/
>+
>+gcc_jit_context *
>+bf_compile (const char *filename)
>+{
>+  bf_compiler bfc;
>+  FILE *f_in;
>+  int ch;
>+
>+  memset (&bfc, 0, sizeof (bfc));
>+
>+  bfc.filename = filename;
>+  f_in = fopen (filename, "r");
>+  if (!f_in)
>+    fatal_error (&bfc, "unable to open file");
>+  bfc.line = 1;
>+
>+  bfc.ctxt = gcc_jit_context_acquire ();
>+
>+  gcc_jit_context_set_int_option (
>+    bfc.ctxt,
>+    GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL,
>+    3);
>+  gcc_jit_context_set_bool_option (
>+    bfc.ctxt,
>+    GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE,
>+    0);
>+  gcc_jit_context_set_bool_option (
>+    bfc.ctxt,
>+    GCC_JIT_BOOL_OPTION_DEBUGINFO,
>+    1);
>+  gcc_jit_context_set_bool_option (
>+    bfc.ctxt,
>+    GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING,
>+    0);
>+  gcc_jit_context_set_bool_option (
>+    bfc.ctxt,
>+    GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES,
>+    0);
>+
>+  bfc.void_type =
>+    gcc_jit_context_get_type (bfc.ctxt, GCC_JIT_TYPE_VOID);
>+  bfc.int_type =
>+    gcc_jit_context_get_type (bfc.ctxt, GCC_JIT_TYPE_INT);
>+  bfc.byte_type =
>+    gcc_jit_context_get_type (bfc.ctxt, GCC_JIT_TYPE_UNSIGNED_CHAR);
>+  bfc.array_type =
>+    gcc_jit_context_new_array_type (bfc.ctxt,
>+				    NULL,
>+				    bfc.byte_type,
>+				    30000);
>+
>+  bfc.func_getchar =
>+    gcc_jit_context_new_function (bfc.ctxt, NULL,
>+				  GCC_JIT_FUNCTION_IMPORTED,
>+				  bfc.int_type,
>+				  "getchar",
>+				  0, NULL,
>+				  0);
>+
>+  gcc_jit_param *param_c =
>+    gcc_jit_context_new_param (bfc.ctxt, NULL, bfc.int_type, "c");
>+  bfc.func_putchar =
>+    gcc_jit_context_new_function (bfc.ctxt, NULL,
>+				  GCC_JIT_FUNCTION_IMPORTED,
>+				  bfc.void_type,
>+				  "putchar",
>+				  1, &param_c,
>+				  0);
>+
>+  bfc.func = make_main (bfc.ctxt);
>+   bfc.curblock =
>+    gcc_jit_function_new_block (bfc.func, "initial");
>+  bfc.int_zero = gcc_jit_context_zero (bfc.ctxt, bfc.int_type);
>+  bfc.int_one = gcc_jit_context_one (bfc.ctxt, bfc.int_type);
>+  bfc.byte_zero = gcc_jit_context_zero (bfc.ctxt, bfc.byte_type);
>+  bfc.byte_one = gcc_jit_context_one (bfc.ctxt, bfc.byte_type);
>+
>+  bfc.data_cells =
>+    gcc_jit_context_new_global (bfc.ctxt, NULL,
>+				 GCC_JIT_GLOBAL_INTERNAL,
>+				 bfc.array_type,
>+				 "data_cells");
>+  bfc.idx =
>+    gcc_jit_function_new_local (bfc.func, NULL,
>+				bfc.int_type,
>+				"idx");
>+
>+  gcc_jit_block_add_comment (bfc.curblock,
>+			     NULL,
>+			     "idx = 0;");
>+  gcc_jit_block_add_assignment (bfc.curblock,
>+				NULL,
>+				bfc.idx,
>+				bfc.int_zero);
>+
>+  bfc.num_open_parens = 0;
>+
>+  while ( EOF != (ch = fgetc (f_in)))
>+    bf_compile_char (&bfc, (unsigned char)ch);
>+
>+  gcc_jit_block_end_with_return (bfc.curblock, NULL, bfc.int_zero);
>+
>+  fclose (f_in);
>+
>+  return bfc.ctxt;
>+}
>+
>+/* Entrypoint to the compiler.  */
>+
>+int
>+main (int argc, char **argv)
>+{
>+  const char *input_file;
>+  const char *output_file;
>+  gcc_jit_context *ctxt;
>+  const char *err;
>+
>+  if (argc != 3)
>+    {
>+      fprintf (stderr, "%s: INPUT_FILE OUTPUT_FILE\n", argv[0]);
>+      return 1;
>+    }
>+
>+  input_file = argv[1];
>+  output_file = argv[2];
>+  ctxt = bf_compile (input_file);
>+
>+  gcc_jit_context_compile_to_file (ctxt,
>+				   GCC_JIT_OUTPUT_KIND_EXECUTABLE,
>+				   output_file);
>+
>+  err = gcc_jit_context_get_first_error (ctxt);
>+
>+  if (err)
>+    {
>+      gcc_jit_context_release (ctxt);
>+      return 1;
>+    }
>+
>+  gcc_jit_context_release (ctxt);
>+  return 0;
>+}
>+
>+/* Use the built compiler to compile the example to an executable:
>+
>+     { dg-jit-set-exe-params
>SRCDIR/gcc/jit/docs/examples/emit-alphabet.bf emit-alphabet.bf.exe }
>+
>+   Then run the executable, and verify that it emits the alphabet:
>+
>+     { dg-final { jit-run-executable emit-alphabet.bf.exe
>"ABCDEFGHIJKLMNOPQRSTUVWXYZ" } } */
>diff --git a/gcc/jit/docs/internals/test-hello-world.exe.log.txt
>b/gcc/jit/docs/internals/test-hello-world.exe.log.txt
>index 113dc35..205b6b4 100644
>--- a/gcc/jit/docs/internals/test-hello-world.exe.log.txt
>+++ b/gcc/jit/docs/internals/test-hello-world.exe.log.txt
>@@ -38,14 +38,20 @@ JIT: entering: gcc_jit_block_add_eval
> JIT: exiting: gcc_jit_block_add_eval
> JIT: entering: gcc_jit_block_end_with_void_return
> JIT: exiting: gcc_jit_block_end_with_void_return
>+JIT: entering: gcc_jit_context_dump_reproducer_to_file
>+JIT:  entering: void
>gcc::jit::recording::context::dump_reproducer_to_file(const char*)
>+JIT:  exiting: void
>gcc::jit::recording::context::dump_reproducer_to_file(const char*)
>+JIT: exiting: gcc_jit_context_dump_reproducer_to_file
> JIT: entering: gcc_jit_context_compile
>-JIT:  compiling ctxt: 0x1283e20
>+JIT:  in-memory compile of ctxt: 0x1283e20
>JIT:  entering: gcc::jit::result*
>gcc::jit::recording::context::compile()
> JIT:   entering: void gcc::jit::recording::context::validate()
> JIT:   exiting: void gcc::jit::recording::context::validate()
>JIT:   entering:
>gcc::jit::playback::context::context(gcc::jit::recording::context*)
>JIT:   exiting:
>gcc::jit::playback::context::context(gcc::jit::recording::context*)
>-JIT:   entering: gcc::jit::result*
>gcc::jit::playback::context::compile()
>+JIT:   entering:
>gcc::jit::playback::compile_to_memory::compile_to_memory(gcc::jit::recording::context*)
>+JIT:   exiting:
>gcc::jit::playback::compile_to_memory::compile_to_memory(gcc::jit::recording::context*)
>+JIT:   entering: void gcc::jit::playback::context::compile()
> JIT:    entering: gcc::jit::tempdir::tempdir(gcc::jit::logger*, int)
> JIT:    exiting: gcc::jit::tempdir::tempdir(gcc::jit::logger*, int)
> JIT:    entering: bool gcc::jit::tempdir::create()
>@@ -86,29 +92,37 @@ JIT:      entering: void
>gcc::jit::playback::function::postprocess()
> JIT:      exiting: void gcc::jit::playback::function::postprocess()
> JIT:     exiting: void gcc::jit::playback::context::replay()
> JIT:     entering: void jit_langhook_write_globals()
>+JIT:      entering: void
>gcc::jit::playback::context::write_global_decls_1()
>+JIT:      exiting: void
>gcc::jit::playback::context::write_global_decls_1()
>+JIT:      entering: void
>gcc::jit::playback::context::write_global_decls_2()
>+JIT:      exiting: void
>gcc::jit::playback::context::write_global_decls_2()
> JIT:     exiting: void jit_langhook_write_globals()
> JIT:    exiting: toplev::main
>JIT:    entering: void
>gcc::jit::playback::context::extract_any_requested_dumps(vec<gcc::jit::recording::requested_dump>*)
>JIT:    exiting: void
>gcc::jit::playback::context::extract_any_requested_dumps(vec<gcc::jit::recording::requested_dump>*)
> JIT:    entering: toplev::finalize
> JIT:    exiting: toplev::finalize
>-JIT:    entering: void
>gcc::jit::playback::context::convert_to_dso(const char*)
>-JIT:     argv[0]: x86_64-unknown-linux-gnu-gcc-5.0.0
>-JIT:     argv[1]: -shared
>-JIT:     argv[2]: /tmp/libgccjit-CKq1M9/fake.s
>-JIT:     argv[3]: -o
>-JIT:     argv[4]: /tmp/libgccjit-CKq1M9/fake.so
>-JIT:     argv[5]: -fno-use-linker-plugin
>-JIT:     argv[6]: (null)
>-JIT:    exiting: void
>gcc::jit::playback::context::convert_to_dso(const char*)
>-JIT:    entering: gcc::jit::result*
>gcc::jit::playback::context::dlopen_built_dso()
>-JIT:     GCC_JIT_BOOL_OPTION_DEBUGINFO was set: handing over tempdir
>to jit::result
>-JIT:     entering: gcc::jit::result::result(gcc::jit::logger*, void*,
>gcc::jit::tempdir*)
>-JIT:     exiting: gcc::jit::result::result(gcc::jit::logger*, void*,
>gcc::jit::tempdir*)
>-JIT:    exiting: gcc::jit::result*
>gcc::jit::playback::context::dlopen_built_dso()
>+JIT:    entering: virtual void
>gcc::jit::playback::compile_to_memory::postprocess(const char*)
>+JIT:     entering: void
>gcc::jit::playback::context::convert_to_dso(const char*)
>+JIT:      entering: void
>gcc::jit::playback::context::invoke_driver(const char*, const char*,
>const char*, timevar_id_t, bool, bool)
>+JIT:       argv[0]: x86_64-unknown-linux-gnu-gcc-5.0.0
>+JIT:       argv[1]: -shared
>+JIT:       argv[2]: /tmp/libgccjit-CKq1M9/fake.s
>+JIT:       argv[3]: -o
>+JIT:       argv[4]: /tmp/libgccjit-CKq1M9/fake.so
>+JIT:       argv[5]: -fno-use-linker-plugin
>+JIT:       argv[6]: (null)
>+JIT:      exiting: void
>gcc::jit::playback::context::invoke_driver(const char*, const char*,
>const char*, timevar_id_t, bool, bool)
>+JIT:     exiting: void
>gcc::jit::playback::context::convert_to_dso(const char*)
>+JIT:     entering: gcc::jit::result*
>gcc::jit::playback::context::dlopen_built_dso()
>+JIT:      GCC_JIT_BOOL_OPTION_DEBUGINFO was set: handing over tempdir
>to jit::result
>+JIT:      entering: gcc::jit::result::result(gcc::jit::logger*, void*,
>gcc::jit::tempdir*)
>+JIT:      exiting: gcc::jit::result::result(gcc::jit::logger*, void*,
>gcc::jit::tempdir*)
>+JIT:     exiting: gcc::jit::result*
>gcc::jit::playback::context::dlopen_built_dso()
>+JIT:    exiting: virtual void
>gcc::jit::playback::compile_to_memory::postprocess(const char*)
> JIT:    entering: void gcc::jit::playback::context::release_mutex()
> JIT:    exiting: void gcc::jit::playback::context::release_mutex()
>-JIT:   exiting: gcc::jit::result*
>gcc::jit::playback::context::compile()
>+JIT:   exiting: void gcc::jit::playback::context::compile()
> JIT:   entering: gcc::jit::playback::context::~context()
> JIT:   exiting: gcc::jit::playback::context::~context()
>JIT:  exiting: gcc::jit::result*
>gcc::jit::recording::context::compile()
>diff --git a/gcc/jit/docs/intro/index.rst
>b/gcc/jit/docs/intro/index.rst
>index d3bcec9..0f51777 100644
>--- a/gcc/jit/docs/intro/index.rst
>+++ b/gcc/jit/docs/intro/index.rst
>@@ -1,4 +1,4 @@
>-.. Copyright (C) 2014 Free Software Foundation, Inc.
>+.. Copyright (C) 2014-2015 Free Software Foundation, Inc.
>    Originally contributed by David Malcolm <dmalcolm@redhat.com>
> 
>    This is free software: you can redistribute it and/or modify it
>@@ -25,3 +25,4 @@ Tutorial
>    tutorial02.rst
>    tutorial03.rst
>    tutorial04.rst
>+   tutorial05.rst
>diff --git a/gcc/jit/docs/intro/tutorial05.rst
>b/gcc/jit/docs/intro/tutorial05.rst
>new file mode 100644
>index 0000000..865a550
>--- /dev/null
>+++ b/gcc/jit/docs/intro/tutorial05.rst
>@@ -0,0 +1,253 @@
>+.. Copyright (C) 2015 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 5: Implementing an Ahead-of-Time compiler
>+-------------------------------------------------------
>+
>+If you have a pre-existing language frontend, it's possible to hook
>+it up to libgccjit as a backend.  In the previous example we showed
>+how to do that for in-memory JIT-compilation, but libgccjit can also
>+compile code directly to a file, allowing you to implement a more
>+traditional ahead-of-time compil


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH] Re: Stage 3 RFC: using "jit" for ahead-of-time compilation
  2015-01-01  0:00 ` Richard Biener
@ 2015-01-01  0:00   ` David Malcolm
  2015-01-01  0:00     ` Richard Biener
  0 siblings, 1 reply; 6+ messages in thread
From: David Malcolm @ 2015-01-01  0:00 UTC (permalink / raw)
  To: Richard Biener; +Cc: jit, gcc-patches, Jakub Jelinek, Joseph Myers

[-- Attachment #1: Type: text/plain, Size: 36174 bytes --]

On Thu, 2015-01-15 at 22:50 +0100, Richard Biener wrote:
> On January 15, 2015 9:05:59 PM CET, David Malcolm <dmalcolm@redhat.com> wrote:
> >Release managers: given that this only touches the jit, and that the
> >jit
> >is off by default, any objections if I go ahead and commit this?
> >It's a late-breaking feature, but the jit as a whole is new, and
> >I think the following is a big win, so I'd like to proceed with this in
> >stage 3 (i.e. in the next 24 hours).  There are docs and testcases.
> >
> >New jit API entrypoint: gcc_jit_context_compile_to_file
> >
> >This patch adds a way to use libgccjit for ahead-of-time compilation.
> >I noticed that given the postprocessing steps the jit has to take to
> >turn the .s file into in-memory code (invoke driver to convert to
> >a .so and then dlopen), that it's not much of a leap to support
> >compiling the .s file into objects, dynamic libraries, and executables.
> >
> >Doing so seems like a big win from a feature standpoint: people with
> >pre-existing frontend code who want a backend can then plug in
> >libgccjit
> >and have a compiler, without needing to write it as a GCC frontend, or
> >use LLVM.
> 
> Note that you should make them aware of our runtime license with
> respect to the eligible compilation process.  Which means this is not
> a way to implement proprietary front ends.
> 
> Richard.

IANAL, but as I understand things, the runtime license is an additional
grant of rights that covers certain components of GCC that bear the GCC
Runtime Library Exception, allowing them to be used in certain
additional ways beyond regular GPLv3-compliance.

libgccjit doesn't have that exception; it's GPLv3.

Perhaps an argument could be made for libgccjit to have the exception,
if the FSF think that that would better serve the FSF's mission; right
now, I'm merely trying to provide a technical means to modularity.

Assuming the above is correct, anything linked against it needs to be
GPLv3-compatible.  Hence any such frontend linked against libgccjit
would need to be GPLv3-compatible.

Attached is a patch (on top of the proposed one below), to clarify the
wording in the new tutorial a little, to remind people that such linking
needs to be license-compatible (without actually spelling out what the
license is, though it's visible at the top of the public header file,
libgccjit.h, as GPLv3 or later without the runtime library exception).

Are the combined patches OK by you?

Thanks
Dave


> >"jit" becomes something of a misnomer for this use-case.
> >
> >As an experiment, I used this technique to add a compiler for the
> >language I'll refer to as "brainf" (ahem), and wrote this up for the
> >libgccjit tutorial (it's all in the patch); prebuilt HTML can be seen
> >at:
> >https://dmalcolm.fedorapeople.org/gcc/libgccjit-api-docs-wip/intro/tutorial05.html
> >
> >The main things that are missing are:
> > * specifying libraries to link against (Uli had some ideas about this)
> >  * cross-compilation support (needs some deeper work, especially the
> >    test suite, so deferrable to gcc 6, I guess)
> >but the feature is useful with the patch as-is.
> >
> >The new test cases take jit.sum's # of expected passes
> >from 7514 to 7571.
> >
> >gcc/jit/ChangeLog:
> >	* docs/cp/topics/results.rst: Rename to...
> >	* docs/cp/topics/compilation.rst: ...this, and add section on
> >	ahead-of-time compilation.
> >	* docs/cp/topics/index.rst: Update for renaming of results.rst
> >	to compilation.rst.
> >	* docs/examples/emit-alphabet.bf: New file, a sample "brainf"
> >	script.
> >	* docs/examples/tut05-bf.c: New file, implementing a compiler
> >	for "brainf".
> >	* docs/internals/test-hello-world.exe.log.txt: Update to reflect
> >	changes to logger output.
> >	* docs/intro/index.rst: Add tutorial05.rst
> >	* docs/intro/tutorial05.rst: New file.
> >	* docs/topics/results.rst: Rename to...
> >	* docs/topics/compilation.rst: ...this, and add section on
> >	ahead-of-time compilation.
> >	* docs/topics/index.rst: Update for renaming of results.rst to
> >	compilation.rst.
> >	* jit-playback.c (gcc::jit::playback::context::compile): Convert
> >	return type from result * to void.  Move the code to convert to
> >	dso and dlopen the result to a new pure virtual "postprocess"
> >	method.
> >	(gcc::jit::playback::compile_to_memory::compile_to_memory): New
> >	function.
> >	(gcc::jit::playback::compile_to_memory::postprocess): New
> >	function, based on playback::context::compile.
> >	(gcc::jit::playback::compile_to_file::compile_to_file): New
> >	function.
> >	(gcc::jit::playback::compile_to_file::postprocess): New function.
> >	(gcc::jit::playback::compile_to_file::copy_file): New function.
> >	(gcc::jit::playback::context::convert_to_dso): Move internals
> >	to...
> >	(gcc::jit::playback::context::invoke_driver): New method.  Add
> >	"-shared" and "-c" options to driver's argv as needed.
> >	* jit-playback.h: Include "timevar.h".
> >	(gcc::jit::playback::context::compile): Convert return type from
> >	result * to void.
> >	(gcc::jit::playback::context::postprocess): New pure virtual
> >	function, making this an abstract base class.
> >	(gcc::jit::playback::context::get_tempdir): New accessor.
> >	(gcc::jit::playback::context::invoke_driver): New function.
> >	(class gcc::jit::playback::compile_to_memory): New subclass of
> >	playback::context.
> >	(class gcc::jit::playback::compile_to_file): Likewise.
> >	* jit-recording.c (gcc::jit::recording::context::compile): Use a
> >	playback::compile_to_memory, and extract its result.
> >	(gcc::jit::recording::context::compile_to_file): New function.
> >	* jit-recording.h (gcc::jit::recording::context::compile_to_file):
> >	New function.
> >	* libgccjit++.h (gccjit::context::compile_to_file): New method.
> >	* libgccjit.c (gcc_jit_context_compile): Update log message to
> >	clarify that this is an in-memory compile.
> >	(gcc_jit_context_compile_to_file): New function.
> >	* libgccjit.h (gcc_jit_context): Clarify that you can compile
> >	a context more than once, and that you can compile to a file
> >	as well as to memory.
> >	(gcc_jit_result): Clarify that this is the result of an
> >	in-memory compilation.
> >	(gcc_jit_context_compile): Clarify that you can compile, and that
> >	this is an in-memory compilation.
> >	(enum gcc_jit_output_kind): New enum.
> >	(gcc_jit_context_compile_to_file): New function.
> >	(gcc_jit_context_enable_dump): Clarify comment to cover both forms
> >	of compilation.
> >	* libgccjit.map (gcc_jit_context_compile_to_file): New API
> >	entrypoint.
> >	* notes.txt: Update to show the playback::context::postprocess
> >	virtual function.
> >
> >gcc/testsuite/ChangeLog:
> >	* jit.dg/harness.h: Include <unistd.h>.
> >	(CHECK_NO_ERRORS): New.
> >	(verify_code): Wrap prototype in #ifndef TEST_COMPILING_TO_FILE.
> >	(test_jit): Support new macro TEST_COMPILING_TO_FILE for exercising
> >	gcc_jit_context_compile_to_file.
> >	* jit.dg/jit.exp (fixed_host_execute): Fix the code for passing on
> >	args to the spawned executable.
> >	(jit-expand-vars): New function.
> >	(jit-exe-params): New variable.
> >	(dg-jit-set-exe-params): New function.
> >	(jit-dg-test): Detect testcases that use
> >	jit-verify-compile-to-file and call jit-setup-compile-to-file.
> >	Set arguments of spawned process to jit-exe-params.
> >	(jit-get-output-filename): New function.
> >	(jit-setup-compile-to-file): New function.
> >	(jit-verify-compile-to-file): New function.
> >	(jit-run-executable): New function.
> >	(jit-verify-executable): New function.
> >	* jit.dg/test-compile-to-assembler.c: New testcase.
> >	* jit.dg/test-compile-to-dynamic-library.c: New testcase.
> >	* jit.dg/test-compile-to-executable.c: New testcase.
> >	* jit.dg/test-compile-to-object.c: New testcase.
> >---
> > gcc/jit/docs/cp/topics/compilation.rst             |  58 +++
> > gcc/jit/docs/cp/topics/index.rst                   |   4 +-
> > gcc/jit/docs/cp/topics/results.rst                 |  48 ---
> > gcc/jit/docs/examples/emit-alphabet.bf             |  17 +
> >gcc/jit/docs/examples/tut05-bf.c                   | 446
> >+++++++++++++++++++++
> > .../docs/internals/test-hello-world.exe.log.txt    |  48 ++-
> > gcc/jit/docs/intro/index.rst                       |   3 +-
> > gcc/jit/docs/intro/tutorial05.rst                  | 253 ++++++++++++
> > gcc/jit/docs/topics/compilation.rst                | 199 +++++++++
> > gcc/jit/docs/topics/index.rst                      |   4 +-
> > gcc/jit/docs/topics/results.rst                    | 127 ------
> >gcc/jit/jit-playback.c                             | 308 +++++++++++++-
> > gcc/jit/jit-playback.h                             |  54 ++-
> > gcc/jit/jit-recording.c                            |  40 +-
> > gcc/jit/jit-recording.h                            |   4 +
> > gcc/jit/libgccjit++.h                              |  12 +
> > gcc/jit/libgccjit.c                                |  31 +-
> > gcc/jit/libgccjit.h                                |  58 ++-
> > gcc/jit/libgccjit.map                              |   1 +
> > gcc/jit/notes.txt                                  |  13 +-
> > gcc/testsuite/jit.dg/harness.h                     |  29 +-
> > gcc/testsuite/jit.dg/jit.exp                       | 209 +++++++++-
> > gcc/testsuite/jit.dg/test-compile-to-assembler.c   |  65 +++
> > .../jit.dg/test-compile-to-dynamic-library.c       |  65 +++
> > gcc/testsuite/jit.dg/test-compile-to-executable.c  | 110 +++++
> > gcc/testsuite/jit.dg/test-compile-to-object.c      |  65 +++
> > 26 files changed, 2026 insertions(+), 245 deletions(-)
> > create mode 100644 gcc/jit/docs/cp/topics/compilation.rst
> > delete mode 100644 gcc/jit/docs/cp/topics/results.rst
> > create mode 100644 gcc/jit/docs/examples/emit-alphabet.bf
> > create mode 100644 gcc/jit/docs/examples/tut05-bf.c
> > create mode 100644 gcc/jit/docs/intro/tutorial05.rst
> > create mode 100644 gcc/jit/docs/topics/compilation.rst
> > delete mode 100644 gcc/jit/docs/topics/results.rst
> > create mode 100644 gcc/testsuite/jit.dg/test-compile-to-assembler.c
> >create mode 100644
> >gcc/testsuite/jit.dg/test-compile-to-dynamic-library.c
> > create mode 100644 gcc/testsuite/jit.dg/test-compile-to-executable.c
> > create mode 100644 gcc/testsuite/jit.dg/test-compile-to-object.c
> >
> >diff --git a/gcc/jit/docs/cp/topics/compilation.rst
> >b/gcc/jit/docs/cp/topics/compilation.rst
> >new file mode 100644
> >index 0000000..05917e8
> >--- /dev/null
> >+++ b/gcc/jit/docs/cp/topics/compilation.rst
> >@@ -0,0 +1,58 @@
> >+.. Copyright (C) 2014-2015 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:: cpp
> >+
> >+Compiling a context
> >+===================
> >+
> >+Once populated, a :class:`gccjit::context` can be compiled to
> >+machine code, either in-memory via :func:`gccjit::context::compile` or
> >+to disk via :func:`gccjit::context::compile_to_file`.
> >+
> >+You can compile a context multiple times (using either form of
> >+compilation), although any errors that occur on the context will
> >+prevent any future compilation of that context.
> >+
> >+In-memory compilation
> >+*********************
> >+
> >+.. function:: gcc_jit_result *\
> >+              gccjit::context::compile ()
> >+
> >+   This calls into GCC and builds the code, returning a
> >+   `gcc_jit_result *`.
> >+
> >+   This is a thin wrapper around the
> >+   :c:func:`gcc_jit_context_compile` API entrypoint.
> >+
> >+Ahead-of-time compilation
> >+*************************
> >+
> >+Although libgccjit is primarily aimed at just-in-time compilation, it
> >+can also be used for implementing more traditional ahead-of-time
> >+compilers, via the :func:`gccjit::context::compile_to_file` method.
> >+
> >+.. function:: void \
> >+              gccjit::context::compile_to_file (enum
> >gcc_jit_output_kind,\
> >+                                                const char
> >*output_path)
> >+
> >+   Compile the :class:`gccjit::context` to a file of the given
> >+   kind.
> >+
> >+   This is a thin wrapper around the
> >+   :c:func:`gcc_jit_context_compile_to_file` API entrypoint.
> >diff --git a/gcc/jit/docs/cp/topics/index.rst
> >b/gcc/jit/docs/cp/topics/index.rst
> >index a129137..4ebb623 100644
> >--- a/gcc/jit/docs/cp/topics/index.rst
> >+++ b/gcc/jit/docs/cp/topics/index.rst
> >@@ -1,4 +1,4 @@
> >-.. Copyright (C) 2014 Free Software Foundation, Inc.
> >+.. Copyright (C) 2014-2015 Free Software Foundation, Inc.
> >    Originally contributed by David Malcolm <dmalcolm@redhat.com>
> > 
> >    This is free software: you can redistribute it and/or modify it
> >@@ -27,4 +27,4 @@ Topic Reference
> >    expressions.rst
> >    functions.rst
> >    locations.rst
> >-   results.rst
> >+   compilation.rst
> >diff --git a/gcc/jit/docs/cp/topics/results.rst
> >b/gcc/jit/docs/cp/topics/results.rst
> >deleted file mode 100644
> >index 18200ac..0000000
> >--- a/gcc/jit/docs/cp/topics/results.rst
> >+++ /dev/null
> >@@ -1,48 +0,0 @@
> >-.. 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:: cpp
> >-
> >-Compilation results
> >-===================
> >-
> >-.. type:: gcc_jit_result
> >-
> >-  A `gcc_jit_result` encapsulates the result of compiling a context.
> >-
> >-.. function:: gcc_jit_result *\
> >-              gccjit::context::compile ()
> >-
> >-   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/examples/emit-alphabet.bf
> >b/gcc/jit/docs/examples/emit-alphabet.bf
> >new file mode 100644
> >index 0000000..6863273
> >--- /dev/null
> >+++ b/gcc/jit/docs/examples/emit-alphabet.bf
> >@@ -0,0 +1,17 @@
> >+[
> >+  Emit the uppercase alphabet
> >+]
> >+
> >+cell 0 = 26
> >+++++++++++++++++++++++++++
> >+
> >+cell 1 = 65
> >+>+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++<
> >+
> >+while cell#0 != 0
> >+[
> >+ >
> >+ .      emit cell#1
> >+ +      increment cell@1
> >+ <-     decrement cell@0
> >+]
> >diff --git a/gcc/jit/docs/examples/tut05-bf.c
> >b/gcc/jit/docs/examples/tut05-bf.c
> >new file mode 100644
> >index 0000000..f948ede
> >--- /dev/null
> >+++ b/gcc/jit/docs/examples/tut05-bf.c
> >@@ -0,0 +1,446 @@
> >+/* A compiler for the "bf" language.  */
> >+
> >+#include <stdlib.h>
> >+#include <string.h>
> >+#include <errno.h>
> >+
> >+#include "libgccjit.h"
> >+
> >+/* Make "main" function:
> >+     int
> >+     main (int argc, char **argv)
> >+     {
> >+       ...
> >+     }
> >+*/
> >+static gcc_jit_function *
> >+make_main (gcc_jit_context *ctxt)
> >+{
> >+  gcc_jit_type *int_type =
> >+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
> >+  gcc_jit_param *param_argc =
> >+    gcc_jit_context_new_param (ctxt, NULL, int_type, "argc");
> >+  gcc_jit_type *char_ptr_ptr_type =
> >+    gcc_jit_type_get_pointer (
> >+      gcc_jit_type_get_pointer (
> >+	gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_CHAR)));
> >+  gcc_jit_param *param_argv =
> >+    gcc_jit_context_new_param (ctxt, NULL, char_ptr_ptr_type, "argv");
> >+  gcc_jit_param *params[2] = {param_argc, param_argv};
> >+  gcc_jit_function *func_main =
> >+    gcc_jit_context_new_function (ctxt, NULL,
> >+				  GCC_JIT_FUNCTION_EXPORTED,
> >+				  int_type,
> >+				  "main",
> >+				  2, params,
> >+				  0);
> >+  return func_main;
> >+}
> >+
> >+#define MAX_OPEN_PARENS 16
> >+
> >+typedef struct bf_compiler
> >+{
> >+  const char *filename;
> >+  int line;
> >+  int column;
> >+
> >+  gcc_jit_context *ctxt;
> >+
> >+  gcc_jit_type *void_type;
> >+  gcc_jit_type *int_type;
> >+  gcc_jit_type *byte_type;
> >+  gcc_jit_type *array_type;
> >+
> >+  gcc_jit_function *func_getchar;
> >+  gcc_jit_function *func_putchar;
> >+
> >+  gcc_jit_function *func;
> >+  gcc_jit_block *curblock;
> >+
> >+  gcc_jit_rvalue *int_zero;
> >+  gcc_jit_rvalue *int_one;
> >+  gcc_jit_rvalue *byte_zero;
> >+  gcc_jit_rvalue *byte_one;
> >+  gcc_jit_lvalue *data_cells;
> >+  gcc_jit_lvalue *idx;
> >+
> >+  int num_open_parens;
> >+  gcc_jit_block *paren_test[MAX_OPEN_PARENS];
> >+  gcc_jit_block *paren_body[MAX_OPEN_PARENS];
> >+  gcc_jit_block *paren_after[MAX_OPEN_PARENS];
> >+
> >+} bf_compiler;
> >+
> >+/* Bail out, with a message on stderr.  */
> >+
> >+static void
> >+fatal_error (bf_compiler *bfc, const char *msg)
> >+{
> >+  fprintf (stderr,
> >+	   "%s:%i:%i: %s",
> >+	   bfc->filename, bfc->line, bfc->column, msg);
> >+  abort ();
> >+}
> >+
> >+/* Get "data_cells[idx]" as an lvalue.  */
> >+
> >+static gcc_jit_lvalue *
> >+bf_get_current_data (bf_compiler *bfc, gcc_jit_location *loc)
> >+{
> >+  return gcc_jit_context_new_array_access (
> >+    bfc->ctxt,
> >+    loc,
> >+    gcc_jit_lvalue_as_rvalue (bfc->data_cells),
> >+    gcc_jit_lvalue_as_rvalue (bfc->idx));
> >+}
> >+
> >+/* Get "data_cells[idx] == 0" as a boolean rvalue.  */
> >+
> >+static gcc_jit_rvalue *
> >+bf_current_data_is_zero (bf_compiler *bfc, gcc_jit_location *loc)
> >+{
> >+  return gcc_jit_context_new_comparison (
> >+    bfc->ctxt,
> >+    loc,
> >+    GCC_JIT_COMPARISON_EQ,
> >+    gcc_jit_lvalue_as_rvalue (bf_get_current_data (bfc, loc)),
> >+    bfc->byte_zero);
> >+}
> >+
> >+/* Compile one bf character.  */
> >+
> >+static void
> >+bf_compile_char (bf_compiler *bfc,
> >+		 unsigned char ch)
> >+{
> >+  gcc_jit_location *loc =
> >+    gcc_jit_context_new_location (bfc->ctxt,
> >+				  bfc->filename,
> >+				  bfc->line,
> >+				  bfc->column);
> >+
> >+  /* Turn this on to trace execution, by injecting putchar ()
> >+     of each source char. */
> >+  if (0)
> >+    {
> >+      gcc_jit_rvalue *arg =
> >+	gcc_jit_context_new_rvalue_from_int (
> >+					     bfc->ctxt,
> >+					     bfc->int_type,
> >+					     ch);
> >+      gcc_jit_rvalue *call =
> >+	gcc_jit_context_new_call (bfc->ctxt,
> >+				  loc,
> >+				  bfc->func_putchar,
> >+				  1, &arg);
> >+      gcc_jit_block_add_eval (bfc->curblock,
> >+			      loc,
> >+			      call);
> >+    }
> >+
> >+  switch (ch)
> >+    {
> >+      case '>':
> >+	gcc_jit_block_add_comment (bfc->curblock,
> >+				   loc,
> >+				   "'>': idx += 1;");
> >+	gcc_jit_block_add_assignment_op (bfc->curblock,
> >+					 loc,
> >+					 bfc->idx,
> >+					 GCC_JIT_BINARY_OP_PLUS,
> >+					 bfc->int_one);
> >+	break;
> >+
> >+      case '<':
> >+	gcc_jit_block_add_comment (bfc->curblock,
> >+				   loc,
> >+				   "'<': idx -= 1;");
> >+	gcc_jit_block_add_assignment_op (bfc->curblock,
> >+					 loc,
> >+					 bfc->idx,
> >+					 GCC_JIT_BINARY_OP_MINUS,
> >+					 bfc->int_one);
> >+	break;
> >+
> >+      case '+':
> >+	gcc_jit_block_add_comment (bfc->curblock,
> >+				   loc,
> >+				   "'+': data[idx] += 1;");
> >+	gcc_jit_block_add_assignment_op (bfc->curblock,
> >+					 loc,
> >+					 bf_get_current_data (bfc, loc),
> >+					 GCC_JIT_BINARY_OP_PLUS,
> >+					 bfc->byte_one);
> >+	break;
> >+
> >+      case '-':
> >+	gcc_jit_block_add_comment (bfc->curblock,
> >+				   loc,
> >+				   "'-': data[idx] -= 1;");
> >+	gcc_jit_block_add_assignment_op (bfc->curblock,
> >+					 loc,
> >+					 bf_get_current_data (bfc, loc),
> >+					 GCC_JIT_BINARY_OP_MINUS,
> >+					 bfc->byte_one);
> >+	break;
> >+
> >+      case '.':
> >+	{
> >+	  gcc_jit_rvalue *arg =
> >+	    gcc_jit_context_new_cast (
> >+	      bfc->ctxt,
> >+	      loc,
> >+	      gcc_jit_lvalue_as_rvalue (bf_get_current_data (bfc, loc)),
> >+	      bfc->int_type);
> >+	  gcc_jit_rvalue *call =
> >+	    gcc_jit_context_new_call (bfc->ctxt,
> >+				      loc,
> >+				      bfc->func_putchar,
> >+				      1, &arg);
> >+	  gcc_jit_block_add_comment (bfc->curblock,
> >+				     loc,
> >+				     "'.': putchar ((int)data[idx]);");
> >+	  gcc_jit_block_add_eval (bfc->curblock,
> >+				  loc,
> >+				  call);
> >+	}
> >+	break;
> >+
> >+      case ',':
> >+	{
> >+	  gcc_jit_rvalue *call =
> >+	    gcc_jit_context_new_call (bfc->ctxt,
> >+				      loc,
> >+				      bfc->func_getchar,
> >+				      0, NULL);
> >+	  gcc_jit_block_add_comment (
> >+	    bfc->curblock,
> >+	    loc,
> >+	    "',': data[idx] = (unsigned char)getchar ();");
> >+	  gcc_jit_block_add_assignment (bfc->curblock,
> >+					loc,
> >+					bf_get_current_data (bfc, loc),
> >+					gcc_jit_context_new_cast (
> >+					  bfc->ctxt,
> >+					  loc,
> >+					  call,
> >+					  bfc->byte_type));
> >+	}
> >+	break;
> >+
> >+      case '[':
> >+	{
> >+	  gcc_jit_block *loop_test =
> >+	    gcc_jit_function_new_block (bfc->func, NULL);
> >+	  gcc_jit_block *on_zero =
> >+	    gcc_jit_function_new_block (bfc->func, NULL);
> >+	  gcc_jit_block *on_non_zero =
> >+	    gcc_jit_function_new_block (bfc->func, NULL);
> >+
> >+	  if (bfc->num_open_parens == MAX_OPEN_PARENS)
> >+	    fatal_error (bfc, "too many open parens");
> >+
> >+	  gcc_jit_block_end_with_jump (
> >+	    bfc->curblock,
> >+	    loc,
> >+	    loop_test);
> >+
> >+	  gcc_jit_block_add_comment (
> >+	    loop_test,
> >+	    loc,
> >+	    "'['");
> >+	  gcc_jit_block_end_with_conditional (
> >+	    loop_test,
> >+	    loc,
> >+	    bf_current_data_is_zero (bfc, loc),
> >+	    on_zero,
> >+	    on_non_zero);
> >+	  bfc->paren_test[bfc->num_open_parens] = loop_test;
> >+	  bfc->paren_body[bfc->num_open_parens] = on_non_zero;
> >+	  bfc->paren_after[bfc->num_open_parens] = on_zero;
> >+	  bfc->num_open_parens += 1;
> >+	  bfc->curblock = on_non_zero;
> >+	}
> >+	break;
> >+
> >+      case ']':
> >+	{
> >+	  gcc_jit_block_add_comment (
> >+	    bfc->curblock,
> >+	    loc,
> >+	    "']'");
> >+
> >+	  if (bfc->num_open_parens == 0)
> >+	    fatal_error (bfc, "mismatching parens");
> >+	  bfc->num_open_parens -= 1;
> >+	  gcc_jit_block_end_with_jump (
> >+	    bfc->curblock,
> >+	    loc,
> >+	    bfc->paren_test[bfc->num_open_parens]);
> >+	  bfc->curblock = bfc->paren_after[bfc->num_open_parens];
> >+	}
> >+	break;
> >+
> >+    case '\n':
> >+      bfc->line +=1;
> >+      bfc->column = 0;
> >+      break;
> >+    }
> >+
> >+  if (ch != '\n')
> >+    bfc->column += 1;
> >+}
> >+
> >+/* Compile the given .bf file into a gcc_jit_context, containing a
> >+   single "main" function suitable for compiling into an executable. 
> >*/
> >+
> >+gcc_jit_context *
> >+bf_compile (const char *filename)
> >+{
> >+  bf_compiler bfc;
> >+  FILE *f_in;
> >+  int ch;
> >+
> >+  memset (&bfc, 0, sizeof (bfc));
> >+
> >+  bfc.filename = filename;
> >+  f_in = fopen (filename, "r");
> >+  if (!f_in)
> >+    fatal_error (&bfc, "unable to open file");
> >+  bfc.line = 1;
> >+
> >+  bfc.ctxt = gcc_jit_context_acquire ();
> >+
> >+  gcc_jit_context_set_int_option (
> >+    bfc.ctxt,
> >+    GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL,
> >+    3);
> >+  gcc_jit_context_set_bool_option (
> >+    bfc.ctxt,
> >+    GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE,
> >+    0);
> >+  gcc_jit_context_set_bool_option (
> >+    bfc.ctxt,
> >+    GCC_JIT_BOOL_OPTION_DEBUGINFO,
> >+    1);
> >+  gcc_jit_context_set_bool_option (
> >+    bfc.ctxt,
> >+    GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING,
> >+    0);
> >+  gcc_jit_context_set_bool_option (
> >+    bfc.ctxt,
> >+    GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES,
> >+    0);
> >+
> >+  bfc.void_type =
> >+    gcc_jit_context_get_type (bfc.ctxt, GCC_JIT_TYPE_VOID);
> >+  bfc.int_type =
> >+    gcc_jit_context_get_type (bfc.ctxt, GCC_JIT_TYPE_INT);
> >+  bfc.byte_type =
> >+    gcc_jit_context_get_type (bfc.ctxt, GCC_JIT_TYPE_UNSIGNED_CHAR);
> >+  bfc.array_type =
> >+    gcc_jit_context_new_array_type (bfc.ctxt,
> >+				    NULL,
> >+				    bfc.byte_type,
> >+				    30000);
> >+
> >+  bfc.func_getchar =
> >+    gcc_jit_context_new_function (bfc.ctxt, NULL,
> >+				  GCC_JIT_FUNCTION_IMPORTED,
> >+				  bfc.int_type,
> >+				  "getchar",
> >+				  0, NULL,
> >+				  0);
> >+
> >+  gcc_jit_param *param_c =
> >+    gcc_jit_context_new_param (bfc.ctxt, NULL, bfc.int_type, "c");
> >+  bfc.func_putchar =
> >+    gcc_jit_context_new_function (bfc.ctxt, NULL,
> >+				  GCC_JIT_FUNCTION_IMPORTED,
> >+				  bfc.void_type,
> >+				  "putchar",
> >+				  1, &param_c,
> >+				  0);
> >+
> >+  bfc.func = make_main (bfc.ctxt);
> >+   bfc.curblock =
> >+    gcc_jit_function_new_block (bfc.func, "initial");
> >+  bfc.int_zero = gcc_jit_context_zero (bfc.ctxt, bfc.int_type);
> >+  bfc.int_one = gcc_jit_context_one (bfc.ctxt, bfc.int_type);
> >+  bfc.byte_zero = gcc_jit_context_zero (bfc.ctxt, bfc.byte_type);
> >+  bfc.byte_one = gcc_jit_context_one (bfc.ctxt, bfc.byte_type);
> >+
> >+  bfc.data_cells =
> >+    gcc_jit_context_new_global (bfc.ctxt, NULL,
> >+				 GCC_JIT_GLOBAL_INTERNAL,
> >+				 bfc.array_type,
> >+				 "data_cells");
> >+  bfc.idx =
> >+    gcc_jit_function_new_local (bfc.func, NULL,
> >+				bfc.int_type,
> >+				"idx");
> >+
> >+  gcc_jit_block_add_comment (bfc.curblock,
> >+			     NULL,
> >+			     "idx = 0;");
> >+  gcc_jit_block_add_assignment (bfc.curblock,
> >+				NULL,
> >+				bfc.idx,
> >+				bfc.int_zero);
> >+
> >+  bfc.num_open_parens = 0;
> >+
> >+  while ( EOF != (ch = fgetc (f_in)))
> >+    bf_compile_char (&bfc, (unsigned char)ch);
> >+
> >+  gcc_jit_block_end_with_return (bfc.curblock, NULL, bfc.int_zero);
> >+
> >+  fclose (f_in);
> >+
> >+  return bfc.ctxt;
> >+}
> >+
> >+/* Entrypoint to the compiler.  */
> >+
> >+int
> >+main (int argc, char **argv)
> >+{
> >+  const char *input_file;
> >+  const char *output_file;
> >+  gcc_jit_context *ctxt;
> >+  const char *err;
> >+
> >+  if (argc != 3)
> >+    {
> >+      fprintf (stderr, "%s: INPUT_FILE OUTPUT_FILE\n", argv[0]);
> >+      return 1;
> >+    }
> >+
> >+  input_file = argv[1];
> >+  output_file = argv[2];
> >+  ctxt = bf_compile (input_file);
> >+
> >+  gcc_jit_context_compile_to_file (ctxt,
> >+				   GCC_JIT_OUTPUT_KIND_EXECUTABLE,
> >+				   output_file);
> >+
> >+  err = gcc_jit_context_get_first_error (ctxt);
> >+
> >+  if (err)
> >+    {
> >+      gcc_jit_context_release (ctxt);
> >+      return 1;
> >+    }
> >+
> >+  gcc_jit_context_release (ctxt);
> >+  return 0;
> >+}
> >+
> >+/* Use the built compiler to compile the example to an executable:
> >+
> >+     { dg-jit-set-exe-params
> >SRCDIR/gcc/jit/docs/examples/emit-alphabet.bf emit-alphabet.bf.exe }
> >+
> >+   Then run the executable, and verify that it emits the alphabet:
> >+
> >+     { dg-final { jit-run-executable emit-alphabet.bf.exe
> >"ABCDEFGHIJKLMNOPQRSTUVWXYZ" } } */
> >diff --git a/gcc/jit/docs/internals/test-hello-world.exe.log.txt
> >b/gcc/jit/docs/internals/test-hello-world.exe.log.txt
> >index 113dc35..205b6b4 100644
> >--- a/gcc/jit/docs/internals/test-hello-world.exe.log.txt
> >+++ b/gcc/jit/docs/internals/test-hello-world.exe.log.txt
> >@@ -38,14 +38,20 @@ JIT: entering: gcc_jit_block_add_eval
> > JIT: exiting: gcc_jit_block_add_eval
> > JIT: entering: gcc_jit_block_end_with_void_return
> > JIT: exiting: gcc_jit_block_end_with_void_return
> >+JIT: entering: gcc_jit_context_dump_reproducer_to_file
> >+JIT:  entering: void
> >gcc::jit::recording::context::dump_reproducer_to_file(const char*)
> >+JIT:  exiting: void
> >gcc::jit::recording::context::dump_reproducer_to_file(const char*)
> >+JIT: exiting: gcc_jit_context_dump_reproducer_to_file
> > JIT: entering: gcc_jit_context_compile
> >-JIT:  compiling ctxt: 0x1283e20
> >+JIT:  in-memory compile of ctxt: 0x1283e20
> >JIT:  entering: gcc::jit::result*
> >gcc::jit::recording::context::compile()
> > JIT:   entering: void gcc::jit::recording::context::validate()
> > JIT:   exiting: void gcc::jit::recording::context::validate()
> >JIT:   entering:
> >gcc::jit::playback::context::context(gcc::jit::recording::context*)
> >JIT:   exiting:
> >gcc::jit::playback::context::context(gcc::jit::recording::context*)
> >-JIT:   entering: gcc::jit::result*
> >gcc::jit::playback::context::compile()
> >+JIT:   entering:
> >gcc::jit::playback::compile_to_memory::compile_to_memory(gcc::jit::recording::context*)
> >+JIT:   exiting:
> >gcc::jit::playback::compile_to_memory::compile_to_memory(gcc::jit::recording::context*)
> >+JIT:   entering: void gcc::jit::playback::context::compile()
> > JIT:    entering: gcc::jit::tempdir::tempdir(gcc::jit::logger*, int)
> > JIT:    exiting: gcc::jit::tempdir::tempdir(gcc::jit::logger*, int)
> > JIT:    entering: bool gcc::jit::tempdir::create()
> >@@ -86,29 +92,37 @@ JIT:      entering: void
> >gcc::jit::playback::function::postprocess()
> > JIT:      exiting: void gcc::jit::playback::function::postprocess()
> > JIT:     exiting: void gcc::jit::playback::context::replay()
> > JIT:     entering: void jit_langhook_write_globals()
> >+JIT:      entering: void
> >gcc::jit::playback::context::write_global_decls_1()
> >+JIT:      exiting: void
> >gcc::jit::playback::context::write_global_decls_1()
> >+JIT:      entering: void
> >gcc::jit::playback::context::write_global_decls_2()
> >+JIT:      exiting: void
> >gcc::jit::playback::context::write_global_decls_2()
> > JIT:     exiting: void jit_langhook_write_globals()
> > JIT:    exiting: toplev::main
> >JIT:    entering: void
> >gcc::jit::playback::context::extract_any_requested_dumps(vec<gcc::jit::recording::requested_dump>*)
> >JIT:    exiting: void
> >gcc::jit::playback::context::extract_any_requested_dumps(vec<gcc::jit::recording::requested_dump>*)
> > JIT:    entering: toplev::finalize
> > JIT:    exiting: toplev::finalize
> >-JIT:    entering: void
> >gcc::jit::playback::context::convert_to_dso(const char*)
> >-JIT:     argv[0]: x86_64-unknown-linux-gnu-gcc-5.0.0
> >-JIT:     argv[1]: -shared
> >-JIT:     argv[2]: /tmp/libgccjit-CKq1M9/fake.s
> >-JIT:     argv[3]: -o
> >-JIT:     argv[4]: /tmp/libgccjit-CKq1M9/fake.so
> >-JIT:     argv[5]: -fno-use-linker-plugin
> >-JIT:     argv[6]: (null)
> >-JIT:    exiting: void
> >gcc::jit::playback::context::convert_to_dso(const char*)
> >-JIT:    entering: gcc::jit::result*
> >gcc::jit::playback::context::dlopen_built_dso()
> >-JIT:     GCC_JIT_BOOL_OPTION_DEBUGINFO was set: handing over tempdir
> >to jit::result
> >-JIT:     entering: gcc::jit::result::result(gcc::jit::logger*, void*,
> >gcc::jit::tempdir*)
> >-JIT:     exiting: gcc::jit::result::result(gcc::jit::logger*, void*,
> >gcc::jit::tempdir*)
> >-JIT:    exiting: gcc::jit::result*
> >gcc::jit::playback::context::dlopen_built_dso()
> >+JIT:    entering: virtual void
> >gcc::jit::playback::compile_to_memory::postprocess(const char*)
> >+JIT:     entering: void
> >gcc::jit::playback::context::convert_to_dso(const char*)
> >+JIT:      entering: void
> >gcc::jit::playback::context::invoke_driver(const char*, const char*,
> >const char*, timevar_id_t, bool, bool)
> >+JIT:       argv[0]: x86_64-unknown-linux-gnu-gcc-5.0.0
> >+JIT:       argv[1]: -shared
> >+JIT:       argv[2]: /tmp/libgccjit-CKq1M9/fake.s
> >+JIT:       argv[3]: -o
> >+JIT:       argv[4]: /tmp/libgccjit-CKq1M9/fake.so
> >+JIT:       argv[5]: -fno-use-linker-plugin
> >+JIT:       argv[6]: (null)
> >+JIT:      exiting: void
> >gcc::jit::playback::context::invoke_driver(const char*, const char*,
> >const char*, timevar_id_t, bool, bool)
> >+JIT:     exiting: void
> >gcc::jit::playback::context::convert_to_dso(const char*)
> >+JIT:     entering: gcc::jit::result*
> >gcc::jit::playback::context::dlopen_built_dso()
> >+JIT:      GCC_JIT_BOOL_OPTION_DEBUGINFO was set: handing over tempdir
> >to jit::result
> >+JIT:      entering: gcc::jit::result::result(gcc::jit::logger*, void*,
> >gcc::jit::tempdir*)
> >+JIT:      exiting: gcc::jit::result::result(gcc::jit::logger*, void*,
> >gcc::jit::tempdir*)
> >+JIT:     exiting: gcc::jit::result*
> >gcc::jit::playback::context::dlopen_built_dso()
> >+JIT:    exiting: virtual void
> >gcc::jit::playback::compile_to_memory::postprocess(const char*)
> > JIT:    entering: void gcc::jit::playback::context::release_mutex()
> > JIT:    exiting: void gcc::jit::playback::context::release_mutex()
> >-JIT:   exiting: gcc::jit::result*
> >gcc::jit::playback::context::compile()
> >+JIT:   exiting: void gcc::jit::playback::context::compile()
> > JIT:   entering: gcc::jit::playback::context::~context()
> > JIT:   exiting: gcc::jit::playback::context::~context()
> >JIT:  exiting: gcc::jit::result*
> >gcc::jit::recording::context::compile()
> >diff --git a/gcc/jit/docs/intro/index.rst
> >b/gcc/jit/docs/intro/index.rst
> >index d3bcec9..0f51777 100644
> >--- a/gcc/jit/docs/intro/index.rst
> >+++ b/gcc/jit/docs/intro/index.rst
> >@@ -1,4 +1,4 @@
> >-.. Copyright (C) 2014 Free Software Foundation, Inc.
> >+.. Copyright (C) 2014-2015 Free Software Foundation, Inc.
> >    Originally contributed by David Malcolm <dmalcolm@redhat.com>
> > 
> >    This is free software: you can redistribute it and/or modify it
> >@@ -25,3 +25,4 @@ Tutorial
> >    tutorial02.rst
> >    tutorial03.rst
> >    tutorial04.rst
> >+   tutorial05.rst
> >diff --git a/gcc/jit/docs/intro/tutorial05.rst
> >b/gcc/jit/docs/intro/tutorial05.rst
> >new file mode 100644
> >index 0000000..865a550
> >--- /dev/null
> >+++ b/gcc/jit/docs/intro/tutorial05.rst
> >@@ -0,0 +1,253 @@
> >+.. Copyright (C) 2015 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 5: Implementing an Ahead-of-Time compiler
> >+-------------------------------------------------------
> >+
> >+If you have a pre-existing language frontend, it's possible to hook
> >+it up to libgccjit as a backend.  In the previous example we showed
> >+how to do that for in-memory JIT-compilation, but libgccjit can also
> >+compile code directly to a file, allowing you to implement a more
> >+traditional ahead-of-time compil
> 
> 


[-- Attachment #2: licensing.patch --]
[-- Type: text/x-patch, Size: 1831 bytes --]

commit 653799d3e851c6bab1991e3e518ca8f40ae78fd7
Author: David Malcolm <dmalcolm@redhat.com>
Date:   Fri Jan 16 13:54:52 2015 -0500

    Remind people of licensing in the new tutorial
    
    gcc/jit/ChangeLog:
    	* docs/intro/tutorial05.rst: Mention the need for
    	license-compatibility in the couple of places that talk
    	about linking libgccjit to a pre-existing frontend.

diff --git a/gcc/jit/docs/intro/tutorial05.rst b/gcc/jit/docs/intro/tutorial05.rst
index 865a550..0de21a2 100644
--- a/gcc/jit/docs/intro/tutorial05.rst
+++ b/gcc/jit/docs/intro/tutorial05.rst
@@ -18,8 +18,9 @@
 Tutorial part 5: Implementing an Ahead-of-Time compiler
 -------------------------------------------------------
 
-If you have a pre-existing language frontend, it's possible to hook
-it up to libgccjit as a backend.  In the previous example we showed
+If you have a pre-existing language frontend that's compatible with
+libgccjit's license, it's possible to hook it up to libgccjit as a
+backend.  In the previous example we showed
 how to do that for in-memory JIT-compilation, but libgccjit can also
 compile code directly to a file, allowing you to implement a more
 traditional ahead-of-time compiler ("JIT" is something of a misnomer
@@ -76,7 +77,9 @@ Here's what a simple ``.bf`` script looks like:
    It's not a particularly useful language, except for providing
    compiler-writers with a test case that's easy to parse.  The point
    is that you can use :c:func:`gcc_jit_context_compile_to_file`
-   to use libgccjit as a backend for a pre-existing language frontend.
+   to use libgccjit as a backend for a pre-existing language frontend
+   (provided that the pre-existing frontend is compatible with libgccjit's
+   license).
 
 Converting a brainf script to libgccjit IR
 ******************************************

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Stage 3 RFC: using "jit" for ahead-of-time compilation
@ 2015-01-01  0:00 David Malcolm
  2015-01-01  0:00 ` Richard Biener
  2015-01-01  0:00 ` Jakub Jelinek
  0 siblings, 2 replies; 6+ messages in thread
From: David Malcolm @ 2015-01-01  0:00 UTC (permalink / raw)
  To: jit, gcc-patches, Jakub Jelinek, Richard Biener, Joseph Myers
  Cc: David Malcolm

Release managers: given that this only touches the jit, and that the jit
is off by default, any objections if I go ahead and commit this?
It's a late-breaking feature, but the jit as a whole is new, and
I think the following is a big win, so I'd like to proceed with this in
stage 3 (i.e. in the next 24 hours).  There are docs and testcases.

New jit API entrypoint: gcc_jit_context_compile_to_file

This patch adds a way to use libgccjit for ahead-of-time compilation.
I noticed that given the postprocessing steps the jit has to take to
turn the .s file into in-memory code (invoke driver to convert to
a .so and then dlopen), that it's not much of a leap to support
compiling the .s file into objects, dynamic libraries, and executables.

Doing so seems like a big win from a feature standpoint: people with
pre-existing frontend code who want a backend can then plug in libgccjit
and have a compiler, without needing to write it as a GCC frontend, or
use LLVM.

"jit" becomes something of a misnomer for this use-case.

As an experiment, I used this technique to add a compiler for the
language I'll refer to as "brainf" (ahem), and wrote this up for the
libgccjit tutorial (it's all in the patch); prebuilt HTML can be seen
at:
https://dmalcolm.fedorapeople.org/gcc/libgccjit-api-docs-wip/intro/tutorial05.html

The main things that are missing are:
  * specifying libraries to link against (Uli had some ideas about this)
  * cross-compilation support (needs some deeper work, especially the
    test suite, so deferrable to gcc 6, I guess)
but the feature is useful with the patch as-is.

The new test cases take jit.sum's # of expected passes
from 7514 to 7571.

gcc/jit/ChangeLog:
	* docs/cp/topics/results.rst: Rename to...
	* docs/cp/topics/compilation.rst: ...this, and add section on
	ahead-of-time compilation.
	* docs/cp/topics/index.rst: Update for renaming of results.rst
	to compilation.rst.
	* docs/examples/emit-alphabet.bf: New file, a sample "brainf"
	script.
	* docs/examples/tut05-bf.c: New file, implementing a compiler
	for "brainf".
	* docs/internals/test-hello-world.exe.log.txt: Update to reflect
	changes to logger output.
	* docs/intro/index.rst: Add tutorial05.rst
	* docs/intro/tutorial05.rst: New file.
	* docs/topics/results.rst: Rename to...
	* docs/topics/compilation.rst: ...this, and add section on
	ahead-of-time compilation.
	* docs/topics/index.rst: Update for renaming of results.rst to
	compilation.rst.
	* jit-playback.c (gcc::jit::playback::context::compile): Convert
	return type from result * to void.  Move the code to convert to
	dso and dlopen the result to a new pure virtual "postprocess"
	method.
	(gcc::jit::playback::compile_to_memory::compile_to_memory): New
	function.
	(gcc::jit::playback::compile_to_memory::postprocess): New
	function, based on playback::context::compile.
	(gcc::jit::playback::compile_to_file::compile_to_file): New
	function.
	(gcc::jit::playback::compile_to_file::postprocess): New function.
	(gcc::jit::playback::compile_to_file::copy_file): New function.
	(gcc::jit::playback::context::convert_to_dso): Move internals
	to...
	(gcc::jit::playback::context::invoke_driver): New method.  Add
	"-shared" and "-c" options to driver's argv as needed.
	* jit-playback.h: Include "timevar.h".
	(gcc::jit::playback::context::compile): Convert return type from
	result * to void.
	(gcc::jit::playback::context::postprocess): New pure virtual
	function, making this an abstract base class.
	(gcc::jit::playback::context::get_tempdir): New accessor.
	(gcc::jit::playback::context::invoke_driver): New function.
	(class gcc::jit::playback::compile_to_memory): New subclass of
	playback::context.
	(class gcc::jit::playback::compile_to_file): Likewise.
	* jit-recording.c (gcc::jit::recording::context::compile): Use a
	playback::compile_to_memory, and extract its result.
	(gcc::jit::recording::context::compile_to_file): New function.
	* jit-recording.h (gcc::jit::recording::context::compile_to_file):
	New function.
	* libgccjit++.h (gccjit::context::compile_to_file): New method.
	* libgccjit.c (gcc_jit_context_compile): Update log message to
	clarify that this is an in-memory compile.
	(gcc_jit_context_compile_to_file): New function.
	* libgccjit.h (gcc_jit_context): Clarify that you can compile
	a context more than once, and that you can compile to a file
	as well as to memory.
	(gcc_jit_result): Clarify that this is the result of an
	in-memory compilation.
	(gcc_jit_context_compile): Clarify that you can compile, and that
	this is an in-memory compilation.
	(enum gcc_jit_output_kind): New enum.
	(gcc_jit_context_compile_to_file): New function.
	(gcc_jit_context_enable_dump): Clarify comment to cover both forms
	of compilation.
	* libgccjit.map (gcc_jit_context_compile_to_file): New API
	entrypoint.
	* notes.txt: Update to show the playback::context::postprocess
	virtual function.

gcc/testsuite/ChangeLog:
	* jit.dg/harness.h: Include <unistd.h>.
	(CHECK_NO_ERRORS): New.
	(verify_code): Wrap prototype in #ifndef TEST_COMPILING_TO_FILE.
	(test_jit): Support new macro TEST_COMPILING_TO_FILE for exercising
	gcc_jit_context_compile_to_file.
	* jit.dg/jit.exp (fixed_host_execute): Fix the code for passing on
	args to the spawned executable.
	(jit-expand-vars): New function.
	(jit-exe-params): New variable.
	(dg-jit-set-exe-params): New function.
	(jit-dg-test): Detect testcases that use
	jit-verify-compile-to-file and call jit-setup-compile-to-file.
	Set arguments of spawned process to jit-exe-params.
	(jit-get-output-filename): New function.
	(jit-setup-compile-to-file): New function.
	(jit-verify-compile-to-file): New function.
	(jit-run-executable): New function.
	(jit-verify-executable): New function.
	* jit.dg/test-compile-to-assembler.c: New testcase.
	* jit.dg/test-compile-to-dynamic-library.c: New testcase.
	* jit.dg/test-compile-to-executable.c: New testcase.
	* jit.dg/test-compile-to-object.c: New testcase.
---
 gcc/jit/docs/cp/topics/compilation.rst             |  58 +++
 gcc/jit/docs/cp/topics/index.rst                   |   4 +-
 gcc/jit/docs/cp/topics/results.rst                 |  48 ---
 gcc/jit/docs/examples/emit-alphabet.bf             |  17 +
 gcc/jit/docs/examples/tut05-bf.c                   | 446 +++++++++++++++++++++
 .../docs/internals/test-hello-world.exe.log.txt    |  48 ++-
 gcc/jit/docs/intro/index.rst                       |   3 +-
 gcc/jit/docs/intro/tutorial05.rst                  | 253 ++++++++++++
 gcc/jit/docs/topics/compilation.rst                | 199 +++++++++
 gcc/jit/docs/topics/index.rst                      |   4 +-
 gcc/jit/docs/topics/results.rst                    | 127 ------
 gcc/jit/jit-playback.c                             | 308 +++++++++++++-
 gcc/jit/jit-playback.h                             |  54 ++-
 gcc/jit/jit-recording.c                            |  40 +-
 gcc/jit/jit-recording.h                            |   4 +
 gcc/jit/libgccjit++.h                              |  12 +
 gcc/jit/libgccjit.c                                |  31 +-
 gcc/jit/libgccjit.h                                |  58 ++-
 gcc/jit/libgccjit.map                              |   1 +
 gcc/jit/notes.txt                                  |  13 +-
 gcc/testsuite/jit.dg/harness.h                     |  29 +-
 gcc/testsuite/jit.dg/jit.exp                       | 209 +++++++++-
 gcc/testsuite/jit.dg/test-compile-to-assembler.c   |  65 +++
 .../jit.dg/test-compile-to-dynamic-library.c       |  65 +++
 gcc/testsuite/jit.dg/test-compile-to-executable.c  | 110 +++++
 gcc/testsuite/jit.dg/test-compile-to-object.c      |  65 +++
 26 files changed, 2026 insertions(+), 245 deletions(-)
 create mode 100644 gcc/jit/docs/cp/topics/compilation.rst
 delete mode 100644 gcc/jit/docs/cp/topics/results.rst
 create mode 100644 gcc/jit/docs/examples/emit-alphabet.bf
 create mode 100644 gcc/jit/docs/examples/tut05-bf.c
 create mode 100644 gcc/jit/docs/intro/tutorial05.rst
 create mode 100644 gcc/jit/docs/topics/compilation.rst
 delete mode 100644 gcc/jit/docs/topics/results.rst
 create mode 100644 gcc/testsuite/jit.dg/test-compile-to-assembler.c
 create mode 100644 gcc/testsuite/jit.dg/test-compile-to-dynamic-library.c
 create mode 100644 gcc/testsuite/jit.dg/test-compile-to-executable.c
 create mode 100644 gcc/testsuite/jit.dg/test-compile-to-object.c

diff --git a/gcc/jit/docs/cp/topics/compilation.rst b/gcc/jit/docs/cp/topics/compilation.rst
new file mode 100644
index 0000000..05917e8
--- /dev/null
+++ b/gcc/jit/docs/cp/topics/compilation.rst
@@ -0,0 +1,58 @@
+.. Copyright (C) 2014-2015 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:: cpp
+
+Compiling a context
+===================
+
+Once populated, a :class:`gccjit::context` can be compiled to
+machine code, either in-memory via :func:`gccjit::context::compile` or
+to disk via :func:`gccjit::context::compile_to_file`.
+
+You can compile a context multiple times (using either form of
+compilation), although any errors that occur on the context will
+prevent any future compilation of that context.
+
+In-memory compilation
+*********************
+
+.. function:: gcc_jit_result *\
+              gccjit::context::compile ()
+
+   This calls into GCC and builds the code, returning a
+   `gcc_jit_result *`.
+
+   This is a thin wrapper around the
+   :c:func:`gcc_jit_context_compile` API entrypoint.
+
+Ahead-of-time compilation
+*************************
+
+Although libgccjit is primarily aimed at just-in-time compilation, it
+can also be used for implementing more traditional ahead-of-time
+compilers, via the :func:`gccjit::context::compile_to_file` method.
+
+.. function:: void \
+              gccjit::context::compile_to_file (enum gcc_jit_output_kind,\
+                                                const char *output_path)
+
+   Compile the :class:`gccjit::context` to a file of the given
+   kind.
+
+   This is a thin wrapper around the
+   :c:func:`gcc_jit_context_compile_to_file` API entrypoint.
diff --git a/gcc/jit/docs/cp/topics/index.rst b/gcc/jit/docs/cp/topics/index.rst
index a129137..4ebb623 100644
--- a/gcc/jit/docs/cp/topics/index.rst
+++ b/gcc/jit/docs/cp/topics/index.rst
@@ -1,4 +1,4 @@
-.. Copyright (C) 2014 Free Software Foundation, Inc.
+.. Copyright (C) 2014-2015 Free Software Foundation, Inc.
    Originally contributed by David Malcolm <dmalcolm@redhat.com>
 
    This is free software: you can redistribute it and/or modify it
@@ -27,4 +27,4 @@ Topic Reference
    expressions.rst
    functions.rst
    locations.rst
-   results.rst
+   compilation.rst
diff --git a/gcc/jit/docs/cp/topics/results.rst b/gcc/jit/docs/cp/topics/results.rst
deleted file mode 100644
index 18200ac..0000000
--- a/gcc/jit/docs/cp/topics/results.rst
+++ /dev/null
@@ -1,48 +0,0 @@
-.. 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:: cpp
-
-Compilation results
-===================
-
-.. type:: gcc_jit_result
-
-  A `gcc_jit_result` encapsulates the result of compiling a context.
-
-.. function:: gcc_jit_result *\
-              gccjit::context::compile ()
-
-   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/examples/emit-alphabet.bf b/gcc/jit/docs/examples/emit-alphabet.bf
new file mode 100644
index 0000000..6863273
--- /dev/null
+++ b/gcc/jit/docs/examples/emit-alphabet.bf
@@ -0,0 +1,17 @@
+[
+  Emit the uppercase alphabet
+]
+
+cell 0 = 26
+++++++++++++++++++++++++++
+
+cell 1 = 65
+>+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++<
+
+while cell#0 != 0
+[
+ >
+ .      emit cell#1
+ +      increment cell@1
+ <-     decrement cell@0
+]
diff --git a/gcc/jit/docs/examples/tut05-bf.c b/gcc/jit/docs/examples/tut05-bf.c
new file mode 100644
index 0000000..f948ede
--- /dev/null
+++ b/gcc/jit/docs/examples/tut05-bf.c
@@ -0,0 +1,446 @@
+/* A compiler for the "bf" language.  */
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "libgccjit.h"
+
+/* Make "main" function:
+     int
+     main (int argc, char **argv)
+     {
+       ...
+     }
+*/
+static gcc_jit_function *
+make_main (gcc_jit_context *ctxt)
+{
+  gcc_jit_type *int_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+  gcc_jit_param *param_argc =
+    gcc_jit_context_new_param (ctxt, NULL, int_type, "argc");
+  gcc_jit_type *char_ptr_ptr_type =
+    gcc_jit_type_get_pointer (
+      gcc_jit_type_get_pointer (
+	gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_CHAR)));
+  gcc_jit_param *param_argv =
+    gcc_jit_context_new_param (ctxt, NULL, char_ptr_ptr_type, "argv");
+  gcc_jit_param *params[2] = {param_argc, param_argv};
+  gcc_jit_function *func_main =
+    gcc_jit_context_new_function (ctxt, NULL,
+				  GCC_JIT_FUNCTION_EXPORTED,
+				  int_type,
+				  "main",
+				  2, params,
+				  0);
+  return func_main;
+}
+
+#define MAX_OPEN_PARENS 16
+
+typedef struct bf_compiler
+{
+  const char *filename;
+  int line;
+  int column;
+
+  gcc_jit_context *ctxt;
+
+  gcc_jit_type *void_type;
+  gcc_jit_type *int_type;
+  gcc_jit_type *byte_type;
+  gcc_jit_type *array_type;
+
+  gcc_jit_function *func_getchar;
+  gcc_jit_function *func_putchar;
+
+  gcc_jit_function *func;
+  gcc_jit_block *curblock;
+
+  gcc_jit_rvalue *int_zero;
+  gcc_jit_rvalue *int_one;
+  gcc_jit_rvalue *byte_zero;
+  gcc_jit_rvalue *byte_one;
+  gcc_jit_lvalue *data_cells;
+  gcc_jit_lvalue *idx;
+
+  int num_open_parens;
+  gcc_jit_block *paren_test[MAX_OPEN_PARENS];
+  gcc_jit_block *paren_body[MAX_OPEN_PARENS];
+  gcc_jit_block *paren_after[MAX_OPEN_PARENS];
+
+} bf_compiler;
+
+/* Bail out, with a message on stderr.  */
+
+static void
+fatal_error (bf_compiler *bfc, const char *msg)
+{
+  fprintf (stderr,
+	   "%s:%i:%i: %s",
+	   bfc->filename, bfc->line, bfc->column, msg);
+  abort ();
+}
+
+/* Get "data_cells[idx]" as an lvalue.  */
+
+static gcc_jit_lvalue *
+bf_get_current_data (bf_compiler *bfc, gcc_jit_location *loc)
+{
+  return gcc_jit_context_new_array_access (
+    bfc->ctxt,
+    loc,
+    gcc_jit_lvalue_as_rvalue (bfc->data_cells),
+    gcc_jit_lvalue_as_rvalue (bfc->idx));
+}
+
+/* Get "data_cells[idx] == 0" as a boolean rvalue.  */
+
+static gcc_jit_rvalue *
+bf_current_data_is_zero (bf_compiler *bfc, gcc_jit_location *loc)
+{
+  return gcc_jit_context_new_comparison (
+    bfc->ctxt,
+    loc,
+    GCC_JIT_COMPARISON_EQ,
+    gcc_jit_lvalue_as_rvalue (bf_get_current_data (bfc, loc)),
+    bfc->byte_zero);
+}
+
+/* Compile one bf character.  */
+
+static void
+bf_compile_char (bf_compiler *bfc,
+		 unsigned char ch)
+{
+  gcc_jit_location *loc =
+    gcc_jit_context_new_location (bfc->ctxt,
+				  bfc->filename,
+				  bfc->line,
+				  bfc->column);
+
+  /* Turn this on to trace execution, by injecting putchar ()
+     of each source char. */
+  if (0)
+    {
+      gcc_jit_rvalue *arg =
+	gcc_jit_context_new_rvalue_from_int (
+					     bfc->ctxt,
+					     bfc->int_type,
+					     ch);
+      gcc_jit_rvalue *call =
+	gcc_jit_context_new_call (bfc->ctxt,
+				  loc,
+				  bfc->func_putchar,
+				  1, &arg);
+      gcc_jit_block_add_eval (bfc->curblock,
+			      loc,
+			      call);
+    }
+
+  switch (ch)
+    {
+      case '>':
+	gcc_jit_block_add_comment (bfc->curblock,
+				   loc,
+				   "'>': idx += 1;");
+	gcc_jit_block_add_assignment_op (bfc->curblock,
+					 loc,
+					 bfc->idx,
+					 GCC_JIT_BINARY_OP_PLUS,
+					 bfc->int_one);
+	break;
+
+      case '<':
+	gcc_jit_block_add_comment (bfc->curblock,
+				   loc,
+				   "'<': idx -= 1;");
+	gcc_jit_block_add_assignment_op (bfc->curblock,
+					 loc,
+					 bfc->idx,
+					 GCC_JIT_BINARY_OP_MINUS,
+					 bfc->int_one);
+	break;
+
+      case '+':
+	gcc_jit_block_add_comment (bfc->curblock,
+				   loc,
+				   "'+': data[idx] += 1;");
+	gcc_jit_block_add_assignment_op (bfc->curblock,
+					 loc,
+					 bf_get_current_data (bfc, loc),
+					 GCC_JIT_BINARY_OP_PLUS,
+					 bfc->byte_one);
+	break;
+
+      case '-':
+	gcc_jit_block_add_comment (bfc->curblock,
+				   loc,
+				   "'-': data[idx] -= 1;");
+	gcc_jit_block_add_assignment_op (bfc->curblock,
+					 loc,
+					 bf_get_current_data (bfc, loc),
+					 GCC_JIT_BINARY_OP_MINUS,
+					 bfc->byte_one);
+	break;
+
+      case '.':
+	{
+	  gcc_jit_rvalue *arg =
+	    gcc_jit_context_new_cast (
+	      bfc->ctxt,
+	      loc,
+	      gcc_jit_lvalue_as_rvalue (bf_get_current_data (bfc, loc)),
+	      bfc->int_type);
+	  gcc_jit_rvalue *call =
+	    gcc_jit_context_new_call (bfc->ctxt,
+				      loc,
+				      bfc->func_putchar,
+				      1, &arg);
+	  gcc_jit_block_add_comment (bfc->curblock,
+				     loc,
+				     "'.': putchar ((int)data[idx]);");
+	  gcc_jit_block_add_eval (bfc->curblock,
+				  loc,
+				  call);
+	}
+	break;
+
+      case ',':
+	{
+	  gcc_jit_rvalue *call =
+	    gcc_jit_context_new_call (bfc->ctxt,
+				      loc,
+				      bfc->func_getchar,
+				      0, NULL);
+	  gcc_jit_block_add_comment (
+	    bfc->curblock,
+	    loc,
+	    "',': data[idx] = (unsigned char)getchar ();");
+	  gcc_jit_block_add_assignment (bfc->curblock,
+					loc,
+					bf_get_current_data (bfc, loc),
+					gcc_jit_context_new_cast (
+					  bfc->ctxt,
+					  loc,
+					  call,
+					  bfc->byte_type));
+	}
+	break;
+
+      case '[':
+	{
+	  gcc_jit_block *loop_test =
+	    gcc_jit_function_new_block (bfc->func, NULL);
+	  gcc_jit_block *on_zero =
+	    gcc_jit_function_new_block (bfc->func, NULL);
+	  gcc_jit_block *on_non_zero =
+	    gcc_jit_function_new_block (bfc->func, NULL);
+
+	  if (bfc->num_open_parens == MAX_OPEN_PARENS)
+	    fatal_error (bfc, "too many open parens");
+
+	  gcc_jit_block_end_with_jump (
+	    bfc->curblock,
+	    loc,
+	    loop_test);
+
+	  gcc_jit_block_add_comment (
+	    loop_test,
+	    loc,
+	    "'['");
+	  gcc_jit_block_end_with_conditional (
+	    loop_test,
+	    loc,
+	    bf_current_data_is_zero (bfc, loc),
+	    on_zero,
+	    on_non_zero);
+	  bfc->paren_test[bfc->num_open_parens] = loop_test;
+	  bfc->paren_body[bfc->num_open_parens] = on_non_zero;
+	  bfc->paren_after[bfc->num_open_parens] = on_zero;
+	  bfc->num_open_parens += 1;
+	  bfc->curblock = on_non_zero;
+	}
+	break;
+
+      case ']':
+	{
+	  gcc_jit_block_add_comment (
+	    bfc->curblock,
+	    loc,
+	    "']'");
+
+	  if (bfc->num_open_parens == 0)
+	    fatal_error (bfc, "mismatching parens");
+	  bfc->num_open_parens -= 1;
+	  gcc_jit_block_end_with_jump (
+	    bfc->curblock,
+	    loc,
+	    bfc->paren_test[bfc->num_open_parens]);
+	  bfc->curblock = bfc->paren_after[bfc->num_open_parens];
+	}
+	break;
+
+    case '\n':
+      bfc->line +=1;
+      bfc->column = 0;
+      break;
+    }
+
+  if (ch != '\n')
+    bfc->column += 1;
+}
+
+/* Compile the given .bf file into a gcc_jit_context, containing a
+   single "main" function suitable for compiling into an executable.  */
+
+gcc_jit_context *
+bf_compile (const char *filename)
+{
+  bf_compiler bfc;
+  FILE *f_in;
+  int ch;
+
+  memset (&bfc, 0, sizeof (bfc));
+
+  bfc.filename = filename;
+  f_in = fopen (filename, "r");
+  if (!f_in)
+    fatal_error (&bfc, "unable to open file");
+  bfc.line = 1;
+
+  bfc.ctxt = gcc_jit_context_acquire ();
+
+  gcc_jit_context_set_int_option (
+    bfc.ctxt,
+    GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL,
+    3);
+  gcc_jit_context_set_bool_option (
+    bfc.ctxt,
+    GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE,
+    0);
+  gcc_jit_context_set_bool_option (
+    bfc.ctxt,
+    GCC_JIT_BOOL_OPTION_DEBUGINFO,
+    1);
+  gcc_jit_context_set_bool_option (
+    bfc.ctxt,
+    GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING,
+    0);
+  gcc_jit_context_set_bool_option (
+    bfc.ctxt,
+    GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES,
+    0);
+
+  bfc.void_type =
+    gcc_jit_context_get_type (bfc.ctxt, GCC_JIT_TYPE_VOID);
+  bfc.int_type =
+    gcc_jit_context_get_type (bfc.ctxt, GCC_JIT_TYPE_INT);
+  bfc.byte_type =
+    gcc_jit_context_get_type (bfc.ctxt, GCC_JIT_TYPE_UNSIGNED_CHAR);
+  bfc.array_type =
+    gcc_jit_context_new_array_type (bfc.ctxt,
+				    NULL,
+				    bfc.byte_type,
+				    30000);
+
+  bfc.func_getchar =
+    gcc_jit_context_new_function (bfc.ctxt, NULL,
+				  GCC_JIT_FUNCTION_IMPORTED,
+				  bfc.int_type,
+				  "getchar",
+				  0, NULL,
+				  0);
+
+  gcc_jit_param *param_c =
+    gcc_jit_context_new_param (bfc.ctxt, NULL, bfc.int_type, "c");
+  bfc.func_putchar =
+    gcc_jit_context_new_function (bfc.ctxt, NULL,
+				  GCC_JIT_FUNCTION_IMPORTED,
+				  bfc.void_type,
+				  "putchar",
+				  1, &param_c,
+				  0);
+
+  bfc.func = make_main (bfc.ctxt);
+   bfc.curblock =
+    gcc_jit_function_new_block (bfc.func, "initial");
+  bfc.int_zero = gcc_jit_context_zero (bfc.ctxt, bfc.int_type);
+  bfc.int_one = gcc_jit_context_one (bfc.ctxt, bfc.int_type);
+  bfc.byte_zero = gcc_jit_context_zero (bfc.ctxt, bfc.byte_type);
+  bfc.byte_one = gcc_jit_context_one (bfc.ctxt, bfc.byte_type);
+
+  bfc.data_cells =
+    gcc_jit_context_new_global (bfc.ctxt, NULL,
+				 GCC_JIT_GLOBAL_INTERNAL,
+				 bfc.array_type,
+				 "data_cells");
+  bfc.idx =
+    gcc_jit_function_new_local (bfc.func, NULL,
+				bfc.int_type,
+				"idx");
+
+  gcc_jit_block_add_comment (bfc.curblock,
+			     NULL,
+			     "idx = 0;");
+  gcc_jit_block_add_assignment (bfc.curblock,
+				NULL,
+				bfc.idx,
+				bfc.int_zero);
+
+  bfc.num_open_parens = 0;
+
+  while ( EOF != (ch = fgetc (f_in)))
+    bf_compile_char (&bfc, (unsigned char)ch);
+
+  gcc_jit_block_end_with_return (bfc.curblock, NULL, bfc.int_zero);
+
+  fclose (f_in);
+
+  return bfc.ctxt;
+}
+
+/* Entrypoint to the compiler.  */
+
+int
+main (int argc, char **argv)
+{
+  const char *input_file;
+  const char *output_file;
+  gcc_jit_context *ctxt;
+  const char *err;
+
+  if (argc != 3)
+    {
+      fprintf (stderr, "%s: INPUT_FILE OUTPUT_FILE\n", argv[0]);
+      return 1;
+    }
+
+  input_file = argv[1];
+  output_file = argv[2];
+  ctxt = bf_compile (input_file);
+
+  gcc_jit_context_compile_to_file (ctxt,
+				   GCC_JIT_OUTPUT_KIND_EXECUTABLE,
+				   output_file);
+
+  err = gcc_jit_context_get_first_error (ctxt);
+
+  if (err)
+    {
+      gcc_jit_context_release (ctxt);
+      return 1;
+    }
+
+  gcc_jit_context_release (ctxt);
+  return 0;
+}
+
+/* Use the built compiler to compile the example to an executable:
+
+     { dg-jit-set-exe-params SRCDIR/gcc/jit/docs/examples/emit-alphabet.bf emit-alphabet.bf.exe }
+
+   Then run the executable, and verify that it emits the alphabet:
+
+     { dg-final { jit-run-executable emit-alphabet.bf.exe "ABCDEFGHIJKLMNOPQRSTUVWXYZ" } } */
diff --git a/gcc/jit/docs/internals/test-hello-world.exe.log.txt b/gcc/jit/docs/internals/test-hello-world.exe.log.txt
index 113dc35..205b6b4 100644
--- a/gcc/jit/docs/internals/test-hello-world.exe.log.txt
+++ b/gcc/jit/docs/internals/test-hello-world.exe.log.txt
@@ -38,14 +38,20 @@ JIT: entering: gcc_jit_block_add_eval
 JIT: exiting: gcc_jit_block_add_eval
 JIT: entering: gcc_jit_block_end_with_void_return
 JIT: exiting: gcc_jit_block_end_with_void_return
+JIT: entering: gcc_jit_context_dump_reproducer_to_file
+JIT:  entering: void gcc::jit::recording::context::dump_reproducer_to_file(const char*)
+JIT:  exiting: void gcc::jit::recording::context::dump_reproducer_to_file(const char*)
+JIT: exiting: gcc_jit_context_dump_reproducer_to_file
 JIT: entering: gcc_jit_context_compile
-JIT:  compiling ctxt: 0x1283e20
+JIT:  in-memory compile of ctxt: 0x1283e20
 JIT:  entering: gcc::jit::result* gcc::jit::recording::context::compile()
 JIT:   entering: void gcc::jit::recording::context::validate()
 JIT:   exiting: void gcc::jit::recording::context::validate()
 JIT:   entering: gcc::jit::playback::context::context(gcc::jit::recording::context*)
 JIT:   exiting: gcc::jit::playback::context::context(gcc::jit::recording::context*)
-JIT:   entering: gcc::jit::result* gcc::jit::playback::context::compile()
+JIT:   entering: gcc::jit::playback::compile_to_memory::compile_to_memory(gcc::jit::recording::context*)
+JIT:   exiting: gcc::jit::playback::compile_to_memory::compile_to_memory(gcc::jit::recording::context*)
+JIT:   entering: void gcc::jit::playback::context::compile()
 JIT:    entering: gcc::jit::tempdir::tempdir(gcc::jit::logger*, int)
 JIT:    exiting: gcc::jit::tempdir::tempdir(gcc::jit::logger*, int)
 JIT:    entering: bool gcc::jit::tempdir::create()
@@ -86,29 +92,37 @@ JIT:      entering: void gcc::jit::playback::function::postprocess()
 JIT:      exiting: void gcc::jit::playback::function::postprocess()
 JIT:     exiting: void gcc::jit::playback::context::replay()
 JIT:     entering: void jit_langhook_write_globals()
+JIT:      entering: void gcc::jit::playback::context::write_global_decls_1()
+JIT:      exiting: void gcc::jit::playback::context::write_global_decls_1()
+JIT:      entering: void gcc::jit::playback::context::write_global_decls_2()
+JIT:      exiting: void gcc::jit::playback::context::write_global_decls_2()
 JIT:     exiting: void jit_langhook_write_globals()
 JIT:    exiting: toplev::main
 JIT:    entering: void gcc::jit::playback::context::extract_any_requested_dumps(vec<gcc::jit::recording::requested_dump>*)
 JIT:    exiting: void gcc::jit::playback::context::extract_any_requested_dumps(vec<gcc::jit::recording::requested_dump>*)
 JIT:    entering: toplev::finalize
 JIT:    exiting: toplev::finalize
-JIT:    entering: void gcc::jit::playback::context::convert_to_dso(const char*)
-JIT:     argv[0]: x86_64-unknown-linux-gnu-gcc-5.0.0
-JIT:     argv[1]: -shared
-JIT:     argv[2]: /tmp/libgccjit-CKq1M9/fake.s
-JIT:     argv[3]: -o
-JIT:     argv[4]: /tmp/libgccjit-CKq1M9/fake.so
-JIT:     argv[5]: -fno-use-linker-plugin
-JIT:     argv[6]: (null)
-JIT:    exiting: void gcc::jit::playback::context::convert_to_dso(const char*)
-JIT:    entering: gcc::jit::result* gcc::jit::playback::context::dlopen_built_dso()
-JIT:     GCC_JIT_BOOL_OPTION_DEBUGINFO was set: handing over tempdir to jit::result
-JIT:     entering: gcc::jit::result::result(gcc::jit::logger*, void*, gcc::jit::tempdir*)
-JIT:     exiting: gcc::jit::result::result(gcc::jit::logger*, void*, gcc::jit::tempdir*)
-JIT:    exiting: gcc::jit::result* gcc::jit::playback::context::dlopen_built_dso()
+JIT:    entering: virtual void gcc::jit::playback::compile_to_memory::postprocess(const char*)
+JIT:     entering: void gcc::jit::playback::context::convert_to_dso(const char*)
+JIT:      entering: void gcc::jit::playback::context::invoke_driver(const char*, const char*, const char*, timevar_id_t, bool, bool)
+JIT:       argv[0]: x86_64-unknown-linux-gnu-gcc-5.0.0
+JIT:       argv[1]: -shared
+JIT:       argv[2]: /tmp/libgccjit-CKq1M9/fake.s
+JIT:       argv[3]: -o
+JIT:       argv[4]: /tmp/libgccjit-CKq1M9/fake.so
+JIT:       argv[5]: -fno-use-linker-plugin
+JIT:       argv[6]: (null)
+JIT:      exiting: void gcc::jit::playback::context::invoke_driver(const char*, const char*, const char*, timevar_id_t, bool, bool)
+JIT:     exiting: void gcc::jit::playback::context::convert_to_dso(const char*)
+JIT:     entering: gcc::jit::result* gcc::jit::playback::context::dlopen_built_dso()
+JIT:      GCC_JIT_BOOL_OPTION_DEBUGINFO was set: handing over tempdir to jit::result
+JIT:      entering: gcc::jit::result::result(gcc::jit::logger*, void*, gcc::jit::tempdir*)
+JIT:      exiting: gcc::jit::result::result(gcc::jit::logger*, void*, gcc::jit::tempdir*)
+JIT:     exiting: gcc::jit::result* gcc::jit::playback::context::dlopen_built_dso()
+JIT:    exiting: virtual void gcc::jit::playback::compile_to_memory::postprocess(const char*)
 JIT:    entering: void gcc::jit::playback::context::release_mutex()
 JIT:    exiting: void gcc::jit::playback::context::release_mutex()
-JIT:   exiting: gcc::jit::result* gcc::jit::playback::context::compile()
+JIT:   exiting: void gcc::jit::playback::context::compile()
 JIT:   entering: gcc::jit::playback::context::~context()
 JIT:   exiting: gcc::jit::playback::context::~context()
 JIT:  exiting: gcc::jit::result* gcc::jit::recording::context::compile()
diff --git a/gcc/jit/docs/intro/index.rst b/gcc/jit/docs/intro/index.rst
index d3bcec9..0f51777 100644
--- a/gcc/jit/docs/intro/index.rst
+++ b/gcc/jit/docs/intro/index.rst
@@ -1,4 +1,4 @@
-.. Copyright (C) 2014 Free Software Foundation, Inc.
+.. Copyright (C) 2014-2015 Free Software Foundation, Inc.
    Originally contributed by David Malcolm <dmalcolm@redhat.com>
 
    This is free software: you can redistribute it and/or modify it
@@ -25,3 +25,4 @@ Tutorial
    tutorial02.rst
    tutorial03.rst
    tutorial04.rst
+   tutorial05.rst
diff --git a/gcc/jit/docs/intro/tutorial05.rst b/gcc/jit/docs/intro/tutorial05.rst
new file mode 100644
index 0000000..865a550
--- /dev/null
+++ b/gcc/jit/docs/intro/tutorial05.rst
@@ -0,0 +1,253 @@
+.. Copyright (C) 2015 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 5: Implementing an Ahead-of-Time compiler
+-------------------------------------------------------
+
+If you have a pre-existing language frontend, it's possible to hook
+it up to libgccjit as a backend.  In the previous example we showed
+how to do that for in-memory JIT-compilation, but libgccjit can also
+compile code directly to a file, allowing you to implement a more
+traditional ahead-of-time compiler ("JIT" is something of a misnomer
+for this use-case).
+
+The essential difference is to compile the context using
+:c:func:`gcc_jit_context_compile_to_file` rather than
+:c:func:`gcc_jit_context_compile`.
+
+The "brainf" language
+*********************
+
+In this example we use libgccjit to construct an ahead-of-time compiler
+for an esoteric programming language that we shall refer to as "brainf".
+
+brainf scripts operate on an array of bytes, with a notional data pointer
+within the array.
+
+brainf is hard for humans to read, but it's trivial to write a parser for
+it, as there is no lexing; just a stream of bytes.  The operations are:
+
+====================== =============================
+Character              Meaning
+====================== =============================
+``>``                  ``idx += 1``
+``<``                  ``idx -= 1``
+``+``                  ``data[idx] += 1``
+``-``                  ``data[idx] -= 1``
+``.``                  ``output (data[idx])``
+``,``                  ``data[idx] = input ()``
+``[``                  loop until ``data[idx] == 0``
+``]``                  end of loop
+Anything else          ignored
+====================== =============================
+
+Unlike the previous example, we'll implement an ahead-of-time compiler,
+which reads ``.bf`` scripts and outputs executables (though it would
+be trivial to have it run them JIT-compiled in-process).
+
+Here's what a simple ``.bf`` script looks like:
+
+   .. literalinclude:: ../examples/emit-alphabet.bf
+    :lines: 1-
+
+.. note::
+
+   This example makes use of whitespace and comments for legibility, but
+   could have been written as::
+
+     ++++++++++++++++++++++++++
+     >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++<
+     [>.+<-]
+
+   It's not a particularly useful language, except for providing
+   compiler-writers with a test case that's easy to parse.  The point
+   is that you can use :c:func:`gcc_jit_context_compile_to_file`
+   to use libgccjit as a backend for a pre-existing language frontend.
+
+Converting a brainf script to libgccjit IR
+******************************************
+
+As before we write simple code to populate a :c:type:`gcc_jit_context *`.
+
+   .. literalinclude:: ../examples/tut05-bf.c
+    :start-after: #define MAX_OPEN_PARENS 16
+    :end-before: /* Entrypoint to the compiler.  */
+    :language: c
+
+Compiling a context to a file
+*****************************
+
+Unlike the previous tutorial, this time we'll compile the context
+directly to an executable, using :c:func:`gcc_jit_context_compile_to_file`:
+
+.. code-block:: c
+
+    gcc_jit_context_compile_to_file (ctxt,
+                                     GCC_JIT_OUTPUT_KIND_EXECUTABLE,
+                                     output_file);
+
+Here's the top-level of the compiler, which is what actually calls into
+:c:func:`gcc_jit_context_compile_to_file`:
+
+ .. literalinclude:: ../examples/tut05-bf.c
+    :start-after: /* Entrypoint to the compiler.  */
+    :end-before: /* Use the built compiler to compile the example to an executable:
+    :language: c
+
+Note how once the context is populated you could trivially instead compile
+it to memory using :c:func:`gcc_jit_context_compile` and run it in-process
+as in the previous tutorial.
+
+To create an executable, we need to export a ``main`` function.  Here's
+how to create one from the JIT API:
+
+ .. literalinclude:: ../examples/tut05-bf.c
+    :start-after: #include "libgccjit.h"
+    :end-before: #define MAX_OPEN_PARENS 16
+    :language: c
+
+.. note::
+
+   The above implementation ignores ``argc`` and ``argv``, but you could
+   make use of them by exposing ``param_argc`` and ``param_argv`` to the
+   caller.
+
+Upon compiling this C code, we obtain a bf-to-machine-code compiler;
+let's call it ``bfc``:
+
+.. code-block:: console
+
+  $ gcc \
+      tut05-bf.c \
+      -o bfc \
+      -lgccjit
+
+We can now use ``bfc`` to compile .bf files into machine code executables:
+
+.. code-block:: console
+
+  $ ./bfc \
+       emit-alphabet.bf \
+       a.out
+
+which we can run directly:
+
+.. code-block:: console
+
+  $ ./a.out
+  ABCDEFGHIJKLMNOPQRSTUVWXYZ
+
+Success!
+
+We can also inspect the generated executable using standard tools:
+
+.. code-block:: console
+
+  $ objdump -d a.out |less
+
+which shows that libgccjit has managed to optimize the function
+somewhat (for example, the runs of 26 and 65 increment operations
+have become integer constants 0x1a and 0x41):
+
+.. code-block:: console
+
+  0000000000400620 <main>:
+    400620:     80 3d 39 0a 20 00 00    cmpb   $0x0,0x200a39(%rip)        # 601060 <data
+    400627:     74 07                   je     400630 <main
+    400629:     eb fe                   jmp    400629 <main+0x9>
+    40062b:     0f 1f 44 00 00          nopl   0x0(%rax,%rax,1)
+    400630:     48 83 ec 08             sub    $0x8,%rsp
+    400634:     0f b6 05 26 0a 20 00    movzbl 0x200a26(%rip),%eax        # 601061 <data_cells+0x1>
+    40063b:     c6 05 1e 0a 20 00 1a    movb   $0x1a,0x200a1e(%rip)       # 601060 <data_cells>
+    400642:     8d 78 41                lea    0x41(%rax),%edi
+    400645:     40 88 3d 15 0a 20 00    mov    %dil,0x200a15(%rip)        # 601061 <data_cells+0x1>
+    40064c:     0f 1f 40 00             nopl   0x0(%rax)
+    400650:     40 0f b6 ff             movzbl %dil,%edi
+    400654:     e8 87 fe ff ff          callq  4004e0 <putchar@plt>
+    400659:     0f b6 05 01 0a 20 00    movzbl 0x200a01(%rip),%eax        # 601061 <data_cells+0x1>
+    400660:     80 2d f9 09 20 00 01    subb   $0x1,0x2009f9(%rip)        # 601060 <data_cells>
+    400667:     8d 78 01                lea    0x1(%rax),%edi
+    40066a:     40 88 3d f0 09 20 00    mov    %dil,0x2009f0(%rip)        # 601061 <data_cells+0x1>
+    400671:     75 dd                   jne    400650 <main+0x30>
+    400673:     31 c0                   xor    %eax,%eax
+    400675:     48 83 c4 08             add    $0x8,%rsp
+    400679:     c3                      retq
+    40067a:     66 0f 1f 44 00 00       nopw   0x0(%rax,%rax,1)
+
+We also set up debugging information (via
+:c:func:`gcc_jit_context_new_location` and
+:c:macro:`GCC_JIT_BOOL_OPTION_DEBUGINFO`), so it's possible to use ``gdb``
+to singlestep through the generated binary and inspect the internal
+state ``idx`` and ``data_cells``:
+
+.. code-block:: console
+
+  (gdb) break main
+  Breakpoint 1 at 0x400790
+  (gdb) run
+  Starting program: a.out
+
+  Breakpoint 1, 0x0000000000400790 in main (argc=1, argv=0x7fffffffe448)
+  (gdb) stepi
+  0x0000000000400797 in main (argc=1, argv=0x7fffffffe448)
+  (gdb) stepi
+  0x00000000004007a0 in main (argc=1, argv=0x7fffffffe448)
+  (gdb) stepi
+  9     >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++<
+  (gdb) list
+  4
+  5     cell 0 = 26
+  6     ++++++++++++++++++++++++++
+  7
+  8     cell 1 = 65
+  9     >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++<
+  10
+  11    while cell#0 != 0
+  12    [
+  13     >
+  (gdb) n
+  6     ++++++++++++++++++++++++++
+  (gdb) n
+  9     >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++<
+  (gdb) p idx
+  $1 = 1
+  (gdb) p data_cells
+  $2 = "\032", '\000' <repeats 29998 times>
+  (gdb) p data_cells[0]
+  $3 = 26 '\032'
+  (gdb) p data_cells[1]
+  $4 = 0 '\000'
+  (gdb) list
+  4
+  5     cell 0 = 26
+  6     ++++++++++++++++++++++++++
+  7
+  8     cell 1 = 65
+  9     >+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++<
+  10
+  11    while cell#0 != 0
+  12    [
+  13     >
+
+
+Other forms of ahead-of-time-compilation
+****************************************
+
+The above demonstrates compiling a :c:type:`gcc_jit_context *` directly
+to an executable.  It's also possible to compile it to an object file,
+and to a dynamic library.  See the documentation of
+:c:func:`gcc_jit_context_compile_to_file` for more information.
diff --git a/gcc/jit/docs/topics/compilation.rst b/gcc/jit/docs/topics/compilation.rst
new file mode 100644
index 0000000..bf59cc2
--- /dev/null
+++ b/gcc/jit/docs/topics/compilation.rst
@@ -0,0 +1,199 @@
+.. Copyright (C) 2014-2015 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
+
+Compiling a context
+===================
+
+Once populated, a :c:type:`gcc_jit_context *` can be compiled to
+machine code, either in-memory via :c:func:`gcc_jit_context_compile` or
+to disk via :c:func:`gcc_jit_context_compile_to_file`.
+
+You can compile a context multiple times (using either form of
+compilation), although any errors that occur on the context will
+prevent any future compilation of that context.
+
+In-memory compilation
+*********************
+
+.. 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 *`.
+
+   If this is non-NULL, the caller becomes responsible for
+   calling :func:`gcc_jit_result_release` on it once they're done
+   with it.
+
+.. type:: gcc_jit_result
+
+  A `gcc_jit_result` encapsulates the result of compiling a context
+  in-memory, and the lifetimes of any machine code functions or globals
+  that are within the resuilt.
+
+.. function:: void *\
+              gcc_jit_result_get_code (gcc_jit_result *result,\
+                                       const char *funcname)
+
+   Locate a given function within the built machine code.
+
+   Functions are looked up by name.  For this to succeed, a function
+   with a name matching `funcname` must have been created on
+   `result`'s context (or a parent context) via a call to
+   :func:`gcc_jit_context_new_function` with `kind`
+   :macro:`GCC_JIT_FUNCTION_EXPORTED`:
+
+   .. code-block:: c
+
+     gcc_jit_context_new_function (ctxt,
+                                   any_location, /* or NULL */
+                                   /* Required for func to be visible to
+                                      gcc_jit_result_get_code: */
+                                   GCC_JIT_FUNCTION_EXPORTED,
+                                   any_return_type,
+                                   /* Must string-compare equal: */
+                                   funcname,
+                                   /* etc */);
+
+   If such a function is not found (or `result` or `funcname` are
+   ``NULL``), an error message will be emitted on stderr and
+   ``NULL`` will be returned.
+
+   If the function is found, the result will need to be cast to a
+   function pointer of the correct type before it can be called.
+
+   Note that the resulting machine code becomes invalid after
+   :func:`gcc_jit_result_release` is called on the
+   :type:`gcc_jit_result *`; attempting to call it after that may lead
+   to a segmentation fault.
+
+.. function:: void *\
+              gcc_jit_result_get_global (gcc_jit_result *result,\
+                                         const char *name)
+
+   Locate a given global within the built machine code.
+
+   Globals are looked up by name.  For this to succeed, a global
+   with a name matching `name` must have been created on
+   `result`'s context (or a parent context) via a call to
+   :func:`gcc_jit_context_new_global` with `kind`
+   :macro:`GCC_JIT_GLOBAL_EXPORTED`.
+
+   If the global is found, the result will need to be cast to a
+   pointer of the correct type before it can be called.
+
+   This is a *pointer* to the global, so e.g. for an :c:type:`int` this is
+   an :c:type:`int *`.
+
+   For example, given an ``int foo;`` created this way:
+
+   .. code-block:: c
+
+     gcc_jit_lvalue *exported_global =
+       gcc_jit_context_new_global (ctxt,
+       any_location, /* or NULL */
+       GCC_JIT_GLOBAL_EXPORTED,
+       int_type,
+       "foo");
+
+   we can access it like this:
+
+   .. code-block:: c
+
+      int *ptr_to_foo =
+        (int *)gcc_jit_result_get_global (result, "foo");
+
+   If such a global is not found (or `result` or `name` are
+   ``NULL``), an error message will be emitted on stderr and
+   ``NULL`` will be returned.
+
+   Note that the resulting address becomes invalid after
+   :func:`gcc_jit_result_release` is called on the
+   :type:`gcc_jit_result *`; attempting to use it after that may lead
+   to a segmentation fault.
+
+.. 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, or any code or globals that were obtained
+   by calling :func:`gcc_jit_result_get_code` or
+   :func:`gcc_jit_result_get_global` on it.
+
+
+Ahead-of-time compilation
+*************************
+
+Although libgccjit is primarily aimed at just-in-time compilation, it
+can also be used for implementing more traditional ahead-of-time
+compilers, via the :c:func:`gcc_jit_context_compile_to_file`
+API entrypoint.
+
+.. function:: void \
+              gcc_jit_context_compile_to_file (gcc_jit_context *ctxt, \
+                                               enum gcc_jit_output_kind output_kind,\
+                                               const char *output_path)
+
+   Compile the :c:type:`gcc_jit_context *` to a file of the given
+   kind.
+
+:c:func:`gcc_jit_context_compile_to_file` ignores the suffix of
+``output_path``, and insteads uses the given
+:c:type:`enum gcc_jit_output_kind` to decide what to do.
+
+.. note::
+
+   This is different from the ``gcc`` program, which does make use of the
+   suffix of the output file when determining what to do.
+
+.. type:: enum gcc_jit_output_kind
+
+The available kinds of output are:
+
+==============================================  ==============
+Output kind                                     Typical suffix
+==============================================  ==============
+:c:macro:`GCC_JIT_OUTPUT_KIND_ASSEMBLER`        .s
+:c:macro:`GCC_JIT_OUTPUT_KIND_OBJECT_FILE`      .o
+:c:macro:`GCC_JIT_OUTPUT_KIND_DYNAMIC_LIBRARY`  .so or .dll
+:c:macro:`GCC_JIT_OUTPUT_KIND_EXECUTABLE`       None, or .exe
+==============================================  ==============
+
+.. c:macro:: GCC_JIT_OUTPUT_KIND_ASSEMBLER
+
+   Compile the context to an assembler file.
+
+.. c:macro:: GCC_JIT_OUTPUT_KIND_OBJECT_FILE
+
+   Compile the context to an object file.
+
+.. c:macro:: GCC_JIT_OUTPUT_KIND_DYNAMIC_LIBRARY
+
+   Compile the context to a dynamic library.
+
+   There is currently no support for specifying other libraries to link
+   against.
+
+.. c:macro:: GCC_JIT_OUTPUT_KIND_EXECUTABLE
+
+   Compile the context to an executable.
+
+   There is currently no support for specifying libraries to link
+   against.
diff --git a/gcc/jit/docs/topics/index.rst b/gcc/jit/docs/topics/index.rst
index a129137..4ebb623 100644
--- a/gcc/jit/docs/topics/index.rst
+++ b/gcc/jit/docs/topics/index.rst
@@ -1,4 +1,4 @@
-.. Copyright (C) 2014 Free Software Foundation, Inc.
+.. Copyright (C) 2014-2015 Free Software Foundation, Inc.
    Originally contributed by David Malcolm <dmalcolm@redhat.com>
 
    This is free software: you can redistribute it and/or modify it
@@ -27,4 +27,4 @@ Topic Reference
    expressions.rst
    functions.rst
    locations.rst
-   results.rst
+   compilation.rst
diff --git a/gcc/jit/docs/topics/results.rst b/gcc/jit/docs/topics/results.rst
deleted file mode 100644
index aa5ea8b..0000000
--- a/gcc/jit/docs/topics/results.rst
+++ /dev/null
@@ -1,127 +0,0 @@
-.. 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,
-  and the lifetimes of any machine code functions or globals that are
-  within it.
-
-.. 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 *`.
-
-   If this is non-NULL, the caller becomes responsible for
-   calling :func:`gcc_jit_result_release` on it once they're done
-   with it.
-
-.. function:: void *\
-              gcc_jit_result_get_code (gcc_jit_result *result,\
-                                       const char *funcname)
-
-   Locate a given function within the built machine code.
-
-   Functions are looked up by name.  For this to succeed, a function
-   with a name matching `funcname` must have been created on
-   `result`'s context (or a parent context) via a call to
-   :func:`gcc_jit_context_new_function` with `kind`
-   :macro:`GCC_JIT_FUNCTION_EXPORTED`:
-
-   .. code-block:: c
-
-     gcc_jit_context_new_function (ctxt,
-                                   any_location, /* or NULL */
-                                   /* Required for func to be visible to
-                                      gcc_jit_result_get_code: */
-                                   GCC_JIT_FUNCTION_EXPORTED,
-                                   any_return_type,
-                                   /* Must string-compare equal: */
-                                   funcname,
-                                   /* etc */);
-
-   If such a function is not found (or `result` or `funcname` are
-   ``NULL``), an error message will be emitted on stderr and
-   ``NULL`` will be returned.
-
-   If the function is found, the result will need to be cast to a
-   function pointer of the correct type before it can be called.
-
-   Note that the resulting machine code becomes invalid after
-   :func:`gcc_jit_result_release` is called on the
-   :type:`gcc_jit_result *`; attempting to call it after that may lead
-   to a segmentation fault.
-
-.. function:: void *\
-              gcc_jit_result_get_global (gcc_jit_result *result,\
-                                         const char *name)
-
-   Locate a given global within the built machine code.
-
-   Globals are looked up by name.  For this to succeed, a global
-   with a name matching `name` must have been created on
-   `result`'s context (or a parent context) via a call to
-   :func:`gcc_jit_context_new_global` with `kind`
-   :macro:`GCC_JIT_GLOBAL_EXPORTED`.
-
-   If the global is found, the result will need to be cast to a
-   pointer of the correct type before it can be called.
-
-   This is a *pointer* to the global, so e.g. for an :c:type:`int` this is
-   an :c:type:`int *`.
-
-   For example, given an ``int foo;`` created this way:
-
-   .. code-block:: c
-
-     gcc_jit_lvalue *exported_global =
-       gcc_jit_context_new_global (ctxt,
-       any_location, /* or NULL */
-       GCC_JIT_GLOBAL_EXPORTED,
-       int_type,
-       "foo");
-
-   we can access it like this:
-
-   .. code-block:: c
-
-      int *ptr_to_foo =
-        (int *)gcc_jit_result_get_global (result, "foo");
-
-   If such a global is not found (or `result` or `name` are
-   ``NULL``), an error message will be emitted on stderr and
-   ``NULL`` will be returned.
-
-   Note that the resulting address becomes invalid after
-   :func:`gcc_jit_result_release` is called on the
-   :type:`gcc_jit_result *`; attempting to use it after that may lead
-   to a segmentation fault.
-
-.. 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, or any code or globals that were obtained
-   by calling :func:`gcc_jit_result_get_code` or
-   :func:`gcc_jit_result_get_global` on it.
diff --git a/gcc/jit/jit-playback.c b/gcc/jit/jit-playback.c
index ca4e112..b4f2073 100644
--- a/gcc/jit/jit-playback.c
+++ b/gcc/jit/jit-playback.c
@@ -1668,26 +1668,37 @@ auto_argvec::~auto_argvec ()
 
    - 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.  */
+   - Assuming it succeeds, we have a .s file.
+   - We then run the "postprocess" vfunc:
 
-result *
+     (A) In-memory compile ("gcc_jit_context_compile")
+
+       For an in-memory compile we have the playback::compile_to_memory
+       subclass; "postprocess" will convert the .s file to a .so DSO,
+       and load it in memory (via dlopen), wrapping the result up as
+       a jit::result and returning it.
+
+     (B) Compile to file ("gcc_jit_context_compile_to_file")
+
+       When compiling to a file, we have the playback::compile_to_file
+       subclass; "postprocess" will either copy the .s file to the
+       destination (for GCC_JIT_OUTPUT_KIND_ASSEMBLER), or invoke
+       the driver to convert it as necessary, copying the result.  */
+
+void
 playback::context::
 compile ()
 {
   JIT_LOG_SCOPE (get_logger ());
 
   const char *ctxt_progname;
-  result *result_obj = NULL;
 
   int keep_intermediates =
     get_bool_option (GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES);
 
   m_tempdir = new tempdir (get_logger (), keep_intermediates);
   if (!m_tempdir->create ())
-    return NULL;
+    return;
 
   /* Call into the rest of gcc.
      For now, we have to assemble command-line options to pass into
@@ -1706,7 +1717,7 @@ compile ()
   auto_argvec fake_args;
   make_fake_args (&fake_args, ctxt_progname, &requested_dumps);
   if (errors_occurred ())
-    return NULL;
+    return;
 
   /* Acquire the JIT mutex and set "this" as the active playback ctxt.  */
   acquire_mutex ();
@@ -1737,24 +1748,258 @@ compile ()
   if (errors_occurred ())
     {
       release_mutex ();
-      return NULL;
+      return;
     }
 
   if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE))
     dump_generated_code ();
 
+  /* We now have a .s file.
+
+     Run any postprocessing steps.  This will either convert the .s file to
+     a .so DSO, and load it in memory (playback::compile_to_memory), or
+     convert the .s file to the requested output format, and copy it to a
+     given file (playback::compile_to_file).  */
+  postprocess (ctxt_progname);
+
+  release_mutex ();
+}
+
+/* Implementation of class gcc::jit::playback::compile_to_memory,
+   a subclass of gcc::jit::playback::context.  */
+
+/*  playback::compile_to_memory's trivial constructor. */
+
+playback::compile_to_memory::compile_to_memory (recording::context *ctxt) :
+  playback::context (ctxt),
+  m_result (NULL)
+{
+  JIT_LOG_SCOPE (get_logger ());
+}
+
+/*  Implementation of the playback::context::process vfunc for compiling
+    to memory.
+
+    Convert the .s file to a .so DSO, and load it in memory (via dlopen),
+    wrapping the result up as a jit::result and returning it.  */
+
+void
+playback::compile_to_memory::postprocess (const char *ctxt_progname)
+{
+  JIT_LOG_SCOPE (get_logger ());
   convert_to_dso (ctxt_progname);
   if (errors_occurred ())
+    return;
+  m_result = dlopen_built_dso ();
+}
+
+/* Implementation of class gcc::jit::playback::compile_to_file,
+   a subclass of gcc::jit::playback::context.  */
+
+/*  playback::compile_to_file's trivial constructor. */
+
+playback::compile_to_file::compile_to_file (recording::context *ctxt,
+					    enum gcc_jit_output_kind output_kind,
+					    const char *output_path) :
+  playback::context (ctxt),
+  m_output_kind (output_kind),
+  m_output_path (output_path)
+{
+  JIT_LOG_SCOPE (get_logger ());
+}
+
+/*  Implementation of the playback::context::process vfunc for compiling
+    to a file.
+
+    Either copy the .s file to the given destination (for
+    GCC_JIT_OUTPUT_KIND_ASSEMBLER), or invoke the driver to convert it
+    as necessary, copying the result.  */
+
+void
+playback::compile_to_file::postprocess (const char *ctxt_progname)
+{
+  JIT_LOG_SCOPE (get_logger ());
+
+  /* The driver takes different actions based on the filename, so
+     we provide a filename with an appropriate suffix for the
+     output kind, and then copy it up to the user-provided path,
+     rather than directly compiling it to the requested output path.  */
+
+  switch (m_output_kind)
     {
-      release_mutex ();
-      return NULL;
+    default:
+      gcc_unreachable ();
+
+    case GCC_JIT_OUTPUT_KIND_ASSEMBLER:
+      copy_file (get_tempdir ()->get_path_s_file (),
+		 m_output_path);
+      break;
+
+    case GCC_JIT_OUTPUT_KIND_OBJECT_FILE:
+      {
+	char *tmp_o_path = ::concat (get_tempdir ()->get_path (),
+				     "/fake.o",
+				     NULL);
+	invoke_driver (ctxt_progname,
+		       get_tempdir ()->get_path_s_file (),
+		       tmp_o_path,
+		       TV_ASSEMBLE,
+		       false, /* bool shared, */
+		       false);/* bool run_linker */
+	if (!errors_occurred ())
+	  copy_file (tmp_o_path,
+		     m_output_path);
+	free (tmp_o_path);
+      }
+      break;
+
+    case GCC_JIT_OUTPUT_KIND_DYNAMIC_LIBRARY:
+      invoke_driver (ctxt_progname,
+		     get_tempdir ()->get_path_s_file (),
+		     get_tempdir ()->get_path_so_file (),
+		     TV_ASSEMBLE,
+		     true, /* bool shared, */
+		     true);/* bool run_linker */
+      if (!errors_occurred ())
+	copy_file (get_tempdir ()->get_path_so_file (),
+		   m_output_path);
+      break;
+
+    case GCC_JIT_OUTPUT_KIND_EXECUTABLE:
+      {
+	char *tmp_exe_path = ::concat (get_tempdir ()->get_path (),
+				     "/fake.exe",
+				     NULL);
+	invoke_driver (ctxt_progname,
+		       get_tempdir ()->get_path_s_file (),
+		       tmp_exe_path,
+		       TV_ASSEMBLE,
+		       false, /* bool shared, */
+		       true);/* bool run_linker */
+	if (!errors_occurred ())
+	  copy_file (tmp_exe_path,
+		     m_output_path);
+	free (tmp_exe_path);
+      }
+      break;
+
     }
 
-  result_obj = dlopen_built_dso ();
+}
+
+/* Copy SRC_PATH to DST_PATH, preserving permission bits (in particular,
+   the "executable" bits).
 
-  release_mutex ();
+   Any errors that occur are reported on the context and hence count as
+   a failure of the compile.
 
-  return result_obj;
+   We can't in general hardlink or use "rename" from the tempdir since
+   it might be on a different filesystem to the destination.  For example,
+   I get EXDEV: "Invalid cross-device link".  */
+
+void
+playback::compile_to_file::copy_file (const char *src_path,
+				      const char *dst_path)
+{
+  JIT_LOG_SCOPE (get_logger ());
+  if (get_logger ())
+    {
+      get_logger ()->log ("src_path: %s", src_path);
+      get_logger ()->log ("dst_path: %s", dst_path);
+    }
+
+  FILE *f_in = NULL;
+  FILE *f_out = NULL;
+  size_t total_sz_in = 0;
+  size_t total_sz_out = 0;
+  char buf[4096];
+  size_t sz_in;
+  struct stat stat_buf;
+
+  f_in = fopen (src_path, "rb");
+  if (!f_in)
+    {
+      add_error (NULL,
+		 "unable to open %s for reading: %s",
+		 src_path,
+		 xstrerror (errno));
+      return;
+    }
+
+  /* Use stat on the filedescriptor to get the mode,
+     so that we can copy it over (in particular, the
+     "executable" bits).  */
+  if (-1 == fstat (fileno (f_in), &stat_buf))
+    {
+      add_error (NULL,
+		 "unable to fstat %s: %s",
+		 src_path,
+		 xstrerror (errno));
+      fclose (f_in);
+      return;
+    }
+
+  f_out = fopen (dst_path, "wb");
+  if (!f_out)
+    {
+      add_error (NULL,
+		 "unable to open %s for writing: %s",
+		 dst_path,
+		 xstrerror (errno));
+      fclose (f_in);
+      return;
+    }
+
+  while ( (sz_in = fread (buf, 1, sizeof (buf), f_in)) )
+    {
+      total_sz_in += sz_in;
+      size_t sz_out_remaining = sz_in;
+      size_t sz_out_so_far = 0;
+      while (sz_out_remaining)
+	{
+	  size_t sz_out = fwrite (buf + sz_out_so_far,
+				  1,
+				  sz_out_remaining,
+				  f_out);
+	  gcc_assert (sz_out <= sz_out_remaining);
+	  if (!sz_out)
+	    {
+	      add_error (NULL,
+			 "error writing to %s: %s",
+			 dst_path,
+			 xstrerror (errno));
+	      fclose (f_in);
+	      fclose (f_out);
+	      return;
+	    }
+	  total_sz_out += sz_out;
+	  sz_out_so_far += sz_out;
+	  sz_out_remaining -= sz_out;
+	}
+      gcc_assert (sz_out_so_far == sz_in);
+    }
+
+  if (!feof (f_in))
+    add_error (NULL,
+	       "error reading from %s: %s",
+	       src_path,
+	       xstrerror (errno));
+
+  fclose (f_in);
+
+  gcc_assert (total_sz_in == total_sz_out);
+  if (get_logger ())
+    get_logger ()->log ("total bytes copied: %ld", total_sz_out);
+
+  /* Set the permissions of the copy to those of the original file,
+     in particular the "executable" bits.  */
+  if (-1 == fchmod (fileno (f_out), stat_buf.st_mode))
+    add_error (NULL,
+	       "error setting mode of %s: %s",
+	       dst_path,
+	       xstrerror (errno));
+
+  fclose (f_out);
 }
 
 /* Helper functions for gcc::jit::playback::context::compile.  */
@@ -1975,9 +2220,28 @@ playback::context::
 convert_to_dso (const char *ctxt_progname)
 {
   JIT_LOG_SCOPE (get_logger ());
+
+  invoke_driver (ctxt_progname,
+		 m_tempdir->get_path_s_file (),
+		 m_tempdir->get_path_so_file (),
+		 TV_ASSEMBLE,
+		 true, /* bool shared, */
+		 true);/* bool run_linker */
+}
+
+void
+playback::context::
+invoke_driver (const char *ctxt_progname,
+	       const char *input_file,
+	       const char *output_file,
+	       timevar_id_t tv_id,
+	       bool shared,
+	       bool run_linker)
+{
+  JIT_LOG_SCOPE (get_logger ());
   /* Currently this lumps together both assembling and linking into
      TV_ASSEMBLE.  */
-  auto_timevar assemble_timevar (TV_ASSEMBLE);
+  auto_timevar assemble_timevar (tv_id);
   const char *errmsg;
   auto_vec <const char *> argvec;
 #define ADD_ARG(arg) argvec.safe_push (arg)
@@ -1986,12 +2250,16 @@ convert_to_dso (const char *ctxt_progname)
   const char *gcc_driver_name = GCC_DRIVER_NAME;
 
   ADD_ARG (gcc_driver_name);
-  ADD_ARG ("-shared");
-  /* The input: assembler.  */
-  ADD_ARG (m_tempdir->get_path_s_file ());
-  /* The output: shared library.  */
+
+  if (shared)
+    ADD_ARG ("-shared");
+
+  if (!run_linker)
+    ADD_ARG ("-c");
+
+  ADD_ARG (input_file);
   ADD_ARG ("-o");
-  ADD_ARG (m_tempdir->get_path_so_file ());
+  ADD_ARG (output_file);
 
   /* Don't use the linker plugin.
      If running with just a "make" and not a "make install", then we'd
diff --git a/gcc/jit/jit-playback.h b/gcc/jit/jit-playback.h
index 8efd506..e9832f0 100644
--- a/gcc/jit/jit-playback.h
+++ b/gcc/jit/jit-playback.h
@@ -23,6 +23,8 @@ along with GCC; see the file COPYING3.  If not see
 
 #include <utility> // for std::pair
 
+#include "timevar.h"
+
 #include "jit-recording.h"
 
 namespace gcc {
@@ -35,6 +37,12 @@ namespace jit {
 
 namespace playback {
 
+/* playback::context is an abstract base class.
+
+   The two concrete subclasses are:
+   - playback::compile_to_memory
+   - playback::compile_to_file.  */
+
 class context : public log_user
 {
 public:
@@ -174,7 +182,7 @@ public:
     return m_recording_ctxt->get_builtins_manager ();
   }
 
-  result *
+  void
   compile ();
 
   void
@@ -252,9 +260,22 @@ private:
   char *
   read_dump_file (const char *path);
 
+  virtual void postprocess (const char *ctxt_progname) = 0;
+
+protected:
+  tempdir *get_tempdir () { return m_tempdir; }
+
   void
   convert_to_dso (const char *ctxt_progname);
 
+  void
+  invoke_driver (const char *ctxt_progname,
+		 const char *input_file,
+		 const char *output_file,
+		 timevar_id_t tv_id,
+		 bool shared,
+		 bool run_linker);
+
   result *
   dlopen_built_dso ();
 
@@ -274,6 +295,37 @@ private:
   auto_vec<std::pair<tree, location *> > m_cached_locations;
 };
 
+class compile_to_memory : public context
+{
+ public:
+  compile_to_memory (recording::context *ctxt);
+  void postprocess (const char *ctxt_progname);
+
+  result *get_result_obj () const { return m_result; }
+
+ private:
+  result *m_result;
+};
+
+class compile_to_file : public context
+{
+ public:
+  compile_to_file (recording::context *ctxt,
+		   enum gcc_jit_output_kind output_kind,
+		   const char *output_path);
+  void postprocess (const char *ctxt_progname);
+
+ private:
+  void
+  copy_file (const char *src_path,
+	     const char *dst_path);
+
+ private:
+  enum gcc_jit_output_kind m_output_kind;
+  const char *m_output_path;
+};
+
+
 /* 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
diff --git a/gcc/jit/jit-recording.c b/gcc/jit/jit-recording.c
index 76eabbd..2b8af1f 100644
--- a/gcc/jit/jit-recording.c
+++ b/gcc/jit/jit-recording.c
@@ -1152,8 +1152,8 @@ recording::context::enable_dump (const char *dumpname,
   m_requested_dumps.safe_push (d);
 }
 
-/* Validate this context, and if it passes, compile it within a
-   mutex.
+/* Validate this context, and if it passes, compile it to memory
+   (within a mutex).
 
    Implements the post-error-checking part of
    gcc_jit_context_compile.  */
@@ -1168,13 +1168,41 @@ recording::context::compile ()
   if (errors_occurred ())
     return NULL;
 
-  /* Set up a playback context.  */
-  ::gcc::jit::playback::context replayer (this);
+  /* Set up a compile_to_memory playback context.  */
+  ::gcc::jit::playback::compile_to_memory replayer (this);
 
   /* Use it.  */
-  result *result_obj = replayer.compile ();
+  replayer.compile ();
 
-  return result_obj;
+  /* Get the jit::result (or NULL) from the
+     compile_to_memory playback context.  */
+  return replayer.get_result_obj ();
+}
+
+/* Validate this context, and if it passes, compile it to a file
+   (within a mutex).
+
+   Implements the post-error-checking part of
+   gcc_jit_context_compile_to_file.  */
+
+void
+recording::context::compile_to_file (enum gcc_jit_output_kind output_kind,
+				     const char *output_path)
+{
+  JIT_LOG_SCOPE (get_logger ());
+
+  validate ();
+
+  if (errors_occurred ())
+    return;
+
+  /* Set up a compile_to_file playback context.  */
+  ::gcc::jit::playback::compile_to_file replayer (this,
+						  output_kind,
+						  output_path);
+
+  /* Use it.  */
+  replayer.compile ();
 }
 
 /* Format the given error using printf's conventions, print
diff --git a/gcc/jit/jit-recording.h b/gcc/jit/jit-recording.h
index 57e7167..0dd3164 100644
--- a/gcc/jit/jit-recording.h
+++ b/gcc/jit/jit-recording.h
@@ -221,6 +221,10 @@ public:
   compile ();
 
   void
+  compile_to_file (enum gcc_jit_output_kind output_kind,
+		   const char *output_path);
+
+  void
   add_error (location *loc, const char *fmt, ...)
       GNU_PRINTF(3, 4);
 
diff --git a/gcc/jit/libgccjit++.h b/gcc/jit/libgccjit++.h
index 9b55c91..62ef6a4 100644
--- a/gcc/jit/libgccjit++.h
+++ b/gcc/jit/libgccjit++.h
@@ -99,6 +99,9 @@ namespace gccjit
 
     gcc_jit_result *compile ();
 
+    void compile_to_file (enum gcc_jit_output_kind output_kind,
+			  const char *output_path);
+
     void dump_to_file (const std::string &path,
 		       bool update_locations);
 
@@ -541,6 +544,15 @@ context::compile ()
 }
 
 inline void
+context::compile_to_file (enum gcc_jit_output_kind output_kind,
+			  const char *output_path)
+{
+  gcc_jit_context_compile_to_file (m_inner_ctxt,
+				   output_kind,
+				   output_path);
+}
+
+inline void
 context::dump_to_file (const std::string &path,
 		       bool update_locations)
 {
diff --git a/gcc/jit/libgccjit.c b/gcc/jit/libgccjit.c
index 0faf0f9..7eb66bd 100644
--- a/gcc/jit/libgccjit.c
+++ b/gcc/jit/libgccjit.c
@@ -2196,7 +2196,7 @@ gcc_jit_context_compile (gcc_jit_context *ctxt)
 
   JIT_LOG_FUNC (ctxt->get_logger ());
 
-  ctxt->log ("compiling ctxt: %p", (void *)ctxt);
+  ctxt->log ("in-memory compile of ctxt: %p", (void *)ctxt);
 
   gcc_jit_result *result = (gcc_jit_result *)ctxt->compile ();
 
@@ -2209,6 +2209,35 @@ gcc_jit_context_compile (gcc_jit_context *ctxt)
 /* Public entrypoint.  See description in libgccjit.h.
 
    After error-checking, the real work is done by the
+   gcc::jit::recording::context::compile_to_file method in
+   jit-recording.c.  */
+
+void
+gcc_jit_context_compile_to_file (gcc_jit_context *ctxt,
+				 enum gcc_jit_output_kind output_kind,
+				 const char *output_path)
+{
+  RETURN_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+  JIT_LOG_FUNC (ctxt->get_logger ());
+  RETURN_IF_FAIL_PRINTF1 (
+    ((output_kind >= GCC_JIT_OUTPUT_KIND_ASSEMBLER)
+     && (output_kind <= GCC_JIT_OUTPUT_KIND_EXECUTABLE)),
+    ctxt, NULL,
+    "unrecognized output_kind: %i",
+    output_kind);
+  RETURN_IF_FAIL (output_path, ctxt, NULL, "NULL output_path");
+
+  ctxt->log ("compile_to_file of ctxt: %p", (void *)ctxt);
+  ctxt->log ("output_kind: %i", output_kind);
+  ctxt->log ("output_path: %s", output_path);
+
+  ctxt->compile_to_file (output_kind, output_path);
+}
+
+
+/* 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.  */
 
diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h
index 2f41087..12514ba 100644
--- a/gcc/jit/libgccjit.h
+++ b/gcc/jit/libgccjit.h
@@ -36,17 +36,20 @@ extern "C" {
    the API below.
 
    Invoking gcc_jit_context_compile on it gives you a gcc_jit_result *
-   (or NULL).
+   (or NULL), representing in-memory machine code.
 
    You can call gcc_jit_context_compile repeatedly on one context, giving
    multiple independent results.
 
+   Similarly, you can call gcc_jit_context_compile_to_file on a context
+   to compile to disk.
+
    Eventually you can call gcc_jit_context_release to clean up the
-   context; any results created from it are still usable, and should be
-   cleaned up via gcc_jit_result_release.  */
+   context; any in-memory results created from it are still usable, and
+   should be cleaned up via gcc_jit_result_release.  */
 typedef struct gcc_jit_context gcc_jit_context;
 
-/* A gcc_jit_result encapsulates the result of a compilation.  */
+/* A gcc_jit_result encapsulates the result of an in-memory compilation.  */
 typedef struct gcc_jit_result gcc_jit_result;
 
 /* An object created within a context.  Such objects are automatically
@@ -240,12 +243,42 @@ 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.  */
+/* Compile the context to in-memory machine code.
+
+   This can be called more that once on a given context,
+   although any errors that occur will block further compilation.  */
+
 extern gcc_jit_result *
 gcc_jit_context_compile (gcc_jit_context *ctxt);
 
+/* Kinds of ahead-of-time compilation, for use with
+   gcc_jit_context_compile_to_file.  */
+
+enum gcc_jit_output_kind
+{
+  /* Compile the context to an assembler file.  */
+  GCC_JIT_OUTPUT_KIND_ASSEMBLER,
+
+  /* Compile the context to an object file.  */
+  GCC_JIT_OUTPUT_KIND_OBJECT_FILE,
+
+  /* Compile the context to a dynamic library.  */
+  GCC_JIT_OUTPUT_KIND_DYNAMIC_LIBRARY,
+
+  /* Compile the context to an executable.  */
+  GCC_JIT_OUTPUT_KIND_EXECUTABLE
+};
+
+/* Compile the context to a file of the given kind.
+
+   This can be called more that once on a given context,
+   although any errors that occur will block further compilation.  */
+
+extern void
+gcc_jit_context_compile_to_file (gcc_jit_context *ctxt,
+				 enum gcc_jit_output_kind output_kind,
+				 const char *output_path);
+
 /* To help with debugging: dump a C-like representation to the given path,
    describing what's been set up on the context.
 
@@ -1079,14 +1112,15 @@ gcc_jit_context_dump_reproducer_to_file (gcc_jit_context *ctxt,
    The context directly stores the dumpname as a (const char *), so the
    passed string must outlive the context.
 
-   gcc_jit_context_compile will capture the dump as a
-   dynamically-allocated buffer, writing it to ``*out_ptr``.
+   gcc_jit_context_compile and gcc_jit_context_to_file
+   will capture the dump as a dynamically-allocated buffer, writing
+   it to ``*out_ptr``.
 
    The caller becomes responsible for calling
       free (*out_ptr)
-   each time that gcc_jit_context_compile is called.  *out_ptr will be
-   written to, either with the address of a buffer, or with NULL if an
-   error occurred.
+   each time that gcc_jit_context_compile or gcc_jit_context_to_file
+   are called.  *out_ptr will be written to, either with the address of a
+   buffer, or with NULL if an error occurred.
 
    This API entrypoint is likely to be less stable than the others.
    In particular, both the precise dumpnames, and the format and content
diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map
index 93d5c26..89bd57be4 100644
--- a/gcc/jit/libgccjit.map
+++ b/gcc/jit/libgccjit.map
@@ -32,6 +32,7 @@
     gcc_jit_block_get_function;
     gcc_jit_context_acquire;
     gcc_jit_context_compile;
+    gcc_jit_context_compile_to_file;
     gcc_jit_context_dump_to_file;
     gcc_jit_context_dump_reproducer_to_file;
     gcc_jit_context_enable_dump;
diff --git a/gcc/jit/notes.txt b/gcc/jit/notes.txt
index 7df4a7b..e92c665 100644
--- a/gcc/jit/notes.txt
+++ b/gcc/jit/notes.txt
@@ -74,9 +74,16 @@ Client Code   . Generated .            libgccjit.so
               .           .          .               . │   (purge internal state)
               .           .    <──────────────────────── end of toplev::finalize
               .           .    │     .               .
-              .           .    │ Convert assembler to DSO ("fake.so")
-              .           .    │     .               .
-              .           .    │ Load DSO (dlopen "fake.so")
+              .           .    V─> playback::context::postprocess:
+              .           .      │   .               .
+              .           .      │   (assuming an in-memory compile):
+              .           .      │   .               .
+              .           .      │   . Convert assembler to DSO ("fake.so")
+              .           .      │   .               .
+              .           .      │   . Load DSO (dlopen "fake.so")
+              .           .      │   .               .
+              .           .      │   . Bundle it up in a jit::result
+              .           .    <──   .               .
               .           .    │     .               .
               .           .    │ RELEASE MUTEX       .
               .           .    │     .               .
diff --git a/gcc/testsuite/jit.dg/harness.h b/gcc/testsuite/jit.dg/harness.h
index 96fc5da..db25637 100644
--- a/gcc/testsuite/jit.dg/harness.h
+++ b/gcc/testsuite/jit.dg/harness.h
@@ -7,12 +7,14 @@
     extern void
     create_code (gcc_jit_context *ctxt, void * user_data);
 
+  and, #ifndef TEST_COMPILING_TO_FILE,
+
     extern void
     verify_code (gcc_jit_context *ctxt, gcc_jit_result *result);
-
  */
 #include <stdlib.h>
 #include <stdio.h>
+#include <unistd.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.
@@ -106,12 +108,23 @@ static char test[1024];
       }				\
   } while (0)
 
+#define CHECK_NO_ERRORS(CTXT) \
+  do { \
+    const char *err = gcc_jit_context_get_first_error (CTXT); \
+    if (err) \
+      fail ("error unexpectedly occurred: %s", err); \
+    else \
+      pass ("no errors occurred"); \
+  } while (0)
+
 /* Hooks that testcases should provide.  */
 extern void
 create_code (gcc_jit_context *ctxt, void * user_data);
 
+#ifndef TEST_COMPILING_TO_FILE
 extern void
 verify_code (gcc_jit_context *ctxt, gcc_jit_result *result);
+#endif
 
 extern void check_string_value (const char *funcname,
 				const char *actual, const char *expected);
@@ -322,7 +335,13 @@ test_jit (const char *argv0, void *user_data)
 {
   gcc_jit_context *ctxt;
   FILE *logfile;
+#ifndef TEST_COMPILING_TO_FILE
   gcc_jit_result *result;
+#endif
+
+#ifdef TEST_COMPILING_TO_FILE
+  unlink (OUTPUT_FILENAME);
+#endif
 
   ctxt = gcc_jit_context_acquire ();
   if (!ctxt)
@@ -339,16 +358,24 @@ test_jit (const char *argv0, void *user_data)
 
   dump_reproducer (ctxt, argv0);
 
+#ifdef TEST_COMPILING_TO_FILE
+  gcc_jit_context_compile_to_file (ctxt,
+				   (OUTPUT_KIND),
+				   (OUTPUT_FILENAME));
+#else /* #ifdef TEST_COMPILING_TO_FILE */
   /* 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);
+#endif
 
   gcc_jit_context_release (ctxt);
 
+#ifndef TEST_COMPILING_TO_FILE
   /* Once we're done with the code, this unloads the built .so file: */
   gcc_jit_result_release (result);
+#endif
 
   if (logfile)
     fclose (logfile);
diff --git a/gcc/testsuite/jit.dg/jit.exp b/gcc/testsuite/jit.dg/jit.exp
index 3caccce..c853f22 100644
--- a/gcc/testsuite/jit.dg/jit.exp
+++ b/gcc/testsuite/jit.dg/jit.exp
@@ -139,6 +139,8 @@ proc fixed_host_execute {args} {
     global text
     global spawn_id
 
+    verbose "fixed_host_execute: $args"
+
     set timeoutmsg "Timed out: Never got started, "
     set timeout 100
     set file all
@@ -148,9 +150,8 @@ proc fixed_host_execute {args} {
     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 "\}"]
+	set executable [lindex $args 0]
+	set params [lindex $args 1]
     }
 
     verbose "The executable is $executable" 2
@@ -159,6 +160,8 @@ proc fixed_host_execute {args} {
 	return "No source file found"
     }
 
+    verbose "params: $params" 2
+
     # spawn the executable and look for the DejaGnu output messages from the
     # test case.
     # spawn -noecho -open [open "|./${executable}" "r"]
@@ -328,6 +331,39 @@ proc get_path_of_driver {} {
     return [file dirname $binary]
 }
 
+# Expand "SRCDIR" within ARG to the location of the top-level
+# src directory
+
+proc jit-expand-vars {arg} {
+    verbose "jit-expand-vars: $arg"
+    global srcdir
+    verbose " srcdir: $srcdir"
+    # "srcdir" is that of the gcc/testsuite directory, so
+    # we need to go up two levels.
+    set arg [string map [list "SRCDIR" $srcdir/../..] $arg]
+    verbose " new arg: $arg"
+    return $arg
+}
+
+# Parameters used when invoking the executables built from the test cases.
+
+global jit-exe-params
+set jit-exe-params {}
+
+# Set "jit-exe-params", expanding "SRCDIR" in each arg to the location of
+# the top-level srcdir.
+
+proc dg-jit-set-exe-params { args } {
+    verbose "dg-jit-set-exe-params: $args"
+
+    global jit-exe-params
+    set jit-exe-params {}
+    # Skip initial arg (line number)
+    foreach arg [lrange $args 1 [llength $args] ] {
+	lappend jit-exe-params [jit-expand-vars $arg]
+    }
+}
+
 proc jit-dg-test { prog do_what extra_tool_flags } {
     verbose "within jit-dg-test..."
     verbose "  prog: $prog"
@@ -339,6 +375,15 @@ proc jit-dg-test { prog do_what extra_tool_flags } {
 	append extra_tool_flags " -lpthread"
     }
 
+    # Any test case that uses
+    #   { dg-final { jit-verify-compile-to-file FOO } }
+    # needs to call jit-setup-compile-to-file here.
+    # (is there a better way to handle setup/finish pairs in dg?)
+    set tmp [grep $prog "jit-verify-compile-to-file"]
+    if {![string match "" $tmp]} {
+	jit-setup-compile-to-file $prog
+    }
+
     # Determine what to name the built executable.
     #
     # We simply append .exe to the filename, e.g.
@@ -464,7 +509,12 @@ proc jit-dg-test { prog do_what extra_tool_flags } {
     #  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]
+
+    global jit-exe-params
+    set args ${jit-exe-params}
+    set jit-exe-params {}
+
+    set result [fixed_host_execute $output_file $args ]
     verbose "result: $result"
 
     # Restore PATH
@@ -530,6 +580,157 @@ proc jit-dg-test { prog do_what extra_tool_flags } {
     return [list $comp_output $output_file]
 }
 
+# Given source file PROG, scrape out the value of
+#   #define OUTPUT_FILENAME
+# failing if it's not found.
+
+proc jit-get-output-filename {prog} {
+    set tmp [grep $prog "#define OUTPUT_FILENAME (.*)"]
+    if {![string match "" $tmp]} {
+	foreach i $tmp {
+	    verbose "i: $i"
+	    if {[regexp "^\#define OUTPUT_FILENAME\[ \t\]\+\"(.*)\"$" $i i group] } {
+		verbose "group: '$group'"
+		return $group
+	    } else {
+		fail "Unable to parse line: $i"
+	    }
+	}
+    }
+    fail "Unable to locate OUTPUT_FILENAME"
+    return ""
+}
+
+# For testcases that use jit-verify-compile-to-file,
+# delete OUTPUT_FILENAME beforehand, to ensure that the
+# testcase is indeed creating it.
+
+proc jit-setup-compile-to-file { prog } {
+    verbose "jit-setup-compile-to-file: $prog"
+    set output_filename [jit-get-output-filename $prog]
+    verbose "  output_filename: $output_filename"
+    if {![string match "" $output_filename]} {
+	catch "exec rm -f $output_filename"
+    }
+}
+
+# Locate OUTPUT_FILENAME within the testcase.  Verify
+# that a file with that name was created, and that
+# the output of running the "file" utility on it
+# matches the given regex.
+# For use by the various test-compile-to-*.c testcases.
+
+proc jit-verify-compile-to-file {args} {
+    verbose "jit-verify-compile-to-file: $args"
+
+    set file_regex [lindex $args 0]
+    verbose "file_regex: $file_regex"
+
+    upvar 2 prog prog
+    verbose "prog: $prog"
+    set output_filename [jit-get-output-filename $prog]
+    verbose "  output_filename: $output_filename"
+
+    # Verify that the expected file was written out
+    if { [file exists $output_filename] == 1} {
+	pass "$output_filename exists"
+    } else {
+	fail "$output_filename does not exist"
+	return
+    }
+
+    # Run "file" on OUTPUT_FILENAME, and verify that the output
+    # matches $file_regex.
+    spawn -noecho "file" $output_filename
+    set file_id $spawn_id
+    expect "\n" {
+	verbose "got newline: $expect_out(buffer)"
+	set classification $expect_out(buffer)
+	verbose "classification: $classification"
+	if { [regexp $file_regex $classification] } {
+	    pass "'file' output on $output_filename matched: $file_regex"
+	} else {
+	    fail "'file' output on $output_filename did not match: $file_regex"
+	}
+    }
+    set $spawn_id $file_id
+    close
+}
+
+# Verify that the given file exists, and is executable.
+# Attempt to execute it, and verify that its stdout matches
+# the given regex.
+
+proc jit-run-executable { args } {
+    verbose "jit-run-executable: $args"
+
+    set executable-name [lindex $args 0]
+    verbose "executable-name: ${executable-name}"
+
+    set dg-output-text [lindex $args 1]
+    verbose "dg-output-text: ${dg-output-text}"
+
+    if { [file executable ${executable-name}] } {
+	pass "${executable-name} has executable bit set"
+    } else {
+	fail "${executable-name} does not have executable bit set"
+    }
+
+    # Attempt to run the executable; adapted from dg.exp's dg-test
+    set status -1
+    set result [jit_load ./${executable-name}]
+    set status [lindex $result 0]
+    set output [lindex $result 1]
+    verbose "  status: $status"
+    verbose "  output: $output"
+    # send_user "After exec, status: $status\n"
+    if { "$status" == "pass" } {
+	pass "${executable-name} execution test"
+	verbose "Exec succeeded." 3
+	set texttmp ${dg-output-text}
+	if { ![regexp $texttmp ${output}] } {
+	    fail "${executable-name} output pattern test, is ${output}, should match $texttmp"
+	    verbose "Failed test for output pattern $texttmp" 3
+	} else {
+	    pass "${executable-name} output pattern test, $texttmp"
+	    verbose "Passed test for output pattern $texttmp" 3
+	}
+	unset texttmp
+    } elseif { "$status" == "fail" } {
+	# It would be nice to get some info out of errorCode.
+	if {[info exists errorCode]} {
+	    verbose "Exec failed, errorCode: $errorCode" 3
+	} else {
+	    verbose "Exec failed, errorCode not defined!" 3
+	}
+	fail "${executable-name} execution test"
+    } else {
+	$status "${executable-name} execution test"
+    }
+}
+
+# A way to invoke "jit-run-executable" with the given regex,
+# using OUTPUT_FILENAME within the testcase to determine
+# the name of the executable to run.
+# For use by the test-compile-to-executable.c testcase.
+
+proc jit-verify-executable { args } {
+    verbose "jit-verify-executable: $args"
+
+    set dg-output-text [lindex $args 0]
+    verbose "dg-output-text: ${dg-output-text}"
+
+    upvar 2 name name
+    verbose "name: $name"
+
+    upvar 2 prog prog
+    verbose "prog: $prog"
+    set output_filename [jit-get-output-filename $prog]
+    verbose "  output_filename: $output_filename"
+
+    jit-run-executable $output_filename ${dg-output-text}
+}
+
 # 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"
diff --git a/gcc/testsuite/jit.dg/test-compile-to-assembler.c b/gcc/testsuite/jit.dg/test-compile-to-assembler.c
new file mode 100644
index 0000000..c5b282c
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-compile-to-assembler.c
@@ -0,0 +1,65 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#define TEST_COMPILING_TO_FILE
+#define OUTPUT_KIND      GCC_JIT_OUTPUT_KIND_ASSEMBLER
+#define OUTPUT_FILENAME  "output-of-test-compile-to-assembler.c.s"
+#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);
+}
+
+/* { dg-final { jit-verify-compile-to-file "assembler source text" } } */
diff --git a/gcc/testsuite/jit.dg/test-compile-to-dynamic-library.c b/gcc/testsuite/jit.dg/test-compile-to-dynamic-library.c
new file mode 100644
index 0000000..095f751
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-compile-to-dynamic-library.c
@@ -0,0 +1,65 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#define TEST_COMPILING_TO_FILE
+#define OUTPUT_KIND      GCC_JIT_OUTPUT_KIND_DYNAMIC_LIBRARY
+#define OUTPUT_FILENAME  "output-of-test-compile-to-dynamic-library.c.so"
+#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);
+}
+
+/* { dg-final { jit-verify-compile-to-file "shared object.+dynamically linked" } } */
diff --git a/gcc/testsuite/jit.dg/test-compile-to-executable.c b/gcc/testsuite/jit.dg/test-compile-to-executable.c
new file mode 100644
index 0000000..8d7b428
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-compile-to-executable.c
@@ -0,0 +1,110 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#define TEST_COMPILING_TO_FILE
+#define OUTPUT_KIND      GCC_JIT_OUTPUT_KIND_EXECUTABLE
+#define OUTPUT_FILENAME  "output-of-test-compile-to-executable.c.exe"
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  /* Let's try to inject the equivalent of:
+     static void
+     hello_world (const char *name)
+     {
+       // a test comment
+       printf ("hello %s\n", name);
+     }
+
+     extern int
+     main (int argc, char **argv)
+     {
+       hello_world (argv[0]);
+       return 0;
+     }
+  */
+  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_INTERNAL,
+				  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);
+
+  gcc_jit_type *int_type = gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+  gcc_jit_param *param_argc =
+    gcc_jit_context_new_param (ctxt, NULL, int_type, "argc");
+  gcc_jit_type *char_ptr_ptr_type =
+    gcc_jit_type_get_pointer (
+      gcc_jit_type_get_pointer (
+	gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_CHAR)));
+  gcc_jit_param *param_argv =
+    gcc_jit_context_new_param (ctxt, NULL, char_ptr_ptr_type, "argv");
+  gcc_jit_param *params[2] = {param_argc, param_argv};
+  gcc_jit_function *func_main =
+    gcc_jit_context_new_function (ctxt, NULL,
+				  GCC_JIT_FUNCTION_EXPORTED,
+				  int_type,
+				  "main",
+				  2, params,
+				  0);
+  block = gcc_jit_function_new_block (func_main, NULL);
+  gcc_jit_rvalue *zero = gcc_jit_context_zero (ctxt, int_type);
+  args[0] = gcc_jit_context_new_cast (
+	ctxt,
+	NULL,
+	gcc_jit_lvalue_as_rvalue (
+	  gcc_jit_context_new_array_access (
+	    ctxt,
+	    NULL,
+	    gcc_jit_param_as_rvalue (param_argv),
+	    zero)),
+	const_char_ptr_type);
+  gcc_jit_block_add_eval (
+    block, NULL,
+    gcc_jit_context_new_call (ctxt,
+			      NULL,
+			      func,
+			      1, args));
+  gcc_jit_block_end_with_return (block, NULL, zero);
+}
+
+/* { dg-final { jit-verify-compile-to-file "executable" } } */
+/* { dg-final { jit-verify-executable "hello .*" } } */
diff --git a/gcc/testsuite/jit.dg/test-compile-to-object.c b/gcc/testsuite/jit.dg/test-compile-to-object.c
new file mode 100644
index 0000000..1f7fcc6
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-compile-to-object.c
@@ -0,0 +1,65 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#define TEST_COMPILING_TO_FILE
+#define OUTPUT_KIND      GCC_JIT_OUTPUT_KIND_OBJECT_FILE
+#define OUTPUT_FILENAME  "output-of-test-compile-to-object.c.o"
+#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);
+}
+
+/* { dg-final { jit-verify-compile-to-file "relocatable" } } */
-- 
1.8.5.3

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] Re: Stage 3 RFC: using "jit" for ahead-of-time compilation
  2015-01-01  0:00   ` [PATCH] " David Malcolm
@ 2015-01-01  0:00     ` Richard Biener
  2015-01-01  0:00       ` David Malcolm
  0 siblings, 1 reply; 6+ messages in thread
From: Richard Biener @ 2015-01-01  0:00 UTC (permalink / raw)
  To: David Malcolm; +Cc: jit, GCC Patches, Jakub Jelinek, Joseph Myers

On Fri, Jan 16, 2015 at 7:47 PM, David Malcolm <dmalcolm@redhat.com> wrote:
> On Thu, 2015-01-15 at 22:50 +0100, Richard Biener wrote:
>> On January 15, 2015 9:05:59 PM CET, David Malcolm <dmalcolm@redhat.com> wrote:
>> >Release managers: given that this only touches the jit, and that the
>> >jit
>> >is off by default, any objections if I go ahead and commit this?
>> >It's a late-breaking feature, but the jit as a whole is new, and
>> >I think the following is a big win, so I'd like to proceed with this in
>> >stage 3 (i.e. in the next 24 hours).  There are docs and testcases.
>> >
>> >New jit API entrypoint: gcc_jit_context_compile_to_file
>> >
>> >This patch adds a way to use libgccjit for ahead-of-time compilation.
>> >I noticed that given the postprocessing steps the jit has to take to
>> >turn the .s file into in-memory code (invoke driver to convert to
>> >a .so and then dlopen), that it's not much of a leap to support
>> >compiling the .s file into objects, dynamic libraries, and executables.
>> >
>> >Doing so seems like a big win from a feature standpoint: people with
>> >pre-existing frontend code who want a backend can then plug in
>> >libgccjit
>> >and have a compiler, without needing to write it as a GCC frontend, or
>> >use LLVM.
>>
>> Note that you should make them aware of our runtime license with
>> respect to the eligible compilation process.  Which means this is not
>> a way to implement proprietary front ends.
>>
>> Richard.
>
> IANAL, but as I understand things, the runtime license is an additional
> grant of rights that covers certain components of GCC that bear the GCC
> Runtime Library Exception, allowing them to be used in certain
> additional ways beyond regular GPLv3-compliance.
>
> libgccjit doesn't have that exception; it's GPLv3.
>
> Perhaps an argument could be made for libgccjit to have the exception,
> if the FSF think that that would better serve the FSF's mission; right
> now, I'm merely trying to provide a technical means to modularity.
>
> Assuming the above is correct, anything linked against it needs to be
> GPLv3-compatible.  Hence any such frontend linked against libgccjit
> would need to be GPLv3-compatible.
>
> Attached is a patch (on top of the proposed one below), to clarify the
> wording in the new tutorial a little, to remind people that such linking
> needs to be license-compatible (without actually spelling out what the
> license is, though it's visible at the top of the public header file,
> libgccjit.h, as GPLv3 or later without the runtime library exception).
>
> Are the combined patches OK by you?

Yes.

Thanks,
Richard.

> Thanks
> Dave
>
>
>> >"jit" becomes something of a misnomer for this use-case.
>> >
>> >As an experiment, I used this technique to add a compiler for the
>> >language I'll refer to as "brainf" (ahem), and wrote this up for the
>> >libgccjit tutorial (it's all in the patch); prebuilt HTML can be seen
>> >at:
>> >https://dmalcolm.fedorapeople.org/gcc/libgccjit-api-docs-wip/intro/tutorial05.html
>> >
>> >The main things that are missing are:
>> > * specifying libraries to link against (Uli had some ideas about this)
>> >  * cross-compilation support (needs some deeper work, especially the
>> >    test suite, so deferrable to gcc 6, I guess)
>> >but the feature is useful with the patch as-is.
>> >
>> >The new test cases take jit.sum's # of expected passes
>> >from 7514 to 7571.
>> >
>> >gcc/jit/ChangeLog:
>> >     * docs/cp/topics/results.rst: Rename to...
>> >     * docs/cp/topics/compilation.rst: ...this, and add section on
>> >     ahead-of-time compilation.
>> >     * docs/cp/topics/index.rst: Update for renaming of results.rst
>> >     to compilation.rst.
>> >     * docs/examples/emit-alphabet.bf: New file, a sample "brainf"
>> >     script.
>> >     * docs/examples/tut05-bf.c: New file, implementing a compiler
>> >     for "brainf".
>> >     * docs/internals/test-hello-world.exe.log.txt: Update to reflect
>> >     changes to logger output.
>> >     * docs/intro/index.rst: Add tutorial05.rst
>> >     * docs/intro/tutorial05.rst: New file.
>> >     * docs/topics/results.rst: Rename to...
>> >     * docs/topics/compilation.rst: ...this, and add section on
>> >     ahead-of-time compilation.
>> >     * docs/topics/index.rst: Update for renaming of results.rst to
>> >     compilation.rst.
>> >     * jit-playback.c (gcc::jit::playback::context::compile): Convert
>> >     return type from result * to void.  Move the code to convert to
>> >     dso and dlopen the result to a new pure virtual "postprocess"
>> >     method.
>> >     (gcc::jit::playback::compile_to_memory::compile_to_memory): New
>> >     function.
>> >     (gcc::jit::playback::compile_to_memory::postprocess): New
>> >     function, based on playback::context::compile.
>> >     (gcc::jit::playback::compile_to_file::compile_to_file): New
>> >     function.
>> >     (gcc::jit::playback::compile_to_file::postprocess): New function.
>> >     (gcc::jit::playback::compile_to_file::copy_file): New function.
>> >     (gcc::jit::playback::context::convert_to_dso): Move internals
>> >     to...
>> >     (gcc::jit::playback::context::invoke_driver): New method.  Add
>> >     "-shared" and "-c" options to driver's argv as needed.
>> >     * jit-playback.h: Include "timevar.h".
>> >     (gcc::jit::playback::context::compile): Convert return type from
>> >     result * to void.
>> >     (gcc::jit::playback::context::postprocess): New pure virtual
>> >     function, making this an abstract base class.
>> >     (gcc::jit::playback::context::get_tempdir): New accessor.
>> >     (gcc::jit::playback::context::invoke_driver): New function.
>> >     (class gcc::jit::playback::compile_to_memory): New subclass of
>> >     playback::context.
>> >     (class gcc::jit::playback::compile_to_file): Likewise.
>> >     * jit-recording.c (gcc::jit::recording::context::compile): Use a
>> >     playback::compile_to_memory, and extract its result.
>> >     (gcc::jit::recording::context::compile_to_file): New function.
>> >     * jit-recording.h (gcc::jit::recording::context::compile_to_file):
>> >     New function.
>> >     * libgccjit++.h (gccjit::context::compile_to_file): New method.
>> >     * libgccjit.c (gcc_jit_context_compile): Update log message to
>> >     clarify that this is an in-memory compile.
>> >     (gcc_jit_context_compile_to_file): New function.
>> >     * libgccjit.h (gcc_jit_context): Clarify that you can compile
>> >     a context more than once, and that you can compile to a file
>> >     as well as to memory.
>> >     (gcc_jit_result): Clarify that this is the result of an
>> >     in-memory compilation.
>> >     (gcc_jit_context_compile): Clarify that you can compile, and that
>> >     this is an in-memory compilation.
>> >     (enum gcc_jit_output_kind): New enum.
>> >     (gcc_jit_context_compile_to_file): New function.
>> >     (gcc_jit_context_enable_dump): Clarify comment to cover both forms
>> >     of compilation.
>> >     * libgccjit.map (gcc_jit_context_compile_to_file): New API
>> >     entrypoint.
>> >     * notes.txt: Update to show the playback::context::postprocess
>> >     virtual function.
>> >
>> >gcc/testsuite/ChangeLog:
>> >     * jit.dg/harness.h: Include <unistd.h>.
>> >     (CHECK_NO_ERRORS): New.
>> >     (verify_code): Wrap prototype in #ifndef TEST_COMPILING_TO_FILE.
>> >     (test_jit): Support new macro TEST_COMPILING_TO_FILE for exercising
>> >     gcc_jit_context_compile_to_file.
>> >     * jit.dg/jit.exp (fixed_host_execute): Fix the code for passing on
>> >     args to the spawned executable.
>> >     (jit-expand-vars): New function.
>> >     (jit-exe-params): New variable.
>> >     (dg-jit-set-exe-params): New function.
>> >     (jit-dg-test): Detect testcases that use
>> >     jit-verify-compile-to-file and call jit-setup-compile-to-file.
>> >     Set arguments of spawned process to jit-exe-params.
>> >     (jit-get-output-filename): New function.
>> >     (jit-setup-compile-to-file): New function.
>> >     (jit-verify-compile-to-file): New function.
>> >     (jit-run-executable): New function.
>> >     (jit-verify-executable): New function.
>> >     * jit.dg/test-compile-to-assembler.c: New testcase.
>> >     * jit.dg/test-compile-to-dynamic-library.c: New testcase.
>> >     * jit.dg/test-compile-to-executable.c: New testcase.
>> >     * jit.dg/test-compile-to-object.c: New testcase.
>> >---
>> > gcc/jit/docs/cp/topics/compilation.rst             |  58 +++
>> > gcc/jit/docs/cp/topics/index.rst                   |   4 +-
>> > gcc/jit/docs/cp/topics/results.rst                 |  48 ---
>> > gcc/jit/docs/examples/emit-alphabet.bf             |  17 +
>> >gcc/jit/docs/examples/tut05-bf.c                   | 446
>> >+++++++++++++++++++++
>> > .../docs/internals/test-hello-world.exe.log.txt    |  48 ++-
>> > gcc/jit/docs/intro/index.rst                       |   3 +-
>> > gcc/jit/docs/intro/tutorial05.rst                  | 253 ++++++++++++
>> > gcc/jit/docs/topics/compilation.rst                | 199 +++++++++
>> > gcc/jit/docs/topics/index.rst                      |   4 +-
>> > gcc/jit/docs/topics/results.rst                    | 127 ------
>> >gcc/jit/jit-playback.c                             | 308 +++++++++++++-
>> > gcc/jit/jit-playback.h                             |  54 ++-
>> > gcc/jit/jit-recording.c                            |  40 +-
>> > gcc/jit/jit-recording.h                            |   4 +
>> > gcc/jit/libgccjit++.h                              |  12 +
>> > gcc/jit/libgccjit.c                                |  31 +-
>> > gcc/jit/libgccjit.h                                |  58 ++-
>> > gcc/jit/libgccjit.map                              |   1 +
>> > gcc/jit/notes.txt                                  |  13 +-
>> > gcc/testsuite/jit.dg/harness.h                     |  29 +-
>> > gcc/testsuite/jit.dg/jit.exp                       | 209 +++++++++-
>> > gcc/testsuite/jit.dg/test-compile-to-assembler.c   |  65 +++
>> > .../jit.dg/test-compile-to-dynamic-library.c       |  65 +++
>> > gcc/testsuite/jit.dg/test-compile-to-executable.c  | 110 +++++
>> > gcc/testsuite/jit.dg/test-compile-to-object.c      |  65 +++
>> > 26 files changed, 2026 insertions(+), 245 deletions(-)
>> > create mode 100644 gcc/jit/docs/cp/topics/compilation.rst
>> > delete mode 100644 gcc/jit/docs/cp/topics/results.rst
>> > create mode 100644 gcc/jit/docs/examples/emit-alphabet.bf
>> > create mode 100644 gcc/jit/docs/examples/tut05-bf.c
>> > create mode 100644 gcc/jit/docs/intro/tutorial05.rst
>> > create mode 100644 gcc/jit/docs/topics/compilation.rst
>> > delete mode 100644 gcc/jit/docs/topics/results.rst
>> > create mode 100644 gcc/testsuite/jit.dg/test-compile-to-assembler.c
>> >create mode 100644
>> >gcc/testsuite/jit.dg/test-compile-to-dynamic-library.c
>> > create mode 100644 gcc/testsuite/jit.dg/test-compile-to-executable.c
>> > create mode 100644 gcc/testsuite/jit.dg/test-compile-to-object.c
>> >
>> >diff --git a/gcc/jit/docs/cp/topics/compilation.rst
>> >b/gcc/jit/docs/cp/topics/compilation.rst
>> >new file mode 100644
>> >index 0000000..05917e8
>> >--- /dev/null
>> >+++ b/gcc/jit/docs/cp/topics/compilation.rst
>> >@@ -0,0 +1,58 @@
>> >+.. Copyright (C) 2014-2015 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:: cpp
>> >+
>> >+Compiling a context
>> >+===================
>> >+
>> >+Once populated, a :class:`gccjit::context` can be compiled to
>> >+machine code, either in-memory via :func:`gccjit::context::compile` or
>> >+to disk via :func:`gccjit::context::compile_to_file`.
>> >+
>> >+You can compile a context multiple times (using either form of
>> >+compilation), although any errors that occur on the context will
>> >+prevent any future compilation of that context.
>> >+
>> >+In-memory compilation
>> >+*********************
>> >+
>> >+.. function:: gcc_jit_result *\
>> >+              gccjit::context::compile ()
>> >+
>> >+   This calls into GCC and builds the code, returning a
>> >+   `gcc_jit_result *`.
>> >+
>> >+   This is a thin wrapper around the
>> >+   :c:func:`gcc_jit_context_compile` API entrypoint.
>> >+
>> >+Ahead-of-time compilation
>> >+*************************
>> >+
>> >+Although libgccjit is primarily aimed at just-in-time compilation, it
>> >+can also be used for implementing more traditional ahead-of-time
>> >+compilers, via the :func:`gccjit::context::compile_to_file` method.
>> >+
>> >+.. function:: void \
>> >+              gccjit::context::compile_to_file (enum
>> >gcc_jit_output_kind,\
>> >+                                                const char
>> >*output_path)
>> >+
>> >+   Compile the :class:`gccjit::context` to a file of the given
>> >+   kind.
>> >+
>> >+   This is a thin wrapper around the
>> >+   :c:func:`gcc_jit_context_compile_to_file` API entrypoint.
>> >diff --git a/gcc/jit/docs/cp/topics/index.rst
>> >b/gcc/jit/docs/cp/topics/index.rst
>> >index a129137..4ebb623 100644
>> >--- a/gcc/jit/docs/cp/topics/index.rst
>> >+++ b/gcc/jit/docs/cp/topics/index.rst
>> >@@ -1,4 +1,4 @@
>> >-.. Copyright (C) 2014 Free Software Foundation, Inc.
>> >+.. Copyright (C) 2014-2015 Free Software Foundation, Inc.
>> >    Originally contributed by David Malcolm <dmalcolm@redhat.com>
>> >
>> >    This is free software: you can redistribute it and/or modify it
>> >@@ -27,4 +27,4 @@ Topic Reference
>> >    expressions.rst
>> >    functions.rst
>> >    locations.rst
>> >-   results.rst
>> >+   compilation.rst
>> >diff --git a/gcc/jit/docs/cp/topics/results.rst
>> >b/gcc/jit/docs/cp/topics/results.rst
>> >deleted file mode 100644
>> >index 18200ac..0000000
>> >--- a/gcc/jit/docs/cp/topics/results.rst
>> >+++ /dev/null
>> >@@ -1,48 +0,0 @@
>> >-.. 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:: cpp
>> >-
>> >-Compilation results
>> >-===================
>> >-
>> >-.. type:: gcc_jit_result
>> >-
>> >-  A `gcc_jit_result` encapsulates the result of compiling a context.
>> >-
>> >-.. function:: gcc_jit_result *\
>> >-              gccjit::context::compile ()
>> >-
>> >-   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/examples/emit-alphabet.bf
>> >b/gcc/jit/docs/examples/emit-alphabet.bf
>> >new file mode 100644
>> >index 0000000..6863273
>> >--- /dev/null
>> >+++ b/gcc/jit/docs/examples/emit-alphabet.bf
>> >@@ -0,0 +1,17 @@
>> >+[
>> >+  Emit the uppercase alphabet
>> >+]
>> >+
>> >+cell 0 = 26
>> >+++++++++++++++++++++++++++
>> >+
>> >+cell 1 = 65
>> >+>+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++<
>> >+
>> >+while cell#0 != 0
>> >+[
>> >+ >
>> >+ .      emit cell#1
>> >+ +      increment cell@1
>> >+ <-     decrement cell@0
>> >+]
>> >diff --git a/gcc/jit/docs/examples/tut05-bf.c
>> >b/gcc/jit/docs/examples/tut05-bf.c
>> >new file mode 100644
>> >index 0000000..f948ede
>> >--- /dev/null
>> >+++ b/gcc/jit/docs/examples/tut05-bf.c
>> >@@ -0,0 +1,446 @@
>> >+/* A compiler for the "bf" language.  */
>> >+
>> >+#include <stdlib.h>
>> >+#include <string.h>
>> >+#include <errno.h>
>> >+
>> >+#include "libgccjit.h"
>> >+
>> >+/* Make "main" function:
>> >+     int
>> >+     main (int argc, char **argv)
>> >+     {
>> >+       ...
>> >+     }
>> >+*/
>> >+static gcc_jit_function *
>> >+make_main (gcc_jit_context *ctxt)
>> >+{
>> >+  gcc_jit_type *int_type =
>> >+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
>> >+  gcc_jit_param *param_argc =
>> >+    gcc_jit_context_new_param (ctxt, NULL, int_type, "argc");
>> >+  gcc_jit_type *char_ptr_ptr_type =
>> >+    gcc_jit_type_get_pointer (
>> >+      gcc_jit_type_get_pointer (
>> >+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_CHAR)));
>> >+  gcc_jit_param *param_argv =
>> >+    gcc_jit_context_new_param (ctxt, NULL, char_ptr_ptr_type, "argv");
>> >+  gcc_jit_param *params[2] = {param_argc, param_argv};
>> >+  gcc_jit_function *func_main =
>> >+    gcc_jit_context_new_function (ctxt, NULL,
>> >+                              GCC_JIT_FUNCTION_EXPORTED,
>> >+                              int_type,
>> >+                              "main",
>> >+                              2, params,
>> >+                              0);
>> >+  return func_main;
>> >+}
>> >+
>> >+#define MAX_OPEN_PARENS 16
>> >+
>> >+typedef struct bf_compiler
>> >+{
>> >+  const char *filename;
>> >+  int line;
>> >+  int column;
>> >+
>> >+  gcc_jit_context *ctxt;
>> >+
>> >+  gcc_jit_type *void_type;
>> >+  gcc_jit_type *int_type;
>> >+  gcc_jit_type *byte_type;
>> >+  gcc_jit_type *array_type;
>> >+
>> >+  gcc_jit_function *func_getchar;
>> >+  gcc_jit_function *func_putchar;
>> >+
>> >+  gcc_jit_function *func;
>> >+  gcc_jit_block *curblock;
>> >+
>> >+  gcc_jit_rvalue *int_zero;
>> >+  gcc_jit_rvalue *int_one;
>> >+  gcc_jit_rvalue *byte_zero;
>> >+  gcc_jit_rvalue *byte_one;
>> >+  gcc_jit_lvalue *data_cells;
>> >+  gcc_jit_lvalue *idx;
>> >+
>> >+  int num_open_parens;
>> >+  gcc_jit_block *paren_test[MAX_OPEN_PARENS];
>> >+  gcc_jit_block *paren_body[MAX_OPEN_PARENS];
>> >+  gcc_jit_block *paren_after[MAX_OPEN_PARENS];
>> >+
>> >+} bf_compiler;
>> >+
>> >+/* Bail out, with a message on stderr.  */
>> >+
>> >+static void
>> >+fatal_error (bf_compiler *bfc, const char *msg)
>> >+{
>> >+  fprintf (stderr,
>> >+       "%s:%i:%i: %s",
>> >+       bfc->filename, bfc->line, bfc->column, msg);
>> >+  abort ();
>> >+}
>> >+
>> >+/* Get "data_cells[idx]" as an lvalue.  */
>> >+
>> >+static gcc_jit_lvalue *
>> >+bf_get_current_data (bf_compiler *bfc, gcc_jit_location *loc)
>> >+{
>> >+  return gcc_jit_context_new_array_access (
>> >+    bfc->ctxt,
>> >+    loc,
>> >+    gcc_jit_lvalue_as_rvalue (bfc->data_cells),
>> >+    gcc_jit_lvalue_as_rvalue (bfc->idx));
>> >+}
>> >+
>> >+/* Get "data_cells[idx] == 0" as a boolean rvalue.  */
>> >+
>> >+static gcc_jit_rvalue *
>> >+bf_current_data_is_zero (bf_compiler *bfc, gcc_jit_location *loc)
>> >+{
>> >+  return gcc_jit_context_new_comparison (
>> >+    bfc->ctxt,
>> >+    loc,
>> >+    GCC_JIT_COMPARISON_EQ,
>> >+    gcc_jit_lvalue_as_rvalue (bf_get_current_data (bfc, loc)),
>> >+    bfc->byte_zero);
>> >+}
>> >+
>> >+/* Compile one bf character.  */
>> >+
>> >+static void
>> >+bf_compile_char (bf_compiler *bfc,
>> >+             unsigned char ch)
>> >+{
>> >+  gcc_jit_location *loc =
>> >+    gcc_jit_context_new_location (bfc->ctxt,
>> >+                              bfc->filename,
>> >+                              bfc->line,
>> >+                              bfc->column);
>> >+
>> >+  /* Turn this on to trace execution, by injecting putchar ()
>> >+     of each source char. */
>> >+  if (0)
>> >+    {
>> >+      gcc_jit_rvalue *arg =
>> >+    gcc_jit_context_new_rvalue_from_int (
>> >+                                         bfc->ctxt,
>> >+                                         bfc->int_type,
>> >+                                         ch);
>> >+      gcc_jit_rvalue *call =
>> >+    gcc_jit_context_new_call (bfc->ctxt,
>> >+                              loc,
>> >+                              bfc->func_putchar,
>> >+                              1, &arg);
>> >+      gcc_jit_block_add_eval (bfc->curblock,
>> >+                          loc,
>> >+                          call);
>> >+    }
>> >+
>> >+  switch (ch)
>> >+    {
>> >+      case '>':
>> >+    gcc_jit_block_add_comment (bfc->curblock,
>> >+                               loc,
>> >+                               "'>': idx += 1;");
>> >+    gcc_jit_block_add_assignment_op (bfc->curblock,
>> >+                                     loc,
>> >+                                     bfc->idx,
>> >+                                     GCC_JIT_BINARY_OP_PLUS,
>> >+                                     bfc->int_one);
>> >+    break;
>> >+
>> >+      case '<':
>> >+    gcc_jit_block_add_comment (bfc->curblock,
>> >+                               loc,
>> >+                               "'<': idx -= 1;");
>> >+    gcc_jit_block_add_assignment_op (bfc->curblock,
>> >+                                     loc,
>> >+                                     bfc->idx,
>> >+                                     GCC_JIT_BINARY_OP_MINUS,
>> >+                                     bfc->int_one);
>> >+    break;
>> >+
>> >+      case '+':
>> >+    gcc_jit_block_add_comment (bfc->curblock,
>> >+                               loc,
>> >+                               "'+': data[idx] += 1;");
>> >+    gcc_jit_block_add_assignment_op (bfc->curblock,
>> >+                                     loc,
>> >+                                     bf_get_current_data (bfc, loc),
>> >+                                     GCC_JIT_BINARY_OP_PLUS,
>> >+                                     bfc->byte_one);
>> >+    break;
>> >+
>> >+      case '-':
>> >+    gcc_jit_block_add_comment (bfc->curblock,
>> >+                               loc,
>> >+                               "'-': data[idx] -= 1;");
>> >+    gcc_jit_block_add_assignment_op (bfc->curblock,
>> >+                                     loc,
>> >+                                     bf_get_current_data (bfc, loc),
>> >+                                     GCC_JIT_BINARY_OP_MINUS,
>> >+                                     bfc->byte_one);
>> >+    break;
>> >+
>> >+      case '.':
>> >+    {
>> >+      gcc_jit_rvalue *arg =
>> >+        gcc_jit_context_new_cast (
>> >+          bfc->ctxt,
>> >+          loc,
>> >+          gcc_jit_lvalue_as_rvalue (bf_get_current_data (bfc, loc)),
>> >+          bfc->int_type);
>> >+      gcc_jit_rvalue *call =
>> >+        gcc_jit_context_new_call (bfc->ctxt,
>> >+                                  loc,
>> >+                                  bfc->func_putchar,
>> >+                                  1, &arg);
>> >+      gcc_jit_block_add_comment (bfc->curblock,
>> >+                                 loc,
>> >+                                 "'.': putchar ((int)data[idx]);");
>> >+      gcc_jit_block_add_eval (bfc->curblock,
>> >+                              loc,
>> >+                              call);
>> >+    }
>> >+    break;
>> >+
>> >+      case ',':
>> >+    {
>> >+      gcc_jit_rvalue *call =
>> >+        gcc_jit_context_new_call (bfc->ctxt,
>> >+                                  loc,
>> >+                                  bfc->func_getchar,
>> >+                                  0, NULL);
>> >+      gcc_jit_block_add_comment (
>> >+        bfc->curblock,
>> >+        loc,
>> >+        "',': data[idx] = (unsigned char)getchar ();");
>> >+      gcc_jit_block_add_assignment (bfc->curblock,
>> >+                                    loc,
>> >+                                    bf_get_current_data (bfc, loc),
>> >+                                    gcc_jit_context_new_cast (
>> >+                                      bfc->ctxt,
>> >+                                      loc,
>> >+                                      call,
>> >+                                      bfc->byte_type));
>> >+    }
>> >+    break;
>> >+
>> >+      case '[':
>> >+    {
>> >+      gcc_jit_block *loop_test =
>> >+        gcc_jit_function_new_block (bfc->func, NULL);
>> >+      gcc_jit_block *on_zero =
>> >+        gcc_jit_function_new_block (bfc->func, NULL);
>> >+      gcc_jit_block *on_non_zero =
>> >+        gcc_jit_function_new_block (bfc->func, NULL);
>> >+
>> >+      if (bfc->num_open_parens == MAX_OPEN_PARENS)
>> >+        fatal_error (bfc, "too many open parens");
>> >+
>> >+      gcc_jit_block_end_with_jump (
>> >+        bfc->curblock,
>> >+        loc,
>> >+        loop_test);
>> >+
>> >+      gcc_jit_block_add_comment (
>> >+        loop_test,
>> >+        loc,
>> >+        "'['");
>> >+      gcc_jit_block_end_with_conditional (
>> >+        loop_test,
>> >+        loc,
>> >+        bf_current_data_is_zero (bfc, loc),
>> >+        on_zero,
>> >+        on_non_zero);
>> >+      bfc->paren_test[bfc->num_open_parens] = loop_test;
>> >+      bfc->paren_body[bfc->num_open_parens] = on_non_zero;
>> >+      bfc->paren_after[bfc->num_open_parens] = on_zero;
>> >+      bfc->num_open_parens += 1;
>> >+      bfc->curblock = on_non_zero;
>> >+    }
>> >+    break;
>> >+
>> >+      case ']':
>> >+    {
>> >+      gcc_jit_block_add_comment (
>> >+        bfc->curblock,
>> >+        loc,
>> >+        "']'");
>> >+
>> >+      if (bfc->num_open_parens == 0)
>> >+        fatal_error (bfc, "mismatching parens");
>> >+      bfc->num_open_parens -= 1;
>> >+      gcc_jit_block_end_with_jump (
>> >+        bfc->curblock,
>> >+        loc,
>> >+        bfc->paren_test[bfc->num_open_parens]);
>> >+      bfc->curblock = bfc->paren_after[bfc->num_open_parens];
>> >+    }
>> >+    break;
>> >+
>> >+    case '\n':
>> >+      bfc->line +=1;
>> >+      bfc->column = 0;
>> >+      break;
>> >+    }
>> >+
>> >+  if (ch != '\n')
>> >+    bfc->column += 1;
>> >+}
>> >+
>> >+/* Compile the given .bf file into a gcc_jit_context, containing a
>> >+   single "main" function suitable for compiling into an executable.
>> >*/
>> >+
>> >+gcc_jit_context *
>> >+bf_compile (const char *filename)
>> >+{
>> >+  bf_compiler bfc;
>> >+  FILE *f_in;
>> >+  int ch;
>> >+
>> >+  memset (&bfc, 0, sizeof (bfc));
>> >+
>> >+  bfc.filename = filename;
>> >+  f_in = fopen (filename, "r");
>> >+  if (!f_in)
>> >+    fatal_error (&bfc, "unable to open file");
>> >+  bfc.line = 1;
>> >+
>> >+  bfc.ctxt = gcc_jit_context_acquire ();
>> >+
>> >+  gcc_jit_context_set_int_option (
>> >+    bfc.ctxt,
>> >+    GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL,
>> >+    3);
>> >+  gcc_jit_context_set_bool_option (
>> >+    bfc.ctxt,
>> >+    GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE,
>> >+    0);
>> >+  gcc_jit_context_set_bool_option (
>> >+    bfc.ctxt,
>> >+    GCC_JIT_BOOL_OPTION_DEBUGINFO,
>> >+    1);
>> >+  gcc_jit_context_set_bool_option (
>> >+    bfc.ctxt,
>> >+    GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING,
>> >+    0);
>> >+  gcc_jit_context_set_bool_option (
>> >+    bfc.ctxt,
>> >+    GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES,
>> >+    0);
>> >+
>> >+  bfc.void_type =
>> >+    gcc_jit_context_get_type (bfc.ctxt, GCC_JIT_TYPE_VOID);
>> >+  bfc.int_type =
>> >+    gcc_jit_context_get_type (bfc.ctxt, GCC_JIT_TYPE_INT);
>> >+  bfc.byte_type =
>> >+    gcc_jit_context_get_type (bfc.ctxt, GCC_JIT_TYPE_UNSIGNED_CHAR);
>> >+  bfc.array_type =
>> >+    gcc_jit_context_new_array_type (bfc.ctxt,
>> >+                                NULL,
>> >+                                bfc.byte_type,
>> >+                                30000);
>> >+
>> >+  bfc.func_getchar =
>> >+    gcc_jit_context_new_function (bfc.ctxt, NULL,
>> >+                              GCC_JIT_FUNCTION_IMPORTED,
>> >+                              bfc.int_type,
>> >+                              "getchar",
>> >+                              0, NULL,
>> >+                              0);
>> >+
>> >+  gcc_jit_param *param_c =
>> >+    gcc_jit_context_new_param (bfc.ctxt, NULL, bfc.int_type, "c");
>> >+  bfc.func_putchar =
>> >+    gcc_jit_context_new_function (bfc.ctxt, NULL,
>> >+                              GCC_JIT_FUNCTION_IMPORTED,
>> >+                              bfc.void_type,
>> >+                              "putchar",
>> >+                              1, &param_c,
>> >+                              0);
>> >+
>> >+  bfc.func = make_main (bfc.ctxt);
>> >+   bfc.curblock =
>> >+    gcc_jit_function_new_block (bfc.func, "initial");
>> >+  bfc.int_zero = gcc_jit_context_zero (bfc.ctxt, bfc.int_type);
>> >+  bfc.int_one = gcc_jit_context_one (bfc.ctxt, bfc.int_type);
>> >+  bfc.byte_zero = gcc_jit_context_zero (bfc.ctxt, bfc.byte_type);
>> >+  bfc.byte_one = gcc_jit_context_one (bfc.ctxt, bfc.byte_type);
>> >+
>> >+  bfc.data_cells =
>> >+    gcc_jit_context_new_global (bfc.ctxt, NULL,
>> >+                             GCC_JIT_GLOBAL_INTERNAL,
>> >+                             bfc.array_type,
>> >+                             "data_cells");
>> >+  bfc.idx =
>> >+    gcc_jit_function_new_local (bfc.func, NULL,
>> >+                            bfc.int_type,
>> >+                            "idx");
>> >+
>> >+  gcc_jit_block_add_comment (bfc.curblock,
>> >+                         NULL,
>> >+                         "idx = 0;");
>> >+  gcc_jit_block_add_assignment (bfc.curblock,
>> >+                            NULL,
>> >+                            bfc.idx,
>> >+                            bfc.int_zero);
>> >+
>> >+  bfc.num_open_parens = 0;
>> >+
>> >+  while ( EOF != (ch = fgetc (f_in)))
>> >+    bf_compile_char (&bfc, (unsigned char)ch);
>> >+
>> >+  gcc_jit_block_end_with_return (bfc.curblock, NULL, bfc.int_zero);
>> >+
>> >+  fclose (f_in);
>> >+
>> >+  return bfc.ctxt;
>> >+}
>> >+
>> >+/* Entrypoint to the compiler.  */
>> >+
>> >+int
>> >+main (int argc, char **argv)
>> >+{
>> >+  const char *input_file;
>> >+  const char *output_file;
>> >+  gcc_jit_context *ctxt;
>> >+  const char *err;
>> >+
>> >+  if (argc != 3)
>> >+    {
>> >+      fprintf (stderr, "%s: INPUT_FILE OUTPUT_FILE\n", argv[0]);
>> >+      return 1;
>> >+    }
>> >+
>> >+  input_file = argv[1];
>> >+  output_file = argv[2];
>> >+  ctxt = bf_compile (input_file);
>> >+
>> >+  gcc_jit_context_compile_to_file (ctxt,
>> >+                               GCC_JIT_OUTPUT_KIND_EXECUTABLE,
>> >+                               output_file);
>> >+
>> >+  err = gcc_jit_context_get_first_error (ctxt);
>> >+
>> >+  if (err)
>> >+    {
>> >+      gcc_jit_context_release (ctxt);
>> >+      return 1;
>> >+    }
>> >+
>> >+  gcc_jit_context_release (ctxt);
>> >+  return 0;
>> >+}
>> >+
>> >+/* Use the built compiler to compile the example to an executable:
>> >+
>> >+     { dg-jit-set-exe-params
>> >SRCDIR/gcc/jit/docs/examples/emit-alphabet.bf emit-alphabet.bf.exe }
>> >+
>> >+   Then run the executable, and verify that it emits the alphabet:
>> >+
>> >+     { dg-final { jit-run-executable emit-alphabet.bf.exe
>> >"ABCDEFGHIJKLMNOPQRSTUVWXYZ" } } */
>> >diff --git a/gcc/jit/docs/internals/test-hello-world.exe.log.txt
>> >b/gcc/jit/docs/internals/test-hello-world.exe.log.txt
>> >index 113dc35..205b6b4 100644
>> >--- a/gcc/jit/docs/internals/test-hello-world.exe.log.txt
>> >+++ b/gcc/jit/docs/internals/test-hello-world.exe.log.txt
>> >@@ -38,14 +38,20 @@ JIT: entering: gcc_jit_block_add_eval
>> > JIT: exiting: gcc_jit_block_add_eval
>> > JIT: entering: gcc_jit_block_end_with_void_return
>> > JIT: exiting: gcc_jit_block_end_with_void_return
>> >+JIT: entering: gcc_jit_context_dump_reproducer_to_file
>> >+JIT:  entering: void
>> >gcc::jit::recording::context::dump_reproducer_to_file(const char*)
>> >+JIT:  exiting: void
>> >gcc::jit::recording::context::dump_reproducer_to_file(const char*)
>> >+JIT: exiting: gcc_jit_context_dump_reproducer_to_file
>> > JIT: entering: gcc_jit_context_compile
>> >-JIT:  compiling ctxt: 0x1283e20
>> >+JIT:  in-memory compile of ctxt: 0x1283e20
>> >JIT:  entering: gcc::jit::result*
>> >gcc::jit::recording::context::compile()
>> > JIT:   entering: void gcc::jit::recording::context::validate()
>> > JIT:   exiting: void gcc::jit::recording::context::validate()
>> >JIT:   entering:
>> >gcc::jit::playback::context::context(gcc::jit::recording::context*)
>> >JIT:   exiting:
>> >gcc::jit::playback::context::context(gcc::jit::recording::context*)
>> >-JIT:   entering: gcc::jit::result*
>> >gcc::jit::playback::context::compile()
>> >+JIT:   entering:
>> >gcc::jit::playback::compile_to_memory::compile_to_memory(gcc::jit::recording::context*)
>> >+JIT:   exiting:
>> >gcc::jit::playback::compile_to_memory::compile_to_memory(gcc::jit::recording::context*)
>> >+JIT:   entering: void gcc::jit::playback::context::compile()
>> > JIT:    entering: gcc::jit::tempdir::tempdir(gcc::jit::logger*, int)
>> > JIT:    exiting: gcc::jit::tempdir::tempdir(gcc::jit::logger*, int)
>> > JIT:    entering: bool gcc::jit::tempdir::create()
>> >@@ -86,29 +92,37 @@ JIT:      entering: void
>> >gcc::jit::playback::function::postprocess()
>> > JIT:      exiting: void gcc::jit::playback::function::postprocess()
>> > JIT:     exiting: void gcc::jit::playback::context::replay()
>> > JIT:     entering: void jit_langhook_write_globals()
>> >+JIT:      entering: void
>> >gcc::jit::playback::context::write_global_decls_1()
>> >+JIT:      exiting: void
>> >gcc::jit::playback::context::write_global_decls_1()
>> >+JIT:      entering: void
>> >gcc::jit::playback::context::write_global_decls_2()
>> >+JIT:      exiting: void
>> >gcc::jit::playback::context::write_global_decls_2()
>> > JIT:     exiting: void jit_langhook_write_globals()
>> > JIT:    exiting: toplev::main
>> >JIT:    entering: void
>> >gcc::jit::playback::context::extract_any_requested_dumps(vec<gcc::jit::recording::requested_dump>*)
>> >JIT:    exiting: void
>> >gcc::jit::playback::context::extract_any_requested_dumps(vec<gcc::jit::recording::requested_dump>*)
>> > JIT:    entering: toplev::finalize
>> > JIT:    exiting: toplev::finalize
>> >-JIT:    entering: void
>> >gcc::jit::playback::context::convert_to_dso(const char*)
>> >-JIT:     argv[0]: x86_64-unknown-linux-gnu-gcc-5.0.0
>> >-JIT:     argv[1]: -shared
>> >-JIT:     argv[2]: /tmp/libgccjit-CKq1M9/fake.s
>> >-JIT:     argv[3]: -o
>> >-JIT:     argv[4]: /tmp/libgccjit-CKq1M9/fake.so
>> >-JIT:     argv[5]: -fno-use-linker-plugin
>> >-JIT:     argv[6]: (null)
>> >-JIT:    exiting: void
>> >gcc::jit::playback::context::convert_to_dso(const char*)
>> >-JIT:    entering: gcc::jit::result*
>> >gcc::jit::playback::context::dlopen_built_dso()
>> >-JIT:     GCC_JIT_BOOL_OPTION_DEBUGINFO was set: handing over tempdir
>> >to jit::result
>> >-JIT:     entering: gcc::jit::result::result(gcc::jit::logger*, void*,
>> >gcc::jit::tempdir*)
>> >-JIT:     exiting: gcc::jit::result::result(gcc::jit::logger*, void*,
>> >gcc::jit::tempdir*)
>> >-JIT:    exiting: gcc::jit::result*
>> >gcc::jit::playback::context::dlopen_built_dso()
>> >+JIT:    entering: virtual void
>> >gcc::jit::playback::compile_to_memory::postprocess(const char*)
>> >+JIT:     entering: void
>> >gcc::jit::playback::context::convert_to_dso(const char*)
>> >+JIT:      entering: void
>> >gcc::jit::playback::context::invoke_driver(const char*, const char*,
>> >const char*, timevar_id_t, bool, bool)
>> >+JIT:       argv[0]: x86_64-unknown-linux-gnu-gcc-5.0.0
>> >+JIT:       argv[1]: -shared
>> >+JIT:       argv[2]: /tmp/libgccjit-CKq1M9/fake.s
>> >+JIT:       argv[3]: -o
>> >+JIT:       argv[4]: /tmp/libgccjit-CKq1M9/fake.so
>> >+JIT:       argv[5]: -fno-use-linker-plugin
>> >+JIT:       argv[6]: (null)
>> >+JIT:      exiting: void
>> >gcc::jit::playback::context::invoke_driver(const char*, const char*,
>> >const char*, timevar_id_t, bool, bool)
>> >+JIT:     exiting: void
>> >gcc::jit::playback::context::convert_to_dso(const char*)
>> >+JIT:     entering: gcc::jit::result*
>> >gcc::jit::playback::context::dlopen_built_dso()
>> >+JIT:      GCC_JIT_BOOL_OPTION_DEBUGINFO was set: handing over tempdir
>> >to jit::result
>> >+JIT:      entering: gcc::jit::result::result(gcc::jit::logger*, void*,
>> >gcc::jit::tempdir*)
>> >+JIT:      exiting: gcc::jit::result::result(gcc::jit::logger*, void*,
>> >gcc::jit::tempdir*)
>> >+JIT:     exiting: gcc::jit::result*
>> >gcc::jit::playback::context::dlopen_built_dso()
>> >+JIT:    exiting: virtual void
>> >gcc::jit::playback::compile_to_memory::postprocess(const char*)
>> > JIT:    entering: void gcc::jit::playback::context::release_mutex()
>> > JIT:    exiting: void gcc::jit::playback::context::release_mutex()
>> >-JIT:   exiting: gcc::jit::result*
>> >gcc::jit::playback::context::compile()
>> >+JIT:   exiting: void gcc::jit::playback::context::compile()
>> > JIT:   entering: gcc::jit::playback::context::~context()
>> > JIT:   exiting: gcc::jit::playback::context::~context()
>> >JIT:  exiting: gcc::jit::result*
>> >gcc::jit::recording::context::compile()
>> >diff --git a/gcc/jit/docs/intro/index.rst
>> >b/gcc/jit/docs/intro/index.rst
>> >index d3bcec9..0f51777 100644
>> >--- a/gcc/jit/docs/intro/index.rst
>> >+++ b/gcc/jit/docs/intro/index.rst
>> >@@ -1,4 +1,4 @@
>> >-.. Copyright (C) 2014 Free Software Foundation, Inc.
>> >+.. Copyright (C) 2014-2015 Free Software Foundation, Inc.
>> >    Originally contributed by David Malcolm <dmalcolm@redhat.com>
>> >
>> >    This is free software: you can redistribute it and/or modify it
>> >@@ -25,3 +25,4 @@ Tutorial
>> >    tutorial02.rst
>> >    tutorial03.rst
>> >    tutorial04.rst
>> >+   tutorial05.rst
>> >diff --git a/gcc/jit/docs/intro/tutorial05.rst
>> >b/gcc/jit/docs/intro/tutorial05.rst
>> >new file mode 100644
>> >index 0000000..865a550
>> >--- /dev/null
>> >+++ b/gcc/jit/docs/intro/tutorial05.rst
>> >@@ -0,0 +1,253 @@
>> >+.. Copyright (C) 2015 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 5: Implementing an Ahead-of-Time compiler
>> >+-------------------------------------------------------
>> >+
>> >+If you have a pre-existing language frontend, it's possible to hook
>> >+it up to libgccjit as a backend.  In the previous example we showed
>> >+how to do that for in-memory JIT-compilation, but libgccjit can also
>> >+compile code directly to a file, allowing you to implement a more
>> >+traditional ahead-of-time compil
>>
>>
>

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2015-01-20  1:41 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-01-01  0:00 Stage 3 RFC: using "jit" for ahead-of-time compilation David Malcolm
2015-01-01  0:00 ` Richard Biener
2015-01-01  0:00   ` [PATCH] " David Malcolm
2015-01-01  0:00     ` Richard Biener
2015-01-01  0:00       ` David Malcolm
2015-01-01  0:00 ` Jakub Jelinek

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).