This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] libgccjit.so: an embeddable JIT-compiler based on GCC


This is very much a proof-of-concept/work-in-progress at this stage, but
attached is a patch to GCC which aims to provide an embeddable
JIT-compilation API, using GCC as the backend: libgccjit.so.

This shared library can then be dynamically-linked into bytecode
interpreters and other such programs that want to generate machine code
"on the fly" at run-time.

The idea is that GCC is configured with a special --enable-host-shared
option, which leads to it being built as position-independent code. You
would configure it with host==target, given that the generated machine
code will be executed within the same process (the whole point of JIT).

libgccjit.so is built against libbackend.a.  To the rest of GCC, it
looks like a "frontend" (in the "gcc/jit" subdir), but the parsing hook
just runs a callback provided by client code.  You can see a diagram of
how it all fits together within the patch (see gcc/jit/notes.txt).  The
jit "frontend" requires --enable-host-shared, so it is off by default,
so you need to configure with:
  --enable-host-shared --enable-languages=jit
to get the jit (and see caveats below).

The "main" function is in the client code.  It uses a pure C API to call
into libgccjit.so, registering a code creation hook:

  gcc_jit_context *ctxt;
  gcc_jit_result *result;

  ctxt = gcc_jit_context_acquire ();

  gcc_jit_context_set_code_factory (ctxt,
     some_code_making_callback, user_data);

  /* This actually calls into GCC and runs the build, all
     in a mutex for now, getting make a result object.  */
  result = gcc_jit_context_compile (ctxt);
    /* result is actually a wrapper around a DSO */  

  /* Now that we have result, we're done with ctxt: */
  gcc_git_context_release (ctxt);

  /* Look up a generated function by name, getting a void* back
     from the result object (pointing to the machine code), and
     cast it to the appropriate type for the function: */
  some_fn_type some_fn  = (some_fn_type)gcc_jit_result_get_code (result,
    "some_fn");

  /* We can now call the machine code: */       
  int val = some_fn (3, 4);

  /* Presumably we'd call it more than once.
     Once we're done with the code, this unloads the built DSO: */
  gcc_jit_result_release (result);

There are some major kludges in there, but it does work: it can
successfully build code in-process 1000 times in a row [1], albeit with
a slow memory leak, with all optimization turned off.   Upon turning on
optimizations I run into crashes owing to not properly purging all state
within the compiler - so this is a great motivation for doing more
state-cleanup work.  I've also hacked timevars to run in "cumulative"
mode, accumulating all timings across all iterations.

The library API hides GCC's internals, and tries to be much more
typesafe than GCC's, giving something rather like Andrew MacLeod's
proposed changes - client code does not see "tree", instead dealing with
types, rvalues, lvalues, jump labels, etc.  It is pure C, given the
horror stories I have heard about people dealing with C++ ABIs.  FWIW I
also have the beginnings of Python bindings for the library (doing the
interface as pure C makes language-bindings easier), though that would
probably live in a separate repository (so not part of this patch).

The API deliberately uses C terminology, given that it's likely that the
user will want to be plugging the JIT-generated code into a C/C++
program (or library).

I've been able to successfully use this API to add JIT-compilation to a
toy bytecode interpreter:
  https://github.com/davidmalcolm/jittest
(where regvm.cc uses this API to compile a bytecode function into
machine code).

There's a DejaGnu-based test suite, which I can invoke via:
  make check-parallel-jit RUNTESTFLAGS=""
(potentially with some -v verbosity options in RUNTESTFLAGS), giving
   # of expected passes		144
and no failures on this box.

Various caveats:
  * Currently it only supports a small subset of C-like code.
  * The API is still in flux: I'm not convinced by the label-placement
approach; I suspect having an explicit "block" type may be easier for
users to deal with.
  * The patch is against r202664, which is a little out-of-date
(2013-09-17), but I'm interested in feedback rather than perfection at
this stage.
  * I'm running into configure/Makefile issues with
--enable-host-shared, where CFLAGS contains -fPIC, but only on
invocations of leaf Makefiles, not on recursive "make" - so it works if
you cd into $builddir/gcc and make (and so on for libcpp etc), but not
from the top-level builddir.  Hence building the thing is currently
unreliable (but again, I'm interested in feedback rather than
perfection).  Help with configure/Makefiles would be appreciated!
  * There are some grotesque kludges in internal-api.c, especially in
how we go from .s assembler files to a DSO (grep for "gross hack" ;) )
  * There are some changes to the rest of GCC that are needed by the JIT
code.  Some of this is state removal.  Some of the changes are gross,
some are probably reasonable.
  * Only tested so far on Fedora and RHEL x86_64 boxes.

Hopefully this is of interest to other GCC people.

Shall I get this into a "jit" branch?  I greatly prefer git to svn, so
I'd probably do:
  http://gcc.gnu.org/wiki/GitMirror#Git-only_branches
assuming that this allows a sane path to (I hope) eventual merger.

Thoughts?
Dave

Current Changelog.jit follows inline:
/
	* configure.ac: Add --enable-host-shared
	* configure: Regenerate.

gcc/
	* Makefile.in (LIBIBERTY): Use pic build of libiberty.a if
	configured with --enable-host-shared.
	(BUILD_LIBIBERTY): Likewise.
	* cgraph.c (cgraph_c_finalize): New.
	* cgraph.h (symtab_c_finalize): New declaration.
	(cgraph_c_finalize): Likewise.
	(cgraphunit_c_finalize): Likewise.
	(cgraphbuild_c_finalize): Likewise.
	(ipa_c_finalize): Likewise.
	(predict_c_finalize): Likewise.
	(varpool_c_finalize): Likewise.
	* cgraphbuild.c (cgraphbuild_c_finalize): New.
	* cgraphunit.c (first_analyzed): Move from analyze_functions
	to file-scope.
	(first_analyzed_var): Likewise.
	(analyze_functions): Move static variables into file-scope.
	(cgraphunit_c_finalize): New.
	* configure.ac: Add --enable-host-shared, adding -fPIC.
	* configure: Regenerate.
	* dwarf2out.c (dwarf2out_c_finalize): New.
	* dwarf2out.h (dwarf2out_c_finalize): Declare.
	* ggc-page.c (init_ggc): Make idempotent.
	* ipa-pure-const.c (function_insertion_hook_holder): Move to be
	a field of class pass_ipa_pure_const.
	(node_duplication_hook_holder): Likewise.
	(node_removal_hook_holder): Likewise.
	(register_hooks): Convert to method...
	(pass_ipa_pure_const::register_hooks): ...here, converting
	static variable init_p into...
	(pass_ipa_pure_const::init_p): ...new field.
	(pure_const_generate_summary): Update invocation of
	register_hooks to invoke as a method of current_pass.
	(pure_const_read_summary): Likewise.
	(propagate): Convert to...
	(pass_ipa_pure_const::execute): ...method.
	* ipa.c (ipa_c_finalize): New.
	* main.c (main): Update usage of toplev_main.
	* params.c (global_init_params): Make idempotent.
	* passes.c (execute_ipa_summary_passes): Set current_pass.
	* predict.c (predict_c_finalize): New.
	* stringpool.c (init_stringpool): Clean up if we're called more
	than once.
	* symtab.c (symtab_c_finalize): New.
	* timevar.c (timevar_init): Ignore repeated calls.
	* timevar.def (TV_CLIENT_CALLBACK): Add.
	(TV_ASSEMBLE): Add.
	(TV_LINK): Add.
	(TV_LOAD): Add.
	* toplev.c (do_compile) Add parameter (const toplev_options *);
	use it to avoid starting/stopping/reporting timevar TV_TOTAL
	for the case where toplev_main does not emcompass all timevars.
	(toplev_main): Add parameter (const toplev_options *); pass it
	to do_compile.
	(toplev_finalize): New.
	* toplev.h (struct toplev_options): New.
	(toplev_main): Add parameter (const toplev_options *).
	(toplev_finalize): New.
	* varpool.c (varpool_c_finalize): New.

gcc/jit/
	* Make-lang.in: New.
	* TODO.rst: New.
	* config-lang.in: New.
	* dummy-frontend.c: New.
	* internal-api.c: New.
	* internal-api.h: New.
	* libgccjit.c: New.
	* libgccjit.h: New.
	* libgccjit.map: New.
	* notes.txt: New.

gcc/testsuite/
	* jit.dg: New subdirectory
	* jit.dg/harness.h: New.
	* jit.dg/jit.exp: New.
	* jit.dg/test-accessing-struct.c: New.
	* jit.dg/test-calling-external-function.c: New.
	* jit.dg/test-dot-product.c: New.
	* jit.dg/test-factorial.c: New.
	* jit.dg/test-failure.c: New.
	* jit.dg/test-fibonacci.c: New.
	* jit.dg/test-hello-world.c: New.
	* jit.dg/test-string-literal.c: New.
	* jit.dg/test-sum-of-squares.c: New.

libbacktrace/
	* configure.ac: Add --enable-host-shared.
	* configure: Regenerate.

libcpp/
	* configure.ac: Add --enable-host-shared.
	* configure: Regenerate.

libdecnumber/
	* configure.ac: Add --enable-host-shared.
	* configure: Regenerate.

libiberty/
	* configure.ac: If --enable-host-shared, use -fPIC.
	* configure: Regenerate.

zlib/
	* configure.ac: Add --enable-host-shared.
	* configure: Regenerate.

diff --git a/configure b/configure
index a91689f..3b399cd 100755
--- a/configure
+++ b/configure
@@ -556,6 +556,7 @@ enable_option_checking=no
 ac_subst_vars='LTLIBOBJS
 LIBOBJS
 compare_exclusions
+host_shared
 stage2_werror_flag
 stage1_checking
 stage1_cflags
@@ -787,6 +788,7 @@ with_build_time_tools
 enable_maintainer_mode
 enable_stage1_checking
 enable_werror
+enable_host_shared
 '
       ac_precious_vars='build_alias
 host_alias
@@ -1490,6 +1492,7 @@ Optional Features:
                           choose additional checking for stage1 of the
                           compiler
   --enable-werror         enable -Werror in bootstrap stage2 and later
+  --enable-host-shared    build host code as shared libraries
 
 Optional Packages:
   --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
@@ -14570,6 +14573,16 @@ case ${enable_werror} in
 esac
 
 
+# Enable --enable-host-shared.
+# Check whether --enable-host-shared was given.
+if test "${enable_host_shared+set}" = set; then :
+  enableval=$enable_host_shared; host_shared=$enableval
+else
+  host_shared=no
+fi
+
+
+
 # Specify what files to not compare during bootstrap.
 
 compare_exclusions="gcc/cc*-checksum\$(objext) | gcc/ada/*tools/*"
diff --git a/configure.ac b/configure.ac
index d72b40a..1bb7c0b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -3301,6 +3301,13 @@ case ${enable_werror} in
 esac
 AC_SUBST(stage2_werror_flag)
 
+# Enable --enable-host-shared.
+AC_ARG_ENABLE(host-shared,
+[AS_HELP_STRING([--enable-host-shared],
+		[build host code as shared libraries])],
+[host_shared=$enableval], [host_shared=no])
+AC_SUBST(host_shared)
+
 # Specify what files to not compare during bootstrap.
 
 compare_exclusions="gcc/cc*-checksum\$(objext) | gcc/ada/*tools/*"
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index a2e3f7a..afcd6e4 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -341,6 +341,8 @@ PLUGINLIBS = @pluginlibs@
 
 enable_plugin = @enable_plugin@
 
+enable_host_shared = @enable_host_shared@
+
 CPPLIB = ../libcpp/libcpp.a
 CPPINC = -I$(srcdir)/../libcpp/include
 
@@ -1022,8 +1024,15 @@ ALL_COMPILERFLAGS = $(ALL_CXXFLAGS)
 ALL_LINKERFLAGS = $(ALL_CXXFLAGS)
 
 # Build and host support libraries.
+
+# Use the "pic" build of libiberty if --enable-host-shared.
+ifeq ($(enable_host_shared),yes)
+LIBIBERTY = ../libiberty/pic/libiberty.a
+BUILD_LIBIBERTY = $(build_libobjdir)/libiberty/pic/libiberty.a
+else
 LIBIBERTY = ../libiberty/libiberty.a
 BUILD_LIBIBERTY = $(build_libobjdir)/libiberty/libiberty.a
+endif
 
 # Dependencies on the intl and portability libraries.
 LIBDEPS= libcommon.a $(CPPLIB) $(LIBIBERTY) $(LIBINTL_DEP) $(LIBICONV_DEP) \
diff --git a/gcc/cgraph.c b/gcc/cgraph.c
index c8e1b9c..5a94374 100644
--- a/gcc/cgraph.c
+++ b/gcc/cgraph.c
@@ -2996,4 +2996,30 @@ cgraph_get_body (struct cgraph_node *node)
   return true;
 }
 
+void cgraph_c_finalize (void)
+{
+  x_cgraph_nodes_queue = NULL;
+  cgraph_n_nodes = 0;
+  cgraph_max_uid = 0;
+  cgraph_edge_max_uid = 0;
+  cgraph_global_info_ready = false;
+  cgraph_state = CGRAPH_STATE_PARSING;
+  cgraph_function_flags_ready = false;
+
+  cgraph_new_nodes = 0;
+  asm_nodes = NULL;
+  symtab_order = 0;
+  cpp_implicit_aliases_done = false;
+
+  first_cgraph_edge_removal_hook = NULL;
+  first_cgraph_node_removal_hook = NULL;
+  first_cgraph_edge_duplicated_hook = NULL;
+  first_cgraph_node_duplicated_hook = NULL;
+  first_cgraph_function_insertion_hook = NULL;
+  free_nodes = NULL;
+  free_edges = NULL;
+  cgraph_fnver_htab = NULL;
+  version_info_node = NULL;
+}
+
 #include "gt-cgraph.h"
diff --git a/gcc/cgraph.h b/gcc/cgraph.h
index 50e8743..135e200 100644
--- a/gcc/cgraph.h
+++ b/gcc/cgraph.h
@@ -597,6 +597,7 @@ extern GTY(()) int symtab_order;
 extern bool cpp_implicit_aliases_done;
 
 /* In symtab.c  */
+void symtab_c_finalize (void);
 void symtab_register_node (symtab_node);
 void symtab_unregister_node (symtab_node);
 void symtab_remove_node (symtab_node);
@@ -630,6 +631,7 @@ enum availability symtab_node_availability (symtab_node);
 bool symtab_semantically_equivalent_p (symtab_node, symtab_node);
 
 /* In cgraph.c  */
+void cgraph_c_finalize (void);
 void dump_cgraph (FILE *);
 void debug_cgraph (void);
 void dump_cgraph_node (FILE *, struct cgraph_node *);
@@ -744,6 +746,7 @@ void cgraph_speculative_call_info (struct cgraph_edge *,
 				   struct ipa_ref *&);
 
 /* In cgraphunit.c  */
+void cgraphunit_c_finalize (void);
 struct asm_node *add_asm_node (tree);
 extern FILE *cgraph_dump_file;
 void cgraph_finalize_function (tree, bool);
@@ -794,6 +797,7 @@ void tree_function_versioning (tree, tree, vec<ipa_replace_map_p, va_gc> *,
 struct cgraph_edge *cgraph_resolve_speculation (struct cgraph_edge *, tree);
 
 /* In cgraphbuild.c  */
+void cgraphbuild_c_finalize (void);
 unsigned int rebuild_cgraph_edges (void);
 void cgraph_rebuild_references (void);
 int compute_call_stmt_bb_frequency (tree, basic_block bb);
@@ -801,6 +805,7 @@ void record_references_in_initializer (tree, bool);
 void ipa_record_stmt_references (struct cgraph_node *, gimple);
 
 /* In ipa.c  */
+void ipa_c_finalize (void);
 bool symtab_remove_unreachable_nodes (bool, FILE *);
 cgraph_node_set cgraph_node_set_new (void);
 cgraph_node_set_iterator cgraph_node_set_find (cgraph_node_set,
@@ -824,10 +829,12 @@ void ipa_discover_readonly_nonaddressable_vars (void);
 bool varpool_externally_visible_p (struct varpool_node *);
 
 /* In predict.c  */
+void predict_c_finalize (void);
 bool cgraph_maybe_hot_edge_p (struct cgraph_edge *e);
 bool cgraph_optimize_for_size_p (struct cgraph_node *);
 
 /* In varpool.c  */
+void varpool_c_finalize (void);
 struct varpool_node *varpool_create_empty_node (void);
 struct varpool_node *varpool_node_for_decl (tree);
 struct varpool_node *varpool_node_for_asm (tree asmname);
diff --git a/gcc/cgraphbuild.c b/gcc/cgraphbuild.c
index 98fd12c..392874f 100644
--- a/gcc/cgraphbuild.c
+++ b/gcc/cgraphbuild.c
@@ -592,3 +592,7 @@ make_pass_remove_cgraph_callee_edges (gcc::context *ctxt)
 {
   return new pass_remove_cgraph_callee_edges (ctxt);
 }
+
+void cgraphbuild_c_finalize (void)
+{
+}
diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c
index 1644ca9..0f9d98f 100644
--- a/gcc/cgraphunit.c
+++ b/gcc/cgraphunit.c
@@ -906,15 +906,15 @@ walk_polymorphic_call_targets (pointer_set_t *reachable_call_targets,
 
 /* Discover all functions and variables that are trivially needed, analyze
    them as well as all functions and variables referred by them  */
+static struct cgraph_node *first_analyzed;
+static struct varpool_node *first_analyzed_var;
 
 static void
 analyze_functions (void)
 {
   /* Keep track of already processed nodes when called multiple times for
      intermodule optimization.  */
-  static struct cgraph_node *first_analyzed;
   struct cgraph_node *first_handled = first_analyzed;
-  static struct varpool_node *first_analyzed_var;
   struct varpool_node *first_handled_var = first_analyzed_var;
   struct pointer_set_t *reachable_call_targets = pointer_set_create ();
 
@@ -2271,5 +2271,16 @@ finalize_compilation_unit (void)
   timevar_pop (TV_CGRAPH);
 }
 
+void cgraphunit_c_finalize (void)
+{
+  cgraph_new_nodes = NULL;
+  cgraph_dump_file = NULL;
+  asm_last_node = NULL;
+  vtable_entry_type =NULL;
+  first = (symtab_node)(void *)1;
+
+  first_analyzed = NULL;
+  first_analyzed_var = NULL;
+}
 
 #include "gt-cgraphunit.h"
diff --git a/gcc/configure b/gcc/configure
index c6bc3a6..996a8b2 100755
--- a/gcc/configure
+++ b/gcc/configure
@@ -600,6 +600,7 @@ ac_includes_default="\
 
 ac_subst_vars='LTLIBOBJS
 LIBOBJS
+enable_host_shared
 enable_plugin
 pluginlibs
 CLOOGINC
@@ -920,6 +921,7 @@ enable_maintainer_mode
 enable_link_mutex
 enable_version_specific_runtime_libs
 enable_plugin
+enable_host_shared
 enable_libquadmath_support
 with_linker_hash_style
 '
@@ -1635,6 +1637,7 @@ Optional Features:
                           specify that runtime libraries should be installed
                           in a compiler-specific directory
   --enable-plugin         enable plugin support
+  --enable-host-shared    build host code as shared libraries
   --disable-libquadmath-support
                           disable libquadmath support for Fortran
 
@@ -17894,7 +17897,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 17897 "configure"
+#line 17900 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -18000,7 +18003,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 18003 "configure"
+#line 18006 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -27695,6 +27698,17 @@ $as_echo "#define ENABLE_PLUGIN 1" >>confdefs.h
 fi
 
 
+# Enable --enable-host-shared, adding -fPIC
+# Check whether --enable-host-shared was given.
+if test "${enable_host_shared+set}" = set; then :
+  enableval=$enable_host_shared; CFLAGS="$CFLAGS -fPIC"
+ CXXFLAGS="$CXXFLAGS -fPIC"
+ LDFLAGS="$LDFLAGS -fPIC"
+fi
+
+
+
+
 # Check whether --enable-libquadmath-support was given.
 if test "${enable_libquadmath_support+set}" = set; then :
   enableval=$enable_libquadmath_support; ENABLE_LIBQUADMATH_SUPPORT=$enableval
diff --git a/gcc/configure.ac b/gcc/configure.ac
index 5d3e5ad..4eae976 100644
--- a/gcc/configure.ac
+++ b/gcc/configure.ac
@@ -5393,6 +5393,16 @@ if test x"$enable_plugin" = x"yes"; then
 fi
 
 
+# Enable --enable-host-shared, adding -fPIC
+AC_ARG_ENABLE(host-shared,
+[AS_HELP_STRING([--enable-host-shared],
+		[build host code as shared libraries])],
+[CFLAGS="$CFLAGS -fPIC"
+ CXXFLAGS="$CXXFLAGS -fPIC"
+ LDFLAGS="$LDFLAGS -fPIC"], [])
+AC_SUBST(enable_host_shared)
+
+
 AC_ARG_ENABLE(libquadmath-support,
 [AS_HELP_STRING([--disable-libquadmath-support],
   [disable libquadmath support for Fortran])],
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 95049e4..3b6bc5b 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -24137,4 +24137,87 @@ dwarf2out_finish (const char *filename)
     output_indirect_strings ();
 }
 
+void dwarf2out_c_finalize (void)
+{
+  last_var_location_insn = NULL;
+  cached_next_real_insn = NULL;
+  used_rtx_array = NULL;
+  incomplete_types = NULL;
+  decl_scope_table = NULL;
+  debug_info_section = NULL;
+  debug_skeleton_info_section = NULL;
+  debug_abbrev_section = NULL;
+  debug_skeleton_abbrev_section = NULL;
+  debug_aranges_section = NULL;
+  debug_addr_section = NULL;
+  debug_macinfo_section = NULL;
+  debug_line_section = NULL;
+  debug_skeleton_line_section = NULL;
+  debug_loc_section = NULL;
+  debug_pubnames_section = NULL;
+  debug_pubtypes_section = NULL;
+  debug_str_section = NULL;
+  debug_str_dwo_section = NULL;
+  debug_str_offsets_section = NULL;
+  debug_ranges_section = NULL;
+  debug_frame_section = NULL;
+  fde_vec = NULL;
+  debug_str_hash = NULL;
+  skeleton_debug_str_hash = NULL;
+  dw2_string_counter = 0;
+  have_multiple_function_sections = false;
+  text_section_used = false;
+  cold_text_section_used = false;
+  cold_text_section = NULL;
+  current_unit_personality = NULL;
+
+  deferred_locations_list = NULL;
+
+  next_die_offset = 0;
+  single_comp_unit_die = NULL;
+  comdat_type_list = NULL;
+  limbo_die_list = NULL;
+  deferred_asm_name = NULL;
+  file_table = NULL;
+  decl_die_table = NULL;
+  common_block_die_table = NULL;
+  decl_loc_table = NULL;
+  call_arg_locations = NULL;
+  call_arg_loc_last = NULL;
+  call_site_count = -1;
+  tail_call_site_count = -1;
+  //block_map = NULL;
+  cached_dw_loc_list_table = NULL;
+  abbrev_die_table = NULL;
+  abbrev_die_table_allocated = 0;
+  abbrev_die_table_in_use = 0;
+  line_info_label_num = 0;
+  cur_line_info_table = NULL;
+  text_section_line_info = NULL;
+  cold_text_section_line_info = NULL;
+  separate_line_info = NULL;
+  info_section_emitted = false;
+  pubname_table = NULL;
+  pubtype_table = NULL;
+  macinfo_table = NULL;
+  ranges_table = NULL;
+  ranges_table_allocated = 0;
+  ranges_table_in_use = 0;
+  ranges_by_label = 0;
+  ranges_by_label_allocated = 0;
+  ranges_by_label_in_use = 0;
+  have_location_lists = false;
+  loclabel_num = 0;
+  poc_label_num = 0;
+  current_function_has_inlines = 0;
+  last_emitted_file = NULL;
+  label_num = 0;
+  file_table_last_lookup = NULL;
+  tmpl_value_parm_die_table = NULL;
+  generic_type_instances = NULL;
+  frame_pointer_fb_offset = 0;
+  frame_pointer_fb_offset_valid = false;
+  //base_types = NULL;
+}
+
 #include "gt-dwarf2out.h"
diff --git a/gcc/dwarf2out.h b/gcc/dwarf2out.h
index ad03a34..1f39101 100644
--- a/gcc/dwarf2out.h
+++ b/gcc/dwarf2out.h
@@ -280,4 +280,6 @@ struct array_descr_info
     } dimen[10];
 };
 
+void dwarf2out_c_finalize (void);
+
 #endif /* GCC_DWARF2OUT_H */
diff --git a/gcc/ggc-page.c b/gcc/ggc-page.c
index 487a6d4..dda3f32 100644
--- a/gcc/ggc-page.c
+++ b/gcc/ggc-page.c
@@ -1642,8 +1642,13 @@ compute_inverse (unsigned order)
 void
 init_ggc (void)
 {
+  static bool init_p = false;
   unsigned order;
 
+  if (init_p)
+    return;
+  init_p = true;
+
   G.pagesize = getpagesize();
   G.lg_pagesize = exact_log2 (G.pagesize);
 
diff --git a/gcc/ipa-pure-const.c b/gcc/ipa-pure-const.c
index 55b679d..2a3a306 100644
--- a/gcc/ipa-pure-const.c
+++ b/gcc/ipa-pure-const.c
@@ -108,10 +108,47 @@ typedef struct funct_state_d * funct_state;
 
 static vec<funct_state> funct_state_vec;
 
-/* Holders of ipa cgraph hooks: */
-static struct cgraph_node_hook_list *function_insertion_hook_holder;
-static struct cgraph_2node_hook_list *node_duplication_hook_holder;
-static struct cgraph_node_hook_list *node_removal_hook_holder;
+static bool gate_pure_const (void);
+
+namespace {
+
+const pass_data pass_data_ipa_pure_const =
+{
+  IPA_PASS, /* type */
+  "pure-const", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  true, /* has_gate */
+  true, /* has_execute */
+  TV_IPA_PURE_CONST, /* tv_id */
+  0, /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  0, /* todo_flags_finish */
+};
+
+class pass_ipa_pure_const : public ipa_opt_pass_d
+{
+public:
+  pass_ipa_pure_const(gcc::context *ctxt);
+
+  /* opt_pass methods: */
+  bool gate () { return gate_pure_const (); }
+  unsigned int execute ();
+
+  void register_hooks (void);
+
+private:
+  bool init_p;
+
+  /* Holders of ipa cgraph hooks: */
+  struct cgraph_node_hook_list *function_insertion_hook_holder;
+  struct cgraph_2node_hook_list *node_duplication_hook_holder;
+  struct cgraph_node_hook_list *node_removal_hook_holder;
+
+}; // class pass_ipa_pure_const
+
+} // anon namespace
 
 /* Try to guess if function body will always be visible to compiler
    when compiling the call and whether compiler will be able
@@ -884,11 +921,10 @@ remove_node_data (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED)
 }
 
 
-static void
+void
+pass_ipa_pure_const::
 register_hooks (void)
 {
-  static bool init_p = false;
-
   if (init_p)
     return;
 
@@ -911,7 +947,8 @@ pure_const_generate_summary (void)
 {
   struct cgraph_node *node;
 
-  register_hooks ();
+  pass_ipa_pure_const *pass = static_cast <pass_ipa_pure_const *> (current_pass);
+  pass->register_hooks ();
 
   /* There are some shared nodes, in particular the initializers on
      static declarations.  We do not need to scan them more than once
@@ -1001,7 +1038,9 @@ pure_const_read_summary (void)
   struct lto_file_decl_data *file_data;
   unsigned int j = 0;
 
-  register_hooks ();
+  pass_ipa_pure_const *pass = static_cast <pass_ipa_pure_const *> (current_pass);
+  pass->register_hooks ();
+
   while ((file_data = file_data_vec[j++]))
     {
       const char *data;
@@ -1469,8 +1508,9 @@ propagate_nothrow (void)
 /* Produce the global information by preforming a transitive closure
    on the local information that was produced by generate_summary.  */
 
-static unsigned int
-propagate (void)
+unsigned int
+pass_ipa_pure_const::
+execute ()
 {
   struct cgraph_node *node;
 
@@ -1500,27 +1540,7 @@ gate_pure_const (void)
 	  && !seen_error ());
 }
 
-namespace {
-
-const pass_data pass_data_ipa_pure_const =
-{
-  IPA_PASS, /* type */
-  "pure-const", /* name */
-  OPTGROUP_NONE, /* optinfo_flags */
-  true, /* has_gate */
-  true, /* has_execute */
-  TV_IPA_PURE_CONST, /* tv_id */
-  0, /* properties_required */
-  0, /* properties_provided */
-  0, /* properties_destroyed */
-  0, /* todo_flags_start */
-  0, /* todo_flags_finish */
-};
-
-class pass_ipa_pure_const : public ipa_opt_pass_d
-{
-public:
-  pass_ipa_pure_const(gcc::context *ctxt)
+pass_ipa_pure_const::pass_ipa_pure_const(gcc::context *ctxt)
     : ipa_opt_pass_d(pass_data_ipa_pure_const, ctxt,
 		     pure_const_generate_summary, /* generate_summary */
 		     pure_const_write_summary, /* write_summary */
@@ -1530,16 +1550,13 @@ public:
 		     NULL, /* stmt_fixup */
 		     0, /* function_transform_todo_flags_start */
 		     NULL, /* function_transform */
-		     NULL) /* variable_transform */
-  {}
-
-  /* opt_pass methods: */
-  bool gate () { return gate_pure_const (); }
-  unsigned int execute () { return propagate (); }
-
-}; // class pass_ipa_pure_const
-
-} // anon namespace
+		     NULL), /* variable_transform */
+  init_p(false),
+  function_insertion_hook_holder(NULL),
+  node_duplication_hook_holder(NULL),
+  node_removal_hook_holder(NULL)
+{
+}
 
 ipa_opt_pass_d *
 make_pass_ipa_pure_const (gcc::context *ctxt)
diff --git a/gcc/ipa.c b/gcc/ipa.c
index 67b3bc0..14d0c60 100644
--- a/gcc/ipa.c
+++ b/gcc/ipa.c
@@ -1585,3 +1585,7 @@ make_pass_ipa_cdtor_merge (gcc::context *ctxt)
 {
   return new pass_ipa_cdtor_merge (ctxt);
 }
+
+void ipa_c_finalize (void)
+{
+}
diff --git a/gcc/jit/ChangeLog b/gcc/jit/ChangeLog
new file mode 100644
index 0000000..5f87293
--- /dev/null
+++ b/gcc/jit/ChangeLog
@@ -0,0 +1,9 @@
+2013-07-26  David Malcolm  <dmalcolm@redhat.com>
+
+	* Initial creation
+
+Copyright (C) 2013 Free Software Foundation, Inc.
+
+Copying and distribution of this file, with or without modification,
+are permitted in any medium without royalty provided the copyright
+notice and this notice are preserved.
diff --git a/gcc/jit/Make-lang.in b/gcc/jit/Make-lang.in
new file mode 100644
index 0000000..8ad66f3
--- /dev/null
+++ b/gcc/jit/Make-lang.in
@@ -0,0 +1,143 @@
+# Top level -*- makefile -*- fragment for libgccjit.so.
+#   Copyright (C) 2013 Free Software Foundation, Inc.
+
+#This file is part of GCC.
+
+#GCC is free software; you can redistribute it and/or modify
+#it under the terms of the GNU General Public License as published by
+#the Free Software Foundation; either version 3, or (at your option)
+#any later version.
+
+#GCC is distributed in the hope that it will be useful,
+#but WITHOUT ANY WARRANTY; without even the implied warranty of
+#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+# This file provides the language dependent support in the main Makefile.
+# Each language makefile fragment must provide the following targets:
+#
+# foo.all.cross, foo.start.encap, foo.rest.encap,
+# foo.install-common, foo.install-man, foo.install-info, foo.install-pdf,
+# foo.install-html, foo.info, foo.dvi, foo.pdf, foo.html, foo.uninstall,
+# foo.mostlyclean, foo.clean, foo.distclean,
+# foo.maintainer-clean, foo.stage1, foo.stage2, foo.stage3, foo.stage4
+#
+# where `foo' is the name of the language.
+#
+# It should also provide rules for:
+#
+# - making any compiler driver (eg: g++)
+# - the compiler proper (eg: cc1plus)
+# - define the names for selecting the language in LANGUAGES.
+
+#
+# Define the names for selecting jit in LANGUAGES.
+# Note that it would be nice to move the dependency on g++
+# into the jit rule, but that needs a little bit of work
+# to do the right thing within all.cross.
+
+jit: libgccjit.so
+
+# Tell GNU make to ignore these if they exist.
+.PHONY: jit
+
+JIT_OBJS = attribs.o jit/dummy-frontend.o jit/libgccjit.o jit/internal-api.o
+
+# Use strict warnings for this front end.
+jit-warn = $(STRICT_WARN)
+
+# We avoid using $(BACKEND) from Makefile.in in order to avoid pulling
+# in main.o
+libgccjit.so: $(JIT_OBJS) \
+	libbackend.a libcommon-target.a libcommon.a \
+	$(CPPLIB) $(LIBDECNUMBER) \
+	$(LIBDEPS) $(srcdir)/jit/libgccjit.map
+	+$(LLINKER) $(ALL_LINKERFLAGS) $(LDFLAGS) -o $@ -shared \
+	     $(JIT_OBJS) libbackend.a libcommon-target.a libcommon.a \
+	     $(CPPLIB) $(LIBDECNUMBER) $(LIBS) $(BACKENDLIBS) \
+	     -Wl,--version-script=$(srcdir)/jit/libgccjit.map
+
+#
+# Build hooks:
+
+jit.all.cross:
+jit.start.encap:
+jit.rest.encap:
+jit.info:
+jit.install-info:
+jit.dvi:
+jit.pdf:
+jit.install-pdf:
+jit.install-html:
+jit.html:
+jit.srcinfo:
+jit.srcextra:
+
+jit.tags:
+
+jit.man:
+
+jit.srcman:
+
+#
+# Install hooks:
+jit.install-common:
+
+jit.install-man:
+
+jit.install-plugin:
+
+jit.uninstall:
+
+#
+# Clean hooks:
+# A lot of the ancillary files are deleted by the main makefile.
+# We just have to delete files specific to us.
+
+jit.mostlyclean:
+
+jit.clean:
+
+jit.distclean:
+
+jit.maintainer-clean:
+
+#
+# Stage hooks:
+# The main makefile has already created stage?/jit.
+
+jit.stage1: stage1-start
+	-mv jit/*$(objext) stage1/jit
+jit.stage2: stage2-start
+	-mv jit/*$(objext) stage2/jit
+jit.stage3: stage3-start
+	-mv jit/*$(objext) stage3/jit
+jit.stage4: stage4-start
+	-mv jit/*$(objext) stage4/jit
+jit.stageprofile: stageprofile-start
+	-mv jit/*$(objext) stageprofile/jit
+jit.stagefeedback: stagefeedback-start
+	-mv jit/*$(objext) stagefeedback/jit
+
+#
+# .o: .h dependencies.
+JIT_INTERNAL_API_H = jit/libgccjit.h $(TREE_H) $(TREE_ITERATOR_H) jit/internal-api.h
+
+jit/dummy-frontend.o: jit/dummy-frontend.c $(CONFIG_H) $(SYSTEM_H) \
+		$(CORETYPES_H) $(OPTS_H) $(TREE_H) $(DEBUG_H) langhooks.h \
+		$(LANGHOOKS_DEF_H) $(CGRAPH_H) \
+		$(TREE_ITERATOR_H) $(GIMPLE_H) $(GIMPLE_PRETTY_PRINT_h) \
+		gt-jit-dummy-frontend.h gtype-jit.h $(JIT_INTERNAL_API_H)
+
+jit/libgccjit.o: jit/libgccjit.c $(CONFIG_H) $(SYSTEM_H) \
+		$(CORETYPES_H) $(OPTS_H) jit/libgccjit.h $(JIT_INTERNAL_API_H) \
+
+jit/internal-api.o: jit/internal-api.c $(CONFIG_H) $(SYSTEM_H) \
+		$(CORETYPES_H) $(OPTS_H) $(TREE_H) $(DEBUG_H) \
+		langhooks.h langhooks-def.h $(CGRAPH_H) $(TOPLEV_H) \
+		$(TREE_ITERATOR_H) $(GIMPLE_H) $(GIMPLE_PRETTY_PRINT_H) \
+		 $(JIT_INTERNAL_API_H)
diff --git a/gcc/jit/TODO.rst b/gcc/jit/TODO.rst
new file mode 100644
index 0000000..65d4dc8
--- /dev/null
+++ b/gcc/jit/TODO.rst
@@ -0,0 +1,35 @@
+TODOs:
+
+* gcc_jit_context_new_local should take a function, not the context (is
+  it building a global?)
+
+* error-handling:
+    * have a client-provided error-handling callback for the context, and
+      call it, rather than asserting/crashing etc, to make the API resilient and helpful
+
+* more language features:
+
+  * more types:
+    * unions
+    * function ptrs
+
+* demo of JIT-compilation of a bytecode interpreter:
+    https://github.com/davidmalcolm/jittest
+  (move this into tree, as an example)
+
+* wiring up testing into a DejaGNU testsuite, rather than testing it
+  by hand.
+
+* docs
+
+* fixing all the state issues
+
+* make the dirty dirty hacks less egregious...
+
+* try porting llvmpipe to gcc
+
+* source locations: line-numbering etc
+
+* pkgconfig .pc file
+
+etc etc
diff --git a/gcc/jit/config-lang.in b/gcc/jit/config-lang.in
new file mode 100644
index 0000000..a804c62
--- /dev/null
+++ b/gcc/jit/config-lang.in
@@ -0,0 +1,38 @@
+# Top level configure fragment for libgccjit.so.
+#   Copyright (C) 2013 Free Software Foundation, Inc.
+
+#This file is part of GCC.
+
+#GCC is free software; you can redistribute it and/or modify
+#it under the terms of the GNU General Public License as published by
+#the Free Software Foundation; either version 3, or (at your option)
+#any later version.
+
+#GCC is distributed in the hope that it will be useful,
+#but WITHOUT ANY WARRANTY; without even the implied warranty of
+#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+# Configure looks for the existence of this file to auto-config each language.
+# We define several parameters used by configure:
+#
+# language	- name of language as it would appear in $(LANGUAGES)
+# compilers	- value to add to $(COMPILERS)
+
+language="jit"
+
+compilers="libgccjit.so"
+
+target_libs=""
+
+gtfiles="\$(srcdir)/jit/dummy-frontend.c"
+
+# The configuration requires --enable-host-shared
+# for jit to be supported.
+# Hence to get the jit, one must configure with:
+#   --enable-host-shared --enable-languages=jit
+build_by_default="no"
diff --git a/gcc/jit/dummy-frontend.c b/gcc/jit/dummy-frontend.c
new file mode 100644
index 0000000..b5a561d
--- /dev/null
+++ b/gcc/jit/dummy-frontend.c
@@ -0,0 +1,238 @@
+/* jit.c -- Dummy "frontend" for use during JIT-compilation.
+   Copyright (C) 2013 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "ansidecl.h"
+#include "coretypes.h"
+#include "opts.h"
+#include "tree.h"
+#include "debug.h"
+#include "langhooks.h"
+#include "langhooks-def.h"
+#include "cgraph.h"
+
+#include "tree-iterator.h"
+#include "gimple.h"
+#include "gimple-pretty-print.h"
+#include "internal-api.h"
+
+#include <mpfr.h>
+
+/* Language-dependent contents of a type.  */
+
+struct GTY(()) lang_type
+{
+  char dummy;
+};
+
+/* Language-dependent contents of a decl.  */
+
+struct GTY((variable_size)) lang_decl
+{
+  char dummy;
+};
+
+/* Language-dependent contents of an identifier.  This must include a
+   tree_identifier.  */
+
+struct GTY(()) lang_identifier
+{
+  struct tree_identifier common;
+};
+
+/* The resulting tree type.  */
+
+union GTY((desc ("TREE_CODE (&%h.generic) == IDENTIFIER_NODE"),
+	   chain_next ("CODE_CONTAINS_STRUCT (TREE_CODE (&%h.generic), TS_COMMON) ? ((union lang_tree_node *) TREE_CHAIN (&%h.generic)) : NULL")))
+lang_tree_node
+{
+  union tree_node GTY((tag ("0"),
+		       desc ("tree_node_structure (&%h)"))) generic;
+  struct lang_identifier GTY((tag ("1"))) identifier;
+};
+
+/* We don't use language_function.  */
+
+struct GTY(()) language_function
+{
+  int dummy;
+};
+
+void my_walker (void *)
+{
+  if (gcc::jit::active_jit_ctxt)
+    gcc::jit::active_jit_ctxt->gt_ggc_mx ();
+}
+
+const char *dummy;
+
+struct ggc_root_tab my_root_tab[] =
+  {
+    {
+      &dummy, 1, 0, my_walker, NULL
+    },
+    LAST_GGC_ROOT_TAB
+  };
+
+/* Language hooks.  */
+
+static bool
+jit_langhook_init (void)
+{
+  // eventually this can be a GTY object, and can thus mark
+  // our state without dealing with gengtype...
+  //g->frontend_ = new frontend ();
+  static bool registered_root_tab = false;
+  if (!registered_root_tab)
+    {
+      ggc_register_root_tab (my_root_tab);
+      registered_root_tab = true;
+    }
+
+  build_common_tree_nodes (false, false);
+
+  /* I don't know why this has to be done explicitly.  */
+  void_list_node = build_tree_list (NULL_TREE, void_type_node);
+
+  build_common_builtin_nodes ();
+
+  /* The default precision for floating point numbers.  This is used
+     for floating point constants with abstract type.  This may
+     eventually be controllable by a command line option.  */
+  mpfr_set_default_prec (256);
+
+  return true;
+}
+
+static void
+jit_langhook_parse_file (void)
+{
+  /* Run the IR-creation code provided by the client.  */
+  gcc_assert (gcc::jit::active_jit_ctxt);
+  gcc::jit::active_jit_ctxt->invoke_code_factory ();
+}
+
+static tree
+jit_langhook_type_for_mode (enum machine_mode mode, int unsignedp)
+{
+  if (mode == TYPE_MODE (float_type_node))
+    return float_type_node;
+
+  if (mode == TYPE_MODE (double_type_node))
+    return double_type_node;
+
+  if (mode == TYPE_MODE (integer_type_node))
+    return unsignedp ? unsigned_type_node : integer_type_node;
+
+  if (mode == TYPE_MODE (long_integer_type_node))
+    return unsignedp ? long_unsigned_type_node : long_integer_type_node;
+
+  if (COMPLEX_MODE_P (mode))
+    {
+      if (mode == TYPE_MODE (complex_float_type_node))
+	return complex_float_type_node;
+      if (mode == TYPE_MODE (complex_double_type_node))
+	return complex_double_type_node;
+      if (mode == TYPE_MODE (complex_long_double_type_node))
+	return complex_long_double_type_node;
+      if (mode == TYPE_MODE (complex_integer_type_node) && !unsignedp)
+	return complex_integer_type_node;
+    }
+
+  /* gcc_unreachable */
+  return NULL;
+}
+
+static tree
+jit_langhook_type_for_size (unsigned int bits ATTRIBUTE_UNUSED,
+			    int unsignedp ATTRIBUTE_UNUSED)
+{
+  gcc_unreachable ();
+  return NULL;
+}
+
+/* Record a builtin function.  We just ignore builtin functions.  */
+
+static tree
+jit_langhook_builtin_function (tree decl)
+{
+  return decl;
+}
+
+static bool
+jit_langhook_global_bindings_p (void)
+{
+  gcc_unreachable ();
+  return true;
+}
+
+static tree
+jit_langhook_pushdecl (tree decl ATTRIBUTE_UNUSED)
+{
+  gcc_unreachable ();
+}
+
+static tree
+jit_langhook_getdecls (void)
+{
+  return NULL;
+}
+
+static void
+jit_langhook_write_globals (void)
+{
+  /* This is the hook that runs the middle and backends: */
+  finalize_compilation_unit ();
+}
+
+#undef LANG_HOOKS_NAME
+#define LANG_HOOKS_NAME		"libgccjit"
+
+#undef LANG_HOOKS_INIT
+#define LANG_HOOKS_INIT		jit_langhook_init
+
+#undef LANG_HOOKS_PARSE_FILE
+#define LANG_HOOKS_PARSE_FILE		jit_langhook_parse_file
+
+#undef LANG_HOOKS_TYPE_FOR_MODE
+#define LANG_HOOKS_TYPE_FOR_MODE	jit_langhook_type_for_mode
+
+#undef LANG_HOOKS_TYPE_FOR_SIZE
+#define LANG_HOOKS_TYPE_FOR_SIZE	jit_langhook_type_for_size
+
+#undef LANG_HOOKS_BUILTIN_FUNCTION
+#define LANG_HOOKS_BUILTIN_FUNCTION	jit_langhook_builtin_function
+
+#undef LANG_HOOKS_GLOBAL_BINDINGS_P
+#define LANG_HOOKS_GLOBAL_BINDINGS_P	jit_langhook_global_bindings_p
+
+#undef LANG_HOOKS_PUSHDECL
+#define LANG_HOOKS_PUSHDECL		jit_langhook_pushdecl
+
+#undef LANG_HOOKS_GETDECLS
+#define LANG_HOOKS_GETDECLS		jit_langhook_getdecls
+
+#undef LANG_HOOKS_WRITE_GLOBALS
+#define LANG_HOOKS_WRITE_GLOBALS	jit_langhook_write_globals
+
+struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER;
+
+#include "gt-jit-dummy-frontend.h"
+#include "gtype-jit.h"
diff --git a/gcc/jit/internal-api.c b/gcc/jit/internal-api.c
new file mode 100644
index 0000000..3943d05
--- /dev/null
+++ b/gcc/jit/internal-api.c
@@ -0,0 +1,1004 @@
+#include "config.h"
+#include "system.h"
+#include "ansidecl.h"
+#include "coretypes.h"
+#include "opts.h"
+#include "tree.h"
+#include "debug.h"
+#include "langhooks.h"
+#include "langhooks-def.h"
+#include "cgraph.h"
+#include "toplev.h"
+#include "tree-iterator.h"
+#include "gimple.h"
+#include "gimple-pretty-print.h"
+#include "timevar.h"
+
+#include <pthread.h>
+
+#include "internal-api.h"
+
+void
+gcc::jit::context::
+gt_ggc_mx ()
+{
+  int i;
+  function *func;
+  FOR_EACH_VEC_ELT (m_functions, i, func)
+    {
+      if (ggc_test_and_set_mark (func))
+	func->gt_ggc_mx ();
+    }
+}
+
+void
+gcc::jit::context::
+set_code_factory (gcc_jit_code_callback cb,
+		  void *user_data)
+{
+  m_code_factory = cb;
+  m_user_data = user_data;
+}
+
+gcc::jit::type *
+gcc::jit::context::
+get_void_type ()
+{
+  return new type (void_type_node);
+}
+
+gcc::jit::type *
+gcc::jit::context::
+get_char_type ()
+{
+  return new type (char_type_node);
+}
+
+gcc::jit::type *
+gcc::jit::context::
+get_int_type ()
+{
+  return new type (intSI_type_node);
+}
+
+gcc::jit::type *
+gcc::jit::context::
+get_float_type ()
+{
+  return new type (float_type_node);
+}
+
+gcc::jit::type *
+gcc::jit::context::
+get_double_type ()
+{
+  return new type (double_type_node);
+}
+
+gcc::jit::field *
+gcc::jit::context::
+new_field (gcc::jit::location *loc,
+	   gcc::jit::type *type,
+	   const char *name)
+{
+  gcc_assert (NULL == loc);
+  gcc_assert (type);
+  gcc_assert (name);
+
+  /* compare with c/c-decl.c:grokfield and grokdeclarator.  */
+  tree decl = build_decl (UNKNOWN_LOCATION, FIELD_DECL,
+			  get_identifier (name), type->as_tree ());
+
+  return new field (decl);
+}
+
+gcc::jit::type *
+gcc::jit::context::
+new_struct_type (gcc::jit::location *loc,
+		 const char *name,
+		 int num_fields,
+		 gcc::jit::field **fields)
+{
+  gcc_assert (NULL == loc);
+  gcc_assert (name);
+  gcc_assert ((num_fields == 0) || fields);
+
+  /* Compare with c/c-decl.c: start_struct and finish_struct. */
+
+  tree t = make_node (RECORD_TYPE);
+  TYPE_NAME (t) = get_identifier (name);
+  TYPE_SIZE (t) = 0;
+
+ tree fieldlist = NULL;
+  for (int i = 0; i < num_fields; i++)
+    {
+      field *f = fields[i];
+      DECL_CONTEXT (f->as_tree ()) = t;
+      fieldlist = chainon (f->as_tree (), fieldlist);
+    }
+  fieldlist = nreverse (fieldlist);
+  TYPE_FIELDS (t) = fieldlist;
+
+  layout_type (t);
+
+  return new type (t);
+}
+
+
+gcc::jit::param *
+gcc::jit::context::
+new_param (location *loc,
+	   type *type,
+	   const char *name)
+{
+  gcc_assert (NULL == loc);
+  gcc_assert (type);
+  gcc_assert (name);
+  tree inner = build_decl (UNKNOWN_LOCATION, PARM_DECL,
+			   get_identifier (name), type->as_tree ());
+  return new param (inner);
+}
+
+gcc::jit::function *
+gcc::jit::context::
+new_function (location *loc,
+	      enum gcc_jit_function_kind kind,
+	      type *return_type,
+	      const char *name,
+	      int num_params,
+	      param **params,
+	      int is_variadic)
+ {
+  gcc_assert (NULL == loc);
+  //can return_type be NULL?
+  gcc_assert (name);
+  gcc_assert ((num_params == 0) || params);
+
+  tree *arg_types = (tree *)xcalloc(num_params, sizeof(tree*));
+  for (int i = 0; i < num_params; i++)
+    {
+      arg_types[i] = TREE_TYPE (params[i]->as_tree ());
+    }
+  tree fn_type;
+  if (is_variadic)
+    fn_type = build_varargs_function_type_array (return_type->as_tree (),
+						 num_params, arg_types);
+  else
+    fn_type = build_function_type_array (return_type->as_tree (),
+					 num_params, arg_types);
+  // FIXME: free arg_types
+
+  /* FIXME: this uses input_location: */
+  tree fndecl = build_fn_decl (name, fn_type);
+
+  tree resdecl = build_decl (UNKNOWN_LOCATION, RESULT_DECL,
+			     NULL_TREE, return_type->as_tree ());
+  DECL_ARTIFICIAL (resdecl) = 1;
+  DECL_IGNORED_P (resdecl) = 1;
+  DECL_RESULT (fndecl) = resdecl;
+
+  if (kind != GCC_JIT_FUNCTION_IMPORTED)
+    {
+      tree param_decl_list = NULL;
+      for (int i = 0; i < num_params; i++)
+	{
+	  param_decl_list = chainon (params[i]->as_tree (), param_decl_list);
+	}
+
+      /* The param list was created in reverse order; fix it: */
+      param_decl_list = nreverse (param_decl_list);
+
+      tree t;
+      for (t = param_decl_list; t; t = DECL_CHAIN (t))
+	{
+	  DECL_CONTEXT (t) = fndecl;
+	  DECL_ARG_TYPE (t) = TREE_TYPE (t);
+	}
+
+      /* Set it up on DECL_ARGUMENTS */
+      DECL_ARGUMENTS(fndecl) = param_decl_list;
+    }
+
+  function *func = new function (this, fndecl, kind);
+  m_functions.safe_push (func);
+  return func;
+}
+
+gcc::jit::local *
+gcc::jit::context::
+new_local (location *loc,
+	   type *type,
+	   const char *name)
+{
+  gcc_assert (NULL == loc);
+  gcc_assert (type);
+  gcc_assert (name);
+  tree inner = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+			   get_identifier (name),
+			   type->as_tree ());
+  return new local (inner);
+}
+
+
+gcc::jit::rvalue *
+gcc::jit::context::
+new_rvalue_from_int (type *type,
+		     int value)
+{
+  // FIXME: type-checking, or coercion?
+  tree inner_type = type->as_tree ();
+  if (INTEGRAL_TYPE_P (inner_type))
+    {
+      tree inner = build_int_cst (inner_type, value);
+      return new rvalue (inner);
+    }
+  else
+    {
+      REAL_VALUE_TYPE real_value;
+      real_from_integer (&real_value, VOIDmode, value, 0, 0);
+      tree inner = build_real (inner_type, real_value);
+      return new rvalue (inner);
+    }
+}
+
+gcc::jit::rvalue *
+gcc::jit::context::
+new_string_literal (const char *value)
+{
+  tree t_str = build_string (strlen (value), value);
+  gcc_assert (m_char_array_type_node);
+  TREE_TYPE (t_str) = m_char_array_type_node;
+
+  /* Convert to (const char*), loosely based on
+     c/c-typeck.c: array_to_pointer_conversion,
+     by taking address of start of string.  */
+  tree t_addr = build1 (ADDR_EXPR, m_const_char_ptr, t_str);
+
+  return new rvalue (t_addr);
+}
+
+gcc::jit::rvalue *
+gcc::jit::context::
+new_binary_op (location *loc,
+	       enum gcc_jit_binary_op op,
+	       type *result_type,
+	       rvalue *a, rvalue *b)
+{
+  // FIXME: type-checking, or coercion?
+  enum tree_code inner_op;
+
+  gcc_assert (NULL == loc);
+  gcc_assert (result_type);
+  gcc_assert (a);
+  gcc_assert (b);
+
+  switch (op)
+    {
+    default: gcc_unreachable ();
+    case GCC_JIT_BINARY_OP_PLUS:
+      inner_op = PLUS_EXPR;
+      break;
+
+    case GCC_JIT_BINARY_OP_MINUS:
+      inner_op = MINUS_EXPR;
+      break;
+
+    case GCC_JIT_BINARY_OP_MULT:
+      inner_op = MULT_EXPR;
+      break;
+    }
+
+  tree inner_expr = build2 (inner_op,
+			    result_type->as_tree (),
+			    a->as_tree (),
+			    b->as_tree ());
+  return new rvalue (inner_expr);
+}
+
+gcc::jit::rvalue *
+gcc::jit::context::
+new_comparison (location *loc,
+		enum gcc_jit_comparison op,
+		rvalue *a, rvalue *b)
+{
+  // FIXME: type-checking, or coercion?
+  enum tree_code inner_op;
+
+  gcc_assert (NULL == loc);
+  gcc_assert (a);
+  gcc_assert (b);
+
+  switch (op)
+    {
+    default: gcc_unreachable ();
+    case GCC_JIT_COMPARISON_LT:
+      inner_op = LT_EXPR;
+      break;
+    case GCC_JIT_COMPARISON_GE:
+      inner_op = GE_EXPR;
+      break;
+    }
+
+  tree inner_expr = build2 (inner_op,
+			    boolean_type_node,
+			    a->as_tree (),
+			    b->as_tree ());
+  return new rvalue (inner_expr);
+}
+
+gcc::jit::rvalue *
+gcc::jit::context::
+new_call (location *loc,
+	  function *func,
+	  int numargs , rvalue **args)
+{
+  tree fndecl;
+  vec<tree, va_gc> *tree_args;
+
+  gcc_assert (NULL == loc);
+  gcc_assert (func);
+  gcc_assert (numargs >= 0);
+  gcc_assert ((args == 0) || (args != NULL));
+
+  // FIXME: type checking
+  // FIXME: check num args and types
+
+  fndecl = func->as_fndecl ();
+
+  vec_alloc (tree_args, numargs);
+  for (int i = 0; i < numargs; i++)
+    tree_args->quick_push (args[i]->as_tree ());
+
+  tree fntype = TREE_TYPE (fndecl);
+  tree fn = build1 (ADDR_EXPR, build_pointer_type (fntype), fndecl);
+
+  return new rvalue (build_call_vec (func->get_return_type_as_tree (),
+				     fn, tree_args));
+
+  /* see c-typeck.c: build_function_call
+     which calls build_function_call_vec
+
+     which does lots of checking, then:
+    result = build_call_array_loc (loc, TREE_TYPE (fntype),
+				   function, nargs, argarray);
+    which is in tree.c
+    (see also build_call_vec)
+   */
+}
+
+gcc::jit::rvalue *
+gcc::jit::context::
+new_array_lookup (location *loc,
+		  rvalue *ptr,
+		  rvalue *index)
+{
+  gcc_assert (NULL == loc);
+  gcc_assert (ptr);
+  gcc_assert (index);
+
+  /* For comparison, see:
+       c/c-typeck.c: build_array_ref
+       c-family/c-common.c: pointer_int_sum
+  */
+  tree t_ptr = ptr->as_tree ();
+  tree t_index = index->as_tree ();
+  tree t_type_ptr = TREE_TYPE (t_ptr);
+  tree t_type_star_ptr = TREE_TYPE (t_type_ptr);
+
+  if (TREE_CODE (t_type_ptr) == ARRAY_TYPE)
+    {
+      tree t_result = build4 (ARRAY_REF, t_type_star_ptr, t_ptr, t_index,
+			      NULL_TREE, NULL_TREE);
+      return new rvalue (t_result);
+    }
+  else
+    {
+      /* Convert index to an offset in bytes.  */
+      tree t_sizeof = size_in_bytes (t_type_star_ptr);
+      t_index = fold_build1 (CONVERT_EXPR, sizetype, t_index);
+      tree t_offset = build2 (MULT_EXPR, sizetype, t_index, t_sizeof);
+
+      /* Locate (ptr + offset).  */
+      tree t_address = build2 (POINTER_PLUS_EXPR, t_type_ptr, t_ptr, t_offset);
+
+      tree t_indirection = build1 (INDIRECT_REF, t_type_star_ptr, t_address);
+      return new rvalue (t_indirection);
+    }
+}
+
+static tree
+get_field (tree type, tree component)
+{
+  for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
+    if (DECL_NAME (field) == component)
+      return field;
+  return NULL;
+}
+
+gcc::jit::lvalue *
+gcc::jit::context::
+new_field_access (location *loc,
+		  rvalue *ptr_or_struct,
+		  const char *fieldname)
+{
+  gcc_assert (NULL == loc);
+  gcc_assert (ptr_or_struct);
+  gcc_assert (fieldname);
+
+  /* Compare with c/ctypeck.c:lookup_field, build_indirect_ref, and
+     build_component_ref. */
+  tree datum = ptr_or_struct->as_tree ();
+  tree type = TREE_TYPE (datum);
+
+  if (TREE_CODE (type) == POINTER_TYPE)
+    {
+      datum = build1 (INDIRECT_REF, type, datum);
+      type = TREE_TYPE (type);
+    }
+
+  tree component = get_identifier (fieldname);
+  tree field = get_field (type, component);
+  if (!field)
+    {
+      // FIXME: field not found
+      return NULL;
+    }
+  tree ref = build3 (COMPONENT_REF, TREE_TYPE (field), datum,
+		     field, NULL_TREE);
+  return new lvalue (ref);
+}
+
+void *
+gcc::jit::wrapper::
+operator new (size_t sz)
+{
+  return ggc_internal_cleared_alloc_stat (sz MEM_STAT_INFO);
+}
+
+gcc::jit::function::
+function(gcc::jit::context *ctxt, tree fndecl, enum gcc_jit_function_kind kind)
+: m_ctxt(ctxt),
+  m_inner_fndecl (fndecl),
+  m_kind (kind)
+{
+  if (m_kind != GCC_JIT_FUNCTION_IMPORTED)
+    {
+      m_stmt_list = alloc_stmt_list ();
+      m_stmt_iter = tsi_start (m_stmt_list);
+    }
+  else
+    {
+      m_stmt_list = NULL;
+    }
+}
+
+void
+gcc::jit::function::
+gt_ggc_mx ()
+{
+  gt_ggc_m_9tree_node (m_inner_fndecl);
+  gt_ggc_m_9tree_node (m_stmt_list);
+}
+
+tree
+gcc::jit::function::
+get_return_type_as_tree () const
+{
+  return TREE_TYPE (TREE_TYPE(m_inner_fndecl));
+}
+
+gcc::jit::label *
+gcc::jit::function::
+new_forward_label (const char *name)
+{
+  gcc_assert (m_kind != GCC_JIT_FUNCTION_IMPORTED);
+  return new label (this, name);
+}
+
+void
+gcc::jit::function::
+postprocess ()
+{
+  if (m_ctxt->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE))
+    debug_tree (m_stmt_list);
+
+  /* Do we need this to force cgraphunit.c to output the function? */
+  if (m_kind == GCC_JIT_FUNCTION_EXPORTED)
+    {
+      DECL_EXTERNAL (m_inner_fndecl) = 0;
+      DECL_PRESERVE_P (m_inner_fndecl) = 1;
+    }
+
+  if (m_kind != GCC_JIT_FUNCTION_IMPORTED)
+    {
+      /* Seem to need this in gimple-low.c: */
+      DECL_INITIAL (m_inner_fndecl) = make_node (BLOCK);
+
+      /* how to add to function? the following appears to be how to
+	 set the body of a m_inner_fndecl: */
+      DECL_SAVED_TREE(m_inner_fndecl) = m_stmt_list;
+      //debug_tree (m_inner_fndecl);
+
+      /* Convert to gimple: */
+      //printf("about to gimplify_function_tree\n");
+      gimplify_function_tree (m_inner_fndecl);
+      //printf("finished gimplify_function_tree\n");
+
+      current_function_decl = m_inner_fndecl;
+      if (m_ctxt->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE))
+	{
+	  gimple_seq gs = gimple_body (m_inner_fndecl);
+	  debug_gimple_seq (gs);
+	  debug_tree (m_inner_fndecl);
+	}
+
+      //printf("about to add to cgraph\n");
+      /* Add to cgraph: */
+      cgraph_finalize_function (m_inner_fndecl, false);
+      /* This can trigger a collection, so we need to have all of
+	 the funcs as roots.  */
+
+      current_function_decl = NULL;
+    }
+}
+
+void
+gcc::jit::function::
+add_eval (location *loc,
+	  rvalue *rvalue)
+{
+  gcc_assert (NULL == loc);
+  gcc_assert (rvalue);
+  gcc_assert (m_kind != GCC_JIT_FUNCTION_IMPORTED);
+
+  tsi_link_after (&m_stmt_iter, rvalue->as_tree (), TSI_CONTINUE_LINKING);
+}
+
+void
+gcc::jit::function::
+add_assignment (location *loc,
+		lvalue *lvalue,
+		rvalue *rvalue)
+{
+  gcc_assert (NULL == loc);
+  gcc_assert (lvalue);
+  gcc_assert (rvalue);
+  gcc_assert (m_kind != GCC_JIT_FUNCTION_IMPORTED);
+
+  tree t_lvalue = lvalue->as_tree ();
+  tree t_rvalue = rvalue->as_tree ();
+  if (TREE_TYPE (t_rvalue) != TREE_TYPE (t_lvalue))
+    t_rvalue = build1 (CONVERT_EXPR,
+		       TREE_TYPE (t_lvalue),
+		       t_rvalue);
+
+  tree stmt =
+    build2 (MODIFY_EXPR, TREE_TYPE (t_lvalue),
+	    t_lvalue, t_rvalue);
+  tsi_link_after (&m_stmt_iter, stmt, TSI_CONTINUE_LINKING);
+}
+
+void
+gcc::jit::function::
+add_conditional (location *loc,
+		 rvalue *boolval,
+		 label *on_true,
+		 label *on_false)
+{
+  gcc_assert (NULL == loc);
+  gcc_assert (boolval);
+  gcc_assert (on_true);
+  /* on_false can be NULL */
+  gcc_assert (m_kind != GCC_JIT_FUNCTION_IMPORTED);
+
+  /* COND_EXPR wants statement lists for the true/false operands, but we
+     want labels.
+     Shim it by creating jumps to the labels */
+  tree true_jump = build1 (GOTO_EXPR, void_type_node,
+			   on_true->as_label_decl ());
+  tree false_jump;
+  if (on_false)
+    false_jump = build1 (GOTO_EXPR, void_type_node,
+			 on_false->as_label_decl ());
+  else
+    false_jump = NULL;
+
+  tree stmt =
+    build3 (COND_EXPR, void_type_node, boolval->as_tree (),
+	    true_jump, false_jump);
+  tsi_link_after (&m_stmt_iter, stmt, TSI_CONTINUE_LINKING);
+}
+
+gcc::jit::label *
+gcc::jit::function::
+add_label (location *loc,
+	   const char *name)
+{
+  gcc_assert (NULL == loc);
+  gcc_assert (m_kind != GCC_JIT_FUNCTION_IMPORTED);
+
+  label *lab = new label (this, name);
+  place_forward_label (lab);
+  return lab;
+}
+
+void
+gcc::jit::function::
+place_forward_label (label *lab)
+{
+  gcc_assert (lab);
+  gcc_assert (NULL == lab->m_label_expr); // must not have already been placed
+  gcc_assert (m_kind != GCC_JIT_FUNCTION_IMPORTED);
+
+  lab->m_label_expr = build1 (LABEL_EXPR,
+			     void_type_node,
+			     lab->as_label_decl ());
+  tsi_link_after (&m_stmt_iter, lab->m_label_expr, TSI_CONTINUE_LINKING);
+}
+
+void
+gcc::jit::function::
+add_jump (location *loc,
+	  label *target)
+{
+  gcc_assert (NULL == loc);
+  gcc_assert (target);
+  gcc_assert (m_kind != GCC_JIT_FUNCTION_IMPORTED);
+
+  // see c_finish_loop
+  //tree top = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
+  //add_stmt (top);
+
+  //tree stmt = build_and_jump (&LABEL_EXPR_LABEL (target->label_));
+  TREE_USED (target->as_label_decl ()) = 1;
+  tree stmt = build1 (GOTO_EXPR, void_type_node, target->as_label_decl ());
+  tsi_link_after (&m_stmt_iter, stmt, TSI_CONTINUE_LINKING);
+
+  /*
+  from c-typeck.c:
+tree
+c_finish_goto_label (location_t loc, tree label)
+{
+  tree decl = lookup_label_for_goto (loc, label);
+  if (!decl)
+    return NULL_TREE;
+  TREE_USED (decl) = 1;
+  {
+    tree t = build1 (GOTO_EXPR, void_type_node, decl);
+    SET_EXPR_LOCATION (t, loc);
+    return add_stmt (t);
+  }
+}
+  */
+
+}
+
+void
+gcc::jit::function::
+add_return (location *loc,
+	    rvalue *rvalue)
+{
+  gcc_assert (NULL == loc);
+  gcc_assert (m_kind != GCC_JIT_FUNCTION_IMPORTED);
+
+  tree return_type = TREE_TYPE (TREE_TYPE (m_inner_fndecl));
+  tree t_lvalue = DECL_RESULT (m_inner_fndecl);
+  tree t_rvalue = rvalue->as_tree ();
+  if (TREE_TYPE (t_rvalue) != TREE_TYPE (t_lvalue))
+    t_rvalue = build1 (CONVERT_EXPR,
+		       TREE_TYPE (t_lvalue),
+		       t_rvalue);
+  tree modify_retval = build2 (MODIFY_EXPR, return_type,
+			       t_lvalue, t_rvalue);
+  tree return_stmt = build1 (RETURN_EXPR, return_type,
+			     modify_retval);
+  tsi_link_after (&m_stmt_iter, return_stmt, TSI_CONTINUE_LINKING);
+}
+
+gcc::jit::loop *
+gcc::jit::function::
+new_loop (location *loc,
+	  rvalue *boolval)
+{
+  return new loop (this, loc, boolval);
+}
+
+gcc::jit::label::
+label (function *func,
+       const char *name)
+{
+  tree identifier;
+
+  gcc_assert (func);
+  // name can be NULL
+  if (name)
+    identifier = get_identifier (name);
+  else
+    identifier = NULL;
+  m_label_decl = build_decl (UNKNOWN_LOCATION, LABEL_DECL,
+			    identifier, void_type_node);
+  DECL_CONTEXT (m_label_decl) = func->as_fndecl ();
+  m_label_expr = NULL;
+}
+
+
+gcc::jit::loop::
+loop (function *func, location *loc, rvalue *boolval) :
+  m_func(func)
+{
+  m_label_cond = func->add_label (loc, "loop_cond");
+  m_label_body = func->new_forward_label ("loop_body");
+  m_label_end = func->new_forward_label ("loop_end");
+  func->add_conditional (loc, boolval, m_label_body, m_label_end);
+  func->place_forward_label (m_label_body);
+}
+
+void
+gcc::jit::loop::
+end (location *loc)
+{
+  m_func->add_jump (loc, m_label_cond);
+  m_func->place_forward_label (m_label_end);
+}
+
+void
+gcc::jit::context::
+set_str_option (enum gcc_jit_str_option opt,
+		const char *value)
+{
+  if (opt < 0 || opt >= GCC_JIT_NUM_STR_OPTIONS)
+    {
+      add_error ("unrecognized str option");
+      return;
+    }
+  m_str_options[opt] = value;
+}
+
+void
+gcc::jit::context::
+set_int_option (enum gcc_jit_int_option opt,
+		int value)
+{
+  if (opt < 0 || opt >= GCC_JIT_NUM_INT_OPTIONS)
+    {
+      add_error ("unrecognized int option");
+      return;
+    }
+  m_int_options[opt] = value;
+}
+
+void
+gcc::jit::context::
+set_bool_option (enum gcc_jit_bool_option opt,
+		 int value)
+{
+  if (opt < 0 || opt >= GCC_JIT_NUM_BOOL_OPTIONS)
+    {
+      add_error ("unrecognized bool option");
+      return;
+    }
+  m_bool_options[opt] = value ? true : false;
+}
+
+namespace gcc
+{
+  namespace jit
+  {
+    static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+    context *active_jit_ctxt;
+  }
+}
+
+gcc::jit::result *
+gcc::jit::context::
+compile ()
+{
+  void *handle = NULL;
+  result *result_obj = NULL;
+
+  /* Acquire the big GCC mutex. */
+  pthread_mutex_lock (&mutex);
+
+  gcc_assert (NULL == active_jit_ctxt);
+  active_jit_ctxt = this;
+
+  /* Call into the rest of gcc.
+     For now, we have to assemble command-line options to pass into
+     toplev_main, so that they can be parsed. */
+  const char *fake_args[20];
+  /* Pass in user-provided "progname", if any, so that it makes it
+     into GCC's "progname" global, used in various diagnostics. */
+  const char *progname = m_str_options[GCC_JIT_STR_OPTION_PROGNAME];
+  fake_args[0] = progname ? progname : "libgccjit.so";
+
+  fake_args[1] = "fake.c";
+  unsigned int num_args = 2;
+
+#define ADD_ARG(arg) \
+  do \
+    { \
+      gcc_assert(num_args < sizeof(fake_args)/sizeof(char*)); \
+      fake_args[num_args++] = arg; \
+    } \
+  while (0)
+
+  ADD_ARG ("-fPIC");
+
+  /* Handle int options: */
+  switch (m_int_options[GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL])
+    {
+    default:
+      add_error ("unrecognized optimization level");
+      goto error;
+
+    case 0:
+      ADD_ARG ("-O0");
+      break;
+
+    case 1:
+      ADD_ARG ("-O1");
+      break;
+
+    case 2:
+      ADD_ARG ("-O2");
+      break;
+
+    case 3:
+      ADD_ARG ("-O3");
+      break;
+    }
+  /* What about -Os? */
+
+  /* Handle bool options: */
+  if (m_bool_options[GCC_JIT_BOOL_OPTION_DEBUGINFO])
+    ADD_ARG ("-g");
+
+  /* Suppress timing (and other) info.  */
+  if (1)
+    {
+      ADD_ARG ("-quiet");
+      quiet_flag = 1;
+    }
+
+  /* Aggressively garbage-collect, to shake out bugs: */
+  if (0)
+    {
+      ADD_ARG ("--param");
+      ADD_ARG ("ggc-min-expand=0");
+      ADD_ARG ("--param");
+      ADD_ARG ("ggc-min-heapsize=0");
+    }
+
+  toplev_options toplev_opts;
+  toplev_opts.use_TV_TOTAL = false;
+
+  if (time_report || !quiet_flag  || flag_detailed_statistics)
+    timevar_init ();
+
+  timevar_start (TV_TOTAL);
+
+  toplev_main (num_args, const_cast <char **> (fake_args), &toplev_opts);
+  toplev_finalize ();
+
+  active_jit_ctxt = NULL;
+
+  if (m_cb_result)
+    goto error;
+
+  timevar_push (TV_ASSEMBLE);
+
+  /* Gross hacks follow:
+     We have a .s file; we want a .so file.
+     We could reuse parts of gcc/gcc.c to do this.
+     For now, just use the /usr/bin/gcc on the system...
+   */
+  /* FIXME: totally faking it for now, not even using pex */
+  /* FIXME: don't use the same filename for everything;
+     also TOCTTOU issues, presumably. */
+  system ("gcc -shared fake.s -o fake.so");
+
+  timevar_pop (TV_ASSEMBLE);
+
+  // TODO: split out assembles vs linker
+
+  /* dlopen the .so file. */
+  {
+    const char *error;
+
+    timevar_push (TV_LOAD);
+
+    /* Clear any existing error.  */
+    dlerror ();
+
+    handle = dlopen ("./fake.so", RTLD_NOW | RTLD_LOCAL);
+    if ((error = dlerror()) != NULL)  {
+      fprintf(stderr, "%s\n", error);
+    }
+    if (handle)
+      result_obj = new result (handle);
+    else
+      result_obj = NULL;
+
+    timevar_pop (TV_LOAD);
+  }
+
+  timevar_stop (TV_TOTAL);
+  timevar_print (stderr);
+
+ error:
+  /* Release the big GCC mutex. */
+  active_jit_ctxt = NULL;
+  pthread_mutex_unlock (&mutex);
+
+  return result_obj;
+}
+
+void
+gcc::jit::context::
+invoke_code_factory ()
+{
+  /* Adapted from c-common.c:c_common_nodes_and_builtins.  */
+  tree array_domain_type = build_index_type (size_int (200));
+  m_char_array_type_node
+    = build_array_type (char_type_node, array_domain_type);
+
+  m_const_char_ptr
+    = build_pointer_type (build_qualified_type (char_type_node,
+						TYPE_QUAL_CONST));
+
+  /* Call the client-provided code factory:  */
+  timevar_push (TV_CLIENT_CALLBACK);
+  m_within_code_factory = true;
+  m_cb_result = m_code_factory ((gcc_jit_context *)this, m_user_data);
+  m_within_code_factory = false;
+  timevar_pop (TV_CLIENT_CALLBACK);
+
+  if (!m_cb_result)
+    {
+      int i;
+      function *func;
+      FOR_EACH_VEC_ELT (m_functions, i, func)
+	{
+	  gcc_assert (func);
+	  func->postprocess ();
+	}
+    }
+}
+
+void
+gcc::jit::context::
+add_error (const char */*msg*/)
+{
+  // TODO
+}
+
+gcc::jit::result::
+result(void *dso_handle)
+  : m_dso_handle(dso_handle)
+{
+}
+
+gcc::jit::result::
+~result()
+{
+  dlclose (m_dso_handle);
+}
+
+void *
+gcc::jit::result::
+get_code (const char *funcname)
+{
+  void *code;
+  const char *error;
+
+  /* Clear any existing error.  */
+  dlerror ();
+
+  code = dlsym (m_dso_handle, funcname);
+
+  if ((error = dlerror()) != NULL)  {
+    fprintf(stderr, "%s\n", error);
+  }
+
+  return code;
+}
diff --git a/gcc/jit/internal-api.h b/gcc/jit/internal-api.h
new file mode 100644
index 0000000..8555d4b
--- /dev/null
+++ b/gcc/jit/internal-api.h
@@ -0,0 +1,363 @@
+#include "libgccjit.h"
+
+#include "tree.h"
+#include "tree-iterator.h"
+
+namespace gcc {
+
+namespace jit {
+
+class result;
+class location;
+class type;
+class field;
+class function;
+class label;
+class rvalue;
+class lvalue;
+class param;
+class local;
+class loop;
+
+/* A JIT-compilation context.  */
+class context
+{
+public:
+  void gt_ggc_mx ();
+
+  void
+  set_code_factory (gcc_jit_code_callback cb,
+		    void *user_data);
+
+  type *
+  get_void_type ();
+
+  type *
+  get_char_type ();
+
+  type *
+  get_int_type ();
+
+  type *
+  get_float_type ();
+
+  type *
+  get_double_type ();
+
+  field *
+  new_field (location *loc,
+	     type *type,
+	     const char *name);
+
+  type *
+  new_struct_type (location *loc,
+		   const char *name,
+		   int num_fields,
+		   field **fields);
+
+
+  param *
+  new_param (location *loc,
+	     type *type,
+	     const char *name);
+
+  function *
+  new_function (location *loc,
+		enum gcc_jit_function_kind kind,
+		type *return_type,
+		const char *name,
+		int num_params,
+		param **params,
+		int is_variadic);
+
+  local *
+  new_local (location *loc,
+	     type *type,
+	     const char *name);
+
+  rvalue *
+  new_rvalue_from_int (type *type,
+		       int value);
+
+  rvalue *
+  new_string_literal (const char *value);
+
+  rvalue *
+  new_binary_op (location *loc,
+		 enum gcc_jit_binary_op op,
+		 type *result_type,
+		 rvalue *a, rvalue *b);
+
+  rvalue *
+  new_comparison (location *loc,
+		  enum gcc_jit_comparison op,
+		  rvalue *a, rvalue *b);
+
+  rvalue *
+  new_call (location *loc,
+	    function *func,
+	    int numargs , rvalue **args);
+
+  rvalue *
+  new_array_lookup (location *loc,
+		    rvalue *ptr,
+		    rvalue *index);
+
+  lvalue *
+  new_field_access (location *loc,
+		    rvalue *ptr_or_struct,
+		    const char *fieldname);
+
+  void
+  set_str_option (enum gcc_jit_str_option opt,
+		  const char *value);
+
+  void
+  set_int_option (enum gcc_jit_int_option opt,
+		  int value);
+
+  void
+  set_bool_option (enum gcc_jit_bool_option opt,
+		   int value);
+
+  int
+  get_bool_option (enum gcc_jit_bool_option opt) const
+  {
+    return m_bool_options[opt];
+  }
+
+  result *
+  compile ();
+
+  void
+  invoke_code_factory ();
+
+  bool
+  within_code_factory () const { return m_within_code_factory; }
+
+  void
+  add_error (const char *msg);
+
+private:
+  gcc_jit_code_callback m_code_factory;
+  bool m_within_code_factory;
+  void *m_user_data;
+  int m_cb_result; /* Result from client-provided code factory.  */
+  vec<function *> m_functions;
+  const char *m_str_options[GCC_JIT_NUM_STR_OPTIONS];
+  int m_int_options[GCC_JIT_NUM_INT_OPTIONS];
+  bool m_bool_options[GCC_JIT_NUM_BOOL_OPTIONS];
+  tree m_char_array_type_node;
+  tree m_const_char_ptr;
+};
+
+/* The result of JIT-compilation.  */
+class result
+{
+public:
+  result(void *dso_handle);
+
+  virtual ~result();
+
+  void *
+  get_code (const char *funcname);
+
+private:
+  void *m_dso_handle;
+};
+
+extern context *active_jit_ctxt;
+
+/* A temporary wrapper object.
+   These objects are (mostly) only valid within the code factory callback.
+   We allocate them on the GC heap, so that they will be cleaned
+   the next time the GC collects.
+   The exception is the "function" class, which is tracked and marked by
+   the jit::context, since it needs to stay alive during post-processing
+   (when the GC could run). */
+class wrapper
+{
+public:
+  /* Allocate in the GC heap.  */
+  void *operator new (size_t sz);
+
+};
+
+class location : public wrapper
+{
+};
+
+class type : public wrapper
+{
+public:
+  type (tree inner)
+    : m_inner(inner)
+  {}
+
+  tree as_tree () const { return m_inner; }
+
+  type *get_pointer () const { return new type (build_pointer_type (m_inner)); }
+
+  type *get_const () const
+  {
+    return new type (build_qualified_type (m_inner, TYPE_QUAL_CONST));
+  }
+
+private:
+  tree m_inner;
+};
+
+class field : public wrapper
+{
+public:
+  field (tree inner)
+    : m_inner(inner)
+  {}
+
+  tree as_tree () const { return m_inner; }
+
+private:
+  tree m_inner;
+};
+
+class function : public wrapper
+{
+public:
+  function(context *ctxt, tree fndecl, enum gcc_jit_function_kind kind);
+
+  void gt_ggc_mx ();
+
+  tree get_return_type_as_tree () const;
+
+  tree as_fndecl () const { return m_inner_fndecl; }
+
+  label*
+  new_forward_label (const char *name);
+
+  void
+  add_eval (location *loc,
+	    rvalue *rvalue);
+
+  void
+  add_assignment (location *loc,
+		  lvalue *lvalue,
+		  rvalue *rvalue);
+
+  void
+  add_conditional (location *loc,
+		   rvalue *boolval,
+		   label *on_true,
+		   label *on_false);
+
+  label *
+  add_label (location *loc,
+	     const char *name);
+
+  void
+  place_forward_label (label *lab);
+
+  void
+  add_jump (location *loc,
+	    label *target);
+
+  void
+  add_return (location *loc,
+	      rvalue *rvalue);
+
+  loop *
+  new_loop (location *loc,
+	    rvalue *boolval);
+
+  void
+  postprocess ();
+
+public:
+  context *m_ctxt;
+
+private:
+  tree m_inner_fndecl;
+  enum gcc_jit_function_kind m_kind;
+  tree m_stmt_list;
+  tree_stmt_iterator m_stmt_iter;
+};
+
+class label : public wrapper
+{
+public:
+  label (function *func,
+	 const char *name);
+
+  tree as_label_decl () const { return m_label_decl; }
+
+private:
+  tree m_label_decl;
+
+public: // for now
+  tree m_label_expr;
+};
+
+class rvalue : public wrapper
+{
+public:
+  rvalue (tree inner)
+    : m_inner(inner)
+  {}
+
+  rvalue *
+  as_rvalue () { return this; }
+
+  tree as_tree () const { return m_inner; }
+
+  type *
+  get_type () { return new type (TREE_TYPE (m_inner)); }
+
+private:
+  tree m_inner;
+};
+
+class lvalue : public rvalue
+{
+public:
+  lvalue (tree inner)
+    : rvalue(inner)
+  {}
+
+  lvalue *
+  as_lvalue () { return this; }
+};
+
+class param : public lvalue
+{
+public:
+  param (tree inner)
+    : lvalue(inner)
+  {}
+};
+
+class local : public lvalue
+{
+public:
+  local (tree inner)
+    : lvalue(inner)
+  {}
+};
+
+class loop : public wrapper
+{
+public:
+  loop (function *func, location *loc, rvalue *boolval);
+
+  void end (location *loc);
+
+private:
+  function *m_func;
+  label *m_label_cond;
+  label *m_label_body;
+  label *m_label_end;
+};
+
+
+} // namespace gcc::jit
+
+} // namespace gcc
+
diff --git a/gcc/jit/libgccjit.c b/gcc/jit/libgccjit.c
new file mode 100644
index 0000000..82f1c5a
--- /dev/null
+++ b/gcc/jit/libgccjit.c
@@ -0,0 +1,466 @@
+/* Implementation of the C API; all wrappers into a C++ API */
+#include "config.h"
+#include "system.h"
+#include "ansidecl.h"
+#include "coretypes.h"
+#include "opts.h"
+
+#include "libgccjit.h"
+#include "internal-api.h"
+
+struct gcc_jit_context : public gcc::jit::context
+{
+};
+
+struct gcc_jit_result : public gcc::jit::result
+{
+};
+
+struct gcc_jit_location : public gcc::jit::location
+{
+};
+
+struct gcc_jit_type : public gcc::jit::type
+{
+};
+
+struct gcc_jit_field : public gcc::jit::field
+{
+};
+
+struct gcc_jit_function : public gcc::jit::function
+{
+};
+
+struct gcc_jit_label : public gcc::jit::label
+{
+};
+
+struct gcc_jit_rvalue : public gcc::jit::rvalue
+{
+};
+
+struct gcc_jit_lvalue : public gcc::jit::lvalue
+{
+};
+
+struct gcc_jit_param : public gcc::jit::param
+{
+};
+
+struct gcc_jit_local : public gcc::jit::local
+{
+};
+
+struct gcc_jit_loop : public gcc::jit::loop
+{
+};
+
+gcc_jit_context *
+gcc_jit_context_acquire (void)
+{
+  return new gcc_jit_context ();
+}
+
+void
+gcc_jit_context_release (gcc_jit_context *ctxt)
+{
+  delete ctxt;
+}
+
+void
+gcc_jit_context_set_code_factory (gcc_jit_context *ctxt,
+				  gcc_jit_code_callback cb,
+				  void *user_data)
+{
+  gcc_assert (ctxt);
+  ctxt->set_code_factory (cb, user_data);
+}
+
+/**********************************************************************
+ Functions for use within the code factory.
+ **********************************************************************/
+#define ASSERT_WITHIN_CALLBACK(CTXT) \
+  do {                                           \
+    gcc_assert ((CTXT)->within_code_factory ()); \
+  } while (0)
+
+#define ASSERT_NOT_WITHIN_CALLBACK(CTXT) \
+  do {                                            \
+    gcc_assert (!(CTXT)->within_code_factory ()); \
+  } while (0)
+
+gcc_jit_type *
+gcc_jit_context_get_void_type (gcc_jit_context *ctxt)
+{
+  ASSERT_WITHIN_CALLBACK (ctxt);
+  return (gcc_jit_type *)ctxt->get_void_type ();
+}
+
+gcc_jit_type *
+gcc_jit_context_get_char_type (gcc_jit_context *ctxt)
+{
+  ASSERT_WITHIN_CALLBACK (ctxt);
+  return (gcc_jit_type *)ctxt->get_char_type ();
+}
+
+gcc_jit_type *
+gcc_jit_context_get_int_type (gcc_jit_context *ctxt)
+{
+  ASSERT_WITHIN_CALLBACK (ctxt);
+  return (gcc_jit_type *)ctxt->get_int_type ();
+}
+
+gcc_jit_type *
+gcc_jit_context_get_float_type (gcc_jit_context *ctxt)
+{
+  ASSERT_WITHIN_CALLBACK (ctxt);
+  return (gcc_jit_type *)ctxt->get_float_type ();
+}
+
+gcc_jit_type *
+gcc_jit_context_get_double_type (gcc_jit_context *ctxt)
+{
+  ASSERT_WITHIN_CALLBACK (ctxt);
+  return (gcc_jit_type *)ctxt->get_double_type ();
+}
+
+gcc_jit_type *
+gcc_jit_type_get_pointer (gcc_jit_type *type)
+{
+  return (gcc_jit_type *)type->get_pointer ();
+}
+
+gcc_jit_type *
+gcc_jit_type_get_const (gcc_jit_type *type)
+{
+  return (gcc_jit_type *)type->get_const ();
+}
+
+gcc_jit_field *
+gcc_jit_context_new_field (gcc_jit_context *ctxt,
+			   gcc_jit_location *loc,
+			   gcc_jit_type *type,
+			   const char *name)
+{
+  return (gcc_jit_field *)ctxt->new_field (loc, type, name);
+}
+
+gcc_jit_type *
+gcc_jit_context_new_struct_type (gcc_jit_context *ctxt,
+				 gcc_jit_location *loc,
+				 const char *name,
+				 int num_fields,
+				 gcc_jit_field **fields)
+{
+  return (gcc_jit_type *)ctxt->new_struct_type (loc, name, num_fields,
+						(gcc::jit::field **)fields);
+}
+
+
+/* Constructing functions.  */
+gcc_jit_param *
+gcc_jit_context_new_param (gcc_jit_context *ctxt,
+			   gcc_jit_location *loc,
+			   gcc_jit_type *type,
+			   const char *name)
+{
+  ASSERT_WITHIN_CALLBACK (ctxt);
+  return (gcc_jit_param *)ctxt->new_param (loc, type, name);
+}
+
+gcc_jit_rvalue *
+gcc_jit_param_as_rvalue (gcc_jit_param *param)
+{
+  return (gcc_jit_rvalue *)param->as_rvalue ();
+}
+
+gcc_jit_function *
+gcc_jit_context_new_function (gcc_jit_context *ctxt,
+			      gcc_jit_location *loc,
+			      enum gcc_jit_function_kind kind,
+			      gcc_jit_type *return_type,
+			      const char *name,
+			      int num_params,
+			      gcc_jit_param **params,
+			      int is_variadic)
+{
+  ASSERT_WITHIN_CALLBACK (ctxt);
+  return (gcc_jit_function*)
+    ctxt->new_function (loc, kind, return_type, name,
+			num_params,
+			(gcc::jit::param **)params,
+			is_variadic);
+}
+
+gcc_jit_label*
+gcc_jit_function_new_forward_label (gcc_jit_function *func,
+				    const char *name)
+{
+  return (gcc_jit_label *)func->new_forward_label (name);
+}
+
+gcc_jit_local *
+gcc_jit_context_new_local (gcc_jit_context *ctxt,
+			   gcc_jit_location *loc,
+			   gcc_jit_type *type,
+			   const char *name)
+{
+  ASSERT_WITHIN_CALLBACK (ctxt);
+  return (gcc_jit_local *)ctxt->new_local (loc, type, name);
+}
+
+gcc_jit_lvalue *
+gcc_jit_local_as_lvalue (gcc_jit_local *local)
+{
+  return (gcc_jit_lvalue *)local->as_lvalue ();
+}
+
+gcc_jit_rvalue *
+gcc_jit_local_as_rvalue (gcc_jit_local *local)
+{
+  return (gcc_jit_rvalue *)local->as_rvalue ();
+}
+
+gcc_jit_rvalue *
+gcc_jit_lvalue_as_rvalue (gcc_jit_lvalue *lvalue)
+{
+  return (gcc_jit_rvalue *)lvalue->as_rvalue ();
+}
+
+gcc_jit_rvalue *
+gcc_jit_context_new_rvalue_from_int (gcc_jit_context *ctxt,
+				     gcc_jit_type *type,
+				     int value)
+{
+  ASSERT_WITHIN_CALLBACK (ctxt);
+  return (gcc_jit_rvalue *)ctxt->new_rvalue_from_int (type, value);
+}
+
+gcc_jit_rvalue *
+gcc_jit_context_zero (gcc_jit_context *ctxt,
+		      gcc_jit_type *type)
+{
+  ASSERT_WITHIN_CALLBACK (ctxt);
+  return gcc_jit_context_new_rvalue_from_int (ctxt, type, 0);
+}
+
+gcc_jit_rvalue *
+gcc_jit_context_one (gcc_jit_context *ctxt,
+		     gcc_jit_type *type)
+{
+  ASSERT_WITHIN_CALLBACK (ctxt);
+  return gcc_jit_context_new_rvalue_from_int (ctxt, type, 1);
+}
+
+gcc_jit_rvalue *
+gcc_jit_context_new_string_literal (gcc_jit_context *ctxt,
+				    const char *value)
+{
+  ASSERT_WITHIN_CALLBACK (ctxt);
+  return (gcc_jit_rvalue *)ctxt->new_string_literal (value);
+}
+
+
+gcc_jit_rvalue *
+gcc_jit_context_new_binary_op (gcc_jit_context *ctxt,
+			       gcc_jit_location *loc,
+			       enum gcc_jit_binary_op op,
+			       gcc_jit_type *result_type,
+			       gcc_jit_rvalue *a, gcc_jit_rvalue *b)
+{
+  ASSERT_WITHIN_CALLBACK (ctxt);
+  return (gcc_jit_rvalue *)ctxt->new_binary_op (loc, op, result_type, a, b);
+}
+
+gcc_jit_rvalue *
+gcc_jit_context_new_comparison (gcc_jit_context *ctxt,
+				gcc_jit_location *loc,
+				enum gcc_jit_comparison op,
+				gcc_jit_rvalue *a, gcc_jit_rvalue *b)
+{
+  ASSERT_WITHIN_CALLBACK (ctxt);
+  return (gcc_jit_rvalue *)ctxt->new_comparison (loc, op, a, b);
+}
+
+
+gcc_jit_rvalue *
+gcc_jit_context_new_call (gcc_jit_context *ctxt,
+			  gcc_jit_location *loc,
+			  gcc_jit_function *func,
+			  int numargs , gcc_jit_rvalue **args)
+{
+  ASSERT_WITHIN_CALLBACK (ctxt);
+  return (gcc_jit_rvalue *)ctxt->new_call (loc,
+					   func,
+					   numargs,
+					   (gcc::jit::rvalue **)args);
+}
+
+extern gcc_jit_rvalue *
+gcc_jit_context_new_array_lookup (gcc_jit_context *ctxt,
+				  gcc_jit_location *loc,
+				  gcc_jit_rvalue *ptr,
+				  gcc_jit_rvalue *index)
+{
+  ASSERT_WITHIN_CALLBACK (ctxt);
+  return (gcc_jit_rvalue *)ctxt->new_array_lookup (loc, ptr, index);
+}
+
+extern gcc_jit_lvalue *
+gcc_jit_context_new_field_access (gcc_jit_context *ctxt,
+				  gcc_jit_location *loc,
+				  gcc_jit_rvalue *ptr_or_struct,
+				  const char *fieldname)
+{
+  ASSERT_WITHIN_CALLBACK (ctxt);
+  return (gcc_jit_lvalue *)ctxt->new_field_access (loc, ptr_or_struct, fieldname);
+}
+
+gcc_jit_label *
+gcc_jit_function_add_label (gcc_jit_function *func,
+			    gcc_jit_location *loc,
+			    const char *name)
+{
+  return (gcc_jit_label *)func->add_label (loc, name);
+}
+
+void
+gcc_jit_function_place_forward_label (gcc_jit_function *func,
+				      gcc_jit_label *lab)
+{
+  func->place_forward_label (lab);
+}
+
+void
+gcc_jit_function_add_eval (gcc_jit_function *func,
+			   gcc_jit_location *loc,
+			   gcc_jit_rvalue *rvalue)
+{
+  return func->add_eval (loc, rvalue);
+}
+
+void
+gcc_jit_function_add_assignment (gcc_jit_function *func,
+				 gcc_jit_location *loc,
+				 gcc_jit_lvalue *lvalue,
+				 gcc_jit_rvalue *rvalue)
+{
+  return func->add_assignment (loc, lvalue, rvalue);
+}
+
+void
+gcc_jit_function_add_assignment_op (gcc_jit_function *func,
+				    gcc_jit_location *loc,
+				    gcc_jit_lvalue *lvalue,
+				    enum gcc_jit_binary_op op,
+				    gcc_jit_rvalue *rvalue)
+{
+  gcc_jit_type *type = (gcc_jit_type *)lvalue->get_type ();
+  gcc_jit_function_add_assignment (
+    func, loc,
+    lvalue,
+    gcc_jit_context_new_binary_op (
+      (gcc_jit_context *)func->m_ctxt,
+      loc, op, type,
+      gcc_jit_lvalue_as_rvalue (lvalue),
+      rvalue));
+}
+
+void
+gcc_jit_function_add_conditional (gcc_jit_function *func,
+				  gcc_jit_location *loc,
+				  gcc_jit_rvalue *boolval,
+				  gcc_jit_label *on_true,
+				  gcc_jit_label *on_false)
+{
+  return func->add_conditional (loc, boolval, on_true, on_false);
+}
+
+void
+gcc_jit_function_add_jump (gcc_jit_function *func,
+			gcc_jit_location *loc,
+			gcc_jit_label *target)
+{
+  func->add_jump (loc, target);
+}
+
+void
+gcc_jit_function_add_return (gcc_jit_function *func,
+			     gcc_jit_location *loc,
+			     gcc_jit_rvalue *rvalue)
+{
+  return func->add_return (loc, rvalue);
+}
+
+gcc_jit_loop *
+gcc_jit_function_new_loop (gcc_jit_function *func,
+			   gcc_jit_location *loc,
+			   gcc_jit_rvalue *boolval)
+{
+  return (gcc_jit_loop *)func->new_loop (loc, boolval);
+}
+
+void
+gcc_jit_loop_end (gcc_jit_loop *loop,
+		  gcc_jit_location *loc)
+{
+  loop->end (loc);
+}
+
+/**********************************************************************
+ Option-management
+ **********************************************************************/
+
+void
+gcc_jit_context_set_str_option (gcc_jit_context *ctxt,
+				enum gcc_jit_str_option opt,
+				const char *value)
+{
+  gcc_assert (ctxt);
+  ASSERT_NOT_WITHIN_CALLBACK (ctxt);
+  ctxt->set_str_option (opt, value);
+}
+
+void
+gcc_jit_context_set_int_option (gcc_jit_context *ctxt,
+				enum gcc_jit_int_option opt,
+				int value)
+{
+  gcc_assert (ctxt);
+  ASSERT_NOT_WITHIN_CALLBACK (ctxt);
+  ctxt->set_int_option (opt, value);
+}
+
+void
+gcc_jit_context_set_bool_option (gcc_jit_context *ctxt,
+				 enum gcc_jit_bool_option opt,
+				 int value)
+{
+  gcc_assert (ctxt);
+  ASSERT_NOT_WITHIN_CALLBACK (ctxt);
+  ctxt->set_bool_option (opt, value);
+}
+
+gcc_jit_result *
+gcc_jit_context_compile (gcc_jit_context *ctxt)
+{
+  gcc_assert (ctxt);
+  ASSERT_NOT_WITHIN_CALLBACK (ctxt);
+  return (gcc_jit_result *)ctxt->compile ();
+}
+
+void *
+gcc_jit_result_get_code (gcc_jit_result *result,
+			 const char *fnname)
+{
+  gcc_assert (result);
+  gcc_assert (fnname);
+  return result->get_code (fnname);
+}
+
+void
+gcc_jit_result_release (gcc_jit_result *result)
+{
+  delete result;
+}
diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h
new file mode 100644
index 0000000..a1e68f8
--- /dev/null
+++ b/gcc/jit/libgccjit.h
@@ -0,0 +1,355 @@
+/*
+  A pure C API to enable client code to embed GCC as a JIT-compiler.
+ */
+#ifndef LIBGCCJIT_H
+#define LIBGCCJIT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/* Various opaque structs. */
+typedef struct gcc_jit_context gcc_jit_context;
+typedef struct gcc_jit_result gcc_jit_result;
+typedef struct gcc_jit_location gcc_jit_location;
+typedef struct gcc_jit_type gcc_jit_type;
+typedef struct gcc_jit_field gcc_jit_field;
+typedef struct gcc_jit_function gcc_jit_function;
+typedef struct gcc_jit_label gcc_jit_label;
+typedef struct gcc_jit_rvalue gcc_jit_rvalue;
+typedef struct gcc_jit_lvalue gcc_jit_lvalue;
+typedef struct gcc_jit_param gcc_jit_param;
+typedef struct gcc_jit_local gcc_jit_local;
+typedef struct gcc_jit_loop gcc_jit_loop;
+
+/*
+   Acquire a JIT-compilation context.
+
+   FIXME: error-handling?
+*/
+extern gcc_jit_context *
+gcc_jit_context_acquire (void);
+
+/* Release the context.  After this call, it's no longer valid to use
+   the ctxt.  */
+extern void
+gcc_jit_context_release (gcc_jit_context *ctxt);
+
+/* A function-pointer type.
+   This is the client-provided hook for calling into the code-generation
+   API.
+   It should return 0 if there were no errors, or nonzero if errors
+   occurred (e.g. within client code that the library has no knowledge
+   of).  */
+typedef int (*gcc_jit_code_callback) (gcc_jit_context *ctxt,
+				      void *user_data);
+
+extern void
+gcc_jit_context_set_code_factory (gcc_jit_context *ctxt,
+				  gcc_jit_code_callback cb,
+				  void *user_data);
+     /* clearly I'm handwaving for now about the details of what that
+	callback looks like, but by doing it in a callback we also
+	avoid dealing with lifetimes of the results: entities can
+	only be referenced within the lifetime of the callback - once
+	control returns out of the callback, you can't use them.  This
+	avoids having to expose details of GCC's garbage-collector,
+	I hope. */
+
+/**********************************************************************
+ Functions for use within the code factory.
+ **********************************************************************/
+
+/* Access to specific types.  */
+extern gcc_jit_type *
+gcc_jit_context_get_void_type (gcc_jit_context *ctxt);
+
+extern gcc_jit_type *
+gcc_jit_context_get_char_type (gcc_jit_context *ctxt);
+
+extern gcc_jit_type *
+gcc_jit_context_get_int_type (gcc_jit_context *ctxt);
+
+extern gcc_jit_type *
+gcc_jit_context_get_float_type (gcc_jit_context *ctxt);
+
+extern gcc_jit_type *
+gcc_jit_context_get_double_type (gcc_jit_context *ctxt);
+
+/* Constructing new types. */
+extern gcc_jit_type *
+gcc_jit_type_get_pointer (gcc_jit_type *type);
+
+extern gcc_jit_type *
+gcc_jit_type_get_const (gcc_jit_type *type);
+
+/* Struct-handling.  */
+extern gcc_jit_field *
+gcc_jit_context_new_field (gcc_jit_context *ctxt,
+			   gcc_jit_location *loc,
+			   gcc_jit_type *type,
+			   const char *name);
+
+extern gcc_jit_type *
+gcc_jit_context_new_struct_type (gcc_jit_context *ctxt,
+				 gcc_jit_location *loc,
+				 const char *name,
+				 int num_fields,
+				 gcc_jit_field **fields);
+
+/* Constructing functions.  */
+extern gcc_jit_param *
+gcc_jit_context_new_param (gcc_jit_context *ctxt,
+			   gcc_jit_location *loc,
+			   gcc_jit_type *type,
+			   const char *name);
+
+extern gcc_jit_rvalue *
+gcc_jit_param_as_rvalue (gcc_jit_param *param);
+
+enum gcc_jit_function_kind
+{
+  /* Function is defined by the client code and visible
+     by name outside of the JIT.  */
+  GCC_JIT_FUNCTION_EXPORTED,
+
+  /* Function is defined by the client code, but is invisible
+     outside of the JIT.  Analogous to a "static" function.  */
+  GCC_JIT_FUNCTION_INTERNAL,
+
+  /* Function is not defined by the client code; we're merely
+     referring to it.  Analogous to using an "extern" function from a
+     header file.  */
+  GCC_JIT_FUNCTION_IMPORTED
+
+};
+
+
+extern gcc_jit_function *
+gcc_jit_context_new_function (gcc_jit_context *ctxt,
+			      gcc_jit_location *loc,
+			      enum gcc_jit_function_kind kind,
+			      gcc_jit_type *return_type,
+			      const char *name,
+			      int num_params,
+			      gcc_jit_param **params,
+			      int is_variadic);
+
+extern gcc_jit_label *
+gcc_jit_function_new_forward_label (gcc_jit_function *func,
+				    const char *name);
+
+extern gcc_jit_local *
+gcc_jit_context_new_local (gcc_jit_context *ctxt,
+			   gcc_jit_location *loc,
+			   gcc_jit_type *type,
+			   const char *name);
+
+extern gcc_jit_lvalue *
+gcc_jit_local_as_lvalue (gcc_jit_local *local);
+
+extern gcc_jit_rvalue *
+gcc_jit_local_as_rvalue (gcc_jit_local *local);
+
+extern gcc_jit_rvalue *
+gcc_jit_lvalue_as_rvalue (gcc_jit_lvalue *lvalue);
+
+/* Integer constants. */
+extern gcc_jit_rvalue *
+gcc_jit_context_new_rvalue_from_int (gcc_jit_context *ctxt,
+				     gcc_jit_type *type,
+				     int value);
+
+extern gcc_jit_rvalue *
+gcc_jit_context_zero (gcc_jit_context *ctxt,
+		      gcc_jit_type *type);
+
+extern gcc_jit_rvalue *
+gcc_jit_context_one (gcc_jit_context *ctxt,
+		     gcc_jit_type *type);
+
+/* String literals. */
+extern gcc_jit_rvalue *
+gcc_jit_context_new_string_literal (gcc_jit_context *ctxt,
+				    const char *value);
+
+
+enum gcc_jit_binary_op
+{
+  GCC_JIT_BINARY_OP_PLUS,
+  GCC_JIT_BINARY_OP_MINUS,
+  GCC_JIT_BINARY_OP_MULT
+};
+
+extern gcc_jit_rvalue *
+gcc_jit_context_new_binary_op (gcc_jit_context *ctxt,
+			       gcc_jit_location *loc,
+			       enum gcc_jit_binary_op op,
+			       gcc_jit_type *result_type,
+			       gcc_jit_rvalue *a, gcc_jit_rvalue *b);
+
+enum gcc_jit_comparison
+{
+  GCC_JIT_COMPARISON_LT,
+  GCC_JIT_COMPARISON_GE
+};
+
+extern gcc_jit_rvalue *
+gcc_jit_context_new_comparison (gcc_jit_context *ctxt,
+				gcc_jit_location *loc,
+				enum gcc_jit_comparison op,
+				gcc_jit_rvalue *a, gcc_jit_rvalue *b);
+
+extern gcc_jit_rvalue *
+gcc_jit_context_new_call (gcc_jit_context *ctxt,
+			  gcc_jit_location *loc,
+			  gcc_jit_function *func,
+			  int numargs , gcc_jit_rvalue **args);
+
+extern gcc_jit_rvalue *
+gcc_jit_context_new_array_lookup (gcc_jit_context *ctxt,
+				  gcc_jit_location *loc,
+				  gcc_jit_rvalue *ptr,
+				  gcc_jit_rvalue *index);
+
+/* Field access, either s.field or s->field.  */
+extern gcc_jit_lvalue *
+gcc_jit_context_new_field_access (gcc_jit_context *ctxt,
+				  gcc_jit_location *loc,
+				  gcc_jit_rvalue *ptr_or_struct,
+				  const char *fieldname);
+
+/* Add evaluation of an rvalue, discarding the result
+   (e.g. a function call that "returns" void).  */
+extern void
+gcc_jit_function_add_eval (gcc_jit_function *func,
+			   gcc_jit_location *loc,
+			   gcc_jit_rvalue *rvalue);
+
+extern void
+gcc_jit_function_add_assignment (gcc_jit_function *func,
+				 gcc_jit_location *loc,
+				 gcc_jit_lvalue *lvalue,
+				 gcc_jit_rvalue *rvalue);
+
+/**
+   Modify an lvalue (analogous to "+=" and friends)
+ */
+extern void
+gcc_jit_function_add_assignment_op (gcc_jit_function *func,
+				    gcc_jit_location *loc,
+				    gcc_jit_lvalue *lvalue,
+				    enum gcc_jit_binary_op op,
+				    gcc_jit_rvalue *rvalue);
+
+extern void
+gcc_jit_function_add_conditional (gcc_jit_function *func,
+				  gcc_jit_location *loc,
+				  gcc_jit_rvalue *boolval,
+				  gcc_jit_label *on_true,
+				  gcc_jit_label *on_false);
+
+extern gcc_jit_label *
+gcc_jit_function_add_label (gcc_jit_function *func,
+			    gcc_jit_location *loc,
+			    const char *name);
+
+extern void
+gcc_jit_function_place_forward_label (gcc_jit_function *func,
+				      gcc_jit_label *lab);
+
+extern void
+gcc_jit_function_add_jump (gcc_jit_function *func,
+			   gcc_jit_location *loc,
+			   gcc_jit_label *target);
+
+extern void
+gcc_jit_function_add_return (gcc_jit_function *func,
+			     gcc_jit_location *loc,
+			     gcc_jit_rvalue *rvalue);
+
+/* Helper function for creating a loop:
+      while (boolval)
+	{
+	   BODY;
+	}
+
+  Statements will be added to the body of the loop until
+  gcc_jit_loop_end is called.
+*/
+extern gcc_jit_loop *
+gcc_jit_function_new_loop (gcc_jit_function *func,
+			   gcc_jit_location *loc,
+			   gcc_jit_rvalue *boolval);
+
+extern void
+gcc_jit_loop_end (gcc_jit_loop *loop,
+		  gcc_jit_location *loc);
+
+/**********************************************************************
+ Option-management
+ **********************************************************************/
+
+/* Options taking string values */
+enum gcc_jit_str_option
+{
+  GCC_JIT_STR_OPTION_PROGNAME,
+  GCC_JIT_NUM_STR_OPTIONS
+};
+
+/* Options taking int values */
+enum gcc_jit_int_option
+{
+  GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL,
+  GCC_JIT_NUM_INT_OPTIONS
+};
+
+/* Options taking boolean values */
+enum gcc_jit_bool_option
+{
+  GCC_JIT_BOOL_OPTION_DEBUGINFO,
+  GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE,
+  GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE,
+  GCC_JIT_NUM_BOOL_OPTIONS
+};
+
+/* The context directly stores the (const char *), so the passed string
+   must outlive the context.  */
+extern void
+gcc_jit_context_set_str_option (gcc_jit_context *ctxt,
+				enum gcc_jit_str_option opt,
+				const char *value);
+
+extern void
+gcc_jit_context_set_int_option (gcc_jit_context *ctxt,
+				enum gcc_jit_int_option opt,
+				int value);
+
+extern void
+gcc_jit_context_set_bool_option (gcc_jit_context *ctxt,
+				 enum gcc_jit_bool_option opt,
+				 int value);
+
+extern gcc_jit_result *
+gcc_jit_context_compile (gcc_jit_context *ctxt);
+  /* This actually calls into GCC and runs the build, all
+     in a mutex for now.  The result is a wrapper around a .so file.
+     Can we only call this once on a given context?  */
+
+
+/* Locate a given function within the built machine code.
+   This will need to be cast to a function pointer of the
+   correct type before it can be called. */
+extern void *
+gcc_jit_result_get_code (gcc_jit_result *result,
+			 const char *funcname);
+
+extern void
+gcc_jit_result_release (gcc_jit_result *result);
+  /* Once we're done with the code, this unloads the built .so file: */
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif  /* LIBGCCJIT_H  */
diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map
new file mode 100644
index 0000000..f1c775a
--- /dev/null
+++ b/gcc/jit/libgccjit.map
@@ -0,0 +1,57 @@
+# Linker script for libgccjit.so
+{
+  global:
+    gcc_jit_context_acquire;
+    gcc_jit_context_release;
+    gcc_jit_context_set_code_factory;
+    gcc_jit_context_get_void_type;
+    gcc_jit_context_get_char_type;
+    gcc_jit_context_get_int_type;
+    gcc_jit_context_get_float_type;
+    gcc_jit_context_get_double_type;
+    gcc_jit_type_get_pointer;
+    gcc_jit_type_get_const;
+    gcc_jit_context_new_field;
+    gcc_jit_context_new_struct_type;
+    gcc_jit_context_new_param;
+    gcc_jit_param_as_rvalue;
+    gcc_jit_context_new_function;
+    gcc_jit_function_new_forward_label;
+    gcc_jit_context_new_local;
+    gcc_jit_local_as_lvalue;
+    gcc_jit_local_as_rvalue;
+    gcc_jit_lvalue_as_rvalue;
+    gcc_jit_context_new_rvalue_from_int;
+    gcc_jit_context_zero;
+    gcc_jit_context_one;
+    gcc_jit_context_new_string_literal;
+    gcc_jit_context_new_binary_op;
+    gcc_jit_context_new_comparison;
+    gcc_jit_context_new_call;
+    gcc_jit_context_new_array_lookup;
+    gcc_jit_context_new_field_access;
+    gcc_jit_function_add_eval;
+    gcc_jit_function_add_assignment;
+    gcc_jit_function_add_assignment_op;
+    gcc_jit_function_add_conditional;
+    gcc_jit_function_add_label;
+    gcc_jit_function_place_forward_label;
+    gcc_jit_function_add_jump;
+    gcc_jit_function_add_return;
+    gcc_jit_function_new_loop;
+    gcc_jit_loop_end;
+    gcc_jit_context_set_str_option;
+    gcc_jit_context_set_int_option;
+    gcc_jit_context_set_bool_option;
+    gcc_jit_context_compile;
+    gcc_jit_result_get_code;
+    gcc_jit_result_release;
+
+    # For now:
+    main;
+
+    # For use by test functions:
+    called_function;
+
+  local: *;
+};
\ No newline at end of file
diff --git a/gcc/jit/notes.txt b/gcc/jit/notes.txt
new file mode 100644
index 0000000..6d1288f
--- /dev/null
+++ b/gcc/jit/notes.txt
@@ -0,0 +1,82 @@
+Client Code   . Generated .            libgccjit.so
+              . code      .
+              .           . JIT API  . JIT "Frontend". (libbackend.a)
+....................................................................................
+   â          .           .          .               .
+   â          .           .          .               .
+   â          .           .          .               .
+   V          .           .  gcc_jit_context_compile .
+    ââââââââââââââââââââââââââ>      .               .
+              .           .    â     .               .
+              .           .    â ACQUIRE MUTEX       .
+              .           .    â     .               .
+              .           .    Vâââââââââââââââââââââââ> toplev_main (for now)
+              .           .          .               .       â
+              .           .          .               .   (various code)
+              .           .          .               .       â
+              .           .          .               .       V
+              .           .          .    <âââââââââââââââââ langhook:parse_file
+              .           .          .    â          .
+              .           .          .    â (jit_langhook_parse_file)
+              .           .          .    â          .
+..........................................â..................VVVVVVVVVVVVV...
+ code factory .           .          .    â          .       No GC in here
+ callback     .           .          .    â          .
+       <âââââââââââââââââââââââââââââââââââ          .
+       â      .           .          .   (invoke_cb) .
+       â      .           .  C API   .               .
+       ââââââââââââââââââââââ>       .               .
+              .           .  â Internal API          .
+              .           .  âââ>    .               .
+              .           .      â   .               .
+              .           .      ââââââââââââââââââââââââ> creation of functions,
+              .           .          .               .     types, expression trees
+              .           .      <ââââââââââââââââââââââââ etc
+              .           .  <âââ    .               .
+              .           .  â       .               .
+       ââââââââââââââââââââââ        .               .
+       âetc   .           .          .               .
+       â      .           .          .               .
+       ââââââââââââââââââââââââââââââââââ>           .
+              .           .          .    â          .       No GC in here
+..........................................â..................AAAAAAAAAAAAA...
+              .           .          .    â for each function
+              .           .          .    ââ> postprocess
+              .           .          .        â      .
+              .           .          .        ââââââââââââ> cgraph_finalize_function
+              .           .          .        <ââââââââââââ
+              .           .          .     <ââ       .
+              .           .          .    â          .
+              .           .          .    ââââââââââââââââââ> (end of
+              .           .          .               .       â langhook_parse_file)
+              .           .          .               .       â
+              .           .          .               .   (various code)
+              .           .          .               .       â
+              .           .          .               .       â
+              .           .          .    <âââââââââââââââââ langhook:write_globals
+              .           .          .    â          .
+              .           .          .    â (jit_langhook_write_globals)
+              .           .          .    â          .
+              .           .          .    â          .
+              .           .          .    ââââââââââââââââââ> finalize_compilation_unit
+              .           .          .               .       â
+              .           .          .               .   (the middleâend and backend)
+              .           .          .               .       â
+              .           .    <âââââââââââââââââââââââââââââ end of toplev_main
+              .           .    â RELEASE MUTEX       .
+              .           .    â     .               .
+              .           .    â Convert assembler to DSO
+              .           .    â     .               .
+              .           .    â Load DSO            .
+   <âââââââââââââââââââââââââââ      .               .
+   â          .           .          .               .
+   Get (void*).           .          .               .
+   â          .           .          .               .
+   â Call it  .           .          .               .
+   âââââââââââââââ>       .          .               .
+              .    â      .          .               .
+              .    â      .          .               .
+   <âââââââââââââââ       .          .               .
+   â          .           .          .               .
+   â          .           .          .               .
+etc
diff --git a/gcc/main.c b/gcc/main.c
index 82acf95..b893308 100644
--- a/gcc/main.c
+++ b/gcc/main.c
@@ -33,5 +33,8 @@ int main (int argc, char **argv);
 int
 main (int argc, char **argv)
 {
-  return toplev_main (argc, argv);
+  toplev_options toplev_opts;
+  toplev_opts.use_TV_TOTAL = true;
+
+  return toplev_main (argc, argv, &toplev_opts);
 }
diff --git a/gcc/params.c b/gcc/params.c
index 2fc1d15..22c7a27 100644
--- a/gcc/params.c
+++ b/gcc/params.c
@@ -69,6 +69,9 @@ add_params (const param_info params[], size_t n)
 void
 global_init_params (void)
 {
+  /* Make param initialization be idempotent.  */
+  if (params_finished)
+    return;
   add_params (lang_independent_params, LAST_PARAM);
   targetm_common.option_default_params ();
 }
diff --git a/gcc/passes.c b/gcc/passes.c
index f3f85fd..4eaf0b6 100644
--- a/gcc/passes.c
+++ b/gcc/passes.c
@@ -1997,6 +1997,7 @@ execute_ipa_summary_passes (struct ipa_opt_pass_d *ipa_pass)
 	  if (pass->tv_id)
 	    timevar_push (pass->tv_id);
 
+          current_pass = pass;
 	  ipa_pass->generate_summary ();
 
 	  /* Stop timevar.  */
diff --git a/gcc/predict.c b/gcc/predict.c
index 3b275d0..fd13e15 100644
--- a/gcc/predict.c
+++ b/gcc/predict.c
@@ -3038,3 +3038,7 @@ rebuild_frequencies (void)
     gcc_unreachable ();
   timevar_pop (TV_REBUILD_FREQUENCIES);
 }
+
+void predict_c_finalize (void)
+{
+}
diff --git a/gcc/stringpool.c b/gcc/stringpool.c
index f4d0dae..503dd43 100644
--- a/gcc/stringpool.c
+++ b/gcc/stringpool.c
@@ -61,6 +61,11 @@ stringpool_ggc_alloc (size_t x)
 void
 init_stringpool (void)
 {
+  /* Clean up if we're called more than once.
+     (We can't make this idempotent since identifiers contain state) */
+  if (ident_hash)
+    ht_destroy (ident_hash);
+
   /* Create with 16K (2^14) entries.  */
   ident_hash = ht_create (14);
   ident_hash->alloc_node = alloc_node;
diff --git a/gcc/symtab.c b/gcc/symtab.c
index 62fe166..af6fb13 100644
--- a/gcc/symtab.c
+++ b/gcc/symtab.c
@@ -1154,4 +1154,13 @@ symtab_semantically_equivalent_p (symtab_node a,
     bb = b;
   return bb == ba;
 }
+
+void symtab_c_finalize (void)
+{
+  symtab_hash = NULL;
+  assembler_name_hash = NULL;
+  symtab_nodes = NULL;
+  symtab_order = 0;
+}
+
 #include "gt-symtab.h"
diff --git a/gcc/testsuite/jit.dg/harness.h b/gcc/testsuite/jit.dg/harness.h
new file mode 100644
index 0000000..11537ea
--- /dev/null
+++ b/gcc/testsuite/jit.dg/harness.h
@@ -0,0 +1,141 @@
+/*
+  Code shared between multiple testcases.
+
+  This file contains "main" and support code.
+  Each testcase should implement the following hooks:
+
+    extern int
+    code_making_callback (gcc_jit_context *ctxt, void * user_data);
+
+    extern void
+    verify_code (gcc_jit_result *result);
+
+ */
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <dejagnu.h>
+
+#include "libgccjit.h"
+
+static char test[1024];
+
+#define CHECK_NON_NULL(PTR) \
+  do {                                       \
+    if ((PTR) != NULL)                       \
+      {                                      \
+	pass ("%s: %s is non-null", test, #PTR); \
+      }                                      \
+    else                                     \
+      {                                      \
+	fail ("%s: %s is NULL", test, #PTR); \
+	abort ();                            \
+    }                                        \
+  } while (0)
+
+#define CHECK_VALUE(ACTUAL, EXPECTED) \
+  do {                                       \
+    if ((ACTUAL) == (EXPECTED))              \
+      {                                      \
+	pass ("%s: actual: %s == expected: %s", test, #ACTUAL, #EXPECTED); \
+      }                                      \
+    else                                     \
+      {                                        \
+	fail ("%s: actual: %s != expected: %s", test, #ACTUAL, #EXPECTED); \
+	fprintf (stderr, "incorrect value\n"); \
+	abort ();                              \
+    }                                        \
+  } while (0)
+
+/* Hooks that testcases should provide.  */
+extern int
+code_making_callback (gcc_jit_context *ctxt, void * user_data);
+
+extern void
+verify_code (gcc_jit_result *result);
+
+/* Run one iteration of the test.  */
+
+static void
+test_jit (const char *argv0)
+{
+  gcc_jit_context *ctxt;
+  gcc_jit_result *result;
+
+  ctxt = gcc_jit_context_acquire ();
+     /* FIXME: error-handling */
+
+  gcc_jit_context_set_code_factory (ctxt, code_making_callback, NULL);
+
+  /* Set up options.  */
+  gcc_jit_context_set_str_option (
+    ctxt,
+    GCC_JIT_STR_OPTION_PROGNAME,
+    argv0);
+  gcc_jit_context_set_int_option (
+    ctxt,
+    GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL,
+    0);
+  gcc_jit_context_set_bool_option (
+    ctxt,
+    GCC_JIT_BOOL_OPTION_DEBUGINFO,
+    1);
+  gcc_jit_context_set_bool_option (
+    ctxt,
+    GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE,
+    0);
+  gcc_jit_context_set_bool_option (
+    ctxt,
+    GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE,
+    0);
+
+  /* This actually calls into GCC and runs the build, all
+     in a mutex for now.  */
+  result = gcc_jit_context_compile (ctxt);
+
+  gcc_jit_context_release (ctxt);
+
+  verify_code (result);
+
+  /* Once we're done with the code, this unloads the built .so file: */
+  gcc_jit_result_release (result);
+}
+
+/* We want to prefix all unit test results with the test, but dejagnu.exp's
+   host_execute appears to get confused by the leading "./" of argv0,
+   leading to all tests simply reporting as a single period character ".".
+
+   Hence strip out the final component of the path to the program name,
+   so that we can use that in unittest reports.  */
+const char*
+extract_progname (const char *argv0)
+{
+  const char *p;
+
+  p = argv0 + strlen (argv0);
+  while (p != argv0 && p[-1] != '/')
+    --p;
+  return p;
+}
+
+int
+main (int argc, char **argv)
+{
+  int i;
+
+  for (i = 1; i <= 5; i++)
+    {
+      snprintf (test, sizeof (test),
+		"%s iteration %d of %d",
+                extract_progname (argv[0]),
+                i, 5);
+
+      //printf ("ITERATION %d\n", i);
+      test_jit (argv[0]);
+      //printf ("\n");
+    }
+
+  totals ();
+
+  return 0;
+}
diff --git a/gcc/testsuite/jit.dg/jit.exp b/gcc/testsuite/jit.dg/jit.exp
new file mode 100644
index 0000000..3f3f30e
--- /dev/null
+++ b/gcc/testsuite/jit.dg/jit.exp
@@ -0,0 +1,95 @@
+# Test code for libgccjit.so
+#
+# We will compile each of jit.dg/test-*.c into an executable
+# dynamically linked against libgccjit.so, and then run each
+# such executable.
+#
+# These executables call into the libgccjit.so API to create
+# code, compile it, and run it, verifying that the results
+# are as expected.  See harness.h for shared code used by all
+# such executables.
+#
+# The executables call into DejaGnu's unit testing C API to
+# report PASS/FAIL results, which this script gathers back
+# up into the Tcl world, reporting a summary of all results
+# across all of the executables.
+
+load_lib dg.exp
+load_lib prune.exp
+load_lib gcc-defs.exp
+load_lib timeout.exp
+load_lib target-libpath.exp
+load_lib gcc.exp
+load_lib dejagnu.exp
+
+# GCC_UNDER_TEST is needed by gcc_target_compile
+global GCC_UNDER_TEST
+if ![info exists GCC_UNDER_TEST] {
+    set GCC_UNDER_TEST "[find_gcc]"
+}
+
+# Initialize dg.
+dg-init
+
+# Gather a list of all tests.
+set tests [lsort [find $srcdir/$subdir test-*.c]]
+verbose "tests: $tests"
+
+proc jit-dg-test { prog do_what extra_tool_flags } {
+    verbose "within jit-dg-test..."
+    verbose "  prog: $prog"
+    verbose "  do_what: $do_what"
+    verbose "  extra_tool_flags: $extra_tool_flags"
+
+    # Determine what to name the built executable.
+    set output_file "[file rootname [file tail $prog]].exe"
+    verbose "output_file: $output_file"
+
+    # Create the test executable:
+    gcc_target_compile $prog $output_file $do_what \
+        "{additional_flags=$extra_tool_flags}"
+
+    # Run the test executable, capturing the PASS/FAIL textual output
+    # from the C API, converting it into the Tcl API.
+
+    # We need to set LD_LIBRARY_PATH so that the test files can find
+    # libgccjit.so
+    # Do this using set_ld_library_path_env_vars from target-libpath.exp
+    global ld_library_path
+    global base_dir
+    set ld_library_path "$base_dir/../../"
+    set_ld_library_path_env_vars
+
+    # If running with just a "make" and not a "make install", then I was
+    # running into
+    #   "fatal error: -fuse-linker-plugin, but liblto_plugin.so not found"
+    # emitted by the inner gcc invoked to convert the .s into .so
+    # This appears to be due to not installing the built compiler;
+    # libto_plugin is a .la at build time, with the .so becoming installed
+    # at install time; the "set_ld_library_path_env_vars" function from
+    # target-libpath.exp that I'm using to set LD_LIBRARY_PATH to find
+    # the library under test, libgccjit.so, was setting GCC_EXEC_PREFIX to
+    # the builddir, thus picking up the built-but-not-installed toolchain.
+    # Hacking in an "unsetenv GCC_EXEC_PREFIX" here fixes the issue,
+    # allowing quick running of testsuite without needing a full install.
+    #
+    unsetenv GCC_EXEC_PREFIX
+
+    # dejagnu.exp's host_execute has code to scrape out test results
+    # from the DejaGnu C API and bring back into the tcl world, so we
+    # use that to invoke the built code:
+    set result [host_execute $output_file]
+    verbose "result: $result"
+
+    restore_ld_library_path_env_vars
+}
+
+# We need to link with --export-dynamic for test-calling-external-function.c
+# so that the JIT-built code can call into functions from the main program.
+set DEFAULT_CFLAGS "-I$srcdir/../jit -lgccjit -g -Wall -Werror -Wl,--export-dynamic"
+
+# Main loop.  This will invoke jig-dg-test on each test-*.c file.
+dg-runtest $tests "" $DEFAULT_CFLAGS
+
+# All done.
+dg-finish
diff --git a/gcc/testsuite/jit.dg/test-accessing-struct.c b/gcc/testsuite/jit.dg/test-accessing-struct.c
new file mode 100644
index 0000000..30fa157
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-accessing-struct.c
@@ -0,0 +1,109 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+struct foo
+{
+  int x;
+  int y;
+  int z;
+};
+
+int
+code_making_callback (gcc_jit_context *ctxt, void *user_data)
+{
+  /* Let's try to inject the equivalent of:
+     void
+     test_fn (struct foo *f)
+     {
+        f->z = f->x * f->y;
+     }
+  */
+  gcc_jit_type *void_type = gcc_jit_context_get_void_type (ctxt);
+  gcc_jit_type *int_type = gcc_jit_context_get_int_type (ctxt);
+  gcc_jit_field *x =
+    gcc_jit_context_new_field (ctxt,
+                               NULL,
+                               int_type,
+                               "x");
+  gcc_jit_field *y =
+    gcc_jit_context_new_field (ctxt,
+                               NULL,
+                               int_type,
+                               "y");
+  gcc_jit_field *z =
+    gcc_jit_context_new_field (ctxt,
+                               NULL,
+                               int_type,
+                               "z");
+  gcc_jit_field *fields[] = {x, y, z};
+  gcc_jit_type *struct_type =
+    gcc_jit_context_new_struct_type (ctxt, NULL, "foo", 3, fields);
+  gcc_jit_type *ptr_type = gcc_jit_type_get_pointer (struct_type);
+
+  /* Build the test_fn.  */
+  gcc_jit_param *param_f =
+    gcc_jit_context_new_param (ctxt, NULL, ptr_type, "f");
+  gcc_jit_function *test_fn =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                  GCC_JIT_FUNCTION_EXPORTED,
+                                  void_type,
+                                  "test_fn",
+                                  1, &param_f,
+                                  0);
+
+  /* f->x * f->y */
+  gcc_jit_rvalue *sum =
+    gcc_jit_context_new_binary_op (
+      ctxt, NULL,
+      GCC_JIT_BINARY_OP_MULT,
+      int_type,
+      gcc_jit_lvalue_as_rvalue (
+        gcc_jit_context_new_field_access (
+          ctxt, NULL,
+          gcc_jit_param_as_rvalue (param_f),
+          "x")),
+      gcc_jit_lvalue_as_rvalue (
+        gcc_jit_context_new_field_access (
+          ctxt, NULL,
+          gcc_jit_param_as_rvalue (param_f),
+          "y")));
+
+  /* f->z = ... */
+  gcc_jit_function_add_assignment (
+    test_fn,
+    NULL,
+    gcc_jit_context_new_field_access (
+      ctxt, NULL,
+      gcc_jit_param_as_rvalue (param_f),
+      "z"),
+    sum);
+
+  return 0;
+}
+
+void
+verify_code (gcc_jit_result *result)
+{
+  typedef void (*fn_type) (struct foo *);
+  CHECK_NON_NULL (result);
+
+  fn_type test_fn =
+    (fn_type)gcc_jit_result_get_code (result, "test_fn");
+  CHECK_NON_NULL (test_fn);
+
+  struct foo tmp;
+  tmp.x = 5;
+  tmp.y = 7;
+  tmp.z = 0;
+
+  /* Call the JIT-generated function.  */
+  test_fn (&tmp);
+
+  /* Verify that the code correctly modified the field "z".  */
+  CHECK_VALUE (tmp.z, 35);
+}
+
diff --git a/gcc/testsuite/jit.dg/test-calling-external-function.c b/gcc/testsuite/jit.dg/test-calling-external-function.c
new file mode 100644
index 0000000..817b326
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-calling-external-function.c
@@ -0,0 +1,117 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+  extern void
+  called_function (int i, int j, int k);
+
+#ifdef __cplusplus
+}
+#endif
+
+int
+code_making_callback (gcc_jit_context *ctxt, void *user_data)
+{
+  /* Let's try to inject the equivalent of:
+     extern void called_function (int i, int j, int k);
+
+     void
+     test_fn (int a)
+     {
+        called_function (a * 3, a * 4, a * 5);
+     }
+  */
+  int i;
+  gcc_jit_type *void_type = gcc_jit_context_get_void_type (ctxt);
+  gcc_jit_type *int_type = gcc_jit_context_get_int_type (ctxt);
+
+  /* Declare the imported function.  */
+  gcc_jit_param *params[3];
+  params[0] =
+    gcc_jit_context_new_param (ctxt, NULL, int_type, "i");
+  params[1] =
+    gcc_jit_context_new_param (ctxt, NULL, int_type, "j");
+  params[2] =
+    gcc_jit_context_new_param (ctxt, NULL, int_type, "k");
+  gcc_jit_function *called_fn =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                  GCC_JIT_FUNCTION_IMPORTED,
+                                  void_type,
+                                  "called_function",
+                                  3, params,
+                                  0);
+
+  /* Build the test_fn.  */
+  gcc_jit_param *param_a =
+    gcc_jit_context_new_param (ctxt, NULL, int_type, "a");
+  gcc_jit_function *test_fn =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                  GCC_JIT_FUNCTION_EXPORTED,
+                                  void_type,
+                                  "test_fn",
+                                  1, &param_a,
+                                  0);
+  /* "a * 3, a * 4, a * 5"  */
+  gcc_jit_rvalue *args[3];
+  for (i = 0; i < 3; i++)
+    args[i] =
+      gcc_jit_context_new_binary_op (
+        ctxt, NULL,
+        GCC_JIT_BINARY_OP_MULT,
+        int_type,
+        gcc_jit_param_as_rvalue (param_a),
+        gcc_jit_context_new_rvalue_from_int (
+          ctxt,
+          int_type,
+          (i + 3) ));
+
+  gcc_jit_function_add_eval (
+    test_fn, NULL,
+    gcc_jit_context_new_call (ctxt,
+                              NULL,
+                              called_fn,
+                              3, args));
+
+    return 0;
+}
+
+static int called_with[3];
+
+extern void
+called_function (int i, int j, int k)
+{
+  called_with[0] = i;
+  called_with[1] = j;
+  called_with[2] = k;
+}
+
+void
+verify_code (gcc_jit_result *result)
+{
+  typedef void (*fn_type) (int);
+  CHECK_NON_NULL (result);
+
+  fn_type test_fn =
+    (fn_type)gcc_jit_result_get_code (result, "test_fn");
+  CHECK_NON_NULL (test_fn);
+
+  called_with[0] = 0;
+  called_with[1] = 0;
+  called_with[2] = 0;
+
+  /* Call the JIT-generated function.  */
+  test_fn (5);
+
+  /* Verify that it correctly called "called_function".  */
+  CHECK_VALUE (called_with[0], 15);
+  CHECK_VALUE (called_with[1], 20);
+  CHECK_VALUE (called_with[2], 25);
+}
+
diff --git a/gcc/testsuite/jit.dg/test-dot-product.c b/gcc/testsuite/jit.dg/test-dot-product.c
new file mode 100644
index 0000000..31cbef4
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-dot-product.c
@@ -0,0 +1,114 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+int
+code_making_callback (gcc_jit_context *ctxt, void *user_data)
+{
+  /* Let's try to inject the equivalent of:
+
+	double
+	my_dot_product (int n, double *a, double *b)
+	{
+	  double result = 0.;
+	  for (int i = 0; i < n; i++)
+	    result += a[i] * b[i];
+	  return result
+	}
+
+     and see what the optimizer can do.  */
+  gcc_jit_type *val_type = gcc_jit_context_get_double_type (ctxt);
+  gcc_jit_type *ptr_type = gcc_jit_type_get_pointer (val_type);
+  gcc_jit_type *int_type = gcc_jit_context_get_int_type (ctxt);
+
+  gcc_jit_type *return_type = val_type;
+  gcc_jit_param *param_n =
+    gcc_jit_context_new_param (ctxt, NULL, int_type, "n");
+  gcc_jit_param *param_a =
+    gcc_jit_context_new_param (ctxt, NULL, ptr_type, "a");
+  gcc_jit_param *param_b =
+    gcc_jit_context_new_param (ctxt, NULL, ptr_type, "b");
+  gcc_jit_param *params[3] = {param_n, param_a, param_b};
+  gcc_jit_function *func =
+    gcc_jit_context_new_function (ctxt, NULL,
+				  GCC_JIT_FUNCTION_EXPORTED,
+				  return_type,
+				  "my_dot_product",
+				  3, params, 0);
+
+  /* Build: "double result = 0.;" */
+  gcc_jit_local *result =
+    gcc_jit_context_new_local (ctxt, NULL, val_type, "result");
+
+  gcc_jit_function_add_assignment (func, NULL,
+    gcc_jit_local_as_lvalue (result),
+    gcc_jit_context_zero (ctxt, val_type));
+
+  /* Build: "for (int i = 0; i < n; i++)" */
+  gcc_jit_local *i =
+    gcc_jit_context_new_local (ctxt, NULL, int_type, "i");
+  gcc_jit_function_add_assignment (func, NULL,
+    gcc_jit_local_as_lvalue (i), gcc_jit_context_zero (ctxt, int_type));
+  gcc_jit_loop *loop = gcc_jit_function_new_loop (func, NULL,
+    /* (i < n) */
+    gcc_jit_context_new_comparison (
+      ctxt, NULL,
+      GCC_JIT_COMPARISON_LT,
+      gcc_jit_local_as_rvalue (i),
+      gcc_jit_param_as_rvalue (param_n)));
+
+  /* Build: "result += a[i] * b[i];" */
+  gcc_jit_function_add_assignment_op (
+    func, NULL,
+    gcc_jit_local_as_lvalue (result),
+    GCC_JIT_BINARY_OP_PLUS,
+    gcc_jit_context_new_binary_op (ctxt, NULL,
+      GCC_JIT_BINARY_OP_MULT,
+      val_type,
+      gcc_jit_context_new_array_lookup(
+        ctxt, NULL,
+        gcc_jit_param_as_rvalue (param_a),
+        gcc_jit_local_as_rvalue (i)),
+      gcc_jit_context_new_array_lookup(
+        ctxt, NULL,
+        gcc_jit_param_as_rvalue (param_b),
+        gcc_jit_local_as_rvalue (i))));
+
+  /* Build: "i++" */
+  gcc_jit_function_add_assignment_op (
+    func, NULL,
+    gcc_jit_local_as_lvalue (i),
+    GCC_JIT_BINARY_OP_PLUS,
+    gcc_jit_context_one (ctxt, int_type));
+
+  gcc_jit_loop_end (loop, NULL);
+
+  /* Build: "return result;" */
+  gcc_jit_function_add_return (
+    func,
+    NULL,
+    gcc_jit_local_as_rvalue (result));
+
+  return 0;
+}
+
+void
+verify_code (gcc_jit_result *result)
+{
+  typedef double (*my_dot_product_fn_type) (int n, double *a, double *b);
+  CHECK_NON_NULL (result);
+
+  my_dot_product_fn_type my_dot_product =
+    (my_dot_product_fn_type)gcc_jit_result_get_code (result,
+						     "my_dot_product");
+  CHECK_NON_NULL (my_dot_product);
+  double test_array[] = {1., 2., 3., 4., 5., 6., 7., 8., 9., 10.};
+  double val = my_dot_product (10, test_array, test_array);
+  printf("my_dot_product returned: %f\n", val);
+  CHECK_VALUE (val, 385.0);
+}
+
diff --git a/gcc/testsuite/jit.dg/test-factorial.c b/gcc/testsuite/jit.dg/test-factorial.c
new file mode 100644
index 0000000..d3b83ba
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-factorial.c
@@ -0,0 +1,105 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+int
+code_making_callback (gcc_jit_context *ctxt, void *user_data)
+{
+  /* Let's try to inject the equivalent of:
+
+      int
+      my_factorial (int x)
+      {
+        if (x < 2)
+          return x;
+        else
+          return x * my_factorial (x - 1);
+      }
+
+     and see if the optimizer eliminates the recursion (it does).
+   */
+  gcc_jit_type *the_type = gcc_jit_context_get_int_type (ctxt);
+  gcc_jit_type *return_type = the_type;
+
+  gcc_jit_param *x =
+    gcc_jit_context_new_param (ctxt, NULL, the_type, "x");
+  gcc_jit_param *params[1] = {x};
+  gcc_jit_function *func =
+    gcc_jit_context_new_function (ctxt, NULL,
+				  GCC_JIT_FUNCTION_EXPORTED,
+				  return_type,
+				  "my_factorial",
+				  1, params, 0);
+
+ /* Create forward labels: */
+  gcc_jit_label *label_true =
+    gcc_jit_function_new_forward_label (func, NULL);
+
+  gcc_jit_label *label_false =
+    gcc_jit_function_new_forward_label (func, NULL);
+
+ /* if (x < 2) */
+  gcc_jit_function_add_conditional (
+    func, NULL,
+    gcc_jit_context_new_comparison (
+      ctxt, NULL,
+      GCC_JIT_COMPARISON_LT,
+      gcc_jit_param_as_rvalue (x),
+      gcc_jit_context_new_rvalue_from_int (
+	ctxt,
+	the_type,
+	2)),
+    label_true,
+    label_false);
+
+  /* true branch: */
+  gcc_jit_function_place_forward_label (func, label_true);
+  /* return x */
+  gcc_jit_function_add_return (
+    func,
+    NULL,
+    gcc_jit_param_as_rvalue (x));
+
+  /* false branch: */
+  gcc_jit_function_place_forward_label (func, label_false);
+  gcc_jit_rvalue *x_minus_1 =
+    gcc_jit_context_new_binary_op (
+      ctxt, NULL,
+      GCC_JIT_BINARY_OP_MINUS, the_type,
+      gcc_jit_param_as_rvalue (x),
+      gcc_jit_context_new_rvalue_from_int (
+	ctxt,
+	the_type,
+	1));
+  gcc_jit_function_add_return (
+    func,
+    NULL,
+    gcc_jit_context_new_binary_op (
+      ctxt, NULL,
+      GCC_JIT_BINARY_OP_MULT, the_type,
+      gcc_jit_param_as_rvalue (x),
+      /* my_factorial (x - 1) */
+      gcc_jit_context_new_call (
+        ctxt, NULL,
+        func,
+        1, &x_minus_1)));
+  return 0;
+}
+
+void
+verify_code (gcc_jit_result *result)
+{
+  typedef int (*my_factorial_fn_type) (int);
+  CHECK_NON_NULL (result);
+  my_factorial_fn_type my_factorial =
+    (my_factorial_fn_type)gcc_jit_result_get_code (result, "my_factorial");
+  CHECK_NON_NULL (my_factorial);
+  int val = my_factorial (10);
+  printf("my_factorial returned: %d\n", val);
+  CHECK_VALUE (val, 3628800);
+}
+
diff --git a/gcc/testsuite/jit.dg/test-failure.c b/gcc/testsuite/jit.dg/test-failure.c
new file mode 100644
index 0000000..ac31964
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-failure.c
@@ -0,0 +1,19 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+int
+code_making_callback (gcc_jit_context *ctxt, void *user_data)
+{
+  return 1;
+}
+
+void
+verify_code (gcc_jit_result *result)
+{
+  CHECK_VALUE (result, NULL);
+}
+
diff --git a/gcc/testsuite/jit.dg/test-fibonacci.c b/gcc/testsuite/jit.dg/test-fibonacci.c
new file mode 100644
index 0000000..235e86e
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-fibonacci.c
@@ -0,0 +1,115 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+int
+code_making_callback (gcc_jit_context *ctxt, void *user_data)
+{
+  /* Let's try to inject the equivalent of:
+
+      fib.c: 1:   int
+      fib.c: 2:   my_fibonacci (int x)
+      fib.c: 3:   {
+      fib.c: 4:     if (x < 2)
+      fib.c: 5:       return x;
+      fib.c: 6:     else
+      fib.c: 7        return my_fibonacci (x - 1) + my_fibonacci (x - 2);
+      fib.c: 8    }
+   */
+  gcc_jit_type *the_type = gcc_jit_context_get_int_type (ctxt);
+  gcc_jit_type *return_type = the_type;
+
+  gcc_jit_param *x =
+    gcc_jit_context_new_param (ctxt, NULL, the_type, "x");
+  gcc_jit_param *params[1] = {x};
+  gcc_jit_function *func =
+    gcc_jit_context_new_function (ctxt, NULL,
+				  GCC_JIT_FUNCTION_EXPORTED,
+				  return_type,
+				  "my_fibonacci",
+				  1, params, 0);
+
+ /* Create forward labels: */
+  gcc_jit_label *label_true =
+    gcc_jit_function_new_forward_label (func, NULL);
+
+  gcc_jit_label *label_false =
+    gcc_jit_function_new_forward_label (func, NULL);
+
+ /* if (x < 2) */
+  gcc_jit_function_add_conditional (
+    func, NULL,
+    gcc_jit_context_new_comparison (
+      ctxt, NULL,
+      GCC_JIT_COMPARISON_LT,
+      gcc_jit_param_as_rvalue (x),
+      gcc_jit_context_new_rvalue_from_int (
+	ctxt,
+	the_type,
+	2)),
+    label_true,
+    label_false);
+
+  /* true branch: */
+  gcc_jit_function_place_forward_label (func, label_true);
+  /* return x */
+  gcc_jit_function_add_return (
+    func,
+    NULL,
+    gcc_jit_param_as_rvalue (x));
+
+  /* false branch: */
+  gcc_jit_function_place_forward_label (func, label_false);
+  gcc_jit_rvalue *x_minus_1 =
+    gcc_jit_context_new_binary_op (
+      ctxt, NULL,
+      GCC_JIT_BINARY_OP_MINUS, the_type,
+      gcc_jit_param_as_rvalue (x),
+      gcc_jit_context_new_rvalue_from_int (
+	ctxt,
+	the_type,
+	1));
+  gcc_jit_rvalue *x_minus_2 =
+    gcc_jit_context_new_binary_op (
+      ctxt, NULL,
+      GCC_JIT_BINARY_OP_MINUS, the_type,
+      gcc_jit_param_as_rvalue (x),
+      gcc_jit_context_new_rvalue_from_int (
+	ctxt,
+	the_type,
+	2));
+  gcc_jit_function_add_return (
+    func,
+    NULL,
+    gcc_jit_context_new_binary_op (
+      ctxt, NULL,
+      GCC_JIT_BINARY_OP_PLUS, the_type,
+      /* my_fibonacci (x - 1) */
+      gcc_jit_context_new_call (
+        ctxt, NULL,
+        func,
+        1, &x_minus_1),
+      /* my_fibonacci (x - 2) */
+      gcc_jit_context_new_call (
+        ctxt, NULL,
+        func,
+        1, &x_minus_2)));
+  return 0;
+}
+
+void
+verify_code (gcc_jit_result *result)
+{
+  typedef int (*my_fibonacci_fn_type) (int);
+  CHECK_NON_NULL (result);
+  my_fibonacci_fn_type my_fibonacci =
+    (my_fibonacci_fn_type)gcc_jit_result_get_code (result, "my_fibonacci");
+  CHECK_NON_NULL (my_fibonacci);
+  int val = my_fibonacci (10);
+  printf("my_fibonacci returned: %d\n", val);
+  CHECK_VALUE (val, 55);
+}
diff --git a/gcc/testsuite/jit.dg/test-hello-world.c b/gcc/testsuite/jit.dg/test-hello-world.c
new file mode 100644
index 0000000..e7856c6
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-hello-world.c
@@ -0,0 +1,64 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+extern int
+code_making_callback (gcc_jit_context *ctxt, void *user_data)
+{
+  /* Let's try to inject the equivalent of:
+     void
+     hello_world (const char *name)
+     {
+        printf ("hello %s\n", name);
+     }
+  */
+  gcc_jit_type *void_type = gcc_jit_context_get_void_type (ctxt);
+  gcc_jit_type *const_char_ptr_type =
+    gcc_jit_type_get_pointer (
+      gcc_jit_type_get_const (gcc_jit_context_get_char_type (ctxt)));
+  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_int_type (ctxt),
+                                  "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_function_add_eval (
+    func, NULL,
+    gcc_jit_context_new_call (ctxt,
+                              NULL,
+                              printf_func,
+                              2, args));
+  return 0;
+}
+
+extern void
+verify_code (gcc_jit_result *result)
+{
+  typedef void (*fn_type) (const char *);
+  CHECK_NON_NULL (result);
+  fn_type hello_world =
+    (fn_type)gcc_jit_result_get_code (result, "hello_world");
+  CHECK_NON_NULL (hello_world);
+  hello_world ("world");
+  fflush (stdout);
+}
diff --git a/gcc/testsuite/jit.dg/test-string-literal.c b/gcc/testsuite/jit.dg/test-string-literal.c
new file mode 100644
index 0000000..6027690
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-string-literal.c
@@ -0,0 +1,54 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+int
+code_making_callback (gcc_jit_context *ctxt, void *user_data)
+{
+  /* Let's try to inject the equivalent of:
+
+     const char *
+     test_fn (void)
+     {
+        return "hello world";
+     }
+  */
+  gcc_jit_type *const_char_ptr_type =
+    gcc_jit_type_get_pointer (
+      gcc_jit_type_get_const (gcc_jit_context_get_char_type (ctxt)));
+
+  /* Build the test_fn.  */
+  gcc_jit_function *test_fn =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                  GCC_JIT_FUNCTION_EXPORTED,
+                                  const_char_ptr_type,
+                                  "test_fn",
+                                  0, NULL,
+                                  0);
+
+  gcc_jit_function_add_return (
+    test_fn, NULL,
+    gcc_jit_context_new_string_literal (ctxt, "hello world"));
+
+  return 0;
+}
+
+void
+verify_code (gcc_jit_result *result)
+{
+  typedef const char *(*fn_type) (void);
+  CHECK_NON_NULL (result);
+  fn_type test_fn =
+    (fn_type)gcc_jit_result_get_code (result, "test_fn");
+  CHECK_NON_NULL (test_fn);
+
+  /* Call the JIT-generated function.  */
+  const char *str = test_fn ();
+  CHECK_NON_NULL (str);
+  CHECK_VALUE (strcmp (str, "hello world"), 0);
+}
+
diff --git a/gcc/testsuite/jit.dg/test-sum-of-squares.c b/gcc/testsuite/jit.dg/test-sum-of-squares.c
new file mode 100644
index 0000000..4f1685d
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-sum-of-squares.c
@@ -0,0 +1,131 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+int
+code_making_callback (gcc_jit_context *ctxt, void *user_data)
+{
+  /*
+    Simple sum-of-squares, to test conditionals and looping
+
+    int loop_test (int n)
+    {
+      int i;
+      int sum = 0;
+      for (i = 0; i < n ; i ++)
+      {
+	sum += i * i;
+      }
+      return sum;
+   */
+  gcc_jit_type *the_type = gcc_jit_context_get_int_type (ctxt);
+  gcc_jit_type *return_type = the_type;
+
+  gcc_jit_param *n =
+    gcc_jit_context_new_param (ctxt, NULL, the_type, "n");
+  gcc_jit_param *params[1] = {n};
+  gcc_jit_function *func =
+    gcc_jit_context_new_function (ctxt, NULL,
+				  GCC_JIT_FUNCTION_EXPORTED,
+				  return_type,
+				  "loop_test",
+				  1, params, 0);
+
+  /* Build locals:  */
+  gcc_jit_local *i =
+    gcc_jit_context_new_local (ctxt, NULL, the_type, "i");
+  gcc_jit_local *sum =
+    gcc_jit_context_new_local (ctxt, NULL, the_type, "sum");
+
+  /* Create forward label: */
+  gcc_jit_label *label_after_loop =
+    gcc_jit_function_new_forward_label (func, "after_loop");
+
+  /* sum = 0; */
+  gcc_jit_function_add_assignment (
+    func, NULL,
+    gcc_jit_local_as_lvalue (sum),
+    gcc_jit_context_new_rvalue_from_int (ctxt, the_type, 0));
+
+  /* i = 0; */
+  gcc_jit_function_add_assignment (
+    func, NULL,
+    gcc_jit_local_as_lvalue (i),
+    gcc_jit_context_new_rvalue_from_int (ctxt, the_type, 0));
+
+
+  /* label "cond:" */
+  gcc_jit_label *label_cond =
+    gcc_jit_function_add_label (func, NULL, "cond");
+
+  /* if (i >= n) */
+  gcc_jit_function_add_conditional (
+    func, NULL,
+    gcc_jit_context_new_comparison (
+       ctxt, NULL,
+       GCC_JIT_COMPARISON_GE,
+       gcc_jit_local_as_rvalue (i),
+       gcc_jit_param_as_rvalue (n)),
+    label_after_loop,
+    NULL);
+
+  /* sum += i * i */
+  gcc_jit_function_add_assignment (
+    func, NULL,
+    gcc_jit_local_as_lvalue (sum),
+    gcc_jit_context_new_binary_op (
+      ctxt, NULL,
+      GCC_JIT_BINARY_OP_PLUS, the_type,
+      gcc_jit_local_as_rvalue (sum),
+      gcc_jit_context_new_binary_op (
+	 ctxt, NULL,
+	 GCC_JIT_BINARY_OP_MULT, the_type,
+	 gcc_jit_local_as_rvalue (i),
+	 gcc_jit_local_as_rvalue (i))));
+
+  /* i++ */
+  gcc_jit_function_add_assignment (
+    func, NULL,
+    gcc_jit_local_as_lvalue (i),
+    gcc_jit_context_new_binary_op (
+      ctxt, NULL,
+      GCC_JIT_BINARY_OP_PLUS, the_type,
+      gcc_jit_local_as_rvalue (i),
+      gcc_jit_context_new_rvalue_from_int (
+	ctxt,
+	the_type,
+	1)));
+
+  /* goto label_cond; */
+  gcc_jit_function_add_jump (
+    func, NULL,
+    label_cond);
+
+  /* label "after_loop:" */
+  gcc_jit_function_place_forward_label (func, label_after_loop);
+
+  /* return sum */
+  gcc_jit_function_add_return (
+    func,
+    NULL,
+    gcc_jit_local_as_rvalue (sum));
+
+  return 0;
+}
+
+void
+verify_code (gcc_jit_result *result)
+{
+  typedef int (*loop_test_fn_type) (int);
+  CHECK_NON_NULL (result);
+  loop_test_fn_type loop_test =
+    (loop_test_fn_type)gcc_jit_result_get_code (result, "loop_test");
+  CHECK_NON_NULL (loop_test);
+  int val = loop_test (10);
+  printf("loop_test returned: %d\n", val);
+  CHECK_VALUE (val, 285);
+}
diff --git a/gcc/timevar.c b/gcc/timevar.c
index 23b7118..2ceee51 100644
--- a/gcc/timevar.c
+++ b/gcc/timevar.c
@@ -223,6 +223,10 @@ timevar_accumulate (struct timevar_time_def *timer,
 void
 timevar_init (void)
 {
+  /* FIXME */
+  if (timevar_enable)
+    return;
+
   timevar_enable = true;
 
   /* Zero all elapsed times.  */
diff --git a/gcc/timevar.def b/gcc/timevar.def
index 5a880a8..9a3b345 100644
--- a/gcc/timevar.def
+++ b/gcc/timevar.def
@@ -273,3 +273,9 @@ DEFTIMEVAR (TV_VERIFY_LOOP_CLOSED    , "verify loop closed")
 DEFTIMEVAR (TV_VERIFY_RTL_SHARING    , "verify RTL sharing")
 DEFTIMEVAR (TV_REBUILD_FREQUENCIES   , "rebuild frequencies")
 DEFTIMEVAR (TV_REPAIR_LOOPS	     , "repair loop structures")
+
+/* Stuff used by libgccjit.so.  */
+DEFTIMEVAR (TV_CLIENT_CALLBACK	     , "JIT client callback")
+DEFTIMEVAR (TV_ASSEMBLE	     , "assemble JIT code")
+DEFTIMEVAR (TV_LINK		     , "link JIT code")
+DEFTIMEVAR (TV_LOAD		     , "load JIT result")
diff --git a/gcc/toplev.c b/gcc/toplev.c
index 3473211..cd0e052 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -77,6 +77,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "diagnostic-color.h"
 #include "context.h"
 #include "pass_manager.h"
+#include "dwarf2out.h"
 
 #if defined(DBX_DEBUGGING_INFO) || defined(XCOFF_DEBUGGING_INFO)
 #include "dbxout.h"
@@ -92,7 +93,7 @@ along with GCC; see the file COPYING3.  If not see
 #endif
 
 static void general_init (const char *);
-static void do_compile (void);
+static void do_compile (const toplev_options *toplev_opts);
 static void process_options (void);
 static void backend_init (void);
 static int lang_dependent_init (const char *);
@@ -1849,13 +1850,17 @@ finalize (bool no_backend)
 
 /* Initialize the compiler, and compile the input file.  */
 static void
-do_compile (void)
+do_compile (const toplev_options *toplev_opts)
 {
   /* Initialize timing first.  The C front ends read the main file in
      the post_options hook, and C++ does file timings.  */
-  if (time_report || !quiet_flag  || flag_detailed_statistics)
-    timevar_init ();
-  timevar_start (TV_TOTAL);
+  if (toplev_opts->use_TV_TOTAL)
+    {
+      if (time_report || !quiet_flag  || flag_detailed_statistics)
+        timevar_init ();
+
+      timevar_start (TV_TOTAL);
+    }
 
   process_options ();
 
@@ -1902,9 +1907,12 @@ do_compile (void)
       timevar_stop (TV_PHASE_FINALIZE);
     }
 
-  /* Stop timing and print the times.  */
-  timevar_stop (TV_TOTAL);
-  timevar_print (stderr);
+  if (toplev_opts->use_TV_TOTAL)
+    {
+      /* Stop timing and print the times.  */
+      timevar_stop (TV_TOTAL);
+      timevar_print (stderr);
+    }
 }
 
 /* Entry point of cc1, cc1plus, jc1, f771, etc.
@@ -1914,7 +1922,7 @@ do_compile (void)
    It is not safe to call this function more than once.  */
 
 int
-toplev_main (int argc, char **argv)
+toplev_main (int argc, char **argv, const toplev_options *toplev_opts)
 {
   /* Parsing and gimplification sometimes need quite large stack.
      Increase stack size limits if possible.  */
@@ -1964,7 +1972,7 @@ toplev_main (int argc, char **argv)
 
   /* Exit early if we can (e.g. -help).  */
   if (!exit_after_options)
-    do_compile ();
+    do_compile (toplev_opts);
 
   if (warningcount || errorcount || werrorcount)
     print_ignored_options ();
@@ -1980,3 +1988,17 @@ toplev_main (int argc, char **argv)
 
   return (SUCCESS_EXIT_CODE);
 }
+
+/* For those that want to, this function aims to clean up enough state that
+   you can call toplev_main again. */
+void toplev_finalize (void)
+{
+  cgraph_c_finalize ();
+  cgraphbuild_c_finalize ();
+  cgraphunit_c_finalize ();
+  dwarf2out_c_finalize ();
+  ipa_c_finalize ();
+  predict_c_finalize ();
+  symtab_c_finalize ();
+  varpool_c_finalize ();
+}
diff --git a/gcc/toplev.h b/gcc/toplev.h
index 84ffdb0..a99fee1 100644
--- a/gcc/toplev.h
+++ b/gcc/toplev.h
@@ -24,7 +24,16 @@ along with GCC; see the file COPYING3.  If not see
 extern struct cl_decoded_option *save_decoded_options;
 extern unsigned int save_decoded_options_count;
 
-extern int toplev_main (int, char **);
+/* Options for invoking toplev_main.  */
+struct toplev_options
+{
+  /* Should do_compile use TV_TOTAL, or is some other wrapper
+     using it? */
+  bool use_TV_TOTAL;
+};
+
+extern int toplev_main (int, char **, const toplev_options *toplev_opts);
+extern void toplev_finalize (void);
 extern void rest_of_decl_compilation (tree, int, int);
 extern void rest_of_type_compilation (tree, int);
 extern void init_optimization_passes (void);
diff --git a/gcc/varpool.c b/gcc/varpool.c
index d5324ad..0852d88 100644
--- a/gcc/varpool.c
+++ b/gcc/varpool.c
@@ -682,3 +682,7 @@ varpool_for_node_and_aliases (struct varpool_node *node,
       }
   return false;
 }
+
+void varpool_c_finalize (void)
+{
+}
diff --git a/libbacktrace/configure b/libbacktrace/configure
index 46ad9ee..eac9146 100755
--- a/libbacktrace/configure
+++ b/libbacktrace/configure
@@ -731,6 +731,7 @@ with_gnu_ld
 enable_libtool_lock
 enable_multilib
 with_system_libunwind
+enable_host_shared
 '
       ac_precious_vars='build_alias
 host_alias
@@ -1369,6 +1370,7 @@ Optional Features:
                           optimize for fast installation [default=yes]
   --disable-libtool-lock  avoid locking (might break parallel builds)
   --enable-multilib       build many library versions (default)
+  --enable-host-shared    build host code as shared libraries
 
 Optional Packages:
   --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
@@ -11081,7 +11083,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11084 "configure"
+#line 11086 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -11187,7 +11189,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11190 "configure"
+#line 11192 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -11690,6 +11692,12 @@ PIC_FLAG=
 if test -n "${with_target_subdir}"; then
   PIC_FLAG=-fPIC
 fi
+# Similarly, use -fPIC with --enable-host-shared:
+# Check whether --enable-host-shared was given.
+if test "${enable_host_shared+set}" = set; then :
+  enableval=$enable_host_shared; PIC_FLAG=-fPIC
+fi
+
 
 
 # Test for __sync support.
diff --git a/libbacktrace/configure.ac b/libbacktrace/configure.ac
index 28b2a1c..48c8620 100644
--- a/libbacktrace/configure.ac
+++ b/libbacktrace/configure.ac
@@ -165,6 +165,11 @@ PIC_FLAG=
 if test -n "${with_target_subdir}"; then
   PIC_FLAG=-fPIC
 fi
+# Similarly, use -fPIC with --enable-host-shared:
+AC_ARG_ENABLE(host-shared,
+[AS_HELP_STRING([--enable-host-shared],
+		[build host code as shared libraries])],
+[PIC_FLAG=-fPIC], [])
 AC_SUBST(PIC_FLAG)
 
 # Test for __sync support.
diff --git a/libcpp/configure b/libcpp/configure
index 60ce2e5..d2eaea0 100755
--- a/libcpp/configure
+++ b/libcpp/configure
@@ -701,6 +701,7 @@ with_libiconv_prefix
 enable_maintainer_mode
 enable_checking
 enable_canonical_system_headers
+enable_host_shared
 '
       ac_precious_vars='build_alias
 host_alias
@@ -1340,6 +1341,7 @@ Optional Features:
                           other strings
   --enable-canonical-system-headers
                           enable or disable system headers canonicalization
+  --enable-host-shared    build host code as shared libraries
 
 Optional Packages:
   --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
@@ -7204,6 +7206,15 @@ fi
 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 esac
 
+# Enable --enable-host-shared.
+# Check whether --enable-host-shared was given.
+if test "${enable_host_shared+set}" = set; then :
+  enableval=$enable_host_shared; CFLAGS="-fPIC $CFLAGS"; CXXFLAGS="-fPIC $CXXFLAGS"
+fi
+
+
+
+
 # Output.
 
 ac_config_headers="$ac_config_headers config.h:config.in"
diff --git a/libcpp/configure.ac b/libcpp/configure.ac
index 799301f..1b4920b 100644
--- a/libcpp/configure.ac
+++ b/libcpp/configure.ac
@@ -220,6 +220,14 @@ case $target in
 		 [Define to 1 if you can assemble SSE4 insns.])])
 esac
 
+# Enable --enable-host-shared.
+AC_ARG_ENABLE(host-shared,
+[AS_HELP_STRING([--enable-host-shared],
+		[build host code as shared libraries])],
+[CFLAGS="-fPIC $CFLAGS"; CXXFLAGS="-fPIC $CXXFLAGS"], [])
+AC_SUBST(CFLAGS)
+AC_SUBST(CXXFLAGS)
+
 # Output.
 
 AC_CONFIG_HEADERS(config.h:config.in, [echo timestamp > stamp-h1])
diff --git a/libdecnumber/configure b/libdecnumber/configure
index 4a1896e..61438ec 100755
--- a/libdecnumber/configure
+++ b/libdecnumber/configure
@@ -593,6 +593,7 @@ ac_includes_default="\
 
 ac_subst_vars='LTLIBOBJS
 LIBOBJS
+CXXFLAGS
 ADDITIONAL_OBJS
 enable_decimal_float
 target_os
@@ -670,6 +671,7 @@ enable_option_checking
 enable_werror_always
 enable_maintainer_mode
 enable_decimal_float
+enable_host_shared
 '
       ac_precious_vars='build_alias
 host_alias
@@ -1301,6 +1303,7 @@ Optional Features:
 			enable decimal float extension to C.  Selecting 'bid'
 			or 'dpd' choses which decimal floating point format
 			to use
+  --enable-host-shared    build host code as shared libraries
 
 Some influential environment variables:
   CC          C compiler command
@@ -4889,6 +4892,15 @@ $as_echo "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h
  esac
 
 
+# Enable --enable-host-shared.
+# Check whether --enable-host-shared was given.
+if test "${enable_host_shared+set}" = set; then :
+  enableval=$enable_host_shared; CFLAGS="-fPIC $CFLAGS"; CXXFLAGS="-fPIC $CXXFLAGS"
+fi
+
+
+
+
 # Output.
 
 ac_config_headers="$ac_config_headers config.h:config.in"
diff --git a/libdecnumber/configure.ac b/libdecnumber/configure.ac
index 6cfc803..e2f0c92 100644
--- a/libdecnumber/configure.ac
+++ b/libdecnumber/configure.ac
@@ -95,6 +95,14 @@ AC_SUBST(ADDITIONAL_OBJS)
 
 AC_C_BIGENDIAN
 
+# Enable --enable-host-shared.
+AC_ARG_ENABLE(host-shared,
+[AS_HELP_STRING([--enable-host-shared],
+		[build host code as shared libraries])],
+[CFLAGS="-fPIC $CFLAGS"; CXXFLAGS="-fPIC $CXXFLAGS"], [])
+AC_SUBST(CFLAGS)
+AC_SUBST(CXXFLAGS)
+
 # Output.
 
 AC_CONFIG_HEADERS(config.h:config.in, [echo timestamp > stamp-h1])
diff --git a/libiberty/configure b/libiberty/configure
index e601ccd..b71141a 100755
--- a/libiberty/configure
+++ b/libiberty/configure
@@ -4963,6 +4963,12 @@ case "${enable_shared}" in
   "") shared=no ;;
   *) shared=yes ;;
 esac
+
+# ...unless --enable-host-shared was passed from top-level config:
+if [ "${enable_host_shared}" = "yes" ]; then
+  shared=yes
+fi
+
 if [ "${shared}" != "yes" ]; then
   PICFLAG=
 fi
diff --git a/libiberty/configure.ac b/libiberty/configure.ac
index fcea46f..4ad88a9 100644
--- a/libiberty/configure.ac
+++ b/libiberty/configure.ac
@@ -225,6 +225,12 @@ case "${enable_shared}" in
   "") shared=no ;;
   *) shared=yes ;;
 esac
+
+# ...unless --enable-host-shared was passed from top-level config:
+if [[ "${enable_host_shared}" = "yes" ]]; then
+  shared=yes
+fi
+
 if [[ "${shared}" != "yes" ]]; then
   PICFLAG=
 fi
diff --git a/zlib/configure b/zlib/configure
index 8e4a93f..11ae8cb 100755
--- a/zlib/configure
+++ b/zlib/configure
@@ -736,6 +736,7 @@ with_pic
 enable_fast_install
 with_gnu_ld
 enable_libtool_lock
+enable_host_shared
 '
       ac_precious_vars='build_alias
 host_alias
@@ -1370,6 +1371,7 @@ Optional Features:
   --enable-fast-install[=PKGS]
                           optimize for fast installation [default=yes]
   --disable-libtool-lock  avoid locking (might break parallel builds)
+  --enable-host-shared    build host code as shared libraries
 
 Optional Packages:
   --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
@@ -10394,7 +10396,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 10397 "configure"
+#line 10399 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -10500,7 +10502,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 10503 "configure"
+#line 10505 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -11196,6 +11198,12 @@ else
   multilib_arg=
 fi
 
+# Check whether --enable-host-shared was given.
+if test "${enable_host_shared+set}" = set; then :
+  enableval=$enable_host_shared; CFLAGS="-fPIC $CFLAGS"
+fi
+
+
 ac_config_files="$ac_config_files Makefile"
 
 cat >confcache <<\_ACEOF
diff --git a/zlib/configure.ac b/zlib/configure.ac
index 80253e4..c2540d9 100644
--- a/zlib/configure.ac
+++ b/zlib/configure.ac
@@ -119,5 +119,10 @@ else
   multilib_arg=
 fi
 
+AC_ARG_ENABLE(host-shared,
+[AS_HELP_STRING([--enable-host-shared],
+		[build host code as shared libraries])],
+[CFLAGS="-fPIC $CFLAGS"], [])
+
 AC_CONFIG_FILES([Makefile])
 AC_OUTPUT

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]