public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH 05/27] New file: gcc/jit/config-lang.in
  2014-10-31 17:07 [PATCH 00/27] Merger of jit branch v3 David Malcolm
                   ` (6 preceding siblings ...)
  2014-10-31 17:07 ` [PATCH 06/27] New file: gcc/jit/Make-lang.in David Malcolm
@ 2014-10-31 17:07 ` David Malcolm
  2014-10-31 21:20   ` Jeff Law
  2014-10-31 17:07 ` [PATCH 09/27] New file: gcc/jit/libgccjit.map David Malcolm
                   ` (17 subsequent siblings)
  25 siblings, 1 reply; 71+ messages in thread
From: David Malcolm @ 2014-10-31 17:07 UTC (permalink / raw)
  To: gcc-patches, jit; +Cc: David Malcolm

gcc/jit/
	* config-lang.in: New.
---
 gcc/jit/config-lang.in | 38 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 38 insertions(+)
 create mode 100644 gcc/jit/config-lang.in

diff --git a/gcc/jit/config-lang.in b/gcc/jit/config-lang.in
new file mode 100644
index 0000000..7a32afe
--- /dev/null
+++ b/gcc/jit/config-lang.in
@@ -0,0 +1,38 @@
+# Top level configure fragment for libgccjit.so.
+#   Copyright (C) 2013-2014 Free Software Foundation, Inc.
+
+#This file is part of GCC.
+
+#GCC is free software; you can redistribute it and/or modify
+#it under the terms of the GNU General Public License as published by
+#the Free Software Foundation; either version 3, or (at your option)
+#any later version.
+
+#GCC is distributed in the hope that it will be useful,
+#but WITHOUT ANY WARRANTY; without even the implied warranty of
+#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+# Configure looks for the existence of this file to auto-config each language.
+# We define several parameters used by configure:
+#
+# language	- name of language as it would appear in $(LANGUAGES)
+# compilers	- value to add to $(COMPILERS)
+
+language="jit"
+
+compilers="libgccjit.so"
+
+target_libs=""
+
+gtfiles="\$(srcdir)/jit/dummy-frontend.c"
+
+# The configuration requires --enable-host-shared
+# for jit to be supported.
+# Hence to get the jit, one must configure with:
+#   --enable-host-shared --enable-languages=jit
+build_by_default="no"
-- 
1.8.5.3

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

* [PATCH 03/27] Add Sphinx to install.texi
  2014-10-31 17:07 [PATCH 00/27] Merger of jit branch v3 David Malcolm
  2014-10-31 17:07 ` [PATCH 02/27] JIT-related changes outside of jit subdir David Malcolm
@ 2014-10-31 17:07 ` David Malcolm
  2014-10-31 21:18   ` Jeff Law
  2014-10-31 17:07 ` [PATCH 07/27] New file: gcc/jit/dummy-frontend.c David Malcolm
                   ` (23 subsequent siblings)
  25 siblings, 1 reply; 71+ messages in thread
From: David Malcolm @ 2014-10-31 17:07 UTC (permalink / raw)
  To: gcc-patches, jit; +Cc: David Malcolm

In https://gcc.gnu.org/ml/gcc-patches/2014-10/msg01793.html,
Joseph said:

> Although Sphinx isn't a build dependency, as a dependency for
> regenerating checked-in files I think it should be documented in
> install.texi (like autoconf, gettext, etc.).

This patch adds such documentation.

gcc/ChangeLog:
	* doc/install.texi (Tools/packages necessary for modifying GCC):
	Add Sphinx.
---
 gcc/doc/install.texi | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/gcc/doc/install.texi b/gcc/doc/install.texi
index 06fcd8a..ef7656c 100644
--- a/gcc/doc/install.texi
+++ b/gcc/doc/install.texi
@@ -491,6 +491,11 @@ Necessary for running @command{texi2dvi} and @command{texi2pdf}, which
 are used when running @command{make dvi} or @command{make pdf} to create
 DVI or PDF files, respectively.
 
+@item Sphinx version 1.0 (or later)
+
+Necessary to regenerate @file{jit/docs/_build/texinfo} from the @file{.rst}
+files in the directories below @file{jit/docs}.
+
 @item SVN (any version)
 @itemx SSH (any version)
 
-- 
1.8.5.3

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

* [PATCH 01/27] gcc: configure and Makefile changes needed by jit
  2014-10-31 17:07 [PATCH 00/27] Merger of jit branch v3 David Malcolm
                   ` (3 preceding siblings ...)
  2014-10-31 17:07 ` [PATCH 20/27] Documentation: Makefile and conf.py David Malcolm
@ 2014-10-31 17:07 ` David Malcolm
  2014-11-03 21:36   ` Jeff Law
  2014-11-13 20:16   ` Thomas Schwinge
  2014-10-31 17:07 ` [PATCH 21/27] Documentation: the "examples" subdirectory David Malcolm
                   ` (20 subsequent siblings)
  25 siblings, 2 replies; 71+ messages in thread
From: David Malcolm @ 2014-10-31 17:07 UTC (permalink / raw)
  To: gcc-patches, jit; +Cc: David Malcolm

An earlier version of this was posted as:
  "[PATCH 2/5] gcc: configure and Makefile changes needed by jit"
    https://gcc.gnu.org/ml/gcc-patches/2014-10/msg01169.html

Since then, I've eliminated the gcc_version, bindir, and pkgconfigdir
additions, and added the FULL_DRIVER_NAME variable and symlink, to
avoid the need to install when running the jit testsuite.

gcc/ChangeLog:
	* Makefile.in (doc_build_sys): New variable, set to "sphinx" if
	sphinx is installed, falling back to "texinfo" otherwise.
	(FULL_DRIVER_NAME): New variable, adapted from the
	install-driver target.  New target, a symlink within the builddir,
	linked to "xgcc", for use when running the JIT library from the
	builddir.
	(MOSTLYCLEANFILES): Add FULL_DRIVER_NAME.
	(install-driver): Use $(FULL_DRIVER_NAME) rather than spelling it
	out.

	* configure.ac (doc_build_sys): New variable, set to "sphinx" if
	sphinx is installed, falling back to "texinfo" otherwise.
	(GCC_DRIVER_NAME): Generate a gcc-driver-name.h file containing
	GCC_DRIVER_NAME for the benefit of jit/internal-api.c.

	* configure: Regenerate.
---
 gcc/Makefile.in  | 20 +++++++++++++++++---
 gcc/configure    | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++--
 gcc/configure.ac | 10 ++++++++++
 3 files changed, 77 insertions(+), 5 deletions(-)

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index e2100ff..ded7471 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -316,6 +316,11 @@ write_entries_to_file = $(shell rm -f $(2) || :) $(shell touch $(2)) \
 			  $(shell expr $(range) + $(write_entries_to_file_split) - 1), $(1))" \
 	     | tr ' ' '\012' >> $(2)))
 
+# The jit documentation looks better if built with sphinx, but can be
+# built with texinfo if sphinx is not available.
+# configure sets "doc_build_sys" to "sphinx" or "texinfo" accordingly
+doc_build_sys=@doc_build_sys@
+
 # --------
 # UNSORTED
 # --------
@@ -1504,6 +1509,9 @@ BACKEND = libbackend.a main.o @TREEBROWSER@ libcommon-target.a libcommon.a \
 # front-end checking.
 TREECHECKING = @TREECHECKING@
 
+# The full name of the driver on installation
+FULL_DRIVER_NAME=$(target_noncanonical)-gcc-$(version)$(exeext)
+
 MOSTLYCLEANFILES = insn-flags.h insn-config.h insn-codes.h \
  insn-output.c insn-recog.c insn-emit.c insn-extract.c insn-peep.c \
  insn-attr.h insn-attr-common.h insn-attrtab.c insn-dfatab.c \
@@ -1511,7 +1519,7 @@ MOSTLYCLEANFILES = insn-flags.h insn-config.h insn-codes.h \
  tm-preds.h tm-constrs.h checksum-options gimple-match.c generic-match.c \
  tree-check.h min-insn-modes.c insn-modes.c insn-modes.h \
  genrtl.h gt-*.h gtype-*.h gtype-desc.c gtyp-input.list \
- xgcc$(exeext) cpp$(exeext) \
+ xgcc$(exeext) cpp$(exeext) $(FULL_DRIVER_NAME) \
  $(EXTRA_PROGRAMS) gcc-cross$(exeext) \
  $(SPECS) collect2$(exeext) gcc-ar$(exeext) gcc-nm$(exeext) \
  gcc-ranlib$(exeext) \
@@ -1520,6 +1528,12 @@ MOSTLYCLEANFILES = insn-flags.h insn-config.h insn-codes.h \
  gengtype$(exeext) *.[0-9][0-9].* *.[si] *-checksum.c libbackend.a \
  libcommon-target.a libcommon.a libgcc.mk
 
+# This symlink makes the full installation name of the driver be available
+# from within the *build* directory, for use when running the JIT library
+# from there (e.g. when running its testsuite).
+$(FULL_DRIVER_NAME): ./xgcc
+	$(LN) -s $< $@
+
 #\f
 # Language makefile fragments.
 
@@ -3280,9 +3294,9 @@ install-driver: installdirs xgcc$(exeext)
 	-rm -f $(DESTDIR)$(bindir)/$(GCC_INSTALL_NAME)$(exeext)
 	-$(INSTALL_PROGRAM) xgcc$(exeext) $(DESTDIR)$(bindir)/$(GCC_INSTALL_NAME)$(exeext)
 	-if [ "$(GCC_INSTALL_NAME)" != "$(target_noncanonical)-gcc-$(version)" ]; then \
-	  rm -f $(DESTDIR)$(bindir)/$(target_noncanonical)-gcc-$(version)$(exeext); \
+	  rm -f $(DESTDIR)$(bindir)/$(FULL_DRIVER_NAME); \
 	  ( cd $(DESTDIR)$(bindir) && \
-	    $(LN) $(GCC_INSTALL_NAME)$(exeext) $(target_noncanonical)-gcc-$(version)$(exeext) ); \
+	    $(LN) $(GCC_INSTALL_NAME)$(exeext) $(FULL_DRIVER_NAME) ); \
 	fi
 	-if [ ! -f gcc-cross$(exeext) ] \
 	    && [ "$(GCC_INSTALL_NAME)" != "$(GCC_TARGET_INSTALL_NAME)" ]; then \
diff --git a/gcc/configure b/gcc/configure
index 16f128f..6779b2a 100755
--- a/gcc/configure
+++ b/gcc/configure
@@ -743,6 +743,7 @@ CXXDEPMODE
 DEPDIR
 am__leading_dot
 CXXCPP
+doc_build_sys
 AR
 NM
 BISON
@@ -8069,6 +8070,47 @@ fi
 
 fi
 
+# The jit documentation looks better if built with sphinx, but can be
+# built with texinfo if sphinx is not available.
+# Set "doc_build_sys" to "sphinx" or "texinfo" accordingly.
+# Extract the first word of "sphinx-build", so it can be a program name with args.
+set dummy sphinx-build; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_doc_build_sys+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$doc_build_sys"; then
+  ac_cv_prog_doc_build_sys="$doc_build_sys" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_doc_build_sys="sphinx"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  test -z "$ac_cv_prog_doc_build_sys" && ac_cv_prog_doc_build_sys="texinfo"
+fi
+fi
+doc_build_sys=$ac_cv_prog_doc_build_sys
+if test -n "$doc_build_sys"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $doc_build_sys" >&5
+$as_echo "$doc_build_sys" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
 
 # --------------------
 # Checks for C headers
@@ -18058,7 +18100,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 18061 "configure"
+#line 18103 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -18164,7 +18206,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 18167 "configure"
+#line 18209 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -28175,6 +28217,12 @@ _ACEOF
 
 fi
 
+# Generate gcc-driver-name.h containing GCC_DRIVER_NAME for the benefit
+# of jit/jit-playback.c.
+cat > gcc-driver-name.h <<EOF
+#define GCC_DRIVER_NAME "${target_noncanonical}-gcc-${gcc_BASEVER}${exeext}"
+EOF
+
 # Configure the subdirectories
 # AC_CONFIG_SUBDIRS($subdirs)
 
diff --git a/gcc/configure.ac b/gcc/configure.ac
index 35ce9ee..31b2e97 100644
--- a/gcc/configure.ac
+++ b/gcc/configure.ac
@@ -971,6 +971,10 @@ else
   AC_CHECK_PROG(AR, ar, ar, ${CONFIG_SHELL-/bin/sh} ${srcdir}/../missing ar)
 fi
 
+# The jit documentation looks better if built with sphinx, but can be
+# built with texinfo if sphinx is not available.
+# Set "doc_build_sys" to "sphinx" or "texinfo" accordingly.
+AC_CHECK_PROG(doc_build_sys, sphinx-build, sphinx, texinfo)
 
 # --------------------
 # Checks for C headers
@@ -5698,6 +5702,12 @@ if test x"${LINKER_HASH_STYLE}" != x; then
                                          [The linker hash style])
 fi
 
+# Generate gcc-driver-name.h containing GCC_DRIVER_NAME for the benefit
+# of jit/jit-playback.c.
+cat > gcc-driver-name.h <<EOF
+#define GCC_DRIVER_NAME "${target_noncanonical}-gcc-${gcc_BASEVER}${exeext}"
+EOF
+
 # Configure the subdirectories
 # AC_CONFIG_SUBDIRS($subdirs)
 
-- 
1.8.5.3

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

* [PATCH 07/27] New file: gcc/jit/dummy-frontend.c
  2014-10-31 17:07 [PATCH 00/27] Merger of jit branch v3 David Malcolm
  2014-10-31 17:07 ` [PATCH 02/27] JIT-related changes outside of jit subdir David Malcolm
  2014-10-31 17:07 ` [PATCH 03/27] Add Sphinx to install.texi David Malcolm
@ 2014-10-31 17:07 ` David Malcolm
  2014-11-03 19:26   ` Jeff Law
  2014-10-31 17:07 ` [PATCH 20/27] Documentation: Makefile and conf.py David Malcolm
                   ` (22 subsequent siblings)
  25 siblings, 1 reply; 71+ messages in thread
From: David Malcolm @ 2014-10-31 17:07 UTC (permalink / raw)
  To: gcc-patches, jit; +Cc: David Malcolm

gcc/jit/
	* dummy-frontend.c: New.
---
 gcc/jit/dummy-frontend.c | 240 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 240 insertions(+)
 create mode 100644 gcc/jit/dummy-frontend.c

diff --git a/gcc/jit/dummy-frontend.c b/gcc/jit/dummy-frontend.c
new file mode 100644
index 0000000..33f126f
--- /dev/null
+++ b/gcc/jit/dummy-frontend.c
@@ -0,0 +1,240 @@
+/* jit.c -- Dummy "frontend" for use during JIT-compilation.
+   Copyright (C) 2013-2014 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "opts.h"
+#include "signop.h"
+#include "tree-core.h"
+#include "stor-layout.h"
+#include "tree.h"
+#include "debug.h"
+#include "langhooks.h"
+#include "langhooks-def.h"
+#include "cgraph.h"
+
+#include "jit-common.h"
+#include "jit-playback.h"
+
+#include <mpfr.h>
+
+/* Language-dependent contents of a type.  */
+
+struct GTY(()) lang_type
+{
+  char dummy;
+};
+
+/* Language-dependent contents of a decl.  */
+
+struct GTY((variable_size)) lang_decl
+{
+  char dummy;
+};
+
+/* Language-dependent contents of an identifier.  This must include a
+   tree_identifier.  */
+
+struct GTY(()) lang_identifier
+{
+  struct tree_identifier common;
+};
+
+/* The resulting tree type.  */
+
+union GTY((desc ("TREE_CODE (&%h.generic) == IDENTIFIER_NODE"),
+	   chain_next ("CODE_CONTAINS_STRUCT (TREE_CODE (&%h.generic), TS_COMMON) ? ((union lang_tree_node *) TREE_CHAIN (&%h.generic)) : NULL")))
+lang_tree_node
+{
+  union tree_node GTY((tag ("0"),
+		       desc ("tree_node_structure (&%h)"))) generic;
+  struct lang_identifier GTY((tag ("1"))) identifier;
+};
+
+/* We don't use language_function.  */
+
+struct GTY(()) language_function
+{
+  int dummy;
+};
+
+/* GC-marking callback for use from jit_root_tab.
+
+   If there's an active playback context, call its marking method
+   so that it can mark any pointers it references.  */
+
+static void my_ggc_walker (void *)
+{
+  if (gcc::jit::active_playback_ctxt)
+    gcc::jit::active_playback_ctxt->gt_ggc_mx ();
+}
+
+const char *dummy;
+
+struct ggc_root_tab jit_root_tab[] =
+  {
+    {
+      &dummy, 1, 0, my_ggc_walker, NULL
+    },
+    LAST_GGC_ROOT_TAB
+  };
+
+/* Language hooks.  */
+
+static bool
+jit_langhook_init (void)
+{
+  static bool registered_root_tab = false;
+  if (!registered_root_tab)
+    {
+      ggc_register_root_tab (jit_root_tab);
+      registered_root_tab = true;
+    }
+
+  build_common_tree_nodes (false, false);
+
+  /* I don't know why this has to be done explicitly.  */
+  void_list_node = build_tree_list (NULL_TREE, void_type_node);
+
+  build_common_builtin_nodes ();
+
+  /* The default precision for floating point numbers.  This is used
+     for floating point constants with abstract type.  This may
+     eventually be controllable by a command line option.  */
+  mpfr_set_default_prec (256);
+
+  return true;
+}
+
+static void
+jit_langhook_parse_file (void)
+{
+  /* Replay the activity by the client, recorded on the context.  */
+  gcc_assert (gcc::jit::active_playback_ctxt);
+  gcc::jit::active_playback_ctxt->replay ();
+}
+
+static tree
+jit_langhook_type_for_mode (enum machine_mode mode, int unsignedp)
+{
+  if (mode == TYPE_MODE (float_type_node))
+    return float_type_node;
+
+  if (mode == TYPE_MODE (double_type_node))
+    return double_type_node;
+
+  if (mode == TYPE_MODE (integer_type_node))
+    return unsignedp ? unsigned_type_node : integer_type_node;
+
+  if (mode == TYPE_MODE (long_integer_type_node))
+    return unsignedp ? long_unsigned_type_node : long_integer_type_node;
+
+  if (COMPLEX_MODE_P (mode))
+    {
+      if (mode == TYPE_MODE (complex_float_type_node))
+	return complex_float_type_node;
+      if (mode == TYPE_MODE (complex_double_type_node))
+	return complex_double_type_node;
+      if (mode == TYPE_MODE (complex_long_double_type_node))
+	return complex_long_double_type_node;
+      if (mode == TYPE_MODE (complex_integer_type_node) && !unsignedp)
+	return complex_integer_type_node;
+    }
+
+  /* gcc_unreachable */
+  return NULL;
+}
+
+static tree
+jit_langhook_type_for_size (unsigned int bits ATTRIBUTE_UNUSED,
+			    int unsignedp ATTRIBUTE_UNUSED)
+{
+  gcc_unreachable ();
+  return NULL;
+}
+
+/* Record a builtin function.  We just ignore builtin functions.  */
+
+static tree
+jit_langhook_builtin_function (tree decl)
+{
+  return decl;
+}
+
+static bool
+jit_langhook_global_bindings_p (void)
+{
+  gcc_unreachable ();
+  return true;
+}
+
+static tree
+jit_langhook_pushdecl (tree decl ATTRIBUTE_UNUSED)
+{
+  gcc_unreachable ();
+}
+
+static tree
+jit_langhook_getdecls (void)
+{
+  return NULL;
+}
+
+static void
+jit_langhook_write_globals (void)
+{
+  /* This is the hook that runs the middle and backends: */
+  symtab->finalize_compilation_unit ();
+}
+
+#undef LANG_HOOKS_NAME
+#define LANG_HOOKS_NAME		"libgccjit"
+
+#undef LANG_HOOKS_INIT
+#define LANG_HOOKS_INIT		jit_langhook_init
+
+#undef LANG_HOOKS_PARSE_FILE
+#define LANG_HOOKS_PARSE_FILE		jit_langhook_parse_file
+
+#undef LANG_HOOKS_TYPE_FOR_MODE
+#define LANG_HOOKS_TYPE_FOR_MODE	jit_langhook_type_for_mode
+
+#undef LANG_HOOKS_TYPE_FOR_SIZE
+#define LANG_HOOKS_TYPE_FOR_SIZE	jit_langhook_type_for_size
+
+#undef LANG_HOOKS_BUILTIN_FUNCTION
+#define LANG_HOOKS_BUILTIN_FUNCTION	jit_langhook_builtin_function
+
+#undef LANG_HOOKS_GLOBAL_BINDINGS_P
+#define LANG_HOOKS_GLOBAL_BINDINGS_P	jit_langhook_global_bindings_p
+
+#undef LANG_HOOKS_PUSHDECL
+#define LANG_HOOKS_PUSHDECL		jit_langhook_pushdecl
+
+#undef LANG_HOOKS_GETDECLS
+#define LANG_HOOKS_GETDECLS		jit_langhook_getdecls
+
+#undef LANG_HOOKS_WRITE_GLOBALS
+#define LANG_HOOKS_WRITE_GLOBALS	jit_langhook_write_globals
+
+struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER;
+
+#include "gt-jit-dummy-frontend.h"
+#include "gtype-jit.h"
-- 
1.8.5.3

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

* [PATCH 00/27] Merger of jit branch v3
@ 2014-10-31 17:07 David Malcolm
  2014-10-31 17:07 ` [PATCH 02/27] JIT-related changes outside of jit subdir David Malcolm
                   ` (25 more replies)
  0 siblings, 26 replies; 71+ messages in thread
From: David Malcolm @ 2014-10-31 17:07 UTC (permalink / raw)
  To: gcc-patches, jit; +Cc: David Malcolm

I'd like to merge the JIT branch into trunk:
  https://gcc.gnu.org/wiki/JIT

This is "v3" since it incorporates fixes for various issues
identified in earlier submissions:
  v1: https://gcc.gnu.org/ml/gcc-patches/2014-09/msg02056.html
  v2: https://gcc.gnu.org/ml/gcc-patches/2014-10/msg01168.html

I've merged some of the work approved earlier into trunk.

Of the remaining work, some has already been approved, and some
hasn't.  I've split the latter up into more fine-grained patches
in the hope it will make review easier, so there are 27 patches
in this kit, compared to 10 in the earlier one.

Here's an overview of the patches:

  01/27: gcc: configure and Makefile changes needed by jit
    Needs review.
    Corresponds to:
      "[PATCH 2/5] gcc: configure and Makefile changes needed by jit"
        https://gcc.gnu.org/ml/gcc-patches/2014-10/msg01169.html
    and has had cleanups in response to concerns from Jeff and Joseph,
    to remove the need to install when running the jit testsuite.

  02/27: JIT-related changes outside of jit subdir
    Already approved by Jeff.

  03/27: Add Sphinx to install.texi
    Needs review.

Patches 04-18 correspond to:
  "[PATCH 06/10] Heart of the JIT implementation
      (was: Re: [PATCH 0/5] Merger of jit branch (v2))"
    https://gcc.gnu.org/ml/gcc-patches/2014-10/msg01247.html
from v2; I've broken them up by file to make them easier to review:

  04/27: New file: gcc/jit/notes.txt
  05/27: New file: gcc/jit/config-lang.in
  06/27: New file: gcc/jit/Make-lang.in
  07/27: New file: gcc/jit/dummy-frontend.c
  08/27: New file: gcc/jit/libgccjit.h
  09/27: New file: gcc/jit/libgccjit.map
  10/27: New file: gcc/jit/libgccjit.c
  11/27: New file: gcc/jit/jit-common.h
  12/27: New file: gcc/jit/jit-recording.h
  13/27: New file: gcc/jit/jit-recording.c
  14/27: New files: gcc/jit/jit-builtins.{c|h}
  15/27: New file: gcc/jit/jit-playback.h
  16/27: New file: gcc/jit/jit-playback.c
  17/27: New file: gcc/jit/libgccjit++.h
  18/27: New file: gcc/jit/TODO.rst
    All of these need review.

  19/27: Testsuite for the JIT
    Earlier version already approved by Jeff, only small changes since.

  20/27: Documentation: Makefile and conf.py
  21/27: Documentation: the "examples" subdirectory
  22/27: Documentation: top-level index.rst
  23/27: Documentation: the "intro" subdirectory
  24/27: Documentation: add "topics" subdirectory
  25/27: Documentation: add "internals" subdirectory
    All of these need review.
    Patches 20-25 correspond to:
      "[PATCH 08/10] Documentation for the JIT library
          (Re: Patches 5-10 of jit merger)"
        https://gcc.gnu.org/ml/gcc-patches/2014-10/msg01392.html
    from v2.  Since then, I've:
      * eliminated all mentions of pkg-config (since we no longer
        support this)
      * eliminated the installation section and the discussion of
        packages
      * converted the final page (docs/internals/index.rst) into a
        short guide for contributors to the project (e.g. myself and
        other maintainers)
     Prebuilt HTML from this can be seen at:
       https://dmalcolm.fedorapeople.org/gcc/libgccjit-api-docs/index.html
     Again, I've broken them up into smaller patches to make them
     easier to review.

  26/27: Prebuilt texinfo documentation for the JIT library
    Already (pre)approved by Jeff.

  27/27: ChangeLog files
    Earlier version approved by Jeff, and presumably all changes
    since count as "obvious".

I've successfully bootstrapped and regression-tested the cumulative
result of all of the patches against a control build, building them
both with --enable-host-shared, and with
  --enable-languages=c,c++,objc,obj-c++,java,fortran,ada,go,lto
adding ",jit" to the test build (both on x86_64-unknown-linux-gnu;
Fedora 20, using Monday's r216746 as the baseline).

There were no regressions vs the control build, and the patched build
gains a jit.sum, with 4663 passes (and no failures).

OK for trunk?
(patches 01, 03, 04-18, 20-25 are the ones needing review)

Overall diffstat follows:

 ChangeLog.jit                                      |   23 +
 MAINTAINERS                                        |    1 +
 contrib/ChangeLog.jit                              |   14 +
 contrib/jit-coverage-report.py                     |   67 +
 gcc/ChangeLog.jit                                  |  360 ++
 gcc/Makefile.in                                    |   20 +-
 gcc/configure                                      |   52 +-
 gcc/configure.ac                                   |   10 +
 gcc/doc/install.texi                               |    7 +-
 gcc/java/ChangeLog.jit                             |   14 +
 gcc/jit/ChangeLog                                  |    9 +
 gcc/jit/ChangeLog.jit                              | 3342 ++++++++++
 gcc/jit/Make-lang.in                               |  298 +
 gcc/jit/TODO.rst                                   |  119 +
 gcc/jit/config-lang.in                             |   38 +
 gcc/jit/docs/Makefile                              |  153 +
 gcc/jit/docs/_build/texinfo/Makefile               |   50 +
 gcc/jit/docs/_build/texinfo/factorial.png          |  Bin 0 -> 183838 bytes
 gcc/jit/docs/_build/texinfo/libgccjit.texi         | 6534 ++++++++++++++++++++
 gcc/jit/docs/_build/texinfo/sum-of-squares.png     |  Bin 0 -> 22839 bytes
 gcc/jit/docs/conf.py                               |  258 +
 gcc/jit/docs/examples/tut01-hello-world.c          |  123 +
 gcc/jit/docs/examples/tut02-square.c               |  107 +
 gcc/jit/docs/examples/tut03-sum-of-squares.c       |  172 +
 gcc/jit/docs/examples/tut04-toyvm/Makefile         |   11 +
 gcc/jit/docs/examples/tut04-toyvm/factorial.toy    |   50 +
 gcc/jit/docs/examples/tut04-toyvm/fibonacci.toy    |   66 +
 gcc/jit/docs/examples/tut04-toyvm/toyvm.c          |  861 +++
 gcc/jit/docs/index.rst                             |   50 +
 gcc/jit/docs/internals/index.rst                   |  216 +
 gcc/jit/docs/intro/factorial.png                   |  Bin 0 -> 183838 bytes
 gcc/jit/docs/intro/index.rst                       |   27 +
 gcc/jit/docs/intro/sum-of-squares.png              |  Bin 0 -> 22839 bytes
 gcc/jit/docs/intro/tutorial01.rst                  |   52 +
 gcc/jit/docs/intro/tutorial02.rst                  |  349 ++
 gcc/jit/docs/intro/tutorial03.rst                  |  378 ++
 gcc/jit/docs/intro/tutorial04.rst                  | 1108 ++++
 gcc/jit/docs/topics/contexts.rst                   |  315 +
 gcc/jit/docs/topics/expressions.rst                |  524 ++
 gcc/jit/docs/topics/functions.rst                  |  311 +
 gcc/jit/docs/topics/index.rst                      |   30 +
 gcc/jit/docs/topics/locations.rst                  |   69 +
 gcc/jit/docs/topics/objects.rst                    |   86 +
 gcc/jit/docs/topics/results.rst                    |   48 +
 gcc/jit/docs/topics/types.rst                      |  217 +
 gcc/jit/dummy-frontend.c                           |  240 +
 gcc/jit/jit-builtins.c                             |  424 ++
 gcc/jit/jit-builtins.h                             |  114 +
 gcc/jit/jit-common.h                               |  182 +
 gcc/jit/jit-playback.c                             | 2104 +++++++
 gcc/jit/jit-playback.h                             |  564 ++
 gcc/jit/jit-recording.c                            | 3434 ++++++++++
 gcc/jit/jit-recording.h                            | 1593 +++++
 gcc/jit/libgccjit++.h                              | 1574 +++++
 gcc/jit/libgccjit.c                                | 1506 +++++
 gcc/jit/libgccjit.h                                |  977 +++
 gcc/jit/libgccjit.map                              |  100 +
 gcc/jit/notes.txt                                  |   84 +
 gcc/testsuite/ChangeLog.jit                        |  619 ++
 gcc/testsuite/jit.dg/all-non-failing-tests.h       |  166 +
 gcc/testsuite/jit.dg/harness.h                     |  242 +
 gcc/testsuite/jit.dg/jit.exp                       |  293 +
 gcc/testsuite/jit.dg/test-accessing-struct.c       |  112 +
 gcc/testsuite/jit.dg/test-accessing-union.c        |   97 +
 gcc/testsuite/jit.dg/test-array-as-pointer.c       |  101 +
 gcc/testsuite/jit.dg/test-arrays.c                 |  165 +
 .../jit.dg/test-calling-external-function.c        |  118 +
 gcc/testsuite/jit.dg/test-calling-function-ptr.c   |  118 +
 gcc/testsuite/jit.dg/test-combination.c            |   67 +
 gcc/testsuite/jit.dg/test-dot-product.c            |  129 +
 gcc/testsuite/jit.dg/test-empty.c                  |   20 +
 .../test-error-accessing-field-in-other-struct.c   |  114 +
 .../jit.dg/test-error-adding-to-terminated-block.c |   48 +
 gcc/testsuite/jit.dg/test-error-array-as-pointer.c |   99 +
 gcc/testsuite/jit.dg/test-error-bad-cast.c         |   63 +
 .../jit.dg/test-error-block-in-wrong-function.c    |   65 +
 ...-error-call-through-ptr-with-mismatching-args.c |   74 +
 ...test-error-call-through-ptr-with-non-function.c |   65 +
 .../test-error-call-through-ptr-with-non-pointer.c |   62 +
 ...t-error-call-through-ptr-with-not-enough-args.c |   70 +
 ...est-error-call-through-ptr-with-too-many-args.c |   87 +
 .../jit.dg/test-error-call-with-mismatching-args.c |   87 +
 .../jit.dg/test-error-call-with-not-enough-args.c  |   87 +
 .../jit.dg/test-error-call-with-too-many-args.c    |   89 +
 .../test-error-dereference-field-of-non-pointer.c  |   95 +
 .../test-error-dereference-read-of-non-pointer.c   |   55 +
 .../jit.dg/test-error-index-not-a-numeric-type.c   |   34 +
 .../test-error-mismatching-types-in-assignment.c   |   61 +
 .../jit.dg/test-error-mismatching-types-in-call.c  |   80 +
 gcc/testsuite/jit.dg/test-error-missing-return.c   |   40 +
 .../jit.dg/test-error-null-passed-to-api.c         |   31 +
 .../test-error-return-within-void-function.c       |   54 +
 .../jit.dg/test-error-unreachable-block.c          |   50 +
 .../jit.dg/test-error-unterminated-block.c         |   42 +
 .../jit.dg/test-error-value-not-a-numeric-type.c   |   29 +
 gcc/testsuite/jit.dg/test-expressions.c            |  896 +++
 gcc/testsuite/jit.dg/test-factorial.c              |  103 +
 gcc/testsuite/jit.dg/test-fibonacci.c              |  136 +
 gcc/testsuite/jit.dg/test-functions.c              |  356 ++
 gcc/testsuite/jit.dg/test-fuzzer.c                 |  462 ++
 gcc/testsuite/jit.dg/test-hello-world.c            |   72 +
 gcc/testsuite/jit.dg/test-linked-list.c            |  141 +
 gcc/testsuite/jit.dg/test-long-names.c             |  112 +
 gcc/testsuite/jit.dg/test-nested-contexts.c        |  641 ++
 gcc/testsuite/jit.dg/test-nested-loops.c           |  179 +
 gcc/testsuite/jit.dg/test-operator-overloading.cc  |  310 +
 gcc/testsuite/jit.dg/test-quadratic.c              |  488 ++
 gcc/testsuite/jit.dg/test-quadratic.cc             |  366 ++
 gcc/testsuite/jit.dg/test-reading-struct.c         |  135 +
 gcc/testsuite/jit.dg/test-string-literal.c         |   52 +
 gcc/testsuite/jit.dg/test-sum-of-squares.c         |  126 +
 gcc/testsuite/jit.dg/test-threads.c                |  252 +
 gcc/testsuite/jit.dg/test-types.c                  |  361 ++
 gcc/testsuite/jit.dg/test-using-global.c           |   73 +
 gcc/testsuite/jit.dg/test-volatile.c               |   66 +
 gcc/timevar.def                                    |    6 +
 include/ChangeLog.jit                              |   11 +
 libbacktrace/ChangeLog.jit                         |   14 +
 libcpp/ChangeLog.jit                               |   22 +
 libdecnumber/ChangeLog.jit                         |   22 +
 libiberty/ChangeLog.jit                            |   23 +
 zlib/ChangeLog.jit                                 |   22 +
 122 files changed, 38704 insertions(+), 6 deletions(-)
 create mode 100644 ChangeLog.jit
 create mode 100644 contrib/ChangeLog.jit
 create mode 100644 contrib/jit-coverage-report.py
 create mode 100644 gcc/ChangeLog.jit
 create mode 100644 gcc/java/ChangeLog.jit
 create mode 100644 gcc/jit/ChangeLog
 create mode 100644 gcc/jit/ChangeLog.jit
 create mode 100644 gcc/jit/Make-lang.in
 create mode 100644 gcc/jit/TODO.rst
 create mode 100644 gcc/jit/config-lang.in
 create mode 100644 gcc/jit/docs/Makefile
 create mode 100644 gcc/jit/docs/_build/texinfo/Makefile
 create mode 100644 gcc/jit/docs/_build/texinfo/factorial.png
 create mode 100644 gcc/jit/docs/_build/texinfo/libgccjit.texi
 create mode 100644 gcc/jit/docs/_build/texinfo/sum-of-squares.png
 create mode 100644 gcc/jit/docs/conf.py
 create mode 100644 gcc/jit/docs/examples/tut01-hello-world.c
 create mode 100644 gcc/jit/docs/examples/tut02-square.c
 create mode 100644 gcc/jit/docs/examples/tut03-sum-of-squares.c
 create mode 100644 gcc/jit/docs/examples/tut04-toyvm/Makefile
 create mode 100644 gcc/jit/docs/examples/tut04-toyvm/factorial.toy
 create mode 100644 gcc/jit/docs/examples/tut04-toyvm/fibonacci.toy
 create mode 100644 gcc/jit/docs/examples/tut04-toyvm/toyvm.c
 create mode 100644 gcc/jit/docs/index.rst
 create mode 100644 gcc/jit/docs/internals/index.rst
 create mode 100644 gcc/jit/docs/intro/factorial.png
 create mode 100644 gcc/jit/docs/intro/index.rst
 create mode 100644 gcc/jit/docs/intro/sum-of-squares.png
 create mode 100644 gcc/jit/docs/intro/tutorial01.rst
 create mode 100644 gcc/jit/docs/intro/tutorial02.rst
 create mode 100644 gcc/jit/docs/intro/tutorial03.rst
 create mode 100644 gcc/jit/docs/intro/tutorial04.rst
 create mode 100644 gcc/jit/docs/topics/contexts.rst
 create mode 100644 gcc/jit/docs/topics/expressions.rst
 create mode 100644 gcc/jit/docs/topics/functions.rst
 create mode 100644 gcc/jit/docs/topics/index.rst
 create mode 100644 gcc/jit/docs/topics/locations.rst
 create mode 100644 gcc/jit/docs/topics/objects.rst
 create mode 100644 gcc/jit/docs/topics/results.rst
 create mode 100644 gcc/jit/docs/topics/types.rst
 create mode 100644 gcc/jit/dummy-frontend.c
 create mode 100644 gcc/jit/jit-builtins.c
 create mode 100644 gcc/jit/jit-builtins.h
 create mode 100644 gcc/jit/jit-common.h
 create mode 100644 gcc/jit/jit-playback.c
 create mode 100644 gcc/jit/jit-playback.h
 create mode 100644 gcc/jit/jit-recording.c
 create mode 100644 gcc/jit/jit-recording.h
 create mode 100644 gcc/jit/libgccjit++.h
 create mode 100644 gcc/jit/libgccjit.c
 create mode 100644 gcc/jit/libgccjit.h
 create mode 100644 gcc/jit/libgccjit.map
 create mode 100644 gcc/jit/notes.txt
 create mode 100644 gcc/testsuite/ChangeLog.jit
 create mode 100644 gcc/testsuite/jit.dg/all-non-failing-tests.h
 create mode 100644 gcc/testsuite/jit.dg/harness.h
 create mode 100644 gcc/testsuite/jit.dg/jit.exp
 create mode 100644 gcc/testsuite/jit.dg/test-accessing-struct.c
 create mode 100644 gcc/testsuite/jit.dg/test-accessing-union.c
 create mode 100644 gcc/testsuite/jit.dg/test-array-as-pointer.c
 create mode 100644 gcc/testsuite/jit.dg/test-arrays.c
 create mode 100644 gcc/testsuite/jit.dg/test-calling-external-function.c
 create mode 100644 gcc/testsuite/jit.dg/test-calling-function-ptr.c
 create mode 100644 gcc/testsuite/jit.dg/test-combination.c
 create mode 100644 gcc/testsuite/jit.dg/test-dot-product.c
 create mode 100644 gcc/testsuite/jit.dg/test-empty.c
 create mode 100644 gcc/testsuite/jit.dg/test-error-accessing-field-in-other-struct.c
 create mode 100644 gcc/testsuite/jit.dg/test-error-adding-to-terminated-block.c
 create mode 100644 gcc/testsuite/jit.dg/test-error-array-as-pointer.c
 create mode 100644 gcc/testsuite/jit.dg/test-error-bad-cast.c
 create mode 100644 gcc/testsuite/jit.dg/test-error-block-in-wrong-function.c
 create mode 100644 gcc/testsuite/jit.dg/test-error-call-through-ptr-with-mismatching-args.c
 create mode 100644 gcc/testsuite/jit.dg/test-error-call-through-ptr-with-non-function.c
 create mode 100644 gcc/testsuite/jit.dg/test-error-call-through-ptr-with-non-pointer.c
 create mode 100644 gcc/testsuite/jit.dg/test-error-call-through-ptr-with-not-enough-args.c
 create mode 100644 gcc/testsuite/jit.dg/test-error-call-through-ptr-with-too-many-args.c
 create mode 100644 gcc/testsuite/jit.dg/test-error-call-with-mismatching-args.c
 create mode 100644 gcc/testsuite/jit.dg/test-error-call-with-not-enough-args.c
 create mode 100644 gcc/testsuite/jit.dg/test-error-call-with-too-many-args.c
 create mode 100644 gcc/testsuite/jit.dg/test-error-dereference-field-of-non-pointer.c
 create mode 100644 gcc/testsuite/jit.dg/test-error-dereference-read-of-non-pointer.c
 create mode 100644 gcc/testsuite/jit.dg/test-error-index-not-a-numeric-type.c
 create mode 100644 gcc/testsuite/jit.dg/test-error-mismatching-types-in-assignment.c
 create mode 100644 gcc/testsuite/jit.dg/test-error-mismatching-types-in-call.c
 create mode 100644 gcc/testsuite/jit.dg/test-error-missing-return.c
 create mode 100644 gcc/testsuite/jit.dg/test-error-null-passed-to-api.c
 create mode 100644 gcc/testsuite/jit.dg/test-error-return-within-void-function.c
 create mode 100644 gcc/testsuite/jit.dg/test-error-unreachable-block.c
 create mode 100644 gcc/testsuite/jit.dg/test-error-unterminated-block.c
 create mode 100644 gcc/testsuite/jit.dg/test-error-value-not-a-numeric-type.c
 create mode 100644 gcc/testsuite/jit.dg/test-expressions.c
 create mode 100644 gcc/testsuite/jit.dg/test-factorial.c
 create mode 100644 gcc/testsuite/jit.dg/test-fibonacci.c
 create mode 100644 gcc/testsuite/jit.dg/test-functions.c
 create mode 100644 gcc/testsuite/jit.dg/test-fuzzer.c
 create mode 100644 gcc/testsuite/jit.dg/test-hello-world.c
 create mode 100644 gcc/testsuite/jit.dg/test-linked-list.c
 create mode 100644 gcc/testsuite/jit.dg/test-long-names.c
 create mode 100644 gcc/testsuite/jit.dg/test-nested-contexts.c
 create mode 100644 gcc/testsuite/jit.dg/test-nested-loops.c
 create mode 100644 gcc/testsuite/jit.dg/test-operator-overloading.cc
 create mode 100644 gcc/testsuite/jit.dg/test-quadratic.c
 create mode 100644 gcc/testsuite/jit.dg/test-quadratic.cc
 create mode 100644 gcc/testsuite/jit.dg/test-reading-struct.c
 create mode 100644 gcc/testsuite/jit.dg/test-string-literal.c
 create mode 100644 gcc/testsuite/jit.dg/test-sum-of-squares.c
 create mode 100644 gcc/testsuite/jit.dg/test-threads.c
 create mode 100644 gcc/testsuite/jit.dg/test-types.c
 create mode 100644 gcc/testsuite/jit.dg/test-using-global.c
 create mode 100644 gcc/testsuite/jit.dg/test-volatile.c
 create mode 100644 include/ChangeLog.jit
 create mode 100644 libbacktrace/ChangeLog.jit
 create mode 100644 libcpp/ChangeLog.jit
 create mode 100644 libdecnumber/ChangeLog.jit
 create mode 100644 libiberty/ChangeLog.jit
 create mode 100644 zlib/ChangeLog.jit

-- 
1.8.5.3

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

* [PATCH 20/27] Documentation: Makefile and conf.py
  2014-10-31 17:07 [PATCH 00/27] Merger of jit branch v3 David Malcolm
                   ` (2 preceding siblings ...)
  2014-10-31 17:07 ` [PATCH 07/27] New file: gcc/jit/dummy-frontend.c David Malcolm
@ 2014-10-31 17:07 ` David Malcolm
  2014-11-03 21:13   ` Jeff Law
  2014-10-31 17:07 ` [PATCH 01/27] gcc: configure and Makefile changes needed by jit David Malcolm
                   ` (21 subsequent siblings)
  25 siblings, 1 reply; 71+ messages in thread
From: David Malcolm @ 2014-10-31 17:07 UTC (permalink / raw)
  To: gcc-patches, jit; +Cc: David Malcolm

When I previously submitted the jit for review, I posted all of the
documentation as one big patch, as:
  "[PATCH 08/10] Documentation for the JIT library (Re: Patches 5-10 of jit merger)"
    https://gcc.gnu.org/ml/gcc-patches/2014-10/msg01392.html

Since then, I've:

  * eliminated all mentions of pkg-config (since we no longer support
    this)

  * eliminated the installation section and the discussion of packages

  * converted the final page (docs/internals/index.rst) into a short
    guide for contributors to the project (e.g. myself and other
    maintainers)

Prebuilt HTML from this can be seen at:
  https://dmalcolm.fedorapeople.org/gcc/libgccjit-api-docs/index.html

To make review easier, I've split the documentation up to smaller
patches, starting with this one.

This patch adds the Makefile and configuration file for Sphinx
for building docs from the .rst files that follow.

gcc/jit/
	* docs/Makefile: New.
	* docs/conf.py: New.
---
 gcc/jit/docs/Makefile | 153 ++++++++++++++++++++++++++++++
 gcc/jit/docs/conf.py  | 258 ++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 411 insertions(+)
 create mode 100644 gcc/jit/docs/Makefile
 create mode 100644 gcc/jit/docs/conf.py

diff --git a/gcc/jit/docs/Makefile b/gcc/jit/docs/Makefile
new file mode 100644
index 0000000..7d20702
--- /dev/null
+++ b/gcc/jit/docs/Makefile
@@ -0,0 +1,153 @@
+# Makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS    =
+SPHINXBUILD   = sphinx-build
+PAPER         =
+BUILDDIR      = _build
+
+# Internal variables.
+PAPEROPT_a4     = -D latex_paper_size=a4
+PAPEROPT_letter = -D latex_paper_size=letter
+ALLSPHINXOPTS   = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+# the i18n builder cannot share the environment and doctrees with the others
+I18NSPHINXOPTS  = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+
+.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
+
+help:
+	@echo "Please use \`make <target>' where <target> is one of"
+	@echo "  html       to make standalone HTML files"
+	@echo "  dirhtml    to make HTML files named index.html in directories"
+	@echo "  singlehtml to make a single large HTML file"
+	@echo "  pickle     to make pickle files"
+	@echo "  json       to make JSON files"
+	@echo "  htmlhelp   to make HTML files and a HTML help project"
+	@echo "  qthelp     to make HTML files and a qthelp project"
+	@echo "  devhelp    to make HTML files and a Devhelp project"
+	@echo "  epub       to make an epub"
+	@echo "  latex      to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
+	@echo "  latexpdf   to make LaTeX files and run them through pdflatex"
+	@echo "  text       to make text files"
+	@echo "  man        to make manual pages"
+	@echo "  texinfo    to make Texinfo files"
+	@echo "  info       to make Texinfo files and run them through makeinfo"
+	@echo "  gettext    to make PO message catalogs"
+	@echo "  changes    to make an overview of all changed/added/deprecated items"
+	@echo "  linkcheck  to check all external links for integrity"
+	@echo "  doctest    to run all doctests embedded in the documentation (if enabled)"
+
+clean:
+	-rm -rf $(BUILDDIR)/*
+
+html:
+	$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
+	@echo
+	@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
+
+dirhtml:
+	$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
+	@echo
+	@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
+
+singlehtml:
+	$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
+	@echo
+	@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
+
+pickle:
+	$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
+	@echo
+	@echo "Build finished; now you can process the pickle files."
+
+json:
+	$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
+	@echo
+	@echo "Build finished; now you can process the JSON files."
+
+htmlhelp:
+	$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
+	@echo
+	@echo "Build finished; now you can run HTML Help Workshop with the" \
+	      ".hhp project file in $(BUILDDIR)/htmlhelp."
+
+qthelp:
+	$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
+	@echo
+	@echo "Build finished; now you can run "qcollectiongenerator" with the" \
+	      ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
+	@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/libgccjit.qhcp"
+	@echo "To view the help file:"
+	@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/libgccjit.qhc"
+
+devhelp:
+	$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
+	@echo
+	@echo "Build finished."
+	@echo "To view the help file:"
+	@echo "# mkdir -p $$HOME/.local/share/devhelp/libgccjit"
+	@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/libgccjit"
+	@echo "# devhelp"
+
+epub:
+	$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
+	@echo
+	@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
+
+latex:
+	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+	@echo
+	@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
+	@echo "Run \`make' in that directory to run these through (pdf)latex" \
+	      "(use \`make latexpdf' here to do that automatically)."
+
+latexpdf:
+	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+	@echo "Running LaTeX files through pdflatex..."
+	$(MAKE) -C $(BUILDDIR)/latex all-pdf
+	@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
+
+text:
+	$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
+	@echo
+	@echo "Build finished. The text files are in $(BUILDDIR)/text."
+
+man:
+	$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
+	@echo
+	@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
+
+texinfo:
+	$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+	@echo
+	@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
+	@echo "Run \`make' in that directory to run these through makeinfo" \
+	      "(use \`make info' here to do that automatically)."
+
+info:
+	$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+	@echo "Running Texinfo files through makeinfo..."
+	make -C $(BUILDDIR)/texinfo info
+	@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
+
+gettext:
+	$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
+	@echo
+	@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
+
+changes:
+	$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
+	@echo
+	@echo "The overview file is in $(BUILDDIR)/changes."
+
+linkcheck:
+	$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
+	@echo
+	@echo "Link check complete; look for any errors in the above output " \
+	      "or in $(BUILDDIR)/linkcheck/output.txt."
+
+doctest:
+	$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
+	@echo "Testing of doctests in the sources finished, look at the " \
+	      "results in $(BUILDDIR)/doctest/output.txt."
diff --git a/gcc/jit/docs/conf.py b/gcc/jit/docs/conf.py
new file mode 100644
index 0000000..c300339
--- /dev/null
+++ b/gcc/jit/docs/conf.py
@@ -0,0 +1,258 @@
+# -*- coding: utf-8 -*-
+#
+# libgccjit documentation build configuration file, created by
+# sphinx-quickstart on Wed Jul 30 13:39:01 2014.
+#
+# This file is execfile()d with the current directory set to its containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+import sys, os
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#sys.path.insert(0, os.path.abspath('.'))
+
+# -- General configuration -----------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+#needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be extensions
+# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
+extensions = []
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The encoding of source files.
+#source_encoding = 'utf-8-sig'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'libgccjit'
+copyright = u'2014, Free Software Foundation'
+
+# GCC-specific: extract version information from "gcc" src subdir for
+# use in "version" and "release" below.
+def __read_file(name):
+    gcc_srcdir = '../..'
+    path = os.path.join(gcc_srcdir, name)
+    if os.path.exists(path):
+        return open(path).read().strip()
+    else:
+        return ''
+gcc_BASEVER = __read_file('BASE-VER')
+gcc_DEVPHASE = __read_file('DEV-PHASE')
+gcc_DATESTAMP = __read_file('DATESTAMP')
+gcc_REVISION = __read_file('REVISION')
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+version = gcc_BASEVER
+# The full version, including alpha/beta/rc tags.
+release = ('%s (%s %s%s)'
+           % (gcc_BASEVER, gcc_DEVPHASE, gcc_DATESTAMP,
+              (' %s' % gcc_REVISION) if gcc_REVISION else ''))
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#language = None
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+#today_fmt = '%B %d, %Y'
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+exclude_patterns = ['_build']
+
+# The reST default role (used for this markup: `text`) to use for all documents.
+#default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+# A list of ignored prefixes for module index sorting.
+#modindex_common_prefix = []
+
+
+# -- Options for HTML output ---------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages.  See the documentation for
+# a list of builtin themes.
+html_theme = 'pyramid'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further.  For a list of options available for each theme, see the
+# documentation.
+#html_theme_options = {}
+
+# Add any paths that contain custom themes here, relative to this directory.
+#html_theme_path = []
+
+# The name for this set of Sphinx documents.  If None, it defaults to
+# "<project> v<release> documentation".
+#html_title = None
+
+# A shorter title for the navigation bar.  Default is the same as html_title.
+#html_short_title = None
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+#html_logo = None
+
+# The name of an image file (within the static path) to use as favicon of the
+# docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+#html_favicon = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['_static']
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+#html_last_updated_fmt = '%b %d, %Y'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+#html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+#html_sidebars = {}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+#html_additional_pages = {}
+
+# If false, no module index is generated.
+#html_domain_indices = True
+
+# If false, no index is generated.
+#html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+#html_split_index = False
+
+# If true, links to the reST sources are added to the pages.
+#html_show_sourcelink = True
+
+# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
+#html_show_sphinx = True
+
+# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
+#html_show_copyright = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it.  The value of this option must be the
+# base URL from which the finished HTML is served.
+#html_use_opensearch = ''
+
+# This is the file name suffix for HTML files (e.g. ".xhtml").
+#html_file_suffix = None
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'libgccjitdoc'
+
+
+# -- Options for LaTeX output --------------------------------------------------
+
+latex_elements = {
+# The paper size ('letterpaper' or 'a4paper').
+#'papersize': 'letterpaper',
+
+# The font size ('10pt', '11pt' or '12pt').
+#'pointsize': '10pt',
+
+# Additional stuff for the LaTeX preamble.
+#'preamble': '',
+}
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title, author, documentclass [howto/manual]).
+latex_documents = [
+  ('index', 'libgccjit.tex', u'libgccjit Documentation',
+   u'David Malcolm', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+#latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#latex_use_parts = False
+
+# If true, show page references after internal links.
+#latex_show_pagerefs = False
+
+# If true, show URL addresses after external links.
+#latex_show_urls = False
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_domain_indices = True
+
+
+# -- Options for manual page output --------------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+    ('index', 'libgccjit', u'libgccjit Documentation',
+     [u'David Malcolm'], 1)
+]
+
+# If true, show URL addresses after external links.
+#man_show_urls = False
+
+
+# -- Options for Texinfo output ------------------------------------------------
+
+# Grouping the document tree into Texinfo files. List of tuples
+# (source start file, target name, title, author,
+#  dir menu entry, description, category)
+texinfo_documents = [
+  ('index', 'libgccjit', u'libgccjit Documentation',
+   u'David Malcolm', 'libgccjit', 'One line description of project.',
+   'Miscellaneous'),
+]
+
+# Documents to append as an appendix to all manuals.
+#texinfo_appendices = []
+
+# If false, no module index is generated.
+#texinfo_domain_indices = True
+
+# How to display URL addresses: 'footnote', 'no', or 'inline'.
+#texinfo_show_urls = 'footnote'
-- 
1.8.5.3

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

* [PATCH 02/27] JIT-related changes outside of jit subdir
  2014-10-31 17:07 [PATCH 00/27] Merger of jit branch v3 David Malcolm
@ 2014-10-31 17:07 ` David Malcolm
  2014-10-31 21:18   ` Jeff Law
  2014-10-31 17:07 ` [PATCH 03/27] Add Sphinx to install.texi David Malcolm
                   ` (24 subsequent siblings)
  25 siblings, 1 reply; 71+ messages in thread
From: David Malcolm @ 2014-10-31 17:07 UTC (permalink / raw)
  To: gcc-patches, jit; +Cc: David Malcolm

This was previously posted as:
  "[PATCH 05/10] JIT-related changes outside of jit subdir"
    https://gcc.gnu.org/ml/gcc-patches/2014-10/msg01246.html

and approved by Jeff in
  https://gcc.gnu.org/ml/gcc-patches/2014-10/msg01410.html
> OK if/when rest of JIT bits are approved.

Joseph pointed out that I should add a note about sphinx
as a dependency to install.texi:
  https://gcc.gnu.org/ml/gcc-patches/2014-10/msg01793.html
I do that in the next patch.

ChangeLog:
	* MAINTAINERS (Various Maintainers): Add myself as jit maintainer.

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

gcc/ChangeLog:
	* doc/install.texi (--enable-host-shared): Specify that this is
	required when building libgccjit.
	* timevar.def (TV_JIT_REPLAY): New.
	(TV_ASSEMBLE): New.
	(TV_LINK): New.
	(TV_LOAD): New.
---
 MAINTAINERS                    |  1 +
 contrib/jit-coverage-report.py | 67 ++++++++++++++++++++++++++++++++++++++++++
 gcc/doc/install.texi           |  2 +-
 gcc/timevar.def                |  6 ++++
 4 files changed, 75 insertions(+), 1 deletion(-)
 create mode 100644 contrib/jit-coverage-report.py

diff --git a/MAINTAINERS b/MAINTAINERS
index 11a28ef..3a7cf6f8 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -260,6 +260,7 @@ testsuite		Janis Johnson		<janisjo@codesourcery.com>
 register allocation	Vladimir Makarov	<vmakarov@redhat.com>
 gdbhooks.py		David Malcolm		<dmalcolm@redhat.com>
 SLSR			Bill Schmidt		<wschmidt@linux.vnet.ibm.com>
+jit			David Malcolm		<dmalcolm@redhat.com>
 
 Note that individuals who maintain parts of the compiler need approval to
 check in changes outside of the parts of the compiler they maintain.
diff --git a/contrib/jit-coverage-report.py b/contrib/jit-coverage-report.py
new file mode 100644
index 0000000..529336f
--- /dev/null
+++ b/contrib/jit-coverage-report.py
@@ -0,0 +1,67 @@
+#! /usr/bin/python
+#
+# Print a report on which libgccjit.so symbols are used in which test
+# cases, and which lack test coverage.  Tested with Python 2.7 and 3.2
+# To be run from the root directory of the source tree.
+#
+# Copyright (C) 2014 Free Software Foundation, Inc.
+# Written by David Malcolm <dmalcolm@redhat.com>.
+#
+# This script is Free Software, and it can be copied, distributed and
+# modified as defined in the GNU General Public License.  A copy of
+# its license can be downloaded from http://www.gnu.org/copyleft/gpl.html
+
+from collections import Counter
+import glob
+import re
+import sys
+
+def parse_map_file(path):
+    """
+    Parse libgccjit.map, returning the symbols in the API as a list of str.
+    """
+    syms = []
+    with open(path) as f:
+        for line in f:
+            m = re.match('^\s+([a-z_]+);$', line)
+            if m:
+                syms.append(m.group(1))
+    return syms
+
+def parse_test_case(path):
+    """
+    Locate all symbol-like things in a C test case, yielding
+    them as a sequence of str.
+    """
+    with open(path) as f:
+        for line in f:
+            for m in re.finditer('([_A-Za-z][_A-Za-z0-9]*)', line):
+                yield m.group(1)
+
+def find_test_cases():
+    for path in glob.glob('gcc/testsuite/jit.dg/*.[ch]'):
+        yield path
+
+api_syms = parse_map_file('gcc/jit/libgccjit.map')
+
+syms_in_test_cases = {}
+for path in find_test_cases():
+    syms_in_test_cases[path] = list(parse_test_case(path))
+
+uses = Counter()
+for sym in sorted(api_syms):
+    print('symbol: %s' % sym)
+    uses[sym] = 0
+    for path in syms_in_test_cases:
+        count = syms_in_test_cases[path].count(sym)
+        uses[sym] += count
+        if count:
+            print('  uses in %s: %i' % (path, count))
+    if uses[sym] == 0:
+        print('  NEVER USED')
+    sys.stdout.write('\n')
+
+layout = '%40s  %5s  %s'
+print(layout % ('SYMBOL', 'USES', 'HISTOGRAM'))
+for sym, count in uses.most_common():
+    print(layout % (sym, count, '*' * count if count else 'UNUSED'))
diff --git a/gcc/doc/install.texi b/gcc/doc/install.texi
index 3df78ff..06fcd8a 100644
--- a/gcc/doc/install.texi
+++ b/gcc/doc/install.texi
@@ -954,7 +954,7 @@ Specify that the @emph{host} code should be built into position-independent
 machine code (with -fPIC), allowing it to be used within shared libraries,
 but yielding a slightly slower compiler.
 
-Currently this option is only of use to people developing GCC itself.
+This option is required when building the libgccjit.so library.
 
 Contrast with @option{--enable-shared}, which affects @emph{target}
 libraries.
diff --git a/gcc/timevar.def b/gcc/timevar.def
index 96b6069..6968a06 100644
--- a/gcc/timevar.def
+++ b/gcc/timevar.def
@@ -279,3 +279,9 @@ DEFTIMEVAR (TV_VERIFY_LOOP_CLOSED    , "verify loop closed")
 DEFTIMEVAR (TV_VERIFY_RTL_SHARING    , "verify RTL sharing")
 DEFTIMEVAR (TV_REBUILD_FREQUENCIES   , "rebuild frequencies")
 DEFTIMEVAR (TV_REPAIR_LOOPS	     , "repair loop structures")
+
+/* Stuff used by libgccjit.so.  */
+DEFTIMEVAR (TV_JIT_REPLAY	     , "replay of JIT client activity")
+DEFTIMEVAR (TV_ASSEMBLE	     , "assemble JIT code")
+DEFTIMEVAR (TV_LINK		     , "link JIT code")
+DEFTIMEVAR (TV_LOAD		     , "load JIT result")
-- 
1.8.5.3

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

* [PATCH 09/27] New file: gcc/jit/libgccjit.map
  2014-10-31 17:07 [PATCH 00/27] Merger of jit branch v3 David Malcolm
                   ` (7 preceding siblings ...)
  2014-10-31 17:07 ` [PATCH 05/27] New file: gcc/jit/config-lang.in David Malcolm
@ 2014-10-31 17:07 ` David Malcolm
  2014-10-31 21:21   ` Jeff Law
  2014-10-31 17:16 ` [PATCH 23/27] Documentation: the "intro" subdirectory David Malcolm
                   ` (16 subsequent siblings)
  25 siblings, 1 reply; 71+ messages in thread
From: David Malcolm @ 2014-10-31 17:07 UTC (permalink / raw)
  To: gcc-patches, jit; +Cc: David Malcolm

This linker script ensures that the library only exports the symbols
we want it to.

gcc/jit/
	* libgccjit.map: New.
---
 gcc/jit/libgccjit.map | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 100 insertions(+)
 create mode 100644 gcc/jit/libgccjit.map

diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map
new file mode 100644
index 0000000..d4ba7b6
--- /dev/null
+++ b/gcc/jit/libgccjit.map
@@ -0,0 +1,100 @@
+# Linker script for libgccjit.so
+#   Copyright (C) 2013-2014 Free Software Foundation, Inc.
+#   Contributed by David Malcolm <dmalcolm@redhat.com>.
+#
+# This file is part of GCC.
+#
+# GCC is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GCC is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.  */
+{
+  global:
+    # Keep this list sorted alphabetically:
+    gcc_jit_block_add_assignment;
+    gcc_jit_block_add_assignment_op;
+    gcc_jit_block_add_comment;
+    gcc_jit_block_add_eval;
+    gcc_jit_block_as_object;
+    gcc_jit_block_end_with_conditional;
+    gcc_jit_block_end_with_jump;
+    gcc_jit_block_end_with_return;
+    gcc_jit_block_end_with_void_return;
+    gcc_jit_block_get_function;
+    gcc_jit_context_acquire;
+    gcc_jit_context_compile;
+    gcc_jit_context_dump_to_file;
+    gcc_jit_context_get_builtin_function;
+    gcc_jit_context_get_first_error;
+    gcc_jit_context_get_type;
+    gcc_jit_context_get_int_type;
+    gcc_jit_context_new_array_access;
+    gcc_jit_context_new_array_type;
+    gcc_jit_context_new_binary_op;
+    gcc_jit_context_new_call;
+    gcc_jit_context_new_call_through_ptr;
+    gcc_jit_context_new_cast;
+    gcc_jit_context_new_child_context;
+    gcc_jit_context_new_comparison;
+    gcc_jit_context_new_field;
+    gcc_jit_context_new_function;
+    gcc_jit_context_new_function_ptr_type;
+    gcc_jit_context_new_global;
+    gcc_jit_context_new_location;
+    gcc_jit_context_new_opaque_struct;
+    gcc_jit_context_new_param;
+    gcc_jit_context_new_rvalue_from_double;
+    gcc_jit_context_new_rvalue_from_int;
+    gcc_jit_context_new_rvalue_from_ptr;
+    gcc_jit_context_new_string_literal;
+    gcc_jit_context_new_struct_type;
+    gcc_jit_context_new_unary_op;
+    gcc_jit_context_new_union_type;
+    gcc_jit_context_null;
+    gcc_jit_context_one;
+    gcc_jit_context_release;
+    gcc_jit_context_set_bool_option;
+    gcc_jit_context_set_int_option;
+    gcc_jit_context_set_str_option;
+    gcc_jit_context_zero;
+    gcc_jit_field_as_object;
+    gcc_jit_function_as_object;
+    gcc_jit_function_dump_to_dot;
+    gcc_jit_function_get_param;
+    gcc_jit_function_new_block;
+    gcc_jit_function_new_local;
+    gcc_jit_location_as_object;
+    gcc_jit_lvalue_as_object;
+    gcc_jit_lvalue_as_rvalue;
+    gcc_jit_lvalue_access_field;
+    gcc_jit_lvalue_get_address;
+    gcc_jit_object_get_context;
+    gcc_jit_object_get_debug_string;
+    gcc_jit_param_as_lvalue;
+    gcc_jit_param_as_object;
+    gcc_jit_param_as_rvalue;
+    gcc_jit_result_get_code;
+    gcc_jit_result_release;
+    gcc_jit_rvalue_access_field;
+    gcc_jit_rvalue_as_object;
+    gcc_jit_rvalue_dereference;
+    gcc_jit_rvalue_dereference_field;
+    gcc_jit_rvalue_get_type;
+    gcc_jit_struct_as_type;
+    gcc_jit_struct_set_fields;
+    gcc_jit_type_as_object;
+    gcc_jit_type_get_const;
+    gcc_jit_type_get_pointer;
+    gcc_jit_type_get_volatile;
+
+  local: *;
+};
\ No newline at end of file
-- 
1.8.5.3

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

* [PATCH 06/27] New file: gcc/jit/Make-lang.in
  2014-10-31 17:07 [PATCH 00/27] Merger of jit branch v3 David Malcolm
                   ` (5 preceding siblings ...)
  2014-10-31 17:07 ` [PATCH 21/27] Documentation: the "examples" subdirectory David Malcolm
@ 2014-10-31 17:07 ` David Malcolm
  2014-11-03 21:35   ` Jeff Law
  2014-10-31 17:07 ` [PATCH 05/27] New file: gcc/jit/config-lang.in David Malcolm
                   ` (18 subsequent siblings)
  25 siblings, 1 reply; 71+ messages in thread
From: David Malcolm @ 2014-10-31 17:07 UTC (permalink / raw)
  To: gcc-patches, jit; +Cc: David Malcolm

gcc/jit/
	* Make-lang.in: New.
---
 gcc/jit/Make-lang.in | 298 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 298 insertions(+)
 create mode 100644 gcc/jit/Make-lang.in

diff --git a/gcc/jit/Make-lang.in b/gcc/jit/Make-lang.in
new file mode 100644
index 0000000..167fcad
--- /dev/null
+++ b/gcc/jit/Make-lang.in
@@ -0,0 +1,298 @@
+# Top level -*- makefile -*- fragment for libgccjit.so.
+#   Copyright (C) 2013-2014 Free Software Foundation, Inc.
+
+#This file is part of GCC.
+
+#GCC is free software; you can redistribute it and/or modify
+#it under the terms of the GNU General Public License as published by
+#the Free Software Foundation; either version 3, or (at your option)
+#any later version.
+
+#GCC is distributed in the hope that it will be useful,
+#but WITHOUT ANY WARRANTY; without even the implied warranty of
+#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+# This file provides the language dependent support in the main Makefile.
+# Each language makefile fragment must provide the following targets:
+#
+# foo.all.cross, foo.start.encap, foo.rest.encap,
+# foo.install-common, foo.install-man, foo.install-info, foo.install-pdf,
+# foo.install-html, foo.info, foo.dvi, foo.pdf, foo.html, foo.uninstall,
+# foo.mostlyclean, foo.clean, foo.distclean,
+# foo.maintainer-clean, foo.stage1, foo.stage2, foo.stage3, foo.stage4
+#
+# where `foo' is the name of the language.
+#
+# It should also provide rules for:
+#
+# - making any compiler driver (eg: g++)
+# - the compiler proper (eg: cc1plus)
+# - define the names for selecting the language in LANGUAGES.
+
+#\f
+# Define the names for selecting jit in LANGUAGES.
+# Note that it would be nice to move the dependency on g++
+# into the jit rule, but that needs a little bit of work
+# to do the right thing within all.cross.
+
+LIBGCCJIT_LINKER_NAME = libgccjit.so
+LIBGCCJIT_VERSION_NUM = 0
+LIBGCCJIT_MINOR_NUM = 0
+LIBGCCJIT_RELEASE_NUM = 1
+LIBGCCJIT_SONAME = $(LIBGCCJIT_LINKER_NAME).$(LIBGCCJIT_VERSION_NUM)
+LIBGCCJIT_FILENAME = \
+  $(LIBGCCJIT_SONAME).$(LIBGCCJIT_MINOR_NUM).$(LIBGCCJIT_RELEASE_NUM)
+
+LIBGCCJIT_LINKER_NAME_SYMLINK = $(LIBGCCJIT_LINKER_NAME)
+LIBGCCJIT_SONAME_SYMLINK = $(LIBGCCJIT_SONAME)
+
+jit: $(LIBGCCJIT_FILENAME) \
+	$(LIBGCCJIT_SYMLINK) \
+	$(LIBGCCJIT_LINKER_NAME_SYMLINK) \
+	$(FULL_DRIVER_NAME)
+
+# Tell GNU make to ignore these if they exist.
+.PHONY: jit
+
+jit_OBJS = attribs.o \
+	jit/dummy-frontend.o \
+	jit/libgccjit.o \
+	jit/jit-recording.o \
+	jit/jit-playback.o \
+	jit/jit-builtins.o
+
+# Use strict warnings for this front end.
+jit-warn = $(STRICT_WARN)
+
+# We avoid using $(BACKEND) from Makefile.in in order to avoid pulling
+# in main.o
+$(LIBGCCJIT_FILENAME): $(jit_OBJS) \
+	libbackend.a libcommon-target.a libcommon.a \
+	$(CPPLIB) $(LIBDECNUMBER) \
+	$(LIBDEPS) $(srcdir)/jit/libgccjit.map
+	+$(LLINKER) $(ALL_LINKERFLAGS) $(LDFLAGS) -o $@ -shared \
+	     $(jit_OBJS) libbackend.a libcommon-target.a libcommon.a \
+	     $(CPPLIB) $(LIBDECNUMBER) $(LIBS) $(BACKENDLIBS) \
+	     -Wl,--version-script=$(srcdir)/jit/libgccjit.map \
+	     -Wl,-soname,$(LIBGCCJIT_SONAME)
+
+$(LIBGCCJIT_SONAME_SYMLINK): $(LIBGCCJIT_FILENAME)
+	ln -sf $(LIBGCCJIT_FILENAME) $(LIBGCCJIT_SONAME_SYMLINK)
+
+$(LIBGCCJIT_LINKER_NAME_SYMLINK): $(LIBGCCJIT_SONAME_SYMLINK)
+	ln -sf $(LIBGCCJIT_SONAME_SYMLINK) $(LIBGCCJIT_LINKER_NAME_SYMLINK)
+
+#\f
+# Build hooks:
+
+jit.all.cross:
+jit.start.encap:
+jit.rest.encap:
+
+# Documentation build hooks.
+#
+# The documentation can be built using the texinfo toolchain, or
+# the sphinx toolchain
+#
+# The jit documentation is authored using Sphinx, which has numerous
+# advantages over Texinfo, including:
+#
+#   * much faster
+#
+#   * use of CSS and JS to provide less of a 1990s feel in the generated
+#     HTML.
+#
+#   * sane, stable HTML page and anchor names
+#
+#   * sane HTML navigation: ability to move forward and back in the HTML
+#     at every node to read the HTML like a book
+#
+#   * syntax-coloring of examples
+#
+#   * the ability to "include" fragments of code inline.  This is used
+#     heavily by the jit docs, so that the example code is shared by both
+#     the test suite and the documentation to ensure that the examples
+#     appearing in the docs actually compile and work
+#
+# Sphinx is not a "blessed" dependency, and so a prebuilt libgccjit.texinfo
+# file built by Sphinx is checked into the source tree to avoid requiring
+# everyone to have Sphinx installed.
+#
+# This prebuilt libgccjit.texinfo has the "include" fragments "baked in",
+# and so contains the content from the sphinx toolchain, but lacks the
+# syntax-coloring, and the generated HTML is (IMHO) greatly inferior to
+# that generated by Sphinx.
+
+# These targets redirect HTML creation and installation to either
+# jit.sphinx.(install-)html or jit.texinfo.(install-)html.
+jit.html: jit.$(doc_build_sys).html
+jit.install-html: jit.$(doc_build_sys).install-html
+
+# For now, use texinfo for pdf, since the sphinx latex toolchain currently
+# fails for me deep inside pdflatex (see notes below)
+jit.pdf: jit.texinfo.pdf
+jit.install-pdf: jit.texinfo.install-pdf
+
+# Hooks for building docs using texinfo
+JIT_TEXI_FILES = $(srcdir)/jit/docs/_build/texinfo/libgccjit.texi
+
+jit.info: doc/libgccjit.info
+doc/libgccjit.info: $(JIT_TEXI_FILES)
+	if test "x$(BUILD_INFO)" = xinfo; then \
+	  rm -f doc/libgccjit.info*; \
+	  $(MAKEINFO) $(MAKEINFOFLAGS) -I $(gcc_docdir) \
+		-I $(gcc_docdir)/include -o $@ $<; \
+	else true; fi
+
+jit.install-info: $(DESTDIR)$(infodir)/libgccjit.info
+
+jit.dvi: doc/libgccjit.dvi
+doc/libgccjit.dvi: $(JIT_TEXI_FILES)
+	$(TEXI2DVI) -I $(abs_docdir) -I $(abs_docdir)/include -o $@ $<
+
+jit.texinfo.html: $(build_htmldir)/jit/index.html
+
+$(build_htmldir)/jit/index.html: $(srcdir)/jit/docs/_build/texinfo/libgccjit.texi
+	$(mkinstalldirs) $(@D)
+	rm -f $(@D)/*
+	$(TEXI2HTML) -I $(gcc_docdir)/include -I $(srcdir)/jit -o $(@D) $<
+
+jit.texinfo.install-html: jit.texinfo.html
+	@$(NORMAL_INSTALL)
+	test -z "$(htmldir)" || $(mkinstalldirs) "$(DESTDIR)$(htmldir)"
+	@for p in $(build_htmldir)/jit; do \
+	  if test -f "$$p" || test -d "$$p"; then d=""; else d="$(srcdir)/"; fi; \
+	  f=$(html__strip_dir) \
+	  if test -d "$$d$$p"; then \
+	    echo " $(mkinstalldirs) '$(DESTDIR)$(htmldir)/$$f'"; \
+	    $(mkinstalldirs) "$(DESTDIR)$(htmldir)/$$f" || exit 1; \
+	    echo " $(INSTALL_DATA) '$$d$$p'/* '$(DESTDIR)$(htmldir)/$$f'"; \
+	    $(INSTALL_DATA) "$$d$$p"/* "$(DESTDIR)$(htmldir)/$$f"; \
+	  else \
+	    echo " $(INSTALL_DATA) '$$d$$p' '$(DESTDIR)$(htmldir)/$$f'"; \
+	    $(INSTALL_DATA) "$$d$$p" "$(DESTDIR)$(htmldir)/$$f"; \
+	  fi; \
+	done
+
+jit.texinfo.pdf: doc/libgccjit.pdf
+
+doc/libgccjit.pdf: $(JIT_TEXI_FILES)
+	$(TEXI2PDF) -I $(abs_docdir) -I $(abs_docdir)/include -o $@ $<
+
+jit.texinfo.install-pdf: doc/libgccjit.pdf
+	@$(NORMAL_INSTALL)
+	test -z "$(pdfdir)" || $(mkinstalldirs) "$(DESTDIR)$(pdfdir)/gcc"
+	@for p in doc/libgccjit.pdf; do \
+	  if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+	  f=$(pdf__strip_dir) \
+	  echo " $(INSTALL_DATA) '$$d$$p' '$(DESTDIR)$(pdfdir)/gcc/$$f'"; \
+	  $(INSTALL_DATA) "$$d$$p" "$(DESTDIR)$(pdfdir)/gcc/$$f"; \
+	done
+
+# Hooks for building docs using the Sphinx toolchain:
+
+SPHINX_BUILD_DIR=jit/sphinx-build
+
+jit.sphinx.html:
+	mkdir -p $(SPHINX_BUILD_DIR)
+	(cd $(srcdir)/jit/docs && \
+	  make html BUILDDIR=$(PWD)/$(SPHINX_BUILD_DIR) )
+
+jit_htmldir=$(htmldir)/jit
+
+jit.sphinx.install-html: jit.sphinx.html
+	@$(NORMAL_INSTALL)
+	test -z "$(jit_htmldir)" || $(mkinstalldirs) "$(DESTDIR)$(jit_htmldir)"
+	@for f in $(shell cd $(SPHINX_BUILD_DIR)/html && find) ; do \
+	  if test -f $(SPHINX_BUILD_DIR)/html/"$$f"; then \
+	     $(INSTALL_DATA) $(SPHINX_BUILD_DIR)/html/"$$f" $(DESTDIR)$(jit_htmldir)/"$$f"; \
+	  else \
+	     mkdir $(DESTDIR)$(jit_htmldir)/"$$f"; \
+	  fi; \
+	done
+
+# (This one is currently failing deep inside pdflatex for me;
+# see https://bugzilla.redhat.com/show_bug.cgi?id=1148845 )
+jit.sphinx.pdf: $(SPHINX_BUILD_DIR)/latex/libgccjit.pdf
+$(SPHINX_BUILD_DIR)/latex/libgccjit.pdf:
+	mkdir -p $(SPHINX_BUILD_DIR)
+	(cd $(srcdir)/jit/docs && \
+	  make latexpdf BUILDDIR=$(PWD)/$(SPHINX_BUILD_DIR) )
+
+jit.sphinx.install-pdf: $(SPHINX_BUILD_DIR)/latex/libgccjit.pdf
+	@$(NORMAL_INSTALL)
+	test -z "$(pdfdir)" || $(mkinstalldirs) "$(DESTDIR)$(pdfdir)/gcc"
+	@for p in $(SPHINX_BUILD_DIR)/latex/libgccjit.pdf; do \
+	  if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+	  f=$(pdf__strip_dir) \
+	  echo " $(INSTALL_DATA) '$$d$$p' '$(DESTDIR)$(pdfdir)/gcc/$$f'"; \
+	  $(INSTALL_DATA) "$$d$$p" "$(DESTDIR)$(pdfdir)/gcc/$$f"; \
+	done
+
+jit.srcinfo:
+jit.srcextra:
+
+jit.tags:
+
+jit.man:
+
+jit.srcman:
+
+lang_checks += check-jit
+
+#\f
+# Install hooks:
+jit.install-common: installdirs
+	$(INSTALL_PROGRAM) $(LIBGCCJIT_FILENAME) \
+	  $(DESTDIR)/$(libdir)/$(LIBGCCJIT_FILENAME)
+	ln -sf \
+	  $(LIBGCCJIT_FILENAME) \
+	  $(DESTDIR)/$(libdir)/$(LIBGCCJIT_SONAME_SYMLINK)
+	ln -sf \
+	  $(LIBGCCJIT_SONAME_SYMLINK)\
+	  $(DESTDIR)/$(libdir)/$(LIBGCCJIT_LINKER_NAME_SYMLINK)
+	$(INSTALL_PROGRAM) $(srcdir)/jit/libgccjit.h \
+	  $(DESTDIR)/$(includedir)/libgccjit.h
+	$(INSTALL_PROGRAM) $(srcdir)/jit/libgccjit++.h \
+	  $(DESTDIR)/$(includedir)/libgccjit++.h
+
+jit.install-man:
+
+jit.install-plugin:
+
+jit.uninstall:
+
+#\f
+# Clean hooks:
+# A lot of the ancillary files are deleted by the main makefile.
+# We just have to delete files specific to us.
+
+jit.mostlyclean:
+
+jit.clean:
+
+jit.distclean:
+
+jit.maintainer-clean:
+
+#\f
+# Stage hooks:
+# The main makefile has already created stage?/jit.
+
+jit.stage1: stage1-start
+	-mv jit/*$(objext) stage1/jit
+jit.stage2: stage2-start
+	-mv jit/*$(objext) stage2/jit
+jit.stage3: stage3-start
+	-mv jit/*$(objext) stage3/jit
+jit.stage4: stage4-start
+	-mv jit/*$(objext) stage4/jit
+jit.stageprofile: stageprofile-start
+	-mv jit/*$(objext) stageprofile/jit
+jit.stagefeedback: stagefeedback-start
+	-mv jit/*$(objext) stagefeedback/jit
-- 
1.8.5.3

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

* [PATCH 21/27] Documentation: the "examples" subdirectory
  2014-10-31 17:07 [PATCH 00/27] Merger of jit branch v3 David Malcolm
                   ` (4 preceding siblings ...)
  2014-10-31 17:07 ` [PATCH 01/27] gcc: configure and Makefile changes needed by jit David Malcolm
@ 2014-10-31 17:07 ` David Malcolm
  2014-10-31 21:31   ` Jeff Law
  2014-10-31 17:07 ` [PATCH 06/27] New file: gcc/jit/Make-lang.in David Malcolm
                   ` (19 subsequent siblings)
  25 siblings, 1 reply; 71+ messages in thread
From: David Malcolm @ 2014-10-31 17:07 UTC (permalink / raw)
  To: gcc-patches, jit; +Cc: David Malcolm

This patch adds examples.  These examples are used included
by the documentation when it is built, and are run as code by the
testsuite, ensuring that the examples shown in the docs build and
run.

gcc/jit/
	* docs/examples/tut01-hello-world.c: New.
	* docs/examples/tut02-square.c: New.
	* docs/examples/tut03-sum-of-squares.c: New.
	* docs/examples/tut04-toyvm/Makefile: New.
	* docs/examples/tut04-toyvm/factorial.toy: New.
	* docs/examples/tut04-toyvm/fibonacci.toy: New.
	* docs/examples/tut04-toyvm/toyvm.c: New.
---
 gcc/jit/docs/examples/tut01-hello-world.c       | 123 ++++
 gcc/jit/docs/examples/tut02-square.c            | 107 +++
 gcc/jit/docs/examples/tut03-sum-of-squares.c    | 172 +++++
 gcc/jit/docs/examples/tut04-toyvm/Makefile      |  11 +
 gcc/jit/docs/examples/tut04-toyvm/factorial.toy |  50 ++
 gcc/jit/docs/examples/tut04-toyvm/fibonacci.toy |  66 ++
 gcc/jit/docs/examples/tut04-toyvm/toyvm.c       | 861 ++++++++++++++++++++++++
 7 files changed, 1390 insertions(+)
 create mode 100644 gcc/jit/docs/examples/tut01-hello-world.c
 create mode 100644 gcc/jit/docs/examples/tut02-square.c
 create mode 100644 gcc/jit/docs/examples/tut03-sum-of-squares.c
 create mode 100644 gcc/jit/docs/examples/tut04-toyvm/Makefile
 create mode 100644 gcc/jit/docs/examples/tut04-toyvm/factorial.toy
 create mode 100644 gcc/jit/docs/examples/tut04-toyvm/fibonacci.toy
 create mode 100644 gcc/jit/docs/examples/tut04-toyvm/toyvm.c

diff --git a/gcc/jit/docs/examples/tut01-hello-world.c b/gcc/jit/docs/examples/tut01-hello-world.c
new file mode 100644
index 0000000..49c9651
--- /dev/null
+++ b/gcc/jit/docs/examples/tut01-hello-world.c
@@ -0,0 +1,123 @@
+/* Smoketest example for libgccjit.so
+   Copyright (C) 2014 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include <libgccjit.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+
+static void
+create_code (gcc_jit_context *ctxt)
+{
+  /* Let's try to inject the equivalent of:
+     void
+     greet (const char *name)
+     {
+        printf ("hello %s\n", name);
+     }
+  */
+  gcc_jit_type *void_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+  gcc_jit_type *const_char_ptr_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_CONST_CHAR_PTR);
+  gcc_jit_param *param_name =
+    gcc_jit_context_new_param (ctxt, NULL, const_char_ptr_type, "name");
+  gcc_jit_function *func =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                  GCC_JIT_FUNCTION_EXPORTED,
+                                  void_type,
+                                  "greet",
+                                  1, &param_name,
+                                  0);
+
+  gcc_jit_param *param_format =
+    gcc_jit_context_new_param (ctxt, NULL, const_char_ptr_type, "format");
+  gcc_jit_function *printf_func =
+    gcc_jit_context_new_function (ctxt, NULL,
+				  GCC_JIT_FUNCTION_IMPORTED,
+				  gcc_jit_context_get_type (
+				     ctxt, GCC_JIT_TYPE_INT),
+				  "printf",
+				  1, &param_format,
+				  1);
+  gcc_jit_rvalue *args[2];
+  args[0] = gcc_jit_context_new_string_literal (ctxt, "hello %s\n");
+  args[1] = gcc_jit_param_as_rvalue (param_name);
+
+  gcc_jit_block *block = gcc_jit_function_new_block (func, NULL);
+
+  gcc_jit_block_add_eval (
+    block, NULL,
+    gcc_jit_context_new_call (ctxt,
+                              NULL,
+                              printf_func,
+                              2, args));
+  gcc_jit_block_end_with_void_return (block, NULL);
+}
+
+int
+main (int argc, char **argv)
+{
+  gcc_jit_context *ctxt;
+  gcc_jit_result *result;
+
+  /* Get a "context" object for working with the library.  */
+  ctxt = gcc_jit_context_acquire ();
+  if (!ctxt)
+    {
+      fprintf (stderr, "NULL ctxt");
+      exit (1);
+    }
+
+  /* Set some options on the context.
+     Let's see the code being generated, in assembler form.  */
+  gcc_jit_context_set_bool_option (
+    ctxt,
+    GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE,
+    0);
+
+  /* Populate the context.  */
+  create_code (ctxt);
+
+  /* Compile the code.  */
+  result = gcc_jit_context_compile (ctxt);
+  if (!result)
+    {
+      fprintf (stderr, "NULL result");
+      exit (1);
+    }
+
+  /* Extract the generated code from "result".  */
+  typedef void (*fn_type) (const char *);
+  fn_type greet =
+    (fn_type)gcc_jit_result_get_code (result, "greet");
+  if (!greet)
+    {
+      fprintf (stderr, "NULL greet");
+      exit (1);
+    }
+
+  /* Now call the generated function: */
+  greet ("world");
+  fflush (stdout);
+
+  gcc_jit_context_release (ctxt);
+  gcc_jit_result_release (result);
+  return 0;
+}
diff --git a/gcc/jit/docs/examples/tut02-square.c b/gcc/jit/docs/examples/tut02-square.c
new file mode 100644
index 0000000..5eae179
--- /dev/null
+++ b/gcc/jit/docs/examples/tut02-square.c
@@ -0,0 +1,107 @@
+/* Usage example for libgccjit.so
+   Copyright (C) 2014 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include <libgccjit.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+
+void
+create_code (gcc_jit_context *ctxt)
+{
+  /* Let's try to inject the equivalent of:
+
+      int square (int i)
+      {
+        return i * i;
+      }
+  */
+  gcc_jit_type *int_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+  gcc_jit_param *param_i =
+    gcc_jit_context_new_param (ctxt, NULL, int_type, "i");
+  gcc_jit_function *func =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                  GCC_JIT_FUNCTION_EXPORTED,
+                                  int_type,
+                                  "square",
+                                  1, &param_i,
+                                  0);
+
+  gcc_jit_block *block = gcc_jit_function_new_block (func, NULL);
+
+  gcc_jit_rvalue *expr =
+    gcc_jit_context_new_binary_op (
+      ctxt, NULL,
+      GCC_JIT_BINARY_OP_MULT, int_type,
+      gcc_jit_param_as_rvalue (param_i),
+      gcc_jit_param_as_rvalue (param_i));
+
+   gcc_jit_block_end_with_return (block, NULL, expr);
+}
+
+int
+main (int argc, char **argv)
+{
+  gcc_jit_context *ctxt = NULL;
+  gcc_jit_result *result = NULL;
+
+  /* Get a "context" object for working with the library.  */
+  ctxt = gcc_jit_context_acquire ();
+  if (!ctxt)
+    {
+      fprintf (stderr, "NULL ctxt");
+      goto error;
+    }
+
+  /* Set some options on the context.
+     Let's see the code being generated, in assembler form.  */
+  gcc_jit_context_set_bool_option (
+    ctxt,
+    GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE,
+    0);
+
+  /* Populate the context.  */
+  create_code (ctxt);
+
+  /* Compile the code.  */
+  result = gcc_jit_context_compile (ctxt);
+  if (!result)
+    {
+      fprintf (stderr, "NULL result");
+      goto error;
+    }
+
+  /* Extract the generated code from "result".  */
+  void *fn_ptr = gcc_jit_result_get_code (result, "square");
+  if (!fn_ptr)
+     {
+       fprintf (stderr, "NULL fn_ptr");
+       goto error;
+     }
+
+  typedef int (*fn_type) (int);
+  fn_type square = (fn_type)fn_ptr;
+  printf ("result: %d", square (5));
+
+ error:
+  gcc_jit_context_release (ctxt);
+  gcc_jit_result_release (result);
+  return 0;
+}
diff --git a/gcc/jit/docs/examples/tut03-sum-of-squares.c b/gcc/jit/docs/examples/tut03-sum-of-squares.c
new file mode 100644
index 0000000..594230b
--- /dev/null
+++ b/gcc/jit/docs/examples/tut03-sum-of-squares.c
@@ -0,0 +1,172 @@
+/* Usage example for libgccjit.so
+   Copyright (C) 2014 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include <libgccjit.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+
+void
+create_code (gcc_jit_context *ctxt)
+{
+  /*
+    Simple sum-of-squares, to test conditionals and looping
+
+    int loop_test (int n)
+    {
+      int i;
+      int sum = 0;
+      for (i = 0; i < n ; i ++)
+      {
+	sum += i * i;
+      }
+      return sum;
+   */
+  gcc_jit_type *the_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+  gcc_jit_type *return_type = the_type;
+
+  gcc_jit_param *n =
+    gcc_jit_context_new_param (ctxt, NULL, the_type, "n");
+  gcc_jit_param *params[1] = {n};
+  gcc_jit_function *func =
+    gcc_jit_context_new_function (ctxt, NULL,
+				  GCC_JIT_FUNCTION_EXPORTED,
+				  return_type,
+				  "loop_test",
+				  1, params, 0);
+
+  /* Build locals:  */
+  gcc_jit_lvalue *i =
+    gcc_jit_function_new_local (func, NULL, the_type, "i");
+  gcc_jit_lvalue *sum =
+    gcc_jit_function_new_local (func, NULL, the_type, "sum");
+
+  gcc_jit_block *b_initial =
+    gcc_jit_function_new_block (func, "initial");
+  gcc_jit_block *b_loop_cond =
+    gcc_jit_function_new_block (func, "loop_cond");
+  gcc_jit_block *b_loop_body =
+    gcc_jit_function_new_block (func, "loop_body");
+  gcc_jit_block *b_after_loop =
+    gcc_jit_function_new_block (func, "after_loop");
+
+  /* sum = 0; */
+  gcc_jit_block_add_assignment (
+    b_initial, NULL,
+    sum,
+    gcc_jit_context_zero (ctxt, the_type));
+
+  /* i = 0; */
+  gcc_jit_block_add_assignment (
+    b_initial, NULL,
+    i,
+    gcc_jit_context_zero (ctxt, the_type));
+
+  gcc_jit_block_end_with_jump (b_initial, NULL, b_loop_cond);
+
+  /* if (i >= n) */
+  gcc_jit_block_end_with_conditional (
+    b_loop_cond, NULL,
+    gcc_jit_context_new_comparison (
+       ctxt, NULL,
+       GCC_JIT_COMPARISON_GE,
+       gcc_jit_lvalue_as_rvalue (i),
+       gcc_jit_param_as_rvalue (n)),
+    b_after_loop,
+    b_loop_body);
+
+  /* sum += i * i */
+  gcc_jit_block_add_assignment_op (
+    b_loop_body, NULL,
+    sum,
+    GCC_JIT_BINARY_OP_PLUS,
+    gcc_jit_context_new_binary_op (
+      ctxt, NULL,
+      GCC_JIT_BINARY_OP_MULT, the_type,
+      gcc_jit_lvalue_as_rvalue (i),
+      gcc_jit_lvalue_as_rvalue (i)));
+
+  /* i++ */
+  gcc_jit_block_add_assignment_op (
+    b_loop_body, NULL,
+    i,
+    GCC_JIT_BINARY_OP_PLUS,
+    gcc_jit_context_one (ctxt, the_type));
+
+  gcc_jit_block_end_with_jump (b_loop_body, NULL, b_loop_cond);
+
+  /* return sum */
+  gcc_jit_block_end_with_return (
+    b_after_loop,
+    NULL,
+    gcc_jit_lvalue_as_rvalue (sum));
+}
+
+int
+main (int argc, char **argv)
+{
+  gcc_jit_context *ctxt = NULL;
+  gcc_jit_result *result = NULL;
+
+  /* Get a "context" object for working with the library.  */
+  ctxt = gcc_jit_context_acquire ();
+  if (!ctxt)
+    {
+      fprintf (stderr, "NULL ctxt");
+      goto error;
+    }
+
+  /* Set some options on the context.
+     Let's see the code being generated, in assembler form.  */
+  gcc_jit_context_set_bool_option (
+    ctxt,
+    GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE,
+    0);
+
+  /* Populate the context.  */
+  create_code (ctxt);
+
+  /* Compile the code.  */
+  result = gcc_jit_context_compile (ctxt);
+  if (!result)
+    {
+      fprintf (stderr, "NULL result");
+      goto error;
+    }
+
+  /* Extract the generated code from "result".  */
+  typedef int (*loop_test_fn_type) (int);
+  loop_test_fn_type loop_test =
+    (loop_test_fn_type)gcc_jit_result_get_code (result, "loop_test");
+  if (!loop_test)
+    {
+      fprintf (stderr, "NULL loop_test");
+      goto error;
+    }
+
+  /* Run the generated code.  */
+  int val = loop_test (10);
+  printf("loop_test returned: %d\n", val);
+
+ error:
+  gcc_jit_context_release (ctxt);
+  gcc_jit_result_release (result);
+  return 0;
+}
diff --git a/gcc/jit/docs/examples/tut04-toyvm/Makefile b/gcc/jit/docs/examples/tut04-toyvm/Makefile
new file mode 100644
index 0000000..1b45c8d
--- /dev/null
+++ b/gcc/jit/docs/examples/tut04-toyvm/Makefile
@@ -0,0 +1,11 @@
+factorial: toyvm
+	./toyvm factorial.toy 10
+
+fibonacci: toyvm
+	./toyvm fibonacci.toy 8
+
+toyvm: toyvm.c Makefile
+	g++ -Wall -g -o $@ $< $(shell pkg-config --cflags --libs libgccjit)
+
+clean:
+	rm -f *.o toyvm
diff --git a/gcc/jit/docs/examples/tut04-toyvm/factorial.toy b/gcc/jit/docs/examples/tut04-toyvm/factorial.toy
new file mode 100644
index 0000000..48e4034
--- /dev/null
+++ b/gcc/jit/docs/examples/tut04-toyvm/factorial.toy
@@ -0,0 +1,50 @@
+# Simple recursive factorial implementation, roughly equivalent to:
+#
+#  int factorial (int arg)
+#  {
+#     if (arg < 2)
+#       return arg
+#     return arg * factorial (arg - 1)
+#  }
+
+# Initial state:
+# stack: [arg]
+
+# 0:
+DUP
+# stack: [arg, arg]
+
+# 1:
+PUSH_CONST 2
+# stack: [arg, arg, 2]
+
+# 2:
+BINARY_COMPARE_LT
+# stack: [arg, (arg < 2)]
+
+# 3:
+JUMP_ABS_IF_TRUE 9
+# stack: [arg]
+
+# 4:
+DUP
+# stack: [arg, arg]
+
+# 5:
+PUSH_CONST 1
+# stack: [arg, arg, 1]
+
+# 6:
+BINARY_SUBTRACT
+# stack: [arg,  (arg - 1)
+
+# 7:
+RECURSE
+# stack: [arg, factorial(arg - 1)]
+
+# 8:
+BINARY_MULT
+# stack: [arg * factorial(arg - 1)]
+
+# 9:
+RETURN
diff --git a/gcc/jit/docs/examples/tut04-toyvm/fibonacci.toy b/gcc/jit/docs/examples/tut04-toyvm/fibonacci.toy
new file mode 100644
index 0000000..5ae0a40
--- /dev/null
+++ b/gcc/jit/docs/examples/tut04-toyvm/fibonacci.toy
@@ -0,0 +1,66 @@
+# Simple recursive fibonacci implementation, roughly equivalent to:
+#
+#  int fibonacci (int arg)
+#  {
+#     if (arg < 2)
+#       return arg
+#     return fibonacci (arg-1) + fibonacci (arg-2)
+#  }
+
+# Initial state:
+# stack: [arg]
+
+# 0:
+DUP
+# stack: [arg, arg]
+
+# 1:
+PUSH_CONST 2
+# stack: [arg, arg, 2]
+
+# 2:
+BINARY_COMPARE_LT
+# stack: [arg, (arg < 2)]
+
+# 3:
+JUMP_ABS_IF_TRUE 13
+# stack: [arg]
+
+# 4:
+DUP
+# stack: [arg, arg]
+
+# 5:
+PUSH_CONST  1
+# stack: [arg, arg, 1]
+
+# 6:
+BINARY_SUBTRACT
+# stack: [arg,  (arg - 1)
+
+# 7:
+RECURSE
+# stack: [arg, fib(arg - 1)]
+
+# 8:
+ROT
+# stack: [fib(arg - 1), arg]
+
+# 9:
+PUSH_CONST  2
+# stack: [fib(arg - 1), arg, 2]
+
+# 10:
+BINARY_SUBTRACT
+# stack: [fib(arg - 1), arg,  (arg - 2)
+
+# 11:
+RECURSE
+# stack: [fib(arg - 1), fib(arg - 1)]
+
+# 12:
+BINARY_ADD
+# stack: [fib(arg - 1) + fib(arg - 1)]
+
+# 13:
+RETURN
diff --git a/gcc/jit/docs/examples/tut04-toyvm/toyvm.c b/gcc/jit/docs/examples/tut04-toyvm/toyvm.c
new file mode 100644
index 0000000..666bf2e
--- /dev/null
+++ b/gcc/jit/docs/examples/tut04-toyvm/toyvm.c
@@ -0,0 +1,861 @@
+/* A simple stack-based virtual machine to demonstrate
+   JIT-compilation.
+   Copyright (C) 2014 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <dejagnu.h>
+
+#include <libgccjit.h>
+
+/* Typedefs.  */
+typedef struct toyvm_op toyvm_op;
+typedef struct toyvm_function toyvm_function;
+typedef struct toyvm_frame toyvm_frame;
+typedef struct compilation_state compilation_state;
+
+/* Functions are compiled to this function ptr type.  */
+typedef int (*toyvm_compiled_func) (int);
+
+enum opcode {
+  /* Ops taking no operand.  */
+  DUP,
+  ROT,
+  BINARY_ADD,
+  BINARY_SUBTRACT,
+  BINARY_MULT,
+  BINARY_COMPARE_LT,
+  RECURSE,
+  RETURN,
+
+  /* Ops taking an operand.  */
+  PUSH_CONST,
+  JUMP_ABS_IF_TRUE
+};
+
+#define FIRST_UNARY_OPCODE (PUSH_CONST)
+
+const char * const opcode_names[] = {
+  "DUP",
+  "ROT",
+  "BINARY_ADD",
+  "BINARY_SUBTRACT",
+  "BINARY_MULT",
+  "BINARY_COMPARE_LT",
+  "RECURSE",
+  "RETURN",
+
+  "PUSH_CONST",
+  "JUMP_ABS_IF_TRUE",
+};
+
+struct toyvm_op
+{
+  /* Which operation.  */
+  enum opcode op_opcode;
+
+  /* Some opcodes take an argument.  */
+  int op_operand;
+
+  /* The line number of the operation within the source file.  */
+  int op_linenum;
+};
+
+#define MAX_OPS  (64)
+
+struct toyvm_function
+{
+  const char *fn_filename;
+  int         fn_num_ops;
+  toyvm_op    fn_ops[MAX_OPS];
+};
+
+#define MAX_STACK_DEPTH (8)
+
+struct toyvm_frame
+{
+  toyvm_function *frm_function;
+  int             frm_pc;
+  int             frm_stack[MAX_STACK_DEPTH];
+  int             frm_cur_depth;
+};
+
+static void
+add_op (toyvm_function *fn, enum opcode opcode,
+	int operand, int linenum)
+{
+  toyvm_op *op;
+  assert (fn->fn_num_ops < MAX_OPS);
+  op = &fn->fn_ops[fn->fn_num_ops++];
+  op->op_opcode = opcode;
+  op->op_operand = operand;
+  op->op_linenum = linenum;
+}
+
+static void
+add_unary_op (toyvm_function *fn, enum opcode opcode,
+	      const char *rest_of_line, int linenum)
+{
+  int operand = atoi (rest_of_line);
+  add_op (fn, opcode, operand, linenum);
+}
+
+static toyvm_function *
+toyvm_function_parse (const char *filename, const char *name)
+{
+  FILE *f = NULL;
+  toyvm_function *fn = NULL;
+  char *line = NULL;
+  ssize_t linelen;
+  size_t bufsize;
+  int linenum = 0;
+
+  assert (filename);
+  assert (name);
+
+  f = fopen (filename, "r");
+  if (!f)
+    {
+      fprintf (stderr,
+	       "cannot open file %s: %s\n",
+	       filename, strerror (errno));
+      goto error;
+    }
+
+  fn = (toyvm_function *)calloc (1, sizeof (toyvm_function));
+  if (!fn)
+    {
+      fprintf (stderr, "out of memory allocating toyvm_function\n");
+      goto error;
+    }
+  fn->fn_filename = name;
+
+  /* Read the lines of the file.  */
+  while ((linelen = getline (&line, &bufsize, f)) != -1)
+    {
+      /* Note that this is a terrible parser, but it avoids the need to
+	 bring in lex/yacc as a dependency.  */
+      linenum++;
+
+      if (0)
+	fprintf (stdout, "%3d: %s", linenum, line);
+
+      /* Lines beginning with # are comments.  */
+      if (line[0] == '#')
+	continue;
+
+      /* Skip blank lines.  */
+      if (line[0] == '\n')
+	continue;
+
+#define LINE_MATCHES(OPCODE) (0 == strncmp ((OPCODE), line, strlen (OPCODE)))
+      if (LINE_MATCHES ("DUP\n"))
+	add_op (fn, DUP, 0, linenum);
+      else if (LINE_MATCHES ("ROT\n"))
+	add_op (fn, ROT, 0, linenum);
+      else if (LINE_MATCHES ("BINARY_ADD\n"))
+	add_op (fn, BINARY_ADD, 0, linenum);
+      else if (LINE_MATCHES ("BINARY_SUBTRACT\n"))
+	add_op (fn, BINARY_SUBTRACT, 0, linenum);
+      else if (LINE_MATCHES ("BINARY_MULT\n"))
+	add_op (fn, BINARY_MULT, 0, linenum);
+      else if (LINE_MATCHES ("BINARY_COMPARE_LT\n"))
+	add_op (fn, BINARY_COMPARE_LT, 0, linenum);
+      else if (LINE_MATCHES ("RECURSE\n"))
+	add_op (fn, RECURSE, 0, linenum);
+      else if (LINE_MATCHES ("RETURN\n"))
+	add_op (fn, RETURN, 0, linenum);
+      else if (LINE_MATCHES ("PUSH_CONST "))
+	add_unary_op (fn, PUSH_CONST,
+		      line + strlen ("PUSH_CONST "), linenum);
+      else if (LINE_MATCHES ("JUMP_ABS_IF_TRUE "))
+	add_unary_op (fn, JUMP_ABS_IF_TRUE,
+		      line + strlen("JUMP_ABS_IF_TRUE "), linenum);
+      else
+	{
+	  fprintf (stderr, "%s:%d: parse error\n", filename, linenum);
+	  free (fn);
+	  fn = NULL;
+	  goto error;
+	}
+#undef LINE_MATCHES
+    }
+  free (line);
+  fclose (f);
+
+  return fn;
+
+ error:
+  free (line);
+  fclose (f);
+  free (fn);
+  return NULL;
+}
+
+static void
+toyvm_function_disassemble_op (toyvm_function *fn, toyvm_op *op, int index, FILE *out)
+{
+  fprintf (out, "%s:%d: index %d: %s",
+	   fn->fn_filename, op->op_linenum, index,
+	   opcode_names[op->op_opcode]);
+  if (op->op_opcode >= FIRST_UNARY_OPCODE)
+    fprintf (out, " %d", op->op_operand);
+  fprintf (out, "\n");
+}
+
+static void
+toyvm_function_disassemble (toyvm_function *fn, FILE *out)
+{
+  int i;
+  for (i = 0; i < fn->fn_num_ops; i++)
+    {
+      toyvm_op *op = &fn->fn_ops[i];
+      toyvm_function_disassemble_op (fn, op, i, out);
+    }
+}
+
+static void
+toyvm_frame_push (toyvm_frame *frame, int arg)
+{
+  assert (frame->frm_cur_depth < MAX_STACK_DEPTH);
+  frame->frm_stack[frame->frm_cur_depth++] = arg;
+}
+
+static int
+toyvm_frame_pop (toyvm_frame *frame)
+{
+  assert (frame->frm_cur_depth > 0);
+  return frame->frm_stack[--frame->frm_cur_depth];
+}
+
+static void
+toyvm_frame_dump_stack (toyvm_frame *frame, FILE *out)
+{
+  int i;
+  fprintf (out, "stack:");
+  for (i = 0; i < frame->frm_cur_depth; i++)
+    {
+      fprintf (out, " %d", frame->frm_stack[i]);
+    }
+  fprintf (out, "\n");
+}
+
+/* Execute the given function.  */
+
+static int
+toyvm_function_interpret (toyvm_function *fn, int arg, FILE *trace)
+{
+  toyvm_frame frame;
+#define PUSH(ARG) (toyvm_frame_push (&frame, (ARG)))
+#define POP(ARG) (toyvm_frame_pop (&frame))
+
+  frame.frm_function = fn;
+  frame.frm_pc = 0;
+  frame.frm_cur_depth = 0;
+
+  PUSH (arg);
+
+  while (1)
+    {
+      toyvm_op *op;
+      int x, y;
+      assert (frame.frm_pc < fn->fn_num_ops);
+      op = &fn->fn_ops[frame.frm_pc++];
+
+      if (trace)
+	{
+	  toyvm_frame_dump_stack (&frame, trace);
+	  toyvm_function_disassemble_op (fn, op, frame.frm_pc, trace);
+	}
+
+      switch (op->op_opcode)
+	{
+	  /* Ops taking no operand.  */
+	case DUP:
+	  x = POP ();
+	  PUSH (x);
+	  PUSH (x);
+	  break;
+
+	case ROT:
+	  y = POP ();
+	  x = POP ();
+	  PUSH (y);
+	  PUSH (x);
+	  break;
+
+	case BINARY_ADD:
+	  y = POP ();
+	  x = POP ();
+	  PUSH (x + y);
+	  break;
+
+	case BINARY_SUBTRACT:
+	  y = POP ();
+	  x = POP ();
+	  PUSH (x - y);
+	  break;
+
+	case BINARY_MULT:
+	  y = POP ();
+	  x = POP ();
+	  PUSH (x * y);
+	  break;
+
+	case BINARY_COMPARE_LT:
+	  y = POP ();
+	  x = POP ();
+	  PUSH (x < y);
+	  break;
+
+	case RECURSE:
+	  x = POP ();
+	  x = toyvm_function_interpret (fn, x, trace);
+	  PUSH (x);
+	  break;
+
+	case RETURN:
+	  return POP ();
+
+	  /* Ops taking an operand.  */
+	case PUSH_CONST:
+	  PUSH (op->op_operand);
+	  break;
+
+	case JUMP_ABS_IF_TRUE:
+	  x = POP ();
+	  if (x)
+	    frame.frm_pc = op->op_operand;
+	  break;
+
+	default:
+	  assert (0); /* unknown opcode */
+
+	} /* end of switch on opcode */
+    } /* end of while loop */
+
+#undef PUSH
+#undef POP
+}
+
+/* JIT compilation.  */
+
+struct compilation_state
+{
+  gcc_jit_context *ctxt;
+
+  gcc_jit_type *int_type;
+  gcc_jit_type *bool_type;
+  gcc_jit_type *stack_type; /* int[MAX_STACK_DEPTH] */
+
+  gcc_jit_rvalue *const_one;
+
+  gcc_jit_function *fn;
+  gcc_jit_param *param_arg;
+  gcc_jit_lvalue *stack;
+  gcc_jit_lvalue *stack_depth;
+  gcc_jit_lvalue *x;
+  gcc_jit_lvalue *y;
+
+  gcc_jit_location *op_locs[MAX_OPS];
+  gcc_jit_block *initial_block;
+  gcc_jit_block *op_blocks[MAX_OPS];
+
+};
+
+/* Stack manipulation.  */
+
+static void
+add_push (compilation_state *state,
+	  gcc_jit_block *block,
+	  gcc_jit_rvalue *rvalue,
+	  gcc_jit_location *loc)
+{
+  /* stack[stack_depth] = RVALUE */
+  gcc_jit_block_add_assignment (
+    block,
+    loc,
+    /* stack[stack_depth] */
+    gcc_jit_context_new_array_access (
+      state->ctxt,
+      loc,
+      gcc_jit_lvalue_as_rvalue (state->stack),
+      gcc_jit_lvalue_as_rvalue (state->stack_depth)),
+    rvalue);
+
+  /* "stack_depth++;".  */
+  gcc_jit_block_add_assignment_op (
+    block,
+    loc,
+    state->stack_depth,
+    GCC_JIT_BINARY_OP_PLUS,
+    state->const_one);
+}
+
+static void
+add_pop (compilation_state *state,
+	 gcc_jit_block *block,
+	 gcc_jit_lvalue *lvalue,
+	 gcc_jit_location *loc)
+{
+  /* "--stack_depth;".  */
+  gcc_jit_block_add_assignment_op (
+    block,
+    loc,
+    state->stack_depth,
+    GCC_JIT_BINARY_OP_MINUS,
+    state->const_one);
+
+  /* "LVALUE = stack[stack_depth];".  */
+  gcc_jit_block_add_assignment (
+    block,
+    loc,
+    lvalue,
+    /* stack[stack_depth] */
+    gcc_jit_lvalue_as_rvalue (
+      gcc_jit_context_new_array_access (
+	state->ctxt,
+	loc,
+	gcc_jit_lvalue_as_rvalue (state->stack),
+	gcc_jit_lvalue_as_rvalue (state->stack_depth))));
+}
+
+/* The main compilation hook.  */
+
+static toyvm_compiled_func
+toyvm_function_compile (toyvm_function *fn)
+{
+  compilation_state state;
+  int pc;
+  char *funcname;
+
+  memset (&state, 0, sizeof (state));
+
+  /* Copy filename to funcname.  */
+  funcname = (char *)malloc (strlen (fn->fn_filename) + 1);
+  strcpy (funcname, fn->fn_filename);
+
+  /* Convert "." to NIL terminator.  */
+  *(strchr (funcname, '.')) = '\0';
+
+  state.ctxt = gcc_jit_context_acquire ();
+
+  gcc_jit_context_set_bool_option (state.ctxt,
+				   GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE,
+				   0);
+  gcc_jit_context_set_bool_option (state.ctxt,
+				   GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE,
+				   0);
+  gcc_jit_context_set_int_option (state.ctxt,
+				  GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL,
+				  3);
+  gcc_jit_context_set_bool_option (state.ctxt,
+				   GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES,
+				   0);
+  gcc_jit_context_set_bool_option (state.ctxt,
+				   GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING,
+				   0);
+  gcc_jit_context_set_bool_option (state.ctxt,
+				   GCC_JIT_BOOL_OPTION_DEBUGINFO,
+				   1);
+
+  /* Create types.  */
+  state.int_type =
+    gcc_jit_context_get_type (state.ctxt, GCC_JIT_TYPE_INT);
+  state.bool_type =
+    gcc_jit_context_get_type (state.ctxt, GCC_JIT_TYPE_BOOL);
+  state.stack_type =
+    gcc_jit_context_new_array_type (state.ctxt, NULL,
+				    state.int_type, MAX_STACK_DEPTH);
+
+  /* The constant value 1.  */
+  state.const_one = gcc_jit_context_one (state.ctxt, state.int_type);
+
+  /* Create locations.  */
+  for (pc = 0; pc < fn->fn_num_ops; pc++)
+    {
+      toyvm_op *op = &fn->fn_ops[pc];
+
+      state.op_locs[pc] = gcc_jit_context_new_location (state.ctxt,
+							fn->fn_filename,
+							op->op_linenum,
+							0); /* column */
+    }
+
+  /* Creating the function.  */
+  state.param_arg =
+    gcc_jit_context_new_param (state.ctxt, state.op_locs[0],
+			       state.int_type, "arg");
+  state.fn =
+    gcc_jit_context_new_function (state.ctxt,
+				  state.op_locs[0],
+				  GCC_JIT_FUNCTION_EXPORTED,
+				  state.int_type,
+				  funcname,
+				  1, &state.param_arg, 0);
+
+  /* Create stack lvalues.  */
+  state.stack =
+    gcc_jit_function_new_local (state.fn, NULL,
+				state.stack_type, "stack");
+  state.stack_depth =
+    gcc_jit_function_new_local (state.fn, NULL,
+				state.int_type, "stack_depth");
+  state.x =
+    gcc_jit_function_new_local (state.fn, NULL,
+				state.int_type, "x");
+  state.y =
+    gcc_jit_function_new_local (state.fn, NULL,
+				state.int_type, "y");
+
+  /* 1st pass: create blocks, one per opcode. */
+
+  /* We need an entry block to do one-time initialization, so create that
+     first.  */
+  state.initial_block = gcc_jit_function_new_block (state.fn, "initial");
+
+  /* Create a block per operation.  */
+  for (pc = 0; pc < fn->fn_num_ops; pc++)
+    {
+      char buf[16];
+      sprintf (buf, "instr%i", pc);
+      state.op_blocks[pc] = gcc_jit_function_new_block (state.fn, buf);
+    }
+
+  /* Populate the initial block.  */
+
+  /* "stack_depth = 0;".  */
+  gcc_jit_block_add_assignment (
+    state.initial_block,
+    state.op_locs[0],
+    state.stack_depth,
+    gcc_jit_context_zero (state.ctxt, state.int_type));
+
+  /* "PUSH (arg);".  */
+  add_push (&state,
+	    state.initial_block,
+	    gcc_jit_param_as_rvalue (state.param_arg),
+	    state.op_locs[0]);
+
+  /* ...and jump to insn 0.  */
+  gcc_jit_block_end_with_jump (state.initial_block,
+			       state.op_locs[0],
+			       state.op_blocks[0]);
+
+  /* 2nd pass: fill in instructions.  */
+  for (pc = 0; pc < fn->fn_num_ops; pc++)
+    {
+      gcc_jit_location *loc = state.op_locs[pc];
+
+      gcc_jit_block *block = state.op_blocks[pc];
+      gcc_jit_block *next_block = (pc < fn->fn_num_ops
+				   ? state.op_blocks[pc + 1]
+				   : NULL);
+
+      toyvm_op *op;
+      op = &fn->fn_ops[pc];
+
+      /* Helper macros.  */
+
+#define X_EQUALS_POP()\
+      add_pop (&state, block, state.x, loc)
+#define Y_EQUALS_POP()\
+      add_pop (&state, block, state.y, loc)
+#define PUSH_RVALUE(RVALUE)\
+      add_push (&state, block, (RVALUE), loc)
+#define PUSH_X()\
+      PUSH_RVALUE (gcc_jit_lvalue_as_rvalue (state.x))
+#define PUSH_Y() \
+      PUSH_RVALUE (gcc_jit_lvalue_as_rvalue (state.y))
+
+      gcc_jit_block_add_comment (block, loc, opcode_names[op->op_opcode]);
+
+      /* Handle the individual opcodes.  */
+
+      switch (op->op_opcode)
+	{
+	case DUP:
+	  X_EQUALS_POP ();
+	  PUSH_X ();
+	  PUSH_X ();
+	  break;
+
+	case ROT:
+	  Y_EQUALS_POP ();
+	  X_EQUALS_POP ();
+	  PUSH_Y ();
+	  PUSH_X ();
+	  break;
+
+	case BINARY_ADD:
+	  Y_EQUALS_POP ();
+	  X_EQUALS_POP ();
+	  PUSH_RVALUE (
+	   gcc_jit_context_new_binary_op (
+	     state.ctxt,
+	     loc,
+	     GCC_JIT_BINARY_OP_PLUS,
+	     state.int_type,
+	     gcc_jit_lvalue_as_rvalue (state.x),
+	     gcc_jit_lvalue_as_rvalue (state.y)));
+	  break;
+
+	case BINARY_SUBTRACT:
+	  Y_EQUALS_POP ();
+	  X_EQUALS_POP ();
+	  PUSH_RVALUE (
+	   gcc_jit_context_new_binary_op (
+	     state.ctxt,
+	     loc,
+	     GCC_JIT_BINARY_OP_MINUS,
+	     state.int_type,
+	     gcc_jit_lvalue_as_rvalue (state.x),
+	     gcc_jit_lvalue_as_rvalue (state.y)));
+	  break;
+
+	case BINARY_MULT:
+	  Y_EQUALS_POP ();
+	  X_EQUALS_POP ();
+	  PUSH_RVALUE (
+	   gcc_jit_context_new_binary_op (
+	     state.ctxt,
+	     loc,
+	     GCC_JIT_BINARY_OP_MULT,
+	     state.int_type,
+	     gcc_jit_lvalue_as_rvalue (state.x),
+	     gcc_jit_lvalue_as_rvalue (state.y)));
+	  break;
+
+	case BINARY_COMPARE_LT:
+	  Y_EQUALS_POP ();
+	  X_EQUALS_POP ();
+	  PUSH_RVALUE (
+	     /* cast of bool to int */
+	     gcc_jit_context_new_cast (
+	       state.ctxt,
+	       loc,
+	       /* (x < y) as a bool */
+	       gcc_jit_context_new_comparison (
+		 state.ctxt,
+		 loc,
+		 GCC_JIT_COMPARISON_LT,
+		 gcc_jit_lvalue_as_rvalue (state.x),
+		 gcc_jit_lvalue_as_rvalue (state.y)),
+	       state.int_type));
+	  break;
+
+	case RECURSE:
+	  {
+	    X_EQUALS_POP ();
+	    gcc_jit_rvalue *arg = gcc_jit_lvalue_as_rvalue (state.x);
+	    PUSH_RVALUE (
+	      gcc_jit_context_new_call (
+		state.ctxt,
+		loc,
+		state.fn,
+		1, &arg));
+	    break;
+	  }
+
+	case RETURN:
+	  X_EQUALS_POP ();
+	  gcc_jit_block_end_with_return (
+	    block,
+	    loc,
+	    gcc_jit_lvalue_as_rvalue (state.x));
+	  break;
+
+	  /* Ops taking an operand.  */
+	case PUSH_CONST:
+	  PUSH_RVALUE (
+	    gcc_jit_context_new_rvalue_from_int (
+	      state.ctxt,
+	      state.int_type,
+	      op->op_operand));
+	  break;
+
+	case JUMP_ABS_IF_TRUE:
+	  X_EQUALS_POP ();
+	  gcc_jit_block_end_with_conditional (
+	    block,
+	    loc,
+	    /* "(bool)x".  */
+	    gcc_jit_context_new_cast (
+	      state.ctxt,
+	      loc,
+	      gcc_jit_lvalue_as_rvalue (state.x),
+	      state.bool_type),
+	    state.op_blocks[op->op_operand], /* on_true */
+	    next_block); /* on_false */
+	  break;
+
+	default:
+	  assert(0);
+	} /* end of switch on opcode */
+
+      /* Go to the next block.  */
+      if (op->op_opcode != JUMP_ABS_IF_TRUE
+	  && op->op_opcode != RETURN)
+	gcc_jit_block_end_with_jump (
+	  block,
+	  loc,
+	  next_block);
+
+    } /* end of loop on PC locations.  */
+
+  /* We've now finished populating the context.  Compile it.  */
+  gcc_jit_result *result = gcc_jit_context_compile (state.ctxt);
+  gcc_jit_context_release (state.ctxt);
+
+  return (toyvm_compiled_func)gcc_jit_result_get_code (result,
+						       funcname);
+  /* (this leaks "result" and "funcname") */
+}
+
+char test[1024];
+
+#define CHECK_NON_NULL(PTR) \
+  do {                                       \
+    if ((PTR) != NULL)                       \
+      {                                      \
+	pass ("%s: %s is non-null", test, #PTR); \
+      }                                      \
+    else                                     \
+      {                                      \
+	fail ("%s: %s is NULL", test, #PTR); \
+	abort ();                            \
+    }                                        \
+  } while (0)
+
+#define CHECK_VALUE(ACTUAL, EXPECTED) \
+  do {                                       \
+    if ((ACTUAL) == (EXPECTED))              \
+      {                                      \
+	pass ("%s: actual: %s == expected: %s", test, #ACTUAL, #EXPECTED); \
+      }                                      \
+    else                                     \
+      {                                        \
+	fail ("%s: actual: %s != expected: %s", test, #ACTUAL, #EXPECTED); \
+	fprintf (stderr, "incorrect value\n"); \
+	abort ();                              \
+    }                                        \
+  } while (0)
+
+static void
+test_script (const char *scripts_dir, const char *script_name, int input,
+	     int expected_result)
+{
+  char *script_path;
+  toyvm_function *fn;
+  int interpreted_result;
+  toyvm_compiled_func code;
+  int compiled_result;
+
+  snprintf (test, sizeof (test), "toyvm.c: %s", script_name);
+
+  script_path = (char *)malloc (strlen (scripts_dir)
+				+ strlen (script_name) + 1);
+  CHECK_NON_NULL (script_path);
+  sprintf (script_path, "%s%s", scripts_dir, script_name);
+
+  fn = toyvm_function_parse (script_path, script_name);
+  CHECK_NON_NULL (fn);
+
+  interpreted_result = toyvm_function_interpret (fn, input, NULL);
+  CHECK_VALUE (interpreted_result, expected_result);
+
+  code = toyvm_function_compile (fn);
+  CHECK_NON_NULL (code);
+
+  compiled_result = code (input);
+  CHECK_VALUE (compiled_result, expected_result);
+
+  free (script_path);
+}
+
+#define PATH_TO_SCRIPTS  ("/jit/docs/examples/tut04-toyvm/")
+
+static void
+test_suite (void)
+{
+  const char *srcdir;
+  char *scripts_dir;
+
+  snprintf (test, sizeof (test), "toyvm.c");
+
+  /* We need to locate the test scripts.
+     Rely on "srcdir" being set in the environment.  */
+
+  srcdir = getenv ("srcdir");
+  CHECK_NON_NULL (srcdir);
+
+  scripts_dir = (char *)malloc (strlen (srcdir) + strlen(PATH_TO_SCRIPTS)
+				+ 1);
+  CHECK_NON_NULL (scripts_dir);
+  sprintf (scripts_dir, "%s%s", srcdir, PATH_TO_SCRIPTS);
+
+  test_script (scripts_dir, "factorial.toy", 10, 3628800);
+  test_script (scripts_dir, "fibonacci.toy", 10, 55);
+
+  free (scripts_dir);
+}
+
+int
+main (int argc, char **argv)
+{
+  const char *filename = NULL;
+  toyvm_function *fn = NULL;
+
+  /* If called with no args, assume we're being run by the test suite.  */
+  if (argc < 3)
+    {
+      test_suite ();
+      return 0;
+    }
+
+  if (argc != 3)
+    {
+      fprintf (stdout,
+	"%s FILENAME INPUT: Parse and run a .toy file\n",
+	argv[0]);
+      exit (1);
+    }
+
+  filename = argv[1];
+  fn = toyvm_function_parse (filename, filename);
+  if (!fn)
+    exit (1);
+
+  if (0)
+    toyvm_function_disassemble (fn, stdout);
+
+  printf ("interpreter result: %d\n",
+	  toyvm_function_interpret (fn, atoi (argv[2]), NULL));
+
+  /* JIT-compilation.  */
+  toyvm_compiled_func code = toyvm_function_compile (fn);
+  printf ("compiler result: %d\n",
+	  code (atoi (argv[2])));
+
+ return 0;
+}
-- 
1.8.5.3

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

* [PATCH 23/27] Documentation: the "intro" subdirectory
  2014-10-31 17:07 [PATCH 00/27] Merger of jit branch v3 David Malcolm
                   ` (8 preceding siblings ...)
  2014-10-31 17:07 ` [PATCH 09/27] New file: gcc/jit/libgccjit.map David Malcolm
@ 2014-10-31 17:16 ` David Malcolm
  2014-10-31 21:48   ` Jeff Law
  2014-10-31 17:21 ` [PATCH 22/27] Documentation: top-level index.rst David Malcolm
                   ` (15 subsequent siblings)
  25 siblings, 1 reply; 71+ messages in thread
From: David Malcolm @ 2014-10-31 17:16 UTC (permalink / raw)
  To: gcc-patches, jit; +Cc: David Malcolm

The "intro" subdirectory of gcc/jit/docs consists of a 4-part tutorial
aimed at experienced developers who are new users of the library, taking
them from beginning use all the way up to adding JIT-compilation to an
interpreter.

gcc/jit/
	* docs/intro/factorial.png: New.
	* docs/intro/index.rst: New.
	* docs/intro/sum-of-squares.png: New.
	* docs/intro/tutorial01.rst: New.
	* docs/intro/tutorial02.rst: New.
	* docs/intro/tutorial03.rst: New.
	* docs/intro/tutorial04.rst: New.
---
 gcc/jit/docs/intro/factorial.png      |  Bin 0 -> 183838 bytes
 gcc/jit/docs/intro/index.rst          |   27 +
 gcc/jit/docs/intro/sum-of-squares.png |  Bin 0 -> 22839 bytes
 gcc/jit/docs/intro/tutorial01.rst     |   52 ++
 gcc/jit/docs/intro/tutorial02.rst     |  349 +++++++++++
 gcc/jit/docs/intro/tutorial03.rst     |  378 +++++++++++
 gcc/jit/docs/intro/tutorial04.rst     | 1108 +++++++++++++++++++++++++++++++++
 7 files changed, 1914 insertions(+)
 create mode 100644 gcc/jit/docs/intro/factorial.png
 create mode 100644 gcc/jit/docs/intro/index.rst
 create mode 100644 gcc/jit/docs/intro/sum-of-squares.png
 create mode 100644 gcc/jit/docs/intro/tutorial01.rst
 create mode 100644 gcc/jit/docs/intro/tutorial02.rst
 create mode 100644 gcc/jit/docs/intro/tutorial03.rst
 create mode 100644 gcc/jit/docs/intro/tutorial04.rst

diff --git a/gcc/jit/docs/intro/factorial.png b/gcc/jit/docs/intro/factorial.png
new file mode 100644
index 0000000..dff47ce
Binary files /dev/null and b/gcc/jit/docs/intro/factorial.png differ
diff --git a/gcc/jit/docs/intro/index.rst b/gcc/jit/docs/intro/index.rst
new file mode 100644
index 0000000..d3bcec9
--- /dev/null
+++ b/gcc/jit/docs/intro/index.rst
@@ -0,0 +1,27 @@
+.. Copyright (C) 2014 Free Software Foundation, Inc.
+   Originally contributed by David Malcolm <dmalcolm@redhat.com>
+
+   This is free software: you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see
+   <http://www.gnu.org/licenses/>.
+
+Tutorial
+========
+
+.. toctree::
+   :maxdepth: 2
+
+   tutorial01.rst
+   tutorial02.rst
+   tutorial03.rst
+   tutorial04.rst
diff --git a/gcc/jit/docs/intro/sum-of-squares.png b/gcc/jit/docs/intro/sum-of-squares.png
new file mode 100644
index 0000000..7a3b4af
Binary files /dev/null and b/gcc/jit/docs/intro/sum-of-squares.png differ
diff --git a/gcc/jit/docs/intro/tutorial01.rst b/gcc/jit/docs/intro/tutorial01.rst
new file mode 100644
index 0000000..b1a5128
--- /dev/null
+++ b/gcc/jit/docs/intro/tutorial01.rst
@@ -0,0 +1,52 @@
+.. Copyright (C) 2014 Free Software Foundation, Inc.
+   Originally contributed by David Malcolm <dmalcolm@redhat.com>
+
+   This is free software: you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see
+   <http://www.gnu.org/licenses/>.
+
+.. default-domain:: c
+
+Tutorial part 1: "Hello world"
+==============================
+
+Before we look at the details of the API, let's look at building and
+running programs that use the library.
+
+Here's a toy "hello world" program that uses the library to synthesize
+a call to `printf` and uses it to write a message to stdout.
+
+Don't worry about the content of the program for now; we'll cover
+the details in later parts of this tutorial.
+
+   .. literalinclude:: ../examples/tut01-hello-world.c
+    :language: c
+
+Copy the above to `tut01-hello-world.c`.
+
+Assuming you have the jit library installed, build the test program
+using:
+
+.. code-block:: console
+
+  $ gcc \
+      tut01-hello-world.c \
+      -o tut01-hello-world \
+      -lgccjit
+
+You should then be able to run the built program:
+
+.. code-block:: console
+
+  $ ./tut01-hello-world
+  hello world
diff --git a/gcc/jit/docs/intro/tutorial02.rst b/gcc/jit/docs/intro/tutorial02.rst
new file mode 100644
index 0000000..f52499e
--- /dev/null
+++ b/gcc/jit/docs/intro/tutorial02.rst
@@ -0,0 +1,349 @@
+.. Copyright (C) 2014 Free Software Foundation, Inc.
+   Originally contributed by David Malcolm <dmalcolm@redhat.com>
+
+   This is free software: you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see
+   <http://www.gnu.org/licenses/>.
+
+.. default-domain:: c
+
+Tutorial part 2: Creating a trivial machine code function
+---------------------------------------------------------
+
+Consider this C function:
+
+.. code-block:: c
+
+   int square (int i)
+   {
+     return i * i;
+   }
+
+How can we construct this at run-time using libgccjit?
+
+First we need to include the relevant header:
+
+.. code-block:: c
+
+  #include <libgccjit.h>
+
+All state associated with compilation is associated with a
+:c:type:`gcc_jit_context *`.
+
+Create one using :c:func:`gcc_jit_context_acquire`:
+
+.. code-block:: c
+
+  gcc_jit_context *ctxt;
+  ctxt = gcc_jit_context_acquire ();
+
+The JIT library has a system of types.  It is statically-typed: every
+expression is of a specific type, fixed at compile-time.  In our example,
+all of the expressions are of the C `int` type, so let's obtain this from
+the context, as a :c:type:`gcc_jit_type *`, using
+:c:func:`gcc_jit_context_get_type`:
+
+.. code-block:: c
+
+  gcc_jit_type *int_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+:c:type:`gcc_jit_type *` is an example of a "contextual" object: every
+entity in the API is associated with a :c:type:`gcc_jit_context *`.
+
+Memory management is easy: all such "contextual" objects are automatically
+cleaned up for you when the context is released, using
+:c:func:`gcc_jit_context_release`:
+
+.. code-block:: c
+
+  gcc_jit_context_release (ctxt);
+
+so you don't need to manually track and cleanup all objects, just the
+contexts.
+
+Although the API is C-based, there is a form of class hierarchy, which
+looks like this::
+
+  +- gcc_jit_object
+      +- gcc_jit_location
+      +- gcc_jit_type
+         +- gcc_jit_struct
+      +- gcc_jit_field
+      +- gcc_jit_function
+      +- gcc_jit_block
+      +- gcc_jit_rvalue
+          +- gcc_jit_lvalue
+             +- gcc_jit_param
+
+There are casting methods for upcasting from subclasses to parent classes.
+For example, :c:func:`gcc_jit_type_as_object`:
+
+.. code-block:: c
+
+   gcc_jit_object *obj = gcc_jit_type_as_object (int_type);
+
+One thing you can do with a :c:type:`gcc_jit_object *` is
+to ask it for a human-readable description, using
+:c:func:`gcc_jit_object_get_debug_string`:
+
+.. code-block:: c
+
+   printf ("obj: %s\n", gcc_jit_object_get_debug_string (obj));
+
+giving this text on stdout:
+
+.. code-block:: bash
+
+   obj: int
+
+This is invaluable when debugging.
+
+Let's create the function.  To do so, we first need to construct
+its single parameter, specifying its type and giving it a name,
+using :c:func:`gcc_jit_context_new_param`:
+
+.. code-block:: c
+
+  gcc_jit_param *param_i =
+    gcc_jit_context_new_param (ctxt, NULL, int_type, "i");
+
+Now we can create the function, using
+:c:func:`gcc_jit_context_new_function`:
+
+.. code-block:: c
+
+  gcc_jit_function *func =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                  GCC_JIT_FUNCTION_EXPORTED,
+                                  int_type,
+                                  "square",
+                                  1, &param_i,
+                                  0);
+
+To define the code within the function, we must create basic blocks
+containing statements.
+
+Every basic block contains a list of statements, eventually terminated
+by a statement that either returns, or jumps to another basic block.
+
+Our function has no control-flow, so we just need one basic block:
+
+.. code-block:: c
+
+  gcc_jit_block *block = gcc_jit_function_new_block (func, NULL);
+
+Our basic block is relatively simple: it immediately terminates by
+returning the value of an expression.
+
+We can build the expression using :c:func:`gcc_jit_context_new_binary_op`:
+
+.. code-block:: c
+
+   gcc_jit_rvalue *expr =
+     gcc_jit_context_new_binary_op (
+       ctxt, NULL,
+       GCC_JIT_BINARY_OP_MULT, int_type,
+       gcc_jit_param_as_rvalue (param_i),
+       gcc_jit_param_as_rvalue (param_i));
+
+A :c:type:`gcc_jit_rvalue *` is another example of a
+:c:type:`gcc_jit_object *` subclass.  We can upcast it using
+:c:func:`gcc_jit_rvalue_as_object` and as before print it with
+:c:func:`gcc_jit_object_get_debug_string`.
+
+.. code-block:: c
+
+   printf ("expr: %s\n",
+           gcc_jit_object_get_debug_string (
+             gcc_jit_rvalue_as_object (expr)));
+
+giving this output:
+
+.. code-block:: bash
+
+   expr: i * i
+
+Creating the expression in itself doesn't do anything; we have to add
+this expression to a statement within the block.  In this case, we use it
+to build a return statement, which terminates the basic block:
+
+.. code-block:: c
+
+  gcc_jit_block_end_with_return (block, NULL, expr);
+
+OK, we've populated the context.  We can now compile it using
+:c:func:`gcc_jit_context_compile`:
+
+.. code-block:: c
+
+   gcc_jit_result *result;
+   result = gcc_jit_context_compile (ctxt);
+
+and get a :c:type:`gcc_jit_result *`.
+
+We can now use :c:func:`gcc_jit_result_get_code` to look up a specific
+machine code routine within the result, in this case, the function we
+created above.
+
+.. code-block:: c
+
+   void *fn_ptr = gcc_jit_result_get_code (result, "square");
+   if (!fn_ptr)
+     {
+       fprintf (stderr, "NULL fn_ptr");
+       goto error;
+     }
+
+We can now cast the pointer to an appropriate function pointer type, and
+then call it:
+
+.. code-block:: c
+
+  typedef int (*fn_type) (int);
+  fn_type square = (fn_type)fn_ptr;
+  printf ("result: %d", square (5));
+
+.. code-block:: bash
+
+  result: 25
+
+
+Options
+*******
+
+To get more information on what's going on, you can set debugging flags
+on the context using :c:func:`gcc_jit_context_set_bool_option`.
+
+.. (I'm deliberately not mentioning
+    :c:macro:`GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE` here since I think
+    it's probably more of use to implementors than to users)
+
+Setting :c:macro:`GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE` will dump a
+C-like representation to stderr when you compile (GCC's "GIMPLE"
+representation):
+
+.. code-block:: c
+
+   gcc_jit_context_set_bool_option (
+     ctxt,
+     GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE,
+     1);
+   result = gcc_jit_context_compile (ctxt);
+
+.. code-block:: c
+
+  square (signed int i)
+  {
+    signed int D.260;
+
+    entry:
+    D.260 = i * i;
+    return D.260;
+  }
+
+We can see the generated machine code in assembler form (on stderr) by
+setting :c:macro:`GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE` on the context
+before compiling:
+
+.. code-block:: c
+
+  gcc_jit_context_set_bool_option (
+    ctxt,
+    GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE,
+    1);
+  result = gcc_jit_context_compile (ctxt);
+
+.. code-block:: gas
+
+        .file   "fake.c"
+        .text
+        .globl  square
+        .type   square, @function
+  square:
+  .LFB6:
+        .cfi_startproc
+        pushq   %rbp
+        .cfi_def_cfa_offset 16
+        .cfi_offset 6, -16
+        movq    %rsp, %rbp
+        .cfi_def_cfa_register 6
+        movl    %edi, -4(%rbp)
+  .L14:
+        movl    -4(%rbp), %eax
+        imull   -4(%rbp), %eax
+        popq    %rbp
+        .cfi_def_cfa 7, 8
+        ret
+        .cfi_endproc
+  .LFE6:
+        .size   square, .-square
+        .ident  "GCC: (GNU) 4.9.0 20131023 (Red Hat 0.2-0.5.1920c315ff984892399893b380305ab36e07b455.fc20)"
+        .section       .note.GNU-stack,"",@progbits
+
+By default, no optimizations are performed, the equivalent of GCC's
+`-O0` option.  We can turn things up to e.g. `-O3` by calling
+:c:func:`gcc_jit_context_set_int_option` with
+:c:macro:`GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL`:
+
+.. code-block:: c
+
+  gcc_jit_context_set_int_option (
+    ctxt,
+    GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL,
+    3);
+
+.. code-block:: gas
+
+        .file   "fake.c"
+        .text
+        .p2align 4,,15
+        .globl  square
+        .type   square, @function
+  square:
+  .LFB7:
+        .cfi_startproc
+  .L16:
+        movl    %edi, %eax
+        imull   %edi, %eax
+        ret
+        .cfi_endproc
+  .LFE7:
+        .size   square, .-square
+        .ident  "GCC: (GNU) 4.9.0 20131023 (Red Hat 0.2-0.5.1920c315ff984892399893b380305ab36e07b455.fc20)"
+        .section        .note.GNU-stack,"",@progbits
+
+Naturally this has only a small effect on such a trivial function.
+
+
+Full example
+************
+
+Here's what the above looks like as a complete program:
+
+   .. literalinclude:: ../examples/tut02-square.c
+    :lines: 1-
+    :language: c
+
+Building and running it:
+
+.. code-block:: console
+
+  $ gcc \
+      tut02-square.c \
+      -o tut02-square \
+      -lgccjit
+
+  # Run the built program:
+  $ ./tut02-square
+  result: 25
diff --git a/gcc/jit/docs/intro/tutorial03.rst b/gcc/jit/docs/intro/tutorial03.rst
new file mode 100644
index 0000000..0845150
--- /dev/null
+++ b/gcc/jit/docs/intro/tutorial03.rst
@@ -0,0 +1,378 @@
+.. Copyright (C) 2014 Free Software Foundation, Inc.
+   Originally contributed by David Malcolm <dmalcolm@redhat.com>
+
+   This is free software: you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see
+   <http://www.gnu.org/licenses/>.
+
+Tutorial part 3: Loops and variables
+------------------------------------
+Consider this C function:
+
+ .. code-block:: c
+
+  int loop_test (int n)
+  {
+    int sum = 0;
+    for (int i = 0; i < n; i++)
+      sum += i * i;
+    return sum;
+  }
+
+This example demonstrates some more features of libgccjit, with local
+variables and a loop.
+
+To break this down into libgccjit terms, it's usually easier to reword
+the `for` loop as a `while` loop, giving:
+
+ .. code-block:: c
+
+  int loop_test (int n)
+  {
+    int sum = 0;
+    int i = 0;
+    while (i < n)
+    {
+      sum += i * i;
+      i++;
+    }
+    return sum;
+  }
+
+Here's what the final control flow graph will look like:
+
+    .. figure:: sum-of-squares.png
+      :alt: image of a control flow graph
+
+As before, we include the libgccjit header and make a
+:c:type:`gcc_jit_context *`.
+
+.. code-block:: c
+
+  #include <libgccjit.h>
+
+  void test (void)
+  {
+    gcc_jit_context *ctxt;
+    ctxt = gcc_jit_context_acquire ();
+
+The function works with the C `int` type:
+
+.. code-block:: c
+
+  gcc_jit_type *the_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+  gcc_jit_type *return_type = the_type;
+
+though we could equally well make it work on, say, `double`:
+
+.. code-block:: c
+
+  gcc_jit_type *the_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_DOUBLE);
+
+Let's build the function:
+
+.. code-block:: c
+
+  gcc_jit_param *n =
+    gcc_jit_context_new_param (ctxt, NULL, the_type, "n");
+  gcc_jit_param *params[1] = {n};
+  gcc_jit_function *func =
+    gcc_jit_context_new_function (ctxt, NULL,
+				  GCC_JIT_FUNCTION_EXPORTED,
+				  return_type,
+				  "loop_test",
+				  1, params, 0);
+
+Expressions: lvalues and rvalues
+********************************
+
+The base class of expression is the :c:type:`gcc_jit_rvalue *`,
+representing an expression that can be on the *right*-hand side of
+an assignment: a value that can be computed somehow, and assigned
+*to* a storage area (such as a variable).  It has a specific
+:c:type:`gcc_jit_type *`.
+
+Anothe important class is :c:type:`gcc_jit_lvalue *`.
+A :c:type:`gcc_jit_lvalue *`. is something that can of the *left*-hand
+side of an assignment: a storage area (such as a variable).
+
+In other words, every assignment can be thought of as:
+
+.. code-block:: c
+
+   LVALUE = RVALUE;
+
+Note that :c:type:`gcc_jit_lvalue *` is a subclass of
+:c:type:`gcc_jit_rvalue *`, where in an assignment of the form:
+
+.. code-block:: c
+
+   LVALUE_A = LVALUE_B;
+
+the `LVALUE_B` implies reading the current value of that storage
+area, assigning it into the `LVALUE_A`.
+
+So far the only expressions we've seen are `i * i`:
+
+.. code-block:: c
+
+   gcc_jit_rvalue *expr =
+     gcc_jit_context_new_binary_op (
+       ctxt, NULL,
+       GCC_JIT_BINARY_OP_MULT, int_type,
+       gcc_jit_param_as_rvalue (param_i),
+       gcc_jit_param_as_rvalue (param_i));
+
+which is a :c:type:`gcc_jit_rvalue *`, and the various function
+parameters: `param_i` and `param_n`, instances of
+:c:type:`gcc_jit_param *`, which is a subclass of
+:c:type:`gcc_jit_lvalue *` (and, in turn, of :c:type:`gcc_jit_rvalue *`):
+we can both read from and write to function parameters within the
+body of a function.
+
+Our new example has a couple of local variables.  We create them by
+calling :c:func:`gcc_jit_function_new_local`, supplying a type and a
+name:
+
+.. code-block:: c
+
+  /* Build locals:  */
+  gcc_jit_lvalue *i =
+    gcc_jit_function_new_local (func, NULL, the_type, "i");
+  gcc_jit_lvalue *sum =
+    gcc_jit_function_new_local (func, NULL, the_type, "sum");
+
+These are instances of :c:type:`gcc_jit_lvalue *` - they can be read from
+and written to.
+
+Note that there is no precanned way to create *and* initialize a variable
+like in C:
+
+.. code-block:: c
+
+   int i = 0;
+
+Instead, having added the local to the function, we have to separately add
+an assignment of `0` to `local_i` at the beginning of the function.
+
+Control flow
+************
+
+This function has a loop, so we need to build some basic blocks to
+handle the control flow.  In this case, we need 4 blocks:
+
+1. before the loop (initializing the locals)
+2. the conditional at the top of the loop (comparing `i < n`)
+3. the body of the loop
+4. after the loop terminates (`return sum`)
+
+so we create these as :c:type:`gcc_jit_block *` instances within the
+:c:type:`gcc_jit_function *`:
+
+.. code-block:: c
+
+  gcc_jit_block *b_initial =
+    gcc_jit_function_new_block (func, "initial");
+  gcc_jit_block *b_loop_cond =
+    gcc_jit_function_new_block (func, "loop_cond");
+  gcc_jit_block *b_loop_body =
+    gcc_jit_function_new_block (func, "loop_body");
+  gcc_jit_block *b_after_loop =
+    gcc_jit_function_new_block (func, "after_loop");
+
+We now populate each block with statements.
+
+The entry block `b_initial` consists of initializations followed by a jump
+to the conditional.  We assign `0` to `i` and to `sum`, using
+:c:func:`gcc_jit_block_add_assignment` to add
+an assignment statement, and using :c:func:`gcc_jit_context_zero` to get
+the constant value `0` for the relevant type for the right-hand side of
+the assignment:
+
+.. code-block:: c
+
+  /* sum = 0; */
+  gcc_jit_block_add_assignment (
+    b_initial, NULL,
+    sum,
+    gcc_jit_context_zero (ctxt, the_type));
+
+  /* i = 0; */
+  gcc_jit_block_add_assignment (
+    b_initial, NULL,
+    i,
+    gcc_jit_context_zero (ctxt, the_type));
+
+We can then terminate the entry block by jumping to the conditional:
+
+.. code-block:: c
+
+  gcc_jit_block_end_with_jump (b_initial, NULL, b_loop_cond);
+
+The conditional block is equivalent to the line `while (i < n)` from our
+C example. It contains a single statement: a conditional, which jumps to
+one of two destination blocks depending on a boolean
+:c:type:`gcc_jit_rvalue *`, in this case the comparison of `i` and `n`.
+We build the comparison using :c:func:`gcc_jit_context_new_comparison`:
+
+.. code-block:: c
+
+   gcc_jit_rvalue *guard =
+     gcc_jit_context_new_comparison (
+       ctxt, NULL,
+       GCC_JIT_COMPARISON_GE,
+       gcc_jit_lvalue_as_rvalue (i),
+       gcc_jit_param_as_rvalue (n));
+
+and can then use this to add `b_loop_cond`'s sole statement, via
+:c:func:`gcc_jit_block_end_with_conditional`:
+
+.. code-block:: c
+
+  gcc_jit_block_end_with_conditional (b_loop_cond, NULL, guard);
+
+Next, we populate the body of the loop.
+
+The C statement `sum += i * i;` is an assignment operation, where an
+lvalue is modified "in-place".  We use
+:c:func:`gcc_jit_block_add_assignment_op` to handle these operations:
+
+.. code-block:: c
+
+  /* sum += i * i */
+  gcc_jit_block_add_assignment_op (
+    b_loop_body, NULL,
+    sum,
+    GCC_JIT_BINARY_OP_PLUS,
+    gcc_jit_context_new_binary_op (
+      ctxt, NULL,
+      GCC_JIT_BINARY_OP_MULT, the_type,
+      gcc_jit_lvalue_as_rvalue (i),
+      gcc_jit_lvalue_as_rvalue (i)));
+
+The `i++` can be thought of as `i += 1`, and can thus be handled in
+a similar way.  We use :c:func:`gcc_jit_context_one` to get the constant
+value `1` (for the relevant type) for the right-hand side
+of the assignment.
+
+.. code-block:: c
+
+  /* i++ */
+  gcc_jit_block_add_assignment_op (
+    b_loop_body, NULL,
+    i,
+    GCC_JIT_BINARY_OP_PLUS,
+    gcc_jit_context_one (ctxt, the_type));
+
+.. note::
+
+  For numeric constants other than 0 or 1, we could use
+  :c:func:`gcc_jit_context_new_rvalue_from_int` and
+  :c:func:`gcc_jit_context_new_rvalue_from_double`.
+
+The loop body completes by jumping back to the conditional:
+
+.. code-block:: c
+
+  gcc_jit_block_end_with_jump (b_loop_body, NULL, b_loop_cond);
+
+Finally, we populate the `b_after_loop` block, reached when the loop
+conditional is false.  We want to generate the equivalent of:
+
+.. code-block:: c
+
+   return sum;
+
+so the block is just one statement:
+
+.. code-block:: c
+
+  /* return sum */
+  gcc_jit_block_end_with_return (
+    b_after_loop,
+    NULL,
+    gcc_jit_lvalue_as_rvalue (sum));
+
+.. note::
+
+   You can intermingle block creation with statement creation,
+   but given that the terminator statements generally include references
+   to other blocks, I find it's clearer to create all the blocks,
+   *then* all the statements.
+
+We've finished populating the function.  As before, we can now compile it
+to machine code:
+
+.. code-block:: c
+
+   gcc_jit_result *result;
+   result = gcc_jit_context_compile (ctxt);
+
+   typedef int (*loop_test_fn_type) (int);
+   loop_test_fn_type loop_test =
+    (loop_test_fn_type)gcc_jit_result_get_code (result, "loop_test");
+   if (!loop_test)
+     goto error;
+   printf ("result: %d", loop_test (10));
+
+.. code-block:: bash
+
+   result: 285
+
+
+Visualizing the control flow graph
+**********************************
+
+You can see the control flow graph of a function using
+:c:func:`gcc_jit_function_dump_to_dot`:
+
+.. code-block:: c
+
+  gcc_jit_function_dump_to_dot (func, "/tmp/sum-of-squares.dot");
+
+giving a .dot file in GraphViz format.
+
+You can convert this to an image using `dot`:
+
+.. code-block:: bash
+
+   $ dot -Tpng /tmp/sum-of-squares.dot -o /tmp/sum-of-squares.png
+
+or use a viewer (my preferred one is xdot.py; see
+https://github.com/jrfonseca/xdot.py; on Fedora you can
+install it with `yum install python-xdot`):
+
+    .. figure:: sum-of-squares.png
+      :alt: image of a control flow graph
+
+Full example
+************
+
+   .. literalinclude:: ../examples/tut03-sum-of-squares.c
+    :lines: 1-
+    :language: c
+
+Building and running it:
+
+.. code-block:: console
+
+  $ gcc \
+      tut03-sum-of-squares.c \
+      -o tut03-sum-of-squares \
+      -lgccjit
+
+  # Run the built program:
+  $ ./tut03-sum-of-squares
+  loop_test returned: 285
diff --git a/gcc/jit/docs/intro/tutorial04.rst b/gcc/jit/docs/intro/tutorial04.rst
new file mode 100644
index 0000000..cafdddb
--- /dev/null
+++ b/gcc/jit/docs/intro/tutorial04.rst
@@ -0,0 +1,1108 @@
+.. Copyright (C) 2014 Free Software Foundation, Inc.
+   Originally contributed by David Malcolm <dmalcolm@redhat.com>
+
+   This is free software: you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see
+   <http://www.gnu.org/licenses/>.
+
+Tutorial part 4: Adding JIT-compilation to a toy interpreter
+------------------------------------------------------------
+In this example we construct a "toy" interpreter, and add JIT-compilation
+to it.
+
+Our toy interpreter
+*******************
+
+It's a stack-based interpreter, and is intended as a (very simple) example
+of the kind of bytecode interpreter seen in dynamic languages such as
+Python, Ruby etc.
+
+For the sake of simplicity, our toy virtual machine is very limited:
+
+  * The only data type is `int`
+
+  * It can only work on one function at a time (so that the only
+    function call that can be made is to recurse).
+
+  * Functions can only take one parameter.
+
+  * Functions have a stack of `int` values.
+
+  * We'll implement function call within the interpreter by calling a
+    function in our implementation, rather than implementing our own
+    frame stack.
+
+  * The parser is only good enough to get the examples to work.
+
+Naturally, a real interpreter would be much more complicated that this.
+
+The following operations are supported:
+
+====================== ======================== =============== ==============
+Operation              Meaning                  Old Stack       New Stack
+====================== ======================== =============== ==============
+DUP                    Duplicate top of stack.  ``[..., x]``    ``[..., x, x]``
+ROT                    Swap top two elements    ``[..., x, y]`` ``[..., y, x]``
+                       of stack.
+BINARY_ADD             Add the top two elements ``[..., x, y]`` ``[..., (x+y)]``
+                       on the stack.
+BINARY_SUBTRACT        Likewise, but subtract.  ``[..., x, y]`` ``[..., (x-y)]``
+BINARY_MULT            Likewise, but multiply.  ``[..., x, y]`` ``[..., (x*y)]``
+BINARY_COMPARE_LT      Compare the top two      ``[..., x, y]`` ``[..., (x<y)]``
+                       elements on the stack
+                       and push a nonzero/zero
+                       if (x<y).
+RECURSE                Recurse, passing the top ``[..., x]``    ``[..., fn(x)]``
+                       of the stack, and
+                       popping the result.
+RETURN                 Return the top of the    ``[x]``         ``[]``
+                       stack.
+PUSH_CONST `arg`       Push an int const.       ``[...]``       ``[..., arg]``
+JUMP_ABS_IF_TRUE `arg` Pop; if top of stack was ``[..., x]``    ``[...]``
+                       nonzero, jump to
+                       ``arg``.
+====================== ======================== =============== ==============
+
+Programs can be interpreted, disassembled, and compiled to machine code.
+
+The interpreter reads ``.toy`` scripts.  Here's what a simple recursive
+factorial program looks like, the script ``factorial.toy``.
+The parser ignores lines beginning with a `#`.
+
+   .. literalinclude:: ../examples/tut04-toyvm/factorial.toy
+    :lines: 1-
+    :language: c
+
+The interpreter is a simple infinite loop with a big ``switch`` statement
+based on what the next opcode is:
+
+   .. literalinclude:: ../examples/tut04-toyvm/toyvm.c
+    :start-after: /* Execute the given function.  */
+    :end-before: /* JIT compilation.  */
+    :language: c
+
+Compiling to machine code
+*************************
+We want to generate machine code that can be cast to this type and
+then directly executed in-process:
+
+   .. literalinclude:: ../examples/tut04-toyvm/toyvm.c
+    :start-after: /* Functions are compiled to this function ptr type.  */
+    :end-before: enum opcode
+    :language: c
+
+Our compiler isn't very sophisticated; it takes the implementation of
+each opcode above, and maps it directly to the operations supported by
+the libgccjit API.
+
+How should we handle the stack?  In theory we could calculate what the
+stack depth will be at each opcode, and optimize away the stack
+manipulation "by hand".  We'll see below that libgccjit is able to do
+this for us, so we'll implement stack manipulation
+in a direct way, by creating a ``stack`` array and ``stack_depth``
+variables, local within the generated function, equivalent to this C code:
+
+.. code-block:: c
+
+  int stack_depth;
+  int stack[MAX_STACK_DEPTH];
+
+We'll also have local variables ``x`` and ``y`` for use when implementing
+the opcodes, equivalent to this:
+
+.. code-block:: c
+
+  int x;
+  int y;
+
+This means our compiler has the following state:
+
+   .. literalinclude:: ../examples/tut04-toyvm/toyvm.c
+    :start-after: /* JIT compilation.  */
+    :end-before: /* Stack manipulation.  */
+    :language: c
+
+Setting things up
+*****************
+
+First we create our types:
+
+   .. literalinclude:: ../examples/tut04-toyvm/toyvm.c
+    :start-after: /* Create types.  */
+    :end-before: /* The constant value 1.  */
+    :language: c
+
+along with extracting a useful `int` constant:
+
+   .. literalinclude:: ../examples/tut04-toyvm/toyvm.c
+    :start-after: /* The constant value 1.  */
+    :end-before: /* Create locations.  */
+    :language: c
+
+We'll implement push and pop in terms of the ``stack`` array and
+``stack_depth``.  Here are helper functions for adding statements to
+a block, implementing pushing and popping values:
+
+   .. literalinclude:: ../examples/tut04-toyvm/toyvm.c
+    :start-after: /* Stack manipulation.  */
+    :end-before: /* The main compilation hook.  */
+    :language: c
+
+We will support single-stepping through the generated code in the
+debugger, so we need to create :c:type:`gcc_jit_location` instances, one
+per operation in the source code.  These will reference the lines of
+e.g. ``factorial.toy``.
+
+   .. literalinclude:: ../examples/tut04-toyvm/toyvm.c
+    :start-after: /* Create locations.  */
+    :end-before: /* Creating the function.  */
+    :language: c
+
+Let's create the function itself.  As usual, we create its parameter
+first, then use the parameter to create the function:
+
+   .. literalinclude:: ../examples/tut04-toyvm/toyvm.c
+    :start-after: /* Creating the function.  */
+    :end-before: /* Create stack lvalues.  */
+    :language: c
+
+We create the locals within the function.
+
+   .. literalinclude:: ../examples/tut04-toyvm/toyvm.c
+    :start-after: /* Create stack lvalues.  */
+    :end-before: /* 1st pass: create blocks, one per opcode.
+    :language: c
+
+Populating the function
+***********************
+
+There's some one-time initialization, and the API treats the first block
+you create as the entrypoint of the function, so we need to create that
+block first:
+
+   .. literalinclude:: ../examples/tut04-toyvm/toyvm.c
+    :start-after: first.  */
+    :end-before: /* Create a block per operation.  */
+    :language: c
+
+We can now create blocks for each of the operations.  Most of these will
+be consolidated into larger blocks when the optimizer runs.
+
+   .. literalinclude:: ../examples/tut04-toyvm/toyvm.c
+    :start-after: /* Create a block per operation.  */
+    :end-before: /* Populate the initial block.  */
+    :language: c
+
+Now that we have a block it can jump to when it's done, we can populate
+the initial block:
+
+   .. literalinclude:: ../examples/tut04-toyvm/toyvm.c
+    :start-after: /* Populate the initial block.  */
+    :end-before: /* 2nd pass: fill in instructions.  */
+    :language: c
+
+We can now populate the blocks for the individual operations.  We loop
+through them, adding instructions to their blocks:
+
+   .. literalinclude:: ../examples/tut04-toyvm/toyvm.c
+    :start-after: /* 2nd pass: fill in instructions.  */
+    :end-before: /* Helper macros.  */
+    :language: c
+
+We're going to have another big ``switch`` statement for implementing
+the opcodes, this time for compiling them, rather than interpreting
+them.  It's helpful to have macros for implementing push and pop, so that
+we can make the ``switch`` statement that's coming up look as much as
+possible like the one above within the interpreter:
+
+.. literalinclude:: ../examples/tut04-toyvm/toyvm.c
+    :start-after: /* Helper macros.  */
+    :end-before: gcc_jit_block_add_comment
+    :language: c
+
+.. note::
+
+   A particularly clever implementation would have an *identical*
+   ``switch`` statement shared by the interpreter and the compiler, with
+   some preprocessor "magic".  We're not doing that here, for the sake
+   of simplicity.
+
+When I first implemented this compiler, I accidentally missed an edit
+when copying and pasting the ``Y_EQUALS_POP`` macro, so that popping the
+stack into ``y`` instead erroneously assigned it to ``x``, leaving ``y``
+uninitialized.
+
+To track this kind of thing down, we can use
+:c:func:`gcc_jit_block_add_comment` to add descriptive comments
+to the internal representation.  This is invaluable when looking through
+the generated IR for, say ``factorial``:
+
+   .. literalinclude:: ../examples/tut04-toyvm/toyvm.c
+    :start-after: PUSH_RVALUE (gcc_jit_lvalue_as_rvalue (state.y))
+    :end-before: /* Handle the individual opcodes.  */
+    :language: c
+
+We can now write the big ``switch`` statement that implements the
+individual opcodes, populating the relevant block with statements:
+
+   .. literalinclude:: ../examples/tut04-toyvm/toyvm.c
+    :start-after: /* Handle the individual opcodes.  */
+    :end-before: /* Go to the next block.  */
+    :language: c
+
+Every block must be terminated, via a call to one of the
+``gcc_jit_block_end_with_`` entrypoints.  This has been done for two
+of the opcodes, but we need to do it for the other ones, by jumping
+to the next block.
+
+   .. literalinclude:: ../examples/tut04-toyvm/toyvm.c
+    :start-after: /* Go to the next block.  */
+    :end-before: /* end of loop on PC locations.  */
+    :language: c
+
+This is analogous to simply incrementing the program counter.
+
+Verifying the control flow graph
+********************************
+Having finished looping over the blocks, the context is complete.
+
+As before, we can verify that the control flow and statements are sane by
+using :c:func:`gcc_jit_function_dump_to_dot`:
+
+.. code-block:: c
+
+  gcc_jit_function_dump_to_dot (state.fn, "/tmp/factorial.dot");
+
+and viewing the result.  Note how the label names, comments, and
+variable names show up in the dump, to make it easier to spot
+errors in our compiler.
+
+  .. figure:: factorial.png
+    :alt: image of a control flow graph
+
+Compiling the context
+*********************
+Having finished looping over the blocks and populating them with
+statements, the context is complete.
+
+We can now compile it, and extract machine code from the result:
+
+   .. literalinclude:: ../examples/tut04-toyvm/toyvm.c
+    :start-after: /* We've now finished populating the context.  Compile it.  */
+    :end-before: /* (this leaks "result" and "funcname") */
+    :language: c
+
+We can now run the result:
+
+   .. literalinclude:: ../examples/tut04-toyvm/toyvm.c
+    :start-after: /* JIT-compilation.  */
+    :end-before: return 0;
+    :language: c
+
+Single-stepping through the generated code
+******************************************
+
+It's possible to debug the generated code.  To do this we need to both:
+
+  * Set up source code locations for our statements, so that we can
+    meaningfully step through the code.  We did this above by
+    calling :c:func:`gcc_jit_context_new_location` and using the
+    results.
+
+  * Enable the generation of debugging information, by setting
+    :c:macro:`GCC_JIT_BOOL_OPTION_DEBUGINFO` on the
+    :c:type:`gcc_jit_context` via
+    :c:func:`gcc_jit_context_set_bool_option`:
+
+    .. code-block:: c
+
+     gcc_jit_context_set_bool_option (
+       ctxt,
+       GCC_JIT_BOOL_OPTION_DEBUGINFO,
+       1);
+
+Having done this, we can put a breakpoint on the generated function:
+
+.. code-block:: console
+
+  $ gdb --args ./toyvm factorial.toy 10
+  (gdb) break factorial
+  Function "factorial" not defined.
+  Make breakpoint pending on future shared library load? (y or [n]) y
+  Breakpoint 1 (factorial) pending.
+  (gdb) run
+  Breakpoint 1, factorial (arg=10) at factorial.toy:14
+  14	DUP
+
+We've set up location information, which references ``factorial.toy``.
+This allows us to use e.g. ``list`` to see where we are in the script:
+
+.. code-block:: console
+
+  (gdb) list
+  9
+  10    # Initial state:
+  11    # stack: [arg]
+  12
+  13    # 0:
+  14    DUP
+  15    # stack: [arg, arg]
+  16
+  17    # 1:
+  18    PUSH_CONST 2
+
+and to step through the function, examining the data:
+
+.. code-block:: console
+
+  (gdb) n
+  18    PUSH_CONST 2
+  (gdb) n
+  22    BINARY_COMPARE_LT
+  (gdb) print stack
+  $5 = {10, 10, 2, 0, -7152, 32767, 0, 0}
+  (gdb) print stack_depth
+  $6 = 3
+
+You'll see that the parts of the ``stack`` array that haven't been
+touched yet are uninitialized.
+
+.. note::
+
+   Turning on optimizations may lead to unpredictable results when
+   stepping through the generated code: the execution may appear to
+   "jump around" the source code.  This is analogous to turning up the
+   optimization level in a regular compiler.
+
+Examining the generated code
+****************************
+
+How good is the optimized code?
+
+We can turn up optimizations, by calling
+:c:func:`gcc_jit_context_set_int_option` with
+:c:macro:`GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL`:
+
+.. code-block:: c
+
+  gcc_jit_context_set_int_option (
+    ctxt,
+    GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL,
+    3);
+
+One of GCC's internal representations is called "gimple".  A dump of the
+initial gimple representation of the code can be seen by setting:
+
+.. code-block:: c
+
+  gcc_jit_context_set_bool_option (ctxt,
+                                   GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE,
+                                   1);
+
+With optimization on and source locations displayed, this gives:
+
+.. We'll use "c" for gimple dumps
+
+.. code-block:: c
+
+  factorial (signed int arg)
+  {
+    <unnamed type> D.80;
+    signed int D.81;
+    signed int D.82;
+    signed int D.83;
+    signed int D.84;
+    signed int D.85;
+    signed int y;
+    signed int x;
+    signed int stack_depth;
+    signed int stack[8];
+
+    try
+      {
+        initial:
+        stack_depth = 0;
+        stack[stack_depth] = arg;
+        stack_depth = stack_depth + 1;
+        goto instr0;
+        instr0:
+        /* DUP */:
+        stack_depth = stack_depth + -1;
+        x = stack[stack_depth];
+        stack[stack_depth] = x;
+        stack_depth = stack_depth + 1;
+        stack[stack_depth] = x;
+        stack_depth = stack_depth + 1;
+        goto instr1;
+        instr1:
+        /* PUSH_CONST */:
+        stack[stack_depth] = 2;
+        stack_depth = stack_depth + 1;
+        goto instr2;
+
+        /* etc */
+
+You can see the generated machine code in assembly form via:
+
+.. code-block:: c
+
+  gcc_jit_context_set_bool_option (
+    ctxt,
+    GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE,
+    1);
+  result = gcc_jit_context_compile (ctxt);
+
+which shows that (on this x86_64 box) the compiler has unrolled the loop
+and is using MMX instructions to perform several multiplications
+simultaneously:
+
+.. code-block:: gas
+
+          .file   "fake.c"
+          .text
+  .Ltext0:
+          .p2align 4,,15
+          .globl  factorial
+          .type   factorial, @function
+  factorial:
+  .LFB0:
+          .file 1 "factorial.toy"
+          .loc 1 14 0
+          .cfi_startproc
+  .LVL0:
+  .L2:
+          .loc 1 26 0
+          cmpl    $1, %edi
+          jle     .L13
+          leal    -1(%rdi), %edx
+          movl    %edx, %ecx
+          shrl    $2, %ecx
+          leal    0(,%rcx,4), %esi
+          testl   %esi, %esi
+          je      .L14
+          cmpl    $9, %edx
+          jbe     .L14
+          leal    -2(%rdi), %eax
+          movl    %eax, -16(%rsp)
+          leal    -3(%rdi), %eax
+          movd    -16(%rsp), %xmm0
+          movl    %edi, -16(%rsp)
+          movl    %eax, -12(%rsp)
+          movd    -16(%rsp), %xmm1
+          xorl    %eax, %eax
+          movl    %edx, -16(%rsp)
+          movd    -12(%rsp), %xmm4
+          movd    -16(%rsp), %xmm6
+          punpckldq       %xmm4, %xmm0
+          movdqa  .LC1(%rip), %xmm4
+          punpckldq       %xmm6, %xmm1
+          punpcklqdq      %xmm0, %xmm1
+          movdqa  .LC0(%rip), %xmm0
+          jmp     .L5
+          # etc - edited for brevity
+
+This is clearly overkill for a function that will likely overflow the
+``int`` type before the vectorization is worthwhile - but then again, this
+is a toy example.
+
+Turning down the optimization level to 2:
+
+.. code-block:: c
+
+  gcc_jit_context_set_int_option (
+    ctxt,
+    GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL,
+    3);
+
+yields this code, which is simple enough to quote in its entirety:
+
+.. code-block:: gas
+
+          .file   "fake.c"
+          .text
+          .p2align 4,,15
+          .globl  factorial
+          .type   factorial, @function
+  factorial:
+  .LFB0:
+          .cfi_startproc
+  .L2:
+          cmpl    $1, %edi
+          jle     .L8
+          movl    $1, %edx
+          jmp     .L4
+          .p2align 4,,10
+          .p2align 3
+  .L6:
+          movl    %eax, %edi
+  .L4:
+  .L5:
+          leal    -1(%rdi), %eax
+          imull   %edi, %edx
+          cmpl    $1, %eax
+          jne     .L6
+  .L3:
+  .L7:
+          imull   %edx, %eax
+          ret
+  .L8:
+          movl    %edi, %eax
+          movl    $1, %edx
+          jmp     .L7
+          .cfi_endproc
+  .LFE0:
+          .size   factorial, .-factorial
+          .ident  "GCC: (GNU) 4.9.0 20131023 (Red Hat 0.2-%{gcc_release})"
+          .section        .note.GNU-stack,"",@progbits
+
+Note that the stack pushing and popping have been eliminated, as has the
+recursive call (in favor of an iteration).
+
+Putting it all together
+***********************
+
+The complete example can be seen in the source tree at
+``gcc/jit/docs/examples/tut04-toyvm/toyvm.c``
+
+along with a Makefile and a couple of sample .toy scripts:
+
+.. code-block:: console
+
+  $ ls -al
+  drwxrwxr-x. 2 david david   4096 Sep 19 17:46 .
+  drwxrwxr-x. 3 david david   4096 Sep 19 15:26 ..
+  -rw-rw-r--. 1 david david    615 Sep 19 12:43 factorial.toy
+  -rw-rw-r--. 1 david david    834 Sep 19 13:08 fibonacci.toy
+  -rw-rw-r--. 1 david david    238 Sep 19 14:22 Makefile
+  -rw-rw-r--. 1 david david  16457 Sep 19 17:07 toyvm.c
+
+  $ make toyvm
+  g++ -Wall -g -o toyvm toyvm.c -lgccjit
+
+  $ ./toyvm factorial.toy 10
+  interpreter result: 3628800
+  compiler result: 3628800
+
+  $ ./toyvm fibonacci.toy 10
+  interpreter result: 55
+  compiler result: 55
+
+Behind the curtain: How does our code get optimized?
+****************************************************
+
+Our example is done, but you may be wondering about exactly how the
+compiler turned what we gave it into the machine code seen above.
+
+We can examine what the compiler is doing in detail by setting:
+
+.. code-block:: c
+
+  gcc_jit_context_set_bool_option (state.ctxt,
+                                   GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING,
+                                   1);
+  gcc_jit_context_set_bool_option (state.ctxt,
+                                   GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES,
+                                   1);
+
+This will dump detailed information about the compiler's state to a
+directory under ``/tmp``, and keep it from being cleaned up.
+
+The precise names and their formats of these files is subject to change.
+Higher optimization levels lead to more files.
+Here's what I saw (edited for brevity; there were almost 200 files):
+
+.. code-block:: console
+
+  intermediate files written to /tmp/libgccjit-KPQbGw
+  $ ls /tmp/libgccjit-KPQbGw/
+  fake.c.000i.cgraph
+  fake.c.000i.type-inheritance
+  fake.c.004t.gimple
+  fake.c.007t.omplower
+  fake.c.008t.lower
+  fake.c.011t.eh
+  fake.c.012t.cfg
+  fake.c.014i.visibility
+  fake.c.015i.early_local_cleanups
+  fake.c.016t.ssa
+  # etc
+
+The gimple code is converted into Static Single Assignment form,
+with annotations for use when generating the debuginfo:
+
+.. code-block:: console
+
+  $ less /tmp/libgccjit-KPQbGw/fake.c.016t.ssa
+
+.. code-block:: c
+
+  ;; Function factorial (factorial, funcdef_no=0, decl_uid=53, symbol_order=0)
+
+  factorial (signed int arg)
+  {
+    signed int stack[8];
+    signed int stack_depth;
+    signed int x;
+    signed int y;
+    <unnamed type> _20;
+    signed int _21;
+    signed int _38;
+    signed int _44;
+    signed int _51;
+    signed int _56;
+
+  initial:
+    stack_depth_3 = 0;
+    # DEBUG stack_depth => stack_depth_3
+    stack[stack_depth_3] = arg_5(D);
+    stack_depth_7 = stack_depth_3 + 1;
+    # DEBUG stack_depth => stack_depth_7
+    # DEBUG instr0 => NULL
+    # DEBUG /* DUP */ => NULL
+    stack_depth_8 = stack_depth_7 + -1;
+    # DEBUG stack_depth => stack_depth_8
+    x_9 = stack[stack_depth_8];
+    # DEBUG x => x_9
+    stack[stack_depth_8] = x_9;
+    stack_depth_11 = stack_depth_8 + 1;
+    # DEBUG stack_depth => stack_depth_11
+    stack[stack_depth_11] = x_9;
+    stack_depth_13 = stack_depth_11 + 1;
+    # DEBUG stack_depth => stack_depth_13
+    # DEBUG instr1 => NULL
+    # DEBUG /* PUSH_CONST */ => NULL
+    stack[stack_depth_13] = 2;
+
+    /* etc; edited for brevity */
+
+We can perhaps better see the code by turning off
+:c:macro:`GCC_JIT_BOOL_OPTION_DEBUGINFO` to suppress all those ``DEBUG``
+statements, giving:
+
+.. code-block:: console
+
+  $ less /tmp/libgccjit-1Hywc0/fake.c.016t.ssa
+
+.. code-block:: c
+
+  ;; Function factorial (factorial, funcdef_no=0, decl_uid=53, symbol_order=0)
+
+  factorial (signed int arg)
+  {
+    signed int stack[8];
+    signed int stack_depth;
+    signed int x;
+    signed int y;
+    <unnamed type> _20;
+    signed int _21;
+    signed int _38;
+    signed int _44;
+    signed int _51;
+    signed int _56;
+
+  initial:
+    stack_depth_3 = 0;
+    stack[stack_depth_3] = arg_5(D);
+    stack_depth_7 = stack_depth_3 + 1;
+    stack_depth_8 = stack_depth_7 + -1;
+    x_9 = stack[stack_depth_8];
+    stack[stack_depth_8] = x_9;
+    stack_depth_11 = stack_depth_8 + 1;
+    stack[stack_depth_11] = x_9;
+    stack_depth_13 = stack_depth_11 + 1;
+    stack[stack_depth_13] = 2;
+    stack_depth_15 = stack_depth_13 + 1;
+    stack_depth_16 = stack_depth_15 + -1;
+    y_17 = stack[stack_depth_16];
+    stack_depth_18 = stack_depth_16 + -1;
+    x_19 = stack[stack_depth_18];
+    _20 = x_19 < y_17;
+    _21 = (signed int) _20;
+    stack[stack_depth_18] = _21;
+    stack_depth_23 = stack_depth_18 + 1;
+    stack_depth_24 = stack_depth_23 + -1;
+    x_25 = stack[stack_depth_24];
+    if (x_25 != 0)
+      goto <bb 4> (instr9);
+    else
+      goto <bb 3> (instr4);
+
+  instr4:
+  /* DUP */:
+    stack_depth_26 = stack_depth_24 + -1;
+    x_27 = stack[stack_depth_26];
+    stack[stack_depth_26] = x_27;
+    stack_depth_29 = stack_depth_26 + 1;
+    stack[stack_depth_29] = x_27;
+    stack_depth_31 = stack_depth_29 + 1;
+    stack[stack_depth_31] = 1;
+    stack_depth_33 = stack_depth_31 + 1;
+    stack_depth_34 = stack_depth_33 + -1;
+    y_35 = stack[stack_depth_34];
+    stack_depth_36 = stack_depth_34 + -1;
+    x_37 = stack[stack_depth_36];
+    _38 = x_37 - y_35;
+    stack[stack_depth_36] = _38;
+    stack_depth_40 = stack_depth_36 + 1;
+    stack_depth_41 = stack_depth_40 + -1;
+    x_42 = stack[stack_depth_41];
+    _44 = factorial (x_42);
+    stack[stack_depth_41] = _44;
+    stack_depth_46 = stack_depth_41 + 1;
+    stack_depth_47 = stack_depth_46 + -1;
+    y_48 = stack[stack_depth_47];
+    stack_depth_49 = stack_depth_47 + -1;
+    x_50 = stack[stack_depth_49];
+    _51 = x_50 * y_48;
+    stack[stack_depth_49] = _51;
+    stack_depth_53 = stack_depth_49 + 1;
+
+    # stack_depth_1 = PHI <stack_depth_24(2), stack_depth_53(3)>
+  instr9:
+  /* RETURN */:
+    stack_depth_54 = stack_depth_1 + -1;
+    x_55 = stack[stack_depth_54];
+    _56 = x_55;
+    stack ={v} {CLOBBER};
+    return _56;
+
+  }
+
+Note in the above how all the :c:type:`gcc_jit_block` instances we
+created have been consolidated into just 3 blocks in GCC's internal
+representation: ``initial``, ``instr4`` and ``instr9``.
+
+Optimizing away stack manipulation
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Recall our simple implementation of stack operations.  Let's examine
+how the stack operations are optimized away.
+
+After a pass of constant-propagation, the depth of the stack at each
+opcode can be determined at compile-time:
+
+.. code-block:: console
+
+  $ less /tmp/libgccjit-1Hywc0/fake.c.021t.ccp1
+
+.. code-block:: c
+
+  ;; Function factorial (factorial, funcdef_no=0, decl_uid=53, symbol_order=0)
+
+  factorial (signed int arg)
+  {
+    signed int stack[8];
+    signed int stack_depth;
+    signed int x;
+    signed int y;
+    <unnamed type> _20;
+    signed int _21;
+    signed int _38;
+    signed int _44;
+    signed int _51;
+
+  initial:
+    stack[0] = arg_5(D);
+    x_9 = stack[0];
+    stack[0] = x_9;
+    stack[1] = x_9;
+    stack[2] = 2;
+    y_17 = stack[2];
+    x_19 = stack[1];
+    _20 = x_19 < y_17;
+    _21 = (signed int) _20;
+    stack[1] = _21;
+    x_25 = stack[1];
+    if (x_25 != 0)
+      goto <bb 4> (instr9);
+    else
+      goto <bb 3> (instr4);
+
+  instr4:
+  /* DUP */:
+    x_27 = stack[0];
+    stack[0] = x_27;
+    stack[1] = x_27;
+    stack[2] = 1;
+    y_35 = stack[2];
+    x_37 = stack[1];
+    _38 = x_37 - y_35;
+    stack[1] = _38;
+    x_42 = stack[1];
+    _44 = factorial (x_42);
+    stack[1] = _44;
+    y_48 = stack[1];
+    x_50 = stack[0];
+    _51 = x_50 * y_48;
+    stack[0] = _51;
+
+  instr9:
+  /* RETURN */:
+    x_55 = stack[0];
+    x_56 = x_55;
+    stack ={v} {CLOBBER};
+    return x_56;
+
+  }
+
+Note how, in the above, all those ``stack_depth`` values are now just
+constants: we're accessing specific stack locations at each opcode.
+
+The "esra" pass ("Early Scalar Replacement of Aggregates") breaks
+out our "stack" array into individual elements:
+
+.. code-block:: console
+
+  $ less /tmp/libgccjit-1Hywc0/fake.c.024t.esra
+
+.. code-block:: c
+
+  ;; Function factorial (factorial, funcdef_no=0, decl_uid=53, symbol_order=0)
+
+  Created a replacement for stack offset: 0, size: 32: stack$0
+  Created a replacement for stack offset: 32, size: 32: stack$1
+  Created a replacement for stack offset: 64, size: 32: stack$2
+
+  Symbols to be put in SSA form
+  { D.89 D.90 D.91 }
+  Incremental SSA update started at block: 0
+  Number of blocks in CFG: 5
+  Number of blocks to update: 4 ( 80%)
+
+
+  factorial (signed int arg)
+  {
+    signed int stack$2;
+    signed int stack$1;
+    signed int stack$0;
+    signed int stack[8];
+    signed int stack_depth;
+    signed int x;
+    signed int y;
+    <unnamed type> _20;
+    signed int _21;
+    signed int _38;
+    signed int _44;
+    signed int _51;
+
+  initial:
+    stack$0_45 = arg_5(D);
+    x_9 = stack$0_45;
+    stack$0_39 = x_9;
+    stack$1_32 = x_9;
+    stack$2_30 = 2;
+    y_17 = stack$2_30;
+    x_19 = stack$1_32;
+    _20 = x_19 < y_17;
+    _21 = (signed int) _20;
+    stack$1_28 = _21;
+    x_25 = stack$1_28;
+    if (x_25 != 0)
+      goto <bb 4> (instr9);
+    else
+      goto <bb 3> (instr4);
+
+  instr4:
+  /* DUP */:
+    x_27 = stack$0_39;
+    stack$0_22 = x_27;
+    stack$1_14 = x_27;
+    stack$2_12 = 1;
+    y_35 = stack$2_12;
+    x_37 = stack$1_14;
+    _38 = x_37 - y_35;
+    stack$1_10 = _38;
+    x_42 = stack$1_10;
+    _44 = factorial (x_42);
+    stack$1_6 = _44;
+    y_48 = stack$1_6;
+    x_50 = stack$0_22;
+    _51 = x_50 * y_48;
+    stack$0_1 = _51;
+
+    # stack$0_52 = PHI <stack$0_39(2), stack$0_1(3)>
+  instr9:
+  /* RETURN */:
+    x_55 = stack$0_52;
+    x_56 = x_55;
+    stack ={v} {CLOBBER};
+    return x_56;
+
+  }
+
+Hence at this point, all those pushes and pops of the stack are now
+simply assignments to specific temporary variables.
+
+After some copy propagation, the stack manipulation has been completely
+optimized away:
+
+.. code-block:: console
+
+  $ less /tmp/libgccjit-1Hywc0/fake.c.026t.copyprop1
+
+.. code-block:: c
+
+  ;; Function factorial (factorial, funcdef_no=0, decl_uid=53, symbol_order=0)
+
+  factorial (signed int arg)
+  {
+    signed int stack$2;
+    signed int stack$1;
+    signed int stack$0;
+    signed int stack[8];
+    signed int stack_depth;
+    signed int x;
+    signed int y;
+    <unnamed type> _20;
+    signed int _21;
+    signed int _38;
+    signed int _44;
+    signed int _51;
+
+  initial:
+    stack$0_39 = arg_5(D);
+    _20 = arg_5(D) <= 1;
+    _21 = (signed int) _20;
+    if (_21 != 0)
+      goto <bb 4> (instr9);
+    else
+      goto <bb 3> (instr4);
+
+  instr4:
+  /* DUP */:
+    _38 = arg_5(D) + -1;
+    _44 = factorial (_38);
+    _51 = arg_5(D) * _44;
+    stack$0_1 = _51;
+
+    # stack$0_52 = PHI <arg_5(D)(2), _51(3)>
+  instr9:
+  /* RETURN */:
+    stack ={v} {CLOBBER};
+    return stack$0_52;
+
+  }
+
+Later on, another pass finally eliminated ``stack_depth`` local and the
+unused parts of the `stack`` array altogether:
+
+.. code-block:: console
+
+  $ less /tmp/libgccjit-1Hywc0/fake.c.036t.release_ssa
+
+.. code-block:: c
+
+  ;; Function factorial (factorial, funcdef_no=0, decl_uid=53, symbol_order=0)
+
+  Released 44 names, 314.29%, removed 44 holes
+  factorial (signed int arg)
+  {
+    signed int stack$0;
+    signed int mult_acc_1;
+    <unnamed type> _5;
+    signed int _6;
+    signed int _7;
+    signed int mul_tmp_10;
+    signed int mult_acc_11;
+    signed int mult_acc_13;
+
+    # arg_9 = PHI <arg_8(D)(0)>
+    # mult_acc_13 = PHI <1(0)>
+  initial:
+
+    <bb 5>:
+    # arg_4 = PHI <arg_9(2), _7(3)>
+    # mult_acc_1 = PHI <mult_acc_13(2), mult_acc_11(3)>
+    _5 = arg_4 <= 1;
+    _6 = (signed int) _5;
+    if (_6 != 0)
+      goto <bb 4> (instr9);
+    else
+      goto <bb 3> (instr4);
+
+  instr4:
+  /* DUP */:
+    _7 = arg_4 + -1;
+    mult_acc_11 = mult_acc_1 * arg_4;
+    goto <bb 5>;
+
+    # stack$0_12 = PHI <arg_4(5)>
+  instr9:
+  /* RETURN */:
+    mul_tmp_10 = mult_acc_1 * stack$0_12;
+    return mul_tmp_10;
+
+  }
+
+
+Elimination of tail recursion
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Another significant optimization is the detection that the call to
+``factorial`` is tail recursion, which can be eliminated in favor of
+an iteration:
+
+.. code-block:: console
+
+  $ less /tmp/libgccjit-1Hywc0/fake.c.030t.tailr1
+
+.. code-block:: c
+
+  ;; Function factorial (factorial, funcdef_no=0, decl_uid=53, symbol_order=0)
+
+
+  Symbols to be put in SSA form
+  { D.88 }
+  Incremental SSA update started at block: 0
+  Number of blocks in CFG: 5
+  Number of blocks to update: 4 ( 80%)
+
+
+  factorial (signed int arg)
+  {
+    signed int stack$2;
+    signed int stack$1;
+    signed int stack$0;
+    signed int stack[8];
+    signed int stack_depth;
+    signed int x;
+    signed int y;
+    signed int mult_acc_1;
+    <unnamed type> _20;
+    signed int _21;
+    signed int _38;
+    signed int mul_tmp_44;
+    signed int mult_acc_51;
+
+    # arg_5 = PHI <arg_39(D)(0), _38(3)>
+    # mult_acc_1 = PHI <1(0), mult_acc_51(3)>
+  initial:
+    _20 = arg_5 <= 1;
+    _21 = (signed int) _20;
+    if (_21 != 0)
+      goto <bb 4> (instr9);
+    else
+      goto <bb 3> (instr4);
+
+  instr4:
+  /* DUP */:
+    _38 = arg_5 + -1;
+    mult_acc_51 = mult_acc_1 * arg_5;
+    goto <bb 2> (initial);
+
+    # stack$0_52 = PHI <arg_5(2)>
+  instr9:
+  /* RETURN */:
+    stack ={v} {CLOBBER};
+    mul_tmp_44 = mult_acc_1 * stack$0_52;
+    return mul_tmp_44;
+
+  }
-- 
1.8.5.3

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

* [PATCH 22/27] Documentation: top-level index.rst
  2014-10-31 17:07 [PATCH 00/27] Merger of jit branch v3 David Malcolm
                   ` (9 preceding siblings ...)
  2014-10-31 17:16 ` [PATCH 23/27] Documentation: the "intro" subdirectory David Malcolm
@ 2014-10-31 17:21 ` David Malcolm
  2014-10-31 21:29   ` Jeff Law
  2014-10-31 17:28 ` [PATCH 12/27] New file: gcc/jit/jit-recording.h David Malcolm
                   ` (14 subsequent siblings)
  25 siblings, 1 reply; 71+ messages in thread
From: David Malcolm @ 2014-10-31 17:21 UTC (permalink / raw)
  To: gcc-patches, jit; +Cc: David Malcolm

The top-level index.rst provides the high-level structure for the
rest of the docs (which will follow in the patches that follow).

gcc/jit/ChangeLog:
	* docs/index.rst: New.
---
 gcc/jit/docs/index.rst | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 50 insertions(+)
 create mode 100644 gcc/jit/docs/index.rst

diff --git a/gcc/jit/docs/index.rst b/gcc/jit/docs/index.rst
new file mode 100644
index 0000000..ed75e36
--- /dev/null
+++ b/gcc/jit/docs/index.rst
@@ -0,0 +1,50 @@
+.. Copyright (C) 2014 Free Software Foundation, Inc.
+   Originally contributed by David Malcolm <dmalcolm@redhat.com>
+
+   This is free software: you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see
+   <http://www.gnu.org/licenses/>.
+
+libgccjit
+=========
+
+Contents:
+
+.. toctree::
+   :maxdepth: 2
+
+   intro/index.rst
+   topics/index.rst
+   internals/index.rst
+
+This document describes `libgccjit <http://gcc.gnu.org/wiki/JIT>`_, an API
+for embedding GCC inside programs and libraries.
+
+Note that libgccjit is currently of "Alpha" quality;
+the APIs are not yet set in stone, and they shouldn't be used in
+production yet.
+
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
+
+.. Some notes:
+
+   The Sphinx C domain appears to lack explicit support for enum values,
+   so I've been using :c:macro: for them.
+
+   See http://sphinx-doc.org/domains.html#the-c-domain
-- 
1.8.5.3

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

* [PATCH 12/27] New file: gcc/jit/jit-recording.h
  2014-10-31 17:07 [PATCH 00/27] Merger of jit branch v3 David Malcolm
                   ` (10 preceding siblings ...)
  2014-10-31 17:21 ` [PATCH 22/27] Documentation: top-level index.rst David Malcolm
@ 2014-10-31 17:28 ` David Malcolm
  2014-11-03 21:27   ` Jeff Law
  2014-10-31 17:28 ` [PATCH 18/27] New file: gcc/jit/TODO.rst David Malcolm
                   ` (13 subsequent siblings)
  25 siblings, 1 reply; 71+ messages in thread
From: David Malcolm @ 2014-10-31 17:28 UTC (permalink / raw)
  To: gcc-patches, jit; +Cc: David Malcolm

This file declares the gcc::jit::recording internal API, so that
libgccjit.c can record the calls that are made to the public API, for
later playback by the dummy frontend.

gcc/jit/
	* jit-recording.h: New.
---
 gcc/jit/jit-recording.h | 1593 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 1593 insertions(+)
 create mode 100644 gcc/jit/jit-recording.h

diff --git a/gcc/jit/jit-recording.h b/gcc/jit/jit-recording.h
new file mode 100644
index 0000000..bb1a2ee
--- /dev/null
+++ b/gcc/jit/jit-recording.h
@@ -0,0 +1,1593 @@
+/* Internals of libgccjit: classes for recording calls made to the JIT API.
+   Copyright (C) 2013-2014 Free Software Foundation, Inc.
+   Contributed by David Malcolm <dmalcolm@redhat.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef JIT_RECORDING_H
+#define JIT_RECORDING_H
+
+#include "jit-common.h"
+
+namespace gcc {
+
+namespace jit {
+
+class result;
+class dump;
+
+/**********************************************************************
+ Recording.
+ **********************************************************************/
+
+namespace recording {
+
+playback::location *
+playback_location (replayer *r, location *loc);
+
+const char *
+playback_string (string *str);
+
+playback::block *
+playback_block (block *b);
+
+/* A JIT-compilation context.  */
+class context
+{
+public:
+  context (context *parent_ctxt);
+  ~context ();
+
+  void record (memento *m);
+  void replay_into (replayer *r);
+  void disassociate_from_playback ();
+
+  string *
+  new_string (const char *text);
+
+  location *
+  new_location (const char *filename,
+		int line,
+		int column);
+
+  type *
+  get_type (enum gcc_jit_types type);
+
+  type *
+  get_int_type (int num_bytes, int is_signed);
+
+  type *
+  new_array_type (location *loc,
+		  type *element_type,
+		  int num_elements);
+
+  field *
+  new_field (location *loc,
+	     type *type,
+	     const char *name);
+
+  struct_ *
+  new_struct_type (location *loc,
+		   const char *name);
+
+  union_ *
+  new_union_type (location *loc,
+		  const char *name);
+
+  type *
+  new_function_ptr_type (location *loc,
+			 type *return_type,
+			 int num_params,
+			 type **param_types,
+			 int is_variadic);
+
+  param *
+  new_param (location *loc,
+	     type *type,
+	     const char *name);
+
+  function *
+  new_function (location *loc,
+		enum gcc_jit_function_kind kind,
+		type *return_type,
+		const char *name,
+		int num_params,
+		param **params,
+		int is_variadic,
+		enum built_in_function builtin_id);
+
+  function *
+  get_builtin_function (const char *name);
+
+  lvalue *
+  new_global (location *loc,
+	      type *type,
+	      const char *name);
+
+  rvalue *
+  new_rvalue_from_int (type *numeric_type,
+		       int value);
+
+  rvalue *
+  new_rvalue_from_double (type *numeric_type,
+			  double value);
+
+  rvalue *
+  new_rvalue_from_ptr (type *pointer_type,
+		       void *value);
+
+  rvalue *
+  new_string_literal (const char *value);
+
+  rvalue *
+  new_unary_op (location *loc,
+		enum gcc_jit_unary_op op,
+		type *result_type,
+		rvalue *a);
+
+  rvalue *
+  new_binary_op (location *loc,
+		 enum gcc_jit_binary_op op,
+		 type *result_type,
+		 rvalue *a, rvalue *b);
+
+  rvalue *
+  new_comparison (location *loc,
+		  enum gcc_jit_comparison op,
+		  rvalue *a, rvalue *b);
+
+  rvalue *
+  new_call (location *loc,
+	    function *func,
+	    int numargs, rvalue **args);
+
+  rvalue *
+  new_call_through_ptr (location *loc,
+			rvalue *fn_ptr,
+			int numargs, rvalue **args);
+
+  rvalue *
+  new_cast (location *loc,
+	    rvalue *expr,
+	    type *type_);
+
+  lvalue *
+  new_array_access (location *loc,
+		    rvalue *ptr,
+		    rvalue *index);
+
+  void
+  set_str_option (enum gcc_jit_str_option opt,
+		  const char *value);
+
+  void
+  set_int_option (enum gcc_jit_int_option opt,
+		  int value);
+
+  void
+  set_bool_option (enum gcc_jit_bool_option opt,
+		   int value);
+
+  const char *
+  get_str_option (enum gcc_jit_str_option opt) const
+  {
+    return m_str_options[opt];
+  }
+
+  int
+  get_int_option (enum gcc_jit_int_option opt) const
+  {
+    return m_int_options[opt];
+  }
+
+  int
+  get_bool_option (enum gcc_jit_bool_option opt) const
+  {
+    return m_bool_options[opt];
+  }
+
+  result *
+  compile ();
+
+  void
+  add_error (location *loc, const char *fmt, ...)
+      GNU_PRINTF(3, 4);
+
+  void
+  add_error_va (location *loc, const char *fmt, va_list ap)
+      GNU_PRINTF(3, 0);
+
+  const char *
+  get_first_error () const;
+
+  bool errors_occurred () const
+  {
+    if (m_parent_ctxt)
+      if (m_parent_ctxt->errors_occurred ())
+	return true;
+    return m_error_count;
+  }
+
+  type *get_opaque_FILE_type ();
+
+  void dump_to_file (const char *path, bool update_locations);
+
+private:
+  void validate ();
+
+private:
+  context *m_parent_ctxt;
+
+  int m_error_count;
+
+  char *m_first_error_str;
+  bool m_owns_first_error_str;
+
+  const char *m_str_options[GCC_JIT_NUM_STR_OPTIONS];
+  int m_int_options[GCC_JIT_NUM_INT_OPTIONS];
+  bool m_bool_options[GCC_JIT_NUM_BOOL_OPTIONS];
+
+  /* Recorded API usage.  */
+  vec<memento *> m_mementos;
+
+  /* Specific recordings, for use by dump_to_file.  */
+  vec<compound_type *> m_compound_types;
+  vec<function *> m_functions;
+
+  type *m_basic_types[NUM_GCC_JIT_TYPES];
+  type *m_FILE_type;
+
+  builtins_manager *m_builtins_manager; // lazily created
+};
+
+
+/* An object with lifetime managed by the context i.e.
+   it lives until the context is released, at which
+   point it itself is cleaned up.  */
+
+class memento
+{
+public:
+  virtual ~memento () {}
+
+  /* Hook for replaying this.  */
+  virtual void replay_into (replayer *r) = 0;
+
+  void set_playback_obj (void *obj) { m_playback_obj = obj; }
+
+
+  /* Get the context that owns this object.
+
+     Implements the post-error-checking part of
+     gcc_jit_object_get_context.  */
+  context *get_context () { return m_ctxt; }
+
+  memento *
+  as_object () { return this; }
+
+  /* Debugging hook, for use in generating error messages etc.
+     Implements the post-error-checking part of
+     gcc_jit_object_get_debug_string.  */
+  const char *
+  get_debug_string ();
+
+  virtual void write_to_dump (dump &d);
+
+protected:
+  memento (context *ctxt)
+  : m_ctxt (ctxt),
+    m_playback_obj (NULL),
+    m_debug_string (NULL)
+  {
+    gcc_assert (ctxt);
+  }
+
+  string *new_string (const char *text) { return m_ctxt->new_string (text); }
+
+private:
+  virtual string * make_debug_string () = 0;
+
+public:
+  context *m_ctxt;
+
+protected:
+  void *m_playback_obj;
+
+private:
+  string *m_debug_string;
+};
+
+/* or just use std::string? */
+class string : public memento
+{
+public:
+  string (context *ctxt, const char *text);
+  ~string ();
+
+  const char *c_str () { return m_buffer; }
+
+  static string * from_printf (context *ctxt, const char *fmt, ...)
+    GNU_PRINTF(2, 3);
+
+  void replay_into (replayer *) {}
+
+private:
+  string * make_debug_string ();
+
+private:
+  size_t m_len;
+  char *m_buffer;
+};
+
+class location : public memento
+{
+public:
+  location (context *ctxt, string *filename, int line, int column)
+  : memento (ctxt),
+    m_filename (filename),
+    m_line (line),
+    m_column (column)
+ {}
+
+  void replay_into (replayer *r);
+
+  playback::location *
+  playback_location (replayer *r)
+  {
+    /* Normally during playback, we can walk forwards through the list of
+       recording objects, playing them back.  The ordering of recording
+       ensures that everything that a recording object refers to has
+       already been played back, so we can simply look up the relevant
+       m_playback_obj.
+
+       Locations are an exception, due to the "write_to_dump" method of
+       recording::statement.  This method can set a new location on a
+       statement after the statement is created, and thus the location
+       appears in the context's memento list *after* the statement that
+       refers to it.
+
+       In such circumstances, the statement is replayed *before* the location,
+       when the latter doesn't yet have a playback object.
+
+       Hence we need to ensure that locations have playback objects.  */
+    if (!m_playback_obj)
+      {
+	replay_into (r);
+      }
+    gcc_assert (m_playback_obj);
+    return static_cast <playback::location *> (m_playback_obj);
+  }
+
+private:
+  string * make_debug_string ();
+
+private:
+  string *m_filename;
+  int m_line;
+  int m_column;
+};
+
+class type : public memento
+{
+public:
+  type *get_pointer ();
+  type *get_const ();
+  type *get_volatile ();
+
+  /* Get the type obtained when dereferencing this type.
+
+     This will return NULL if it's not valid to dereference this type.
+     The caller is responsible for setting an error.  */
+  virtual type *dereference () = 0;
+
+  /* Dynamic casts.  */
+  virtual function_type *dyn_cast_function_type () { return NULL; }
+  virtual function_type *as_a_function_type() { gcc_unreachable (); return NULL; }
+  virtual struct_ *dyn_cast_struct () { return NULL; }
+
+  /* Is it typesafe to copy to this type from rtype?  */
+  virtual bool accepts_writes_from (type *rtype)
+  {
+    gcc_assert (rtype);
+    return this == rtype->unqualified ();
+  }
+
+  /* Strip off "const" etc */
+  virtual type *unqualified ()
+  {
+    return this;
+  }
+
+  virtual bool is_int () const = 0;
+  virtual bool is_float () const = 0;
+  virtual bool is_bool () const = 0;
+  virtual type *is_pointer () = 0;
+  virtual type *is_array () = 0;
+
+  bool is_numeric () const
+  {
+    return is_int () || is_float () || is_bool ();
+  }
+
+  playback::type *
+  playback_type ()
+  {
+    return static_cast <playback::type *> (m_playback_obj);
+  }
+
+protected:
+  type (context *ctxt)
+    : memento (ctxt),
+    m_pointer_to_this_type (NULL)
+  {}
+
+private:
+  type *m_pointer_to_this_type;
+};
+
+/* Result of "gcc_jit_type_get_type".  */
+class memento_of_get_type : public type
+{
+public:
+  memento_of_get_type (context *ctxt,
+		       enum gcc_jit_types kind)
+  : type (ctxt),
+    m_kind (kind) {}
+
+  type *dereference ();
+
+  bool accepts_writes_from (type *rtype)
+  {
+    if (m_kind == GCC_JIT_TYPE_VOID_PTR)
+      if (rtype->is_pointer ())
+	{
+	  /* LHS (this) is type (void *), and the RHS is a pointer:
+	     accept it:  */
+	  return true;
+	}
+
+    return type::accepts_writes_from (rtype);
+  }
+
+  bool is_int () const;
+  bool is_float () const;
+  bool is_bool () const;
+  type *is_pointer () { return dereference (); }
+  type *is_array () { return NULL; }
+
+public:
+  void replay_into (replayer *r);
+
+private:
+  string * make_debug_string ();
+
+private:
+  enum gcc_jit_types m_kind;
+};
+
+/* Result of "gcc_jit_type_get_pointer".  */
+class memento_of_get_pointer : public type
+{
+public:
+  memento_of_get_pointer (type *other_type)
+  : type (other_type->m_ctxt),
+    m_other_type (other_type) {}
+
+  type *dereference () { return m_other_type; }
+
+  bool accepts_writes_from (type *rtype);
+
+  void replay_into (replayer *r);
+
+  bool is_int () const { return false; }
+  bool is_float () const { return false; }
+  bool is_bool () const { return false; }
+  type *is_pointer () { return m_other_type; }
+  type *is_array () { return NULL; }
+
+private:
+  string * make_debug_string ();
+
+private:
+  type *m_other_type;
+};
+
+/* Result of "gcc_jit_type_get_const".  */
+class memento_of_get_const : public type
+{
+public:
+  memento_of_get_const (type *other_type)
+  : type (other_type->m_ctxt),
+    m_other_type (other_type) {}
+
+  type *dereference () { return m_other_type->dereference (); }
+
+  bool accepts_writes_from (type */*rtype*/)
+  {
+    /* Can't write to a "const".  */
+    return false;
+  }
+
+  /* Strip off the "const", giving the underlying type.  */
+  type *unqualified () { return m_other_type; }
+
+  bool is_int () const { return m_other_type->is_int (); }
+  bool is_float () const { return m_other_type->is_float (); }
+  bool is_bool () const { return m_other_type->is_bool (); }
+  type *is_pointer () { return m_other_type->is_pointer (); }
+  type *is_array () { return m_other_type->is_array (); }
+
+  void replay_into (replayer *);
+
+private:
+  string * make_debug_string ();
+
+private:
+  type *m_other_type;
+};
+
+/* Result of "gcc_jit_type_get_volatile".  */
+class memento_of_get_volatile : public type
+{
+public:
+  memento_of_get_volatile (type *other_type)
+  : type (other_type->m_ctxt),
+    m_other_type (other_type) {}
+
+  type *dereference () { return m_other_type->dereference (); }
+
+  /* Strip off the "volatile", giving the underlying type.  */
+  type *unqualified () { return m_other_type; }
+
+  bool is_int () const { return m_other_type->is_int (); }
+  bool is_float () const { return m_other_type->is_float (); }
+  bool is_bool () const { return m_other_type->is_bool (); }
+  type *is_pointer () { return m_other_type->is_pointer (); }
+  type *is_array () { return m_other_type->is_array (); }
+
+  void replay_into (replayer *);
+
+private:
+  string * make_debug_string ();
+
+private:
+  type *m_other_type;
+};
+
+class array_type : public type
+{
+ public:
+  array_type (context *ctxt,
+	      location *loc,
+	      type *element_type,
+	      int num_elements)
+  : type (ctxt),
+    m_loc (loc),
+    m_element_type (element_type),
+    m_num_elements (num_elements)
+  {}
+
+  type *dereference ();
+
+  bool is_int () const { return false; }
+  bool is_float () const { return false; }
+  bool is_bool () const { return false; }
+  type *is_pointer () { return NULL; }
+  type *is_array () { return m_element_type; }
+
+  void replay_into (replayer *);
+
+ private:
+  string * make_debug_string ();
+
+ private:
+  location *m_loc;
+  type *m_element_type;
+  int m_num_elements;
+};
+
+class function_type : public type
+{
+public:
+  function_type (context *ctxt,
+		 type *return_type,
+		 int num_params,
+		 type **param_types,
+		 int is_variadic);
+
+  type *dereference ();
+  function_type *dyn_cast_function_type () { return this; }
+  function_type *as_a_function_type () { return this; }
+
+  bool is_int () const { return false; }
+  bool is_float () const { return false; }
+  bool is_bool () const { return false; }
+  type *is_pointer () { return NULL; }
+  type *is_array () { return NULL; }
+
+  void replay_into (replayer *);
+
+  type * get_return_type () const { return m_return_type; }
+  vec<type *> get_param_types () const { return m_param_types; }
+  int is_variadic () const { return m_is_variadic; }
+
+  string * make_debug_string_with_ptr ();
+
+ private:
+  string * make_debug_string ();
+  string * make_debug_string_with (const char *);
+
+private:
+  type *m_return_type;
+  vec<type *> m_param_types;
+  int m_is_variadic;
+};
+
+class field : public memento
+{
+public:
+  field (context *ctxt,
+	 location *loc,
+	 type *type,
+	 string *name)
+  : memento (ctxt),
+    m_loc (loc),
+    m_type (type),
+    m_name (name),
+    m_container (NULL)
+  {}
+
+  type * get_type () const { return m_type; }
+
+  compound_type * get_container () const { return m_container; }
+  void set_container (compound_type *c) { m_container = c; }
+
+  void replay_into (replayer *);
+
+  void write_to_dump (dump &d);
+
+  playback::field *
+  playback_field () const
+  {
+    return static_cast <playback::field *> (m_playback_obj);
+  }
+
+private:
+  string * make_debug_string ();
+
+private:
+  location *m_loc;
+  type *m_type;
+  string *m_name;
+  compound_type *m_container;
+};
+
+/* Base class for struct_ and union_ */
+class compound_type : public type
+{
+public:
+  compound_type (context *ctxt,
+		 location *loc,
+		 string *name);
+
+  string *get_name () const { return m_name; }
+  location *get_loc () const { return m_loc; }
+  fields * get_fields () { return m_fields; }
+
+  void
+  set_fields (location *loc,
+	      int num_fields,
+	      field **fields);
+
+  type *dereference ();
+
+  bool is_int () const { return false; }
+  bool is_float () const { return false; }
+  bool is_bool () const { return false; }
+  type *is_pointer () { return NULL; }
+  type *is_array () { return NULL; }
+
+  playback::compound_type *
+  playback_compound_type ()
+  {
+    return static_cast <playback::compound_type *> (m_playback_obj);
+  }
+
+private:
+  location *m_loc;
+  string *m_name;
+  fields *m_fields;
+};
+
+class struct_ : public compound_type
+{
+public:
+  struct_ (context *ctxt,
+	   location *loc,
+	   string *name);
+
+  struct_ *dyn_cast_struct () { return this; }
+
+  type *
+  as_type () { return this; }
+
+  void replay_into (replayer *r);
+
+private:
+  string * make_debug_string ();
+
+};
+
+// memento of struct_::set_fields
+class fields : public memento
+{
+public:
+  fields (compound_type *struct_or_union,
+	  int num_fields,
+	  field **fields);
+
+  void replay_into (replayer *r);
+
+  void write_to_dump (dump &d);
+
+private:
+  string * make_debug_string ();
+
+private:
+  compound_type *m_struct_or_union;
+  vec<field *> m_fields;
+};
+
+class union_ : public compound_type
+{
+public:
+  union_ (context *ctxt,
+	  location *loc,
+	  string *name);
+
+  void replay_into (replayer *r);
+
+private:
+  string * make_debug_string ();
+
+private:
+  location *m_loc;
+  string *m_name;
+  fields *m_fields;
+};
+
+class rvalue : public memento
+{
+public:
+  rvalue (context *ctxt,
+	  location *loc,
+	  type *type_)
+  : memento (ctxt),
+    m_loc (loc),
+    m_type (type_)
+  {
+    gcc_assert (type_);
+  }
+
+  /* Get the recording::type of this rvalue.
+
+     Implements the post-error-checking part of
+     gcc_jit_rvalue_get_type.  */
+  type * get_type () const { return m_type; }
+
+  playback::rvalue *
+  playback_rvalue () const
+  {
+    return static_cast <playback::rvalue *> (m_playback_obj);
+  }
+  rvalue *
+  access_field (location *loc,
+		field *field);
+
+  lvalue *
+  dereference_field (location *loc,
+		     field *field);
+
+  lvalue *
+  dereference (location *loc);
+
+protected:
+  location *m_loc;
+  type *m_type;
+};
+
+class lvalue : public rvalue
+{
+public:
+  lvalue (context *ctxt,
+	  location *loc,
+	  type *type_)
+    : rvalue (ctxt, loc, type_)
+    {}
+
+  playback::lvalue *
+  playback_lvalue () const
+  {
+    return static_cast <playback::lvalue *> (m_playback_obj);
+  }
+
+  lvalue *
+  access_field (location *loc,
+		field *field);
+
+  rvalue *
+  get_address (location *loc);
+
+  rvalue *
+  as_rvalue () { return this; }
+};
+
+class param : public lvalue
+{
+public:
+  param (context *ctxt,
+	 location *loc,
+	 type *type,
+	 string *name)
+    : lvalue (ctxt, loc, type),
+    m_name (name) {}
+
+  lvalue *
+  as_lvalue () { return this; }
+
+  void replay_into (replayer *r);
+
+  playback::param *
+  playback_param () const
+  {
+    return static_cast <playback::param *> (m_playback_obj);
+  }
+
+private:
+  string * make_debug_string () { return m_name; }
+
+private:
+  string *m_name;
+};
+
+class function : public memento
+{
+public:
+  function (context *ctxt,
+	    location *loc,
+	    enum gcc_jit_function_kind kind,
+	    type *return_type,
+	    string *name,
+	    int num_params,
+	    param **params,
+	    int is_variadic,
+	    enum built_in_function builtin_id);
+
+  void replay_into (replayer *r);
+
+  playback::function *
+  playback_function () const
+  {
+    return static_cast <playback::function *> (m_playback_obj);
+  }
+
+  enum gcc_jit_function_kind get_kind () const { return m_kind; }
+
+  lvalue *
+  new_local (location *loc,
+	     type *type,
+	     const char *name);
+
+  block*
+  new_block (const char *name);
+
+  type *get_return_type () const { return m_return_type; }
+  string * get_name () const { return m_name; }
+  vec<param *> get_params () const { return m_params; }
+
+  /* Get the given param by index.
+     Implements the post-error-checking part of
+     gcc_jit_function_get_param.  */
+  param *get_param (int i) const { return m_params[i]; }
+
+  bool is_variadic () const { return m_is_variadic; }
+
+  void write_to_dump (dump &d);
+
+  void validate ();
+
+  void dump_to_dot (const char *path);
+
+private:
+  string * make_debug_string ();
+
+private:
+  location *m_loc;
+  enum gcc_jit_function_kind m_kind;
+  type *m_return_type;
+  string *m_name;
+  vec<param *> m_params;
+  int m_is_variadic;
+  enum built_in_function m_builtin_id;
+  vec<local *> m_locals;
+  vec<block *> m_blocks;
+};
+
+class block : public memento
+{
+public:
+  block (function *func, int index, string *name)
+  : memento (func->m_ctxt),
+    m_func (func),
+    m_index (index),
+    m_name (name),
+    m_statements (),
+    m_has_been_terminated (false),
+    m_is_reachable (false)
+  {
+  }
+
+  /* Get the recording::function containing this block.
+     Implements the post-error-checking part of
+     gcc_jit_block_get_function.  */
+  function *get_function () { return m_func; }
+
+  bool has_been_terminated () { return m_has_been_terminated; }
+  bool is_reachable () { return m_is_reachable; }
+
+  void
+  add_eval (location *loc,
+	    rvalue *rvalue);
+
+  void
+  add_assignment (location *loc,
+		  lvalue *lvalue,
+		  rvalue *rvalue);
+
+  void
+  add_assignment_op (location *loc,
+		     lvalue *lvalue,
+		     enum gcc_jit_binary_op op,
+		     rvalue *rvalue);
+
+  void
+  add_comment (location *loc,
+	       const char *text);
+
+  void
+  end_with_conditional (location *loc,
+			rvalue *boolval,
+			block *on_true,
+			block *on_false);
+
+  void
+  end_with_jump (location *loc,
+		 block *target);
+
+  void
+  end_with_return (location *loc,
+		   rvalue *rvalue);
+
+  playback::block *
+  playback_block () const
+  {
+    return static_cast <playback::block *> (m_playback_obj);
+  }
+
+  void write_to_dump (dump &d);
+
+  bool validate ();
+
+  location *get_loc () const;
+
+  statement *get_first_statement () const;
+  statement *get_last_statement () const;
+
+  int get_successor_blocks (block **next1, block **next2) const;
+
+private:
+  string * make_debug_string ();
+
+  void replay_into (replayer *r);
+
+  void dump_to_dot (pretty_printer *pp);
+  void dump_edges_to_dot (pretty_printer *pp);
+
+private:
+  function *m_func;
+  int m_index;
+  string *m_name;
+  vec<statement *> m_statements;
+  bool m_has_been_terminated;
+  bool m_is_reachable;
+
+  friend class function;
+};
+
+class global : public lvalue
+{
+public:
+  global (context *ctxt,
+	  location *loc,
+	  type *type,
+	  string *name)
+  : lvalue (ctxt, loc, type),
+    m_name (name)
+  {}
+
+  void replay_into (replayer *);
+
+private:
+  string * make_debug_string () { return m_name; }
+
+private:
+  string *m_name;
+};
+
+class memento_of_new_rvalue_from_int : public rvalue
+{
+public:
+  memento_of_new_rvalue_from_int (context *ctxt,
+				  location *loc,
+				  type *numeric_type,
+				  int value)
+  : rvalue (ctxt, loc, numeric_type),
+    m_value (value) {}
+
+  void replay_into (replayer *r);
+
+private:
+  string * make_debug_string ();
+
+private:
+  int m_value;
+};
+
+class memento_of_new_rvalue_from_double : public rvalue
+{
+public:
+  memento_of_new_rvalue_from_double (context *ctxt,
+				     location *loc,
+				     type *numeric_type,
+				     double value)
+  : rvalue (ctxt, loc, numeric_type),
+    m_value (value)
+  {}
+
+  void replay_into (replayer *);
+
+private:
+  string * make_debug_string ();
+
+private:
+  double m_value;
+};
+
+class memento_of_new_rvalue_from_ptr : public rvalue
+{
+public:
+  memento_of_new_rvalue_from_ptr (context *ctxt,
+				  location *loc,
+				  type *pointer_type,
+				  void *value)
+  : rvalue (ctxt, loc, pointer_type),
+    m_value (value)
+  {}
+
+  void replay_into (replayer *);
+
+private:
+  string * make_debug_string ();
+
+private:
+  void *m_value;
+};
+
+class memento_of_new_string_literal : public rvalue
+{
+public:
+  memento_of_new_string_literal (context *ctxt,
+				 location *loc,
+				 string *value)
+  : rvalue (ctxt, loc, ctxt->get_type (GCC_JIT_TYPE_CONST_CHAR_PTR)),
+    m_value (value) {}
+
+  void replay_into (replayer *r);
+
+private:
+  string * make_debug_string ();
+
+private:
+  string *m_value;
+};
+
+class unary_op : public rvalue
+{
+public:
+  unary_op (context *ctxt,
+	    location *loc,
+	    enum gcc_jit_unary_op op,
+	    type *result_type,
+	    rvalue *a)
+  : rvalue (ctxt, loc, result_type),
+    m_op (op),
+    m_a (a)
+  {}
+
+  void replay_into (replayer *r);
+
+private:
+  string * make_debug_string ();
+
+private:
+  enum gcc_jit_unary_op m_op;
+  rvalue *m_a;
+};
+
+class binary_op : public rvalue
+{
+public:
+  binary_op (context *ctxt,
+	     location *loc,
+	     enum gcc_jit_binary_op op,
+	     type *result_type,
+	     rvalue *a, rvalue *b)
+  : rvalue (ctxt, loc, result_type),
+    m_op (op),
+    m_a (a),
+    m_b (b) {}
+
+  void replay_into (replayer *r);
+
+private:
+  string * make_debug_string ();
+
+private:
+  enum gcc_jit_binary_op m_op;
+  rvalue *m_a;
+  rvalue *m_b;
+};
+
+class comparison : public rvalue
+{
+public:
+  comparison (context *ctxt,
+	      location *loc,
+	      enum gcc_jit_comparison op,
+	      rvalue *a, rvalue *b)
+  : rvalue (ctxt, loc, ctxt->get_type (GCC_JIT_TYPE_BOOL)),
+    m_op (op),
+    m_a (a),
+    m_b (b)
+  {}
+
+  void replay_into (replayer *r);
+
+private:
+  string * make_debug_string ();
+
+private:
+  enum gcc_jit_comparison m_op;
+  rvalue *m_a;
+  rvalue *m_b;
+};
+
+class cast : public rvalue
+{
+public:
+  cast (context *ctxt,
+	location *loc,
+	rvalue *a,
+	type *type_)
+  : rvalue (ctxt, loc, type_),
+    m_rvalue (a)
+  {}
+
+  void replay_into (replayer *r);
+
+private:
+  string * make_debug_string ();
+
+private:
+  rvalue *m_rvalue;
+};
+
+class call : public rvalue
+{
+public:
+  call (context *ctxt,
+	location *loc,
+	function *func,
+	int numargs,
+	rvalue **args);
+
+  void replay_into (replayer *r);
+
+private:
+  string * make_debug_string ();
+
+private:
+  function *m_func;
+  vec<rvalue *> m_args;
+};
+
+class call_through_ptr : public rvalue
+{
+public:
+  call_through_ptr (context *ctxt,
+		    location *loc,
+		    rvalue *fn_ptr,
+		    int numargs,
+		    rvalue **args);
+
+  void replay_into (replayer *r);
+
+private:
+  string * make_debug_string ();
+
+private:
+  rvalue *m_fn_ptr;
+  vec<rvalue *> m_args;
+};
+
+class array_access : public lvalue
+{
+public:
+  array_access (context *ctxt,
+		location *loc,
+		rvalue *ptr,
+		rvalue *index)
+  : lvalue (ctxt, loc, ptr->get_type ()->dereference ()),
+    m_ptr (ptr),
+    m_index (index)
+  {}
+
+  void replay_into (replayer *r);
+
+private:
+  string * make_debug_string ();
+
+private:
+  rvalue *m_ptr;
+  rvalue *m_index;
+};
+
+class access_field_of_lvalue : public lvalue
+{
+public:
+  access_field_of_lvalue (context *ctxt,
+			  location *loc,
+			  lvalue *val,
+			  field *field)
+  : lvalue (ctxt, loc, field->get_type ()),
+    m_lvalue (val),
+    m_field (field)
+  {}
+
+  void replay_into (replayer *r);
+
+private:
+  string * make_debug_string ();
+
+private:
+  lvalue *m_lvalue;
+  field *m_field;
+};
+
+class access_field_rvalue : public rvalue
+{
+public:
+  access_field_rvalue (context *ctxt,
+		       location *loc,
+		       rvalue *val,
+		       field *field)
+  : rvalue (ctxt, loc, field->get_type ()),
+    m_rvalue (val),
+    m_field (field)
+  {}
+
+  void replay_into (replayer *r);
+
+private:
+  string * make_debug_string ();
+
+private:
+  rvalue *m_rvalue;
+  field *m_field;
+};
+
+class dereference_field_rvalue : public lvalue
+{
+public:
+  dereference_field_rvalue (context *ctxt,
+			    location *loc,
+			    rvalue *val,
+			    field *field)
+  : lvalue (ctxt, loc, field->get_type ()),
+    m_rvalue (val),
+    m_field (field)
+  {}
+
+  void replay_into (replayer *r);
+
+private:
+  string * make_debug_string ();
+
+private:
+  rvalue *m_rvalue;
+  field *m_field;
+};
+
+class dereference_rvalue : public lvalue
+{
+public:
+  dereference_rvalue (context *ctxt,
+		      location *loc,
+		      rvalue *val)
+  : lvalue (ctxt, loc, val->get_type ()->dereference ()),
+    m_rvalue (val) {}
+
+  void replay_into (replayer *r);
+
+private:
+  string * make_debug_string ();
+
+private:
+  rvalue *m_rvalue;
+};
+
+class get_address_of_lvalue : public rvalue
+{
+public:
+  get_address_of_lvalue (context *ctxt,
+			 location *loc,
+			 lvalue *val)
+  : rvalue (ctxt, loc, val->get_type ()->get_pointer ()),
+    m_lvalue (val)
+  {}
+
+  void replay_into (replayer *r);
+
+private:
+  string * make_debug_string ();
+
+private:
+  lvalue *m_lvalue;
+};
+
+class local : public lvalue
+{
+public:
+  local (function *func, location *loc, type *type_, string *name)
+    : lvalue (func->m_ctxt, loc, type_),
+    m_func (func),
+    m_name (name) {}
+
+  void replay_into (replayer *r);
+
+  void write_to_dump (dump &d);
+
+private:
+  string * make_debug_string () { return m_name; }
+
+private:
+  function *m_func;
+  string *m_name;
+};
+
+class statement : public memento
+{
+public:
+  virtual int get_successor_blocks (block **out_next1,
+				    block **out_next2) const;
+
+  void write_to_dump (dump &d);
+
+  location *get_loc () const { return m_loc; }
+
+protected:
+  statement (block *b, location *loc)
+  : memento (b->m_ctxt),
+    m_block (b),
+    m_loc (loc) {}
+
+  block *get_block () const { return m_block; }
+
+  playback::location *
+  playback_location (replayer *r) const
+  {
+    return ::gcc::jit::recording::playback_location (r, m_loc);
+  }
+
+private:
+  block *m_block;
+  location *m_loc;
+};
+
+class eval : public statement
+{
+public:
+  eval (block *b,
+	location *loc,
+	rvalue *rvalue)
+  : statement (b, loc),
+    m_rvalue (rvalue) {}
+
+  void replay_into (replayer *r);
+
+private:
+  string * make_debug_string ();
+
+private:
+  rvalue *m_rvalue;
+};
+
+class assignment : public statement
+{
+public:
+  assignment (block *b,
+	      location *loc,
+	      lvalue *lvalue,
+	      rvalue *rvalue)
+  : statement (b, loc),
+    m_lvalue (lvalue),
+    m_rvalue (rvalue) {}
+
+  void replay_into (replayer *r);
+
+private:
+  string * make_debug_string ();
+
+private:
+  lvalue *m_lvalue;
+  rvalue *m_rvalue;
+};
+
+class assignment_op : public statement
+{
+public:
+  assignment_op (block *b,
+		 location *loc,
+		 lvalue *lvalue,
+		 enum gcc_jit_binary_op op,
+		 rvalue *rvalue)
+  : statement (b, loc),
+    m_lvalue (lvalue),
+    m_op (op),
+    m_rvalue (rvalue) {}
+
+  void replay_into (replayer *r);
+
+private:
+  string * make_debug_string ();
+
+private:
+  lvalue *m_lvalue;
+  enum gcc_jit_binary_op m_op;
+  rvalue *m_rvalue;
+};
+
+class comment : public statement
+{
+public:
+  comment (block *b,
+	   location *loc,
+	   string *text)
+  : statement (b, loc),
+    m_text (text) {}
+
+  void replay_into (replayer *r);
+
+private:
+  string * make_debug_string ();
+
+private:
+  string *m_text;
+};
+
+class conditional : public statement
+{
+public:
+  conditional (block *b,
+	       location *loc,
+	       rvalue *boolval,
+	       block *on_true,
+	       block *on_false)
+  : statement (b, loc),
+    m_boolval (boolval),
+    m_on_true (on_true),
+    m_on_false (on_false) {}
+
+  void replay_into (replayer *r);
+
+  int get_successor_blocks (block **out_next1,
+			    block **out_next2) const;
+
+private:
+  string * make_debug_string ();
+
+private:
+  rvalue *m_boolval;
+  block *m_on_true;
+  block *m_on_false;
+};
+
+class jump : public statement
+{
+public:
+  jump (block *b,
+	location *loc,
+	block *target)
+  : statement (b, loc),
+    m_target (target) {}
+
+  void replay_into (replayer *r);
+
+  int get_successor_blocks (block **out_next1,
+			    block **out_next2) const;
+
+private:
+  string * make_debug_string ();
+
+private:
+  block *m_target;
+};
+
+class return_ : public statement
+{
+public:
+  return_ (block *b,
+	   location *loc,
+	   rvalue *rvalue)
+  : statement (b, loc),
+    m_rvalue (rvalue) {}
+
+  void replay_into (replayer *r);
+
+  int get_successor_blocks (block **out_next1,
+			    block **out_next2) const;
+
+private:
+  string * make_debug_string ();
+
+private:
+  rvalue *m_rvalue;
+};
+
+} // namespace gcc::jit::recording
+
+/* The result of JIT-compilation.  */
+class result
+{
+public:
+  result(void *dso_handle);
+
+  virtual ~result();
+
+  void *
+  get_code (const char *funcname);
+
+private:
+  void *m_dso_handle;
+};
+
+} // namespace gcc::jit
+
+} // namespace gcc
+
+#endif /* JIT_RECORDING_H */
+
-- 
1.8.5.3

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

* [PATCH 11/27] New file: gcc/jit/jit-common.h
  2014-10-31 17:07 [PATCH 00/27] Merger of jit branch v3 David Malcolm
                   ` (12 preceding siblings ...)
  2014-10-31 17:28 ` [PATCH 18/27] New file: gcc/jit/TODO.rst David Malcolm
@ 2014-10-31 17:28 ` David Malcolm
  2014-11-03 19:34   ` Jeff Law
  2014-10-31 17:28 ` [PATCH 10/27] New file: gcc/jit/libgccjit.c David Malcolm
                   ` (11 subsequent siblings)
  25 siblings, 1 reply; 71+ messages in thread
From: David Malcolm @ 2014-10-31 17:28 UTC (permalink / raw)
  To: gcc-patches, jit; +Cc: David Malcolm

This header has forward declarations of both the jit::recording
and jit::playback internal APIs.

gcc/jit/
	* jit-common.h: New.
---
 gcc/jit/jit-common.h | 182 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 182 insertions(+)
 create mode 100644 gcc/jit/jit-common.h

diff --git a/gcc/jit/jit-common.h b/gcc/jit/jit-common.h
new file mode 100644
index 0000000..58e4a8c
--- /dev/null
+++ b/gcc/jit/jit-common.h
@@ -0,0 +1,182 @@
+/* Core of implementation of libgccjit.so
+   Copyright (C) 2013-2014 Free Software Foundation, Inc.
+   Contributed by David Malcolm <dmalcolm@redhat.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef JIT_COMMON_H
+#define JIT_COMMON_H
+
+#include "libgccjit.h"
+
+#include "tree.h"
+#include "tree-iterator.h"
+
+#ifdef GCC_VERSION
+#if GCC_VERSION >= 4001
+#define GNU_PRINTF(M, N) __attribute__ ((format (gnu_printf, (M), (N))))
+#else
+#define GNU_PRINTF(M, N)
+#endif
+#endif
+
+const int NUM_GCC_JIT_TYPES = GCC_JIT_TYPE_FILE_PTR + 1;
+
+/* This comment is included by the docs.
+
+   In order to allow jit objects to be usable outside of a compile
+   whilst working with the existing structure of GCC's code the
+   C API is implemented in terms of a gcc::jit::recording::context,
+   which records the calls made to it.
+
+   When a gcc_jit_context is compiled, the recording context creates a
+   playback context.  The playback context invokes the bulk of the GCC
+   code, and within the "frontend" parsing hook, plays back the recorded
+   API calls, creating GCC tree objects.
+
+   So there are two parallel families of classes: those relating to
+   recording, and those relating to playback:
+
+   * Visibility: recording objects are exposed back to client code,
+     whereas playback objects are internal to the library.
+
+   * Lifetime: recording objects have a lifetime equal to that of the
+     recording context that created them, whereas playback objects only
+     exist within the frontend hook.
+
+   * Memory allocation: recording objects are allocated by the recording
+     context, and automatically freed by it when the context is released,
+     whereas playback objects are allocated within the GC heap, and
+     garbage-collected; they can own GC-references.
+
+   * Integration with rest of GCC: recording objects are unrelated to the
+     rest of GCC, whereas playback objects are wrappers around "tree"
+     instances.  Hence you can't ask a recording rvalue or lvalue what its
+     type is, whereas you can for a playback rvalue of lvalue (since it
+     can work with the underlying GCC tree nodes).
+
+   * Instancing: There can be multiple recording contexts "alive" at once
+     (albeit it only one compiling at once), whereas there can only be one
+     playback context alive at one time (since it interacts with the GC).
+
+   Ultimately if GCC could support multiple GC heaps and contexts, and
+   finer-grained initialization, then this recording vs playback
+   distinction could be eliminated.
+
+   During a playback, we associate objects from the recording with
+   their counterparts during this playback.  For simplicity, we store this
+   within the recording objects, as ``void *m_playback_obj``, casting it to
+   the appropriate playback object subclass.  For these casts to make
+   sense, the two class hierarchies need to have the same structure.
+
+   Note that the playback objects that ``m_playback_obj`` points to are
+   GC-allocated, but the recording objects don't own references:
+   these associations only exist within a part of the code where
+   the GC doesn't collect, and are set back to NULL before the GC can
+   run.
+
+   End of comment for inclusion in the docs.  */
+
+namespace gcc {
+
+namespace jit {
+
+class result;
+class dump;
+
+namespace recording {
+
+  /* Recording types.  */
+
+  /* Indentation indicates inheritance: */
+  class context;
+  class builtins_manager; // declared within jit-builtins.h
+  class memento;
+    class string;
+    class location;
+    class type;
+      class function_type;
+      class compound_type;
+        class struct_;
+	class union_;
+    class field;
+    class fields;
+    class function;
+    class block;
+    class rvalue;
+      class lvalue;
+        class local;
+	class global;
+        class param;
+    class statement;
+
+  /* End of recording types. */
+}
+
+namespace playback {
+  /* Playback types.  */
+
+  /* Indentation indicates inheritance: */
+  class context;
+  class wrapper;
+    class type;
+      class compound_type;
+    class field;
+    class function;
+    class block;
+    class rvalue;
+      class lvalue;
+        class param;
+    class source_file;
+    class source_line;
+    class location;
+
+  /* End of playback types. */
+}
+
+typedef playback::context replayer;
+
+class dump
+{
+public:
+  dump (recording::context &ctxt,
+	const char *filename,
+	bool update_locations);
+  ~dump ();
+
+  void write (const char *fmt, ...)
+    GNU_PRINTF(2, 3);
+
+  bool update_locations () const { return m_update_locations; }
+
+  recording::location *
+  make_location () const;
+
+private:
+  recording::context &m_ctxt;
+  const char *m_filename;
+  bool m_update_locations;
+  int m_line;
+  int m_column;
+  FILE *m_file;
+};
+
+} // namespace gcc::jit
+
+} // namespace gcc
+
+#endif /* JIT_COMMON_H */
-- 
1.8.5.3

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

* [PATCH 10/27] New file: gcc/jit/libgccjit.c
  2014-10-31 17:07 [PATCH 00/27] Merger of jit branch v3 David Malcolm
                   ` (13 preceding siblings ...)
  2014-10-31 17:28 ` [PATCH 11/27] New file: gcc/jit/jit-common.h David Malcolm
@ 2014-10-31 17:28 ` David Malcolm
  2014-11-03 20:32   ` Jeff Law
  2014-10-31 17:29 ` [PATCH 08/27] New file: gcc/jit/libgccjit.h David Malcolm
                   ` (10 subsequent siblings)
  25 siblings, 1 reply; 71+ messages in thread
From: David Malcolm @ 2014-10-31 17:28 UTC (permalink / raw)
  To: gcc-patches, jit; +Cc: David Malcolm

This file implements the entrypoints of the library's public API.

It performs error-checking at this boundary, before calling into the
jit-recording.h internal API.

gcc/jit/
	* libgccjit.c: New.
---
 gcc/jit/libgccjit.c | 1506 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 1506 insertions(+)
 create mode 100644 gcc/jit/libgccjit.c

diff --git a/gcc/jit/libgccjit.c b/gcc/jit/libgccjit.c
new file mode 100644
index 0000000..286a85e
--- /dev/null
+++ b/gcc/jit/libgccjit.c
@@ -0,0 +1,1506 @@
+/* Implementation of the C API; all wrappers into the internal C++ API
+   Copyright (C) 2013-2014 Free Software Foundation, Inc.
+   Contributed by David Malcolm <dmalcolm@redhat.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "opts.h"
+
+#include "libgccjit.h"
+#include "jit-common.h"
+#include "jit-recording.h"
+
+#define IS_ASCII_ALPHA(CHAR) \
+  (					\
+    ((CHAR) >= 'a' && (CHAR) <='z')	\
+    ||					\
+    ((CHAR) >= 'A' && (CHAR) <= 'Z')	\
+  )
+
+#define IS_ASCII_DIGIT(CHAR) \
+  ((CHAR) >= '0' && (CHAR) <='9')
+
+#define IS_ASCII_ALNUM(CHAR) \
+  (IS_ASCII_ALPHA (CHAR) || IS_ASCII_DIGIT (CHAR))
+
+struct gcc_jit_context : public gcc::jit::recording::context
+{
+  gcc_jit_context (gcc_jit_context *parent_ctxt) :
+    context (parent_ctxt)
+  {}
+};
+
+struct gcc_jit_result : public gcc::jit::result
+{
+};
+
+struct gcc_jit_object : public gcc::jit::recording::memento
+{
+};
+
+struct gcc_jit_location : public gcc::jit::recording::location
+{
+};
+
+struct gcc_jit_type : public gcc::jit::recording::type
+{
+};
+
+struct gcc_jit_struct : public gcc::jit::recording::struct_
+{
+};
+
+struct gcc_jit_field : public gcc::jit::recording::field
+{
+};
+
+struct gcc_jit_function : public gcc::jit::recording::function
+{
+};
+
+struct gcc_jit_block : public gcc::jit::recording::block
+{
+};
+
+struct gcc_jit_rvalue : public gcc::jit::recording::rvalue
+{
+};
+
+struct gcc_jit_lvalue : public gcc::jit::recording::lvalue
+{
+};
+
+struct gcc_jit_param : public gcc::jit::recording::param
+{
+};
+
+/**********************************************************************
+ Error-handling.
+
+ We try to gracefully handle API usage errors by being defensive
+ at the API boundary.
+ **********************************************************************/
+
+#define JIT_BEGIN_STMT do {
+#define JIT_END_STMT   } while(0)
+
+/* TODO: mark failure branches as unlikely? */
+
+#define RETURN_VAL_IF_FAIL(TEST_EXPR, RETURN_EXPR, CTXT, LOC, ERR_MSG)	\
+  JIT_BEGIN_STMT							\
+    if (!(TEST_EXPR))							\
+      {								\
+	jit_error ((CTXT), (LOC), "%s: %s", __func__, (ERR_MSG));	\
+	return (RETURN_EXPR);						\
+      }								\
+  JIT_END_STMT
+
+#define RETURN_VAL_IF_FAIL_PRINTF1(TEST_EXPR, RETURN_EXPR, CTXT, LOC, ERR_FMT, A0) \
+  JIT_BEGIN_STMT							\
+    if (!(TEST_EXPR))							\
+      {								\
+	jit_error ((CTXT), (LOC), "%s: " ERR_FMT,			\
+		   __func__, (A0));				\
+	return (RETURN_EXPR);						\
+      }								\
+  JIT_END_STMT
+
+#define RETURN_VAL_IF_FAIL_PRINTF2(TEST_EXPR, RETURN_EXPR, CTXT, LOC, ERR_FMT, A0, A1) \
+  JIT_BEGIN_STMT							\
+    if (!(TEST_EXPR))							\
+      {								\
+	jit_error ((CTXT), (LOC), "%s: " ERR_FMT,				\
+		   __func__, (A0), (A1));				\
+	return (RETURN_EXPR);						\
+      }								\
+  JIT_END_STMT
+
+#define RETURN_VAL_IF_FAIL_PRINTF3(TEST_EXPR, RETURN_EXPR, CTXT, LOC, ERR_FMT, A0, A1, A2) \
+  JIT_BEGIN_STMT							\
+    if (!(TEST_EXPR))							\
+      {								\
+	jit_error ((CTXT), (LOC), "%s: " ERR_FMT,				\
+		   __func__, (A0), (A1), (A2));			\
+	return (RETURN_EXPR);						\
+      }								\
+  JIT_END_STMT
+
+#define RETURN_VAL_IF_FAIL_PRINTF4(TEST_EXPR, RETURN_EXPR, CTXT, LOC, ERR_FMT, A0, A1, A2, A3) \
+  JIT_BEGIN_STMT							\
+    if (!(TEST_EXPR))							\
+      {								\
+	jit_error ((CTXT), (LOC), "%s: " ERR_FMT,				\
+		   __func__, (A0), (A1), (A2), (A3));			\
+	return (RETURN_EXPR);						\
+      }								\
+  JIT_END_STMT
+
+#define RETURN_VAL_IF_FAIL_PRINTF6(TEST_EXPR, RETURN_EXPR, CTXT, LOC, ERR_FMT, A0, A1, A2, A3, A4, A5) \
+  JIT_BEGIN_STMT							\
+    if (!(TEST_EXPR))							\
+      {								\
+	jit_error ((CTXT), (LOC), "%s: " ERR_FMT,				\
+		   __func__, (A0), (A1), (A2), (A3), (A4), (A5));	\
+	return (RETURN_EXPR);						\
+      }								\
+  JIT_END_STMT
+
+#define RETURN_NULL_IF_FAIL(TEST_EXPR, CTXT, LOC, ERR_MSG) \
+  RETURN_VAL_IF_FAIL ((TEST_EXPR), NULL, (CTXT), (LOC), (ERR_MSG))
+
+#define RETURN_NULL_IF_FAIL_PRINTF1(TEST_EXPR, CTXT, LOC, ERR_FMT, A0) \
+  RETURN_VAL_IF_FAIL_PRINTF1 (TEST_EXPR, NULL, CTXT, LOC, ERR_FMT, A0)
+
+#define RETURN_NULL_IF_FAIL_PRINTF2(TEST_EXPR, CTXT, LOC, ERR_FMT, A0, A1) \
+  RETURN_VAL_IF_FAIL_PRINTF2 (TEST_EXPR, NULL, CTXT, LOC, ERR_FMT, A0, A1)
+
+#define RETURN_NULL_IF_FAIL_PRINTF3(TEST_EXPR, CTXT, LOC, ERR_FMT, A0, A1, A2) \
+  RETURN_VAL_IF_FAIL_PRINTF3 (TEST_EXPR, NULL, CTXT, LOC, ERR_FMT, A0, A1, A2)
+
+#define RETURN_NULL_IF_FAIL_PRINTF4(TEST_EXPR, CTXT, LOC, ERR_FMT, A0, A1, A2, A3) \
+  RETURN_VAL_IF_FAIL_PRINTF4 (TEST_EXPR, NULL, CTXT, LOC, ERR_FMT, A0, A1, A2, A3)
+
+#define RETURN_NULL_IF_FAIL_PRINTF6(TEST_EXPR, CTXT, LOC, ERR_FMT, A0, A1, A2, A3, A4, A5) \
+  RETURN_VAL_IF_FAIL_PRINTF6 (TEST_EXPR, NULL, CTXT, LOC, ERR_FMT, A0, A1, A2, A3, A4, A5)
+
+#define RETURN_IF_FAIL(TEST_EXPR, CTXT, LOC, ERR_MSG)			\
+  JIT_BEGIN_STMT							\
+    if (!(TEST_EXPR))							\
+      {								\
+	jit_error ((CTXT), (LOC), "%s: %s", __func__, (ERR_MSG));		\
+	return;							\
+      }								\
+  JIT_END_STMT
+
+#define RETURN_IF_FAIL_PRINTF1(TEST_EXPR, CTXT, LOC, ERR_FMT, A0) \
+  JIT_BEGIN_STMT							\
+    if (!(TEST_EXPR))							\
+      {								\
+	jit_error ((CTXT), (LOC), "%s: " ERR_FMT,				\
+		   __func__, (A0));					\
+	return;							\
+      }								\
+  JIT_END_STMT
+
+#define RETURN_IF_FAIL_PRINTF2(TEST_EXPR, CTXT, LOC, ERR_FMT, A0, A1) \
+  JIT_BEGIN_STMT							\
+    if (!(TEST_EXPR))							\
+      {								\
+	jit_error ((CTXT), (LOC), "%s: " ERR_FMT,				\
+		   __func__, (A0), (A1));				\
+	return;							\
+      }								\
+  JIT_END_STMT
+
+#define RETURN_IF_FAIL_PRINTF4(TEST_EXPR, CTXT, LOC, ERR_FMT, A0, A1, A2, A3) \
+  JIT_BEGIN_STMT							\
+    if (!(TEST_EXPR))							\
+      {								\
+	jit_error ((CTXT), (LOC), "%s: " ERR_FMT,				\
+		   __func__, (A0), (A1), (A2), (A3));			\
+	return;							\
+      }								\
+  JIT_END_STMT
+
+/* Check that BLOCK is non-NULL, and that it's OK to add statements to
+   it.  */
+#define RETURN_IF_NOT_VALID_BLOCK(BLOCK, LOC)				\
+  JIT_BEGIN_STMT							\
+    RETURN_IF_FAIL ((BLOCK), NULL, (LOC), "NULL block");		\
+    RETURN_IF_FAIL_PRINTF2 (						\
+      !(BLOCK)->has_been_terminated (),				\
+      (BLOCK)->get_context (),						\
+      (LOC),								\
+      "adding to terminated block: %s (already terminated by: %s)",	\
+      (BLOCK)->get_debug_string (),					\
+      (BLOCK)->get_last_statement ()->get_debug_string ());		\
+  JIT_END_STMT
+
+#define RETURN_NULL_IF_NOT_VALID_BLOCK(BLOCK, LOC)			\
+  JIT_BEGIN_STMT							\
+    RETURN_NULL_IF_FAIL ((BLOCK), NULL, (LOC), "NULL block");		\
+    RETURN_NULL_IF_FAIL_PRINTF2 (					\
+      !(BLOCK)->has_been_terminated (),				\
+      (BLOCK)->get_context (),						\
+      (LOC),								\
+      "adding to terminated block: %s (already terminated by: %s)",	\
+      (BLOCK)->get_debug_string (),					\
+      (BLOCK)->get_last_statement ()->get_debug_string ());		\
+  JIT_END_STMT
+
+static void
+jit_error (gcc::jit::recording::context *ctxt,
+	   gcc_jit_location *loc,
+	   const char *fmt, ...)
+  GNU_PRINTF(3, 4);
+
+static void
+jit_error (gcc::jit::recording::context *ctxt,
+	   gcc_jit_location *loc,
+	   const char *fmt, ...)
+{
+  va_list ap;
+  va_start (ap, fmt);
+
+  if (ctxt)
+    ctxt->add_error_va (loc, fmt, ap);
+  else
+    {
+      /* No context?  Send to stderr.  */
+      vfprintf (stderr, fmt, ap);
+      fprintf (stderr, "\n");
+    }
+
+  va_end (ap);
+}
+
+static bool
+compatible_types (gcc::jit::recording::type *ltype,
+		  gcc::jit::recording::type *rtype)
+{
+  return ltype->accepts_writes_from (rtype);
+}
+
+gcc_jit_context *
+gcc_jit_context_acquire (void)
+{
+  return new gcc_jit_context (NULL);
+}
+
+void
+gcc_jit_context_release (gcc_jit_context *ctxt)
+{
+  delete ctxt;
+}
+
+gcc_jit_context *
+gcc_jit_context_new_child_context (gcc_jit_context *parent_ctxt)
+{
+  return new gcc_jit_context (parent_ctxt);
+}
+
+gcc_jit_location *
+gcc_jit_context_new_location (gcc_jit_context *ctxt,
+			      const char *filename,
+			      int line,
+			      int column)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+
+  return (gcc_jit_location *)ctxt->new_location (filename, line, column);
+}
+
+gcc_jit_object *
+gcc_jit_location_as_object (gcc_jit_location *loc)
+{
+  RETURN_NULL_IF_FAIL (loc, NULL, NULL, "NULL location");
+
+  return static_cast <gcc_jit_object *> (loc->as_object ());
+}
+
+gcc_jit_object *
+gcc_jit_type_as_object (gcc_jit_type *type)
+{
+  RETURN_NULL_IF_FAIL (type, NULL, NULL, "NULL type");
+
+  return static_cast <gcc_jit_object *> (type->as_object ());
+}
+
+gcc_jit_type *
+gcc_jit_context_get_type (gcc_jit_context *ctxt,
+			  enum gcc_jit_types type)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+  /* The inner function checks "type" for us.  */
+
+  return (gcc_jit_type *)ctxt->get_type (type);
+}
+
+gcc_jit_type *
+gcc_jit_context_get_int_type (gcc_jit_context *ctxt,
+			      int num_bytes, int is_signed)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+  RETURN_NULL_IF_FAIL (num_bytes >= 0, ctxt, NULL, "negative size");
+
+  return (gcc_jit_type *)ctxt->get_int_type (num_bytes, is_signed);
+}
+
+gcc_jit_type *
+gcc_jit_type_get_pointer (gcc_jit_type *type)
+{
+  RETURN_NULL_IF_FAIL (type, NULL, NULL, "NULL type");
+
+  return (gcc_jit_type *)type->get_pointer ();
+}
+
+gcc_jit_type *
+gcc_jit_type_get_const (gcc_jit_type *type)
+{
+  RETURN_NULL_IF_FAIL (type, NULL, NULL, "NULL type");
+
+  return (gcc_jit_type *)type->get_const ();
+}
+
+gcc_jit_type *
+gcc_jit_type_get_volatile (gcc_jit_type *type)
+{
+  RETURN_NULL_IF_FAIL (type, NULL, NULL, "NULL type");
+
+  return (gcc_jit_type *)type->get_volatile ();
+}
+
+gcc_jit_type *
+gcc_jit_context_new_array_type (gcc_jit_context *ctxt,
+				gcc_jit_location *loc,
+				gcc_jit_type *element_type,
+				int num_elements)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL context");
+  RETURN_NULL_IF_FAIL (element_type, ctxt, loc, "NULL type");
+
+  return (gcc_jit_type *)ctxt->new_array_type (loc,
+					       element_type,
+					       num_elements);
+}
+
+gcc_jit_field *
+gcc_jit_context_new_field (gcc_jit_context *ctxt,
+			   gcc_jit_location *loc,
+			   gcc_jit_type *type,
+			   const char *name)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+  RETURN_NULL_IF_FAIL (type, ctxt, loc, "NULL type");
+  RETURN_NULL_IF_FAIL (name, ctxt, loc, "NULL name");
+
+  return (gcc_jit_field *)ctxt->new_field (loc, type, name);
+}
+
+gcc_jit_object *
+gcc_jit_field_as_object (gcc_jit_field *field)
+{
+  RETURN_NULL_IF_FAIL (field, NULL, NULL, "NULL field");
+
+  return static_cast <gcc_jit_object *> (field->as_object ());
+}
+
+gcc_jit_struct *
+gcc_jit_context_new_struct_type (gcc_jit_context *ctxt,
+				 gcc_jit_location *loc,
+				 const char *name,
+				 int num_fields,
+				 gcc_jit_field **fields)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+  RETURN_NULL_IF_FAIL (name, ctxt, loc, "NULL name");
+  if (num_fields)
+    RETURN_NULL_IF_FAIL (fields, ctxt, loc, "NULL fields ptr");
+  for (int i = 0; i < num_fields; i++)
+    {
+      RETURN_NULL_IF_FAIL (fields[i], ctxt, loc, "NULL field ptr");
+      RETURN_NULL_IF_FAIL_PRINTF2 (
+	NULL == fields[i]->get_container (),
+	ctxt, loc,
+	"%s is already a field of %s",
+	fields[i]->get_debug_string (),
+	fields[i]->get_container ()->get_debug_string ());
+    }
+
+  gcc::jit::recording::struct_ *result =
+    ctxt->new_struct_type (loc, name);
+  result->set_fields (loc,
+		      num_fields,
+		      (gcc::jit::recording::field **)fields);
+  return static_cast<gcc_jit_struct *> (result);
+}
+
+gcc_jit_struct *
+gcc_jit_context_new_opaque_struct (gcc_jit_context *ctxt,
+				   gcc_jit_location *loc,
+				   const char *name)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL context");
+  RETURN_NULL_IF_FAIL (name, ctxt, loc, "NULL name");
+
+  return (gcc_jit_struct *)ctxt->new_struct_type (loc, name);
+}
+
+gcc_jit_type *
+gcc_jit_struct_as_type (gcc_jit_struct *struct_type)
+{
+  RETURN_NULL_IF_FAIL (struct_type, NULL, NULL, "NULL struct_type");
+
+  return static_cast <gcc_jit_type *> (struct_type->as_type ());
+}
+
+void
+gcc_jit_struct_set_fields (gcc_jit_struct *struct_type,
+			   gcc_jit_location *loc,
+			   int num_fields,
+			   gcc_jit_field **fields)
+{
+  RETURN_IF_FAIL (struct_type, NULL, loc, "NULL struct_type");
+  gcc::jit::recording::context *ctxt = struct_type->m_ctxt;
+  RETURN_IF_FAIL_PRINTF1 (
+    NULL == struct_type->get_fields (), ctxt, loc,
+    "%s already has had fields set",
+    struct_type->get_debug_string ());
+  if (num_fields)
+    RETURN_IF_FAIL (fields, ctxt, loc, "NULL fields ptr");
+  for (int i = 0; i < num_fields; i++)
+    {
+      RETURN_IF_FAIL (fields[i], ctxt, loc, "NULL field ptr");
+      RETURN_IF_FAIL_PRINTF2 (
+	NULL == fields[i]->get_container (),
+	ctxt, loc,
+	"%s is already a field of %s",
+	fields[i]->get_debug_string (),
+	fields[i]->get_container ()->get_debug_string ());
+    }
+
+  struct_type->set_fields (loc, num_fields,
+			   (gcc::jit::recording::field **)fields);
+}
+
+gcc_jit_type *
+gcc_jit_context_new_union_type (gcc_jit_context *ctxt,
+				gcc_jit_location *loc,
+				const char *name,
+				int num_fields,
+				gcc_jit_field **fields)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+  RETURN_NULL_IF_FAIL (name, ctxt, loc, "NULL name");
+  if (num_fields)
+    RETURN_NULL_IF_FAIL (fields, ctxt, loc, "NULL fields ptr");
+  for (int i = 0; i < num_fields; i++)
+    {
+      RETURN_NULL_IF_FAIL (fields[i], ctxt, loc, "NULL field ptr");
+      RETURN_NULL_IF_FAIL_PRINTF2 (
+	NULL == fields[i]->get_container (),
+	ctxt, loc,
+	"%s is already a field of %s",
+	fields[i]->get_debug_string (),
+	fields[i]->get_container ()->get_debug_string ());
+    }
+
+  gcc::jit::recording::union_ *result =
+    ctxt->new_union_type (loc, name);
+  result->set_fields (loc,
+		      num_fields,
+		      (gcc::jit::recording::field **)fields);
+  return (gcc_jit_type *) (result);
+}
+
+gcc_jit_type *
+gcc_jit_context_new_function_ptr_type (gcc_jit_context *ctxt,
+				       gcc_jit_location *loc,
+				       gcc_jit_type *return_type,
+				       int num_params,
+				       gcc_jit_type **param_types,
+				       int is_variadic)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL context");
+  RETURN_NULL_IF_FAIL (return_type, ctxt, loc, "NULL return_type");
+  RETURN_NULL_IF_FAIL (
+    (num_params == 0) || param_types,
+    ctxt, loc,
+    "NULL param_types creating function pointer type");
+  for (int i = 0; i < num_params; i++)
+    RETURN_NULL_IF_FAIL_PRINTF1 (
+      param_types[i],
+      ctxt, loc,
+      "NULL parameter type %i creating function pointer type", i);
+
+  return (gcc_jit_type*)
+    ctxt->new_function_ptr_type (loc, return_type,
+				 num_params,
+				 (gcc::jit::recording::type **)param_types,
+				 is_variadic);
+}
+
+/* Constructing functions.  */
+gcc_jit_param *
+gcc_jit_context_new_param (gcc_jit_context *ctxt,
+			   gcc_jit_location *loc,
+			   gcc_jit_type *type,
+			   const char *name)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL context");
+  RETURN_NULL_IF_FAIL (type, ctxt, loc, "NULL type");
+  RETURN_NULL_IF_FAIL (name, ctxt, loc, "NULL name");
+
+  return (gcc_jit_param *)ctxt->new_param (loc, type, name);
+}
+
+gcc_jit_object *
+gcc_jit_param_as_object (gcc_jit_param *param)
+{
+  RETURN_NULL_IF_FAIL (param, NULL, NULL, "NULL param");
+
+  return static_cast <gcc_jit_object *> (param->as_object ());
+}
+
+gcc_jit_lvalue *
+gcc_jit_param_as_lvalue (gcc_jit_param *param)
+{
+  RETURN_NULL_IF_FAIL (param, NULL, NULL, "NULL param");
+
+  return (gcc_jit_lvalue *)param->as_lvalue ();
+}
+
+gcc_jit_rvalue *
+gcc_jit_param_as_rvalue (gcc_jit_param *param)
+{
+  RETURN_NULL_IF_FAIL (param, NULL, NULL, "NULL param");
+
+  return (gcc_jit_rvalue *)param->as_rvalue ();
+}
+
+gcc_jit_function *
+gcc_jit_context_new_function (gcc_jit_context *ctxt,
+			      gcc_jit_location *loc,
+			      enum gcc_jit_function_kind kind,
+			      gcc_jit_type *return_type,
+			      const char *name,
+			      int num_params,
+			      gcc_jit_param **params,
+			      int is_variadic)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL context");
+  RETURN_NULL_IF_FAIL (return_type, ctxt, loc, "NULL return_type");
+  RETURN_NULL_IF_FAIL (name, ctxt, loc, "NULL name");
+  /* The assembler can only handle certain names, so for now, enforce
+     C's rules for identiers upon the name.
+     Eventually we'll need some way to interact with e.g. C++ name mangling.  */
+  {
+    /* Leading char: */
+    char ch = *name;
+    RETURN_NULL_IF_FAIL_PRINTF2 (
+	IS_ASCII_ALPHA (ch) || ch == '_',
+	ctxt, loc,
+	"name \"%s\" contains invalid character: '%c'",
+	name, ch);
+    /* Subsequent chars: */
+    for (const char *ptr = name + 1; (ch = *ptr); ptr++)
+      {
+	RETURN_NULL_IF_FAIL_PRINTF2 (
+	  IS_ASCII_ALNUM (ch) || ch == '_',
+	  ctxt, loc,
+	  "name \"%s\" contains invalid character: '%c'",
+	  name, ch);
+      }
+  }
+  RETURN_NULL_IF_FAIL_PRINTF1 (
+    (num_params == 0) || params,
+    ctxt, loc,
+    "NULL params creating function %s", name);
+  for (int i = 0; i < num_params; i++)
+    RETURN_NULL_IF_FAIL_PRINTF2 (
+      params[i],
+      ctxt, loc,
+      "NULL parameter %i creating function %s", i, name);
+
+  return (gcc_jit_function*)
+    ctxt->new_function (loc, kind, return_type, name,
+			num_params,
+			(gcc::jit::recording::param **)params,
+			is_variadic,
+			BUILT_IN_NONE);
+}
+
+gcc_jit_function *
+gcc_jit_context_get_builtin_function (gcc_jit_context *ctxt,
+				      const char *name)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+  RETURN_NULL_IF_FAIL (name, ctxt, NULL, "NULL name");
+
+  return static_cast <gcc_jit_function *> (ctxt->get_builtin_function (name));
+}
+
+gcc_jit_object *
+gcc_jit_function_as_object (gcc_jit_function *func)
+{
+  RETURN_NULL_IF_FAIL (func, NULL, NULL, "NULL function");
+
+  return static_cast <gcc_jit_object *> (func->as_object ());
+}
+
+gcc_jit_param *
+gcc_jit_function_get_param (gcc_jit_function *func, int index)
+{
+  RETURN_NULL_IF_FAIL (func, NULL, NULL, "NULL function");
+  gcc::jit::recording::context *ctxt = func->m_ctxt;
+  RETURN_NULL_IF_FAIL (index >= 0, ctxt, NULL, "negative index");
+  int num_params = func->get_params ().length ();
+  RETURN_NULL_IF_FAIL_PRINTF3 (index < num_params,
+			       ctxt, NULL,
+			       "index of %d is too large (%s has %d params)",
+			       index,
+			       func->get_debug_string (),
+			       num_params);
+
+  return static_cast <gcc_jit_param *> (func->get_param (index));
+}
+
+void
+gcc_jit_function_dump_to_dot (gcc_jit_function *func,
+			      const char *path)
+{
+  RETURN_IF_FAIL (func, NULL, NULL, "NULL function");
+  gcc::jit::recording::context *ctxt = func->m_ctxt;
+  RETURN_IF_FAIL (path, ctxt, NULL, "NULL path");
+
+  func->dump_to_dot (path);
+}
+
+gcc_jit_block*
+gcc_jit_function_new_block (gcc_jit_function *func,
+			    const char *name)
+{
+  RETURN_NULL_IF_FAIL (func, NULL, NULL, "NULL function");
+  RETURN_NULL_IF_FAIL (func->get_kind () != GCC_JIT_FUNCTION_IMPORTED,
+		       func->get_context (), NULL,
+		       "cannot add block to an imported function");
+  /* name can be NULL.  */
+
+  return (gcc_jit_block *)func->new_block (name);
+}
+
+gcc_jit_object *
+gcc_jit_block_as_object (gcc_jit_block *block)
+{
+  RETURN_NULL_IF_FAIL (block, NULL, NULL, "NULL block");
+
+  return static_cast <gcc_jit_object *> (block->as_object ());
+}
+
+gcc_jit_function *
+gcc_jit_block_get_function (gcc_jit_block *block)
+{
+  RETURN_NULL_IF_FAIL (block, NULL, NULL, "NULL block");
+
+  return static_cast <gcc_jit_function *> (block->get_function ());
+}
+
+gcc_jit_lvalue *
+gcc_jit_context_new_global (gcc_jit_context *ctxt,
+			    gcc_jit_location *loc,
+			    gcc_jit_type *type,
+			    const char *name)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL context");
+  RETURN_NULL_IF_FAIL (type, ctxt, loc, "NULL type");
+  RETURN_NULL_IF_FAIL (name, ctxt, loc, "NULL name");
+
+  return (gcc_jit_lvalue *)ctxt->new_global (loc, type, name);
+}
+
+gcc_jit_object *
+gcc_jit_lvalue_as_object (gcc_jit_lvalue *lvalue)
+{
+  RETURN_NULL_IF_FAIL (lvalue, NULL, NULL, "NULL lvalue");
+
+  return static_cast <gcc_jit_object *> (lvalue->as_object ());
+}
+
+gcc_jit_rvalue *
+gcc_jit_lvalue_as_rvalue (gcc_jit_lvalue *lvalue)
+{
+  RETURN_NULL_IF_FAIL (lvalue, NULL, NULL, "NULL lvalue");
+
+  return (gcc_jit_rvalue *)lvalue->as_rvalue ();
+}
+
+gcc_jit_object *
+gcc_jit_rvalue_as_object (gcc_jit_rvalue *rvalue)
+{
+  RETURN_NULL_IF_FAIL (rvalue, NULL, NULL, "NULL rvalue");
+
+  return static_cast <gcc_jit_object *> (rvalue->as_object ());
+}
+
+gcc_jit_type *
+gcc_jit_rvalue_get_type (gcc_jit_rvalue *rvalue)
+{
+  RETURN_NULL_IF_FAIL (rvalue, NULL, NULL, "NULL rvalue");
+
+  return static_cast <gcc_jit_type *> (rvalue->get_type ());
+}
+
+#define RETURN_NULL_IF_FAIL_NONNULL_NUMERIC_TYPE(CTXT, NUMERIC_TYPE) \
+  RETURN_NULL_IF_FAIL (NUMERIC_TYPE, CTXT, NULL, "NULL type"); \
+  RETURN_NULL_IF_FAIL_PRINTF1 (                                \
+    NUMERIC_TYPE->is_numeric (), ctxt, NULL,                   \
+    "not a numeric type: %s",                                  \
+    NUMERIC_TYPE->get_debug_string ());
+
+gcc_jit_rvalue *
+gcc_jit_context_new_rvalue_from_int (gcc_jit_context *ctxt,
+				     gcc_jit_type *numeric_type,
+				     int value)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+  RETURN_NULL_IF_FAIL_NONNULL_NUMERIC_TYPE (ctxt, numeric_type);
+
+  return (gcc_jit_rvalue *)ctxt->new_rvalue_from_int (numeric_type, value);
+}
+
+gcc_jit_rvalue *
+gcc_jit_context_zero (gcc_jit_context *ctxt,
+		      gcc_jit_type *numeric_type)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+  RETURN_NULL_IF_FAIL_NONNULL_NUMERIC_TYPE (ctxt, numeric_type);
+
+  return gcc_jit_context_new_rvalue_from_int (ctxt, numeric_type, 0);
+}
+
+gcc_jit_rvalue *
+gcc_jit_context_one (gcc_jit_context *ctxt,
+		     gcc_jit_type *numeric_type)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+  RETURN_NULL_IF_FAIL_NONNULL_NUMERIC_TYPE (ctxt, numeric_type);
+
+  return gcc_jit_context_new_rvalue_from_int (ctxt, numeric_type, 1);
+}
+
+gcc_jit_rvalue *
+gcc_jit_context_new_rvalue_from_double (gcc_jit_context *ctxt,
+					gcc_jit_type *numeric_type,
+					double value)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+  RETURN_NULL_IF_FAIL_NONNULL_NUMERIC_TYPE (ctxt, numeric_type);
+
+  return (gcc_jit_rvalue *)ctxt->new_rvalue_from_double (numeric_type, value);
+}
+
+gcc_jit_rvalue *
+gcc_jit_context_new_rvalue_from_ptr (gcc_jit_context *ctxt,
+				     gcc_jit_type *pointer_type,
+				     void *value)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+  RETURN_NULL_IF_FAIL (pointer_type, ctxt, NULL, "NULL type");
+  RETURN_NULL_IF_FAIL_PRINTF1 (
+    pointer_type->is_pointer (),
+    ctxt, NULL,
+    "not a pointer type (type: %s)",
+    pointer_type->get_debug_string ());
+
+  return (gcc_jit_rvalue *)ctxt->new_rvalue_from_ptr (pointer_type, value);
+}
+
+gcc_jit_rvalue *
+gcc_jit_context_null (gcc_jit_context *ctxt,
+		      gcc_jit_type *pointer_type)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+  RETURN_NULL_IF_FAIL (pointer_type, ctxt, NULL, "NULL type");
+  RETURN_NULL_IF_FAIL_PRINTF1 (
+    pointer_type->is_pointer (),
+    ctxt, NULL,
+    "not a pointer type (type: %s)",
+    pointer_type->get_debug_string ());
+
+  return gcc_jit_context_new_rvalue_from_ptr (ctxt, pointer_type, NULL);
+}
+
+gcc_jit_rvalue *
+gcc_jit_context_new_string_literal (gcc_jit_context *ctxt,
+				    const char *value)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+  RETURN_NULL_IF_FAIL (value, ctxt, NULL, "NULL value");
+
+  return (gcc_jit_rvalue *)ctxt->new_string_literal (value);
+}
+
+gcc_jit_rvalue *
+gcc_jit_context_new_unary_op (gcc_jit_context *ctxt,
+			      gcc_jit_location *loc,
+			      enum gcc_jit_unary_op op,
+			      gcc_jit_type *result_type,
+			      gcc_jit_rvalue *rvalue)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL context");
+  /* op is checked by the inner function.  */
+  RETURN_NULL_IF_FAIL (result_type, ctxt, loc, "NULL result_type");
+  RETURN_NULL_IF_FAIL (rvalue, ctxt, loc, "NULL rvalue");
+
+  return (gcc_jit_rvalue *)ctxt->new_unary_op (loc, op, result_type, rvalue);
+}
+
+gcc_jit_rvalue *
+gcc_jit_context_new_binary_op (gcc_jit_context *ctxt,
+			       gcc_jit_location *loc,
+			       enum gcc_jit_binary_op op,
+			       gcc_jit_type *result_type,
+			       gcc_jit_rvalue *a, gcc_jit_rvalue *b)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL context");
+  /* op is checked by the inner function.  */
+  RETURN_NULL_IF_FAIL (result_type, ctxt, loc, "NULL result_type");
+  RETURN_NULL_IF_FAIL (a, ctxt, loc, "NULL a");
+  RETURN_NULL_IF_FAIL (b, ctxt, loc, "NULL b");
+  RETURN_NULL_IF_FAIL_PRINTF4 (
+    a->get_type () == b->get_type (),
+    ctxt, loc,
+    "mismatching types for binary op:"
+    " a: %s (type: %s) b: %s (type: %s)",
+    a->get_debug_string (),
+    a->get_type ()->get_debug_string (),
+    b->get_debug_string (),
+    b->get_type ()->get_debug_string ());
+
+  return (gcc_jit_rvalue *)ctxt->new_binary_op (loc, op, result_type, a, b);
+}
+
+gcc_jit_rvalue *
+gcc_jit_context_new_comparison (gcc_jit_context *ctxt,
+				gcc_jit_location *loc,
+				enum gcc_jit_comparison op,
+				gcc_jit_rvalue *a, gcc_jit_rvalue *b)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL context");
+  /* op is checked by the inner function.  */
+  RETURN_NULL_IF_FAIL (a, ctxt, loc, "NULL a");
+  RETURN_NULL_IF_FAIL (b, ctxt, loc, "NULL b");
+  RETURN_NULL_IF_FAIL_PRINTF4 (
+    a->get_type ()->unqualified () == b->get_type ()->unqualified (),
+    ctxt, loc,
+    "mismatching types for comparison:"
+    " a: %s (type: %s) b: %s (type: %s)",
+    a->get_debug_string (),
+    a->get_type ()->get_debug_string (),
+    b->get_debug_string (),
+    b->get_type ()->get_debug_string ());
+
+  return (gcc_jit_rvalue *)ctxt->new_comparison (loc, op, a, b);
+}
+
+gcc_jit_rvalue *
+gcc_jit_context_new_call (gcc_jit_context *ctxt,
+			  gcc_jit_location *loc,
+			  gcc_jit_function *func,
+			  int numargs , gcc_jit_rvalue **args)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL context");
+  RETURN_NULL_IF_FAIL (func, ctxt, loc, "NULL function");
+  if (numargs)
+    RETURN_NULL_IF_FAIL (args, ctxt, loc, "NULL args");
+
+  int min_num_params = func->get_params ().length ();
+  bool is_variadic = func->is_variadic ();
+
+  RETURN_NULL_IF_FAIL_PRINTF3 (
+    numargs >= min_num_params,
+    ctxt, loc,
+    "not enough arguments to function \"%s\""
+    " (got %i args, expected %i)",
+    func->get_name ()->c_str (),
+    numargs, min_num_params);
+
+  RETURN_NULL_IF_FAIL_PRINTF3 (
+    (numargs == min_num_params || is_variadic),
+    ctxt, loc,
+    "too many arguments to function \"%s\""
+    " (got %i args, expected %i)",
+    func->get_name ()->c_str (),
+    numargs, min_num_params);
+
+  for (int i = 0; i < min_num_params; i++)
+    {
+      gcc::jit::recording::param *param = func->get_param (i);
+      gcc_jit_rvalue *arg = args[i];
+
+      RETURN_NULL_IF_FAIL_PRINTF4 (
+	arg,
+	ctxt, loc,
+	"NULL argument %i to function \"%s\":"
+	" param %s (type: %s)",
+	i + 1,
+	func->get_name ()->c_str (),
+	param->get_debug_string (),
+	param->get_type ()->get_debug_string ());
+
+      RETURN_NULL_IF_FAIL_PRINTF6 (
+	compatible_types (param->get_type (),
+			  arg->get_type ()),
+	ctxt, loc,
+	"mismatching types for argument %d of function \"%s\":"
+	" assignment to param %s (type: %s) from %s (type: %s)",
+	i + 1,
+	func->get_name ()->c_str (),
+	param->get_debug_string (),
+	param->get_type ()->get_debug_string (),
+	arg->get_debug_string (),
+	arg->get_type ()->get_debug_string ());
+    }
+
+  return (gcc_jit_rvalue *)ctxt->new_call (loc,
+					   func,
+					   numargs,
+					   (gcc::jit::recording::rvalue **)args);
+}
+
+gcc_jit_rvalue *
+gcc_jit_context_new_call_through_ptr (gcc_jit_context *ctxt,
+				      gcc_jit_location *loc,
+				      gcc_jit_rvalue *fn_ptr,
+				      int numargs, gcc_jit_rvalue **args)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL context");
+  RETURN_NULL_IF_FAIL (fn_ptr, ctxt, loc, "NULL fn_ptr");
+  if (numargs)
+    RETURN_NULL_IF_FAIL (args, ctxt, loc, "NULL args");
+
+  gcc::jit::recording::type *ptr_type = fn_ptr->get_type ()->dereference ();
+  RETURN_NULL_IF_FAIL_PRINTF2 (
+    ptr_type, ctxt, loc,
+    "fn_ptr is not a ptr: %s"
+    " type: %s",
+    fn_ptr->get_debug_string (),
+    fn_ptr->get_type ()->get_debug_string ());
+
+  gcc::jit::recording::function_type *fn_type =
+    ptr_type->dyn_cast_function_type();
+  RETURN_NULL_IF_FAIL_PRINTF2 (
+    fn_type, ctxt, loc,
+    "fn_ptr is not a function ptr: %s"
+    " type: %s",
+    fn_ptr->get_debug_string (),
+    fn_ptr->get_type ()->get_debug_string ());
+
+  int min_num_params = fn_type->get_param_types ().length ();
+  bool is_variadic = fn_type->is_variadic ();
+
+  RETURN_NULL_IF_FAIL_PRINTF3 (
+    numargs >= min_num_params,
+    ctxt, loc,
+    "not enough arguments to fn_ptr: %s"
+    " (got %i args, expected %i)",
+    fn_ptr->get_debug_string (),
+    numargs, min_num_params);
+
+  RETURN_NULL_IF_FAIL_PRINTF3 (
+    (numargs == min_num_params || is_variadic),
+    ctxt, loc,
+    "too many arguments to fn_ptr: %s"
+    " (got %i args, expected %i)",
+    fn_ptr->get_debug_string (),
+    numargs, min_num_params);
+
+  for (int i = 0; i < min_num_params; i++)
+    {
+      gcc::jit::recording::type *param_type = fn_type->get_param_types ()[i];
+      gcc_jit_rvalue *arg = args[i];
+
+      RETURN_NULL_IF_FAIL_PRINTF3 (
+	arg,
+	ctxt, loc,
+	"NULL argument %i to fn_ptr: %s"
+	" (type: %s)",
+	i + 1,
+	fn_ptr->get_debug_string (),
+	param_type->get_debug_string ());
+
+      RETURN_NULL_IF_FAIL_PRINTF6 (
+	compatible_types (param_type,
+			  arg->get_type ()),
+	ctxt, loc,
+	"mismatching types for argument %d of fn_ptr: %s:"
+	" assignment to param %d (type: %s) from %s (type: %s)",
+	i + 1,
+	fn_ptr->get_debug_string (),
+	i + 1,
+	param_type->get_debug_string (),
+	arg->get_debug_string (),
+	arg->get_type ()->get_debug_string ());
+    }
+
+  return (gcc_jit_rvalue *)(
+	    ctxt->new_call_through_ptr (loc,
+					fn_ptr,
+					numargs,
+					(gcc::jit::recording::rvalue **)args));
+}
+
+static bool
+is_valid_cast (gcc::jit::recording::type *src_type,
+	       gcc_jit_type *dst_type)
+{
+  bool src_is_int = src_type->is_int ();
+  bool dst_is_int = dst_type->is_int ();
+  bool src_is_float = src_type->is_float ();
+  bool dst_is_float = dst_type->is_float ();
+  bool src_is_bool = src_type->is_bool ();
+  bool dst_is_bool = dst_type->is_bool ();
+
+  if (src_is_int)
+    if (dst_is_int || dst_is_float || dst_is_bool)
+      return true;
+
+  if (src_is_float)
+    if (dst_is_int || dst_is_float)
+      return true;
+
+  if (src_is_bool)
+    if (dst_is_int || dst_is_bool)
+      return true;
+
+  /* Permit casts between pointer types.  */
+  gcc::jit::recording::type *deref_src_type = src_type->is_pointer ();
+  gcc::jit::recording::type *deref_dst_type = dst_type->is_pointer ();
+  if (deref_src_type && deref_dst_type)
+    return true;
+
+  return false;
+}
+
+gcc_jit_rvalue *
+gcc_jit_context_new_cast (gcc_jit_context *ctxt,
+			  gcc_jit_location *loc,
+			  gcc_jit_rvalue *rvalue,
+			  gcc_jit_type *type)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL context");
+  RETURN_NULL_IF_FAIL (rvalue, ctxt, loc, "NULL rvalue");
+  RETURN_NULL_IF_FAIL (type, ctxt, loc, "NULL type");
+  RETURN_NULL_IF_FAIL_PRINTF3 (
+    is_valid_cast (rvalue->get_type (), type),
+    ctxt, loc,
+    "cannot cast %s from type: %s to type: %s",
+    rvalue->get_debug_string (),
+    rvalue->get_type ()->get_debug_string (),
+    type->get_debug_string ());
+
+  return static_cast <gcc_jit_rvalue *> (ctxt->new_cast (loc, rvalue, type));
+}
+
+extern gcc_jit_lvalue *
+gcc_jit_context_new_array_access (gcc_jit_context *ctxt,
+				  gcc_jit_location *loc,
+				  gcc_jit_rvalue *ptr,
+				  gcc_jit_rvalue *index)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL context");
+  RETURN_NULL_IF_FAIL (ptr, ctxt, loc, "NULL ptr");
+  RETURN_NULL_IF_FAIL (index, ctxt, loc, "NULL index");
+  RETURN_NULL_IF_FAIL_PRINTF2 (
+    ptr->get_type ()->dereference (),
+    ctxt, loc,
+    "ptr: %s (type: %s) is not a pointer or array",
+    ptr->get_debug_string (),
+    ptr->get_type ()->get_debug_string ());
+  RETURN_NULL_IF_FAIL_PRINTF2 (
+    index->get_type ()->is_numeric (),
+    ctxt, loc,
+    "index: %s (type: %s) is not of numeric type",
+    index->get_debug_string (),
+    index->get_type ()->get_debug_string ());
+
+  return (gcc_jit_lvalue *)ctxt->new_array_access (loc, ptr, index);
+}
+
+gcc_jit_context *
+gcc_jit_object_get_context (gcc_jit_object *obj)
+{
+  RETURN_NULL_IF_FAIL (obj, NULL, NULL, "NULL object");
+
+  return static_cast <gcc_jit_context *> (obj->get_context ());
+}
+
+const char *
+gcc_jit_object_get_debug_string (gcc_jit_object *obj)
+{
+  RETURN_NULL_IF_FAIL (obj, NULL, NULL, "NULL object");
+
+  return obj->get_debug_string ();
+}
+
+gcc_jit_lvalue *
+gcc_jit_lvalue_access_field (gcc_jit_lvalue *struct_,
+			     gcc_jit_location *loc,
+			     gcc_jit_field *field)
+{
+  RETURN_NULL_IF_FAIL (struct_, NULL, loc, "NULL struct");
+  gcc::jit::recording::context *ctxt = struct_->m_ctxt;
+  RETURN_NULL_IF_FAIL (field, ctxt, loc, "NULL field");
+  RETURN_NULL_IF_FAIL_PRINTF1 (field->get_container (), field->m_ctxt, loc,
+			       "field %s has not been placed in a struct",
+			       field->get_debug_string ());
+
+  return (gcc_jit_lvalue *)struct_->access_field (loc, field);
+}
+
+gcc_jit_rvalue *
+gcc_jit_rvalue_access_field (gcc_jit_rvalue *struct_,
+			     gcc_jit_location *loc,
+			     gcc_jit_field *field)
+{
+  RETURN_NULL_IF_FAIL (struct_, NULL, loc, "NULL struct");
+  gcc::jit::recording::context *ctxt = struct_->m_ctxt;
+  RETURN_NULL_IF_FAIL (field, ctxt, loc, "NULL field");
+  RETURN_NULL_IF_FAIL_PRINTF1 (field->get_container (), field->m_ctxt, loc,
+			       "field %s has not been placed in a struct",
+			       field->get_debug_string ());
+
+  return (gcc_jit_rvalue *)struct_->access_field (loc, field);
+}
+
+gcc_jit_lvalue *
+gcc_jit_rvalue_dereference_field (gcc_jit_rvalue *ptr,
+				  gcc_jit_location *loc,
+				  gcc_jit_field *field)
+{
+  RETURN_NULL_IF_FAIL (ptr, NULL, loc, "NULL ptr");
+  RETURN_NULL_IF_FAIL (field, NULL, loc, "NULL field");
+  gcc::jit::recording::type *underlying_type =
+    ptr->get_type ()->is_pointer ();
+  RETURN_NULL_IF_FAIL_PRINTF1 (field->get_container (), field->m_ctxt, loc,
+			       "field %s has not been placed in a struct",
+			       field->get_debug_string ());
+  RETURN_NULL_IF_FAIL_PRINTF3 (
+    underlying_type,
+    ptr->m_ctxt, loc,
+    "dereference of non-pointer %s (type: %s) when accessing ->%s",
+    ptr->get_debug_string (),
+    ptr->get_type ()->get_debug_string (),
+    field->get_debug_string ());
+  RETURN_NULL_IF_FAIL_PRINTF2 (
+    (field->get_container ()->unqualified ()
+     == underlying_type->unqualified ()),
+    ptr->m_ctxt, loc,
+    "%s is not a field of %s",
+    field->get_debug_string (),
+    underlying_type->get_debug_string ());
+
+  return (gcc_jit_lvalue *)ptr->dereference_field (loc, field);
+}
+
+gcc_jit_lvalue *
+gcc_jit_rvalue_dereference (gcc_jit_rvalue *rvalue,
+			    gcc_jit_location *loc)
+{
+  RETURN_NULL_IF_FAIL (rvalue, NULL, loc, "NULL rvalue");
+
+  gcc::jit::recording::type *underlying_type =
+    rvalue->get_type ()->is_pointer ();
+
+  RETURN_NULL_IF_FAIL_PRINTF2 (
+    underlying_type,
+    rvalue->m_ctxt, loc,
+    "dereference of non-pointer %s (type: %s)",
+    rvalue->get_debug_string (),
+    rvalue->get_type ()->get_debug_string ());
+
+  return (gcc_jit_lvalue *)rvalue->dereference (loc);
+}
+
+gcc_jit_rvalue *
+gcc_jit_lvalue_get_address (gcc_jit_lvalue *lvalue,
+			    gcc_jit_location *loc)
+{
+  RETURN_NULL_IF_FAIL (lvalue, NULL, loc, "NULL lvalue");
+
+  return (gcc_jit_rvalue *)lvalue->get_address (loc);
+}
+
+gcc_jit_lvalue *
+gcc_jit_function_new_local (gcc_jit_function *func,
+			    gcc_jit_location *loc,
+			    gcc_jit_type *type,
+			    const char *name)
+{
+  RETURN_NULL_IF_FAIL (func, NULL, loc, "NULL function");
+  gcc::jit::recording::context *ctxt = func->m_ctxt;
+  RETURN_NULL_IF_FAIL (func->get_kind () != GCC_JIT_FUNCTION_IMPORTED,
+		       ctxt, loc,
+		       "Cannot add locals to an imported function");
+  RETURN_NULL_IF_FAIL (type, ctxt, loc, "NULL type");
+  RETURN_NULL_IF_FAIL (name, ctxt, loc, "NULL name");
+
+  return (gcc_jit_lvalue *)func->new_local (loc, type, name);
+}
+
+void
+gcc_jit_block_add_eval (gcc_jit_block *block,
+			gcc_jit_location *loc,
+			gcc_jit_rvalue *rvalue)
+{
+  RETURN_IF_NOT_VALID_BLOCK (block, loc);
+  gcc::jit::recording::context *ctxt = block->get_context ();
+  RETURN_IF_FAIL (rvalue, ctxt, loc, "NULL rvalue");
+
+  return block->add_eval (loc, rvalue);
+}
+
+void
+gcc_jit_block_add_assignment (gcc_jit_block *block,
+			      gcc_jit_location *loc,
+			      gcc_jit_lvalue *lvalue,
+			      gcc_jit_rvalue *rvalue)
+{
+  RETURN_IF_NOT_VALID_BLOCK (block, loc);
+  gcc::jit::recording::context *ctxt = block->get_context ();
+  RETURN_IF_FAIL (lvalue, ctxt, loc, "NULL lvalue");
+  RETURN_IF_FAIL (rvalue, ctxt, loc, "NULL rvalue");
+  RETURN_IF_FAIL_PRINTF4 (
+    compatible_types (lvalue->get_type (),
+		      rvalue->get_type ()),
+    ctxt, loc,
+    "mismatching types:"
+    " assignment to %s (type: %s) from %s (type: %s)",
+    lvalue->get_debug_string (),
+    lvalue->get_type ()->get_debug_string (),
+    rvalue->get_debug_string (),
+    rvalue->get_type ()->get_debug_string ());
+
+  return block->add_assignment (loc, lvalue, rvalue);
+}
+
+void
+gcc_jit_block_add_assignment_op (gcc_jit_block *block,
+				 gcc_jit_location *loc,
+				 gcc_jit_lvalue *lvalue,
+				 enum gcc_jit_binary_op op,
+				 gcc_jit_rvalue *rvalue)
+{
+  RETURN_IF_NOT_VALID_BLOCK (block, loc);
+  gcc::jit::recording::context *ctxt = block->get_context ();
+  RETURN_IF_FAIL (lvalue, ctxt, loc, "NULL lvalue");
+  /* FIXME: op is checked by new_binary_op */
+  RETURN_IF_FAIL (rvalue, ctxt, loc, "NULL rvalue");
+
+  return block->add_assignment_op (loc, lvalue, op, rvalue);
+}
+
+static bool
+is_bool (gcc_jit_rvalue *boolval)
+{
+  gcc::jit::recording::type *actual_type = boolval->get_type ();
+  gcc::jit::recording::type *bool_type =
+    boolval->m_ctxt->get_type (GCC_JIT_TYPE_BOOL);
+  return actual_type == bool_type;
+}
+
+void
+gcc_jit_block_end_with_conditional (gcc_jit_block *block,
+				    gcc_jit_location *loc,
+				    gcc_jit_rvalue *boolval,
+				    gcc_jit_block *on_true,
+				    gcc_jit_block *on_false)
+{
+  RETURN_IF_NOT_VALID_BLOCK (block, loc);
+  gcc::jit::recording::context *ctxt = block->get_context ();
+  RETURN_IF_FAIL (boolval, ctxt, loc, "NULL boolval");
+  RETURN_IF_FAIL_PRINTF2 (
+   is_bool (boolval), ctxt, loc,
+   "%s (type: %s) is not of boolean type ",
+   boolval->get_debug_string (),
+   boolval->get_type ()->get_debug_string ());
+  RETURN_IF_FAIL (on_true, ctxt, loc, "NULL on_true");
+  RETURN_IF_FAIL (on_true, ctxt, loc, "NULL on_false");
+  RETURN_IF_FAIL_PRINTF4 (
+    block->get_function () == on_true->get_function (),
+    ctxt, loc,
+    "\"on_true\" block is not in same function:"
+    " source block %s is in function %s"
+    " whereas target block %s is in function %s",
+    block->get_debug_string (),
+    block->get_function ()->get_debug_string (),
+    on_true->get_debug_string (),
+    on_true->get_function ()->get_debug_string ());
+  RETURN_IF_FAIL_PRINTF4 (
+    block->get_function () == on_false->get_function (),
+    ctxt, loc,
+    "\"on_false\" block is not in same function:"
+    " source block %s is in function %s"
+    " whereas target block %s is in function %s",
+    block->get_debug_string (),
+    block->get_function ()->get_debug_string (),
+    on_false->get_debug_string (),
+    on_false->get_function ()->get_debug_string ());
+
+  return block->end_with_conditional (loc, boolval, on_true, on_false);
+}
+
+void
+gcc_jit_block_add_comment (gcc_jit_block *block,
+			   gcc_jit_location *loc,
+			   const char *text)
+{
+  RETURN_IF_NOT_VALID_BLOCK (block, loc);
+  gcc::jit::recording::context *ctxt = block->get_context ();
+  RETURN_IF_FAIL (text, ctxt, loc, "NULL text");
+
+  block->add_comment (loc, text);
+}
+
+void
+gcc_jit_block_end_with_jump (gcc_jit_block *block,
+			     gcc_jit_location *loc,
+			     gcc_jit_block *target)
+{
+  RETURN_IF_NOT_VALID_BLOCK (block, loc);
+  gcc::jit::recording::context *ctxt = block->get_context ();
+  RETURN_IF_FAIL (target, ctxt, loc, "NULL target");
+  RETURN_IF_FAIL_PRINTF4 (
+    block->get_function () == target->get_function (),
+    ctxt, loc,
+    "target block is not in same function:"
+    " source block %s is in function %s"
+    " whereas target block %s is in function %s",
+    block->get_debug_string (),
+    block->get_function ()->get_debug_string (),
+    target->get_debug_string (),
+    target->get_function ()->get_debug_string ());
+
+  block->end_with_jump (loc, target);
+}
+
+void
+gcc_jit_block_end_with_return (gcc_jit_block *block,
+			       gcc_jit_location *loc,
+			       gcc_jit_rvalue *rvalue)
+{
+  RETURN_IF_NOT_VALID_BLOCK (block, loc);
+  gcc::jit::recording::context *ctxt = block->get_context ();
+  gcc::jit::recording::function *func = block->get_function ();
+  RETURN_IF_FAIL (rvalue, ctxt, loc, "NULL rvalue");
+  RETURN_IF_FAIL_PRINTF4 (
+    compatible_types (
+      func->get_return_type (),
+      rvalue->get_type ()),
+    ctxt, loc,
+    "mismatching types:"
+    " return of %s (type: %s) in function %s (return type: %s)",
+    rvalue->get_debug_string (),
+    rvalue->get_type ()->get_debug_string (),
+    func->get_debug_string (),
+    func->get_return_type ()->get_debug_string ());
+
+  return block->end_with_return (loc, rvalue);
+}
+
+void
+gcc_jit_block_end_with_void_return (gcc_jit_block *block,
+				    gcc_jit_location *loc)
+{
+  RETURN_IF_NOT_VALID_BLOCK (block, loc);
+  gcc::jit::recording::context *ctxt = block->get_context ();
+  gcc::jit::recording::function *func = block->get_function ();
+  RETURN_IF_FAIL_PRINTF2 (
+    func->get_return_type () == ctxt->get_type (GCC_JIT_TYPE_VOID),
+    ctxt, loc,
+    "mismatching types:"
+    " void return in function %s (return type: %s)",
+    func->get_debug_string (),
+    func->get_return_type ()->get_debug_string ());
+
+  return block->end_with_return (loc, NULL);
+}
+
+/**********************************************************************
+ Option-management
+ **********************************************************************/
+
+void
+gcc_jit_context_set_str_option (gcc_jit_context *ctxt,
+				enum gcc_jit_str_option opt,
+				const char *value)
+{
+  RETURN_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+  /* opt is checked by the inner function.
+     value can be NULL.  */
+
+  ctxt->set_str_option (opt, value);
+}
+
+void
+gcc_jit_context_set_int_option (gcc_jit_context *ctxt,
+				enum gcc_jit_int_option opt,
+				int value)
+{
+  RETURN_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+  /* opt is checked by the inner function.  */
+
+  ctxt->set_int_option (opt, value);
+}
+
+void
+gcc_jit_context_set_bool_option (gcc_jit_context *ctxt,
+				 enum gcc_jit_bool_option opt,
+				 int value)
+{
+  RETURN_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+  /* opt is checked by the inner function.  */
+
+  ctxt->set_bool_option (opt, value);
+}
+
+gcc_jit_result *
+gcc_jit_context_compile (gcc_jit_context *ctxt)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+
+  return (gcc_jit_result *)ctxt->compile ();
+}
+
+void
+gcc_jit_context_dump_to_file (gcc_jit_context *ctxt,
+			      const char *path,
+			      int update_locations)
+{
+  RETURN_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+  RETURN_IF_FAIL (path, ctxt, NULL, "NULL path");
+  ctxt->dump_to_file (path, update_locations);
+}
+
+const char *
+gcc_jit_context_get_first_error (gcc_jit_context *ctxt)
+{
+  RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
+
+  return ctxt->get_first_error ();
+}
+
+void *
+gcc_jit_result_get_code (gcc_jit_result *result,
+			 const char *fnname)
+{
+  RETURN_NULL_IF_FAIL (result, NULL, NULL, "NULL result");
+  RETURN_NULL_IF_FAIL (fnname, NULL, NULL, "NULL fnname");
+
+  return result->get_code (fnname);
+}
+
+void
+gcc_jit_result_release (gcc_jit_result *result)
+{
+  RETURN_IF_FAIL (result, NULL, NULL, "NULL result");
+
+  delete result;
+}
-- 
1.8.5.3

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

* [PATCH 18/27] New file: gcc/jit/TODO.rst
  2014-10-31 17:07 [PATCH 00/27] Merger of jit branch v3 David Malcolm
                   ` (11 preceding siblings ...)
  2014-10-31 17:28 ` [PATCH 12/27] New file: gcc/jit/jit-recording.h David Malcolm
@ 2014-10-31 17:28 ` David Malcolm
  2014-10-31 21:26   ` Jeff Law
  2014-10-31 17:28 ` [PATCH 11/27] New file: gcc/jit/jit-common.h David Malcolm
                   ` (12 subsequent siblings)
  25 siblings, 1 reply; 71+ messages in thread
From: David Malcolm @ 2014-10-31 17:28 UTC (permalink / raw)
  To: gcc-patches, jit; +Cc: David Malcolm

This is a list of TODOs for working on the JIT.

gcc/jit/
	* TODO.rst: New.
---
 gcc/jit/TODO.rst | 119 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 119 insertions(+)
 create mode 100644 gcc/jit/TODO.rst

diff --git a/gcc/jit/TODO.rst b/gcc/jit/TODO.rst
new file mode 100644
index 0000000..09c4d9d
--- /dev/null
+++ b/gcc/jit/TODO.rst
@@ -0,0 +1,119 @@
+TODOs
+-----
+
+API
+===
+* error-handling:
+    * have a client-provided error-handling callback for the context, and
+      call it, rather than asserting/crashing etc, to make the API resilient and helpful
+
+* probably should turn off signal handlers and backtracing, leaving that to
+  the client code
+
+* enums and ABI: give enums specific numbers, in ranges, to make it
+  possible to maintain a logical ordering whilst preserving ABI.
+
+* expose the statements in the API? (mostly so they can be stringified?)
+
+* support more arithmetic ops and comparison modes
+
+* access to a function by address::
+
+    extern gcc_jit_function *
+    gcc_jit_context_get_function (ctxt,
+                                  void *); /* need type information */
+
+  so you can access "static" fns in your code.
+
+* ability to turn a function into a function pointer::
+
+    gcc_jit_function_as_rvalue ()
+
+* expressing branch probabilies (like __builtin_expect)::
+
+    extern gcc_jit_rvalue *
+    gcc_jit_rvalue_likely (gcc_jit_rvalue *rvalue,
+                           int is_likely);
+
+  though would:
+
+    extern void
+    gcc_jit_block_set_likelihood (gcc_jit_block *block,
+                                  int hotness);
+
+  be better?  (for expressing how hot the current location is)
+
+* add a SONAME to the library (and potentially version the symbols?)
+
+* do we need alternative forms of division (floor vs rounding)?
+
+* are we missing any ops?
+
+* error-checking:
+
+    * gcc_jit_context_new_unary_op: various checks needed
+
+    * gcc_jit_context_new_binary_op: various checks needed
+
+    * gcc_jit_context_new_comparison: must be numeric or pointer types
+
+    * gcc_jit_context_new_array_access: "index" must be of numeric type.
+
+    * gcc_jit_lvalue_access_field: must be field of correct struct
+
+    * gcc_jit_rvalue_access_field: must be field of correct struct
+
+    * gcc_jit_block_add_assignment_op: check the types
+
+* Implement more kinds of casts e.g. pointers
+
+Bugs
+====
+* fixing all the state issues: make it work repeatedly with optimization
+  turned up to full.
+
+* make the dirty dirty hacks less egregious...
+
+* test under valgrind; fix memory leaks
+
+* re-architect gcc so we don't have to reinitialize everything every time
+  a context is compiled
+
+Test suite
+==========
+* get DejaGnu to build and run C++ testcases
+
+* measure code coverage in testing of libgccjit.so
+
+Future milestones
+=================
+* try porting llvmpipe to gcc
+
+* inline assembler?
+
+* Detect and issue warnings/errors about uses of uninitialized variables
+
+* Warn about unused objects in a context (e.g. rvalues/lvalues)?  (e.g.
+  for gcc_jit_context_new_call vs gcc_jit_block_add_eval)
+
+Nice to have
+============
+* Currently each function has a single stmt_list, which is built in
+  postprocessing by walking the list of blocks.  Presumably we could
+  have each block have its own stmt_list, avoiding the need for this
+  traversal, and having the block structure show up within tree dumps.
+  Alternatively, could we skip tree and go straight to gimple?
+
+* ability to give contexts names, for ease of debugging?
+
+
+Probably not needed
+===================
+* "switch" and "case" ?
+
+* sizeof (should this be an API hook?)  do we even need it? presumably
+  client code can just do the sizeof() in its own code.
+
+* do we need unary plus?
+
+etc etc
-- 
1.8.5.3

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

* [PATCH 08/27] New file: gcc/jit/libgccjit.h
  2014-10-31 17:07 [PATCH 00/27] Merger of jit branch v3 David Malcolm
                   ` (14 preceding siblings ...)
  2014-10-31 17:28 ` [PATCH 10/27] New file: gcc/jit/libgccjit.c David Malcolm
@ 2014-10-31 17:29 ` David Malcolm
  2014-11-03 20:22   ` Jeff Law
  2014-10-31 17:29 ` [PATCH 14/27] New files: gcc/jit/jit-builtins.{c|h} David Malcolm
                   ` (9 subsequent siblings)
  25 siblings, 1 reply; 71+ messages in thread
From: David Malcolm @ 2014-10-31 17:29 UTC (permalink / raw)
  To: gcc-patches, jit; +Cc: David Malcolm

This header is the public API for the library.

gcc/jit/
	* libgccjit.h: New.
---
 gcc/jit/libgccjit.h | 977 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 977 insertions(+)
 create mode 100644 gcc/jit/libgccjit.h

diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h
new file mode 100644
index 0000000..8e03412
--- /dev/null
+++ b/gcc/jit/libgccjit.h
@@ -0,0 +1,977 @@
+/* A pure C API to enable client code to embed GCC as a JIT-compiler.
+   Copyright (C) 2013-2014 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef LIBGCCJIT_H
+#define LIBGCCJIT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/**********************************************************************
+ Data structures.
+ **********************************************************************/
+/* All structs within the API are opaque. */
+
+/* A gcc_jit_context encapsulates the state of a compilation.  It goes
+   through two states:
+
+   (1) "initial", during which you can set up options on it, and add
+       types, functions and code, using the API below.
+       Invoking gcc_jit_context_compile on it transitions it to the
+       "after compilation" state.
+
+   (2) "after compilation", when you can call gcc_jit_context_release to
+       clean up.  */
+typedef struct gcc_jit_context gcc_jit_context;
+
+/* A gcc_jit_result encapsulates the result of a compilation.  */
+typedef struct gcc_jit_result gcc_jit_result;
+
+/* An object created within a context.  Such objects are automatically
+   cleaned up when the context is released.
+
+   The class hierarchy looks like this:
+
+     +- gcc_jit_object
+         +- gcc_jit_location
+         +- gcc_jit_type
+	    +- gcc_jit_struct
+         +- gcc_jit_field
+         +- gcc_jit_function
+         +- gcc_jit_block
+         +- gcc_jit_rvalue
+             +- gcc_jit_lvalue
+                 +- gcc_jit_param
+*/
+typedef struct gcc_jit_object gcc_jit_object;
+
+/* A gcc_jit_location encapsulates a source code location, so that
+   you can (optionally) associate locations in your language with
+   statements in the JIT-compiled code, allowing the debugger to
+   single-step through your language.
+
+   Note that to do so, you also need to enable
+     GCC_JIT_BOOL_OPTION_DEBUGINFO
+   on the gcc_jit_context.
+
+   gcc_jit_location instances are optional; you can always pass
+   NULL.  */
+typedef struct gcc_jit_location gcc_jit_location;
+
+/* A gcc_jit_type encapsulates a type e.g. "int" or a "struct foo*".  */
+typedef struct gcc_jit_type gcc_jit_type;
+
+/* A gcc_jit_field encapsulates a field within a struct; it is used
+   when creating a struct type (using gcc_jit_context_new_struct_type).
+   Fields cannot be shared between structs.  */
+typedef struct gcc_jit_field gcc_jit_field;
+
+/* A gcc_jit_struct encapsulates a struct type, either one that we have
+   the layout for, or an opaque type.  */
+typedef struct gcc_jit_struct gcc_jit_struct;
+
+/* A gcc_jit_function encapsulates a function: either one that you're
+   creating yourself, or a reference to one that you're dynamically
+   linking to within the rest of the process.  */
+typedef struct gcc_jit_function gcc_jit_function;
+
+/* A gcc_jit_block encapsulates a "basic block" of statements within a
+   function (i.e. with one entry point and one exit point).
+
+   Every block within a function must be terminated with a conditional,
+   a branch, or a return.
+
+   The blocks within a function form a directed graph.
+
+   The entrypoint to the function is the first block created within
+   it.
+
+   All of the blocks in a function must be reachable via some path from
+   the first block.
+
+   It's OK to have more than one "return" from a function (i.e. multiple
+   blocks that terminate by returning).  */
+typedef struct gcc_jit_block gcc_jit_block;
+
+/* A gcc_jit_rvalue is an expression within your code, with some type.  */
+typedef struct gcc_jit_rvalue gcc_jit_rvalue;
+
+/* A gcc_jit_lvalue is a storage location within your code (e.g. a
+   variable, a parameter, etc).  It is also a gcc_jit_rvalue; use
+   gcc_jit_lvalue_as_rvalue to cast.  */
+typedef struct gcc_jit_lvalue gcc_jit_lvalue;
+
+/* A gcc_jit_param is a function parameter, used when creating a
+   gcc_jit_function.  It is also a gcc_jit_lvalue (and thus also an
+   rvalue); use gcc_jit_param_as_lvalue to convert.  */
+typedef struct gcc_jit_param gcc_jit_param;
+
+/*
+   Acquire a JIT-compilation context.
+
+   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);
+
+/* Options taking string values. */
+enum gcc_jit_str_option
+{
+  /* The name of the program, for use as a prefix when printing error
+     messages to stderr.  If NULL, or default, "libgccjit.so" is used.  */
+  GCC_JIT_STR_OPTION_PROGNAME,
+
+  GCC_JIT_NUM_STR_OPTIONS
+};
+
+/* Options taking int values. */
+enum gcc_jit_int_option
+{
+  /* How much to optimize the code.
+     Valid values are 0-3, corresponding to GCC's command-line options
+     -O0 through -O3.
+
+     The default value is 0 (unoptimized).  */
+  GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL,
+
+  GCC_JIT_NUM_INT_OPTIONS
+};
+
+/* Options taking boolean values.
+   These all default to "false".  */
+enum gcc_jit_bool_option
+{
+  /* If true, gcc_jit_context_compile will attempt to do the right
+     thing so that if you attach a debugger to the process, it will
+     be able to inspect variables and step through your code.
+
+     Note that you can't step through code unless you set up source
+     location information for the code (by creating and passing in
+     gcc_jit_location instances).  */
+  GCC_JIT_BOOL_OPTION_DEBUGINFO,
+
+  /* If true, gcc_jit_context_compile will dump its initial "tree"
+     representation of your code to stderr (before any
+     optimizations).  */
+  GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE,
+
+  /* If true, gcc_jit_context_compile will dump the "gimple"
+     representation of your code to stderr, before any optimizations
+     are performed.  The dump resembles C code.  */
+  GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE,
+
+  /* If true, gcc_jit_context_compile will dump the final
+     generated code to stderr, in the form of assembly language.  */
+  GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE,
+
+  /* If true, gcc_jit_context_compile will print information to stderr
+     on the actions it is performing, followed by a profile showing
+     the time taken and memory usage of each phase.
+   */
+  GCC_JIT_BOOL_OPTION_DUMP_SUMMARY,
+
+  /* If true, gcc_jit_context_compile will dump copious
+     amount of information on what it's doing to various
+     files within a temporary directory.  Use
+     GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES (see below) to
+     see the results.  The files are intended to be human-readable,
+     but the exact files and their formats are subject to change.
+  */
+  GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING,
+
+  /* If true, libgccjit will aggressively run its garbage collector, to
+     shake out bugs (greatly slowing down the compile).  This is likely
+     to only be of interest to developers *of* the library.  It is
+     used when running the selftest suite.  */
+  GCC_JIT_BOOL_OPTION_SELFCHECK_GC,
+
+  /* If true, gcc_jit_context_release will not clean up
+     intermediate files written to the filesystem, and will display
+     their location on stderr.  */
+  GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES,
+
+  GCC_JIT_NUM_BOOL_OPTIONS
+};
+
+/* Set a string option on the given context.
+
+   The context directly stores the (const char *), so the passed string
+   must outlive the context.  */
+extern void
+gcc_jit_context_set_str_option (gcc_jit_context *ctxt,
+				enum gcc_jit_str_option opt,
+				const char *value);
+
+/* Set an int option on the given context.  */
+extern void
+gcc_jit_context_set_int_option (gcc_jit_context *ctxt,
+				enum gcc_jit_int_option opt,
+				int value);
+
+/* Set a boolean option on the given context.
+
+   Zero is "false" (the default), non-zero is "true".  */
+extern void
+gcc_jit_context_set_bool_option (gcc_jit_context *ctxt,
+				 enum gcc_jit_bool_option opt,
+				 int value);
+
+/* This actually calls into GCC and runs the build, all
+   in a mutex for now.  The result is a wrapper around a .so file.
+   It can only be called once on a given context.  */
+extern gcc_jit_result *
+gcc_jit_context_compile (gcc_jit_context *ctxt);
+
+/* To help with debugging: dump a C-like representation to the given path,
+   describing what's been set up on the context.
+
+   If "update_locations" is true, then also set up gcc_jit_location
+   information throughout the context, pointing at the dump file as if it
+   were a source file.  This may be of use in conjunction with
+   GCC_JIT_BOOL_OPTION_DEBUGINFO to allow stepping through the code in a
+   debugger.  */
+extern void
+gcc_jit_context_dump_to_file (gcc_jit_context *ctxt,
+			      const char *path,
+			      int update_locations);
+
+/* To be called after a compile, this gives the first error message
+   that occurred on the context.
+
+   The returned string is valid for the rest of the lifetime of the
+   context.
+
+   If no errors occurred, this will be NULL.  */
+extern const char *
+gcc_jit_context_get_first_error (gcc_jit_context *ctxt);
+
+/* Locate a given function within the built machine code.
+   This will need to be cast to a function pointer of the
+   correct type before it can be called. */
+extern void *
+gcc_jit_result_get_code (gcc_jit_result *result,
+			 const char *funcname);
+
+/* Once we're done with the code, this unloads the built .so file.
+   This cleans up the result; after calling this, it's no longer
+   valid to use the result.  */
+extern void
+gcc_jit_result_release (gcc_jit_result *result);
+
+
+/**********************************************************************
+ Functions for creating "contextual" objects.
+
+ All objects created by these functions share the lifetime of the context
+ they are created within, and are automatically cleaned up for you when
+ you call gcc_jit_context_release on the context.
+
+ Note that this means you can't use references to them after you've
+ released their context.
+
+ All (const char *) string arguments passed to these functions are
+ copied, so you don't need to keep them around.  Note that this *isn't*
+ the case for other parts of the API.
+
+ You create code by adding a sequence of statements to blocks.
+**********************************************************************/
+
+/**********************************************************************
+ The base class of "contextual" object.
+ **********************************************************************/
+/* Which context is "obj" within?  */
+extern gcc_jit_context *
+gcc_jit_object_get_context (gcc_jit_object *obj);
+
+/* Get a human-readable description of this object.
+   The string buffer is created the first time this is called on a given
+   object, and persists until the object's context is released.  */
+extern const char *
+gcc_jit_object_get_debug_string (gcc_jit_object *obj);
+
+/**********************************************************************
+ Debugging information.
+ **********************************************************************/
+
+/* Creating source code locations for use by the debugger.
+   Line and column numbers are 1-based.  */
+extern gcc_jit_location *
+gcc_jit_context_new_location (gcc_jit_context *ctxt,
+			      const char *filename,
+			      int line,
+			      int column);
+
+/* Upcasting from location to object.  */
+extern gcc_jit_object *
+gcc_jit_location_as_object (gcc_jit_location *loc);
+
+
+/**********************************************************************
+ Types.
+ **********************************************************************/
+
+/* Upcasting from type to object.  */
+extern gcc_jit_object *
+gcc_jit_type_as_object (gcc_jit_type *type);
+
+/* Access to specific types.  */
+enum gcc_jit_types
+{
+  /* C's "void" type.  */
+  GCC_JIT_TYPE_VOID,
+
+  /* "void *".  */
+  GCC_JIT_TYPE_VOID_PTR,
+
+  /* C++'s bool type; also C99's "_Bool" type, aka "bool" if using
+     stdbool.h.  */
+  GCC_JIT_TYPE_BOOL,
+
+  /* Various integer types.  */
+
+  /* C's "char" (of some signedness) and the variants where the
+     signedness is specified.  */
+  GCC_JIT_TYPE_CHAR,
+  GCC_JIT_TYPE_SIGNED_CHAR,
+  GCC_JIT_TYPE_UNSIGNED_CHAR,
+
+  /* C's "short" and "unsigned short".  */
+  GCC_JIT_TYPE_SHORT, /* signed */
+  GCC_JIT_TYPE_UNSIGNED_SHORT,
+
+  /* C's "int" and "unsigned int".  */
+  GCC_JIT_TYPE_INT, /* signed */
+  GCC_JIT_TYPE_UNSIGNED_INT,
+
+  /* C's "long" and "unsigned long".  */
+  GCC_JIT_TYPE_LONG, /* signed */
+  GCC_JIT_TYPE_UNSIGNED_LONG,
+
+  /* C99's "long long" and "unsigned long long".  */
+  GCC_JIT_TYPE_LONG_LONG, /* signed */
+  GCC_JIT_TYPE_UNSIGNED_LONG_LONG,
+
+  /* Floating-point types  */
+
+  GCC_JIT_TYPE_FLOAT,
+  GCC_JIT_TYPE_DOUBLE,
+  GCC_JIT_TYPE_LONG_DOUBLE,
+
+  /* C type: (const char *).  */
+  GCC_JIT_TYPE_CONST_CHAR_PTR,
+
+ /* The C "size_t" type.  */
+  GCC_JIT_TYPE_SIZE_T,
+
+ /* C type: (FILE *)  */
+  GCC_JIT_TYPE_FILE_PTR
+};
+
+extern gcc_jit_type *
+gcc_jit_context_get_type (gcc_jit_context *ctxt,
+			  enum gcc_jit_types type_);
+
+extern gcc_jit_type *
+gcc_jit_context_get_int_type (gcc_jit_context *ctxt,
+			      int num_bytes, int is_signed);
+
+/* Constructing new types. */
+
+/* Given type "T", get type "T*".  */
+extern gcc_jit_type *
+gcc_jit_type_get_pointer (gcc_jit_type *type);
+
+/* Given type "T", get type "const T".  */
+extern gcc_jit_type *
+gcc_jit_type_get_const (gcc_jit_type *type);
+
+/* Given type "T", get type "volatile T".  */
+extern gcc_jit_type *
+gcc_jit_type_get_volatile (gcc_jit_type *type);
+
+/* Given type "T", get type "T[N]" (for a constant N).  */
+extern gcc_jit_type *
+gcc_jit_context_new_array_type (gcc_jit_context *ctxt,
+				gcc_jit_location *loc,
+				gcc_jit_type *element_type,
+				int num_elements);
+
+/* Struct-handling.  */
+extern gcc_jit_field *
+gcc_jit_context_new_field (gcc_jit_context *ctxt,
+			   gcc_jit_location *loc,
+			   gcc_jit_type *type,
+			   const char *name);
+
+/* Upcasting from field to object.  */
+extern gcc_jit_object *
+gcc_jit_field_as_object (gcc_jit_field *field);
+
+extern gcc_jit_struct *
+gcc_jit_context_new_struct_type (gcc_jit_context *ctxt,
+				 gcc_jit_location *loc,
+				 const char *name,
+				 int num_fields,
+				 gcc_jit_field **fields);
+
+extern gcc_jit_struct *
+gcc_jit_context_new_opaque_struct (gcc_jit_context *ctxt,
+				   gcc_jit_location *loc,
+				   const char *name);
+
+extern gcc_jit_type *
+gcc_jit_struct_as_type (gcc_jit_struct *struct_type);
+
+/* Populating the fields of a formerly-opaque struct type.
+   This can only be called once on a given struct type.  */
+extern void
+gcc_jit_struct_set_fields (gcc_jit_struct *struct_type,
+			   gcc_jit_location *loc,
+			   int num_fields,
+			   gcc_jit_field **fields);
+
+/* Unions work similarly to structs.  */
+extern gcc_jit_type *
+gcc_jit_context_new_union_type (gcc_jit_context *ctxt,
+				gcc_jit_location *loc,
+				const char *name,
+				int num_fields,
+				gcc_jit_field **fields);
+
+/* Function pointers. */
+
+extern gcc_jit_type *
+gcc_jit_context_new_function_ptr_type (gcc_jit_context *ctxt,
+				       gcc_jit_location *loc,
+				       gcc_jit_type *return_type,
+				       int num_params,
+				       gcc_jit_type **param_types,
+				       int is_variadic);
+
+/**********************************************************************
+ Constructing functions.
+ **********************************************************************/
+extern gcc_jit_param *
+gcc_jit_context_new_param (gcc_jit_context *ctxt,
+			   gcc_jit_location *loc,
+			   gcc_jit_type *type,
+			   const char *name);
+
+/* Upcasting from param to object.  */
+extern gcc_jit_object *
+gcc_jit_param_as_object (gcc_jit_param *param);
+
+extern gcc_jit_lvalue *
+gcc_jit_param_as_lvalue (gcc_jit_param *param);
+
+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,
+
+  /* Function is only ever inlined into other functions, and is
+     invisible outside of the JIT.
+
+     Analogous to prefixing with "inline" and adding
+     __attribute__((always_inline)).
+
+     Inlining will only occur when the optimization level is
+     above 0; when optimization is off, this is essentially the
+     same as GCC_JIT_FUNCTION_INTERNAL.  */
+  GCC_JIT_FUNCTION_ALWAYS_INLINE
+};
+
+
+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_function *
+gcc_jit_context_get_builtin_function (gcc_jit_context *ctxt,
+				      const char *name);
+
+/* Upcasting from function to object.  */
+extern gcc_jit_object *
+gcc_jit_function_as_object (gcc_jit_function *func);
+
+extern gcc_jit_param *
+gcc_jit_function_get_param (gcc_jit_function *func, int index);
+
+/* Emit the function in graphviz format.  */
+extern void
+gcc_jit_function_dump_to_dot (gcc_jit_function *func,
+			      const char *path);
+
+/* Create a block.
+
+   The name can be NULL, or you can give it a meaningful name, which
+   may show up in dumps of the internal representation, and in error
+   messages.  */
+extern gcc_jit_block *
+gcc_jit_function_new_block (gcc_jit_function *func,
+			    const char *name);
+
+/* Upcasting from block to object.  */
+extern gcc_jit_object *
+gcc_jit_block_as_object (gcc_jit_block *block);
+
+/* Which function is this block within?  */
+extern gcc_jit_function *
+gcc_jit_block_get_function (gcc_jit_block *block);
+
+/**********************************************************************
+ lvalues, rvalues and expressions.
+ **********************************************************************/
+
+extern gcc_jit_lvalue *
+gcc_jit_context_new_global (gcc_jit_context *ctxt,
+			    gcc_jit_location *loc,
+			    gcc_jit_type *type,
+			    const char *name);
+
+/* Upcasting.  */
+extern gcc_jit_object *
+gcc_jit_lvalue_as_object (gcc_jit_lvalue *lvalue);
+
+extern gcc_jit_rvalue *
+gcc_jit_lvalue_as_rvalue (gcc_jit_lvalue *lvalue);
+
+extern gcc_jit_object *
+gcc_jit_rvalue_as_object (gcc_jit_rvalue *rvalue);
+
+extern gcc_jit_type *
+gcc_jit_rvalue_get_type (gcc_jit_rvalue *rvalue);
+
+/* Integer constants. */
+extern gcc_jit_rvalue *
+gcc_jit_context_new_rvalue_from_int (gcc_jit_context *ctxt,
+				     gcc_jit_type *numeric_type,
+				     int value);
+
+extern gcc_jit_rvalue *
+gcc_jit_context_zero (gcc_jit_context *ctxt,
+		      gcc_jit_type *numeric_type);
+
+extern gcc_jit_rvalue *
+gcc_jit_context_one (gcc_jit_context *ctxt,
+		     gcc_jit_type *numeric_type);
+
+/* Floating-point constants.  */
+extern gcc_jit_rvalue *
+gcc_jit_context_new_rvalue_from_double (gcc_jit_context *ctxt,
+					gcc_jit_type *numeric_type,
+					double value);
+
+/* Pointers.  */
+extern gcc_jit_rvalue *
+gcc_jit_context_new_rvalue_from_ptr (gcc_jit_context *ctxt,
+				     gcc_jit_type *pointer_type,
+				     void *value);
+
+extern gcc_jit_rvalue *
+gcc_jit_context_null (gcc_jit_context *ctxt,
+		      gcc_jit_type *pointer_type);
+
+/* String literals. */
+extern gcc_jit_rvalue *
+gcc_jit_context_new_string_literal (gcc_jit_context *ctxt,
+				    const char *value);
+
+enum gcc_jit_unary_op
+{
+  /* Negate an arithmetic value; analogous to:
+       -(EXPR)
+     in C.  */
+  GCC_JIT_UNARY_OP_MINUS,
+
+  /* Bitwise negation of an integer value (one's complement); analogous
+     to:
+       ~(EXPR)
+     in C.  */
+  GCC_JIT_UNARY_OP_BITWISE_NEGATE,
+
+  /* Logical negation of an arithmetic or pointer value; analogous to:
+       !(EXPR)
+     in C.  */
+  GCC_JIT_UNARY_OP_LOGICAL_NEGATE
+};
+
+extern gcc_jit_rvalue *
+gcc_jit_context_new_unary_op (gcc_jit_context *ctxt,
+			      gcc_jit_location *loc,
+			      enum gcc_jit_unary_op op,
+			      gcc_jit_type *result_type,
+			      gcc_jit_rvalue *rvalue);
+
+enum gcc_jit_binary_op
+{
+  /* Addition of arithmetic values; analogous to:
+       (EXPR_A) + (EXPR_B)
+     in C.
+     For pointer addition, use gcc_jit_context_new_array_access.  */
+  GCC_JIT_BINARY_OP_PLUS,
+
+  /* Subtraction of arithmetic values; analogous to:
+       (EXPR_A) - (EXPR_B)
+     in C.  */
+  GCC_JIT_BINARY_OP_MINUS,
+
+  /* Multiplication of a pair of arithmetic values; analogous to:
+       (EXPR_A) * (EXPR_B)
+     in C.  */
+  GCC_JIT_BINARY_OP_MULT,
+
+  /* Quotient of division of arithmetic values; analogous to:
+       (EXPR_A) / (EXPR_B)
+     in C.
+     The result type affects the kind of division: if the result type is
+     integer-based, then the result is truncated towards zero, whereas
+     a floating-point result type indicates floating-point division.  */
+  GCC_JIT_BINARY_OP_DIVIDE,
+
+  /* Remainder of division of arithmetic values; analogous to:
+       (EXPR_A) % (EXPR_B)
+     in C.  */
+  GCC_JIT_BINARY_OP_MODULO,
+
+  /* Bitwise AND; analogous to:
+       (EXPR_A) & (EXPR_B)
+     in C.  */
+  GCC_JIT_BINARY_OP_BITWISE_AND,
+
+  /* Bitwise exclusive OR; analogous to:
+       (EXPR_A) ^ (EXPR_B)
+     in C.  */
+  GCC_JIT_BINARY_OP_BITWISE_XOR,
+
+  /* Bitwise inclusive OR; analogous to:
+       (EXPR_A) | (EXPR_B)
+     in C.  */
+  GCC_JIT_BINARY_OP_BITWISE_OR,
+
+  /* Logical AND; analogous to:
+       (EXPR_A) && (EXPR_B)
+     in C.  */
+  GCC_JIT_BINARY_OP_LOGICAL_AND,
+
+  /* Logical OR; analogous to:
+       (EXPR_A) || (EXPR_B)
+     in C.  */
+  GCC_JIT_BINARY_OP_LOGICAL_OR,
+
+  /* Left shift; analogous to:
+       (EXPR_A) << (EXPR_B)
+     in C.  */
+  GCC_JIT_BINARY_OP_LSHIFT,
+
+  /* Right shift; analogous to:
+       (EXPR_A) >> (EXPR_B)
+     in C.  */
+  GCC_JIT_BINARY_OP_RSHIFT
+};
+
+extern gcc_jit_rvalue *
+gcc_jit_context_new_binary_op (gcc_jit_context *ctxt,
+			       gcc_jit_location *loc,
+			       enum gcc_jit_binary_op op,
+			       gcc_jit_type *result_type,
+			       gcc_jit_rvalue *a, gcc_jit_rvalue *b);
+
+/* (Comparisons are treated as separate from "binary_op" to save
+   you having to specify the result_type).  */
+
+enum gcc_jit_comparison
+{
+  /* (EXPR_A) == (EXPR_B).  */
+  GCC_JIT_COMPARISON_EQ,
+
+  /* (EXPR_A) != (EXPR_B).  */
+  GCC_JIT_COMPARISON_NE,
+
+  /* (EXPR_A) < (EXPR_B).  */
+  GCC_JIT_COMPARISON_LT,
+
+  /* (EXPR_A) <=(EXPR_B).  */
+  GCC_JIT_COMPARISON_LE,
+
+  /* (EXPR_A) > (EXPR_B).  */
+  GCC_JIT_COMPARISON_GT,
+
+  /* (EXPR_A) >= (EXPR_B).  */
+  GCC_JIT_COMPARISON_GE
+};
+
+extern gcc_jit_rvalue *
+gcc_jit_context_new_comparison (gcc_jit_context *ctxt,
+				gcc_jit_location *loc,
+				enum gcc_jit_comparison op,
+				gcc_jit_rvalue *a, gcc_jit_rvalue *b);
+
+/* Function calls.  */
+
+/* Call of a specific function.  */
+extern gcc_jit_rvalue *
+gcc_jit_context_new_call (gcc_jit_context *ctxt,
+			  gcc_jit_location *loc,
+			  gcc_jit_function *func,
+			  int numargs , gcc_jit_rvalue **args);
+
+/* Call through a function pointer.  */
+extern gcc_jit_rvalue *
+gcc_jit_context_new_call_through_ptr (gcc_jit_context *ctxt,
+				      gcc_jit_location *loc,
+				      gcc_jit_rvalue *fn_ptr,
+				      int numargs, gcc_jit_rvalue **args);
+
+/* Type-coercion.
+
+   Currently only a limited set of conversions are possible:
+     int <-> float
+     int <-> bool  */
+extern gcc_jit_rvalue *
+gcc_jit_context_new_cast (gcc_jit_context *ctxt,
+			  gcc_jit_location *loc,
+			  gcc_jit_rvalue *rvalue,
+			  gcc_jit_type *type);
+
+extern gcc_jit_lvalue *
+gcc_jit_context_new_array_access (gcc_jit_context *ctxt,
+				  gcc_jit_location *loc,
+				  gcc_jit_rvalue *ptr,
+				  gcc_jit_rvalue *index);
+
+/* Field access is provided separately for both lvalues and rvalues.  */
+
+/* Accessing a field of an lvalue of struct type, analogous to:
+      (EXPR).field = ...;
+   in C.  */
+extern gcc_jit_lvalue *
+gcc_jit_lvalue_access_field (gcc_jit_lvalue *struct_or_union,
+			     gcc_jit_location *loc,
+			     gcc_jit_field *field);
+
+/* Accessing a field of an rvalue of struct type, analogous to:
+      (EXPR).field
+   in C.  */
+extern gcc_jit_rvalue *
+gcc_jit_rvalue_access_field (gcc_jit_rvalue *struct_or_union,
+			     gcc_jit_location *loc,
+			     gcc_jit_field *field);
+
+/* Accessing a field of an rvalue of pointer type, analogous to:
+      (EXPR)->field
+   in C, itself equivalent to (*EXPR).FIELD  */
+extern gcc_jit_lvalue *
+gcc_jit_rvalue_dereference_field (gcc_jit_rvalue *ptr,
+				  gcc_jit_location *loc,
+				  gcc_jit_field *field);
+
+/* Dereferencing a pointer; analogous to:
+     *(EXPR)
+*/
+extern gcc_jit_lvalue *
+gcc_jit_rvalue_dereference (gcc_jit_rvalue *rvalue,
+			    gcc_jit_location *loc);
+
+/* Taking the address of an lvalue; analogous to:
+     &(EXPR)
+   in C.  */
+extern gcc_jit_rvalue *
+gcc_jit_lvalue_get_address (gcc_jit_lvalue *lvalue,
+			    gcc_jit_location *loc);
+
+extern gcc_jit_lvalue *
+gcc_jit_function_new_local (gcc_jit_function *func,
+			    gcc_jit_location *loc,
+			    gcc_jit_type *type,
+			    const char *name);
+
+/**********************************************************************
+ Statement-creation.
+ **********************************************************************/
+
+/* Add evaluation of an rvalue, discarding the result
+   (e.g. a function call that "returns" void).
+
+   This is equivalent to this C code:
+
+     (void)expression;
+*/
+extern void
+gcc_jit_block_add_eval (gcc_jit_block *block,
+			gcc_jit_location *loc,
+			gcc_jit_rvalue *rvalue);
+
+/* Add evaluation of an rvalue, assigning the result to the given
+   lvalue.
+
+   This is roughly equivalent to this C code:
+
+     lvalue = rvalue;
+*/
+extern void
+gcc_jit_block_add_assignment (gcc_jit_block *block,
+			      gcc_jit_location *loc,
+			      gcc_jit_lvalue *lvalue,
+			      gcc_jit_rvalue *rvalue);
+
+/* Add evaluation of an rvalue, using the result to modify an
+   lvalue.
+
+   This is analogous to "+=" and friends:
+
+     lvalue += rvalue;
+     lvalue *= rvalue;
+     lvalue /= rvalue;
+   etc  */
+extern void
+gcc_jit_block_add_assignment_op (gcc_jit_block *block,
+				 gcc_jit_location *loc,
+				 gcc_jit_lvalue *lvalue,
+				 enum gcc_jit_binary_op op,
+				 gcc_jit_rvalue *rvalue);
+
+/* Add a no-op textual comment to the internal representation of the
+   code.  It will be optimized away, but will be visible in the dumps
+   seen via
+     GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE
+   and
+     GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE,
+   and thus may be of use when debugging how your project's internal
+   representation gets converted to the libgccjit IR.  */
+extern void
+gcc_jit_block_add_comment (gcc_jit_block *block,
+			   gcc_jit_location *loc,
+			   const char *text);
+
+/* Terminate a block by adding evaluation of an rvalue, branching on the
+   result to the appropriate successor block.
+
+   This is roughly equivalent to this C code:
+
+     if (boolval)
+       goto on_true;
+     else
+       goto on_false;
+
+   block, boolval, on_true, and on_false must be non-NULL.  */
+extern void
+gcc_jit_block_end_with_conditional (gcc_jit_block *block,
+				    gcc_jit_location *loc,
+				    gcc_jit_rvalue *boolval,
+				    gcc_jit_block *on_true,
+				    gcc_jit_block *on_false);
+
+/* Terminate a block by adding a jump to the given target block.
+
+   This is roughly equivalent to this C code:
+
+      goto target;
+*/
+extern void
+gcc_jit_block_end_with_jump (gcc_jit_block *block,
+			     gcc_jit_location *loc,
+			     gcc_jit_block *target);
+
+/* Terminate a block by adding evaluation of an rvalue, returning the value.
+
+   This is roughly equivalent to this C code:
+
+      return expression;
+*/
+extern void
+gcc_jit_block_end_with_return (gcc_jit_block *block,
+			       gcc_jit_location *loc,
+			       gcc_jit_rvalue *rvalue);
+
+/* Terminate a block by adding a valueless return, for use within a function
+   with "void" return type.
+
+   This is equivalent to this C code:
+
+      return;
+*/
+extern void
+gcc_jit_block_end_with_void_return (gcc_jit_block *block,
+				    gcc_jit_location *loc);
+
+/**********************************************************************
+ Nested contexts.
+ **********************************************************************/
+
+/* Given an existing JIT context, create a child context.
+
+   The child inherits a copy of all option-settings from the parent.
+
+   The child can reference objects created within the parent, but not
+   vice-versa.
+
+   The lifetime of the child context must be bounded by that of the
+   parent: you should release a child context before releasing the parent
+   context.
+
+   If you use a function from a parent context within a child context,
+   you have to compile the parent context before you can compile the
+   child context, and the gcc_jit_result of the parent context must
+   outlive the gcc_jit_result of the child context.
+
+   This allows caching of shared initializations.  For example, you could
+   create types and declarations of global functions in a parent context
+   once within a process, and then create child contexts whenever a
+   function or loop becomes hot. Each such child context can be used for
+   JIT-compiling just one function or loop, but can reference types
+   and helper functions created within the parent context.
+
+   Contexts can be arbitrarily nested, provided the above rules are
+   followed, but it's probably not worth going above 2 or 3 levels, and
+   there will likely be a performance hit for such nesting.  */
+
+extern gcc_jit_context *
+gcc_jit_context_new_child_context (gcc_jit_context *parent_ctxt);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif  /* LIBGCCJIT_H  */
-- 
1.8.5.3

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

* [PATCH 14/27] New files: gcc/jit/jit-builtins.{c|h}
  2014-10-31 17:07 [PATCH 00/27] Merger of jit branch v3 David Malcolm
                   ` (15 preceding siblings ...)
  2014-10-31 17:29 ` [PATCH 08/27] New file: gcc/jit/libgccjit.h David Malcolm
@ 2014-10-31 17:29 ` David Malcolm
  2014-11-03 21:04   ` Jeff Law
  2014-10-31 17:30 ` [PATCH 17/27] New file: gcc/jit/libgccjit++.h David Malcolm
                   ` (8 subsequent siblings)
  25 siblings, 1 reply; 71+ messages in thread
From: David Malcolm @ 2014-10-31 17:29 UTC (permalink / raw)
  To: gcc-patches, jit; +Cc: David Malcolm

These files implement support for builtins, for the
  gcc_jit_context_get_builtin_function
API entrypoint.

Only a subset of builtins are currently supported, based on those
that I needed when porting GNU Octave's JIT.

Attempts to use other builtins may lead to an error:
  "unimplemented primitive type for builtin"
being emitted on the gcc_jit_context.

gcc/jit/
	* jit-builtins.c: New.
	* jit-builtins.h: New.
---
 gcc/jit/jit-builtins.c | 424 +++++++++++++++++++++++++++++++++++++++++++++++++
 gcc/jit/jit-builtins.h | 114 +++++++++++++
 2 files changed, 538 insertions(+)
 create mode 100644 gcc/jit/jit-builtins.c
 create mode 100644 gcc/jit/jit-builtins.h

diff --git a/gcc/jit/jit-builtins.c b/gcc/jit/jit-builtins.c
new file mode 100644
index 0000000..07902e8
--- /dev/null
+++ b/gcc/jit/jit-builtins.c
@@ -0,0 +1,424 @@
+/* jit-builtins.c -- Handling of builtin functions during JIT-compilation.
+   Copyright (C) 2014 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "opts.h"
+#include "tree.h"
+#include "target.h"
+
+#include "jit-common.h"
+#include "jit-builtins.h"
+#include "jit-recording.h"
+
+namespace gcc {
+
+namespace jit {
+
+namespace recording {
+
+const char *const prefix = "__builtin_";
+const size_t prefix_len = strlen (prefix);
+
+/* Create "builtin_data", a const table of the data within builtins.def.  */
+struct builtin_data
+{
+  const char *name;
+  enum jit_builtin_type type;
+  bool both_p;
+  bool fallback_p;
+
+  const char *get_asm_name () const
+  {
+    if (both_p && fallback_p)
+      return name + prefix_len;
+    else
+      return name;
+  }
+};
+
+#define DEF_BUILTIN(X, NAME, C, TYPE, LT, BOTH_P, FALLBACK_P, NA, AT, IM, COND)\
+  {NAME, TYPE, BOTH_P, FALLBACK_P},
+static const struct builtin_data builtin_data[] =
+{
+#include "builtins.def"
+};
+#undef DEF_BUILTIN
+
+/* Helper function for find_builtin_by_name.  */
+
+static bool
+matches_builtin (const char *in_name,
+		 const struct builtin_data& bd)
+{
+  const bool debug = 0;
+  gcc_assert (bd.name);
+
+  if (debug)
+    fprintf (stderr, "seen builtin: %s\n", bd.name);
+
+  if (0 == strcmp (bd.name, in_name))
+    {
+      return true;
+    }
+
+  if (bd.both_p)
+    {
+      /* Then the macros in builtins.def gave a "__builtin_"
+	 prefix to bd.name, but we should also recognize the form
+	 without the prefix.  */
+      gcc_assert (0 == strncmp (bd.name, prefix, prefix_len));
+      if (debug)
+	fprintf (stderr, "testing without prefix as: %s\n",
+		 bd.name + prefix_len);
+      if (0 == strcmp (bd.name + prefix_len, in_name))
+	{
+	  return true;
+	}
+    }
+
+  return false;
+}
+
+/* Locate the built-in function that matches name IN_NAME,
+   writing the result to OUT_ID and returning true if found,
+   or returning false if not found.  */
+
+static bool
+find_builtin_by_name (const char *in_name,
+		      enum built_in_function *out_id)
+{
+  /* Locate builtin.  This currently works by performing repeated
+     strcmp against every possible candidate, which is likely to
+     inefficient.
+
+     We start at index 1 to skip the initial entry (BUILT_IN_NONE), which
+     has a NULL name.  */
+  for (unsigned int i = 1;
+       i < sizeof (builtin_data) / sizeof (builtin_data[0]);
+       i++)
+    {
+      const struct builtin_data& bd = builtin_data[i];
+      if (matches_builtin (in_name, bd))
+	{
+	  /* Found a match.  */
+	  *out_id = static_cast<enum built_in_function> (i);
+	  return true;
+	}
+    }
+
+  /* Not found.  */
+  return false;
+}
+
+// class builtins_manager
+
+/* Constructor for gcc::jit::recording::builtins_manager.  */
+
+builtins_manager::builtins_manager (context *ctxt)
+  : m_ctxt (ctxt)
+{
+  memset (m_types, 0, sizeof (m_types));
+  memset (m_builtin_functions, 0, sizeof (m_builtin_functions));
+}
+
+/* Locate a builtin function by name.
+   Create a recording::function of the appropriate type, reusing them
+   if they've already been seen.  */
+
+function *
+builtins_manager::get_builtin_function (const char *name)
+{
+  enum built_in_function builtin_id;
+  if (!find_builtin_by_name (name, &builtin_id))
+    {
+      m_ctxt->add_error (NULL, "builtin \"%s\" not found", name);
+      return NULL;
+    }
+
+  gcc_assert (builtin_id >= 0);
+  gcc_assert (builtin_id < END_BUILTINS);
+
+  /* Lazily build the functions, caching them so that repeated calls for
+     the same id on a context give back the same object.  */
+  if (!m_builtin_functions[builtin_id])
+    {
+      m_builtin_functions[builtin_id] = make_builtin_function (builtin_id);
+      m_ctxt->record (m_builtin_functions[builtin_id]);
+    }
+
+  return m_builtin_functions[builtin_id];
+}
+
+/* Create the recording::function for a given builtin function, by ID.  */
+
+function *
+builtins_manager::make_builtin_function (enum built_in_function builtin_id)
+{
+  const struct builtin_data& bd = builtin_data[builtin_id];
+  enum jit_builtin_type type_id = bd.type;
+  function_type *func_type = get_type (type_id)->as_a_function_type ();
+  if (!func_type)
+    return NULL;
+
+  vec<type *> param_types = func_type->get_param_types ();
+  recording::param **params = new recording::param *[param_types.length ()];
+
+  int i;
+  type *param_type;
+  FOR_EACH_VEC_ELT (param_types, i, param_type)
+    {
+      char buf[16];
+      snprintf (buf, 16, "arg%d", i);
+      params[i] = m_ctxt->new_param (NULL,
+				     param_type,
+				     buf);
+    }
+  const char *asm_name = bd.get_asm_name ();
+  function *result =
+    new function (m_ctxt,
+		  NULL,
+		  GCC_JIT_FUNCTION_IMPORTED, // FIXME
+		  func_type->get_return_type (),
+		  m_ctxt->new_string (asm_name),
+		  param_types.length (),
+		  params,
+		  func_type->is_variadic (),
+		  builtin_id);
+  delete[] params;
+  return result;
+}
+
+/* Get the recording::type for a given type of builtin function,
+   by ID, creating it if it doesn't already exist.  */
+
+type *
+builtins_manager::get_type (enum jit_builtin_type type_id)
+{
+  if (!m_types[type_id])
+    m_types[type_id] = make_type (type_id);
+  return m_types[type_id];
+}
+
+/* Create the recording::type for a given type of builtin function.  */
+
+type *
+builtins_manager::make_type (enum jit_builtin_type type_id)
+{
+  /* Use builtin-types.def to construct a switch statement, with each
+     case deferring to one of the methods below:
+       - DEF_PRIMITIVE_TYPE is handled as a call to make_primitive_type.
+       - the various DEF_FUNCTION_TYPE_n are handled by variadic calls
+	 to make_fn_type.
+       - similarly for DEF_FUNCTION_TYPE_VAR_n, but setting the
+	"is_variadic" argument.
+       - DEF_POINTER_TYPE is handled by make_ptr_type.
+     That should handle everything, but just in case we also suppy a
+     gcc_unreachable default clause.  */
+  switch (type_id)
+    {
+#define DEF_PRIMITIVE_TYPE(ENUM, VALUE) \
+      case ENUM: return make_primitive_type (ENUM);
+#define DEF_FUNCTION_TYPE_0(ENUM, RETURN) \
+      case ENUM: return make_fn_type (ENUM, RETURN, 0, 0);
+#define DEF_FUNCTION_TYPE_1(ENUM, RETURN, ARG1) \
+      case ENUM: return make_fn_type (ENUM, RETURN, 0, 1, ARG1);
+#define DEF_FUNCTION_TYPE_2(ENUM, RETURN, ARG1, ARG2) \
+      case ENUM: return make_fn_type (ENUM, RETURN, 0, 2, ARG1, ARG2);
+#define DEF_FUNCTION_TYPE_3(ENUM, RETURN, ARG1, ARG2, ARG3) \
+      case ENUM: return make_fn_type (ENUM, RETURN, 0, 3, ARG1, ARG2, ARG3);
+#define DEF_FUNCTION_TYPE_4(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4) \
+      case ENUM: return make_fn_type (ENUM, RETURN, 0, 4, ARG1, ARG2, ARG3, ARG4);
+#define DEF_FUNCTION_TYPE_5(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5)	\
+      case ENUM: return make_fn_type (ENUM, RETURN, 0, 5, ARG1, ARG2, ARG3, ARG4, ARG5);
+#define DEF_FUNCTION_TYPE_6(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
+			    ARG6)					\
+      case ENUM: return make_fn_type (ENUM, RETURN, 0, 6, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6);
+#define DEF_FUNCTION_TYPE_7(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
+			    ARG6, ARG7)					\
+      case ENUM: return make_fn_type (ENUM, RETURN, 0, 7, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7);
+#define DEF_FUNCTION_TYPE_8(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
+			    ARG6, ARG7, ARG8)				\
+      case ENUM: return make_fn_type (ENUM, RETURN, 0, 8, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, \
+				      ARG7, ARG8);
+#define DEF_FUNCTION_TYPE_VAR_0(ENUM, RETURN) \
+      case ENUM: return make_fn_type (ENUM, RETURN, 1, 0);
+#define DEF_FUNCTION_TYPE_VAR_1(ENUM, RETURN, ARG1) \
+      case ENUM: return make_fn_type (ENUM, RETURN, 1, 1, ARG1);
+#define DEF_FUNCTION_TYPE_VAR_2(ENUM, RETURN, ARG1, ARG2) \
+      case ENUM: return make_fn_type (ENUM, RETURN, 1, 2, ARG1, ARG2);
+#define DEF_FUNCTION_TYPE_VAR_3(ENUM, RETURN, ARG1, ARG2, ARG3) \
+      case ENUM: return make_fn_type (ENUM, RETURN, 1, 3, ARG1, ARG2, ARG3);
+#define DEF_FUNCTION_TYPE_VAR_4(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4) \
+      case ENUM: return make_fn_type (ENUM, RETURN, 1, 4, ARG1, ARG2, ARG3, ARG4);
+#define DEF_FUNCTION_TYPE_VAR_5(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) \
+      case ENUM: return make_fn_type (ENUM, RETURN, 1, 5, ARG1, ARG2, ARG3, ARG4, ARG5);
+#define DEF_POINTER_TYPE(ENUM, TYPE) \
+      case ENUM: return make_ptr_type (ENUM, TYPE);
+
+#include "builtin-types.def"
+
+#undef DEF_PRIMITIVE_TYPE
+#undef DEF_FUNCTION_TYPE_1
+#undef DEF_FUNCTION_TYPE_2
+#undef DEF_FUNCTION_TYPE_3
+#undef DEF_FUNCTION_TYPE_4
+#undef DEF_FUNCTION_TYPE_5
+#undef DEF_FUNCTION_TYPE_6
+#undef DEF_FUNCTION_TYPE_VAR_0
+#undef DEF_FUNCTION_TYPE_VAR_1
+#undef DEF_FUNCTION_TYPE_VAR_2
+#undef DEF_FUNCTION_TYPE_VAR_3
+#undef DEF_FUNCTION_TYPE_VAR_4
+#undef DEF_FUNCTION_TYPE_VAR_5
+#undef DEF_POINTER_TYPE
+
+    default:
+      gcc_unreachable ();
+    }
+}
+
+/* Create the recording::type for a given primitive type within the
+   builtin system.
+
+   Only some types are currently supported.  */
+
+type*
+builtins_manager::make_primitive_type (enum jit_builtin_type type_id)
+{
+  switch (type_id)
+    {
+    default:
+      // only some of these types are implemented so far:
+      m_ctxt->add_error (NULL,
+			 "unimplemented primitive type for builtin: %d", type_id);
+      return NULL;
+
+    case BT_VOID: return m_ctxt->get_type (GCC_JIT_TYPE_VOID);
+    case BT_BOOL: return m_ctxt->get_type (GCC_JIT_TYPE_BOOL);
+    case BT_INT: return m_ctxt->get_type (GCC_JIT_TYPE_INT);
+    case BT_UINT: return m_ctxt->get_type (GCC_JIT_TYPE_UNSIGNED_INT);
+    case BT_LONG: return m_ctxt->get_type (GCC_JIT_TYPE_LONG);
+    case BT_ULONG: return m_ctxt->get_type (GCC_JIT_TYPE_UNSIGNED_LONG);
+    case BT_LONGLONG: return m_ctxt->get_type (GCC_JIT_TYPE_LONG_LONG);
+    case BT_ULONGLONG:
+      return m_ctxt->get_type (GCC_JIT_TYPE_UNSIGNED_LONG_LONG);
+    // case BT_INT128:
+    // case BT_UINT128:
+    // case BT_INTMAX:
+    // case BT_UINTMAX:
+    case BT_UINT16: return m_ctxt->get_int_type (2, false);
+    case BT_UINT32: return m_ctxt->get_int_type (4, false);
+    case BT_UINT64: return m_ctxt->get_int_type (8, false);
+    // case BT_WORD:
+    // case BT_UNWINDWORD:
+    case BT_FLOAT: return m_ctxt->get_type (GCC_JIT_TYPE_FLOAT);
+    case BT_DOUBLE: return m_ctxt->get_type (GCC_JIT_TYPE_DOUBLE);
+    case BT_LONGDOUBLE: return m_ctxt->get_type (GCC_JIT_TYPE_LONG_DOUBLE);
+    // case BT_COMPLEX_FLOAT:
+    // case BT_COMPLEX_DOUBLE:
+    // case BT_COMPLEX_LONGDOUBLE:
+    case BT_PTR: return m_ctxt->get_type (GCC_JIT_TYPE_VOID_PTR);
+    case BT_FILEPTR: return m_ctxt->get_type (GCC_JIT_TYPE_FILE_PTR);
+    // case BT_CONST:
+    // case BT_VOLATILE_PTR:
+    // case BT_CONST_VOLATILE_PTR:
+    // case BT_PTRMODE:
+    // case BT_INT_PTR:
+    // case BT_FLOAT_PTR:
+    // case BT_DOUBLE_PTR:
+    // case BT_CONST_DOUBLE_PTR:
+    // case BT_LONGDOUBLE_PTR:
+    // case BT_PID:
+    // case BT_SIZE:
+    // case BT_SSIZE:
+    // case BT_WINT:
+    // case BT_STRING:
+    case BT_CONST_STRING: return m_ctxt->get_type (GCC_JIT_TYPE_CONST_CHAR_PTR);
+    // case BT_DFLOAT32:
+    // case BT_DFLOAT64:
+    // case BT_DFLOAT128:
+    // case BT_DFLOAT32_PTR:
+    // case BT_DFLOAT64_PTR:
+    // case BT_DFLOAT128_PTR:
+    // case BT_VALIST_REF:
+    // case BT_VALIST_ARG:
+    // case BT_I1:
+    // case BT_I2:
+    // case BT_I4:
+    // case BT_I8:
+    // case BT_I16:
+    }
+}
+
+/* Create the recording::function_type for a given function type
+   signature.  */
+
+function_type *
+builtins_manager::make_fn_type (enum jit_builtin_type,
+				enum jit_builtin_type return_type_id,
+				bool is_variadic,
+				int num_args, ...)
+{
+  va_list list;
+  int i;
+  type **param_types = new type *[num_args];
+  type *return_type = NULL;
+  function_type *result = NULL;
+
+  va_start (list, num_args);
+  for (i = 0; i < num_args; ++i)
+    {
+      enum jit_builtin_type arg_type_id =
+	(enum jit_builtin_type) va_arg (list, int);
+      param_types[i] = get_type (arg_type_id);
+      if (!param_types[i])
+	goto error;
+    }
+  va_end (list);
+
+  return_type = get_type (return_type_id);
+  if (!return_type)
+    goto error;
+
+  result = new function_type (m_ctxt,
+			      return_type,
+			      num_args,
+			      param_types,
+			      is_variadic);
+
+ error:
+  delete[] param_types;
+  return result;
+}
+
+/* Handler for DEF_POINTER_TYPE within builtins_manager::make_type.  */
+
+type *
+builtins_manager::make_ptr_type (enum jit_builtin_type,
+				 enum jit_builtin_type other_type_id)
+{
+  type *base_type = get_type (other_type_id);
+  return base_type->get_pointer ();
+}
+
+} // namespace recording
+} // namespace jit
+} // namespace gcc
diff --git a/gcc/jit/jit-builtins.h b/gcc/jit/jit-builtins.h
new file mode 100644
index 0000000..7c46bfd
--- /dev/null
+++ b/gcc/jit/jit-builtins.h
@@ -0,0 +1,114 @@
+/* jit-builtins.h -- Handling of builtin functions during JIT-compilation.
+   Copyright (C) 2014 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef JIT_BUILTINS_H
+#define JIT_BUILTINS_H
+
+#include "jit-common.h"
+
+namespace gcc {
+
+namespace jit {
+
+namespace recording {
+
+/* Create an enum of the builtin types.  */
+
+enum jit_builtin_type
+{
+#define DEF_PRIMITIVE_TYPE(NAME, VALUE) NAME,
+#define DEF_FUNCTION_TYPE_0(NAME, RETURN) NAME,
+#define DEF_FUNCTION_TYPE_1(NAME, RETURN, ARG1) NAME,
+#define DEF_FUNCTION_TYPE_2(NAME, RETURN, ARG1, ARG2) NAME,
+#define DEF_FUNCTION_TYPE_3(NAME, RETURN, ARG1, ARG2, ARG3) NAME,
+#define DEF_FUNCTION_TYPE_4(NAME, RETURN, ARG1, ARG2, ARG3, ARG4) NAME,
+#define DEF_FUNCTION_TYPE_5(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) NAME,
+#define DEF_FUNCTION_TYPE_6(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6) NAME,
+#define DEF_FUNCTION_TYPE_7(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7) NAME,
+#define DEF_FUNCTION_TYPE_8(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7, ARG8) NAME,
+#define DEF_FUNCTION_TYPE_VAR_0(NAME, RETURN) NAME,
+#define DEF_FUNCTION_TYPE_VAR_1(NAME, RETURN, ARG1) NAME,
+#define DEF_FUNCTION_TYPE_VAR_2(NAME, RETURN, ARG1, ARG2) NAME,
+#define DEF_FUNCTION_TYPE_VAR_3(NAME, RETURN, ARG1, ARG2, ARG3) NAME,
+#define DEF_FUNCTION_TYPE_VAR_4(NAME, RETURN, ARG1, ARG2, ARG3, ARG4) NAME,
+#define DEF_FUNCTION_TYPE_VAR_5(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG6) \
+  NAME,
+#define DEF_POINTER_TYPE(NAME, TYPE) NAME,
+#include "builtin-types.def"
+#undef DEF_PRIMITIVE_TYPE
+#undef DEF_FUNCTION_TYPE_0
+#undef DEF_FUNCTION_TYPE_1
+#undef DEF_FUNCTION_TYPE_2
+#undef DEF_FUNCTION_TYPE_3
+#undef DEF_FUNCTION_TYPE_4
+#undef DEF_FUNCTION_TYPE_5
+#undef DEF_FUNCTION_TYPE_6
+#undef DEF_FUNCTION_TYPE_7
+#undef DEF_FUNCTION_TYPE_8
+#undef DEF_FUNCTION_TYPE_VAR_0
+#undef DEF_FUNCTION_TYPE_VAR_1
+#undef DEF_FUNCTION_TYPE_VAR_2
+#undef DEF_FUNCTION_TYPE_VAR_3
+#undef DEF_FUNCTION_TYPE_VAR_4
+#undef DEF_FUNCTION_TYPE_VAR_5
+#undef DEF_POINTER_TYPE
+  BT_LAST
+}; /* enum jit_builtin_type */
+
+/***********************************************************************/
+
+class builtins_manager
+{
+public:
+  builtins_manager (context *ctxt);
+
+  function *
+  get_builtin_function (const char *name);
+
+private:
+  function *make_builtin_function (enum built_in_function builtin_id);
+
+  type *get_type (enum jit_builtin_type type_id);
+
+  type *make_type (enum jit_builtin_type type_id);
+
+  type*
+  make_primitive_type (enum jit_builtin_type type_id);
+
+  function_type*
+  make_fn_type (enum jit_builtin_type type_id,
+		enum jit_builtin_type return_type_id,
+		bool is_variadic,
+		int num_args, ...);
+
+  type*
+  make_ptr_type (enum jit_builtin_type type_id,
+		 enum jit_builtin_type other_type_id);
+
+private:
+  context *m_ctxt;
+  type *m_types[BT_LAST];
+  function *m_builtin_functions[END_BUILTINS];
+};
+
+} // namespace recording
+} // namespace jit
+} // namespace gcc
+
+#endif /* JIT_BUILTINS_H */
-- 
1.8.5.3

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

* [PATCH 17/27] New file: gcc/jit/libgccjit++.h
  2014-10-31 17:07 [PATCH 00/27] Merger of jit branch v3 David Malcolm
                   ` (16 preceding siblings ...)
  2014-10-31 17:29 ` [PATCH 14/27] New files: gcc/jit/jit-builtins.{c|h} David Malcolm
@ 2014-10-31 17:30 ` David Malcolm
  2014-11-03 21:12   ` Jeff Law
  2014-10-31 17:31 ` [PATCH 16/27] New file: gcc/jit/jit-playback.c David Malcolm
                   ` (7 subsequent siblings)
  25 siblings, 1 reply; 71+ messages in thread
From: David Malcolm @ 2014-10-31 17:30 UTC (permalink / raw)
  To: gcc-patches, jit; +Cc: David Malcolm

This adds a C++ wrapper API, with syntactic sugar for reducing the
verbosity compared to the C API.

gcc/jit/
	* libgccjit++.h: New.
---
 gcc/jit/libgccjit++.h | 1574 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 1574 insertions(+)
 create mode 100644 gcc/jit/libgccjit++.h

diff --git a/gcc/jit/libgccjit++.h b/gcc/jit/libgccjit++.h
new file mode 100644
index 0000000..67ed5d5
--- /dev/null
+++ b/gcc/jit/libgccjit++.h
@@ -0,0 +1,1574 @@
+/* A C++ API for libgccjit, purely as inline wrapper functions.
+   Copyright (C) 2014 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef LIBGCCJIT_PLUS_PLUS_H
+#define LIBGCCJIT_PLUS_PLUS_H
+
+#include "libgccjit.h"
+
+#include <limits>
+#include <ostream>
+#include <vector>
+
+/****************************************************************************
+ C++ API
+ ****************************************************************************/
+
+namespace gccjit
+{
+  class context;
+  class location;
+  class field;
+  class type;
+  class struct_;
+  class param;
+  class function;
+  class block;
+  class rvalue;
+  class lvalue;
+
+  /* Errors within the API become C++ exceptions of this class.  */
+  class error
+  {
+  };
+
+  class object
+  {
+  public:
+    context get_context () const;
+
+    std::string get_debug_string () const;
+
+  protected:
+    object ();
+    object (gcc_jit_object *obj);
+
+    gcc_jit_object *get_inner_object () const;
+
+  private:
+    gcc_jit_object *m_inner_obj;
+  };
+
+  inline std::ostream& operator << (std::ostream& stream, const object &obj);
+
+  /* Some client code will want to supply source code locations, others
+     won't.  To avoid doubling the number of entrypoints, everything
+     accepting a location also has a default argument.  To do this, the
+     other classes need to see that "location" has a default constructor,
+     hence we need to declare it first.  */
+  class location : public object
+  {
+  public:
+    location ();
+    location (gcc_jit_location *loc);
+
+    gcc_jit_location *get_inner_location () const;
+  };
+
+  class context
+  {
+  public:
+    static context acquire ();
+    context ();
+    context (gcc_jit_context *ctxt);
+
+    gccjit::context new_child_context ();
+
+    gcc_jit_context *get_inner_context () { return m_inner_ctxt; }
+
+    void release ();
+
+    gcc_jit_result *compile ();
+
+    void dump_to_file (const std::string &path,
+		       bool update_locations);
+
+    void set_int_option (enum gcc_jit_int_option opt,
+			 int value);
+
+    void set_bool_option (enum gcc_jit_bool_option opt,
+			  int value);
+
+    location
+    new_location (const std::string &filename,
+		  int line,
+		  int column);
+
+    type get_type (enum gcc_jit_types kind);
+    type get_int_type (size_t num_bytes, int is_signed);
+
+    /* A way to map a specific int type, using the compiler to
+       get the details automatically e.g.:
+	  gccjit::type type = get_int_type <my_int_type_t> ();  */
+    template <typename T>
+    type get_int_type ();
+
+    type new_array_type (type element_type, int num_elements,
+			 location loc = location ());
+
+    field new_field (type type_, const std::string &name,
+		     location loc = location ());
+
+    struct_ new_struct_type (const std::string &name,
+			     std::vector<field> &fields,
+			     location loc = location ());
+
+    struct_ new_opaque_struct_type (const std::string &name,
+				    location loc = location ());
+
+    param new_param (type type_,
+		     const std::string &name,
+		     location loc = location ());
+
+    function new_function (enum gcc_jit_function_kind kind,
+			   type return_type,
+			   const std::string &name,
+			   std::vector<param> &params,
+			   int is_variadic,
+			   location loc = location ());
+
+    function get_builtin_function (const std::string &name);
+
+    lvalue new_global (type type_,
+		       const std::string &name,
+		       location loc = location ());
+
+    rvalue new_rvalue (type numeric_type,
+		       int value) const;
+    rvalue zero (type numeric_type) const;
+    rvalue one (type numeric_type) const;
+    rvalue new_rvalue (type numeric_type,
+		       double value) const;
+    rvalue new_rvalue (type pointer_type,
+		       void *value) const;
+    rvalue new_rvalue (const std::string &value) const;
+
+    /* Generic unary operations...  */
+    rvalue new_unary_op (enum gcc_jit_unary_op op,
+			 type result_type,
+			 rvalue a,
+			 location loc = location ());
+
+    /* ...and shorter ways to spell the various specific kinds of
+       unary op.  */
+    rvalue new_minus (type result_type,
+		      rvalue a,
+		      location loc = location ());
+    rvalue new_bitwise_negate (type result_type,
+			       rvalue a,
+			       location loc = location ());
+    rvalue new_logical_negate (type result_type,
+			       rvalue a,
+			       location loc = location ());
+
+    /* Generic binary operations...  */
+    rvalue new_binary_op (enum gcc_jit_binary_op op,
+			  type result_type,
+			  rvalue a, rvalue b,
+			  location loc = location ());
+
+    /* ...and shorter ways to spell the various specific kinds of
+       binary op.  */
+    rvalue new_plus (type result_type,
+		     rvalue a, rvalue b,
+		     location loc = location ());
+    rvalue new_minus (type result_type,
+		      rvalue a, rvalue b,
+		      location loc = location ());
+    rvalue new_mult (type result_type,
+		     rvalue a, rvalue b,
+		     location loc = location ());
+    rvalue new_divide (type result_type,
+		       rvalue a, rvalue b,
+		       location loc = location ());
+    rvalue new_modulo (type result_type,
+		       rvalue a, rvalue b,
+		       location loc = location ());
+    rvalue new_bitwise_and (type result_type,
+			    rvalue a, rvalue b,
+			    location loc = location ());
+    rvalue new_bitwise_xor (type result_type,
+			    rvalue a, rvalue b,
+			    location loc = location ());
+    rvalue new_bitwise_or (type result_type,
+			   rvalue a, rvalue b,
+			   location loc = location ());
+    rvalue new_logical_and (type result_type,
+			    rvalue a, rvalue b,
+			    location loc = location ());
+    rvalue new_logical_or (type result_type,
+			   rvalue a, rvalue b,
+			   location loc = location ());
+
+    /* Generic comparisons...  */
+    rvalue new_comparison (enum gcc_jit_comparison op,
+			   rvalue a, rvalue b,
+			   location loc = location ());
+    /* ...and shorter ways to spell the various specific kinds of
+       comparison.  */
+    rvalue new_eq (rvalue a, rvalue b,
+		   location loc = location ());
+    rvalue new_ne (rvalue a, rvalue b,
+		   location loc = location ());
+    rvalue new_lt (rvalue a, rvalue b,
+		   location loc = location ());
+    rvalue new_le (rvalue a, rvalue b,
+		   location loc = location ());
+    rvalue new_gt (rvalue a, rvalue b,
+		   location loc = location ());
+    rvalue new_ge (rvalue a, rvalue b,
+		   location loc = location ());
+
+    /* The most general way of creating a function call.  */
+    rvalue new_call (function func,
+		     std::vector<rvalue> &args,
+		     location loc = location ());
+
+    /* In addition, we provide a series of overloaded "new_call" methods
+       for specific numbers of args (from 0 - 6), to avoid the need for
+       client code to manually build a vector.  */
+    rvalue new_call (function func,
+		     location loc = location ());
+    rvalue new_call (function func,
+		     rvalue arg0,
+		     location loc = location ());
+    rvalue new_call (function func,
+		     rvalue arg0, rvalue arg1,
+		     location loc = location ());
+    rvalue new_call (function func,
+		     rvalue arg0, rvalue arg1, rvalue arg2,
+		     location loc = location ());
+    rvalue new_call (function func,
+		     rvalue arg0, rvalue arg1, rvalue arg2,
+		     rvalue arg3,
+		     location loc = location ());
+    rvalue new_call (function func,
+		     rvalue arg0, rvalue arg1, rvalue arg2,
+		     rvalue arg3, rvalue arg4,
+		     location loc = location ());
+    rvalue new_call (function func,
+		     rvalue arg0, rvalue arg1, rvalue arg2,
+		     rvalue arg3, rvalue arg4, rvalue arg5,
+		     location loc = location ());
+
+    rvalue new_cast (rvalue expr,
+		     type type_,
+		     location loc = location ());
+
+    lvalue new_array_access (rvalue ptr,
+			     rvalue index,
+			     location loc = location ());
+
+  private:
+    gcc_jit_context *m_inner_ctxt;
+  };
+
+  class field : public object
+  {
+  public:
+    field ();
+    field (gcc_jit_field *inner);
+
+    gcc_jit_field *get_inner_field () const;
+  };
+
+  class type : public object
+  {
+  public:
+    type ();
+    type (gcc_jit_type *inner);
+
+    gcc_jit_type *get_inner_type () const;
+
+    type get_pointer ();
+    type get_volatile ();
+
+    // Shortcuts for getting values of numeric types:
+    rvalue zero ();
+    rvalue one ();
+ };
+
+  class struct_ : public type
+  {
+  public:
+    struct_ ();
+    struct_ (gcc_jit_struct *inner);
+
+    gcc_jit_struct *get_inner_struct () const;
+  };
+
+  class function : public object
+  {
+  public:
+    function ();
+    function (gcc_jit_function *func);
+
+    gcc_jit_function *get_inner_function () const;
+
+    void dump_to_dot (const std::string &path);
+
+    param get_param (int index) const;
+
+    block new_block ();
+    block new_block (const std::string &name);
+
+    lvalue new_local (type type_,
+		      const std::string &name,
+		      location loc = location ());
+
+    /* A series of overloaded operator () with various numbers of arguments
+       for a very terse way of creating a call to this function.  The call
+       is created within the same context as the function itself, which may
+       not be what you want.  */
+    rvalue operator() (location loc = location ());
+    rvalue operator() (rvalue arg0,
+		       location loc = location ());
+    rvalue operator() (rvalue arg0, rvalue arg1,
+		       location loc = location ());
+    rvalue operator() (rvalue arg0, rvalue arg1, rvalue arg2,
+		       location loc = location ());
+  };
+
+  class block : public object
+  {
+  public:
+    block ();
+    block (gcc_jit_block *inner);
+
+    gcc_jit_block *get_inner_block () const;
+
+    function get_function () const;
+
+    void add_eval (rvalue rvalue,
+		   location loc = location ());
+
+    void add_assignment (lvalue lvalue,
+			 rvalue rvalue,
+			 location loc = location ());
+
+    void add_assignment_op (lvalue lvalue,
+			    enum gcc_jit_binary_op op,
+			    rvalue rvalue,
+			    location loc = location ());
+
+    /* A way to add a function call to the body of a function being
+       defined, with various numbers of args.  */
+    rvalue add_call (function other,
+		     location loc = location ());
+    rvalue add_call (function other,
+		     rvalue arg0,
+		     location loc = location ());
+    rvalue add_call (function other,
+		     rvalue arg0, rvalue arg1,
+		     location loc = location ());
+    rvalue add_call (function other,
+		     rvalue arg0, rvalue arg1, rvalue arg2,
+		     location loc = location ());
+    rvalue add_call (function other,
+		     rvalue arg0, rvalue arg1, rvalue arg2, rvalue arg3,
+		     location loc = location ());
+
+    void add_comment (const std::string &text,
+		      location loc = location ());
+
+    void end_with_conditional (rvalue boolval,
+			       block on_true,
+			       block on_false,
+			       location loc = location ());
+
+    void end_with_jump (block target,
+			location loc = location ());
+
+    void end_with_return (rvalue rvalue,
+			  location loc = location ());
+    void end_with_return (location loc = location ());
+
+  };
+
+  class rvalue : public object
+  {
+  public:
+    rvalue ();
+    rvalue (gcc_jit_rvalue *inner);
+    gcc_jit_rvalue *get_inner_rvalue () const;
+
+    type get_type ();
+
+    rvalue access_field (field field,
+			 location loc = location ());
+
+    lvalue dereference_field (field field,
+			      location loc = location ());
+
+    lvalue dereference (location loc = location ());
+
+    rvalue cast_to (type type_,
+		    location loc = location ());
+
+    /* Array access.  */
+    lvalue operator[] (rvalue index);
+    lvalue operator[] (int index);
+  };
+
+  class lvalue : public rvalue
+  {
+  public:
+    lvalue ();
+    lvalue (gcc_jit_lvalue *inner);
+
+    gcc_jit_lvalue *get_inner_lvalue () const;
+
+    lvalue access_field (field field,
+			 location loc = location ());
+
+    rvalue get_address (location loc = location ());
+  };
+
+  class param : public lvalue
+  {
+  public:
+    param ();
+    param (gcc_jit_param *inner);
+
+    gcc_jit_param *get_inner_param () const;
+  };
+
+
+  /* Overloaded operators, for those who want the most terse API
+     (at the possible risk of being a little too magical).
+
+     In each case, the first parameter is used to determine which context
+     owns the resulting expression, and, where appropriate,  what the
+     latter's type is. */
+
+  /* Unary operators.  */
+  rvalue operator- (rvalue a); // unary minus
+  rvalue operator~ (rvalue a); // unary bitwise negate
+  rvalue operator! (rvalue a); // unary logical negate
+
+  /* Binary operators.  */
+  rvalue operator+ (rvalue a, rvalue b);
+  rvalue operator- (rvalue a, rvalue b);
+  rvalue operator* (rvalue a, rvalue b);
+  rvalue operator/ (rvalue a, rvalue b);
+  rvalue operator% (rvalue a, rvalue b);
+  rvalue operator& (rvalue a, rvalue b); //  bitwise and
+  rvalue operator^ (rvalue a, rvalue b); // bitwise_xor
+  rvalue operator| (rvalue a, rvalue b); // bitwise_or
+  rvalue operator&& (rvalue a, rvalue b); // logical_and
+  rvalue operator|| (rvalue a, rvalue b); // logical_or
+
+  /* Comparisons.  */
+  rvalue operator== (rvalue a, rvalue b);
+  rvalue operator!= (rvalue a, rvalue b);
+  rvalue operator< (rvalue a, rvalue b);
+  rvalue operator<= (rvalue a, rvalue b);
+  rvalue operator> (rvalue a, rvalue b);
+  rvalue operator>= (rvalue a, rvalue b);
+
+  /* Dereferencing. */
+  lvalue operator* (rvalue ptr);
+}
+
+/****************************************************************************
+ Implementation of the API
+ ****************************************************************************/
+namespace gccjit {
+
+// class context
+inline context context::acquire ()
+{
+  return context (gcc_jit_context_acquire ());
+}
+inline context::context () : m_inner_ctxt (NULL) {}
+inline context::context (gcc_jit_context *inner) : m_inner_ctxt (inner)
+{
+  if (!inner)
+    throw error ();
+}
+
+inline gccjit::context
+context::new_child_context ()
+{
+  return context (gcc_jit_context_new_child_context (m_inner_ctxt));
+}
+
+inline void
+context::release ()
+{
+  gcc_jit_context_release (m_inner_ctxt);
+  m_inner_ctxt = NULL;
+}
+
+inline gcc_jit_result *
+context::compile ()
+{
+  gcc_jit_result *result = gcc_jit_context_compile (m_inner_ctxt);
+  if (!result)
+    throw error ();
+  return result;
+}
+
+inline void
+context::dump_to_file (const std::string &path,
+		       bool update_locations)
+{
+  gcc_jit_context_dump_to_file (m_inner_ctxt,
+				path.c_str (),
+				update_locations);
+}
+
+inline void
+context::set_int_option (enum gcc_jit_int_option opt,
+			 int value)
+{
+  gcc_jit_context_set_int_option (m_inner_ctxt, opt, value);
+
+}
+
+inline void
+context::set_bool_option (enum gcc_jit_bool_option opt,
+			  int value)
+{
+  gcc_jit_context_set_bool_option (m_inner_ctxt, opt, value);
+
+}
+
+inline location
+context::new_location (const std::string &filename,
+		       int line,
+		       int column)
+{
+  return location (gcc_jit_context_new_location (m_inner_ctxt,
+						 filename.c_str (),
+						 line,
+						 column));
+}
+
+inline type
+context::get_type (enum gcc_jit_types kind)
+{
+  return type (gcc_jit_context_get_type (m_inner_ctxt, kind));
+}
+
+inline type
+context::get_int_type (size_t num_bytes, int is_signed)
+{
+  return type (gcc_jit_context_get_int_type (m_inner_ctxt,
+					     num_bytes,
+					     is_signed));
+}
+
+template <typename T>
+inline type
+context::get_int_type ()
+{
+  return get_int_type (sizeof (T), std::numeric_limits<T>::is_signed);
+}
+
+inline type
+context::new_array_type (type element_type, int num_elements, location loc)
+{
+  return type (gcc_jit_context_new_array_type (
+		 m_inner_ctxt,
+		 loc.get_inner_location (),
+		 element_type.get_inner_type (),
+		 num_elements));
+}
+
+inline field
+context::new_field (type type_, const std::string &name, location loc)
+{
+  return field (gcc_jit_context_new_field (m_inner_ctxt,
+					   loc.get_inner_location (),
+					   type_.get_inner_type (),
+					   name.c_str ()));
+}
+
+inline struct_
+context::new_struct_type (const std::string &name,
+			  std::vector<field> &fields,
+			  location loc)
+{
+  /* Treat std::vector as an array, relying on it not being resized: */
+  field *as_array_of_wrappers = &fields[0];
+
+  /* Treat the array as being of the underlying pointers, relying on
+     the wrapper type being such a pointer internally.	*/
+  gcc_jit_field **as_array_of_ptrs =
+    reinterpret_cast<gcc_jit_field **> (as_array_of_wrappers);
+
+  return struct_ (gcc_jit_context_new_struct_type (m_inner_ctxt,
+						   loc.get_inner_location (),
+						   name.c_str (),
+						   fields.size (),
+						   as_array_of_ptrs));
+}
+
+inline struct_
+context::new_opaque_struct_type (const std::string &name,
+				 location loc)
+{
+  return struct_ (gcc_jit_context_new_opaque_struct (
+		    m_inner_ctxt,
+		    loc.get_inner_location (),
+		    name.c_str ()));
+}
+
+inline param
+context::new_param (type type_,
+		    const std::string &name,
+		    location loc)
+{
+  return param (gcc_jit_context_new_param (m_inner_ctxt,
+					   loc.get_inner_location (),
+					   type_.get_inner_type (),
+					   name.c_str ()));
+}
+
+inline function
+context::new_function (enum gcc_jit_function_kind kind,
+		       type return_type,
+		       const std::string &name,
+		       std::vector<param> &params,
+		       int is_variadic,
+		       location loc)
+{
+  /* Treat std::vector as an array, relying on it not being resized: */
+  param *as_array_of_wrappers = &params[0];
+
+  /* Treat the array as being of the underlying pointers, relying on
+     the wrapper type being such a pointer internally.	*/
+  gcc_jit_param **as_array_of_ptrs =
+    reinterpret_cast<gcc_jit_param **> (as_array_of_wrappers);
+
+  return function (gcc_jit_context_new_function (m_inner_ctxt,
+						 loc.get_inner_location (),
+						 kind,
+						 return_type.get_inner_type (),
+						 name.c_str (),
+						 params.size (),
+						 as_array_of_ptrs,
+						 is_variadic));
+}
+
+inline function
+context::get_builtin_function (const std::string &name)
+{
+  return function (gcc_jit_context_get_builtin_function (m_inner_ctxt,
+							 name.c_str ()));
+}
+
+inline lvalue
+context::new_global (type type_,
+		     const std::string &name,
+		     location loc)
+{
+  return lvalue (gcc_jit_context_new_global (m_inner_ctxt,
+					     loc.get_inner_location (),
+					     type_.get_inner_type (),
+					     name.c_str ()));
+}
+
+inline rvalue
+context::new_rvalue (type numeric_type,
+		     int value) const
+{
+  return rvalue (
+    gcc_jit_context_new_rvalue_from_int (m_inner_ctxt,
+					 numeric_type.get_inner_type (),
+					 value));
+}
+
+inline rvalue
+context::zero (type numeric_type) const
+{
+  return rvalue (gcc_jit_context_zero (m_inner_ctxt,
+				       numeric_type.get_inner_type ()));
+}
+
+inline rvalue
+context::one (type numeric_type) const
+{
+  return rvalue (gcc_jit_context_one (m_inner_ctxt,
+				       numeric_type.get_inner_type ()));
+}
+
+inline rvalue
+context::new_rvalue (type numeric_type,
+		     double value) const
+{
+  return rvalue (
+    gcc_jit_context_new_rvalue_from_double (m_inner_ctxt,
+					    numeric_type.get_inner_type (),
+					    value));
+}
+
+inline rvalue
+context::new_rvalue (type pointer_type,
+		     void *value) const
+{
+  return rvalue (
+    gcc_jit_context_new_rvalue_from_ptr (m_inner_ctxt,
+					 pointer_type.get_inner_type (),
+					 value));
+}
+
+inline rvalue
+context::new_rvalue (const std::string &value) const
+{
+  return rvalue (
+    gcc_jit_context_new_string_literal (m_inner_ctxt, value.c_str ()));
+}
+
+inline rvalue
+context::new_unary_op (enum gcc_jit_unary_op op,
+		       type result_type,
+		       rvalue a,
+		       location loc)
+{
+  return rvalue (gcc_jit_context_new_unary_op (m_inner_ctxt,
+					       loc.get_inner_location (),
+					       op,
+					       result_type.get_inner_type (),
+					       a.get_inner_rvalue ()));
+}
+inline rvalue
+context::new_minus (type result_type,
+		    rvalue a,
+		    location loc)
+{
+  return rvalue (new_unary_op (GCC_JIT_UNARY_OP_MINUS,
+			       result_type, a, loc));
+}
+inline rvalue
+context::new_bitwise_negate (type result_type,
+			     rvalue a,
+			     location loc)
+{
+  return rvalue (new_unary_op (GCC_JIT_UNARY_OP_BITWISE_NEGATE,
+			       result_type, a, loc));
+}
+inline rvalue
+context::new_logical_negate (type result_type,
+			     rvalue a,
+			     location loc)
+{
+  return rvalue (new_unary_op (GCC_JIT_UNARY_OP_LOGICAL_NEGATE,
+			       result_type, a, loc));
+}
+
+inline rvalue
+context::new_binary_op (enum gcc_jit_binary_op op,
+			type result_type,
+			rvalue a, rvalue b,
+			location loc)
+{
+  return rvalue (gcc_jit_context_new_binary_op (m_inner_ctxt,
+						loc.get_inner_location (),
+						op,
+						result_type.get_inner_type (),
+						a.get_inner_rvalue (),
+						b.get_inner_rvalue ()));
+}
+inline rvalue
+context::new_plus (type result_type,
+		   rvalue a, rvalue b,
+		   location loc)
+{
+  return new_binary_op (GCC_JIT_BINARY_OP_PLUS,
+			result_type, a, b, loc);
+}
+inline rvalue
+context::new_minus (type result_type,
+		    rvalue a, rvalue b,
+		    location loc)
+{
+  return new_binary_op (GCC_JIT_BINARY_OP_MINUS,
+			result_type, a, b, loc);
+}
+inline rvalue
+context::new_mult (type result_type,
+		   rvalue a, rvalue b,
+		   location loc)
+{
+  return new_binary_op (GCC_JIT_BINARY_OP_MULT,
+			result_type, a, b, loc);
+}
+inline rvalue
+context::new_divide (type result_type,
+		     rvalue a, rvalue b,
+		     location loc)
+{
+  return new_binary_op (GCC_JIT_BINARY_OP_DIVIDE,
+			result_type, a, b, loc);
+}
+inline rvalue
+context::new_modulo (type result_type,
+		     rvalue a, rvalue b,
+		     location loc)
+{
+  return new_binary_op (GCC_JIT_BINARY_OP_MODULO,
+			result_type, a, b, loc);
+}
+inline rvalue
+context::new_bitwise_and (type result_type,
+			  rvalue a, rvalue b,
+			  location loc)
+{
+  return new_binary_op (GCC_JIT_BINARY_OP_BITWISE_AND,
+			result_type, a, b, loc);
+}
+inline rvalue
+context::new_bitwise_xor (type result_type,
+			  rvalue a, rvalue b,
+			  location loc)
+{
+  return new_binary_op (GCC_JIT_BINARY_OP_BITWISE_XOR,
+			result_type, a, b, loc);
+}
+inline rvalue
+context::new_bitwise_or (type result_type,
+			 rvalue a, rvalue b,
+			 location loc)
+{
+  return new_binary_op (GCC_JIT_BINARY_OP_BITWISE_OR,
+			result_type, a, b, loc);
+}
+inline rvalue
+context::new_logical_and (type result_type,
+			  rvalue a, rvalue b,
+			  location loc)
+{
+  return new_binary_op (GCC_JIT_BINARY_OP_LOGICAL_AND,
+			result_type, a, b, loc);
+}
+inline rvalue
+context::new_logical_or (type result_type,
+			 rvalue a, rvalue b,
+			 location loc)
+{
+  return new_binary_op (GCC_JIT_BINARY_OP_LOGICAL_OR,
+			result_type, a, b, loc);
+}
+
+inline rvalue
+context::new_comparison (enum gcc_jit_comparison op,
+			 rvalue a, rvalue b,
+			 location loc)
+{
+  return rvalue (gcc_jit_context_new_comparison (m_inner_ctxt,
+						 loc.get_inner_location (),
+						 op,
+						 a.get_inner_rvalue (),
+						 b.get_inner_rvalue ()));
+}
+inline rvalue
+context::new_eq (rvalue a, rvalue b,
+		 location loc)
+{
+  return new_comparison (GCC_JIT_COMPARISON_EQ,
+			 a, b, loc);
+}
+inline rvalue
+context::new_ne (rvalue a, rvalue b,
+		 location loc)
+{
+  return new_comparison (GCC_JIT_COMPARISON_NE,
+			 a, b, loc);
+}
+inline rvalue
+context::new_lt (rvalue a, rvalue b,
+		 location loc)
+{
+  return new_comparison (GCC_JIT_COMPARISON_LT,
+			 a, b, loc);
+}
+inline rvalue
+context::new_le (rvalue a, rvalue b,
+		 location loc)
+{
+  return new_comparison (GCC_JIT_COMPARISON_LE,
+			 a, b, loc);
+}
+inline rvalue
+context::new_gt (rvalue a, rvalue b,
+		 location loc)
+{
+  return new_comparison (GCC_JIT_COMPARISON_GT,
+			 a, b, loc);
+}
+inline rvalue
+context::new_ge (rvalue a, rvalue b,
+		 location loc)
+{
+  return new_comparison (GCC_JIT_COMPARISON_GE,
+			 a, b, loc);
+}
+
+inline rvalue
+context::new_call (function func,
+		   std::vector<rvalue> &args,
+		   location loc)
+{
+  /* Treat std::vector as an array, relying on it not being resized: */
+  rvalue *as_array_of_wrappers = &args[0];
+
+  /* Treat the array as being of the underlying pointers, relying on
+     the wrapper type being such a pointer internally.	*/
+  gcc_jit_rvalue **as_array_of_ptrs =
+    reinterpret_cast<gcc_jit_rvalue **> (as_array_of_wrappers);
+  return gcc_jit_context_new_call (m_inner_ctxt,
+				   loc.get_inner_location (),
+				   func.get_inner_function (),
+				   args.size (),
+				   as_array_of_ptrs);
+}
+inline rvalue
+context::new_call (function func,
+		   location loc)
+{
+  std::vector<rvalue> args;
+  return new_call (func, args, loc);
+}
+
+inline rvalue
+context::new_call (function func,
+		   rvalue arg0,
+		   location loc)
+{
+  std::vector<rvalue> args(1);
+  args[0] = arg0;
+  return new_call (func, args, loc);
+}
+inline rvalue
+context::new_call (function func,
+		   rvalue arg0, rvalue arg1,
+		   location loc)
+{
+  std::vector<rvalue> args(2);
+  args[0] = arg0;
+  args[1] = arg1;
+  return new_call (func, args, loc);
+}
+inline rvalue
+context::new_call (function func,
+		   rvalue arg0, rvalue arg1, rvalue arg2,
+		   location loc)
+{
+  std::vector<rvalue> args(3);
+  args[0] = arg0;
+  args[1] = arg1;
+  args[2] = arg2;
+  return new_call (func, args, loc);
+}
+inline rvalue
+context::new_call (function func,
+		   rvalue arg0, rvalue arg1, rvalue arg2,
+		   rvalue arg3,
+		   location loc)
+{
+  std::vector<rvalue> args(4);
+  args[0] = arg0;
+  args[1] = arg1;
+  args[2] = arg2;
+  args[3] = arg3;
+  return new_call (func, args, loc);
+}
+inline rvalue
+context::new_call (function func,
+		   rvalue arg0, rvalue arg1, rvalue arg2,
+		   rvalue arg3, rvalue arg4,
+		   location loc)
+{
+  std::vector<rvalue> args(5);
+  args[0] = arg0;
+  args[1] = arg1;
+  args[2] = arg2;
+  args[3] = arg3;
+  args[4] = arg4;
+  return new_call (func, args, loc);
+}
+inline rvalue
+context::new_call (function func,
+		   rvalue arg0, rvalue arg1, rvalue arg2,
+		   rvalue arg3, rvalue arg4, rvalue arg5,
+		   location loc)
+{
+  std::vector<rvalue> args(6);
+  args[0] = arg0;
+  args[1] = arg1;
+  args[2] = arg2;
+  args[3] = arg3;
+  args[4] = arg4;
+  args[5] = arg5;
+  return new_call (func, args, loc);
+}
+
+inline rvalue
+context::new_cast (rvalue expr,
+		   type type_,
+		   location loc)
+{
+  return rvalue (gcc_jit_context_new_cast (m_inner_ctxt,
+					   loc.get_inner_location (),
+					   expr.get_inner_rvalue (),
+					   type_.get_inner_type ()));
+}
+
+inline lvalue
+context::new_array_access (rvalue ptr,
+			   rvalue index,
+			   location loc)
+{
+  return lvalue (gcc_jit_context_new_array_access (m_inner_ctxt,
+						   loc.get_inner_location (),
+						   ptr.get_inner_rvalue (),
+						   index.get_inner_rvalue ()));
+}
+
+// class object
+inline context
+object::get_context () const
+{
+  return context (gcc_jit_object_get_context (m_inner_obj));
+}
+
+inline std::string
+object::get_debug_string () const
+{
+  return gcc_jit_object_get_debug_string (m_inner_obj);
+}
+
+inline object::object () : m_inner_obj (NULL) {}
+inline object::object (gcc_jit_object *obj) : m_inner_obj (obj)
+{
+  if (!obj)
+    throw error ();
+}
+
+inline gcc_jit_object *
+object::get_inner_object () const
+{
+  return m_inner_obj;
+}
+
+inline std::ostream&
+operator << (std::ostream& stream, const object &obj)
+{
+  return stream << obj.get_debug_string ();
+}
+
+// class location
+inline location::location () : object () {}
+inline location::location (gcc_jit_location *loc)
+  : object (gcc_jit_location_as_object (loc))
+{}
+
+inline gcc_jit_location *
+location::get_inner_location () const
+{
+  /* Manual downcast: */
+  return reinterpret_cast<gcc_jit_location *> (get_inner_object ());
+}
+
+// class field
+inline field::field () : object () {}
+inline field::field (gcc_jit_field *inner)
+  : object (gcc_jit_field_as_object (inner))
+{}
+
+inline gcc_jit_field *
+field::get_inner_field () const
+{
+  /* Manual downcast: */
+  return reinterpret_cast<gcc_jit_field *> (get_inner_object ());
+}
+
+// class type
+inline type::type () : object () {}
+inline type::type (gcc_jit_type *inner)
+  : object (gcc_jit_type_as_object (inner))
+{}
+
+inline gcc_jit_type *
+type::get_inner_type () const
+{
+  /* Manual downcast: */
+  return reinterpret_cast<gcc_jit_type *> (get_inner_object ());
+}
+
+inline type
+type::get_pointer ()
+{
+  return type (gcc_jit_type_get_pointer (get_inner_type ()));
+}
+
+inline type
+type::get_volatile ()
+{
+  return type (gcc_jit_type_get_volatile (get_inner_type ()));
+}
+
+inline rvalue
+type::zero ()
+{
+  return get_context ().new_rvalue (*this, 0);
+}
+
+inline rvalue
+type::one ()
+{
+  return get_context ().new_rvalue (*this, 1);
+}
+
+// class struct_
+inline struct_::struct_ () : type (NULL) {}
+inline struct_::struct_ (gcc_jit_struct *inner) :
+  type (gcc_jit_struct_as_type (inner))
+{
+}
+
+inline gcc_jit_struct *
+struct_::get_inner_struct () const
+{
+  /* Manual downcast: */
+  return reinterpret_cast<gcc_jit_struct *> (get_inner_object ());
+}
+
+// class function
+inline function::function () : object () {}
+inline function::function (gcc_jit_function *inner)
+  : object (gcc_jit_function_as_object (inner))
+{}
+
+inline gcc_jit_function *
+function::get_inner_function () const
+{
+  /* Manual downcast: */
+  return reinterpret_cast<gcc_jit_function *> (get_inner_object ());
+}
+
+inline void
+function::dump_to_dot (const std::string &path)
+{
+  gcc_jit_function_dump_to_dot (get_inner_function (),
+				path.c_str ());
+}
+
+inline param
+function::get_param (int index) const
+{
+  return param (gcc_jit_function_get_param (get_inner_function (),
+					    index));
+}
+
+inline block
+function::new_block ()
+{
+  return block (gcc_jit_function_new_block (get_inner_function (),
+					    NULL));
+}
+
+inline block
+function::new_block (const std::string &name)
+{
+  return block (gcc_jit_function_new_block (get_inner_function (),
+					    name.c_str ()));
+}
+
+inline lvalue
+function::new_local (type type_,
+		     const std::string &name,
+		     location loc)
+{
+  return lvalue (gcc_jit_function_new_local (get_inner_function (),
+					     loc.get_inner_location (),
+					     type_.get_inner_type (),
+					     name.c_str ()));
+}
+
+inline function
+block::get_function () const
+{
+  return function (gcc_jit_block_get_function ( get_inner_block ()));
+}
+
+inline void
+block::add_eval (rvalue rvalue,
+		 location loc)
+{
+  gcc_jit_block_add_eval (get_inner_block (),
+			  loc.get_inner_location (),
+			  rvalue.get_inner_rvalue ());
+}
+
+inline void
+block::add_assignment (lvalue lvalue,
+		       rvalue rvalue,
+		       location loc)
+{
+  gcc_jit_block_add_assignment (get_inner_block (),
+				loc.get_inner_location (),
+				lvalue.get_inner_lvalue (),
+				rvalue.get_inner_rvalue ());
+}
+
+inline void
+block::add_assignment_op (lvalue lvalue,
+			  enum gcc_jit_binary_op op,
+			  rvalue rvalue,
+			  location loc)
+{
+  gcc_jit_block_add_assignment_op (get_inner_block (),
+				   loc.get_inner_location (),
+				   lvalue.get_inner_lvalue (),
+				   op,
+				   rvalue.get_inner_rvalue ());
+}
+
+inline void
+block::add_comment (const std::string &text,
+		    location loc)
+{
+  gcc_jit_block_add_comment (get_inner_block (),
+			     loc.get_inner_location (),
+			     text.c_str ());
+}
+
+inline void
+block::end_with_conditional (rvalue boolval,
+			     block on_true,
+			     block on_false,
+			     location loc)
+{
+  gcc_jit_block_end_with_conditional (get_inner_block (),
+				      loc.get_inner_location (),
+				      boolval.get_inner_rvalue (),
+				      on_true.get_inner_block (),
+				      on_false.get_inner_block ());
+}
+
+inline void
+block::end_with_jump (block target,
+		      location loc)
+{
+  gcc_jit_block_end_with_jump (get_inner_block (),
+			       loc.get_inner_location (),
+			       target.get_inner_block ());
+}
+
+inline void
+block::end_with_return (rvalue rvalue,
+			location loc)
+{
+  gcc_jit_block_end_with_return (get_inner_block (),
+				 loc.get_inner_location (),
+				 rvalue.get_inner_rvalue ());
+}
+
+inline void
+block::end_with_return (location loc)
+{
+  gcc_jit_block_end_with_void_return (get_inner_block (),
+				      loc.get_inner_location ());
+}
+
+inline rvalue
+block::add_call (function other,
+		 location loc)
+{
+  rvalue c = get_context ().new_call (other, loc);
+  add_eval (c);
+  return c;
+}
+inline rvalue
+block::add_call (function other,
+		 rvalue arg0,
+		 location loc)
+{
+  rvalue c = get_context ().new_call (other, arg0, loc);
+  add_eval (c);
+  return c;
+}
+inline rvalue
+block::add_call (function other,
+		 rvalue arg0, rvalue arg1,
+		 location loc)
+{
+  rvalue c = get_context ().new_call (other, arg0, arg1, loc);
+  add_eval (c);
+  return c;
+}
+inline rvalue
+block::add_call (function other,
+		 rvalue arg0, rvalue arg1, rvalue arg2,
+		 location loc)
+{
+  rvalue c = get_context ().new_call (other, arg0, arg1, arg2, loc);
+  add_eval (c);
+  return c;
+}
+
+inline rvalue
+block::add_call (function other,
+		 rvalue arg0, rvalue arg1, rvalue arg2, rvalue arg3,
+		 location loc)
+{
+  rvalue c = get_context ().new_call (other, arg0, arg1, arg2, arg3, loc);
+  add_eval (c);
+  return c;
+}
+
+inline rvalue
+function::operator() (location loc)
+{
+  return get_context ().new_call (*this, loc);
+}
+inline rvalue
+function::operator() (rvalue arg0,
+		      location loc)
+{
+  return get_context ().new_call (*this,
+				  arg0,
+				  loc);
+}
+inline rvalue
+function::operator() (rvalue arg0, rvalue arg1,
+		      location loc)
+{
+  return get_context ().new_call (*this,
+				  arg0, arg1,
+				  loc);
+}
+inline rvalue
+function::operator() (rvalue arg0, rvalue arg1, rvalue arg2,
+		      location loc)
+{
+  return get_context ().new_call (*this,
+				  arg0, arg1, arg2,
+				  loc);
+}
+
+// class block
+inline block::block () : object () {}
+inline block::block (gcc_jit_block *inner)
+  : object (gcc_jit_block_as_object (inner))
+{}
+
+inline gcc_jit_block *
+block::get_inner_block () const
+{
+  /* Manual downcast: */
+  return reinterpret_cast<gcc_jit_block *> (get_inner_object ());
+}
+
+//  class rvalue
+inline rvalue::rvalue () : object () {}
+inline rvalue::rvalue (gcc_jit_rvalue *inner)
+  : object (gcc_jit_rvalue_as_object (inner))
+{}
+
+inline gcc_jit_rvalue *
+rvalue::get_inner_rvalue () const
+{
+  /* Manual downcast: */
+  return reinterpret_cast<gcc_jit_rvalue *> (get_inner_object ());
+}
+
+inline type
+rvalue::get_type ()
+{
+  return type (gcc_jit_rvalue_get_type (get_inner_rvalue ()));
+}
+
+inline rvalue
+rvalue::access_field (field field,
+		      location loc)
+{
+  return rvalue (gcc_jit_rvalue_access_field (get_inner_rvalue (),
+					      loc.get_inner_location (),
+					      field.get_inner_field ()));
+}
+
+inline lvalue
+rvalue::dereference_field (field field,
+			   location loc)
+{
+  return lvalue (gcc_jit_rvalue_dereference_field (get_inner_rvalue (),
+						   loc.get_inner_location (),
+						   field.get_inner_field ()));
+}
+
+inline lvalue
+rvalue::dereference (location loc)
+{
+  return lvalue (gcc_jit_rvalue_dereference (get_inner_rvalue (),
+					     loc.get_inner_location ()));
+}
+
+inline rvalue
+rvalue::cast_to (type type_,
+		 location loc)
+{
+  return get_context ().new_cast (*this, type_, loc);
+}
+
+inline lvalue
+rvalue::operator[] (rvalue index)
+{
+  return get_context ().new_array_access (*this, index);
+}
+
+inline lvalue
+rvalue::operator[] (int index)
+{
+  context ctxt = get_context ();
+  type int_t = ctxt.get_int_type <int> ();
+  return ctxt.new_array_access (*this,
+				ctxt.new_rvalue (int_t,
+						 index));
+}
+
+// class lvalue : public rvalue
+inline lvalue::lvalue () : rvalue () {}
+inline lvalue::lvalue (gcc_jit_lvalue *inner)
+  : rvalue (gcc_jit_lvalue_as_rvalue (inner))
+{}
+
+inline gcc_jit_lvalue *
+lvalue::get_inner_lvalue () const
+{
+  /* Manual downcast: */
+  return reinterpret_cast<gcc_jit_lvalue *> (get_inner_object ());
+}
+
+inline lvalue
+lvalue::access_field (field field, location loc)
+{
+  return lvalue (gcc_jit_lvalue_access_field (get_inner_lvalue (),
+					      loc.get_inner_location (),
+					      field.get_inner_field ()));
+}
+
+inline rvalue
+lvalue::get_address (location loc)
+{
+  return rvalue (gcc_jit_lvalue_get_address (get_inner_lvalue (),
+					     loc.get_inner_location ()));
+}
+
+// class param : public lvalue
+inline param::param () : lvalue () {}
+inline param::param (gcc_jit_param *inner)
+  : lvalue (gcc_jit_param_as_lvalue (inner))
+{}
+
+/* Overloaded operators.  */
+// Unary operators
+inline rvalue operator- (rvalue a)
+{
+  return a.get_context ().new_minus (a.get_type (), a);
+}
+inline rvalue operator~ (rvalue a)
+{
+  return a.get_context ().new_bitwise_negate (a.get_type (), a);
+}
+inline rvalue operator! (rvalue a)
+{
+  return a.get_context ().new_logical_negate (a.get_type (), a);
+}
+
+// Binary operators
+inline rvalue operator+ (rvalue a, rvalue b)
+{
+  return a.get_context ().new_plus (a.get_type (), a, b);
+}
+inline rvalue operator- (rvalue a, rvalue b)
+{
+  return a.get_context ().new_minus (a.get_type (), a, b);
+}
+inline rvalue operator* (rvalue a, rvalue b)
+{
+  return a.get_context ().new_mult (a.get_type (), a, b);
+}
+inline rvalue operator/ (rvalue a, rvalue b)
+{
+  return a.get_context ().new_divide (a.get_type (), a, b);
+}
+inline rvalue operator% (rvalue a, rvalue b)
+{
+  return a.get_context ().new_modulo (a.get_type (), a, b);
+}
+inline rvalue operator& (rvalue a, rvalue b)
+{
+  return a.get_context ().new_bitwise_and (a.get_type (), a, b);
+}
+inline rvalue operator^ (rvalue a, rvalue b)
+{
+  return a.get_context ().new_bitwise_xor (a.get_type (), a, b);
+}
+inline rvalue operator| (rvalue a, rvalue b)
+{
+  return a.get_context ().new_bitwise_or (a.get_type (), a, b);
+}
+inline rvalue operator&& (rvalue a, rvalue b)
+{
+  return a.get_context ().new_logical_and (a.get_type (), a, b);
+}
+inline rvalue operator|| (rvalue a, rvalue b)
+{
+  return a.get_context ().new_logical_or (a.get_type (), a, b);
+}
+
+/* Comparisons.  */
+inline rvalue operator== (rvalue a, rvalue b)
+{
+  return a.get_context ().new_eq (a, b);
+}
+inline rvalue operator!= (rvalue a, rvalue b)
+{
+  return a.get_context ().new_ne (a, b);
+}
+inline rvalue operator< (rvalue a, rvalue b)
+{
+  return a.get_context ().new_lt (a, b);
+}
+inline rvalue operator<= (rvalue a, rvalue b)
+{
+  return a.get_context ().new_le (a, b);
+}
+inline rvalue operator> (rvalue a, rvalue b)
+{
+  return a.get_context ().new_gt (a, b);
+}
+inline rvalue operator>= (rvalue a, rvalue b)
+{
+  return a.get_context ().new_ge (a, b);
+}
+
+/* Dereferencing. */
+inline lvalue operator* (rvalue ptr)
+{
+  return ptr.dereference ();
+}
+
+} // namespace gccjit
+
+#endif /* #ifndef LIBGCCJIT_PLUS_PLUS_H */
-- 
1.8.5.3

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

* [PATCH 24/27] Documentation: add "topics" subdirectory
  2014-10-31 17:07 [PATCH 00/27] Merger of jit branch v3 David Malcolm
                   ` (18 preceding siblings ...)
  2014-10-31 17:31 ` [PATCH 16/27] New file: gcc/jit/jit-playback.c David Malcolm
@ 2014-10-31 17:31 ` David Malcolm
  2014-10-31 17:32 ` [PATCH 25/27] Documentation: add "internals" subdirectory David Malcolm
                   ` (5 subsequent siblings)
  25 siblings, 0 replies; 71+ messages in thread
From: David Malcolm @ 2014-10-31 17:31 UTC (permalink / raw)
  To: gcc-patches, jit; +Cc: David Malcolm

This patch adds a series of topic-based reference articles, intended
to give developers who've read the tutorial more detailed descriptions
of particular aspects of the library.

gcc/jit/
	* docs/topics/contexts.rst: New.
	* docs/topics/expressions.rst: New.
	* docs/topics/functions.rst: New.
	* docs/topics/index.rst: New.
	* docs/topics/locations.rst: New.
	* docs/topics/objects.rst: New.
	* docs/topics/results.rst: New.
	* docs/topics/types.rst: New.
---
 gcc/jit/docs/topics/contexts.rst    | 315 ++++++++++++++++++++++
 gcc/jit/docs/topics/expressions.rst | 524 ++++++++++++++++++++++++++++++++++++
 gcc/jit/docs/topics/functions.rst   | 311 +++++++++++++++++++++
 gcc/jit/docs/topics/index.rst       |  30 +++
 gcc/jit/docs/topics/locations.rst   |  69 +++++
 gcc/jit/docs/topics/objects.rst     |  86 ++++++
 gcc/jit/docs/topics/results.rst     |  48 ++++
 gcc/jit/docs/topics/types.rst       | 217 +++++++++++++++
 8 files changed, 1600 insertions(+)
 create mode 100644 gcc/jit/docs/topics/contexts.rst
 create mode 100644 gcc/jit/docs/topics/expressions.rst
 create mode 100644 gcc/jit/docs/topics/functions.rst
 create mode 100644 gcc/jit/docs/topics/index.rst
 create mode 100644 gcc/jit/docs/topics/locations.rst
 create mode 100644 gcc/jit/docs/topics/objects.rst
 create mode 100644 gcc/jit/docs/topics/results.rst
 create mode 100644 gcc/jit/docs/topics/types.rst

diff --git a/gcc/jit/docs/topics/contexts.rst b/gcc/jit/docs/topics/contexts.rst
new file mode 100644
index 0000000..d8dd4f8
--- /dev/null
+++ b/gcc/jit/docs/topics/contexts.rst
@@ -0,0 +1,315 @@
+.. Copyright (C) 2014 Free Software Foundation, Inc.
+   Originally contributed by David Malcolm <dmalcolm@redhat.com>
+
+   This is free software: you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see
+   <http://www.gnu.org/licenses/>.
+
+.. default-domain:: c
+
+Compilation contexts
+====================
+
+.. type:: gcc_jit_context
+
+The top-level of the API is the :c:type:`gcc_jit_context` type.
+
+A :c:type:`gcc_jit_context` instance encapsulates the state of a
+compilation.
+
+You can set up options on it, and add types, functions and code.
+Invoking :c:func:`gcc_jit_context_compile` on it gives you a
+:c:type:`gcc_jit_result`.
+
+Lifetime-management
+-------------------
+Contexts are the unit of lifetime-management within the API: objects
+have their lifetime bounded by the context they are created within, and
+cleanup of such objects is done for you when the context is released.
+
+.. function:: gcc_jit_context *gcc_jit_context_acquire (void)
+
+  This function acquires a new :c:type:`gcc_jit_object *` instance,
+  which is independent of any others that may be present within this
+  process.
+
+.. function:: void gcc_jit_context_release (gcc_jit_context *ctxt)
+
+  This function releases all resources associated with the given context.
+  Both the context itself and all of its :c:type:`gcc_jit_object *`
+  instances are cleaned up.  It should be called exactly once on a given
+  context.
+
+  It is invalid to use the context or any of its "contextual" objects
+  after calling this.
+
+  .. code-block:: c
+
+    gcc_jit_context_release (ctxt);
+
+.. function:: gcc_jit_context * gcc_jit_context_new_child_context (gcc_jit_context *parent_ctxt)
+
+   Given an existing JIT context, create a child context.
+
+   The child inherits a copy of all option-settings from the parent.
+
+   The child can reference objects created within the parent, but not
+   vice-versa.
+
+   The lifetime of the child context must be bounded by that of the
+   parent: you should release a child context before releasing the parent
+   context.
+
+   If you use a function from a parent context within a child context,
+   you have to compile the parent context before you can compile the
+   child context, and the gcc_jit_result of the parent context must
+   outlive the gcc_jit_result of the child context.
+
+   This allows caching of shared initializations.  For example, you could
+   create types and declarations of global functions in a parent context
+   once within a process, and then create child contexts whenever a
+   function or loop becomes hot. Each such child context can be used for
+   JIT-compiling just one function or loop, but can reference types
+   and helper functions created within the parent context.
+
+   Contexts can be arbitrarily nested, provided the above rules are
+   followed, but it's probably not worth going above 2 or 3 levels, and
+   there will likely be a performance hit for such nesting.
+
+
+Thread-safety
+-------------
+Instances of :c:type:`gcc_jit_object *` created via
+:c:func:`gcc_jit_context_acquire` are independent from each other:
+only one thread may use a given context at once, but multiple threads
+could each have their own contexts without needing locks.
+
+Contexts created via :c:func:`gcc_jit_context_new_child_context` are
+related to their parent context.  They can be partitioned by their
+ultimate ancestor into independent "family trees".   Only one thread
+within a process may use a given "family tree" of such contexts at once,
+and if you're using multiple threads you should provide your own locking
+around entire such context partitions.
+
+
+Error-handling
+--------------
+You can only compile and get code from a context if no errors occur.
+
+In general, if an error occurs when using an API entrypoint, it returns
+NULL.  You don't have to check everywhere for NULL results, since the
+API gracefully handles a NULL being passed in for any argument.
+
+Errors are printed on stderr and can be queried using
+:c:func:`gcc_jit_context_get_first_error`.
+
+.. function:: const char *\
+              gcc_jit_context_get_first_error (gcc_jit_context *ctxt)
+
+   Returns the first error message that occurred on the context.
+
+   The returned string is valid for the rest of the lifetime of the
+   context.
+
+   If no errors occurred, this will be NULL.
+
+Debugging
+---------
+
+.. function:: void\
+              gcc_jit_context_dump_to_file (gcc_jit_context *ctxt,\
+                                            const char *path,\
+                                            int update_locations)
+
+   To help with debugging: dump a C-like representation to the given path,
+   describing what's been set up on the context.
+
+   If "update_locations" is true, then also set up :type:`gcc_jit_location`
+   information throughout the context, pointing at the dump file as if it
+   were a source file.  This may be of use in conjunction with
+   :macro:`GCC_JIT_BOOL_OPTION_DEBUGINFO` to allow stepping through the
+   code in a debugger.
+
+
+Options
+-------
+
+String Options
+**************
+
+.. function:: void gcc_jit_context_set_str_option(gcc_jit_context *ctxt, \
+                                                  enum gcc_jit_str_option opt, \
+                                                  const char *value)
+
+   Set a string option of the context.
+
+   .. type:: enum gcc_jit_str_option
+
+   There is currently just one string option:
+
+   .. macro:: GCC_JIT_STR_OPTION_PROGNAME
+
+      The name of the program, for use as a prefix when printing error
+      messages to stderr.  If `NULL`, or default, "libgccjit.so" is used.
+
+Boolean options
+***************
+
+.. function:: void gcc_jit_context_set_bool_option(gcc_jit_context *ctxt, \
+				                   enum gcc_jit_bool_option opt, \
+				                   int value)
+
+  Set a boolean option of the context.
+  Zero is "false" (the default), non-zero is "true".
+
+  .. type:: enum gcc_jit_bool_option
+
+  .. macro:: GCC_JIT_BOOL_OPTION_DEBUGINFO
+
+     If true, :func:`gcc_jit_context_compile` will attempt to do the right
+     thing so that if you attach a debugger to the process, it will
+     be able to inspect variables and step through your code.
+
+     Note that you can't step through code unless you set up source
+     location information for the code (by creating and passing in
+     :type:`gcc_jit_location` instances).
+
+  .. macro:: GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE
+
+     If true, :func:`gcc_jit_context_compile` will dump its initial
+     "tree" representation of your code to stderr (before any
+     optimizations).
+
+     Here's some sample output (from the `square` example)::
+
+        <statement_list 0x7f4875a62cc0
+           type <void_type 0x7f4875a64bd0 VOID
+               align 8 symtab 0 alias set -1 canonical type 0x7f4875a64bd0
+               pointer_to_this <pointer_type 0x7f4875a64c78>>
+           side-effects head 0x7f4875a761e0 tail 0x7f4875a761f8 stmts 0x7f4875a62d20 0x7f4875a62d00
+
+           stmt <label_expr 0x7f4875a62d20 type <void_type 0x7f4875a64bd0>
+               side-effects
+               arg 0 <label_decl 0x7f4875a79080 entry type <void_type 0x7f4875a64bd0>
+                   VOID file (null) line 0 col 0
+                   align 1 context <function_decl 0x7f4875a77500 square>>>
+           stmt <return_expr 0x7f4875a62d00
+               type <integer_type 0x7f4875a645e8 public SI
+                   size <integer_cst 0x7f4875a623a0 constant 32>
+                   unit size <integer_cst 0x7f4875a623c0 constant 4>
+                   align 32 symtab 0 alias set -1 canonical type 0x7f4875a645e8 precision 32 min <integer_cst 0x7f4875a62340 -2147483648> max <integer_cst 0x7f4875a62360 2147483647>
+                   pointer_to_this <pointer_type 0x7f4875a6b348>>
+               side-effects
+               arg 0 <modify_expr 0x7f4875a72a78 type <integer_type 0x7f4875a645e8>
+                   side-effects arg 0 <result_decl 0x7f4875a7a000 D.54>
+                   arg 1 <mult_expr 0x7f4875a72a50 type <integer_type 0x7f4875a645e8>
+                       arg 0 <parm_decl 0x7f4875a79000 i> arg 1 <parm_decl 0x7f4875a79000 i>>>>>
+
+  .. macro:: GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE
+
+     If true, :func:`gcc_jit_context_compile` will dump the "gimple"
+     representation of your code to stderr, before any optimizations
+     are performed.  The dump resembles C code:
+
+     .. code-block:: c
+
+       square (signed int i)
+       {
+         signed int D.56;
+
+         entry:
+         D.56 = i * i;
+         return D.56;
+       }
+
+  .. macro:: GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE
+
+     If true, :func:`gcc_jit_context_compile` will dump the final
+     generated code to stderr, in the form of assembly language:
+
+     .. code-block:: gas
+
+           .file    "fake.c"
+           .text
+           .globl    square
+           .type    square, @function
+       square:
+       .LFB0:
+           .cfi_startproc
+           pushq    %rbp
+           .cfi_def_cfa_offset 16
+           .cfi_offset 6, -16
+           movq    %rsp, %rbp
+           .cfi_def_cfa_register 6
+           movl    %edi, -4(%rbp)
+       .L2:
+           movl    -4(%rbp), %eax
+           imull    -4(%rbp), %eax
+           popq    %rbp
+           .cfi_def_cfa 7, 8
+           ret
+           .cfi_endproc
+       .LFE0:
+           .size    square, .-square
+           .ident    "GCC: (GNU) 4.9.0 20131023 (Red Hat 0.1-%{gcc_release})"
+           .section    .note.GNU-stack,"",@progbits
+
+
+  .. macro:: GCC_JIT_BOOL_OPTION_DUMP_SUMMARY
+
+     If true, :func:`gcc_jit_context_compile` will print information to stderr
+     on the actions it is performing, followed by a profile showing
+     the time taken and memory usage of each phase.
+
+  .. macro:: GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING
+
+     If true, :func:`gcc_jit_context_compile` will dump copious
+     amount of information on what it's doing to various
+     files within a temporary directory.  Use
+     :macro:`GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES` (see below) to
+     see the results.  The files are intended to be human-readable,
+     but the exact files and their formats are subject to change.
+
+  .. macro:: GCC_JIT_BOOL_OPTION_SELFCHECK_GC
+
+     If true, libgccjit will aggressively run its garbage collector, to
+     shake out bugs (greatly slowing down the compile).  This is likely
+     to only be of interest to developers *of* the library.  It is
+     used when running the selftest suite.
+
+  .. macro:: GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES
+
+     If true, the :type:`gcc_jit_context` will not clean up intermediate files
+     written to the filesystem, and will display their location on stderr.
+
+Integer options
+***************
+
+.. function:: void gcc_jit_context_set_int_option (gcc_jit_context *ctxt, \
+				                   enum gcc_jit_int_option opt, \
+				                   int value)
+
+  Set an integer option of the context.
+
+  .. type:: enum gcc_jit_int_option
+
+  There is currently just one integer option:
+
+  .. macro:: GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL
+
+     How much to optimize the code.
+
+     Valid values are 0-3, corresponding to GCC's command-line options
+     -O0 through -O3.
+
+     The default value is 0 (unoptimized).
diff --git a/gcc/jit/docs/topics/expressions.rst b/gcc/jit/docs/topics/expressions.rst
new file mode 100644
index 0000000..a95f5c9
--- /dev/null
+++ b/gcc/jit/docs/topics/expressions.rst
@@ -0,0 +1,524 @@
+.. Copyright (C) 2014 Free Software Foundation, Inc.
+   Originally contributed by David Malcolm <dmalcolm@redhat.com>
+
+   This is free software: you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see
+   <http://www.gnu.org/licenses/>.
+
+.. default-domain:: c
+
+Expressions
+===========
+
+Rvalues
+-------
+.. type:: gcc_jit_rvalue
+
+A :c:type:`gcc_jit_rvalue *` is an expression that can be computed.
+
+It can be simple, e.g.:
+
+  * an integer value e.g. `0` or `42`
+  * a string literal e.g. `"Hello world"`
+  * a variable e.g. `i`.  These are also lvalues (see below).
+
+or compound e.g.:
+
+  * a unary expression e.g. `!cond`
+  * a binary expression e.g. `(a + b)`
+  * a function call e.g. `get_distance (&player_ship, &target)`
+  * etc.
+
+Every rvalue has an associated type, and the API will check to ensure
+that types match up correctly (otherwise the context will emit an error).
+
+.. function:: gcc_jit_type *gcc_jit_rvalue_get_type (gcc_jit_rvalue *rvalue)
+
+  Get the type of this rvalue.
+
+.. function:: gcc_jit_object *gcc_jit_rvalue_as_object (gcc_jit_rvalue *rvalue)
+
+  Upcast the given rvalue to be an object.
+
+
+Simple expressions
+******************
+
+.. function:: gcc_jit_rvalue *\
+              gcc_jit_context_new_rvalue_from_int (gcc_jit_context *ctxt, \
+                                                   gcc_jit_type *numeric_type, \
+                                                   int value)
+
+   Given a numeric type (integer or floating point), build an rvalue for
+   the given constant value.
+
+.. function::  gcc_jit_rvalue *gcc_jit_context_zero (gcc_jit_context *ctxt, \
+                                                     gcc_jit_type *numeric_type)
+
+   Given a numeric type (integer or floating point), get the rvalue for
+   zero.  Essentially this is just a shortcut for:
+
+   .. code-block:: c
+
+      gcc_jit_context_new_rvalue_from_int (ctxt, numeric_type, 0)
+
+.. function::  gcc_jit_rvalue *gcc_jit_context_one (gcc_jit_context *ctxt, \
+                                                    gcc_jit_type *numeric_type)
+
+   Given a numeric type (integer or floating point), get the rvalue for
+   zero.  Essentially this is just a shortcut for:
+
+   .. code-block:: c
+
+      gcc_jit_context_new_rvalue_from_int (ctxt, numeric_type, 1)
+
+.. function::  gcc_jit_rvalue *\
+               gcc_jit_context_new_rvalue_from_double (gcc_jit_context *ctxt, \
+                                                       gcc_jit_type *numeric_type, \
+                                                       double value)
+
+   Given a numeric type (integer or floating point), build an rvalue for
+   the given constant value.
+
+.. function:: gcc_jit_rvalue *\
+              gcc_jit_context_new_rvalue_from_ptr (gcc_jit_context *ctxt, \
+                                                   gcc_jit_type *pointer_type, \
+                                                   void *value)
+
+   Given a pointer type, build an rvalue for the given address.
+
+.. function:: gcc_jit_rvalue *gcc_jit_context_null (gcc_jit_context *ctxt, \
+                                                    gcc_jit_type *pointer_type)
+
+   Given a pointer type, build an rvalue for ``NULL``.  Essentially this
+   is just a shortcut for:
+
+   .. code-block:: c
+
+      gcc_jit_context_new_rvalue_from_ptr (ctxt, pointer_type, NULL)
+
+.. function:: gcc_jit_rvalue *\
+              gcc_jit_context_new_string_literal (gcc_jit_context *ctxt, \
+                                                  const char *value)
+
+   Generate an rvalue for the given NIL-terminated string, of type
+   :c:data:`GCC_JIT_TYPE_CONST_CHAR_PTR`.
+
+
+Unary Operations
+****************
+
+.. function:: gcc_jit_rvalue * \
+              gcc_jit_context_new_unary_op (gcc_jit_context *ctxt, \
+                                            gcc_jit_location *loc, \
+                                            enum gcc_jit_unary_op op, \
+                                            gcc_jit_type *result_type, \
+                                            gcc_jit_rvalue *rvalue)
+
+   Build a unary operation out of an input rvalue.
+
+.. type:: enum gcc_jit_unary_op
+
+The available unary operations are:
+
+==========================================  ============
+Unary Operation                             C equivalent
+==========================================  ============
+:c:macro:`GCC_JIT_UNARY_OP_MINUS`           `-(EXPR)`
+:c:macro:`GCC_JIT_UNARY_OP_BITWISE_NEGATE`  `~(EXPR)`
+:c:macro:`GCC_JIT_UNARY_OP_LOGICAL_NEGATE`  `!(EXPR)`
+==========================================  ============
+
+.. c:macro:: GCC_JIT_UNARY_OP_MINUS
+
+    Negate an arithmetic value; analogous to:
+
+    .. code-block:: c
+
+       -(EXPR)
+
+    in C.
+
+.. c:macro:: GCC_JIT_UNARY_OP_BITWISE_NEGATE
+
+    Bitwise negation of an integer value (one's complement); analogous
+    to:
+
+    .. code-block:: c
+
+       ~(EXPR)
+
+    in C.
+
+.. c:macro:: GCC_JIT_UNARY_OP_LOGICAL_NEGATE
+
+    Logical negation of an arithmetic or pointer value; analogous to:
+
+    .. code-block:: c
+
+       !(EXPR)
+
+    in C.
+
+Binary Operations
+*****************
+
+.. function:: gcc_jit_rvalue *gcc_jit_context_new_binary_op (gcc_jit_context *ctxt, \
+                                                             gcc_jit_location *loc, \
+                                                             enum gcc_jit_binary_op op, \
+                                                             gcc_jit_type *result_type, \
+                                                             gcc_jit_rvalue *a, gcc_jit_rvalue *b)
+
+   Build a binary operation out of two constituent rvalues.
+
+.. type:: enum gcc_jit_binary_op
+
+The available binary operations are:
+
+========================================  ============
+Binary Operation                          C equivalent
+========================================  ============
+:c:macro:`GCC_JIT_BINARY_OP_PLUS`         `x + y`
+:c:macro:`GCC_JIT_BINARY_OP_MINUS`        `x - y`
+:c:macro:`GCC_JIT_BINARY_OP_MULT`         `x * y`
+:c:macro:`GCC_JIT_BINARY_OP_DIVIDE`       `x / y`
+:c:macro:`GCC_JIT_BINARY_OP_MODULO`       `x % y`
+:c:macro:`GCC_JIT_BINARY_OP_BITWISE_AND`  `x & y`
+:c:macro:`GCC_JIT_BINARY_OP_BITWISE_XOR`  `x ^ y`
+:c:macro:`GCC_JIT_BINARY_OP_BITWISE_OR`   `x | y`
+:c:macro:`GCC_JIT_BINARY_OP_LOGICAL_AND`  `x && y`
+:c:macro:`GCC_JIT_BINARY_OP_LOGICAL_OR`   `x || y`
+:c:macro:`GCC_JIT_BINARY_OP_LSHIFT`       `x << y`
+:c:macro:`GCC_JIT_BINARY_OP_RSHIFT`       `x >> y`
+========================================  ============
+
+.. c:macro:: GCC_JIT_BINARY_OP_PLUS
+
+   Addition of arithmetic values; analogous to:
+
+   .. code-block:: c
+
+     (EXPR_A) + (EXPR_B)
+
+   in C.
+
+   For pointer addition, use :c:func:`gcc_jit_context_new_array_access`.
+
+.. c:macro:: GCC_JIT_BINARY_OP_MINUS`
+
+   Subtraction of arithmetic values; analogous to:
+
+   .. code-block:: c
+
+     (EXPR_A) - (EXPR_B)
+
+   in C.
+
+.. c:macro:: GCC_JIT_BINARY_OP_MULT
+
+   Multiplication of a pair of arithmetic values; analogous to:
+
+   .. code-block:: c
+
+     (EXPR_A) * (EXPR_B)
+
+   in C.
+
+.. c:macro:: GCC_JIT_BINARY_OP_DIVIDE
+
+   Quotient of division of arithmetic values; analogous to:
+
+   .. code-block:: c
+
+     (EXPR_A) / (EXPR_B)
+
+   in C.
+
+   The result type affects the kind of division: if the result type is
+   integer-based, then the result is truncated towards zero, whereas
+   a floating-point result type indicates floating-point division.
+
+.. c:macro:: GCC_JIT_BINARY_OP_MODULO
+
+   Remainder of division of arithmetic values; analogous to:
+
+   .. code-block:: c
+
+     (EXPR_A) % (EXPR_B)
+
+   in C.
+
+.. c:macro:: GCC_JIT_BINARY_OP_BITWISE_AND
+
+   Bitwise AND; analogous to:
+
+   .. code-block:: c
+
+     (EXPR_A) & (EXPR_B)
+
+   in C.
+
+.. c:macro:: GCC_JIT_BINARY_OP_BITWISE_XOR
+
+   Bitwise exclusive OR; analogous to:
+
+   .. code-block:: c
+
+      (EXPR_A) ^ (EXPR_B)
+
+   in C.
+
+.. c:macro:: GCC_JIT_BINARY_OP_BITWISE_OR
+
+   Bitwise inclusive OR; analogous to:
+
+   .. code-block:: c
+
+     (EXPR_A) | (EXPR_B)
+
+   in C.
+
+.. c:macro:: GCC_JIT_BINARY_OP_LOGICAL_AND
+
+   Logical AND; analogous to:
+
+   .. code-block:: c
+
+     (EXPR_A) && (EXPR_B)
+
+   in C.
+
+.. c:macro:: GCC_JIT_BINARY_OP_LOGICAL_OR
+
+   Logical OR; analogous to:
+
+   .. code-block:: c
+
+     (EXPR_A) || (EXPR_B)
+
+   in C.
+
+.. c:macro:: GCC_JIT_BINARY_OP_LSHIFT
+
+   Left shift; analogous to:
+
+   .. code-block:: c
+
+     (EXPR_A) << (EXPR_B)
+
+   in C.
+
+.. c:macro:: GCC_JIT_BINARY_OP_RSHIFT
+
+   Right shift; analogous to:
+
+   .. code-block:: c
+
+     (EXPR_A) >> (EXPR_B)
+
+   in C.
+
+Comparisons
+***********
+
+.. function:: gcc_jit_rvalue *\
+              gcc_jit_context_new_comparison (gcc_jit_context *ctxt,\
+                                              gcc_jit_location *loc,\
+                                              enum gcc_jit_comparison op,\
+                                              gcc_jit_rvalue *a, gcc_jit_rvalue *b)
+
+   Build a boolean rvalue out of the comparison of two other rvalues.
+
+.. type:: enum gcc_jit_comparison
+
+=======================================  ============
+Comparison                               C equivalent
+=======================================  ============
+:c:macro:`GCC_JIT_COMPARISON_EQ`         `x == y`
+:c:macro:`GCC_JIT_COMPARISON_NE`         `x != y`
+:c:macro:`GCC_JIT_COMPARISON_LT`         `x < y`
+:c:macro:`GCC_JIT_COMPARISON_LE`         `x <= y`
+:c:macro:`GCC_JIT_COMPARISON_GT`         `x > y`
+:c:macro:`GCC_JIT_COMPARISON_GE`         `x >= y`
+=======================================  ============
+
+
+Function calls
+**************
+.. function:: gcc_jit_rvalue *\
+              gcc_jit_context_new_call (gcc_jit_context *ctxt,\
+                                        gcc_jit_location *loc,\
+                                        gcc_jit_function *func,\
+                                        int numargs , gcc_jit_rvalue **args)
+
+   Given a function and the given table of argument rvalues, construct a
+   call to the function, with the result as an rvalue.
+
+   .. note::
+
+      :c:func:`gcc_jit_context_new_call` merely builds a
+      :c:type:`gcc_jit_rvalue` i.e. an expression that can be evaluated,
+      perhaps as part of a more complicated expression.
+      The call *won't* happen unless you add a statement to a function
+      that evaluates the expression.
+
+      For example, if you want to call a function and discard the result
+      (or to call a function with ``void`` return type), use
+      :c:func:`gcc_jit_block_add_eval`:
+
+      .. code-block:: c
+
+         /* Add "(void)printf (arg0, arg1);".  */
+         gcc_jit_block_add_eval (
+           block, NULL,
+           gcc_jit_context_new_call (
+             ctxt,
+             NULL,
+             printf_func,
+             2, args));
+
+Type-coercion
+*************
+
+.. function:: gcc_jit_rvalue *\
+              gcc_jit_context_new_cast (gcc_jit_context *ctxt,\
+                                        gcc_jit_location *loc,\
+                                        gcc_jit_rvalue *rvalue,\
+                                        gcc_jit_type *type)
+
+   Given an rvalue of T, construct another rvalue of another type.
+
+   Currently only a limited set of conversions are possible:
+
+     * int <-> float
+     * int <-> bool
+
+Lvalues
+-------
+
+.. type:: gcc_jit_lvalue
+
+An lvalue is something that can of the *left*-hand side of an assignment:
+a storage area (such as a variable).  It is also usable as an rvalue,
+where the rvalue is computed by reading from the storage area.
+
+.. function:: gcc_jit_object *\
+              gcc_jit_lvalue_as_object (gcc_jit_lvalue *lvalue)
+
+   Upcast an lvalue to be an object.
+
+.. function:: gcc_jit_rvalue *\
+              gcc_jit_lvalue_as_rvalue (gcc_jit_lvalue *lvalue)
+
+   Upcast an lvalue to be an rvalue.
+
+.. function:: gcc_jit_rvalue *\
+              gcc_jit_lvalue_get_address (gcc_jit_lvalue *lvalue,\
+                                          gcc_jit_location *loc)
+
+   Take the address of an lvalue; analogous to:
+
+   .. code-block:: c
+
+     &(EXPR)
+
+   in C.
+
+Global variables
+****************
+
+.. function:: gcc_jit_lvalue *\
+              gcc_jit_context_new_global (gcc_jit_context *ctxt,\
+                                          gcc_jit_location *loc,\
+                                          gcc_jit_type *type,\
+                                          const char *name)
+
+   Add a new global variable of the given type and name to the context.
+
+
+Working with pointers, structs and unions
+-----------------------------------------
+
+.. function:: gcc_jit_lvalue *\
+              gcc_jit_rvalue_dereference (gcc_jit_rvalue *rvalue,\
+                                          gcc_jit_location *loc)
+
+   Given an rvalue of pointer type ``T *``, dereferencing the pointer,
+   getting an lvalue of type ``T``.  Analogous to:
+
+   .. code-block:: c
+
+     *(EXPR)
+
+   in C.
+
+Field access is provided separately for both lvalues and rvalues.
+
+.. function:: gcc_jit_lvalue *\
+              gcc_jit_lvalue_access_field (gcc_jit_lvalue *struct_,\
+                                           gcc_jit_location *loc,\
+                                           gcc_jit_field *field)
+
+   Given an lvalue of struct or union type, access the given field,
+   getting an lvalue of the field's type.  Analogous to:
+
+   .. code-block:: c
+
+      (EXPR).field = ...;
+
+   in C.
+
+.. function:: gcc_jit_rvalue *\
+              gcc_jit_rvalue_access_field (gcc_jit_rvalue *struct_,\
+                                           gcc_jit_location *loc,\
+                                           gcc_jit_field *field)
+
+   Given an rvalue of struct or union type, access the given field
+   as an rvalue.  Analogous to:
+
+   .. code-block:: c
+
+      (EXPR).field
+
+   in C.
+
+.. function:: gcc_jit_lvalue *\
+              gcc_jit_rvalue_dereference_field (gcc_jit_rvalue *ptr,\
+                                                gcc_jit_location *loc,\
+                                                gcc_jit_field *field)
+
+   Given an rvalue of pointer type ``T *`` where T is of struct or union
+   type, access the given field as an lvalue.  Analogous to:
+
+   .. code-block:: c
+
+      (EXPR)->field
+
+   in C, itself equivalent to ``(*EXPR).FIELD``.
+
+.. function:: gcc_jit_lvalue *\
+              gcc_jit_context_new_array_access (gcc_jit_context *ctxt,\
+                                                gcc_jit_location *loc,\
+                                                gcc_jit_rvalue *ptr,\
+                                                gcc_jit_rvalue *index)
+
+   Given an rvalue of pointer type ``T *``, get at the element `T` at
+   the given index, using standard C array indexing rules i.e. each
+   increment of ``index`` corresponds to ``sizeof(T)`` bytes.
+   Analogous to:
+
+   .. code-block:: c
+
+      PTR[INDEX]
+
+   in C (or, indeed, to ``PTR + INDEX``).
diff --git a/gcc/jit/docs/topics/functions.rst b/gcc/jit/docs/topics/functions.rst
new file mode 100644
index 0000000..aa0c069
--- /dev/null
+++ b/gcc/jit/docs/topics/functions.rst
@@ -0,0 +1,311 @@
+.. Copyright (C) 2014 Free Software Foundation, Inc.
+   Originally contributed by David Malcolm <dmalcolm@redhat.com>
+
+   This is free software: you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see
+   <http://www.gnu.org/licenses/>.
+
+.. default-domain:: c
+
+Creating and using functions
+============================
+
+Params
+------
+.. type:: gcc_jit_param
+
+   A `gcc_jit_param` represents a parameter to a function.
+
+.. function:: gcc_jit_param *\
+              gcc_jit_context_new_param (gcc_jit_context *ctxt,\
+                                         gcc_jit_location *loc,\
+                                         gcc_jit_type *type,\
+                                         const char *name)
+
+   In preparation for creating a function, create a new parameter of the
+   given type and name.
+
+Parameters are lvalues, and thus are also rvalues (and objects), so the
+following upcasts are available:
+
+.. function::  gcc_jit_lvalue *\
+               gcc_jit_param_as_lvalue (gcc_jit_param *param)
+
+   Upcasting from param to lvalue.
+
+.. function::  gcc_jit_rvalue *\
+               gcc_jit_param_as_rvalue (gcc_jit_param *param)
+
+   Upcasting from param to rvalue.
+
+.. function::  gcc_jit_object *\
+               gcc_jit_param_as_object (gcc_jit_param *param)
+
+   Upcasting from param to object.
+
+
+Functions
+---------
+
+.. type:: gcc_jit_function
+
+   A `gcc_jit_function` represents a function - either one that we're
+   creating ourselves, or one that we're referencing.
+
+.. function::  gcc_jit_function *\
+               gcc_jit_context_new_function (gcc_jit_context *ctxt,\
+                                             gcc_jit_location *loc,\
+                                             enum gcc_jit_function_kind kind,\
+                                             gcc_jit_type *return_type,\
+                                             const char *name,\
+                                             int num_params,\
+                                             gcc_jit_param **params,\
+                                             int is_variadic)
+
+   Create a gcc_jit_function with the given name and parameters.
+
+   .. type:: enum gcc_jit_function_kind
+
+   This enum controls the kind of function created, and has the following
+   values:
+
+      .. macro:: GCC_JIT_FUNCTION_EXPORTED
+
+         Function is defined by the client code and visible
+         by name outside of the JIT.
+
+      .. macro::   GCC_JIT_FUNCTION_INTERNAL
+
+         Function is defined by the client code, but is invisible
+         outside of the JIT.  Analogous to a "static" function.
+
+      .. macro::   GCC_JIT_FUNCTION_IMPORTED
+
+         Function is not defined by the client code; we're merely
+         referring to it.  Analogous to using an "extern" function from a
+         header file.
+
+      .. macro::   GCC_JIT_FUNCTION_ALWAYS_INLINE
+
+         Function is only ever inlined into other functions, and is
+         invisible outside of the JIT.
+
+         Analogous to prefixing with ``inline`` and adding
+         ``__attribute__((always_inline))``
+
+         Inlining will only occur when the optimization level is
+         above 0; when optimization is off, this is essentially the
+         same as GCC_JIT_FUNCTION_INTERNAL.
+
+.. function::  gcc_jit_function *\
+               gcc_jit_context_get_builtin_function (gcc_jit_context *ctxt,\
+                                                     const char *name)
+
+.. function::  gcc_jit_object *\
+               gcc_jit_function_as_object (gcc_jit_function *func)
+
+    Upcasting from function to object.
+
+.. function::  gcc_jit_param *\
+               gcc_jit_function_get_param (gcc_jit_function *func, int index)
+
+   Get the param of the given index (0-based).
+
+.. function::  void \
+               gcc_jit_function_dump_to_dot (gcc_jit_function *func,\
+                                             const char *path)
+
+   Emit the function in graphviz format to the given path.
+
+.. function:: gcc_jit_lvalue *\
+              gcc_jit_function_new_local (gcc_jit_function *func,\
+                                          gcc_jit_location *loc,\
+                                          gcc_jit_type *type,\
+                                          const char *name)
+
+   Create a new local variable within the function, of the given type and
+   name.
+
+
+Blocks
+------
+.. type:: gcc_jit_block
+
+   A `gcc_jit_block` represents a basic block within a function  i.e. a
+   sequence of statements with a single entry point and a single exit
+   point.
+
+   The first basic block that you create within a function will
+   be the entrypoint.
+
+   Each basic block that you create within a function must be
+   terminated, either with a conditional, a jump, or a return.
+
+   It's legal to have multiple basic blocks that return within
+   one function.
+
+.. function::  gcc_jit_block *\
+               gcc_jit_function_new_block (gcc_jit_function *func,\
+                                           const char *name)
+
+   Create a basic block of the given name.  The name may be NULL, but
+   providing meaningful names is often helpful when debugging: it may
+   show up in dumps of the internal representation, and in error
+   messages.
+
+.. function::  gcc_jit_object *\
+               gcc_jit_block_as_object (gcc_jit_block *block)
+
+   Upcast from block to object.
+
+.. function::  gcc_jit_function *\
+               gcc_jit_block_get_function (gcc_jit_block *block)
+
+   Which function is this block within?
+
+
+Statements
+----------
+
+.. function:: void\
+              gcc_jit_block_add_eval (gcc_jit_block *block,\
+                                      gcc_jit_location *loc,\
+                                      gcc_jit_rvalue *rvalue)
+
+   Add evaluation of an rvalue, discarding the result
+   (e.g. a function call that "returns" void).
+
+   This is equivalent to this C code:
+
+   .. code-block:: c
+
+     (void)expression;
+
+.. function:: void\
+              gcc_jit_block_add_assignment (gcc_jit_block *block,\
+                                            gcc_jit_location *loc,\
+                                            gcc_jit_lvalue *lvalue,\
+                                            gcc_jit_rvalue *rvalue)
+
+   Add evaluation of an rvalue, assigning the result to the given
+   lvalue.
+
+   This is roughly equivalent to this C code:
+
+   .. code-block:: c
+
+     lvalue = rvalue;
+
+.. function:: void\
+              gcc_jit_block_add_assignment_op (gcc_jit_block *block,\
+                                 gcc_jit_location *loc,\
+                                 gcc_jit_lvalue *lvalue,\
+                                 enum gcc_jit_binary_op op,\
+                                 gcc_jit_rvalue *rvalue)
+
+   Add evaluation of an rvalue, using the result to modify an
+   lvalue.
+
+   This is analogous to "+=" and friends:
+
+   .. code-block:: c
+
+     lvalue += rvalue;
+     lvalue *= rvalue;
+     lvalue /= rvalue;
+
+   etc.  For example:
+
+   .. code-block:: c
+
+     /* "i++" */
+     gcc_jit_block_add_assignment_op (
+       loop_body, NULL,
+       i,
+       GCC_JIT_BINARY_OP_PLUS,
+       gcc_jit_context_one (ctxt, int_type));
+
+.. function:: void\
+              gcc_jit_block_add_comment (gcc_jit_block *block,\
+                                         gcc_jit_location *loc,\
+                                         const char *text)
+
+   Add a no-op textual comment to the internal representation of the
+   code.  It will be optimized away, but will be visible in the dumps
+   seen via :macro:`GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE`
+   and :macro:`GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE`,
+   and thus may be of use when debugging how your project's internal
+   representation gets converted to the libgccjit IR.
+
+.. function:: void\
+              gcc_jit_block_end_with_conditional (gcc_jit_block *block,\
+                                                  gcc_jit_location *loc,\
+                                                  gcc_jit_rvalue *boolval,\
+                                                  gcc_jit_block *on_true,\
+                                                  gcc_jit_block *on_false)
+
+   Terminate a block by adding evaluation of an rvalue, branching on the
+   result to the appropriate successor block.
+
+   This is roughly equivalent to this C code:
+
+   .. code-block:: c
+
+     if (boolval)
+       goto on_true;
+     else
+       goto on_false;
+
+   block, boolval, on_true, and on_false must be non-NULL.
+
+.. function:: void\
+              gcc_jit_block_end_with_jump (gcc_jit_block *block,\
+                                           gcc_jit_location *loc,\
+                                           gcc_jit_block *target)
+
+
+   Terminate a block by adding a jump to the given target block.
+
+   This is roughly equivalent to this C code:
+
+   .. code-block:: c
+
+      goto target;
+
+.. function:: void\
+              gcc_jit_block_end_with_return (gcc_jit_block *block,\
+                                             gcc_jit_location *loc,\
+                                             gcc_jit_rvalue *rvalue)
+
+
+   Terminate a block by adding evaluation of an rvalue, returning the value.
+
+   This is roughly equivalent to this C code:
+
+   .. code-block:: c
+
+      return expression;
+
+.. function:: void\
+              gcc_jit_block_end_with_void_return (gcc_jit_block *block,\
+                                                  gcc_jit_location *loc)
+
+
+   Terminate a block by adding a valueless return, for use within a function
+   with "void" return type.
+
+   This is equivalent to this C code:
+
+   .. code-block:: c
+
+      return;
diff --git a/gcc/jit/docs/topics/index.rst b/gcc/jit/docs/topics/index.rst
new file mode 100644
index 0000000..a129137
--- /dev/null
+++ b/gcc/jit/docs/topics/index.rst
@@ -0,0 +1,30 @@
+.. Copyright (C) 2014 Free Software Foundation, Inc.
+   Originally contributed by David Malcolm <dmalcolm@redhat.com>
+
+   This is free software: you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see
+   <http://www.gnu.org/licenses/>.
+
+Topic Reference
+===============
+
+.. toctree::
+   :maxdepth: 2
+
+   contexts.rst
+   objects.rst
+   types.rst
+   expressions.rst
+   functions.rst
+   locations.rst
+   results.rst
diff --git a/gcc/jit/docs/topics/locations.rst b/gcc/jit/docs/topics/locations.rst
new file mode 100644
index 0000000..d1db974
--- /dev/null
+++ b/gcc/jit/docs/topics/locations.rst
@@ -0,0 +1,69 @@
+.. Copyright (C) 2014 Free Software Foundation, Inc.
+   Originally contributed by David Malcolm <dmalcolm@redhat.com>
+
+   This is free software: you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see
+   <http://www.gnu.org/licenses/>.
+
+.. default-domain:: c
+
+Source Locations
+================
+
+.. type:: gcc_jit_location
+
+   A `gcc_jit_location` encapsulates a source code location, so that
+   you can (optionally) associate locations in your language with
+   statements in the JIT-compiled code, allowing the debugger to
+   single-step through your language.
+
+   `gcc_jit_location` instances are optional: you can always pass NULL to
+   any API entrypoint accepting one.
+
+   You can construct them using :c:func:`gcc_jit_context_new_location`.
+
+   You need to enable :c:macro:`GCC_JIT_BOOL_OPTION_DEBUGINFO` on the
+   :c:type:`gcc_jit_context` for these locations to actually be usable by
+   the debugger:
+
+   .. code-block:: c
+
+     gcc_jit_context_set_bool_option (
+       ctxt,
+       GCC_JIT_BOOL_OPTION_DEBUGINFO,
+       1);
+
+.. function:: gcc_jit_location *\
+              gcc_jit_context_new_location (gcc_jit_context *ctxt,\
+                                            const char *filename,\
+                                            int line,\
+                                            int column)
+
+   Create a `gcc_jit_location` instance representing the given source
+   location.
+
+Faking it
+---------
+If you don't have source code for your internal representation, but need
+to debug, you can generate a C-like representation of the functions in
+your context using :c:func:`gcc_jit_context_dump_to_file()`:
+
+.. code-block:: c
+
+  gcc_jit_context_dump_to_file (ctxt, "/tmp/something.c",
+                                1 /* update_locations */);
+
+This will dump C-like code to the given path.  If the `update_locations`
+argument is true, this will also set up `gcc_jit_location` information
+throughout the context, pointing at the dump file as if it were a source
+file, giving you *something* you can step through in the debugger.
diff --git a/gcc/jit/docs/topics/objects.rst b/gcc/jit/docs/topics/objects.rst
new file mode 100644
index 0000000..b05888d
--- /dev/null
+++ b/gcc/jit/docs/topics/objects.rst
@@ -0,0 +1,86 @@
+.. Copyright (C) 2014 Free Software Foundation, Inc.
+   Originally contributed by David Malcolm <dmalcolm@redhat.com>
+
+   This is free software: you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see
+   <http://www.gnu.org/licenses/>.
+
+.. default-domain:: c
+
+Objects
+=======
+
+.. type:: gcc_jit_object
+
+Almost every entity in the API (with the exception of
+:c:type:`gcc_jit_context *` and :c:type:`gcc_jit_result *`) is a
+"contextual" object, a :c:type:`gcc_jit_object *`
+
+A JIT object:
+
+  * is associated with a :c:type:`gcc_jit_context *`.
+
+  * is automatically cleaned up for you when its context is released so
+    you don't need to manually track and cleanup all objects, just the
+    contexts.
+
+Although the API is C-based, there is a form of class hierarchy, which
+looks like this::
+
+  +- gcc_jit_object
+      +- gcc_jit_location
+      +- gcc_jit_type
+         +- gcc_jit_struct
+      +- gcc_jit_field
+      +- gcc_jit_function
+      +- gcc_jit_block
+      +- gcc_jit_rvalue
+          +- gcc_jit_lvalue
+             +- gcc_jit_param
+
+There are casting methods for upcasting from subclasses to parent classes.
+For example, :c:func:`gcc_jit_type_as_object`:
+
+.. code-block:: c
+
+   gcc_jit_object *obj = gcc_jit_type_as_object (int_type);
+
+The object "base class" has the following operations:
+
+.. function:: gcc_jit_context *gcc_jit_object_get_context (gcc_jit_object *obj)
+
+  Which context is "obj" within?
+
+
+.. function:: const char *gcc_jit_object_get_debug_string (gcc_jit_object *obj)
+
+  Generate a human-readable description for the given object.
+
+  For example,
+
+  .. code-block:: c
+
+     printf ("obj: %s\n", gcc_jit_object_get_debug_string (obj));
+
+  might give this text on stdout:
+
+  .. code-block:: bash
+
+     obj: 4.0 * (float)i
+
+  .. note::
+
+     If you call this on an object, the `const char *` buffer is allocated
+     and generated on the first call for that object, and the buffer will
+     have the same lifetime as the object  i.e. it will exist until the
+     object's context is released.
diff --git a/gcc/jit/docs/topics/results.rst b/gcc/jit/docs/topics/results.rst
new file mode 100644
index 0000000..10dc94f
--- /dev/null
+++ b/gcc/jit/docs/topics/results.rst
@@ -0,0 +1,48 @@
+.. Copyright (C) 2014 Free Software Foundation, Inc.
+   Originally contributed by David Malcolm <dmalcolm@redhat.com>
+
+   This is free software: you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see
+   <http://www.gnu.org/licenses/>.
+
+.. default-domain:: c
+
+Compilation results
+===================
+
+.. type:: gcc_jit_result
+
+  A `gcc_jit_result` encapsulates the result of compiling a context.
+
+.. function:: gcc_jit_result *\
+              gcc_jit_context_compile (gcc_jit_context *ctxt)
+
+   This calls into GCC and builds the code, returning a
+   `gcc_jit_result *`.
+
+
+.. function:: void *\
+              gcc_jit_result_get_code (gcc_jit_result *result,\
+                                       const char *funcname)
+
+   Locate a given function within the built machine code.
+   This will need to be cast to a function pointer of the
+   correct type before it can be called.
+
+
+.. function:: void\
+              gcc_jit_result_release (gcc_jit_result *result)
+
+   Once we're done with the code, this unloads the built .so file.
+   This cleans up the result; after calling this, it's no longer
+   valid to use the result.
diff --git a/gcc/jit/docs/topics/types.rst b/gcc/jit/docs/topics/types.rst
new file mode 100644
index 0000000..6770eca
--- /dev/null
+++ b/gcc/jit/docs/topics/types.rst
@@ -0,0 +1,217 @@
+.. Copyright (C) 2014 Free Software Foundation, Inc.
+   Originally contributed by David Malcolm <dmalcolm@redhat.com>
+
+   This is free software: you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see
+   <http://www.gnu.org/licenses/>.
+
+.. default-domain:: c
+
+Types
+=====
+
+.. c:type:: gcc_jit_type
+
+   gcc_jit_type represents a type within the library.
+
+.. function:: gcc_jit_object *gcc_jit_type_as_object (gcc_jit_type *type)
+
+   Upcast a type to an object.
+
+Types can be created in several ways:
+
+* fundamental types can be accessed using
+  :func:`gcc_jit_context_get_type`:
+
+  .. code-block:: c
+
+      gcc_jit_type *int_type = gcc_jit_context_get_type (GCC_JIT_TYPE_INT);
+
+  See :func:`gcc_jit_context_get_type` for the available types.
+
+* derived types can be accessed by using functions such as
+  :func:`gcc_jit_type_get_pointer` and :func:`gcc_jit_type_get_const`:
+
+  .. code-block:: c
+
+    gcc_jit_type *const_int_star = gcc_jit_type_get_pointer (gcc_jit_type_get_const (int_type));
+    gcc_jit_type *int_const_star = gcc_jit_type_get_const (gcc_jit_type_get_pointer (int_type));
+
+* by creating structures (see below).
+
+Standard types
+--------------
+
+.. function:: gcc_jit_type *gcc_jit_context_get_type (gcc_jit_context *ctxt, \
+                                                      enum gcc_jit_types type_)
+
+   Access a specific type.  The available types are:
+
+   =========================================  ================================
+   `enum gcc_jit_types` value                 Meaning
+   =========================================  ================================
+   :c:data:`GCC_JIT_TYPE_VOID`                C's ``void`` type.
+   :c:data:`GCC_JIT_TYPE_VOID_PTR`            C's ``void *``.
+   :c:data:`GCC_JIT_TYPE_BOOL`                C++'s ``bool`` type; also C99's
+                                              ``_Bool`` type, aka ``bool`` if
+                                              using stdbool.h.
+   :c:data:`GCC_JIT_TYPE_CHAR`                C's ``char`` (of some signedness)
+   :c:data:`GCC_JIT_TYPE_SIGNED_CHAR`         C's ``signed char``
+   :c:data:`GCC_JIT_TYPE_UNSIGNED_CHAR`       C's ``unsigned char``
+   :c:data:`GCC_JIT_TYPE_SHORT`               C's ``short`` (signed)
+   :c:data:`GCC_JIT_TYPE_UNSIGNED_SHORT`      C's ``unsigned short``
+   :c:data:`GCC_JIT_TYPE_INT`                 C's ``int`` (signed)
+   :c:data:`GCC_JIT_TYPE_UNSIGNED_INT`        C's ``unsigned int``
+   :c:data:`GCC_JIT_TYPE_LONG`                C's ``long`` (signed)
+   :c:data:`GCC_JIT_TYPE_UNSIGNED_LONG`       C's ``unsigned long``
+   :c:data:`GCC_JIT_TYPE_LONG_LONG`           C99's ``long long`` (signed)
+   :c:data:`GCC_JIT_TYPE_UNSIGNED_LONG_LONG`  C99's ``unsigned long long``
+   :c:data:`GCC_JIT_TYPE_FLOAT`
+   :c:data:`GCC_JIT_TYPE_DOUBLE`
+   :c:data:`GCC_JIT_TYPE_LONG_DOUBLE`
+   :c:data:`GCC_JIT_TYPE_CONST_CHAR_PTR`      C type: ``(const char *)``
+   :c:data:`GCC_JIT_TYPE_SIZE_T`              C's ``size_t`` type
+   :c:data:`GCC_JIT_TYPE_FILE_PTR`            C type: ``(FILE *)``
+   =========================================  ================================
+
+.. function:: gcc_jit_type *\
+              gcc_jit_context_get_int_type (gcc_jit_context *ctxt, \
+                                            int num_bytes, int is_signed)
+
+   Access the integer type of the given size.
+
+
+Pointers, `const`, and `volatile`
+---------------------------------
+
+.. function::  gcc_jit_type *gcc_jit_type_get_pointer (gcc_jit_type *type)
+
+   Given type "T", get type "T*".
+
+.. function::  gcc_jit_type *gcc_jit_type_get_const (gcc_jit_type *type)
+
+   Given type "T", get type "const T".
+
+.. function::  gcc_jit_type *gcc_jit_type_get_volatile (gcc_jit_type *type)
+
+   Given type "T", get type "volatile T".
+
+.. function::  gcc_jit_type *\
+               gcc_jit_context_new_array_type (gcc_jit_context *ctxt, \
+                                               gcc_jit_location *loc, \
+                                               gcc_jit_type *element_type, \
+                                               int num_elements)
+
+   Given type "T", get type "T[N]" (for a constant N).
+
+
+Structures and unions
+---------------------
+
+.. c:type:: gcc_jit_struct
+
+A compound type analagous to a C `struct`.
+
+.. c:type:: gcc_jit_field
+
+A field within a :c:type:`gcc_jit_struct`.
+
+You can model C `struct` types by creating :c:type:`gcc_jit_struct *` and
+:c:type:`gcc_jit_field` instances, in either order:
+
+* by creating the fields, then the structure.  For example, to model:
+
+  .. code-block:: c
+
+    struct coord {double x; double y; };
+
+  you could call:
+
+  .. code-block:: c
+
+    gcc_jit_field *field_x =
+      gcc_jit_context_new_field (ctxt, NULL, double_type, "x");
+    gcc_jit_field *field_y =
+      gcc_jit_context_new_field (ctxt, NULL, double_type, "y");
+    gcc_jit_field *fields[2] = {field_x, field_y};
+    gcc_jit_struct *coord =
+      gcc_jit_context_new_struct_type (ctxt, NULL, "coord", 2, fields);
+
+* by creating the structure, then populating it with fields, typically
+  to allow modelling self-referential structs such as:
+
+  .. code-block:: c
+
+    struct node { int m_hash; struct node *m_next; };
+
+  like this:
+
+  .. code-block:: c
+
+    gcc_jit_type *node =
+      gcc_jit_context_new_opaque_struct (ctxt, NULL, "node");
+    gcc_jit_type *node_ptr =
+      gcc_jit_type_get_pointer (node);
+    gcc_jit_field *field_hash =
+      gcc_jit_context_new_field (ctxt, NULL, int_type, "m_hash");
+    gcc_jit_field *field_next =
+      gcc_jit_context_new_field (ctxt, NULL, node_ptr, "m_next");
+    gcc_jit_field *fields[2] = {field_hash, field_next};
+    gcc_jit_struct_set_fields (node, NULL, 2, fields);
+
+.. function:: gcc_jit_field *\
+              gcc_jit_context_new_field (gcc_jit_context *ctxt,\
+                                         gcc_jit_location *loc,\
+                                         gcc_jit_type *type,\
+                                         const char *name)
+
+   Construct a new field, with the given type and name.
+
+.. function:: gcc_jit_object *\
+              gcc_jit_field_as_object (gcc_jit_field *field)
+
+   Upcast from field to object.
+
+.. function:: gcc_jit_struct *\
+   gcc_jit_context_new_struct_type (gcc_jit_context *ctxt,\
+                                    gcc_jit_location *loc,\
+                                    const char *name,\
+                                    int num_fields,\
+                                    gcc_jit_field **fields)
+
+     Construct a new struct type, with the given name and fields.
+
+.. function:: gcc_jit_struct *\
+              gcc_jit_context_new_opaque_struct (gcc_jit_context *ctxt,\
+                                                 gcc_jit_location *loc,\
+                                                 const char *name)
+
+     Construct a new struct type, with the given name, but without
+     specifying the fields.   The fields can be omitted (in which case the
+     size of the struct is not known), or later specified using
+     :c:func:`gcc_jit_struct_set_fields`.
+
+.. function:: gcc_jit_type *\
+              gcc_jit_struct_as_type (gcc_jit_struct *struct_type)
+
+   Upcast from struct to type.
+
+.. function:: void\
+              gcc_jit_struct_set_fields (gcc_jit_struct *struct_type,\
+                                         gcc_jit_location *loc,\
+                                         int num_fields,\
+                                         gcc_jit_field **fields)
+
+   Populate the fields of a formerly-opaque struct type.
+
+   This can only be called once on a given struct type.
-- 
1.8.5.3

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

* [PATCH 16/27] New file: gcc/jit/jit-playback.c
  2014-10-31 17:07 [PATCH 00/27] Merger of jit branch v3 David Malcolm
                   ` (17 preceding siblings ...)
  2014-10-31 17:30 ` [PATCH 17/27] New file: gcc/jit/libgccjit++.h David Malcolm
@ 2014-10-31 17:31 ` David Malcolm
  2014-11-04 22:21   ` Jeff Law
  2014-10-31 17:31 ` [PATCH 24/27] Documentation: add "topics" subdirectory David Malcolm
                   ` (6 subsequent siblings)
  25 siblings, 1 reply; 71+ messages in thread
From: David Malcolm @ 2014-10-31 17:31 UTC (permalink / raw)
  To: gcc-patches, jit; +Cc: David Malcolm

This files implements the gcc::jit::playback internal API, called by
the dummy "frontend" to replay the public API calls made to the
library.  A thin wrapper around trees.

gcc/jit/
	* jit-playback.c: New.
---
 gcc/jit/jit-playback.c | 2104 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 2104 insertions(+)
 create mode 100644 gcc/jit/jit-playback.c

diff --git a/gcc/jit/jit-playback.c b/gcc/jit/jit-playback.c
new file mode 100644
index 0000000..dc1b468
--- /dev/null
+++ b/gcc/jit/jit-playback.c
@@ -0,0 +1,2104 @@
+/* Internals of libgccjit: classes for playing back recorded API calls.
+   Copyright (C) 2013-2014 Free Software Foundation, Inc.
+   Contributed by David Malcolm <dmalcolm@redhat.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "opts.h"
+#include "tree.h"
+#include "cgraph.h"
+#include "toplev.h"
+#include "timevar.h"
+#include "tree-cfg.h"
+#include "target.h"
+#include "convert.h"
+#include "stringpool.h"
+#include "stor-layout.h"
+#include "print-tree.h"
+#include "gimplify.h"
+#include "gcc-driver-name.h"
+
+#include "jit-common.h"
+#include "jit-playback.h"
+
+
+/* gcc::jit::playback::context::build_cast uses the convert.h API,
+   which in turn requires the frontend to provide a "convert"
+   function, apparently as a fallback.
+
+   Hence we provide this dummy one, with the requirement that any casts
+   are handled before reaching this.  */
+extern tree convert (tree type, tree expr);
+
+tree
+convert (tree dst_type, tree expr)
+{
+  gcc_assert (gcc::jit::active_playback_ctxt);
+  gcc::jit::active_playback_ctxt->add_error (NULL, "unhandled conversion");
+  fprintf (stderr, "input expression:\n");
+  debug_tree (expr);
+  fprintf (stderr, "requested type:\n");
+  debug_tree (dst_type);
+  return error_mark_node;
+}
+
+namespace gcc {
+namespace jit {
+
+/**********************************************************************
+ Playback.
+ **********************************************************************/
+
+/* The constructor for gcc::jit::playback::context.  */
+
+playback::context::context (recording::context *ctxt)
+  : m_recording_ctxt (ctxt),
+    m_char_array_type_node (NULL),
+    m_const_char_ptr (NULL)
+{
+  m_functions.create (0);
+  m_source_files.create (0);
+  m_cached_locations.create (0);
+}
+
+/* The destructor for gcc::jit::playback::context.  */
+
+playback::context::~context ()
+{
+  if (get_bool_option (GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES))
+    fprintf (stderr, "intermediate files written to %s\n", m_path_tempdir);
+  else
+    {
+      /* Clean up .s/.so and tempdir. */
+      if (m_path_s_file)
+        unlink (m_path_s_file);
+      if (m_path_so_file)
+        unlink (m_path_so_file);
+      if (m_path_tempdir)
+        rmdir (m_path_tempdir);
+    }
+
+  free (m_path_template);
+  /* m_path_tempdir aliases m_path_template, or is NULL, so don't
+     attempt to free it .  */
+  free (m_path_c_file);
+  free (m_path_s_file);
+  free (m_path_so_file);
+  m_functions.release ();
+}
+
+/* A playback::context can reference GC-managed pointers.  Mark them
+   ("by hand", rather than by gengtype).
+
+   This is called on the active playback context (if any) by the
+   my_ggc_walker hook in the jit_root_table in dummy-frontend.c.  */
+
+void
+playback::context::
+gt_ggc_mx ()
+{
+  int i;
+  function *func;
+  FOR_EACH_VEC_ELT (m_functions, i, func)
+    {
+      if (ggc_test_and_set_mark (func))
+	func->gt_ggc_mx ();
+    }
+}
+
+/* Given an enum gcc_jit_types value, get a "tree" type.  */
+
+static tree
+get_tree_node_for_type (enum gcc_jit_types type_)
+{
+  switch (type_)
+    {
+    case GCC_JIT_TYPE_VOID:
+      return void_type_node;
+
+    case GCC_JIT_TYPE_VOID_PTR:
+      return ptr_type_node;
+
+    case GCC_JIT_TYPE_BOOL:
+      return boolean_type_node;
+
+    case GCC_JIT_TYPE_CHAR:
+      return char_type_node;
+    case GCC_JIT_TYPE_SIGNED_CHAR:
+      return signed_char_type_node;
+    case GCC_JIT_TYPE_UNSIGNED_CHAR:
+      return unsigned_char_type_node;
+
+    case GCC_JIT_TYPE_SHORT:
+      return short_integer_type_node;
+    case GCC_JIT_TYPE_UNSIGNED_SHORT:
+      return short_unsigned_type_node;
+
+    case GCC_JIT_TYPE_CONST_CHAR_PTR:
+      {
+	tree const_char = build_qualified_type (char_type_node,
+						TYPE_QUAL_CONST);
+	return build_pointer_type (const_char);
+      }
+
+    case GCC_JIT_TYPE_INT:
+      return integer_type_node;
+    case GCC_JIT_TYPE_UNSIGNED_INT:
+      return unsigned_type_node;
+
+    case GCC_JIT_TYPE_LONG:
+      return long_integer_type_node;
+    case GCC_JIT_TYPE_UNSIGNED_LONG:
+      return long_unsigned_type_node;
+
+    case GCC_JIT_TYPE_LONG_LONG:
+      return long_long_integer_type_node;
+    case GCC_JIT_TYPE_UNSIGNED_LONG_LONG:
+      return long_long_unsigned_type_node;
+
+    case GCC_JIT_TYPE_FLOAT:
+      return float_type_node;
+    case GCC_JIT_TYPE_DOUBLE:
+      return double_type_node;
+    case GCC_JIT_TYPE_LONG_DOUBLE:
+      return long_double_type_node;
+
+    case GCC_JIT_TYPE_SIZE_T:
+      return size_type_node;
+
+    case GCC_JIT_TYPE_FILE_PTR:
+      return fileptr_type_node;
+    }
+
+  return NULL;
+}
+
+/* Construct a playback::type instance (wrapping a tree) for the given
+   enum value.  */
+
+playback::type *
+playback::context::
+get_type (enum gcc_jit_types type_)
+{
+  tree type_node = get_tree_node_for_type (type_);
+  if (NULL == type_node)
+    {
+      add_error (NULL,
+		 "unrecognized (enum gcc_jit_types) value: %i", type_);
+      return NULL;
+    }
+
+  return new type (type_node);
+}
+
+/* Construct a playback::type instance (wrapping a tree) for the given
+   array type.  */
+
+playback::type *
+playback::context::
+new_array_type (playback::location *loc,
+		playback::type *element_type,
+		int num_elements)
+{
+  gcc_assert (element_type);
+
+  tree t = build_array_type_nelts (element_type->as_tree (),
+				   num_elements);
+  layout_type (t);
+
+  if (loc)
+    set_tree_location (t, loc);
+
+  return new type (t);
+}
+
+/* Construct a playback::field instance (wrapping a tree).  */
+
+playback::field *
+playback::context::
+new_field (location *loc,
+	   type *type,
+	   const char *name)
+{
+  gcc_assert (type);
+  gcc_assert (name);
+
+  /* compare with c/c-decl.c:grokfield and grokdeclarator.  */
+  tree decl = build_decl (UNKNOWN_LOCATION, FIELD_DECL,
+			  get_identifier (name), type->as_tree ());
+
+  if (loc)
+    set_tree_location (decl, loc);
+
+  return new field (decl);
+}
+
+/* Construct a playback::compound_type instance (wrapping a tree).  */
+
+playback::compound_type *
+playback::context::
+new_compound_type (location *loc,
+		   const char *name,
+		   bool is_struct) /* else is union */
+{
+  gcc_assert (name);
+
+  /* Compare with c/c-decl.c: start_struct. */
+
+  tree t = make_node (is_struct ? RECORD_TYPE : UNION_TYPE);
+  TYPE_NAME (t) = get_identifier (name);
+  TYPE_SIZE (t) = 0;
+
+  if (loc)
+    set_tree_location (t, loc);
+
+  return new compound_type (t);
+}
+
+void
+playback::compound_type::set_fields (const vec<playback::field *> &fields)
+{
+  /* Compare with c/c-decl.c: finish_struct. */
+  tree t = as_tree ();
+
+  tree fieldlist = NULL;
+  for (unsigned i = 0; i < fields.length (); i++)
+    {
+      field *f = fields[i];
+      DECL_CONTEXT (f->as_tree ()) = t;
+      fieldlist = chainon (f->as_tree (), fieldlist);
+    }
+  fieldlist = nreverse (fieldlist);
+  TYPE_FIELDS (t) = fieldlist;
+
+  layout_type (t);
+}
+
+/* Construct a playback::type instance (wrapping a tree) for a function
+   type.  */
+
+playback::type *
+playback::context::
+new_function_type (type *return_type,
+		   vec<type *> *param_types,
+		   int is_variadic)
+{
+  int i;
+  type *param_type;
+
+  tree *arg_types = (tree *)xcalloc(param_types->length (), sizeof(tree*));
+
+  FOR_EACH_VEC_ELT (*param_types, i, param_type)
+    arg_types[i] = param_type->as_tree ();
+
+  tree fn_type;
+  if (is_variadic)
+    fn_type =
+      build_varargs_function_type_array (return_type->as_tree (),
+					 param_types->length (),
+					 arg_types);
+  else
+    fn_type = build_function_type_array (return_type->as_tree (),
+					 param_types->length (),
+					 arg_types);
+  free (arg_types);
+
+  return new type (fn_type);
+}
+
+/* Construct a playback::param instance (wrapping a tree).  */
+
+playback::param *
+playback::context::
+new_param (location *loc,
+	   type *type,
+	   const char *name)
+{
+  gcc_assert (type);
+  gcc_assert (name);
+  tree inner = build_decl (UNKNOWN_LOCATION, PARM_DECL,
+			   get_identifier (name), type->as_tree ());
+  if (loc)
+    set_tree_location (inner, loc);
+
+  return new param (this, inner);
+}
+
+/* Construct a playback::function instance.  */
+
+playback::function *
+playback::context::
+new_function (location *loc,
+	      enum gcc_jit_function_kind kind,
+	      type *return_type,
+	      const char *name,
+	      vec<param *> *params,
+	      int is_variadic,
+	      enum built_in_function builtin_id)
+{
+  int i;
+  param *param;
+
+  //can return_type be NULL?
+  gcc_assert (name);
+
+  tree *arg_types = (tree *)xcalloc(params->length (), sizeof(tree*));
+  FOR_EACH_VEC_ELT (*params, i, param)
+    arg_types[i] = TREE_TYPE (param->as_tree ());
+
+  tree fn_type;
+  if (is_variadic)
+    fn_type = build_varargs_function_type_array (return_type->as_tree (),
+						 params->length (), arg_types);
+  else
+    fn_type = build_function_type_array (return_type->as_tree (),
+					 params->length (), arg_types);
+  free (arg_types);
+
+  /* FIXME: this uses input_location: */
+  tree fndecl = build_fn_decl (name, fn_type);
+
+  if (loc)
+    set_tree_location (fndecl, loc);
+
+  tree resdecl = build_decl (UNKNOWN_LOCATION, RESULT_DECL,
+			     NULL_TREE, return_type->as_tree ());
+  DECL_ARTIFICIAL (resdecl) = 1;
+  DECL_IGNORED_P (resdecl) = 1;
+  DECL_RESULT (fndecl) = resdecl;
+
+  if (builtin_id)
+    {
+      DECL_BUILT_IN_CLASS (fndecl) = BUILT_IN_NORMAL;
+      DECL_FUNCTION_CODE (fndecl) = builtin_id;
+      gcc_assert (loc == NULL);
+      DECL_SOURCE_LOCATION (fndecl) = BUILTINS_LOCATION;
+    }
+
+  if (kind != GCC_JIT_FUNCTION_IMPORTED)
+    {
+      tree param_decl_list = NULL;
+      FOR_EACH_VEC_ELT (*params, i, param)
+	{
+	  param_decl_list = chainon (param->as_tree (), param_decl_list);
+	}
+
+      /* The param list was created in reverse order; fix it: */
+      param_decl_list = nreverse (param_decl_list);
+
+      tree t;
+      for (t = param_decl_list; t; t = DECL_CHAIN (t))
+	{
+	  DECL_CONTEXT (t) = fndecl;
+	  DECL_ARG_TYPE (t) = TREE_TYPE (t);
+	}
+
+      /* Set it up on DECL_ARGUMENTS */
+      DECL_ARGUMENTS(fndecl) = param_decl_list;
+    }
+
+  if (kind == GCC_JIT_FUNCTION_ALWAYS_INLINE)
+    {
+      DECL_DECLARED_INLINE_P (fndecl) = 1;
+
+      /* Add attribute "always_inline": */
+      DECL_ATTRIBUTES (fndecl) =
+	tree_cons (get_identifier ("always_inline"),
+		   NULL,
+		   DECL_ATTRIBUTES (fndecl));
+    }
+
+  function *func = new function (this, fndecl, kind);
+  m_functions.safe_push (func);
+  return func;
+}
+
+/* Construct a playback::lvalue instance (wrapping a tree).  */
+
+playback::lvalue *
+playback::context::
+new_global (location *loc,
+            type *type,
+            const char *name)
+{
+  gcc_assert (type);
+  gcc_assert (name);
+  tree inner = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+			   get_identifier (name),
+			   type->as_tree ());
+  TREE_PUBLIC (inner) = 1;
+  DECL_COMMON (inner) = 1;
+  DECL_EXTERNAL (inner) = 1;
+
+  if (loc)
+    set_tree_location (inner, loc);
+
+  return new lvalue (this, inner);
+}
+
+/* Construct a playback::rvalue instance (wrapping a tree).  */
+
+playback::rvalue *
+playback::context::
+new_rvalue_from_int (type *type,
+		     int value)
+{
+  // FIXME: type-checking, or coercion?
+  tree inner_type = type->as_tree ();
+  if (INTEGRAL_TYPE_P (inner_type))
+    {
+      tree inner = build_int_cst (inner_type, value);
+      return new rvalue (this, inner);
+    }
+  else
+    {
+      REAL_VALUE_TYPE real_value;
+      real_from_integer (&real_value, VOIDmode, value, SIGNED);
+      tree inner = build_real (inner_type, real_value);
+      return new rvalue (this, inner);
+    }
+}
+
+/* Construct a playback::rvalue instance (wrapping a tree).  */
+
+playback::rvalue *
+playback::context::
+new_rvalue_from_double (type *type,
+			double value)
+{
+  // FIXME: type-checking, or coercion?
+  tree inner_type = type->as_tree ();
+
+  /* We have a "double", we want a REAL_VALUE_TYPE.
+
+     real.c:real_from_target appears to require the representation to be
+     split into 32-bit values, and then sent as an pair of host long
+     ints.  */
+  REAL_VALUE_TYPE real_value;
+  union
+  {
+    double as_double;
+    uint32_t as_uint32s[2];
+  } u;
+  u.as_double = value;
+  long int as_long_ints[2];
+  as_long_ints[0] = u.as_uint32s[0];
+  as_long_ints[1] = u.as_uint32s[1];
+  real_from_target (&real_value, as_long_ints, DFmode);
+  tree inner = build_real (inner_type, real_value);
+  return new rvalue (this, inner);
+}
+
+/* Construct a playback::rvalue instance (wrapping a tree).  */
+
+playback::rvalue *
+playback::context::
+new_rvalue_from_ptr (type *type,
+		     void *value)
+{
+  tree inner_type = type->as_tree ();
+  /* FIXME: how to ensure we have a wide enough type?  */
+  tree inner = build_int_cstu (inner_type, (unsigned HOST_WIDE_INT)value);
+  return new rvalue (this, inner);
+}
+
+/* Construct a playback::rvalue instance (wrapping a tree).  */
+
+playback::rvalue *
+playback::context::
+new_string_literal (const char *value)
+{
+  tree t_str = build_string (strlen (value), value);
+  gcc_assert (m_char_array_type_node);
+  TREE_TYPE (t_str) = m_char_array_type_node;
+
+  /* Convert to (const char*), loosely based on
+     c/c-typeck.c: array_to_pointer_conversion,
+     by taking address of start of string.  */
+  tree t_addr = build1 (ADDR_EXPR, m_const_char_ptr, t_str);
+
+  return new rvalue (this, t_addr);
+}
+
+/* Coerce a tree expression into a boolean tree expression.  */
+
+tree
+playback::context::
+as_truth_value (tree expr, location *loc)
+{
+  /* Compare to c-typeck.c:c_objc_common_truthvalue_conversion */
+  tree typed_zero = fold_build1 (CONVERT_EXPR,
+				 TREE_TYPE (expr),
+				 integer_zero_node);
+  if (loc)
+    set_tree_location (typed_zero, loc);
+
+  expr = build2 (NE_EXPR, integer_type_node, expr, typed_zero);
+  if (loc)
+    set_tree_location (expr, loc);
+
+  return expr;
+}
+
+/* Construct a playback::rvalue instance (wrapping a tree) for a
+   unary op.  */
+
+playback::rvalue *
+playback::context::
+new_unary_op (location *loc,
+	      enum gcc_jit_unary_op op,
+	      type *result_type,
+	      rvalue *a)
+{
+  // FIXME: type-checking, or coercion?
+  enum tree_code inner_op;
+
+  gcc_assert (result_type);
+  gcc_assert (a);
+
+  tree node = a->as_tree ();
+  tree inner_result = NULL;
+
+  switch (op)
+    {
+    default:
+      add_error (loc, "unrecognized (enum gcc_jit_unary_op) value: %i", op);
+      return NULL;
+
+    case GCC_JIT_UNARY_OP_MINUS:
+      inner_op = NEGATE_EXPR;
+      break;
+
+    case GCC_JIT_UNARY_OP_BITWISE_NEGATE:
+      inner_op = BIT_NOT_EXPR;
+      break;
+
+    case GCC_JIT_UNARY_OP_LOGICAL_NEGATE:
+      node = as_truth_value (node, loc);
+      inner_result = invert_truthvalue (node);
+      if (loc)
+	set_tree_location (inner_result, loc);
+      return new rvalue (this, inner_result);
+    }
+
+  inner_result = build1 (inner_op,
+			 result_type->as_tree (),
+			 node);
+  if (loc)
+    set_tree_location (inner_result, loc);
+
+  return new rvalue (this, inner_result);
+}
+
+/* Construct a playback::rvalue instance (wrapping a tree) for a
+   binary op.  */
+
+playback::rvalue *
+playback::context::
+new_binary_op (location *loc,
+	       enum gcc_jit_binary_op op,
+	       type *result_type,
+	       rvalue *a, rvalue *b)
+{
+  // FIXME: type-checking, or coercion?
+  enum tree_code inner_op;
+
+  gcc_assert (result_type);
+  gcc_assert (a);
+  gcc_assert (b);
+
+  tree node_a = a->as_tree ();
+  tree node_b = b->as_tree ();
+
+  switch (op)
+    {
+    default:
+      add_error (loc, "unrecognized (enum gcc_jit_binary_op) value: %i", op);
+      return NULL;
+
+    case GCC_JIT_BINARY_OP_PLUS:
+      inner_op = PLUS_EXPR;
+      break;
+
+    case GCC_JIT_BINARY_OP_MINUS:
+      inner_op = MINUS_EXPR;
+      break;
+
+    case GCC_JIT_BINARY_OP_MULT:
+      inner_op = MULT_EXPR;
+      break;
+
+    case GCC_JIT_BINARY_OP_DIVIDE:
+      if (FLOAT_TYPE_P (result_type->as_tree ()))
+	/* Floating-point division: */
+	inner_op = RDIV_EXPR;
+      else
+	/* Truncating to zero: */
+	inner_op = TRUNC_DIV_EXPR;
+      break;
+
+    case GCC_JIT_BINARY_OP_MODULO:
+      inner_op = TRUNC_MOD_EXPR;
+      break;
+
+    case GCC_JIT_BINARY_OP_BITWISE_AND:
+      inner_op = BIT_AND_EXPR;
+      break;
+
+    case GCC_JIT_BINARY_OP_BITWISE_XOR:
+      inner_op = BIT_XOR_EXPR;
+      break;
+
+    case GCC_JIT_BINARY_OP_BITWISE_OR:
+      inner_op = BIT_IOR_EXPR;
+      break;
+
+    case GCC_JIT_BINARY_OP_LOGICAL_AND:
+      node_a = as_truth_value (node_a, loc);
+      node_b = as_truth_value (node_b, loc);
+      inner_op = TRUTH_ANDIF_EXPR;
+      break;
+
+    case GCC_JIT_BINARY_OP_LOGICAL_OR:
+      node_a = as_truth_value (node_a, loc);
+      node_b = as_truth_value (node_b, loc);
+      inner_op = TRUTH_ORIF_EXPR;
+      break;
+
+    case GCC_JIT_BINARY_OP_LSHIFT:
+      inner_op = LSHIFT_EXPR;
+      break;
+
+    case GCC_JIT_BINARY_OP_RSHIFT:
+      inner_op = RSHIFT_EXPR;
+      break;
+    }
+
+  tree inner_expr = build2 (inner_op,
+			    result_type->as_tree (),
+			    node_a,
+			    node_b);
+  if (loc)
+    set_tree_location (inner_expr, loc);
+
+  return new rvalue (this, inner_expr);
+}
+
+/* Construct a playback::rvalue instance (wrapping a tree) for a
+   comparison.  */
+
+playback::rvalue *
+playback::context::
+new_comparison (location *loc,
+		enum gcc_jit_comparison op,
+		rvalue *a, rvalue *b)
+{
+  // FIXME: type-checking, or coercion?
+  enum tree_code inner_op;
+
+  gcc_assert (a);
+  gcc_assert (b);
+
+  switch (op)
+    {
+    default:
+      add_error (loc, "unrecognized (enum gcc_jit_comparison) value: %i", op);
+      return NULL;
+
+    case GCC_JIT_COMPARISON_EQ:
+      inner_op = EQ_EXPR;
+      break;
+    case GCC_JIT_COMPARISON_NE:
+      inner_op = NE_EXPR;
+      break;
+    case GCC_JIT_COMPARISON_LT:
+      inner_op = LT_EXPR;
+      break;
+    case GCC_JIT_COMPARISON_LE:
+      inner_op = LE_EXPR;
+      break;
+    case GCC_JIT_COMPARISON_GT:
+      inner_op = GT_EXPR;
+      break;
+    case GCC_JIT_COMPARISON_GE:
+      inner_op = GE_EXPR;
+      break;
+    }
+
+  tree inner_expr = build2 (inner_op,
+			    boolean_type_node,
+			    a->as_tree (),
+			    b->as_tree ());
+  if (loc)
+    set_tree_location (inner_expr, loc);
+  return new rvalue (this, inner_expr);
+}
+
+/* Construct a playback::rvalue instance (wrapping a tree) for a
+   function call.  */
+
+playback::rvalue *
+playback::context::
+build_call (location *loc,
+	    tree fn_ptr,
+	    vec<rvalue *> args)
+{
+  vec<tree, va_gc> *tree_args;
+  vec_alloc (tree_args, args.length ());
+  for (unsigned i = 0; i < args.length (); i++)
+    tree_args->quick_push (args[i]->as_tree ());
+
+  if (loc)
+    set_tree_location (fn_ptr, loc);
+
+  tree fn = TREE_TYPE (fn_ptr);
+  tree fn_type = TREE_TYPE (fn);
+  tree return_type = TREE_TYPE (fn_type);
+
+  return new rvalue (this,
+		     build_call_vec (return_type,
+				     fn_ptr, tree_args));
+
+  /* see c-typeck.c: build_function_call
+     which calls build_function_call_vec
+
+     which does lots of checking, then:
+    result = build_call_array_loc (loc, TREE_TYPE (fntype),
+				   function, nargs, argarray);
+    which is in tree.c
+    (see also build_call_vec)
+   */
+}
+
+/* Construct a playback::rvalue instance (wrapping a tree) for a
+   call to a specific function.  */
+
+playback::rvalue *
+playback::context::
+new_call (location *loc,
+	  function *func,
+	  vec<rvalue *> args)
+{
+  tree fndecl;
+
+  gcc_assert (func);
+
+  fndecl = func->as_fndecl ();
+
+  tree fntype = TREE_TYPE (fndecl);
+
+  tree fn = build1 (ADDR_EXPR, build_pointer_type (fntype), fndecl);
+
+  return build_call (loc, fn, args);
+}
+
+/* Construct a playback::rvalue instance (wrapping a tree) for a
+   call through a function pointer.  */
+
+playback::rvalue *
+playback::context::
+new_call_through_ptr (location *loc,
+		      rvalue *fn_ptr,
+		      vec<rvalue *> args)
+{
+  gcc_assert (fn_ptr);
+  tree t_fn_ptr = fn_ptr->as_tree ();
+
+  return build_call (loc, t_fn_ptr, args);
+}
+
+/* Construct a tree for a cast.  */
+
+tree
+playback::context::build_cast (playback::location *loc,
+			       playback::rvalue *expr,
+			       playback::type *type_)
+{
+  /* For comparison, see:
+     - c/c-typeck.c:build_c_cast
+     - c/c-convert.c: convert
+     - convert.h
+
+     Only some kinds of cast are currently supported here.  */
+  tree t_expr = expr->as_tree ();
+  tree t_dst_type = type_->as_tree ();
+  tree t_ret = NULL;
+  t_ret = targetm.convert_to_type (t_dst_type, t_expr);
+  if (t_ret)
+      return t_ret;
+  enum tree_code dst_code = TREE_CODE (t_dst_type);
+  switch (dst_code)
+    {
+    case INTEGER_TYPE:
+    case ENUMERAL_TYPE:
+      t_ret = convert_to_integer (t_dst_type, t_expr);
+      goto maybe_fold;
+
+    case BOOLEAN_TYPE:
+      /* Compare with c_objc_common_truthvalue_conversion and
+	 c_common_truthvalue_conversion. */
+      /* For now, convert to: (t_expr != 0)  */
+      t_ret = build2 (NE_EXPR, t_dst_type,
+		      t_expr, integer_zero_node);
+      goto maybe_fold;
+
+    case REAL_TYPE:
+      t_ret = convert_to_real (t_dst_type, t_expr);
+      goto maybe_fold;
+
+    case POINTER_TYPE:
+      t_ret = build1 (NOP_EXPR, t_dst_type, t_expr);
+      goto maybe_fold;
+
+    default:
+      add_error (loc, "couldn't handle cast during playback");
+      fprintf (stderr, "input expression:\n");
+      debug_tree (t_expr);
+      fprintf (stderr, "requested type:\n");
+      debug_tree (t_dst_type);
+      return error_mark_node;
+
+    maybe_fold:
+      if (TREE_CODE (t_ret) != C_MAYBE_CONST_EXPR)
+	t_ret = fold (t_ret);
+      return t_ret;
+    }
+}
+
+/* Construct a playback::rvalue instance (wrapping a tree) for a
+   cast.  */
+
+playback::rvalue *
+playback::context::
+new_cast (playback::location *loc,
+	  playback::rvalue *expr,
+	  playback::type *type_)
+{
+
+  tree t_cast = build_cast (loc, expr, type_);
+  if (loc)
+    set_tree_location (t_cast, loc);
+  return new rvalue (this, t_cast);
+}
+
+/* Construct a playback::lvalue instance (wrapping a tree) for an
+   array access.  */
+
+playback::lvalue *
+playback::context::
+new_array_access (location *loc,
+		  rvalue *ptr,
+		  rvalue *index)
+{
+  gcc_assert (ptr);
+  gcc_assert (index);
+
+  /* For comparison, see:
+       c/c-typeck.c: build_array_ref
+       c-family/c-common.c: pointer_int_sum
+  */
+  tree t_ptr = ptr->as_tree ();
+  tree t_index = index->as_tree ();
+  tree t_type_ptr = TREE_TYPE (t_ptr);
+  tree t_type_star_ptr = TREE_TYPE (t_type_ptr);
+
+  if (TREE_CODE (t_type_ptr) == ARRAY_TYPE)
+    {
+      tree t_result = build4 (ARRAY_REF, t_type_star_ptr, t_ptr, t_index,
+			      NULL_TREE, NULL_TREE);
+      if (loc)
+        set_tree_location (t_result, loc);
+      return new lvalue (this, t_result);
+    }
+  else
+    {
+      /* Convert index to an offset in bytes.  */
+      tree t_sizeof = size_in_bytes (t_type_star_ptr);
+      t_index = fold_build1 (CONVERT_EXPR, sizetype, t_index);
+      tree t_offset = build2 (MULT_EXPR, sizetype, t_index, t_sizeof);
+
+      /* Locate (ptr + offset).  */
+      tree t_address = build2 (POINTER_PLUS_EXPR, t_type_ptr, t_ptr, t_offset);
+
+      tree t_indirection = build1 (INDIRECT_REF, t_type_star_ptr, t_address);
+      if (loc)
+        {
+          set_tree_location (t_sizeof, loc);
+          set_tree_location (t_offset, loc);
+          set_tree_location (t_address, loc);
+          set_tree_location (t_indirection, loc);
+        }
+
+      return new lvalue (this, t_indirection);
+    }
+}
+
+/* Construct a tree for a field access.  */
+
+tree
+playback::context::
+new_field_access (location *loc,
+		  tree datum,
+		  field *field)
+{
+  gcc_assert (datum);
+  gcc_assert (field);
+
+  /* Compare with c/c-typeck.c:lookup_field, build_indirect_ref, and
+     build_component_ref. */
+  tree type = TREE_TYPE (datum);
+  gcc_assert (type);
+  gcc_assert (TREE_CODE (type) != POINTER_TYPE);
+
+ tree t_field = field->as_tree ();
+ tree ref = build3 (COMPONENT_REF, TREE_TYPE (t_field), datum,
+		     t_field, NULL_TREE);
+  if (loc)
+    set_tree_location (ref, loc);
+  return ref;
+}
+
+/* Construct a tree for a dereference.  */
+
+tree
+playback::context::
+new_dereference (tree ptr,
+		 location *loc)
+{
+  gcc_assert (ptr);
+
+  tree type = TREE_TYPE (TREE_TYPE(ptr));
+  tree datum = build1 (INDIRECT_REF, type, ptr);
+  if (loc)
+    set_tree_location (datum, loc);
+  return datum;
+}
+
+/* Construct a playback::lvalue instance (wrapping a tree) for a
+   field access.  */
+
+playback::lvalue *
+playback::lvalue::
+access_field (location *loc,
+	      field *field)
+{
+  tree datum = as_tree ();
+  tree ref = get_context ()->new_field_access (loc, datum, field);
+  if (!ref)
+    return NULL;
+  return new lvalue (get_context (), ref);
+}
+
+/* Construct a playback::rvalue instance (wrapping a tree) for a
+   field access.  */
+
+playback::rvalue *
+playback::rvalue::
+access_field (location *loc,
+	      field *field)
+{
+  tree datum = as_tree ();
+  tree ref = get_context ()->new_field_access (loc, datum, field);
+  if (!ref)
+    return NULL;
+  return new rvalue (get_context (), ref);
+}
+
+/* Construct a playback::lvalue instance (wrapping a tree) for a
+   dereferenced field access.  */
+
+playback::lvalue *
+playback::rvalue::
+dereference_field (location *loc,
+		   field *field)
+{
+  tree ptr = as_tree ();
+  tree datum = get_context ()->new_dereference (ptr, loc);
+  if (!datum)
+    return NULL;
+  tree ref = get_context ()->new_field_access (loc, datum, field);
+  if (!ref)
+    return NULL;
+  return new lvalue (get_context (), ref);
+}
+
+/* Construct a playback::lvalue instance (wrapping a tree) for a
+   dereference.  */
+
+playback::lvalue *
+playback::rvalue::
+dereference (location *loc)
+{
+  tree ptr = as_tree ();
+  tree datum = get_context ()->new_dereference (ptr, loc);
+  return new lvalue (get_context (), datum);
+}
+
+/* Construct a playback::rvalue instance (wrapping a tree) for an
+   address-lookup.  */
+
+playback::rvalue *
+playback::lvalue::
+get_address (location *loc)
+{
+  tree t_lvalue = as_tree ();
+  tree t_thistype = TREE_TYPE (t_lvalue);
+  tree t_ptrtype = build_pointer_type (t_thistype);
+  tree ptr = build1 (ADDR_EXPR, t_ptrtype, t_lvalue);
+  if (loc)
+    get_context ()->set_tree_location (ptr, loc);
+  return new rvalue (get_context (), ptr);
+}
+
+/* gcc::jit::playback::wrapper subclasses are GC-managed:
+   allocate them using ggc_internal_cleared_alloc.  */
+
+void *
+playback::wrapper::
+operator new (size_t sz)
+{
+  return ggc_internal_cleared_alloc (sz MEM_STAT_INFO);
+}
+
+/* Constructor for gcc:jit::playback::function.  */
+
+playback::function::
+function (context *ctxt,
+	  tree fndecl,
+	  enum gcc_jit_function_kind kind)
+: m_ctxt(ctxt),
+  m_inner_fndecl (fndecl),
+  m_inner_bind_expr (NULL),
+  m_kind (kind)
+{
+  if (m_kind != GCC_JIT_FUNCTION_IMPORTED)
+    {
+      /* Create a BIND_EXPR, and within it, a statement list.  */
+      m_stmt_list = alloc_stmt_list ();
+      m_stmt_iter = tsi_start (m_stmt_list);
+      m_inner_block = make_node (BLOCK);
+      m_inner_bind_expr =
+	build3 (BIND_EXPR, void_type_node, NULL, m_stmt_list, m_inner_block);
+    }
+  else
+    {
+      m_inner_block = NULL;
+      m_stmt_list = NULL;
+    }
+}
+
+/* Hand-written GC-marking hook for playback functions.  */
+
+void
+playback::function::
+gt_ggc_mx ()
+{
+  gt_ggc_m_9tree_node (m_inner_fndecl);
+  gt_ggc_m_9tree_node (m_inner_bind_expr);
+  gt_ggc_m_9tree_node (m_stmt_list);
+  gt_ggc_m_9tree_node (m_inner_block);
+}
+
+/* Get the return type of a playback function, in tree form.  */
+
+tree
+playback::function::
+get_return_type_as_tree () const
+{
+  return TREE_TYPE (TREE_TYPE(m_inner_fndecl));
+}
+
+/* Construct a new local within this playback::function.  */
+
+playback::lvalue *
+playback::function::
+new_local (location *loc,
+	   type *type,
+	   const char *name)
+{
+  gcc_assert (type);
+  gcc_assert (name);
+  tree inner = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+			   get_identifier (name),
+			   type->as_tree ());
+  DECL_CONTEXT (inner) = this->m_inner_fndecl;
+
+  /* Prepend to BIND_EXPR_VARS: */
+  DECL_CHAIN (inner) = BIND_EXPR_VARS (m_inner_bind_expr);
+  BIND_EXPR_VARS (m_inner_bind_expr) = inner;
+
+  if (loc)
+    set_tree_location (inner, loc);
+  return new lvalue (m_ctxt, inner);
+}
+
+/* Construct a new block within this playback::function.  */
+
+playback::block *
+playback::function::
+new_block (const char *name)
+{
+  gcc_assert (m_kind != GCC_JIT_FUNCTION_IMPORTED);
+
+  block *result = new playback::block (this, name);
+  m_blocks.safe_push (result);
+  return result;
+}
+
+/* Build a statement list for the function as a whole out of the
+   lists of statements for the individual blocks, building labels
+   for each block.  */
+
+void
+playback::function::
+build_stmt_list ()
+{
+  int i;
+  block *b;
+
+  FOR_EACH_VEC_ELT (m_blocks, i, b)
+    {
+      int j;
+      tree stmt;
+
+      b->m_label_expr = build1 (LABEL_EXPR,
+				void_type_node,
+				b->as_label_decl ());
+      tsi_link_after (&m_stmt_iter, b->m_label_expr, TSI_CONTINUE_LINKING);
+
+      FOR_EACH_VEC_ELT (b->m_stmts, j, stmt)
+	tsi_link_after (&m_stmt_iter, stmt, TSI_CONTINUE_LINKING);
+    }
+}
+
+/* Finish compiling the given function, potentially running the
+   garbage-collector.
+   The function will have a statement list by now.
+   Amongst other things, this gimplifies the statement list,
+   and calls cgraph_node::finalize_function on the function.  */
+
+void
+playback::function::
+postprocess ()
+{
+  if (m_ctxt->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE))
+    debug_tree (m_stmt_list);
+
+  /* Do we need this to force cgraphunit.c to output the function? */
+  if (m_kind == GCC_JIT_FUNCTION_EXPORTED)
+    {
+      DECL_EXTERNAL (m_inner_fndecl) = 0;
+      DECL_PRESERVE_P (m_inner_fndecl) = 1;
+    }
+
+  if (m_kind == GCC_JIT_FUNCTION_INTERNAL
+      ||m_kind == GCC_JIT_FUNCTION_ALWAYS_INLINE)
+    {
+      DECL_EXTERNAL (m_inner_fndecl) = 0;
+      TREE_PUBLIC (m_inner_fndecl) = 0;
+    }
+
+  if (m_kind != GCC_JIT_FUNCTION_IMPORTED)
+    {
+      /* Seem to need this in gimple-low.c: */
+      gcc_assert (m_inner_block);
+      DECL_INITIAL (m_inner_fndecl) = m_inner_block;
+
+      /* how to add to function? the following appears to be how to
+	 set the body of a m_inner_fndecl: */
+      DECL_SAVED_TREE(m_inner_fndecl) = m_inner_bind_expr;
+
+      /* Ensure that locals appear in the debuginfo.  */
+      BLOCK_VARS (m_inner_block) = BIND_EXPR_VARS (m_inner_bind_expr);
+
+      //debug_tree (m_inner_fndecl);
+
+      /* Convert to gimple: */
+      //printf("about to gimplify_function_tree\n");
+      gimplify_function_tree (m_inner_fndecl);
+      //printf("finished gimplify_function_tree\n");
+
+      current_function_decl = m_inner_fndecl;
+      if (m_ctxt->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE))
+	dump_function_to_file (m_inner_fndecl, stderr, TDF_VOPS|TDF_MEMSYMS|TDF_LINENO);
+      //debug_tree (m_inner_fndecl);
+
+      //printf("about to add to cgraph\n");
+      /* Add to cgraph: */
+      cgraph_node::finalize_function (m_inner_fndecl, false);
+      /* This can trigger a collection, so we need to have all of
+	 the funcs as roots.  */
+
+      current_function_decl = NULL;
+    }
+}
+
+/* Add an eval of the rvalue to the function's statement list.  */
+
+void
+playback::block::
+add_eval (location *loc,
+	  rvalue *rvalue)
+{
+  gcc_assert (rvalue);
+
+  if (loc)
+    set_tree_location (rvalue->as_tree (), loc);
+
+  add_stmt (rvalue->as_tree ());
+}
+
+/* Add an assignment to the function's statement list.  */
+
+void
+playback::block::
+add_assignment (location *loc,
+		lvalue *lvalue,
+		rvalue *rvalue)
+{
+  gcc_assert (lvalue);
+  gcc_assert (rvalue);
+
+  tree t_lvalue = lvalue->as_tree ();
+  tree t_rvalue = rvalue->as_tree ();
+  if (TREE_TYPE (t_rvalue) != TREE_TYPE (t_lvalue))
+    {
+      t_rvalue = build1 (CONVERT_EXPR,
+		         TREE_TYPE (t_lvalue),
+		         t_rvalue);
+      if (loc)
+	set_tree_location (t_rvalue, loc);
+    }
+
+  tree stmt =
+    build2 (MODIFY_EXPR, TREE_TYPE (t_lvalue),
+	    t_lvalue, t_rvalue);
+  if (loc)
+    set_tree_location (stmt, loc);
+  add_stmt (stmt);
+}
+
+/* Add a comment to the function's statement list.
+   For now this is done by adding a dummy label.  */
+
+void
+playback::block::
+add_comment (location *loc,
+	     const char *text)
+{
+  /* Wrap the text in C-style comment delimiters.  */
+  size_t sz =
+    (3 /* opening delim */
+     + strlen (text)
+     + 3 /* closing delim */
+     + 1 /* terminator */);
+  char *wrapped = (char *)ggc_internal_alloc (sz);
+  snprintf (wrapped, sz, "/* %s */", text);
+
+  /* For now we simply implement this by adding a dummy label with a name
+     containing the given text.  */
+  tree identifier = get_identifier (wrapped);
+  tree label_decl = build_decl (UNKNOWN_LOCATION, LABEL_DECL,
+				identifier, void_type_node);
+  DECL_CONTEXT (label_decl) = m_func->as_fndecl ();
+
+  tree label_expr = build1 (LABEL_EXPR, void_type_node, label_decl);
+  if (loc)
+    set_tree_location (label_expr, loc);
+  add_stmt (label_expr);
+}
+
+/* Add a conditional jump statement to the function's statement list.  */
+
+void
+playback::block::
+add_conditional (location *loc,
+		 rvalue *boolval,
+		 block *on_true,
+		 block *on_false)
+{
+  gcc_assert (boolval);
+  gcc_assert (on_true);
+  gcc_assert (on_false);
+
+  /* COND_EXPR wants statement lists for the true/false operands, but we
+     want labels.
+     Shim it by creating jumps to the labels */
+  tree true_jump = build1 (GOTO_EXPR, void_type_node,
+			   on_true->as_label_decl ());
+  if (loc)
+    set_tree_location (true_jump, loc);
+
+  tree false_jump = build1 (GOTO_EXPR, void_type_node,
+			    on_false->as_label_decl ());
+  if (loc)
+    set_tree_location (false_jump, loc);
+
+  tree stmt =
+    build3 (COND_EXPR, void_type_node, boolval->as_tree (),
+	    true_jump, false_jump);
+  if (loc)
+    set_tree_location (stmt, loc);
+  add_stmt (stmt);
+}
+
+/* Add an unconditional jump statement to the function's statement list.  */
+
+void
+playback::block::
+add_jump (location *loc,
+	  block *target)
+{
+  gcc_assert (target);
+
+  // see c_finish_loop
+  //tree top = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
+  //add_stmt (top);
+
+  //tree stmt = build_and_jump (&LABEL_EXPR_LABEL (target->label_));
+  TREE_USED (target->as_label_decl ()) = 1;
+  tree stmt = build1 (GOTO_EXPR, void_type_node, target->as_label_decl ());
+  if (loc)
+    set_tree_location (stmt, loc);
+  add_stmt (stmt);
+
+  /*
+  from c-typeck.c:
+tree
+c_finish_goto_label (location_t loc, tree label)
+{
+  tree decl = lookup_label_for_goto (loc, label);
+  if (!decl)
+    return NULL_TREE;
+  TREE_USED (decl) = 1;
+  {
+    tree t = build1 (GOTO_EXPR, void_type_node, decl);
+    SET_EXPR_LOCATION (t, loc);
+    return add_stmt (t);
+  }
+}
+  */
+
+}
+
+/* Add a return statement to the function's statement list.  */
+
+void
+playback::block::
+add_return (location *loc,
+	    rvalue *rvalue)
+{
+  tree modify_retval = NULL;
+  tree return_type = m_func->get_return_type_as_tree ();
+  if (rvalue)
+    {
+      tree t_lvalue = DECL_RESULT (m_func->as_fndecl ());
+      tree t_rvalue = rvalue->as_tree ();
+      if (TREE_TYPE (t_rvalue) != TREE_TYPE (t_lvalue))
+	t_rvalue = build1 (CONVERT_EXPR,
+			   TREE_TYPE (t_lvalue),
+			   t_rvalue);
+      modify_retval = build2 (MODIFY_EXPR, return_type,
+			      t_lvalue, t_rvalue);
+      if (loc)
+	set_tree_location (modify_retval, loc);
+    }
+  tree return_stmt = build1 (RETURN_EXPR, return_type,
+			     modify_retval);
+  if (loc)
+    set_tree_location (return_stmt, loc);
+
+  add_stmt (return_stmt);
+}
+
+/* Constructor for gcc::jit::playback::block.  */
+
+playback::block::
+block (function *func,
+       const char *name)
+: m_func (func),
+  m_stmts ()
+{
+  tree identifier;
+
+  gcc_assert (func);
+  // name can be NULL
+  if (name)
+    identifier = get_identifier (name);
+  else
+    identifier = NULL;
+  m_label_decl = build_decl (UNKNOWN_LOCATION, LABEL_DECL,
+			    identifier, void_type_node);
+  DECL_CONTEXT (m_label_decl) = func->as_fndecl ();
+  m_label_expr = NULL;
+}
+
+/* Construct a tempdir path template suitable for use by mkdtemp
+   e.g. "/tmp/libgccjit-XXXXXX", but respecting the rules in
+   libiberty's choose_tempdir rather than hardcoding "/tmp/".
+
+   The memory is allocated using malloc and must be freed.
+   Aborts the process if allocation fails. */
+
+static char *
+make_tempdir_path_template ()
+{
+  const char *tmpdir_buf;
+  size_t tmpdir_len;
+  const char *file_template_buf;
+  size_t file_template_len;
+  char *result;
+
+  /* The result of choose_tmpdir is a cached buffer within libiberty, so
+     we must *not* free it.  */
+  tmpdir_buf = choose_tmpdir ();
+
+  /* choose_tmpdir aborts on malloc failure.  */
+  gcc_assert (tmpdir_buf);
+
+  tmpdir_len = strlen (tmpdir_buf);
+  /* tmpdir_buf should now have a dir separator as the final byte.  */
+  gcc_assert (tmpdir_len > 0);
+  gcc_assert (tmpdir_buf[tmpdir_len - 1] == DIR_SEPARATOR);
+
+  file_template_buf = "libgccjit-XXXXXX";
+  file_template_len = strlen (file_template_buf);
+
+  result = XNEWVEC (char, tmpdir_len + file_template_len + 1);
+  strcpy (result, tmpdir_buf);
+  strcpy (result + tmpdir_len, file_template_buf);
+
+  return result;
+}
+
+/* Compile a playback::context:
+
+   - Use the context's options to cconstruct command-line options, and
+     call into the rest of GCC (toplev::main).
+   - Assuming it succeeds, we have a .s file; we want a .so file.
+     Invoke another gcc to convert the .s file to a .so file.
+   - dlopen the .so file
+   - Wrap the result up as a playback::result and return it.  */
+
+result *
+playback::context::
+compile ()
+{
+  void *handle = NULL;
+  const char *ctxt_progname;
+  result *result_obj = NULL;
+  const char *fake_args[20];
+  unsigned int num_args;
+
+  m_path_template = make_tempdir_path_template ();
+  if (!m_path_template)
+    return NULL;
+
+  /* Create tempdir using mkdtemp.  This is created with 0700 perms and
+     is unique.  Hence no other (non-root) users should have access to
+     the paths within it.  */
+  m_path_tempdir = mkdtemp (m_path_template);
+  if (!m_path_tempdir)
+    return NULL;
+  m_path_c_file = concat (m_path_tempdir, "/fake.c", NULL);
+  m_path_s_file = concat (m_path_tempdir, "/fake.s", NULL);
+  m_path_so_file = concat (m_path_tempdir, "/fake.so", NULL);
+
+  /* Call into the rest of gcc.
+     For now, we have to assemble command-line options to pass into
+     toplev::main, so that they can be parsed. */
+
+  /* Pass in user-provided program name as argv0, if any, so that it
+     makes it into GCC's "progname" global, used in various diagnostics. */
+  ctxt_progname = get_str_option (GCC_JIT_STR_OPTION_PROGNAME);
+  fake_args[0] =
+    (ctxt_progname ? ctxt_progname : "libgccjit.so");
+
+  fake_args[1] = m_path_c_file;
+  num_args = 2;
+
+#define ADD_ARG(arg) \
+  do \
+    { \
+      gcc_assert(num_args < sizeof(fake_args)/sizeof(char*)); \
+      fake_args[num_args++] = arg; \
+    } \
+  while (0)
+
+  ADD_ARG ("-fPIC");
+
+  /* Handle int options: */
+  switch (get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL))
+    {
+    default:
+      add_error (NULL,
+		 "unrecognized optimization level: %i",
+		 get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL));
+      return NULL;
+
+    case 0:
+      ADD_ARG ("-O0");
+      break;
+
+    case 1:
+      ADD_ARG ("-O1");
+      break;
+
+    case 2:
+      ADD_ARG ("-O2");
+      break;
+
+    case 3:
+      ADD_ARG ("-O3");
+      break;
+    }
+  /* What about -Os? */
+
+  /* Handle bool options: */
+  if (get_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO))
+    ADD_ARG ("-g");
+
+  /* Suppress timing (and other) info.  */
+  if (!get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_SUMMARY))
+    {
+      ADD_ARG ("-quiet");
+      quiet_flag = 1;
+    }
+
+  /* Aggressively garbage-collect, to shake out bugs: */
+  if (get_bool_option (GCC_JIT_BOOL_OPTION_SELFCHECK_GC))
+    {
+      ADD_ARG ("--param");
+      ADD_ARG ("ggc-min-expand=0");
+      ADD_ARG ("--param");
+      ADD_ARG ("ggc-min-heapsize=0");
+    }
+
+  if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING))
+    {
+      ADD_ARG ("-fdump-tree-all");
+      ADD_ARG ("-fdump-rtl-all");
+      ADD_ARG ("-fdump-ipa-all");
+    }
+
+  toplev toplev (false);
+
+  toplev.main (num_args, const_cast <char **> (fake_args));
+  toplev.finalize ();
+
+  active_playback_ctxt = NULL;
+
+  if (errors_occurred ())
+    return NULL;
+
+  if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE))
+   dump_generated_code ();
+
+  /* Gross hacks follow:
+     We have a .s file; we want a .so file.
+     We could reuse parts of gcc/gcc.c to do this.
+     For now, just use the driver binary from the install, as
+     named in gcc-driver-name.h
+     e.g. "x86_64-unknown-linux-gnu-gcc-5.0.0".
+   */
+  {
+    auto_timevar assemble_timevar (TV_ASSEMBLE);
+    const char *errmsg;
+    const char *argv[7];
+    int exit_status = 0;
+    int err = 0;
+    const char *gcc_driver_name = GCC_DRIVER_NAME;
+
+    argv[0] = gcc_driver_name;
+    argv[1] = "-shared";
+    /* The input: assembler.  */
+    argv[2] = m_path_s_file;
+    /* The output: shared library.  */
+    argv[3] = "-o";
+    argv[4] = m_path_so_file;
+
+    /* Don't use the linker plugin.
+       If running with just a "make" and not a "make install", then we'd
+       run into
+          "fatal error: -fuse-linker-plugin, but liblto_plugin.so not found"
+       libto_plugin is a .la at build time, with it becoming installed with
+       ".so" suffix: i.e. it doesn't exist with a .so suffix until install
+       time.  */
+    argv[5] = "-fno-use-linker-plugin";
+
+    /* pex argv arrays are NULL-terminated.  */
+    argv[6] = NULL;
+
+    errmsg = pex_one (PEX_SEARCH, /* int flags, */
+		      gcc_driver_name,
+		      const_cast<char * const *> (argv),
+		      ctxt_progname, /* const char *pname */
+		      NULL, /* const char *outname */
+		      NULL, /* const char *errname */
+		      &exit_status, /* int *status */
+		      &err); /* int *err*/
+    if (errmsg)
+      {
+	add_error (NULL, "error invoking gcc driver: %s", errmsg);
+	return NULL;
+      }
+
+    /* pex_one can return a NULL errmsg when the executable wasn't
+       found (or doesn't exist), so trap these cases also.  */
+    if (exit_status || err)
+      {
+	add_error (NULL,
+		   "error invoking gcc driver: exit_status: %i err: %i",
+		   exit_status, err);
+	add_error (NULL,
+		   "whilst attempting to run a driver named: %s",
+		   gcc_driver_name);
+	add_error (NULL,
+		   "PATH was: %s",
+		   getenv ("PATH"));
+	return NULL;
+      }
+  }
+
+  // TODO: split out assembles vs linker
+
+  /* dlopen the .so file. */
+  {
+    auto_timevar load_timevar (TV_LOAD);
+
+    const char *error;
+
+    /* Clear any existing error.  */
+    dlerror ();
+
+    handle = dlopen (m_path_so_file, RTLD_NOW | RTLD_LOCAL);
+    if ((error = dlerror()) != NULL)  {
+      add_error (NULL, "%s", error);
+    }
+    if (handle)
+      result_obj = new result (handle);
+    else
+      result_obj = NULL;
+  }
+
+  return result_obj;
+}
+
+/* Top-level hook for playing back a recording context.
+
+   This plays back m_recording_ctxt, and, if no errors
+   occurred builds statement lists for and then postprocesses
+   every function in the result.  */
+
+void
+playback::context::
+replay ()
+{
+  /* Adapted from c-common.c:c_common_nodes_and_builtins.  */
+  tree array_domain_type = build_index_type (size_int (200));
+  m_char_array_type_node
+    = build_array_type (char_type_node, array_domain_type);
+
+  m_const_char_ptr
+    = build_pointer_type (build_qualified_type (char_type_node,
+						TYPE_QUAL_CONST));
+
+  /* Replay the recorded events:  */
+  timevar_push (TV_JIT_REPLAY);
+
+  m_recording_ctxt->replay_into (this);
+
+  /* Clean away the temporary references from recording objects
+     to playback objects.  We have to do this now since the
+     latter are GC-allocated, but the former don't mark these
+     refs.  Hence we must stop using them before the GC can run.  */
+  m_recording_ctxt->disassociate_from_playback ();
+
+  timevar_pop (TV_JIT_REPLAY);
+
+  if (!errors_occurred ())
+    {
+      int i;
+      function *func;
+
+      /* No GC can happen yet; process the cached source locations.  */
+      handle_locations ();
+
+      /* We've now created tree nodes for the stmts in the various blocks
+	 in each function, but we haven't built each function's single stmt
+	 list yet.  Do so now.  */
+      FOR_EACH_VEC_ELT (m_functions, i, func)
+	func->build_stmt_list ();
+
+      /* No GC can have happened yet.  */
+
+      /* Postprocess the functions.  This could trigger GC.  */
+      FOR_EACH_VEC_ELT (m_functions, i, func)
+	{
+	  gcc_assert (func);
+	  func->postprocess ();
+	}
+    }
+}
+
+/* Dump the generated .s file to stderr.  */
+
+void
+playback::context::
+dump_generated_code ()
+{
+  char buf[4096];
+  size_t sz;
+  FILE *f_in = fopen (m_path_s_file, "r");
+  if (!f_in)
+    return;
+
+  while ( (sz = fread (buf, 1, sizeof (buf), f_in)) )
+    fwrite (buf, 1, sz, stderr);
+
+  fclose (f_in);
+}
+
+/* qsort comparator for comparing pairs of playback::source_line *,
+   ordering them by line number.  */
+
+static int
+line_comparator (const void *lhs, const void *rhs)
+{
+  const playback::source_line *line_lhs = \
+    *static_cast<const playback::source_line * const*> (lhs);
+  const playback::source_line *line_rhs = \
+    *static_cast<const playback::source_line * const*> (rhs);
+  return line_lhs->get_line_num () - line_rhs->get_line_num ();
+}
+
+/* qsort comparator for comparing pairs of playback::location *,
+   ordering them by column number.  */
+
+static int
+location_comparator (const void *lhs, const void *rhs)
+{
+  const playback::location *loc_lhs = \
+    *static_cast<const playback::location * const *> (lhs);
+  const playback::location *loc_rhs = \
+    *static_cast<const playback::location * const *> (rhs);
+  return loc_lhs->get_column_num () - loc_rhs->get_column_num ();
+}
+
+/* Our API allows locations to be created in arbitrary orders, but the
+   linemap API requires locations to be created in ascending order
+   as if we were tokenizing files.
+
+   This hook sorts all of the the locations that have been created, and
+   calls into the linemap API, creating linemap entries in sorted order
+   for our locations.  */
+
+void
+playback::context::
+handle_locations ()
+{
+  /* Create the source code locations, following the ordering rules
+     imposed by the linemap API.
+
+     line_table is a global.  */
+  int i;
+  source_file *file;
+
+  FOR_EACH_VEC_ELT (m_source_files, i, file)
+    {
+      linemap_add (line_table, LC_ENTER, false, file->get_filename (), 0);
+
+      /* Sort lines by ascending line numbers.  */
+      file->m_source_lines.qsort (&line_comparator);
+
+      int j;
+      source_line *line;
+      FOR_EACH_VEC_ELT (file->m_source_lines, j, line)
+	{
+	  int k;
+	  location *loc;
+
+	  /* Sort locations in line by ascending column numbers.  */
+	  line->m_locations.qsort (&location_comparator);
+
+	  /* Determine maximum column within this line.  */
+	  gcc_assert (line->m_locations.length () > 0);
+	  location *final_column =
+	    line->m_locations[line->m_locations.length () - 1];
+	  int max_col = final_column->get_column_num ();
+
+	  linemap_line_start (line_table, line->get_line_num (), max_col);
+	  FOR_EACH_VEC_ELT (line->m_locations, k, loc)
+	    {
+	      loc->m_srcloc =					   \
+		linemap_position_for_column (line_table, loc->get_column_num ());
+	    }
+	}
+
+      linemap_add (line_table, LC_LEAVE, false, NULL, 0);
+    }
+
+  /* line_table should now be populated; every playback::location should
+     now have an m_srcloc.  */
+
+  if (0)
+    line_table_dump (stderr,
+		     line_table,
+		     LINEMAPS_ORDINARY_USED (line_table),
+		     LINEMAPS_MACRO_USED (line_table));
+
+  /* Now assign them to tree nodes as appropriate.  */
+  std::pair<tree, location *> *cached_location;
+
+  FOR_EACH_VEC_ELT (m_cached_locations, i, cached_location)
+    {
+      tree t = cached_location->first;
+      source_location srcloc = cached_location->second->m_srcloc;
+#if 0
+      inform (srcloc, "location of ");
+      debug_tree (t);
+#endif
+
+      /* This covers expressions: */
+      if (CAN_HAVE_LOCATION_P (t))
+	SET_EXPR_LOCATION (t, srcloc);
+      else if (CODE_CONTAINS_STRUCT(TREE_CODE(t), TS_DECL_MINIMAL))
+	DECL_SOURCE_LOCATION (t) = srcloc;
+      else
+	{
+	  /* Don't know how to set location on this node.  */
+	  if (0)
+	    {
+	      fprintf (stderr, "can't set location on:");
+	      debug_tree (t);
+	      fprintf (stderr, "\n");
+	    }
+	}
+    }
+}
+
+/* We handle errors on a playback::context by adding them to the
+   corresponding recording::context.  */
+
+void
+playback::context::
+add_error (location *loc, const char *fmt, ...)
+{
+  va_list ap;
+  va_start (ap, fmt);
+  m_recording_ctxt->add_error_va (loc ? loc->get_recording_loc () : NULL,
+				  fmt, ap);
+  va_end (ap);
+}
+
+/* We handle errors on a playback::context by adding them to the
+   corresponding recording::context.  */
+
+void
+playback::context::
+add_error_va (location *loc, const char *fmt, va_list ap)
+{
+  m_recording_ctxt->add_error_va (loc ? loc->get_recording_loc () : NULL,
+				  fmt, ap);
+}
+
+/* Constructor for gcc::jit::playback::result.  */
+
+result::
+result(void *dso_handle)
+  : m_dso_handle(dso_handle)
+{
+}
+
+/* gcc::jit::playback::result's destructor.
+
+   Called implicitly by gcc_jit_result_release.  */
+
+result::~result()
+{
+  dlclose (m_dso_handle);
+}
+
+/* Attempt to locate the given function by name within the
+   playback::result, using dlsym.
+
+   Implements the post-error-checking part of
+   gcc_jit_result_get_code.  */
+
+void *
+result::
+get_code (const char *funcname)
+{
+  void *code;
+  const char *error;
+
+  /* Clear any existing error.  */
+  dlerror ();
+
+  code = dlsym (m_dso_handle, funcname);
+
+  if ((error = dlerror()) != NULL)  {
+    fprintf(stderr, "%s\n", error);
+  }
+
+  return code;
+}
+
+/* Dealing with the linemap API.  */
+
+/* Construct a playback::location for a recording::location, if it
+   doesn't exist already.  */
+
+playback::location *
+playback::context::
+new_location (recording::location *rloc,
+	      const char *filename,
+	      int line,
+	      int column)
+{
+  /* Get the source_file for filename, creating if necessary.  */
+  source_file *src_file = get_source_file (filename);
+  /* Likewise for the line within the file.  */
+  source_line *src_line = src_file->get_source_line (line);
+  /* Likewise for the column within the line.  */
+  location *loc = src_line->get_location (rloc, column);
+  return loc;
+}
+
+/* Deferred setting of the location for a given tree, by adding the
+   (tree, playback::location) pair to a list of deferred associations.
+   We will actually set the location on the tree later on once
+   the source_location for the playback::location exists.  */
+
+void
+playback::context::
+set_tree_location (tree t, location *loc)
+{
+  gcc_assert (loc);
+  m_cached_locations.safe_push (std::make_pair (t, loc));
+}
+
+
+/* Construct a playback::source_file for the given source
+   filename, if it doesn't exist already.  */
+
+playback::source_file *
+playback::context::
+get_source_file (const char *filename)
+{
+  /* Locate the file.
+     For simplicitly, this is currently a linear search.
+     Replace with a hash if this shows up in the profile.  */
+  int i;
+  source_file *file;
+  tree ident_filename = get_identifier (filename);
+
+  FOR_EACH_VEC_ELT (m_source_files, i, file)
+    if (file->filename_as_tree () == ident_filename)
+      return file;
+
+  /* Not found.  */
+  file = new source_file (ident_filename);
+  m_source_files.safe_push (file);
+  return file;
+}
+
+/* Constructor for gcc::jit::playback::source_file.  */
+
+playback::source_file::source_file (tree filename) :
+  m_source_lines (),
+  m_filename (filename)
+{
+}
+
+/* Construct a playback::source_line for the given line
+   within this source file, if one doesn't exist already.  */
+
+playback::source_line *
+playback::source_file::
+get_source_line (int line_num)
+{
+  /* Locate the line.
+     For simplicitly, this is currently a linear search.
+     Replace with a hash if this shows up in the profile.  */
+  int i;
+  source_line *line;
+
+  FOR_EACH_VEC_ELT (m_source_lines, i, line)
+    if (line->get_line_num () == line_num)
+      return line;
+
+  /* Not found.  */
+  line = new source_line (this, line_num);
+  m_source_lines.safe_push (line);
+  return line;
+}
+
+/* Constructor for gcc::jit::playback::source_line.  */
+
+playback::source_line::source_line (source_file *file, int line_num) :
+  m_locations (),
+  m_source_file (file),
+  m_line_num (line_num)
+{
+}
+
+/* Construct a playback::location for the given column
+   within this line of a specific source file, if one doesn't exist
+   already.  */
+
+playback::location *
+playback::source_line::
+get_location (recording::location *rloc, int column_num)
+{
+  int i;
+  location *loc;
+
+  /* Another linear search that probably should be a hash table.  */
+  FOR_EACH_VEC_ELT (m_locations, i, loc)
+    if (loc->get_column_num () == column_num)
+      return loc;
+
+  /* Not found.  */
+  loc = new location (rloc, this, column_num);
+  m_locations.safe_push (loc);
+  return loc;
+}
+
+/* Constructor for gcc::jit::playback::location.  */
+
+playback::location::location (recording::location *loc,
+			      source_line *line,
+			      int column_num) :
+  m_srcloc (UNKNOWN_LOCATION),
+  m_recording_loc (loc),
+  m_line (line),
+  m_column_num(column_num)
+{
+}
+
+/* The active gcc::jit::playback::context instance.  This is a singleton,
+   guarded by jit_mutex.  */
+
+playback::context *active_playback_ctxt;
+
+} // namespace gcc::jit
+
+} // namespace gcc
-- 
1.8.5.3

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

* [PATCH 25/27] Documentation: add "internals" subdirectory
  2014-10-31 17:07 [PATCH 00/27] Merger of jit branch v3 David Malcolm
                   ` (19 preceding siblings ...)
  2014-10-31 17:31 ` [PATCH 24/27] Documentation: add "topics" subdirectory David Malcolm
@ 2014-10-31 17:32 ` David Malcolm
  2014-10-31 17:38 ` [PATCH 13/27] New file: gcc/jit/jit-recording.c David Malcolm
                   ` (4 subsequent siblings)
  25 siblings, 0 replies; 71+ messages in thread
From: David Malcolm @ 2014-10-31 17:32 UTC (permalink / raw)
  To: gcc-patches, jit; +Cc: David Malcolm

This final part of the documentation is a guide to the internals of
the library, aimed at current and future contributors to the library
(including myself).

gcc/jit/
	* docs/internals/index.rst: New.
---
 gcc/jit/docs/internals/index.rst | 216 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 216 insertions(+)
 create mode 100644 gcc/jit/docs/internals/index.rst

diff --git a/gcc/jit/docs/internals/index.rst b/gcc/jit/docs/internals/index.rst
new file mode 100644
index 0000000..80626e4
--- /dev/null
+++ b/gcc/jit/docs/internals/index.rst
@@ -0,0 +1,216 @@
+.. Copyright (C) 2014 Free Software Foundation, Inc.
+   Originally contributed by David Malcolm <dmalcolm@redhat.com>
+
+   This is free software: you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see
+   <http://www.gnu.org/licenses/>.
+
+Internals
+=========
+
+Working on the JIT library
+--------------------------
+Having checked out the source code (to "src"), you can configure and build
+the JIT library like this:
+
+.. code-block:: bash
+
+  mkdir build
+  mkdir install
+  PREFIX=$(pwd)/install
+  cd build
+  ../src/configure \
+     --enable-host-shared \
+     --enable-languages=jit \
+     --disable-bootstrap \
+     --enable-checking=release \
+     --prefix=$PREFIX
+  nice make -j4 # altering the "4" to however many cores you have
+
+This should build a libgccjit.so within jit/build/gcc:
+
+.. code-block:: console
+
+ [build] $ file gcc/libgccjit.so*
+ gcc/libgccjit.so:       symbolic link to `libgccjit.so.0'
+ gcc/libgccjit.so.0:     symbolic link to `libgccjit.so.0.0.1'
+ gcc/libgccjit.so.0.0.1: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, not stripped
+
+Here's what those configuration options mean:
+
+.. option:: --enable-host-shared
+
+  Configuring with this option means that the compiler is built as
+  position-independent code, which incurs a slight performance hit,
+  but it necessary for a shared library.
+
+.. option:: --enable-languages=jit
+
+  This specifies which frontends to build.  The JIT library looks like
+  a frontend to the rest of the code.
+
+.. option:: --disable-bootstrap
+
+  For hacking on the "jit" subdirectory, performing a full
+  bootstrap can be overkill, since it's unused by a bootstrap.  However,
+  when submitting patches, you should remove this option, to ensure that
+  the compiler can still bootstrap itself.
+
+.. option:: --enable-checking=release
+
+  The compile can perform extensive self-checking as it runs, useful when
+  debugging, but slowing things down.
+
+  For maximum speed, configure with ``--enable-checking=release`` to
+  disable this self-checking.
+
+Running the test suite
+----------------------
+
+.. code-block:: console
+
+  [build] $ cd gcc
+  [gcc] $ make check-jit RUNTESTFLAGS="-v -v -v"
+
+A summary of the tests can then be seen in:
+
+.. code-block:: console
+
+  jit/build/gcc/testsuite/jit/jit.sum
+
+and detailed logs in:
+
+.. code-block:: console
+
+  jit/build/gcc/testsuite/jit/jit.log
+
+The test executables can be seen as:
+
+.. code-block:: console
+
+  jit/build/gcc/testsuite/jit/*.exe
+
+which can be run independently.
+
+You can compile and run individual tests by passing "jit.exp=TESTNAME" to RUNTESTFLAGS e.g.:
+
+.. code-block:: console
+
+   [gcc] $ make check-jit RUNTESTFLAGS="-v -v -v jit.exp=test-factorial.c"
+
+and once a test has been compiled, you can debug it directly:
+
+.. code-block:: console
+
+   [gcc] $ PATH=.:$PATH \
+           LD_LIBRARY_PATH=. \
+           LIBRARY_PATH=. \
+             gdb --args \
+               testsuite/jit/test-factorial.exe
+
+Environment variables
+---------------------
+When running client code against a locally-built libgccjit, three
+environment variables need to be set up:
+
+.. envvar:: LD_LIBRARY_PATH
+
+   `libgccjit.so` is dynamically linked into client code, so if running
+   against a locally-built library, ``LD_LIBRARY_PATH`` needs to be set
+   up appropriately.  The library can be found within the "gcc"
+   subdirectory of the build tree:
+
+  .. code-block:: console
+
+    $ file libgccjit.so*
+    libgccjit.so:       symbolic link to `libgccjit.so.0'
+    libgccjit.so.0:     symbolic link to `libgccjit.so.0.0.1'
+    libgccjit.so.0.0.1: ELF 64-bit LSB shared object, x86-64, version 1 (GNU/Linux), dynamically linked, not stripped
+
+.. envvar:: PATH
+
+  The library uses a driver executable for converting from .s assembler
+  files to .so shared libraries.  Specifically, it looks for a name
+  expanded from
+  ``${target_noncanonical}-gcc-${gcc_BASEVER}${exeext}``
+  such as ``x86_64-unknown-linux-gnu-gcc-5.0.0``.
+
+  Hence ``PATH`` needs to include a directory where the library can
+  locate this executable.
+
+  The executable is normally installed to the installation bindir
+  (e.g. /usr/bin), but a copy is also created within the "gcc"
+  subdirectory of the build tree for running the testsuite, and for ease
+  of development.
+
+.. envvar:: LIBRARY_PATH
+
+  The driver executable invokes the linker, and the latter needs to locate
+  support libraries needed by the generated code, or you will see errors
+  like:
+
+  .. code-block:: console
+
+    ld: cannot find crtbeginS.o: No such file or directory
+    ld: cannot find -lgcc
+    ld: cannot find -lgcc_s
+
+  Hence if running directly from a locally-built copy (without installing),
+  ``LIBRARY_PATH`` needs to contain the "gcc" subdirectory of the build
+  tree.
+
+For example, to run a binary that uses the library against a non-installed
+build of the library in LIBGCCJIT_BUILD_DIR you need an invocation of the
+client code like this, to preprend the dir to each of the environment
+variables:
+
+.. code-block:: console
+
+  $ LD_LIBRARY_PATH=$(LIBGCCJIT_BUILD_DIR):$(LD_LIBRARY_PATH) \
+    PATH=$(LIBGCCJIT_BUILD_DIR):$(PATH) \
+    LIBRARY_PATH=$(LIBGCCJIT_BUILD_DIR):$(LIBRARY_PATH) \
+      ./jit-hello-world
+  hello world
+
+Overview of code structure
+--------------------------
+
+* ``libgccjit.c`` implements the API entrypoints.  It performs error
+  checking, then calls into classes of the gcc::jit::recording namespace
+  within ``jit-recording.c`` and ``jit-recording.h``.
+
+* The gcc::jit::recording classes (within ``jit-recording.c`` and
+  ``jit-recording.h``) record the API calls that are made:
+
+   .. literalinclude:: ../../jit-common.h
+    :start-after: /* Recording types.  */
+    :end-before: /* End of recording types. */
+    :language: c++
+
+* When the context is compiled, the gcc::jit::playback classes (within
+  ``jit-playback.c`` and ``jit-playback.h``) replay the API calls
+  within langhook:parse_file:
+
+   .. literalinclude:: ../../jit-common.h
+    :start-after: /* Playback types.  */
+    :end-before: /* End of playback types. */
+    :language: c++
+
+   .. literalinclude:: ../../notes.txt
+    :lines: 1-
+
+Here is a high-level summary from ``jit-common.h``:
+
+.. include:: ../../jit-common.h
+  :start-after: This comment is included by the docs.
+  :end-before: End of comment for inclusion in the docs.  */
-- 
1.8.5.3

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

* [PATCH 13/27] New file: gcc/jit/jit-recording.c
  2014-10-31 17:07 [PATCH 00/27] Merger of jit branch v3 David Malcolm
                   ` (20 preceding siblings ...)
  2014-10-31 17:32 ` [PATCH 25/27] Documentation: add "internals" subdirectory David Malcolm
@ 2014-10-31 17:38 ` David Malcolm
  2014-11-03 22:04   ` Jeff Law
  2014-10-31 17:41 ` [PATCH 15/27] New file: gcc/jit/jit-playback.h David Malcolm
                   ` (3 subsequent siblings)
  25 siblings, 1 reply; 71+ messages in thread
From: David Malcolm @ 2014-10-31 17:38 UTC (permalink / raw)
  To: gcc-patches, jit; +Cc: David Malcolm

Implementation of the gcc::jit::recording internal API, so that
libgccjit.c can record the calls that are made to the public API, for
later playback by the dummy frontend.

gcc/jit/
	* jit-recording.c: New.
---
 gcc/jit/jit-recording.c | 3434 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 3434 insertions(+)
 create mode 100644 gcc/jit/jit-recording.c

diff --git a/gcc/jit/jit-recording.c b/gcc/jit/jit-recording.c
new file mode 100644
index 0000000..8daa8f2
--- /dev/null
+++ b/gcc/jit/jit-recording.c
@@ -0,0 +1,3434 @@
+/* Internals of libgccjit: classes for recording calls made to the JIT API.
+   Copyright (C) 2013-2014 Free Software Foundation, Inc.
+   Contributed by David Malcolm <dmalcolm@redhat.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "opts.h"
+#include "tree.h"
+#include "pretty-print.h"
+
+#include <pthread.h>
+
+#include "jit-common.h"
+#include "jit-builtins.h"
+#include "jit-recording.h"
+#include "jit-playback.h"
+
+namespace gcc {
+namespace jit {
+
+// class dump
+
+dump::dump (recording::context &ctxt,
+	    const char *filename,
+	    bool update_locations)
+: m_ctxt (ctxt),
+  m_filename (filename),
+  m_update_locations (update_locations),
+  m_line (0),
+  m_column (0)
+{
+  m_file = fopen (filename, "w");
+  if (!m_file)
+    ctxt.add_error (NULL,
+		    "error opening dump file %s for writing: %s",
+		    filename,
+		    xstrerror (errno));
+}
+
+dump::~dump ()
+{
+  if (m_file)
+    {
+      int err = fclose (m_file);
+      if (err)
+	m_ctxt.add_error (NULL,
+			  "error closing dump file %s: %s",
+			  m_filename,
+			  xstrerror (errno));
+    }
+}
+
+/* Write the given message to the dump, using printf-formatting
+   conventions, updating the line/column within the dump.
+
+   Emit an error on the context if a failure occurs.  */
+
+void
+dump::write (const char *fmt, ...)
+{
+  va_list ap;
+  char *buf = NULL;
+
+  /* If there was an error opening the file, we've already reported it.
+     Don't attempt further work.  */
+  if (!m_file)
+    return;
+
+  va_start (ap, fmt);
+  vasprintf (&buf, fmt, ap);
+  va_end (ap);
+
+  if (!buf)
+    {
+      m_ctxt.add_error (NULL, "malloc failure writing to dumpfile %s",
+			m_filename);
+      return;
+    }
+
+  if (fwrite (buf, strlen (buf), 1, m_file) != 1)
+    m_ctxt.add_error (NULL, "error writing to dump file %s",
+		      m_filename);
+
+  /* Update line/column: */
+  for (const char *ptr = buf; *ptr; ptr++)
+    {
+      if ('\n' == *ptr)
+	{
+	  m_line++;
+	  m_column = 0;
+	}
+      else
+	m_column++;
+    }
+
+  free (buf);
+}
+
+/* Construct a gcc::jit::recording::location instance for the current
+   location within the dump.  */
+
+recording::location *
+dump::make_location () const
+{
+  return m_ctxt.new_location (m_filename, m_line, m_column);
+}
+
+/**********************************************************************
+ Recording.
+ **********************************************************************/
+
+/* Get the playback::location for the given recording::location,
+   handling a NULL input with a NULL output.  */
+
+playback::location *
+recording::playback_location (replayer *r, recording::location *loc)
+{
+  if (loc)
+    return loc->playback_location (r);
+  else
+    return NULL;
+}
+
+/* Get a const char * for the given recording::string
+   handling a NULL input with a NULL output.  */
+
+const char *
+recording::playback_string (recording::string *str)
+{
+  if (str)
+    return str->c_str ();
+  else
+    return NULL;
+}
+
+/* Get the playback::block for the given recording::block,
+   handling a NULL input with a NULL output.  */
+
+playback::block *
+recording::playback_block (recording::block *b)
+{
+  if (b)
+    return b->playback_block ();
+  else
+    return NULL;
+}
+
+/* Methods of cc::jit::recording::context.  */
+
+/* The constructor for gcc::jit::recording::context, used by
+   gcc_jit_context_acquire and gcc_jit_context_new_child_context.  */
+
+recording::context::context (context *parent_ctxt)
+  : m_parent_ctxt (parent_ctxt),
+    m_error_count (0),
+    m_first_error_str (NULL),
+    m_owns_first_error_str (false),
+    m_mementos (),
+    m_compound_types (),
+    m_functions (),
+    m_FILE_type (NULL),
+    m_builtins_manager(NULL)
+{
+  if (parent_ctxt)
+    {
+      /* Inherit options from parent.
+         Note that the first memcpy means copying pointers to strings.  */
+      memcpy (m_str_options,
+              parent_ctxt->m_str_options,
+              sizeof (m_str_options));
+      memcpy (m_int_options,
+              parent_ctxt->m_int_options,
+              sizeof (m_int_options));
+      memcpy (m_bool_options,
+              parent_ctxt->m_bool_options,
+              sizeof (m_bool_options));
+    }
+  else
+    {
+      memset (m_str_options, 0, sizeof (m_str_options));
+      memset (m_int_options, 0, sizeof (m_int_options));
+      memset (m_bool_options, 0, sizeof (m_bool_options));
+    }
+
+  memset (m_basic_types, 0, sizeof (m_basic_types));
+}
+
+/* The destructor for gcc::jit::recording::context, implicitly used by
+   gcc_jit_context_release.  */
+
+recording::context::~context ()
+{
+  int i;
+  memento *m;
+  FOR_EACH_VEC_ELT (m_mementos, i, m)
+    {
+      delete m;
+    }
+
+  if (m_builtins_manager)
+    delete m_builtins_manager;
+
+  if (m_owns_first_error_str)
+    free (m_first_error_str);
+}
+
+/* Add the given mememto to the list of those tracked by this
+   gcc::jit::recording::context, so that e.g. it can be deleted
+   when this context is released.  */
+
+void
+recording::context::record (memento *m)
+{
+  gcc_assert (m);
+
+  m_mementos.safe_push (m);
+}
+
+/* Replay this context (and any parents) into the given replayer.  */
+
+void
+recording::context::replay_into (replayer *r)
+{
+  int i;
+  memento *m;
+
+  /* If we have a parent context, we must replay it.  This will
+     recursively walk backwards up the historical tree, then replay things
+     forwards "in historical order", starting with the ultimate parent
+     context, until we reach the "this" context.
+
+     Note that we fully replay the parent, then fully replay the child,
+     which means that inter-context references can only exist from child
+     to parent, not the other way around.
+
+     All of this replaying is suboptimal - it would be better to do the
+     work for the parent context *once*, rather than replaying the parent
+     every time we replay each child.  However, fixing this requires deep
+     surgery to lifetime-management: we'd need every context family tree
+     to have its own GC heap, and to initialize the GCC code to use that
+     heap (with a mutex on such a heap).  */
+  if (m_parent_ctxt)
+    m_parent_ctxt->replay_into (r);
+
+  if (r->errors_occurred ())
+    return;
+
+  /* Replay this context's saved operations into r.  */
+  FOR_EACH_VEC_ELT (m_mementos, i, m)
+    {
+      /* Disabled low-level debugging, here if we need it: print what
+	 we're replaying.
+	 Note that the calls to get_debug_string might lead to more
+	 mementos being created for the strings.
+	 This can also be used to exercise the debug_string
+	 machinery.  */
+      if (0)
+	printf ("context %p replaying (%p): %s\n",
+		(void *)this, (void *)m, m->get_debug_string ());
+
+      m->replay_into (r);
+
+      if (r->errors_occurred ())
+	return;
+    }
+}
+
+/* During a playback, we associate objects from the recording with
+   their counterparts during this playback.
+
+   For simplicity, we store this within the recording objects.
+
+   The following method cleans away these associations, to ensure that
+   we never have out-of-date associations lingering on subsequent
+   playbacks (the objects pointed to are GC-managed, but the
+   recording objects don't own refs to them).  */
+
+void
+recording::context::disassociate_from_playback ()
+{
+  int i;
+  memento *m;
+
+  if (m_parent_ctxt)
+    m_parent_ctxt->disassociate_from_playback ();
+
+  FOR_EACH_VEC_ELT (m_mementos, i, m)
+    {
+      m->set_playback_obj (NULL);
+    }
+}
+
+/* Create a recording::string instance and add it to this context's list
+   of mementos.
+
+   This creates a fresh copy of the given 0-terminated buffer.  */
+
+recording::string *
+recording::context::new_string (const char *text)
+{
+  if (!text)
+    return NULL;
+
+  recording::string *result = new string (this, text);
+  record (result);
+  return result;
+}
+
+/* Create a recording::location instance and add it to this context's
+   list of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_new_location.  */
+
+recording::location *
+recording::context::new_location (const char *filename,
+				 int line,
+				 int column)
+{
+  recording::location *result =
+    new recording::location (this,
+			    new_string (filename),
+			    line, column);
+  record (result);
+  return result;
+}
+
+/* If we haven't seen this enum value yet, create a recording::type
+   instance and add it to this context's list of mementos.
+
+   If we have seen it before, reuse our cached value, so that repeated
+   calls on the context give the same object.
+
+   If we have a parent context, the cache is within the ultimate
+   ancestor context.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_get_type.  */
+
+recording::type *
+recording::context::get_type (enum gcc_jit_types kind)
+{
+  if (!m_basic_types[kind])
+    {
+      if (m_parent_ctxt)
+	m_basic_types[kind] = m_parent_ctxt->get_type (kind);
+      else
+	{
+	  recording::type *result = new memento_of_get_type (this, kind);
+	  record (result);
+	  m_basic_types[kind] = result;
+	}
+    }
+
+  return m_basic_types[kind];
+}
+
+/* Get a recording::type instance for the given size and signedness.
+   This is implemented in terms of recording::context::get_type
+   above.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_get_int_type.  */
+
+recording::type *
+recording::context::get_int_type (int num_bytes, int is_signed)
+{
+  /* We can't use a switch here since some of the values are macros affected
+     by options; e.g. i386.h has
+       #define LONG_TYPE_SIZE (TARGET_X32 ? 32 : BITS_PER_WORD)
+     Compare with tree.c's make_or_reuse_type.  Note that the _SIZE macros
+     are in bits, rather than bytes.
+  */
+  const int num_bits = num_bytes * 8;
+  if (num_bits == INT_TYPE_SIZE)
+    return get_type (is_signed
+		     ? GCC_JIT_TYPE_INT
+		     : GCC_JIT_TYPE_UNSIGNED_INT);
+  if (num_bits == CHAR_TYPE_SIZE)
+    return get_type (is_signed
+		     ? GCC_JIT_TYPE_SIGNED_CHAR
+		     : GCC_JIT_TYPE_UNSIGNED_CHAR);
+  if (num_bits == SHORT_TYPE_SIZE)
+    return get_type (is_signed
+		     ? GCC_JIT_TYPE_SHORT
+		     : GCC_JIT_TYPE_UNSIGNED_SHORT);
+  if (num_bits == LONG_TYPE_SIZE)
+    return get_type (is_signed
+		     ? GCC_JIT_TYPE_LONG
+		     : GCC_JIT_TYPE_UNSIGNED_LONG);
+  if (num_bits == LONG_LONG_TYPE_SIZE)
+    return get_type (is_signed
+		     ? GCC_JIT_TYPE_LONG_LONG
+		     : GCC_JIT_TYPE_UNSIGNED_LONG_LONG);
+
+  /* Some other size, not corresponding to the C int types.  */
+  /* To be written: support arbitrary other sizes, sharing by
+     memoizing at the recording::context level?  */
+  gcc_unreachable ();
+}
+
+/* Create a recording::type instance and add it to this context's list
+   of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_new_array_type.  */
+
+recording::type *
+recording::context::new_array_type (recording::location *loc,
+				    recording::type *element_type,
+				    int num_elements)
+{
+  if (struct_ *s = element_type->dyn_cast_struct ())
+    if (!s->get_fields ())
+      {
+	add_error (NULL,
+		   "cannot create an array of type %s"
+		   " until the fields have been set",
+		   s->get_name ()->c_str ());
+	return NULL;
+      }
+  recording::type *result =
+    new recording::array_type (this, loc, element_type, num_elements);
+  record (result);
+  return result;
+}
+
+/* Create a recording::field instance and add it to this context's list
+   of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_new_field.  */
+
+recording::field *
+recording::context::new_field (recording::location *loc,
+			       recording::type *type,
+			       const char *name)
+{
+  recording::field *result =
+    new recording::field (this, loc, type, new_string (name));
+  record (result);
+  return result;
+}
+
+/* Create a recording::struct_ instance and add it to this context's
+   list of mementos and list of compound types.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_new_struct_type.  */
+
+recording::struct_ *
+recording::context::new_struct_type (recording::location *loc,
+				     const char *name)
+{
+  recording::struct_ *result = new struct_ (this, loc, new_string (name));
+  record (result);
+  m_compound_types.safe_push (result);
+  return result;
+}
+
+/* Create a recording::union_ instance and add it to this context's
+   list of mementos and list of compound types.
+
+   Implements the first post-error-checking part of
+   gcc_jit_context_new_union_type.  */
+
+recording::union_ *
+recording::context::new_union_type (recording::location *loc,
+				    const char *name)
+{
+  recording::union_ *result = new union_ (this, loc, new_string (name));
+  record (result);
+  m_compound_types.safe_push (result);
+  return result;
+}
+
+/* Create a recording::type instance and add it to this context's list
+   of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_new_function_ptr_type.  */
+
+recording::type *
+recording::context::new_function_ptr_type (recording::location *, /* unused loc */
+					   recording::type *return_type,
+					   int num_params,
+					   recording::type **param_types,
+					   int is_variadic)
+{
+  recording::function_type *fn_type =
+    new function_type (this,
+		       return_type,
+		       num_params,
+		       param_types,
+		       is_variadic);
+  record (fn_type);
+
+  /* Return a pointer-type to the the function type.  */
+  return fn_type->get_pointer ();
+}
+
+/* Create a recording::param instance and add it to this context's list
+   of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_new_param.  */
+
+recording::param *
+recording::context::new_param (recording::location *loc,
+			       recording::type *type,
+			       const char *name)
+{
+  recording::param *result = new recording::param (this, loc, type, new_string (name));
+  record (result);
+  return result;
+}
+
+/* Create a recording::function instance and add it to this context's list
+   of mementos and list of functions.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_new_function.  */
+
+recording::function *
+recording::context::new_function (recording::location *loc,
+				  enum gcc_jit_function_kind kind,
+				  recording::type *return_type,
+				  const char *name,
+				  int num_params,
+				  recording::param **params,
+				  int is_variadic,
+				  enum built_in_function builtin_id)
+{
+  recording::function *result =
+    new recording::function (this,
+			     loc, kind, return_type,
+			     new_string (name),
+			     num_params, params, is_variadic,
+			     builtin_id);
+  record (result);
+  m_functions.safe_push (result);
+
+  return result;
+}
+
+/* Get a recording::function instance, which is lazily-created and added
+   to the context's lists of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_get_builtin_function.  */
+
+recording::function *
+recording::context::get_builtin_function (const char *name)
+{
+  if (!m_builtins_manager)
+    m_builtins_manager = new builtins_manager (this);
+  return m_builtins_manager->get_builtin_function (name);
+}
+
+/* Create a recording::global instance and add it to this context's list
+   of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_new_global.  */
+
+recording::lvalue *
+recording::context::new_global (recording::location *loc,
+				recording::type *type,
+				const char *name)
+{
+  recording::lvalue *result =
+    new recording::global (this, loc, type, new_string (name));
+  record (result);
+  return result;
+}
+
+/* Create a recording::memento_of_new_rvalue_from_int instance and add
+   it to this context's list of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_new_rvalue_from_int.  */
+
+recording::rvalue *
+recording::context::new_rvalue_from_int (recording::type *type,
+					 int value)
+{
+  recording::rvalue *result =
+    new memento_of_new_rvalue_from_int (this, NULL, type, value);
+  record (result);
+  return result;
+}
+
+/* Create a recording::memento_of_new_rvalue_from_double instance and
+   add it to this context's list of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_new_rvalue_from_double.  */
+
+recording::rvalue *
+recording::context::new_rvalue_from_double (recording::type *type,
+					    double value)
+{
+  recording::rvalue *result =
+    new memento_of_new_rvalue_from_double (this, NULL, type, value);
+  record (result);
+  return result;
+}
+
+/* Create a recording::memento_of_new_rvalue_from_ptr instance and add
+   it to this context's list of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_new_rvalue_from_ptr.  */
+
+recording::rvalue *
+recording::context::new_rvalue_from_ptr (recording::type *type,
+					 void *value)
+{
+  recording::rvalue *result =
+    new memento_of_new_rvalue_from_ptr (this, NULL, type, value);
+  record (result);
+  return result;
+}
+
+/* Create a recording::memento_of_new_string_literal instance and add it
+   to this context's list of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_new_string_literal.  */
+
+recording::rvalue *
+recording::context::new_string_literal (const char *value)
+{
+  recording::rvalue *result =
+    new memento_of_new_string_literal (this, NULL, new_string (value));
+  record (result);
+  return result;
+}
+
+/* Create a recording::unary_op instance and add it to this context's
+   list of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_new_unary_op.  */
+
+recording::rvalue *
+recording::context::new_unary_op (recording::location *loc,
+				  enum gcc_jit_unary_op op,
+				  recording::type *result_type,
+				  recording::rvalue *a)
+{
+  recording::rvalue *result =
+    new unary_op (this, loc, op, result_type, a);
+  record (result);
+  return result;
+}
+
+/* Create a recording::binary_op instance and add it to this context's
+   list of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_new_binary_op.  */
+
+recording::rvalue *
+recording::context::new_binary_op (recording::location *loc,
+				   enum gcc_jit_binary_op op,
+				   recording::type *result_type,
+				   recording::rvalue *a,
+				   recording::rvalue *b)
+{
+  recording::rvalue *result =
+    new binary_op (this, loc, op, result_type, a, b);
+  record (result);
+  return result;
+}
+
+/* Create a recording::comparison instance and add it to this context's
+   list of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_new_comparison.  */
+
+recording::rvalue *
+recording::context::new_comparison (recording::location *loc,
+				    enum gcc_jit_comparison op,
+				    recording::rvalue *a,
+				    recording::rvalue *b)
+{
+  recording::rvalue *result = new comparison (this, loc, op, a, b);
+  record (result);
+  return result;
+}
+
+/* Create a recording::cast instance and add it to this context's list
+   of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_new_cast.  */
+
+recording::rvalue *
+recording::context::new_cast (recording::location *loc,
+			      recording::rvalue *expr,
+			      recording::type *type_)
+{
+  recording::rvalue *result = new cast (this, loc, expr, type_);
+  record (result);
+  return result;
+}
+
+/* Create a recording::call instance and add it to this context's list
+   of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_new_call.  */
+
+recording::rvalue *
+recording::context::new_call (recording::location *loc,
+			      function *func,
+			      int numargs , recording::rvalue **args)
+{
+  recording::rvalue *result = new call (this, loc, func, numargs, args);
+  record (result);
+  return result;
+}
+
+/* Create a recording::call_through_ptr instance and add it to this
+   context's list of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_new_call_through_ptr.  */
+
+recording::rvalue *
+recording::context::new_call_through_ptr (recording::location *loc,
+					  recording::rvalue *fn_ptr,
+					  int numargs,
+					  recording::rvalue **args)
+  {
+  recording::rvalue *result = new call_through_ptr (this, loc, fn_ptr, numargs, args);
+  record (result);
+  return result;
+}
+
+/* Create a recording::array_access instance and add it to this context's list
+   of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_new_array_access.  */
+
+recording::lvalue *
+recording::context::new_array_access (recording::location *loc,
+				      recording::rvalue *ptr,
+				      recording::rvalue *index)
+{
+  recording::lvalue *result = new array_access (this, loc, ptr, index);
+  record (result);
+  return result;
+}
+
+/* Set the given string option for this context, or add an error if
+   it's not recognized.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_set_str_option.  */
+
+void
+recording::context::set_str_option (enum gcc_jit_str_option opt,
+				    const char *value)
+{
+  if (opt < 0 || opt >= GCC_JIT_NUM_STR_OPTIONS)
+    {
+      add_error (NULL,
+		 "unrecognized (enum gcc_jit_str_option) value: %i", opt);
+      return;
+    }
+  m_str_options[opt] = value;
+}
+
+/* Set the given integer option for this context, or add an error if
+   it's not recognized.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_set_int_option.  */
+
+void
+recording::context::set_int_option (enum gcc_jit_int_option opt,
+				    int value)
+{
+  if (opt < 0 || opt >= GCC_JIT_NUM_INT_OPTIONS)
+    {
+      add_error (NULL,
+		 "unrecognized (enum gcc_jit_int_option) value: %i", opt);
+      return;
+    }
+  m_int_options[opt] = value;
+}
+
+/* Set the given boolean option for this context, or add an error if
+   it's not recognized.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_set_bool_option.  */
+
+void
+recording::context::set_bool_option (enum gcc_jit_bool_option opt,
+				     int value)
+{
+  if (opt < 0 || opt >= GCC_JIT_NUM_BOOL_OPTIONS)
+    {
+      add_error (NULL,
+		 "unrecognized (enum gcc_jit_bool_option) value: %i", opt);
+      return;
+    }
+  m_bool_options[opt] = value ? true : false;
+}
+
+/* This mutex guards gcc::jit::recording::context::compile, so that only
+   one thread can be accessing the bulk of GCC's state at once.  */
+
+static pthread_mutex_t jit_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+/* Validate this context, and if it passes, compile it within a
+   mutex.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_compile.  */
+
+result *
+recording::context::compile ()
+{
+  validate ();
+
+  if (errors_occurred ())
+    return NULL;
+
+  /* Acquire the big GCC mutex. */
+  pthread_mutex_lock (&jit_mutex);
+  gcc_assert (NULL == ::gcc::jit::active_playback_ctxt);
+
+  /* Set up a playback context.  */
+  ::gcc::jit::playback::context replayer (this);
+  ::gcc::jit::active_playback_ctxt = &replayer;
+
+  result *result_obj = replayer.compile ();
+
+  /* Release the big GCC mutex. */
+  ::gcc::jit::active_playback_ctxt = NULL;
+  pthread_mutex_unlock (&jit_mutex);
+
+  return result_obj;
+}
+
+/* Format the given error using printf's conventions, print
+   it to stderr, and add it to the context.  */
+
+void
+recording::context::add_error (location *loc, const char *fmt, ...)
+{
+  va_list ap;
+  va_start (ap, fmt);
+  add_error_va (loc, fmt, ap);
+  va_end (ap);
+}
+
+/* Format the given error using printf's conventions, print
+   it to stderr, and add it to the context.  */
+
+void
+recording::context::add_error_va (location *loc, const char *fmt, va_list ap)
+{
+  char *malloced_msg;
+  const char *errmsg;
+  bool has_ownership;
+
+  vasprintf (&malloced_msg, fmt, ap);
+  if (malloced_msg)
+    {
+      errmsg = malloced_msg;
+      has_ownership = true;
+    }
+  else
+    {
+      errmsg = "out of memory generating error message";
+      has_ownership = false;
+    }
+
+  const char *ctxt_progname =
+    get_str_option (GCC_JIT_STR_OPTION_PROGNAME);
+  if (!ctxt_progname)
+    ctxt_progname = "libgccjit.so";
+
+  if (loc)
+    fprintf (stderr, "%s: %s: error: %s\n",
+	     ctxt_progname,
+	     loc->get_debug_string (),
+	     errmsg);
+  else
+    fprintf (stderr, "%s: error: %s\n",
+	     ctxt_progname,
+	     errmsg);
+
+  if (!m_error_count)
+    {
+      m_first_error_str = const_cast <char *> (errmsg);
+      m_owns_first_error_str = has_ownership;
+    }
+  else
+    if (has_ownership)
+      free (malloced_msg);
+
+  m_error_count++;
+}
+
+/* Get the message for the first error that occurred on this context, or
+   NULL if no errors have occurred on it.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_get_first_error.  */
+
+const char *
+recording::context::get_first_error () const
+{
+  return m_first_error_str;
+}
+
+/* Lazily generate and record a recording::type representing an opaque
+   struct named "FILE".
+
+   For use if client code tries to dereference the result of
+   get_type (GCC_JIT_TYPE_FILE_PTR).  */
+
+recording::type *
+recording::context::get_opaque_FILE_type ()
+{
+  if (!m_FILE_type)
+    m_FILE_type = new_struct_type (NULL, "FILE");
+  return m_FILE_type;
+}
+
+/* Dump a C-like representation of the given context to the given path.
+   If UPDATE_LOCATIONS is true, update the locations within the
+   context's mementos to point to the dumpfile.
+
+   Implements the post-error-checking part of
+   gcc_jit_context_dump_to_file.  */
+
+void
+recording::context::dump_to_file (const char *path, bool update_locations)
+{
+  int i;
+  dump d (*this, path, update_locations);
+
+  /* Forward declaration of structs and unions.  */
+  compound_type *st;
+  FOR_EACH_VEC_ELT (m_compound_types, i, st)
+    {
+      d.write ("%s;\n\n", st->get_debug_string ());
+    }
+
+  /* Content of structs, where set.  */
+  FOR_EACH_VEC_ELT (m_compound_types, i, st)
+    if (st->get_fields ())
+      {
+	st->get_fields ()->write_to_dump (d);
+	d.write ("\n");
+      }
+
+  function *fn;
+  FOR_EACH_VEC_ELT (m_functions, i, fn)
+    {
+      fn->write_to_dump (d);
+    }
+}
+
+/* This is a pre-compilation check for the context (and any parents).
+
+   Detect errors within the context, adding errors if any are found.  */
+
+void
+recording::context::validate ()
+{
+  if (m_parent_ctxt)
+    m_parent_ctxt->validate ();
+
+  int i;
+  function *fn;
+  FOR_EACH_VEC_ELT (m_functions, i, fn)
+    fn->validate ();
+}
+
+/* The implementation of class gcc::jit::recording::memento.  */
+
+/* Get a (const char *) debug description of the given memento, by
+   calling the pure-virtual make_debug_string hook, caching the
+   result.
+
+   It is intended that this should only be called in debugging and
+   error-handling paths, so this doesn't need to be particularly
+   optimized.  */
+
+const char *
+recording::memento::get_debug_string ()
+{
+  if (!m_debug_string)
+    m_debug_string = make_debug_string ();
+  return m_debug_string->c_str ();
+}
+
+/* Default implementation of recording::memento::write_to_dump, writing
+   an indented form of the memento's debug string to the dump.  */
+
+void
+recording::memento::write_to_dump (dump &d)
+{
+  d.write("  %s\n", get_debug_string ());
+}
+
+/* The implementation of class gcc::jit::recording::string.  */
+
+/* Constructor for gcc::jit::recording::string::string, allocating a
+   copy of the given text using new char[].  */
+
+recording::string::string (context *ctxt, const char *text)
+  : memento (ctxt)
+{
+  m_len = strlen (text);
+  m_buffer = new char[m_len + 1];
+  strcpy (m_buffer, text);
+}
+
+/* Destructor for gcc::jit::recording::string::string.  */
+
+recording::string::~string ()
+{
+  delete[] m_buffer;
+}
+
+/* Function for making gcc::jit::recording::string instances on a
+   context via printf-style formatting.
+
+   It is intended that this should only be called in debugging and
+   error-handling paths, so this doesn't need to be particularly
+   optimized, hence the double-copy of the string is acceptable.  */
+
+recording::string *
+recording::string::from_printf (context *ctxt, const char *fmt, ...)
+{
+  va_list ap;
+  char *buf = NULL;
+  recording::string *result;
+
+  va_start (ap, fmt);
+  vasprintf (&buf, fmt, ap);
+  va_end (ap);
+
+  if (!buf)
+    {
+      ctxt->add_error (NULL, "malloc failure");
+      return NULL;
+    }
+
+  result = ctxt->new_string (buf);
+  free (buf);
+  return result;
+}
+
+/* Implementation of recording::memento::make_debug_string for strings,
+   wrapping the given string in quotes and escaping as necessary.  */
+
+recording::string *
+recording::string::make_debug_string ()
+{
+  /* Hack to avoid infinite recursion into strings when logging all
+     mementos: don't re-escape strings:  */
+  if (m_buffer[0] == '"')
+    return this;
+
+  /* Wrap in quotes and do escaping etc */
+
+  size_t sz = (1 /* opening quote */
+	       + (m_len * 2) /* each char might get escaped */
+	       + 1 /* closing quote */
+	       + 1); /* nil termintator */
+  char *tmp = new char[sz];
+  size_t len = 0;
+
+#define APPEND(CH)  do { gcc_assert (len < sz); tmp[len++] = (CH); } while (0)
+  APPEND('"'); /* opening quote */
+  for (size_t i = 0; i < m_len ; i++)
+    {
+      char ch = m_buffer[i];
+      if (ch == '\t' || ch == '\n' || ch == '\\' || ch == '"')
+	APPEND('\\');
+      APPEND(ch);
+    }
+  APPEND('"'); /* closing quote */
+#undef APPEND
+  tmp[len] = '\0'; /* nil termintator */
+
+  string *result = m_ctxt->new_string (tmp);
+
+  delete[] tmp;
+  return result;
+}
+
+/* The implementation of class gcc::jit::recording::location.  */
+
+/* Implementation of recording::memento::replay_into for locations.
+
+   Create a new playback::location and store it into the
+   recording::location's m_playback_obj field.  */
+
+void
+recording::location::replay_into (replayer *r)
+{
+  m_playback_obj = r->new_location (this,
+				    m_filename->c_str (),
+				    m_line,
+				    m_column);
+}
+
+/* Implementation of recording::memento::make_debug_string for locations,
+   turning them into the usual form:
+     FILENAME:LINE:COLUMN
+   like we do when emitting diagnostics.  */
+
+recording::string *
+recording::location::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "%s:%i:%i",
+			      m_filename->c_str (), m_line, m_column);
+}
+
+/* The implementation of class gcc::jit::recording::type.  */
+
+/* Given a type T, get the type T*.
+
+   If this doesn't already exist, generate a new memento_of_get_pointer
+   instance and add it to this type's context's list of mementos.
+
+   Otherwise, use the cached type.
+
+   Implements the post-error-checking part of
+   gcc_jit_type_get_pointer.  */
+
+recording::type *
+recording::type::get_pointer ()
+{
+  if (!m_pointer_to_this_type)
+    {
+      m_pointer_to_this_type = new memento_of_get_pointer (this);
+      m_ctxt->record (m_pointer_to_this_type);
+    }
+  return m_pointer_to_this_type;
+}
+
+/* Given a type T, get the type const T.
+
+   Implements the post-error-checking part of
+   gcc_jit_type_get_const.  */
+
+recording::type *
+recording::type::get_const ()
+{
+  recording::type *result = new memento_of_get_const (this);
+  m_ctxt->record (result);
+  return result;
+}
+
+/* Given a type T, get the type volatile T.
+
+   Implements the post-error-checking part of
+   gcc_jit_type_get_volatile.  */
+
+recording::type *
+recording::type::get_volatile ()
+{
+  recording::type *result = new memento_of_get_volatile (this);
+  m_ctxt->record (result);
+  return result;
+}
+
+/* Implementation of pure virtual hook recording::type::dereference for
+   recording::memento_of_get_type.  */
+
+recording::type *
+recording::memento_of_get_type::dereference ()
+{
+  switch (m_kind)
+    {
+    default: gcc_unreachable ();
+
+    case GCC_JIT_TYPE_VOID:
+      return NULL;
+
+    case GCC_JIT_TYPE_VOID_PTR:
+      return m_ctxt->get_type (GCC_JIT_TYPE_VOID);
+
+    case GCC_JIT_TYPE_BOOL:
+    case GCC_JIT_TYPE_CHAR:
+    case GCC_JIT_TYPE_SIGNED_CHAR:
+    case GCC_JIT_TYPE_UNSIGNED_CHAR:
+    case GCC_JIT_TYPE_SHORT:
+    case GCC_JIT_TYPE_UNSIGNED_SHORT:
+    case GCC_JIT_TYPE_INT:
+    case GCC_JIT_TYPE_UNSIGNED_INT:
+    case GCC_JIT_TYPE_LONG:
+    case GCC_JIT_TYPE_UNSIGNED_LONG:
+    case GCC_JIT_TYPE_LONG_LONG:
+    case GCC_JIT_TYPE_UNSIGNED_LONG_LONG:
+    case GCC_JIT_TYPE_FLOAT:
+    case GCC_JIT_TYPE_DOUBLE:
+    case GCC_JIT_TYPE_LONG_DOUBLE:
+      /* Not a pointer: */
+      return NULL;
+
+    case GCC_JIT_TYPE_CONST_CHAR_PTR:
+      return m_ctxt->get_type (GCC_JIT_TYPE_CHAR)->get_const ();
+
+    case GCC_JIT_TYPE_SIZE_T:
+      /* Not a pointer: */
+      return NULL;
+
+    case GCC_JIT_TYPE_FILE_PTR:
+      /* Give the client code back an opaque "struct FILE".  */
+      return m_ctxt->get_opaque_FILE_type ();
+    }
+}
+
+/* Implementation of pure virtual hook recording::type::is_int for
+   recording::memento_of_get_type.  */
+
+bool
+recording::memento_of_get_type::is_int () const
+{
+  switch (m_kind)
+    {
+    default: gcc_unreachable ();
+
+    case GCC_JIT_TYPE_VOID:
+      return false;
+
+    case GCC_JIT_TYPE_VOID_PTR:
+      return false;
+
+    case GCC_JIT_TYPE_BOOL:
+      return false;
+
+    case GCC_JIT_TYPE_CHAR:
+    case GCC_JIT_TYPE_SIGNED_CHAR:
+    case GCC_JIT_TYPE_UNSIGNED_CHAR:
+    case GCC_JIT_TYPE_SHORT:
+    case GCC_JIT_TYPE_UNSIGNED_SHORT:
+    case GCC_JIT_TYPE_INT:
+    case GCC_JIT_TYPE_UNSIGNED_INT:
+    case GCC_JIT_TYPE_LONG:
+    case GCC_JIT_TYPE_UNSIGNED_LONG:
+    case GCC_JIT_TYPE_LONG_LONG:
+    case GCC_JIT_TYPE_UNSIGNED_LONG_LONG:
+      return true;
+
+    case GCC_JIT_TYPE_FLOAT:
+    case GCC_JIT_TYPE_DOUBLE:
+    case GCC_JIT_TYPE_LONG_DOUBLE:
+      return false;
+
+    case GCC_JIT_TYPE_CONST_CHAR_PTR:
+      return false;
+
+    case GCC_JIT_TYPE_SIZE_T:
+      return true;
+
+    case GCC_JIT_TYPE_FILE_PTR:
+      return false;
+    }
+}
+
+/* Implementation of pure virtual hook recording::type::is_float for
+   recording::memento_of_get_type.  */
+
+bool
+recording::memento_of_get_type::is_float () const
+{
+  switch (m_kind)
+    {
+    default: gcc_unreachable ();
+
+    case GCC_JIT_TYPE_VOID:
+      return false;
+
+    case GCC_JIT_TYPE_VOID_PTR:
+      return false;
+
+    case GCC_JIT_TYPE_BOOL:
+      return false;
+
+    case GCC_JIT_TYPE_CHAR:
+    case GCC_JIT_TYPE_SIGNED_CHAR:
+    case GCC_JIT_TYPE_UNSIGNED_CHAR:
+    case GCC_JIT_TYPE_SHORT:
+    case GCC_JIT_TYPE_UNSIGNED_SHORT:
+    case GCC_JIT_TYPE_INT:
+    case GCC_JIT_TYPE_UNSIGNED_INT:
+    case GCC_JIT_TYPE_LONG:
+    case GCC_JIT_TYPE_UNSIGNED_LONG:
+    case GCC_JIT_TYPE_LONG_LONG:
+    case GCC_JIT_TYPE_UNSIGNED_LONG_LONG:
+      return false;
+
+    case GCC_JIT_TYPE_FLOAT:
+    case GCC_JIT_TYPE_DOUBLE:
+    case GCC_JIT_TYPE_LONG_DOUBLE:
+      return true;
+
+    case GCC_JIT_TYPE_CONST_CHAR_PTR:
+      return false;
+
+    case GCC_JIT_TYPE_SIZE_T:
+      return false;
+
+    case GCC_JIT_TYPE_FILE_PTR:
+      return false;
+    }
+}
+
+/* Implementation of pure virtual hook recording::type::is_bool for
+   recording::memento_of_get_type.  */
+
+bool
+recording::memento_of_get_type::is_bool () const
+{
+  switch (m_kind)
+    {
+    default: gcc_unreachable ();
+
+    case GCC_JIT_TYPE_VOID:
+      return false;
+
+    case GCC_JIT_TYPE_VOID_PTR:
+      return false;
+
+    case GCC_JIT_TYPE_BOOL:
+      return true;
+
+    case GCC_JIT_TYPE_CHAR:
+    case GCC_JIT_TYPE_SIGNED_CHAR:
+    case GCC_JIT_TYPE_UNSIGNED_CHAR:
+    case GCC_JIT_TYPE_SHORT:
+    case GCC_JIT_TYPE_UNSIGNED_SHORT:
+    case GCC_JIT_TYPE_INT:
+    case GCC_JIT_TYPE_UNSIGNED_INT:
+    case GCC_JIT_TYPE_LONG:
+    case GCC_JIT_TYPE_UNSIGNED_LONG:
+    case GCC_JIT_TYPE_LONG_LONG:
+    case GCC_JIT_TYPE_UNSIGNED_LONG_LONG:
+      return false;
+
+    case GCC_JIT_TYPE_FLOAT:
+    case GCC_JIT_TYPE_DOUBLE:
+    case GCC_JIT_TYPE_LONG_DOUBLE:
+      return false;
+
+    case GCC_JIT_TYPE_CONST_CHAR_PTR:
+      return false;
+
+    case GCC_JIT_TYPE_SIZE_T:
+      return false;
+
+    case GCC_JIT_TYPE_FILE_PTR:
+      return false;
+    }
+}
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::memento_of_get_type.  */
+
+void
+recording::memento_of_get_type::replay_into (replayer *r)
+{
+  set_playback_obj (r->get_type (m_kind));
+}
+
+/* The implementation of class gcc::jit::recording::memento_of_get_type.  */
+
+/* Descriptive strings for each of enum gcc_jit_types.  */
+
+static const char * const get_type_strings[] = {
+  "void",    /* GCC_JIT_TYPE_VOID */
+  "void *",  /* GCC_JIT_TYPE_VOID_PTR */
+
+  "bool",  /* GCC_JIT_TYPE_BOOL */
+
+  "char",           /* GCC_JIT_TYPE_CHAR */
+  "signed char",    /* GCC_JIT_TYPE_SIGNED_CHAR */
+  "unsigned char",  /* GCC_JIT_TYPE_UNSIGNED_CHAR */
+
+  "short",           /* GCC_JIT_TYPE_SHORT */
+  "unsigned short",  /* GCC_JIT_TYPE_UNSIGNED_SHORT */
+
+  "int",           /* GCC_JIT_TYPE_INT */
+  "unsigned int",  /* GCC_JIT_TYPE_UNSIGNED_INT */
+
+  "long",           /* GCC_JIT_TYPE_LONG  */
+  "unsigned long",  /* GCC_JIT_TYPE_UNSIGNED_LONG, */
+
+  "long long",           /* GCC_JIT_TYPE_LONG_LONG */
+  "unsigned long long",  /* GCC_JIT_TYPE_UNSIGNED_LONG_LONG */
+
+  "float",        /* GCC_JIT_TYPE_FLOAT */
+  "double",       /* GCC_JIT_TYPE_DOUBLE */
+  "long double",  /* GCC_JIT_TYPE_LONG_DOUBLE */
+
+  "const char *",  /* GCC_JIT_TYPE_CONST_CHAR_PTR */
+
+  "size_t",  /* GCC_JIT_TYPE_SIZE_T */
+
+  "FILE *"  /* GCC_JIT_TYPE_FILE_PTR */
+
+};
+
+/* Implementation of recording::memento::make_debug_string for
+   results of get_type, using a simple table of type names.  */
+
+recording::string *
+recording::memento_of_get_type::make_debug_string ()
+{
+  return m_ctxt->new_string (get_type_strings[m_kind]);
+}
+
+/* The implementation of class gcc::jit::recording::memento_of_get_pointer.  */
+
+/* Override of default implementation of
+   recording::type::accepts_writes_from for get_pointer.
+
+   Require a pointer type, and allowing writes to
+   (const T *) from a (T*), but not the other way around.  */
+
+bool
+recording::memento_of_get_pointer::accepts_writes_from (type *rtype)
+{
+  /* Must be a pointer type: */
+  type *rtype_points_to = rtype->is_pointer ();
+  if (!rtype_points_to)
+    return false;
+
+  /* It's OK to assign to a (const T *) from a (T *).  */
+  return m_other_type->unqualified ()
+    ->accepts_writes_from (rtype_points_to);
+}
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::memento_of_get_pointer.  */
+
+void
+recording::memento_of_get_pointer::replay_into (replayer *)
+{
+  set_playback_obj (m_other_type->playback_type ()->get_pointer ());
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   results of get_pointer, adding " *" to the underlying type,
+   with special-casing to handle function pointer types.  */
+
+recording::string *
+recording::memento_of_get_pointer::make_debug_string ()
+{
+  /* Special-case function pointer types, to put the "*" in parens between
+     the return type and the params (for one level of dereferencing, at
+     least).  */
+  if (function_type *fn_type = m_other_type->dyn_cast_function_type ())
+    return fn_type->make_debug_string_with_ptr ();
+
+  return string::from_printf (m_ctxt,
+			      "%s *", m_other_type->get_debug_string ());
+}
+
+/* The implementation of class gcc::jit::recording::memento_of_get_const.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::memento_of_get_const.  */
+
+void
+recording::memento_of_get_const::replay_into (replayer *)
+{
+  set_playback_obj (m_other_type->playback_type ()->get_const ());
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   results of get_const, prepending "const ".  */
+
+recording::string *
+recording::memento_of_get_const::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "const %s", m_other_type->get_debug_string ());
+}
+
+/* The implementation of class gcc::jit::recording::memento_of_get_volatile.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::memento_of_get_volatile.  */
+
+void
+recording::memento_of_get_volatile::replay_into (replayer *)
+{
+  set_playback_obj (m_other_type->playback_type ()->get_volatile ());
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   results of get_volatile, prepending "volatile ".  */
+
+recording::string *
+recording::memento_of_get_volatile::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "volatile %s", m_other_type->get_debug_string ());
+}
+
+/* The implementation of class gcc::jit::recording::array_type */
+
+/* Implementation of pure virtual hook recording::type::dereference for
+   recording::array_type.  */
+
+recording::type *
+recording::array_type::dereference ()
+{
+  return m_element_type;
+}
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::array_type.  */
+
+void
+recording::array_type::replay_into (replayer *r)
+{
+  set_playback_obj (r->new_array_type (playback_location (r, m_loc),
+				       m_element_type->playback_type (),
+				       m_num_elements));
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   results of new_array_type.  */
+
+recording::string *
+recording::array_type::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "%s[%d]",
+			      m_element_type->get_debug_string (),
+			      m_num_elements);
+}
+
+/* The implementation of class gcc::jit::recording::function_type */
+
+/* Constructor for gcc::jit::recording::function_type.  */
+
+recording::function_type::function_type (context *ctxt,
+					 type *return_type,
+					 int num_params,
+					 type **param_types,
+					 int is_variadic)
+: type (ctxt),
+  m_return_type (return_type),
+  m_param_types (),
+  m_is_variadic (is_variadic)
+{
+  for (int i = 0; i< num_params; i++)
+    m_param_types.safe_push (param_types[i]);
+}
+
+/* Implementation of pure virtual hook recording::type::dereference for
+   recording::function_type.  */
+
+recording::type *
+recording::function_type::dereference ()
+{
+  return NULL;
+}
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::function_type.  */
+
+void
+recording::function_type::replay_into (replayer *r)
+{
+  /* Convert m_param_types to a vec of playback type.  */
+  vec <playback::type *> param_types;
+  int i;
+  recording::type *type;
+  param_types.create (m_param_types.length ());
+  FOR_EACH_VEC_ELT (m_param_types, i, type)
+    param_types.safe_push (type->playback_type ());
+
+  set_playback_obj (r->new_function_type (m_return_type->playback_type (),
+					  &param_types,
+					  m_is_variadic));
+}
+
+/* Special-casing for make_debug_string for get_pointer results for
+   handling (one level) of pointers to functions.  */
+
+recording::string *
+recording::function_type::make_debug_string_with_ptr ()
+{
+  return make_debug_string_with ("(*) ");
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   results of new_function_type.  */
+
+recording::string *
+recording::function_type::make_debug_string ()
+{
+  return make_debug_string_with ("");
+}
+
+/* Build a debug string representation of the form:
+
+     RESULT_TYPE INSERT (PARAM_TYPES)
+
+   for use when handling 0 and 1 level of indirection to this
+   function type.  */
+
+recording::string *
+recording::function_type::make_debug_string_with (const char *insert)
+{
+  /* First, build a buffer for the arguments.  */
+  /* Calculate length of said buffer.  */
+  size_t sz = 1; /* nil terminator */
+  for (unsigned i = 0; i< m_param_types.length (); i++)
+    {
+      sz += strlen (m_param_types[i]->get_debug_string ());
+      sz += 2; /* ", " separator */
+    }
+  if (m_is_variadic)
+    sz += 5; /* ", ..." separator and ellipsis */
+
+  /* Now allocate and populate the buffer.  */
+  char *argbuf = new char[sz];
+  size_t len = 0;
+
+  for (unsigned i = 0; i< m_param_types.length (); i++)
+    {
+      strcpy (argbuf + len, m_param_types[i]->get_debug_string ());
+      len += strlen (m_param_types[i]->get_debug_string ());
+      if (i + 1 < m_param_types.length ())
+	{
+	  strcpy (argbuf + len, ", ");
+	  len += 2;
+	}
+    }
+  if (m_is_variadic)
+    {
+      if (m_param_types.length ())
+	{
+	  strcpy (argbuf + len, ", ");
+	  len += 2;
+	}
+      strcpy (argbuf + len, "...");
+      len += 3;
+    }
+  argbuf[len] = '\0';
+
+  /* ...and use it to get the string for the call as a whole.  */
+  string *result = string::from_printf (m_ctxt,
+					"%s %s(%s)",
+					m_return_type->get_debug_string (),
+					insert,
+					argbuf);
+
+  delete[] argbuf;
+
+  return result;
+}
+
+/* The implementation of class gcc::jit::recording::field.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::field.  */
+
+void
+recording::field::replay_into (replayer *r)
+{
+  set_playback_obj (r->new_field (playback_location (r, m_loc),
+				  m_type->playback_type (),
+				  playback_string (m_name)));
+}
+
+/* Override the default implementation of
+   recording::memento::write_to_dump.  Dump each field
+   by dumping a line of the form:
+      TYPE NAME;
+   so that we can build up a struct/union field-byfield.  */
+
+void
+recording::field::write_to_dump (dump &d)
+{
+  d.write ("  %s %s;\n",
+	   m_type->get_debug_string (),
+	   m_name->c_str ());
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   results of new_field.  */
+
+recording::string *
+recording::field::make_debug_string ()
+{
+  return m_name;
+}
+
+/* The implementation of class gcc::jit::recording::compound_type */
+
+/* The constructor for gcc::jit::recording::compound_type.  */
+
+recording::compound_type::compound_type (context *ctxt,
+					 location *loc,
+					 string *name)
+: type (ctxt),
+  m_loc (loc),
+  m_name (name),
+  m_fields (NULL)
+{
+}
+
+/* Set the fields of a compound type.
+
+   Implements the post-error-checking part of
+   gcc_jit_struct_set_fields, and is also used by
+   gcc_jit_context_new_union_type.  */
+
+void
+recording::compound_type::set_fields (location *loc,
+				      int num_fields,
+				      field **field_array)
+{
+  m_loc = loc;
+  gcc_assert (NULL == m_fields);
+
+  m_fields = new fields (this, num_fields, field_array);
+  m_ctxt->record (m_fields);
+}
+
+/* Implementation of pure virtual hook recording::type::dereference for
+   recording::compound_type.  */
+
+recording::type *
+recording::compound_type::dereference ()
+{
+  return NULL; /* not a pointer */
+}
+
+/* The implementation of class gcc::jit::recording::struct_.  */
+
+/* The constructor for gcc::jit::recording::struct_.  */
+
+recording::struct_::struct_ (context *ctxt,
+			     location *loc,
+			     string *name)
+: compound_type (ctxt, loc, name)
+{
+}
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::struct_.  */
+
+void
+recording::struct_::replay_into (replayer *r)
+{
+  set_playback_obj (
+    r->new_compound_type (playback_location (r, get_loc ()),
+			  get_name ()->c_str (),
+			  true /* is_struct */));
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   structs.  */
+
+recording::string *
+recording::struct_::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "struct %s", get_name ()->c_str ());
+}
+
+/* The implementation of class gcc::jit::recording::union_.  */
+
+/* The constructor for gcc::jit::recording::union_.  */
+
+recording::union_::union_ (context *ctxt,
+			   location *loc,
+			   string *name)
+: compound_type (ctxt, loc, name)
+{
+}
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::union_.  */
+
+void
+recording::union_::replay_into (replayer *r)
+{
+  set_playback_obj (
+    r->new_compound_type (playback_location (r, get_loc ()),
+			  get_name ()->c_str (),
+			  false /* is_struct */));
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   unions.  */
+
+recording::string *
+recording::union_::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "union %s", get_name ()->c_str ());
+}
+
+/* The implementation of class gcc::jit::recording::fields.  */
+
+/* The constructor for gcc::jit::recording::fields.  */
+
+recording::fields::fields (compound_type *struct_or_union,
+			   int num_fields,
+			   field **fields)
+: memento (struct_or_union->m_ctxt),
+  m_struct_or_union (struct_or_union),
+  m_fields ()
+{
+  for (int i = 0; i < num_fields; i++)
+    {
+      gcc_assert (fields[i]->get_container () == NULL);
+      fields[i]->set_container (m_struct_or_union);
+      m_fields.safe_push (fields[i]);
+    }
+}
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::fields.  */
+
+void
+recording::fields::replay_into (replayer *)
+{
+  vec<playback::field *> playback_fields;
+  playback_fields.create (m_fields.length ());
+  for (unsigned i = 0; i < m_fields.length (); i++)
+    playback_fields.safe_push (m_fields[i]->playback_field ());
+  m_struct_or_union->playback_compound_type ()->set_fields (playback_fields);
+}
+
+/* Override the default implementation of
+   recording::memento::write_to_dump by writing a union/struct
+   declaration of this form:
+
+      struct/union NAME {
+        TYPE_1 NAME_1;
+        TYPE_2 NAME_2;
+	....
+        TYPE_N NAME_N;
+      };
+
+    to the dump.  */
+
+void
+recording::fields::write_to_dump (dump &d)
+{
+  int i;
+  field *f;
+
+  d.write ("%s\n{\n", m_struct_or_union->get_debug_string ());
+  FOR_EACH_VEC_ELT (m_fields, i, f)
+    f->write_to_dump (d);
+  d.write ("};\n");
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   field tables.  */
+
+recording::string *
+recording::fields::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "fields");
+}
+
+/* The implementation of class gcc::jit::recording::rvalue.  */
+
+/* Create a recording::access_field_rvalue instance and add it to
+   the rvalue's context's list of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_rvalue_access_field.  */
+
+recording::rvalue *
+recording::rvalue::access_field (recording::location *loc,
+				 field *field)
+{
+  recording::rvalue *result =
+    new access_field_rvalue (m_ctxt, loc, this, field);
+  m_ctxt->record (result);
+  return result;
+}
+
+/* Create a recording::dereference_field_rvalue instance and add it to
+   the rvalue's context's list of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_rvalue_dereference_field.  */
+
+recording::lvalue *
+recording::rvalue::dereference_field (recording::location *loc,
+				      field *field)
+{
+  recording::lvalue *result =
+    new dereference_field_rvalue (m_ctxt, loc, this, field);
+  m_ctxt->record (result);
+  return result;
+}
+
+/* Create a recording::dereference_rvalue instance and add it to the
+   rvalue's context's list of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_rvalue_dereference.  */
+
+recording::lvalue *
+recording::rvalue::dereference (recording::location *loc)
+{
+  recording::lvalue *result =
+    new dereference_rvalue (m_ctxt, loc, this);
+  m_ctxt->record (result);
+  return result;
+}
+
+/* The implementation of class gcc::jit::recording::lvalue.  */
+
+/* Create a recording::new_access_field_of_lvalue instance and add it to
+   the lvalue's context's list of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_lvalue_access_field.  */
+
+recording::lvalue *
+recording::lvalue::access_field (recording::location *loc,
+				 field *field)
+{
+  recording::lvalue *result =
+    new access_field_of_lvalue (m_ctxt, loc, this, field);
+  m_ctxt->record (result);
+  return result;
+}
+
+/* Create a recording::get_address_of_lvalue instance and add it to
+   the lvalue's context's list of mementos.
+
+   Implements the post-error-checking part of
+   gcc_jit_lvalue_get_address.  */
+
+recording::rvalue *
+recording::lvalue::get_address (recording::location *loc)
+{
+  recording::rvalue *result =
+    new get_address_of_lvalue (m_ctxt, loc, this);
+  m_ctxt->record (result);
+  return result;
+}
+
+/* The implementation of class gcc::jit::recording::param.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::param.  */
+
+void
+recording::param::replay_into (replayer *r)
+{
+  set_playback_obj (r->new_param (playback_location (r, m_loc),
+				  m_type->playback_type (),
+				  m_name->c_str ()));
+}
+
+
+/* The implementation of class gcc::jit::recording::function.  */
+
+/* gcc::jit::recording::function's constructor.  */
+
+recording::function::function (context *ctxt,
+			       recording::location *loc,
+			       enum gcc_jit_function_kind kind,
+			       type *return_type,
+			       recording::string *name,
+			       int num_params,
+			       recording::param **params,
+			       int is_variadic,
+			       enum built_in_function builtin_id)
+: memento (ctxt),
+  m_loc (loc),
+  m_kind (kind),
+  m_return_type (return_type),
+  m_name (name),
+  m_params (),
+  m_is_variadic (is_variadic),
+  m_builtin_id (builtin_id),
+  m_locals (),
+  m_blocks ()
+{
+  for (int i = 0; i< num_params; i++)
+    m_params.safe_push (params[i]);
+}
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::function.  */
+
+void
+recording::function::replay_into (replayer *r)
+{
+  /* Convert m_params to a vec of playback param.  */
+  vec <playback::param *> params;
+  int i;
+  recording::param *param;
+  params.create (m_params.length ());
+  FOR_EACH_VEC_ELT (m_params, i, param)
+    params.safe_push (param->playback_param ());
+
+  set_playback_obj (r->new_function (playback_location (r, m_loc),
+				     m_kind,
+				     m_return_type->playback_type (),
+				     m_name->c_str (),
+				     &params,
+				     m_is_variadic,
+				     m_builtin_id));
+}
+
+/* Create a recording::local instance and add it to
+   the functions's context's list of mementos, and to the function's
+   list of locals.
+
+   Implements the post-error-checking part of
+   gcc_jit_function_new_local.  */
+
+recording::lvalue *
+recording::function::new_local (recording::location *loc,
+				type *type,
+				const char *name)
+{
+  local *result = new local (this, loc, type, new_string (name));
+  m_ctxt->record (result);
+  m_locals.safe_push (result);
+  return result;
+}
+
+/* Create a recording::block instance and add it to
+   the functions's context's list of mementos, and to the function's
+   list of blocks.
+
+   Implements the post-error-checking part of
+   gcc_jit_function_new_block.  */
+
+recording::block*
+recording::function::new_block (const char *name)
+{
+  gcc_assert (m_kind != GCC_JIT_FUNCTION_IMPORTED);
+
+  recording::block *result =
+    new recording::block (this, m_blocks.length (), new_string (name));
+  m_ctxt->record (result);
+  m_blocks.safe_push (result);
+  return result;
+}
+
+/* Override the default implementation of
+   recording::memento::write_to_dump by dumping a C-like
+   representation of the function; either like a prototype
+   for GCC_JIT_FUNCTION_IMPORTED, or like a full definition for
+   all other kinds of function.  */
+
+void
+recording::function::write_to_dump (dump &d)
+{
+  switch (m_kind)
+    {
+    default: gcc_unreachable ();
+    case GCC_JIT_FUNCTION_EXPORTED:
+    case GCC_JIT_FUNCTION_IMPORTED:
+      d.write ("extern ");
+      break;
+    case GCC_JIT_FUNCTION_INTERNAL:
+      d.write ("static ");
+      break;
+    case GCC_JIT_FUNCTION_ALWAYS_INLINE:
+      d.write ("static inline ");
+      break;
+     }
+  d.write ("%s\n", m_return_type->get_debug_string ());
+
+  if (d.update_locations ())
+    m_loc = d.make_location ();
+
+  d.write ("%s (", get_debug_string ());
+
+  int i;
+  recording::param *param;
+  FOR_EACH_VEC_ELT (m_params, i, param)
+    {
+      if (i > 0)
+	d.write (", ");
+      d.write ("%s %s",
+	       param->get_type ()->get_debug_string (),
+	       param->get_debug_string ());
+    }
+  d.write (")");
+  if (m_kind == GCC_JIT_FUNCTION_IMPORTED)
+    {
+      d.write ("; /* (imported) */\n\n");
+    }
+  else
+    {
+      int i;
+      local *var = NULL;
+      block *b;
+      d.write ("\n{\n");
+
+      /* Write locals: */
+      FOR_EACH_VEC_ELT (m_locals, i, var)
+	var->write_to_dump (d);
+      if (m_locals.length ())
+	d.write ("\n");
+
+      /* Write each block: */
+      FOR_EACH_VEC_ELT (m_blocks, i, b)
+	{
+	  if (i > 0)
+	    d.write ("\n");
+	  b->write_to_dump (d);
+	}
+
+      d.write ("}\n\n");
+    }
+}
+
+/* Pre-compilation validation of a function, for those things we can't
+   check until the context is (supposedly) fully-populated.  */
+
+void
+recording::function::validate ()
+{
+  /* Complain about empty functions with non-void return type.  */
+  if (m_kind != GCC_JIT_FUNCTION_IMPORTED
+      && m_return_type != m_ctxt->get_type (GCC_JIT_TYPE_VOID))
+    if (0 == m_blocks.length ())
+      m_ctxt->add_error (m_loc,
+			 "function %s returns non-void (type: %s)"
+			 " but has no blocks",
+			 get_debug_string (),
+			 m_return_type->get_debug_string ());
+
+  /* Check that all blocks are terminated.  */
+  int num_invalid_blocks = 0;
+  {
+    int i;
+    block *b;
+
+    FOR_EACH_VEC_ELT (m_blocks, i, b)
+      if (!b->validate ())
+	num_invalid_blocks++;
+  }
+
+  /* Check that all blocks are reachable.  */
+  if (m_blocks.length () > 0 && 0 == num_invalid_blocks)
+    {
+      /* Iteratively walk the graph of blocks, marking their "m_is_reachable"
+	 flag, starting at the initial block.  */
+      vec<block *> worklist;
+      worklist.create (m_blocks.length ());
+      worklist.safe_push (m_blocks[0]);
+      while (worklist.length () > 0)
+	{
+	  block *b = worklist.pop ();
+	  b->m_is_reachable = true;
+
+	  /* Add successor blocks that aren't yet marked to the worklist.  */
+	  /* We checked that each block has a terminating statement above .  */
+	  block *next1, *next2;
+	  int n = b->get_successor_blocks (&next1, &next2);
+	  switch (n)
+	    {
+	    default:
+	      gcc_unreachable ();
+	    case 2:
+	      if (!next2->m_is_reachable)
+		worklist.safe_push (next2);
+	      /* fallthrough */
+	    case 1:
+	      if (!next1->m_is_reachable)
+		worklist.safe_push (next1);
+	      break;
+	    case 0:
+	      break;
+	    }
+	}
+
+      /* Now complain about any blocks that haven't been marked.  */
+      {
+	int i;
+	block *b;
+	FOR_EACH_VEC_ELT (m_blocks, i, b)
+	  if (!b->m_is_reachable)
+	    m_ctxt->add_error (b->get_loc (),
+			       "unreachable block: %s",
+			       b->get_debug_string ());
+      }
+    }
+}
+
+/* Implements the post-error-checking part of
+   gcc_jit_function_dump_to_dot.  */
+
+void
+recording::function::dump_to_dot (const char *path)
+{
+  FILE *fp  = fopen (path, "w");
+  if (!fp)
+    return;
+
+  pretty_printer the_pp;
+  the_pp.buffer->stream = fp;
+
+  pretty_printer *pp = &the_pp;
+
+  pp_printf (pp,
+	     "digraph %s {\n", get_debug_string ());
+
+  /* Blocks: */
+  {
+    int i;
+    block *b;
+    FOR_EACH_VEC_ELT (m_blocks, i, b)
+      b->dump_to_dot (pp);
+  }
+
+  /* Edges: */
+  {
+    int i;
+    block *b;
+    FOR_EACH_VEC_ELT (m_blocks, i, b)
+      b->dump_edges_to_dot (pp);
+  }
+
+  pp_printf (pp, "}\n");
+  pp_flush (pp);
+  fclose (fp);
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   functions.  */
+
+recording::string *
+recording::function::make_debug_string ()
+{
+  return m_name;
+}
+
+/* The implementation of class gcc::jit::recording::block.  */
+
+/* Create a recording::eval instance and add it to
+   the block's context's list of mementos, and to the block's
+   list of statements.
+
+   Implements the post-error-checking part of
+   gcc_jit_block_add_eval.  */
+
+void
+recording::block::add_eval (recording::location *loc,
+			    recording::rvalue *rvalue)
+{
+  statement *result = new eval (this, loc, rvalue);
+  m_ctxt->record (result);
+  m_statements.safe_push (result);
+}
+
+/* Create a recording::assignment instance and add it to
+   the block's context's list of mementos, and to the block's
+   list of statements.
+
+   Implements the post-error-checking part of
+   gcc_jit_block_add_assignment.  */
+
+void
+recording::block::add_assignment (recording::location *loc,
+				  recording::lvalue *lvalue,
+				  recording::rvalue *rvalue)
+{
+  statement *result = new assignment (this, loc, lvalue, rvalue);
+  m_ctxt->record (result);
+  m_statements.safe_push (result);
+}
+
+/* Create a recording::assignment_op instance and add it to
+   the block's context's list of mementos, and to the block's
+   list of statements.
+
+   Implements the post-error-checking part of
+   gcc_jit_block_add_assignment_op.  */
+
+void
+recording::block::add_assignment_op (recording::location *loc,
+				     recording::lvalue *lvalue,
+				     enum gcc_jit_binary_op op,
+				     recording::rvalue *rvalue)
+{
+  statement *result = new assignment_op (this, loc, lvalue, op, rvalue);
+  m_ctxt->record (result);
+  m_statements.safe_push (result);
+}
+
+/* Create a recording::comment instance and add it to
+   the block's context's list of mementos, and to the block's
+   list of statements.
+
+   Implements the post-error-checking part of
+   gcc_jit_block_add_comment.  */
+
+void
+recording::block::add_comment (recording::location *loc,
+			       const char *text)
+{
+  statement *result = new comment (this, loc, new_string (text));
+  m_ctxt->record (result);
+  m_statements.safe_push (result);
+}
+
+/* Create a recording::end_with_conditional instance and add it to
+   the block's context's list of mementos, and to the block's
+   list of statements.
+
+   Implements the post-error-checking part of
+   gcc_jit_block_end_with_conditional.  */
+
+void
+recording::block::end_with_conditional (recording::location *loc,
+					recording::rvalue *boolval,
+					recording::block *on_true,
+					recording::block *on_false)
+{
+  statement *result = new conditional (this, loc, boolval, on_true, on_false);
+  m_ctxt->record (result);
+  m_statements.safe_push (result);
+  m_has_been_terminated = true;
+}
+
+/* Create a recording::end_with_jump instance and add it to
+   the block's context's list of mementos, and to the block's
+   list of statements.
+
+   Implements the post-error-checking part of
+   gcc_jit_block_end_with_jump.  */
+
+void
+recording::block::end_with_jump (recording::location *loc,
+				 recording::block *target)
+{
+  statement *result = new jump (this, loc, target);
+  m_ctxt->record (result);
+  m_statements.safe_push (result);
+  m_has_been_terminated = true;
+}
+
+/* Create a recording::end_with_return instance and add it to
+   the block's context's list of mementos, and to the block's
+   list of statements.
+
+   Implements the post-error-checking parts of
+   gcc_jit_block_end_with_return and
+   gcc_jit_block_end_with_void_return.  */
+
+void
+recording::block::end_with_return (recording::location *loc,
+				   recording::rvalue *rvalue)
+{
+  /* This is used by both gcc_jit_function_add_return and
+     gcc_jit_function_add_void_return; rvalue will be non-NULL for
+     the former and NULL for the latter.  */
+  statement *result = new return_ (this, loc, rvalue);
+  m_ctxt->record (result);
+  m_statements.safe_push (result);
+  m_has_been_terminated = true;
+}
+
+/* Override the default implementation of
+   recording::memento::write_to_dump for blocks by writing
+   an unindented block name as a label, followed by the indented
+   statements:
+
+    BLOCK_NAME:
+      STATEMENT_1;
+      STATEMENT_2;
+      ...
+      STATEMENT_N;  */
+
+void
+recording::block::write_to_dump (dump &d)
+{
+  d.write ("%s:\n", get_debug_string ());
+
+  int i;
+  statement *s;
+  FOR_EACH_VEC_ELT (m_statements, i, s)
+    s->write_to_dump (d);
+}
+
+/* Validate a block by ensuring that it has been terminated.  */
+
+bool
+recording::block::validate ()
+{
+  if (!has_been_terminated ())
+    {
+      statement *stmt = get_last_statement ();
+      location *loc = stmt ? stmt->get_loc () : NULL;
+      m_func->get_context ()->add_error (loc,
+					 "unterminated block in %s: %s",
+					 m_func->get_debug_string (),
+					 get_debug_string ());
+      return false;
+    }
+
+  return true;
+}
+
+/* Get the source-location of a block by using that of the first
+   statement within it, if any.  */
+
+recording::location *
+recording::block::get_loc () const
+{
+  recording::statement *stmt = get_first_statement ();
+  if (stmt)
+    return stmt->get_loc ();
+  else
+    return NULL;
+}
+
+/* Get the first statement within a block, if any.  */
+
+recording::statement *
+recording::block::get_first_statement () const
+{
+  if (m_statements.length ())
+    return m_statements[0];
+  else
+    return NULL;
+}
+
+/* Get the last statement within a block, if any.  */
+
+recording::statement *
+recording::block::get_last_statement () const
+{
+  if (m_statements.length ())
+    return m_statements[m_statements.length () - 1];
+  else
+    return NULL;
+}
+
+/* Assuming that this block has been terminated, get the number of
+   successor blocks, which will be 0, 1 or 2, for return, unconditional
+   jump, and conditional jump respectively.
+   NEXT1 and NEXT2 must be non-NULL.  The first successor block (if any)
+   is written to NEXT1, and the second (if any) to NEXT2.
+
+   Used when validating functions, and when dumping dot representations
+   of them.  */
+
+int
+recording::block::get_successor_blocks (block **next1, block **next2) const
+{
+  gcc_assert (m_has_been_terminated);
+  gcc_assert (next1);
+  gcc_assert (next2);
+  statement *last_statement = get_last_statement ();
+  gcc_assert (last_statement);
+  return last_statement->get_successor_blocks (next1, next2);
+}
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::block.  */
+
+void
+recording::block::replay_into (replayer *)
+{
+  set_playback_obj (m_func->playback_function ()
+		      ->new_block (playback_string (m_name)));
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   blocks.  */
+
+recording::string *
+recording::block::make_debug_string ()
+{
+  if (m_name)
+    return m_name;
+  else
+    return string::from_printf (m_ctxt,
+				"<UNNAMED BLOCK %p>",
+				(void *)this);
+}
+
+/* Dump a block in graphviz form into PP, capturing the block name (if
+   any) and the statements.  */
+
+void
+recording::block::dump_to_dot (pretty_printer *pp)
+{
+  pp_printf (pp,
+	     ("\tblock_%d "
+	      "[shape=record,style=filled,fillcolor=white,label=\"{"),
+	     m_index);
+  pp_write_text_to_stream (pp);
+  if (m_name)
+    {
+      pp_string (pp, m_name->c_str ());
+      pp_string (pp, ":");
+      pp_newline (pp);
+      pp_write_text_as_dot_label_to_stream (pp, true /*for_record*/);
+    }
+
+  int i;
+  statement *s;
+  FOR_EACH_VEC_ELT (m_statements, i, s)
+    {
+      pp_string (pp, s->get_debug_string ());
+      pp_newline (pp);
+      pp_write_text_as_dot_label_to_stream (pp, true /*for_record*/);
+    }
+
+  pp_printf (pp,
+	     "}\"];\n\n");
+  pp_flush (pp);
+}
+
+/* Dump the out-edges of the block in graphviz form into PP.  */
+
+void
+recording::block::dump_edges_to_dot (pretty_printer *pp)
+{
+  block *next[2];
+  int num_succs = get_successor_blocks (&next[0], &next[1]);
+  for (int i = 0; i < num_succs; i++)
+    pp_printf (pp,
+	       "\tblock_%d:s -> block_%d:n;\n",
+	       m_index, next[i]->m_index);
+}
+
+/* The implementation of class gcc::jit::recording::global.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::global.  */
+
+void
+recording::global::replay_into (replayer *r)
+{
+  set_playback_obj (r->new_global (playback_location (r, m_loc),
+				   m_type->playback_type (),
+				   playback_string (m_name)));
+}
+
+/* The implementation of class gcc::jit::recording::memento_of_new_rvalue_from_int.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::memento_of_new_rvalue_from_int.  */
+
+void
+recording::memento_of_new_rvalue_from_int::replay_into (replayer *r)
+{
+  set_playback_obj (r->new_rvalue_from_int (m_type->playback_type (),
+					    m_value));
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   rvalue_from_int, rendering it as
+     (TYPE)LITERAL
+   e.g.
+     "(int)42".  */
+
+recording::string *
+recording::memento_of_new_rvalue_from_int::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "(%s)%i",
+			      m_type->get_debug_string (),
+			      m_value);
+}
+
+/* The implementation of class gcc::jit::recording::memento_of_new_rvalue_from_double.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::memento_of_new_rvalue_from_double.  */
+
+void
+recording::memento_of_new_rvalue_from_double::replay_into (replayer *r)
+{
+  set_playback_obj (r->new_rvalue_from_double (m_type->playback_type (),
+					       m_value));
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   rvalue_from_double, rendering it as
+     (TYPE)LITERAL
+   e.g.
+     "(float)42.0".  */
+
+recording::string *
+recording::memento_of_new_rvalue_from_double::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "(%s)%f",
+			      m_type->get_debug_string (),
+			      m_value);
+}
+
+/* The implementation of class gcc::jit::recording::memento_of_new_rvalue_from_ptr.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::memento_of_new_rvalue_from_ptr.  */
+
+void
+recording::memento_of_new_rvalue_from_ptr::replay_into (replayer *r)
+{
+  set_playback_obj (r->new_rvalue_from_ptr (m_type->playback_type (),
+					    m_value));
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   rvalue_from_ptr, rendering it as
+     (TYPE)HEX
+   e.g.
+     "(int *)0xdeadbeef"
+
+   Zero is rendered as NULL e.g.
+     "(int *)NULL".  */
+
+recording::string *
+recording::memento_of_new_rvalue_from_ptr::make_debug_string ()
+{
+  if (m_value != NULL)
+    return string::from_printf (m_ctxt,
+				"(%s)%p",
+				m_type->get_debug_string (), m_value);
+  else
+    return string::from_printf (m_ctxt,
+				"(%s)NULL",
+				m_type->get_debug_string ());
+}
+
+/* The implementation of class gcc::jit::recording::memento_of_new_string_literal.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::memento_of_new_string_literal.  */
+
+void
+recording::memento_of_new_string_literal::replay_into (replayer *r)
+{
+  set_playback_obj (r->new_string_literal (m_value->c_str ()));
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   string literals.  */
+
+recording::string *
+recording::memento_of_new_string_literal::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      m_value->get_debug_string ());
+}
+
+/* The implementation of class gcc::jit::recording::unary_op.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::unary_op.  */
+
+void
+recording::unary_op::replay_into (replayer *r)
+{
+  set_playback_obj (r->new_unary_op (playback_location (r, m_loc),
+				     m_op,
+				     get_type ()->playback_type (),
+				     m_a->playback_rvalue ()));
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   unary ops.  */
+
+static const char * const unary_op_strings[] = {
+  "-", /* GCC_JIT_UNARY_OP_MINUS */
+  "~", /* GCC_JIT_UNARY_OP_BITWISE_NEGATE */
+  "!", /* GCC_JIT_UNARY_OP_LOGICAL_NEGATE */
+};
+
+recording::string *
+recording::unary_op::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "%s(%s)",
+			      unary_op_strings[m_op],
+			      m_a->get_debug_string ());
+}
+
+/* The implementation of class gcc::jit::recording::binary_op.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::binary_op.  */
+
+void
+recording::binary_op::replay_into (replayer *r)
+{
+  set_playback_obj (r->new_binary_op (playback_location (r, m_loc),
+				      m_op,
+				      get_type ()->playback_type (),
+				      m_a->playback_rvalue (),
+				      m_b->playback_rvalue ()));
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   binary ops.  */
+
+static const char * const binary_op_strings[] = {
+  "+", /* GCC_JIT_BINARY_OP_PLUS */
+  "-", /* GCC_JIT_BINARY_OP_MINUS */
+  "*", /* GCC_JIT_BINARY_OP_MULT */
+  "/", /* GCC_JIT_BINARY_OP_DIVIDE */
+  "%", /* GCC_JIT_BINARY_OP_MODULO */
+  "&", /* GCC_JIT_BINARY_OP_BITWISE_AND */
+  "^", /* GCC_JIT_BINARY_OP_BITWISE_XOR */
+  "|", /* GCC_JIT_BINARY_OP_BITWISE_OR */
+  "&&", /* GCC_JIT_BINARY_OP_LOGICAL_AND */
+  "||", /* GCC_JIT_BINARY_OP_LOGICAL_OR */
+  "<<", /* GCC_JIT_BINARY_OP_LSHIFT */
+  ">>", /* GCC_JIT_BINARY_OP_RSHIFT */
+};
+
+recording::string *
+recording::binary_op::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "%s %s %s",
+			      m_a->get_debug_string (),
+			      binary_op_strings[m_op],
+			      m_b->get_debug_string ());
+}
+
+/* The implementation of class gcc::jit::recording::comparison.  */
+
+/* Implementation of recording::memento::make_debug_string for
+   comparisons.  */
+
+static const char * const comparison_strings[] =
+{
+  "==", /* GCC_JIT_COMPARISON_EQ */
+  "!=", /* GCC_JIT_COMPARISON_NE */
+  "<",  /* GCC_JIT_COMPARISON_LT */
+  "<=", /* GCC_JIT_COMPARISON_LE */
+  ">",  /* GCC_JIT_COMPARISON_GT */
+  ">=", /* GCC_JIT_COMPARISON_GE */
+};
+
+recording::string *
+recording::comparison::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "%s %s %s",
+			      m_a->get_debug_string (),
+			      comparison_strings[m_op],
+			      m_b->get_debug_string ());
+}
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::comparison.  */
+
+void
+recording::comparison::replay_into (replayer *r)
+{
+  set_playback_obj (r->new_comparison (playback_location (r, m_loc),
+				       m_op,
+				       m_a->playback_rvalue (),
+				       m_b->playback_rvalue ()));
+}
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::cast.  */
+
+void
+recording::cast::replay_into (replayer *r)
+{
+  set_playback_obj (r->new_cast (playback_location (r, m_loc),
+				 m_rvalue->playback_rvalue (),
+				 get_type ()->playback_type ()));
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   casts.  */
+
+recording::string *
+recording::cast::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "(%s)%s",
+			      get_type ()->get_debug_string (),
+			      m_rvalue->get_debug_string ());
+}
+
+/* The implementation of class gcc::jit::recording::call.  */
+
+/* The constructor for gcc::jit::recording::call.  */
+
+recording::call::call (recording::context *ctxt,
+		       recording::location *loc,
+		       recording::function *func,
+		       int numargs,
+		       rvalue **args)
+: rvalue (ctxt, loc, func->get_return_type ()),
+  m_func (func),
+  m_args ()
+{
+  for (int i = 0; i< numargs; i++)
+    m_args.safe_push (args[i]);
+}
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::call.  */
+
+void
+recording::call::replay_into (replayer *r)
+{
+  vec<playback::rvalue *> playback_args;
+  playback_args.create (m_args.length ());
+  for (unsigned i = 0; i< m_args.length (); i++)
+    playback_args.safe_push (m_args[i]->playback_rvalue ());
+
+  set_playback_obj (r->new_call (playback_location (r, m_loc),
+				 m_func->playback_function (),
+				 playback_args));
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   function calls.  */
+
+recording::string *
+recording::call::make_debug_string ()
+{
+  /* First, build a buffer for the arguments.  */
+  /* Calculate length of said buffer.  */
+  size_t sz = 1; /* nil terminator */
+  for (unsigned i = 0; i< m_args.length (); i++)
+    {
+      sz += strlen (m_args[i]->get_debug_string ());
+      sz += 2; /* ", " separator */
+    }
+
+  /* Now allocate and populate the buffer.  */
+  char *argbuf = new char[sz];
+  size_t len = 0;
+
+  for (unsigned i = 0; i< m_args.length (); i++)
+    {
+      strcpy (argbuf + len, m_args[i]->get_debug_string ());
+      len += strlen (m_args[i]->get_debug_string ());
+      if (i + 1 < m_args.length ())
+	{
+	  strcpy (argbuf + len, ", ");
+	  len += 2;
+	}
+    }
+  argbuf[len] = '\0';
+
+  /* ...and use it to get the string for the call as a whole.  */
+  string *result = string::from_printf (m_ctxt,
+					"%s (%s)",
+					m_func->get_debug_string (),
+					argbuf);
+
+  delete[] argbuf;
+
+  return result;
+}
+
+/* The implementation of class gcc::jit::recording::call_through_ptr.  */
+
+/* The constructor for recording::call_through_ptr. */
+
+recording::call_through_ptr::call_through_ptr (recording::context *ctxt,
+					       recording::location *loc,
+					       recording::rvalue *fn_ptr,
+					       int numargs,
+					       rvalue **args)
+: rvalue (ctxt, loc,
+	  fn_ptr->get_type ()->dereference ()
+	    ->as_a_function_type ()->get_return_type ()),
+  m_fn_ptr (fn_ptr),
+  m_args ()
+{
+  for (int i = 0; i< numargs; i++)
+    m_args.safe_push (args[i]);
+}
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::call_through_ptr.  */
+
+void
+recording::call_through_ptr::replay_into (replayer *r)
+{
+  vec<playback::rvalue *> playback_args;
+  playback_args.create (m_args.length ());
+  for (unsigned i = 0; i< m_args.length (); i++)
+    playback_args.safe_push (m_args[i]->playback_rvalue ());
+
+  set_playback_obj (r->new_call_through_ptr (playback_location (r, m_loc),
+					     m_fn_ptr->playback_rvalue (),
+					     playback_args));
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   calls through function ptrs.  */
+
+recording::string *
+recording::call_through_ptr::make_debug_string ()
+{
+  /* First, build a buffer for the arguments.  */
+  /* Calculate length of said buffer.  */
+  size_t sz = 1; /* nil terminator */
+  for (unsigned i = 0; i< m_args.length (); i++)
+    {
+      sz += strlen (m_args[i]->get_debug_string ());
+      sz += 2; /* ", " separator */
+    }
+
+  /* Now allocate and populate the buffer.  */
+  char *argbuf = new char[sz];
+  size_t len = 0;
+
+  for (unsigned i = 0; i< m_args.length (); i++)
+    {
+      strcpy (argbuf + len, m_args[i]->get_debug_string ());
+      len += strlen (m_args[i]->get_debug_string ());
+      if (i + 1 < m_args.length ())
+	{
+	  strcpy (argbuf + len, ", ");
+	  len += 2;
+	}
+    }
+  argbuf[len] = '\0';
+
+  /* ...and use it to get the string for the call as a whole.  */
+  string *result = string::from_printf (m_ctxt,
+					"%s (%s)",
+					m_fn_ptr->get_debug_string (),
+					argbuf);
+
+  delete[] argbuf;
+
+  return result;
+}
+
+/* The implementation of class gcc::jit::recording::array_access.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::array_access.  */
+
+void
+recording::array_access::replay_into (replayer *r)
+{
+  set_playback_obj (
+    r->new_array_access (playback_location (r, m_loc),
+			 m_ptr->playback_rvalue (),
+			 m_index->playback_rvalue ()));
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   array accesses.  */
+
+recording::string *
+recording::array_access::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "%s[%s]",
+			      m_ptr->get_debug_string (),
+			      m_index->get_debug_string ());
+}
+
+/* The implementation of class gcc::jit::recording::access_field_of_lvalue.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::access_field_of_lvalue.  */
+
+void
+recording::access_field_of_lvalue::replay_into (replayer *r)
+{
+  set_playback_obj (
+    m_lvalue->playback_lvalue ()
+      ->access_field (playback_location (r, m_loc),
+		      m_field->playback_field ()));
+
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   accessing a field of an lvalue.  */
+
+recording::string *
+recording::access_field_of_lvalue::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "%s.%s",
+			      m_lvalue->get_debug_string (),
+			      m_field->get_debug_string ());
+}
+
+/* The implementation of class gcc::jit::recording::access_field_rvalue.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::access_field_rvalue.  */
+
+void
+recording::access_field_rvalue::replay_into (replayer *r)
+{
+  set_playback_obj (
+    m_rvalue->playback_rvalue ()
+      ->access_field (playback_location (r, m_loc),
+		      m_field->playback_field ()));
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   accessing a field of an rvalue.  */
+
+recording::string *
+recording::access_field_rvalue::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "%s.%s",
+			      m_rvalue->get_debug_string (),
+			      m_field->get_debug_string ());
+}
+
+/* The implementation of class
+   gcc::jit::recording::dereference_field_rvalue.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::dereference_field_rvalue.  */
+
+void
+recording::dereference_field_rvalue::replay_into (replayer *r)
+{
+  set_playback_obj (
+    m_rvalue->playback_rvalue ()->
+      dereference_field (playback_location (r, m_loc),
+			 m_field->playback_field ()));
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   dereferencing a field of an rvalue.  */
+
+recording::string *
+recording::dereference_field_rvalue::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "%s->%s",
+			      m_rvalue->get_debug_string (),
+			      m_field->get_debug_string ());
+}
+
+/* The implementation of class gcc::jit::recording::dereference_rvalue.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::dereference_rvalue.  */
+
+void
+recording::dereference_rvalue::replay_into (replayer *r)
+{
+  set_playback_obj (
+    m_rvalue->playback_rvalue ()->
+      dereference (playback_location (r, m_loc)));
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   dereferencing an rvalue.  */
+
+recording::string *
+recording::dereference_rvalue::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "*%s",
+			      m_rvalue->get_debug_string ());
+}
+
+/* The implementation of class gcc::jit::recording::get_address_of_lvalue.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::get_address_of_lvalue.  */
+
+void
+recording::get_address_of_lvalue::replay_into (replayer *r)
+{
+  set_playback_obj (
+    m_lvalue->playback_lvalue ()->
+      get_address (playback_location (r, m_loc)));
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   getting the address of an lvalue.  */
+
+recording::string *
+recording::get_address_of_lvalue::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "&%s",
+			      m_lvalue->get_debug_string ());
+}
+
+/* The implementation of class gcc::jit::recording::local.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::local.  */
+
+void
+recording::local::replay_into (replayer *r)
+{
+  set_playback_obj (
+    m_func->playback_function ()
+      ->new_local (playback_location (r, m_loc),
+		   m_type->playback_type (),
+		   playback_string (m_name)));
+}
+
+/* Override the default implementation of
+   recording::memento::write_to_dump for locals by writing
+      TYPE NAME;
+   for use at the top of the function body as if it were a
+   declaration.  */
+
+void
+recording::local::write_to_dump (dump &d)
+{
+  if (d.update_locations ())
+    m_loc = d.make_location ();
+  d.write("  %s %s;\n",
+	  m_type->get_debug_string (),
+	  get_debug_string ());
+}
+
+/* The implementation of class gcc::jit::recording::statement.  */
+
+/* We poison the default implementation of
+   gcc::jit::recording::statement::get_successor_blocks
+   since this vfunc must only ever be called on terminator
+   statements.  */
+
+int
+recording::statement::get_successor_blocks (block **/*out_next1*/,
+					    block **/*out_next2*/) const
+{
+  /* The base class implementation is for non-terminating statements,
+     and thus should never be called.  */
+  gcc_unreachable ();
+  return 0;
+}
+
+/* Extend the default implementation of
+   recording::memento::write_to_dump for statements by (if requested)
+   updating the location of the statement to the current location in
+   the dumpfile.  */
+
+void
+recording::statement::write_to_dump (dump &d)
+{
+  memento::write_to_dump (d);
+  if (d.update_locations ())
+    m_loc = d.make_location ();
+}
+
+/* The implementation of class gcc::jit::recording::eval.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::eval.  */
+
+void
+recording::eval::replay_into (replayer *r)
+{
+  playback_block (get_block ())
+    ->add_eval (playback_location (r),
+		m_rvalue->playback_rvalue ());
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   an eval statement.  */
+
+recording::string *
+recording::eval::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "(void)%s;",
+			      m_rvalue->get_debug_string ());
+}
+
+/* The implementation of class gcc::jit::recording::assignment.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::assignment.  */
+
+void
+recording::assignment::replay_into (replayer *r)
+{
+  playback_block (get_block ())
+    ->add_assignment (playback_location (r),
+		      m_lvalue->playback_lvalue (),
+		      m_rvalue->playback_rvalue ());
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   an assignment statement.  */
+
+recording::string *
+recording::assignment::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "%s = %s;",
+			      m_lvalue->get_debug_string (),
+			      m_rvalue->get_debug_string ());
+}
+
+/* The implementation of class gcc::jit::recording::assignment_op.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::assignment_op.  */
+
+void
+recording::assignment_op::replay_into (replayer *r)
+{
+  playback::type *result_type =
+    m_lvalue->playback_lvalue ()->get_type ();
+
+  playback::rvalue *binary_op =
+    r->new_binary_op (playback_location (r),
+		      m_op,
+		      result_type,
+		      m_lvalue->playback_rvalue (),
+		      m_rvalue->playback_rvalue ());
+
+  playback_block (get_block ())
+    ->add_assignment (playback_location (r),
+		      m_lvalue->playback_lvalue (),
+		      binary_op);
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   an assignment_op statement.  */
+
+recording::string *
+recording::assignment_op::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "%s %s= %s;",
+			      m_lvalue->get_debug_string (),
+			      binary_op_strings[m_op],
+			      m_rvalue->get_debug_string ());
+}
+
+/* The implementation of class gcc::jit::recording::comment.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::comment.  */
+
+void
+recording::comment::replay_into (replayer *r)
+{
+  playback_block (get_block ())
+    ->add_comment (playback_location (r),
+		   m_text->c_str ());
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   a comment "statement".  */
+
+recording::string *
+recording::comment::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "/* %s */",
+			      m_text->c_str ());
+}
+
+/* The implementation of class gcc::jit::recording::conditional.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::conditional.  */
+
+void
+recording::conditional::replay_into (replayer *r)
+{
+  playback_block (get_block ())
+    ->add_conditional (playback_location (r),
+		       m_boolval->playback_rvalue (),
+		       playback_block (m_on_true),
+		       playback_block (m_on_false));
+}
+
+/* Override the poisoned default implementation of
+   gcc::jit::recording::statement::get_successor_blocks
+
+   A conditional jump has 2 successor blocks.  */
+
+int
+recording::conditional::get_successor_blocks (block **out_next1,
+					      block **out_next2) const
+{
+  *out_next1 = m_on_true;
+  *out_next2 = m_on_false;
+  return 2;
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   a conditional jump statement.  */
+
+recording::string *
+recording::conditional::make_debug_string ()
+{
+  if (m_on_false)
+    return string::from_printf (m_ctxt,
+				"if (%s) goto %s; else goto %s;",
+				m_boolval->get_debug_string (),
+				m_on_true->get_debug_string (),
+				m_on_false->get_debug_string ());
+  else
+    return string::from_printf (m_ctxt,
+				"if (%s) goto %s;",
+				m_boolval->get_debug_string (),
+				m_on_true->get_debug_string ());
+}
+
+/* The implementation of class gcc::jit::recording::jump.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::jump.  */
+
+void
+recording::jump::replay_into (replayer *r)
+{
+  playback_block (get_block ())
+    ->add_jump (playback_location (r),
+		m_target->playback_block ());
+}
+
+/* Override the poisoned default implementation of
+   gcc::jit::recording::statement::get_successor_blocks
+
+   An unconditional jump has 1 successor block.  */
+
+int
+recording::jump::get_successor_blocks (block **out_next1,
+				       block **/*out_next2*/) const
+{
+  *out_next1 = m_target;
+  return 1;
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   a unconditional jump statement.  */
+
+recording::string *
+recording::jump::make_debug_string ()
+{
+  return string::from_printf (m_ctxt,
+			      "goto %s;",
+			      m_target->get_debug_string ());
+}
+
+/* The implementation of class gcc::jit::recording::return_.  */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+   for recording::return_.  */
+
+void
+recording::return_::replay_into (replayer *r)
+{
+  playback_block (get_block ())
+    ->add_return (playback_location (r),
+		  m_rvalue ? m_rvalue->playback_rvalue () : NULL);
+}
+
+/* Override the poisoned default implementation of
+   gcc::jit::recording::statement::get_successor_blocks
+
+   A return statement has no successor block.  */
+
+int
+recording::return_::get_successor_blocks (block **/*out_next1*/,
+					  block **/*out_next2*/) const
+{
+  return 0;
+}
+
+/* Implementation of recording::memento::make_debug_string for
+   a return statement (covers both those with and without rvalues).  */
+
+recording::string *
+recording::return_::make_debug_string ()
+{
+  if (m_rvalue)
+    return string::from_printf (m_ctxt,
+				"return %s;",
+				m_rvalue->get_debug_string ());
+  else
+    return string::from_printf (m_ctxt,
+				"return;");
+}
+
+} // namespace gcc::jit
+
+} // namespace gcc
-- 
1.8.5.3

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

* [PATCH 15/27] New file: gcc/jit/jit-playback.h
  2014-10-31 17:07 [PATCH 00/27] Merger of jit branch v3 David Malcolm
                   ` (21 preceding siblings ...)
  2014-10-31 17:38 ` [PATCH 13/27] New file: gcc/jit/jit-recording.c David Malcolm
@ 2014-10-31 17:41 ` David Malcolm
  2014-11-03 21:10   ` Jeff Law
  2014-10-31 17:59 ` [PATCH 04/27] New file: gcc/jit/notes.txt David Malcolm
                   ` (2 subsequent siblings)
  25 siblings, 1 reply; 71+ messages in thread
From: David Malcolm @ 2014-10-31 17:41 UTC (permalink / raw)
  To: gcc-patches, jit; +Cc: David Malcolm

This files declares the gcc::jit::playback internal API, called by
the dummy "frontend" to replay the public API calls made to the
library.  A thin wrapper around trees.

gcc/jit/
	* jit-playback.h: New.
---
 gcc/jit/jit-playback.h | 564 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 564 insertions(+)
 create mode 100644 gcc/jit/jit-playback.h

diff --git a/gcc/jit/jit-playback.h b/gcc/jit/jit-playback.h
new file mode 100644
index 0000000..dcb19bf
--- /dev/null
+++ b/gcc/jit/jit-playback.h
@@ -0,0 +1,564 @@
+/* Internals of libgccjit: classes for playing back recorded API calls.
+   Copyright (C) 2013-2014 Free Software Foundation, Inc.
+   Contributed by David Malcolm <dmalcolm@redhat.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef JIT_PLAYBACK_H
+#define JIT_PLAYBACK_H
+
+#include <utility> // for std::pair
+
+#include "jit-recording.h"
+
+namespace gcc {
+
+namespace jit {
+
+/**********************************************************************
+ Playback.
+ **********************************************************************/
+
+namespace playback {
+
+class context
+{
+public:
+  context (::gcc::jit::recording::context *ctxt);
+  ~context ();
+
+  void gt_ggc_mx ();
+
+  void replay ();
+
+  location *
+  new_location (recording::location *rloc,
+		const char *filename,
+		int line,
+		int column);
+
+  type *
+  get_type (enum gcc_jit_types type);
+
+  type *
+  new_array_type (location *loc,
+		  type *element_type,
+		  int num_elements);
+
+  field *
+  new_field (location *loc,
+	     type *type,
+	     const char *name);
+
+  compound_type *
+  new_compound_type (location *loc,
+		     const char *name,
+		     bool is_struct); /* else is union */
+
+  type *
+  new_function_type (type *return_type,
+		     vec<type *> *param_types,
+		     int is_variadic);
+
+  param *
+  new_param (location *loc,
+	     type *type,
+	     const char *name);
+
+  function *
+  new_function (location *loc,
+		enum gcc_jit_function_kind kind,
+		type *return_type,
+		const char *name,
+		vec<param *> *params,
+		int is_variadic,
+		enum built_in_function builtin_id);
+
+  lvalue *
+  new_global (location *loc,
+	      type *type,
+	      const char *name);
+
+  rvalue *
+  new_rvalue_from_int (type *type,
+		       int value);
+
+  rvalue *
+  new_rvalue_from_double (type *type,
+			  double value);
+
+  rvalue *
+  new_rvalue_from_ptr (type *type,
+		       void *value);
+
+  rvalue *
+  new_string_literal (const char *value);
+
+  rvalue *
+  new_unary_op (location *loc,
+		enum gcc_jit_unary_op op,
+		type *result_type,
+		rvalue *a);
+
+  rvalue *
+  new_binary_op (location *loc,
+		 enum gcc_jit_binary_op op,
+		 type *result_type,
+		 rvalue *a, rvalue *b);
+
+  rvalue *
+  new_comparison (location *loc,
+		  enum gcc_jit_comparison op,
+		  rvalue *a, rvalue *b);
+
+  rvalue *
+  new_call (location *loc,
+	    function *func,
+	    vec<rvalue *> args);
+
+  rvalue *
+  new_call_through_ptr (location *loc,
+			rvalue *fn_ptr,
+			vec<rvalue *> args);
+
+  rvalue *
+  new_cast (location *loc,
+	    rvalue *expr,
+	    type *type_);
+
+  lvalue *
+  new_array_access (location *loc,
+		    rvalue *ptr,
+		    rvalue *index);
+
+  void
+  set_str_option (enum gcc_jit_str_option opt,
+		  const char *value);
+
+  void
+  set_int_option (enum gcc_jit_int_option opt,
+		  int value);
+
+  void
+  set_bool_option (enum gcc_jit_bool_option opt,
+		   int value);
+
+  const char *
+  get_str_option (enum gcc_jit_str_option opt) const
+  {
+    return m_recording_ctxt->get_str_option (opt);
+  }
+
+  int
+  get_int_option (enum gcc_jit_int_option opt) const
+  {
+    return m_recording_ctxt->get_int_option (opt);
+  }
+
+  int
+  get_bool_option (enum gcc_jit_bool_option opt) const
+  {
+    return m_recording_ctxt->get_bool_option (opt);
+  }
+
+  result *
+  compile ();
+
+  void
+  add_error (location *loc, const char *fmt, ...)
+      GNU_PRINTF(3, 4);
+
+  void
+  add_error_va (location *loc, const char *fmt, va_list ap)
+      GNU_PRINTF(3, 0);
+
+  const char *
+  get_first_error () const;
+
+  void
+  set_tree_location (tree t, location *loc);
+
+  tree
+  new_field_access (location *loc,
+		    tree datum,
+		    field *field);
+
+  tree
+  new_dereference (tree ptr, location *loc);
+
+  tree
+  as_truth_value (tree expr, location *loc);
+
+  bool errors_occurred () const
+  {
+    return m_recording_ctxt->errors_occurred ();
+  }
+
+private:
+  void dump_generated_code ();
+
+  rvalue *
+  build_call (location *loc,
+	      tree fn_ptr,
+	      vec<rvalue *> args);
+
+  tree
+  build_cast (location *loc,
+	      rvalue *expr,
+	      type *type_);
+
+  source_file *
+  get_source_file (const char *filename);
+
+  void handle_locations ();
+
+private:
+  ::gcc::jit::recording::context *m_recording_ctxt;
+
+  /* Allocated using xmalloc (by xstrdup).  */
+  char *m_path_template;
+
+  /* This either aliases m_path_template, or is NULL.  */
+  char *m_path_tempdir;
+
+  /* The following are allocated using xmalloc.  */
+  char *m_path_c_file;
+  char *m_path_s_file;
+  char *m_path_so_file;
+
+  vec<function *> m_functions;
+  tree m_char_array_type_node;
+  tree m_const_char_ptr;
+
+  /* Source location handling.  */
+  vec<source_file *> m_source_files;
+
+  vec<std::pair<tree, location *> > m_cached_locations;
+};
+
+/* A temporary wrapper object.
+   These objects are (mostly) only valid during replay.
+   We allocate them on the GC heap, so that they will be cleaned
+   the next time the GC collects.
+   The exception is the "function" class, which is tracked and marked by
+   the jit::context, since it needs to stay alive during post-processing
+   (when the GC could run). */
+class wrapper
+{
+public:
+  /* Allocate in the GC heap.  */
+  void *operator new (size_t sz);
+
+};
+
+class type : public wrapper
+{
+public:
+  type (tree inner)
+    : m_inner(inner)
+  {}
+
+  tree as_tree () const { return m_inner; }
+
+  type *get_pointer () const { return new type (build_pointer_type (m_inner)); }
+
+  type *get_const () const
+  {
+    return new type (build_qualified_type (m_inner, TYPE_QUAL_CONST));
+  }
+
+  type *get_volatile () const
+  {
+    return new type (build_qualified_type (m_inner, TYPE_QUAL_VOLATILE));
+  }
+
+private:
+  tree m_inner;
+};
+
+class compound_type : public type
+{
+public:
+  compound_type (tree inner)
+    : type (inner)
+  {}
+
+  void set_fields (const vec<field *> &fields);
+};
+
+class field : public wrapper
+{
+public:
+  field (tree inner)
+    : m_inner(inner)
+  {}
+
+  tree as_tree () const { return m_inner; }
+
+private:
+  tree m_inner;
+};
+
+class function : public wrapper
+{
+public:
+  function(context *ctxt, tree fndecl, enum gcc_jit_function_kind kind);
+
+  void gt_ggc_mx ();
+
+  tree get_return_type_as_tree () const;
+
+  tree as_fndecl () const { return m_inner_fndecl; }
+
+  enum gcc_jit_function_kind get_kind () const { return m_kind; }
+
+  lvalue *
+  new_local (location *loc,
+	     type *type,
+	     const char *name);
+
+  block*
+  new_block (const char *name);
+
+  void
+  build_stmt_list ();
+
+  void
+  postprocess ();
+
+public:
+  context *m_ctxt;
+
+public:
+  void
+  set_tree_location (tree t, location *loc)
+  {
+    m_ctxt->set_tree_location (t, loc);
+  }
+
+private:
+  tree m_inner_fndecl;
+  tree m_inner_block;
+  tree m_inner_bind_expr;
+  enum gcc_jit_function_kind m_kind;
+  tree m_stmt_list;
+  tree_stmt_iterator m_stmt_iter;
+  vec<block *> m_blocks;
+};
+
+class block : public wrapper
+{
+public:
+  block (function *func,
+	 const char *name);
+
+  tree as_label_decl () const { return m_label_decl; }
+
+  void
+  add_eval (location *loc,
+	    rvalue *rvalue);
+
+  void
+  add_assignment (location *loc,
+		  lvalue *lvalue,
+		  rvalue *rvalue);
+
+  void
+  add_comment (location *loc,
+	       const char *text);
+
+  void
+  add_conditional (location *loc,
+		   rvalue *boolval,
+		   block *on_true,
+		   block *on_false);
+
+  block *
+  add_block (location *loc,
+	     const char *name);
+
+  void
+  add_jump (location *loc,
+	    block *target);
+
+  void
+  add_return (location *loc,
+	      rvalue *rvalue);
+
+private:
+  void
+  set_tree_location (tree t, location *loc)
+  {
+    m_func->set_tree_location (t, loc);
+  }
+
+  void add_stmt (tree stmt)
+  {
+    /* TODO: use one stmt_list per block.  */
+    m_stmts.safe_push (stmt);
+  }
+
+private:
+  function *m_func;
+  tree m_label_decl;
+  vec<tree> m_stmts;
+
+public: // for now
+  tree m_label_expr;
+
+  friend class function;
+};
+
+class rvalue : public wrapper
+{
+public:
+  rvalue (context *ctxt, tree inner)
+    : m_ctxt (ctxt),
+      m_inner (inner)
+  {}
+
+  rvalue *
+  as_rvalue () { return this; }
+
+  tree as_tree () const { return m_inner; }
+
+  context *get_context () const { return m_ctxt; }
+
+  type *
+  get_type () { return new type (TREE_TYPE (m_inner)); }
+
+  rvalue *
+  access_field (location *loc,
+		field *field);
+
+  lvalue *
+  dereference_field (location *loc,
+		     field *field);
+
+  lvalue *
+  dereference (location *loc);
+
+private:
+  context *m_ctxt;
+  tree m_inner;
+};
+
+class lvalue : public rvalue
+{
+public:
+  lvalue (context *ctxt, tree inner)
+    : rvalue(ctxt, inner)
+  {}
+
+  lvalue *
+  as_lvalue () { return this; }
+
+  lvalue *
+  access_field (location *loc,
+		field *field);
+
+  rvalue *
+  get_address (location *loc);
+
+};
+
+class param : public lvalue
+{
+public:
+  param (context *ctxt, tree inner)
+    : lvalue(ctxt, inner)
+  {}
+};
+
+/* Dealing with the linemap API.
+
+   It appears that libcpp requires locations to be created as if by
+   a tokenizer, creating them by filename, in ascending order of
+   line/column, whereas our API doesn't impose any such constraints:
+   we allow client code to create locations in arbitrary orders.
+
+   To square this circle, we need to cache all location creation,
+   grouping things up by filename/line, and then creating the linemap
+   entries in a post-processing phase.  */
+
+/* A set of locations, all sharing a filename */
+class source_file : public wrapper
+{
+public:
+  source_file (tree filename);
+
+  source_line *
+  get_source_line (int line_num);
+
+  tree filename_as_tree () const { return m_filename; }
+
+  const char*
+  get_filename () const { return IDENTIFIER_POINTER (m_filename); }
+
+  vec<source_line *> m_source_lines;
+
+private:
+  tree m_filename;
+};
+
+/* A source line, with one or more locations of interest.  */
+class source_line : public wrapper
+{
+public:
+  source_line (source_file *file, int line_num);
+
+  location *
+  get_location (recording::location *rloc, int column_num);
+
+  int get_line_num () const { return m_line_num; }
+
+  vec<location *> m_locations;
+
+private:
+  source_file *m_source_file;
+  int m_line_num;
+};
+
+/* A specific location on a source line.  This is what we expose
+   to the client API.  */
+class location : public wrapper
+{
+public:
+  location (recording::location *loc, source_line *line, int column_num);
+
+  int get_column_num () const { return m_column_num; }
+
+  recording::location *get_recording_loc () const { return m_recording_loc; }
+
+  source_location m_srcloc;
+
+private:
+  recording::location *m_recording_loc;
+  source_line *m_line;
+  int m_column_num;
+};
+
+} // namespace gcc::jit::playback
+
+extern playback::context *active_playback_ctxt;
+
+} // namespace gcc::jit
+
+} // namespace gcc
+
+#endif /* JIT_PLAYBACK_H */
+
-- 
1.8.5.3

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

* [PATCH 04/27] New file: gcc/jit/notes.txt
  2014-10-31 17:07 [PATCH 00/27] Merger of jit branch v3 David Malcolm
                   ` (22 preceding siblings ...)
  2014-10-31 17:41 ` [PATCH 15/27] New file: gcc/jit/jit-playback.h David Malcolm
@ 2014-10-31 17:59 ` David Malcolm
  2014-10-31 21:19   ` Jeff Law
  2014-10-31 21:17 ` [PATCH 00/27] Merger of jit branch v3 Jeff Law
  2014-11-05 20:47 ` [PATCH 0/3] Minor tweaks to jit David Malcolm
  25 siblings, 1 reply; 71+ messages in thread
From: David Malcolm @ 2014-10-31 17:59 UTC (permalink / raw)
  To: gcc-patches, jit; +Cc: David Malcolm

An earlier version of this was posted as part of:
      "[PATCH 06/10] Heart of the JIT implementation (was: Re: [PATCH 0/5] Merger of jit branch (v2))"
        https://gcc.gnu.org/ml/gcc-patches/2014-10/msg01247.html

I've broken that up into separate patches for ease of review.

This first patch within gcc/jit adds a high-level overview
diagram of how the JIT library works.

gcc/jit/
	* notes.txt: New.
---
 gcc/jit/notes.txt | 84 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 84 insertions(+)
 create mode 100644 gcc/jit/notes.txt

diff --git a/gcc/jit/notes.txt b/gcc/jit/notes.txt
new file mode 100644
index 0000000..d337cb4
--- /dev/null
+++ b/gcc/jit/notes.txt
@@ -0,0 +1,84 @@
+Client Code   . Generated .            libgccjit.so
+              . code      .
+              .           . JIT API  . JIT "Frontend". (libbackend.a)
+....................................................................................
+   │          .           .          .               .
+    ──────────────────────────>      .               .
+              .           .    │     .               .
+              .           .    V     .               .
+              .           .    ──> libgccjit.c       .
+              .           .        │ (error-checking).
+              .           .        │                 .
+              .           .        ──> jit-recording.c
+              .           .              (record API calls)
+              .           .    <───────              .
+              .           .    │     .               .
+   <───────────────────────────      .               .
+   │          .           .          .               .
+   │          .           .          .               .
+   V          .           .  gcc_jit_context_compile .
+    ──────────────────────────>      .               .
+              .           .    │     .               .
+              .           .    │ ACQUIRE MUTEX       .
+              .           .    │     .               .
+              .           .    V───────────────────────> toplev::main (for now)
+              .           .          .               .       │
+              .           .          .               .   (various code)
+              .           .          .               .       │
+              .           .          .               .       V
+              .           .          .    <───────────────── langhook:parse_file
+              .           .          .    │          .
+              .           .          .    │ (jit_langhook_parse_file)
+              .           .          .    │          .
+..........................................│..................VVVVVVVVVVVVV...
+              .           .          .    │          .       No GC in here
+              .           .          .    │ jit-playback.c
+              .           .          .    │   (playback of API calls)
+              .           .          .    ───────────────> creation of functions,
+              .           .          .               .     types, expression trees
+              .           .          .    <──────────────── etc
+              .           .          .    │(handle_locations: add locations to
+              .           .          .    │ linemap and associate them with trees)
+              .           .          .    │          .
+              .           .          .    │          .       No GC in here
+..........................................│..................AAAAAAAAAAAAA...
+              .           .          .    │ for each function
+              .           .          .    ──> postprocess
+              .           .          .        │      .
+              .           .          .        ────────────> cgraph_finalize_function
+              .           .          .        <────────────
+              .           .          .     <──       .
+              .           .          .    │          .
+              .           .          .    ──────────────────> (end of
+              .           .          .               .       │ langhook_parse_file)
+              .           .          .               .       │
+              .           .          .               .   (various code)
+              .           .          .               .       │
+              .           .          .               .       ↓
+              .           .          .    <───────────────── langhook:write_globals
+              .           .          .    │          .
+              .           .          .    │ (jit_langhook_write_globals)
+              .           .          .    │          .
+              .           .          .    │          .
+              .           .          .    ──────────────────> finalize_compilation_unit
+              .           .          .               .       │
+              .           .          .               .   (the middle─end and backend)
+              .           .          .               .       ↓
+              .           .    <───────────────────────────── end of toplev::main
+              .           .    │ RELEASE MUTEX       .
+              .           .    │     .               .
+              .           .    │ Convert assembler to DSO
+              .           .    │     .               .
+              .           .    │ Load DSO            .
+   <───────────────────────────      .               .
+   │          .           .          .               .
+   Get (void*).           .          .               .
+   │          .           .          .               .
+   │ Call it  .           .          .               .
+   ───────────────>       .          .               .
+              .    │      .          .               .
+              .    │      .          .               .
+   <───────────────       .          .               .
+   │          .           .          .               .
+   │          .           .          .               .
+etc
-- 
1.8.5.3

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

* Re: [PATCH 00/27] Merger of jit branch v3
  2014-10-31 17:07 [PATCH 00/27] Merger of jit branch v3 David Malcolm
                   ` (23 preceding siblings ...)
  2014-10-31 17:59 ` [PATCH 04/27] New file: gcc/jit/notes.txt David Malcolm
@ 2014-10-31 21:17 ` Jeff Law
  2014-11-05 20:47 ` [PATCH 0/3] Minor tweaks to jit David Malcolm
  25 siblings, 0 replies; 71+ messages in thread
From: Jeff Law @ 2014-10-31 21:17 UTC (permalink / raw)
  To: David Malcolm, gcc-patches, jit

On 10/31/14 11:02, David Malcolm wrote:
> I'd like to merge the JIT branch into trunk:
>    https://gcc.gnu.org/wiki/JIT
>
> This is "v3" since it incorporates fixes for various issues
> identified in earlier submissions:
>    v1: https://gcc.gnu.org/ml/gcc-patches/2014-09/msg02056.html
>    v2: https://gcc.gnu.org/ml/gcc-patches/2014-10/msg01168.html
>
> I've merged some of the work approved earlier into trunk.
>
> Of the remaining work, some has already been approved, and some
> hasn't.  I've split the latter up into more fine-grained patches
> in the hope it will make review easier, so there are 27 patches
> in this kit, compared to 10 in the earlier one.
>
> Here's an overview of the patches:
>
>    01/27: gcc: configure and Makefile changes needed by jit
>      Needs review.
>      Corresponds to:
>        "[PATCH 2/5] gcc: configure and Makefile changes needed by jit"
>          https://gcc.gnu.org/ml/gcc-patches/2014-10/msg01169.html
>      and has had cleanups in response to concerns from Jeff and Joseph,
>      to remove the need to install when running the jit testsuite.
>
>    02/27: JIT-related changes outside of jit subdir
>      Already approved by Jeff.
>
>    03/27: Add Sphinx to install.texi
>      Needs review.
>
> Patches 04-18 correspond to:
>    "[PATCH 06/10] Heart of the JIT implementation
>        (was: Re: [PATCH 0/5] Merger of jit branch (v2))"
>      https://gcc.gnu.org/ml/gcc-patches/2014-10/msg01247.html
> from v2; I've broken them up by file to make them easier to review:
Going to start working my way through this.  I'm going to assume the 
plan is to commit everything at once.  If I see something that should be 
broken out, I'll mention it explicitly.

Reviews may come out of order as I tend to scan the entire kit, then go 
back and start looking at the easy hunks.

jeff


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

* Re: [PATCH 02/27] JIT-related changes outside of jit subdir
  2014-10-31 17:07 ` [PATCH 02/27] JIT-related changes outside of jit subdir David Malcolm
@ 2014-10-31 21:18   ` Jeff Law
  0 siblings, 0 replies; 71+ messages in thread
From: Jeff Law @ 2014-10-31 21:18 UTC (permalink / raw)
  To: David Malcolm, gcc-patches, jit

On 10/31/14 11:02, David Malcolm wrote:
> This was previously posted as:
>    "[PATCH 05/10] JIT-related changes outside of jit subdir"
>      https://gcc.gnu.org/ml/gcc-patches/2014-10/msg01246.html
>
> and approved by Jeff in
>    https://gcc.gnu.org/ml/gcc-patches/2014-10/msg01410.html
>> OK if/when rest of JIT bits are approved.
>
> Joseph pointed out that I should add a note about sphinx
> as a dependency to install.texi:
>    https://gcc.gnu.org/ml/gcc-patches/2014-10/msg01793.html
> I do that in the next patch.
>
> ChangeLog:
> 	* MAINTAINERS (Various Maintainers): Add myself as jit maintainer.
>
> contrib/ChangeLog:
> 	* jit-coverage-report.py: New file: a script to print crude
> 	code-coverage information for the libgccjit API.
>
> gcc/ChangeLog:
> 	* doc/install.texi (--enable-host-shared): Specify that this is
> 	required when building libgccjit.
> 	* timevar.def (TV_JIT_REPLAY): New.
> 	(TV_ASSEMBLE): New.
> 	(TV_LINK): New.
> 	(TV_LOAD): New.
Still OK for the trunk.

Jeff

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

* Re: [PATCH 03/27] Add Sphinx to install.texi
  2014-10-31 17:07 ` [PATCH 03/27] Add Sphinx to install.texi David Malcolm
@ 2014-10-31 21:18   ` Jeff Law
  0 siblings, 0 replies; 71+ messages in thread
From: Jeff Law @ 2014-10-31 21:18 UTC (permalink / raw)
  To: David Malcolm, gcc-patches, jit

On 10/31/14 11:02, David Malcolm wrote:
> In https://gcc.gnu.org/ml/gcc-patches/2014-10/msg01793.html,
> Joseph said:
>
>> Although Sphinx isn't a build dependency, as a dependency for
>> regenerating checked-in files I think it should be documented in
>> install.texi (like autoconf, gettext, etc.).
>
> This patch adds such documentation.
>
> gcc/ChangeLog:
> 	* doc/install.texi (Tools/packages necessary for modifying GCC):
> 	Add Sphinx.
OK.
Jeff


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

* Re: [PATCH 04/27] New file: gcc/jit/notes.txt
  2014-10-31 17:59 ` [PATCH 04/27] New file: gcc/jit/notes.txt David Malcolm
@ 2014-10-31 21:19   ` Jeff Law
  0 siblings, 0 replies; 71+ messages in thread
From: Jeff Law @ 2014-10-31 21:19 UTC (permalink / raw)
  To: David Malcolm, gcc-patches, jit

On 10/31/14 11:02, David Malcolm wrote:
> An earlier version of this was posted as part of:
>        "[PATCH 06/10] Heart of the JIT implementation (was: Re: [PATCH 0/5] Merger of jit branch (v2))"
>          https://gcc.gnu.org/ml/gcc-patches/2014-10/msg01247.html
>
> I've broken that up into separate patches for ease of review.
>
> This first patch within gcc/jit adds a high-level overview
> diagram of how the JIT library works.
>
> gcc/jit/
> 	* notes.txt: New.
OK.
jeff

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

* Re: [PATCH 05/27] New file: gcc/jit/config-lang.in
  2014-10-31 17:07 ` [PATCH 05/27] New file: gcc/jit/config-lang.in David Malcolm
@ 2014-10-31 21:20   ` Jeff Law
  0 siblings, 0 replies; 71+ messages in thread
From: Jeff Law @ 2014-10-31 21:20 UTC (permalink / raw)
  To: David Malcolm, gcc-patches, jit

On 10/31/14 11:02, David Malcolm wrote:
> gcc/jit/
> 	* config-lang.in: New.
OK.
jeff

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

* Re: [PATCH 09/27] New file: gcc/jit/libgccjit.map
  2014-10-31 17:07 ` [PATCH 09/27] New file: gcc/jit/libgccjit.map David Malcolm
@ 2014-10-31 21:21   ` Jeff Law
  0 siblings, 0 replies; 71+ messages in thread
From: Jeff Law @ 2014-10-31 21:21 UTC (permalink / raw)
  To: David Malcolm, gcc-patches, jit

On 10/31/14 11:02, David Malcolm wrote:
> This linker script ensures that the library only exports the symbols
> we want it to.
>
> gcc/jit/
> 	* libgccjit.map: New.
OK.
jeff

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

* Re: [PATCH 18/27] New file: gcc/jit/TODO.rst
  2014-10-31 17:28 ` [PATCH 18/27] New file: gcc/jit/TODO.rst David Malcolm
@ 2014-10-31 21:26   ` Jeff Law
  0 siblings, 0 replies; 71+ messages in thread
From: Jeff Law @ 2014-10-31 21:26 UTC (permalink / raw)
  To: David Malcolm, gcc-patches, jit

On 10/31/14 11:02, David Malcolm wrote:
> This is a list of TODOs for working on the JIT.
>
> gcc/jit/
> 	* TODO.rst: New.
OK.
jeff

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

* Re: [PATCH 22/27] Documentation: top-level index.rst
  2014-10-31 17:21 ` [PATCH 22/27] Documentation: top-level index.rst David Malcolm
@ 2014-10-31 21:29   ` Jeff Law
  0 siblings, 0 replies; 71+ messages in thread
From: Jeff Law @ 2014-10-31 21:29 UTC (permalink / raw)
  To: David Malcolm, gcc-patches, jit

On 10/31/14 11:02, David Malcolm wrote:
> The top-level index.rst provides the high-level structure for the
> rest of the docs (which will follow in the patches that follow).
>
> gcc/jit/ChangeLog:
> 	* docs/index.rst: New.
OK.
Jeff
> ---

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

* Re: [PATCH 21/27] Documentation: the "examples" subdirectory
  2014-10-31 17:07 ` [PATCH 21/27] Documentation: the "examples" subdirectory David Malcolm
@ 2014-10-31 21:31   ` Jeff Law
  0 siblings, 0 replies; 71+ messages in thread
From: Jeff Law @ 2014-10-31 21:31 UTC (permalink / raw)
  To: David Malcolm, gcc-patches, jit

On 10/31/14 11:02, David Malcolm wrote:
> This patch adds examples.  These examples are used included
> by the documentation when it is built, and are run as code by the
> testsuite, ensuring that the examples shown in the docs build and
> run.
>
> gcc/jit/
> 	* docs/examples/tut01-hello-world.c: New.
> 	* docs/examples/tut02-square.c: New.
> 	* docs/examples/tut03-sum-of-squares.c: New.
> 	* docs/examples/tut04-toyvm/Makefile: New.
> 	* docs/examples/tut04-toyvm/factorial.toy: New.
> 	* docs/examples/tut04-toyvm/fibonacci.toy: New.
> 	* docs/examples/tut04-toyvm/toyvm.c: New.
OK.
jeff

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

* Re: [PATCH 23/27] Documentation: the "intro" subdirectory
  2014-10-31 17:16 ` [PATCH 23/27] Documentation: the "intro" subdirectory David Malcolm
@ 2014-10-31 21:48   ` Jeff Law
  2014-10-31 22:12     ` David Malcolm
  0 siblings, 1 reply; 71+ messages in thread
From: Jeff Law @ 2014-10-31 21:48 UTC (permalink / raw)
  To: David Malcolm, gcc-patches, jit

On 10/31/14 11:02, David Malcolm wrote:
> The "intro" subdirectory of gcc/jit/docs consists of a 4-part tutorial
> aimed at experienced developers who are new users of the library, taking
> them from beginning use all the way up to adding JIT-compilation to an
> interpreter.
>
> gcc/jit/
> 	* docs/intro/factorial.png: New.
> 	* docs/intro/index.rst: New.
> 	* docs/intro/sum-of-squares.png: New.
> 	* docs/intro/tutorial01.rst: New.
> 	* docs/intro/tutorial02.rst: New.
> 	* docs/intro/tutorial03.rst: New.
> 	* docs/intro/tutorial04.rst: New.
I'm not actually reviewing the .rst bits, but instead looking at the 
generate docs -- and I'm mostly just looking at them from a higher level 
(ie, what belongs, what doesn't and such).  Given you've addressed the 
issues raised earlier I don't expect further changes in this area.

Patches 23, 24, 25 are all OK.

I don't see #26 or #27 in the series?  Were they particularly large?


jeff


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

* Re: [PATCH 23/27] Documentation: the "intro" subdirectory
  2014-10-31 21:48   ` Jeff Law
@ 2014-10-31 22:12     ` David Malcolm
  2014-11-03 16:23       ` Jeff Law
  0 siblings, 1 reply; 71+ messages in thread
From: David Malcolm @ 2014-10-31 22:12 UTC (permalink / raw)
  To: Jeff Law; +Cc: gcc-patches, jit

On Fri, 2014-10-31 at 15:29 -0600, Jeff Law wrote:
> On 10/31/14 11:02, David Malcolm wrote:
> > The "intro" subdirectory of gcc/jit/docs consists of a 4-part tutorial
> > aimed at experienced developers who are new users of the library, taking
> > them from beginning use all the way up to adding JIT-compilation to an
> > interpreter.
> >
> > gcc/jit/
> > 	* docs/intro/factorial.png: New.
> > 	* docs/intro/index.rst: New.
> > 	* docs/intro/sum-of-squares.png: New.
> > 	* docs/intro/tutorial01.rst: New.
> > 	* docs/intro/tutorial02.rst: New.
> > 	* docs/intro/tutorial03.rst: New.
> > 	* docs/intro/tutorial04.rst: New.
> I'm not actually reviewing the .rst bits, but instead looking at the 
> generate docs -- and I'm mostly just looking at them from a higher level 
> (ie, what belongs, what doesn't and such).  Given you've addressed the 
> issues raised earlier I don't expect further changes in this area.
> 
> Patches 23, 24, 25 are all OK.
> 
> I don't see #26 or #27 in the series?  Were they particularly large?

Yes: I deliberately didn't send 19, 26, 27 as they were large (170k and
up), and are essentially already approved:

-rw-rw-r--. 1 david david 267546 Oct 31 12:35 0019-Testsuite-for-the-JIT.patch
-rw-rw-r--. 1 david david 177604 Oct 31 12:35 0026-Prebuilt-texinfo-documentation-for-the-JIT-library.patch
-rw-rw-r--. 1 david david 188093 Oct 31 12:35 0027-ChangeLog-files.patch

(and it's all in git, fwiw).

Some notes on each of these:

re [PATCH 19/27] Testsuite for the JIT

An earlier version of this was posted as:
  "[PATCH 07/10] Testsuite for the JIT (Re: Patches 5-10 of jit merger (was: Re: [PATCH 0/5] Merger of jit branch (v2)))"
    https://gcc.gnu.org/ml/gcc-patches/2014-10/msg01248.html

which you approved in
  https://gcc.gnu.org/ml/gcc-patches/2014-10/msg01413.html
with:
> OK when rest of JIT bits are approved.
> I just did some very rough sanity checking -- the details of the
> testsuite I'm totally leaving in your hands :-)

The only changes have been to jit.exp, to handle running the
testsuite without needing to install.



re [PATCH 26/27] Prebuilt texinfo documentation for the JIT library

This is for the benefit of those without Sphinx installed,
and is autogenerated by running "make texinfo" in the gcc/jit/docs
subdirectory.

I posted an earlier version of this as:
  "[PATCH 09/10] Prebuilt texinfo documentation for the JIT library (Re: Patches 5-10 of jit merger)"
    https://gcc.gnu.org/ml/gcc-patches/2014-10/msg01395.html

which you approved in https://gcc.gnu.org/ml/gcc-patches/2014-10/msg01415.html
> Assuming these are built from the sphinx stuff, these are fine
> once the rest of the JIT stuff is approved -- as it updating these
> things if there's any updates necessary to the source sphinx
> documentation.

which preapproves this updated version.



re [PATCH 27/27] ChangeLog files

The dmalcolm/jit branch has ChangeLog.jit files describing the
history of the branch.  Add them to trunk for the record.

Also, there will be a gcc/jit/ChangeLog.

I posted an earlier version of this as:
  "[PATCH 10/10] ChangeLog files (Re: Patches 5-10 of jit merger (was: Re: [PATCH 0/5] Merger of jit branch (v2)))"
    https://gcc.gnu.org/ml/gcc-patches/2014-10/msg01250.html

which you approved in
https://gcc.gnu.org/ml/gcc-patches/2014-10/msg01416.html :
> OK once the rest of the JIT stuff is approved.
> Not going to look at these in any detail.

Relative to that, this version merely adds new entries for the work
I've done on the branch since the original merger request, and is
thus presumably an obvious change.


Do you need me to post anything more for these three?

Thanks
Dave

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

* Re: [PATCH 23/27] Documentation: the "intro" subdirectory
  2014-10-31 22:12     ` David Malcolm
@ 2014-11-03 16:23       ` Jeff Law
  0 siblings, 0 replies; 71+ messages in thread
From: Jeff Law @ 2014-11-03 16:23 UTC (permalink / raw)
  To: David Malcolm; +Cc: gcc-patches, jit

On 10/31/14 15:44, David Malcolm wrote:
>>
>> I don't see #26 or #27 in the series?  Were they particularly large?
>
> Yes: I deliberately didn't send 19, 26, 27 as they were large (170k and
> up), and are essentially already approved:
OK.  No worries then.

Jeff

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

* Re: [PATCH 07/27] New file: gcc/jit/dummy-frontend.c
  2014-10-31 17:07 ` [PATCH 07/27] New file: gcc/jit/dummy-frontend.c David Malcolm
@ 2014-11-03 19:26   ` Jeff Law
  0 siblings, 0 replies; 71+ messages in thread
From: Jeff Law @ 2014-11-03 19:26 UTC (permalink / raw)
  To: David Malcolm, gcc-patches, jit

On 10/31/14 11:02, David Malcolm wrote:
> gcc/jit/
> 	* dummy-frontend.c: New.
OK.

jeff

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

* Re: [PATCH 11/27] New file: gcc/jit/jit-common.h
  2014-10-31 17:28 ` [PATCH 11/27] New file: gcc/jit/jit-common.h David Malcolm
@ 2014-11-03 19:34   ` Jeff Law
  0 siblings, 0 replies; 71+ messages in thread
From: Jeff Law @ 2014-11-03 19:34 UTC (permalink / raw)
  To: David Malcolm, gcc-patches, jit

On 10/31/14 11:02, David Malcolm wrote:
> This header has forward declarations of both the jit::recording
> and jit::playback internal APIs.
>
> gcc/jit/
> 	* jit-common.h: New.
OK
jeff

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

* Re: [PATCH 08/27] New file: gcc/jit/libgccjit.h
  2014-10-31 17:29 ` [PATCH 08/27] New file: gcc/jit/libgccjit.h David Malcolm
@ 2014-11-03 20:22   ` Jeff Law
  2014-11-04  1:26     ` David Malcolm
  0 siblings, 1 reply; 71+ messages in thread
From: Jeff Law @ 2014-11-03 20:22 UTC (permalink / raw)
  To: David Malcolm, gcc-patches, jit

On 10/31/14 11:02, David Malcolm wrote:
> This header is the public API for the library.
>
> gcc/jit/
> 	* libgccjit.h: New.
Given this is inside the JIT subdirectory, I'm not doing a depth review.

  +
> +/* A gcc_jit_block encapsulates a "basic block" of statements within a
> +   function (i.e. with one entry point and one exit point).
> +
> +   Every block within a function must be terminated with a conditional,
> +   a branch, or a return.
? That doesn't seem right.   We don't really place restrictions on what 
ends a block, but we do place restrictions on what kinds of IL 
statements can appear in the middle of a block.

> +
> +   All of the blocks in a function must be reachable via some path from
> +   the first block.
?  Is this something your code requires?  While we have some code which 
assumes unreachable blocks do not exist, we generally deal with that by 
running the cfgcleanup passes which will identify and remove the 
unreachables.

And this raises one of those questions that's been in the back of my 
mind.  What's the right level of documentation and exposure of 
internals.  When I read the docs, one of questions I kept to myself was 
whether or not we've giving the users too much or too little 
information.  As well as a vague concern that actually using the JIT is 
going to be so painful due to exposure of implementation details that we 
might want to just go in with the expectation that this is really a V0 
implementation and that it's all going to have to change and be 
rewritten as GCC's internals get sorted out.



> +
> +/*
> +   Acquire a JIT-compilation context.
> +
> +   FIXME: error-handling?
There's a whole class of problems with error handling. GCC has always 
had this notation that it can terminate compilation when something "bad" 
happens.  In a JIT world that may not be appropriate.  But that's 
probably outside the scope of what we want to try and tackle at this stage.


> +enum gcc_jit_int_option
> +{
> +  /* How much to optimize the code.
> +     Valid values are 0-3, corresponding to GCC's command-line options
> +     -O0 through -O3.
> +
> +     The default value is 0 (unoptimized).  */
> +  GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL,
> +
> +  GCC_JIT_NUM_INT_OPTIONS
> +};
I don't think we explicitly disallow optimization values > 3, they just 
don't do anything.


> +
> +/* Options taking boolean values.
> +   These all default to "false".  */
> +enum gcc_jit_bool_option
> +{
> +  /* If true, gcc_jit_context_compile will attempt to do the right
> +     thing so that if you attach a debugger to the process, it will
> +     be able to inspect variables and step through your code.
> +
> +     Note that you can't step through code unless you set up source
> +     location information for the code (by creating and passing in
> +     gcc_jit_location instances).  */
> +  GCC_JIT_BOOL_OPTION_DEBUGINFO,
The comment makes me ask, why not always have this on and have 
gcc_jit_context_compile try to do the right thing? :-)

> +
> +  /* If true, gcc_jit_context_compile will dump its initial "tree"
> +     representation of your code to stderr (before any
> +     optimizations).  */
> +  GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE,
Is stderr really the best place for the debugging dumps?


> +
> +/* Populating the fields of a formerly-opaque struct type.
> +   This can only be called once on a given struct type.  */
> +extern void
> +gcc_jit_struct_set_fields (gcc_jit_struct *struct_type,
> +			   gcc_jit_location *loc,
> +			   int num_fields,
> +			   gcc_jit_field **fields);
What happens if you call it more than once?  Is the once only property 
something we ought to be enforcing, or is that really an internal issue?

> +
> +enum gcc_jit_function_kind
[ ... ]
So do we have any use for alias, thunks, etc here?

And WRT types (and perhaps other stuff), there's a pretty direct mapping 
between the rest of GCC and the JIT stuff.  I worry a bit that someone 
changing the core of GCC may not know they need to make analogous 
changes to the JIT bits.  It's a general concern, no need to do anything 
about it right now.  If it breaks you get to fix it ;-)
[ ... ]

In your code to build up the contents of blocks, would it make sense to 
"finalize" the block or somesuch concept after adding a  statement which 
terminates the block to ensure someone doesn't append statements after 
the block terminitating statement?


Patch is OK -- the issues noted above are more things I think are worth 
discussing and possibly making changes in the future.  Nothing above is 
significant enough today to warrant making changes in the codebase IMHO.
Jeff

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

* Re: [PATCH 10/27] New file: gcc/jit/libgccjit.c
  2014-10-31 17:28 ` [PATCH 10/27] New file: gcc/jit/libgccjit.c David Malcolm
@ 2014-11-03 20:32   ` Jeff Law
  2014-11-04 17:02     ` David Malcolm
  0 siblings, 1 reply; 71+ messages in thread
From: Jeff Law @ 2014-11-03 20:32 UTC (permalink / raw)
  To: David Malcolm, gcc-patches, jit

On 10/31/14 11:02, David Malcolm wrote:
> This file implements the entrypoints of the library's public API.
>
> It performs error-checking at this boundary, before calling into the
> jit-recording.h internal API.
>
> gcc/jit/
> 	* libgccjit.c: New.
> ---
>   gcc/jit/libgccjit.c | 1506 +++++++++++++++++++++++++++++++++++++++++++++++++++
>   1 file changed, 1506 insertions(+)
>   create mode 100644 gcc/jit/libgccjit.c
>
> +
> +#define IS_ASCII_ALPHA(CHAR) \
> +  (					\
> +    ((CHAR) >= 'a' && (CHAR) <='z')	\
> +    ||					\
> +    ((CHAR) >= 'A' && (CHAR) <= 'Z')	\
> +  )
> +
> +#define IS_ASCII_DIGIT(CHAR) \
> +  ((CHAR) >= '0' && (CHAR) <='9')
> +
> +#define IS_ASCII_ALNUM(CHAR) \
> +  (IS_ASCII_ALPHA (CHAR) || IS_ASCII_DIGIT (CHAR))
Can't we rely on the C library to give us equivalents?

> +
> +/* TODO: mark failure branches as unlikely? */
> +
Not likely worth the effort.  And it'd be better to somehow mark 
jit_error such that anytime a path unconditionally calls jit_error, the 
whole path is considered unlikely.

I think it was Ball & Larus that had a predictor of this nature, I don't 
recall its effectiveness offhand.  But I'd rather be marking the 
function than sprinlkling unlikely all over the actual codepaths.



> +static bool
> +compatible_types (gcc::jit::recording::type *ltype,
> +		  gcc::jit::recording::type *rtype)
All function definitions should have a block comment describing the 
function and its arguments.   This comment applies throughout the code 
and needs to be addressed prior to commit.  In fact I really can't even 
continue review of this code due to the lack of comments -- I rely 
heavily on them.

jeff


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

* Re: [PATCH 14/27] New files: gcc/jit/jit-builtins.{c|h}
  2014-10-31 17:29 ` [PATCH 14/27] New files: gcc/jit/jit-builtins.{c|h} David Malcolm
@ 2014-11-03 21:04   ` Jeff Law
  2014-11-04 16:39     ` David Malcolm
  0 siblings, 1 reply; 71+ messages in thread
From: Jeff Law @ 2014-11-03 21:04 UTC (permalink / raw)
  To: David Malcolm, gcc-patches, jit

On 10/31/14 11:02, David Malcolm wrote:
> These files implement support for builtins, for the
>    gcc_jit_context_get_builtin_function
> API entrypoint.
>
> Only a subset of builtins are currently supported, based on those
> that I needed when porting GNU Octave's JIT.
>
> Attempts to use other builtins may lead to an error:
>    "unimplemented primitive type for builtin"
> being emitted on the gcc_jit_context.
>
> gcc/jit/
> 	* jit-builtins.c: New.
> 	* jit-builtins.h: New.
So how do you envision maintenance on this in the future?  Reality is 
folks are regularly adding new builtins, are they going to have to 
update the JIT too?

OK for the trunk.

jeff

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

* Re: [PATCH 15/27] New file: gcc/jit/jit-playback.h
  2014-10-31 17:41 ` [PATCH 15/27] New file: gcc/jit/jit-playback.h David Malcolm
@ 2014-11-03 21:10   ` Jeff Law
  0 siblings, 0 replies; 71+ messages in thread
From: Jeff Law @ 2014-11-03 21:10 UTC (permalink / raw)
  To: David Malcolm, gcc-patches, jit

On 10/31/14 11:02, David Malcolm wrote:
> This files declares the gcc::jit::playback internal API, called by
> the dummy "frontend" to replay the public API calls made to the
> library.  A thin wrapper around trees.
>
> gcc/jit/
> 	* jit-playback.h: New.
OK.
jeff

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

* Re: [PATCH 17/27] New file: gcc/jit/libgccjit++.h
  2014-10-31 17:30 ` [PATCH 17/27] New file: gcc/jit/libgccjit++.h David Malcolm
@ 2014-11-03 21:12   ` Jeff Law
  0 siblings, 0 replies; 71+ messages in thread
From: Jeff Law @ 2014-11-03 21:12 UTC (permalink / raw)
  To: David Malcolm, gcc-patches, jit

On 10/31/14 11:02, David Malcolm wrote:
> This adds a C++ wrapper API, with syntactic sugar for reducing the
> verbosity compared to the C API.
>
> gcc/jit/
> 	* libgccjit++.h: New.
OK.
Jeff

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

* Re: [PATCH 20/27] Documentation: Makefile and conf.py
  2014-10-31 17:07 ` [PATCH 20/27] Documentation: Makefile and conf.py David Malcolm
@ 2014-11-03 21:13   ` Jeff Law
  0 siblings, 0 replies; 71+ messages in thread
From: Jeff Law @ 2014-11-03 21:13 UTC (permalink / raw)
  To: David Malcolm, gcc-patches, jit

On 10/31/14 11:02, David Malcolm wrote:
> When I previously submitted the jit for review, I posted all of the
> documentation as one big patch, as:
>    "[PATCH 08/10] Documentation for the JIT library (Re: Patches 5-10 of jit merger)"
>      https://gcc.gnu.org/ml/gcc-patches/2014-10/msg01392.html
>
> Since then, I've:
>
>    * eliminated all mentions of pkg-config (since we no longer support
>      this)
>
>    * eliminated the installation section and the discussion of packages
>
>    * converted the final page (docs/internals/index.rst) into a short
>      guide for contributors to the project (e.g. myself and other
>      maintainers)
>
> Prebuilt HTML from this can be seen at:
>    https://dmalcolm.fedorapeople.org/gcc/libgccjit-api-docs/index.html
>
> To make review easier, I've split the documentation up to smaller
> patches, starting with this one.
>
> This patch adds the Makefile and configuration file for Sphinx
> for building docs from the .rst files that follow.
>
> gcc/jit/
> 	* docs/Makefile: New.
> 	* docs/conf.py: New.
OK.
Jeff

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

* Re: [PATCH 12/27] New file: gcc/jit/jit-recording.h
  2014-10-31 17:28 ` [PATCH 12/27] New file: gcc/jit/jit-recording.h David Malcolm
@ 2014-11-03 21:27   ` Jeff Law
  2014-11-04 16:16     ` David Malcolm
  0 siblings, 1 reply; 71+ messages in thread
From: Jeff Law @ 2014-11-03 21:27 UTC (permalink / raw)
  To: David Malcolm, gcc-patches, jit

On 10/31/14 11:02, David Malcolm wrote:
> This file declares the gcc::jit::recording internal API, so that
> libgccjit.c can record the calls that are made to the public API, for
> later playback by the dummy frontend.
>
> gcc/jit/
> 	* jit-recording.h: New.
> ---
>   gcc/jit/jit-recording.h | 1593 +++++++++++++++++++++++++++++++++++++++++++++++
>   1 file changed, 1593 insertions(+)
>   create mode 100644 gcc/jit/jit-recording.h
>
> diff --git a/gcc/jit/jit-recording.h b/gcc/jit/jit-recording.h
> new file mode 100644
> index 0000000..bb1a2ee
> --- /dev/null
> +++ b/gcc/jit/jit-recording.h
[ ... ]

> +
> +private:
> +  void validate ();
So give the complexities in interfacing with the guts of GCC, would it 
make sense to expose the validate method?

> +/* or just use std::string? */
> +class string : public memento
Is there some reason not to use std::string?  I really like using 
standard components rather than rolling our own.



OK for the trunk.

jeff

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

* Re: [PATCH 06/27] New file: gcc/jit/Make-lang.in
  2014-10-31 17:07 ` [PATCH 06/27] New file: gcc/jit/Make-lang.in David Malcolm
@ 2014-11-03 21:35   ` Jeff Law
  0 siblings, 0 replies; 71+ messages in thread
From: Jeff Law @ 2014-11-03 21:35 UTC (permalink / raw)
  To: David Malcolm, gcc-patches, jit

On 10/31/14 11:02, David Malcolm wrote:
> gcc/jit/
> 	* Make-lang.in: New.
OK.
jeff

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

* Re: [PATCH 01/27] gcc: configure and Makefile changes needed by jit
  2014-10-31 17:07 ` [PATCH 01/27] gcc: configure and Makefile changes needed by jit David Malcolm
@ 2014-11-03 21:36   ` Jeff Law
  2014-11-13 20:16   ` Thomas Schwinge
  1 sibling, 0 replies; 71+ messages in thread
From: Jeff Law @ 2014-11-03 21:36 UTC (permalink / raw)
  To: David Malcolm, gcc-patches, jit

On 10/31/14 11:02, David Malcolm wrote:
> An earlier version of this was posted as:
>    "[PATCH 2/5] gcc: configure and Makefile changes needed by jit"
>      https://gcc.gnu.org/ml/gcc-patches/2014-10/msg01169.html
>
> Since then, I've eliminated the gcc_version, bindir, and pkgconfigdir
> additions, and added the FULL_DRIVER_NAME variable and symlink, to
> avoid the need to install when running the jit testsuite.
>
> gcc/ChangeLog:
> 	* Makefile.in (doc_build_sys): New variable, set to "sphinx" if
> 	sphinx is installed, falling back to "texinfo" otherwise.
> 	(FULL_DRIVER_NAME): New variable, adapted from the
> 	install-driver target.  New target, a symlink within the builddir,
> 	linked to "xgcc", for use when running the JIT library from the
> 	builddir.
> 	(MOSTLYCLEANFILES): Add FULL_DRIVER_NAME.
> 	(install-driver): Use $(FULL_DRIVER_NAME) rather than spelling it
> 	out.
>
> 	* configure.ac (doc_build_sys): New variable, set to "sphinx" if
> 	sphinx is installed, falling back to "texinfo" otherwise.
> 	(GCC_DRIVER_NAME): Generate a gcc-driver-name.h file containing
> 	GCC_DRIVER_NAME for the benefit of jit/internal-api.c.
>
> 	* configure: Regenerate.
OK.
jeff

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

* Re: [PATCH 13/27] New file: gcc/jit/jit-recording.c
  2014-10-31 17:38 ` [PATCH 13/27] New file: gcc/jit/jit-recording.c David Malcolm
@ 2014-11-03 22:04   ` Jeff Law
  2014-11-04 16:29     ` David Malcolm
  0 siblings, 1 reply; 71+ messages in thread
From: Jeff Law @ 2014-11-03 22:04 UTC (permalink / raw)
  To: David Malcolm, gcc-patches, jit

On 10/31/14 11:02, David Malcolm wrote:
> Implementation of the gcc::jit::recording internal API, so that
> libgccjit.c can record the calls that are made to the public API, for
> later playback by the dummy frontend.
>
> gcc/jit/
> 	* jit-recording.c: New.
Cursory review since it's the JIT implementation directory which you'll 
likely end up owning...


> +
> +/* Assuming that this block has been terminated, get the number of
> +   successor blocks, which will be 0, 1 or 2, for return, unconditional
> +   jump, and conditional jump respectively.
> +   NEXT1 and NEXT2 must be non-NULL.  The first successor block (if any)
> +   is written to NEXT1, and the second (if any) to NEXT2.
> +
> +   Used when validating functions, and when dumping dot representations
> +   of them.  */
So presumably no multi-way branches yet?  Might be better to build the 
API in such a way that it handles multi-way branches from the get-go 
rather than retrofitting later.  Your call.

Otherwise I don't see anything objectionable.  OK for the trunk.
jeff


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

* Re: [PATCH 08/27] New file: gcc/jit/libgccjit.h
  2014-11-03 20:22   ` Jeff Law
@ 2014-11-04  1:26     ` David Malcolm
  0 siblings, 0 replies; 71+ messages in thread
From: David Malcolm @ 2014-11-04  1:26 UTC (permalink / raw)
  To: Jeff Law; +Cc: gcc-patches, jit

On Mon, 2014-11-03 at 13:22 -0700, Jeff Law wrote:
> On 10/31/14 11:02, David Malcolm wrote:
> > This header is the public API for the library.
> >
> > gcc/jit/
> > 	* libgccjit.h: New.
> Given this is inside the JIT subdirectory, I'm not doing a depth review.
> 
>   +
> > +/* A gcc_jit_block encapsulates a "basic block" of statements within a
> > +   function (i.e. with one entry point and one exit point).
> > +
> > +   Every block within a function must be terminated with a conditional,
> > +   a branch, or a return.
> ? That doesn't seem right.   We don't really place restrictions on what 
> ends a block, but we do place restrictions on what kinds of IL 
> statements can appear in the middle of a block.

Adding a conditional, branch or return to a gcc_jit_block terminates
that block, so you can't add further statements to it.  Hence the API
*does* restrict those statements from being in the middle of a block.

> > +
> > +   All of the blocks in a function must be reachable via some path from
> > +   the first block.
> ?  Is this something your code requires?  While we have some code which 
> assumes unreachable blocks do not exist, we generally deal with that by 
> running the cfgcleanup passes which will identify and remove the 
> unreachables.

An earlier version of the API was much more freeform, without blocks,
instead having labels, requiring the client code to add statements in
order.  It initially seemed like a good idea, but my experience porting
the GNU Octave JIT from llvm was that as a user I needed warnings from
the API about messed-up control flow: it's just too easy to add a
statement to the wrong block, or to use the wrong block for a jump
target.  Once I added these restrictions (and validation checks), it
became dramatically easier to do the port.

The requirement above that blocks are explicitly terminated also came
from this experience: I felt that having the ability for control flow to
implicitly "fall off the end of a block" was more of a liability for
library users than a benefit; better to require them to explicitly state
where control flow should go.

Bear in mind that the intended user of this library is a language
implementer, and they typically not writing code to build a specific
function; they're writing code that walks some other IR (e.g. bytecode)
and uses it to build another function. 
This gives them three levels of implementation: 
  A) the high-level function (e.g. Octave),
  B) the IR for that function (e.g. Octave AST), and 
  C) libgccjit API's version of it
Figuring out where something is going wrong is "fun" to debug.  Hence
the more validation checks we can build in, the easier it will be for
them.   That's my thinking, anyway :)


> And this raises one of those questions that's been in the back of my 
> mind.  What's the right level of documentation and exposure of 
> internals.  When I read the docs, one of questions I kept to myself was 
> whether or not we've giving the users too much or too little 
> information.  As well as a vague concern that actually using the JIT is 
> going to be so painful due to exposure of implementation details that we 
> might want to just go in with the expectation that this is really a V0 
> implementation and that it's all going to have to change and be 
> rewritten as GCC's internals get sorted out.

Hmmm...  I guess we'll have to see.

> > +
> > +/*
> > +   Acquire a JIT-compilation context.
> > +
> > +   FIXME: error-handling?
> There's a whole class of problems with error handling. GCC has always 
> had this notation that it can terminate compilation when something "bad" 
> happens.  In a JIT world that may not be appropriate.  But that's 
> probably outside the scope of what we want to try and tackle at this stage.
Right.  FWIW I consider it a bug if a shared library ever aborts the
process it's in, which is at odds with how much of libiberty and gcc are
written, so changing that is a long-term thing.

The FIXME above relates specifically to the gcc_jit_context_acquire
entrypoint: the rest of the API handles errors by reporting them on a
context, but clearly we can't do that until we have a context.  Though
it can only fail due to memory failure, and given the amount of other
code that aborts on memory failure, it may be futile trapping that.

> > +enum gcc_jit_int_option
> > +{
> > +  /* How much to optimize the code.
> > +     Valid values are 0-3, corresponding to GCC's command-line options
> > +     -O0 through -O3.
> > +
> > +     The default value is 0 (unoptimized).  */
> > +  GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL,
> > +
> > +  GCC_JIT_NUM_INT_OPTIONS
> > +};
> I don't think we explicitly disallow optimization values > 3, they just 
> don't do anything.
> 
> 
> > +
> > +/* Options taking boolean values.
> > +   These all default to "false".  */
> > +enum gcc_jit_bool_option
> > +{
> > +  /* If true, gcc_jit_context_compile will attempt to do the right
> > +     thing so that if you attach a debugger to the process, it will
> > +     be able to inspect variables and step through your code.
> > +
> > +     Note that you can't step through code unless you set up source
> > +     location information for the code (by creating and passing in
> > +     gcc_jit_location instances).  */
> > +  GCC_JIT_BOOL_OPTION_DEBUGINFO,
> The comment makes me ask, why not always have this on and have 
> gcc_jit_context_compile try to do the right thing? :-)

Maybe this should be reworded from
  "to do the right thing" 
to
  "to do the extra work needed"
?

There's a compile-time expense to tracking and generating the debuginfo,
and typically you don't need it (you might not even have source
locations).  Though right now the profile is dominated by invoking the
driver to assembler and link the generated assembler.

> > +
> > +  /* If true, gcc_jit_context_compile will dump its initial "tree"
> > +     representation of your code to stderr (before any
> > +     optimizations).  */
> > +  GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE,
> Is stderr really the best place for the debugging dumps?

I guess we could have the user supply a FILE *, or a filename?


> > +
> > +/* Populating the fields of a formerly-opaque struct type.
> > +   This can only be called once on a given struct type.  */
> > +extern void
> > +gcc_jit_struct_set_fields (gcc_jit_struct *struct_type,
> > +			   gcc_jit_location *loc,
> > +			   int num_fields,
> > +			   gcc_jit_field **fields);
> What happens if you call it more than once?

Then an error will be emitted on the context, and attempts to compile
will fail.

> Is the once only property 
> something we ought to be enforcing, or is that really an internal issue?

I've attempted to do a lot of error-checking at the API boundary, since
otherwise you typically get an ICE deep inside the compiler code, for
the JIT there isn't a driver to provide an error message, it's a crash
in the user's process.

The jit looks like a frontend to the rest of the compiler code, and that
analogy is useful here: part of the job of a gcc frontend is to ensure a
basic level of sanity for the IR that it's supplying to the rest of the
compiler.

If you can change the fields of a struct, then you could have a function
in which some statements are accessing struct foo with one set of a
fields, and later statements access it with another set of fields.  This
is likely to ICE the compiler.

> > +
> > +enum gcc_jit_function_kind
> [ ... ]
> So do we have any use for alias, thunks, etc here?

Not yet supported.

> And WRT types (and perhaps other stuff), there's a pretty direct mapping 
> between the rest of GCC and the JIT stuff.  I worry a bit that someone 
> changing the core of GCC may not know they need to make analogous 
> changes to the JIT bits.  It's a general concern, no need to do anything 
> about it right now.  If it breaks you get to fix it ;-)

(nods)

> [ ... ]
> 
> In your code to build up the contents of blocks, would it make sense to 
> "finalize" the block or somesuch concept after adding a  statement which 
> terminates the block to ensure someone doesn't append statements after 
> the block terminitating statement?

Attempts to add statements to a block after a terminating statement on
it lead of an error being emitted on the context; see
  jit.dg/test-error-adding-to-terminated-block.c
for a testcase of this.


> Patch is OK -- the issues noted above are more things I think are worth 
> discussing and possibly making changes in the future.  Nothing above is 
> significant enough today to warrant making changes in the codebase IMHO.

Thanks
Dave

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

* Re: [PATCH 12/27] New file: gcc/jit/jit-recording.h
  2014-11-03 21:27   ` Jeff Law
@ 2014-11-04 16:16     ` David Malcolm
  2014-11-04 21:23       ` Jeff Law
  0 siblings, 1 reply; 71+ messages in thread
From: David Malcolm @ 2014-11-04 16:16 UTC (permalink / raw)
  To: Jeff Law; +Cc: gcc-patches, jit

On Mon, 2014-11-03 at 14:27 -0700, Jeff Law wrote:
> On 10/31/14 11:02, David Malcolm wrote:
> > This file declares the gcc::jit::recording internal API, so that
> > libgccjit.c can record the calls that are made to the public API, for
> > later playback by the dummy frontend.
> >
> > gcc/jit/
> > 	* jit-recording.h: New.
> > ---
> >   gcc/jit/jit-recording.h | 1593 +++++++++++++++++++++++++++++++++++++++++++++++
> >   1 file changed, 1593 insertions(+)
> >   create mode 100644 gcc/jit/jit-recording.h
> >
> > diff --git a/gcc/jit/jit-recording.h b/gcc/jit/jit-recording.h
> > new file mode 100644
> > index 0000000..bb1a2ee
> > --- /dev/null
> > +++ b/gcc/jit/jit-recording.h
> [ ... ]
> 
> > +
> > +private:
> > +  void validate ();
> So give the complexities in interfacing with the guts of GCC, would it 
> make sense to expose the validate method?

Most of the error-checking in the API happens in the API calls in
libgccjit.c, testing that the individual pieces are sane.

The validate method tests the things that can only be verified "as a
whole", when the context is about to be compiled: are there unreachable
blocks?  is every block terminated?  etc

I can't quite see why client code might want to perform the latter kind
of validation without actually doing a compile, so I don't plan to
expose this at this time.  It's trivial to do so if someone needs it.

> > +/* or just use std::string? */
> > +class string : public memento
> Is there some reason not to use std::string?  I really like using 
> standard components rather than rolling our own.

I think I was trying to avoid std::string for some reason, but I'm not
quite sure why, perhaps out of a misremembered idea that libstdc++ was
verboten (I currently use std:: in one place, in jit-playback.h, where a
playback::context has a:
  vec<std::pair<tree, location *> > m_cached_locations;
).

In any case recording::string is an implementation detail hidden within
the library.  It is a recording::memento and hence has the same lifetime
as the recording::context.  I can't think of a reason off the top of my
head why a std::string wouldn't work instead, but the existing code
works, and has been through a fair amount of debugging.

One thing I do make use of is that it's a pointer, for this field within
recording::memento:

  string *m_debug_string;

so that I can use NULL for the common case of "no debug string has been
built for this thing yet" - though I suspect I could use a std::string *
for that.

> OK for the trunk.

Thanks.

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

* Re: [PATCH 13/27] New file: gcc/jit/jit-recording.c
  2014-11-03 22:04   ` Jeff Law
@ 2014-11-04 16:29     ` David Malcolm
  2014-11-04 21:24       ` Jeff Law
  0 siblings, 1 reply; 71+ messages in thread
From: David Malcolm @ 2014-11-04 16:29 UTC (permalink / raw)
  To: Jeff Law; +Cc: gcc-patches, jit

On Mon, 2014-11-03 at 15:03 -0700, Jeff Law wrote:
> On 10/31/14 11:02, David Malcolm wrote:
> > Implementation of the gcc::jit::recording internal API, so that
> > libgccjit.c can record the calls that are made to the public API, for
> > later playback by the dummy frontend.
> >
> > gcc/jit/
> > 	* jit-recording.c: New.
> Cursory review since it's the JIT implementation directory which you'll 
> likely end up owning...
> 
> 
> > +
> > +/* Assuming that this block has been terminated, get the number of
> > +   successor blocks, which will be 0, 1 or 2, for return, unconditional
> > +   jump, and conditional jump respectively.
> > +   NEXT1 and NEXT2 must be non-NULL.  The first successor block (if any)
> > +   is written to NEXT1, and the second (if any) to NEXT2.
> > +
> > +   Used when validating functions, and when dumping dot representations
> > +   of them.  */
> So presumably no multi-way branches yet?  Might be better to build the 
> API in such a way that it handles multi-way branches from the get-go 
> rather than retrofitting later.  Your call.

This is an internal API.  If the external API needs to support building
switch statements from client code maybe with something like this:

  extern void
  gcc_jit_block_end_with_switch (gcc_jit_block *block,
                                 gcc_jit_location *loc,
                                 gcc_jit_rvalue *expr,
                                 int num_cases,
                                 gcc_jit_rvalue **case_values,
                                 gcc_jit_block **case_blocks,
                                 gcc_jit_block *default_block);

then this internal API would obviously need to change, maybe becoming:

  virtual int get_num_successor_blocks () const;
  virtual block *get_successor_block (int index) const;

but that won't affect the public API.

That said it's not clear to me that we do need to support switch
statements; no JIT implementation I've seen has needed them
(I put them in the "Probably not needed" section of TODO.rst).

> Otherwise I don't see anything objectionable.  OK for the trunk.

Thanks
Dave



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

* Re: [PATCH 14/27] New files: gcc/jit/jit-builtins.{c|h}
  2014-11-03 21:04   ` Jeff Law
@ 2014-11-04 16:39     ` David Malcolm
  0 siblings, 0 replies; 71+ messages in thread
From: David Malcolm @ 2014-11-04 16:39 UTC (permalink / raw)
  To: Jeff Law; +Cc: gcc-patches, jit

On Mon, 2014-11-03 at 14:04 -0700, Jeff Law wrote:
> On 10/31/14 11:02, David Malcolm wrote:
> > These files implement support for builtins, for the
> >    gcc_jit_context_get_builtin_function
> > API entrypoint.
> >
> > Only a subset of builtins are currently supported, based on those
> > that I needed when porting GNU Octave's JIT.
> >
> > Attempts to use other builtins may lead to an error:
> >    "unimplemented primitive type for builtin"
> > being emitted on the gcc_jit_context.
> >
> > gcc/jit/
> > 	* jit-builtins.c: New.
> > 	* jit-builtins.h: New.
> So how do you envision maintenance on this in the future?  Reality is 
> folks are regularly adding new builtins, are they going to have to 
> update the JIT too?

I believe the jit will only need updating if someone adds a new *macro*
to builtin-types.def e.g. if someone adds a new

  DEF_FUNCTION_TYPE_9

or somesuch.

Everything is keyed off the .def files, so GCC developers adding a new
builtin shouldn't need to touch the jit.

As I noted above, only a subset of the types are currently supported
from the jit; attempts to use builtins of other types from the jit will
fail at runtime with the type error I pasted above (and can be fixed up
on a case-by-case basis if the users file bug reports).

> OK for the trunk.

Thanks
Dave

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

* Re: [PATCH 10/27] New file: gcc/jit/libgccjit.c
  2014-11-03 20:32   ` Jeff Law
@ 2014-11-04 17:02     ` David Malcolm
  2014-11-04 21:40       ` Jeff Law
  0 siblings, 1 reply; 71+ messages in thread
From: David Malcolm @ 2014-11-04 17:02 UTC (permalink / raw)
  To: Jeff Law; +Cc: gcc-patches, jit

On Mon, 2014-11-03 at 13:32 -0700, Jeff Law wrote:
> On 10/31/14 11:02, David Malcolm wrote:
> > This file implements the entrypoints of the library's public API.
> >
> > It performs error-checking at this boundary, before calling into the
> > jit-recording.h internal API.
> >
> > gcc/jit/
> > 	* libgccjit.c: New.
> > ---
> >   gcc/jit/libgccjit.c | 1506 +++++++++++++++++++++++++++++++++++++++++++++++++++
> >   1 file changed, 1506 insertions(+)
> >   create mode 100644 gcc/jit/libgccjit.c
> >
> > +
> > +#define IS_ASCII_ALPHA(CHAR) \
> > +  (					\
> > +    ((CHAR) >= 'a' && (CHAR) <='z')	\
> > +    ||					\
> > +    ((CHAR) >= 'A' && (CHAR) <= 'Z')	\
> > +  )
> > +
> > +#define IS_ASCII_DIGIT(CHAR) \
> > +  ((CHAR) >= '0' && (CHAR) <='9')
> > +
> > +#define IS_ASCII_ALNUM(CHAR) \
> > +  (IS_ASCII_ALPHA (CHAR) || IS_ASCII_DIGIT (CHAR))
> Can't we rely on the C library to give us equivalents?

I've been burned in the past by the C library using locales, in
particular the two lowercase "i" variants in Turkish.

These macros are used by gcc_jit_context_new_function to enforce C's
naming restrictions, to avoid errors from the assembler.  The comment I
put there was:

  /* The assembler can only handle certain names, so for now, enforce
     C's rules for identifiers upon the name.
     Eventually we'll need some way to interact with e.g. C++ name mangling.  */

Am I right in thinking that for the assembler we need to enforce the C
naming rules specifically on *ASCII*.

(clearly another comment is needed here).

> > +
> > +/* TODO: mark failure branches as unlikely? */
> > +
> Not likely worth the effort.  And it'd be better to somehow mark 
> jit_error such that anytime a path unconditionally calls jit_error, the 
> whole path is considered unlikely.

(nods)

> I think it was Ball & Larus that had a predictor of this nature, I don't 
> recall its effectiveness offhand.  But I'd rather be marking the 
> function than sprinlkling unlikely all over the actual codepaths.

Presumably by marking it with __attribute__((cold)) ?  (with a suitable
macro in case we're not being compiled with a gcc that supports it).

I suspect doing so will be of more use in teaching me about gcc
internals and the effect on generated code that in measurable benefits
to said code in this case :)

> > +static bool
> > +compatible_types (gcc::jit::recording::type *ltype,
> > +		  gcc::jit::recording::type *rtype)
> All function definitions should have a block comment describing the 
> function and its arguments.   This comment applies throughout the code 
> and needs to be addressed prior to commit.  In fact I really can't even 
> continue review of this code due to the lack of comments -- I rely 
> heavily on them.

Sorry.  I'll post a followup with comments added.

Many of the functions are public API entrypoints, where there's a
comment in the public header.  Should I simply duplicate the comment
from there into the .c file, or put a comment like:

  /* Public entrypoint.  See description in libgccjit.h.  */

for each of these?  (perhaps with additional text giving implementation
notes?)


Thanks for all the reviews.  Looks like this and patch 16 are now the
only non-approved parts of the kit (I didn't see a review of 16).

Dave

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

* Re: [PATCH 12/27] New file: gcc/jit/jit-recording.h
  2014-11-04 16:16     ` David Malcolm
@ 2014-11-04 21:23       ` Jeff Law
  0 siblings, 0 replies; 71+ messages in thread
From: Jeff Law @ 2014-11-04 21:23 UTC (permalink / raw)
  To: David Malcolm; +Cc: gcc-patches, jit

On 11/04/14 09:12, David Malcolm wrote:
>> So give the complexities in interfacing with the guts of GCC, would it
>> make sense to expose the validate method?
>
> Most of the error-checking in the API happens in the API calls in
> libgccjit.c, testing that the individual pieces are sane.
>
> The validate method tests the things that can only be verified "as a
> whole", when the context is about to be compiled: are there unreachable
> blocks?  is every block terminated?  etc
>
> I can't quite see why client code might want to perform the latter kind
> of validation without actually doing a compile, so I don't plan to
> expose this at this time.  It's trivial to do so if someone needs it.
Yea, I saw all the border checking -- I was thinking mostly about things 
that require larger context.  In particular I was thinking block 
contents, the cfg and such.

Thinking about how I tend to work and might use this, I'd be likely to 
start building up statements/blocks and want to verify them without 
going all the way through compilation.  But that may be an artifact of 
living in a world where we have many points (between each pass) where a 
verification step for key data structures is useful.

I certainly don't see it as a blocking issue, just wanted to raise the 
possibility that exposing the verification step in the ABI might be 
useful.  If you don't want to do that right now, I can live with it.

>
> I think I was trying to avoid std::string for some reason, but I'm not
> quite sure why, perhaps out of a misremembered idea that libstdc++ was
> verboten (I currently use std:: in one place, in jit-playback.h, where a
> playback::context has a:
>    vec<std::pair<tree, location *> > m_cached_locations;
> ).
I can't see any reason why we wouldn't use basic capabilities of the C++ 
runtime system.  To use an example we both know and understand, 
switching EXPR_LIST to a forward_list would be something I would look 
favorably upon simply because everyone doing C++ knows what a 
forward_list is, it's proprties, strenghts & weaknesses.  Only GCC 
junkies happen to know that EXPR_LIST is just a hand-rolled forward list :-)


>
> In any case recording::string is an implementation detail hidden within
> the library.  It is a recording::memento and hence has the same lifetime
> as the recording::context.  I can't think of a reason off the top of my
> head why a std::string wouldn't work instead, but the existing code
> works, and has been through a fair amount of debugging.
How about as a follow-up?  I don't see this as being big enough to 
warrant blocking the work.

jeff

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

* Re: [PATCH 13/27] New file: gcc/jit/jit-recording.c
  2014-11-04 16:29     ` David Malcolm
@ 2014-11-04 21:24       ` Jeff Law
  0 siblings, 0 replies; 71+ messages in thread
From: Jeff Law @ 2014-11-04 21:24 UTC (permalink / raw)
  To: David Malcolm; +Cc: gcc-patches, jit

On 11/04/14 09:24, David Malcolm wrote:
>> So presumably no multi-way branches yet?  Might be better to build the
>> API in such a way that it handles multi-way branches from the get-go
>> rather than retrofitting later.  Your call.
>
> This is an internal API.  If the external API needs to support building
> switch statements from client code maybe with something like this:
>
>    extern void
>    gcc_jit_block_end_with_switch (gcc_jit_block *block,
>                                   gcc_jit_location *loc,
>                                   gcc_jit_rvalue *expr,
>                                   int num_cases,
>                                   gcc_jit_rvalue **case_values,
>                                   gcc_jit_block **case_blocks,
>                                   gcc_jit_block *default_block);
>
> then this internal API would obviously need to change, maybe becoming:
>
>    virtual int get_num_successor_blocks () const;
>    virtual block *get_successor_block (int index) const;
>
> but that won't affect the public API.
>
> That said it's not clear to me that we do need to support switch
> statements; no JIT implementation I've seen has needed them
> (I put them in the "Probably not needed" section of TODO.rst).
Fair enough :-)

jeff

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

* Re: [PATCH 10/27] New file: gcc/jit/libgccjit.c
  2014-11-04 17:02     ` David Malcolm
@ 2014-11-04 21:40       ` Jeff Law
  2014-11-05 15:52         ` [jit] Use ISALPHA and ISALNUM rather than writing our own David Malcolm
  2014-11-05 19:38         ` [PATCH 10/27] New file: gcc/jit/libgccjit.c David Malcolm
  0 siblings, 2 replies; 71+ messages in thread
From: Jeff Law @ 2014-11-04 21:40 UTC (permalink / raw)
  To: David Malcolm; +Cc: gcc-patches, jit

On 11/04/14 09:57, David Malcolm wrote:
>>> +#define IS_ASCII_DIGIT(CHAR) \
>>> +  ((CHAR) >= '0' && (CHAR) <='9')
>>> +
>>> +#define IS_ASCII_ALNUM(CHAR) \
>>> +  (IS_ASCII_ALPHA (CHAR) || IS_ASCII_DIGIT (CHAR))
>> Can't we rely on the C library to give us equivalents?
>
> I've been burned in the past by the C library using locales, in
> particular the two lowercase "i" variants in Turkish.
>
> These macros are used by gcc_jit_context_new_function to enforce C's
> naming restrictions, to avoid errors from the assembler.  The comment I
> put there was:
>
>    /* The assembler can only handle certain names, so for now, enforce
>       C's rules for identifiers upon the name.
>       Eventually we'll need some way to interact with e.g. C++ name mangling.  */
>
> Am I right in thinking that for the assembler we need to enforce the C
> naming rules specifically on *ASCII*.
>
> (clearly another comment is needed here).
I guess you've got to do it somewhere.  Presumably there isn't something 
already in GCC that enforces an input character set?  I guess I just 
dislike seeing something that feels like it ought to already be available.

>
> Presumably by marking it with __attribute__((cold)) ?  (with a suitable
> macro in case we're not being compiled with a gcc that supports it).
Yup.  That's precisely what you want since that gives the predictors 
enough information to mark paths as unlikely without having to mark each 
path yourself.

>
> Sorry.  I'll post a followup with comments added.
Thanks.  I probably rely more on those for this kind of review than 
anything, so the lack of them really stood out.

>
> Many of the functions are public API entrypoints, where there's a
> comment in the public header.  Should I simply duplicate the comment
> from there into the .c file, or put a comment like:
Good question.  Normally in the past we'd have you duplicate the 
comment, but with this new usage scenario that may not make a lot of 
sense since one or the other will likely get out of sync at some point.

At this point a snarky comment about generating documentation and the 
interface from a single definition would be appropriate.


>
>    /* Public entrypoint.  See description in libgccjit.h.  */
>
> for each of these?  (perhaps with additional text giving implementation
> notes?)
Let's go with this.  If folks want the comment duplicated, they can 
argue for it after the fact :-)

>
>
> Thanks for all the reviews.  Looks like this and patch 16 are now the
> only non-approved parts of the kit (I didn't see a review of 16).
Right.  I didn't get to #16 yesterday.

jeff

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

* Re: [PATCH 16/27] New file: gcc/jit/jit-playback.c
  2014-10-31 17:31 ` [PATCH 16/27] New file: gcc/jit/jit-playback.c David Malcolm
@ 2014-11-04 22:21   ` Jeff Law
  2014-11-05 20:23     ` [jit] Drop the disabled debugging code within handle_locations David Malcolm
  0 siblings, 1 reply; 71+ messages in thread
From: Jeff Law @ 2014-11-04 22:21 UTC (permalink / raw)
  To: David Malcolm, gcc-patches, jit

On 10/31/14 11:02, David Malcolm wrote:
> This files implements the gcc::jit::playback internal API, called by
> the dummy "frontend" to replay the public API calls made to the
> library.  A thin wrapper around trees.
>
> gcc/jit/
> 	* jit-playback.c: New.


> +  /* line_table should now be populated; every playback::location should
> +     now have an m_srcloc.  */
> +
> +  if (0)
> +    line_table_dump (stderr,
> +		     line_table,
> +		     LINEMAPS_ORDINARY_USED (line_table),
> +		     LINEMAPS_MACRO_USED (line_table));
> +
> +  /* Now assign them to tree nodes as appropriate.  */
> +  std::pair<tree, location *> *cached_location;
> +
> +  FOR_EACH_VEC_ELT (m_cached_locations, i, cached_location)
> +    {
> +      tree t = cached_location->first;
> +      source_location srcloc = cached_location->second->m_srcloc;
> +#if 0
> +      inform (srcloc, "location of ");
> +      debug_tree (t);
> +#endif
Put the if () #if0 under some kind of debugging control or remove them. 
  Similarly for later instances.

With that change, this is good for the trunk.

jeff

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

* [jit] Use ISALPHA and ISALNUM rather than writing our own
  2014-11-04 21:40       ` Jeff Law
@ 2014-11-05 15:52         ` David Malcolm
  2014-11-05 20:02           ` Jeff Law
  2014-11-05 19:38         ` [PATCH 10/27] New file: gcc/jit/libgccjit.c David Malcolm
  1 sibling, 1 reply; 71+ messages in thread
From: David Malcolm @ 2014-11-05 15:52 UTC (permalink / raw)
  To: Jeff Law; +Cc: gcc-patches, jit, David Malcolm

On Tue, 2014-11-04 at 14:39 -0700, Jeff Law wrote:
> On 11/04/14 09:57, David Malcolm wrote:
> >>> +#define IS_ASCII_DIGIT(CHAR) \
> >>> +  ((CHAR) >= '0' && (CHAR) <='9')
> >>> +
> >>> +#define IS_ASCII_ALNUM(CHAR) \
> >>> +  (IS_ASCII_ALPHA (CHAR) || IS_ASCII_DIGIT (CHAR))
> >> Can't we rely on the C library to give us equivalents?
> >
> > I've been burned in the past by the C library using locales, in
> > particular the two lowercase "i" variants in Turkish.
> >
> > These macros are used by gcc_jit_context_new_function to enforce C's
> > naming restrictions, to avoid errors from the assembler.  The comment I
> > put there was:
> >
> >    /* The assembler can only handle certain names, so for now, enforce
> >       C's rules for identifiers upon the name.
> >       Eventually we'll need some way to interact with e.g. C++ name mangling.  */
> >
> > Am I right in thinking that for the assembler we need to enforce the C
> > naming rules specifically on *ASCII*.
> >
> > (clearly another comment is needed here).
> I guess you've got to do it somewhere.  Presumably there isn't something 
> already in GCC that enforces an input character set?  I guess I just 
> dislike seeing something that feels like it ought to already be available.

It turns out that locale-independent tests for this did already exist in
libiberty, in safe-ctype.h, so I've committed this to the jit branch:

gcc/jit/ChangeLog.jit:
	* libgccjit.c: Include safe-ctype.h from libiberty.
	(IS_ASCII_ALPHA): Delete.
	(IS_ASCII_DIGIT): Delete.
	(IS_ASCII_ALNUM): Delete.
	(gcc_jit_context_new_function): Replace use of IS_ASCII_ALPHA and
	IS_ASCII_ALNUM with ISALPHA and ISALNUM respectively, from
	libiberty.
---
 gcc/jit/ChangeLog.jit | 10 ++++++++++
 gcc/jit/libgccjit.c   | 24 +++++++-----------------
 2 files changed, 17 insertions(+), 17 deletions(-)

diff --git a/gcc/jit/ChangeLog.jit b/gcc/jit/ChangeLog.jit
index 90fccdb..3d6361c 100644
--- a/gcc/jit/ChangeLog.jit
+++ b/gcc/jit/ChangeLog.jit
@@ -1,3 +1,13 @@
+2014-11-05  David Malcolm  <dmalcolm@redhat.com>
+
+	* libgccjit.c: Include safe-ctype.h from libiberty.
+	(IS_ASCII_ALPHA): Delete.
+	(IS_ASCII_DIGIT): Delete.
+	(IS_ASCII_ALNUM): Delete.
+	(gcc_jit_context_new_function): Replace use of IS_ASCII_ALPHA and
+	IS_ASCII_ALNUM with ISALPHA and ISALNUM respectively, from
+	libiberty.
+
 2014-10-30  David Malcolm  <dmalcolm@redhat.com>
 
 	* dummy-frontend.c (jit_langhook_init): Remove some dead code.
diff --git a/gcc/jit/libgccjit.c b/gcc/jit/libgccjit.c
index 286a85e..d9f259e 100644
--- a/gcc/jit/libgccjit.c
+++ b/gcc/jit/libgccjit.c
@@ -22,24 +22,12 @@ along with GCC; see the file COPYING3.  If not see
 #include "system.h"
 #include "coretypes.h"
 #include "opts.h"
+#include "safe-ctype.h"
 
 #include "libgccjit.h"
 #include "jit-common.h"
 #include "jit-recording.h"
 
-#define IS_ASCII_ALPHA(CHAR) \
-  (					\
-    ((CHAR) >= 'a' && (CHAR) <='z')	\
-    ||					\
-    ((CHAR) >= 'A' && (CHAR) <= 'Z')	\
-  )
-
-#define IS_ASCII_DIGIT(CHAR) \
-  ((CHAR) >= '0' && (CHAR) <='9')
-
-#define IS_ASCII_ALNUM(CHAR) \
-  (IS_ASCII_ALPHA (CHAR) || IS_ASCII_DIGIT (CHAR))
-
 struct gcc_jit_context : public gcc::jit::recording::context
 {
   gcc_jit_context (gcc_jit_context *parent_ctxt) :
@@ -589,13 +577,15 @@ gcc_jit_context_new_function (gcc_jit_context *ctxt,
   RETURN_NULL_IF_FAIL (return_type, ctxt, loc, "NULL return_type");
   RETURN_NULL_IF_FAIL (name, ctxt, loc, "NULL name");
   /* The assembler can only handle certain names, so for now, enforce
-     C's rules for identiers upon the name.
-     Eventually we'll need some way to interact with e.g. C++ name mangling.  */
+     C's rules for identiers upon the name, using ISALPHA and ISALNUM
+     from safe-ctype.h to ignore the current locale.
+     Eventually we'll need some way to interact with e.g. C++ name
+     mangling.  */
   {
     /* Leading char: */
     char ch = *name;
     RETURN_NULL_IF_FAIL_PRINTF2 (
-	IS_ASCII_ALPHA (ch) || ch == '_',
+	ISALPHA (ch) || ch == '_',
 	ctxt, loc,
 	"name \"%s\" contains invalid character: '%c'",
 	name, ch);
@@ -603,7 +593,7 @@ gcc_jit_context_new_function (gcc_jit_context *ctxt,
     for (const char *ptr = name + 1; (ch = *ptr); ptr++)
       {
 	RETURN_NULL_IF_FAIL_PRINTF2 (
-	  IS_ASCII_ALNUM (ch) || ch == '_',
+	  ISALNUM (ch) || ch == '_',
 	  ctxt, loc,
 	  "name \"%s\" contains invalid character: '%c'",
 	  name, ch);
-- 
1.7.11.7

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

* Re: [PATCH 10/27] New file: gcc/jit/libgccjit.c
  2014-11-04 21:40       ` Jeff Law
  2014-11-05 15:52         ` [jit] Use ISALPHA and ISALNUM rather than writing our own David Malcolm
@ 2014-11-05 19:38         ` David Malcolm
  2014-11-07 19:47           ` Jeff Law
  1 sibling, 1 reply; 71+ messages in thread
From: David Malcolm @ 2014-11-05 19:38 UTC (permalink / raw)
  To: Jeff Law; +Cc: gcc-patches, jit

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

On Tue, 2014-11-04 at 14:39 -0700, Jeff Law wrote:
> On 11/04/14 09:57, David Malcolm wrote:
> >>> +#define IS_ASCII_DIGIT(CHAR) \
> >>> +  ((CHAR) >= '0' && (CHAR) <='9')
> >>> +
> >>> +#define IS_ASCII_ALNUM(CHAR) \
> >>> +  (IS_ASCII_ALPHA (CHAR) || IS_ASCII_DIGIT (CHAR))
> >> Can't we rely on the C library to give us equivalents?
> >
> > I've been burned in the past by the C library using locales, in
> > particular the two lowercase "i" variants in Turkish.
> >
> > These macros are used by gcc_jit_context_new_function to enforce C's
> > naming restrictions, to avoid errors from the assembler.  The comment I
> > put there was:
> >
> >    /* The assembler can only handle certain names, so for now, enforce
> >       C's rules for identifiers upon the name.
> >       Eventually we'll need some way to interact with e.g. C++ name mangling.  */
> >
> > Am I right in thinking that for the assembler we need to enforce the C
> > naming rules specifically on *ASCII*.
> >
> > (clearly another comment is needed here).
> I guess you've got to do it somewhere.  Presumably there isn't something 
> already in GCC that enforces an input character set?  I guess I just 
> dislike seeing something that feels like it ought to already be available.
> 
> >
> > Presumably by marking it with __attribute__((cold)) ?  (with a suitable
> > macro in case we're not being compiled with a gcc that supports it).
> Yup.  That's precisely what you want since that gives the predictors 
> enough information to mark paths as unlikely without having to mark each 
> path yourself.
> 
> >
> > Sorry.  I'll post a followup with comments added.
> Thanks.  I probably rely more on those for this kind of review than 
> anything, so the lack of them really stood out.
> 
> >
> > Many of the functions are public API entrypoints, where there's a
> > comment in the public header.  Should I simply duplicate the comment
> > from there into the .c file, or put a comment like:
> Good question.  Normally in the past we'd have you duplicate the 
> comment, but with this new usage scenario that may not make a lot of 
> sense since one or the other will likely get out of sync at some point.
> 
> At this point a snarky comment about generating documentation and the 
> interface from a single definition would be appropriate.
> 
> 
> >
> >    /* Public entrypoint.  See description in libgccjit.h.  */
> >
> > for each of these?  (perhaps with additional text giving implementation
> > notes?)
> Let's go with this.  If folks want the comment duplicated, they can 
> argue for it after the fact :-)
> 
> >
> >
> > Thanks for all the reviews.  Looks like this and patch 16 are now the
> > only non-approved parts of the kit (I didn't see a review of 16).
> Right.  I didn't get to #16 yesterday.

Thanks.

I've added comments throughout the file.

I didn't bother adding __attribute__((cold)), instead simply dropping
that "TODO".

Attached is the current state of the file gcc/jit/libgccjit.c (on the
branch) for review.

OK for trunk? (conditional on all the rest being approved, and usual
bootstrap&regrtesting; I've merely verified a non-bootstrap compile and
successful make check-jit so far).

There were a few other changes relative to what you've approved, which
I'll post for review shortly.

Dave

[-- Attachment #2: libgccjit.c --]
[-- Type: text/x-csrc, Size: 62994 bytes --]

/* Implementation of the C API; all wrappers into the internal C++ API
   Copyright (C) 2013-2014 Free Software Foundation, Inc.
   Contributed by David Malcolm <dmalcolm@redhat.com>.

This file is part of GCC.

GCC is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.

GCC is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.

You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3.  If not see
<http://www.gnu.org/licenses/>.  */

#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "opts.h"
#include "safe-ctype.h"

#include "libgccjit.h"
#include "jit-common.h"
#include "jit-recording.h"

/* The opaque types used by the public API are actually subclasses
   of the gcc::jit::recording classes.  */

struct gcc_jit_context : public gcc::jit::recording::context
{
  gcc_jit_context (gcc_jit_context *parent_ctxt) :
    context (parent_ctxt)
  {}
};

struct gcc_jit_result : public gcc::jit::result
{
};

struct gcc_jit_object : public gcc::jit::recording::memento
{
};

struct gcc_jit_location : public gcc::jit::recording::location
{
};

struct gcc_jit_type : public gcc::jit::recording::type
{
};

struct gcc_jit_struct : public gcc::jit::recording::struct_
{
};

struct gcc_jit_field : public gcc::jit::recording::field
{
};

struct gcc_jit_function : public gcc::jit::recording::function
{
};

struct gcc_jit_block : public gcc::jit::recording::block
{
};

struct gcc_jit_rvalue : public gcc::jit::recording::rvalue
{
};

struct gcc_jit_lvalue : public gcc::jit::recording::lvalue
{
};

struct gcc_jit_param : public gcc::jit::recording::param
{
};

/**********************************************************************
 Error-handling.

 We try to gracefully handle API usage errors by being defensive
 at the API boundary.
 **********************************************************************/

#define JIT_BEGIN_STMT do {
#define JIT_END_STMT   } while(0)

/* Each of these error-handling macros determines if TEST_EXPR holds.

   If TEXT_EXPR fails to hold we return from the enclosing function and
   print an error, either via adding an error on the given context CTXT
   if CTXT is non-NULL, falling back to simply printing to stderr if CTXT
   is NULL.

   They have to be macros since they inject their "return" into the
   function they are placed in.

   The variant macros express:

     (A) whether or not we need to return a value:
	    RETURN_VAL_IF_FAIL* vs
	    RETURN_IF_FAIL*,
	 with the former returning RETURN_EXPR, and
	    RETURN_NULL_IF_FAIL*
	 for the common case where a NULL value is to be returned on
	 error, and

     (B) whether the error message is to be directly printed:
	   RETURN_*IF_FAIL
	 or is a format string with some number of arguments:
	   RETURN_*IF_FAIL_PRINTF*

   They all use JIT_BEGIN_STMT/JIT_END_STMT so they can be written with
   trailing semicolons.
*/

#define RETURN_VAL_IF_FAIL(TEST_EXPR, RETURN_EXPR, CTXT, LOC, ERR_MSG)	\
  JIT_BEGIN_STMT							\
    if (!(TEST_EXPR))							\
      {								\
	jit_error ((CTXT), (LOC), "%s: %s", __func__, (ERR_MSG));	\
	return (RETURN_EXPR);						\
      }								\
  JIT_END_STMT

#define RETURN_VAL_IF_FAIL_PRINTF1(TEST_EXPR, RETURN_EXPR, CTXT, LOC, ERR_FMT, A0) \
  JIT_BEGIN_STMT							\
    if (!(TEST_EXPR))							\
      {								\
	jit_error ((CTXT), (LOC), "%s: " ERR_FMT,			\
		   __func__, (A0));				\
	return (RETURN_EXPR);						\
      }								\
  JIT_END_STMT

#define RETURN_VAL_IF_FAIL_PRINTF2(TEST_EXPR, RETURN_EXPR, CTXT, LOC, ERR_FMT, A0, A1) \
  JIT_BEGIN_STMT							\
    if (!(TEST_EXPR))							\
      {								\
	jit_error ((CTXT), (LOC), "%s: " ERR_FMT,				\
		   __func__, (A0), (A1));				\
	return (RETURN_EXPR);						\
      }								\
  JIT_END_STMT

#define RETURN_VAL_IF_FAIL_PRINTF3(TEST_EXPR, RETURN_EXPR, CTXT, LOC, ERR_FMT, A0, A1, A2) \
  JIT_BEGIN_STMT							\
    if (!(TEST_EXPR))							\
      {								\
	jit_error ((CTXT), (LOC), "%s: " ERR_FMT,				\
		   __func__, (A0), (A1), (A2));			\
	return (RETURN_EXPR);						\
      }								\
  JIT_END_STMT

#define RETURN_VAL_IF_FAIL_PRINTF4(TEST_EXPR, RETURN_EXPR, CTXT, LOC, ERR_FMT, A0, A1, A2, A3) \
  JIT_BEGIN_STMT							\
    if (!(TEST_EXPR))							\
      {								\
	jit_error ((CTXT), (LOC), "%s: " ERR_FMT,				\
		   __func__, (A0), (A1), (A2), (A3));			\
	return (RETURN_EXPR);						\
      }								\
  JIT_END_STMT

#define RETURN_VAL_IF_FAIL_PRINTF6(TEST_EXPR, RETURN_EXPR, CTXT, LOC, ERR_FMT, A0, A1, A2, A3, A4, A5) \
  JIT_BEGIN_STMT							\
    if (!(TEST_EXPR))							\
      {								\
	jit_error ((CTXT), (LOC), "%s: " ERR_FMT,				\
		   __func__, (A0), (A1), (A2), (A3), (A4), (A5));	\
	return (RETURN_EXPR);						\
      }								\
  JIT_END_STMT

#define RETURN_NULL_IF_FAIL(TEST_EXPR, CTXT, LOC, ERR_MSG) \
  RETURN_VAL_IF_FAIL ((TEST_EXPR), NULL, (CTXT), (LOC), (ERR_MSG))

#define RETURN_NULL_IF_FAIL_PRINTF1(TEST_EXPR, CTXT, LOC, ERR_FMT, A0) \
  RETURN_VAL_IF_FAIL_PRINTF1 (TEST_EXPR, NULL, CTXT, LOC, ERR_FMT, A0)

#define RETURN_NULL_IF_FAIL_PRINTF2(TEST_EXPR, CTXT, LOC, ERR_FMT, A0, A1) \
  RETURN_VAL_IF_FAIL_PRINTF2 (TEST_EXPR, NULL, CTXT, LOC, ERR_FMT, A0, A1)

#define RETURN_NULL_IF_FAIL_PRINTF3(TEST_EXPR, CTXT, LOC, ERR_FMT, A0, A1, A2) \
  RETURN_VAL_IF_FAIL_PRINTF3 (TEST_EXPR, NULL, CTXT, LOC, ERR_FMT, A0, A1, A2)

#define RETURN_NULL_IF_FAIL_PRINTF4(TEST_EXPR, CTXT, LOC, ERR_FMT, A0, A1, A2, A3) \
  RETURN_VAL_IF_FAIL_PRINTF4 (TEST_EXPR, NULL, CTXT, LOC, ERR_FMT, A0, A1, A2, A3)

#define RETURN_NULL_IF_FAIL_PRINTF6(TEST_EXPR, CTXT, LOC, ERR_FMT, A0, A1, A2, A3, A4, A5) \
  RETURN_VAL_IF_FAIL_PRINTF6 (TEST_EXPR, NULL, CTXT, LOC, ERR_FMT, A0, A1, A2, A3, A4, A5)

#define RETURN_IF_FAIL(TEST_EXPR, CTXT, LOC, ERR_MSG)			\
  JIT_BEGIN_STMT							\
    if (!(TEST_EXPR))							\
      {								\
	jit_error ((CTXT), (LOC), "%s: %s", __func__, (ERR_MSG));		\
	return;							\
      }								\
  JIT_END_STMT

#define RETURN_IF_FAIL_PRINTF1(TEST_EXPR, CTXT, LOC, ERR_FMT, A0) \
  JIT_BEGIN_STMT							\
    if (!(TEST_EXPR))							\
      {								\
	jit_error ((CTXT), (LOC), "%s: " ERR_FMT,				\
		   __func__, (A0));					\
	return;							\
      }								\
  JIT_END_STMT

#define RETURN_IF_FAIL_PRINTF2(TEST_EXPR, CTXT, LOC, ERR_FMT, A0, A1) \
  JIT_BEGIN_STMT							\
    if (!(TEST_EXPR))							\
      {								\
	jit_error ((CTXT), (LOC), "%s: " ERR_FMT,				\
		   __func__, (A0), (A1));				\
	return;							\
      }								\
  JIT_END_STMT

#define RETURN_IF_FAIL_PRINTF4(TEST_EXPR, CTXT, LOC, ERR_FMT, A0, A1, A2, A3) \
  JIT_BEGIN_STMT							\
    if (!(TEST_EXPR))							\
      {								\
	jit_error ((CTXT), (LOC), "%s: " ERR_FMT,				\
		   __func__, (A0), (A1), (A2), (A3));			\
	return;							\
      }								\
  JIT_END_STMT

/* Check that BLOCK is non-NULL, and that it's OK to add statements to
   it.  This will fail if BLOCK has already been terminated by some
   kind of jump or a return.  */
#define RETURN_IF_NOT_VALID_BLOCK(BLOCK, LOC)				\
  JIT_BEGIN_STMT							\
    RETURN_IF_FAIL ((BLOCK), NULL, (LOC), "NULL block");		\
    RETURN_IF_FAIL_PRINTF2 (						\
      !(BLOCK)->has_been_terminated (),				\
      (BLOCK)->get_context (),						\
      (LOC),								\
      "adding to terminated block: %s (already terminated by: %s)",	\
      (BLOCK)->get_debug_string (),					\
      (BLOCK)->get_last_statement ()->get_debug_string ());		\
  JIT_END_STMT

/* As RETURN_IF_NOT_VALID_BLOCK, but injecting a "return NULL;" if it
   fails.  */
#define RETURN_NULL_IF_NOT_VALID_BLOCK(BLOCK, LOC)			\
  JIT_BEGIN_STMT							\
    RETURN_NULL_IF_FAIL ((BLOCK), NULL, (LOC), "NULL block");		\
    RETURN_NULL_IF_FAIL_PRINTF2 (					\
      !(BLOCK)->has_been_terminated (),				\
      (BLOCK)->get_context (),						\
      (LOC),								\
      "adding to terminated block: %s (already terminated by: %s)",	\
      (BLOCK)->get_debug_string (),					\
      (BLOCK)->get_last_statement ()->get_debug_string ());		\
  JIT_END_STMT

/* Format the given string, and report it as an error, either on CTXT
   if non-NULL, or by printing to stderr if we have a NULL context.
   LOC gives the source location where the error occcurred, and can be
   NULL.  */

static void
jit_error (gcc::jit::recording::context *ctxt,
	   gcc_jit_location *loc,
	   const char *fmt, ...)
  GNU_PRINTF(3, 4);

static void
jit_error (gcc::jit::recording::context *ctxt,
	   gcc_jit_location *loc,
	   const char *fmt, ...)
{
  va_list ap;
  va_start (ap, fmt);

  if (ctxt)
    ctxt->add_error_va (loc, fmt, ap);
  else
    {
      /* No context?  Send to stderr.  */
      vfprintf (stderr, fmt, ap);
      fprintf (stderr, "\n");
    }

  va_end (ap);
}

/* Determine whether or not we can write to lvalues of type LTYPE from
   rvalues of type RTYPE, detecting type errors such as attempting to
   write to an int with a string literal (without an explicit cast).

   This is implemented by calling the
   gcc::jit::recording::type::accepts_writes_from virtual function on
   LTYPE.  */

static bool
compatible_types (gcc::jit::recording::type *ltype,
		  gcc::jit::recording::type *rtype)
{
  return ltype->accepts_writes_from (rtype);
}

/* Public entrypoint for acquiring a gcc_jit_context.
   Note that this creates a new top-level context; contrast with
   gcc_jit_context_new_child_context below.

   The real work is done in the constructor for
   gcc::jit::recording::context in jit-recording.c. */

gcc_jit_context *
gcc_jit_context_acquire (void)
{
  return new gcc_jit_context (NULL);
}

/* Public entrypoint for releasing a gcc_jit_context.
   The real work is done in the destructor for
   gcc::jit::recording::context in jit-recording.c.  */

void
gcc_jit_context_release (gcc_jit_context *ctxt)
{
  delete ctxt;
}

/* Public entrypoint for creating a child context within
   PARENT_CTXT.  See description in libgccjit.h.

   The real work is done in the constructor for
   gcc::jit::recording::context in jit-recording.c. */

gcc_jit_context *
gcc_jit_context_new_child_context (gcc_jit_context *parent_ctxt)
{
  return new gcc_jit_context (parent_ctxt);
}

/* Public entrypoint.  See description in libgccjit.h.

   After error-checking, the real work is done by the
     gcc::jit::recording::context::new_location
   method in jit-recording.c.  */

gcc_jit_location *
gcc_jit_context_new_location (gcc_jit_context *ctxt,
			      const char *filename,
			      int line,
			      int column)
{
  RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");

  return (gcc_jit_location *)ctxt->new_location (filename, line, column);
}

/* Public entrypoint.  See description in libgccjit.h.

   After error-checking, this calls the trivial
   gcc::jit::recording::memento::as_object method (a location is a
   memento), in jit-recording.h.  */

gcc_jit_object *
gcc_jit_location_as_object (gcc_jit_location *loc)
{
  RETURN_NULL_IF_FAIL (loc, NULL, NULL, "NULL location");

  return static_cast <gcc_jit_object *> (loc->as_object ());
}

/* Public entrypoint.  See description in libgccjit.h.

   After error-checking, this calls the trivial
   gcc::jit::recording::memento::as_object method (a type is a
   memento), in jit-recording.h.  */

gcc_jit_object *
gcc_jit_type_as_object (gcc_jit_type *type)
{
  RETURN_NULL_IF_FAIL (type, NULL, NULL, "NULL type");

  return static_cast <gcc_jit_object *> (type->as_object ());
}

/* Public entrypoint for getting a specific type from a context.

   After error-checking, the real work is done by the
   gcc::jit::recording::context::get_type method, in
   jit-recording.c  */

gcc_jit_type *
gcc_jit_context_get_type (gcc_jit_context *ctxt,
			  enum gcc_jit_types type)
{
  RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
  RETURN_NULL_IF_FAIL_PRINTF1 (
    (type >= GCC_JIT_TYPE_VOID
     && type <= GCC_JIT_TYPE_FILE_PTR),
    ctxt, NULL,
    "unrecognized value for enum gcc_jit_types: %i", type);

  return (gcc_jit_type *)ctxt->get_type (type);
}

/* Public entrypoint for getting the integer type of the given size and
   signedness.

   After error-checking, the real work is done by the
   gcc::jit::recording::context::get_int_type method,
   in jit-recording.c.  */

gcc_jit_type *
gcc_jit_context_get_int_type (gcc_jit_context *ctxt,
			      int num_bytes, int is_signed)
{
  RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
  RETURN_NULL_IF_FAIL (num_bytes >= 0, ctxt, NULL, "negative size");

  return (gcc_jit_type *)ctxt->get_int_type (num_bytes, is_signed);
}

/* Public entrypoint.  See description in libgccjit.h.

   After error-checking, the real work is done by the
   gcc::jit::recording::type::get_pointer method, in
   jit-recording.c  */

gcc_jit_type *
gcc_jit_type_get_pointer (gcc_jit_type *type)
{
  RETURN_NULL_IF_FAIL (type, NULL, NULL, "NULL type");

  return (gcc_jit_type *)type->get_pointer ();
}

/* Public entrypoint.  See description in libgccjit.h.

   After error-checking, the real work is done by the
   gcc::jit::recording::type::get_const method, in
   jit-recording.c.  */

gcc_jit_type *
gcc_jit_type_get_const (gcc_jit_type *type)
{
  RETURN_NULL_IF_FAIL (type, NULL, NULL, "NULL type");

  return (gcc_jit_type *)type->get_const ();
}

/* Public entrypoint.  See description in libgccjit.h.

   After error-checking, the real work is done by the
   gcc::jit::recording::type::get_volatile method, in
   jit-recording.c.  */

gcc_jit_type *
gcc_jit_type_get_volatile (gcc_jit_type *type)
{
  RETURN_NULL_IF_FAIL (type, NULL, NULL, "NULL type");

  return (gcc_jit_type *)type->get_volatile ();
}

/* Public entrypoint.  See description in libgccjit.h.

   After error-checking, the real work is done by the
   gcc::jit::recording::context::new_array_type method, in
   jit-recording.c.  */

gcc_jit_type *
gcc_jit_context_new_array_type (gcc_jit_context *ctxt,
				gcc_jit_location *loc,
				gcc_jit_type *element_type,
				int num_elements)
{
  RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL context");
  /* LOC can be NULL.  */
  RETURN_NULL_IF_FAIL (element_type, ctxt, loc, "NULL type");
  RETURN_NULL_IF_FAIL (num_elements >= 0, ctxt, NULL, "negative size");

  return (gcc_jit_type *)ctxt->new_array_type (loc,
					       element_type,
					       num_elements);
}

/* Public entrypoint.  See description in libgccjit.h.

   After error-checking, the real work is done by the
   gcc::jit::recording::context::new_field method, in
   jit-recording.c.  */

gcc_jit_field *
gcc_jit_context_new_field (gcc_jit_context *ctxt,
			   gcc_jit_location *loc,
			   gcc_jit_type *type,
			   const char *name)
{
  RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
  /* LOC can be NULL.  */
  RETURN_NULL_IF_FAIL (type, ctxt, loc, "NULL type");
  RETURN_NULL_IF_FAIL (name, ctxt, loc, "NULL name");

  return (gcc_jit_field *)ctxt->new_field (loc, type, name);
}

/* Public entrypoint.  See description in libgccjit.h.

   After error-checking, this calls the trivial
   gcc::jit::recording::memento::as_object method (a field is a
   memento), in jit-recording.h.  */

gcc_jit_object *
gcc_jit_field_as_object (gcc_jit_field *field)
{
  RETURN_NULL_IF_FAIL (field, NULL, NULL, "NULL field");

  return static_cast <gcc_jit_object *> (field->as_object ());
}

/* Public entrypoint.  See description in libgccjit.h.

   After error-checking, the real work is done by the
   gcc::jit::recording::context::new_struct_type method,
   immediately followed by a "set_fields" call on the resulting
   gcc::jit::recording::compound_type *, both in jit-recording.c  */

gcc_jit_struct *
gcc_jit_context_new_struct_type (gcc_jit_context *ctxt,
				 gcc_jit_location *loc,
				 const char *name,
				 int num_fields,
				 gcc_jit_field **fields)
{
  RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
  /* LOC can be NULL.  */
  RETURN_NULL_IF_FAIL (name, ctxt, loc, "NULL name");
  if (num_fields)
    RETURN_NULL_IF_FAIL (fields, ctxt, loc, "NULL fields ptr");
  for (int i = 0; i < num_fields; i++)
    {
      RETURN_NULL_IF_FAIL (fields[i], ctxt, loc, "NULL field ptr");
      RETURN_NULL_IF_FAIL_PRINTF2 (
	NULL == fields[i]->get_container (),
	ctxt, loc,
	"%s is already a field of %s",
	fields[i]->get_debug_string (),
	fields[i]->get_container ()->get_debug_string ());
    }

  gcc::jit::recording::struct_ *result =
    ctxt->new_struct_type (loc, name);
  result->set_fields (loc,
		      num_fields,
		      (gcc::jit::recording::field **)fields);
  return static_cast<gcc_jit_struct *> (result);
}

/* Public entrypoint.  See description in libgccjit.h.

   After error-checking, the real work is done by the
   gcc::jit::recording::context::new_struct_type method in
   jit-recording.c.  */

gcc_jit_struct *
gcc_jit_context_new_opaque_struct (gcc_jit_context *ctxt,
				   gcc_jit_location *loc,
				   const char *name)
{
  RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL context");
  /* LOC can be NULL.  */
  RETURN_NULL_IF_FAIL (name, ctxt, loc, "NULL name");

  return (gcc_jit_struct *)ctxt->new_struct_type (loc, name);
}

/* Public entrypoint.  See description in libgccjit.h.

   After error-checking, this calls the trivial
   gcc::jit::recording::struct_::as_object method in
   jit-recording.h.  */

gcc_jit_type *
gcc_jit_struct_as_type (gcc_jit_struct *struct_type)
{
  RETURN_NULL_IF_FAIL (struct_type, NULL, NULL, "NULL struct_type");

  return static_cast <gcc_jit_type *> (struct_type->as_type ());
}

/* Public entrypoint.  See description in libgccjit.h.

   After error-checking, the real work is done by the
   gcc::jit::recording::compound_type::set_fields method in
   jit-recording.c.  */

void
gcc_jit_struct_set_fields (gcc_jit_struct *struct_type,
			   gcc_jit_location *loc,
			   int num_fields,
			   gcc_jit_field **fields)
{
  RETURN_IF_FAIL (struct_type, NULL, loc, "NULL struct_type");
  /* LOC can be NULL.  */
  gcc::jit::recording::context *ctxt = struct_type->m_ctxt;
  RETURN_IF_FAIL_PRINTF1 (
    NULL == struct_type->get_fields (), ctxt, loc,
    "%s already has had fields set",
    struct_type->get_debug_string ());
  if (num_fields)
    RETURN_IF_FAIL (fields, ctxt, loc, "NULL fields ptr");
  for (int i = 0; i < num_fields; i++)
    {
      RETURN_IF_FAIL (fields[i], ctxt, loc, "NULL field ptr");
      RETURN_IF_FAIL_PRINTF2 (
	NULL == fields[i]->get_container (),
	ctxt, loc,
	"%s is already a field of %s",
	fields[i]->get_debug_string (),
	fields[i]->get_container ()->get_debug_string ());
    }

  struct_type->set_fields (loc, num_fields,
			   (gcc::jit::recording::field **)fields);
}

/* Public entrypoint.  See description in libgccjit.h.

   After error-checking, the real work is done by the
   gcc::jit::recording::context::new_union_type method,
   immediately followed by a "set_fields" call on the resulting
   gcc::jit::recording::compound_type *, both in jit-recording.c  */

gcc_jit_type *
gcc_jit_context_new_union_type (gcc_jit_context *ctxt,
				gcc_jit_location *loc,
				const char *name,
				int num_fields,
				gcc_jit_field **fields)
{
  RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
  /* LOC can be NULL.  */
  RETURN_NULL_IF_FAIL (name, ctxt, loc, "NULL name");
  if (num_fields)
    RETURN_NULL_IF_FAIL (fields, ctxt, loc, "NULL fields ptr");
  for (int i = 0; i < num_fields; i++)
    {
      RETURN_NULL_IF_FAIL (fields[i], ctxt, loc, "NULL field ptr");
      RETURN_NULL_IF_FAIL_PRINTF2 (
	NULL == fields[i]->get_container (),
	ctxt, loc,
	"%s is already a field of %s",
	fields[i]->get_debug_string (),
	fields[i]->get_container ()->get_debug_string ());
    }

  gcc::jit::recording::union_ *result =
    ctxt->new_union_type (loc, name);
  result->set_fields (loc,
		      num_fields,
		      (gcc::jit::recording::field **)fields);
  return (gcc_jit_type *) (result);
}

/* Public entrypoint.  See description in libgccjit.h.

   After error-checking, the real work is done by the
   gcc::jit::recording::context::new_function_ptr_type method,
   in jit-recording.c  */

gcc_jit_type *
gcc_jit_context_new_function_ptr_type (gcc_jit_context *ctxt,
				       gcc_jit_location *loc,
				       gcc_jit_type *return_type,
				       int num_params,
				       gcc_jit_type **param_types,
				       int is_variadic)
{
  RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL context");
  /* LOC can be NULL.  */
  RETURN_NULL_IF_FAIL (return_type, ctxt, loc, "NULL return_type");
  RETURN_NULL_IF_FAIL (
    (num_params == 0) || param_types,
    ctxt, loc,
    "NULL param_types creating function pointer type");
  for (int i = 0; i < num_params; i++)
    RETURN_NULL_IF_FAIL_PRINTF1 (
      param_types[i],
      ctxt, loc,
      "NULL parameter type %i creating function pointer type", i);

  return (gcc_jit_type*)
    ctxt->new_function_ptr_type (loc, return_type,
				 num_params,
				 (gcc::jit::recording::type **)param_types,
				 is_variadic);
}

/* Constructing functions.  */

/* Public entrypoint.  See description in libgccjit.h.

   After error-checking, the real work is done by the
   gcc::jit::recording::context::new_param method, in jit-recording.c  */

gcc_jit_param *
gcc_jit_context_new_param (gcc_jit_context *ctxt,
			   gcc_jit_location *loc,
			   gcc_jit_type *type,
			   const char *name)
{
  RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL context");
  /* LOC can be NULL.  */
  RETURN_NULL_IF_FAIL (type, ctxt, loc, "NULL type");
  RETURN_NULL_IF_FAIL (name, ctxt, loc, "NULL name");

  return (gcc_jit_param *)ctxt->new_param (loc, type, name);
}

/* Public entrypoint.  See description in libgccjit.h.

   After error-checking, this calls the trivial
   gcc::jit::recording::memento::as_object method (a param is a memento),
   in jit-recording.h.  */

gcc_jit_object *
gcc_jit_param_as_object (gcc_jit_param *param)
{
  RETURN_NULL_IF_FAIL (param, NULL, NULL, "NULL param");

  return static_cast <gcc_jit_object *> (param->as_object ());
}

/* Public entrypoint.  See description in libgccjit.h.

   After error-checking, this calls the trivial
   gcc::jit::recording::param::as_lvalue method in jit-recording.h.  */

gcc_jit_lvalue *
gcc_jit_param_as_lvalue (gcc_jit_param *param)
{
  RETURN_NULL_IF_FAIL (param, NULL, NULL, "NULL param");

  return (gcc_jit_lvalue *)param->as_lvalue ();
}

/* Public entrypoint.  See description in libgccjit.h.

   After error-checking, this calls the trivial
   gcc::jit::recording::lvalue::as_rvalue method (a param is an rvalue),
   in jit-recording.h.  */

gcc_jit_rvalue *
gcc_jit_param_as_rvalue (gcc_jit_param *param)
{
  RETURN_NULL_IF_FAIL (param, NULL, NULL, "NULL param");

  return (gcc_jit_rvalue *)param->as_rvalue ();
}

/* Public entrypoint.  See description in libgccjit.h.

   After error-checking, the real work is done by the
   gcc::jit::recording::context::new_function method, in
   jit-recording.c.  */

gcc_jit_function *
gcc_jit_context_new_function (gcc_jit_context *ctxt,
			      gcc_jit_location *loc,
			      enum gcc_jit_function_kind kind,
			      gcc_jit_type *return_type,
			      const char *name,
			      int num_params,
			      gcc_jit_param **params,
			      int is_variadic)
{
  RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL context");
  /* LOC can be NULL.  */
  RETURN_NULL_IF_FAIL_PRINTF1 (
    ((kind >= GCC_JIT_FUNCTION_EXPORTED)
     && (kind <= GCC_JIT_FUNCTION_ALWAYS_INLINE)),
    ctxt, loc,
    "unrecognized value for enum gcc_jit_function_kind: %i",
    kind);
  RETURN_NULL_IF_FAIL (return_type, ctxt, loc, "NULL return_type");
  RETURN_NULL_IF_FAIL (name, ctxt, loc, "NULL name");
  /* The assembler can only handle certain names, so for now, enforce
     C's rules for identiers upon the name, using ISALPHA and ISALNUM
     from safe-ctype.h to ignore the current locale.
     Eventually we'll need some way to interact with e.g. C++ name
     mangling.  */
  {
    /* Leading char: */
    char ch = *name;
    RETURN_NULL_IF_FAIL_PRINTF2 (
	ISALPHA (ch) || ch == '_',
	ctxt, loc,
	"name \"%s\" contains invalid character: '%c'",
	name, ch);
    /* Subsequent chars: */
    for (const char *ptr = name + 1; (ch = *ptr); ptr++)
      {
	RETURN_NULL_IF_FAIL_PRINTF2 (
	  ISALNUM (ch) || ch == '_',
	  ctxt, loc,
	  "name \"%s\" contains invalid character: '%c'",
	  name, ch);
      }
  }
  RETURN_NULL_IF_FAIL_PRINTF1 (
    (num_params == 0) || params,
    ctxt, loc,
    "NULL params creating function %s", name);
  for (int i = 0; i < num_params; i++)
    RETURN_NULL_IF_FAIL_PRINTF2 (
      params[i],
      ctxt, loc,
      "NULL parameter %i creating function %s", i, name);

  return (gcc_jit_function*)
    ctxt->new_function (loc, kind, return_type, name,
			num_params,
			(gcc::jit::recording::param **)params,
			is_variadic,
			BUILT_IN_NONE);
}

/* Public entrypoint.  See description in libgccjit.h.

   After error-checking, the real work is done by the
   gcc::jit::recording::context::get_builtin_function method, in
   jit-recording.c.  */

gcc_jit_function *
gcc_jit_context_get_builtin_function (gcc_jit_context *ctxt,
				      const char *name)
{
  RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
  RETURN_NULL_IF_FAIL (name, ctxt, NULL, "NULL name");

  return static_cast <gcc_jit_function *> (ctxt->get_builtin_function (name));
}

/* Public entrypoint.  See description in libgccjit.h.

   After error-checking, this calls the trivial
   gcc::jit::recording::memento::as_object method (a function is a
   memento), in jit-recording.h.  */

gcc_jit_object *
gcc_jit_function_as_object (gcc_jit_function *func)
{
  RETURN_NULL_IF_FAIL (func, NULL, NULL, "NULL function");

  return static_cast <gcc_jit_object *> (func->as_object ());
}

/* Public entrypoint.  See description in libgccjit.h.

   After error-checking, the real work is done by the
   gcc::jit::recording::function::get_param method, in
   jit-recording.h.  */

gcc_jit_param *
gcc_jit_function_get_param (gcc_jit_function *func, int index)
{
  RETURN_NULL_IF_FAIL (func, NULL, NULL, "NULL function");
  gcc::jit::recording::context *ctxt = func->m_ctxt;
  RETURN_NULL_IF_FAIL (index >= 0, ctxt, NULL, "negative index");
  int num_params = func->get_params ().length ();
  RETURN_NULL_IF_FAIL_PRINTF3 (index < num_params,
			       ctxt, NULL,
			       "index of %d is too large (%s has %d params)",
			       index,
			       func->get_debug_string (),
			       num_params);

  return static_cast <gcc_jit_param *> (func->get_param (index));
}

/* Public entrypoint.  See description in libgccjit.h.

   After error-checking, the real work is done by the
   gcc::jit::recording::function::dump_to_dot method, in
   jit-recording.c.  */

void
gcc_jit_function_dump_to_dot (gcc_jit_function *func,
			      const char *path)
{
  RETURN_IF_FAIL (func, NULL, NULL, "NULL function");
  gcc::jit::recording::context *ctxt = func->m_ctxt;
  RETURN_IF_FAIL (path, ctxt, NULL, "NULL path");

  func->dump_to_dot (path);
}

/* Public entrypoint.  See description in libgccjit.h.

   After error-checking, the real work is done by the
   gcc::jit::recording::function::new_block method, in
   jit-recording.c.  */

gcc_jit_block*
gcc_jit_function_new_block (gcc_jit_function *func,
			    const char *name)
{
  RETURN_NULL_IF_FAIL (func, NULL, NULL, "NULL function");
  RETURN_NULL_IF_FAIL (func->get_kind () != GCC_JIT_FUNCTION_IMPORTED,
		       func->get_context (), NULL,
		       "cannot add block to an imported function");
  /* name can be NULL.  */

  return (gcc_jit_block *)func->new_block (name);
}

/* Public entrypoint.  See description in libgccjit.h.

   After error-checking, this calls the trivial
   gcc::jit::recording::memento::as_object method (a block is a
   memento), in jit-recording.h.  */

gcc_jit_object *
gcc_jit_block_as_object (gcc_jit_block *block)
{
  RETURN_NULL_IF_FAIL (block, NULL, NULL, "NULL block");

  return static_cast <gcc_jit_object *> (block->as_object ());
}

/* Public entrypoint.  See description in libgccjit.h.

   After error-checking, the real work is done by the
   gcc::jit::recording::block::get_function method, in
   jit-recording.h.  */

gcc_jit_function *
gcc_jit_block_get_function (gcc_jit_block *block)
{
  RETURN_NULL_IF_FAIL (block, NULL, NULL, "NULL block");

  return static_cast <gcc_jit_function *> (block->get_function ());
}

/* Public entrypoint.  See description in libgccjit.h.

   After error-checking, the real work is done by the
   gcc::jit::recording::context::new_global method, in
   jit-recording.c.  */

gcc_jit_lvalue *
gcc_jit_context_new_global (gcc_jit_context *ctxt,
			    gcc_jit_location *loc,
			    gcc_jit_type *type,
			    const char *name)
{
  RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL context");
  /* LOC can be NULL.  */
  RETURN_NULL_IF_FAIL (type, ctxt, loc, "NULL type");
  RETURN_NULL_IF_FAIL (name, ctxt, loc, "NULL name");

  return (gcc_jit_lvalue *)ctxt->new_global (loc, type, name);
}

/* Public entrypoint.  See description in libgccjit.h.

   After error-checking, this calls the trivial
   gcc::jit::recording::memento::as_object method (an lvalue is a
   memento), in jit-recording.h.  */

gcc_jit_object *
gcc_jit_lvalue_as_object (gcc_jit_lvalue *lvalue)
{
  RETURN_NULL_IF_FAIL (lvalue, NULL, NULL, "NULL lvalue");

  return static_cast <gcc_jit_object *> (lvalue->as_object ());
}

/* Public entrypoint.  See description in libgccjit.h.

   After error-checking, this calls the trivial
   gcc::jit::recording::lvalue::as_rvalue method in jit-recording.h.  */

gcc_jit_rvalue *
gcc_jit_lvalue_as_rvalue (gcc_jit_lvalue *lvalue)
{
  RETURN_NULL_IF_FAIL (lvalue, NULL, NULL, "NULL lvalue");

  return (gcc_jit_rvalue *)lvalue->as_rvalue ();
}

/* Public entrypoint.  See description in libgccjit.h.

   After error-checking, this calls the trivial
   gcc::jit::recording::memento::as_object method (an rvalue is a
   memento), in jit-recording.h.  */

gcc_jit_object *
gcc_jit_rvalue_as_object (gcc_jit_rvalue *rvalue)
{
  RETURN_NULL_IF_FAIL (rvalue, NULL, NULL, "NULL rvalue");

  return static_cast <gcc_jit_object *> (rvalue->as_object ());
}

/* Public entrypoint.  See description in libgccjit.h.

   After error-checking, the real work is done by the
   gcc::jit::recording::rvalue::get_type method, in
   jit-recording.h.  */

gcc_jit_type *
gcc_jit_rvalue_get_type (gcc_jit_rvalue *rvalue)
{
  RETURN_NULL_IF_FAIL (rvalue, NULL, NULL, "NULL rvalue");

  return static_cast <gcc_jit_type *> (rvalue->get_type ());
}

/* Verify that NUMERIC_TYPE is non-NULL, and that it is a "numeric"
   type i.e. it satisfies gcc::jit::type::is_numeric (), such as the
   result of gcc_jit_context_get_type (GCC_JIT_TYPE_INT).  */

#define RETURN_NULL_IF_FAIL_NONNULL_NUMERIC_TYPE(CTXT, NUMERIC_TYPE) \
  RETURN_NULL_IF_FAIL (NUMERIC_TYPE, CTXT, NULL, "NULL type"); \
  RETURN_NULL_IF_FAIL_PRINTF1 (                                \
    NUMERIC_TYPE->is_numeric (), ctxt, NULL,                   \
    "not a numeric type: %s",                                  \
    NUMERIC_TYPE->get_debug_string ());

/* Public entrypoint.  See description in libgccjit.h.

   After error-checking, the real work is done by the
   gcc::jit::recording::context::new_rvalue_from_int method in
   jit-recording.c.  */

gcc_jit_rvalue *
gcc_jit_context_new_rvalue_from_int (gcc_jit_context *ctxt,
				     gcc_jit_type *numeric_type,
				     int value)
{
  RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
  RETURN_NULL_IF_FAIL_NONNULL_NUMERIC_TYPE (ctxt, numeric_type);

  return (gcc_jit_rvalue *)ctxt->new_rvalue_from_int (numeric_type, value);
}

/* Public entrypoint.  See description in libgccjit.h.

   This is essentially equivalent to:
      gcc_jit_context_new_rvalue_from_int (ctxt, numeric_type, 0);
   albeit with slightly different error messages if an error occurs.  */

gcc_jit_rvalue *
gcc_jit_context_zero (gcc_jit_context *ctxt,
		      gcc_jit_type *numeric_type)
{
  RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
  RETURN_NULL_IF_FAIL_NONNULL_NUMERIC_TYPE (ctxt, numeric_type);

  return gcc_jit_context_new_rvalue_from_int (ctxt, numeric_type, 0);
}

/* Public entrypoint.  See description in libgccjit.h.

   This is essentially equivalent to:
      gcc_jit_context_new_rvalue_from_int (ctxt, numeric_type, 1);
   albeit with slightly different error messages if an error occurs.  */

gcc_jit_rvalue *
gcc_jit_context_one (gcc_jit_context *ctxt,
		     gcc_jit_type *numeric_type)
{
  RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
  RETURN_NULL_IF_FAIL_NONNULL_NUMERIC_TYPE (ctxt, numeric_type);

  return gcc_jit_context_new_rvalue_from_int (ctxt, numeric_type, 1);
}

/* Public entrypoint.  See description in libgccjit.h.

   After error-checking, the real work is done by the
   gcc::jit::recording::context::new_rvalue_from_double method in
   jit-recording.c.  */

gcc_jit_rvalue *
gcc_jit_context_new_rvalue_from_double (gcc_jit_context *ctxt,
					gcc_jit_type *numeric_type,
					double value)
{
  RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
  RETURN_NULL_IF_FAIL_NONNULL_NUMERIC_TYPE (ctxt, numeric_type);

  return (gcc_jit_rvalue *)ctxt->new_rvalue_from_double (numeric_type, value);
}

/* Public entrypoint.  See description in libgccjit.h.

   After error-checking, the real work is done by the
   gcc::jit::recording::context::new_rvalue_from_ptr method in
   jit-recording.c.  */

gcc_jit_rvalue *
gcc_jit_context_new_rvalue_from_ptr (gcc_jit_context *ctxt,
				     gcc_jit_type *pointer_type,
				     void *value)
{
  RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
  RETURN_NULL_IF_FAIL (pointer_type, ctxt, NULL, "NULL type");
  RETURN_NULL_IF_FAIL_PRINTF1 (
    pointer_type->is_pointer (),
    ctxt, NULL,
    "not a pointer type (type: %s)",
    pointer_type->get_debug_string ());

  return (gcc_jit_rvalue *)ctxt->new_rvalue_from_ptr (pointer_type, value);
}

/* Public entrypoint.  See description in libgccjit.h.

   This is essentially equivalent to:
      gcc_jit_context_new_rvalue_from_ptr (ctxt, pointer_type, NULL);
   albeit with slightly different error messages if an error occurs.  */

gcc_jit_rvalue *
gcc_jit_context_null (gcc_jit_context *ctxt,
		      gcc_jit_type *pointer_type)
{
  RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
  RETURN_NULL_IF_FAIL (pointer_type, ctxt, NULL, "NULL type");
  RETURN_NULL_IF_FAIL_PRINTF1 (
    pointer_type->is_pointer (),
    ctxt, NULL,
    "not a pointer type (type: %s)",
    pointer_type->get_debug_string ());

  return gcc_jit_context_new_rvalue_from_ptr (ctxt, pointer_type, NULL);
}

/* Public entrypoint.  See description in libgccjit.h.

   After error-checking, the real work is done by the
   gcc::jit::recording::context::new_string_literal method in
   jit-recording.c.  */

gcc_jit_rvalue *
gcc_jit_context_new_string_literal (gcc_jit_context *ctxt,
				    const char *value)
{
  RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
  RETURN_NULL_IF_FAIL (value, ctxt, NULL, "NULL value");

  return (gcc_jit_rvalue *)ctxt->new_string_literal (value);
}

/* Public entrypoint.  See description in libgccjit.h.

   After error-checking, the real work is done by the
   gcc::jit::recording::context::new_unary_op method in
   jit-recording.c.  */

gcc_jit_rvalue *
gcc_jit_context_new_unary_op (gcc_jit_context *ctxt,
			      gcc_jit_location *loc,
			      enum gcc_jit_unary_op op,
			      gcc_jit_type *result_type,
			      gcc_jit_rvalue *rvalue)
{
  RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL context");
  /* LOC can be NULL.  */
  RETURN_NULL_IF_FAIL_PRINTF1 (
    (op >= GCC_JIT_UNARY_OP_MINUS
     && op <= GCC_JIT_UNARY_OP_LOGICAL_NEGATE),
    ctxt, loc,
    "unrecognized value for enum gcc_jit_unary_op: %i",
    op);
  RETURN_NULL_IF_FAIL (result_type, ctxt, loc, "NULL result_type");
  RETURN_NULL_IF_FAIL (rvalue, ctxt, loc, "NULL rvalue");

  return (gcc_jit_rvalue *)ctxt->new_unary_op (loc, op, result_type, rvalue);
}

/* Determine if OP is a valid value for enum gcc_jit_binary_op.
   For use by both gcc_jit_context_new_binary_op and
   gcc_jit_block_add_assignment_op.  */

static bool
valid_binary_op_p (enum gcc_jit_binary_op op)
{
  return (op >= GCC_JIT_BINARY_OP_PLUS
	  && op <= GCC_JIT_BINARY_OP_RSHIFT);
}

/* Public entrypoint.  See description in libgccjit.h.

   After error-checking, the real work is done by the
   gcc::jit::recording::context::new_binary_op method in
   jit-recording.c.  */

gcc_jit_rvalue *
gcc_jit_context_new_binary_op (gcc_jit_context *ctxt,
			       gcc_jit_location *loc,
			       enum gcc_jit_binary_op op,
			       gcc_jit_type *result_type,
			       gcc_jit_rvalue *a, gcc_jit_rvalue *b)
{
  RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL context");
  /* LOC can be NULL.  */
  RETURN_NULL_IF_FAIL_PRINTF1 (
    valid_binary_op_p (op),
    ctxt, loc,
    "unrecognized value for enum gcc_jit_binary_op: %i",
    op);
  RETURN_NULL_IF_FAIL (result_type, ctxt, loc, "NULL result_type");
  RETURN_NULL_IF_FAIL (a, ctxt, loc, "NULL a");
  RETURN_NULL_IF_FAIL (b, ctxt, loc, "NULL b");
  RETURN_NULL_IF_FAIL_PRINTF4 (
    a->get_type () == b->get_type (),
    ctxt, loc,
    "mismatching types for binary op:"
    " a: %s (type: %s) b: %s (type: %s)",
    a->get_debug_string (),
    a->get_type ()->get_debug_string (),
    b->get_debug_string (),
    b->get_type ()->get_debug_string ());

  return (gcc_jit_rvalue *)ctxt->new_binary_op (loc, op, result_type, a, b);
}

/* Public entrypoint.  See description in libgccjit.h.

   After error-checking, the real work is done by the
   gcc::jit::recording::context::new_comparison method in
   jit-recording.c.  */

gcc_jit_rvalue *
gcc_jit_context_new_comparison (gcc_jit_context *ctxt,
				gcc_jit_location *loc,
				enum gcc_jit_comparison op,
				gcc_jit_rvalue *a, gcc_jit_rvalue *b)
{
  RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL context");
  /* LOC can be NULL.  */
  RETURN_NULL_IF_FAIL_PRINTF1 (
    (op >= GCC_JIT_COMPARISON_EQ
     && op <= GCC_JIT_COMPARISON_GE),
    ctxt, loc,
    "unrecognized value for enum gcc_jit_comparison: %i",
    op);
  RETURN_NULL_IF_FAIL (a, ctxt, loc, "NULL a");
  RETURN_NULL_IF_FAIL (b, ctxt, loc, "NULL b");
  RETURN_NULL_IF_FAIL_PRINTF4 (
    a->get_type ()->unqualified () == b->get_type ()->unqualified (),
    ctxt, loc,
    "mismatching types for comparison:"
    " a: %s (type: %s) b: %s (type: %s)",
    a->get_debug_string (),
    a->get_type ()->get_debug_string (),
    b->get_debug_string (),
    b->get_type ()->get_debug_string ());

  return (gcc_jit_rvalue *)ctxt->new_comparison (loc, op, a, b);
}

/* Public entrypoint.  See description in libgccjit.h.

   After error-checking, the real work is done by the
   gcc::jit::recording::context::new_call method in
   jit-recording.c.  */

gcc_jit_rvalue *
gcc_jit_context_new_call (gcc_jit_context *ctxt,
			  gcc_jit_location *loc,
			  gcc_jit_function *func,
			  int numargs , gcc_jit_rvalue **args)
{
  RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL context");
  /* LOC can be NULL.  */
  RETURN_NULL_IF_FAIL (func, ctxt, loc, "NULL function");
  if (numargs)
    RETURN_NULL_IF_FAIL (args, ctxt, loc, "NULL args");

  int min_num_params = func->get_params ().length ();
  bool is_variadic = func->is_variadic ();

  RETURN_NULL_IF_FAIL_PRINTF3 (
    numargs >= min_num_params,
    ctxt, loc,
    "not enough arguments to function \"%s\""
    " (got %i args, expected %i)",
    func->get_name ()->c_str (),
    numargs, min_num_params);

  RETURN_NULL_IF_FAIL_PRINTF3 (
    (numargs == min_num_params || is_variadic),
    ctxt, loc,
    "too many arguments to function \"%s\""
    " (got %i args, expected %i)",
    func->get_name ()->c_str (),
    numargs, min_num_params);

  for (int i = 0; i < min_num_params; i++)
    {
      gcc::jit::recording::param *param = func->get_param (i);
      gcc_jit_rvalue *arg = args[i];

      RETURN_NULL_IF_FAIL_PRINTF4 (
	arg,
	ctxt, loc,
	"NULL argument %i to function \"%s\":"
	" param %s (type: %s)",
	i + 1,
	func->get_name ()->c_str (),
	param->get_debug_string (),
	param->get_type ()->get_debug_string ());

      RETURN_NULL_IF_FAIL_PRINTF6 (
	compatible_types (param->get_type (),
			  arg->get_type ()),
	ctxt, loc,
	"mismatching types for argument %d of function \"%s\":"
	" assignment to param %s (type: %s) from %s (type: %s)",
	i + 1,
	func->get_name ()->c_str (),
	param->get_debug_string (),
	param->get_type ()->get_debug_string (),
	arg->get_debug_string (),
	arg->get_type ()->get_debug_string ());
    }

  return (gcc_jit_rvalue *)ctxt->new_call (loc,
					   func,
					   numargs,
					   (gcc::jit::recording::rvalue **)args);
}

/* Public entrypoint.  See description in libgccjit.h.

   After error-checking, the real work is done by the
   gcc::jit::recording::context::new_call_through_ptr method in
   jit-recording.c.  */

gcc_jit_rvalue *
gcc_jit_context_new_call_through_ptr (gcc_jit_context *ctxt,
				      gcc_jit_location *loc,
				      gcc_jit_rvalue *fn_ptr,
				      int numargs, gcc_jit_rvalue **args)
{
  RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL context");
  /* LOC can be NULL.  */
  RETURN_NULL_IF_FAIL (fn_ptr, ctxt, loc, "NULL fn_ptr");
  if (numargs)
    RETURN_NULL_IF_FAIL (args, ctxt, loc, "NULL args");

  gcc::jit::recording::type *ptr_type = fn_ptr->get_type ()->dereference ();
  RETURN_NULL_IF_FAIL_PRINTF2 (
    ptr_type, ctxt, loc,
    "fn_ptr is not a ptr: %s"
    " type: %s",
    fn_ptr->get_debug_string (),
    fn_ptr->get_type ()->get_debug_string ());

  gcc::jit::recording::function_type *fn_type =
    ptr_type->dyn_cast_function_type();
  RETURN_NULL_IF_FAIL_PRINTF2 (
    fn_type, ctxt, loc,
    "fn_ptr is not a function ptr: %s"
    " type: %s",
    fn_ptr->get_debug_string (),
    fn_ptr->get_type ()->get_debug_string ());

  int min_num_params = fn_type->get_param_types ().length ();
  bool is_variadic = fn_type->is_variadic ();

  RETURN_NULL_IF_FAIL_PRINTF3 (
    numargs >= min_num_params,
    ctxt, loc,
    "not enough arguments to fn_ptr: %s"
    " (got %i args, expected %i)",
    fn_ptr->get_debug_string (),
    numargs, min_num_params);

  RETURN_NULL_IF_FAIL_PRINTF3 (
    (numargs == min_num_params || is_variadic),
    ctxt, loc,
    "too many arguments to fn_ptr: %s"
    " (got %i args, expected %i)",
    fn_ptr->get_debug_string (),
    numargs, min_num_params);

  for (int i = 0; i < min_num_params; i++)
    {
      gcc::jit::recording::type *param_type = fn_type->get_param_types ()[i];
      gcc_jit_rvalue *arg = args[i];

      RETURN_NULL_IF_FAIL_PRINTF3 (
	arg,
	ctxt, loc,
	"NULL argument %i to fn_ptr: %s"
	" (type: %s)",
	i + 1,
	fn_ptr->get_debug_string (),
	param_type->get_debug_string ());

      RETURN_NULL_IF_FAIL_PRINTF6 (
	compatible_types (param_type,
			  arg->get_type ()),
	ctxt, loc,
	"mismatching types for argument %d of fn_ptr: %s:"
	" assignment to param %d (type: %s) from %s (type: %s)",
	i + 1,
	fn_ptr->get_debug_string (),
	i + 1,
	param_type->get_debug_string (),
	arg->get_debug_string (),
	arg->get_type ()->get_debug_string ());
    }

  return (gcc_jit_rvalue *)(
	    ctxt->new_call_through_ptr (loc,
					fn_ptr,
					numargs,
					(gcc::jit::recording::rvalue **)args));
}

/* Helper function for determining if we can cast an rvalue from SRC_TYPE
   to DST_TYPE, for use by gcc_jit_context_new_cast.

   We only permit these kinds of cast:

     int <-> float
     int <-> bool
     P*  <-> Q*   for pointer types P and Q.  */

static bool
is_valid_cast (gcc::jit::recording::type *src_type,
	       gcc_jit_type *dst_type)
{
  bool src_is_int = src_type->is_int ();
  bool dst_is_int = dst_type->is_int ();
  bool src_is_float = src_type->is_float ();
  bool dst_is_float = dst_type->is_float ();
  bool src_is_bool = src_type->is_bool ();
  bool dst_is_bool = dst_type->is_bool ();

  if (src_is_int)
    if (dst_is_int || dst_is_float || dst_is_bool)
      return true;

  if (src_is_float)
    if (dst_is_int || dst_is_float)
      return true;

  if (src_is_bool)
    if (dst_is_int || dst_is_bool)
      return true;

  /* Permit casts between pointer types.  */
  gcc::jit::recording::type *deref_src_type = src_type->is_pointer ();
  gcc::jit::recording::type *deref_dst_type = dst_type->is_pointer ();
  if (deref_src_type && deref_dst_type)
    return true;

  return false;
}

/* Public entrypoint.  See description in libgccjit.h.

   After error-checking, the real work is done by the
   gcc::jit::recording::context::new_cast method in jit-recording.c.  */

gcc_jit_rvalue *
gcc_jit_context_new_cast (gcc_jit_context *ctxt,
			  gcc_jit_location *loc,
			  gcc_jit_rvalue *rvalue,
			  gcc_jit_type *type)
{
  RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL context");
  /* LOC can be NULL.  */
  RETURN_NULL_IF_FAIL (rvalue, ctxt, loc, "NULL rvalue");
  RETURN_NULL_IF_FAIL (type, ctxt, loc, "NULL type");
  RETURN_NULL_IF_FAIL_PRINTF3 (
    is_valid_cast (rvalue->get_type (), type),
    ctxt, loc,
    "cannot cast %s from type: %s to type: %s",
    rvalue->get_debug_string (),
    rvalue->get_type ()->get_debug_string (),
    type->get_debug_string ());

  return static_cast <gcc_jit_rvalue *> (ctxt->new_cast (loc, rvalue, type));
}

/* Public entrypoint.  See description in libgccjit.h.

   After error-checking, the real work is done by the
   gcc::jit::recording::context::new_array_access method in
   jit-recording.c.  */

extern gcc_jit_lvalue *
gcc_jit_context_new_array_access (gcc_jit_context *ctxt,
				  gcc_jit_location *loc,
				  gcc_jit_rvalue *ptr,
				  gcc_jit_rvalue *index)
{
  RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL context");
  /* LOC can be NULL.  */
  RETURN_NULL_IF_FAIL (ptr, ctxt, loc, "NULL ptr");
  RETURN_NULL_IF_FAIL (index, ctxt, loc, "NULL index");
  RETURN_NULL_IF_FAIL_PRINTF2 (
    ptr->get_type ()->dereference (),
    ctxt, loc,
    "ptr: %s (type: %s) is not a pointer or array",
    ptr->get_debug_string (),
    ptr->get_type ()->get_debug_string ());
  RETURN_NULL_IF_FAIL_PRINTF2 (
    index->get_type ()->is_numeric (),
    ctxt, loc,
    "index: %s (type: %s) is not of numeric type",
    index->get_debug_string (),
    index->get_type ()->get_debug_string ());

  return (gcc_jit_lvalue *)ctxt->new_array_access (loc, ptr, index);
}

/* Public entrypoint.  See description in libgccjit.h.

   After error-checking, the real work is done by the
   gcc::jit::recording::memento::get_context method in
   jit-recording.h.  */

gcc_jit_context *
gcc_jit_object_get_context (gcc_jit_object *obj)
{
  RETURN_NULL_IF_FAIL (obj, NULL, NULL, "NULL object");

  return static_cast <gcc_jit_context *> (obj->get_context ());
}

/* Public entrypoint.  See description in libgccjit.h.

   After error-checking, the real work is done by the
   gcc::jit::recording::memento::get_debug_string method in
   jit-recording.c.  */

const char *
gcc_jit_object_get_debug_string (gcc_jit_object *obj)
{
  RETURN_NULL_IF_FAIL (obj, NULL, NULL, "NULL object");

  return obj->get_debug_string ();
}

/* Public entrypoint.  See description in libgccjit.h.

   After error-checking, the real work is done by the
   gcc::jit::recording::lvalue::access_field method in
   jit-recording.c.  */

gcc_jit_lvalue *
gcc_jit_lvalue_access_field (gcc_jit_lvalue *struct_,
			     gcc_jit_location *loc,
			     gcc_jit_field *field)
{
  RETURN_NULL_IF_FAIL (struct_, NULL, loc, "NULL struct");
  /* LOC can be NULL.  */
  gcc::jit::recording::context *ctxt = struct_->m_ctxt;
  RETURN_NULL_IF_FAIL (field, ctxt, loc, "NULL field");
  RETURN_NULL_IF_FAIL_PRINTF1 (field->get_container (), field->m_ctxt, loc,
			       "field %s has not been placed in a struct",
			       field->get_debug_string ());

  return (gcc_jit_lvalue *)struct_->access_field (loc, field);
}

/* Public entrypoint.  See description in libgccjit.h.

   After error-checking, the real work is done by the
   gcc::jit::recording::rvalue::access_field method in
   jit-recording.c.  */

gcc_jit_rvalue *
gcc_jit_rvalue_access_field (gcc_jit_rvalue *struct_,
			     gcc_jit_location *loc,
			     gcc_jit_field *field)
{
  RETURN_NULL_IF_FAIL (struct_, NULL, loc, "NULL struct");
  /* LOC can be NULL.  */
  gcc::jit::recording::context *ctxt = struct_->m_ctxt;
  RETURN_NULL_IF_FAIL (field, ctxt, loc, "NULL field");
  RETURN_NULL_IF_FAIL_PRINTF1 (field->get_container (), field->m_ctxt, loc,
			       "field %s has not been placed in a struct",
			       field->get_debug_string ());

  return (gcc_jit_rvalue *)struct_->access_field (loc, field);
}

/* Public entrypoint.  See description in libgccjit.h.

   After error-checking, the real work is done by the
   gcc::jit::recording::rvalue::deference_field method in
   jit-recording.c.  */

gcc_jit_lvalue *
gcc_jit_rvalue_dereference_field (gcc_jit_rvalue *ptr,
				  gcc_jit_location *loc,
				  gcc_jit_field *field)
{
  RETURN_NULL_IF_FAIL (ptr, NULL, loc, "NULL ptr");
  /* LOC can be NULL.  */
  RETURN_NULL_IF_FAIL (field, NULL, loc, "NULL field");
  gcc::jit::recording::type *underlying_type =
    ptr->get_type ()->is_pointer ();
  RETURN_NULL_IF_FAIL_PRINTF1 (field->get_container (), field->m_ctxt, loc,
			       "field %s has not been placed in a struct",
			       field->get_debug_string ());
  RETURN_NULL_IF_FAIL_PRINTF3 (
    underlying_type,
    ptr->m_ctxt, loc,
    "dereference of non-pointer %s (type: %s) when accessing ->%s",
    ptr->get_debug_string (),
    ptr->get_type ()->get_debug_string (),
    field->get_debug_string ());
  RETURN_NULL_IF_FAIL_PRINTF2 (
    (field->get_container ()->unqualified ()
     == underlying_type->unqualified ()),
    ptr->m_ctxt, loc,
    "%s is not a field of %s",
    field->get_debug_string (),
    underlying_type->get_debug_string ());

  return (gcc_jit_lvalue *)ptr->dereference_field (loc, field);
}

/* Public entrypoint.  See description in libgccjit.h.

   After error-checking, the real work is done by the
   gcc::jit::recording::rvalue::deference method in
   jit-recording.c.  */

gcc_jit_lvalue *
gcc_jit_rvalue_dereference (gcc_jit_rvalue *rvalue,
			    gcc_jit_location *loc)
{
  RETURN_NULL_IF_FAIL (rvalue, NULL, loc, "NULL rvalue");
  /* LOC can be NULL.  */

  gcc::jit::recording::type *underlying_type =
    rvalue->get_type ()->is_pointer ();

  RETURN_NULL_IF_FAIL_PRINTF2 (
    underlying_type,
    rvalue->m_ctxt, loc,
    "dereference of non-pointer %s (type: %s)",
    rvalue->get_debug_string (),
    rvalue->get_type ()->get_debug_string ());

  return (gcc_jit_lvalue *)rvalue->dereference (loc);
}

/* Public entrypoint.  See description in libgccjit.h.

   After error-checking, the real work is done by the
   gcc::jit::recording::lvalue::get_address method in jit-recording.c.  */

gcc_jit_rvalue *
gcc_jit_lvalue_get_address (gcc_jit_lvalue *lvalue,
			    gcc_jit_location *loc)
{
  RETURN_NULL_IF_FAIL (lvalue, NULL, loc, "NULL lvalue");
  /* LOC can be NULL.  */

  return (gcc_jit_rvalue *)lvalue->get_address (loc);
}

/* Public entrypoint.  See description in libgccjit.h.

   After error-checking, the real work is done by the
   gcc::jit::recording::function::new_local method in jit-recording.c.  */

gcc_jit_lvalue *
gcc_jit_function_new_local (gcc_jit_function *func,
			    gcc_jit_location *loc,
			    gcc_jit_type *type,
			    const char *name)
{
  RETURN_NULL_IF_FAIL (func, NULL, loc, "NULL function");
  /* LOC can be NULL.  */
  gcc::jit::recording::context *ctxt = func->m_ctxt;
  RETURN_NULL_IF_FAIL (func->get_kind () != GCC_JIT_FUNCTION_IMPORTED,
		       ctxt, loc,
		       "Cannot add locals to an imported function");
  RETURN_NULL_IF_FAIL (type, ctxt, loc, "NULL type");
  RETURN_NULL_IF_FAIL (name, ctxt, loc, "NULL name");

  return (gcc_jit_lvalue *)func->new_local (loc, type, name);
}

/* Public entrypoint.  See description in libgccjit.h.

   After error-checking, the real work is done by the
   gcc::jit::recording::block::add_eval method in jit-recording.c.  */

void
gcc_jit_block_add_eval (gcc_jit_block *block,
			gcc_jit_location *loc,
			gcc_jit_rvalue *rvalue)
{
  RETURN_IF_NOT_VALID_BLOCK (block, loc);
  /* LOC can be NULL.  */
  gcc::jit::recording::context *ctxt = block->get_context ();
  RETURN_IF_FAIL (rvalue, ctxt, loc, "NULL rvalue");

  return block->add_eval (loc, rvalue);
}

/* Public entrypoint.  See description in libgccjit.h.

   After error-checking, the real work is done by the
   gcc::jit::recording::block::add_assignment method in
   jit-recording.c.  */

void
gcc_jit_block_add_assignment (gcc_jit_block *block,
			      gcc_jit_location *loc,
			      gcc_jit_lvalue *lvalue,
			      gcc_jit_rvalue *rvalue)
{
  RETURN_IF_NOT_VALID_BLOCK (block, loc);
  /* LOC can be NULL.  */
  gcc::jit::recording::context *ctxt = block->get_context ();
  RETURN_IF_FAIL (lvalue, ctxt, loc, "NULL lvalue");
  RETURN_IF_FAIL (rvalue, ctxt, loc, "NULL rvalue");
  RETURN_IF_FAIL_PRINTF4 (
    compatible_types (lvalue->get_type (),
		      rvalue->get_type ()),
    ctxt, loc,
    "mismatching types:"
    " assignment to %s (type: %s) from %s (type: %s)",
    lvalue->get_debug_string (),
    lvalue->get_type ()->get_debug_string (),
    rvalue->get_debug_string (),
    rvalue->get_type ()->get_debug_string ());

  return block->add_assignment (loc, lvalue, rvalue);
}

/* Public entrypoint.  See description in libgccjit.h.

   After error-checking, the real work is done by the
   gcc::jit::recording::block::add_assignment_op method in
   jit-recording.c.  */

void
gcc_jit_block_add_assignment_op (gcc_jit_block *block,
				 gcc_jit_location *loc,
				 gcc_jit_lvalue *lvalue,
				 enum gcc_jit_binary_op op,
				 gcc_jit_rvalue *rvalue)
{
  RETURN_IF_NOT_VALID_BLOCK (block, loc);
  /* LOC can be NULL.  */
  gcc::jit::recording::context *ctxt = block->get_context ();
  RETURN_IF_FAIL (lvalue, ctxt, loc, "NULL lvalue");
  RETURN_IF_FAIL_PRINTF1 (
    valid_binary_op_p (op),
    ctxt, loc,
    "unrecognized value for enum gcc_jit_binary_op: %i",
    op);
  RETURN_IF_FAIL (rvalue, ctxt, loc, "NULL rvalue");

  return block->add_assignment_op (loc, lvalue, op, rvalue);
}

/* Internal helper function for determining if rvalue BOOLVAL is of
   boolean type.  For use by gcc_jit_block_end_with_conditional.  */

static bool
is_bool (gcc_jit_rvalue *boolval)
{
  gcc::jit::recording::type *actual_type = boolval->get_type ();
  gcc::jit::recording::type *bool_type =
    boolval->m_ctxt->get_type (GCC_JIT_TYPE_BOOL);
  return actual_type == bool_type;
}

/* Public entrypoint.  See description in libgccjit.h.

   After error-checking, the real work is done by the
   gcc::jit::recording::block::end_with_conditional method in
   jit-recording.c.  */

void
gcc_jit_block_end_with_conditional (gcc_jit_block *block,
				    gcc_jit_location *loc,
				    gcc_jit_rvalue *boolval,
				    gcc_jit_block *on_true,
				    gcc_jit_block *on_false)
{
  RETURN_IF_NOT_VALID_BLOCK (block, loc);
  /* LOC can be NULL.  */
  gcc::jit::recording::context *ctxt = block->get_context ();
  RETURN_IF_FAIL (boolval, ctxt, loc, "NULL boolval");
  RETURN_IF_FAIL_PRINTF2 (
   is_bool (boolval), ctxt, loc,
   "%s (type: %s) is not of boolean type ",
   boolval->get_debug_string (),
   boolval->get_type ()->get_debug_string ());
  RETURN_IF_FAIL (on_true, ctxt, loc, "NULL on_true");
  RETURN_IF_FAIL (on_true, ctxt, loc, "NULL on_false");
  RETURN_IF_FAIL_PRINTF4 (
    block->get_function () == on_true->get_function (),
    ctxt, loc,
    "\"on_true\" block is not in same function:"
    " source block %s is in function %s"
    " whereas target block %s is in function %s",
    block->get_debug_string (),
    block->get_function ()->get_debug_string (),
    on_true->get_debug_string (),
    on_true->get_function ()->get_debug_string ());
  RETURN_IF_FAIL_PRINTF4 (
    block->get_function () == on_false->get_function (),
    ctxt, loc,
    "\"on_false\" block is not in same function:"
    " source block %s is in function %s"
    " whereas target block %s is in function %s",
    block->get_debug_string (),
    block->get_function ()->get_debug_string (),
    on_false->get_debug_string (),
    on_false->get_function ()->get_debug_string ());

  return block->end_with_conditional (loc, boolval, on_true, on_false);
}

/* Public entrypoint.  See description in libgccjit.h.

   After error-checking, the real work is done by the
   gcc::jit::recording::block::add_comment method in
   jit-recording.c.  */

void
gcc_jit_block_add_comment (gcc_jit_block *block,
			   gcc_jit_location *loc,
			   const char *text)
{
  RETURN_IF_NOT_VALID_BLOCK (block, loc);
  /* LOC can be NULL.  */
  gcc::jit::recording::context *ctxt = block->get_context ();
  RETURN_IF_FAIL (text, ctxt, loc, "NULL text");

  block->add_comment (loc, text);
}

/* Public entrypoint.  See description in libgccjit.h.

   After error-checking, the real work is done by the
   gcc::jit::recording::block::end_with_jump method in
   jit-recording.c.  */

void
gcc_jit_block_end_with_jump (gcc_jit_block *block,
			     gcc_jit_location *loc,
			     gcc_jit_block *target)
{
  RETURN_IF_NOT_VALID_BLOCK (block, loc);
  /* LOC can be NULL.  */
  gcc::jit::recording::context *ctxt = block->get_context ();
  RETURN_IF_FAIL (target, ctxt, loc, "NULL target");
  RETURN_IF_FAIL_PRINTF4 (
    block->get_function () == target->get_function (),
    ctxt, loc,
    "target block is not in same function:"
    " source block %s is in function %s"
    " whereas target block %s is in function %s",
    block->get_debug_string (),
    block->get_function ()->get_debug_string (),
    target->get_debug_string (),
    target->get_function ()->get_debug_string ());

  block->end_with_jump (loc, target);
}

/* Public entrypoint.  See description in libgccjit.h.

   After error-checking, the real work is done by the
   gcc::jit::recording::block::end_with_return method in
   jit-recording.c.  */

void
gcc_jit_block_end_with_return (gcc_jit_block *block,
			       gcc_jit_location *loc,
			       gcc_jit_rvalue *rvalue)
{
  RETURN_IF_NOT_VALID_BLOCK (block, loc);
  /* LOC can be NULL.  */
  gcc::jit::recording::context *ctxt = block->get_context ();
  gcc::jit::recording::function *func = block->get_function ();
  RETURN_IF_FAIL (rvalue, ctxt, loc, "NULL rvalue");
  RETURN_IF_FAIL_PRINTF4 (
    compatible_types (
      func->get_return_type (),
      rvalue->get_type ()),
    ctxt, loc,
    "mismatching types:"
    " return of %s (type: %s) in function %s (return type: %s)",
    rvalue->get_debug_string (),
    rvalue->get_type ()->get_debug_string (),
    func->get_debug_string (),
    func->get_return_type ()->get_debug_string ());

  return block->end_with_return (loc, rvalue);
}

/* Public entrypoint.  See description in libgccjit.h.

   After error-checking, the real work is done by the
   gcc::jit::recording::block::end_with_return method in
   jit-recording.c.  */

void
gcc_jit_block_end_with_void_return (gcc_jit_block *block,
				    gcc_jit_location *loc)
{
  RETURN_IF_NOT_VALID_BLOCK (block, loc);
  /* LOC can be NULL.  */
  gcc::jit::recording::context *ctxt = block->get_context ();
  gcc::jit::recording::function *func = block->get_function ();
  RETURN_IF_FAIL_PRINTF2 (
    func->get_return_type () == ctxt->get_type (GCC_JIT_TYPE_VOID),
    ctxt, loc,
    "mismatching types:"
    " void return in function %s (return type: %s)",
    func->get_debug_string (),
    func->get_return_type ()->get_debug_string ());

  return block->end_with_return (loc, NULL);
}

/**********************************************************************
 Option-management
 **********************************************************************/

/* Public entrypoint.  See description in libgccjit.h.

   After error-checking, the real work is done by the
   gcc::jit::recording::context::set_str_option method in
   jit-recording.c.  */

void
gcc_jit_context_set_str_option (gcc_jit_context *ctxt,
				enum gcc_jit_str_option opt,
				const char *value)
{
  RETURN_IF_FAIL (ctxt, NULL, NULL, "NULL context");
  /* opt is checked by the inner function.
     value can be NULL.  */

  ctxt->set_str_option (opt, value);
}

/* Public entrypoint.  See description in libgccjit.h.

   After error-checking, the real work is done by the
   gcc::jit::recording::context::set_int_option method in
   jit-recording.c.  */

void
gcc_jit_context_set_int_option (gcc_jit_context *ctxt,
				enum gcc_jit_int_option opt,
				int value)
{
  RETURN_IF_FAIL (ctxt, NULL, NULL, "NULL context");
  /* opt is checked by the inner function.  */

  ctxt->set_int_option (opt, value);
}

/* Public entrypoint.  See description in libgccjit.h.

   After error-checking, the real work is done by the
   gcc::jit::recording::context::set_bool_option method in
   jit-recording.c.  */

void
gcc_jit_context_set_bool_option (gcc_jit_context *ctxt,
				 enum gcc_jit_bool_option opt,
				 int value)
{
  RETURN_IF_FAIL (ctxt, NULL, NULL, "NULL context");
  /* opt is checked by the inner function.  */

  ctxt->set_bool_option (opt, value);
}

/* Public entrypoint.  See description in libgccjit.h.

   After error-checking, the real work is done by the
   gcc::jit::recording::context::compile method in
   jit-recording.c.  */

gcc_jit_result *
gcc_jit_context_compile (gcc_jit_context *ctxt)
{
  RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");

  return (gcc_jit_result *)ctxt->compile ();
}

/* Public entrypoint.  See description in libgccjit.h.

   After error-checking, the real work is done by the
   gcc::jit::recording::context::dump_to_file method in
   jit-recording.c.  */

void
gcc_jit_context_dump_to_file (gcc_jit_context *ctxt,
			      const char *path,
			      int update_locations)
{
  RETURN_IF_FAIL (ctxt, NULL, NULL, "NULL context");
  RETURN_IF_FAIL (path, ctxt, NULL, "NULL path");
  ctxt->dump_to_file (path, update_locations);
}

/* Public entrypoint.  See description in libgccjit.h.

   After error-checking, the real work is done by the
   gcc::jit::recording::context::get_first_error method in
   jit-recording.c.  */

const char *
gcc_jit_context_get_first_error (gcc_jit_context *ctxt)
{
  RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");

  return ctxt->get_first_error ();
}

/* Public entrypoint.  See description in libgccjit.h.

   After error-checking, the real work is done by the
   gcc::jit::playback::result::get_code method in
   jit-playback.c.  */

void *
gcc_jit_result_get_code (gcc_jit_result *result,
			 const char *fnname)
{
  RETURN_NULL_IF_FAIL (result, NULL, NULL, "NULL result");
  RETURN_NULL_IF_FAIL (fnname, NULL, NULL, "NULL fnname");

  return result->get_code (fnname);
}

/* Public entrypoint.  See description in libgccjit.h.

   After error-checking, this is essentially a wrapper around the
   destructor for gcc::jit::playback::result in jit-playback.c.  */

void
gcc_jit_result_release (gcc_jit_result *result)
{
  RETURN_IF_FAIL (result, NULL, NULL, "NULL result");

  delete result;
}

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

* Re: [jit] Use ISALPHA and ISALNUM rather than writing our own
  2014-11-05 15:52         ` [jit] Use ISALPHA and ISALNUM rather than writing our own David Malcolm
@ 2014-11-05 20:02           ` Jeff Law
  0 siblings, 0 replies; 71+ messages in thread
From: Jeff Law @ 2014-11-05 20:02 UTC (permalink / raw)
  To: David Malcolm; +Cc: gcc-patches, jit

On 11/05/14 08:48, David Malcolm wrote:
> On Tue, 2014-11-04 at 14:39 -0700, Jeff Law wrote:
>> On 11/04/14 09:57, David Malcolm wrote:
>>>>> +#define IS_ASCII_DIGIT(CHAR) \
>>>>> +  ((CHAR) >= '0' && (CHAR) <='9')
>>>>> +
>>>>> +#define IS_ASCII_ALNUM(CHAR) \
>>>>> +  (IS_ASCII_ALPHA (CHAR) || IS_ASCII_DIGIT (CHAR))
>>>> Can't we rely on the C library to give us equivalents?
>>>
>>> I've been burned in the past by the C library using locales, in
>>> particular the two lowercase "i" variants in Turkish.
>>>
>>> These macros are used by gcc_jit_context_new_function to enforce C's
>>> naming restrictions, to avoid errors from the assembler.  The comment I
>>> put there was:
>>>
>>>     /* The assembler can only handle certain names, so for now, enforce
>>>        C's rules for identifiers upon the name.
>>>        Eventually we'll need some way to interact with e.g. C++ name mangling.  */
>>>
>>> Am I right in thinking that for the assembler we need to enforce the C
>>> naming rules specifically on *ASCII*.
>>>
>>> (clearly another comment is needed here).
>> I guess you've got to do it somewhere.  Presumably there isn't something
>> already in GCC that enforces an input character set?  I guess I just
>> dislike seeing something that feels like it ought to already be available.
>
> It turns out that locale-independent tests for this did already exist in
> libiberty, in safe-ctype.h, so I've committed this to the jit branch:
>
> gcc/jit/ChangeLog.jit:
> 	* libgccjit.c: Include safe-ctype.h from libiberty.
> 	(IS_ASCII_ALPHA): Delete.
> 	(IS_ASCII_DIGIT): Delete.
> 	(IS_ASCII_ALNUM): Delete.
> 	(gcc_jit_context_new_function): Replace use of IS_ASCII_ALPHA and
> 	IS_ASCII_ALNUM with ISALPHA and ISALNUM respectively, from
> 	libiberty.
Excellent.  Thanks for the cleanup.

Jeff

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

* [jit] Drop the disabled debugging code within handle_locations
  2014-11-04 22:21   ` Jeff Law
@ 2014-11-05 20:23     ` David Malcolm
  0 siblings, 0 replies; 71+ messages in thread
From: David Malcolm @ 2014-11-05 20:23 UTC (permalink / raw)
  To: Jeff Law; +Cc: gcc-patches, jit, David Malcolm

On Tue, 2014-11-04 at 15:21 -0700, Jeff Law wrote:
> On 10/31/14 11:02, David Malcolm wrote:
> > This files implements the gcc::jit::playback internal API, called by
> > the dummy "frontend" to replay the public API calls made to the
> > library.  A thin wrapper around trees.
> >
> > gcc/jit/
> >     * jit-playback.c: New.
> 
> 
> > +  /* line_table should now be populated; every playback::location should
> > +     now have an m_srcloc.  */
> > +
> > +  if (0)
> > +    line_table_dump (stderr,
> > +                         line_table,
> > +                                LINEMAPS_ORDINARY_USED (line_table),
> > +                                                            LINEMAPS_MACRO_USED (line_table));
> > +
> > +  /* Now assign them to tree nodes as appropriate.  */
> > +  std::pair<tree, location *> *cached_location;
> > +
> > +  FOR_EACH_VEC_ELT (m_cached_locations, i, cached_location)
> > +    {
> > +      tree t = cached_location->first;
> > +      source_location srcloc = cached_location->second->m_srcloc;
> > +#if 0
> > +      inform (srcloc, "location of ");
> > +      debug_tree (t);
> > +#endif
> Put the if () #if0 under some kind of debugging control or remove them. 
>   Similarly for later instances.
> 
> With that change, this is good for the trunk.

Thanks.  I removed them in the following commit (on the branch):

gcc/jit/ChangeLog.jit:
	* jit-playback.c (gcc::jit::playback::context::handle_locations):
	Drop the disabled debugging code.
---
 gcc/jit/ChangeLog.jit  |  5 +++++
 gcc/jit/jit-playback.c | 16 ----------------
 2 files changed, 5 insertions(+), 16 deletions(-)

diff --git a/gcc/jit/ChangeLog.jit b/gcc/jit/ChangeLog.jit
index 8de64ac..6212b53 100644
--- a/gcc/jit/ChangeLog.jit
+++ b/gcc/jit/ChangeLog.jit
@@ -1,5 +1,10 @@
 2014-11-05  David Malcolm  <dmalcolm@redhat.com>
 
+	* jit-playback.c (gcc::jit::playback::context::handle_locations):
+	Drop the disabled debugging code.
+
+2014-11-05  David Malcolm  <dmalcolm@redhat.com>
+
 	* docs/topics/expressions.rst (Type-coercion): Casts between
 	pointer types are valid.
 	* libgccjit.c: Document that gcc_jit_context et al are actually
diff --git a/gcc/jit/jit-playback.c b/gcc/jit/jit-playback.c
index dc1b468..1dbb778 100644
--- a/gcc/jit/jit-playback.c
+++ b/gcc/jit/jit-playback.c
@@ -1858,12 +1858,6 @@ handle_locations ()
   /* line_table should now be populated; every playback::location should
      now have an m_srcloc.  */
 
-  if (0)
-    line_table_dump (stderr,
-		     line_table,
-		     LINEMAPS_ORDINARY_USED (line_table),
-		     LINEMAPS_MACRO_USED (line_table));
-
   /* Now assign them to tree nodes as appropriate.  */
   std::pair<tree, location *> *cached_location;
 
@@ -1871,10 +1865,6 @@ handle_locations ()
     {
       tree t = cached_location->first;
       source_location srcloc = cached_location->second->m_srcloc;
-#if 0
-      inform (srcloc, "location of ");
-      debug_tree (t);
-#endif
 
       /* This covers expressions: */
       if (CAN_HAVE_LOCATION_P (t))
@@ -1884,12 +1874,6 @@ handle_locations ()
       else
 	{
 	  /* Don't know how to set location on this node.  */
-	  if (0)
-	    {
-	      fprintf (stderr, "can't set location on:");
-	      debug_tree (t);
-	      fprintf (stderr, "\n");
-	    }
 	}
     }
 }
-- 
1.7.11.7

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

* [PATCH 3/3] Add comments to various functions in libgccjit.h
  2014-11-05 20:47 ` [PATCH 0/3] Minor tweaks to jit David Malcolm
  2014-11-05 20:47   ` [PATCH 1/3] New test cases David Malcolm
  2014-11-05 20:47   ` [PATCH 2/3] Documentation tweak David Malcolm
@ 2014-11-05 20:47   ` David Malcolm
  2014-11-06 23:51   ` [PATCH 0/3] Minor tweaks to jit Jeff Law
  3 siblings, 0 replies; 71+ messages in thread
From: David Malcolm @ 2014-11-05 20:47 UTC (permalink / raw)
  To: Jeff Law; +Cc: gcc-patches, jit, David Malcolm

---
 gcc/jit/libgccjit.h | 21 +++++++++++++++------
 1 file changed, 15 insertions(+), 6 deletions(-)

diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h
index 8e03412..e07002d 100644
--- a/gcc/jit/libgccjit.h
+++ b/gcc/jit/libgccjit.h
@@ -123,11 +123,7 @@ typedef struct gcc_jit_lvalue gcc_jit_lvalue;
    rvalue); use gcc_jit_param_as_lvalue to convert.  */
 typedef struct gcc_jit_param gcc_jit_param;
 
-/*
-   Acquire a JIT-compilation context.
-
-   FIXME: error-handling?
-*/
+/* Acquire a JIT-compilation context.  */
 extern gcc_jit_context *
 gcc_jit_context_acquire (void);
 
@@ -393,6 +389,7 @@ extern gcc_jit_type *
 gcc_jit_context_get_type (gcc_jit_context *ctxt,
 			  enum gcc_jit_types type_);
 
+/* Get the integer type of the given size and signedness.  */
 extern gcc_jit_type *
 gcc_jit_context_get_int_type (gcc_jit_context *ctxt,
 			      int num_bytes, int is_signed);
@@ -419,6 +416,8 @@ gcc_jit_context_new_array_type (gcc_jit_context *ctxt,
 				int num_elements);
 
 /* Struct-handling.  */
+
+/* Create a field, for use within a struct or union.  */
 extern gcc_jit_field *
 gcc_jit_context_new_field (gcc_jit_context *ctxt,
 			   gcc_jit_location *loc,
@@ -429,6 +428,7 @@ gcc_jit_context_new_field (gcc_jit_context *ctxt,
 extern gcc_jit_object *
 gcc_jit_field_as_object (gcc_jit_field *field);
 
+/* Create a struct type from an array of fields.  */
 extern gcc_jit_struct *
 gcc_jit_context_new_struct_type (gcc_jit_context *ctxt,
 				 gcc_jit_location *loc,
@@ -436,11 +436,13 @@ gcc_jit_context_new_struct_type (gcc_jit_context *ctxt,
 				 int num_fields,
 				 gcc_jit_field **fields);
 
+/* Create an opaque struct type.  */
 extern gcc_jit_struct *
 gcc_jit_context_new_opaque_struct (gcc_jit_context *ctxt,
 				   gcc_jit_location *loc,
 				   const char *name);
 
+/* Upcast a struct to a type.  */
 extern gcc_jit_type *
 gcc_jit_struct_as_type (gcc_jit_struct *struct_type);
 
@@ -473,6 +475,7 @@ gcc_jit_context_new_function_ptr_type (gcc_jit_context *ctxt,
 /**********************************************************************
  Constructing functions.
  **********************************************************************/
+/* Create a function param.  */
 extern gcc_jit_param *
 gcc_jit_context_new_param (gcc_jit_context *ctxt,
 			   gcc_jit_location *loc,
@@ -483,12 +486,15 @@ gcc_jit_context_new_param (gcc_jit_context *ctxt,
 extern gcc_jit_object *
 gcc_jit_param_as_object (gcc_jit_param *param);
 
+/* Upcasting from param to lvalue.  */
 extern gcc_jit_lvalue *
 gcc_jit_param_as_lvalue (gcc_jit_param *param);
 
+/* Upcasting from param to rvalue.  */
 extern gcc_jit_rvalue *
 gcc_jit_param_as_rvalue (gcc_jit_param *param);
 
+/* Kinds of function.  */
 enum gcc_jit_function_kind
 {
   /* Function is defined by the client code and visible
@@ -516,7 +522,7 @@ enum gcc_jit_function_kind
   GCC_JIT_FUNCTION_ALWAYS_INLINE
 };
 
-
+/* Create a function.  */
 extern gcc_jit_function *
 gcc_jit_context_new_function (gcc_jit_context *ctxt,
 			      gcc_jit_location *loc,
@@ -527,6 +533,8 @@ gcc_jit_context_new_function (gcc_jit_context *ctxt,
 			      gcc_jit_param **params,
 			      int is_variadic);
 
+/* Create a reference to a builtin function (sometimes called
+   intrinsic functions).  */
 extern gcc_jit_function *
 gcc_jit_context_get_builtin_function (gcc_jit_context *ctxt,
 				      const char *name);
@@ -535,6 +543,7 @@ gcc_jit_context_get_builtin_function (gcc_jit_context *ctxt,
 extern gcc_jit_object *
 gcc_jit_function_as_object (gcc_jit_function *func);
 
+/* Get a specific param of a function by index.  */
 extern gcc_jit_param *
 gcc_jit_function_get_param (gcc_jit_function *func, int index);
 
-- 
1.8.5.3

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

* [PATCH 0/3] Minor tweaks to jit
  2014-10-31 17:07 [PATCH 00/27] Merger of jit branch v3 David Malcolm
                   ` (24 preceding siblings ...)
  2014-10-31 21:17 ` [PATCH 00/27] Merger of jit branch v3 Jeff Law
@ 2014-11-05 20:47 ` David Malcolm
  2014-11-05 20:47   ` [PATCH 1/3] New test cases David Malcolm
                     ` (3 more replies)
  25 siblings, 4 replies; 71+ messages in thread
From: David Malcolm @ 2014-11-05 20:47 UTC (permalink / raw)
  To: Jeff Law; +Cc: gcc-patches, jit, David Malcolm

Here are some minor tweaks I've made on the JIT branch since v3 of
the review began.

Are the following OK for trunk, assuming the rest of the JIT work
is approved?

David Malcolm (3):
  New test cases
  Documentation tweak
  Add comments to various functions in libgccjit.h

 gcc/jit/docs/topics/expressions.rst                |  1 +
 gcc/jit/libgccjit.h                                | 21 +++++++----
 .../jit.dg/test-error-get-type-bad-enum.c          | 27 ++++++++++++++
 .../jit.dg/test-error-new-binary-op-bad-op.c       | 37 +++++++++++++++++++
 .../jit.dg/test-error-new-function-bad-kind.c      | 41 ++++++++++++++++++++++
 .../jit.dg/test-error-new-unary-op-bad-op.c        | 36 +++++++++++++++++++
 6 files changed, 157 insertions(+), 6 deletions(-)
 create mode 100644 gcc/testsuite/jit.dg/test-error-get-type-bad-enum.c
 create mode 100644 gcc/testsuite/jit.dg/test-error-new-binary-op-bad-op.c
 create mode 100644 gcc/testsuite/jit.dg/test-error-new-function-bad-kind.c
 create mode 100644 gcc/testsuite/jit.dg/test-error-new-unary-op-bad-op.c

-- 
1.8.5.3

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

* [PATCH 1/3] New test cases
  2014-11-05 20:47 ` [PATCH 0/3] Minor tweaks to jit David Malcolm
@ 2014-11-05 20:47   ` David Malcolm
  2014-11-05 20:47   ` [PATCH 2/3] Documentation tweak David Malcolm
                     ` (2 subsequent siblings)
  3 siblings, 0 replies; 71+ messages in thread
From: David Malcolm @ 2014-11-05 20:47 UTC (permalink / raw)
  To: Jeff Law; +Cc: gcc-patches, jit, David Malcolm

gcc/testsuite:
	* jit.dg/test-error-get-type-bad-enum.c: New.
	* jit.dg/test-error-new-binary-op-bad-op.c: New.
	* jit.dg/test-error-new-function-bad-kind.c: New.
	* jit.dg/test-error-new-unary-op-bad-op.c: New.
---
 .../jit.dg/test-error-get-type-bad-enum.c          | 27 ++++++++++++++
 .../jit.dg/test-error-new-binary-op-bad-op.c       | 37 +++++++++++++++++++
 .../jit.dg/test-error-new-function-bad-kind.c      | 41 ++++++++++++++++++++++
 .../jit.dg/test-error-new-unary-op-bad-op.c        | 36 +++++++++++++++++++
 4 files changed, 141 insertions(+)
 create mode 100644 gcc/testsuite/jit.dg/test-error-get-type-bad-enum.c
 create mode 100644 gcc/testsuite/jit.dg/test-error-new-binary-op-bad-op.c
 create mode 100644 gcc/testsuite/jit.dg/test-error-new-function-bad-kind.c
 create mode 100644 gcc/testsuite/jit.dg/test-error-new-unary-op-bad-op.c

diff --git a/gcc/testsuite/jit.dg/test-error-get-type-bad-enum.c b/gcc/testsuite/jit.dg/test-error-get-type-bad-enum.c
new file mode 100644
index 0000000..67b712e
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-error-get-type-bad-enum.c
@@ -0,0 +1,27 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  /* Trigger an API error by passing bad data.  */
+  gcc_jit_context_get_type (ctxt, 42);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  /* Ensure that the bad API usage prevents the API giving a bogus
+     result back.  */
+  CHECK_VALUE (result, NULL);
+
+  /* Verify that the correct error message was emitted.  */
+  CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+		      ("gcc_jit_context_get_type:"
+		       " unrecognized value for enum gcc_jit_types: 42"));
+}
+
diff --git a/gcc/testsuite/jit.dg/test-error-new-binary-op-bad-op.c b/gcc/testsuite/jit.dg/test-error-new-binary-op-bad-op.c
new file mode 100644
index 0000000..0592f55
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-error-new-binary-op-bad-op.c
@@ -0,0 +1,37 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  /* Trigger an API error by passing bad data.  */
+  (void)gcc_jit_context_new_binary_op (
+	  ctxt,
+	  NULL,
+
+	  /* Non-valid enum value: */
+	  (enum gcc_jit_binary_op) 42,
+
+	  /* These aren't valid either: */
+	  NULL, /* gcc_jit_type *result_type, */
+	  NULL, NULL); /* gcc_jit_rvalue *a, gcc_jit_rvalue *b */
+
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  /* Ensure that the bad API usage prevents the API giving a bogus
+     result back.  */
+  CHECK_VALUE (result, NULL);
+
+  /* Verify that the correct error message was emitted.  */
+  CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+		      ("gcc_jit_context_new_binary_op:"
+		       " unrecognized value for enum gcc_jit_binary_op: 42"));
+}
+
diff --git a/gcc/testsuite/jit.dg/test-error-new-function-bad-kind.c b/gcc/testsuite/jit.dg/test-error-new-function-bad-kind.c
new file mode 100644
index 0000000..f9772de
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-error-new-function-bad-kind.c
@@ -0,0 +1,41 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  gcc_jit_type *int_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+  /* Trigger an API error by passing bad data.  */
+  (void)gcc_jit_context_new_function (
+	  ctxt,
+	  NULL,
+
+	  /* Non-valid enum value: */
+	  (enum gcc_jit_function_kind)42,
+
+	  int_type, /* gcc_jit_type *return_type, */
+	  "foo", /* const char *name, */
+	  0, /* int num_params, */
+	  NULL, /* gcc_jit_param **params, */
+	  0); /* int is_variadic */
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  /* Ensure that the bad API usage prevents the API giving a bogus
+     result back.  */
+  CHECK_VALUE (result, NULL);
+
+  /* Verify that the correct error message was emitted.  */
+  CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+		      ("gcc_jit_context_new_function:"
+		       " unrecognized value for enum gcc_jit_function_kind: 42"));
+}
+
diff --git a/gcc/testsuite/jit.dg/test-error-new-unary-op-bad-op.c b/gcc/testsuite/jit.dg/test-error-new-unary-op-bad-op.c
new file mode 100644
index 0000000..faab139
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-error-new-unary-op-bad-op.c
@@ -0,0 +1,36 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  /* Trigger an API error by passing bad data.  */
+  (void)gcc_jit_context_new_unary_op (
+	  ctxt,
+	  NULL,
+
+	  /* Non-valid enum value: */
+	  (enum gcc_jit_unary_op) 42,
+
+	  /* These aren't valid either: */
+	  NULL, /* gcc_jit_type *result_type, */
+	  NULL); /* gcc_jit_rvalue *rvalue */
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  /* Ensure that the bad API usage prevents the API giving a bogus
+     result back.  */
+  CHECK_VALUE (result, NULL);
+
+  /* Verify that the correct error message was emitted.  */
+  CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+		      ("gcc_jit_context_new_unary_op:"
+		       " unrecognized value for enum gcc_jit_unary_op: 42"));
+}
+
-- 
1.8.5.3

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

* [PATCH 2/3] Documentation tweak
  2014-11-05 20:47 ` [PATCH 0/3] Minor tweaks to jit David Malcolm
  2014-11-05 20:47   ` [PATCH 1/3] New test cases David Malcolm
@ 2014-11-05 20:47   ` David Malcolm
  2014-11-05 20:47   ` [PATCH 3/3] Add comments to various functions in libgccjit.h David Malcolm
  2014-11-06 23:51   ` [PATCH 0/3] Minor tweaks to jit Jeff Law
  3 siblings, 0 replies; 71+ messages in thread
From: David Malcolm @ 2014-11-05 20:47 UTC (permalink / raw)
  To: Jeff Law; +Cc: gcc-patches, jit, David Malcolm

gcc/jit/
	* docs/topics/expressions.rst (Type-coercion): Note that
	we support casting between pointer types.
---
 gcc/jit/docs/topics/expressions.rst | 1 +
 1 file changed, 1 insertion(+)

diff --git a/gcc/jit/docs/topics/expressions.rst b/gcc/jit/docs/topics/expressions.rst
index a95f5c9..1cf9641 100644
--- a/gcc/jit/docs/topics/expressions.rst
+++ b/gcc/jit/docs/topics/expressions.rst
@@ -402,6 +402,7 @@ Type-coercion
 
      * int <-> float
      * int <-> bool
+     * P*  <-> Q*, for pointer types P and Q
 
 Lvalues
 -------
-- 
1.8.5.3

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

* Re: [PATCH 0/3] Minor tweaks to jit
  2014-11-05 20:47 ` [PATCH 0/3] Minor tweaks to jit David Malcolm
                     ` (2 preceding siblings ...)
  2014-11-05 20:47   ` [PATCH 3/3] Add comments to various functions in libgccjit.h David Malcolm
@ 2014-11-06 23:51   ` Jeff Law
  2014-11-07  1:22     ` David Malcolm
  3 siblings, 1 reply; 71+ messages in thread
From: Jeff Law @ 2014-11-06 23:51 UTC (permalink / raw)
  To: David Malcolm; +Cc: gcc-patches, jit

On 11/05/14 13:54, David Malcolm wrote:
> Here are some minor tweaks I've made on the JIT branch since v3 of
> the review began.
>
> Are the following OK for trunk, assuming the rest of the JIT work
> is approved?
>
> David Malcolm (3):
>    New test cases
>    Documentation tweak
>    Add comments to various functions in libgccjit.h
Yes, these are OK once the remaining stuff is OK'd.

jeff

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

* Re: [PATCH 0/3] Minor tweaks to jit
  2014-11-06 23:51   ` [PATCH 0/3] Minor tweaks to jit Jeff Law
@ 2014-11-07  1:22     ` David Malcolm
  0 siblings, 0 replies; 71+ messages in thread
From: David Malcolm @ 2014-11-07  1:22 UTC (permalink / raw)
  To: Jeff Law; +Cc: gcc-patches, jit

On Thu, 2014-11-06 at 16:51 -0700, Jeff Law wrote:
> On 11/05/14 13:54, David Malcolm wrote:
> > Here are some minor tweaks I've made on the JIT branch since v3 of
> > the review began.
> >
> > Are the following OK for trunk, assuming the rest of the JIT work
> > is approved?
> >
> > David Malcolm (3):
> >    New test cases
> >    Documentation tweak
> >    Add comments to various functions in libgccjit.h
> Yes, these are OK once the remaining stuff is OK'd.

Thanks.  I believe the only outstanding item is now libgccjit.c; the
latest version for review is:
  https://gcc.gnu.org/ml/gcc-patches/2014-11/msg00358.html




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

* Re: [PATCH 10/27] New file: gcc/jit/libgccjit.c
  2014-11-05 19:38         ` [PATCH 10/27] New file: gcc/jit/libgccjit.c David Malcolm
@ 2014-11-07 19:47           ` Jeff Law
  2014-11-07 20:32             ` David Malcolm
  0 siblings, 1 reply; 71+ messages in thread
From: Jeff Law @ 2014-11-07 19:47 UTC (permalink / raw)
  To: David Malcolm; +Cc: gcc-patches, jit

On 11/05/14 12:34, David Malcolm wrote:

>
> I've added comments throughout the file.
>
> I didn't bother adding __attribute__((cold)), instead simply dropping
> that "TODO".
Fine.

>
> Attached is the current state of the file gcc/jit/libgccjit.c (on the
> branch) for review.
>
> OK for trunk? (conditional on all the rest being approved, and usual
> bootstrap&regrtesting; I've merely verified a non-bootstrap compile and
> successful make check-jit so far).
>
> There were a few other changes relative to what you've approved, which
> I'll post for review shortly.
>
> Dave
>
>
> libgccjit.c
>
>
> /* Implementation of the C API; all wrappers into the internal C++ API
>     Copyright (C) 2013-2014 Free Software Foundation, Inc.
>     Contributed by David Malcolm<dmalcolm@redhat.com>.
This is fine.  With the comments, it became a lot clearer this was just 
the error checking wrappers and not a whole lot else.

The one thing this does make me wonder is should we add something about 
the error checking may change in significant ways from one release to 
the next, much like the ABI/API.

This seems important as the error checking in many ways specifies the 
language for the JIT and I suspect we haven't got all the corner cases 
sorted out yet (and probably can't until this gets into wider distribution).

jeff

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

* Re: [PATCH 10/27] New file: gcc/jit/libgccjit.c
  2014-11-07 19:47           ` Jeff Law
@ 2014-11-07 20:32             ` David Malcolm
  0 siblings, 0 replies; 71+ messages in thread
From: David Malcolm @ 2014-11-07 20:32 UTC (permalink / raw)
  To: Jeff Law; +Cc: gcc-patches, jit

On Fri, 2014-11-07 at 12:47 -0700, Jeff Law wrote:
> On 11/05/14 12:34, David Malcolm wrote:
> 
> >
> > I've added comments throughout the file.
> >
> > I didn't bother adding __attribute__((cold)), instead simply dropping
> > that "TODO".
> Fine.
> 
> >
> > Attached is the current state of the file gcc/jit/libgccjit.c (on the
> > branch) for review.
> >
> > OK for trunk? (conditional on all the rest being approved, and usual
> > bootstrap&regrtesting; I've merely verified a non-bootstrap compile and
> > successful make check-jit so far).
> >
> > There were a few other changes relative to what you've approved, which
> > I'll post for review shortly.
> >
> > Dave
> >
> >
> > libgccjit.c
> >
> >
> > /* Implementation of the C API; all wrappers into the internal C++ API
> >     Copyright (C) 2013-2014 Free Software Foundation, Inc.
> >     Contributed by David Malcolm<dmalcolm@redhat.com>.
> This is fine.  With the comments, it became a lot clearer this was just 
> the error checking wrappers and not a whole lot else.

Thanks.  That was the last of the review requests, so I believe the jit
branch is now approved for merger.  I plan to do this early next week,
to give time to rebase against latest trunk and retest it.

> The one thing this does make me wonder is should we add something about 
> the error checking may change in significant ways from one release to 
> the next, much like the ABI/API.
> 
> This seems important as the error checking in many ways specifies the 
> language for the JIT and I suspect we haven't got all the corner cases 
> sorted out yet (and probably can't until this gets into wider distribution).

I agree that the JIT language is specified by the runtime error-checking
behaviour, but it's also specified by the types in the API.

We're in slightly better shape here than, say gcc's internal tree API,
in that the types in the API make a rigid separation between types vs
expressions, and it also captures some lvalue vs rvalue distinctions, so
client code is likely to not compile if it gets those things wrong.
I've also tried to name the params in such a way as to hint at
restrictions, e.g. gcc_jit_context_zero's second param is:
  gcc_jit_type *numeric_type
i.e. the "numeric_type" name of that param describes a requirement.

There are probably some under-specified behaviors in the JIT language as
it stands - perhaps in ordering of operations?

In any case, the current disclaimer reads:

"Note that libgccjit is currently of “Alpha” quality; the APIs are not
yet set in stone, and they shouldn’t be used in production yet."

I'm sure we'll want to reword that at some point.

One big potential change might be to create a stable *plugin* API,
unified with the JIT API (so we'd allow client code to use the same API
for both embedding GCC and being embedded within GCC).  Most of the
"gcc_jit_*" symbols would become just "gcc_*".

I've experimented with that, but I don't see myself getting it done in
time for the close of stage1 close (am frantically trying to finish the
gimple-classes work), so I'm thinking of that unified jit-and-plugin API
as a GCC 6 feature.

Dave

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

* Re: [PATCH 01/27] gcc: configure and Makefile changes needed by jit
  2014-10-31 17:07 ` [PATCH 01/27] gcc: configure and Makefile changes needed by jit David Malcolm
  2014-11-03 21:36   ` Jeff Law
@ 2014-11-13 20:16   ` Thomas Schwinge
  1 sibling, 0 replies; 71+ messages in thread
From: Thomas Schwinge @ 2014-11-13 20:16 UTC (permalink / raw)
  To: David Malcolm; +Cc: gcc-patches, jit

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

Hi!

JIT/GCC as a shared library merged!  \o/

On Fri, 31 Oct 2014 13:02:34 -0400, David Malcolm <dmalcolm@redhat.com> wrote:
> An earlier version of this was posted as:
>   "[PATCH 2/5] gcc: configure and Makefile changes needed by jit"
>     https://gcc.gnu.org/ml/gcc-patches/2014-10/msg01169.html
> 
> Since then, I've eliminated the gcc_version, bindir, and pkgconfigdir
> additions, and added the FULL_DRIVER_NAME variable and symlink, to
> avoid the need to install when running the jit testsuite.

> --- a/gcc/Makefile.in
> +++ b/gcc/Makefile.in
> @@ -1504,6 +1509,9 @@ BACKEND = libbackend.a main.o @TREEBROWSER@ libcommon-target.a libcommon.a \
>  # front-end checking.
>  TREECHECKING = @TREECHECKING@
>  
> +# The full name of the driver on installation
> +FULL_DRIVER_NAME=$(target_noncanonical)-gcc-$(version)$(exeext)

May I suggest to remove $(exeext) here...

> @@ -1511,7 +1519,7 @@ MOSTLYCLEANFILES = insn-flags.h insn-config.h insn-codes.h \
>   tm-preds.h tm-constrs.h checksum-options gimple-match.c generic-match.c \
>   tree-check.h min-insn-modes.c insn-modes.c insn-modes.h \
>   genrtl.h gt-*.h gtype-*.h gtype-desc.c gtyp-input.list \
> - xgcc$(exeext) cpp$(exeext) \
> + xgcc$(exeext) cpp$(exeext) $(FULL_DRIVER_NAME) \

..., and add it here...

> +# This symlink makes the full installation name of the driver be available
> +# from within the *build* directory, for use when running the JIT library
> +# from there (e.g. when running its testsuite).
> +$(FULL_DRIVER_NAME): ./xgcc
> +	$(LN) -s $< $@

..., and here...

> @@ -3280,9 +3294,9 @@ install-driver: installdirs xgcc$(exeext)
>  	-rm -f $(DESTDIR)$(bindir)/$(GCC_INSTALL_NAME)$(exeext)
>  	-$(INSTALL_PROGRAM) xgcc$(exeext) $(DESTDIR)$(bindir)/$(GCC_INSTALL_NAME)$(exeext)
>  	-if [ "$(GCC_INSTALL_NAME)" != "$(target_noncanonical)-gcc-$(version)" ]; then \
> -	  rm -f $(DESTDIR)$(bindir)/$(target_noncanonical)-gcc-$(version)$(exeext); \
> +	  rm -f $(DESTDIR)$(bindir)/$(FULL_DRIVER_NAME); \
>  	  ( cd $(DESTDIR)$(bindir) && \
> -	    $(LN) $(GCC_INSTALL_NAME)$(exeext) $(target_noncanonical)-gcc-$(version)$(exeext) ); \
> +	    $(LN) $(GCC_INSTALL_NAME)$(exeext) $(FULL_DRIVER_NAME) ); \

..., and here (also obviously also everywhere else where it is being
used, if applicable), and then also use $(FULL_DRIVER_NAME) in the if
statement just prior, comparing $(GCC_INSTALL_NAME) to what used to be
$(FULL_DRIVER_NAME) -- just without $(exeext)?  Alternatively, add
$(exeext) to $(GCC_INSTALL_NAME) in the if statement, but I think
generally variables such as $(FULL_DRIVER_NAME) are set up without
$(exeext).

That said, and I'll be quick to note that I have not yet looked what
you're using this for, don't you need to pass -B and similar flags to
xgcc when invoking it from the build directory?  Or is this not relevant
for your use case?  (I just stumbled over this, because we have a similar
case with "un-installed" offloading/accelerator xgcc builds that are to
be used for build-tree testing.


Another thing, just curious: why did you merge all the ChangeLog.jit
files into trunk?  I see that there are a few ChangeLog.* files from
development branch merges, but as this is not generally done, I wonder
when/why it is sometimes being done this way?


Grüße,
 Thomas

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 472 bytes --]

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

end of thread, other threads:[~2014-11-13 20:04 UTC | newest]

Thread overview: 71+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-10-31 17:07 [PATCH 00/27] Merger of jit branch v3 David Malcolm
2014-10-31 17:07 ` [PATCH 02/27] JIT-related changes outside of jit subdir David Malcolm
2014-10-31 21:18   ` Jeff Law
2014-10-31 17:07 ` [PATCH 03/27] Add Sphinx to install.texi David Malcolm
2014-10-31 21:18   ` Jeff Law
2014-10-31 17:07 ` [PATCH 07/27] New file: gcc/jit/dummy-frontend.c David Malcolm
2014-11-03 19:26   ` Jeff Law
2014-10-31 17:07 ` [PATCH 20/27] Documentation: Makefile and conf.py David Malcolm
2014-11-03 21:13   ` Jeff Law
2014-10-31 17:07 ` [PATCH 01/27] gcc: configure and Makefile changes needed by jit David Malcolm
2014-11-03 21:36   ` Jeff Law
2014-11-13 20:16   ` Thomas Schwinge
2014-10-31 17:07 ` [PATCH 21/27] Documentation: the "examples" subdirectory David Malcolm
2014-10-31 21:31   ` Jeff Law
2014-10-31 17:07 ` [PATCH 06/27] New file: gcc/jit/Make-lang.in David Malcolm
2014-11-03 21:35   ` Jeff Law
2014-10-31 17:07 ` [PATCH 05/27] New file: gcc/jit/config-lang.in David Malcolm
2014-10-31 21:20   ` Jeff Law
2014-10-31 17:07 ` [PATCH 09/27] New file: gcc/jit/libgccjit.map David Malcolm
2014-10-31 21:21   ` Jeff Law
2014-10-31 17:16 ` [PATCH 23/27] Documentation: the "intro" subdirectory David Malcolm
2014-10-31 21:48   ` Jeff Law
2014-10-31 22:12     ` David Malcolm
2014-11-03 16:23       ` Jeff Law
2014-10-31 17:21 ` [PATCH 22/27] Documentation: top-level index.rst David Malcolm
2014-10-31 21:29   ` Jeff Law
2014-10-31 17:28 ` [PATCH 12/27] New file: gcc/jit/jit-recording.h David Malcolm
2014-11-03 21:27   ` Jeff Law
2014-11-04 16:16     ` David Malcolm
2014-11-04 21:23       ` Jeff Law
2014-10-31 17:28 ` [PATCH 18/27] New file: gcc/jit/TODO.rst David Malcolm
2014-10-31 21:26   ` Jeff Law
2014-10-31 17:28 ` [PATCH 11/27] New file: gcc/jit/jit-common.h David Malcolm
2014-11-03 19:34   ` Jeff Law
2014-10-31 17:28 ` [PATCH 10/27] New file: gcc/jit/libgccjit.c David Malcolm
2014-11-03 20:32   ` Jeff Law
2014-11-04 17:02     ` David Malcolm
2014-11-04 21:40       ` Jeff Law
2014-11-05 15:52         ` [jit] Use ISALPHA and ISALNUM rather than writing our own David Malcolm
2014-11-05 20:02           ` Jeff Law
2014-11-05 19:38         ` [PATCH 10/27] New file: gcc/jit/libgccjit.c David Malcolm
2014-11-07 19:47           ` Jeff Law
2014-11-07 20:32             ` David Malcolm
2014-10-31 17:29 ` [PATCH 08/27] New file: gcc/jit/libgccjit.h David Malcolm
2014-11-03 20:22   ` Jeff Law
2014-11-04  1:26     ` David Malcolm
2014-10-31 17:29 ` [PATCH 14/27] New files: gcc/jit/jit-builtins.{c|h} David Malcolm
2014-11-03 21:04   ` Jeff Law
2014-11-04 16:39     ` David Malcolm
2014-10-31 17:30 ` [PATCH 17/27] New file: gcc/jit/libgccjit++.h David Malcolm
2014-11-03 21:12   ` Jeff Law
2014-10-31 17:31 ` [PATCH 16/27] New file: gcc/jit/jit-playback.c David Malcolm
2014-11-04 22:21   ` Jeff Law
2014-11-05 20:23     ` [jit] Drop the disabled debugging code within handle_locations David Malcolm
2014-10-31 17:31 ` [PATCH 24/27] Documentation: add "topics" subdirectory David Malcolm
2014-10-31 17:32 ` [PATCH 25/27] Documentation: add "internals" subdirectory David Malcolm
2014-10-31 17:38 ` [PATCH 13/27] New file: gcc/jit/jit-recording.c David Malcolm
2014-11-03 22:04   ` Jeff Law
2014-11-04 16:29     ` David Malcolm
2014-11-04 21:24       ` Jeff Law
2014-10-31 17:41 ` [PATCH 15/27] New file: gcc/jit/jit-playback.h David Malcolm
2014-11-03 21:10   ` Jeff Law
2014-10-31 17:59 ` [PATCH 04/27] New file: gcc/jit/notes.txt David Malcolm
2014-10-31 21:19   ` Jeff Law
2014-10-31 21:17 ` [PATCH 00/27] Merger of jit branch v3 Jeff Law
2014-11-05 20:47 ` [PATCH 0/3] Minor tweaks to jit David Malcolm
2014-11-05 20:47   ` [PATCH 1/3] New test cases David Malcolm
2014-11-05 20:47   ` [PATCH 2/3] Documentation tweak David Malcolm
2014-11-05 20:47   ` [PATCH 3/3] Add comments to various functions in libgccjit.h David Malcolm
2014-11-06 23:51   ` [PATCH 0/3] Minor tweaks to jit Jeff Law
2014-11-07  1:22     ` David Malcolm

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