+2014-11-11 David Malcolm <dmalcolm@redhat.com>
+
+ * ChangeLog.jit: New.
+ * MAINTAINERS (Various Maintainers): Add myself as jit maintainer.
+
2014-11-11 Francois-Xavier Coudert <fxcoudert@gcc.gnu.org>
PR target/63610
--- /dev/null
+2014-10-02 David Malcolm <dmalcolm@redhat.com>
+
+ * MAINTAINERS: Update jit entry to match formatting change on
+ trunk: "Put all email addresses between '<' and '>'."
+
+2014-09-24 David Malcolm <dmalcolm@redhat.com>
+
+ * ChangeLog.jit: Add copyright footer.
+
+2014-09-11 David Malcolm <dmalcolm@redhat.com>
+
+ * MAINTAINERS (Various Maintainers): Add myself as jit maintainer.
+
+2013-10-03 David Malcolm <dmalcolm@redhat.com>
+
+ * configure.ac: Add --enable-host-shared
+ * configure: Regenerate.
+\f
+Copyright (C) 2013-2014 Free Software Foundation, Inc.
+
+Copying and distribution of this file, with or without modification,
+are permitted in any medium without royalty provided the copyright
+notice and this notice are preserved.
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.
+2014-11-11 David Malcolm <dmalcolm@redhat.com>
+
+ * ChangeLog.jit: New.
+ * jit-coverage-report.py: New file: a script to print crude
+ code-coverage information for the libgccjit API.
+
2014-11-11 Marat Zakirov <m.zakirov@samsung.com>
* mklog: Symbol '}' stops search for changes.
--- /dev/null
+2014-09-24 David Malcolm <dmalcolm@redhat.com>
+
+ * ChangeLog.jit: Add copyright footer.
+
+2014-01-23 David Malcolm <dmalcolm@redhat.com>
+
+ * jit-coverage-report.py: New file: a script to print crude
+ code-coverage information for the libgccjit API.
+\f
+Copyright (C) 2014 Free Software Foundation, Inc.
+
+Copying and distribution of this file, with or without modification,
+are permitted in any medium without royalty provided the copyright
+notice and this notice are preserved.
--- /dev/null
+#! /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'))
+2014-11-11 David Malcolm <dmalcolm@redhat.com>
+
+ * ChangeLog.jit: New.
+ * Makefile.in (doc_build_sys): New variable, set to "sphinx" if
+ sphinx is installed, falling back to "texinfo" otherwise.
+ (FULL_DRIVER_NAME): New variable, adapted from the
+ install-driver target. New target, a symlink within the builddir,
+ linked to "xgcc", for use when running the JIT library from the
+ builddir.
+ (MOSTLYCLEANFILES): Add FULL_DRIVER_NAME.
+ (install-driver): Use $(FULL_DRIVER_NAME) rather than spelling it
+ out.
+ * configure.ac (doc_build_sys): New variable, set to "sphinx" if
+ sphinx is installed, falling back to "texinfo" otherwise.
+ (GCC_DRIVER_NAME): Generate a gcc-driver-name.h file containing
+ GCC_DRIVER_NAME for the benefit of jit/internal-api.c.
+ * configure: Regenerate.
+ * doc/install.texi (--enable-host-shared): Specify that this is
+ required when building libgccjit.
+ (Tools/packages necessary for modifying GCC): Add Sphinx.
+ * timevar.def (TV_JIT_REPLAY): New.
+ (TV_ASSEMBLE): New.
+ (TV_LINK): New.
+ (TV_LOAD): New.
+
2014-11-11 Francois-Xavier Coudert <fxcoudert@gcc.gnu.org>
PR target/63610
--- /dev/null
+2014-10-29 David Malcolm <dmalcolm@redhat.com>
+
+ * doc/install.texi (Tools/packages necessary for modifying GCC):
+ Specify that Sphinx version 1.0 or later is required. Wrap .rst
+ inside an @file command.
+
+2014-10-22 David Malcolm <dmalcolm@redhat.com>
+
+ * cgraph.h: Drop now-redundant prototype of ipa_cp_c_finalize,
+ since trunk added this in ipa-prop.h.
+ * ipa-icf.c (ipa_icf_driver): Set optimizer to NULL when
+ done.
+
+2014-10-20 David Malcolm <dmalcolm@redhat.com>
+
+ * doc/install.texi (Tools/packages necessary for modifying GCC):
+ Add Sphinx.
+
+2014-10-20 David Malcolm <dmalcolm@redhat.com>
+
+ * Makefile.in (pkgconfigdir): Drop this.
+ (installdirs): Likewise.
+ * configure.ac (gcc_version): Don't AC_SUBST this.
+ * configure: Regenerate.
+
+2014-10-17 David Malcolm <dmalcolm@redhat.com>
+
+ * Makefile.in (FULL_DRIVER_NAME): New variable, adapted from the
+ install-driver target. New target, a symlink within the builddir,
+ linked to "xgcc", for use when running the JIT library from the
+ builddir.
+ (MOSTLYCLEANFILES): Add FULL_DRIVER_NAME.
+ (install-driver): Use $(FULL_DRIVER_NAME) rather than spelling it
+ out.
+ (site.exp): Don't set "bindir", as this is no longer needed when
+ running the jit testsuite.
+
+2014-10-13 David Malcolm <dmalcolm@redhat.com>
+
+ * configure.ac: Update a reference to jit/internal-api.c to
+ jit/jit-playback.c.
+ * configure: Regenerate.
+
+2014-10-07 David Malcolm <dmalcolm@redhat.com>
+
+ * Makefile.in (site.exp): When constructing site.exp, add a line
+ to set "bindir".
+ * configure.ac: Generate a gcc-driver-name.h file containing
+ GCC_DRIVER_NAME for the benefit of jit/internal-api.c.
+ * configure: Regenerate.
+
+2014-10-03 David Malcolm <dmalcolm@redhat.com>
+
+ * diagnostic.c (diagnostic_finish): Free the memory for
+ context->classify_diagnostic and context->printer, running the
+ destructor for the latter.
+
+2014-10-02 David Malcolm <dmalcolm@redhat.com>
+
+ * configure: Regenerate, after merger from trunk.
+
+2014-10-02 David Malcolm <dmalcolm@redhat.com>
+
+ * configure.ac (doc_build_sys): New variable, set to "sphinx" if
+ sphinx is installed, falling back to "texinfo" otherwise.
+ * configure: Regenerate.
+ * Makefile.in (doc_build_sys): New.
+
+2014-09-24 David Malcolm <dmalcolm@redhat.com>
+
+ * ChangeLog.jit: Add copyright footer.
+
+2014-09-24 David Malcolm <dmalcolm@redhat.com>
+
+ * cgraph.h (cgraphbuild_c_finalize): Delete prototype of empty
+ function.
+ (ipa_c_finalize): Likewise.
+ (predict_c_finalize): Likewise.
+ (symtab_c_finalize): Likewise.
+ (varpool_c_finalize): Likewise.
+
+ * cgraph.c (cgraph_c_finalize): Add leading comment. Put return
+ type on line before function name.
+ * cgraphunit.c (cgraphunit_c_finalize): Likewise.
+ * dwarf2out.c (dwarf2out_c_finalize): Likewise.
+ * gcse.c (gcse_c_finalize): Likewise.
+ * ipa-cp.c (ipa_cp_c_finalize): Likewise.
+ * ipa-reference.c (ipa_reference_c_finalize): Likewise.
+
+ * params.c (params_c_finalize): Update leading comment to match
+ format of the others mentioned above.
+
+ * cgraphbuild.c (cgraphbuild_c_finalize): Delete empty function.
+ * ipa.c (ipa_c_finalize): Likewise.
+ * predict.c (predict_c_finalize): Likewise.
+ * symtab.c (symtab_c_finalize): Likewise.
+ * varpool.c (varpool_c_finalize): Likewise.
+
+ * toplev.c (toplev::finalize): Remove calls to empty functions
+ cgraphbuild_c_finalize, ipa_c_finalize, predict_c_finalize,
+ symtab_c_finalize, varpool_c_finalize.
+
+2014-09-23 David Malcolm <dmalcolm@redhat.com>
+
+ * passes.c (execute_ipa_summary_passes): Fix whitespace when
+ assigning to current_pass.
+ (ipa_write_summaries_2): Assign "pass" to "current_pass" global
+ before calling write_summary hook.
+ (ipa_write_optimization_summaries_1): Likewise when calling
+ write_optimization_summary hook.
+ (ipa_read_summaries_1): Likewise for read_summary hook.
+ (ipa_read_optimization_summaries_1): Likewise for
+ read_optimization_summary hook.
+ (execute_ipa_stmt_fixups): Likewise for stmt_fixup hook.
+
+2014-09-22 David Malcolm <dmalcolm@redhat.com>
+
+ * cgraph.c (cgraph_c_finalize): Remove FIXME.
+ * timevar.c (timevar_init): Likewise.
+
+2014-09-18 David Malcolm <dmalcolm@redhat.com>
+
+ * Makefile.in (pkgconfigdir): New.
+ (installdirs): Add creation of $(DESTDIR)$(pkgconfigdir).
+ * configure.ac (gcc_version): Expose this value for use via
+ AC_SUBST, since we need it within the new file libgccjit.pc.in.
+ * configure: Regenerate.
+
+2014-09-10 David Malcolm <dmalcolm@redhat.com>
+
+ * cgraph.c (cgraph_c_finalize): Update to reflect the movement of
+ many globals into fields of the "symtab" object.
+ * cgraphunit.c (graphunit_c_finalize): Likewise.
+ * symtab.c (symtab_c_finalize): Likewise.
+
+ * toplev.c (initialize_rtl): Move static local "initialized_once"
+ into file scope, and rename to...
+ (rtl_initialized): New variable.
+ (toplev::finalize): Clear rtl_initialized and
+ this_target_rtl->target_specific_initialized so that RTL will be
+ reinitialized when the compiler is run more than once in-process.
+
+2014-07-14 David Malcolm <dmalcolm@redhat.com>
+
+ * cgraph.h (ipa_cp_c_finalize): Add prototype.
+ * ipa-cp.c (ipa_cp_c_finalize): New.
+ * toplev.c (toplev::finalize): Add call to ipa_cp_c_finalize.
+
+2014-05-08 David Malcolm <dmalcolm@redhat.com>
+
+ * params.c (global_init_params): Require that params_finished be
+ false, rather than being idempotent, in favor of purging all state
+ between toplev invocations, since in a release build
+ init_ggc_heuristics calls set_param_value_internal, and the
+ latter assumes that params_finished is true.
+ (params_c_finalize): New.
+ * params.h (params_c_finalize): New.
+ * toplev.c (toplev::finalize): Call params_c_finalize.
+
+2014-03-24 Tom Tromey <tromey@redhat.com>
+
+ * toplev.c (general_init): Initialize input_location.
+ * input.c (input_location): Initialize to UNKNOWN_LOCATION.
+
+2014-03-19 Tom Tromey <tromey@redhat.com>
+
+ * timevar.h (auto_timevar): New class.
+
+2014-03-19 Tom Tromey <tromey@redhat.com>
+
+ * diagnostic.c (bt_stop): Use toplev::main.
+ * main.c (main): Update.
+ * toplev.c (do_compile): Remove argument. Don't check
+ use_TV_TOTAL.
+ (toplev::toplev, toplev::~toplev, toplev::start_timevars): New
+ functions.
+ (toplev::main): Rename from toplev_main. Update.
+ (toplev::finalize): Rename from toplev_finalize. Update.
+ * toplev.h (class toplev): New.
+ (struct toplev_options): Remove.
+ (toplev_main, toplev_finalize): Don't declare.
+
+2014-03-11 David Malcolm <dmalcolm@redhat.com>
+
+ * gcse.c (gcse_c_finalize): New, to clear test_insn between
+ in-process compiles.
+ * gcse.h (gcse_c_finalize): New.
+ * toplev.c: Include "gcse.h" so that we can...
+ (toplev_finalize): Call gcse_c_finalize.
+
+2014-03-11 David Malcolm <dmalcolm@redhat.com>
+
+ * dwarf2out.c (dwarf2out_c_finalize): Release base_types.
+
+2014-03-10 David Malcolm <dmalcolm@redhat.com>
+
+ * ipa-reference.c (ipa_init): Move static bool init_p from here
+ to...
+ (ipa_init_p): New file-scope variable, so that it can be reset
+ when repeatedly invoking the compiler within one process by...
+ (ipa_reference_c_finalize): New function.
+ * ipa-reference.h (ipa_reference_c_finalize): New.
+ * toplev.c (toplev_finalize): Invoke new function
+ ipa_reference_c_finalize.
+
+2014-01-24 David Malcolm <dmalcolm@redhat.com>
+
+ * timevar.def: Replace TV_CLIENT_CALLBACK with TV_JIT_REPLAY.
+
+2013-10-11 David Malcolm <dmalcolm@redhat.com>
+
+ * doc/install.texi (--enable-shared): Add note contrasting it
+ with...
+ (--enable-host-shared): New option.
+
+2013-10-11 David Malcolm <dmalcolm@redhat.com>
+
+ * dumpfile.h (gcc::dump_manager): New class, to hold state
+ relating to dumpfile management.
+ (get_dump_file_name): Remove in favor of method of dump_manager.
+ (dump_initialized_p): Likewise.
+ (dump_start): Likewise.
+ (dump_finish): Likewise.
+ (dump_switch_p): Likewise.
+ (dump_register): Likewise.
+ (get_dump_file_info): Likewise.
+ * context.c (gcc::context::context): Construct the dump_manager
+ instance.
+ * context.h (gcc::context::get_dumps): New.
+ (gcc::context::m_dumps): New.
+ * coverage.c (coverage_init): Port to dump_manager API.
+ * dumpfile.c (extra_dump_files): Convert to field of
+ gcc::dump_manager.
+ (extra_dump_files_in_use): Likewise.
+ (extra_dump_files_alloced): Likewise.
+ (gcc::dump_manager::dump_manager): New.
+ (dump_register): Convert to...
+ (gcc::dump_manager::dump_register): ...method, replacing
+ function-static next_dump with m_next_dump field.
+ (get_dump_file_info): Convert to...
+ (gcc::dump_manager::get_dump_file_info): ...method.
+ (get_dump_file_name): Convert to...
+ (gcc::dump_manager::get_dump_file_name): ...method.
+ (dump_start): Convert to...
+ (gcc::dump_manager::dump_start): ...method.
+ (dump_finish): Convert to...
+ (gcc::dump_manager::dump_finish): ...method.
+ (dump_begin): Replace body with...
+ (gcc::dump_manager::dump_begin): ...new method.
+ (dump_phase_enabled_p): Convert to...
+ (gcc::dump_manager::dump_phase_enabled_p): ...method.
+ (dump_phase_enabled_p): Convert to...
+ (gcc::dump_manager::dump_phase_enabled_p): ...method.
+ (dump_initialized_p): Convert to...
+ (gcc::dump_manager::dump_initialized_p): ...method.
+ (dump_flag_name): Replace body with...
+ (gcc::dump_manager::dump_flag_name): ...new method.
+ (dump_enable_all): Convert to...
+ (gcc::dump_manager::dump_enable_all): ...new method.
+ (opt_info_enable_passes): Convert to...
+ (gcc::dump_manager::opt_info_enable_passes): ...new method.
+ (dump_switch_p_1): Convert to...
+ (gcc::dump_manager::dump_switch_p_1): ...new method.
+ (dump_switch_p): Convert to...
+ (gcc::dump_manager::dump_switch_p): ...new method.
+ (opt_info_switch_p): Port to dump_manager API.
+ (enable_rtl_dump_file): Likewise.
+ * opts-global.c (handle_common_deferred_options): Port to new
+ dump_manager API.
+ * passes.c (pass_manager::finish_optimization_passes): Likewise.
+ (pass_manager::register_one_dump_file): Likewise.
+ (pass_manager::register_pass): Likewise.
+ (pass_init_dump_file): Likewise.
+ (pass_fini_dump_file): Likewise.
+ * statistics.c (statistics_early_init): Likewise.
+
+2013-10-08 David Malcolm <dmalcolm@redhat.com>
+
+ * ipa-inline.c (ipa_inline): Fix leak of "order" when
+ optimizations are disabled.
+
+2013-10-08 David Malcolm <dmalcolm@redhat.com>
+
+ * coverage.c (coverage_finish): Fix leak of da_file_name.
+
+2013-10-07 David Malcolm <dmalcolm@redhat.com>
+
+ * Makefile.in: Set PICFLAG from configure script; add it to
+ INTERNAL_CFLAGS.
+ * configure.ac (--enable-host-shared): Set up PICFLAG rather
+ than attempting to append -fPIC to CFLAGS, CXXFLAGS, LDFLAGS.
+ * configure: Regenerate.
+
+2013-10-03 David Malcolm <dmalcolm@redhat.com>
+
+ * Makefile.in (LIBIBERTY): Use pic build of libiberty.a if
+ configured with --enable-host-shared.
+ (BUILD_LIBIBERTY): Likewise.
+ * cgraph.c (cgraph_c_finalize): New.
+ * cgraph.h (symtab_c_finalize): New declaration.
+ (cgraph_c_finalize): Likewise.
+ (cgraphunit_c_finalize): Likewise.
+ (cgraphbuild_c_finalize): Likewise.
+ (ipa_c_finalize): Likewise.
+ (predict_c_finalize): Likewise.
+ (varpool_c_finalize): Likewise.
+ * cgraphbuild.c (cgraphbuild_c_finalize): New.
+ * cgraphunit.c (first_analyzed): Move from analyze_functions
+ to file-scope.
+ (first_analyzed_var): Likewise.
+ (analyze_functions): Move static variables into file-scope.
+ (cgraphunit_c_finalize): New.
+ * configure.ac: Add --enable-host-shared, adding -fPIC.
+ * configure: Regenerate.
+ * dwarf2out.c (dwarf2out_c_finalize): New.
+ * dwarf2out.h (dwarf2out_c_finalize): Declare.
+ * ggc-page.c (init_ggc): Make idempotent.
+ * ipa-pure-const.c (function_insertion_hook_holder): Move to be
+ a field of class pass_ipa_pure_const.
+ (node_duplication_hook_holder): Likewise.
+ (node_removal_hook_holder): Likewise.
+ (register_hooks): Convert to method...
+ (pass_ipa_pure_const::register_hooks): ...here, converting
+ static variable init_p into...
+ (pass_ipa_pure_const::init_p): ...new field.
+ (pure_const_generate_summary): Update invocation of
+ register_hooks to invoke as a method of current_pass.
+ (pure_const_read_summary): Likewise.
+ (propagate): Convert to...
+ (pass_ipa_pure_const::execute): ...method.
+ * ipa.c (ipa_c_finalize): New.
+ * main.c (main): Update usage of toplev_main.
+ * params.c (global_init_params): Make idempotent.
+ * passes.c (execute_ipa_summary_passes): Set current_pass.
+ * predict.c (predict_c_finalize): New.
+ * stringpool.c (init_stringpool): Clean up if we're called more
+ than once.
+ * symtab.c (symtab_c_finalize): New.
+ * timevar.c (timevar_init): Ignore repeated calls.
+ * timevar.def (TV_CLIENT_CALLBACK): Add.
+ (TV_ASSEMBLE): Add.
+ (TV_LINK): Add.
+ (TV_LOAD): Add.
+ * toplev.c (do_compile) Add parameter (const toplev_options *);
+ use it to avoid starting/stopping/reporting timevar TV_TOTAL
+ for the case where toplev_main does not emcompass all timevars.
+ (toplev_main): Add parameter (const toplev_options *); pass it
+ to do_compile.
+ (toplev_finalize): New.
+ * toplev.h (struct toplev_options): New.
+ (toplev_main): Add parameter (const toplev_options *).
+ (toplev_finalize): New.
+ * varpool.c (varpool_c_finalize): New.
+
+\f
+Copyright (C) 2013-2014 Free Software Foundation, Inc.
+
+Copying and distribution of this file, with or without modification,
+are permitted in any medium without royalty provided the copyright
+notice and this notice are preserved.
$(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
# --------
# 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 \
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) \
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.
-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 \
DEPDIR
am__leading_dot
CXXCPP
+doc_build_sys
AR
NM
BISON
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
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
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
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)
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
[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)
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)
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.
+2014-11-11 David Malcolm <dmalcolm@redhat.com>
+
+ * gcc/ChangeLog.jit: New.
+
2014-10-29 Richard Sandiford <richard.sandiford@arm.com>
* builtins.c, java-tree.h, typeck.c: Remove redundant enum from
--- /dev/null
+2014-09-24 David Malcolm <dmalcolm@redhat.com>
+
+ * ChangeLog.jit: Add copyright footer.
+
+2013-10-11 David Malcolm <dmalcolm@redhat.com>
+
+ * lang.c (java_handle_option): Update for introduction of
+ gcc::dump_manager.
+\f
+Copyright (C) 2013-2014 Free Software Foundation, Inc.
+
+Copying and distribution of this file, with or without modification,
+are permitted in any medium without royalty provided the copyright
+notice and this notice are preserved.
--- /dev/null
+2014-11-11 David Malcolm <dmalcolm@redhat.com>
+
+ * ChangeLog.jit: New.
+ * ChangeLog: New.
+ * Make-lang.in: New.
+ * TODO.rst: New.
+ * config-lang.in: New.
+ * docs/Makefile: New.
+ * docs/_build/texinfo/Makefile: New.
+ * docs/_build/texinfo/factorial.png: New.
+ * docs/_build/texinfo/libgccjit.texi: New.
+ * docs/_build/texinfo/sum-of-squares.png: New.
+ * docs/conf.py: New.
+ * docs/examples/tut01-hello-world.c: New.
+ * docs/examples/tut02-square.c: New.
+ * docs/examples/tut03-sum-of-squares.c: New.
+ * docs/examples/tut04-toyvm/Makefile: New.
+ * docs/examples/tut04-toyvm/factorial.toy: New.
+ * docs/examples/tut04-toyvm/fibonacci.toy: New.
+ * docs/examples/tut04-toyvm/toyvm.c: New.
+ * docs/index.rst: New.
+ * docs/internals/index.rst: New.
+ * docs/intro/factorial.png: New.
+ * docs/intro/index.rst: New.
+ * docs/intro/sum-of-squares.png: New.
+ * docs/intro/tutorial01.rst: New.
+ * docs/intro/tutorial02.rst: New.
+ * docs/intro/tutorial03.rst: New.
+ * docs/intro/tutorial04.rst: New.
+ * docs/topics/contexts.rst: New.
+ * docs/topics/expressions.rst: New.
+ * docs/topics/functions.rst: New.
+ * docs/topics/index.rst: New.
+ * docs/topics/locations.rst: New.
+ * docs/topics/objects.rst: New.
+ * docs/topics/results.rst: New.
+ * docs/topics/types.rst: New.
+ * dummy-frontend.c: New.
+ * jit-builtins.c: New.
+ * jit-builtins.h: New.
+ * jit-common.h: New.
+ * jit-playback.c: New.
+ * jit-playback.h: New.
+ * jit-recording.c: New.
+ * jit-recording.h: New.
+ * libgccjit++.h: New.
+ * libgccjit.c: New.
+ * libgccjit.h: New.
+ * libgccjit.map: New.
+ * notes.txt: New.
+
+2013-07-26 David Malcolm <dmalcolm@redhat.com>
+
+ * Initial creation
+
+Copyright (C) 2013-2014 Free Software Foundation, Inc.
+
+Copying and distribution of this file, with or without modification,
+are permitted in any medium without royalty provided the copyright
+notice and this notice are preserved.
--- /dev/null
+2014-11-10 David Malcolm <dmalcolm@redhat.com>
+
+ * docs/_build/texinfo/libgccjit.texi: Regenerate.
+
+2014-11-10 David Malcolm <dmalcolm@redhat.com>
+
+ * dummy-frontend.c: Add includes now needed since r216805 by
+ cgraph.h: hash-map.h, is-a.h, plugin-api.h, vec.h, hashtab.h,
+ hash-set.h, machmode.h, tm.h, hard-reg-set.h, function.h,
+ ipa-ref.h, dumpfile.h.
+ * jit-playback.c: Likewise.
+
+2014-11-05 David Malcolm <dmalcolm@redhat.com>
+
+ * jit-playback.c (gcc::jit::playback::context::handle_locations):
+ Drop the disabled debugging code.
+
+2014-11-05 David Malcolm <dmalcolm@redhat.com>
+
+ * docs/topics/expressions.rst (Type-coercion): Casts between
+ pointer types are valid.
+ * libgccjit.c: Document that gcc_jit_context et al are actually
+ subclasses of the gcc::jit::recording classes.
+ (RETURN_VAL_IF_FAIL): Add top-level descriptive comment.
+ (RETURN_IF_NOT_VALID_BLOCK): Likewise.
+ (RETURN_NULL_IF_NOT_VALID_BLOCK): Likewise.
+ (jit_error): Likewise.
+ (compatible_types): Likewise.
+ (gcc_jit_context_acquire): Likewise.
+ (gcc_jit_context_release): Likewise.
+ (gcc_jit_context_new_child_context): Likewise.
+ (gcc_jit_context_new_location): Likewise.
+ (gcc_jit_location_as_object): Likewise.
+ (gcc_jit_type_as_object): Likewise.
+ (gcc_jit_context_get_type): Likewise.
+ (gcc_jit_context_get_int_type): Likewise.
+ (gcc_jit_type_get_pointer): Likewise.
+ (gcc_jit_type_get_const): Likewise.
+ (gcc_jit_type_get_volatile): Likewise.
+ (gcc_jit_context_new_array_type): Likewise. Also document that
+ LOC can be NULL. Fail with an error on negative size.
+ (gcc_jit_context_new_field): Add top-level descriptive comment and
+ document that LOC can be NULL.
+ (gcc_jit_field_as_object): Add top-level descriptive comment.
+ (gcc_jit_context_new_struct_type): Likewise. Also document that
+ LOC can be NULL.
+ (gcc_jit_context_new_opaque_struct): Likewise.
+ (gcc_jit_struct_as_type): Add top-level descriptive comment.
+ (gcc_jit_struct_set_fields): Likewise. Also document that LOC can
+ be NULL.
+ (gcc_jit_context_new_union_type): Likewise.
+ (gcc_jit_context_new_function_ptr_type): Likewise.
+ (gcc_jit_context_new_param): Likewise.
+ (gcc_jit_param_as_object): Add top-level descriptive comment.
+ (gcc_jit_param_as_lvalue): Likewise.
+ (gcc_jit_param_as_rvalue): Likewise.
+ (gcc_jit_context_new_function): Likewise. Also document that LOC
+ can be NULL.
+ (gcc_jit_context_get_builtin_function): Add top-level descriptive
+ comment.
+ (gcc_jit_function_as_object): Likewise.
+ (gcc_jit_function_get_param): Likewise.
+ (gcc_jit_function_dump_to_dot): Likewise.
+ (gcc_jit_function_new_block): Likewise.
+ (gcc_jit_block_as_object): Likewise.
+ (gcc_jit_block_get_function): Likewise.
+ (gcc_jit_context_new_global): Likewise. Also document that LOC
+ can be NULL.
+ (gcc_jit_lvalue_as_object): Add top-level descriptive comment.
+ (gcc_jit_lvalue_as_rvalue): Likewise.
+ (gcc_jit_rvalue_as_object): Likewise.
+ (gcc_jit_rvalue_get_type): Likewise.
+ (RETURN_NULL_IF_FAIL_NONNULL_NUMERIC_TYPE): Likewise.
+ (gcc_jit_context_new_rvalue_from_int): Likewise.
+ (gcc_jit_context_zero): Likewise.
+ (gcc_jit_context_one): Likewise.
+ (gcc_jit_context_new_rvalue_from_double): Likewise.
+ (gcc_jit_context_new_rvalue_from_ptr): Likewise.
+ (gcc_jit_context_null): Likewise.
+ (gcc_jit_context_new_string_literal): Likewise.
+ (gcc_jit_context_new_unary_op): Likewise. Also document that LOC
+ can be NULL.
+ (gcc_jit_context_new_binary_op): Likewise.
+ (gcc_jit_context_new_comparison): Likewise.
+ (gcc_jit_context_new_call): Likewise.
+ (gcc_jit_context_new_call_through_ptr): Likewise.
+ (is_valid_cast): Add top-level descriptive comment.
+ (gcc_jit_context_new_cast): Likewise. Also document that LOC can
+ be NULL.
+ (gcc_jit_context_new_array_access): Likewise.
+ (gcc_jit_object_get_context): Add top-level descriptive comment.
+ (gcc_jit_object_get_debug_string): Likewise.
+ (gcc_jit_lvalue_access_field): Likewise. Also document that LOC can
+ be NULL.
+ (gcc_jit_rvalue_access_field): Likewise.
+ (gcc_jit_rvalue_dereference_field): Likewise.
+ (gcc_jit_rvalue_dereference): Likewise.
+ (gcc_jit_lvalue_get_address): Likewise.
+ (gcc_jit_function_new_local): Likewise.
+ (gcc_jit_block_add_eval): Likewise.
+ (gcc_jit_block_add_assignment): Likewise.
+ (gcc_jit_block_add_assignment_op): Likewise.
+ (is_bool): Add top-level descriptive comment.
+ (gcc_jit_block_end_with_conditional): Likewise. Also document
+ that LOC can be NULL.
+ (gcc_jit_block_add_comment): Likewise.
+ (gcc_jit_block_end_with_jump): Likewise.
+ (gcc_jit_block_end_with_return): Likewise.
+ (gcc_jit_block_end_with_void_return): Likewise.
+ (gcc_jit_context_set_str_option): Add top-level descriptive
+ comment.
+ (gcc_jit_context_set_int_option): Likewise.
+ (gcc_jit_context_set_bool_option): Likewise.
+ (gcc_jit_context_compile): Likewise.
+ (gcc_jit_context_dump_to_file): Likewise.
+ (gcc_jit_context_get_first_error): Likewise.
+ (gcc_jit_result_get_code): Likewise.
+ (gcc_jit_result_release): Likewise.
+
+ * libgccjit.h (gcc_jit_context_acquire): Remove FIXME from
+ comment.
+ (gcc_jit_context_get_int_type): Add comment.
+ (gcc_jit_context_new_field): Likewise.
+ (gcc_jit_context_new_struct_type): Likewise.
+ (gcc_jit_context_new_opaque_struct): Likewise.
+ (gcc_jit_struct_as_type): Likewise.
+ (gcc_jit_context_new_param): Likewise.
+ (gcc_jit_param_as_lvalue): Likewise.
+ (gcc_jit_param_as_rvalue): Likewise.
+ (enum gcc_jit_function_kind): Likewise.
+ (gcc_jit_context_new_function): Likewise.
+ (gcc_jit_context_get_builtin_function): Likewise.
+ (gcc_jit_function_get_param): Likewise.
+
+2014-11-05 David Malcolm <dmalcolm@redhat.com>
+
+ * libgccjit.c (gcc_jit_context_get_type): Verify that "type"
+ is valid immediately, rather than relying on called code.
+ (gcc_jit_context_new_function): Likewise for "kind".
+ (gcc_jit_context_new_unary_op): Likewise for "op".
+ (valid_binary_op_p): New.
+ (gcc_jit_context_new_binary_op): Verify that "op" is valid
+ immediately, rather than relying on called code.
+ (gcc_jit_context_new_comparison): Likewise.
+ (gcc_jit_block_add_assignment_op): Likewise.
+
+2014-11-05 David Malcolm <dmalcolm@redhat.com>
+
+ * libgccjit.c: Include safe-ctype.h from libiberty.
+ (IS_ASCII_ALPHA): Delete.
+ (IS_ASCII_DIGIT): Delete.
+ (IS_ASCII_ALNUM): Delete.
+ (gcc_jit_context_new_function): Replace use of IS_ASCII_ALPHA and
+ IS_ASCII_ALNUM with ISALPHA and ISALNUM respectively, from
+ libiberty.
+
+2014-10-30 David Malcolm <dmalcolm@redhat.com>
+
+ * dummy-frontend.c (jit_langhook_init): Remove some dead code.
+
+2014-10-27 David Malcolm <dmalcolm@redhat.com>
+
+ * dummy-frontend.c: Drop includes of tree-iterator.h,
+ tree-ssa-alias.h, gimple-expr.h, gimple.h, gimple-pretty-print.h.
+ * jit-playback.c: Drop includes of debug.h, langhooks.h,
+ langhooks-def.h, tree-iterator.h, gimple-expr.h, tree-ssa-alias.h,
+ gimple.h, gimple-pretty-print.h, diagnostic-core.h, dumpfile.h.
+
+2014-10-21 David Malcolm <dmalcolm@redhat.com>
+
+ * jit-recording.c: Include tm.h. Don't include function.h.
+
+2014-10-21 David Malcolm <dmalcolm@redhat.com>
+
+ * docs/_build/texinfo/libgccjit.texi: Regenerate.
+
+2014-10-21 David Malcolm <dmalcolm@redhat.com>
+
+ * docs/intro/index.rst: Drop install.rst. Add tutorial04.rst.
+ * docs/intro/install.rst: Rename to...
+ * docs/intro/tutorial01.rst: ...this, renaming old tutorial01.rst to...
+ * docs/intro/tutorial02.rst: ...this, renaming old tutorial02.rst to...
+ * docs/intro/tutorial03.rst: ...this, renaming old tutorial03.rst to...
+ * docs/intro/tutorial04.rst: ...this.
+ * docs/examples/install-hello-world.c: Rename to...
+ * docs/examples/tut01-hello-world.c: ...this.
+ * docs/examples/tut01-square.c: Rename to...
+ * docs/examples/tut02-square.c: ...this.
+ * docs/examples/tut02-sum-of-squares.c: Rename to...
+ * docs/examples/tut03-sum-of-squares.c: ...this.
+ * docs/examples/tut03-toyvm: Rename directory to...
+ * docs/examples/tut04-toyvm: ...this.
+ * docs/examples/tut04-toyvm/toyvm.c (PATH_TO_SCRIPTS): Update
+ for directory renaming.
+
+2014-10-21 David Malcolm <dmalcolm@redhat.com>
+
+ * docs/intro/install.rst ("Installation via packages"): Drop
+ this section.
+ ("Installation from source"): Drop this section, moving parts
+ of it to https://gcc.gnu.org/wiki/JIT and some others to
+ docs/internals/index.rst.
+ ("Hello world"): This section becomes the only remaining part
+ of this file. Eliminate references to pkg-config.
+
+ * docs/internals/index.rst
+ ("Using a working copy without installing every time"): Rewrite
+ as...
+ ("Working on the JIT library"): ...new section, aimed at
+ contributors (and myself) working from a build directory,
+ eliminating references to installation. Add description
+ of pertinent configuration options.
+ ("Running the test suite"): Add setting of LIBRARY_PATH to
+ description of how to run a built binary outside of the test
+ suite.
+ ("Environment variables"): New section, describing pertinent
+ environment variables.
+
+2014-10-20 David Malcolm <dmalcolm@redhat.com>
+
+ * jit-recording.c (gcc::jit::dump::dump): Handle fopen failures
+ by emitting an error on the context.
+ (gcc::jit::dump::~dump): Likewise for fclose failures.
+ (gcc::jit::dump::write): Don't attempt further work if the fopen
+ failed. Handle fwrite failures by emitting an error on the
+ context.
+
+2014-10-20 David Malcolm <dmalcolm@redhat.com>
+
+ * Make-lang.in (jit.install-common): Drop installation of
+ libgccjit.pc.
+ * config-lang.in (outputs): Drop jit/libgccjit.pc.
+ * libgccjit.pc.in: Delete.
+
+2014-10-17 David Malcolm <dmalcolm@redhat.com>
+
+ * Make-lang.in (jit): Add $(FULL_DRIVER_NAME) as a dependency, so
+ that the symlink is created for testing.
+
+ * jit-playback.c (gcc::jit::playback::context::compile): Add
+ "-fno-use-linker-plugin" when invoking the driver. Update error
+ messages to talk about the "gcc driver" rather than the
+ "gcc harness". To ease troubleshooting, add error messages giving
+ the driver name and PATH to the error-handling code that fires
+ when the driver can't be found.
+
+2014-10-07 David Malcolm <dmalcolm@redhat.com>
+
+ * docs/_build/texinfo/libgccjit.texi: Regenerate.
+
+2014-10-07 David Malcolm <dmalcolm@redhat.com>
+
+ * docs/internals/index.rst (Overview of code structure): Directly
+ include the comment from jit-common.h as rst, rather than as a
+ quoted C++ comment.
+ * jit-common.h: Convert the summary format to valid reStructured
+ text for inclusion by docs/internals/index.rst.
+ * notes.txt: Clarify where libgccjit.c, jit-recording.c and
+ jit-playback.c fit into the high-level diagram.
+
+2014-10-07 David Malcolm <dmalcolm@redhat.com>
+
+ * Make-lang.in (jit_OBJS): Drop jit/internal-api.o.
+ Add jit/jit-recording.o and jit/jit-playback.o.
+
+ * internal-api.c: Delete, moving content to new files jit-recording.c
+ and jit-playback.c.
+ * internal-api.h: Delete, moving content to new files
+ jit-common.h, jit-playback.h, jit-recording.h.
+ * jit-common.h: New file, containing the forward decls of classes
+ formerly in internal-api.h.
+ * jit-recording.c: New file, containing the gcc::jit::recording
+ code formerly in internal-api.c, and gcc::jit::dump.
+ * jit-recording.h: New file, containing the gcc::jit::recording
+ prototypes formerly in internal-api.h.
+ * jit-playback.c: New file, containing the gcc::jit::playback
+ code formerly in internal-api.c.
+ * jit-playback.h: New file, containing the gcc::jit::playback
+ prototypes formerly in internal-api.h.
+
+ * dummy-frontend.c: Don't include "internal-api.h". Add includes
+ of jit-common.h and jit-playback.h.
+ * jit-builtins.h: Replace include of internal-api.h with
+ jit-common.h.
+ * jit-builtins.c: Replace include of internal-api.h with
+ jit-common.h. Add include of jit-recording.h.
+ * libgccjit.c: Likewise.
+
+ * docs/internals/index.rst (Overview of code structure): Update
+ to reflect the above changes.
+
+2014-10-07 David Malcolm <dmalcolm@redhat.com>
+
+ * docs/internals/index.rst
+ (Using a working copy without installing): Rename to...
+ (Using a working copy without installing every time): ...this, and
+ update to reflect the need to have installed the driver binary
+ when running directly from a build directory.
+ (Running the test suite): Add PATH setting to the example.
+ * docs/intro/install.rst ("Hello world"): Likewise.
+ * internal-api.c: Include new autogenerated header
+ "gcc-driver-name.h".
+ (gcc::jit::playback::context::compile): Rather than looking for a
+ "gcc" on the path, look for GCC_DRIVER_NAME from gcc-driver-name.h,
+ as created by the configure script, so that we are using one for
+ the correct target.
+
+2014-10-02 David Malcolm <dmalcolm@redhat.com>
+
+ * Make-lang.in (jit.info): Implement.
+ (jit.install-info): Implement.
+ (jit.dvi): Implement.
+ (jit.pdf): Implement in terms of new target "jit.texinfo.pdf".
+ (jit.install-pdf): Likewise for new target
+ "jit.texinfo.install-pdf".
+ (jit.install-html): Implement in terms of
+ "jit.$(doc_build_sys).install-html" to redirect to new targets
+ "jit.sphinx.install-html" or "jit.texinfo.install-html".
+ (jit.html): Implement in terms of "jit.$(doc_build_sys).html" to
+ redirect to new targets "jit.sphinx.html" or "jit.texinfo.html".
+ (JIT_TEXI_FILES): New variable.
+ (jit.texinfo.html): New target.
+ (jit.texinfo.install-html): New target.
+ (jit.texinfo.pdf): New target.
+ (jit.texinfo.install-pdf): New target.
+ (SPHINX_BUILD_DIR): New variable.
+ (jit.sphinx.html): New target.
+ (jit_htmldir): New variable.
+ (jit.sphinx.install-html): New target.
+ (jit.sphinx.pdf): New target.
+
+2014-09-26 David Malcolm <dmalcolm@redhat.com>
+
+ * internal-api.h (gcc::jit::recording::context): Convert field
+ "m_first_error_str" from a fixed-size buffer to a pointer, and add
+ a field "m_owns_first_error_str" to determine if we're responsible
+ for freeing it.
+ * internal-api.c (gcc::jit::recording::context::context): Update
+ initializations in ctor for above change.
+ (gcc::jit::recording::context::~context): Free m_first_error_str
+ if we own it.
+ (gcc::jit::recording::context::add_error_va): When capturing the
+ first error message on a context, rather than copying "errmsg" to
+ a fixed-size buffer and truncating if oversize, simply store the
+ pointer to the error message, and flag whether we need to free it.
+ (gcc::jit::recording::context::get_first_error): Update for change
+ of "m_first_error_str" from an internal buffer to a pointer.
+
+2014-09-25 David Malcolm <dmalcolm@redhat.com>
+
+ * internal-api.c (gcc::jit::playback::context::compile): Use
+ pex_one rather than system when invoking "gcc" to go from a .s
+ file to a .so file.
+
+2014-09-25 David Malcolm <dmalcolm@redhat.com>
+
+ * internal-api.c (make_tempdir_path_template): New.
+ (gcc::jit::playback::context::compile): Call
+ make_tempdir_path_template to make m_path_template, rather than
+ hardcoding "/tmp/" within "/tmp/libgccjit-XXXXXX".
+
+2014-09-24 David Malcolm <dmalcolm@redhat.com>
+
+ * docs/internals/index.rst ("Overview of code structure"): Add
+ more descriptive text, including various fragments of
+ internal-api.h as appropriate.
+ * internal-api.h: Add marker comments for use by "literalinclude"
+ directives in docs/internals/index.rst.
+
+2014-09-24 David Malcolm <dmalcolm@redhat.com>
+
+ * dummy-frontend.c (my_walker): Rename to...
+ (my_ggc_walker): ...this.
+ (my_root_tab): Rename to...
+ (jit_root_tab): ...this.
+ (jit_langhook_init): Update for renaming of "my_root_tab" to
+ "jit_root_tab".
+ * internal-api.c: Add descriptive API comments to functions
+ throughout.
+ (mutex): Rename to...
+ (jit_mutex): ...this.
+ (gcc::jit::recording::context::compile): Update for renaming of
+ "mutex" to "jit_mutex".
+ * internal-api.h: Add descriptive API comments to functions
+ throughout. Add indentation to forward declarations of classes
+ to indicate inheritance.
+ * jit-builtins.c: Likewise.
+
+2014-09-24 David Malcolm <dmalcolm@redhat.com>
+
+ * internal-api.c (gcc::jit::dump::write): Eliminate fixed-size
+ buffer "buf" by replacing call to vsnprintf with one to vasprintf
+ and a free, emitting an error on the dump's context if a malloc
+ failure occurs.
+ (gcc::jit::recording::context::add_error_va): Likewise, using
+ a precanned message if the malloc inside vasprinf fails. Split
+ local "buf" into "malloced_msg" and "errmsg" to ensure that we
+ free the message iff we're using one malloc-ed by vasprintf.
+ (gcc::jit::recording::string::from_printf): Eliminate fixed-size
+ buffer "buf" by replacing call to vsnprintf with one to vasprintf
+ and a free, emitting an error on the relevant context if a malloc
+ failure occurs.
+
+2014-09-24 David Malcolm <dmalcolm@redhat.com>
+
+ * dummy-frontend.c: Update copyright year. Follow standard for
+ initial includes by removing redundant include of "ansidecl.h".
+ * internal-api.c: Follow standard for initial includes by removing
+ redundant include of "ansidecl.h".
+ * jit-builtins.c: Likewise.
+ * libgccjit.c: Likewise.
+
+2014-09-24 David Malcolm <dmalcolm@redhat.com>
+
+ * ChangeLog.jit: Add copyright footer.
+ * Make-lang.in: Update copyright.
+ * config-lang.in: Update copyright.
+ * docs/examples/install-hello-world.c: Add copyright header.
+ * docs/examples/tut01-square.c: Likewise.
+ * docs/examples/tut02-sum-of-squares.c: Likewise.
+ * docs/examples/tut03-toyvm/toyvm.c: Likewise.
+ * internal-api.c: Likewise.
+ * internal-api.h: Likewise.
+ * libgccjit++.h: Likewise.
+ * libgccjit.c: Likewise.
+ * libgccjit.h: Likewise.
+ * libgccjit.map: Likewise.
+
+2014-09-23 David Malcolm <dmalcolm@redhat.com>
+
+ * TODO.rst (API): Shift operators are done.
+ * docs/topics/expressions.rst (Binary): Add shift operators.
+ * internal-api.c (binary_op_strings): Likewise.
+ (gcc::jit::playback::context::new_binary_op): Likewise.
+ * libgccjit.h (enum gcc_jit_binary_op): Likewise.
+
+2014-09-23 David Malcolm <dmalcolm@redhat.com>
+
+ * TODO.rst: Rename "Initial Release" section to "API", and
+ remove completed items: builtins, docs, pkgconfig file, fuzz
+ testing. Move ability to name contexts and stmt_list per block
+ ideas to a new "Nice to have" section and note that it might be
+ better to go straight to gimple.
+ Move code coverage to "Test suite" section.
+ Add a "Probably not needed" section, moving some items to it.
+ Note that we're still missing shift operators.
+ Add idea that we could warn about unused objects in a context.
+
+2014-09-23 David Malcolm <dmalcolm@redhat.com>
+
+ * docs/examples/tut03-toyvm/toyvm.c: Include <dejagnu.h>.
+ Add missing typedef of compilation_state.
+ (toyvm_function_parse): Add "name param.
+ (test): New.
+ (CHECK_NON_NULL): New, from harness.h
+ (CHECK_VALUE): Likewise.
+ (test_script): New.
+ (PATH_TO_SCRIPTS): New define.
+ (test_suite): New.
+ (main): If called with no args, run the test suite.
+
+2014-09-23 David Malcolm <dmalcolm@redhat.com>
+
+ * docs/conf.py (__read_file): New helper function, for
+ extracting...
+ (gcc_BASEVER): New variable, read from "BASE-VER" in gcc src dir.
+ (gcc_DEVPHASE): Likewise, from file "DEV-PHASE".
+ (gcc_DATESTAMP): Likewise, from file "DATESTAMP".
+ (gcc_REVISION): Likewise, from file "REVISION" (if present).
+ (version): Rather than hardcoding this variable, extract from file
+ BASE-VER, via gcc_BASEVER local.
+ (release): Likewise, building it up from the files read above.
+ * docs/_build/texinfo/libgccjit.texi: Regenerate.
+
+2014-09-22 David Malcolm <dmalcolm@redhat.com>
+
+ * docs/intro/tutorial01.rst: Remove stray "FIXME".
+ * docs/_build/texinfo/libgccjit.texi: Regenerate.
+
+2014-09-22 David Malcolm <dmalcolm@redhat.com>
+
+ * docs/index.rst: Add internals/index.rst.
+ * docs/internals/index.rst: New.
+ * notes.txt: Update to reflect renaming of toplev_main to
+ toplev::main.
+
+2014-09-22 David Malcolm <dmalcolm@redhat.com>
+
+ * docs/_build/texinfo/libgccjit.texi: Regenerate.
+ * docs/intro/install.rst: Reduce width of listing.
+ * docs/intro/tutorial01.rst: Use <libgccjit.h> rather than
+ "libgccjit.h" when including the header.
+ * docs/intro/tutorial02.rst: Likewise.
+ * docs/intro/tutorial03.rst: Clarify various sections; show
+ effect of reducing optimization level down from 3 to 2.
+ ("Putting it all together"): Move to above...
+ ("Behind the curtain: optimizing away stack manipulation"):
+ ...this, and rename this to...
+ ("Behind the curtain: How does our code get optimized?"): ...and
+ add more detail, and discussion of elimination of tail recursion.
+
+2014-09-19 David Malcolm <dmalcolm@redhat.com>
+
+ * TODO.rst: Add detection of uninitialized variables, since
+ this bit me when developing "toyvm".
+
+ * docs/examples/tut03-toyvm/Makefile: New.
+ * docs/examples/tut03-toyvm/factorial.toy: New.
+ * docs/examples/tut03-toyvm/fibonacci.toy: New.
+ * docs/examples/tut03-toyvm/toyvm.c: New.
+
+ * docs/intro/index.rst: Add tutorial03.rst.
+ * docs/intro/tutorial01.rst: Fix example of how to dump
+ generated machine code.
+ * docs/intro/tutorial03.rst: New.
+ * docs/intro/factorial.png: New.
+
+ * docs/_build/texinfo/libgccjit.texi: Regenerate.
+ * docs/_build/texinfo/factorial.png: New (copied by sphinx from
+ docs/intro/factorial.png).
+
+2014-09-18 David Malcolm <dmalcolm@redhat.com>
+
+ * Make-lang.in (jit.install-common): Install libgccjit.pc to
+ "$(DESTDIR)/$(libdir)/pkgconfig".
+ * config-lang.in (outputs): Define this, adding jit/libgccjit.pc
+ so that it makes it into AC_CONFIG_FILES and is thus generated from
+ jit/libgccjit.pc.in at configure time.
+ * docs/intro/install.rst ("Hello world"): Add discussion about the
+ use of pkg-config when building against an install in
+ a non-standard location.
+ * docs/_build/texinfo/libgccjit.texi: Regenerate.
+ * libgccjit.pc.in: New.
+
+2014-09-18 David Malcolm <dmalcolm@redhat.com>
+
+ * docs/index.rst: Split index out into two new files...
+ * docs/intro/index.rst: New file.
+ * docs/topics/index.rst: New file.
+ * docs/_build/texinfo/libgccjit.texi: Regenerate.
+
+2014-09-18 David Malcolm <dmalcolm@redhat.com>
+
+ * docs/_build/texinfo/Makefile: New file, generated by Sphinx, by
+ running "make texinfo" in docs directory.
+ * docs/_build/texinfo/libgccjit.texi: Likewise.
+ * docs/_build/texinfo/sum-of-squares.png: Likewise.
+
+2014-09-18 David Malcolm <dmalcolm@redhat.com>
+
+ * docs/conf.py (Options for HTML output): Update html_theme from
+ "default" to "pyramid".
+
+2014-09-18 David Malcolm <dmalcolm@redhat.com>
+
+ * docs/intro/install.rst: Markup fixes.
+ * docs/intro/tutorial01.rst: Likewise.
+ * docs/intro/tutorial02.rst: Likewise.
+ * docs/topics/contexts.rst: Likewise.
+ * docs/topics/expressions.rst: Likewise.
+ * docs/topics/functions.rst: Likewise.
+ * docs/topics/locations.rst: Likewise.
+ * docs/topics/types.rst: Likewise.
+
+2014-09-18 David Malcolm <dmalcolm@redhat.com>
+
+ * docs/examples/install-hello-world.c (main): Fix missing
+ "return".
+ * docs/examples/tut01-square.c (main): Likewise.
+ * docs/examples/tut02-sum-of-squares.c (main): Likewise.
+
+2014-09-17 David Malcolm <dmalcolm@redhat.com>
+
+ * docs/Makefile: New file.
+ * docs/conf.py: New file.
+ * docs/examples/install-hello-world.c: New file.
+ * docs/examples/tut01-square.c: New file.
+ * docs/examples/tut02-sum-of-squares.c: New file.
+ * docs/index.rst: New file.
+ * docs/intro/install.rst: New file.
+ * docs/intro/sum-of-squares.png: New file.
+ * docs/intro/tutorial01.rst: New file.
+ * docs/intro/tutorial02.rst: New file.
+ * docs/topics/contexts.rst: New file.
+ * docs/topics/expressions.rst: New file.
+ * docs/topics/functions.rst: New file.
+ * docs/topics/locations.rst: New file.
+ * docs/topics/objects.rst: New file.
+ * docs/topics/results.rst: New file.
+ * docs/topics/types.rst: New file.
+
+2014-09-11 David Malcolm <dmalcolm@redhat.com>
+
+ * TODO.rst (Initial Release): Update for addition of myself as
+ maintainer.
+
+2014-09-10 David Malcolm <dmalcolm@redhat.com>
+
+ * TODO.rst (Test suite): Multithreaded test is done.
+
+2014-09-10 David Malcolm <dmalcolm@redhat.com>
+
+ * dummy-frontend.c: Fix up for the header file flattening on
+ trunk by adding includes of signop.h, tree-core.h, stor-layout.h,
+ tree-ssa-alias.h, gimple-expr.h.
+ (jit_langhook_write_globals): Update call to
+ finalize_compilation_unit to symtab->finalize_compilation_unit to
+ track change made on trunk in r214422.
+
+ * internal-api.c: Fix up for the header file flattening on trunk
+ by adding includes of gimple-expr.h, tree-ssa-alias.h,
+ stringpool.h, stor-layout.h, print-tree.h, gimplify.h.
+ (new_rvalue_from_int): Update call to real_from_integer.
+ (gcc::jit::playback::wrapper::operator new): Use
+ ggc_internal_cleared_alloc rather than
+ ggc_internal_cleared_alloc_stat.
+ (gcc::jit::playback::function::postprocess): Update call to
+ cgraph_finalize_function tocgraph_node::finalize_function.
+ (gcc::jit::playback::block::add_comment): Update call to
+ ggc_internal_alloc_stat to ggc_internal_alloc.
+
+2014-08-08 David Malcolm <dmalcolm@redhat.com>
+
+ * libgccjit.h (gcc_jit_context_new_union_type): New entrypoint.
+ (gcc_jit_lvalue_access_field): Rename first param from "struct_"
+ to "struct_or_union".
+ (gcc_jit_rvalue_access_field): Likewise.
+
+ * libgccjit.c (gcc_jit_context_new_union_type): New entrypoint.
+
+ * libgccjit.map (gcc_jit_context_new_union_type): New entrypoint.
+
+ * internal-api.h (gcc::jit::recording::compound_type): New class
+ (gcc::jit::recording::union): New class.
+ (gcc::jit::playback::struct_): Rename this class to...
+ (gcc::jit::playback::compound_type): ...this.
+ (gcc::jit::recording::context::new_union_type): New method.
+ (gcc::jit::recording::context): Rename field "m_structs" to
+ "m_compound_types", generalizing from a vec <struct_ *> to a
+ vec<compound_type *>.
+ (gcc::jit::recording::field): Update field m_container from
+ struct * to container_type *.
+ (gcc::jit::recording::field::get_container): Generalize from
+ struct_ * to container_type *.
+ (gcc::jit::recording::field::set_container): Likewise.
+ (gcc::jit::recording::compound_type): New subclass of type, to
+ be a superclass of existing class struct_ and new class union_.
+ (gcc::jit::recording::struct_::get_name): Move to...
+ (gcc::jit::recording::compound_type::get_name): ...here.
+ (gcc::jit::recording::struct_::get_loc): Move to...
+ (gcc::jit::recording::compound_type::get_loc): ...here.
+ (gcc::jit::recording::struct_::set_fields): Move to...
+ (gcc::jit::recording::compound_type::set_fields): ...here.
+ (gcc::jit::recording::struct_::dereference): Move to...
+ (gcc::jit::recording::compound_type::dereference): ...here.
+ (gcc::jit::recording::struct_::is_int): Move to...
+ (gcc::jit::recording::compound_type::is_int): ...here.
+ (gcc::jit::recording::struct_::is_float): Move to...
+ (gcc::jit::recording::compound_type::is_float): ...here.
+ (gcc::jit::recording::struct_::is_bool): Move to...
+ (gcc::jit::recording::compound_type::is_bool): ...here.
+ (gcc::jit::recording::struct_::is_pointer): Move to...
+ (gcc::jit::recording::compound_type::is_pointer): ...here.
+ (gcc::jit::recording::struct_::is_array): Move to...
+ (gcc::jit::recording::compound_type::is_array): ...here.
+ (gcc::jit::recording::struct_::playback_struct): Move to...
+ (gcc::jit::recording::compound_type::playback_compound_type):
+ ...here, renaming and updating return type.
+ (gcc::jit::recording::struct_): Inherit from compound_type,
+ rather than just type.
+ (gcc::jit::recording::fields): Update to work on compound_type *
+ rather than struct_ *, renaming "m_struct" to "m_struct_or_union".
+ (gcc::jit::recording::union): New subclass of compound_type.
+ (gcc::jit::playback::context::new_struct_type): Generalize by
+ renaming to...
+ (gcc::jit::playback::context::new_compound_type): ...this, and
+ and an "is_struct" bool param.
+ (gcc::jit::playback::struct_): Generalize by renaming class to...
+ (gcc::jit::playback::compound_type): ...this.
+
+ * internal-api.c (gcc::jit::recording::context::context): Rename
+ field "m_structs" to "m_compound_types".
+ (gcc::jit::recording::context::new_struct_type): Likewise.
+ (gcc::jit::recording::context::new_union_type): New method.
+ (gcc::jit::recording::context::dump_to_file): Field "m_structs"
+ is renamed "m_compound_types" and changes type from struct_ *
+ to compound_type *.
+ (gcc::jit::recording::compound_type::compound_type): New ctor,
+ built from old body of gcc::jit::recording::struct_::struct_.
+ (gcc::jit::recording::struct_::set_fields): Move class to...
+ (gcc::jit::recording::compound_type::set_fields): ... here.
+ (gcc::jit::recording::struct_::dereference): Move class to...
+ (gcc::jit::recording::compound_type::dereference): ...here.
+ (gcc::jit::recording::struct_::struct_): Reimplement by calling
+ base class ctor.
+ (gcc::jit::recording::struct_::replay_into): The playback hook
+ is now "new_compound_type" and adds a bool, with true for
+ "is_struct" (vs a union).
+ (gcc::jit::recording::struct_::make_debug_string): "m_name" is
+ now moved to base class and private, so use an accessor.
+ (gcc::jit::recording::union_::union_): New function.
+ (gcc::jit::recording::union_::replay_into): New function.
+ (gcc::jit::recording::union_::make_debug_string): New function.
+ (gcc::jit::recording::fields::fields): Update first param from
+ struct_ * to compound_type *, and rename field "m_struct" to
+ "m_struct_or_union".
+ (gcc::jit::recording::fields::replay_into): "m_struct" is now
+ "m_struct_or_union" and has a playback_compound_type rather
+ than a playback_struct.
+ (gcc::jit::recording::fields::write_to_dump): Update for
+ renaming of m_struct to m_struct_or_union.
+ (gcc::jit::playback::context::new_struct_type): Rename method
+ to...
+ (gcc::jit::playback::context::new_compound_type): this,
+ generalizing so that it can make unions as well as structs; the
+ underlying playback type is now called "compound_type".
+ (gcc::jit::playback::struct_::set_fields): This method's class has
+ changed name, so this is now...
+ (gcc::jit::playback::compound_type::set_fields): ...this method.
+
+ * TODO.rst: Unions are done.
+
+2014-08-08 David Malcolm <dmalcolm@redhat.com>
+
+ * TODO.rst: Function ptrs are done.
+ * internal-api.c
+ (gcc::jit::recording::context::new_function_ptr_type): New method.
+ (gcc::jit::recording::context::new_call_through_ptr): New method.
+ (gcc::jit::recording::memento_of_get_pointer::make_debug_string):
+ Add special-case handling of function pointer types.
+ (gcc::jit::recording::function_type::make_debug_string_with_ptr):
+ New method.
+ (gcc::jit::recording::function_type::make_debug_string):
+ Reimplement in terms of...
+ (gcc::jit::recording::function_type::make_debug_string_with): New
+ method, based on make_debug_string, but allowing for arbitrary
+ text between the return type and the parameters.
+ (gcc::jit::recording::call_through_ptr::call_through_ptr): New
+ method.
+ (gcc::jit::recording::call_through_ptr::replay_into): New method.
+ (gcc::jit::recording::call_through_ptr::make_debug_string): New
+ method.
+ (gcc::jit::playback::context::new_call): Reimplement in terms of...
+ (gcc::jit::playback::context::build_call): New method, using parts
+ of old implementation of new_call, so that we can share this
+ with...
+ (gcc::jit::playback::context::new_call_through_ptr): New method.
+ * internal-api.h
+ (gcc::jit::recording::context::new_function_ptr_type): New method.
+ (gcc::jit::recording::context::new_call_through_ptr): New method.
+ (gcc::jit::recording::type::dyn_cast_function_type): New method.
+ (gcc::jit::recording::function_type::dyn_cast_function_type): New
+ method.
+ (gcc::jit::recording::function_type::make_debug_string_with_ptr):
+ New method.
+ (gcc::jit::recording::function_type::make_debug_string_with): New
+ method.
+ (gcc::jit::recording::call_through_ptr): New subclass of rvalue.
+ (gcc::jit::playback::context::new_call_through_ptr): New method.
+ (gcc::jit::playback::context::build_call): New method.
+ * libgccjit.c (gcc_jit_context_new_function_ptr_type): New
+ function.
+ (gcc_jit_context_new_call_through_ptr): New function.
+ * libgccjit.h (gcc_jit_context_new_function_ptr_type): New
+ function.
+ (gcc_jit_context_new_call_through_ptr): New function.
+ * libgccjit.map (gcc_jit_context_new_call_through_ptr): New function.
+ (gcc_jit_context_new_function_ptr_type): New function.
+
+2014-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * TODO.rst (error-checking): Remove various items that either
+ already were implemented, or are implemented by this commit.
+ * internal-api.h (gcc::jit::recording::type::is_numeric): New.
+ * libgccjit.c (RETURN_NULL_IF_FAIL_NONNULL_NUMERIC_TYPE): New macro.
+ (gcc_jit_context_new_rvalue_from_int): Verify that numeric_type is
+ indeed numeric.
+ (gcc_jit_context_zero): Likewise.
+ (gcc_jit_context_one): Likewise.
+ (gcc_jit_context_new_rvalue_from_double): Likewise.
+ (gcc_jit_context_new_array_access): Likewise for type of "index".
+
+2014-07-14 David Malcolm <dmalcolm@redhat.com>
+
+ * internal-api.c (gcc::jit::recording::context::new_array_type):
+ Reject attempts to create an array of a struct if the fields of
+ the struct haven't yet been set.
+ * internal-api.h (gcc::jit::recording::type::dyn_cast_struct): New
+ virtual function.
+ (gcc::jit::recording::struct_::dyn_cast_struct): New, overriding
+ for this subclass.
+ (gcc::jit::recording::struct_::get_name): New.
+
+2014-05-07 David Malcolm <dmalcolm@redhat.com>
+
+ * Make-lang.in (LIBGCCJIT_LINKER_NAME): New.
+ (LIBGCCJIT_VERSION_NUM): New.
+ (LIBGCCJIT_MINOR_NUM): New.
+ (LIBGCCJIT_RELEASE_NUM): New.
+ (LIBGCCJIT_SONAME): New.
+ (LIBGCCJIT_FILENAME): New.
+ (LIBGCCJIT_LINKER_NAME_SYMLINK): New.
+ (LIBGCCJIT_SONAME_SYMLINK): New.
+ (jit): Add symlink targets.
+ (libgccjit.so): Convert to...
+ (LIBGCCJIT_FILENAME): ...and add a soname.
+ (jit.install-common): Install the library with a soname, and
+ symlinks. Install libgccjit++.h.
+
+2014-04-25 David Malcolm <dmalcolm@redhat.com>
+
+ * internal-api.c (gcc::jit::playback::context::compile): Put
+ any output of dlerror through the add_error method, rather
+ than merely printing it to stderr, so that the error is also
+ recorded on the context.
+
+2014-03-19 Tom Tromey <tromey@redhat.com>
+
+ * internal-api.c (compile): Use auto_timevar.
+
+2014-03-19 Tom Tromey <tromey@redhat.com>
+
+ * internal-api.c (compile): Use toplev, not toplev_options.
+ Simplify.
+
+2014-03-19 David Malcolm <dmalcolm@redhat.com>
+
+ * internal-api.c (gcc::jit::recording::context::add_error_va):
+ Rename local "progname" to "ctxt_progname" to avoid shadowing
+ the related global, for clarity.
+ (gcc::jit::playback::context::compile): Likewise.
+
+2014-03-19 David Malcolm <dmalcolm@redhat.com>
+
+ * internal-api.c (gcc::jit::recording::memento_of_get_pointer::
+ accepts_writes_from): Accept writes from pointers, but not arrays.
+
+ * internal-api.h (gcc::jit::recording::type::is_pointer): New.
+ (gcc::jit::recording::type::is_array): New.
+ (gcc::jit::recording::memento_of_get_type::accepts_writes_from):
+ Allow (void *) to accept writes of pointers, but not arrays.
+ (gcc::jit::recording::memento_of_get_type::is_pointer): New.
+ (gcc::jit::recording::memento_of_get_type::is_array): New.
+ (gcc::jit::recording::memento_of_get_pointer::is_pointer): New.
+ (gcc::jit::recording::memento_of_get_pointer::is_array): New.
+ (gcc::jit::recording::memento_of_get_const::is_pointer): New.
+ (gcc::jit::recording::memento_of_get_const::is_array): New.
+ (gcc::jit::recording::memento_of_get_volatile::is_pointer): New.
+ (gcc::jit::recording::memento_of_get_volatile::is_array): New.
+ (gcc::jit::recording::array_type::is_pointer): New.
+ (gcc::jit::recording::array_type::is_array): New.
+ (gcc::jit::recording::function_type::is_pointer): New.
+ (gcc::jit::recording::function_type::is_array): New.
+ (gcc::jit::recording::struct_::is_pointer): New.
+ (gcc::jit::recording::struct_::is_array): New.
+
+ * libgccjit.c (gcc_jit_context_new_rvalue_from_ptr): Require the
+ pointer_type to be a pointer, not an array.
+ (gcc_jit_context_null): Likewise.
+ (is_valid_cast): Require pointer casts to be between pointer types,
+ not arrays.
+ (gcc_jit_context_new_array_access): Update error message from "not
+ a pointer" to "not a pointer or array".
+ (gcc_jit_rvalue_dereference_field): Require the pointer arg to be
+ of pointer type, not an array.
+ (gcc_jit_rvalue_dereference): Likewise.
+
+2014-03-14 David Malcolm <dmalcolm@redhat.com>
+
+ * libgccjit.c (is_valid_cast): Permit casts between pointer types.
+
+ * internal-api.c (convert): Report more information if this ever
+ occurs, and make the error occur on the playback context, so that
+ it makes the gcc_jit_result be NULL.
+ (gcc::jit::playback::context::build_cast): Handle pointers. Report
+ more information if an unhandlable cast reaches here.
+
+2014-03-13 David Malcolm <dmalcolm@redhat.com>
+
+ * libgccjit.c (is_valid_cast): New.
+ (gcc_jit_context_new_cast): Check for compatible types.
+
+ * internal-api.c (gcc::jit::recording::memento_of_get_type::
+ is_int): New.
+ (gcc::jit::recording::memento_of_get_type::is_float): New.
+ (gcc::jit::recording::memento_of_get_type::is_bool): New.
+
+ * internal-api.h (gcc::jit::recording::type::is_int): New.
+ (gcc::jit::recording::type::is_float): New.
+ (gcc::jit::recording::type::is_bool): New.
+
+ (gcc::jit::recording::memento_of_get_type::is_int): New.
+ (gcc::jit::recording::memento_of_get_type::is_float): New.
+ (gcc::jit::recording::memento_of_get_type::is_bool): New.
+
+ (gcc::jit::recording::memento_of_get_pointer::is_int): New.
+ (gcc::jit::recording::memento_of_get_pointer::is_float): New.
+ (gcc::jit::recording::memento_of_get_pointer::is_bool): New.
+
+ (gcc::jit::recording::memento_of_get_const::is_int): New.
+ (gcc::jit::recording::memento_of_get_const::is_float): New.
+ (gcc::jit::recording::memento_of_get_const::is_bool): New.
+
+ (gcc::jit::recording::memento_of_get_volatile::is_int): New.
+ (gcc::jit::recording::memento_of_get_volatile::is_float): New.
+ (gcc::jit::recording::memento_of_get_volatile::is_bool): New.
+
+ (gcc::jit::recording::array_type::is_int): New.
+ (gcc::jit::recording::array_type::is_float): New.
+ (gcc::jit::recording::array_type::is_bool): New.
+
+ (gcc::jit::recording::function_type::is_int): New.
+ (gcc::jit::recording::function_type::is_float): New.
+ (gcc::jit::recording::function_type::is_bool): New.
+
+ (gcc::jit::recording::struct_::is_int): New.
+ (gcc::jit::recording::struct_::is_float): New.
+ (gcc::jit::recording::struct_::is_bool): New.
+
+2014-03-13 David Malcolm <dmalcolm@redhat.com>
+
+ * internal-api.c (gcc::jit::recording::context::set_str_option):
+ Provide NULL recording::location to add_error.
+ (gcc::jit::recording::context::set_int_option): Likewise.
+ (gcc::jit::recording::context::set_bool_option): Likewise.
+ (gcc::jit::playback::context::compile): Likewise.
+ (gcc::jit::recording::context::add_error): Add recording::location
+ param.
+ (gcc::jit::recording::context::add_error_va): Likewise; print it
+ when present; add "error: " to stderr messages.
+ (gcc::jit::recording::location::replay_into): Provide
+ recording::location to the playback::location.
+
+ (gcc::jit::recording::function::validate): Add locations to the
+ add_error invocations.
+ (gcc::jit::recording::block::validate): Likewise.
+ (gcc::jit::playback::context::get_type): Likewise.
+ (gcc::jit::playback::context::new_unary_op): Likewise.
+ (gcc::jit::playback::context::new_binary_op): Likewise.
+ (gcc::jit::playback::context::new_comparison): Likewise.
+
+ (gcc::jit::recording::block::get_loc): New.
+ (gcc::jit::recording::block::get_first_statement): New.
+
+ (gcc::jit::playback::context::build_cast): Pass in higher-level
+ arguments in the hope of eventually providing better error
+ messages when a cast isn't possible.
+ (gcc::jit::playback::context::new_cast): As above.
+
+ (gcc::jit::playback::context::add_error): Add playback::location
+ parameter, using it to provide the corresponding
+ recording::location (if any) when reporting the error to the
+ recording::context.
+ (gcc::jit::playback::context::add_error_va): Likewise.
+ (gcc::jit::playback::context::new_location): Likewise.
+ (gcc::jit::playback::source_line::get_location): Likewise.
+ (gcc::jit::playback::location::location): Likewise.
+
+ * internal-api.h (gcc::jit::recording::context::add_error): Add
+ recording::location param.
+ (gcc::jit::recording::context::add_error_va): Likewise.
+
+ (gcc::jit::recording::context::errors_occurred): Also consider
+ errors that occur on a parent or ancestor context, recursively.
+
+ (gcc::jit::recording::block::get_loc): New.
+ (gcc::jit::recording::block::get_first_statement): New.
+ (gcc::jit::recording::statement::get_loc): New.
+
+ (gcc::jit::playback::context::new_location): Add recording::location
+ parameter.
+
+ (gcc::jit::playback::context::add_error): Add playback::location
+ parameter.
+ (gcc::jit::playback::context::add_error_va): Likewise.
+
+ (gcc::jit::playback::context::build_cast): Pass in higher-level
+ arguments in the hope of eventually providing better error
+ messages when a cast isn't possible.
+
+ (gcc::jit::playback::source_line::get_location): Add
+ recording::location parameter.
+ (gcc::jit::playback::location::location): Likewise.
+ (gcc::jit::playback::location::get_recording_loc): New.
+ (gcc::jit::playback::location::m_recording_loc): New.
+
+ * jit-builtins.c (gcc::jit::builtins_manager::get_builtin_function):
+ Provide NULL recording::location to add_error.
+ (gcc::jit::builtins_manager::make_primitive_type): Likewise.
+
+ * libgccjit.c (RETURN_VAL_IF_FAIL): Add location argument.
+ (RETURN_VAL_IF_FAIL_PRINTF1): Likewise.
+ (RETURN_VAL_IF_FAIL_PRINTF2): Likewise.
+ (RETURN_VAL_IF_FAIL_PRINTF3): Likewise.
+ (RETURN_VAL_IF_FAIL_PRINTF4): Likewise.
+ (RETURN_VAL_IF_FAIL_PRINTF6): Likewise.
+ (RETURN_NULL_IF_FAIL): Likewise.
+ (RETURN_NULL_IF_FAIL_PRINTF1): Likewise.
+ (RETURN_NULL_IF_FAIL_PRINTF2): Likewise.
+ (RETURN_NULL_IF_FAIL_PRINTF3): Likewise.
+ (RETURN_NULL_IF_FAIL_PRINTF4): Likewise.
+ (RETURN_NULL_IF_FAIL_PRINTF6): Likewise.
+ (RETURN_IF_FAIL): Likewise.
+ (RETURN_IF_FAIL_PRINTF1): Likewise.
+ (RETURN_IF_FAIL_PRINTF2): Likewise.
+ (RETURN_IF_FAIL_PRINTF4): Likewise.
+ (RETURN_IF_NOT_VALID_BLOCK): Likewise.
+ (RETURN_NULL_IF_NOT_VALID_BLOCK): Likewise.
+
+ (jit_error): Likewise.
+
+ (gcc_jit_location_as_object): Provided location argument to
+ error-handling macros.
+ (gcc_jit_type_as_object): Likewise.
+ (gcc_jit_context_get_type): Likewise.
+ (gcc_jit_context_get_int_type): Likewise.
+ (gcc_jit_type_get_pointer): Likewise.
+ (gcc_jit_type_get_const): Likewise.
+ (gcc_jit_type_get_volatile): Likewise.
+ (gcc_jit_context_new_array_type): Likewise.
+ (gcc_jit_context_new_field): Likewise.
+ (gcc_jit_context_new_struct_type): Likewise.
+ (gcc_jit_context_new_opaque_struct): Likewise.
+ (gcc_jit_struct_as_type): Likewise.
+ (gcc_jit_struct_set_fields): Likewise.
+ (gcc_jit_context_new_param): Likewise.
+ (gcc_jit_param_as_object): Likewise.
+ (gcc_jit_param_as_lvalue): Likewise.
+ (gcc_jit_param_as_rvalue): Likewise.
+ (gcc_jit_context_new_function): Likewise.
+ (gcc_jit_context_get_builtin_function): Likewise.
+ (gcc_jit_function_as_object): Likewise.
+ (gcc_jit_function_get_param): Likewise.
+ (gcc_jit_function_dump_to_dot): Likewise.
+ (gcc_jit_function_new_block): Likewise.
+ (gcc_jit_block_as_object): Likewise.
+ (gcc_jit_block_get_function): Likewise.
+ (gcc_jit_context_new_global): Likewise.
+ (gcc_jit_lvalue_as_object): Likewise.
+ (gcc_jit_lvalue_as_rvalue): Likewise.
+ (gcc_jit_rvalue_as_object): Likewise.
+ (gcc_jit_rvalue_get_type): Likewise.
+ (gcc_jit_context_new_rvalue_from_int): Likewise.
+ (gcc_jit_context_zero): Likewise.
+ (gcc_jit_context_one): Likewise.
+ (gcc_jit_context_new_rvalue_from_double): Likewise.
+ (gcc_jit_context_new_rvalue_from_ptr): Likewise.
+ (gcc_jit_context_null): Likewise.
+ (gcc_jit_context_new_string_literal): Likewise.
+ (gcc_jit_context_new_unary_op): Likewise.
+ (gcc_jit_context_new_binary_op): Likewise.
+ (gcc_jit_context_new_comparison): Likewise.
+ (gcc_jit_context_new_call): Likewise.
+ (gcc_jit_context_new_cast): Likewise.
+ (gcc_jit_context_new_array_access): Likewise.
+ (gcc_jit_object_get_context): Likewise.
+ (gcc_jit_object_get_debug_string): Likewise.
+ (gcc_jit_lvalue_access_field): Likewise.
+ (gcc_jit_rvalue_access_field): Likewise.
+ (gcc_jit_rvalue_dereference_field): Likewise.
+ (gcc_jit_rvalue_dereference_field): Likewise.
+ (gcc_jit_rvalue_dereference): Likewise.
+ (gcc_jit_lvalue_get_address): Likewise.
+ (gcc_jit_function_new_local): Likewise.
+ (gcc_jit_block_add_eval): Likewise.
+ (gcc_jit_block_add_assignment): Likewise.
+ (gcc_jit_block_add_assignment_op): Likewise.
+ (gcc_jit_block_end_with_conditional): Likewise.
+ (gcc_jit_block_add_comment): Likewise.
+ (gcc_jit_block_end_with_jump): Likewise.
+ (gcc_jit_block_end_with_return): Likewise.
+ (gcc_jit_block_end_with_void_return): Likewise.
+ (gcc_jit_context_set_str_option): Likewise.
+ (gcc_jit_context_set_int_option): Likewise.
+ (gcc_jit_context_set_bool_option): Likewise.
+ (gcc_jit_context_compile): Likewise.
+ (gcc_jit_context_dump_to_file): Likewise.
+ (gcc_jit_context_get_first_error): Likewise.
+ (gcc_jit_result_get_code): Likewise.
+ (gcc_jit_result_get_code): Likewise.
+ (gcc_jit_result_release): Likewise.
+
+2014-03-10 David Malcolm <dmalcolm@redhat.com>
+
+ * libgccjit++.h (gccjit::context::new_rvalue): Make these
+ methods const.
+ (gccjit::context::zero): Likewise.
+ (gccjit::context::one): Likewise.
+ (gccjit::function::get_param): Likewise.
+
+2014-03-10 David Malcolm <dmalcolm@redhat.com>
+
+ * libgccjit++.h (gccjit::error): New class, for exceptions.
+ (gccjit::context::get_inner_context): New accessor, so that we
+ can...
+ (gccjit::context::m_inner_ctxt): Make private.
+ (gccjit::context::context): Throw a gccjit::error if a NULL
+ context is passed in.
+ (gccjit::context::compile): Throw a gccjit::error if a NULL
+ result is returned from the C API, which indicates an error.
+ (gccjit::object::object): Throw a gccjit::error if a NULL
+ object is passed in, since that indicates that an error has
+ occurred.
+ (gccjit::location::location): In the default ctor, call the
+ base class default ctor rather than passing in a NULL to the
+ single-argument ctor, since the latter now indicates an error
+ has occurred at the C API level.
+ (gccjit::field::field): Likewise.
+ (gccjit::type::type): Likewise.
+ (gccjit::function::function): Likewise.
+ (gccjit::block::block): Likewise.
+ (gccjit::rvalue::rvalue): Likewise.
+
+2014-03-07 David Malcolm <dmalcolm@redhat.com>
+
+ * libgccjit.h (enum gcc_jit_function_kind): Add
+ GCC_JIT_FUNCTION_ALWAYS_INLINE.
+ * internal-api.c (gcc::jit::recording::function::write_to_dump):
+ Handle GCC_JIT_FUNCTION_ALWAYS_INLINE.
+ (gcc::jit::playback::context::new_function): Likewise.
+ (gcc::jit::playback::context::postprocess): Handle
+ GCC_JIT_FUNCTION_INTERNAL and GCC_JIT_FUNCTION_ALWAYS_INLINE by
+ clearing DECL_EXTERNAL and TREE_PUBLIC. Doing so fixes the
+ "undefined symbol" bug seen with GCC_JIT_FUNCTION_INTERNAL.
+ * TODO.rst: Update.
+
+2014-03-07 David Malcolm <dmalcolm@redhat.com>
+
+ * libgccjit++.h (gccjit::context::new_global): New.
+
+2014-03-07 David Malcolm <dmalcolm@redhat.com>
+
+ * internal-api.c (gcc::jit::playback::context::handle_locations):
+ Add a disabled call to line_table_dump, in case it's handy for
+ debugging in the future.
+ (gcc::jit::playback::context::set_tree_location): Assert that
+ the location is non-NULL.
+ (gcc::jit::playback::location::location): Initialize m_src_loc
+ to UNKNOWN_LOCATION. This field should always be overwritten by
+ handle_locations before use, but given recent issues with bogus
+ locations it seems safer to initialize it.
+
+2014-03-06 David Malcolm <dmalcolm@redhat.com>
+
+ * internal-api.c (gcc::jit::recording::context::
+ disassociate_from_playback): Recursively visit parent contexts.
+
+2014-03-05 David Malcolm <dmalcolm@redhat.com>
+
+ * libgccjit.h (gcc_jit_function_dump_to_dot): New.
+ * libgccjit.map (gcc_jit_function_dump_to_dot): New.
+ * libgccjit++.h (gccjit::function::dump_to_dot): New.
+ * libgccjit.c (gcc_jit_function_dump_to_dot): New.
+ * internal-api.h (gcc::jit::recording::function::dump_to_dot): New.
+ (gcc::jit::recording::block::block): Add m_index member.
+ (gcc::jit::recording::block::dump_to_dot): New.
+ (gcc::jit::recording::block::dump_edges_to_dot): New.
+ * internal-api.c (gcc::jit::recording::function::new_block): Give
+ each block an index.
+ (gcc::jit::recording::function::dump_to_dot): New.
+ (gcc::jit::recording::block::dump_to_dot): New.
+ (gcc::jit::recording::block::dump_edges_to_dot): New.
+
+2014-03-04 David Malcolm <dmalcolm@redhat.com>
+
+ * internal-api.c (gcc::jit::recording::memento_of_get_pointer::
+ accepts_writes_from): Avoid segfaulting when the argument is not
+ of pointer type.
+ * internal-api.h (gcc::jit::recording::accepts_writes_from): Add
+ an assertion.
+ * libgccjit.c (gcc_jit_context_new_comparison): Strip away const
+ and volatile when comparing input types.
+
+2014-03-04 David Malcolm <dmalcolm@redhat.com>
+
+ * libgccjit.h (gcc_jit_type_get_volatile): New.
+ * libgccjit.map (gcc_jit_type_get_volatile): New.
+ * libgccjit.c (gcc_jit_type_get_volatile): New.
+ * libgccjit++.h (gccjit::type::get_volatile): New.
+ * internal-api.c (gcc::jit::recording::type::get_volatile): New.
+ (gcc::jit::recording::memento_of_get_volatile::replay_into): New.
+ (gcc::jit::recording::memento_of_get_volatile::make_debug_string): New.
+ * internal-api.h (gcc::jit::recording::type::get_volatile): New.
+ (gcc::jit::recording::type::accepts_writes_from): Strip off
+ qualifiers such as "const" and "volatile" from the source type.
+ (gcc::jit::recording::memento_of_get_volatile): New class.
+ (gcc::jit::playback::type::get_volatile): New.
+ * TODO.rst: Update.
+
+2014-03-03 David Malcolm <dmalcolm@redhat.com>
+
+ * libgccjit++.h (gccjit::function::operator()): Add overload for
+ a call with 3 arguments.
+ (gccjit::block::add_call): Likewise for 4 arguments.
+ (gccjit::rvalue::cast_to): New method.
+ (gccjit::rvalue::operator[]): New methods.
+
+2014-02-28 David Malcolm <dmalcolm@redhat.com>
+
+ * libgccjit.c (gcc_jit_context_new_binary_op): Check that the
+ operands have the same type.
+ (gcc_jit_context_new_comparison): Likewise.
+
+2014-02-28 David Malcolm <dmalcolm@redhat.com>
+
+ * libgccjit.h (gcc_jit_context_new_cast): New.
+ * libgccjit.map (gcc_jit_context_new_cast): New.
+ * libgccjit++.h (gccjit::context::new_cast): New method.
+ * libgccjit.c (gcc_jit_context_new_cast): New.
+
+ * internal-api.h (gcc::jit::recording::context::new_cast): New method.
+ (gcc::jit::recording::cast): New subclass of rvalue.
+ (gcc::jit::playback::context::new_cast): New method.
+ (gcc::jit::playback::context::build_cast): New method.
+
+ * internal-api.c (convert): New.
+ (gcc::jit::recording::context::new_cast): New.
+ (gcc::jit::recording::cast::replay_into): New.
+ (gcc::jit::recording::cast::make_debug_string): New.
+ (gcc::jit::playback::context::build_cast): New.
+ (gcc::jit::playback::context::new_cast): New.
+
+ * TODO.rst: Update.
+
+2014-02-28 David Malcolm <dmalcolm@redhat.com>
+
+ * libgccjit.h (gcc_jit_block_get_function): New.
+ * libgccjit.map (gcc_jit_block_get_function): New.
+ * libgccjit++.h (gccjit::block::get_function): New method.
+ * libgccjit.c (gcc_jit_block_get_function): New.
+
+2014-02-27 David Malcolm <dmalcolm@redhat.com>
+
+ * libgccjit.h (gcc_jit_label): Delete in favor of...
+ (gcc_jit_block): New type.
+ (gcc_jit_loop): Delete.
+
+ (gcc_jit_function_new_forward_label): Delete in favor of...
+ (gcc_jit_function_new_block): New.
+
+ (gcc_jit_label_as_object): Delete in favor of...
+ (gcc_jit_block_as_object): New.
+
+ (gcc_jit_function_add_eval): Delete in favor of...
+ (gcc_jit_block_add_eval): New.
+
+ (gcc_jit_function_add_assignment): Delete in favor of...
+ (gcc_jit_block_add_assignment): New.
+
+ (gcc_jit_function_add_assignment_op): Delete in favor of...
+ (gcc_jit_block_add_assignment_op): New.
+
+ (gcc_jit_function_add_comment): Delete in favor of...
+ (gcc_jit_block_add_comment): New.
+
+ (gcc_jit_label_as_object): Delete in favor of...
+ (gcc_jit_block_as_object): New.
+
+ (gcc_jit_function_add_conditional): Delete in favor of...
+ (gcc_jit_block_end_with_conditional): New.
+
+ (gcc_jit_function_add_jump): Delete in favor of...
+ (gcc_jit_block_end_with_jump): New.
+
+ (gcc_jit_function_add_return): Delete in favor of...
+ (gcc_jit_block_end_with_return): New.
+
+ (gcc_jit_function_add_void_return): Delete in favor of...
+ (gcc_jit_block_end_with_void_return): New.
+
+ (gcc_jit_function_new_loop): Delete.
+ (gcc_jit_function_new_loop_over_range): Delete.
+ (gcc_jit_loop_as_object): Delete.
+ (gcc_jit_loop_end): Delete.
+
+ * libgccjit.map (gcc_jit_function_add_assignment): Delete in favor of...
+ (gcc_jit_block_add_assignment): New.
+
+ (gcc_jit_function_add_assignment_op): Delete in favor of...
+ (gcc_jit_block_add_assignment_op): New.
+
+ (gcc_jit_function_add_comment): Delete in favor of...
+ (gcc_jit_block_add_comment): New.
+
+ (gcc_jit_function_add_eval): Delete in favor of...
+ (gcc_jit_block_add_eval): New.
+
+ (gcc_jit_label_as_object): Delete in favor of...
+ (gcc_jit_block_as_object): New.
+
+ (gcc_jit_function_add_conditional): Delete in favor of...
+ (gcc_jit_block_end_with_conditional): New.
+
+ (gcc_jit_function_add_jump): Delete in favor of...
+ (gcc_jit_block_end_with_jump): New.
+
+ (gcc_jit_function_add_return): Delete in favor of...
+ (gcc_jit_block_end_with_return): New.
+
+ (gcc_jit_function_add_void_return): Delete in favor of...
+ (gcc_jit_block_end_with_void_return): New.
+
+ (gcc_jit_function_add_label): Delete in favor of...
+ (gcc_jit_function_new_block): New.
+ (gcc_jit_function_new_forward_label): Delete.
+ (gcc_jit_function_place_forward_label): Delete.
+
+ (gcc_jit_function_new_loop): Delete.
+ (gcc_jit_function_new_loop_over_range): Delete.
+ (gcc_jit_loop_as_object): Delete.
+ (gcc_jit_loop_end): Delete.
+
+ * libgccjit.c (gcc_jit_label): Delete in favor of...
+ (gcc_jit_block): New type.
+ (gcc_jit_loop): Delete.
+
+ (RETURN_IF_NOT_FUNC_DEFINITION): Delete in favor of...
+ (RETURN_IF_NOT_VALID_BLOCK): New macro.
+ (RETURN_NULL_IF_NOT_FUNC_DEFINITION): Delete in favor of...
+ (RETURN_NULL_IF_NOT_VALID_BLOCK): New macro.
+
+ (gcc_jit_function_new_forward_label): Delete in favor of...
+ (gcc_jit_function_new_block): New.
+
+ (gcc_jit_label_as_object): Delete in favor of...
+ (gcc_jit_block_as_object): New.
+
+ (gcc_jit_rvalue_dereference_field): Ensure that field has been
+ placed.
+
+ (gcc_jit_function_add_label): Delete
+ (gcc_jit_function_place_forward_label): Delete.
+
+ (gcc_jit_function_add_eval): Delete in favor of...
+ (gcc_jit_block_add_eval): New.
+
+ (gcc_jit_function_add_assignment): Delete in favor of...
+ (gcc_jit_block_add_assignment): New.
+
+ (gcc_jit_function_add_assignment_op): Delete in favor of...
+ (gcc_jit_block_add_assignment_op): New.
+
+ (gcc_jit_function_add_conditional): Delete in favor of...
+ (gcc_jit_block_end_with_conditional): New.
+
+ (gcc_jit_function_add_comment): Delete in favor of...
+ (gcc_jit_block_add_comment): New.
+
+ (gcc_jit_function_add_jump): Delete in favor of...
+ (gcc_jit_block_end_with_jump): New.
+
+ (gcc_jit_function_add_return): Delete in favor of...
+ (gcc_jit_block_end_with_return): New.
+
+ (gcc_jit_function_add_void_return): Delete in favor of...
+ (gcc_jit_block_end_with_void_return): New.
+
+ (gcc_jit_function_new_loop): Delete.
+ (gcc_jit_function_new_loop_over_range): Delete.
+ (gcc_jit_loop_as_object): Delete.
+ (gcc_jit_loop_end): Delete.
+
+ * internal-api.h (gcc::jit::recording::label): Delete class in
+ favor of...
+ (gcc::jit::recording::block): New class.
+ (gcc::jit::recording::loop): Delete class.
+ (gcc::jit::recording::loop_end): Delete class.
+
+ (gcc::jit::playback::label): Delete class in favor of...
+ (gcc::jit::playback::block): New class.
+
+ (gcc::jit::playback::loop): Delete class.
+
+ (gcc::jit::recording::playback_label): Delete function in favor of...
+ (gcc::jit::recording::playback_block): New function.
+
+ (gcc::jit::recording::context::validate): New.
+
+ (gcc::jit::recording::function::new_forward_label): Delete method.
+ (gcc::jit::recording::function::add_eval): Delete method in favor
+ of method of new gcc::jit::recording::block class.
+ (gcc::jit::recording::function::add_assignment): Likewise.
+ (gcc::jit::recording::function::add_assignment_op): Likewise.
+ (gcc::jit::recording::function::add_comment): Likewise.
+ (gcc::jit::recording::function::add_conditional): Likewise.
+ (gcc::jit::recording::function::place_forward_label): Likewise.
+ (gcc::jit::recording::function::add_jump): Likewise.
+ (gcc::jit::recording::function::add_return): Likewise.
+
+ (gcc::jit::recording::function::add_label): Delete method in favor of...
+ (gcc::jit::recording::function::new_block): New method.
+
+ (gcc::jit::recording::function::new_loop): Delete method.
+
+ (gcc::jit::recording::function::validate): New method.
+ (gcc::jit::recording::function::m_activity): Delete field in favor of...
+ (gcc::jit::recording::function::m_blocks): New field.
+
+ (gcc::jit::recording::statement::get_successor_blocks): New method.
+ (gcc::jit::recording::statement::write_to_dump): Make public.
+ (gcc::jit::recording::statement::statement): Accept a block rather
+ than a function.
+ (gcc::jit::recording::statement::playback_function): Delete.
+ (gcc::jit::recording::statement::get_block): New.
+ (gcc::jit::recording::statement::m_func): Delete in favor of...
+ (gcc::jit::recording::statement::m_block): ...this.
+
+ (gcc::jit::recording::eval::eval): Accept a block rather than a
+ function.
+ (gcc::jit::recording::assignment::assignment): Likewise.
+ (gcc::jit::recording::assignment_op::assignment_op): Likewise.
+ (gcc::jit::recording::comment::comment): Likewise.
+ (gcc::jit::recording::return::return): Likewise.
+ (gcc::jit::recording::conditional::conditional): Likewise; accept
+ blocks rather than labels.
+ (gcc::jit::recording::jump::jump): Likewise.
+ (gcc::jit::recording::conditional::get_successor_blocks): New.
+ (gcc::jit::recording::jump::get_successor_blocks): New.
+
+ (gcc::jit::playback::function::new_forward_label): Delete method
+ in favor of...
+ (gcc::jit::playback::function::new_block): New method.
+ (gcc::jit::playback::function::build_stmt_list): New method.
+ (gcc::jit::playback::function::m_blocks): New field.
+
+ * libgccjit++.h (gccjit::label): Delete class in favor of...
+ (gccjit::block): New class.
+ (gccjit::function::new_forward_label): Delete methods in favor of...
+ (gccjit::function::new_block): New methods.
+ (gccjit::function::add_comment): Delete methods in favor of methods
+ of new class gccjit::block.
+ (gccjit::function::add_conditional): Likewise.
+ (gccjit::function::add_label): Likewise.
+ (gccjit::function::place_forward_label): Likewise.
+ (gccjit::function::add_jump): Likewise.
+ (gccjit::function::add_return): Likewise.
+ (gccjit::function::add_call): Likewise.
+
+ * internal-api.c (gcc::jit::recording::playback_label): Delete in
+ favor of...
+ (gcc::jit::recording::playback_block): New.
+ (gcc::jit::recording::context::compile): Validate.
+ (gcc::jit::recording::context::validate): New.
+ (gcc::jit::recording::function::function): Update.
+ (gcc::jit::recording::function::new_forward_label): Delete.
+ (gcc::jit::recording::function::add_eval): Delete.
+ (gcc::jit::recording::function::add_assignment): Delete.
+ (gcc::jit::recording::function::add_assignment_op): Delete.
+ (gcc::jit::recording::function::new_block): New.
+ (gcc::jit::recording::function::add_comment): Delete.
+ (gcc::jit::ecording::function::add_conditional): Delete.
+ (gcc::jit::recording::function::add_label): Delete.
+ (gcc::jit::recording::function::place_forward_label): Delete.
+ (gcc::jit::recording::function::add_jump): Delete.
+ (gcc::jit::recording::function::add_return): Delete.
+ (gcc::jit::recording::function::new_loop): Delete.
+ (gcc::jit::recording::function::write_to_dump): Port to block-based
+ representation.
+ (gcc::jit::recording::function::validate): New.
+ (gcc::jit::recording::block::add_eval): New.
+ (gcc::jit::recording::block::add_assignment): New.
+ (gcc::jit::recording::label::replay_into): Delete.
+ (gcc::jit::recording::block::add_assignment_op): New.
+ (gcc::jit::recording::block::add_comment): New.
+ (gcc::jit::recording::block::end_with_conditional): New.
+ (gcc::jit::recording::block::end_with_jump): New.
+ (gcc::jit::recording::block::end_with_return): New.
+ (gcc::jit::recording::block::write_to_dump): New.
+ (gcc::jit::recording::block::validate): New.
+ (gcc::jit::recording::block::get_last_statement): New.
+ (gcc::jit::recording::block::get_successor_blocks): New.
+ (gcc::jit::recording::block::replay_into): New.
+ (gcc::jit::recording::label::make_debug_string): Delete.
+ (gcc::jit::recording::block::make_debug_string): New.
+ (gcc::jit::recording::statement::get_successor_blocks): New.
+ (gcc::jit::recording::eval::replay_into): Port to block-based
+ representation.
+ (gcc::jit::recording::assignment::replay_into): Likewise.
+ (gcc::jit::recording::assignment_op::replay_into): Likewise.
+ (gcc::jit::recording::comment::replay_into): Likewise.
+ (gcc::jit::recording::conditional::replay_into): Likewise.
+ (gcc::jit::recording::jump::replay_into): Likewise.
+ (gcc::jit::recording::return_::replay_into): Likewise.
+
+ (gcc::jit::recording::conditional::get_successor_blocks): New.
+ (gcc::jit::recording::place_label::place_label): Delete.
+ (gcc::jit::recording::place_label::replay_into): Delete.
+ (gcc::jit::recording::place_label::make_debug_string): Delete.
+ (gcc::jit::recording::place_label::write_to_dump): Delete.
+
+ (gcc::jit::recording::jump::get_successor_blocks): New.
+ (gcc::jit::recording::return_::get_successor_blocks): New.
+
+ (gcc::jit::recording::loop::replay_into): Delete.
+ (gcc::jit::recording::loop::make_debug_string): Delete.
+ (gcc::jit::recording::loop::end): Delete.
+ (gcc::jit::recording::loop_end::replay_into): Delete.
+ (gcc::jit::recording::loop_end::make_debug_string): Delete.
+
+ (gcc::jit::playback::function::new_forward_label): Delete.
+ (gcc::jit::playback::function::new_block): New.
+ (gcc::jit::playback::function::build_stmt_list): New.
+ (gcc::jit::playback::function::add_eval): Replace with...
+ (gcc::jit::playback::block::add_eval): New.
+ (gcc::jit::playback::function::add_assignment): Replace with...
+ (gcc::jit::playback::block::add_assignment): New.
+ (gcc::jit::playback::function::add_comment): Replace with...
+ (gcc::jit::playback::block::add_comment): New, reimplementing,
+ given that we no longer have labels.
+ (gcc::jit::playback::function::add_conditional): Replace with...
+ (gcc::jit::playback::block::add_conditional): New, reworking,
+ given that on_false can no longer be NULL.
+ (gcc::jit::playback::function::add_label): Delete.
+ (gcc::jit::playback::function::place_forward_label): Delete.
+ (gcc::jit::playback::function::add_jump): Replace with...
+ (gcc::jit::playback::block::add_jump): New.
+ (gcc::jit::playback::function::add_return): Replace with...
+ (gcc::jit::playback::block::add_return): New.
+ (gcc::jit::playback::function::new_loop): Delete.
+ (gcc::jit::playback::label::label): Replace with...
+ (gcc::jit::playback::block::block): ...this.
+
+ (gcc::jit::playback::loop::loop): Delete.
+ (gcc::jit::playback::loop::end): Delete.
+
+ (gcc::jit::playback::context::replay): Call each function's
+ build_stmt_list.
+
+ * TODO.rst: Update
+
+2014-02-25 David Malcolm <dmalcolm@redhat.com>
+
+ * libgccjit.h (gcc_jit_function_add_void_return): New.
+ * libgccjit.map (gcc_jit_function_add_void_return): New.
+ * libgccjit.c (gcc_jit_function_add_void_return): New.
+ * libgccjit++.h (add_return): Add overloaded variant with no
+ rvalue, calling gcc_jit_function_add_void_return.
+
+ * internal-api.c (gcc::jit::recording::function::add_return): Add
+ comment that rvalue could be NULL.
+ (gcc::jit::playback::function::add_return): Support rvalue being
+ NULL.
+
+2014-02-25 David Malcolm <dmalcolm@redhat.com>
+
+ * internal-api.h (gcc::jit::playback::function): Add field
+ m_inner_block.
+
+ * internal-api.c (gcc::jit::playback::function::function):
+ Create BLOCK here and link it to the BIND_EXPR.
+ (gcc::jit::playback::function::gt_ggc_mx): Walk m_inner_block.
+ (gcc::jit::playback::function::postprocess): Set up BLOCK_VARS on
+ the block, so that the local variables make it into the debuginfo.
+
+2014-02-24 Philip Herron <redbrain@gcc.gnu.org>
+
+ * Make-lang.in (jit.install-common): Implement.
+
+2014-02-21 David Malcolm <dmalcolm@redhat.com>
+
+ * libgccjit.h (gcc_jit_context_dump_to_file): New.
+ * libgccjit.map (gcc_jit_context_dump_to_file): New.
+ * libgccjit.c (gcc_jit_context_dump_to_file): New.
+ * libgccjit++.h (gccjit::context::dump_to_file): New.
+
+ * internal-api.h (gcc::jit::dump): New class.
+ (gcc::jit::recording::playback_location): Add a replayer argument,
+ so that playback locations can be created before playback statements.
+ (gcc::jit::recording::location::playback_location): Likewise.
+ (gcc::jit::recording::statement::playback_location): Likewise.
+ (gcc::jit::recording::context::dump_to_file): New.
+ (gcc::jit::recording::context::m_structs): New field, for use by
+ dump_to_file.
+ (gcc::jit::recording::context::m_functions): Likewise.
+ (gcc::jit::recording::memento::write_to_dump): New virtual function.
+ (gcc::jit::recording::field::write_to_dump): New.
+ (gcc::jit::recording::fields::write_to_dump): New.
+ (gcc::jit::recording::function::write_to_dump): New.
+ (gcc::jit::recording::function::m_locals): New field for use by
+ write_to_dump.
+ (gcc::jit::recording::function::m_activity): Likewise.
+ (gcc::jit::recording::local::write_to_dump): New.
+ (gcc::jit::recording::statement::write_to_dump): New.
+ (gcc::jit::recording::place_label::write_to_dump): New.
+
+ * internal-api.c (gcc::jit::dump::dump): New.
+ (gcc::jit::dump::~dump): New.
+ (gcc::jit::dump::write): New.
+ (gcc::jit::dump::make_location): New.
+ (gcc::jit::recording::playback_location): Add a replayer argument,
+ so that playback locations can be created before playback statements.
+
+ (gcc::jit::recording::context::context): Initialize new fields.
+ (gcc::jit::recording::function::function): Likewise.
+
+ (gcc::jit::recording::context::new_struct_type): Add struct to the
+ context's m_structs vector.
+ (gcc::jit::recording::context::new_function): Add function to the
+ context's m_functions vector.
+ (gcc::jit::recording::context::dump_to_file): New.
+ (gcc::jit::recording::memento::write_to_dump): New.
+ (gcc::jit::recording::field::write_to_dump): New.
+ (gcc::jit::recording::fields::write_to_dump): New.
+ (gcc::jit::recording::function::write_to_dump): New.
+ (gcc::jit::recording::local::write_to_dump): New.
+ (gcc::jit::recording::statement::write_to_dump): New.
+ (gcc::jit::recording::place_label::write_to_dump): New.
+
+ (gcc::jit::recording::array_type::replay_into): Pass on replayer
+ to call to playback_location.
+ (gcc::jit::recording::field::replay_into): Likewise.
+ (gcc::jit::recording::struct_::replay_into): Likewise.
+ (gcc::jit::recording::param::replay_into): Likewise.
+ (gcc::jit::recording::function::replay_into): Likewise.
+ (gcc::jit::recording::global::replay_into): Likewise.
+ (gcc::jit::recording::unary_op::replay_into): Likewise.
+ (gcc::jit::recording::binary_op::replay_into): Likewise.
+ (gcc::jit::recording::comparison::replay_into): Likewise.
+ (gcc::jit::recording::call::replay_into): Likewise.
+ (gcc::jit::recording::array_access::replay_into): Likewise.
+ (gcc::jit::recording::access_field_of_lvalue::replay_into): Likewise.
+ (gcc::jit::recording::access_field_rvalue::replay_into): Likewise.
+ (gcc::jit::recording::dereference_field_rvalue::replay_into): Likewise.
+ (gcc::jit::recording::dereference_rvalue::replay_into): Likewise.
+ (gcc::jit::recording::get_address_of_lvalue::replay_into): Likewise.
+ (gcc::jit::recording::local::replay_into): Likewise.
+ (gcc::jit::recording::eval::replay_into): Likewise.
+ (gcc::jit::recording::assignment::replay_into): Likewise.
+ (gcc::jit::recording::assignment_op::replay_into): Likewise.
+ (gcc::jit::recording::comment::replay_into): Likewise.
+ (gcc::jit::recording::conditional::replay_into): Likewise.
+ (gcc::jit::recording::place_label::replay_into): Likewise.
+ (gcc::jit::recording::jump::replay_into): Likewise.
+ (gcc::jit::recording::return_::replay_into): Likewise.
+ (gcc::jit::recording::loop::replay_into): Likewise.
+ (gcc::jit::recording::loop_end::replay_into): Likewise.
+
+ (gcc::jit::recording::function::new_local): Add to the function's
+ vector of locals.
+ (gcc::jit::recording::function::add_eval): Add to the function's
+ m_activity field.
+ (gcc::jit::recording::function::add_assignment): Likewise.
+ (gcc::jit::recording::function::add_assignment_op): Likewise.
+ (gcc::jit::recording::function::add_comment): Likewise.
+ (gcc::jit::recording::function::add_conditional): Likewise.
+ (gcc::jit::recording::function::place_forward_label): Likewise.
+ (gcc::jit::recording::function::add_jump): Likewise.
+ (gcc::jit::recording::function::add_return): Likewise.
+ (gcc::jit::recording::function::new_loop): Likewise.
+
+ (gcc::jit::recording::conditional::make_debug_string): Add missing
+ semicolon.
+
+2014-02-19 David Malcolm <dmalcolm@redhat.com>
+
+ * libgccjit.c (gcc_jit_context_new_rvalue_from_ptr): Verify that
+ pointer_type is indeed a pointer type.
+ (gcc_jit_context_null): Likewise.
+ (gcc_jit_context_new_array_access): Verify that ptr is indeed a
+ pointer.
+
+ * TODO.rst: Update
+
+2014-02-18 David Malcolm <dmalcolm@redhat.com>
+
+ * libgccjit.h (gcc_jit_struct): New.
+ (gcc_jit_context_new_struct_type): Change return type from gcc_jit_type
+ to gcc_jit_struct.
+ (gcc_jit_context_new_opaque_struct): New.
+ (gcc_jit_struct_as_type): New.
+ (gcc_jit_struct_set_fields): New.
+ (gcc_jit_context_null): New.
+
+ * libgccjit.map (gcc_jit_context_new_opaque_struct): New.
+ (gcc_jit_context_null): New.
+ (gcc_jit_struct_as_type): New.
+ (gcc_jit_struct_set_fields): New.
+
+ * libgccjit++.h (gccjit::context::new_struct_type): Return a
+ struct_ rather than a type.
+ (gccjit::context::new_opaque_struct_type): New.
+ (gccjit::struct_): New subclass of type.
+
+ * libgccjit.c (gcc_jit_struct): New.
+ (RETURN_VAL_IF_FAIL_PRINTF1): New.
+ (RETURN_VAL_IF_FAIL_PRINTF2): New.
+ (RETURN_NULL_IF_FAIL_PRINTF1): New.
+ (RETURN_IF_FAIL_PRINTF1): New.
+ (RETURN_IF_FAIL_PRINTF2): New.
+ (gcc_jit_context_new_struct_type): Return a gcc_jit_struct rather
+ than a gcc_jit_type; implement by creating the struct, then
+ setting the fields in it.
+ (gcc_jit_context_new_opaque_struct): New.
+ (gcc_jit_struct_as_type): New.
+ (gcc_jit_struct_set_fields): New.
+ (gcc_jit_context_null): New.
+ (gcc_jit_lvalue_access_field): Use the struct's context when
+ reporting on a NULL field; verify that the field has been placed
+ in a struct.
+ (gcc_jit_rvalue_access_field): Likewise.
+ (is_bool): New.
+ (gcc_jit_function_add_conditional): Use the function's context
+ when reporting errors; verify that boolval's type is indeed
+ boolean.
+ (gcc_jit_function_new_loop): Likewise.
+
+ * internal-api.h (gcc::jit::recording::context::new_struct_type):
+ Don't accept fields, and return a struct_ rather than a type_, so
+ that fields can be set later.
+ (gcc::jit::recording::struct_::struct_): Store a (fields *) rather
+ than a vec of fields.
+ (gcc::jit::recording::struct_::as_type): New.
+ (gcc::jit::recording::struct_::get_fields): New.
+ (gcc::jit::recording::struct_::set_fields): New.
+ (gcc::jit::recording::struct_::playback_struct): New.
+ (gcc::jit::recording::fields): New class.
+ (gcc::jit::playback::context::new_struct_type): Don't accept
+ fields, and return a struct_ rather than a type_, so that fields
+ can be set later.
+ (gcc::jit::playback::struct_): New subclass of type.
+
+ * internal-api.c (gcc::jit::recording::context::get_type): With
+ nested contexts, create basic types within the ultimate parent
+ context, allowing for a fast check for the boolean type using
+ pointer equality.
+ (gcc::jit::recording::context::new_struct_type): Don't accept
+ fields, and return a struct_ rather than a type_, so that fields
+ can be set later.
+ (gcc::jit::recording::context::get_opaque_FILE_type): Update for
+ struct-creation changes.
+ (gcc::jit::recording::struct_::struct_): Store a (fields *) rather
+ than a vec of fields.
+ (gcc::jit::recording::struct_::set_fields): New.
+ (gcc::jit::recording::struct_::replay_into): Don't playback the
+ fields, as this is now done by a fields instance.
+ (gcc::jit::recording::fields::fields): New.
+ (gcc::jit::recording::fields::replay_into): New.
+ (gcc::jit::recording::fields::make_debug_string): New.
+ (gcc::jit:: playback::context::new_struct_type): Don't accept
+ fields, and return a struct_ rather than a type_, so that fields
+ can be set later.
+ (gcc::jit::playback::struct_::set_fields): New.
+
+ * TODO.rst: Update.
+
+2014-02-18 David Malcolm <dmalcolm@redhat.com>
+
+ * libgccjit.c (gcc_jit_function_new_local): Use the context of the
+ function when reporting errors.
+ (gcc_jit_function_place_forward_label): Likewise.
+ (gcc_jit_function_add_eval): Likewise.
+ (gcc_jit_function_add_assignment_op): Likewise.
+ (gcc_jit_function_add_comment): Likewise.
+ (gcc_jit_function_add_jump): Likewise.
+
+2014-02-14 David Malcolm <dmalcolm@redhat.com>
+
+ * libgccjit++.h (gccjit::type::zero): New method.
+ (gccjit::type::one): New method.
+ (gccjit::function::add_call): New family of overloaded methods.
+
+2014-02-13 David Malcolm <dmalcolm@redhat.com>
+
+ * libgccjit.h (gcc_jit_context_get_builtin_function): New.
+ * libgccjit.map (gcc_jit_context_get_builtin_function): New.
+ * libgccjit++.h (gccjit::context::get_builtin_function): New method.
+
+ * Make-lang.in (jit_OBJS): Add jit/jit-builtins.o
+ * jit-builtins.c: New source file, for managing builtin functions
+ and their types.
+ * jit-builtins.h: Likewise.
+
+ * libgccjit.c (gcc_jit_context_new_function): Pass BUILT_IN_NONE for
+ the new argument of new_function
+ (gcc_jit_context_get_builtin_function): New.
+
+ * internal-api.h: Add idempotency guards.
+ (gcc::jit::recording::context::new_function): Add parameter
+ for builtin functions.
+ (gcc::jit::recording::context::get_builtin_function): New method.
+ (gcc::jit::recording::context::m_builtins_manager): New field.
+ (gcc::jit::recording::type::as_a_function_type): New virtual function.
+ (gcc::jit::recording::function_type): New subclass of type.
+ (gcc::jit::recording::function::function): Add parameter for
+ builtin functions.
+ (gcc::jit::recording::function::m_builtin_id): New field.
+ (gcc::jit::recording::function::new_function_type): New method.
+ (gcc::jit::playback::function::function): Add parameter for
+ builtin functions.
+ * internal-api.c (gcc::jit::recording::context::context):
+ NULL-initialize new field m_builtins_manager.
+ (gcc::jit::recording::context::~context): Clean up the builtins
+ manager, if one has been created.
+ (gcc::jit::recording::context::new_function): Add parameter
+ (gcc::jit::recording::context::get_builtin_function): New method.
+ (gcc::jit::recording::function_type::function_type): Implement
+ constructor for new subclass.
+ (gcc::jit::recording::function_type::dereference): Implement
+ method for new subclass.
+ (gcc::jit::recording::function_type::replay_into): Likewise.
+ (gcc::jit::recording::function_type::make_debug_string): Likewise.
+ (gcc::jit::recording::function::function): Add parameter for
+ builtin functions.
+ (gcc::jit::recording::function::replay_into): Likewise for
+ creation of playback object.
+ (gcc::jit::recording::function::new_function_type): New method.
+ (gcc::jit::playback::function::new_function): Add parameter for
+ builtin functions, using it to set up the fndecl accordingly.
+
+2014-02-11 David Malcolm <dmalcolm@redhat.com>
+
+ * libgccjit.c (IS_ASCII_ALPHA): New macro.
+ (IS_ASCII_DIGIT): New macro.
+ (IS_ASCII_ALNUM): New macro.
+ (gcc_jit_context_new_function): Require that function names be valid
+ C identifiers for now, to avoid later problems in the assembler.
+
+2014-02-11 David Malcolm <dmalcolm@redhat.com>
+
+ * libgccjit.h (enum gcc_jit_types): Add GCC_JIT_TYPE_BOOL.
+
+ * internal-api.h (gcc::jit::recording::comparison::comparison): Use
+ GCC_JIT_TYPE_BOOL as the types of comparisons, rather than
+ GCC_JIT_TYPE_INT.
+
+ * internal-api.c (gcc::jit::recording::memento_of_get_type::
+ dereference): Handle GCC_JIT_TYPE_BOOL (with an error).
+ (get_type_strings): Add GCC_JIT_TYPE_BOOL.
+ (get_tree_node_for_type): Handle GCC_JIT_TYPE_BOOL.
+
+2014-02-11 David Malcolm <dmalcolm@redhat.com>
+
+ * internal-api.c (gcc::jit::recording::context::add_error_va): If
+ GCC_JIT_STR_OPTION_PROGNAME is NULL, use "libgccjit.so", as per
+ the comment in libgccjit.h
+ (gcc::jit::recording::label::replay_into): When reporting on an
+ unplaced label, include the name of the containing function in
+ the error message.
+ * libgccjit.c: Remove comment about "Functions for use within the
+ code factory", as this distinction went away in commit
+ 96b218c9a1d5f39fb649e02c0e77586b180e8516.
+ (RETURN_VAL_IF_FAIL_PRINTF4): New.
+ (RETURN_NULL_IF_FAIL_PRINTF4): New.
+ (jit_error): Invoke vfprintf with the correct format string in
+ the NULL context case.
+ (gcc_jit_context_new_call): Check for NULL entries within the
+ array of arguments.
+
+2014-02-10 David Malcolm <dmalcolm@redhat.com>
+
+ * libgccjit.h (gcc_jit_context_get_int_type): New.
+ * libgccjit.map (gcc_jit_context_get_int_type): New.
+ * libgccjit.c (gcc_jit_context_get_int_type): New.
+
+ * internal-api.h (gcc::jit::recording::context::get_int_type): New.
+ (gcc::jit::recording::context::get_int_type<T>): New template.
+ * internal-api.c (gcc::jit::recording::context::get_int_type): New.
+
+ * libgccjit++.h: Include <limits> so we can use std::numeric_limits.
+ (gccjit::context::get_int_type): New.
+ (gccjit::context::get_int_type<T>): New.
+
+2014-02-10 David Malcolm <dmalcolm@redhat.com>
+
+ * libgccjit.h (gcc_jit_function_get_param): New.
+ * libgccjit.map (gcc_jit_function_get_param): New.
+ * libgccjit.c (gcc_jit_function_get_param): New.
+ * libgccjit++.h (gccjit::function::get_param): New.
+
+2014-02-10 David Malcolm <dmalcolm@redhat.com>
+
+ * libgccjit++.h (gccjit::object::get_inner_object): Make const.
+ (gccjit::location::get_inner_location): Likewise.
+ (gccjit::field::get_inner_field): Likewise.
+ (gccjit::type::get_inner_type): Likewise.
+ (gccjit::function::get_inner_function): Likewise.
+ (gccjit::label::get_inner_label): Likewise.
+ (gccjit::rvalue::get_inner_rvalue): Likewise.
+ (gccjit::lvalue::get_inner_lvalue): Likewise.
+ (gccjit::param::get_inner_param): Likewise.
+
+2014-02-10 David Malcolm <dmalcolm@redhat.com>
+
+ * libgccjit++.h (gccjit::object::get_context): New method.
+ (gccjit::function): Add overloaded operator () for various
+ numbers of arguments as a very terse way of creating function calls.
+ (gccjit::rvalue::get_type): New method.
+
+ (operator-): New overloaded unary op for rvalues.
+ (operator~): Likewise.
+ (operator!): Likewise.
+
+ (operator+): New overloaded binary op for rvalues.
+ (operator-): Likewise.
+ (operator*): Likewise.
+ (operator/): Likewise.
+ (operator%): Likewise.
+ (operator&): Likewise.
+ (operator^): Likewise.
+ (operator|): Likewise.
+ (operator&&): Likewise.
+ (operator||): Likewise.
+
+ (operator==): New overloaded comparison for rvalues.
+ (operator!=): Likewise.
+ (operator<): Likewise.
+ (operator<=): Likewise.
+ (operator>): Likewise.
+ (operator>=): Likewise.
+
+ (operator*): New overloaded operator for dereferencing an
+ rvalue representing a pointer.
+
+ * libgccjit.c (gcc_jit_rvalue_get_type): New.
+ * libgccjit.h (gcc_jit_rvalue_get_type): New.
+ * libgccjit.map (gcc_jit_rvalue_get_type): New.
+
+2014-02-10 David Malcolm <dmalcolm@redhat.com>
+
+ * libgccjit++.h (gccjit::context::new_minus): New method,
+ providing a way to do a specific unary op with less typing.
+ (gccjit::context::new_bitwise_negate): Likewise.
+ (gccjit::context::new_logical_negate): Likewise.
+
+ (gccjit::context::new_plus): Likewise, for binary op.
+ (gccjit::context::new_minus): Likewise.
+ (gccjit::context::new_mult): Likewise.
+ (gccjit::context::new_divide): Likewise.
+ (gccjit::context::new_modulo): Likewise.
+ (gccjit::context::new_bitwise_and): Likewise.
+ (gccjit::context::new_bitwise_xor): Likewise.
+ (gccjit::context::new_bitwise_or): Likewise.
+ (gccjit::context::new_logical_and): Likewise.
+ (gccjit::context::new_logical_or): Likewise.
+
+ (gccjit::context::new_eq): Likewise, for comparison.
+ (gccjit::context::new_ne): Likewise.
+ (gccjit::context::new_lt): Likewise.
+ (gccjit::context::new_le): Likewise.
+ (gccjit::context::gccjit::context::new_gt): Likewise.
+ (gccjit::context::gccjit::context::new_ge): Likewise.
+
+ (gccjit::context::new_call): Add a series of overloaded methods
+ for specific numbers of args (from 0 - 6), to avoid the need for
+ client code to manually build a std::vector (or requiring C++11).
+
+2014-02-10 David Malcolm <dmalcolm@redhat.com>
+
+ * libgccjit++.h (gccjit::context::new_struct_type): Pass std::vector
+ "fields" argument by reference rather than by value.
+ (gccjit::context::new_function): Likewise, for "params" arg.
+ (gccjit::context::new_call): Likewise, for "args" arg.
+
+2014-02-10 David Malcolm <dmalcolm@redhat.com>
+
+ * libgccjit++.h (gccjit::context::new_location): Update filename
+ arg from a const char * to a const std::string &.
+ (gccjit::context::new_field): Likewise for "name" arg.
+ (gccjit::context::new_struct_type): Likewise.
+ (gccjit::context::new_param): Likewise.
+ (gccjit::context::new_function): Likewise.
+ (gccjit::function::new_local): Likewise.
+ (gccjit::context::new_rvalue): Likewise for "value" arg.
+ (gccjit::function::add_comment): Likewise for "text" arg.
+ (gccjit::function::new_forward_label): Likewise for "name" arg; add
+ variant taking no args for anonymous labels.
+ (gccjit::function::add_label): Likewise.
+
+2014-02-10 David Malcolm <dmalcolm@redhat.com>
+
+ * libgccjit++.h (gccjit::object, gccjit::location): Move
+ these declarations to before that of gccjit::context so that
+ the various methods of context taking a location can have a
+ default location value.
+ (gccjit::context::new_array_type): Consolidate two methods,
+ one accepting a gccjit::location, the other without, by
+ providing a default argument (which thus has to be moved to the
+ end of the argument list).
+ (gccjit::context::new_field): Likewise.
+ (gccjit::context::new_struct_type): Likewise.
+ (gccjit::context::new_param): Likewise.
+ (gccjit::context::new_function): Likewise.
+ (gccjit::context::new_unary_op): Likewise.
+ (gccjit::context::new_binary_op): Likewise.
+ (gccjit::context::new_comparison): Likewise.
+ (gccjit::context::new_call): Likewise.
+ (gccjit::context::new_array_access): Likewise.
+ (gccjit::function::new_local): Likewise.
+ (gccjit::function::add_eval): Likewise.
+ (gccjit::function::add_assignment): Likewise.
+ (gccjit::function::add_assignment_op): Likewise.
+ (gccjit::function::add_comment): Likewise.
+ (gccjit::function::add_conditional): Likewise.
+ (gccjit::function::add_label): Likewise.
+ (gccjit::function::place_forward_label): Likewise.
+ (gccjit::function::add_jump): Likewise.
+ (gccjit::function::add_return): Likewise.
+ (gccjit::rvalue::access_field): Likewise.
+ (gccjit::rvalue::dereference_field): Likewise.
+ (gccjit::rvalue::dereference): Likewise.
+ (gccjit::lvalue::access_field): Likewise.
+ (gccjit::lvalue::get_address): Likewise.
+
+2014-02-10 David Malcolm <dmalcolm@redhat.com>
+
+ * TODO.rst: Update.
+
+2014-02-06 David Malcolm <dmalcolm@redhat.com>
+
+ * libgccjit++.h: Include <ostream> rather than <iostream>, since
+ the former gets us std::ostream, and the latter may introduce
+ startup-time overhead for constructing std::cout et al.
+ (gccjit::context::new_child_context): New.
+ (gccjit::context::release): New.
+ (gccjit::context::compile): New.
+ (gccjit::context::set_int_option): New.
+ (gccjit::context::set_bool_option): New.
+
+2014-02-03 David Malcolm <dmalcolm@redhat.com>
+
+ * libgccjit.h (struct gcc_jit_object): New.
+ (gcc_jit_object_get_context): New.
+ (gcc_jit_object_get_debug_string): New.
+ (gcc_jit_location_as_object): New.
+ (gcc_jit_type_as_object): New.
+ (gcc_jit_field_as_object): New.
+ (gcc_jit_param_as_object): New.
+ (gcc_jit_function_as_object): New.
+ (gcc_jit_label_as_object): New.
+ (gcc_jit_lvalue_as_object): New.
+ (gcc_jit_rvalue_as_object): New.
+ (gcc_jit_loop_as_object): New.
+
+ * libgccjit.map (gcc_jit_field_as_object): New.
+ (gcc_jit_function_as_object): New.
+ (gcc_jit_label_as_object): New.
+ (gcc_jit_location_as_object): New.
+ (gcc_jit_loop_as_object): New.
+ (gcc_jit_lvalue_as_object): New.
+ (gcc_jit_object_get_context): New.
+ (gcc_jit_object_get_debug_string): New.
+ (gcc_jit_param_as_object): New.
+ (gcc_jit_rvalue_as_object): New.
+ (gcc_jit_type_as_object): New.
+
+ * libgccjit.c (struct gcc_jit_object): New.
+ (gcc_jit_location_as_object): New.
+ (gcc_jit_type_as_object): New.
+ (gcc_jit_field_as_object): New.
+ (gcc_jit_param_as_object): New.
+ (gcc_jit_function_as_object): New.
+ (gcc_jit_label_as_object): New.
+ (gcc_jit_lvalue_as_object): New.
+ (gcc_jit_rvalue_as_object): New.
+ (gcc_jit_object_get_context): New.
+ (gcc_jit_object_get_debug_string): New.
+ (gcc_jit_loop_as_object): New.
+ * internal-api.h (gcc::jit::recording::memento::get_context): New.
+ (gcc::jit::recording::memento::as_object): New.
+
+ * libgccjit++.h: Require iostream, for std::ostream.
+ (class object): New base class.
+ (operator << (std::ostream& stream, const object &obj)): New.
+ (location): Inherit from the new "object" base class.
+ (location::m_inner_loc): Remove, in favor of...
+ (location::get_inner_location): ...new method.
+ (field): Inherit from the new "object" base class.
+ (field::m_inner_field): Remove, in favor of...
+ (field::get_inner_field): ...new method.
+ (type): Inherit from the new "object" base class.
+ (type::m_inner_type): Remove, in favor of...
+ (type::get_inner_type): ...new method.
+ (function): Inherit from the new "object" base class.
+ (function::m_inner_func): Remove, in favor of...
+ (function::get_inner_function): ...new method.
+ (label): Inherit from the new "object" base class.
+ (label::m_inner_label): Remove, in favor of...
+ (label::get_inner_label): ...new method.
+ (rvalue) Inherit from the new "object" base class.
+ (rvalue::m_inner_rvalue): Remove, in favor of...
+ (rvalue::get_inner_rvalue): ...new method.
+
+ (context::new_field): Update for move of inner pointer to the
+ "object" base class.
+ (context::new_struct_type): Likewise.
+ (context::new_param): Likewise.
+ (context::new_function): Likewise.
+ (context::new_rvalue): Likewise.
+ (context::zero): Likewise.
+ (context::one): Likewise.
+ (context::new_rvalue): Likewise.
+ (context::new_rvalue): Likewise.
+ (context::new_unary_op): Likewise.
+ (context::new_binary_op): Likewise.
+ (context::new_comparison): Likewise.
+ (context::new_call): Likewise.
+
+ (object::get_debug_string): New.
+ (object::object): New.
+ (object::get_inner_object): New.
+ (operator << (std::ostream&, const object &)): New.
+
+ (location::location): Update for move of inner pointer to the
+ "object" base class.
+ (location::get_inner_location): New.
+
+ (field::field): Update for move of inner pointer to the
+ "object" base class.
+ (field::get_inner_field): New.
+
+ (type::type): Update for move of inner pointer to the
+ "object" base class.
+ (type::get_pointer): Likewise.
+ (type::get_inner_type): New.
+
+ (function::function): Update for move of inner pointer to the
+ "object" base class.
+ (function::new_forward_label): Likewise.
+ (function::new_local): Likewise.
+ (function::add_eval): Likewise.
+ (function::add_assignment): Likewise.
+ (function::add_assignment_op): Likewise.
+ (function::add_comment): Likewise.
+ (function::add_conditional): Likewise.
+ (function::add_label): Likewise.
+ (function::place_forward_label): Likewise.
+ (function::add_jump): Likewise.
+ (function::add_return): Likewise.
+ (function::get_inner_function): New.
+
+ (label::label): Update for move of inner pointer to the "object"
+ base class.
+ (label::get_inner_label): New
+
+ (rvalue::rvalue): Update for move of inner pointer to the "object"
+ base class.
+ (rvalue::get_inner_rvalue): New.
+ (rvalue::access_field): Likewise.
+ (rvalue::dereference_field): Likewise.
+ (rvalue::dereference): Likewise.
+
+ (lvalue::get_inner_lvalue): Update for move of inner pointer to
+ the "object" base class.
+ (lvalue::access_field): Likewise.
+ (lvalue::get_address): Likewise.
+
+2014-01-31 David Malcolm <dmalcolm@redhat.com>
+
+ * libgccjit++.h: New file - a C++ wrapper for the libgccjit.h API.
+
+ * TODO.rst ("Test Suite"): New section, adding note about C++
+ tests.
+
+2014-01-31 David Malcolm <dmalcolm@redhat.com>
+
+ * libgccjit.h (gcc_jit_context_new_rvalue_from_int): Give the type
+ parameter a more descriptive name.
+ (gcc_jit_context_zero): Likewise.
+ (gcc_jit_context_one): Likewise.
+ (gcc_jit_context_new_rvalue_from_double): Likewise.
+ (gcc_jit_context_new_rvalue_from_ptr): Likewise.
+
+ * libgccjit.c (gcc_jit_context_new_rvalue_from_int): Likewise.
+ (gcc_jit_context_zero): Likewise.
+ (gcc_jit_context_one): Likewise.
+ (gcc_jit_context_new_rvalue_from_double): Likewise.
+ (gcc_jit_context_new_rvalue_from_ptr): Likewise.
+
+ * internal-api.h (gcc::jit::recording::context::
+ new_rvalue_from_int): Likewise.
+ (gcc::jit::recording::context::
+ new_rvalue_from_double): Likewise.
+ (gcc::jit::recording::memento_of_new_rvalue_from_int::
+ memento_of_new_rvalue_from_int): Likewise.
+ (gcc::jit::recording::memento_of_new_rvalue_from_double::
+ memento_of_new_rvalue_from_double): Likewise.
+ (gcc::jit::recording::memento_of_new_rvalue_from_ptr::
+ memento_of_new_rvalue_from_ptr): Likewise.
+
+2014-01-30 David Malcolm <dmalcolm@redhat.com>
+
+ * TODO.rst: Label-placement is now checked.
+
+ * internal-api.c (gcc::jit::recording::context::replay_into): Give
+ up if any errors occur during the playback.
+ (gcc::jit::recording::label::replay_into): Issue an error if the
+ label has not yet been placed (at playback time).
+ (gcc::jit::recording::place_label::place_label): Move this here
+ from internal-api.h. Issue an error if the label has already
+ been placed (at recording time).
+
+ * internal-api.h (gcc::jit::recording::label): Add an
+ m_has_been_placed field, and make class place_label a friend so
+ it can set it.
+ (gcc::jit::recording::label::has_been_placed): New accessor.
+ (gcc::jit::recording::place_label::place_label): Move to
+ internal-api.c.
+
+ (gcc::jit::playback::context::errors_occurred): Make public, for
+ use by gcc::jit::recording::context::replay_into.
+
+2014-01-30 David Malcolm <dmalcolm@redhat.com>
+
+ * internal-api.c (gcc::jit::recording::type::get_pointer):
+ Ensure that repeated calls yield the same type.
+ (gcc::jit::recording::memento_of_get_pointer::
+ accepts_writes_from): New.
+ (gcc::jit::recording::context::new_call): Move
+ the existing argument checking to...
+
+ * libgccjit.c (gcc_jit_context_new_call): ...here, and add
+ checking of the types of the arguments against the function.
+ (RETURN_VAL_IF_FAIL_PRINTF6): New.
+ (RETURN_NULL_IF_FAIL_PRINTF6): New.
+
+ * internal-api.h (gcc::jit::recording::type): New field
+ m_pointer_to_this_type, for use by get_pointer method.
+ (gcc::jit::recording::memento_of_get_pointer::
+ accepts_writes_from): New.
+ (gcc::jit::recording::function::get_param): New.
+
+ * TODO.rst (argument checking of gcc_jit_context_new_call): Done.
+
+2014-01-30 David Malcolm <dmalcolm@redhat.com>
+
+ * TODO.rst: begin a list of error-checking we could do that this
+ commit *doesn't* cover.
+
+ * libgccjit.h (gcc_jit_field): Add note that fields can't be
+ shared between structs.
+ (GCC_JIT_BINARY_OP_MODULO): Fix typo in comment.
+
+ * libgccjit.c: (RETURN_VAL_IF_FAIL_PRINTF2): New.
+ (RETURN_VAL_IF_FAIL_PRINTF3): New.
+ (RETURN_NULL_IF_FAIL_PRINTF2): New.
+ (RETURN_NULL_IF_FAIL_PRINTF3): New.
+ (RETURN_IF_FAIL_PRINTF4): New.
+
+ (jit_error): Take a gcc::jit::recording::context rather than
+ a gcc_jit_context so that we pass in contexts from the inner
+ layer.
+
+ (compatible_types): New, for use in type-checking.
+
+ (gcc_jit_context_new_struct_type): Check each field to ensure that
+ it isn't already in use by another struct.
+
+ (gcc_jit_rvalue_dereference_field): Check that ptr is of a pointer
+ type and that the field is within the correct struct, using new
+ get_debug_string hooks to generate error messages.
+
+ (gcc_jit_rvalue_dereference): Check that rvalue is of a pointer
+ type.
+
+ (gcc_jit_function_add_assignment): Use the function's context when
+ reporting on NULL lvalue or rvalue. Verify that the lvalue and
+ rvalue have compatible types.
+
+ (gcc_jit_function_add_return): Use the function's context when
+ reporting on NULL rvalue. Verify that the rvalue is of an
+ appropriate type given the function's return type.
+
+ * internal-api.h (NUM_GCC_JIT_TYPES): New.
+ (gcc::jit::recording::context::record): Move from here to
+ internal-api.c.
+ (gcc::jit::recording::context::get_opaque_FILE_type): New.
+ (gcc::jit::recording::context::m_basic_types): New field.
+ (gcc::jit::recording::context::m_FILE_type): New field.
+
+ (gcc::jit::recording::memento::get_debug_string): New method.
+ (gcc::jit::recording::memento::memento): Initialize new field
+ m_debug_string, and verify context is non-NULL.
+ (gcc::jit::recording::memento::make_debug_string): New
+ pure-virtual function lazily used by get_debug_string.
+ (gcc::jit::recording::memento::m_debug_string): New field, for
+ get_debug_string to use as a cache.
+
+ (gcc::jit::recording::string): Rename field m_copy to m_buffer.
+ (gcc::jit::recording::from_printf): New factory function.
+ (gcc::jit::recording::make_debug_string): New.
+
+ (gcc::jit::recording::location::make_debug_string): New.
+
+ (gcc::jit::recording::type::dereference): New pure-virtual
+ function.
+ (gcc::jit::recording::type::accepts_writes_from): New virtual
+ function.
+ (gcc::jit::recording::type::unqualified): New virtual function.
+
+ (gcc::jit::recording::memento_of_get_type::dereference): New.
+ (gcc::jit::recording::memento_of_get_type::
+ accepts_writes_from): New.
+ (gcc::jit::recording::memento_of_get_type::make_debug_string):
+ New.
+
+ (gcc::jit::recording::memento_of_get_pointer::make_debug_string):
+ New.
+ (gcc::jit::recording::memento_of_get_pointer::dereference): New.
+ New.
+
+ (gcc::jit::recording::memento_of_get_const::make_debug_string):
+ New.
+ (gcc::jit::recording::memento_of_get_const::dereference): New.
+ New.
+ (gcc::jit::recording::memento_of_get_const::accepts_writes_from):
+ New.
+ (gcc::jit::recording::memento_of_get_const::unqualified): New.
+
+ (gcc::jit::recording::field): New field m_container, for the
+ containing struct (or union, if we implement that).
+ (gcc::jit::recording::field::get_type): New.
+ (gcc::jit::recording::field::get_container): New.
+ (gcc::jit::recording::field:set_container): New.
+ (gcc::jit::recording::field::make_debug_string): New.
+
+ (gcc::jit::recording::struct_::struct_): Move ctor implementation
+ from here into internal-api.c.
+ (gcc::jit::recording::struct_::dereference): New.
+ (gcc::jit::recording::struct_::make_debug_string): New.
+
+ (gcc::jit::recording::rvalue::m_type): New field.
+ (gcc::jit::recording::rvalue::rvalue): Require a non-NULL type for
+ new rvalue instances.
+ (gcc::jit::recording::rvalue::get_type): New accessor.
+
+ (gcc::jit::recording::lvalue): Eliminate field m_type in favor of
+ that within the rvalue base class.
+
+ (gcc::jit::recording::param::make_debug_string): New.
+
+ (gcc::jit::recording::function::get_return_type): New accessor.
+ (gcc::jit::recording::function::make_debug_string): New.
+
+ (gcc::jit::recording::label::make_debug_string): New.
+
+ (gcc::jit::recording::global): Eliminate field m_type in favor of
+ that within the rvalue ultimate base class (via lvalue).
+ (gcc::jit::recording::make_debug_string): New.
+
+ (gcc::jit::recording::memento_of_new_rvalue_from_int): Eliminate
+ field m_type in favor of that within the rvalue base class.
+ (gcc::jit::recording::memento_of_new_rvalue_from_int::
+ make_debug_string): New.
+
+ (gcc::jit::recording::memento_of_new_rvalue_from_double): Eliminate
+ field m_type in favor of that within the rvalue base class.
+ (gcc::jit::recording::memento_of_new_rvalue_from_double::
+ make_debug_string): New.
+
+ (gcc::jit::recording::memento_of_new_rvalue_from_ptr): Eliminate
+ field m_type in favor of that within the rvalue base class.
+ (gcc::jit::recording::memento_of_new_rvalue_from_ptr::
+ make_debug_string): New.
+
+ (gcc::jit::recording::memento_of_new_string_literal::
+ memento_of_new_string_literal): Initialize type.
+ (gcc::jit::recording::memento_of_new_string_literal::
+ make_debug_string): New.
+
+ (gcc::jit::recording::unary_op): Eliminate field m_result_type in
+ favor of m_type within the rvalue base class.
+ (gcc::jit::recording::unary_op::make_debug_string): New.
+
+ (gcc::jit::recording::binary_op): Eliminate field m_result_type in
+ favor of m_type within the rvalue base class.
+ (gcc::jit::recording::binary_op::make_debug_string): New.
+
+ (gcc::jit::recording::comparison): Eliminate field m_result_type
+ in favor of m_type within the rvalue base class.
+ (gcc::jit::recording::comparison::make_debug_string): New.
+
+ (gcc::jit::recording::make_debug_string): New.
+
+ (gcc::jit::recording::array_lookup::array_lookup): Initialize type
+ by dereferencing the type of the pointer.
+ (gcc::jit::recording::array_lookup::make_debug_string): New.
+
+ (gcc::jit::recording::access_field_of_lvalue::
+ access_field_of_lvalue): Initialize type from that of the field.
+ (gcc::jit::recording::access_field_of_lvalue::
+ make_debug_string): New.
+
+ (gcc::jit::recording::access_field_rvalue::
+ access_field_of_rvalue): Initialize type from that of the field.
+ (gcc::jit::recording::access_field_rvalue::make_debug_string):
+ New.
+
+ (gcc::jit::recording::dereference_field_rvalue::
+ dereference_field_rvalue): Initialize type from that of the field.
+ (gcc::jit::recording::dereference_field_rvalue::
+ make_debug_string): New.
+
+ (gcc::jit::recording::dereference_rvalue::dereference_rvalue):
+ Initialize type by dereferencing the type of the pointer.
+ (gcc::jit::recording::dereference_rvalue::make_debug_string): New.
+
+ (gcc::jit::recording::get_address_of_lvalue::
+ get_address_of_lvalue): Initialize type by dereferencing the type
+ of the pointer.
+ (gcc::jit::recording::get_address_of_lvalue::make_debug_string):
+ New.
+
+ (gcc::jit::recording::local): Eliminate field m_type in favor of
+ that within the rvalue ultimate base class (via lvalue).
+ (gcc::jit::recording::make_debug_string): New.
+
+ (gcc::jit::recording::eval::make_debug_string): New.
+ (gcc::jit::recording::assignment::make_debug_string): New.
+ (gcc::jit::recording::assignment_op::make_debug_string): New.
+ (gcc::jit::recording::comment::make_debug_string): New.
+ (gcc::jit::recording::conditional::make_debug_string): New.
+ (gcc::jit::recording::place_label::make_debug_string): New.
+ (gcc::jit::recording::jump::make_debug_string): New.
+ (gcc::jit::recording::return_::make_debug_string): New.
+ (gcc::jit::recording::loop::make_debug_string): New.
+ (gcc::jit::recording::loop_end::make_debug_string): New.
+
+ * internal-api.c (gcc::jit::recording::context::context):
+ Initialize m_FILE_type and m_basic_types.
+ (gcc::jit::recording::context::record): Move here from
+ internal-api.h.
+ (gcc::jit::recording::context::replay_into): Add a disabled way to
+ log everything during a replay, exercising the stringification
+ machinery.
+ (gcc::jit::recording::context::get_type): Cache and reuse the
+ types, so that repeated calls on the context give the same object.
+ (gcc::jit::recording::context::get_opaque_FILE_type): New, for
+ the result of dereferencing (FILE*), mostly so that fuzz-testing
+ that tries this gets something sane back.
+ (gcc::jit::recording::memento::get_debug_string): New method,
+ giving a way to easily get a descriptive (const char *) for
+ an API entity. Internally, it lazily calls the make_debug_string
+ virtual function, storing the result in m_debug_string.
+
+ (gcc::jit::recording::string::string): Rename field m_copy to m_buffer.
+ (gcc::jit::recording::string::~string): Likewise.
+ (gcc::jit::recording::string::from_printf): New factory function,
+ to make it easy to implement the make_debug_string hooks.
+
+ (gcc::jit::recording::string::make_debug_string): New.
+
+ (gcc::jit::recording::location::make_debug_string): New.
+
+ (gcc::jit::recording::memento_of_get_type::dereference): New.
+
+ (get_type_strings): New table of strings, for use by...
+ (gcc::jit::recording::memento_of_get_type::make_debug_string): New.
+
+ (gcc::jit::recording::memento_of_get_pointer::make_debug_string): New.
+
+ (gcc::jit::recording::memento_of_get_const::make_debug_string): New.
+
+ (gcc::jit::recording::field::make_debug_string): New.
+
+ (gcc::jit::recording::struct_::struct_): Move here from
+ internal-api.h. Mark all fields as belonging to the new struct.
+
+ (gcc::jit::recording::struct_::dereference): New.
+ (gcc::jit::recording::struct_::make_debug_string): New.
+
+ (gcc::jit::recording::function::make_debug_string): New.
+
+ (gcc::jit::recording::label::make_debug_string): New.
+
+ (gcc::jit::recording::memento_of_new_rvalue_from_int::
+ make_debug_string): New.
+ (gcc::jit::recording::memento_of_new_rvalue_from_double::
+ make_debug_string): New.
+ (gcc::jit::recording::memento_of_new_rvalue_from_ptr::
+ make_debug_string): New.
+ (gcc::jit::recording::memento_of_new_string_literal::
+ make_debug_string): New.
+
+ (gcc::jit::recording::unary_op::replay_into): Use get_type ()
+ rather than the now-defunct m_result_type.
+ (gcc::jit::recording::binary_op::replay_into): Likewise.
+
+ (unary_op_strings): New table of strings for use by...
+ (gcc::jit::recording::unary_op::make_debug_string): New.
+
+ (binary_op_strings): New table of strings for use by...
+ (gcc::jit::recording::binary_op::make_debug_string): New.
+
+ (comparison_strings): New table of strings for use by...
+ (gcc::jit::recording::comparison::make_debug_string): New.
+
+ (gcc::jit::recording::call::call): Initialize the type.
+ (gcc::jit::recording::call::make_debug_string): New.
+
+ (gcc::jit::recording::array_lookup::make_debug_string): New.
+ (gcc::jit::recording::access_field_of_lvalue::
+ make_debug_string): New.
+ (gcc::jit::recording::access_field_rvalue::
+ make_debug_string): New.
+ (gcc::jit::recording::dereference_field_rvalue::
+ make_debug_string): New.
+ (gcc::jit::recording::dereference_rvalue::make_debug_string): New.
+ (gcc::jit::recording::get_address_of_lvalue::
+ make_debug_string): New.
+ (gcc::jit::recording::eval::make_debug_string): New.
+ (gcc::jit::recording::assignment::make_debug_string): New.
+ (gcc::jit::recording::assignment_op::make_debug_string): New.
+ (gcc::jit::recording::comment::make_debug_string): New.
+ (gcc::jit::recording::conditional::make_debug_string): New.
+ (gcc::jit::recording::place_label::make_debug_string): New.
+ (gcc::jit::recording::jump::make_debug_string): New.
+ (gcc::jit::recording::return_::make_debug_string): New.
+ (gcc::jit::recording::loop::make_debug_string): New.
+ (gcc::jit::recording::loop_end::make_debug_string): New.
+
+2014-01-29 David Malcolm <dmalcolm@redhat.com>
+
+ * libgccjit.h (gcc_jit_lvalue_access_field): Require
+ a (gcc_jit_field *) rather than a field name.
+ (gcc_jit_rvalue_access_field): Likewise.
+ (gcc_jit_rvalue_dereference_field): Likewise.
+
+ * libgccjit.c (gcc_jit_lvalue_access_field): Require
+ a (gcc_jit_field *) rather than a field name.
+ (gcc_jit_rvalue_access_field): Likewise.
+ (gcc_jit_rvalue_dereference_field): Likewise.
+
+ * internal-api.c (gcc::jit::recording::rvalue::access_field):
+ Require a field rather than a fieldname string.
+ (gcc::jit::recording::rvalue::dereference_field): Likewise.
+ (gcc::jit::recording::lvalue::access_field): Likewise.
+
+ (gcc::jit::recording::access_field_of_lvalue::replay_into): Update
+ given that this now has a field, rather than a fieldname.
+ (gcc::jit::recording::access_field_rvalue::replay_into): Likewise.
+ (gcc::jit::recording::dereference_field_rvalue::replay_into): Likewise.
+
+ (get_field): Delete, as we no longer need to convert
+ from (struct, identifier) pairs to fields, instead directly using
+ fields.
+
+ (gcc::jit::playback::context::new_field_access): Require a field
+ rather than a fieldname, removing the need to look up the field by
+ name within the struct.
+
+ (gcc::jit::playback::lvalue::access_field): Likewise.
+ (gcc::jit::playback::rvalue::access_field): Likewise.
+ (gcc::jit::playback::rvalue::dereference_field): Likewise.
+
+ * internal-api.h (gcc::jit::recording::rvalue::access_field):
+ Require a field rather than a fieldname string.
+ (gcc::jit::recording::rvalue::dereference_field): Likewise.
+ (gcc::jit::recording::lvalue::access_field): Likewise.
+
+ (gcc::jit::recording::access_field_of_lvalue::access_field_of_lvalue):
+ Likewise.
+ (gcc::jit::recording::access_field_of_lvalue::m_fieldname): Drop
+ string field in favor of...
+ (gcc::jit::recording::access_field_of_lvalue::m_field):
+ ..."field" field, as it were.
+
+ (gcc::jit::recording::access_field_of_rvalue::access_field_of_rvalue):
+ Likewise.
+ (gcc::jit::recording::access_field_of_rvalue::m_fieldname): Drop
+ string field in favor of...
+ (gcc::jit::recording::access_field_of_rvalue::m_field):
+ ..."field" field.
+
+ (gcc::jit::recording::dereference_field_rvalue::
+ dereference_field_rvalue): Likewise.
+ (gcc::jit::recording::dereference_field_rvalue::m_fieldname): Drop
+ string field in favor of...
+ (gcc::jit::recording::dereference_field_rvalue::m_field):
+ ..."field" field.
+
+ (gcc::jit::playback::context::new_field_access): Require a field
+ rather than a fieldname string.
+ (gcc::jit::playback::context::access_field): Likewise.
+ (gcc::jit::playback::context::dereference_field): Likewise.
+ (gcc::jit::playback::rvalue::access_field):
+
+2014-01-28 David Malcolm <dmalcolm@redhat.com>
+
+ * libgccjit.h (gcc_jit_context_new_child_context): New function.
+
+ * libgccjit.map (gcc_jit_context_new_child_context): New function.
+
+ * libgccjit.c (gcc_jit_context): Make the constructor explicit,
+ with a parent context as a parameter.
+ (gcc_jit_context_acquire): Create context with a NULL parent.
+ (gcc_jit_context_new_child_context): New function, creating a
+ context with the given parent.
+
+ * internal-api.h (gcc::jit::recording::context::context): New
+ explicit constructor, taking a parent context as a parameter.
+ (gcc::jit::recording::context::m_parent_ctxt): New field.
+
+ * internal-api.c (gcc::jit::recording::context::context): New
+ explicit constructor, taking a parent context as a parameter.
+ (gcc::jit::recording::context::replay_into): Replay parent contexts
+ before replaying the context itself.
+
+2014-01-27 David Malcolm <dmalcolm@redhat.com>
+
+ * internal-api.c (gcc::jit::playback::context::compile): Removal
+ of the code-creation callback (96b218c9a1d5f39fb649e02c0e77586b180e8516)
+ accidentally removed the implementation of
+ GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE; reinstate it.
+
+2014-01-27 David Malcolm <dmalcolm@redhat.com>
+
+ * internal-api (gcc::jit::recording::context::new_call): Verify
+ the argument count of the call against the parameter count of the
+ function, issuing an error if there's a mismatch.
+
+ * internal-api.h (gcc::jit::recording::function::get_name): New.
+ * (gcc::jit::recording::function::get_params): New.
+ * (gcc::jit::recording::function::is_variadic): New.
+
+2014-01-27 David Malcolm <dmalcolm@redhat.com>
+
+ * libgccjit.h (enum gcc_jit_binary_op): Remove
+ GCC_JIT_BINARY_OP_FLOATING_DIVIDE, which I accidentally added
+ as part of a880c0d9c642730550f39d328f29a1d9935cb07e.
+
+2014-01-24 David Malcolm <dmalcolm@redhat.com>
+
+ * libgccjit.h: Update comments to eliminate the code-creation
+ callback. All "contextual" objects change from merely being
+ "alive" during the callback to having a lifetime equal to that
+ of the context they are created within, with automatic cleanup
+ when the context is released.
+ (gcc_jit_code_callback): Delete.
+ (gcc_jit_context_set_code_factory): Delete.
+
+ * libgccjit.map (gcc_jit_context_set_code_factory): Delete.
+
+ * dummy-frontend.c (my_walker): Update for rename of the singleton
+ reference-owning context.
+ (jit_langhook_parse_file): Rather than run a client-provided
+ callback, we now replay a recording of the client activity.
+
+ * internal-api.h (gcc::jit): Split the existing API into two
+ copies...
+ (gcc::jit::recording): ...a class hierarchy used to implement
+ the client-facing API, which records the API calls made to it
+ and...
+ (gcc::jit::playback): ...a class hierarchy used within the
+ dummy GCC frontend, which plays back the recorded API calls once
+ GCC is initialized.
+
+ * internal-api.c (gcc::jit::recording::playback_location): New
+ API, in which client API calls are recorded as a list of "memento"
+ objects, to be played back into GCC when the dummy frontend runs.
+ (gcc::jit::recording::playback_string): Likewise.
+ (gcc::jit::recording::playback_label): Likewise.
+ (gcc::jit::recording::context::~context): Likewise.
+ (gcc::jit::recording::context::replay_into): Likewise.
+ (gcc::jit::recording::context::disassociate_from_playback): Likewise.
+ (gcc::jit::recording::context::new_string): Likewise.
+ (gcc::jit::recording::context::new_location): Likewise.
+ (gcc::jit::recording::context::get_type): Likewise.
+ (gcc::jit::recording::context::new_field): Likewise.
+ (gcc::jit::recording::context::new_struct_type): Likewise.
+ (gcc::jit::recording::context::new_param): Likewise.
+ (gcc::jit::recording::context::new_function): Likewise.
+ (gcc::jit::recording::context::new_global): Likewise.
+ (gcc::jit::recording::context::new_rvalue_from_int): Likewise.
+ (gcc::jit::recording::context::new_rvalue_from_double): Likewise.
+ (gcc::jit::recording::context::new_rvalue_from_ptr): Likewise.
+ (gcc::jit::recording::context::new_string_literal): Likewise.
+ (gcc::jit::recording::context::new_unary_op): Likewise.
+ (gcc::jit::recording::context::new_binary_op): Likewise.
+ (gcc::jit::recording::context::new_comparison): Likewise.
+ (gcc::jit::recording::context::new_call): Likewise.
+ (gcc::jit::recording::context::new_array_lookup): Likewise.
+ (gcc::jit::recording::string::string): Likewise.
+ (gcc::jit::recording::string::~string): Likewise.
+ (gcc::jit::recording::location::replay_into): Likewise.
+ (gcc::jit::recording::type::get_pointer): Likewise.
+ (gcc::jit::recording::type::get_const): Likewise.
+ (gcc::jit::recording::memento_of_get_type::replay_into): Likewise.
+ (gcc::jit::recording::memento_of_get_pointer::replay_into): Likewise.
+ (gcc::jit::recording::memento_of_get_const::replay_into): Likewise.
+ (gcc::jit::recording::field::replay_into): Likewise.
+ (gcc::jit::recording::struct_::replay_into): Likewise.
+ (gcc::jit::recording::rvalue::access_field): Likewise.
+ (gcc::jit::recording::rvalue::dereference_field): Likewise.
+ (gcc::jit::recording::rvalue::dereference): Likewise.
+ (gcc::jit::recording::lvalue::access_field): Likewise.
+ (gcc::jit::recording::lvalue::get_address): Likewise.
+ (gcc::jit::recording::param::replay_into): Likewise.
+ (gcc::jit::recording::function::function): Likewise.
+ (gcc::jit::recording::function::replay_into): Likewise.
+ (gcc::jit::recording::function::new_local): Likewise.
+ (gcc::jit::recording::function::new_forward_label): Likewise.
+ (gcc::jit::recording::function::add_eval): Likewise.
+ (gcc::jit::recording::function::add_assignment): Likewise.
+ (gcc::jit::recording::function::add_assignment_op): Likewise.
+ (gcc::jit::recording::function::add_comment): Likewise.
+ (gcc::jit::recording::function::add_conditional): Likewise.
+ (gcc::jit::recording::function::add_label): Likewise.
+ (gcc::jit::recording::function::place_forward_label): Likewise.
+ (gcc::jit::recording::function::add_jump): Likewise.
+ (gcc::jit::recording::function::add_return): Likewise.
+ (gcc::jit::recording::function::new_loop): Likewise.
+ (gcc::jit::recording::label::replay_into): Likewise.
+ (gcc::jit::recording::global::replay_into): Likewise.
+ (gcc::jit::recording::memento_of_new_rvalue_from_int::replay_into):
+ Likewise.
+ (gcc::jit::recording::memento_of_new_rvalue_from_double::replay_into):
+ Likewise.
+ (gcc::jit::recording::memento_of_new_rvalue_from_ptr::replay_into):
+ Likewise.
+ (gcc::jit::recording::memento_of_new_string_literal::replay_into):
+ Likewise.
+ (gcc::jit::recording::unary_op::replay_into): Likewise.
+ (gcc::jit::recording::binary_op::replay_into): Likewise.
+ (gcc::jit::recording::comparison::replay_into): Likewise.
+ (gcc::jit::recording::call::call): Likewise.
+ (gcc::jit::recording::call::replay_into): Likewise.
+ (gcc::jit::recording::array_lookup::replay_into): Likewise.
+ (gcc::jit::recording::access_field_of_lvalue::replay_into): Likewise.
+ (gcc::jit::recording::access_field_rvalue::replay_into): Likewise.
+ (gcc::jit::recording::dereference_field_rvalue::replay_into): Likewise.
+ (gcc::jit::recording::dereference_rvalue::replay_into): Likewise.
+ (gcc::jit::recording::get_address_of_lvalue::replay_into): Likewise.
+ (gcc::jit::recording::local::replay_into): Likewise.
+ (gcc::jit::recording::eval::replay_into): Likewise.
+ (gcc::jit::recording::assignment::replay_into): Likewise.
+ (gcc::jit::recording::assignment_op::replay_into): Likewise.
+ (gcc::jit::recording::comment::replay_into): Likewise.
+ (gcc::jit::recording::conditional::replay_into): Likewise.
+ (gcc::jit::recording::place_label::replay_into): Likewise.
+ (gcc::jit::recording::jump::replay_into): Likewise.
+ (gcc::jit::recording::return_::replay_into): Likewise.
+ (gcc::jit::recording::loop::replay_into): Likewise.
+ (gcc::jit::recording::loop::end): Likewise.
+ (gcc::jit::recording::loop_end::replay_into): Likewise.
+
+ (gcc::jit::recording::context::set_str_option): Likewise.
+ Option setting and error-handling is now "owned" by the recording
+ context; the playback context delegates to the recording context
+ for these aspects.
+ (gcc::jit::recording::context::set_int_option): Likewise.
+ (gcc::jit::recording::context::set_bool_option): Likewise.
+ (gcc::jit::recording::context::compile): Likewise.
+ (gcc::jit::recording::context::add_error): Likewise.
+ (gcc::jit::recording::context::add_error_va): Likewise.
+ (gcc::jit::recording::context::get_first_error): Likewise.
+
+ (gcc::jit::context::context): Rename to...
+ (gcc::jit::playback::context::context): ...this.
+ (gcc::jit::context::~context): Rename to...
+ (gcc::jit::playback::context::~context): ...this.
+ (gcc::jit::context::gt_ggc_mx): Rename to...
+ (gcc::jit::playback::context::gt_ggc_mx): ...this.
+
+ (gcc::jit::context::set_code_factory): Eliminate.
+
+ (gcc::jit::context::get_type): Rename to...
+ (gcc::jit::playback::context::get_type): ...this.
+ (gcc::jit::context::new_field): Rename to...
+ (gcc::jit::playback::context::new_field): ...this.
+ (gcc::jit::context::new_struct_type): Rename to...
+ (gcc::jit::playback::context::new_struct_type): ...this, and
+ update to require a vec<field *>.
+ (gcc::jit::context::new_param): Rename to...
+ (gcc::jit::playback::context::new_param): ...this.
+ (gcc::jit::context::new_function): Rename to...
+ (gcc::jit::playback::context::new_function): ...this, and update
+ to require a vec<param *>.
+ (gcc::jit::context::new_global): Rename to...
+ (gcc::jit::playback::context::new_global): ...this.
+ (gcc::jit::context::new_rvalue_from_int): Rename to...
+ (gcc::jit::playback::context::new_rvalue_from_int): ...this.
+ (gcc::jit::context::new_rvalue_from_double): Rename to...
+ (gcc::jit::playback::context::new_rvalue_from_double): ...this.
+ (gcc::jit::context::new_rvalue_from_ptr): Rename to...
+ (gcc::jit::playback::context::new_rvalue_from_ptr): ...this.
+ (gcc::jit::context::new_string_literal): Rename to...
+ (gcc::jit::playback::context::new_string_literal): ...this.
+ (gcc::jit::context::as_truth_value): Rename to...
+ (gcc::jit::playback::context::as_truth_value): ...this.
+ (gcc::jit::context::new_unary_op): Rename to...
+ (gcc::jit::playback::context::new_unary_op): ...this.
+ (gcc::jit::context::new_binary_op): Rename to...
+ (gcc::jit::playback::context::new_binary_op): ...this.
+ (gcc::jit::context::new_comparison): Rename to...
+ (gcc::jit::playback::context::new_comparison): ...this.
+ (gcc::jit::context::new_call): Rename to...
+ (gcc::jit::playback::context::new_call): ...this, and update
+ to require a vec<rvalue *>.
+ (gcc::jit::context::new_array_lookup): Rename to...
+ (gcc::jit::playback::context::new_array_lookup): ...this.
+ (gcc::jit::context::new_field_access): Rename to...
+ (gcc::jit::playback::context::new_field_access): ...this.
+ (gcc::jit::context::new_dereference): Rename to...
+ (gcc::jit::playback::context::new_dereference): ...this.
+
+ (gcc::jit::lvalue::access_field): Rename to...
+ (gcc::jit::playback::lvalue::access_field): ...this.
+ (gcc::jit::lvalue::get_address): Rename to...
+ (gcc::jit::playback::lvalue::get_address): ...this.
+
+ (gcc::jit::rvalue::dereference_field): Rename to...
+ (gcc::jit::playback::rvalue::dereference_field): ...this.
+
+ (gcc::jit::rvalue::dereference): Rename to...
+ (gcc::jit::playback::rvalue::dereference): ...this.
+
+ (gcc::jit::wrapper::operator new): Rename to...
+ (gcc::jit::playback::wrapper::operator new): ...this.
+
+ (gcc::jit::function::function): Rename to...
+ (gcc::jit::playback::function::function): ...this.
+ (gcc::jit::function::gt_ggc_mx): Rename to...
+ (gcc::jit::playback::function::gt_ggc_mx): ...this.
+ (gcc::jit::function::get_return_type_as_tree): Rename to...
+ (gcc::jit::playback::function::get_return_type_as_tree): ...this.
+ (gcc::jit::function::new_local): Rename to...
+ (gcc::jit::playback::function::new_local): ...this.
+ (gcc::jit::function::new_forward_label): Rename to...
+ (gcc::jit::playback::function::new_forward_label): ...this.
+ (gcc::jit::function::postprocess): Rename to...
+ (gcc::jit::playback::function::postprocess): ...this.
+ (gcc::jit::function::add_eval): Rename to...
+ (gcc::jit::playback::function::add_eval): ...this.
+ (gcc::jit::function::add_assignment): Rename to...
+ (gcc::jit::playback::function::add_assignment): ...this.
+ (gcc::jit::function::add_comment): Rename to...
+ (gcc::jit::playback::function::add_comment): ...this.
+ (gcc::jit::function::add_conditional): Rename to...
+ (gcc::jit::playback::function::add_conditional): ...this.
+ (gcc::jit::function::add_label): Rename to...
+ (gcc::jit::playback::function::add_label): ...this.
+ (gcc::jit::function::place_forward_label): Rename to...
+ (gcc::jit::playback::function::place_forward_label): ...this.
+ (gcc::jit::function::add_jump): Rename to...
+ (gcc::jit::playback::function::add_jump): ...this.
+ (gcc::jit::function::add_return): Rename to...
+ (gcc::jit::playback::function::add_return): ...this.
+ (gcc::jit::function::new_loop): Rename to...
+ (gcc::jit::playback::function::new_loop): ...this.
+
+ (gcc::jit::label::label): Rename to...
+ (gcc::jit::playback::label::label): ...this.
+
+ (gcc::jit::loop::loop): Rename to...
+ (gc::jit::playback::loop::loop): ...this.
+ (gcc::jit::loop::end): Rename to...
+ (gcc::jit::playback::loop): ...this.
+
+ (gcc::jit::active_jit_ctxt): Eliminate in favor of...
+ (gcc::jit::active_playback_ctxt): ...this.
+
+ (gcc::jit::context::compile): Rename to...
+ (gcc::jit::playback::context::compile): ...this, and eliminate the
+ mutex handling; this is done for us by the caller.
+
+ (gcc::jit::context::invoke_code_factory): Rename to...
+ (gcc::jit::playback::context::replay): this. Rather than call
+ a client-provided callback, instead replay the recorded API
+ calls.
+
+ (gcc::jit::context::dump_generated_code): Rename to...
+ (gcc::jit::playback::context::dump_generated_code): ...this.
+
+ (location_comparator): Update for renamed types.
+
+ (gcc::jit::context::handle_locations): Rename to...
+ (gcc::jit::playback::context::handle_locations): ...this.
+
+ (gcc::jit::context::add_error): Rename to...
+ (gcc::jit::playback::context::add_error): this, and delegate to
+ the recording context's add_error_va.
+
+ (gcc::jit::context::add_error_va): Rename to...
+ (gcc::jit::playback::context::add_error_va): this, and delegate
+ to the recording context.
+
+ (gcc::jit::context::new_location): Rename to...
+ (gcc::jit::playback::context::new_location): ...this.
+ (gcc::jit::context::set_tree_location): Rename to...
+ (gcc::jit::playback::context::set_tree_location): ...this.
+ (gcc::jit::context::get_source_file): Rename to...
+ (gcc::jit::playback::context::get_source_file): ...this.
+ (gcc::jit::source_file::source_file): Rename to...
+ (gcc::jit::playback::source_file::source_file): ...this.
+ (gcc::jit::source_file::get_source_line): Rename to...
+ (gcc::jit::playback::source_file::get_source_line): ...this.
+ (gcc::jit::source_line::source_line): Rename to...
+ (gcc::jit::playback::source_line::source_line): ...this.
+ (gcc::jit::source_line::get_location): Rename to...
+ (gcc::jit::playback::source_line::get_location): ...this.
+
+ (gcc::jit::location::location): Rename to...
+ (gcc::jit::playback::location::location): ...this.
+
+ * libgccjit.c: Update classes to derive from the "jit::recording"
+ class hierarchy.
+ (RETURN_IF_NOT_INITIAL_CTXT): Eliminate, as it relates to
+ code-creation callbacks.
+ (RETURN_NULL_IF_NOT_INITIAL_CTXT): Likewise.
+ (RETURN_NULL_IF_NOT_CALLBACK_CTXT): Likewise.
+ (jit_error): There isn't an "active jit context" anymore, except
+ during actual compilation, so simplify the logic here.
+ (gcc_jit_context_set_code_factory): Delete.
+
+ (gcc_jit_context_new_location): Update preconditions now that we
+ don't have code-creation callbacks.
+ (gcc_jit_context_get_type): Likewise.
+ (gcc_jit_type_get_pointer): Likewise.
+ (gcc_jit_type_get_const): Likewise.
+ (gcc_jit_context_new_field): Likewise.
+ (gcc_jit_context_new_struct_type): Likewise.
+ (gcc_jit_context_new_param): Likewise.
+ (gcc_jit_param_as_lvalue): Likewise.
+ (gcc_jit_param_as_rvalue): Likewise.
+ (gcc_jit_context_new_function): Likewise.
+ (gcc_jit_context_new_function): Likewise.
+ (gcc_jit_function_new_forward_label): Likewise.
+ (gcc_jit_context_new_global): Likewise.
+ (gcc_jit_lvalue_as_rvalue): Likewise.
+ (gcc_jit_context_new_rvalue_from_int): Likewise.
+ (gcc_jit_context_zero): Likewise.
+ (gcc_jit_context_one): Likewise.
+ (gcc_jit_context_new_rvalue_from_double): Likewise.
+ (gcc_jit_context_new_rvalue_from_ptr): Likewise.
+ (gcc_jit_context_new_string_literal): Likewise.
+ (gcc_jit_context_new_unary_op): Likewise.
+ (gcc_jit_context_new_binary_op): Likewise.
+ (gcc_jit_context_new_comparison): Likewise.
+ (gcc_jit_context_new_call): Likewise.
+ (gcc_jit_context_new_call): Likewise.
+ (gcc_jit_context_new_array_lookup): Likewise.
+ (gcc_jit_context_set_str_option): Likewise.
+ (gcc_jit_context_set_int_option): Likewise.
+ (gcc_jit_context_set_bool_option): Likewise.
+ (gcc_jit_context_compile): Likewise.
+ (gcc_jit_function_add_assignment_op): Likewise. Also,
+ reimplement as a separate kind of recording, since we can't know
+ the type of the lvalue at recording-time.
+
+ * notes.txt: Update diagram to reflect the new implementation.
+
+2014-01-24 David Malcolm <dmalcolm@redhat.com>
+
+ * libgccjit.h (enum gcc_jit_binary_op): We will use the result
+ type to determine if GCC_JIT_BINARY_OP_DIVIDE should
+ truncate towards zero, or be floating-point division.
+
+ * internal-api.c (gcc::jit::context::new_binary_op): Likewise.
+
+2014-01-24 David Malcolm <dmalcolm@redhat.com>
+
+ * internal-api.h (gcc::jit::context::get_str_option): New access
+ method.
+ (gcc::jit::context::get_int_option): Likewise.
+
+ * internal-api.c (gcc::jit::context::~context): Use access methods
+ for options, rather than direct field access.
+ (gcc::jit::context::compile): Likewise.
+
+2014-01-23 David Malcolm <dmalcolm@redhat.com>
+
+ * libgccjit.h (enum gcc_jit_bool_option): New value:
+ GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE.
+
+ * internal-api.c (gcc::jit::context::compile): Call
+ dump_generated_code if the user has requested it.
+ (gcc::jit::context::dump_generated_code): New, copying
+ from the .s file to stderr.
+
+ * internal-api.h (gcc::jit::context::dump_generated_code): New.
+
+2014-01-23 David Malcolm <dmalcolm@redhat.com>
+
+ * internal-api.h (gcc::jit::function): Add field
+ "m_inner_bind_expr".
+ * internal-api.c (gcc::jit::function::function): Create a BIND_EXPR
+ for all non-imported functions, and put the statement list within
+ it.
+ (gcc::jit::function::gt_ggc_mx): Visit m_inner_bind_expr.
+ (gcc::jit::function::new_local): Set the DECL_CONTEXT of the new
+ local to be the function's BIND_EXPR, and prepend the new local
+ to said BIND_EXPR's BIND_EXPR_VARS chain.
+ (gcc::jit::function::postprocess): Set the DECL_SAVED_TREE of the
+ FUNCTION_DECL to be the BIND_EXPR, rather than the statement list.
+ The latter is now contained within the former.
+
+2014-01-23 David Malcolm <dmalcolm@redhat.com>
+
+ * internal-api.h (gcc::jit::function::add_stmt): New.
+
+ * internal-api.c (gcc::jit::function::add_eval): Replace use of
+ tsi_link_stmt with call to add_stmt.
+ (gcc::jit::function::add_assignment): Likewise.
+ (gcc::jit::function::add_conditional): Likewise.
+ (gcc::jit::function::place_forward_label): Likewise.
+ (gcc::jit::function::add_jump): Likewise.
+ (gcc::jit::function::add_return): Likewise.
+
+2014-01-21 David Malcolm <dmalcolm@redhat.com>
+
+ * internal-api.c (gcc::jit::function::add_comment): New.
+ * internal-api.h (gcc::jit::function::add_comment): New.
+ * libgccjit.c (gcc_jit_function_add_comment): New.
+ * libgccjit.h (gcc_jit_function_add_comment): New.
+ * libgccjit.map: Add gcc_jit_function_add_comment.
+
+2013-10-24 David Malcolm <dmalcolm@redhat.com>
+
+ * internal-api.c (gcc::jit::function::add_eval): Handle non-NULL
+ locations.
+ (gcc::jit::context::handle_locations): Fix test for the various
+ kinds of declarations, replacing use of DECL_MINIMAL_CHECK,
+ which aborts on failure (such as if we saw a type).
+ * libgccjit.h (GCC_JIT_BOOL_OPTION_DEBUGINFO): Fix out-of-date
+ comment.
+
+2013-10-23 David Malcolm <dmalcolm@redhat.com>
+
+ * internal-api.c: Update for rename of tree-flow.h to tree-cfg.h
+ in r203320, for declaration of dump_function_to_file.
+ * TODO.rst ("segfault seen in libbacktrace"): Remove - this was
+ fixed by Ian in r203810.
+
+2013-10-23 David Malcolm <dmalcolm@redhat.com>
+
+ * internal-api.c: Add missing include of diagnostic-core.h
+
+2013-10-22 David Malcolm <dmalcolm@redhat.com>
+
+ * internal-api.c (gcc::jit::context::add_error_va): Record the
+ first error that occurs on a context.
+ (gcc::jit::context::get_first_error): New.
+ * internal-api.h (gcc::jit::context::get_first_error): New.
+ (gcc::jit::context::m_first_error_str): New.
+ * libgccjit.c (gcc_jit_context_get_first_error): New.
+ * libgccjit.h (gcc_jit_context_get_first_error): New.
+ * libgccjit.map (gcc_jit_context_get_first_error): New.
+
+2013-10-21 David Malcolm <dmalcolm@redhat.com>
+
+ * internal-api.c (gcc::jit::context::compile): Correctly cleanup
+ timevars in error-handling, preventing an issue where an error
+ on a context left timevar.c in an unstopped state, leading to an
+ assertion failure when restarting timevars in the next compile.
+ Found via fuzz-testing.
+
+2013-10-21 David Malcolm <dmalcolm@redhat.com>
+
+ * internal-api.c (gcc::jit::context::postprocess): Show source
+ line numbers (if any) in gimple dump.
+
+2013-10-21 David Malcolm <dmalcolm@redhat.com>
+
+ * libgccjit.c (gcc_jit_function_new_local): Use a more clear
+ error message for the case where someone tries to add a local
+ to a function imported from elsewhere.
+
+2013-10-21 David Malcolm <dmalcolm@redhat.com>
+
+ * TODO.rst ("the C unary prefix "&" operator"): Remove completed item.
+ * internal-api.c (gcc::jit::lvalue::get_address): New.
+ * internal-api.h (gcc::jit::lvalue::get_address): New.
+ * libgccjit.c (gcc_jit_lvalue_get_address): New.
+ * libgccjit.h (gcc_jit_lvalue_get_address): New.
+ * libgccjit.map (gcc_jit_lvalue_get_address): New.
+
+2013-10-18 David Malcolm <dmalcolm@redhat.com>
+
+ * internal-api.c (gcc::jit::context::new_param): Add context
+ argument to ctor for rvalue and its subclasses.
+ (gcc::jit::context::new_global): Likewise.
+ (gcc::jit::context::new_rvalue_from_int): Likewise.
+ (gcc::jit::context::new_rvalue_from_double): Likewise.
+ (gcc::jit::context::new_rvalue_from_ptr): Likewise.
+ (gcc::jit::context::new_string_literal): Likewise.
+ (gcc::jit::context::new_call): Likewise.
+ (gcc::jit::context::new_array_lookup): Likewise.
+ (gcc::jit::function::new_local): Likewise.
+ (gcc::jit::context::new_binary_op): Likewise; add new
+ operations.
+ (gcc::jit::context::new_comparison): Likewise; add new
+ comparisons.
+ (gcc::jit::context::as_truth_value): New.
+ (gcc::jit::context::new_unary_op): New.
+ (gcc::jit::context::new_field_access): Convert to a helper
+ method for use by the access_fields methods.
+ (gcc::jit::context::new_dereference): New.
+ (gcc::jit::lvalue::access_field): New.
+ (gcc::jit::rvalue::access_field): New.
+ (gcc::jit::rvalue::dereference_field): New.
+ (gcc::jit::rvalue::dereference): New.
+ * internal-api.h (gcc::jit::context::new_unary_op): New.
+ (gcc::jit::context::new_field_access): Work
+ (gcc::jit::context::new_dereference): New.
+ (gcc::jit::context::as_truth_value): New.
+ (gcc::jit::rvalue): Add a context field.
+ (gcc::jit::rvalue::access_field): New.
+ (gcc::jit::rvalue::dereference_field): New.
+ (gcc::jit::rvalue::dereference): New.
+ (gcc::jit::lvalue::lvalue): Add context to ctor.
+ (gcc::jit::lvalue::access_field): New.
+ (gcc::jit::param::param): Add context to ctor.
+ * libgccjit.c (gcc_jit_context_new_unary_op): New.
+ (gcc_jit_context_new_field_access): Remove.
+ (gcc_jit_lvalue_access_field): New.
+ (gcc_jit_rvalue_access_field): New.
+ (gcc_jit_rvalue_dereference_field): New.
+ (gcc_jit_rvalue_dereference): New.
+ *libgccjit.h (enum gcc_jit_unary_op): New.
+ (gcc_jit_context_new_unary_op): New.
+ (enum gcc_jit_binary_op): Document values, and add...
+ (GCC_JIT_BINARY_OP_DIVIDE): New.
+ (GCC_JIT_BINARY_OP_MODULO): New.
+ (GCC_JIT_BINARY_OP_BITWISE_AND): New.
+ (GCC_JIT_BINARY_OP_BITWISE_XOR): New.
+ (GCC_JIT_BINARY_OP_BITWISE_OR): New.
+ (GCC_JIT_BINARY_OP_LOGICAL_AND): New.
+ (GCC_JIT_BINARY_OP_LOGICAL_OR): New.
+ (enum gcc_jit_comparison): Document values, and add...
+ (GCC_JIT_COMPARISON_EQ): New.
+ (GCC_JIT_COMPARISON_NE): New.
+ (GCC_JIT_COMPARISON_LE): New.
+ (GCC_JIT_COMPARISON_GT): New.
+ (GCC_JIT_COMPARISON_GE): New.
+ (gcc_jit_context_new_field_access): Remove.
+ (gcc_jit_lvalue_access_field): New.
+ (gcc_jit_rvalue_access_field): New.
+ (gcc_jit_rvalue_dereference_field): New.
+ (gcc_jit_rvalue_dereference): New.
+ * libgccjit.map (gcc_jit_context_new_field_access): Remove.
+ (gcc_jit_lvalue_access_field): New.
+ (gcc_jit_rvalue_access_field): New.
+ (gcc_jit_rvalue_dereference_field): New.
+ (gcc_jit_rvalue_dereference): New.
+ * TODO.rst: Update
+
+2013-10-18 David Malcolm <dmalcolm@redhat.com>
+
+ * internal-api.c (gcc::jit::context::get_type): Improve error
+ message, and report the bogus value.
+ (gcc::jit::context::new_binary_op): Likewise.
+ (gcc::jit::context::new_comparison): Likewise.
+ (gcc::jit::context::set_str_option): Likewise.
+ (gcc::jit::context::set_int_option): Likewise.
+ (gcc::jit::context::set_bool_option): Likewise.
+ (gcc::jit::context::compile): Likewise, and make the errors
+ block the creation of result, rather than just the return
+ value of the client callback.
+ (gcc::jit::context::add_error): Add varargs and provide
+ implementation, calling into...
+ (gcc::jit::context::add_error_va): New.
+ * internal-api.h (GNU_PRINTF): New.
+ (gcc::jit::context::add_error): Add varargs and GNU_PRINTF
+ attribute macro.
+ (gcc::jit::context::add_error_va): New.
+ (gcc::jit::context::errors_occurred): New.
+ (gcc::jit::context::m_error_count): New.
+ (gcc::jit::function::get_kind): New.
+ * libgccjit.c (JIT_BEGIN_STMT): New.
+ (JIT_END_STMT): New.
+ (RETURN_VAL_IF_FAIL): New.
+ (RETURN_NULL_IF_FAIL): New.
+ (RETURN_IF_FAIL): New.
+ (RETURN_IF_NOT_INITIAL_CTXT): New.
+ (RETURN_NULL_IF_NOT_INITIAL_CTXT): New.
+ (RETURN_NULL_IF_NOT_CALLBACK_CTXT): New.
+ (RETURN_IF_NOT_FUNC_DEFINITION): New.
+ (RETURN_NULL_IF_NOT_FUNC_DEFINITION): New.
+ (jit_error): New.
+ (gcc_jit_context_set_code_factory): Use new error-checking
+ macros.
+ (ASSERT_WITHIN_CALLBACK): Remove.
+ (ASSERT_NOT_WITHIN_CALLBACK): Remove.
+ (gcc_jit_context_new_location): Use new error-checking macros.
+ (gcc_jit_context_get_type): Likewise.
+ (gcc_jit_type_get_pointer): Likewise.
+ (gcc_jit_type_get_const): Likewise.
+ (gcc_jit_context_new_field): Likewise.
+ (gcc_jit_context_new_struct_type): Likewise.
+ (gcc_jit_context_new_param): Likewise.
+ (gcc_jit_param_as_lvalue): Likewise.
+ (gcc_jit_param_as_rvalue): Likewise.
+ (gcc_jit_context_new_function): Likewise.
+ (gcc_jit_function_new_forward_label): Likewise.
+ (gcc_jit_context_new_global): Likewise.
+ (gcc_jit_lvalue_as_rvalue): Likewise.
+ (gcc_jit_context_new_rvalue_from_int): Likewise.
+ (gcc_jit_context_zero): Likewise.
+ (gcc_jit_context_one): Likewise.
+ (gcc_jit_context_new_rvalue_from_double): Likewise.
+ (gcc_jit_context_new_rvalue_from_ptr): Likewise.
+ (gcc_jit_context_new_string_literal): Likewise.
+ (gcc_jit_context_new_binary_op): Likewise.
+ (gcc_jit_context_new_comparison): Likewise.
+ (gcc_jit_context_new_call): Likewise.
+ (gcc_jit_context_new_array_lookup): Likewise.
+ (gcc_jit_context_new_field_access): Likewise.
+ (gcc_jit_function_new_local): Likewise.
+ (gcc_jit_function_add_label): Likewise.
+ (gcc_jit_function_place_forward_label): Likewise.
+ (gcc_jit_function_add_eval): Likewise.
+ (gcc_jit_function_add_assignment): Likewise.
+ (gcc_jit_function_add_assignment_op): Likewise.
+ (gcc_jit_function_add_conditional): Likewise.
+ (gcc_jit_function_add_jump): Likewise.
+ (gcc_jit_function_add_return): Likewise.
+ (gcc_jit_function_new_loop): Likewise.
+ (gcc_jit_loop_end): Likewise.
+ (gcc_jit_context_set_str_option): Likewise.
+ (gcc_jit_context_set_int_option): Likewise.
+ (gcc_jit_context_set_bool_option): Likewise.
+ (gcc_jit_context_compile): Likewise.
+ (gcc_jit_result_get_code): Likewise.
+ (gcc_jit_result_release): Likewise.
+ * libgccjit.h (gcc_jit_function_new_forward_label): Clarify
+ behavior.
+ (gcc_jit_function_add_label): Likewise.
+
+2013-10-17 David Malcolm <dmalcolm@redhat.com>
+
+ * internal-api.c (gcc::jit::context::get_void_type): Remove.
+ (gcc::jit::context::get_char_type): Remove.
+ (gcc::jit::context::get_int_type): Remove.
+ (gcc::jit::context::get_float_type): Remove.
+ (gcc::jit::context::get_double_type): Remove.
+ (get_tree_node_for_type): New.
+ (gcc::jit::context::get_type): New.
+ (gcc::jit::context::new_rvalue_from_double): New.
+ (gcc::jit::context::new_rvalue_from_ptr): New.
+ * internal-api.h (gcc::jit::context::get_void_type): Remove.
+ (gcc::jit::context::get_char_type): Remove.
+ (gcc::jit::context::get_int_type): Remove.
+ (gcc::jit::context::get_float_type): Remove.
+ (gcc::jit::context::get_double_type): Remove.
+ (gcc::jit::context::get_type): New.
+ (gcc::jit::context::new_rvalue_from_double): New.
+ (gcc::jit::context::new_rvalue_from_ptr): New.
+ * libgccjit.c (gcc_jit_context_get_void_type): Remove.
+ (gcc_jit_context_get_char_type): Remove.
+ (gcc_jit_context_get_int_type): Remove.
+ (gcc_jit_context_get_float_type): Remove.
+ (gcc_jit_context_get_double_type): Remove.
+ (gcc_jit_context_get_type): New.
+ (gcc_jit_context_new_rvalue_from_double): New.
+ (gcc_jit_context_new_rvalue_from_ptr): New.
+ * libgccjit.h (gcc_jit_context_get_void_type): Remove.
+ (gcc_jit_context_get_char_type): Remove.
+ (gcc_jit_context_get_int_type): Remove.
+ (gcc_jit_context_get_float_type): Remove.
+ (gcc_jit_context_get_double_type): Remove.
+ (enum gcc_jit_types): New.
+ (gcc_jit_context_get_type): New.
+ (gcc_jit_context_new_rvalue_from_double): New.
+ (gcc_jit_context_new_rvalue_from_ptr): New.
+ * libgccjit.map (gcc_jit_context_get_void_type): Remove.
+ (gcc_jit_context_get_char_type): Remove.
+ (gcc_jit_context_get_int_type): Remove.
+ (gcc_jit_context_get_float_type): Remove.
+ (gcc_jit_context_get_double_type): Remove.
+ (enum gcc_jit_types): New.
+ (gcc_jit_context_get_type): New.
+ (gcc_jit_context_new_rvalue_from_double): New.
+ (gcc_jit_context_new_rvalue_from_ptr): New.
+ * TODO.rst ("access to more primitive types"): Remove
+ completed item.
+
+2013-10-17 David Malcolm <dmalcolm@redhat.com>
+
+ * libgccjit.h: Add and reword comments throughout.
+
+2013-10-17 David Malcolm <dmalcolm@redhat.com>
+
+ * TODO.rst: Update.
+
+2013-10-16 David Malcolm <dmalcolm@redhat.com>
+
+ * TODO.rst (gcc_jit_context_new_local): Remove completed item.
+ * internal-api.c (gcc::jit::context::new_local): Replace with...
+ (gcc::jit::function::new_local): ...this, and change return type
+ from (local*) to (lvalue*).
+ * internal-api.h (gcc::jit::local): Eliminate.
+ (gcc::jit::context::new_local): Replace with...
+ (gcc::jit::function::new_local): ...this, and change return type
+ from (local*) to (lvalue*).
+ * libgccjit.c (gcc_jit_local): Eliminate.
+ (gcc_jit_context_new_local): Replace with...
+ (gcc_jit_function_new_local): ...this, and change return type
+ from (gcc_jit_local*) to (gcc_jit_lvalue*).
+ (gcc_jit_local_as_lvalue): Remove.
+ (gcc_jit_local_as_rvalue): Remove.
+ * libgccjit.h (gcc_jit_local): Remove.
+ (gcc_jit_context_new_local): Replace with...
+ (gcc_jit_function_new_local): ...this, and change return type
+ from (gcc_jit_local*) to (gcc_jit_lvalue*).
+ (gcc_jit_local_as_lvalue): Remove.
+ (gcc_jit_local_as_rvalue): Remove.
+ * libgccjit.map (gcc_jit_context_new_local): Replace with...
+ (gcc_jit_function_new_local): ...this.
+ (gcc_jit_local_as_lvalue): Remove.
+ (gcc_jit_local_as_rvalue): Remove.
+
+2013-10-15 David Malcolm <dmalcolm@redhat.com>
+
+ * libgccjit.h (gcc_jit_location): Rewrite comment to reflect
+ that this part of the API is now implemented.
+ ("Functions for use within the code factory."): Add notes on
+ memory-management and lifetimes.
+ * notes.txt: Update diagram to show handle_locations.
+
+2013-10-15 David Malcolm <dmalcolm@redhat.com>
+
+ * TODO.rst: Update.
+
+2013-10-14 David Malcolm <dmalcolm@redhat.com>
+
+ * libgccjit.map: Alphabetize the exported symbols.
+
+2013-10-14 David Malcolm <dmalcolm@redhat.com>
+
+ * internal-api.c (gcc::jit::context::new_field): Implement
+ location support, by calling set_tree_location.
+ (gcc::jit::context::new_struct_type): Likewise.
+ (gcc::jit::context::new_param): Likewise.
+ (gcc::jit::context::new_function): Likewise.
+ (gcc::jit::context::new_global): Likewise.
+ (gcc::jit::context::new_local): Likewise.
+ (gcc::jit::context::new_binary_op): Likewise.
+ (gcc::jit::context::new_comparison): Likewise.
+ (gcc::jit::context::new_call): Likewise.
+ (gcc::jit::context::new_array_lookup): Likewise.
+ (gcc::jit::context::new_field_access): Likewise.
+ (gcc::jit::context::add_assignment): Likewise.
+ (gcc::jit::context::add_conditional): Likewise.
+ (gcc::jit::function::add_label): Likewise.
+ (gcc::jit::function::add_jump): Likewise.
+ (gcc::jit::function::add_return): Likewise.
+ (gcc::jit::function::place_forward_label): Likewise, adding
+ location parameter.
+ (gcc::jit::loop::loop): Add loc arg to place_forward_label.
+ (gcc::jit::loop::end): Likewise.
+ (gcc::jit::context::invoke_code_factory): Call handle_locations
+ after the client callback is done, before any GC can run.
+ (line_comparator): New.
+ (location_comparator): New.
+ (gcc::jit::context::handle_locations): New.
+ (gcc::jit::context::new_location): New.
+ (gcc::jit::context::set_tree_location): New.
+ (gcc::jit::context::get_source_file): New.
+ (gcc::jit::source_file::source_file): New.
+ (gcc::jit::source_file::get_source_line): New.
+ (gcc::jit::source_line::source_line): New.
+ (gcc::jit::source_line::get_location): New.
+ (gcc::jit::location::location): New.
+ * internal-api.h (gcc::jit::context::new_location): New.
+ (gcc::jit::context::set_tree_location): New.
+ (gcc::jit::context::handle_locations): New.
+ (gcc::jit::context::get_source_file): New.
+ (gcc::jit::context::m_source_files): New field.
+ (gcc::jit::context::m_cached_locations: New field.
+ (gcc::jit::function::place_forward_label): Add location
+ parameter.
+ (gcc::jit::function::set_tree_location): New.
+ (gcc::jit::source_file): New class.
+ (gcc::jit::source_line): New class.
+ (gcc::jit::location): New class.
+ * libgccjit.c (gcc_jit_context_new_location): New.
+ (gcc_jit_function_place_forward_label): Add location parameter,
+ changing public API.
+ * libgccjit.h (gcc_jit_context_new_location): New.
+ (gcc_jit_function_place_forward_label): Add location parameter,
+ changing public API.
+ * libgccjit.map (gcc_jit_context_new_location): New.
+ (main): Remove obsolete export.
+ (called_function): Likewise.
+
+2013-10-11 David Malcolm <dmalcolm@redhat.com>
+
+ * internal-api.c: Update includes to reflect move of decl of
+ dump_function_to_file from tree-dump.h to tree-flow.h in
+ r203320.
+
+2013-10-10 David Malcolm <dmalcolm@redhat.com>
+
+ * libgccjit.h (GCC_JIT_BOOL_OPTION_DUMP_SUMMARY): New.
+ * internal-api.c ((gcc::jit::context::compile): Implement
+ GCC_JIT_BOOL_OPTION_DUMP_SUMMARY.
+
+2013-10-10 David Malcolm <dmalcolm@redhat.com>
+
+ * libgccjit.h (GCC_JIT_BOOL_OPTION_SELFCHECK_GC): Improve
+ documentation.
+ (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE): Likewise.
+
+2013-10-10 David Malcolm <dmalcolm@redhat.com>
+
+ * libgccjit.h: Clarify the separation of the API into "outside
+ the callback" and "within the callback" entrypoints, moving the
+ latter to the bottom of the header.
+
+2013-10-10 David Malcolm <dmalcolm@redhat.com>
+
+ * libgccjit.h: Add comments throughout.
+
+2013-10-09 David Malcolm <dmalcolm@redhat.com>
+
+ * internal-api.c (gcc::jit::context::~context): Fix indentation;
+ clean up memory allocations when using
+ GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES.
+
+2013-10-09 David Malcolm <dmalcolm@redhat.com>
+
+ * libgccjit.h (enum gcc_jit_bool_option): Add
+ GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING.
+ * internal-api.c (gcc::jit::context::compile): Implement
+ GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING.
+
+2013-10-09 David Malcolm <dmalcolm@redhat.com>
+
+ * libgccjit.h (enum gcc_jit_bool_option): Add
+ GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES.
+ * internal-api.c (gcc::jit::context::~context): Implement
+ GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES.
+
+2013-10-08 David Malcolm <dmalcolm@redhat.com>
+
+ * internal-api.c (gcc::jit::context::compile): Use mkdtemp to
+ create a temporary directory and create the .s and .so files
+ there, rather than writing to "fake.s" and then reading it to
+ make "fake.so", then using it, fixing various possible race
+ attacks by processes that can write to the process' current
+ working directory.
+ (gcc::jit::context::~context): Clean up tempfiles and path
+ buffers.
+ * internal-api.h (gcc::jit::context): Add fields
+ m_path_template, m_path_tempdir, m_path_c_file, m_path_s_file,
+ m_path_so_file.
+
+2013-10-08 David Malcolm <dmalcolm@redhat.com>
+
+ * internal-api.c (gcc::jit::context::new_function): Fix leak of
+ arg_types.
+
+2013-10-08 David Malcolm <dmalcolm@redhat.com>
+
+ * internal-api.c (gcc::jit::context::~context): New.
+ * internal-api.h (gcc::jit::context::~context): New.
+
+2013-10-07 David Malcolm <dmalcolm@redhat.com>
+
+ * internal-api.c (gcc::jit::context::compile): Implement
+ GCC_JIT_BOOL_OPTION_SELFCHECK_GC.
+
+ * libgccjit.h (enum gcc_jit_bool_option): Add
+ GCC_JIT_BOOL_OPTION_SELFCHECK_GC.
+
+2013-10-07 David Malcolm <dmalcolm@redhat.com>
+
+ * Make-lang.in: Rename JIT_OBJS to jit_OBJS. Delete manual
+ dependencies.
+
+2013-10-04 David Malcolm <dmalcolm@redhat.com>
+
+ * internal-api.c (gcc::jit::context::new_global): New.
+ * internal-api.h (gcc::jit::context::new_global): New.
+ * libgccjit.c (gcc_jit_context_new_global) New.
+ * libgccjit.h (gcc_jit_context_new_global) New.
+ * libgccjit.map: Add gcc_jit_context_new_global.
+
+2013-10-03 David Malcolm <dmalcolm@redhat.com>
+
+ * libgccjit.c (gcc_jit_param_as_lvalue): New.
+ * libgccjit.h (gcc_jit_param_as_lvalue): New.
+ * libgccjit.map: Add gcc_jit_param_as_lvalue.
+
+2013-10-03 David Malcolm <dmalcolm@redhat.com>
+
+ * internal-api.c (gcc::jit::function::postprocess): Dump gimple
+ using dump_function_to_file rather than debug_gimple_seq so that
+ we also get the declaration.
+
+2013-10-03 David Malcolm <dmalcolm@redhat.com>
+
+ * Make-lang.in: New.
+ * TODO.rst: New.
+ * config-lang.in: New.
+ * dummy-frontend.c: New.
+ * internal-api.c: New.
+ * internal-api.h: New.
+ * libgccjit.c: New.
+ * libgccjit.h: New.
+ * libgccjit.map: New.
+ * notes.txt: New.
+\f
+Copyright (C) 2013-2014 Free Software Foundation, Inc.
+
+Copying and distribution of this file, with or without modification,
+are permitted in any medium without royalty provided the copyright
+notice and this notice are preserved.
--- /dev/null
+# 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
--- /dev/null
+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
--- /dev/null
+# 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"
--- /dev/null
+# 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."
--- /dev/null
+# Makefile for Sphinx Texinfo output
+
+infodir ?= /usr/share/info
+
+MAKEINFO = makeinfo --no-split
+MAKEINFO_html = makeinfo --no-split --html
+MAKEINFO_plaintext = makeinfo --no-split --plaintext
+TEXI2PDF = texi2pdf --batch --expand
+INSTALL_INFO = install-info
+
+ALLDOCS = $(basename $(wildcard *.texi))
+
+all: info
+info: $(addsuffix .info,$(ALLDOCS))
+plaintext: $(addsuffix .txt,$(ALLDOCS))
+html: $(addsuffix .html,$(ALLDOCS))
+pdf: $(addsuffix .pdf,$(ALLDOCS))
+
+install-info: info
+ for f in *.info; do \
+ cp -t $(infodir) "$$f" && \
+ $(INSTALL_INFO) --info-dir=$(infodir) "$$f" ; \
+ done
+
+uninstall-info: info
+ for f in *.info; do \
+ rm -f "$(infodir)/$$f" ; \
+ $(INSTALL_INFO) --delete --info-dir=$(infodir) "$$f" ; \
+ done
+
+%.info: %.texi
+ $(MAKEINFO) -o '$@' '$<'
+
+%.txt: %.texi
+ $(MAKEINFO_plaintext) -o '$@' '$<'
+
+%.html: %.texi
+ $(MAKEINFO_html) -o '$@' '$<'
+
+%.pdf: %.texi
+ -$(TEXI2PDF) '$<'
+ -$(TEXI2PDF) '$<'
+ -$(TEXI2PDF) '$<'
+
+clean:
+ -rm -f *.info *.pdf *.txt *.html
+ -rm -f *.log *.ind *.aux *.toc *.syn *.idx *.out *.ilg *.pla *.ky *.pg
+ -rm -f *.vr *.tp *.fn *.fns *.def *.defs *.cp *.cps *.ge *.ges *.mo
+
+.PHONY: all info plaintext html pdf install-info uninstall-info clean
--- /dev/null
+\input texinfo @c -*-texinfo-*-
+@c %**start of header
+@setfilename libgccjit.info
+@documentencoding UTF-8
+@ifinfo
+@*Generated by Sphinx 1.1.3.@*
+@end ifinfo
+@settitle libgccjit Documentation
+@defindex ge
+@paragraphindent 2
+@exampleindent 4
+@afourlatex
+@dircategory Miscellaneous
+@direntry
+* libgccjit: (libgccjit.info). One line description of project.
+@end direntry
+
+@c %**end of header
+
+@copying
+@quotation
+libgccjit 5.0.0 (experimental 20141110), November 10, 2014
+
+David Malcolm
+
+Copyright @copyright{} 2014, Free Software Foundation
+@end quotation
+
+@end copying
+
+@titlepage
+@title libgccjit Documentation
+@insertcopying
+@end titlepage
+@contents
+
+@c %** start of user preamble
+
+@c %** end of user preamble
+
+@ifnottex
+@node Top
+@top libgccjit Documentation
+@insertcopying
+@end ifnottex
+
+@c %**start of body
+@anchor{index doc}@anchor{0}
+@c Copyright (C) 2014 Free Software Foundation, Inc.
+@c Originally contributed by David Malcolm <dmalcolm@redhat.com>
+@c
+@c This is free software: you can redistribute it and/or modify it
+@c under the terms of the GNU General Public License as published by
+@c the Free Software Foundation, either version 3 of the License, or
+@c (at your option) any later version.
+@c
+@c This program is distributed in the hope that it will be useful, but
+@c WITHOUT ANY WARRANTY; without even the implied warranty of
+@c MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+@c General Public License for more details.
+@c
+@c You should have received a copy of the GNU General Public License
+@c along with this program. If not, see
+@c <http://www.gnu.org/licenses/>.
+
+Contents:
+
+@c Copyright (C) 2014 Free Software Foundation, Inc.
+@c Originally contributed by David Malcolm <dmalcolm@redhat.com>
+@c
+@c This is free software: you can redistribute it and/or modify it
+@c under the terms of the GNU General Public License as published by
+@c the Free Software Foundation, either version 3 of the License, or
+@c (at your option) any later version.
+@c
+@c This program is distributed in the hope that it will be useful, but
+@c WITHOUT ANY WARRANTY; without even the implied warranty of
+@c MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+@c General Public License for more details.
+@c
+@c You should have received a copy of the GNU General Public License
+@c along with this program. If not, see
+@c <http://www.gnu.org/licenses/>.
+
+@menu
+* Tutorial::
+* Topic Reference::
+* Internals::
+* Indices and tables::
+* Index::
+
+@detailmenu
+ --- The Detailed Node Listing ---
+
+Tutorial
+
+* Tutorial part 1; "Hello world": Tutorial part 1 "Hello world".
+* Tutorial part 2; Creating a trivial machine code function: Tutorial part 2 Creating a trivial machine code function.
+* Tutorial part 3; Loops and variables: Tutorial part 3 Loops and variables.
+* Tutorial part 4; Adding JIT-compilation to a toy interpreter: Tutorial part 4 Adding JIT-compilation to a toy interpreter.
+
+Tutorial part 2: Creating a trivial machine code function
+
+* Options::
+* Full example::
+
+Tutorial part 3: Loops and variables
+
+* Expressions; lvalues and rvalues: Expressions lvalues and rvalues.
+* Control flow::
+* Visualizing the control flow graph::
+* Full example: Full example<2>.
+
+Tutorial part 4: Adding JIT-compilation to a toy interpreter
+
+* Our toy interpreter::
+* Compiling to machine code::
+* Setting things up::
+* Populating the function::
+* Verifying the control flow graph::
+* Compiling the context::
+* Single-stepping through the generated code::
+* Examining the generated code::
+* Putting it all together::
+* Behind the curtain; How does our code get optimized?: Behind the curtain How does our code get optimized?.
+
+Behind the curtain: How does our code get optimized?
+
+* Optimizing away stack manipulation::
+* Elimination of tail recursion::
+
+Topic Reference
+
+* Compilation contexts::
+* Objects::
+* Types::
+* Expressions::
+* Creating and using functions::
+* Source Locations::
+* Compilation results::
+
+Compilation contexts
+
+* Lifetime-management::
+* Thread-safety::
+* Error-handling::
+* Debugging::
+* Options: Options<2>.
+
+Options
+
+* String Options::
+* Boolean options::
+* Integer options::
+
+Types
+
+* Standard types::
+* Pointers@comma{} const@comma{} and volatile: Pointers const and volatile.
+* Structures and unions::
+
+Expressions
+
+* Rvalues::
+* Lvalues::
+* Working with pointers@comma{} structs and unions: Working with pointers structs and unions.
+
+Rvalues
+
+* Simple expressions::
+* Unary Operations::
+* Binary Operations::
+* Comparisons::
+* Function calls::
+* Type-coercion::
+
+Lvalues
+
+* Global variables::
+
+Creating and using functions
+
+* Params::
+* Functions::
+* Blocks::
+* Statements::
+
+Source Locations
+
+* Faking it::
+
+Internals
+
+* Working on the JIT library::
+* Running the test suite::
+* Environment variables::
+* Overview of code structure::
+
+@end detailmenu
+@end menu
+
+
+@node Tutorial,Topic Reference,Top,Top
+@anchor{intro/index libgccjit}@anchor{1}@anchor{intro/index doc}@anchor{2}@anchor{intro/index tutorial}@anchor{3}
+@chapter Tutorial
+
+
+@c Copyright (C) 2014 Free Software Foundation, Inc.
+@c Originally contributed by David Malcolm <dmalcolm@redhat.com>
+@c
+@c This is free software: you can redistribute it and/or modify it
+@c under the terms of the GNU General Public License as published by
+@c the Free Software Foundation, either version 3 of the License, or
+@c (at your option) any later version.
+@c
+@c This program is distributed in the hope that it will be useful, but
+@c WITHOUT ANY WARRANTY; without even the implied warranty of
+@c MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+@c General Public License for more details.
+@c
+@c You should have received a copy of the GNU General Public License
+@c along with this program. If not, see
+@c <http://www.gnu.org/licenses/>.
+
+@menu
+* Tutorial part 1; "Hello world": Tutorial part 1 "Hello world".
+* Tutorial part 2; Creating a trivial machine code function: Tutorial part 2 Creating a trivial machine code function.
+* Tutorial part 3; Loops and variables: Tutorial part 3 Loops and variables.
+* Tutorial part 4; Adding JIT-compilation to a toy interpreter: Tutorial part 4 Adding JIT-compilation to a toy interpreter.
+
+@end menu
+
+@node Tutorial part 1 "Hello world",Tutorial part 2 Creating a trivial machine code function,,Tutorial
+@anchor{intro/tutorial01 doc}@anchor{4}@anchor{intro/tutorial01 tutorial-part-1-hello-world}@anchor{5}
+@section Tutorial part 1: "Hello world"
+
+
+Before we look at the details of the API, let's look at building and
+running programs that use the library.
+
+Here's a toy "hello world" program that uses the library to synthesize
+a call to @cite{printf} and uses it to write a message to stdout.
+
+Don't worry about the content of the program for now; we'll cover
+the details in later parts of this tutorial.
+
+@quotation
+
+@example
+/* Smoketest example for libgccjit.so
+ Copyright (C) 2014 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include <libgccjit.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+
+static void
+create_code (gcc_jit_context *ctxt)
+@{
+ /* Let's try to inject the equivalent of:
+ void
+ greet (const char *name)
+ @{
+ printf ("hello %s\n", name);
+ @}
+ */
+ gcc_jit_type *void_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+ gcc_jit_type *const_char_ptr_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_CONST_CHAR_PTR);
+ gcc_jit_param *param_name =
+ gcc_jit_context_new_param (ctxt, NULL, const_char_ptr_type, "name");
+ gcc_jit_function *func =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ void_type,
+ "greet",
+ 1, ¶m_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, ¶m_format,
+ 1);
+ gcc_jit_rvalue *args[2];
+ args[0] = gcc_jit_context_new_string_literal (ctxt, "hello %s\n");
+ args[1] = gcc_jit_param_as_rvalue (param_name);
+
+ gcc_jit_block *block = gcc_jit_function_new_block (func, NULL);
+
+ gcc_jit_block_add_eval (
+ block, NULL,
+ gcc_jit_context_new_call (ctxt,
+ NULL,
+ printf_func,
+ 2, args));
+ gcc_jit_block_end_with_void_return (block, NULL);
+@}
+
+int
+main (int argc, char **argv)
+@{
+ gcc_jit_context *ctxt;
+ gcc_jit_result *result;
+
+ /* Get a "context" object for working with the library. */
+ ctxt = gcc_jit_context_acquire ();
+ if (!ctxt)
+ @{
+ fprintf (stderr, "NULL ctxt");
+ exit (1);
+ @}
+
+ /* Set some options on the context.
+ Let's see the code being generated, in assembler form. */
+ gcc_jit_context_set_bool_option (
+ ctxt,
+ GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE,
+ 0);
+
+ /* Populate the context. */
+ create_code (ctxt);
+
+ /* Compile the code. */
+ result = gcc_jit_context_compile (ctxt);
+ if (!result)
+ @{
+ fprintf (stderr, "NULL result");
+ exit (1);
+ @}
+
+ /* Extract the generated code from "result". */
+ typedef void (*fn_type) (const char *);
+ fn_type greet =
+ (fn_type)gcc_jit_result_get_code (result, "greet");
+ if (!greet)
+ @{
+ fprintf (stderr, "NULL greet");
+ exit (1);
+ @}
+
+ /* Now call the generated function: */
+ greet ("world");
+ fflush (stdout);
+
+ gcc_jit_context_release (ctxt);
+ gcc_jit_result_release (result);
+ return 0;
+@}
+
+@end example
+
+@noindent
+@end quotation
+
+Copy the above to @cite{tut01-hello-world.c}.
+
+Assuming you have the jit library installed, build the test program
+using:
+
+@example
+$ gcc \
+ tut01-hello-world.c \
+ -o tut01-hello-world \
+ -lgccjit
+@end example
+
+@noindent
+
+You should then be able to run the built program:
+
+@example
+$ ./tut01-hello-world
+hello world
+@end example
+
+@noindent
+
+@c Copyright (C) 2014 Free Software Foundation, Inc.
+@c Originally contributed by David Malcolm <dmalcolm@redhat.com>
+@c
+@c This is free software: you can redistribute it and/or modify it
+@c under the terms of the GNU General Public License as published by
+@c the Free Software Foundation, either version 3 of the License, or
+@c (at your option) any later version.
+@c
+@c This program is distributed in the hope that it will be useful, but
+@c WITHOUT ANY WARRANTY; without even the implied warranty of
+@c MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+@c General Public License for more details.
+@c
+@c You should have received a copy of the GNU General Public License
+@c along with this program. If not, see
+@c <http://www.gnu.org/licenses/>.
+
+@node Tutorial part 2 Creating a trivial machine code function,Tutorial part 3 Loops and variables,Tutorial part 1 "Hello world",Tutorial
+@anchor{intro/tutorial02 doc}@anchor{6}@anchor{intro/tutorial02 tutorial-part-2-creating-a-trivial-machine-code-function}@anchor{7}
+@section Tutorial part 2: Creating a trivial machine code function
+
+
+Consider this C function:
+
+@example
+int square (int i)
+@{
+ return i * i;
+@}
+@end example
+
+@noindent
+
+How can we construct this at run-time using libgccjit?
+
+First we need to include the relevant header:
+
+@example
+#include <libgccjit.h>
+@end example
+
+@noindent
+
+All state associated with compilation is associated with a
+@pxref{8,,gcc_jit_context *}.
+
+Create one using @pxref{9,,gcc_jit_context_acquire()}:
+
+@example
+gcc_jit_context *ctxt;
+ctxt = gcc_jit_context_acquire ();
+@end example
+
+@noindent
+
+The JIT library has a system of types. It is statically-typed: every
+expression is of a specific type, fixed at compile-time. In our example,
+all of the expressions are of the C @cite{int} type, so let's obtain this from
+the context, as a @pxref{a,,gcc_jit_type *}, using
+@pxref{b,,gcc_jit_context_get_type()}:
+
+@example
+gcc_jit_type *int_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+@end example
+
+@noindent
+
+@pxref{a,,gcc_jit_type *} is an example of a "contextual" object: every
+entity in the API is associated with a @pxref{8,,gcc_jit_context *}.
+
+Memory management is easy: all such "contextual" objects are automatically
+cleaned up for you when the context is released, using
+@pxref{c,,gcc_jit_context_release()}:
+
+@example
+gcc_jit_context_release (ctxt);
+@end example
+
+@noindent
+
+so you don't need to manually track and cleanup all objects, just the
+contexts.
+
+Although the API is C-based, there is a form of class hierarchy, which
+looks like this:
+
+@example
++- gcc_jit_object
+ +- gcc_jit_location
+ +- gcc_jit_type
+ +- gcc_jit_struct
+ +- gcc_jit_field
+ +- gcc_jit_function
+ +- gcc_jit_block
+ +- gcc_jit_rvalue
+ +- gcc_jit_lvalue
+ +- gcc_jit_param
+@end example
+
+@noindent
+
+There are casting methods for upcasting from subclasses to parent classes.
+For example, @pxref{d,,gcc_jit_type_as_object()}:
+
+@example
+gcc_jit_object *obj = gcc_jit_type_as_object (int_type);
+@end example
+
+@noindent
+
+One thing you can do with a @pxref{e,,gcc_jit_object *} is
+to ask it for a human-readable description, using
+@pxref{f,,gcc_jit_object_get_debug_string()}:
+
+@example
+printf ("obj: %s\n", gcc_jit_object_get_debug_string (obj));
+@end example
+
+@noindent
+
+giving this text on stdout:
+
+@example
+obj: int
+@end example
+
+@noindent
+
+This is invaluable when debugging.
+
+Let's create the function. To do so, we first need to construct
+its single parameter, specifying its type and giving it a name,
+using @pxref{10,,gcc_jit_context_new_param()}:
+
+@example
+gcc_jit_param *param_i =
+ gcc_jit_context_new_param (ctxt, NULL, int_type, "i");
+@end example
+
+@noindent
+
+Now we can create the function, using
+@pxref{11,,gcc_jit_context_new_function()}:
+
+@example
+gcc_jit_function *func =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ int_type,
+ "square",
+ 1, ¶m_i,
+ 0);
+@end example
+
+@noindent
+
+To define the code within the function, we must create basic blocks
+containing statements.
+
+Every basic block contains a list of statements, eventually terminated
+by a statement that either returns, or jumps to another basic block.
+
+Our function has no control-flow, so we just need one basic block:
+
+@example
+gcc_jit_block *block = gcc_jit_function_new_block (func, NULL);
+@end example
+
+@noindent
+
+Our basic block is relatively simple: it immediately terminates by
+returning the value of an expression.
+
+We can build the expression using @pxref{12,,gcc_jit_context_new_binary_op()}:
+
+@example
+gcc_jit_rvalue *expr =
+ gcc_jit_context_new_binary_op (
+ ctxt, NULL,
+ GCC_JIT_BINARY_OP_MULT, int_type,
+ gcc_jit_param_as_rvalue (param_i),
+ gcc_jit_param_as_rvalue (param_i));
+@end example
+
+@noindent
+
+A @pxref{13,,gcc_jit_rvalue *} is another example of a
+@pxref{e,,gcc_jit_object *} subclass. We can upcast it using
+@pxref{14,,gcc_jit_rvalue_as_object()} and as before print it with
+@pxref{f,,gcc_jit_object_get_debug_string()}.
+
+@example
+printf ("expr: %s\n",
+ gcc_jit_object_get_debug_string (
+ gcc_jit_rvalue_as_object (expr)));
+@end example
+
+@noindent
+
+giving this output:
+
+@example
+expr: i * i
+@end example
+
+@noindent
+
+Creating the expression in itself doesn't do anything; we have to add
+this expression to a statement within the block. In this case, we use it
+to build a return statement, which terminates the basic block:
+
+@example
+gcc_jit_block_end_with_return (block, NULL, expr);
+@end example
+
+@noindent
+
+OK, we've populated the context. We can now compile it using
+@pxref{15,,gcc_jit_context_compile()}:
+
+@example
+gcc_jit_result *result;
+result = gcc_jit_context_compile (ctxt);
+@end example
+
+@noindent
+
+and get a @pxref{16,,gcc_jit_result *}.
+
+We can now use @pxref{17,,gcc_jit_result_get_code()} to look up a specific
+machine code routine within the result, in this case, the function we
+created above.
+
+@example
+void *fn_ptr = gcc_jit_result_get_code (result, "square");
+if (!fn_ptr)
+ @{
+ fprintf (stderr, "NULL fn_ptr");
+ goto error;
+ @}
+@end example
+
+@noindent
+
+We can now cast the pointer to an appropriate function pointer type, and
+then call it:
+
+@example
+typedef int (*fn_type) (int);
+fn_type square = (fn_type)fn_ptr;
+printf ("result: %d", square (5));
+@end example
+
+@noindent
+
+@example
+result: 25
+@end example
+
+@noindent
+
+@menu
+* Options::
+* Full example::
+
+@end menu
+
+@node Options,Full example,,Tutorial part 2 Creating a trivial machine code function
+@anchor{intro/tutorial02 options}@anchor{18}
+@subsection Options
+
+
+To get more information on what's going on, you can set debugging flags
+on the context using @pxref{19,,gcc_jit_context_set_bool_option()}.
+
+@c (I'm deliberately not mentioning
+@c :c:macro:`GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE` here since I think
+@c it's probably more of use to implementors than to users)
+
+Setting @pxref{1a,,GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE} will dump a
+C-like representation to stderr when you compile (GCC's "GIMPLE"
+representation):
+
+@example
+gcc_jit_context_set_bool_option (
+ ctxt,
+ GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE,
+ 1);
+result = gcc_jit_context_compile (ctxt);
+@end example
+
+@noindent
+
+@example
+square (signed int i)
+@{
+ signed int D.260;
+
+ entry:
+ D.260 = i * i;
+ return D.260;
+@}
+@end example
+
+@noindent
+
+We can see the generated machine code in assembler form (on stderr) by
+setting @pxref{1b,,GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE} on the context
+before compiling:
+
+@example
+gcc_jit_context_set_bool_option (
+ ctxt,
+ GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE,
+ 1);
+result = gcc_jit_context_compile (ctxt);
+@end example
+
+@noindent
+
+@example
+ .file "fake.c"
+ .text
+ .globl square
+ .type square, @@function
+square:
+.LFB6:
+ .cfi_startproc
+ pushq %rbp
+ .cfi_def_cfa_offset 16
+ .cfi_offset 6, -16
+ movq %rsp, %rbp
+ .cfi_def_cfa_register 6
+ movl %edi, -4(%rbp)
+.L14:
+ movl -4(%rbp), %eax
+ imull -4(%rbp), %eax
+ popq %rbp
+ .cfi_def_cfa 7, 8
+ ret
+ .cfi_endproc
+.LFE6:
+ .size square, .-square
+ .ident "GCC: (GNU) 4.9.0 20131023 (Red Hat 0.2-0.5.1920c315ff984892399893b380305ab36e07b455.fc20)"
+ .section .note.GNU-stack,"",@@progbits
+@end example
+
+@noindent
+
+By default, no optimizations are performed, the equivalent of GCC's
+@cite{-O0} option. We can turn things up to e.g. @cite{-O3} by calling
+@pxref{1c,,gcc_jit_context_set_int_option()} with
+@pxref{1d,,GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL}:
+
+@example
+gcc_jit_context_set_int_option (
+ ctxt,
+ GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL,
+ 3);
+@end example
+
+@noindent
+
+@example
+ .file "fake.c"
+ .text
+ .p2align 4,,15
+ .globl square
+ .type square, @@function
+square:
+.LFB7:
+ .cfi_startproc
+.L16:
+ movl %edi, %eax
+ imull %edi, %eax
+ ret
+ .cfi_endproc
+.LFE7:
+ .size square, .-square
+ .ident "GCC: (GNU) 4.9.0 20131023 (Red Hat 0.2-0.5.1920c315ff984892399893b380305ab36e07b455.fc20)"
+ .section .note.GNU-stack,"",@@progbits
+@end example
+
+@noindent
+
+Naturally this has only a small effect on such a trivial function.
+
+@node Full example,,Options,Tutorial part 2 Creating a trivial machine code function
+@anchor{intro/tutorial02 full-example}@anchor{1e}
+@subsection Full example
+
+
+Here's what the above looks like as a complete program:
+
+@quotation
+
+@example
+/* Usage example for libgccjit.so
+ Copyright (C) 2014 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include <libgccjit.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+
+void
+create_code (gcc_jit_context *ctxt)
+@{
+ /* Let's try to inject the equivalent of:
+
+ int square (int i)
+ @{
+ return i * i;
+ @}
+ */
+ gcc_jit_type *int_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+ gcc_jit_param *param_i =
+ gcc_jit_context_new_param (ctxt, NULL, int_type, "i");
+ gcc_jit_function *func =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ int_type,
+ "square",
+ 1, ¶m_i,
+ 0);
+
+ gcc_jit_block *block = gcc_jit_function_new_block (func, NULL);
+
+ gcc_jit_rvalue *expr =
+ gcc_jit_context_new_binary_op (
+ ctxt, NULL,
+ GCC_JIT_BINARY_OP_MULT, int_type,
+ gcc_jit_param_as_rvalue (param_i),
+ gcc_jit_param_as_rvalue (param_i));
+
+ gcc_jit_block_end_with_return (block, NULL, expr);
+@}
+
+int
+main (int argc, char **argv)
+@{
+ gcc_jit_context *ctxt = NULL;
+ gcc_jit_result *result = NULL;
+
+ /* Get a "context" object for working with the library. */
+ ctxt = gcc_jit_context_acquire ();
+ if (!ctxt)
+ @{
+ fprintf (stderr, "NULL ctxt");
+ goto error;
+ @}
+
+ /* Set some options on the context.
+ Let's see the code being generated, in assembler form. */
+ gcc_jit_context_set_bool_option (
+ ctxt,
+ GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE,
+ 0);
+
+ /* Populate the context. */
+ create_code (ctxt);
+
+ /* Compile the code. */
+ result = gcc_jit_context_compile (ctxt);
+ if (!result)
+ @{
+ fprintf (stderr, "NULL result");
+ goto error;
+ @}
+
+ /* Extract the generated code from "result". */
+ void *fn_ptr = gcc_jit_result_get_code (result, "square");
+ if (!fn_ptr)
+ @{
+ fprintf (stderr, "NULL fn_ptr");
+ goto error;
+ @}
+
+ typedef int (*fn_type) (int);
+ fn_type square = (fn_type)fn_ptr;
+ printf ("result: %d", square (5));
+
+ error:
+ gcc_jit_context_release (ctxt);
+ gcc_jit_result_release (result);
+ return 0;
+@}
+
+@end example
+
+@noindent
+@end quotation
+
+Building and running it:
+
+@example
+$ gcc \
+ tut02-square.c \
+ -o tut02-square \
+ -lgccjit
+
+# Run the built program:
+$ ./tut02-square
+result: 25
+@end example
+
+@noindent
+
+@c Copyright (C) 2014 Free Software Foundation, Inc.
+@c Originally contributed by David Malcolm <dmalcolm@redhat.com>
+@c
+@c This is free software: you can redistribute it and/or modify it
+@c under the terms of the GNU General Public License as published by
+@c the Free Software Foundation, either version 3 of the License, or
+@c (at your option) any later version.
+@c
+@c This program is distributed in the hope that it will be useful, but
+@c WITHOUT ANY WARRANTY; without even the implied warranty of
+@c MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+@c General Public License for more details.
+@c
+@c You should have received a copy of the GNU General Public License
+@c along with this program. If not, see
+@c <http://www.gnu.org/licenses/>.
+
+@node Tutorial part 3 Loops and variables,Tutorial part 4 Adding JIT-compilation to a toy interpreter,Tutorial part 2 Creating a trivial machine code function,Tutorial
+@anchor{intro/tutorial03 tutorial-part-3-loops-and-variables}@anchor{1f}@anchor{intro/tutorial03 doc}@anchor{20}
+@section Tutorial part 3: Loops and variables
+
+
+Consider this C function:
+
+@quotation
+
+@example
+int loop_test (int n)
+@{
+ int sum = 0;
+ for (int i = 0; i < n; i++)
+ sum += i * i;
+ return sum;
+@}
+@end example
+
+@noindent
+@end quotation
+
+This example demonstrates some more features of libgccjit, with local
+variables and a loop.
+
+To break this down into libgccjit terms, it's usually easier to reword
+the @cite{for} loop as a @cite{while} loop, giving:
+
+@quotation
+
+@example
+int loop_test (int n)
+@{
+ int sum = 0;
+ int i = 0;
+ while (i < n)
+ @{
+ sum += i * i;
+ i++;
+ @}
+ return sum;
+@}
+@end example
+
+@noindent
+@end quotation
+
+Here's what the final control flow graph will look like:
+
+@quotation
+
+
+@float Figure
+
+@image{sum-of-squares,,,image of a control flow graph,png}
+
+@end float
+
+@end quotation
+
+As before, we include the libgccjit header and make a
+@pxref{8,,gcc_jit_context *}.
+
+@example
+#include <libgccjit.h>
+
+void test (void)
+@{
+ gcc_jit_context *ctxt;
+ ctxt = gcc_jit_context_acquire ();
+@end example
+
+@noindent
+
+The function works with the C @cite{int} type:
+
+@example
+gcc_jit_type *the_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+gcc_jit_type *return_type = the_type;
+@end example
+
+@noindent
+
+though we could equally well make it work on, say, @cite{double}:
+
+@example
+gcc_jit_type *the_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_DOUBLE);
+@end example
+
+@noindent
+
+Let's build the function:
+
+@example
+gcc_jit_param *n =
+ gcc_jit_context_new_param (ctxt, NULL, the_type, "n");
+gcc_jit_param *params[1] = @{n@};
+gcc_jit_function *func =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ return_type,
+ "loop_test",
+ 1, params, 0);
+@end example
+
+@noindent
+
+@menu
+* Expressions; lvalues and rvalues: Expressions lvalues and rvalues.
+* Control flow::
+* Visualizing the control flow graph::
+* Full example: Full example<2>.
+
+@end menu
+
+@node Expressions lvalues and rvalues,Control flow,,Tutorial part 3 Loops and variables
+@anchor{intro/tutorial03 expressions-lvalues-and-rvalues}@anchor{21}
+@subsection Expressions: lvalues and rvalues
+
+
+The base class of expression is the @pxref{13,,gcc_jit_rvalue *},
+representing an expression that can be on the @emph{right}-hand side of
+an assignment: a value that can be computed somehow, and assigned
+@emph{to} a storage area (such as a variable). It has a specific
+@pxref{a,,gcc_jit_type *}.
+
+Anothe important class is @pxref{22,,gcc_jit_lvalue *}.
+A @pxref{22,,gcc_jit_lvalue *}. is something that can of the @emph{left}-hand
+side of an assignment: a storage area (such as a variable).
+
+In other words, every assignment can be thought of as:
+
+@example
+LVALUE = RVALUE;
+@end example
+
+@noindent
+
+Note that @pxref{22,,gcc_jit_lvalue *} is a subclass of
+@pxref{13,,gcc_jit_rvalue *}, where in an assignment of the form:
+
+@example
+LVALUE_A = LVALUE_B;
+@end example
+
+@noindent
+
+the @cite{LVALUE_B} implies reading the current value of that storage
+area, assigning it into the @cite{LVALUE_A}.
+
+So far the only expressions we've seen are @cite{i * i}:
+
+@example
+gcc_jit_rvalue *expr =
+ gcc_jit_context_new_binary_op (
+ ctxt, NULL,
+ GCC_JIT_BINARY_OP_MULT, int_type,
+ gcc_jit_param_as_rvalue (param_i),
+ gcc_jit_param_as_rvalue (param_i));
+@end example
+
+@noindent
+
+which is a @pxref{13,,gcc_jit_rvalue *}, and the various function
+parameters: @cite{param_i} and @cite{param_n}, instances of
+@pxref{23,,gcc_jit_param *}, which is a subclass of
+@pxref{22,,gcc_jit_lvalue *} (and, in turn, of @pxref{13,,gcc_jit_rvalue *}):
+we can both read from and write to function parameters within the
+body of a function.
+
+Our new example has a couple of local variables. We create them by
+calling @pxref{24,,gcc_jit_function_new_local()}, supplying a type and a
+name:
+
+@example
+/* Build locals: */
+gcc_jit_lvalue *i =
+ gcc_jit_function_new_local (func, NULL, the_type, "i");
+gcc_jit_lvalue *sum =
+ gcc_jit_function_new_local (func, NULL, the_type, "sum");
+@end example
+
+@noindent
+
+These are instances of @pxref{22,,gcc_jit_lvalue *} - they can be read from
+and written to.
+
+Note that there is no precanned way to create @emph{and} initialize a variable
+like in C:
+
+@example
+int i = 0;
+@end example
+
+@noindent
+
+Instead, having added the local to the function, we have to separately add
+an assignment of @cite{0} to @cite{local_i} at the beginning of the function.
+
+@node Control flow,Visualizing the control flow graph,Expressions lvalues and rvalues,Tutorial part 3 Loops and variables
+@anchor{intro/tutorial03 control-flow}@anchor{25}
+@subsection Control flow
+
+
+This function has a loop, so we need to build some basic blocks to
+handle the control flow. In this case, we need 4 blocks:
+
+
+@enumerate
+
+@item
+before the loop (initializing the locals)
+
+@item
+the conditional at the top of the loop (comparing @cite{i < n})
+
+@item
+the body of the loop
+
+@item
+after the loop terminates (@cite{return sum})
+@end enumerate
+
+so we create these as @pxref{26,,gcc_jit_block *} instances within the
+@pxref{27,,gcc_jit_function *}:
+
+@example
+gcc_jit_block *b_initial =
+ gcc_jit_function_new_block (func, "initial");
+gcc_jit_block *b_loop_cond =
+ gcc_jit_function_new_block (func, "loop_cond");
+gcc_jit_block *b_loop_body =
+ gcc_jit_function_new_block (func, "loop_body");
+gcc_jit_block *b_after_loop =
+ gcc_jit_function_new_block (func, "after_loop");
+@end example
+
+@noindent
+
+We now populate each block with statements.
+
+The entry block @cite{b_initial} consists of initializations followed by a jump
+to the conditional. We assign @cite{0} to @cite{i} and to @cite{sum}, using
+@pxref{28,,gcc_jit_block_add_assignment()} to add
+an assignment statement, and using @pxref{29,,gcc_jit_context_zero()} to get
+the constant value @cite{0} for the relevant type for the right-hand side of
+the assignment:
+
+@example
+/* sum = 0; */
+gcc_jit_block_add_assignment (
+ b_initial, NULL,
+ sum,
+ gcc_jit_context_zero (ctxt, the_type));
+
+/* i = 0; */
+gcc_jit_block_add_assignment (
+ b_initial, NULL,
+ i,
+ gcc_jit_context_zero (ctxt, the_type));
+@end example
+
+@noindent
+
+We can then terminate the entry block by jumping to the conditional:
+
+@example
+gcc_jit_block_end_with_jump (b_initial, NULL, b_loop_cond);
+@end example
+
+@noindent
+
+The conditional block is equivalent to the line @cite{while (i < n)} from our
+C example. It contains a single statement: a conditional, which jumps to
+one of two destination blocks depending on a boolean
+@pxref{13,,gcc_jit_rvalue *}, in this case the comparison of @cite{i} and @cite{n}.
+We build the comparison using @pxref{2a,,gcc_jit_context_new_comparison()}:
+
+@example
+gcc_jit_rvalue *guard =
+ gcc_jit_context_new_comparison (
+ ctxt, NULL,
+ GCC_JIT_COMPARISON_GE,
+ gcc_jit_lvalue_as_rvalue (i),
+ gcc_jit_param_as_rvalue (n));
+@end example
+
+@noindent
+
+and can then use this to add @cite{b_loop_cond}'s sole statement, via
+@pxref{2b,,gcc_jit_block_end_with_conditional()}:
+
+@example
+gcc_jit_block_end_with_conditional (b_loop_cond, NULL, guard);
+@end example
+
+@noindent
+
+Next, we populate the body of the loop.
+
+The C statement @cite{sum += i * i;} is an assignment operation, where an
+lvalue is modified "in-place". We use
+@pxref{2c,,gcc_jit_block_add_assignment_op()} to handle these operations:
+
+@example
+/* sum += i * i */
+gcc_jit_block_add_assignment_op (
+ b_loop_body, NULL,
+ sum,
+ GCC_JIT_BINARY_OP_PLUS,
+ gcc_jit_context_new_binary_op (
+ ctxt, NULL,
+ GCC_JIT_BINARY_OP_MULT, the_type,
+ gcc_jit_lvalue_as_rvalue (i),
+ gcc_jit_lvalue_as_rvalue (i)));
+@end example
+
+@noindent
+
+The @cite{i++} can be thought of as @cite{i += 1}, and can thus be handled in
+a similar way. We use @pxref{2d,,gcc_jit_context_one()} to get the constant
+value @cite{1} (for the relevant type) for the right-hand side
+of the assignment.
+
+@example
+/* i++ */
+gcc_jit_block_add_assignment_op (
+ b_loop_body, NULL,
+ i,
+ GCC_JIT_BINARY_OP_PLUS,
+ gcc_jit_context_one (ctxt, the_type));
+@end example
+
+@noindent
+
+@cartouche
+@quotation Note
+For numeric constants other than 0 or 1, we could use
+@pxref{2e,,gcc_jit_context_new_rvalue_from_int()} and
+@pxref{2f,,gcc_jit_context_new_rvalue_from_double()}.
+@end quotation
+@end cartouche
+
+The loop body completes by jumping back to the conditional:
+
+@example
+gcc_jit_block_end_with_jump (b_loop_body, NULL, b_loop_cond);
+@end example
+
+@noindent
+
+Finally, we populate the @cite{b_after_loop} block, reached when the loop
+conditional is false. We want to generate the equivalent of:
+
+@example
+return sum;
+@end example
+
+@noindent
+
+so the block is just one statement:
+
+@example
+/* return sum */
+gcc_jit_block_end_with_return (
+ b_after_loop,
+ NULL,
+ gcc_jit_lvalue_as_rvalue (sum));
+@end example
+
+@noindent
+
+@cartouche
+@quotation Note
+You can intermingle block creation with statement creation,
+but given that the terminator statements generally include references
+to other blocks, I find it's clearer to create all the blocks,
+@emph{then} all the statements.
+@end quotation
+@end cartouche
+
+We've finished populating the function. As before, we can now compile it
+to machine code:
+
+@example
+gcc_jit_result *result;
+result = gcc_jit_context_compile (ctxt);
+
+typedef int (*loop_test_fn_type) (int);
+loop_test_fn_type loop_test =
+ (loop_test_fn_type)gcc_jit_result_get_code (result, "loop_test");
+if (!loop_test)
+ goto error;
+printf ("result: %d", loop_test (10));
+@end example
+
+@noindent
+
+@example
+result: 285
+@end example
+
+@noindent
+
+@node Visualizing the control flow graph,Full example<2>,Control flow,Tutorial part 3 Loops and variables
+@anchor{intro/tutorial03 visualizing-the-control-flow-graph}@anchor{30}
+@subsection Visualizing the control flow graph
+
+
+You can see the control flow graph of a function using
+@pxref{31,,gcc_jit_function_dump_to_dot()}:
+
+@example
+gcc_jit_function_dump_to_dot (func, "/tmp/sum-of-squares.dot");
+@end example
+
+@noindent
+
+giving a .dot file in GraphViz format.
+
+You can convert this to an image using @cite{dot}:
+
+@example
+$ dot -Tpng /tmp/sum-of-squares.dot -o /tmp/sum-of-squares.png
+@end example
+
+@noindent
+
+or use a viewer (my preferred one is xdot.py; see
+@indicateurl{https://github.com/jrfonseca/xdot.py}; on Fedora you can
+install it with @cite{yum install python-xdot}):
+
+@quotation
+
+
+@float Figure
+
+@image{sum-of-squares,,,image of a control flow graph,png}
+
+@end float
+
+@end quotation
+
+@node Full example<2>,,Visualizing the control flow graph,Tutorial part 3 Loops and variables
+@anchor{intro/tutorial03 full-example}@anchor{32}
+@subsection Full example
+
+
+@quotation
+
+@example
+/* Usage example for libgccjit.so
+ Copyright (C) 2014 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include <libgccjit.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+
+void
+create_code (gcc_jit_context *ctxt)
+@{
+ /*
+ Simple sum-of-squares, to test conditionals and looping
+
+ int loop_test (int n)
+ @{
+ int i;
+ int sum = 0;
+ for (i = 0; i < n ; i ++)
+ @{
+ sum += i * i;
+ @}
+ return sum;
+ */
+ gcc_jit_type *the_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+ gcc_jit_type *return_type = the_type;
+
+ gcc_jit_param *n =
+ gcc_jit_context_new_param (ctxt, NULL, the_type, "n");
+ gcc_jit_param *params[1] = @{n@};
+ gcc_jit_function *func =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ return_type,
+ "loop_test",
+ 1, params, 0);
+
+ /* Build locals: */
+ gcc_jit_lvalue *i =
+ gcc_jit_function_new_local (func, NULL, the_type, "i");
+ gcc_jit_lvalue *sum =
+ gcc_jit_function_new_local (func, NULL, the_type, "sum");
+
+ gcc_jit_block *b_initial =
+ gcc_jit_function_new_block (func, "initial");
+ gcc_jit_block *b_loop_cond =
+ gcc_jit_function_new_block (func, "loop_cond");
+ gcc_jit_block *b_loop_body =
+ gcc_jit_function_new_block (func, "loop_body");
+ gcc_jit_block *b_after_loop =
+ gcc_jit_function_new_block (func, "after_loop");
+
+ /* sum = 0; */
+ gcc_jit_block_add_assignment (
+ b_initial, NULL,
+ sum,
+ gcc_jit_context_zero (ctxt, the_type));
+
+ /* i = 0; */
+ gcc_jit_block_add_assignment (
+ b_initial, NULL,
+ i,
+ gcc_jit_context_zero (ctxt, the_type));
+
+ gcc_jit_block_end_with_jump (b_initial, NULL, b_loop_cond);
+
+ /* if (i >= n) */
+ gcc_jit_block_end_with_conditional (
+ b_loop_cond, NULL,
+ gcc_jit_context_new_comparison (
+ ctxt, NULL,
+ GCC_JIT_COMPARISON_GE,
+ gcc_jit_lvalue_as_rvalue (i),
+ gcc_jit_param_as_rvalue (n)),
+ b_after_loop,
+ b_loop_body);
+
+ /* sum += i * i */
+ gcc_jit_block_add_assignment_op (
+ b_loop_body, NULL,
+ sum,
+ GCC_JIT_BINARY_OP_PLUS,
+ gcc_jit_context_new_binary_op (
+ ctxt, NULL,
+ GCC_JIT_BINARY_OP_MULT, the_type,
+ gcc_jit_lvalue_as_rvalue (i),
+ gcc_jit_lvalue_as_rvalue (i)));
+
+ /* i++ */
+ gcc_jit_block_add_assignment_op (
+ b_loop_body, NULL,
+ i,
+ GCC_JIT_BINARY_OP_PLUS,
+ gcc_jit_context_one (ctxt, the_type));
+
+ gcc_jit_block_end_with_jump (b_loop_body, NULL, b_loop_cond);
+
+ /* return sum */
+ gcc_jit_block_end_with_return (
+ b_after_loop,
+ NULL,
+ gcc_jit_lvalue_as_rvalue (sum));
+@}
+
+int
+main (int argc, char **argv)
+@{
+ gcc_jit_context *ctxt = NULL;
+ gcc_jit_result *result = NULL;
+
+ /* Get a "context" object for working with the library. */
+ ctxt = gcc_jit_context_acquire ();
+ if (!ctxt)
+ @{
+ fprintf (stderr, "NULL ctxt");
+ goto error;
+ @}
+
+ /* Set some options on the context.
+ Let's see the code being generated, in assembler form. */
+ gcc_jit_context_set_bool_option (
+ ctxt,
+ GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE,
+ 0);
+
+ /* Populate the context. */
+ create_code (ctxt);
+
+ /* Compile the code. */
+ result = gcc_jit_context_compile (ctxt);
+ if (!result)
+ @{
+ fprintf (stderr, "NULL result");
+ goto error;
+ @}
+
+ /* Extract the generated code from "result". */
+ typedef int (*loop_test_fn_type) (int);
+ loop_test_fn_type loop_test =
+ (loop_test_fn_type)gcc_jit_result_get_code (result, "loop_test");
+ if (!loop_test)
+ @{
+ fprintf (stderr, "NULL loop_test");
+ goto error;
+ @}
+
+ /* Run the generated code. */
+ int val = loop_test (10);
+ printf("loop_test returned: %d\n", val);
+
+ error:
+ gcc_jit_context_release (ctxt);
+ gcc_jit_result_release (result);
+ return 0;
+@}
+
+@end example
+
+@noindent
+@end quotation
+
+Building and running it:
+
+@example
+$ gcc \
+ tut03-sum-of-squares.c \
+ -o tut03-sum-of-squares \
+ -lgccjit
+
+# Run the built program:
+$ ./tut03-sum-of-squares
+loop_test returned: 285
+@end example
+
+@noindent
+
+@c Copyright (C) 2014 Free Software Foundation, Inc.
+@c Originally contributed by David Malcolm <dmalcolm@redhat.com>
+@c
+@c This is free software: you can redistribute it and/or modify it
+@c under the terms of the GNU General Public License as published by
+@c the Free Software Foundation, either version 3 of the License, or
+@c (at your option) any later version.
+@c
+@c This program is distributed in the hope that it will be useful, but
+@c WITHOUT ANY WARRANTY; without even the implied warranty of
+@c MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+@c General Public License for more details.
+@c
+@c You should have received a copy of the GNU General Public License
+@c along with this program. If not, see
+@c <http://www.gnu.org/licenses/>.
+
+@node Tutorial part 4 Adding JIT-compilation to a toy interpreter,,Tutorial part 3 Loops and variables,Tutorial
+@anchor{intro/tutorial04 tutorial-part-4-adding-jit-compilation-to-a-toy-interpreter}@anchor{33}@anchor{intro/tutorial04 doc}@anchor{34}
+@section Tutorial part 4: Adding JIT-compilation to a toy interpreter
+
+
+In this example we construct a "toy" interpreter, and add JIT-compilation
+to it.
+
+@menu
+* Our toy interpreter::
+* Compiling to machine code::
+* Setting things up::
+* Populating the function::
+* Verifying the control flow graph::
+* Compiling the context::
+* Single-stepping through the generated code::
+* Examining the generated code::
+* Putting it all together::
+* Behind the curtain; How does our code get optimized?: Behind the curtain How does our code get optimized?.
+
+@end menu
+
+@node Our toy interpreter,Compiling to machine code,,Tutorial part 4 Adding JIT-compilation to a toy interpreter
+@anchor{intro/tutorial04 our-toy-interpreter}@anchor{35}
+@subsection Our toy interpreter
+
+
+It's a stack-based interpreter, and is intended as a (very simple) example
+of the kind of bytecode interpreter seen in dynamic languages such as
+Python, Ruby etc.
+
+For the sake of simplicity, our toy virtual machine is very limited:
+
+@quotation
+
+
+@itemize *
+
+@item
+The only data type is @cite{int}
+
+@item
+It can only work on one function at a time (so that the only
+function call that can be made is to recurse).
+
+@item
+Functions can only take one parameter.
+
+@item
+Functions have a stack of @cite{int} values.
+
+@item
+We'll implement function call within the interpreter by calling a
+function in our implementation, rather than implementing our own
+frame stack.
+
+@item
+The parser is only good enough to get the examples to work.
+@end itemize
+@end quotation
+
+Naturally, a real interpreter would be much more complicated that this.
+
+The following operations are supported:
+
+
+@multitable {xxxxxxxxxxxxxxxxxxxxxxxx} {xxxxxxxxxxxxxxxxxxxxxxxxxx} {xxxxxxxxxxxxxxxxx} {xxxxxxxxxxxxxxxxxx}
+@headitem
+
+Operation
+
+@tab
+
+Meaning
+
+@tab
+
+Old Stack
+
+@tab
+
+New Stack
+
+@item
+
+DUP
+
+@tab
+
+Duplicate top of stack.
+
+@tab
+
+@code{[..., x]}
+
+@tab
+
+@code{[..., x, x]}
+
+@item
+
+ROT
+
+@tab
+
+Swap top two elements
+of stack.
+
+@tab
+
+@code{[..., x, y]}
+
+@tab
+
+@code{[..., y, x]}
+
+@item
+
+BINARY_ADD
+
+@tab
+
+Add the top two elements
+on the stack.
+
+@tab
+
+@code{[..., x, y]}
+
+@tab
+
+@code{[..., (x+y)]}
+
+@item
+
+BINARY_SUBTRACT
+
+@tab
+
+Likewise, but subtract.
+
+@tab
+
+@code{[..., x, y]}
+
+@tab
+
+@code{[..., (x-y)]}
+
+@item
+
+BINARY_MULT
+
+@tab
+
+Likewise, but multiply.
+
+@tab
+
+@code{[..., x, y]}
+
+@tab
+
+@code{[..., (x*y)]}
+
+@item
+
+BINARY_COMPARE_LT
+
+@tab
+
+Compare the top two
+elements on the stack
+and push a nonzero/zero
+if (x<y).
+
+@tab
+
+@code{[..., x, y]}
+
+@tab
+
+@code{[..., (x<y)]}
+
+@item
+
+RECURSE
+
+@tab
+
+Recurse, passing the top
+of the stack, and
+popping the result.
+
+@tab
+
+@code{[..., x]}
+
+@tab
+
+@code{[..., fn(x)]}
+
+@item
+
+RETURN
+
+@tab
+
+Return the top of the
+stack.
+
+@tab
+
+@code{[x]}
+
+@tab
+
+@code{[]}
+
+@item
+
+PUSH_CONST @cite{arg}
+
+@tab
+
+Push an int const.
+
+@tab
+
+@code{[...]}
+
+@tab
+
+@code{[..., arg]}
+
+@item
+
+JUMP_ABS_IF_TRUE @cite{arg}
+
+@tab
+
+Pop; if top of stack was
+nonzero, jump to
+@code{arg}.
+
+@tab
+
+@code{[..., x]}
+
+@tab
+
+@code{[...]}
+
+@end multitable
+
+
+Programs can be interpreted, disassembled, and compiled to machine code.
+
+The interpreter reads @code{.toy} scripts. Here's what a simple recursive
+factorial program looks like, the script @code{factorial.toy}.
+The parser ignores lines beginning with a @cite{#}.
+
+@quotation
+
+@example
+# Simple recursive factorial implementation, roughly equivalent to:
+#
+# int factorial (int arg)
+# @{
+# if (arg < 2)
+# return arg
+# return arg * factorial (arg - 1)
+# @}
+
+# Initial state:
+# stack: [arg]
+
+# 0:
+DUP
+# stack: [arg, arg]
+
+# 1:
+PUSH_CONST 2
+# stack: [arg, arg, 2]
+
+# 2:
+BINARY_COMPARE_LT
+# stack: [arg, (arg < 2)]
+
+# 3:
+JUMP_ABS_IF_TRUE 9
+# stack: [arg]
+
+# 4:
+DUP
+# stack: [arg, arg]
+
+# 5:
+PUSH_CONST 1
+# stack: [arg, arg, 1]
+
+# 6:
+BINARY_SUBTRACT
+# stack: [arg, (arg - 1)
+
+# 7:
+RECURSE
+# stack: [arg, factorial(arg - 1)]
+
+# 8:
+BINARY_MULT
+# stack: [arg * factorial(arg - 1)]
+
+# 9:
+RETURN
+
+@end example
+
+@noindent
+@end quotation
+
+The interpreter is a simple infinite loop with a big @code{switch} statement
+based on what the next opcode is:
+
+@quotation
+
+@example
+
+static int
+toyvm_function_interpret (toyvm_function *fn, int arg, FILE *trace)
+@{
+ toyvm_frame frame;
+#define PUSH(ARG) (toyvm_frame_push (&frame, (ARG)))
+#define POP(ARG) (toyvm_frame_pop (&frame))
+
+ frame.frm_function = fn;
+ frame.frm_pc = 0;
+ frame.frm_cur_depth = 0;
+
+ PUSH (arg);
+
+ while (1)
+ @{
+ toyvm_op *op;
+ int x, y;
+ assert (frame.frm_pc < fn->fn_num_ops);
+ op = &fn->fn_ops[frame.frm_pc++];
+
+ if (trace)
+ @{
+ toyvm_frame_dump_stack (&frame, trace);
+ toyvm_function_disassemble_op (fn, op, frame.frm_pc, trace);
+ @}
+
+ switch (op->op_opcode)
+ @{
+ /* Ops taking no operand. */
+ case DUP:
+ x = POP ();
+ PUSH (x);
+ PUSH (x);
+ break;
+
+ case ROT:
+ y = POP ();
+ x = POP ();
+ PUSH (y);
+ PUSH (x);
+ break;
+
+ case BINARY_ADD:
+ y = POP ();
+ x = POP ();
+ PUSH (x + y);
+ break;
+
+ case BINARY_SUBTRACT:
+ y = POP ();
+ x = POP ();
+ PUSH (x - y);
+ break;
+
+ case BINARY_MULT:
+ y = POP ();
+ x = POP ();
+ PUSH (x * y);
+ break;
+
+ case BINARY_COMPARE_LT:
+ y = POP ();
+ x = POP ();
+ PUSH (x < y);
+ break;
+
+ case RECURSE:
+ x = POP ();
+ x = toyvm_function_interpret (fn, x, trace);
+ PUSH (x);
+ break;
+
+ case RETURN:
+ return POP ();
+
+ /* Ops taking an operand. */
+ case PUSH_CONST:
+ PUSH (op->op_operand);
+ break;
+
+ case JUMP_ABS_IF_TRUE:
+ x = POP ();
+ if (x)
+ frame.frm_pc = op->op_operand;
+ break;
+
+ default:
+ assert (0); /* unknown opcode */
+
+ @} /* end of switch on opcode */
+ @} /* end of while loop */
+
+#undef PUSH
+#undef POP
+@}
+
+
+@end example
+
+@noindent
+@end quotation
+
+@node Compiling to machine code,Setting things up,Our toy interpreter,Tutorial part 4 Adding JIT-compilation to a toy interpreter
+@anchor{intro/tutorial04 compiling-to-machine-code}@anchor{36}
+@subsection Compiling to machine code
+
+
+We want to generate machine code that can be cast to this type and
+then directly executed in-process:
+
+@quotation
+
+@example
+typedef int (*toyvm_compiled_func) (int);
+
+
+@end example
+
+@noindent
+@end quotation
+
+Our compiler isn't very sophisticated; it takes the implementation of
+each opcode above, and maps it directly to the operations supported by
+the libgccjit API.
+
+How should we handle the stack? In theory we could calculate what the
+stack depth will be at each opcode, and optimize away the stack
+manipulation "by hand". We'll see below that libgccjit is able to do
+this for us, so we'll implement stack manipulation
+in a direct way, by creating a @code{stack} array and @code{stack_depth}
+variables, local within the generated function, equivalent to this C code:
+
+@example
+int stack_depth;
+int stack[MAX_STACK_DEPTH];
+@end example
+
+@noindent
+
+We'll also have local variables @code{x} and @code{y} for use when implementing
+the opcodes, equivalent to this:
+
+@example
+int x;
+int y;
+@end example
+
+@noindent
+
+This means our compiler has the following state:
+
+@quotation
+
+@example
+
+struct compilation_state
+@{
+ gcc_jit_context *ctxt;
+
+ gcc_jit_type *int_type;
+ gcc_jit_type *bool_type;
+ gcc_jit_type *stack_type; /* int[MAX_STACK_DEPTH] */
+
+ gcc_jit_rvalue *const_one;
+
+ gcc_jit_function *fn;
+ gcc_jit_param *param_arg;
+ gcc_jit_lvalue *stack;
+ gcc_jit_lvalue *stack_depth;
+ gcc_jit_lvalue *x;
+ gcc_jit_lvalue *y;
+
+ gcc_jit_location *op_locs[MAX_OPS];
+ gcc_jit_block *initial_block;
+ gcc_jit_block *op_blocks[MAX_OPS];
+
+@};
+
+
+@end example
+
+@noindent
+@end quotation
+
+@node Setting things up,Populating the function,Compiling to machine code,Tutorial part 4 Adding JIT-compilation to a toy interpreter
+@anchor{intro/tutorial04 setting-things-up}@anchor{37}
+@subsection Setting things up
+
+
+First we create our types:
+
+@quotation
+
+@example
+ state.int_type =
+ gcc_jit_context_get_type (state.ctxt, GCC_JIT_TYPE_INT);
+ state.bool_type =
+ gcc_jit_context_get_type (state.ctxt, GCC_JIT_TYPE_BOOL);
+ state.stack_type =
+ gcc_jit_context_new_array_type (state.ctxt, NULL,
+ state.int_type, MAX_STACK_DEPTH);
+
+
+@end example
+
+@noindent
+@end quotation
+
+along with extracting a useful @cite{int} constant:
+
+@quotation
+
+@example
+ state.const_one = gcc_jit_context_one (state.ctxt, state.int_type);
+
+
+@end example
+
+@noindent
+@end quotation
+
+We'll implement push and pop in terms of the @code{stack} array and
+@code{stack_depth}. Here are helper functions for adding statements to
+a block, implementing pushing and popping values:
+
+@quotation
+
+@example
+
+static void
+add_push (compilation_state *state,
+ gcc_jit_block *block,
+ gcc_jit_rvalue *rvalue,
+ gcc_jit_location *loc)
+@{
+ /* stack[stack_depth] = RVALUE */
+ gcc_jit_block_add_assignment (
+ block,
+ loc,
+ /* stack[stack_depth] */
+ gcc_jit_context_new_array_access (
+ state->ctxt,
+ loc,
+ gcc_jit_lvalue_as_rvalue (state->stack),
+ gcc_jit_lvalue_as_rvalue (state->stack_depth)),
+ rvalue);
+
+ /* "stack_depth++;". */
+ gcc_jit_block_add_assignment_op (
+ block,
+ loc,
+ state->stack_depth,
+ GCC_JIT_BINARY_OP_PLUS,
+ state->const_one);
+@}
+
+static void
+add_pop (compilation_state *state,
+ gcc_jit_block *block,
+ gcc_jit_lvalue *lvalue,
+ gcc_jit_location *loc)
+@{
+ /* "--stack_depth;". */
+ gcc_jit_block_add_assignment_op (
+ block,
+ loc,
+ state->stack_depth,
+ GCC_JIT_BINARY_OP_MINUS,
+ state->const_one);
+
+ /* "LVALUE = stack[stack_depth];". */
+ gcc_jit_block_add_assignment (
+ block,
+ loc,
+ lvalue,
+ /* stack[stack_depth] */
+ gcc_jit_lvalue_as_rvalue (
+ gcc_jit_context_new_array_access (
+ state->ctxt,
+ loc,
+ gcc_jit_lvalue_as_rvalue (state->stack),
+ gcc_jit_lvalue_as_rvalue (state->stack_depth))));
+@}
+
+
+@end example
+
+@noindent
+@end quotation
+
+We will support single-stepping through the generated code in the
+debugger, so we need to create @pxref{38,,gcc_jit_location} instances, one
+per operation in the source code. These will reference the lines of
+e.g. @code{factorial.toy}.
+
+@quotation
+
+@example
+ for (pc = 0; pc < fn->fn_num_ops; pc++)
+ @{
+ toyvm_op *op = &fn->fn_ops[pc];
+
+ state.op_locs[pc] = gcc_jit_context_new_location (state.ctxt,
+ fn->fn_filename,
+ op->op_linenum,
+ 0); /* column */
+ @}
+
+
+@end example
+
+@noindent
+@end quotation
+
+Let's create the function itself. As usual, we create its parameter
+first, then use the parameter to create the function:
+
+@quotation
+
+@example
+ state.param_arg =
+ gcc_jit_context_new_param (state.ctxt, state.op_locs[0],
+ state.int_type, "arg");
+ state.fn =
+ gcc_jit_context_new_function (state.ctxt,
+ state.op_locs[0],
+ GCC_JIT_FUNCTION_EXPORTED,
+ state.int_type,
+ funcname,
+ 1, &state.param_arg, 0);
+
+
+@end example
+
+@noindent
+@end quotation
+
+We create the locals within the function.
+
+@quotation
+
+@example
+ state.stack =
+ gcc_jit_function_new_local (state.fn, NULL,
+ state.stack_type, "stack");
+ state.stack_depth =
+ gcc_jit_function_new_local (state.fn, NULL,
+ state.int_type, "stack_depth");
+ state.x =
+ gcc_jit_function_new_local (state.fn, NULL,
+ state.int_type, "x");
+ state.y =
+ gcc_jit_function_new_local (state.fn, NULL,
+ state.int_type, "y");
+
+
+@end example
+
+@noindent
+@end quotation
+
+@node Populating the function,Verifying the control flow graph,Setting things up,Tutorial part 4 Adding JIT-compilation to a toy interpreter
+@anchor{intro/tutorial04 populating-the-function}@anchor{39}
+@subsection Populating the function
+
+
+There's some one-time initialization, and the API treats the first block
+you create as the entrypoint of the function, so we need to create that
+block first:
+
+@quotation
+
+@example
+ state.initial_block = gcc_jit_function_new_block (state.fn, "initial");
+
+
+@end example
+
+@noindent
+@end quotation
+
+We can now create blocks for each of the operations. Most of these will
+be consolidated into larger blocks when the optimizer runs.
+
+@quotation
+
+@example
+ for (pc = 0; pc < fn->fn_num_ops; pc++)
+ @{
+ char buf[16];
+ sprintf (buf, "instr%i", pc);
+ state.op_blocks[pc] = gcc_jit_function_new_block (state.fn, buf);
+ @}
+
+
+@end example
+
+@noindent
+@end quotation
+
+Now that we have a block it can jump to when it's done, we can populate
+the initial block:
+
+@quotation
+
+@example
+
+ /* "stack_depth = 0;". */
+ gcc_jit_block_add_assignment (
+ state.initial_block,
+ state.op_locs[0],
+ state.stack_depth,
+ gcc_jit_context_zero (state.ctxt, state.int_type));
+
+ /* "PUSH (arg);". */
+ add_push (&state,
+ state.initial_block,
+ gcc_jit_param_as_rvalue (state.param_arg),
+ state.op_locs[0]);
+
+ /* ...and jump to insn 0. */
+ gcc_jit_block_end_with_jump (state.initial_block,
+ state.op_locs[0],
+ state.op_blocks[0]);
+
+
+@end example
+
+@noindent
+@end quotation
+
+We can now populate the blocks for the individual operations. We loop
+through them, adding instructions to their blocks:
+
+@quotation
+
+@example
+ for (pc = 0; pc < fn->fn_num_ops; pc++)
+ @{
+ gcc_jit_location *loc = state.op_locs[pc];
+
+ gcc_jit_block *block = state.op_blocks[pc];
+ gcc_jit_block *next_block = (pc < fn->fn_num_ops
+ ? state.op_blocks[pc + 1]
+ : NULL);
+
+ toyvm_op *op;
+ op = &fn->fn_ops[pc];
+
+
+@end example
+
+@noindent
+@end quotation
+
+We're going to have another big @code{switch} statement for implementing
+the opcodes, this time for compiling them, rather than interpreting
+them. It's helpful to have macros for implementing push and pop, so that
+we can make the @code{switch} statement that's coming up look as much as
+possible like the one above within the interpreter:
+
+@example
+
+#define X_EQUALS_POP()\
+ add_pop (&state, block, state.x, loc)
+#define Y_EQUALS_POP()\
+ add_pop (&state, block, state.y, loc)
+#define PUSH_RVALUE(RVALUE)\
+ add_push (&state, block, (RVALUE), loc)
+#define PUSH_X()\
+ PUSH_RVALUE (gcc_jit_lvalue_as_rvalue (state.x))
+#define PUSH_Y() \
+ PUSH_RVALUE (gcc_jit_lvalue_as_rvalue (state.y))
+
+
+@end example
+
+@noindent
+
+@cartouche
+@quotation Note
+A particularly clever implementation would have an @emph{identical}
+@code{switch} statement shared by the interpreter and the compiler, with
+some preprocessor "magic". We're not doing that here, for the sake
+of simplicity.
+@end quotation
+@end cartouche
+
+When I first implemented this compiler, I accidentally missed an edit
+when copying and pasting the @code{Y_EQUALS_POP} macro, so that popping the
+stack into @code{y} instead erroneously assigned it to @code{x}, leaving @code{y}
+uninitialized.
+
+To track this kind of thing down, we can use
+@pxref{3a,,gcc_jit_block_add_comment()} to add descriptive comments
+to the internal representation. This is invaluable when looking through
+the generated IR for, say @code{factorial}:
+
+@quotation
+
+@example
+
+ gcc_jit_block_add_comment (block, loc, opcode_names[op->op_opcode]);
+
+
+@end example
+
+@noindent
+@end quotation
+
+We can now write the big @code{switch} statement that implements the
+individual opcodes, populating the relevant block with statements:
+
+@quotation
+
+@example
+
+ switch (op->op_opcode)
+ @{
+ case DUP:
+ X_EQUALS_POP ();
+ PUSH_X ();
+ PUSH_X ();
+ break;
+
+ case ROT:
+ Y_EQUALS_POP ();
+ X_EQUALS_POP ();
+ PUSH_Y ();
+ PUSH_X ();
+ break;
+
+ case BINARY_ADD:
+ Y_EQUALS_POP ();
+ X_EQUALS_POP ();
+ PUSH_RVALUE (
+ gcc_jit_context_new_binary_op (
+ state.ctxt,
+ loc,
+ GCC_JIT_BINARY_OP_PLUS,
+ state.int_type,
+ gcc_jit_lvalue_as_rvalue (state.x),
+ gcc_jit_lvalue_as_rvalue (state.y)));
+ break;
+
+ case BINARY_SUBTRACT:
+ Y_EQUALS_POP ();
+ X_EQUALS_POP ();
+ PUSH_RVALUE (
+ gcc_jit_context_new_binary_op (
+ state.ctxt,
+ loc,
+ GCC_JIT_BINARY_OP_MINUS,
+ state.int_type,
+ gcc_jit_lvalue_as_rvalue (state.x),
+ gcc_jit_lvalue_as_rvalue (state.y)));
+ break;
+
+ case BINARY_MULT:
+ Y_EQUALS_POP ();
+ X_EQUALS_POP ();
+ PUSH_RVALUE (
+ gcc_jit_context_new_binary_op (
+ state.ctxt,
+ loc,
+ GCC_JIT_BINARY_OP_MULT,
+ state.int_type,
+ gcc_jit_lvalue_as_rvalue (state.x),
+ gcc_jit_lvalue_as_rvalue (state.y)));
+ break;
+
+ case BINARY_COMPARE_LT:
+ Y_EQUALS_POP ();
+ X_EQUALS_POP ();
+ PUSH_RVALUE (
+ /* cast of bool to int */
+ gcc_jit_context_new_cast (
+ state.ctxt,
+ loc,
+ /* (x < y) as a bool */
+ gcc_jit_context_new_comparison (
+ state.ctxt,
+ loc,
+ GCC_JIT_COMPARISON_LT,
+ gcc_jit_lvalue_as_rvalue (state.x),
+ gcc_jit_lvalue_as_rvalue (state.y)),
+ state.int_type));
+ break;
+
+ case RECURSE:
+ @{
+ X_EQUALS_POP ();
+ gcc_jit_rvalue *arg = gcc_jit_lvalue_as_rvalue (state.x);
+ PUSH_RVALUE (
+ gcc_jit_context_new_call (
+ state.ctxt,
+ loc,
+ state.fn,
+ 1, &arg));
+ break;
+ @}
+
+ case RETURN:
+ X_EQUALS_POP ();
+ gcc_jit_block_end_with_return (
+ block,
+ loc,
+ gcc_jit_lvalue_as_rvalue (state.x));
+ break;
+
+ /* Ops taking an operand. */
+ case PUSH_CONST:
+ PUSH_RVALUE (
+ gcc_jit_context_new_rvalue_from_int (
+ state.ctxt,
+ state.int_type,
+ op->op_operand));
+ break;
+
+ case JUMP_ABS_IF_TRUE:
+ X_EQUALS_POP ();
+ gcc_jit_block_end_with_conditional (
+ block,
+ loc,
+ /* "(bool)x". */
+ gcc_jit_context_new_cast (
+ state.ctxt,
+ loc,
+ gcc_jit_lvalue_as_rvalue (state.x),
+ state.bool_type),
+ state.op_blocks[op->op_operand], /* on_true */
+ next_block); /* on_false */
+ break;
+
+ default:
+ assert(0);
+ @} /* end of switch on opcode */
+
+
+@end example
+
+@noindent
+@end quotation
+
+Every block must be terminated, via a call to one of the
+@code{gcc_jit_block_end_with_} entrypoints. This has been done for two
+of the opcodes, but we need to do it for the other ones, by jumping
+to the next block.
+
+@quotation
+
+@example
+ if (op->op_opcode != JUMP_ABS_IF_TRUE
+ && op->op_opcode != RETURN)
+ gcc_jit_block_end_with_jump (
+ block,
+ loc,
+ next_block);
+
+
+@end example
+
+@noindent
+@end quotation
+
+This is analogous to simply incrementing the program counter.
+
+@node Verifying the control flow graph,Compiling the context,Populating the function,Tutorial part 4 Adding JIT-compilation to a toy interpreter
+@anchor{intro/tutorial04 verifying-the-control-flow-graph}@anchor{3b}
+@subsection Verifying the control flow graph
+
+
+Having finished looping over the blocks, the context is complete.
+
+As before, we can verify that the control flow and statements are sane by
+using @pxref{31,,gcc_jit_function_dump_to_dot()}:
+
+@example
+gcc_jit_function_dump_to_dot (state.fn, "/tmp/factorial.dot");
+@end example
+
+@noindent
+
+and viewing the result. Note how the label names, comments, and
+variable names show up in the dump, to make it easier to spot
+errors in our compiler.
+
+@quotation
+
+
+@float Figure
+
+@image{factorial,,,image of a control flow graph,png}
+
+@end float
+
+@end quotation
+
+@node Compiling the context,Single-stepping through the generated code,Verifying the control flow graph,Tutorial part 4 Adding JIT-compilation to a toy interpreter
+@anchor{intro/tutorial04 compiling-the-context}@anchor{3c}
+@subsection Compiling the context
+
+
+Having finished looping over the blocks and populating them with
+statements, the context is complete.
+
+We can now compile it, and extract machine code from the result:
+
+@quotation
+
+@example
+ gcc_jit_result *result = gcc_jit_context_compile (state.ctxt);
+ gcc_jit_context_release (state.ctxt);
+
+ return (toyvm_compiled_func)gcc_jit_result_get_code (result,
+ funcname);
+
+@end example
+
+@noindent
+@end quotation
+
+We can now run the result:
+
+@quotation
+
+@example
+ toyvm_compiled_func code = toyvm_function_compile (fn);
+ printf ("compiler result: %d\n",
+ code (atoi (argv[2])));
+
+
+@end example
+
+@noindent
+@end quotation
+
+@node Single-stepping through the generated code,Examining the generated code,Compiling the context,Tutorial part 4 Adding JIT-compilation to a toy interpreter
+@anchor{intro/tutorial04 single-stepping-through-the-generated-code}@anchor{3d}
+@subsection Single-stepping through the generated code
+
+
+It's possible to debug the generated code. To do this we need to both:
+
+@quotation
+
+
+@itemize *
+
+@item
+Set up source code locations for our statements, so that we can
+meaningfully step through the code. We did this above by
+calling @pxref{3e,,gcc_jit_context_new_location()} and using the
+results.
+
+@item
+Enable the generation of debugging information, by setting
+@pxref{3f,,GCC_JIT_BOOL_OPTION_DEBUGINFO} on the
+@pxref{8,,gcc_jit_context} via
+@pxref{19,,gcc_jit_context_set_bool_option()}:
+
+@example
+gcc_jit_context_set_bool_option (
+ ctxt,
+ GCC_JIT_BOOL_OPTION_DEBUGINFO,
+ 1);
+@end example
+
+@noindent
+@end itemize
+@end quotation
+
+Having done this, we can put a breakpoint on the generated function:
+
+@example
+$ gdb --args ./toyvm factorial.toy 10
+(gdb) break factorial
+Function "factorial" not defined.
+Make breakpoint pending on future shared library load? (y or [n]) y
+Breakpoint 1 (factorial) pending.
+(gdb) run
+Breakpoint 1, factorial (arg=10) at factorial.toy:14
+14 DUP
+@end example
+
+@noindent
+
+We've set up location information, which references @code{factorial.toy}.
+This allows us to use e.g. @code{list} to see where we are in the script:
+
+@example
+(gdb) list
+9
+10 # Initial state:
+11 # stack: [arg]
+12
+13 # 0:
+14 DUP
+15 # stack: [arg, arg]
+16
+17 # 1:
+18 PUSH_CONST 2
+@end example
+
+@noindent
+
+and to step through the function, examining the data:
+
+@example
+(gdb) n
+18 PUSH_CONST 2
+(gdb) n
+22 BINARY_COMPARE_LT
+(gdb) print stack
+$5 = @{10, 10, 2, 0, -7152, 32767, 0, 0@}
+(gdb) print stack_depth
+$6 = 3
+@end example
+
+@noindent
+
+You'll see that the parts of the @code{stack} array that haven't been
+touched yet are uninitialized.
+
+@cartouche
+@quotation Note
+Turning on optimizations may lead to unpredictable results when
+stepping through the generated code: the execution may appear to
+"jump around" the source code. This is analogous to turning up the
+optimization level in a regular compiler.
+@end quotation
+@end cartouche
+
+@node Examining the generated code,Putting it all together,Single-stepping through the generated code,Tutorial part 4 Adding JIT-compilation to a toy interpreter
+@anchor{intro/tutorial04 examining-the-generated-code}@anchor{40}
+@subsection Examining the generated code
+
+
+How good is the optimized code?
+
+We can turn up optimizations, by calling
+@pxref{1c,,gcc_jit_context_set_int_option()} with
+@pxref{1d,,GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL}:
+
+@example
+gcc_jit_context_set_int_option (
+ ctxt,
+ GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL,
+ 3);
+@end example
+
+@noindent
+
+One of GCC's internal representations is called "gimple". A dump of the
+initial gimple representation of the code can be seen by setting:
+
+@example
+gcc_jit_context_set_bool_option (ctxt,
+ GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE,
+ 1);
+@end example
+
+@noindent
+
+With optimization on and source locations displayed, this gives:
+
+@c We'll use "c" for gimple dumps
+
+@example
+factorial (signed int arg)
+@{
+ <unnamed type> D.80;
+ signed int D.81;
+ signed int D.82;
+ signed int D.83;
+ signed int D.84;
+ signed int D.85;
+ signed int y;
+ signed int x;
+ signed int stack_depth;
+ signed int stack[8];
+
+ try
+ @{
+ initial:
+ stack_depth = 0;
+ stack[stack_depth] = arg;
+ stack_depth = stack_depth + 1;
+ goto instr0;
+ instr0:
+ /* DUP */:
+ stack_depth = stack_depth + -1;
+ x = stack[stack_depth];
+ stack[stack_depth] = x;
+ stack_depth = stack_depth + 1;
+ stack[stack_depth] = x;
+ stack_depth = stack_depth + 1;
+ goto instr1;
+ instr1:
+ /* PUSH_CONST */:
+ stack[stack_depth] = 2;
+ stack_depth = stack_depth + 1;
+ goto instr2;
+
+ /* etc */
+@end example
+
+@noindent
+
+You can see the generated machine code in assembly form via:
+
+@example
+gcc_jit_context_set_bool_option (
+ ctxt,
+ GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE,
+ 1);
+result = gcc_jit_context_compile (ctxt);
+@end example
+
+@noindent
+
+which shows that (on this x86_64 box) the compiler has unrolled the loop
+and is using MMX instructions to perform several multiplications
+simultaneously:
+
+@example
+ .file "fake.c"
+ .text
+.Ltext0:
+ .p2align 4,,15
+ .globl factorial
+ .type factorial, @@function
+factorial:
+.LFB0:
+ .file 1 "factorial.toy"
+ .loc 1 14 0
+ .cfi_startproc
+.LVL0:
+.L2:
+ .loc 1 26 0
+ cmpl $1, %edi
+ jle .L13
+ leal -1(%rdi), %edx
+ movl %edx, %ecx
+ shrl $2, %ecx
+ leal 0(,%rcx,4), %esi
+ testl %esi, %esi
+ je .L14
+ cmpl $9, %edx
+ jbe .L14
+ leal -2(%rdi), %eax
+ movl %eax, -16(%rsp)
+ leal -3(%rdi), %eax
+ movd -16(%rsp), %xmm0
+ movl %edi, -16(%rsp)
+ movl %eax, -12(%rsp)
+ movd -16(%rsp), %xmm1
+ xorl %eax, %eax
+ movl %edx, -16(%rsp)
+ movd -12(%rsp), %xmm4
+ movd -16(%rsp), %xmm6
+ punpckldq %xmm4, %xmm0
+ movdqa .LC1(%rip), %xmm4
+ punpckldq %xmm6, %xmm1
+ punpcklqdq %xmm0, %xmm1
+ movdqa .LC0(%rip), %xmm0
+ jmp .L5
+ # etc - edited for brevity
+@end example
+
+@noindent
+
+This is clearly overkill for a function that will likely overflow the
+@code{int} type before the vectorization is worthwhile - but then again, this
+is a toy example.
+
+Turning down the optimization level to 2:
+
+@example
+gcc_jit_context_set_int_option (
+ ctxt,
+ GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL,
+ 3);
+@end example
+
+@noindent
+
+yields this code, which is simple enough to quote in its entirety:
+
+@example
+ .file "fake.c"
+ .text
+ .p2align 4,,15
+ .globl factorial
+ .type factorial, @@function
+factorial:
+.LFB0:
+ .cfi_startproc
+.L2:
+ cmpl $1, %edi
+ jle .L8
+ movl $1, %edx
+ jmp .L4
+ .p2align 4,,10
+ .p2align 3
+.L6:
+ movl %eax, %edi
+.L4:
+.L5:
+ leal -1(%rdi), %eax
+ imull %edi, %edx
+ cmpl $1, %eax
+ jne .L6
+.L3:
+.L7:
+ imull %edx, %eax
+ ret
+.L8:
+ movl %edi, %eax
+ movl $1, %edx
+ jmp .L7
+ .cfi_endproc
+.LFE0:
+ .size factorial, .-factorial
+ .ident "GCC: (GNU) 4.9.0 20131023 (Red Hat 0.2-%@{gcc_release@})"
+ .section .note.GNU-stack,"",@@progbits
+@end example
+
+@noindent
+
+Note that the stack pushing and popping have been eliminated, as has the
+recursive call (in favor of an iteration).
+
+@node Putting it all together,Behind the curtain How does our code get optimized?,Examining the generated code,Tutorial part 4 Adding JIT-compilation to a toy interpreter
+@anchor{intro/tutorial04 putting-it-all-together}@anchor{41}
+@subsection Putting it all together
+
+
+The complete example can be seen in the source tree at
+@code{gcc/jit/docs/examples/tut04-toyvm/toyvm.c}
+
+along with a Makefile and a couple of sample .toy scripts:
+
+@example
+$ ls -al
+drwxrwxr-x. 2 david david 4096 Sep 19 17:46 .
+drwxrwxr-x. 3 david david 4096 Sep 19 15:26 ..
+-rw-rw-r--. 1 david david 615 Sep 19 12:43 factorial.toy
+-rw-rw-r--. 1 david david 834 Sep 19 13:08 fibonacci.toy
+-rw-rw-r--. 1 david david 238 Sep 19 14:22 Makefile
+-rw-rw-r--. 1 david david 16457 Sep 19 17:07 toyvm.c
+
+$ make toyvm
+g++ -Wall -g -o toyvm toyvm.c -lgccjit
+
+$ ./toyvm factorial.toy 10
+interpreter result: 3628800
+compiler result: 3628800
+
+$ ./toyvm fibonacci.toy 10
+interpreter result: 55
+compiler result: 55
+@end example
+
+@noindent
+
+@node Behind the curtain How does our code get optimized?,,Putting it all together,Tutorial part 4 Adding JIT-compilation to a toy interpreter
+@anchor{intro/tutorial04 behind-the-curtain-how-does-our-code-get-optimized}@anchor{42}
+@subsection Behind the curtain: How does our code get optimized?
+
+
+Our example is done, but you may be wondering about exactly how the
+compiler turned what we gave it into the machine code seen above.
+
+We can examine what the compiler is doing in detail by setting:
+
+@example
+gcc_jit_context_set_bool_option (state.ctxt,
+ GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING,
+ 1);
+gcc_jit_context_set_bool_option (state.ctxt,
+ GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES,
+ 1);
+@end example
+
+@noindent
+
+This will dump detailed information about the compiler's state to a
+directory under @code{/tmp}, and keep it from being cleaned up.
+
+The precise names and their formats of these files is subject to change.
+Higher optimization levels lead to more files.
+Here's what I saw (edited for brevity; there were almost 200 files):
+
+@example
+intermediate files written to /tmp/libgccjit-KPQbGw
+$ ls /tmp/libgccjit-KPQbGw/
+fake.c.000i.cgraph
+fake.c.000i.type-inheritance
+fake.c.004t.gimple
+fake.c.007t.omplower
+fake.c.008t.lower
+fake.c.011t.eh
+fake.c.012t.cfg
+fake.c.014i.visibility
+fake.c.015i.early_local_cleanups
+fake.c.016t.ssa
+# etc
+@end example
+
+@noindent
+
+The gimple code is converted into Static Single Assignment form,
+with annotations for use when generating the debuginfo:
+
+@example
+$ less /tmp/libgccjit-KPQbGw/fake.c.016t.ssa
+@end example
+
+@noindent
+
+@example
+;; Function factorial (factorial, funcdef_no=0, decl_uid=53, symbol_order=0)
+
+factorial (signed int arg)
+@{
+ signed int stack[8];
+ signed int stack_depth;
+ signed int x;
+ signed int y;
+ <unnamed type> _20;
+ signed int _21;
+ signed int _38;
+ signed int _44;
+ signed int _51;
+ signed int _56;
+
+initial:
+ stack_depth_3 = 0;
+ # DEBUG stack_depth => stack_depth_3
+ stack[stack_depth_3] = arg_5(D);
+ stack_depth_7 = stack_depth_3 + 1;
+ # DEBUG stack_depth => stack_depth_7
+ # DEBUG instr0 => NULL
+ # DEBUG /* DUP */ => NULL
+ stack_depth_8 = stack_depth_7 + -1;
+ # DEBUG stack_depth => stack_depth_8
+ x_9 = stack[stack_depth_8];
+ # DEBUG x => x_9
+ stack[stack_depth_8] = x_9;
+ stack_depth_11 = stack_depth_8 + 1;
+ # DEBUG stack_depth => stack_depth_11
+ stack[stack_depth_11] = x_9;
+ stack_depth_13 = stack_depth_11 + 1;
+ # DEBUG stack_depth => stack_depth_13
+ # DEBUG instr1 => NULL
+ # DEBUG /* PUSH_CONST */ => NULL
+ stack[stack_depth_13] = 2;
+
+ /* etc; edited for brevity */
+@end example
+
+@noindent
+
+We can perhaps better see the code by turning off
+@pxref{3f,,GCC_JIT_BOOL_OPTION_DEBUGINFO} to suppress all those @code{DEBUG}
+statements, giving:
+
+@example
+$ less /tmp/libgccjit-1Hywc0/fake.c.016t.ssa
+@end example
+
+@noindent
+
+@example
+;; Function factorial (factorial, funcdef_no=0, decl_uid=53, symbol_order=0)
+
+factorial (signed int arg)
+@{
+ signed int stack[8];
+ signed int stack_depth;
+ signed int x;
+ signed int y;
+ <unnamed type> _20;
+ signed int _21;
+ signed int _38;
+ signed int _44;
+ signed int _51;
+ signed int _56;
+
+initial:
+ stack_depth_3 = 0;
+ stack[stack_depth_3] = arg_5(D);
+ stack_depth_7 = stack_depth_3 + 1;
+ stack_depth_8 = stack_depth_7 + -1;
+ x_9 = stack[stack_depth_8];
+ stack[stack_depth_8] = x_9;
+ stack_depth_11 = stack_depth_8 + 1;
+ stack[stack_depth_11] = x_9;
+ stack_depth_13 = stack_depth_11 + 1;
+ stack[stack_depth_13] = 2;
+ stack_depth_15 = stack_depth_13 + 1;
+ stack_depth_16 = stack_depth_15 + -1;
+ y_17 = stack[stack_depth_16];
+ stack_depth_18 = stack_depth_16 + -1;
+ x_19 = stack[stack_depth_18];
+ _20 = x_19 < y_17;
+ _21 = (signed int) _20;
+ stack[stack_depth_18] = _21;
+ stack_depth_23 = stack_depth_18 + 1;
+ stack_depth_24 = stack_depth_23 + -1;
+ x_25 = stack[stack_depth_24];
+ if (x_25 != 0)
+ goto <bb 4> (instr9);
+ else
+ goto <bb 3> (instr4);
+
+instr4:
+/* DUP */:
+ stack_depth_26 = stack_depth_24 + -1;
+ x_27 = stack[stack_depth_26];
+ stack[stack_depth_26] = x_27;
+ stack_depth_29 = stack_depth_26 + 1;
+ stack[stack_depth_29] = x_27;
+ stack_depth_31 = stack_depth_29 + 1;
+ stack[stack_depth_31] = 1;
+ stack_depth_33 = stack_depth_31 + 1;
+ stack_depth_34 = stack_depth_33 + -1;
+ y_35 = stack[stack_depth_34];
+ stack_depth_36 = stack_depth_34 + -1;
+ x_37 = stack[stack_depth_36];
+ _38 = x_37 - y_35;
+ stack[stack_depth_36] = _38;
+ stack_depth_40 = stack_depth_36 + 1;
+ stack_depth_41 = stack_depth_40 + -1;
+ x_42 = stack[stack_depth_41];
+ _44 = factorial (x_42);
+ stack[stack_depth_41] = _44;
+ stack_depth_46 = stack_depth_41 + 1;
+ stack_depth_47 = stack_depth_46 + -1;
+ y_48 = stack[stack_depth_47];
+ stack_depth_49 = stack_depth_47 + -1;
+ x_50 = stack[stack_depth_49];
+ _51 = x_50 * y_48;
+ stack[stack_depth_49] = _51;
+ stack_depth_53 = stack_depth_49 + 1;
+
+ # stack_depth_1 = PHI <stack_depth_24(2), stack_depth_53(3)>
+instr9:
+/* RETURN */:
+ stack_depth_54 = stack_depth_1 + -1;
+ x_55 = stack[stack_depth_54];
+ _56 = x_55;
+ stack =@{v@} @{CLOBBER@};
+ return _56;
+
+@}
+@end example
+
+@noindent
+
+Note in the above how all the @pxref{26,,gcc_jit_block} instances we
+created have been consolidated into just 3 blocks in GCC's internal
+representation: @code{initial}, @code{instr4} and @code{instr9}.
+
+@menu
+* Optimizing away stack manipulation::
+* Elimination of tail recursion::
+
+@end menu
+
+@node Optimizing away stack manipulation,Elimination of tail recursion,,Behind the curtain How does our code get optimized?
+@anchor{intro/tutorial04 optimizing-away-stack-manipulation}@anchor{43}
+@subsubsection Optimizing away stack manipulation
+
+
+Recall our simple implementation of stack operations. Let's examine
+how the stack operations are optimized away.
+
+After a pass of constant-propagation, the depth of the stack at each
+opcode can be determined at compile-time:
+
+@example
+$ less /tmp/libgccjit-1Hywc0/fake.c.021t.ccp1
+@end example
+
+@noindent
+
+@example
+;; Function factorial (factorial, funcdef_no=0, decl_uid=53, symbol_order=0)
+
+factorial (signed int arg)
+@{
+ signed int stack[8];
+ signed int stack_depth;
+ signed int x;
+ signed int y;
+ <unnamed type> _20;
+ signed int _21;
+ signed int _38;
+ signed int _44;
+ signed int _51;
+
+initial:
+ stack[0] = arg_5(D);
+ x_9 = stack[0];
+ stack[0] = x_9;
+ stack[1] = x_9;
+ stack[2] = 2;
+ y_17 = stack[2];
+ x_19 = stack[1];
+ _20 = x_19 < y_17;
+ _21 = (signed int) _20;
+ stack[1] = _21;
+ x_25 = stack[1];
+ if (x_25 != 0)
+ goto <bb 4> (instr9);
+ else
+ goto <bb 3> (instr4);
+
+instr4:
+/* DUP */:
+ x_27 = stack[0];
+ stack[0] = x_27;
+ stack[1] = x_27;
+ stack[2] = 1;
+ y_35 = stack[2];
+ x_37 = stack[1];
+ _38 = x_37 - y_35;
+ stack[1] = _38;
+ x_42 = stack[1];
+ _44 = factorial (x_42);
+ stack[1] = _44;
+ y_48 = stack[1];
+ x_50 = stack[0];
+ _51 = x_50 * y_48;
+ stack[0] = _51;
+
+instr9:
+/* RETURN */:
+ x_55 = stack[0];
+ x_56 = x_55;
+ stack =@{v@} @{CLOBBER@};
+ return x_56;
+
+@}
+@end example
+
+@noindent
+
+Note how, in the above, all those @code{stack_depth} values are now just
+constants: we're accessing specific stack locations at each opcode.
+
+The "esra" pass ("Early Scalar Replacement of Aggregates") breaks
+out our "stack" array into individual elements:
+
+@example
+$ less /tmp/libgccjit-1Hywc0/fake.c.024t.esra
+@end example
+
+@noindent
+
+@example
+;; Function factorial (factorial, funcdef_no=0, decl_uid=53, symbol_order=0)
+
+Created a replacement for stack offset: 0, size: 32: stack$0
+Created a replacement for stack offset: 32, size: 32: stack$1
+Created a replacement for stack offset: 64, size: 32: stack$2
+
+Symbols to be put in SSA form
+@{ D.89 D.90 D.91 @}
+Incremental SSA update started at block: 0
+Number of blocks in CFG: 5
+Number of blocks to update: 4 ( 80%)
+
+
+factorial (signed int arg)
+@{
+ signed int stack$2;
+ signed int stack$1;
+ signed int stack$0;
+ signed int stack[8];
+ signed int stack_depth;
+ signed int x;
+ signed int y;
+ <unnamed type> _20;
+ signed int _21;
+ signed int _38;
+ signed int _44;
+ signed int _51;
+
+initial:
+ stack$0_45 = arg_5(D);
+ x_9 = stack$0_45;
+ stack$0_39 = x_9;
+ stack$1_32 = x_9;
+ stack$2_30 = 2;
+ y_17 = stack$2_30;
+ x_19 = stack$1_32;
+ _20 = x_19 < y_17;
+ _21 = (signed int) _20;
+ stack$1_28 = _21;
+ x_25 = stack$1_28;
+ if (x_25 != 0)
+ goto <bb 4> (instr9);
+ else
+ goto <bb 3> (instr4);
+
+instr4:
+/* DUP */:
+ x_27 = stack$0_39;
+ stack$0_22 = x_27;
+ stack$1_14 = x_27;
+ stack$2_12 = 1;
+ y_35 = stack$2_12;
+ x_37 = stack$1_14;
+ _38 = x_37 - y_35;
+ stack$1_10 = _38;
+ x_42 = stack$1_10;
+ _44 = factorial (x_42);
+ stack$1_6 = _44;
+ y_48 = stack$1_6;
+ x_50 = stack$0_22;
+ _51 = x_50 * y_48;
+ stack$0_1 = _51;
+
+ # stack$0_52 = PHI <stack$0_39(2), stack$0_1(3)>
+instr9:
+/* RETURN */:
+ x_55 = stack$0_52;
+ x_56 = x_55;
+ stack =@{v@} @{CLOBBER@};
+ return x_56;
+
+@}
+@end example
+
+@noindent
+
+Hence at this point, all those pushes and pops of the stack are now
+simply assignments to specific temporary variables.
+
+After some copy propagation, the stack manipulation has been completely
+optimized away:
+
+@example
+$ less /tmp/libgccjit-1Hywc0/fake.c.026t.copyprop1
+@end example
+
+@noindent
+
+@example
+;; Function factorial (factorial, funcdef_no=0, decl_uid=53, symbol_order=0)
+
+factorial (signed int arg)
+@{
+ signed int stack$2;
+ signed int stack$1;
+ signed int stack$0;
+ signed int stack[8];
+ signed int stack_depth;
+ signed int x;
+ signed int y;
+ <unnamed type> _20;
+ signed int _21;
+ signed int _38;
+ signed int _44;
+ signed int _51;
+
+initial:
+ stack$0_39 = arg_5(D);
+ _20 = arg_5(D) <= 1;
+ _21 = (signed int) _20;
+ if (_21 != 0)
+ goto <bb 4> (instr9);
+ else
+ goto <bb 3> (instr4);
+
+instr4:
+/* DUP */:
+ _38 = arg_5(D) + -1;
+ _44 = factorial (_38);
+ _51 = arg_5(D) * _44;
+ stack$0_1 = _51;
+
+ # stack$0_52 = PHI <arg_5(D)(2), _51(3)>
+instr9:
+/* RETURN */:
+ stack =@{v@} @{CLOBBER@};
+ return stack$0_52;
+
+@}
+@end example
+
+@noindent
+
+Later on, another pass finally eliminated @code{stack_depth} local and the
+unused parts of the @cite{stack`} array altogether:
+
+@example
+$ less /tmp/libgccjit-1Hywc0/fake.c.036t.release_ssa
+@end example
+
+@noindent
+
+@example
+;; Function factorial (factorial, funcdef_no=0, decl_uid=53, symbol_order=0)
+
+Released 44 names, 314.29%, removed 44 holes
+factorial (signed int arg)
+@{
+ signed int stack$0;
+ signed int mult_acc_1;
+ <unnamed type> _5;
+ signed int _6;
+ signed int _7;
+ signed int mul_tmp_10;
+ signed int mult_acc_11;
+ signed int mult_acc_13;
+
+ # arg_9 = PHI <arg_8(D)(0)>
+ # mult_acc_13 = PHI <1(0)>
+initial:
+
+ <bb 5>:
+ # arg_4 = PHI <arg_9(2), _7(3)>
+ # mult_acc_1 = PHI <mult_acc_13(2), mult_acc_11(3)>
+ _5 = arg_4 <= 1;
+ _6 = (signed int) _5;
+ if (_6 != 0)
+ goto <bb 4> (instr9);
+ else
+ goto <bb 3> (instr4);
+
+instr4:
+/* DUP */:
+ _7 = arg_4 + -1;
+ mult_acc_11 = mult_acc_1 * arg_4;
+ goto <bb 5>;
+
+ # stack$0_12 = PHI <arg_4(5)>
+instr9:
+/* RETURN */:
+ mul_tmp_10 = mult_acc_1 * stack$0_12;
+ return mul_tmp_10;
+
+@}
+@end example
+
+@noindent
+
+@node Elimination of tail recursion,,Optimizing away stack manipulation,Behind the curtain How does our code get optimized?
+@anchor{intro/tutorial04 elimination-of-tail-recursion}@anchor{44}
+@subsubsection Elimination of tail recursion
+
+
+Another significant optimization is the detection that the call to
+@code{factorial} is tail recursion, which can be eliminated in favor of
+an iteration:
+
+@example
+$ less /tmp/libgccjit-1Hywc0/fake.c.030t.tailr1
+@end example
+
+@noindent
+
+@example
+;; Function factorial (factorial, funcdef_no=0, decl_uid=53, symbol_order=0)
+
+
+Symbols to be put in SSA form
+@{ D.88 @}
+Incremental SSA update started at block: 0
+Number of blocks in CFG: 5
+Number of blocks to update: 4 ( 80%)
+
+
+factorial (signed int arg)
+@{
+ signed int stack$2;
+ signed int stack$1;
+ signed int stack$0;
+ signed int stack[8];
+ signed int stack_depth;
+ signed int x;
+ signed int y;
+ signed int mult_acc_1;
+ <unnamed type> _20;
+ signed int _21;
+ signed int _38;
+ signed int mul_tmp_44;
+ signed int mult_acc_51;
+
+ # arg_5 = PHI <arg_39(D)(0), _38(3)>
+ # mult_acc_1 = PHI <1(0), mult_acc_51(3)>
+initial:
+ _20 = arg_5 <= 1;
+ _21 = (signed int) _20;
+ if (_21 != 0)
+ goto <bb 4> (instr9);
+ else
+ goto <bb 3> (instr4);
+
+instr4:
+/* DUP */:
+ _38 = arg_5 + -1;
+ mult_acc_51 = mult_acc_1 * arg_5;
+ goto <bb 2> (initial);
+
+ # stack$0_52 = PHI <arg_5(2)>
+instr9:
+/* RETURN */:
+ stack =@{v@} @{CLOBBER@};
+ mul_tmp_44 = mult_acc_1 * stack$0_52;
+ return mul_tmp_44;
+
+@}
+@end example
+
+@noindent
+
+@c Copyright (C) 2014 Free Software Foundation, Inc.
+@c Originally contributed by David Malcolm <dmalcolm@redhat.com>
+@c
+@c This is free software: you can redistribute it and/or modify it
+@c under the terms of the GNU General Public License as published by
+@c the Free Software Foundation, either version 3 of the License, or
+@c (at your option) any later version.
+@c
+@c This program is distributed in the hope that it will be useful, but
+@c WITHOUT ANY WARRANTY; without even the implied warranty of
+@c MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+@c General Public License for more details.
+@c
+@c You should have received a copy of the GNU General Public License
+@c along with this program. If not, see
+@c <http://www.gnu.org/licenses/>.
+
+@node Topic Reference,Internals,Tutorial,Top
+@anchor{topics/index doc}@anchor{45}@anchor{topics/index topic-reference}@anchor{46}
+@chapter Topic Reference
+
+
+@c Copyright (C) 2014 Free Software Foundation, Inc.
+@c Originally contributed by David Malcolm <dmalcolm@redhat.com>
+@c
+@c This is free software: you can redistribute it and/or modify it
+@c under the terms of the GNU General Public License as published by
+@c the Free Software Foundation, either version 3 of the License, or
+@c (at your option) any later version.
+@c
+@c This program is distributed in the hope that it will be useful, but
+@c WITHOUT ANY WARRANTY; without even the implied warranty of
+@c MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+@c General Public License for more details.
+@c
+@c You should have received a copy of the GNU General Public License
+@c along with this program. If not, see
+@c <http://www.gnu.org/licenses/>.
+
+@menu
+* Compilation contexts::
+* Objects::
+* Types::
+* Expressions::
+* Creating and using functions::
+* Source Locations::
+* Compilation results::
+
+Compilation contexts
+
+* Lifetime-management::
+* Thread-safety::
+* Error-handling::
+* Debugging::
+* Options: Options<2>.
+
+Options
+
+* String Options::
+* Boolean options::
+* Integer options::
+
+Types
+
+* Standard types::
+* Pointers@comma{} const@comma{} and volatile: Pointers const and volatile.
+* Structures and unions::
+
+Expressions
+
+* Rvalues::
+* Lvalues::
+* Working with pointers@comma{} structs and unions: Working with pointers structs and unions.
+
+Rvalues
+
+* Simple expressions::
+* Unary Operations::
+* Binary Operations::
+* Comparisons::
+* Function calls::
+* Type-coercion::
+
+Lvalues
+
+* Global variables::
+
+Creating and using functions
+
+* Params::
+* Functions::
+* Blocks::
+* Statements::
+
+Source Locations
+
+* Faking it::
+
+@end menu
+
+
+@node Compilation contexts,Objects,,Topic Reference
+@anchor{topics/contexts compilation-contexts}@anchor{47}@anchor{topics/contexts doc}@anchor{48}
+@section Compilation contexts
+
+
+@geindex gcc_jit_context (C type)
+@anchor{topics/contexts gcc_jit_context}@anchor{8}
+@deffn {C Type} gcc_jit_context
+@end deffn
+
+The top-level of the API is the @pxref{8,,gcc_jit_context} type.
+
+A @pxref{8,,gcc_jit_context} instance encapsulates the state of a
+compilation.
+
+You can set up options on it, and add types, functions and code.
+Invoking @pxref{15,,gcc_jit_context_compile()} on it gives you a
+@pxref{16,,gcc_jit_result}.
+
+@menu
+* Lifetime-management::
+* Thread-safety::
+* Error-handling::
+* Debugging::
+* Options: Options<2>.
+
+@end menu
+
+@node Lifetime-management,Thread-safety,,Compilation contexts
+@anchor{topics/contexts lifetime-management}@anchor{49}
+@subsection Lifetime-management
+
+
+Contexts are the unit of lifetime-management within the API: objects
+have their lifetime bounded by the context they are created within, and
+cleanup of such objects is done for you when the context is released.
+
+@geindex gcc_jit_context_acquire (C function)
+@anchor{topics/contexts gcc_jit_context_acquire}@anchor{9}
+@deffn {C Function} gcc_jit_context *gcc_jit_context_acquire (void)
+
+This function acquires a new @pxref{e,,gcc_jit_object *} instance,
+which is independent of any others that may be present within this
+process.
+@end deffn
+
+@geindex gcc_jit_context_release (C function)
+@anchor{topics/contexts gcc_jit_context_release}@anchor{c}
+@deffn {C Function} void gcc_jit_context_release (gcc_jit_context@w{ }*ctxt)
+
+This function releases all resources associated with the given context.
+Both the context itself and all of its @pxref{e,,gcc_jit_object *}
+instances are cleaned up. It should be called exactly once on a given
+context.
+
+It is invalid to use the context or any of its "contextual" objects
+after calling this.
+
+@example
+gcc_jit_context_release (ctxt);
+@end example
+
+@noindent
+@end deffn
+
+@geindex gcc_jit_context_new_child_context (C function)
+@anchor{topics/contexts gcc_jit_context_new_child_context}@anchor{4a}
+@deffn {C Function} gcc_jit_context * gcc_jit_context_new_child_context (gcc_jit_context@w{ }*parent_ctxt)
+
+Given an existing JIT context, create a child context.
+
+The child inherits a copy of all option-settings from the parent.
+
+The child can reference objects created within the parent, but not
+vice-versa.
+
+The lifetime of the child context must be bounded by that of the
+parent: you should release a child context before releasing the parent
+context.
+
+If you use a function from a parent context within a child context,
+you have to compile the parent context before you can compile the
+child context, and the gcc_jit_result of the parent context must
+outlive the gcc_jit_result of the child context.
+
+This allows caching of shared initializations. For example, you could
+create types and declarations of global functions in a parent context
+once within a process, and then create child contexts whenever a
+function or loop becomes hot. Each such child context can be used for
+JIT-compiling just one function or loop, but can reference types
+and helper functions created within the parent context.
+
+Contexts can be arbitrarily nested, provided the above rules are
+followed, but it's probably not worth going above 2 or 3 levels, and
+there will likely be a performance hit for such nesting.
+@end deffn
+
+@node Thread-safety,Error-handling,Lifetime-management,Compilation contexts
+@anchor{topics/contexts thread-safety}@anchor{4b}
+@subsection Thread-safety
+
+
+Instances of @pxref{e,,gcc_jit_object *} created via
+@pxref{9,,gcc_jit_context_acquire()} are independent from each other:
+only one thread may use a given context at once, but multiple threads
+could each have their own contexts without needing locks.
+
+Contexts created via @pxref{4a,,gcc_jit_context_new_child_context()} are
+related to their parent context. They can be partitioned by their
+ultimate ancestor into independent "family trees". Only one thread
+within a process may use a given "family tree" of such contexts at once,
+and if you're using multiple threads you should provide your own locking
+around entire such context partitions.
+
+@node Error-handling,Debugging,Thread-safety,Compilation contexts
+@anchor{topics/contexts error-handling}@anchor{4c}
+@subsection Error-handling
+
+
+You can only compile and get code from a context if no errors occur.
+
+In general, if an error occurs when using an API entrypoint, it returns
+NULL. You don't have to check everywhere for NULL results, since the
+API gracefully handles a NULL being passed in for any argument.
+
+Errors are printed on stderr and can be queried using
+@pxref{4d,,gcc_jit_context_get_first_error()}.
+
+@geindex gcc_jit_context_get_first_error (C function)
+@anchor{topics/contexts gcc_jit_context_get_first_error}@anchor{4d}
+@deffn {C Function} const char * gcc_jit_context_get_first_error (gcc_jit_context@w{ }*ctxt)
+
+Returns the first error message that occurred on the context.
+
+The returned string is valid for the rest of the lifetime of the
+context.
+
+If no errors occurred, this will be NULL.
+@end deffn
+
+@node Debugging,Options<2>,Error-handling,Compilation contexts
+@anchor{topics/contexts debugging}@anchor{4e}
+@subsection Debugging
+
+
+@geindex gcc_jit_context_dump_to_file (C function)
+@anchor{topics/contexts gcc_jit_context_dump_to_file}@anchor{4f}
+@deffn {C Function} void gcc_jit_context_dump_to_file (gcc_jit_context@w{ }*ctxt, const char@w{ }*path, int@w{ }update_locations)
+
+To help with debugging: dump a C-like representation to the given path,
+describing what's been set up on the context.
+
+If "update_locations" is true, then also set up @pxref{38,,gcc_jit_location}
+information throughout the context, pointing at the dump file as if it
+were a source file. This may be of use in conjunction with
+@pxref{3f,,GCC_JIT_BOOL_OPTION_DEBUGINFO} to allow stepping through the
+code in a debugger.
+@end deffn
+
+@node Options<2>,,Debugging,Compilation contexts
+@anchor{topics/contexts options}@anchor{50}
+@subsection Options
+
+
+@menu
+* String Options::
+* Boolean options::
+* Integer options::
+
+@end menu
+
+@node String Options,Boolean options,,Options<2>
+@anchor{topics/contexts string-options}@anchor{51}
+@subsubsection String Options
+
+
+@geindex gcc_jit_context_set_str_option (C function)
+@anchor{topics/contexts gcc_jit_context_set_str_option}@anchor{52}
+@deffn {C Function} void gcc_jit_context_set_str_option (gcc_jit_context@w{ }*ctxt, enum gcc_jit_str_option@w{ }opt, const char@w{ }*value)
+
+Set a string option of the context.
+
+@geindex gcc_jit_str_option (C type)
+@anchor{topics/contexts gcc_jit_str_option}@anchor{53}
+@deffn {C Type} enum gcc_jit_str_option
+@end deffn
+
+There is currently just one string option:
+
+@geindex GCC_JIT_STR_OPTION_PROGNAME (C macro)
+@anchor{topics/contexts GCC_JIT_STR_OPTION_PROGNAME}@anchor{54}
+@deffn {C Macro} GCC_JIT_STR_OPTION_PROGNAME
+
+The name of the program, for use as a prefix when printing error
+messages to stderr. If @cite{NULL}, or default, "libgccjit.so" is used.
+@end deffn
+@end deffn
+
+@node Boolean options,Integer options,String Options,Options<2>
+@anchor{topics/contexts boolean-options}@anchor{55}
+@subsubsection Boolean options
+
+
+@geindex gcc_jit_context_set_bool_option (C function)
+@anchor{topics/contexts gcc_jit_context_set_bool_option}@anchor{19}
+@deffn {C Function} void gcc_jit_context_set_bool_option (gcc_jit_context@w{ }*ctxt, enum gcc_jit_bool_option@w{ }opt, int@w{ }value)
+
+Set a boolean option of the context.
+Zero is "false" (the default), non-zero is "true".
+
+@geindex gcc_jit_bool_option (C type)
+@anchor{topics/contexts gcc_jit_bool_option}@anchor{56}
+@deffn {C Type} enum gcc_jit_bool_option
+@end deffn
+
+@geindex GCC_JIT_BOOL_OPTION_DEBUGINFO (C macro)
+@anchor{topics/contexts GCC_JIT_BOOL_OPTION_DEBUGINFO}@anchor{3f}
+@deffn {C Macro} GCC_JIT_BOOL_OPTION_DEBUGINFO
+
+If true, @pxref{15,,gcc_jit_context_compile()} will attempt to do the right
+thing so that if you attach a debugger to the process, it will
+be able to inspect variables and step through your code.
+
+Note that you can't step through code unless you set up source
+location information for the code (by creating and passing in
+@pxref{38,,gcc_jit_location} instances).
+@end deffn
+
+@geindex GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE (C macro)
+@anchor{topics/contexts GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE}@anchor{57}
+@deffn {C Macro} GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE
+
+If true, @pxref{15,,gcc_jit_context_compile()} will dump its initial
+"tree" representation of your code to stderr (before any
+optimizations).
+
+Here's some sample output (from the @cite{square} example):
+
+@example
+<statement_list 0x7f4875a62cc0
+ type <void_type 0x7f4875a64bd0 VOID
+ align 8 symtab 0 alias set -1 canonical type 0x7f4875a64bd0
+ pointer_to_this <pointer_type 0x7f4875a64c78>>
+ side-effects head 0x7f4875a761e0 tail 0x7f4875a761f8 stmts 0x7f4875a62d20 0x7f4875a62d00
+
+ stmt <label_expr 0x7f4875a62d20 type <void_type 0x7f4875a64bd0>
+ side-effects
+ arg 0 <label_decl 0x7f4875a79080 entry type <void_type 0x7f4875a64bd0>
+ VOID file (null) line 0 col 0
+ align 1 context <function_decl 0x7f4875a77500 square>>>
+ stmt <return_expr 0x7f4875a62d00
+ type <integer_type 0x7f4875a645e8 public SI
+ size <integer_cst 0x7f4875a623a0 constant 32>
+ unit size <integer_cst 0x7f4875a623c0 constant 4>
+ align 32 symtab 0 alias set -1 canonical type 0x7f4875a645e8 precision 32 min <integer_cst 0x7f4875a62340 -2147483648> max <integer_cst 0x7f4875a62360 2147483647>
+ pointer_to_this <pointer_type 0x7f4875a6b348>>
+ side-effects
+ arg 0 <modify_expr 0x7f4875a72a78 type <integer_type 0x7f4875a645e8>
+ side-effects arg 0 <result_decl 0x7f4875a7a000 D.54>
+ arg 1 <mult_expr 0x7f4875a72a50 type <integer_type 0x7f4875a645e8>
+ arg 0 <parm_decl 0x7f4875a79000 i> arg 1 <parm_decl 0x7f4875a79000 i>>>>>
+@end example
+
+@noindent
+@end deffn
+
+@geindex GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE (C macro)
+@anchor{topics/contexts GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE}@anchor{1a}
+@deffn {C Macro} GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE
+
+If true, @pxref{15,,gcc_jit_context_compile()} will dump the "gimple"
+representation of your code to stderr, before any optimizations
+are performed. The dump resembles C code:
+
+@example
+square (signed int i)
+@{
+ signed int D.56;
+
+ entry:
+ D.56 = i * i;
+ return D.56;
+@}
+@end example
+
+@noindent
+@end deffn
+
+@geindex GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE (C macro)
+@anchor{topics/contexts GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE}@anchor{1b}
+@deffn {C Macro} GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE
+
+If true, @pxref{15,,gcc_jit_context_compile()} will dump the final
+generated code to stderr, in the form of assembly language:
+
+@example
+ .file "fake.c"
+ .text
+ .globl square
+ .type square, @@function
+square:
+.LFB0:
+ .cfi_startproc
+ pushq %rbp
+ .cfi_def_cfa_offset 16
+ .cfi_offset 6, -16
+ movq %rsp, %rbp
+ .cfi_def_cfa_register 6
+ movl %edi, -4(%rbp)
+.L2:
+ movl -4(%rbp), %eax
+ imull -4(%rbp), %eax
+ popq %rbp
+ .cfi_def_cfa 7, 8
+ ret
+ .cfi_endproc
+.LFE0:
+ .size square, .-square
+ .ident "GCC: (GNU) 4.9.0 20131023 (Red Hat 0.1-%@{gcc_release@})"
+ .section .note.GNU-stack,"",@@progbits
+@end example
+
+@noindent
+@end deffn
+
+@geindex GCC_JIT_BOOL_OPTION_DUMP_SUMMARY (C macro)
+@anchor{topics/contexts GCC_JIT_BOOL_OPTION_DUMP_SUMMARY}@anchor{58}
+@deffn {C Macro} GCC_JIT_BOOL_OPTION_DUMP_SUMMARY
+
+If true, @pxref{15,,gcc_jit_context_compile()} will print information to stderr
+on the actions it is performing, followed by a profile showing
+the time taken and memory usage of each phase.
+@end deffn
+
+@geindex GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING (C macro)
+@anchor{topics/contexts GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING}@anchor{59}
+@deffn {C Macro} GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING
+
+If true, @pxref{15,,gcc_jit_context_compile()} will dump copious
+amount of information on what it's doing to various
+files within a temporary directory. Use
+@pxref{5a,,GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES} (see below) to
+see the results. The files are intended to be human-readable,
+but the exact files and their formats are subject to change.
+@end deffn
+
+@geindex GCC_JIT_BOOL_OPTION_SELFCHECK_GC (C macro)
+@anchor{topics/contexts GCC_JIT_BOOL_OPTION_SELFCHECK_GC}@anchor{5b}
+@deffn {C Macro} GCC_JIT_BOOL_OPTION_SELFCHECK_GC
+
+If true, libgccjit will aggressively run its garbage collector, to
+shake out bugs (greatly slowing down the compile). This is likely
+to only be of interest to developers @emph{of} the library. It is
+used when running the selftest suite.
+@end deffn
+
+@geindex GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES (C macro)
+@anchor{topics/contexts GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES}@anchor{5a}
+@deffn {C Macro} GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES
+
+If true, the @pxref{8,,gcc_jit_context} will not clean up intermediate files
+written to the filesystem, and will display their location on stderr.
+@end deffn
+@end deffn
+
+@node Integer options,,Boolean options,Options<2>
+@anchor{topics/contexts integer-options}@anchor{5c}
+@subsubsection Integer options
+
+
+@geindex gcc_jit_context_set_int_option (C function)
+@anchor{topics/contexts gcc_jit_context_set_int_option}@anchor{1c}
+@deffn {C Function} void gcc_jit_context_set_int_option (gcc_jit_context@w{ }*ctxt, enum gcc_jit_int_option@w{ }opt, int@w{ }value)
+
+Set an integer option of the context.
+
+@geindex gcc_jit_int_option (C type)
+@anchor{topics/contexts gcc_jit_int_option}@anchor{5d}
+@deffn {C Type} enum gcc_jit_int_option
+@end deffn
+
+There is currently just one integer option:
+
+@geindex GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL (C macro)
+@anchor{topics/contexts GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL}@anchor{1d}
+@deffn {C Macro} GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL
+
+How much to optimize the code.
+
+Valid values are 0-3, corresponding to GCC's command-line options
+-O0 through -O3.
+
+The default value is 0 (unoptimized).
+@end deffn
+@end deffn
+
+@c Copyright (C) 2014 Free Software Foundation, Inc.
+@c Originally contributed by David Malcolm <dmalcolm@redhat.com>
+@c
+@c This is free software: you can redistribute it and/or modify it
+@c under the terms of the GNU General Public License as published by
+@c the Free Software Foundation, either version 3 of the License, or
+@c (at your option) any later version.
+@c
+@c This program is distributed in the hope that it will be useful, but
+@c WITHOUT ANY WARRANTY; without even the implied warranty of
+@c MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+@c General Public License for more details.
+@c
+@c You should have received a copy of the GNU General Public License
+@c along with this program. If not, see
+@c <http://www.gnu.org/licenses/>.
+
+@node Objects,Types,Compilation contexts,Topic Reference
+@anchor{topics/objects objects}@anchor{5e}@anchor{topics/objects doc}@anchor{5f}
+@section Objects
+
+
+@geindex gcc_jit_object (C type)
+@anchor{topics/objects gcc_jit_object}@anchor{e}
+@deffn {C Type} gcc_jit_object
+@end deffn
+
+Almost every entity in the API (with the exception of
+@pxref{8,,gcc_jit_context *} and @pxref{16,,gcc_jit_result *}) is a
+"contextual" object, a @pxref{e,,gcc_jit_object *}
+
+A JIT object:
+
+@quotation
+
+
+@itemize *
+
+@item
+is associated with a @pxref{8,,gcc_jit_context *}.
+
+@item
+is automatically cleaned up for you when its context is released so
+you don't need to manually track and cleanup all objects, just the
+contexts.
+@end itemize
+@end quotation
+
+Although the API is C-based, there is a form of class hierarchy, which
+looks like this:
+
+@example
++- gcc_jit_object
+ +- gcc_jit_location
+ +- gcc_jit_type
+ +- gcc_jit_struct
+ +- gcc_jit_field
+ +- gcc_jit_function
+ +- gcc_jit_block
+ +- gcc_jit_rvalue
+ +- gcc_jit_lvalue
+ +- gcc_jit_param
+@end example
+
+@noindent
+
+There are casting methods for upcasting from subclasses to parent classes.
+For example, @pxref{d,,gcc_jit_type_as_object()}:
+
+@example
+gcc_jit_object *obj = gcc_jit_type_as_object (int_type);
+@end example
+
+@noindent
+
+The object "base class" has the following operations:
+
+@geindex gcc_jit_object_get_context (C function)
+@anchor{topics/objects gcc_jit_object_get_context}@anchor{60}
+@deffn {C Function} gcc_jit_context *gcc_jit_object_get_context (gcc_jit_object@w{ }*obj)
+
+Which context is "obj" within?
+@end deffn
+
+@geindex gcc_jit_object_get_debug_string (C function)
+@anchor{topics/objects gcc_jit_object_get_debug_string}@anchor{f}
+@deffn {C Function} const char *gcc_jit_object_get_debug_string (gcc_jit_object@w{ }*obj)
+
+Generate a human-readable description for the given object.
+
+For example,
+
+@example
+printf ("obj: %s\n", gcc_jit_object_get_debug_string (obj));
+@end example
+
+@noindent
+
+might give this text on stdout:
+
+@example
+obj: 4.0 * (float)i
+@end example
+
+@noindent
+
+@cartouche
+@quotation Note
+If you call this on an object, the @cite{const char *} buffer is allocated
+and generated on the first call for that object, and the buffer will
+have the same lifetime as the object i.e. it will exist until the
+object's context is released.
+@end quotation
+@end cartouche
+@end deffn
+
+@c Copyright (C) 2014 Free Software Foundation, Inc.
+@c Originally contributed by David Malcolm <dmalcolm@redhat.com>
+@c
+@c This is free software: you can redistribute it and/or modify it
+@c under the terms of the GNU General Public License as published by
+@c the Free Software Foundation, either version 3 of the License, or
+@c (at your option) any later version.
+@c
+@c This program is distributed in the hope that it will be useful, but
+@c WITHOUT ANY WARRANTY; without even the implied warranty of
+@c MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+@c General Public License for more details.
+@c
+@c You should have received a copy of the GNU General Public License
+@c along with this program. If not, see
+@c <http://www.gnu.org/licenses/>.
+
+@node Types,Expressions,Objects,Topic Reference
+@anchor{topics/types doc}@anchor{61}@anchor{topics/types types}@anchor{62}
+@section Types
+
+
+@geindex gcc_jit_type (C type)
+@anchor{topics/types gcc_jit_type}@anchor{a}
+@deffn {C Type} gcc_jit_type
+
+gcc_jit_type represents a type within the library.
+@end deffn
+
+@geindex gcc_jit_type_as_object (C function)
+@anchor{topics/types gcc_jit_type_as_object}@anchor{d}
+@deffn {C Function} gcc_jit_object *gcc_jit_type_as_object (gcc_jit_type@w{ }*type)
+
+Upcast a type to an object.
+@end deffn
+
+Types can be created in several ways:
+
+
+@itemize *
+
+@item
+fundamental types can be accessed using
+@pxref{b,,gcc_jit_context_get_type()}:
+
+@example
+gcc_jit_type *int_type = gcc_jit_context_get_type (GCC_JIT_TYPE_INT);
+@end example
+
+@noindent
+
+See @pxref{b,,gcc_jit_context_get_type()} for the available types.
+
+@item
+derived types can be accessed by using functions such as
+@pxref{63,,gcc_jit_type_get_pointer()} and @pxref{64,,gcc_jit_type_get_const()}:
+
+@example
+gcc_jit_type *const_int_star = gcc_jit_type_get_pointer (gcc_jit_type_get_const (int_type));
+gcc_jit_type *int_const_star = gcc_jit_type_get_const (gcc_jit_type_get_pointer (int_type));
+@end example
+
+@noindent
+
+@item
+by creating structures (see below).
+@end itemize
+
+@menu
+* Standard types::
+* Pointers@comma{} const@comma{} and volatile: Pointers const and volatile.
+* Structures and unions::
+
+@end menu
+
+@node Standard types,Pointers const and volatile,,Types
+@anchor{topics/types standard-types}@anchor{65}
+@subsection Standard types
+
+
+@geindex gcc_jit_context_get_type (C function)
+@anchor{topics/types gcc_jit_context_get_type}@anchor{b}
+@deffn {C Function} gcc_jit_type *gcc_jit_context_get_type (gcc_jit_context@w{ }*ctxt, enum gcc_jit_types@w{ }type_)
+
+Access a specific type. The available types are:
+
+
+@multitable {xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx} {xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}
+@headitem
+
+@cite{enum gcc_jit_types} value
+
+@tab
+
+Meaning
+
+@item
+
+@code{GCC_JIT_TYPE_VOID}
+
+@tab
+
+C's @code{void} type.
+
+@item
+
+@code{GCC_JIT_TYPE_VOID_PTR}
+
+@tab
+
+C's @code{void *}.
+
+@item
+
+@code{GCC_JIT_TYPE_BOOL}
+
+@tab
+
+C++'s @code{bool} type; also C99's
+@code{_Bool} type, aka @code{bool} if
+using stdbool.h.
+
+@item
+
+@code{GCC_JIT_TYPE_CHAR}
+
+@tab
+
+C's @code{char} (of some signedness)
+
+@item
+
+@code{GCC_JIT_TYPE_SIGNED_CHAR}
+
+@tab
+
+C's @code{signed char}
+
+@item
+
+@code{GCC_JIT_TYPE_UNSIGNED_CHAR}
+
+@tab
+
+C's @code{unsigned char}
+
+@item
+
+@code{GCC_JIT_TYPE_SHORT}
+
+@tab
+
+C's @code{short} (signed)
+
+@item
+
+@code{GCC_JIT_TYPE_UNSIGNED_SHORT}
+
+@tab
+
+C's @code{unsigned short}
+
+@item
+
+@code{GCC_JIT_TYPE_INT}
+
+@tab
+
+C's @code{int} (signed)
+
+@item
+
+@code{GCC_JIT_TYPE_UNSIGNED_INT}
+
+@tab
+
+C's @code{unsigned int}
+
+@item
+
+@code{GCC_JIT_TYPE_LONG}
+
+@tab
+
+C's @code{long} (signed)
+
+@item
+
+@code{GCC_JIT_TYPE_UNSIGNED_LONG}
+
+@tab
+
+C's @code{unsigned long}
+
+@item
+
+@code{GCC_JIT_TYPE_LONG_LONG}
+
+@tab
+
+C99's @code{long long} (signed)
+
+@item
+
+@code{GCC_JIT_TYPE_UNSIGNED_LONG_LONG}
+
+@tab
+
+C99's @code{unsigned long long}
+
+@item
+
+@code{GCC_JIT_TYPE_FLOAT}
+
+@tab
+
+@item
+
+@code{GCC_JIT_TYPE_DOUBLE}
+
+@tab
+
+@item
+
+@code{GCC_JIT_TYPE_LONG_DOUBLE}
+
+@tab
+
+@item
+
+@code{GCC_JIT_TYPE_CONST_CHAR_PTR}
+
+@tab
+
+C type: @code{(const char *)}
+
+@item
+
+@code{GCC_JIT_TYPE_SIZE_T}
+
+@tab
+
+C's @code{size_t} type
+
+@item
+
+@code{GCC_JIT_TYPE_FILE_PTR}
+
+@tab
+
+C type: @code{(FILE *)}
+
+@end multitable
+
+@end deffn
+
+@geindex gcc_jit_context_get_int_type (C function)
+@anchor{topics/types gcc_jit_context_get_int_type}@anchor{66}
+@deffn {C Function} gcc_jit_type * gcc_jit_context_get_int_type (gcc_jit_context@w{ }*ctxt, int@w{ }num_bytes, int@w{ }is_signed)
+
+Access the integer type of the given size.
+@end deffn
+
+@node Pointers const and volatile,Structures and unions,Standard types,Types
+@anchor{topics/types pointers-const-and-volatile}@anchor{67}
+@subsection Pointers, @cite{const}, and @cite{volatile}
+
+
+@geindex gcc_jit_type_get_pointer (C function)
+@anchor{topics/types gcc_jit_type_get_pointer}@anchor{63}
+@deffn {C Function} gcc_jit_type *gcc_jit_type_get_pointer (gcc_jit_type@w{ }*type)
+
+Given type "T", get type "T*".
+@end deffn
+
+@geindex gcc_jit_type_get_const (C function)
+@anchor{topics/types gcc_jit_type_get_const}@anchor{64}
+@deffn {C Function} gcc_jit_type *gcc_jit_type_get_const (gcc_jit_type@w{ }*type)
+
+Given type "T", get type "const T".
+@end deffn
+
+@geindex gcc_jit_type_get_volatile (C function)
+@anchor{topics/types gcc_jit_type_get_volatile}@anchor{68}
+@deffn {C Function} gcc_jit_type *gcc_jit_type_get_volatile (gcc_jit_type@w{ }*type)
+
+Given type "T", get type "volatile T".
+@end deffn
+
+@geindex gcc_jit_context_new_array_type (C function)
+@anchor{topics/types gcc_jit_context_new_array_type}@anchor{69}
+@deffn {C Function} gcc_jit_type * gcc_jit_context_new_array_type (gcc_jit_context@w{ }*ctxt, gcc_jit_location@w{ }*loc, gcc_jit_type@w{ }*element_type, int@w{ }num_elements)
+
+Given type "T", get type "T[N]" (for a constant N).
+@end deffn
+
+@node Structures and unions,,Pointers const and volatile,Types
+@anchor{topics/types structures-and-unions}@anchor{6a}
+@subsection Structures and unions
+
+
+@geindex gcc_jit_struct (C type)
+@anchor{topics/types gcc_jit_struct}@anchor{6b}
+@deffn {C Type} gcc_jit_struct
+@end deffn
+
+A compound type analagous to a C @cite{struct}.
+
+@geindex gcc_jit_field (C type)
+@anchor{topics/types gcc_jit_field}@anchor{6c}
+@deffn {C Type} gcc_jit_field
+@end deffn
+
+A field within a @pxref{6b,,gcc_jit_struct}.
+
+You can model C @cite{struct} types by creating @pxref{6b,,gcc_jit_struct *} and
+@pxref{6c,,gcc_jit_field} instances, in either order:
+
+
+@itemize *
+
+@item
+by creating the fields, then the structure. For example, to model:
+
+@example
+struct coord @{double x; double y; @};
+@end example
+
+@noindent
+
+you could call:
+
+@example
+gcc_jit_field *field_x =
+ gcc_jit_context_new_field (ctxt, NULL, double_type, "x");
+gcc_jit_field *field_y =
+ gcc_jit_context_new_field (ctxt, NULL, double_type, "y");
+gcc_jit_field *fields[2] = @{field_x, field_y@};
+gcc_jit_struct *coord =
+ gcc_jit_context_new_struct_type (ctxt, NULL, "coord", 2, fields);
+@end example
+
+@noindent
+
+@item
+by creating the structure, then populating it with fields, typically
+to allow modelling self-referential structs such as:
+
+@example
+struct node @{ int m_hash; struct node *m_next; @};
+@end example
+
+@noindent
+
+like this:
+
+@example
+gcc_jit_type *node =
+ gcc_jit_context_new_opaque_struct (ctxt, NULL, "node");
+gcc_jit_type *node_ptr =
+ gcc_jit_type_get_pointer (node);
+gcc_jit_field *field_hash =
+ gcc_jit_context_new_field (ctxt, NULL, int_type, "m_hash");
+gcc_jit_field *field_next =
+ gcc_jit_context_new_field (ctxt, NULL, node_ptr, "m_next");
+gcc_jit_field *fields[2] = @{field_hash, field_next@};
+gcc_jit_struct_set_fields (node, NULL, 2, fields);
+@end example
+
+@noindent
+@end itemize
+
+@geindex gcc_jit_context_new_field (C function)
+@anchor{topics/types gcc_jit_context_new_field}@anchor{6d}
+@deffn {C Function} gcc_jit_field * gcc_jit_context_new_field (gcc_jit_context@w{ }*ctxt, gcc_jit_location@w{ }*loc, gcc_jit_type@w{ }*type, const char@w{ }*name)
+
+Construct a new field, with the given type and name.
+@end deffn
+
+@geindex gcc_jit_field_as_object (C function)
+@anchor{topics/types gcc_jit_field_as_object}@anchor{6e}
+@deffn {C Function} gcc_jit_object * gcc_jit_field_as_object (gcc_jit_field@w{ }*field)
+
+Upcast from field to object.
+@end deffn
+
+@geindex gcc_jit_context_new_struct_type (C function)
+@anchor{topics/types gcc_jit_context_new_struct_type}@anchor{6f}
+@deffn {C Function} gcc_jit_struct *gcc_jit_context_new_struct_type (gcc_jit_context@w{ }*ctxt, gcc_jit_location@w{ }*loc, const char@w{ }*name, int@w{ }num_fields, gcc_jit_field@w{ }**fields)
+
+@quotation
+
+Construct a new struct type, with the given name and fields.
+@end quotation
+@end deffn
+
+@geindex gcc_jit_context_new_opaque_struct (C function)
+@anchor{topics/types gcc_jit_context_new_opaque_struct}@anchor{70}
+@deffn {C Function} gcc_jit_struct * gcc_jit_context_new_opaque_struct (gcc_jit_context@w{ }*ctxt, gcc_jit_location@w{ }*loc, const char@w{ }*name)
+
+Construct a new struct type, with the given name, but without
+specifying the fields. The fields can be omitted (in which case the
+size of the struct is not known), or later specified using
+@pxref{71,,gcc_jit_struct_set_fields()}.
+@end deffn
+
+@geindex gcc_jit_struct_as_type (C function)
+@anchor{topics/types gcc_jit_struct_as_type}@anchor{72}
+@deffn {C Function} gcc_jit_type * gcc_jit_struct_as_type (gcc_jit_struct@w{ }*struct_type)
+
+Upcast from struct to type.
+@end deffn
+
+@geindex gcc_jit_struct_set_fields (C function)
+@anchor{topics/types gcc_jit_struct_set_fields}@anchor{71}
+@deffn {C Function} void gcc_jit_struct_set_fields (gcc_jit_struct@w{ }*struct_type, gcc_jit_location@w{ }*loc, int@w{ }num_fields, gcc_jit_field@w{ }**fields)
+
+Populate the fields of a formerly-opaque struct type.
+
+This can only be called once on a given struct type.
+@end deffn
+
+@c Copyright (C) 2014 Free Software Foundation, Inc.
+@c Originally contributed by David Malcolm <dmalcolm@redhat.com>
+@c
+@c This is free software: you can redistribute it and/or modify it
+@c under the terms of the GNU General Public License as published by
+@c the Free Software Foundation, either version 3 of the License, or
+@c (at your option) any later version.
+@c
+@c This program is distributed in the hope that it will be useful, but
+@c WITHOUT ANY WARRANTY; without even the implied warranty of
+@c MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+@c General Public License for more details.
+@c
+@c You should have received a copy of the GNU General Public License
+@c along with this program. If not, see
+@c <http://www.gnu.org/licenses/>.
+
+@node Expressions,Creating and using functions,Types,Topic Reference
+@anchor{topics/expressions expressions}@anchor{73}@anchor{topics/expressions doc}@anchor{74}
+@section Expressions
+
+
+@menu
+* Rvalues::
+* Lvalues::
+* Working with pointers@comma{} structs and unions: Working with pointers structs and unions.
+
+Rvalues
+
+* Simple expressions::
+* Unary Operations::
+* Binary Operations::
+* Comparisons::
+* Function calls::
+* Type-coercion::
+
+Lvalues
+
+* Global variables::
+
+@end menu
+
+
+@node Rvalues,Lvalues,,Expressions
+@anchor{topics/expressions rvalues}@anchor{75}
+@subsection Rvalues
+
+
+@geindex gcc_jit_rvalue (C type)
+@anchor{topics/expressions gcc_jit_rvalue}@anchor{13}
+@deffn {C Type} gcc_jit_rvalue
+@end deffn
+
+A @pxref{13,,gcc_jit_rvalue *} is an expression that can be computed.
+
+It can be simple, e.g.:
+
+@quotation
+
+
+@itemize *
+
+@item
+an integer value e.g. @cite{0} or @cite{42}
+
+@item
+a string literal e.g. @cite{"Hello world"}
+
+@item
+a variable e.g. @cite{i}. These are also lvalues (see below).
+@end itemize
+@end quotation
+
+or compound e.g.:
+
+@quotation
+
+
+@itemize *
+
+@item
+a unary expression e.g. @cite{!cond}
+
+@item
+a binary expression e.g. @cite{(a + b)}
+
+@item
+a function call e.g. @cite{get_distance (&player_ship@comma{} &target)}
+
+@item
+etc.
+@end itemize
+@end quotation
+
+Every rvalue has an associated type, and the API will check to ensure
+that types match up correctly (otherwise the context will emit an error).
+
+@geindex gcc_jit_rvalue_get_type (C function)
+@anchor{topics/expressions gcc_jit_rvalue_get_type}@anchor{76}
+@deffn {C Function} gcc_jit_type *gcc_jit_rvalue_get_type (gcc_jit_rvalue@w{ }*rvalue)
+
+Get the type of this rvalue.
+@end deffn
+
+@geindex gcc_jit_rvalue_as_object (C function)
+@anchor{topics/expressions gcc_jit_rvalue_as_object}@anchor{14}
+@deffn {C Function} gcc_jit_object *gcc_jit_rvalue_as_object (gcc_jit_rvalue@w{ }*rvalue)
+
+Upcast the given rvalue to be an object.
+@end deffn
+
+@menu
+* Simple expressions::
+* Unary Operations::
+* Binary Operations::
+* Comparisons::
+* Function calls::
+* Type-coercion::
+
+@end menu
+
+@node Simple expressions,Unary Operations,,Rvalues
+@anchor{topics/expressions simple-expressions}@anchor{77}
+@subsubsection Simple expressions
+
+
+@geindex gcc_jit_context_new_rvalue_from_int (C function)
+@anchor{topics/expressions gcc_jit_context_new_rvalue_from_int}@anchor{2e}
+@deffn {C Function} gcc_jit_rvalue * gcc_jit_context_new_rvalue_from_int (gcc_jit_context@w{ }*ctxt, gcc_jit_type@w{ }*numeric_type, int@w{ }value)
+
+Given a numeric type (integer or floating point), build an rvalue for
+the given constant value.
+@end deffn
+
+@geindex gcc_jit_context_zero (C function)
+@anchor{topics/expressions gcc_jit_context_zero}@anchor{29}
+@deffn {C Function} gcc_jit_rvalue *gcc_jit_context_zero (gcc_jit_context@w{ }*ctxt, gcc_jit_type@w{ }*numeric_type)
+
+Given a numeric type (integer or floating point), get the rvalue for
+zero. Essentially this is just a shortcut for:
+
+@example
+gcc_jit_context_new_rvalue_from_int (ctxt, numeric_type, 0)
+@end example
+
+@noindent
+@end deffn
+
+@geindex gcc_jit_context_one (C function)
+@anchor{topics/expressions gcc_jit_context_one}@anchor{2d}
+@deffn {C Function} gcc_jit_rvalue *gcc_jit_context_one (gcc_jit_context@w{ }*ctxt, gcc_jit_type@w{ }*numeric_type)
+
+Given a numeric type (integer or floating point), get the rvalue for
+zero. Essentially this is just a shortcut for:
+
+@example
+gcc_jit_context_new_rvalue_from_int (ctxt, numeric_type, 1)
+@end example
+
+@noindent
+@end deffn
+
+@geindex gcc_jit_context_new_rvalue_from_double (C function)
+@anchor{topics/expressions gcc_jit_context_new_rvalue_from_double}@anchor{2f}
+@deffn {C Function} gcc_jit_rvalue * gcc_jit_context_new_rvalue_from_double (gcc_jit_context@w{ }*ctxt, gcc_jit_type@w{ }*numeric_type, double@w{ }value)
+
+Given a numeric type (integer or floating point), build an rvalue for
+the given constant value.
+@end deffn
+
+@geindex gcc_jit_context_new_rvalue_from_ptr (C function)
+@anchor{topics/expressions gcc_jit_context_new_rvalue_from_ptr}@anchor{78}
+@deffn {C Function} gcc_jit_rvalue * gcc_jit_context_new_rvalue_from_ptr (gcc_jit_context@w{ }*ctxt, gcc_jit_type@w{ }*pointer_type, void@w{ }*value)
+
+Given a pointer type, build an rvalue for the given address.
+@end deffn
+
+@geindex gcc_jit_context_null (C function)
+@anchor{topics/expressions gcc_jit_context_null}@anchor{79}
+@deffn {C Function} gcc_jit_rvalue *gcc_jit_context_null (gcc_jit_context@w{ }*ctxt, gcc_jit_type@w{ }*pointer_type)
+
+Given a pointer type, build an rvalue for @code{NULL}. Essentially this
+is just a shortcut for:
+
+@example
+gcc_jit_context_new_rvalue_from_ptr (ctxt, pointer_type, NULL)
+@end example
+
+@noindent
+@end deffn
+
+@geindex gcc_jit_context_new_string_literal (C function)
+@anchor{topics/expressions gcc_jit_context_new_string_literal}@anchor{7a}
+@deffn {C Function} gcc_jit_rvalue * gcc_jit_context_new_string_literal (gcc_jit_context@w{ }*ctxt, const char@w{ }*value)
+
+Generate an rvalue for the given NIL-terminated string, of type
+@code{GCC_JIT_TYPE_CONST_CHAR_PTR}.
+@end deffn
+
+@node Unary Operations,Binary Operations,Simple expressions,Rvalues
+@anchor{topics/expressions unary-operations}@anchor{7b}
+@subsubsection Unary Operations
+
+
+@geindex gcc_jit_context_new_unary_op (C function)
+@anchor{topics/expressions gcc_jit_context_new_unary_op}@anchor{7c}
+@deffn {C Function} gcc_jit_rvalue * gcc_jit_context_new_unary_op (gcc_jit_context@w{ }*ctxt, gcc_jit_location@w{ }*loc, enum gcc_jit_unary_op@w{ }op, gcc_jit_type@w{ }*result_type, gcc_jit_rvalue@w{ }*rvalue)
+
+Build a unary operation out of an input rvalue.
+@end deffn
+
+@geindex gcc_jit_unary_op (C type)
+@anchor{topics/expressions gcc_jit_unary_op}@anchor{7d}
+@deffn {C Type} enum gcc_jit_unary_op
+@end deffn
+
+The available unary operations are:
+
+
+@multitable {xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx} {xxxxxxxxxxxxxx}
+@headitem
+
+Unary Operation
+
+@tab
+
+C equivalent
+
+@item
+
+@pxref{7e,,GCC_JIT_UNARY_OP_MINUS}
+
+@tab
+
+@cite{-(EXPR)}
+
+@item
+
+@pxref{7f,,GCC_JIT_UNARY_OP_BITWISE_NEGATE}
+
+@tab
+
+@cite{~(EXPR)}
+
+@item
+
+@pxref{80,,GCC_JIT_UNARY_OP_LOGICAL_NEGATE}
+
+@tab
+
+@cite{!(EXPR)}
+
+@end multitable
+
+
+@geindex GCC_JIT_UNARY_OP_MINUS (C macro)
+@anchor{topics/expressions GCC_JIT_UNARY_OP_MINUS}@anchor{7e}
+@deffn {C Macro} GCC_JIT_UNARY_OP_MINUS
+
+Negate an arithmetic value; analogous to:
+
+@example
+-(EXPR)
+@end example
+
+@noindent
+
+in C.
+@end deffn
+
+@geindex GCC_JIT_UNARY_OP_BITWISE_NEGATE (C macro)
+@anchor{topics/expressions GCC_JIT_UNARY_OP_BITWISE_NEGATE}@anchor{7f}
+@deffn {C Macro} GCC_JIT_UNARY_OP_BITWISE_NEGATE
+
+Bitwise negation of an integer value (one's complement); analogous
+to:
+
+@example
+~(EXPR)
+@end example
+
+@noindent
+
+in C.
+@end deffn
+
+@geindex GCC_JIT_UNARY_OP_LOGICAL_NEGATE (C macro)
+@anchor{topics/expressions GCC_JIT_UNARY_OP_LOGICAL_NEGATE}@anchor{80}
+@deffn {C Macro} GCC_JIT_UNARY_OP_LOGICAL_NEGATE
+
+Logical negation of an arithmetic or pointer value; analogous to:
+
+@example
+!(EXPR)
+@end example
+
+@noindent
+
+in C.
+@end deffn
+
+@node Binary Operations,Comparisons,Unary Operations,Rvalues
+@anchor{topics/expressions binary-operations}@anchor{81}
+@subsubsection Binary Operations
+
+
+@geindex gcc_jit_context_new_binary_op (C function)
+@anchor{topics/expressions gcc_jit_context_new_binary_op}@anchor{12}
+@deffn {C Function} gcc_jit_rvalue *gcc_jit_context_new_binary_op (gcc_jit_context@w{ }*ctxt, gcc_jit_location@w{ }*loc, enum gcc_jit_binary_op@w{ }op, gcc_jit_type@w{ }*result_type, gcc_jit_rvalue@w{ }*a, gcc_jit_rvalue@w{ }*b)
+
+Build a binary operation out of two constituent rvalues.
+@end deffn
+
+@geindex gcc_jit_binary_op (C type)
+@anchor{topics/expressions gcc_jit_binary_op}@anchor{82}
+@deffn {C Type} enum gcc_jit_binary_op
+@end deffn
+
+The available binary operations are:
+
+
+@multitable {xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx} {xxxxxxxxxxxxxx}
+@headitem
+
+Binary Operation
+
+@tab
+
+C equivalent
+
+@item
+
+@pxref{83,,GCC_JIT_BINARY_OP_PLUS}
+
+@tab
+
+@cite{x + y}
+
+@item
+
+@code{GCC_JIT_BINARY_OP_MINUS}
+
+@tab
+
+@cite{x - y}
+
+@item
+
+@pxref{84,,GCC_JIT_BINARY_OP_MULT}
+
+@tab
+
+@cite{x * y}
+
+@item
+
+@pxref{85,,GCC_JIT_BINARY_OP_DIVIDE}
+
+@tab
+
+@cite{x / y}
+
+@item
+
+@pxref{86,,GCC_JIT_BINARY_OP_MODULO}
+
+@tab
+
+@cite{x % y}
+
+@item
+
+@pxref{87,,GCC_JIT_BINARY_OP_BITWISE_AND}
+
+@tab
+
+@cite{x & y}
+
+@item
+
+@pxref{88,,GCC_JIT_BINARY_OP_BITWISE_XOR}
+
+@tab
+
+@cite{x ^ y}
+
+@item
+
+@pxref{89,,GCC_JIT_BINARY_OP_BITWISE_OR}
+
+@tab
+
+@cite{x | y}
+
+@item
+
+@pxref{8a,,GCC_JIT_BINARY_OP_LOGICAL_AND}
+
+@tab
+
+@cite{x && y}
+
+@item
+
+@pxref{8b,,GCC_JIT_BINARY_OP_LOGICAL_OR}
+
+@tab
+
+@cite{x || y}
+
+@item
+
+@pxref{8c,,GCC_JIT_BINARY_OP_LSHIFT}
+
+@tab
+
+@cite{x << y}
+
+@item
+
+@pxref{8d,,GCC_JIT_BINARY_OP_RSHIFT}
+
+@tab
+
+@cite{x >> y}
+
+@end multitable
+
+
+@geindex GCC_JIT_BINARY_OP_PLUS (C macro)
+@anchor{topics/expressions GCC_JIT_BINARY_OP_PLUS}@anchor{83}
+@deffn {C Macro} GCC_JIT_BINARY_OP_PLUS
+
+Addition of arithmetic values; analogous to:
+
+@example
+(EXPR_A) + (EXPR_B)
+@end example
+
+@noindent
+
+in C.
+
+For pointer addition, use @pxref{8e,,gcc_jit_context_new_array_access()}.
+@end deffn
+
+
+@deffn {C Macro} GCC_JIT_BINARY_OP_MINUS`
+
+Subtraction of arithmetic values; analogous to:
+
+@example
+(EXPR_A) - (EXPR_B)
+@end example
+
+@noindent
+
+in C.
+@end deffn
+
+@geindex GCC_JIT_BINARY_OP_MULT (C macro)
+@anchor{topics/expressions GCC_JIT_BINARY_OP_MULT}@anchor{84}
+@deffn {C Macro} GCC_JIT_BINARY_OP_MULT
+
+Multiplication of a pair of arithmetic values; analogous to:
+
+@example
+(EXPR_A) * (EXPR_B)
+@end example
+
+@noindent
+
+in C.
+@end deffn
+
+@geindex GCC_JIT_BINARY_OP_DIVIDE (C macro)
+@anchor{topics/expressions GCC_JIT_BINARY_OP_DIVIDE}@anchor{85}
+@deffn {C Macro} GCC_JIT_BINARY_OP_DIVIDE
+
+Quotient of division of arithmetic values; analogous to:
+
+@example
+(EXPR_A) / (EXPR_B)
+@end example
+
+@noindent
+
+in C.
+
+The result type affects the kind of division: if the result type is
+integer-based, then the result is truncated towards zero, whereas
+a floating-point result type indicates floating-point division.
+@end deffn
+
+@geindex GCC_JIT_BINARY_OP_MODULO (C macro)
+@anchor{topics/expressions GCC_JIT_BINARY_OP_MODULO}@anchor{86}
+@deffn {C Macro} GCC_JIT_BINARY_OP_MODULO
+
+Remainder of division of arithmetic values; analogous to:
+
+@example
+(EXPR_A) % (EXPR_B)
+@end example
+
+@noindent
+
+in C.
+@end deffn
+
+@geindex GCC_JIT_BINARY_OP_BITWISE_AND (C macro)
+@anchor{topics/expressions GCC_JIT_BINARY_OP_BITWISE_AND}@anchor{87}
+@deffn {C Macro} GCC_JIT_BINARY_OP_BITWISE_AND
+
+Bitwise AND; analogous to:
+
+@example
+(EXPR_A) & (EXPR_B)
+@end example
+
+@noindent
+
+in C.
+@end deffn
+
+@geindex GCC_JIT_BINARY_OP_BITWISE_XOR (C macro)
+@anchor{topics/expressions GCC_JIT_BINARY_OP_BITWISE_XOR}@anchor{88}
+@deffn {C Macro} GCC_JIT_BINARY_OP_BITWISE_XOR
+
+Bitwise exclusive OR; analogous to:
+
+@example
+(EXPR_A) ^ (EXPR_B)
+@end example
+
+@noindent
+
+in C.
+@end deffn
+
+@geindex GCC_JIT_BINARY_OP_BITWISE_OR (C macro)
+@anchor{topics/expressions GCC_JIT_BINARY_OP_BITWISE_OR}@anchor{89}
+@deffn {C Macro} GCC_JIT_BINARY_OP_BITWISE_OR
+
+Bitwise inclusive OR; analogous to:
+
+@example
+(EXPR_A) | (EXPR_B)
+@end example
+
+@noindent
+
+in C.
+@end deffn
+
+@geindex GCC_JIT_BINARY_OP_LOGICAL_AND (C macro)
+@anchor{topics/expressions GCC_JIT_BINARY_OP_LOGICAL_AND}@anchor{8a}
+@deffn {C Macro} GCC_JIT_BINARY_OP_LOGICAL_AND
+
+Logical AND; analogous to:
+
+@example
+(EXPR_A) && (EXPR_B)
+@end example
+
+@noindent
+
+in C.
+@end deffn
+
+@geindex GCC_JIT_BINARY_OP_LOGICAL_OR (C macro)
+@anchor{topics/expressions GCC_JIT_BINARY_OP_LOGICAL_OR}@anchor{8b}
+@deffn {C Macro} GCC_JIT_BINARY_OP_LOGICAL_OR
+
+Logical OR; analogous to:
+
+@example
+(EXPR_A) || (EXPR_B)
+@end example
+
+@noindent
+
+in C.
+@end deffn
+
+@geindex GCC_JIT_BINARY_OP_LSHIFT (C macro)
+@anchor{topics/expressions GCC_JIT_BINARY_OP_LSHIFT}@anchor{8c}
+@deffn {C Macro} GCC_JIT_BINARY_OP_LSHIFT
+
+Left shift; analogous to:
+
+@example
+(EXPR_A) << (EXPR_B)
+@end example
+
+@noindent
+
+in C.
+@end deffn
+
+@geindex GCC_JIT_BINARY_OP_RSHIFT (C macro)
+@anchor{topics/expressions GCC_JIT_BINARY_OP_RSHIFT}@anchor{8d}
+@deffn {C Macro} GCC_JIT_BINARY_OP_RSHIFT
+
+Right shift; analogous to:
+
+@example
+(EXPR_A) >> (EXPR_B)
+@end example
+
+@noindent
+
+in C.
+@end deffn
+
+@node Comparisons,Function calls,Binary Operations,Rvalues
+@anchor{topics/expressions comparisons}@anchor{8f}
+@subsubsection Comparisons
+
+
+@geindex gcc_jit_context_new_comparison (C function)
+@anchor{topics/expressions gcc_jit_context_new_comparison}@anchor{2a}
+@deffn {C Function} gcc_jit_rvalue * gcc_jit_context_new_comparison (gcc_jit_context@w{ }*ctxt, gcc_jit_location@w{ }*loc, enum gcc_jit_comparison@w{ }op, gcc_jit_rvalue@w{ }*a, gcc_jit_rvalue@w{ }*b)
+
+Build a boolean rvalue out of the comparison of two other rvalues.
+@end deffn
+
+@geindex gcc_jit_comparison (C type)
+@anchor{topics/expressions gcc_jit_comparison}@anchor{90}
+@deffn {C Type} enum gcc_jit_comparison
+@end deffn
+
+
+@multitable {xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx} {xxxxxxxxxxxxxx}
+@headitem
+
+Comparison
+
+@tab
+
+C equivalent
+
+@item
+
+@code{GCC_JIT_COMPARISON_EQ}
+
+@tab
+
+@cite{x == y}
+
+@item
+
+@code{GCC_JIT_COMPARISON_NE}
+
+@tab
+
+@cite{x != y}
+
+@item
+
+@code{GCC_JIT_COMPARISON_LT}
+
+@tab
+
+@cite{x < y}
+
+@item
+
+@code{GCC_JIT_COMPARISON_LE}
+
+@tab
+
+@cite{x <= y}
+
+@item
+
+@code{GCC_JIT_COMPARISON_GT}
+
+@tab
+
+@cite{x > y}
+
+@item
+
+@code{GCC_JIT_COMPARISON_GE}
+
+@tab
+
+@cite{x >= y}
+
+@end multitable
+
+
+@node Function calls,Type-coercion,Comparisons,Rvalues
+@anchor{topics/expressions function-calls}@anchor{91}
+@subsubsection Function calls
+
+
+@geindex gcc_jit_context_new_call (C function)
+@anchor{topics/expressions gcc_jit_context_new_call}@anchor{92}
+@deffn {C Function} gcc_jit_rvalue * gcc_jit_context_new_call (gcc_jit_context@w{ }*ctxt, gcc_jit_location@w{ }*loc, gcc_jit_function@w{ }*func, int@w{ }numargs, gcc_jit_rvalue@w{ }**args)
+
+Given a function and the given table of argument rvalues, construct a
+call to the function, with the result as an rvalue.
+
+@cartouche
+@quotation Note
+@pxref{92,,gcc_jit_context_new_call()} merely builds a
+@pxref{13,,gcc_jit_rvalue} i.e. an expression that can be evaluated,
+perhaps as part of a more complicated expression.
+The call @emph{won't} happen unless you add a statement to a function
+that evaluates the expression.
+
+For example, if you want to call a function and discard the result
+(or to call a function with @code{void} return type), use
+@pxref{93,,gcc_jit_block_add_eval()}:
+
+@example
+/* Add "(void)printf (arg0, arg1);". */
+gcc_jit_block_add_eval (
+ block, NULL,
+ gcc_jit_context_new_call (
+ ctxt,
+ NULL,
+ printf_func,
+ 2, args));
+@end example
+
+@noindent
+@end quotation
+@end cartouche
+@end deffn
+
+@node Type-coercion,,Function calls,Rvalues
+@anchor{topics/expressions type-coercion}@anchor{94}
+@subsubsection Type-coercion
+
+
+@geindex gcc_jit_context_new_cast (C function)
+@anchor{topics/expressions gcc_jit_context_new_cast}@anchor{95}
+@deffn {C Function} gcc_jit_rvalue * gcc_jit_context_new_cast (gcc_jit_context@w{ }*ctxt, gcc_jit_location@w{ }*loc, gcc_jit_rvalue@w{ }*rvalue, gcc_jit_type@w{ }*type)
+
+Given an rvalue of T, construct another rvalue of another type.
+
+Currently only a limited set of conversions are possible:
+
+@quotation
+
+
+@itemize *
+
+@item
+int <-> float
+
+@item
+int <-> bool
+
+@item
+P* <-> Q*, for pointer types P and Q
+@end itemize
+@end quotation
+@end deffn
+
+@node Lvalues,Working with pointers structs and unions,Rvalues,Expressions
+@anchor{topics/expressions lvalues}@anchor{96}
+@subsection Lvalues
+
+
+@geindex gcc_jit_lvalue (C type)
+@anchor{topics/expressions gcc_jit_lvalue}@anchor{22}
+@deffn {C Type} gcc_jit_lvalue
+@end deffn
+
+An lvalue is something that can of the @emph{left}-hand side of an assignment:
+a storage area (such as a variable). It is also usable as an rvalue,
+where the rvalue is computed by reading from the storage area.
+
+@geindex gcc_jit_lvalue_as_object (C function)
+@anchor{topics/expressions gcc_jit_lvalue_as_object}@anchor{97}
+@deffn {C Function} gcc_jit_object * gcc_jit_lvalue_as_object (gcc_jit_lvalue@w{ }*lvalue)
+
+Upcast an lvalue to be an object.
+@end deffn
+
+@geindex gcc_jit_lvalue_as_rvalue (C function)
+@anchor{topics/expressions gcc_jit_lvalue_as_rvalue}@anchor{98}
+@deffn {C Function} gcc_jit_rvalue * gcc_jit_lvalue_as_rvalue (gcc_jit_lvalue@w{ }*lvalue)
+
+Upcast an lvalue to be an rvalue.
+@end deffn
+
+@geindex gcc_jit_lvalue_get_address (C function)
+@anchor{topics/expressions gcc_jit_lvalue_get_address}@anchor{99}
+@deffn {C Function} gcc_jit_rvalue * gcc_jit_lvalue_get_address (gcc_jit_lvalue@w{ }*lvalue, gcc_jit_location@w{ }*loc)
+
+Take the address of an lvalue; analogous to:
+
+@example
+&(EXPR)
+@end example
+
+@noindent
+
+in C.
+@end deffn
+
+@menu
+* Global variables::
+
+@end menu
+
+@node Global variables,,,Lvalues
+@anchor{topics/expressions global-variables}@anchor{9a}
+@subsubsection Global variables
+
+
+@geindex gcc_jit_context_new_global (C function)
+@anchor{topics/expressions gcc_jit_context_new_global}@anchor{9b}
+@deffn {C Function} gcc_jit_lvalue * gcc_jit_context_new_global (gcc_jit_context@w{ }*ctxt, gcc_jit_location@w{ }*loc, gcc_jit_type@w{ }*type, const char@w{ }*name)
+
+Add a new global variable of the given type and name to the context.
+@end deffn
+
+@node Working with pointers structs and unions,,Lvalues,Expressions
+@anchor{topics/expressions working-with-pointers-structs-and-unions}@anchor{9c}
+@subsection Working with pointers, structs and unions
+
+
+@geindex gcc_jit_rvalue_dereference (C function)
+@anchor{topics/expressions gcc_jit_rvalue_dereference}@anchor{9d}
+@deffn {C Function} gcc_jit_lvalue * gcc_jit_rvalue_dereference (gcc_jit_rvalue@w{ }*rvalue, gcc_jit_location@w{ }*loc)
+
+Given an rvalue of pointer type @code{T *}, dereferencing the pointer,
+getting an lvalue of type @code{T}. Analogous to:
+
+@example
+*(EXPR)
+@end example
+
+@noindent
+
+in C.
+@end deffn
+
+Field access is provided separately for both lvalues and rvalues.
+
+@geindex gcc_jit_lvalue_access_field (C function)
+@anchor{topics/expressions gcc_jit_lvalue_access_field}@anchor{9e}
+@deffn {C Function} gcc_jit_lvalue * gcc_jit_lvalue_access_field (gcc_jit_lvalue@w{ }*struct_, gcc_jit_location@w{ }*loc, gcc_jit_field@w{ }*field)
+
+Given an lvalue of struct or union type, access the given field,
+getting an lvalue of the field's type. Analogous to:
+
+@example
+(EXPR).field = ...;
+@end example
+
+@noindent
+
+in C.
+@end deffn
+
+@geindex gcc_jit_rvalue_access_field (C function)
+@anchor{topics/expressions gcc_jit_rvalue_access_field}@anchor{9f}
+@deffn {C Function} gcc_jit_rvalue * gcc_jit_rvalue_access_field (gcc_jit_rvalue@w{ }*struct_, gcc_jit_location@w{ }*loc, gcc_jit_field@w{ }*field)
+
+Given an rvalue of struct or union type, access the given field
+as an rvalue. Analogous to:
+
+@example
+(EXPR).field
+@end example
+
+@noindent
+
+in C.
+@end deffn
+
+@geindex gcc_jit_rvalue_dereference_field (C function)
+@anchor{topics/expressions gcc_jit_rvalue_dereference_field}@anchor{a0}
+@deffn {C Function} gcc_jit_lvalue * gcc_jit_rvalue_dereference_field (gcc_jit_rvalue@w{ }*ptr, gcc_jit_location@w{ }*loc, gcc_jit_field@w{ }*field)
+
+Given an rvalue of pointer type @code{T *} where T is of struct or union
+type, access the given field as an lvalue. Analogous to:
+
+@example
+(EXPR)->field
+@end example
+
+@noindent
+
+in C, itself equivalent to @code{(*EXPR).FIELD}.
+@end deffn
+
+@geindex gcc_jit_context_new_array_access (C function)
+@anchor{topics/expressions gcc_jit_context_new_array_access}@anchor{8e}
+@deffn {C Function} gcc_jit_lvalue * gcc_jit_context_new_array_access (gcc_jit_context@w{ }*ctxt, gcc_jit_location@w{ }*loc, gcc_jit_rvalue@w{ }*ptr, gcc_jit_rvalue@w{ }*index)
+
+Given an rvalue of pointer type @code{T *}, get at the element @cite{T} at
+the given index, using standard C array indexing rules i.e. each
+increment of @code{index} corresponds to @code{sizeof(T)} bytes.
+Analogous to:
+
+@example
+PTR[INDEX]
+@end example
+
+@noindent
+
+in C (or, indeed, to @code{PTR + INDEX}).
+@end deffn
+
+@c Copyright (C) 2014 Free Software Foundation, Inc.
+@c Originally contributed by David Malcolm <dmalcolm@redhat.com>
+@c
+@c This is free software: you can redistribute it and/or modify it
+@c under the terms of the GNU General Public License as published by
+@c the Free Software Foundation, either version 3 of the License, or
+@c (at your option) any later version.
+@c
+@c This program is distributed in the hope that it will be useful, but
+@c WITHOUT ANY WARRANTY; without even the implied warranty of
+@c MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+@c General Public License for more details.
+@c
+@c You should have received a copy of the GNU General Public License
+@c along with this program. If not, see
+@c <http://www.gnu.org/licenses/>.
+
+@node Creating and using functions,Source Locations,Expressions,Topic Reference
+@anchor{topics/functions doc}@anchor{a1}@anchor{topics/functions creating-and-using-functions}@anchor{a2}
+@section Creating and using functions
+
+
+@menu
+* Params::
+* Functions::
+* Blocks::
+* Statements::
+
+@end menu
+
+@node Params,Functions,,Creating and using functions
+@anchor{topics/functions params}@anchor{a3}
+@subsection Params
+
+
+@geindex gcc_jit_param (C type)
+@anchor{topics/functions gcc_jit_param}@anchor{23}
+@deffn {C Type} gcc_jit_param
+
+A @cite{gcc_jit_param} represents a parameter to a function.
+@end deffn
+
+@geindex gcc_jit_context_new_param (C function)
+@anchor{topics/functions gcc_jit_context_new_param}@anchor{10}
+@deffn {C Function} gcc_jit_param * gcc_jit_context_new_param (gcc_jit_context@w{ }*ctxt, gcc_jit_location@w{ }*loc, gcc_jit_type@w{ }*type, const char@w{ }*name)
+
+In preparation for creating a function, create a new parameter of the
+given type and name.
+@end deffn
+
+Parameters are lvalues, and thus are also rvalues (and objects), so the
+following upcasts are available:
+
+@geindex gcc_jit_param_as_lvalue (C function)
+@anchor{topics/functions gcc_jit_param_as_lvalue}@anchor{a4}
+@deffn {C Function} gcc_jit_lvalue * gcc_jit_param_as_lvalue (gcc_jit_param@w{ }*param)
+
+Upcasting from param to lvalue.
+@end deffn
+
+@geindex gcc_jit_param_as_rvalue (C function)
+@anchor{topics/functions gcc_jit_param_as_rvalue}@anchor{a5}
+@deffn {C Function} gcc_jit_rvalue * gcc_jit_param_as_rvalue (gcc_jit_param@w{ }*param)
+
+Upcasting from param to rvalue.
+@end deffn
+
+@geindex gcc_jit_param_as_object (C function)
+@anchor{topics/functions gcc_jit_param_as_object}@anchor{a6}
+@deffn {C Function} gcc_jit_object * gcc_jit_param_as_object (gcc_jit_param@w{ }*param)
+
+Upcasting from param to object.
+@end deffn
+
+@node Functions,Blocks,Params,Creating and using functions
+@anchor{topics/functions functions}@anchor{a7}
+@subsection Functions
+
+
+@geindex gcc_jit_function (C type)
+@anchor{topics/functions gcc_jit_function}@anchor{27}
+@deffn {C Type} gcc_jit_function
+
+A @cite{gcc_jit_function} represents a function - either one that we're
+creating ourselves, or one that we're referencing.
+@end deffn
+
+@geindex gcc_jit_context_new_function (C function)
+@anchor{topics/functions gcc_jit_context_new_function}@anchor{11}
+@deffn {C Function} gcc_jit_function * gcc_jit_context_new_function (gcc_jit_context@w{ }*ctxt, gcc_jit_location@w{ }*loc, enum gcc_jit_function_kind@w{ }kind, gcc_jit_type@w{ }*return_type, const char@w{ }*name, int@w{ }num_params, gcc_jit_param@w{ }**params, int@w{ }is_variadic)
+
+Create a gcc_jit_function with the given name and parameters.
+
+@geindex gcc_jit_function_kind (C type)
+@anchor{topics/functions gcc_jit_function_kind}@anchor{a8}
+@deffn {C Type} enum gcc_jit_function_kind
+@end deffn
+
+This enum controls the kind of function created, and has the following
+values:
+
+@quotation
+
+@geindex GCC_JIT_FUNCTION_EXPORTED (C macro)
+@anchor{topics/functions GCC_JIT_FUNCTION_EXPORTED}@anchor{a9}
+@deffn {C Macro} GCC_JIT_FUNCTION_EXPORTED
+
+Function is defined by the client code and visible
+by name outside of the JIT.
+@end deffn
+
+@geindex GCC_JIT_FUNCTION_INTERNAL (C macro)
+@anchor{topics/functions GCC_JIT_FUNCTION_INTERNAL}@anchor{aa}
+@deffn {C Macro} GCC_JIT_FUNCTION_INTERNAL
+
+Function is defined by the client code, but is invisible
+outside of the JIT. Analogous to a "static" function.
+@end deffn
+
+@geindex GCC_JIT_FUNCTION_IMPORTED (C macro)
+@anchor{topics/functions GCC_JIT_FUNCTION_IMPORTED}@anchor{ab}
+@deffn {C Macro} GCC_JIT_FUNCTION_IMPORTED
+
+Function is not defined by the client code; we're merely
+referring to it. Analogous to using an "extern" function from a
+header file.
+@end deffn
+
+@geindex GCC_JIT_FUNCTION_ALWAYS_INLINE (C macro)
+@anchor{topics/functions GCC_JIT_FUNCTION_ALWAYS_INLINE}@anchor{ac}
+@deffn {C Macro} GCC_JIT_FUNCTION_ALWAYS_INLINE
+
+Function is only ever inlined into other functions, and is
+invisible outside of the JIT.
+
+Analogous to prefixing with @code{inline} and adding
+@code{__attribute__((always_inline))}
+
+Inlining will only occur when the optimization level is
+above 0; when optimization is off, this is essentially the
+same as GCC_JIT_FUNCTION_INTERNAL.
+@end deffn
+@end quotation
+@end deffn
+
+@geindex gcc_jit_context_get_builtin_function (C function)
+@anchor{topics/functions gcc_jit_context_get_builtin_function}@anchor{ad}
+@deffn {C Function} gcc_jit_function *gcc_jit_context_get_builtin_function (gcc_jit_context@w{ }*ctxt, const char@w{ }*name)
+@end deffn
+
+@geindex gcc_jit_function_as_object (C function)
+@anchor{topics/functions gcc_jit_function_as_object}@anchor{ae}
+@deffn {C Function} gcc_jit_object * gcc_jit_function_as_object (gcc_jit_function@w{ }*func)
+
+Upcasting from function to object.
+@end deffn
+
+@geindex gcc_jit_function_get_param (C function)
+@anchor{topics/functions gcc_jit_function_get_param}@anchor{af}
+@deffn {C Function} gcc_jit_param * gcc_jit_function_get_param (gcc_jit_function@w{ }*func, int@w{ }index)
+
+Get the param of the given index (0-based).
+@end deffn
+
+@geindex gcc_jit_function_dump_to_dot (C function)
+@anchor{topics/functions gcc_jit_function_dump_to_dot}@anchor{31}
+@deffn {C Function} void gcc_jit_function_dump_to_dot (gcc_jit_function@w{ }*func, const char@w{ }*path)
+
+Emit the function in graphviz format to the given path.
+@end deffn
+
+@geindex gcc_jit_function_new_local (C function)
+@anchor{topics/functions gcc_jit_function_new_local}@anchor{24}
+@deffn {C Function} gcc_jit_lvalue * gcc_jit_function_new_local (gcc_jit_function@w{ }*func, gcc_jit_location@w{ }*loc, gcc_jit_type@w{ }*type, const char@w{ }*name)
+
+Create a new local variable within the function, of the given type and
+name.
+@end deffn
+
+@node Blocks,Statements,Functions,Creating and using functions
+@anchor{topics/functions blocks}@anchor{b0}
+@subsection Blocks
+
+
+@geindex gcc_jit_block (C type)
+@anchor{topics/functions gcc_jit_block}@anchor{26}
+@deffn {C Type} gcc_jit_block
+
+A @cite{gcc_jit_block} represents a basic block within a function i.e. a
+sequence of statements with a single entry point and a single exit
+point.
+
+The first basic block that you create within a function will
+be the entrypoint.
+
+Each basic block that you create within a function must be
+terminated, either with a conditional, a jump, or a return.
+
+It's legal to have multiple basic blocks that return within
+one function.
+@end deffn
+
+@geindex gcc_jit_function_new_block (C function)
+@anchor{topics/functions gcc_jit_function_new_block}@anchor{b1}
+@deffn {C Function} gcc_jit_block * gcc_jit_function_new_block (gcc_jit_function@w{ }*func, const char@w{ }*name)
+
+Create a basic block of the given name. The name may be NULL, but
+providing meaningful names is often helpful when debugging: it may
+show up in dumps of the internal representation, and in error
+messages.
+@end deffn
+
+@geindex gcc_jit_block_as_object (C function)
+@anchor{topics/functions gcc_jit_block_as_object}@anchor{b2}
+@deffn {C Function} gcc_jit_object * gcc_jit_block_as_object (gcc_jit_block@w{ }*block)
+
+Upcast from block to object.
+@end deffn
+
+@geindex gcc_jit_block_get_function (C function)
+@anchor{topics/functions gcc_jit_block_get_function}@anchor{b3}
+@deffn {C Function} gcc_jit_function * gcc_jit_block_get_function (gcc_jit_block@w{ }*block)
+
+Which function is this block within?
+@end deffn
+
+@node Statements,,Blocks,Creating and using functions
+@anchor{topics/functions statements}@anchor{b4}
+@subsection Statements
+
+
+@geindex gcc_jit_block_add_eval (C function)
+@anchor{topics/functions gcc_jit_block_add_eval}@anchor{93}
+@deffn {C Function} void gcc_jit_block_add_eval (gcc_jit_block@w{ }*block, gcc_jit_location@w{ }*loc, gcc_jit_rvalue@w{ }*rvalue)
+
+Add evaluation of an rvalue, discarding the result
+(e.g. a function call that "returns" void).
+
+This is equivalent to this C code:
+
+@example
+(void)expression;
+@end example
+
+@noindent
+@end deffn
+
+@geindex gcc_jit_block_add_assignment (C function)
+@anchor{topics/functions gcc_jit_block_add_assignment}@anchor{28}
+@deffn {C Function} void gcc_jit_block_add_assignment (gcc_jit_block@w{ }*block, gcc_jit_location@w{ }*loc, gcc_jit_lvalue@w{ }*lvalue, gcc_jit_rvalue@w{ }*rvalue)
+
+Add evaluation of an rvalue, assigning the result to the given
+lvalue.
+
+This is roughly equivalent to this C code:
+
+@example
+lvalue = rvalue;
+@end example
+
+@noindent
+@end deffn
+
+@geindex gcc_jit_block_add_assignment_op (C function)
+@anchor{topics/functions gcc_jit_block_add_assignment_op}@anchor{2c}
+@deffn {C Function} void gcc_jit_block_add_assignment_op (gcc_jit_block@w{ }*block, gcc_jit_location@w{ }*loc, gcc_jit_lvalue@w{ }*lvalue, enum gcc_jit_binary_op@w{ }op, gcc_jit_rvalue@w{ }*rvalue)
+
+Add evaluation of an rvalue, using the result to modify an
+lvalue.
+
+This is analogous to "+=" and friends:
+
+@example
+lvalue += rvalue;
+lvalue *= rvalue;
+lvalue /= rvalue;
+@end example
+
+@noindent
+
+etc. For example:
+
+@example
+/* "i++" */
+gcc_jit_block_add_assignment_op (
+ loop_body, NULL,
+ i,
+ GCC_JIT_BINARY_OP_PLUS,
+ gcc_jit_context_one (ctxt, int_type));
+@end example
+
+@noindent
+@end deffn
+
+@geindex gcc_jit_block_add_comment (C function)
+@anchor{topics/functions gcc_jit_block_add_comment}@anchor{3a}
+@deffn {C Function} void gcc_jit_block_add_comment (gcc_jit_block@w{ }*block, gcc_jit_location@w{ }*loc, const char@w{ }*text)
+
+Add a no-op textual comment to the internal representation of the
+code. It will be optimized away, but will be visible in the dumps
+seen via @pxref{57,,GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE}
+and @pxref{1a,,GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE},
+and thus may be of use when debugging how your project's internal
+representation gets converted to the libgccjit IR.
+@end deffn
+
+@geindex gcc_jit_block_end_with_conditional (C function)
+@anchor{topics/functions gcc_jit_block_end_with_conditional}@anchor{2b}
+@deffn {C Function} void gcc_jit_block_end_with_conditional (gcc_jit_block@w{ }*block, gcc_jit_location@w{ }*loc, gcc_jit_rvalue@w{ }*boolval, gcc_jit_block@w{ }*on_true, gcc_jit_block@w{ }*on_false)
+
+Terminate a block by adding evaluation of an rvalue, branching on the
+result to the appropriate successor block.
+
+This is roughly equivalent to this C code:
+
+@example
+if (boolval)
+ goto on_true;
+else
+ goto on_false;
+@end example
+
+@noindent
+
+block, boolval, on_true, and on_false must be non-NULL.
+@end deffn
+
+@geindex gcc_jit_block_end_with_jump (C function)
+@anchor{topics/functions gcc_jit_block_end_with_jump}@anchor{b5}
+@deffn {C Function} void gcc_jit_block_end_with_jump (gcc_jit_block@w{ }*block, gcc_jit_location@w{ }*loc, gcc_jit_block@w{ }*target)
+
+Terminate a block by adding a jump to the given target block.
+
+This is roughly equivalent to this C code:
+
+@example
+goto target;
+@end example
+
+@noindent
+@end deffn
+
+@geindex gcc_jit_block_end_with_return (C function)
+@anchor{topics/functions gcc_jit_block_end_with_return}@anchor{b6}
+@deffn {C Function} void gcc_jit_block_end_with_return (gcc_jit_block@w{ }*block, gcc_jit_location@w{ }*loc, gcc_jit_rvalue@w{ }*rvalue)
+
+Terminate a block by adding evaluation of an rvalue, returning the value.
+
+This is roughly equivalent to this C code:
+
+@example
+return expression;
+@end example
+
+@noindent
+@end deffn
+
+@geindex gcc_jit_block_end_with_void_return (C function)
+@anchor{topics/functions gcc_jit_block_end_with_void_return}@anchor{b7}
+@deffn {C Function} void gcc_jit_block_end_with_void_return (gcc_jit_block@w{ }*block, gcc_jit_location@w{ }*loc)
+
+Terminate a block by adding a valueless return, for use within a function
+with "void" return type.
+
+This is equivalent to this C code:
+
+@example
+return;
+@end example
+
+@noindent
+@end deffn
+
+@c Copyright (C) 2014 Free Software Foundation, Inc.
+@c Originally contributed by David Malcolm <dmalcolm@redhat.com>
+@c
+@c This is free software: you can redistribute it and/or modify it
+@c under the terms of the GNU General Public License as published by
+@c the Free Software Foundation, either version 3 of the License, or
+@c (at your option) any later version.
+@c
+@c This program is distributed in the hope that it will be useful, but
+@c WITHOUT ANY WARRANTY; without even the implied warranty of
+@c MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+@c General Public License for more details.
+@c
+@c You should have received a copy of the GNU General Public License
+@c along with this program. If not, see
+@c <http://www.gnu.org/licenses/>.
+
+@node Source Locations,Compilation results,Creating and using functions,Topic Reference
+@anchor{topics/locations source-locations}@anchor{b8}@anchor{topics/locations doc}@anchor{b9}
+@section Source Locations
+
+
+@geindex gcc_jit_location (C type)
+@anchor{topics/locations gcc_jit_location}@anchor{38}
+@deffn {C Type} gcc_jit_location
+
+A @cite{gcc_jit_location} encapsulates a source code location, so that
+you can (optionally) associate locations in your language with
+statements in the JIT-compiled code, allowing the debugger to
+single-step through your language.
+
+@cite{gcc_jit_location} instances are optional: you can always pass NULL to
+any API entrypoint accepting one.
+
+You can construct them using @pxref{3e,,gcc_jit_context_new_location()}.
+
+You need to enable @pxref{3f,,GCC_JIT_BOOL_OPTION_DEBUGINFO} on the
+@pxref{8,,gcc_jit_context} for these locations to actually be usable by
+the debugger:
+
+@example
+gcc_jit_context_set_bool_option (
+ ctxt,
+ GCC_JIT_BOOL_OPTION_DEBUGINFO,
+ 1);
+@end example
+
+@noindent
+@end deffn
+
+@geindex gcc_jit_context_new_location (C function)
+@anchor{topics/locations gcc_jit_context_new_location}@anchor{3e}
+@deffn {C Function} gcc_jit_location * gcc_jit_context_new_location (gcc_jit_context@w{ }*ctxt, const char@w{ }*filename, int@w{ }line, int@w{ }column)
+
+Create a @cite{gcc_jit_location} instance representing the given source
+location.
+@end deffn
+
+@menu
+* Faking it::
+
+@end menu
+
+@node Faking it,,,Source Locations
+@anchor{topics/locations faking-it}@anchor{ba}
+@subsection Faking it
+
+
+If you don't have source code for your internal representation, but need
+to debug, you can generate a C-like representation of the functions in
+your context using @pxref{4f,,gcc_jit_context_dump_to_file()}:
+
+@example
+gcc_jit_context_dump_to_file (ctxt, "/tmp/something.c",
+ 1 /* update_locations */);
+@end example
+
+@noindent
+
+This will dump C-like code to the given path. If the @cite{update_locations}
+argument is true, this will also set up @cite{gcc_jit_location} information
+throughout the context, pointing at the dump file as if it were a source
+file, giving you @emph{something} you can step through in the debugger.
+
+@c Copyright (C) 2014 Free Software Foundation, Inc.
+@c Originally contributed by David Malcolm <dmalcolm@redhat.com>
+@c
+@c This is free software: you can redistribute it and/or modify it
+@c under the terms of the GNU General Public License as published by
+@c the Free Software Foundation, either version 3 of the License, or
+@c (at your option) any later version.
+@c
+@c This program is distributed in the hope that it will be useful, but
+@c WITHOUT ANY WARRANTY; without even the implied warranty of
+@c MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+@c General Public License for more details.
+@c
+@c You should have received a copy of the GNU General Public License
+@c along with this program. If not, see
+@c <http://www.gnu.org/licenses/>.
+
+@node Compilation results,,Source Locations,Topic Reference
+@anchor{topics/results compilation-results}@anchor{bb}@anchor{topics/results doc}@anchor{bc}
+@section Compilation results
+
+
+@geindex gcc_jit_result (C type)
+@anchor{topics/results gcc_jit_result}@anchor{16}
+@deffn {C Type} gcc_jit_result
+
+A @cite{gcc_jit_result} encapsulates the result of compiling a context.
+@end deffn
+
+@geindex gcc_jit_context_compile (C function)
+@anchor{topics/results gcc_jit_context_compile}@anchor{15}
+@deffn {C Function} gcc_jit_result * gcc_jit_context_compile (gcc_jit_context@w{ }*ctxt)
+
+This calls into GCC and builds the code, returning a
+@cite{gcc_jit_result *}.
+@end deffn
+
+@geindex gcc_jit_result_get_code (C function)
+@anchor{topics/results gcc_jit_result_get_code}@anchor{17}
+@deffn {C Function} void * gcc_jit_result_get_code (gcc_jit_result@w{ }*result, const char@w{ }*funcname)
+
+Locate a given function within the built machine code.
+This will need to be cast to a function pointer of the
+correct type before it can be called.
+@end deffn
+
+@geindex gcc_jit_result_release (C function)
+@anchor{topics/results gcc_jit_result_release}@anchor{bd}
+@deffn {C Function} void gcc_jit_result_release (gcc_jit_result@w{ }*result)
+
+Once we're done with the code, this unloads the built .so file.
+This cleans up the result; after calling this, it's no longer
+valid to use the result.
+@end deffn
+
+@c Copyright (C) 2014 Free Software Foundation, Inc.
+@c Originally contributed by David Malcolm <dmalcolm@redhat.com>
+@c
+@c This is free software: you can redistribute it and/or modify it
+@c under the terms of the GNU General Public License as published by
+@c the Free Software Foundation, either version 3 of the License, or
+@c (at your option) any later version.
+@c
+@c This program is distributed in the hope that it will be useful, but
+@c WITHOUT ANY WARRANTY; without even the implied warranty of
+@c MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+@c General Public License for more details.
+@c
+@c You should have received a copy of the GNU General Public License
+@c along with this program. If not, see
+@c <http://www.gnu.org/licenses/>.
+
+@node Internals,Indices and tables,Topic Reference,Top
+@anchor{internals/index internals}@anchor{be}@anchor{internals/index doc}@anchor{bf}
+@chapter Internals
+
+
+@menu
+* Working on the JIT library::
+* Running the test suite::
+* Environment variables::
+* Overview of code structure::
+
+@end menu
+
+@node Working on the JIT library,Running the test suite,,Internals
+@anchor{internals/index working-on-the-jit-library}@anchor{c0}
+@section Working on the JIT library
+
+
+Having checked out the source code (to "src"), you can configure and build
+the JIT library like this:
+
+@example
+mkdir build
+mkdir install
+PREFIX=$(pwd)/install
+cd build
+../src/configure \
+ --enable-host-shared \
+ --enable-languages=jit \
+ --disable-bootstrap \
+ --enable-checking=release \
+ --prefix=$PREFIX
+nice make -j4 # altering the "4" to however many cores you have
+@end example
+
+@noindent
+
+This should build a libgccjit.so within jit/build/gcc:
+
+@example
+[build] $ file gcc/libgccjit.so*
+gcc/libgccjit.so: symbolic link to `libgccjit.so.0'
+gcc/libgccjit.so.0: symbolic link to `libgccjit.so.0.0.1'
+gcc/libgccjit.so.0.0.1: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, not stripped
+@end example
+
+@noindent
+
+Here's what those configuration options mean:
+
+@geindex command line option; --enable-host-shared
+@anchor{internals/index cmdoption--enable-host-shared}@anchor{c1}
+@deffn {Option} --enable-host-shared
+
+Configuring with this option means that the compiler is built as
+position-independent code, which incurs a slight performance hit,
+but it necessary for a shared library.
+@end deffn
+
+@geindex command line option; --enable-languages=jit
+@anchor{internals/index cmdoption--enable-languages}@anchor{c2}
+@deffn {Option} --enable-languages=jit
+
+This specifies which frontends to build. The JIT library looks like
+a frontend to the rest of the code.
+@end deffn
+
+@geindex command line option; --disable-bootstrap
+@anchor{internals/index cmdoption--disable-bootstrap}@anchor{c3}
+@deffn {Option} --disable-bootstrap
+
+For hacking on the "jit" subdirectory, performing a full
+bootstrap can be overkill, since it's unused by a bootstrap. However,
+when submitting patches, you should remove this option, to ensure that
+the compiler can still bootstrap itself.
+@end deffn
+
+@geindex command line option; --enable-checking=release
+@anchor{internals/index cmdoption--enable-checking}@anchor{c4}
+@deffn {Option} --enable-checking=release
+
+The compile can perform extensive self-checking as it runs, useful when
+debugging, but slowing things down.
+
+For maximum speed, configure with @code{--enable-checking=release} to
+disable this self-checking.
+@end deffn
+
+@node Running the test suite,Environment variables,Working on the JIT library,Internals
+@anchor{internals/index running-the-test-suite}@anchor{c5}
+@section Running the test suite
+
+
+@example
+[build] $ cd gcc
+[gcc] $ make check-jit RUNTESTFLAGS="-v -v -v"
+@end example
+
+@noindent
+
+A summary of the tests can then be seen in:
+
+@example
+jit/build/gcc/testsuite/jit/jit.sum
+@end example
+
+@noindent
+
+and detailed logs in:
+
+@example
+jit/build/gcc/testsuite/jit/jit.log
+@end example
+
+@noindent
+
+The test executables can be seen as:
+
+@example
+jit/build/gcc/testsuite/jit/*.exe
+@end example
+
+@noindent
+
+which can be run independently.
+
+You can compile and run individual tests by passing "jit.exp=TESTNAME" to RUNTESTFLAGS e.g.:
+
+@example
+[gcc] $ make check-jit RUNTESTFLAGS="-v -v -v jit.exp=test-factorial.c"
+@end example
+
+@noindent
+
+and once a test has been compiled, you can debug it directly:
+
+@example
+[gcc] $ PATH=.:$PATH \
+ LD_LIBRARY_PATH=. \
+ LIBRARY_PATH=. \
+ gdb --args \
+ testsuite/jit/test-factorial.exe
+@end example
+
+@noindent
+
+@node Environment variables,Overview of code structure,Running the test suite,Internals
+@anchor{internals/index environment-variables}@anchor{c6}
+@section Environment variables
+
+
+When running client code against a locally-built libgccjit, three
+environment variables need to be set up:
+
+@geindex environment variable; LD_LIBRARY_PATH
+@anchor{internals/index envvar-LD_LIBRARY_PATH}@anchor{c7}
+@deffn {Environment Variable} LD_LIBRARY_PATH
+
+@quotation
+
+@cite{libgccjit.so} is dynamically linked into client code, so if running
+against a locally-built library, @code{LD_LIBRARY_PATH} needs to be set
+up appropriately. The library can be found within the "gcc"
+subdirectory of the build tree:
+@end quotation
+
+@example
+$ file libgccjit.so*
+libgccjit.so: symbolic link to `libgccjit.so.0'
+libgccjit.so.0: symbolic link to `libgccjit.so.0.0.1'
+libgccjit.so.0.0.1: ELF 64-bit LSB shared object, x86-64, version 1 (GNU/Linux), dynamically linked, not stripped
+@end example
+
+@noindent
+@end deffn
+
+@geindex environment variable; PATH
+@anchor{internals/index envvar-PATH}@anchor{c8}
+@deffn {Environment Variable} PATH
+
+The library uses a driver executable for converting from .s assembler
+files to .so shared libraries. Specifically, it looks for a name
+expanded from
+@code{$@{target_noncanonical@}-gcc-$@{gcc_BASEVER@}$@{exeext@}}
+such as @code{x86_64-unknown-linux-gnu-gcc-5.0.0}.
+
+Hence @code{PATH} needs to include a directory where the library can
+locate this executable.
+
+The executable is normally installed to the installation bindir
+(e.g. /usr/bin), but a copy is also created within the "gcc"
+subdirectory of the build tree for running the testsuite, and for ease
+of development.
+@end deffn
+
+@geindex environment variable; LIBRARY_PATH
+@anchor{internals/index envvar-LIBRARY_PATH}@anchor{c9}
+@deffn {Environment Variable} LIBRARY_PATH
+
+The driver executable invokes the linker, and the latter needs to locate
+support libraries needed by the generated code, or you will see errors
+like:
+
+@example
+ld: cannot find crtbeginS.o: No such file or directory
+ld: cannot find -lgcc
+ld: cannot find -lgcc_s
+@end example
+
+@noindent
+
+Hence if running directly from a locally-built copy (without installing),
+@code{LIBRARY_PATH} needs to contain the "gcc" subdirectory of the build
+tree.
+@end deffn
+
+For example, to run a binary that uses the library against a non-installed
+build of the library in LIBGCCJIT_BUILD_DIR you need an invocation of the
+client code like this, to preprend the dir to each of the environment
+variables:
+
+@example
+$ LD_LIBRARY_PATH=$(LIBGCCJIT_BUILD_DIR):$(LD_LIBRARY_PATH) \
+ PATH=$(LIBGCCJIT_BUILD_DIR):$(PATH) \
+ LIBRARY_PATH=$(LIBGCCJIT_BUILD_DIR):$(LIBRARY_PATH) \
+ ./jit-hello-world
+hello world
+@end example
+
+@noindent
+
+@node Overview of code structure,,Environment variables,Internals
+@anchor{internals/index overview-of-code-structure}@anchor{ca}
+@section Overview of code structure
+
+
+
+@itemize *
+
+@item
+@code{libgccjit.c} implements the API entrypoints. It performs error
+checking, then calls into classes of the gcc::jit::recording namespace
+within @code{jit-recording.c} and @code{jit-recording.h}.
+
+@item
+The gcc::jit::recording classes (within @code{jit-recording.c} and
+@code{jit-recording.h}) record the API calls that are made:
+
+@quotation
+
+@example
+
+ /* Indentation indicates inheritance: */
+ class context;
+ class builtins_manager; // declared within jit-builtins.h
+ class memento;
+ class string;
+ class location;
+ class type;
+ class function_type;
+ class compound_type;
+ class struct_;
+ class union_;
+ class field;
+ class fields;
+ class function;
+ class block;
+ class rvalue;
+ class lvalue;
+ class local;
+ class global;
+ class param;
+ class statement;
+
+
+@end example
+
+@noindent
+@end quotation
+
+@item
+When the context is compiled, the gcc::jit::playback classes (within
+@code{jit-playback.c} and @code{jit-playback.h}) replay the API calls
+within langhook:parse_file:
+
+@quotation
+
+@example
+
+ /* Indentation indicates inheritance: */
+ class context;
+ class wrapper;
+ class type;
+ class compound_type;
+ class field;
+ class function;
+ class block;
+ class rvalue;
+ class lvalue;
+ class param;
+ class source_file;
+ class source_line;
+ class location;
+
+
+@end example
+
+@noindent
+
+@example
+Client Code . Generated . libgccjit.so
+ . code .
+ . . JIT API . JIT "Frontend". (libbackend.a)
+....................................................................................
+ │ . . . .
+ ──────────────────────────> . .
+ . . │ . .
+ . . V . .
+ . . ──> libgccjit.c .
+ . . │ (error-checking).
+ . . │ .
+ . . ──> jit-recording.c
+ . . (record API calls)
+ . . <─────── .
+ . . │ . .
+ <─────────────────────────── . .
+ │ . . . .
+ │ . . . .
+ V . . gcc_jit_context_compile .
+ ──────────────────────────> . .
+ . . │ . .
+ . . │ ACQUIRE MUTEX .
+ . . │ . .
+ . . V───────────────────────> toplev::main (for now)
+ . . . . │
+ . . . . (various code)
+ . . . . │
+ . . . . V
+ . . . <───────────────── langhook:parse_file
+ . . . │ .
+ . . . │ (jit_langhook_parse_file)
+ . . . │ .
+..........................................│..................VVVVVVVVVVVVV...
+ . . . │ . No GC in here
+ . . . │ jit-playback.c
+ . . . │ (playback of API calls)
+ . . . ───────────────> creation of functions,
+ . . . . types, expression trees
+ . . . <──────────────── etc
+ . . . │(handle_locations: add locations to
+ . . . │ linemap and associate them with trees)
+ . . . │ .
+ . . . │ . No GC in here
+..........................................│..................AAAAAAAAAAAAA...
+ . . . │ for each function
+ . . . ──> postprocess
+ . . . │ .
+ . . . ────────────> cgraph_finalize_function
+ . . . <────────────
+ . . . <── .
+ . . . │ .
+ . . . ──────────────────> (end of
+ . . . . │ langhook_parse_file)
+ . . . . │
+ . . . . (various code)
+ . . . . │
+ . . . . ↓
+ . . . <───────────────── langhook:write_globals
+ . . . │ .
+ . . . │ (jit_langhook_write_globals)
+ . . . │ .
+ . . . │ .
+ . . . ──────────────────> finalize_compilation_unit
+ . . . . │
+ . . . . (the middle─end and backend)
+ . . . . ↓
+ . . <───────────────────────────── end of toplev::main
+ . . │ RELEASE MUTEX .
+ . . │ . .
+ . . │ Convert assembler to DSO
+ . . │ . .
+ . . │ Load DSO .
+ <─────────────────────────── . .
+ │ . . . .
+ Get (void*). . . .
+ │ . . . .
+ │ Call it . . . .
+ ───────────────> . . .
+ . │ . . .
+ . │ . . .
+ <─────────────── . . .
+ │ . . . .
+ │ . . . .
+etc
+
+@end example
+
+@noindent
+@end quotation
+@end itemize
+
+Here is a high-level summary from @code{jit-common.h}:
+
+@quotation
+
+In order to allow jit objects to be usable outside of a compile
+whilst working with the existing structure of GCC's code the
+C API is implemented in terms of a gcc::jit::recording::context,
+which records the calls made to it.
+
+When a gcc_jit_context is compiled, the recording context creates a
+playback context. The playback context invokes the bulk of the GCC
+code, and within the "frontend" parsing hook, plays back the recorded
+API calls, creating GCC tree objects.
+
+So there are two parallel families of classes: those relating to
+recording, and those relating to playback:
+
+
+@itemize *
+
+@item
+Visibility: recording objects are exposed back to client code,
+whereas playback objects are internal to the library.
+
+@item
+Lifetime: recording objects have a lifetime equal to that of the
+recording context that created them, whereas playback objects only
+exist within the frontend hook.
+
+@item
+Memory allocation: recording objects are allocated by the recording
+context, and automatically freed by it when the context is released,
+whereas playback objects are allocated within the GC heap, and
+garbage-collected; they can own GC-references.
+
+@item
+Integration with rest of GCC: recording objects are unrelated to the
+rest of GCC, whereas playback objects are wrappers around "tree"
+instances. Hence you can't ask a recording rvalue or lvalue what its
+type is, whereas you can for a playback rvalue of lvalue (since it
+can work with the underlying GCC tree nodes).
+
+@item
+Instancing: There can be multiple recording contexts "alive" at once
+(albeit it only one compiling at once), whereas there can only be one
+playback context alive at one time (since it interacts with the GC).
+@end itemize
+
+Ultimately if GCC could support multiple GC heaps and contexts, and
+finer-grained initialization, then this recording vs playback
+distinction could be eliminated.
+
+During a playback, we associate objects from the recording with
+their counterparts during this playback. For simplicity, we store this
+within the recording objects, as @code{void *m_playback_obj}, casting it to
+the appropriate playback object subclass. For these casts to make
+sense, the two class hierarchies need to have the same structure.
+
+Note that the playback objects that @code{m_playback_obj} points to are
+GC-allocated, but the recording objects don't own references:
+these associations only exist within a part of the code where
+the GC doesn't collect, and are set back to NULL before the GC can
+run.
+@end quotation
+
+This document describes libgccjit@footnote{http://gcc.gnu.org/wiki/JIT}, an API
+for embedding GCC inside programs and libraries.
+
+Note that libgccjit is currently of "Alpha" quality;
+the APIs are not yet set in stone, and they shouldn't be used in
+production yet.
+
+@node Indices and tables,Index,Internals,Top
+@anchor{index indices-and-tables}@anchor{cb}
+@unnumbered Indices and tables
+
+
+
+@itemize *
+
+@item
+@emph{genindex}
+
+@item
+@emph{modindex}
+
+@item
+@emph{search}
+@end itemize
+
+@c Some notes:
+@c
+@c The Sphinx C domain appears to lack explicit support for enum values,
+@c so I've been using :c:macro: for them.
+@c
+@c See http://sphinx-doc.org/domains.html#the-c-domain
+
+@node Index,,Indices and tables,Top
+@unnumbered Index
+
+
+@printindex ge
+
+@c %**end of body
+@bye
--- /dev/null
+# -*- 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'
--- /dev/null
+/* 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, ¶m_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, ¶m_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;
+}
--- /dev/null
+/* 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, ¶m_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;
+}
--- /dev/null
+/* 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;
+}
--- /dev/null
+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
--- /dev/null
+# 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
--- /dev/null
+# 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
--- /dev/null
+/* 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;
+}
--- /dev/null
+.. 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
--- /dev/null
+.. 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. */
--- /dev/null
+.. 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
--- /dev/null
+.. 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
--- /dev/null
+.. 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, ¶m_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
--- /dev/null
+.. 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
--- /dev/null
+.. 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;
+
+ }
--- /dev/null
+.. 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).
--- /dev/null
+.. Copyright (C) 2014 Free Software Foundation, Inc.
+ Originally contributed by David Malcolm <dmalcolm@redhat.com>
+
+ This is free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see
+ <http://www.gnu.org/licenses/>.
+
+.. default-domain:: c
+
+Expressions
+===========
+
+Rvalues
+-------
+.. type:: gcc_jit_rvalue
+
+A :c:type:`gcc_jit_rvalue *` is an expression that can be computed.
+
+It can be simple, e.g.:
+
+ * an integer value e.g. `0` or `42`
+ * a string literal e.g. `"Hello world"`
+ * a variable e.g. `i`. These are also lvalues (see below).
+
+or compound e.g.:
+
+ * a unary expression e.g. `!cond`
+ * a binary expression e.g. `(a + b)`
+ * a function call e.g. `get_distance (&player_ship, &target)`
+ * etc.
+
+Every rvalue has an associated type, and the API will check to ensure
+that types match up correctly (otherwise the context will emit an error).
+
+.. function:: gcc_jit_type *gcc_jit_rvalue_get_type (gcc_jit_rvalue *rvalue)
+
+ Get the type of this rvalue.
+
+.. function:: gcc_jit_object *gcc_jit_rvalue_as_object (gcc_jit_rvalue *rvalue)
+
+ Upcast the given rvalue to be an object.
+
+
+Simple expressions
+******************
+
+.. function:: gcc_jit_rvalue *\
+ gcc_jit_context_new_rvalue_from_int (gcc_jit_context *ctxt, \
+ gcc_jit_type *numeric_type, \
+ int value)
+
+ Given a numeric type (integer or floating point), build an rvalue for
+ the given constant value.
+
+.. function:: gcc_jit_rvalue *gcc_jit_context_zero (gcc_jit_context *ctxt, \
+ gcc_jit_type *numeric_type)
+
+ Given a numeric type (integer or floating point), get the rvalue for
+ zero. Essentially this is just a shortcut for:
+
+ .. code-block:: c
+
+ gcc_jit_context_new_rvalue_from_int (ctxt, numeric_type, 0)
+
+.. function:: gcc_jit_rvalue *gcc_jit_context_one (gcc_jit_context *ctxt, \
+ gcc_jit_type *numeric_type)
+
+ Given a numeric type (integer or floating point), get the rvalue for
+ zero. Essentially this is just a shortcut for:
+
+ .. code-block:: c
+
+ gcc_jit_context_new_rvalue_from_int (ctxt, numeric_type, 1)
+
+.. function:: gcc_jit_rvalue *\
+ gcc_jit_context_new_rvalue_from_double (gcc_jit_context *ctxt, \
+ gcc_jit_type *numeric_type, \
+ double value)
+
+ Given a numeric type (integer or floating point), build an rvalue for
+ the given constant value.
+
+.. function:: gcc_jit_rvalue *\
+ gcc_jit_context_new_rvalue_from_ptr (gcc_jit_context *ctxt, \
+ gcc_jit_type *pointer_type, \
+ void *value)
+
+ Given a pointer type, build an rvalue for the given address.
+
+.. function:: gcc_jit_rvalue *gcc_jit_context_null (gcc_jit_context *ctxt, \
+ gcc_jit_type *pointer_type)
+
+ Given a pointer type, build an rvalue for ``NULL``. Essentially this
+ is just a shortcut for:
+
+ .. code-block:: c
+
+ gcc_jit_context_new_rvalue_from_ptr (ctxt, pointer_type, NULL)
+
+.. function:: gcc_jit_rvalue *\
+ gcc_jit_context_new_string_literal (gcc_jit_context *ctxt, \
+ const char *value)
+
+ Generate an rvalue for the given NIL-terminated string, of type
+ :c:data:`GCC_JIT_TYPE_CONST_CHAR_PTR`.
+
+
+Unary Operations
+****************
+
+.. function:: gcc_jit_rvalue * \
+ gcc_jit_context_new_unary_op (gcc_jit_context *ctxt, \
+ gcc_jit_location *loc, \
+ enum gcc_jit_unary_op op, \
+ gcc_jit_type *result_type, \
+ gcc_jit_rvalue *rvalue)
+
+ Build a unary operation out of an input rvalue.
+
+.. type:: enum gcc_jit_unary_op
+
+The available unary operations are:
+
+========================================== ============
+Unary Operation C equivalent
+========================================== ============
+:c:macro:`GCC_JIT_UNARY_OP_MINUS` `-(EXPR)`
+:c:macro:`GCC_JIT_UNARY_OP_BITWISE_NEGATE` `~(EXPR)`
+:c:macro:`GCC_JIT_UNARY_OP_LOGICAL_NEGATE` `!(EXPR)`
+========================================== ============
+
+.. c:macro:: GCC_JIT_UNARY_OP_MINUS
+
+ Negate an arithmetic value; analogous to:
+
+ .. code-block:: c
+
+ -(EXPR)
+
+ in C.
+
+.. c:macro:: GCC_JIT_UNARY_OP_BITWISE_NEGATE
+
+ Bitwise negation of an integer value (one's complement); analogous
+ to:
+
+ .. code-block:: c
+
+ ~(EXPR)
+
+ in C.
+
+.. c:macro:: GCC_JIT_UNARY_OP_LOGICAL_NEGATE
+
+ Logical negation of an arithmetic or pointer value; analogous to:
+
+ .. code-block:: c
+
+ !(EXPR)
+
+ in C.
+
+Binary Operations
+*****************
+
+.. function:: gcc_jit_rvalue *gcc_jit_context_new_binary_op (gcc_jit_context *ctxt, \
+ gcc_jit_location *loc, \
+ enum gcc_jit_binary_op op, \
+ gcc_jit_type *result_type, \
+ gcc_jit_rvalue *a, gcc_jit_rvalue *b)
+
+ Build a binary operation out of two constituent rvalues.
+
+.. type:: enum gcc_jit_binary_op
+
+The available binary operations are:
+
+======================================== ============
+Binary Operation C equivalent
+======================================== ============
+:c:macro:`GCC_JIT_BINARY_OP_PLUS` `x + y`
+:c:macro:`GCC_JIT_BINARY_OP_MINUS` `x - y`
+:c:macro:`GCC_JIT_BINARY_OP_MULT` `x * y`
+:c:macro:`GCC_JIT_BINARY_OP_DIVIDE` `x / y`
+:c:macro:`GCC_JIT_BINARY_OP_MODULO` `x % y`
+:c:macro:`GCC_JIT_BINARY_OP_BITWISE_AND` `x & y`
+:c:macro:`GCC_JIT_BINARY_OP_BITWISE_XOR` `x ^ y`
+:c:macro:`GCC_JIT_BINARY_OP_BITWISE_OR` `x | y`
+:c:macro:`GCC_JIT_BINARY_OP_LOGICAL_AND` `x && y`
+:c:macro:`GCC_JIT_BINARY_OP_LOGICAL_OR` `x || y`
+:c:macro:`GCC_JIT_BINARY_OP_LSHIFT` `x << y`
+:c:macro:`GCC_JIT_BINARY_OP_RSHIFT` `x >> y`
+======================================== ============
+
+.. c:macro:: GCC_JIT_BINARY_OP_PLUS
+
+ Addition of arithmetic values; analogous to:
+
+ .. code-block:: c
+
+ (EXPR_A) + (EXPR_B)
+
+ in C.
+
+ For pointer addition, use :c:func:`gcc_jit_context_new_array_access`.
+
+.. c:macro:: GCC_JIT_BINARY_OP_MINUS`
+
+ Subtraction of arithmetic values; analogous to:
+
+ .. code-block:: c
+
+ (EXPR_A) - (EXPR_B)
+
+ in C.
+
+.. c:macro:: GCC_JIT_BINARY_OP_MULT
+
+ Multiplication of a pair of arithmetic values; analogous to:
+
+ .. code-block:: c
+
+ (EXPR_A) * (EXPR_B)
+
+ in C.
+
+.. c:macro:: GCC_JIT_BINARY_OP_DIVIDE
+
+ Quotient of division of arithmetic values; analogous to:
+
+ .. code-block:: c
+
+ (EXPR_A) / (EXPR_B)
+
+ in C.
+
+ The result type affects the kind of division: if the result type is
+ integer-based, then the result is truncated towards zero, whereas
+ a floating-point result type indicates floating-point division.
+
+.. c:macro:: GCC_JIT_BINARY_OP_MODULO
+
+ Remainder of division of arithmetic values; analogous to:
+
+ .. code-block:: c
+
+ (EXPR_A) % (EXPR_B)
+
+ in C.
+
+.. c:macro:: GCC_JIT_BINARY_OP_BITWISE_AND
+
+ Bitwise AND; analogous to:
+
+ .. code-block:: c
+
+ (EXPR_A) & (EXPR_B)
+
+ in C.
+
+.. c:macro:: GCC_JIT_BINARY_OP_BITWISE_XOR
+
+ Bitwise exclusive OR; analogous to:
+
+ .. code-block:: c
+
+ (EXPR_A) ^ (EXPR_B)
+
+ in C.
+
+.. c:macro:: GCC_JIT_BINARY_OP_BITWISE_OR
+
+ Bitwise inclusive OR; analogous to:
+
+ .. code-block:: c
+
+ (EXPR_A) | (EXPR_B)
+
+ in C.
+
+.. c:macro:: GCC_JIT_BINARY_OP_LOGICAL_AND
+
+ Logical AND; analogous to:
+
+ .. code-block:: c
+
+ (EXPR_A) && (EXPR_B)
+
+ in C.
+
+.. c:macro:: GCC_JIT_BINARY_OP_LOGICAL_OR
+
+ Logical OR; analogous to:
+
+ .. code-block:: c
+
+ (EXPR_A) || (EXPR_B)
+
+ in C.
+
+.. c:macro:: GCC_JIT_BINARY_OP_LSHIFT
+
+ Left shift; analogous to:
+
+ .. code-block:: c
+
+ (EXPR_A) << (EXPR_B)
+
+ in C.
+
+.. c:macro:: GCC_JIT_BINARY_OP_RSHIFT
+
+ Right shift; analogous to:
+
+ .. code-block:: c
+
+ (EXPR_A) >> (EXPR_B)
+
+ in C.
+
+Comparisons
+***********
+
+.. function:: gcc_jit_rvalue *\
+ gcc_jit_context_new_comparison (gcc_jit_context *ctxt,\
+ gcc_jit_location *loc,\
+ enum gcc_jit_comparison op,\
+ gcc_jit_rvalue *a, gcc_jit_rvalue *b)
+
+ Build a boolean rvalue out of the comparison of two other rvalues.
+
+.. type:: enum gcc_jit_comparison
+
+======================================= ============
+Comparison C equivalent
+======================================= ============
+:c:macro:`GCC_JIT_COMPARISON_EQ` `x == y`
+:c:macro:`GCC_JIT_COMPARISON_NE` `x != y`
+:c:macro:`GCC_JIT_COMPARISON_LT` `x < y`
+:c:macro:`GCC_JIT_COMPARISON_LE` `x <= y`
+:c:macro:`GCC_JIT_COMPARISON_GT` `x > y`
+:c:macro:`GCC_JIT_COMPARISON_GE` `x >= y`
+======================================= ============
+
+
+Function calls
+**************
+.. function:: gcc_jit_rvalue *\
+ gcc_jit_context_new_call (gcc_jit_context *ctxt,\
+ gcc_jit_location *loc,\
+ gcc_jit_function *func,\
+ int numargs , gcc_jit_rvalue **args)
+
+ Given a function and the given table of argument rvalues, construct a
+ call to the function, with the result as an rvalue.
+
+ .. note::
+
+ :c:func:`gcc_jit_context_new_call` merely builds a
+ :c:type:`gcc_jit_rvalue` i.e. an expression that can be evaluated,
+ perhaps as part of a more complicated expression.
+ The call *won't* happen unless you add a statement to a function
+ that evaluates the expression.
+
+ For example, if you want to call a function and discard the result
+ (or to call a function with ``void`` return type), use
+ :c:func:`gcc_jit_block_add_eval`:
+
+ .. code-block:: c
+
+ /* Add "(void)printf (arg0, arg1);". */
+ gcc_jit_block_add_eval (
+ block, NULL,
+ gcc_jit_context_new_call (
+ ctxt,
+ NULL,
+ printf_func,
+ 2, args));
+
+Type-coercion
+*************
+
+.. function:: gcc_jit_rvalue *\
+ gcc_jit_context_new_cast (gcc_jit_context *ctxt,\
+ gcc_jit_location *loc,\
+ gcc_jit_rvalue *rvalue,\
+ gcc_jit_type *type)
+
+ Given an rvalue of T, construct another rvalue of another type.
+
+ Currently only a limited set of conversions are possible:
+
+ * int <-> float
+ * int <-> bool
+ * P* <-> Q*, for pointer types P and Q
+
+Lvalues
+-------
+
+.. type:: gcc_jit_lvalue
+
+An lvalue is something that can of the *left*-hand side of an assignment:
+a storage area (such as a variable). It is also usable as an rvalue,
+where the rvalue is computed by reading from the storage area.
+
+.. function:: gcc_jit_object *\
+ gcc_jit_lvalue_as_object (gcc_jit_lvalue *lvalue)
+
+ Upcast an lvalue to be an object.
+
+.. function:: gcc_jit_rvalue *\
+ gcc_jit_lvalue_as_rvalue (gcc_jit_lvalue *lvalue)
+
+ Upcast an lvalue to be an rvalue.
+
+.. function:: gcc_jit_rvalue *\
+ gcc_jit_lvalue_get_address (gcc_jit_lvalue *lvalue,\
+ gcc_jit_location *loc)
+
+ Take the address of an lvalue; analogous to:
+
+ .. code-block:: c
+
+ &(EXPR)
+
+ in C.
+
+Global variables
+****************
+
+.. function:: gcc_jit_lvalue *\
+ gcc_jit_context_new_global (gcc_jit_context *ctxt,\
+ gcc_jit_location *loc,\
+ gcc_jit_type *type,\
+ const char *name)
+
+ Add a new global variable of the given type and name to the context.
+
+
+Working with pointers, structs and unions
+-----------------------------------------
+
+.. function:: gcc_jit_lvalue *\
+ gcc_jit_rvalue_dereference (gcc_jit_rvalue *rvalue,\
+ gcc_jit_location *loc)
+
+ Given an rvalue of pointer type ``T *``, dereferencing the pointer,
+ getting an lvalue of type ``T``. Analogous to:
+
+ .. code-block:: c
+
+ *(EXPR)
+
+ in C.
+
+Field access is provided separately for both lvalues and rvalues.
+
+.. function:: gcc_jit_lvalue *\
+ gcc_jit_lvalue_access_field (gcc_jit_lvalue *struct_,\
+ gcc_jit_location *loc,\
+ gcc_jit_field *field)
+
+ Given an lvalue of struct or union type, access the given field,
+ getting an lvalue of the field's type. Analogous to:
+
+ .. code-block:: c
+
+ (EXPR).field = ...;
+
+ in C.
+
+.. function:: gcc_jit_rvalue *\
+ gcc_jit_rvalue_access_field (gcc_jit_rvalue *struct_,\
+ gcc_jit_location *loc,\
+ gcc_jit_field *field)
+
+ Given an rvalue of struct or union type, access the given field
+ as an rvalue. Analogous to:
+
+ .. code-block:: c
+
+ (EXPR).field
+
+ in C.
+
+.. function:: gcc_jit_lvalue *\
+ gcc_jit_rvalue_dereference_field (gcc_jit_rvalue *ptr,\
+ gcc_jit_location *loc,\
+ gcc_jit_field *field)
+
+ Given an rvalue of pointer type ``T *`` where T is of struct or union
+ type, access the given field as an lvalue. Analogous to:
+
+ .. code-block:: c
+
+ (EXPR)->field
+
+ in C, itself equivalent to ``(*EXPR).FIELD``.
+
+.. function:: gcc_jit_lvalue *\
+ gcc_jit_context_new_array_access (gcc_jit_context *ctxt,\
+ gcc_jit_location *loc,\
+ gcc_jit_rvalue *ptr,\
+ gcc_jit_rvalue *index)
+
+ Given an rvalue of pointer type ``T *``, get at the element `T` at
+ the given index, using standard C array indexing rules i.e. each
+ increment of ``index`` corresponds to ``sizeof(T)`` bytes.
+ Analogous to:
+
+ .. code-block:: c
+
+ PTR[INDEX]
+
+ in C (or, indeed, to ``PTR + INDEX``).
--- /dev/null
+.. 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;
--- /dev/null
+.. 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
--- /dev/null
+.. 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.
--- /dev/null
+.. 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.
--- /dev/null
+.. 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.
--- /dev/null
+.. 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.
--- /dev/null
+/* jit.c -- Dummy "frontend" for use during JIT-compilation.
+ Copyright (C) 2013-2014 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "opts.h"
+#include "signop.h"
+#include "tree-core.h"
+#include "stor-layout.h"
+#include "tree.h"
+#include "debug.h"
+#include "langhooks.h"
+#include "langhooks-def.h"
+#include "hash-map.h"
+#include "is-a.h"
+#include "plugin-api.h"
+#include "vec.h"
+#include "hashtab.h"
+#include "hash-set.h"
+#include "machmode.h"
+#include "tm.h"
+#include "hard-reg-set.h"
+#include "function.h"
+#include "ipa-ref.h"
+#include "dumpfile.h"
+#include "cgraph.h"
+
+#include "jit-common.h"
+#include "jit-playback.h"
+
+#include <mpfr.h>
+
+/* Language-dependent contents of a type. */
+
+struct GTY(()) lang_type
+{
+ char dummy;
+};
+
+/* Language-dependent contents of a decl. */
+
+struct GTY((variable_size)) lang_decl
+{
+ char dummy;
+};
+
+/* Language-dependent contents of an identifier. This must include a
+ tree_identifier. */
+
+struct GTY(()) lang_identifier
+{
+ struct tree_identifier common;
+};
+
+/* The resulting tree type. */
+
+union GTY((desc ("TREE_CODE (&%h.generic) == IDENTIFIER_NODE"),
+ chain_next ("CODE_CONTAINS_STRUCT (TREE_CODE (&%h.generic), TS_COMMON) ? ((union lang_tree_node *) TREE_CHAIN (&%h.generic)) : NULL")))
+lang_tree_node
+{
+ union tree_node GTY((tag ("0"),
+ desc ("tree_node_structure (&%h)"))) generic;
+ struct lang_identifier GTY((tag ("1"))) identifier;
+};
+
+/* We don't use language_function. */
+
+struct GTY(()) language_function
+{
+ int dummy;
+};
+
+/* GC-marking callback for use from jit_root_tab.
+
+ If there's an active playback context, call its marking method
+ so that it can mark any pointers it references. */
+
+static void my_ggc_walker (void *)
+{
+ if (gcc::jit::active_playback_ctxt)
+ gcc::jit::active_playback_ctxt->gt_ggc_mx ();
+}
+
+const char *dummy;
+
+struct ggc_root_tab jit_root_tab[] =
+ {
+ {
+ &dummy, 1, 0, my_ggc_walker, NULL
+ },
+ LAST_GGC_ROOT_TAB
+ };
+
+/* Language hooks. */
+
+static bool
+jit_langhook_init (void)
+{
+ static bool registered_root_tab = false;
+ if (!registered_root_tab)
+ {
+ ggc_register_root_tab (jit_root_tab);
+ registered_root_tab = true;
+ }
+
+ build_common_tree_nodes (false, false);
+
+ /* I don't know why this has to be done explicitly. */
+ void_list_node = build_tree_list (NULL_TREE, void_type_node);
+
+ build_common_builtin_nodes ();
+
+ /* The default precision for floating point numbers. This is used
+ for floating point constants with abstract type. This may
+ eventually be controllable by a command line option. */
+ mpfr_set_default_prec (256);
+
+ return true;
+}
+
+static void
+jit_langhook_parse_file (void)
+{
+ /* Replay the activity by the client, recorded on the context. */
+ gcc_assert (gcc::jit::active_playback_ctxt);
+ gcc::jit::active_playback_ctxt->replay ();
+}
+
+static tree
+jit_langhook_type_for_mode (enum machine_mode mode, int unsignedp)
+{
+ if (mode == TYPE_MODE (float_type_node))
+ return float_type_node;
+
+ if (mode == TYPE_MODE (double_type_node))
+ return double_type_node;
+
+ if (mode == TYPE_MODE (integer_type_node))
+ return unsignedp ? unsigned_type_node : integer_type_node;
+
+ if (mode == TYPE_MODE (long_integer_type_node))
+ return unsignedp ? long_unsigned_type_node : long_integer_type_node;
+
+ if (COMPLEX_MODE_P (mode))
+ {
+ if (mode == TYPE_MODE (complex_float_type_node))
+ return complex_float_type_node;
+ if (mode == TYPE_MODE (complex_double_type_node))
+ return complex_double_type_node;
+ if (mode == TYPE_MODE (complex_long_double_type_node))
+ return complex_long_double_type_node;
+ if (mode == TYPE_MODE (complex_integer_type_node) && !unsignedp)
+ return complex_integer_type_node;
+ }
+
+ /* gcc_unreachable */
+ return NULL;
+}
+
+static tree
+jit_langhook_type_for_size (unsigned int bits ATTRIBUTE_UNUSED,
+ int unsignedp ATTRIBUTE_UNUSED)
+{
+ gcc_unreachable ();
+ return NULL;
+}
+
+/* Record a builtin function. We just ignore builtin functions. */
+
+static tree
+jit_langhook_builtin_function (tree decl)
+{
+ return decl;
+}
+
+static bool
+jit_langhook_global_bindings_p (void)
+{
+ gcc_unreachable ();
+ return true;
+}
+
+static tree
+jit_langhook_pushdecl (tree decl ATTRIBUTE_UNUSED)
+{
+ gcc_unreachable ();
+}
+
+static tree
+jit_langhook_getdecls (void)
+{
+ return NULL;
+}
+
+static void
+jit_langhook_write_globals (void)
+{
+ /* This is the hook that runs the middle and backends: */
+ symtab->finalize_compilation_unit ();
+}
+
+#undef LANG_HOOKS_NAME
+#define LANG_HOOKS_NAME "libgccjit"
+
+#undef LANG_HOOKS_INIT
+#define LANG_HOOKS_INIT jit_langhook_init
+
+#undef LANG_HOOKS_PARSE_FILE
+#define LANG_HOOKS_PARSE_FILE jit_langhook_parse_file
+
+#undef LANG_HOOKS_TYPE_FOR_MODE
+#define LANG_HOOKS_TYPE_FOR_MODE jit_langhook_type_for_mode
+
+#undef LANG_HOOKS_TYPE_FOR_SIZE
+#define LANG_HOOKS_TYPE_FOR_SIZE jit_langhook_type_for_size
+
+#undef LANG_HOOKS_BUILTIN_FUNCTION
+#define LANG_HOOKS_BUILTIN_FUNCTION jit_langhook_builtin_function
+
+#undef LANG_HOOKS_GLOBAL_BINDINGS_P
+#define LANG_HOOKS_GLOBAL_BINDINGS_P jit_langhook_global_bindings_p
+
+#undef LANG_HOOKS_PUSHDECL
+#define LANG_HOOKS_PUSHDECL jit_langhook_pushdecl
+
+#undef LANG_HOOKS_GETDECLS
+#define LANG_HOOKS_GETDECLS jit_langhook_getdecls
+
+#undef LANG_HOOKS_WRITE_GLOBALS
+#define LANG_HOOKS_WRITE_GLOBALS jit_langhook_write_globals
+
+struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER;
+
+#include "gt-jit-dummy-frontend.h"
+#include "gtype-jit.h"
--- /dev/null
+/* 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
--- /dev/null
+/* 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 */
--- /dev/null
+/* 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 */
--- /dev/null
+/* Internals of libgccjit: classes for playing back recorded API calls.
+ Copyright (C) 2013-2014 Free Software Foundation, Inc.
+ Contributed by David Malcolm <dmalcolm@redhat.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "opts.h"
+#include "tree.h"
+#include "hash-map.h"
+#include "is-a.h"
+#include "plugin-api.h"
+#include "vec.h"
+#include "hashtab.h"
+#include "hash-set.h"
+#include "machmode.h"
+#include "tm.h"
+#include "hard-reg-set.h"
+#include "function.h"
+#include "ipa-ref.h"
+#include "dumpfile.h"
+#include "cgraph.h"
+#include "toplev.h"
+#include "timevar.h"
+#include "tree-cfg.h"
+#include "target.h"
+#include "convert.h"
+#include "stringpool.h"
+#include "stor-layout.h"
+#include "print-tree.h"
+#include "gimplify.h"
+#include "gcc-driver-name.h"
+
+#include "jit-common.h"
+#include "jit-playback.h"
+
+
+/* gcc::jit::playback::context::build_cast uses the convert.h API,
+ which in turn requires the frontend to provide a "convert"
+ function, apparently as a fallback.
+
+ Hence we provide this dummy one, with the requirement that any casts
+ are handled before reaching this. */
+extern tree convert (tree type, tree expr);
+
+tree
+convert (tree dst_type, tree expr)
+{
+ gcc_assert (gcc::jit::active_playback_ctxt);
+ gcc::jit::active_playback_ctxt->add_error (NULL, "unhandled conversion");
+ fprintf (stderr, "input expression:\n");
+ debug_tree (expr);
+ fprintf (stderr, "requested type:\n");
+ debug_tree (dst_type);
+ return error_mark_node;
+}
+
+namespace gcc {
+namespace jit {
+
+/**********************************************************************
+ Playback.
+ **********************************************************************/
+
+/* The constructor for gcc::jit::playback::context. */
+
+playback::context::context (recording::context *ctxt)
+ : m_recording_ctxt (ctxt),
+ m_char_array_type_node (NULL),
+ m_const_char_ptr (NULL)
+{
+ m_functions.create (0);
+ m_source_files.create (0);
+ m_cached_locations.create (0);
+}
+
+/* The destructor for gcc::jit::playback::context. */
+
+playback::context::~context ()
+{
+ if (get_bool_option (GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES))
+ fprintf (stderr, "intermediate files written to %s\n", m_path_tempdir);
+ else
+ {
+ /* Clean up .s/.so and tempdir. */
+ if (m_path_s_file)
+ unlink (m_path_s_file);
+ if (m_path_so_file)
+ unlink (m_path_so_file);
+ if (m_path_tempdir)
+ rmdir (m_path_tempdir);
+ }
+
+ free (m_path_template);
+ /* m_path_tempdir aliases m_path_template, or is NULL, so don't
+ attempt to free it . */
+ free (m_path_c_file);
+ free (m_path_s_file);
+ free (m_path_so_file);
+ m_functions.release ();
+}
+
+/* A playback::context can reference GC-managed pointers. Mark them
+ ("by hand", rather than by gengtype).
+
+ This is called on the active playback context (if any) by the
+ my_ggc_walker hook in the jit_root_table in dummy-frontend.c. */
+
+void
+playback::context::
+gt_ggc_mx ()
+{
+ int i;
+ function *func;
+ FOR_EACH_VEC_ELT (m_functions, i, func)
+ {
+ if (ggc_test_and_set_mark (func))
+ func->gt_ggc_mx ();
+ }
+}
+
+/* Given an enum gcc_jit_types value, get a "tree" type. */
+
+static tree
+get_tree_node_for_type (enum gcc_jit_types type_)
+{
+ switch (type_)
+ {
+ case GCC_JIT_TYPE_VOID:
+ return void_type_node;
+
+ case GCC_JIT_TYPE_VOID_PTR:
+ return ptr_type_node;
+
+ case GCC_JIT_TYPE_BOOL:
+ return boolean_type_node;
+
+ case GCC_JIT_TYPE_CHAR:
+ return char_type_node;
+ case GCC_JIT_TYPE_SIGNED_CHAR:
+ return signed_char_type_node;
+ case GCC_JIT_TYPE_UNSIGNED_CHAR:
+ return unsigned_char_type_node;
+
+ case GCC_JIT_TYPE_SHORT:
+ return short_integer_type_node;
+ case GCC_JIT_TYPE_UNSIGNED_SHORT:
+ return short_unsigned_type_node;
+
+ case GCC_JIT_TYPE_CONST_CHAR_PTR:
+ {
+ tree const_char = build_qualified_type (char_type_node,
+ TYPE_QUAL_CONST);
+ return build_pointer_type (const_char);
+ }
+
+ case GCC_JIT_TYPE_INT:
+ return integer_type_node;
+ case GCC_JIT_TYPE_UNSIGNED_INT:
+ return unsigned_type_node;
+
+ case GCC_JIT_TYPE_LONG:
+ return long_integer_type_node;
+ case GCC_JIT_TYPE_UNSIGNED_LONG:
+ return long_unsigned_type_node;
+
+ case GCC_JIT_TYPE_LONG_LONG:
+ return long_long_integer_type_node;
+ case GCC_JIT_TYPE_UNSIGNED_LONG_LONG:
+ return long_long_unsigned_type_node;
+
+ case GCC_JIT_TYPE_FLOAT:
+ return float_type_node;
+ case GCC_JIT_TYPE_DOUBLE:
+ return double_type_node;
+ case GCC_JIT_TYPE_LONG_DOUBLE:
+ return long_double_type_node;
+
+ case GCC_JIT_TYPE_SIZE_T:
+ return size_type_node;
+
+ case GCC_JIT_TYPE_FILE_PTR:
+ return fileptr_type_node;
+ }
+
+ return NULL;
+}
+
+/* Construct a playback::type instance (wrapping a tree) for the given
+ enum value. */
+
+playback::type *
+playback::context::
+get_type (enum gcc_jit_types type_)
+{
+ tree type_node = get_tree_node_for_type (type_);
+ if (NULL == type_node)
+ {
+ add_error (NULL,
+ "unrecognized (enum gcc_jit_types) value: %i", type_);
+ return NULL;
+ }
+
+ return new type (type_node);
+}
+
+/* Construct a playback::type instance (wrapping a tree) for the given
+ array type. */
+
+playback::type *
+playback::context::
+new_array_type (playback::location *loc,
+ playback::type *element_type,
+ int num_elements)
+{
+ gcc_assert (element_type);
+
+ tree t = build_array_type_nelts (element_type->as_tree (),
+ num_elements);
+ layout_type (t);
+
+ if (loc)
+ set_tree_location (t, loc);
+
+ return new type (t);
+}
+
+/* Construct a playback::field instance (wrapping a tree). */
+
+playback::field *
+playback::context::
+new_field (location *loc,
+ type *type,
+ const char *name)
+{
+ gcc_assert (type);
+ gcc_assert (name);
+
+ /* compare with c/c-decl.c:grokfield and grokdeclarator. */
+ tree decl = build_decl (UNKNOWN_LOCATION, FIELD_DECL,
+ get_identifier (name), type->as_tree ());
+
+ if (loc)
+ set_tree_location (decl, loc);
+
+ return new field (decl);
+}
+
+/* Construct a playback::compound_type instance (wrapping a tree). */
+
+playback::compound_type *
+playback::context::
+new_compound_type (location *loc,
+ const char *name,
+ bool is_struct) /* else is union */
+{
+ gcc_assert (name);
+
+ /* Compare with c/c-decl.c: start_struct. */
+
+ tree t = make_node (is_struct ? RECORD_TYPE : UNION_TYPE);
+ TYPE_NAME (t) = get_identifier (name);
+ TYPE_SIZE (t) = 0;
+
+ if (loc)
+ set_tree_location (t, loc);
+
+ return new compound_type (t);
+}
+
+void
+playback::compound_type::set_fields (const vec<playback::field *> &fields)
+{
+ /* Compare with c/c-decl.c: finish_struct. */
+ tree t = as_tree ();
+
+ tree fieldlist = NULL;
+ for (unsigned i = 0; i < fields.length (); i++)
+ {
+ field *f = fields[i];
+ DECL_CONTEXT (f->as_tree ()) = t;
+ fieldlist = chainon (f->as_tree (), fieldlist);
+ }
+ fieldlist = nreverse (fieldlist);
+ TYPE_FIELDS (t) = fieldlist;
+
+ layout_type (t);
+}
+
+/* Construct a playback::type instance (wrapping a tree) for a function
+ type. */
+
+playback::type *
+playback::context::
+new_function_type (type *return_type,
+ vec<type *> *param_types,
+ int is_variadic)
+{
+ int i;
+ type *param_type;
+
+ tree *arg_types = (tree *)xcalloc(param_types->length (), sizeof(tree*));
+
+ FOR_EACH_VEC_ELT (*param_types, i, param_type)
+ arg_types[i] = param_type->as_tree ();
+
+ tree fn_type;
+ if (is_variadic)
+ fn_type =
+ build_varargs_function_type_array (return_type->as_tree (),
+ param_types->length (),
+ arg_types);
+ else
+ fn_type = build_function_type_array (return_type->as_tree (),
+ param_types->length (),
+ arg_types);
+ free (arg_types);
+
+ return new type (fn_type);
+}
+
+/* Construct a playback::param instance (wrapping a tree). */
+
+playback::param *
+playback::context::
+new_param (location *loc,
+ type *type,
+ const char *name)
+{
+ gcc_assert (type);
+ gcc_assert (name);
+ tree inner = build_decl (UNKNOWN_LOCATION, PARM_DECL,
+ get_identifier (name), type->as_tree ());
+ if (loc)
+ set_tree_location (inner, loc);
+
+ return new param (this, inner);
+}
+
+/* Construct a playback::function instance. */
+
+playback::function *
+playback::context::
+new_function (location *loc,
+ enum gcc_jit_function_kind kind,
+ type *return_type,
+ const char *name,
+ vec<param *> *params,
+ int is_variadic,
+ enum built_in_function builtin_id)
+{
+ int i;
+ param *param;
+
+ //can return_type be NULL?
+ gcc_assert (name);
+
+ tree *arg_types = (tree *)xcalloc(params->length (), sizeof(tree*));
+ FOR_EACH_VEC_ELT (*params, i, param)
+ arg_types[i] = TREE_TYPE (param->as_tree ());
+
+ tree fn_type;
+ if (is_variadic)
+ fn_type = build_varargs_function_type_array (return_type->as_tree (),
+ params->length (), arg_types);
+ else
+ fn_type = build_function_type_array (return_type->as_tree (),
+ params->length (), arg_types);
+ free (arg_types);
+
+ /* FIXME: this uses input_location: */
+ tree fndecl = build_fn_decl (name, fn_type);
+
+ if (loc)
+ set_tree_location (fndecl, loc);
+
+ tree resdecl = build_decl (UNKNOWN_LOCATION, RESULT_DECL,
+ NULL_TREE, return_type->as_tree ());
+ DECL_ARTIFICIAL (resdecl) = 1;
+ DECL_IGNORED_P (resdecl) = 1;
+ DECL_RESULT (fndecl) = resdecl;
+
+ if (builtin_id)
+ {
+ DECL_BUILT_IN_CLASS (fndecl) = BUILT_IN_NORMAL;
+ DECL_FUNCTION_CODE (fndecl) = builtin_id;
+ gcc_assert (loc == NULL);
+ DECL_SOURCE_LOCATION (fndecl) = BUILTINS_LOCATION;
+ }
+
+ if (kind != GCC_JIT_FUNCTION_IMPORTED)
+ {
+ tree param_decl_list = NULL;
+ FOR_EACH_VEC_ELT (*params, i, param)
+ {
+ param_decl_list = chainon (param->as_tree (), param_decl_list);
+ }
+
+ /* The param list was created in reverse order; fix it: */
+ param_decl_list = nreverse (param_decl_list);
+
+ tree t;
+ for (t = param_decl_list; t; t = DECL_CHAIN (t))
+ {
+ DECL_CONTEXT (t) = fndecl;
+ DECL_ARG_TYPE (t) = TREE_TYPE (t);
+ }
+
+ /* Set it up on DECL_ARGUMENTS */
+ DECL_ARGUMENTS(fndecl) = param_decl_list;
+ }
+
+ if (kind == GCC_JIT_FUNCTION_ALWAYS_INLINE)
+ {
+ DECL_DECLARED_INLINE_P (fndecl) = 1;
+
+ /* Add attribute "always_inline": */
+ DECL_ATTRIBUTES (fndecl) =
+ tree_cons (get_identifier ("always_inline"),
+ NULL,
+ DECL_ATTRIBUTES (fndecl));
+ }
+
+ function *func = new function (this, fndecl, kind);
+ m_functions.safe_push (func);
+ return func;
+}
+
+/* Construct a playback::lvalue instance (wrapping a tree). */
+
+playback::lvalue *
+playback::context::
+new_global (location *loc,
+ type *type,
+ const char *name)
+{
+ gcc_assert (type);
+ gcc_assert (name);
+ tree inner = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+ get_identifier (name),
+ type->as_tree ());
+ TREE_PUBLIC (inner) = 1;
+ DECL_COMMON (inner) = 1;
+ DECL_EXTERNAL (inner) = 1;
+
+ if (loc)
+ set_tree_location (inner, loc);
+
+ return new lvalue (this, inner);
+}
+
+/* Construct a playback::rvalue instance (wrapping a tree). */
+
+playback::rvalue *
+playback::context::
+new_rvalue_from_int (type *type,
+ int value)
+{
+ // FIXME: type-checking, or coercion?
+ tree inner_type = type->as_tree ();
+ if (INTEGRAL_TYPE_P (inner_type))
+ {
+ tree inner = build_int_cst (inner_type, value);
+ return new rvalue (this, inner);
+ }
+ else
+ {
+ REAL_VALUE_TYPE real_value;
+ real_from_integer (&real_value, VOIDmode, value, SIGNED);
+ tree inner = build_real (inner_type, real_value);
+ return new rvalue (this, inner);
+ }
+}
+
+/* Construct a playback::rvalue instance (wrapping a tree). */
+
+playback::rvalue *
+playback::context::
+new_rvalue_from_double (type *type,
+ double value)
+{
+ // FIXME: type-checking, or coercion?
+ tree inner_type = type->as_tree ();
+
+ /* We have a "double", we want a REAL_VALUE_TYPE.
+
+ real.c:real_from_target appears to require the representation to be
+ split into 32-bit values, and then sent as an pair of host long
+ ints. */
+ REAL_VALUE_TYPE real_value;
+ union
+ {
+ double as_double;
+ uint32_t as_uint32s[2];
+ } u;
+ u.as_double = value;
+ long int as_long_ints[2];
+ as_long_ints[0] = u.as_uint32s[0];
+ as_long_ints[1] = u.as_uint32s[1];
+ real_from_target (&real_value, as_long_ints, DFmode);
+ tree inner = build_real (inner_type, real_value);
+ return new rvalue (this, inner);
+}
+
+/* Construct a playback::rvalue instance (wrapping a tree). */
+
+playback::rvalue *
+playback::context::
+new_rvalue_from_ptr (type *type,
+ void *value)
+{
+ tree inner_type = type->as_tree ();
+ /* FIXME: how to ensure we have a wide enough type? */
+ tree inner = build_int_cstu (inner_type, (unsigned HOST_WIDE_INT)value);
+ return new rvalue (this, inner);
+}
+
+/* Construct a playback::rvalue instance (wrapping a tree). */
+
+playback::rvalue *
+playback::context::
+new_string_literal (const char *value)
+{
+ tree t_str = build_string (strlen (value), value);
+ gcc_assert (m_char_array_type_node);
+ TREE_TYPE (t_str) = m_char_array_type_node;
+
+ /* Convert to (const char*), loosely based on
+ c/c-typeck.c: array_to_pointer_conversion,
+ by taking address of start of string. */
+ tree t_addr = build1 (ADDR_EXPR, m_const_char_ptr, t_str);
+
+ return new rvalue (this, t_addr);
+}
+
+/* Coerce a tree expression into a boolean tree expression. */
+
+tree
+playback::context::
+as_truth_value (tree expr, location *loc)
+{
+ /* Compare to c-typeck.c:c_objc_common_truthvalue_conversion */
+ tree typed_zero = fold_build1 (CONVERT_EXPR,
+ TREE_TYPE (expr),
+ integer_zero_node);
+ if (loc)
+ set_tree_location (typed_zero, loc);
+
+ expr = build2 (NE_EXPR, integer_type_node, expr, typed_zero);
+ if (loc)
+ set_tree_location (expr, loc);
+
+ return expr;
+}
+
+/* Construct a playback::rvalue instance (wrapping a tree) for a
+ unary op. */
+
+playback::rvalue *
+playback::context::
+new_unary_op (location *loc,
+ enum gcc_jit_unary_op op,
+ type *result_type,
+ rvalue *a)
+{
+ // FIXME: type-checking, or coercion?
+ enum tree_code inner_op;
+
+ gcc_assert (result_type);
+ gcc_assert (a);
+
+ tree node = a->as_tree ();
+ tree inner_result = NULL;
+
+ switch (op)
+ {
+ default:
+ add_error (loc, "unrecognized (enum gcc_jit_unary_op) value: %i", op);
+ return NULL;
+
+ case GCC_JIT_UNARY_OP_MINUS:
+ inner_op = NEGATE_EXPR;
+ break;
+
+ case GCC_JIT_UNARY_OP_BITWISE_NEGATE:
+ inner_op = BIT_NOT_EXPR;
+ break;
+
+ case GCC_JIT_UNARY_OP_LOGICAL_NEGATE:
+ node = as_truth_value (node, loc);
+ inner_result = invert_truthvalue (node);
+ if (loc)
+ set_tree_location (inner_result, loc);
+ return new rvalue (this, inner_result);
+ }
+
+ inner_result = build1 (inner_op,
+ result_type->as_tree (),
+ node);
+ if (loc)
+ set_tree_location (inner_result, loc);
+
+ return new rvalue (this, inner_result);
+}
+
+/* Construct a playback::rvalue instance (wrapping a tree) for a
+ binary op. */
+
+playback::rvalue *
+playback::context::
+new_binary_op (location *loc,
+ enum gcc_jit_binary_op op,
+ type *result_type,
+ rvalue *a, rvalue *b)
+{
+ // FIXME: type-checking, or coercion?
+ enum tree_code inner_op;
+
+ gcc_assert (result_type);
+ gcc_assert (a);
+ gcc_assert (b);
+
+ tree node_a = a->as_tree ();
+ tree node_b = b->as_tree ();
+
+ switch (op)
+ {
+ default:
+ add_error (loc, "unrecognized (enum gcc_jit_binary_op) value: %i", op);
+ return NULL;
+
+ case GCC_JIT_BINARY_OP_PLUS:
+ inner_op = PLUS_EXPR;
+ break;
+
+ case GCC_JIT_BINARY_OP_MINUS:
+ inner_op = MINUS_EXPR;
+ break;
+
+ case GCC_JIT_BINARY_OP_MULT:
+ inner_op = MULT_EXPR;
+ break;
+
+ case GCC_JIT_BINARY_OP_DIVIDE:
+ if (FLOAT_TYPE_P (result_type->as_tree ()))
+ /* Floating-point division: */
+ inner_op = RDIV_EXPR;
+ else
+ /* Truncating to zero: */
+ inner_op = TRUNC_DIV_EXPR;
+ break;
+
+ case GCC_JIT_BINARY_OP_MODULO:
+ inner_op = TRUNC_MOD_EXPR;
+ break;
+
+ case GCC_JIT_BINARY_OP_BITWISE_AND:
+ inner_op = BIT_AND_EXPR;
+ break;
+
+ case GCC_JIT_BINARY_OP_BITWISE_XOR:
+ inner_op = BIT_XOR_EXPR;
+ break;
+
+ case GCC_JIT_BINARY_OP_BITWISE_OR:
+ inner_op = BIT_IOR_EXPR;
+ break;
+
+ case GCC_JIT_BINARY_OP_LOGICAL_AND:
+ node_a = as_truth_value (node_a, loc);
+ node_b = as_truth_value (node_b, loc);
+ inner_op = TRUTH_ANDIF_EXPR;
+ break;
+
+ case GCC_JIT_BINARY_OP_LOGICAL_OR:
+ node_a = as_truth_value (node_a, loc);
+ node_b = as_truth_value (node_b, loc);
+ inner_op = TRUTH_ORIF_EXPR;
+ break;
+
+ case GCC_JIT_BINARY_OP_LSHIFT:
+ inner_op = LSHIFT_EXPR;
+ break;
+
+ case GCC_JIT_BINARY_OP_RSHIFT:
+ inner_op = RSHIFT_EXPR;
+ break;
+ }
+
+ tree inner_expr = build2 (inner_op,
+ result_type->as_tree (),
+ node_a,
+ node_b);
+ if (loc)
+ set_tree_location (inner_expr, loc);
+
+ return new rvalue (this, inner_expr);
+}
+
+/* Construct a playback::rvalue instance (wrapping a tree) for a
+ comparison. */
+
+playback::rvalue *
+playback::context::
+new_comparison (location *loc,
+ enum gcc_jit_comparison op,
+ rvalue *a, rvalue *b)
+{
+ // FIXME: type-checking, or coercion?
+ enum tree_code inner_op;
+
+ gcc_assert (a);
+ gcc_assert (b);
+
+ switch (op)
+ {
+ default:
+ add_error (loc, "unrecognized (enum gcc_jit_comparison) value: %i", op);
+ return NULL;
+
+ case GCC_JIT_COMPARISON_EQ:
+ inner_op = EQ_EXPR;
+ break;
+ case GCC_JIT_COMPARISON_NE:
+ inner_op = NE_EXPR;
+ break;
+ case GCC_JIT_COMPARISON_LT:
+ inner_op = LT_EXPR;
+ break;
+ case GCC_JIT_COMPARISON_LE:
+ inner_op = LE_EXPR;
+ break;
+ case GCC_JIT_COMPARISON_GT:
+ inner_op = GT_EXPR;
+ break;
+ case GCC_JIT_COMPARISON_GE:
+ inner_op = GE_EXPR;
+ break;
+ }
+
+ tree inner_expr = build2 (inner_op,
+ boolean_type_node,
+ a->as_tree (),
+ b->as_tree ());
+ if (loc)
+ set_tree_location (inner_expr, loc);
+ return new rvalue (this, inner_expr);
+}
+
+/* Construct a playback::rvalue instance (wrapping a tree) for a
+ function call. */
+
+playback::rvalue *
+playback::context::
+build_call (location *loc,
+ tree fn_ptr,
+ vec<rvalue *> args)
+{
+ vec<tree, va_gc> *tree_args;
+ vec_alloc (tree_args, args.length ());
+ for (unsigned i = 0; i < args.length (); i++)
+ tree_args->quick_push (args[i]->as_tree ());
+
+ if (loc)
+ set_tree_location (fn_ptr, loc);
+
+ tree fn = TREE_TYPE (fn_ptr);
+ tree fn_type = TREE_TYPE (fn);
+ tree return_type = TREE_TYPE (fn_type);
+
+ return new rvalue (this,
+ build_call_vec (return_type,
+ fn_ptr, tree_args));
+
+ /* see c-typeck.c: build_function_call
+ which calls build_function_call_vec
+
+ which does lots of checking, then:
+ result = build_call_array_loc (loc, TREE_TYPE (fntype),
+ function, nargs, argarray);
+ which is in tree.c
+ (see also build_call_vec)
+ */
+}
+
+/* Construct a playback::rvalue instance (wrapping a tree) for a
+ call to a specific function. */
+
+playback::rvalue *
+playback::context::
+new_call (location *loc,
+ function *func,
+ vec<rvalue *> args)
+{
+ tree fndecl;
+
+ gcc_assert (func);
+
+ fndecl = func->as_fndecl ();
+
+ tree fntype = TREE_TYPE (fndecl);
+
+ tree fn = build1 (ADDR_EXPR, build_pointer_type (fntype), fndecl);
+
+ return build_call (loc, fn, args);
+}
+
+/* Construct a playback::rvalue instance (wrapping a tree) for a
+ call through a function pointer. */
+
+playback::rvalue *
+playback::context::
+new_call_through_ptr (location *loc,
+ rvalue *fn_ptr,
+ vec<rvalue *> args)
+{
+ gcc_assert (fn_ptr);
+ tree t_fn_ptr = fn_ptr->as_tree ();
+
+ return build_call (loc, t_fn_ptr, args);
+}
+
+/* Construct a tree for a cast. */
+
+tree
+playback::context::build_cast (playback::location *loc,
+ playback::rvalue *expr,
+ playback::type *type_)
+{
+ /* For comparison, see:
+ - c/c-typeck.c:build_c_cast
+ - c/c-convert.c: convert
+ - convert.h
+
+ Only some kinds of cast are currently supported here. */
+ tree t_expr = expr->as_tree ();
+ tree t_dst_type = type_->as_tree ();
+ tree t_ret = NULL;
+ t_ret = targetm.convert_to_type (t_dst_type, t_expr);
+ if (t_ret)
+ return t_ret;
+ enum tree_code dst_code = TREE_CODE (t_dst_type);
+ switch (dst_code)
+ {
+ case INTEGER_TYPE:
+ case ENUMERAL_TYPE:
+ t_ret = convert_to_integer (t_dst_type, t_expr);
+ goto maybe_fold;
+
+ case BOOLEAN_TYPE:
+ /* Compare with c_objc_common_truthvalue_conversion and
+ c_common_truthvalue_conversion. */
+ /* For now, convert to: (t_expr != 0) */
+ t_ret = build2 (NE_EXPR, t_dst_type,
+ t_expr, integer_zero_node);
+ goto maybe_fold;
+
+ case REAL_TYPE:
+ t_ret = convert_to_real (t_dst_type, t_expr);
+ goto maybe_fold;
+
+ case POINTER_TYPE:
+ t_ret = build1 (NOP_EXPR, t_dst_type, t_expr);
+ goto maybe_fold;
+
+ default:
+ add_error (loc, "couldn't handle cast during playback");
+ fprintf (stderr, "input expression:\n");
+ debug_tree (t_expr);
+ fprintf (stderr, "requested type:\n");
+ debug_tree (t_dst_type);
+ return error_mark_node;
+
+ maybe_fold:
+ if (TREE_CODE (t_ret) != C_MAYBE_CONST_EXPR)
+ t_ret = fold (t_ret);
+ return t_ret;
+ }
+}
+
+/* Construct a playback::rvalue instance (wrapping a tree) for a
+ cast. */
+
+playback::rvalue *
+playback::context::
+new_cast (playback::location *loc,
+ playback::rvalue *expr,
+ playback::type *type_)
+{
+
+ tree t_cast = build_cast (loc, expr, type_);
+ if (loc)
+ set_tree_location (t_cast, loc);
+ return new rvalue (this, t_cast);
+}
+
+/* Construct a playback::lvalue instance (wrapping a tree) for an
+ array access. */
+
+playback::lvalue *
+playback::context::
+new_array_access (location *loc,
+ rvalue *ptr,
+ rvalue *index)
+{
+ gcc_assert (ptr);
+ gcc_assert (index);
+
+ /* For comparison, see:
+ c/c-typeck.c: build_array_ref
+ c-family/c-common.c: pointer_int_sum
+ */
+ tree t_ptr = ptr->as_tree ();
+ tree t_index = index->as_tree ();
+ tree t_type_ptr = TREE_TYPE (t_ptr);
+ tree t_type_star_ptr = TREE_TYPE (t_type_ptr);
+
+ if (TREE_CODE (t_type_ptr) == ARRAY_TYPE)
+ {
+ tree t_result = build4 (ARRAY_REF, t_type_star_ptr, t_ptr, t_index,
+ NULL_TREE, NULL_TREE);
+ if (loc)
+ set_tree_location (t_result, loc);
+ return new lvalue (this, t_result);
+ }
+ else
+ {
+ /* Convert index to an offset in bytes. */
+ tree t_sizeof = size_in_bytes (t_type_star_ptr);
+ t_index = fold_build1 (CONVERT_EXPR, sizetype, t_index);
+ tree t_offset = build2 (MULT_EXPR, sizetype, t_index, t_sizeof);
+
+ /* Locate (ptr + offset). */
+ tree t_address = build2 (POINTER_PLUS_EXPR, t_type_ptr, t_ptr, t_offset);
+
+ tree t_indirection = build1 (INDIRECT_REF, t_type_star_ptr, t_address);
+ if (loc)
+ {
+ set_tree_location (t_sizeof, loc);
+ set_tree_location (t_offset, loc);
+ set_tree_location (t_address, loc);
+ set_tree_location (t_indirection, loc);
+ }
+
+ return new lvalue (this, t_indirection);
+ }
+}
+
+/* Construct a tree for a field access. */
+
+tree
+playback::context::
+new_field_access (location *loc,
+ tree datum,
+ field *field)
+{
+ gcc_assert (datum);
+ gcc_assert (field);
+
+ /* Compare with c/c-typeck.c:lookup_field, build_indirect_ref, and
+ build_component_ref. */
+ tree type = TREE_TYPE (datum);
+ gcc_assert (type);
+ gcc_assert (TREE_CODE (type) != POINTER_TYPE);
+
+ tree t_field = field->as_tree ();
+ tree ref = build3 (COMPONENT_REF, TREE_TYPE (t_field), datum,
+ t_field, NULL_TREE);
+ if (loc)
+ set_tree_location (ref, loc);
+ return ref;
+}
+
+/* Construct a tree for a dereference. */
+
+tree
+playback::context::
+new_dereference (tree ptr,
+ location *loc)
+{
+ gcc_assert (ptr);
+
+ tree type = TREE_TYPE (TREE_TYPE(ptr));
+ tree datum = build1 (INDIRECT_REF, type, ptr);
+ if (loc)
+ set_tree_location (datum, loc);
+ return datum;
+}
+
+/* Construct a playback::lvalue instance (wrapping a tree) for a
+ field access. */
+
+playback::lvalue *
+playback::lvalue::
+access_field (location *loc,
+ field *field)
+{
+ tree datum = as_tree ();
+ tree ref = get_context ()->new_field_access (loc, datum, field);
+ if (!ref)
+ return NULL;
+ return new lvalue (get_context (), ref);
+}
+
+/* Construct a playback::rvalue instance (wrapping a tree) for a
+ field access. */
+
+playback::rvalue *
+playback::rvalue::
+access_field (location *loc,
+ field *field)
+{
+ tree datum = as_tree ();
+ tree ref = get_context ()->new_field_access (loc, datum, field);
+ if (!ref)
+ return NULL;
+ return new rvalue (get_context (), ref);
+}
+
+/* Construct a playback::lvalue instance (wrapping a tree) for a
+ dereferenced field access. */
+
+playback::lvalue *
+playback::rvalue::
+dereference_field (location *loc,
+ field *field)
+{
+ tree ptr = as_tree ();
+ tree datum = get_context ()->new_dereference (ptr, loc);
+ if (!datum)
+ return NULL;
+ tree ref = get_context ()->new_field_access (loc, datum, field);
+ if (!ref)
+ return NULL;
+ return new lvalue (get_context (), ref);
+}
+
+/* Construct a playback::lvalue instance (wrapping a tree) for a
+ dereference. */
+
+playback::lvalue *
+playback::rvalue::
+dereference (location *loc)
+{
+ tree ptr = as_tree ();
+ tree datum = get_context ()->new_dereference (ptr, loc);
+ return new lvalue (get_context (), datum);
+}
+
+/* Construct a playback::rvalue instance (wrapping a tree) for an
+ address-lookup. */
+
+playback::rvalue *
+playback::lvalue::
+get_address (location *loc)
+{
+ tree t_lvalue = as_tree ();
+ tree t_thistype = TREE_TYPE (t_lvalue);
+ tree t_ptrtype = build_pointer_type (t_thistype);
+ tree ptr = build1 (ADDR_EXPR, t_ptrtype, t_lvalue);
+ if (loc)
+ get_context ()->set_tree_location (ptr, loc);
+ return new rvalue (get_context (), ptr);
+}
+
+/* gcc::jit::playback::wrapper subclasses are GC-managed:
+ allocate them using ggc_internal_cleared_alloc. */
+
+void *
+playback::wrapper::
+operator new (size_t sz)
+{
+ return ggc_internal_cleared_alloc (sz MEM_STAT_INFO);
+}
+
+/* Constructor for gcc:jit::playback::function. */
+
+playback::function::
+function (context *ctxt,
+ tree fndecl,
+ enum gcc_jit_function_kind kind)
+: m_ctxt(ctxt),
+ m_inner_fndecl (fndecl),
+ m_inner_bind_expr (NULL),
+ m_kind (kind)
+{
+ if (m_kind != GCC_JIT_FUNCTION_IMPORTED)
+ {
+ /* Create a BIND_EXPR, and within it, a statement list. */
+ m_stmt_list = alloc_stmt_list ();
+ m_stmt_iter = tsi_start (m_stmt_list);
+ m_inner_block = make_node (BLOCK);
+ m_inner_bind_expr =
+ build3 (BIND_EXPR, void_type_node, NULL, m_stmt_list, m_inner_block);
+ }
+ else
+ {
+ m_inner_block = NULL;
+ m_stmt_list = NULL;
+ }
+}
+
+/* Hand-written GC-marking hook for playback functions. */
+
+void
+playback::function::
+gt_ggc_mx ()
+{
+ gt_ggc_m_9tree_node (m_inner_fndecl);
+ gt_ggc_m_9tree_node (m_inner_bind_expr);
+ gt_ggc_m_9tree_node (m_stmt_list);
+ gt_ggc_m_9tree_node (m_inner_block);
+}
+
+/* Get the return type of a playback function, in tree form. */
+
+tree
+playback::function::
+get_return_type_as_tree () const
+{
+ return TREE_TYPE (TREE_TYPE(m_inner_fndecl));
+}
+
+/* Construct a new local within this playback::function. */
+
+playback::lvalue *
+playback::function::
+new_local (location *loc,
+ type *type,
+ const char *name)
+{
+ gcc_assert (type);
+ gcc_assert (name);
+ tree inner = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+ get_identifier (name),
+ type->as_tree ());
+ DECL_CONTEXT (inner) = this->m_inner_fndecl;
+
+ /* Prepend to BIND_EXPR_VARS: */
+ DECL_CHAIN (inner) = BIND_EXPR_VARS (m_inner_bind_expr);
+ BIND_EXPR_VARS (m_inner_bind_expr) = inner;
+
+ if (loc)
+ set_tree_location (inner, loc);
+ return new lvalue (m_ctxt, inner);
+}
+
+/* Construct a new block within this playback::function. */
+
+playback::block *
+playback::function::
+new_block (const char *name)
+{
+ gcc_assert (m_kind != GCC_JIT_FUNCTION_IMPORTED);
+
+ block *result = new playback::block (this, name);
+ m_blocks.safe_push (result);
+ return result;
+}
+
+/* Build a statement list for the function as a whole out of the
+ lists of statements for the individual blocks, building labels
+ for each block. */
+
+void
+playback::function::
+build_stmt_list ()
+{
+ int i;
+ block *b;
+
+ FOR_EACH_VEC_ELT (m_blocks, i, b)
+ {
+ int j;
+ tree stmt;
+
+ b->m_label_expr = build1 (LABEL_EXPR,
+ void_type_node,
+ b->as_label_decl ());
+ tsi_link_after (&m_stmt_iter, b->m_label_expr, TSI_CONTINUE_LINKING);
+
+ FOR_EACH_VEC_ELT (b->m_stmts, j, stmt)
+ tsi_link_after (&m_stmt_iter, stmt, TSI_CONTINUE_LINKING);
+ }
+}
+
+/* Finish compiling the given function, potentially running the
+ garbage-collector.
+ The function will have a statement list by now.
+ Amongst other things, this gimplifies the statement list,
+ and calls cgraph_node::finalize_function on the function. */
+
+void
+playback::function::
+postprocess ()
+{
+ if (m_ctxt->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE))
+ debug_tree (m_stmt_list);
+
+ /* Do we need this to force cgraphunit.c to output the function? */
+ if (m_kind == GCC_JIT_FUNCTION_EXPORTED)
+ {
+ DECL_EXTERNAL (m_inner_fndecl) = 0;
+ DECL_PRESERVE_P (m_inner_fndecl) = 1;
+ }
+
+ if (m_kind == GCC_JIT_FUNCTION_INTERNAL
+ ||m_kind == GCC_JIT_FUNCTION_ALWAYS_INLINE)
+ {
+ DECL_EXTERNAL (m_inner_fndecl) = 0;
+ TREE_PUBLIC (m_inner_fndecl) = 0;
+ }
+
+ if (m_kind != GCC_JIT_FUNCTION_IMPORTED)
+ {
+ /* Seem to need this in gimple-low.c: */
+ gcc_assert (m_inner_block);
+ DECL_INITIAL (m_inner_fndecl) = m_inner_block;
+
+ /* how to add to function? the following appears to be how to
+ set the body of a m_inner_fndecl: */
+ DECL_SAVED_TREE(m_inner_fndecl) = m_inner_bind_expr;
+
+ /* Ensure that locals appear in the debuginfo. */
+ BLOCK_VARS (m_inner_block) = BIND_EXPR_VARS (m_inner_bind_expr);
+
+ //debug_tree (m_inner_fndecl);
+
+ /* Convert to gimple: */
+ //printf("about to gimplify_function_tree\n");
+ gimplify_function_tree (m_inner_fndecl);
+ //printf("finished gimplify_function_tree\n");
+
+ current_function_decl = m_inner_fndecl;
+ if (m_ctxt->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE))
+ dump_function_to_file (m_inner_fndecl, stderr, TDF_VOPS|TDF_MEMSYMS|TDF_LINENO);
+ //debug_tree (m_inner_fndecl);
+
+ //printf("about to add to cgraph\n");
+ /* Add to cgraph: */
+ cgraph_node::finalize_function (m_inner_fndecl, false);
+ /* This can trigger a collection, so we need to have all of
+ the funcs as roots. */
+
+ current_function_decl = NULL;
+ }
+}
+
+/* Add an eval of the rvalue to the function's statement list. */
+
+void
+playback::block::
+add_eval (location *loc,
+ rvalue *rvalue)
+{
+ gcc_assert (rvalue);
+
+ if (loc)
+ set_tree_location (rvalue->as_tree (), loc);
+
+ add_stmt (rvalue->as_tree ());
+}
+
+/* Add an assignment to the function's statement list. */
+
+void
+playback::block::
+add_assignment (location *loc,
+ lvalue *lvalue,
+ rvalue *rvalue)
+{
+ gcc_assert (lvalue);
+ gcc_assert (rvalue);
+
+ tree t_lvalue = lvalue->as_tree ();
+ tree t_rvalue = rvalue->as_tree ();
+ if (TREE_TYPE (t_rvalue) != TREE_TYPE (t_lvalue))
+ {
+ t_rvalue = build1 (CONVERT_EXPR,
+ TREE_TYPE (t_lvalue),
+ t_rvalue);
+ if (loc)
+ set_tree_location (t_rvalue, loc);
+ }
+
+ tree stmt =
+ build2 (MODIFY_EXPR, TREE_TYPE (t_lvalue),
+ t_lvalue, t_rvalue);
+ if (loc)
+ set_tree_location (stmt, loc);
+ add_stmt (stmt);
+}
+
+/* Add a comment to the function's statement list.
+ For now this is done by adding a dummy label. */
+
+void
+playback::block::
+add_comment (location *loc,
+ const char *text)
+{
+ /* Wrap the text in C-style comment delimiters. */
+ size_t sz =
+ (3 /* opening delim */
+ + strlen (text)
+ + 3 /* closing delim */
+ + 1 /* terminator */);
+ char *wrapped = (char *)ggc_internal_alloc (sz);
+ snprintf (wrapped, sz, "/* %s */", text);
+
+ /* For now we simply implement this by adding a dummy label with a name
+ containing the given text. */
+ tree identifier = get_identifier (wrapped);
+ tree label_decl = build_decl (UNKNOWN_LOCATION, LABEL_DECL,
+ identifier, void_type_node);
+ DECL_CONTEXT (label_decl) = m_func->as_fndecl ();
+
+ tree label_expr = build1 (LABEL_EXPR, void_type_node, label_decl);
+ if (loc)
+ set_tree_location (label_expr, loc);
+ add_stmt (label_expr);
+}
+
+/* Add a conditional jump statement to the function's statement list. */
+
+void
+playback::block::
+add_conditional (location *loc,
+ rvalue *boolval,
+ block *on_true,
+ block *on_false)
+{
+ gcc_assert (boolval);
+ gcc_assert (on_true);
+ gcc_assert (on_false);
+
+ /* COND_EXPR wants statement lists for the true/false operands, but we
+ want labels.
+ Shim it by creating jumps to the labels */
+ tree true_jump = build1 (GOTO_EXPR, void_type_node,
+ on_true->as_label_decl ());
+ if (loc)
+ set_tree_location (true_jump, loc);
+
+ tree false_jump = build1 (GOTO_EXPR, void_type_node,
+ on_false->as_label_decl ());
+ if (loc)
+ set_tree_location (false_jump, loc);
+
+ tree stmt =
+ build3 (COND_EXPR, void_type_node, boolval->as_tree (),
+ true_jump, false_jump);
+ if (loc)
+ set_tree_location (stmt, loc);
+ add_stmt (stmt);
+}
+
+/* Add an unconditional jump statement to the function's statement list. */
+
+void
+playback::block::
+add_jump (location *loc,
+ block *target)
+{
+ gcc_assert (target);
+
+ // see c_finish_loop
+ //tree top = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
+ //add_stmt (top);
+
+ //tree stmt = build_and_jump (&LABEL_EXPR_LABEL (target->label_));
+ TREE_USED (target->as_label_decl ()) = 1;
+ tree stmt = build1 (GOTO_EXPR, void_type_node, target->as_label_decl ());
+ if (loc)
+ set_tree_location (stmt, loc);
+ add_stmt (stmt);
+
+ /*
+ from c-typeck.c:
+tree
+c_finish_goto_label (location_t loc, tree label)
+{
+ tree decl = lookup_label_for_goto (loc, label);
+ if (!decl)
+ return NULL_TREE;
+ TREE_USED (decl) = 1;
+ {
+ tree t = build1 (GOTO_EXPR, void_type_node, decl);
+ SET_EXPR_LOCATION (t, loc);
+ return add_stmt (t);
+ }
+}
+ */
+
+}
+
+/* Add a return statement to the function's statement list. */
+
+void
+playback::block::
+add_return (location *loc,
+ rvalue *rvalue)
+{
+ tree modify_retval = NULL;
+ tree return_type = m_func->get_return_type_as_tree ();
+ if (rvalue)
+ {
+ tree t_lvalue = DECL_RESULT (m_func->as_fndecl ());
+ tree t_rvalue = rvalue->as_tree ();
+ if (TREE_TYPE (t_rvalue) != TREE_TYPE (t_lvalue))
+ t_rvalue = build1 (CONVERT_EXPR,
+ TREE_TYPE (t_lvalue),
+ t_rvalue);
+ modify_retval = build2 (MODIFY_EXPR, return_type,
+ t_lvalue, t_rvalue);
+ if (loc)
+ set_tree_location (modify_retval, loc);
+ }
+ tree return_stmt = build1 (RETURN_EXPR, return_type,
+ modify_retval);
+ if (loc)
+ set_tree_location (return_stmt, loc);
+
+ add_stmt (return_stmt);
+}
+
+/* Constructor for gcc::jit::playback::block. */
+
+playback::block::
+block (function *func,
+ const char *name)
+: m_func (func),
+ m_stmts ()
+{
+ tree identifier;
+
+ gcc_assert (func);
+ // name can be NULL
+ if (name)
+ identifier = get_identifier (name);
+ else
+ identifier = NULL;
+ m_label_decl = build_decl (UNKNOWN_LOCATION, LABEL_DECL,
+ identifier, void_type_node);
+ DECL_CONTEXT (m_label_decl) = func->as_fndecl ();
+ m_label_expr = NULL;
+}
+
+/* Construct a tempdir path template suitable for use by mkdtemp
+ e.g. "/tmp/libgccjit-XXXXXX", but respecting the rules in
+ libiberty's choose_tempdir rather than hardcoding "/tmp/".
+
+ The memory is allocated using malloc and must be freed.
+ Aborts the process if allocation fails. */
+
+static char *
+make_tempdir_path_template ()
+{
+ const char *tmpdir_buf;
+ size_t tmpdir_len;
+ const char *file_template_buf;
+ size_t file_template_len;
+ char *result;
+
+ /* The result of choose_tmpdir is a cached buffer within libiberty, so
+ we must *not* free it. */
+ tmpdir_buf = choose_tmpdir ();
+
+ /* choose_tmpdir aborts on malloc failure. */
+ gcc_assert (tmpdir_buf);
+
+ tmpdir_len = strlen (tmpdir_buf);
+ /* tmpdir_buf should now have a dir separator as the final byte. */
+ gcc_assert (tmpdir_len > 0);
+ gcc_assert (tmpdir_buf[tmpdir_len - 1] == DIR_SEPARATOR);
+
+ file_template_buf = "libgccjit-XXXXXX";
+ file_template_len = strlen (file_template_buf);
+
+ result = XNEWVEC (char, tmpdir_len + file_template_len + 1);
+ strcpy (result, tmpdir_buf);
+ strcpy (result + tmpdir_len, file_template_buf);
+
+ return result;
+}
+
+/* Compile a playback::context:
+
+ - Use the context's options to cconstruct command-line options, and
+ call into the rest of GCC (toplev::main).
+ - Assuming it succeeds, we have a .s file; we want a .so file.
+ Invoke another gcc to convert the .s file to a .so file.
+ - dlopen the .so file
+ - Wrap the result up as a playback::result and return it. */
+
+result *
+playback::context::
+compile ()
+{
+ void *handle = NULL;
+ const char *ctxt_progname;
+ result *result_obj = NULL;
+ const char *fake_args[20];
+ unsigned int num_args;
+
+ m_path_template = make_tempdir_path_template ();
+ if (!m_path_template)
+ return NULL;
+
+ /* Create tempdir using mkdtemp. This is created with 0700 perms and
+ is unique. Hence no other (non-root) users should have access to
+ the paths within it. */
+ m_path_tempdir = mkdtemp (m_path_template);
+ if (!m_path_tempdir)
+ return NULL;
+ m_path_c_file = concat (m_path_tempdir, "/fake.c", NULL);
+ m_path_s_file = concat (m_path_tempdir, "/fake.s", NULL);
+ m_path_so_file = concat (m_path_tempdir, "/fake.so", NULL);
+
+ /* Call into the rest of gcc.
+ For now, we have to assemble command-line options to pass into
+ toplev::main, so that they can be parsed. */
+
+ /* Pass in user-provided program name as argv0, if any, so that it
+ makes it into GCC's "progname" global, used in various diagnostics. */
+ ctxt_progname = get_str_option (GCC_JIT_STR_OPTION_PROGNAME);
+ fake_args[0] =
+ (ctxt_progname ? ctxt_progname : "libgccjit.so");
+
+ fake_args[1] = m_path_c_file;
+ num_args = 2;
+
+#define ADD_ARG(arg) \
+ do \
+ { \
+ gcc_assert(num_args < sizeof(fake_args)/sizeof(char*)); \
+ fake_args[num_args++] = arg; \
+ } \
+ while (0)
+
+ ADD_ARG ("-fPIC");
+
+ /* Handle int options: */
+ switch (get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL))
+ {
+ default:
+ add_error (NULL,
+ "unrecognized optimization level: %i",
+ get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL));
+ return NULL;
+
+ case 0:
+ ADD_ARG ("-O0");
+ break;
+
+ case 1:
+ ADD_ARG ("-O1");
+ break;
+
+ case 2:
+ ADD_ARG ("-O2");
+ break;
+
+ case 3:
+ ADD_ARG ("-O3");
+ break;
+ }
+ /* What about -Os? */
+
+ /* Handle bool options: */
+ if (get_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO))
+ ADD_ARG ("-g");
+
+ /* Suppress timing (and other) info. */
+ if (!get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_SUMMARY))
+ {
+ ADD_ARG ("-quiet");
+ quiet_flag = 1;
+ }
+
+ /* Aggressively garbage-collect, to shake out bugs: */
+ if (get_bool_option (GCC_JIT_BOOL_OPTION_SELFCHECK_GC))
+ {
+ ADD_ARG ("--param");
+ ADD_ARG ("ggc-min-expand=0");
+ ADD_ARG ("--param");
+ ADD_ARG ("ggc-min-heapsize=0");
+ }
+
+ if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING))
+ {
+ ADD_ARG ("-fdump-tree-all");
+ ADD_ARG ("-fdump-rtl-all");
+ ADD_ARG ("-fdump-ipa-all");
+ }
+
+ toplev toplev (false);
+
+ toplev.main (num_args, const_cast <char **> (fake_args));
+ toplev.finalize ();
+
+ active_playback_ctxt = NULL;
+
+ if (errors_occurred ())
+ return NULL;
+
+ if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE))
+ dump_generated_code ();
+
+ /* Gross hacks follow:
+ We have a .s file; we want a .so file.
+ We could reuse parts of gcc/gcc.c to do this.
+ For now, just use the driver binary from the install, as
+ named in gcc-driver-name.h
+ e.g. "x86_64-unknown-linux-gnu-gcc-5.0.0".
+ */
+ {
+ auto_timevar assemble_timevar (TV_ASSEMBLE);
+ const char *errmsg;
+ const char *argv[7];
+ int exit_status = 0;
+ int err = 0;
+ const char *gcc_driver_name = GCC_DRIVER_NAME;
+
+ argv[0] = gcc_driver_name;
+ argv[1] = "-shared";
+ /* The input: assembler. */
+ argv[2] = m_path_s_file;
+ /* The output: shared library. */
+ argv[3] = "-o";
+ argv[4] = m_path_so_file;
+
+ /* Don't use the linker plugin.
+ If running with just a "make" and not a "make install", then we'd
+ run into
+ "fatal error: -fuse-linker-plugin, but liblto_plugin.so not found"
+ libto_plugin is a .la at build time, with it becoming installed with
+ ".so" suffix: i.e. it doesn't exist with a .so suffix until install
+ time. */
+ argv[5] = "-fno-use-linker-plugin";
+
+ /* pex argv arrays are NULL-terminated. */
+ argv[6] = NULL;
+
+ errmsg = pex_one (PEX_SEARCH, /* int flags, */
+ gcc_driver_name,
+ const_cast<char * const *> (argv),
+ ctxt_progname, /* const char *pname */
+ NULL, /* const char *outname */
+ NULL, /* const char *errname */
+ &exit_status, /* int *status */
+ &err); /* int *err*/
+ if (errmsg)
+ {
+ add_error (NULL, "error invoking gcc driver: %s", errmsg);
+ return NULL;
+ }
+
+ /* pex_one can return a NULL errmsg when the executable wasn't
+ found (or doesn't exist), so trap these cases also. */
+ if (exit_status || err)
+ {
+ add_error (NULL,
+ "error invoking gcc driver: exit_status: %i err: %i",
+ exit_status, err);
+ add_error (NULL,
+ "whilst attempting to run a driver named: %s",
+ gcc_driver_name);
+ add_error (NULL,
+ "PATH was: %s",
+ getenv ("PATH"));
+ return NULL;
+ }
+ }
+
+ // TODO: split out assembles vs linker
+
+ /* dlopen the .so file. */
+ {
+ auto_timevar load_timevar (TV_LOAD);
+
+ const char *error;
+
+ /* Clear any existing error. */
+ dlerror ();
+
+ handle = dlopen (m_path_so_file, RTLD_NOW | RTLD_LOCAL);
+ if ((error = dlerror()) != NULL) {
+ add_error (NULL, "%s", error);
+ }
+ if (handle)
+ result_obj = new result (handle);
+ else
+ result_obj = NULL;
+ }
+
+ return result_obj;
+}
+
+/* Top-level hook for playing back a recording context.
+
+ This plays back m_recording_ctxt, and, if no errors
+ occurred builds statement lists for and then postprocesses
+ every function in the result. */
+
+void
+playback::context::
+replay ()
+{
+ /* Adapted from c-common.c:c_common_nodes_and_builtins. */
+ tree array_domain_type = build_index_type (size_int (200));
+ m_char_array_type_node
+ = build_array_type (char_type_node, array_domain_type);
+
+ m_const_char_ptr
+ = build_pointer_type (build_qualified_type (char_type_node,
+ TYPE_QUAL_CONST));
+
+ /* Replay the recorded events: */
+ timevar_push (TV_JIT_REPLAY);
+
+ m_recording_ctxt->replay_into (this);
+
+ /* Clean away the temporary references from recording objects
+ to playback objects. We have to do this now since the
+ latter are GC-allocated, but the former don't mark these
+ refs. Hence we must stop using them before the GC can run. */
+ m_recording_ctxt->disassociate_from_playback ();
+
+ timevar_pop (TV_JIT_REPLAY);
+
+ if (!errors_occurred ())
+ {
+ int i;
+ function *func;
+
+ /* No GC can happen yet; process the cached source locations. */
+ handle_locations ();
+
+ /* We've now created tree nodes for the stmts in the various blocks
+ in each function, but we haven't built each function's single stmt
+ list yet. Do so now. */
+ FOR_EACH_VEC_ELT (m_functions, i, func)
+ func->build_stmt_list ();
+
+ /* No GC can have happened yet. */
+
+ /* Postprocess the functions. This could trigger GC. */
+ FOR_EACH_VEC_ELT (m_functions, i, func)
+ {
+ gcc_assert (func);
+ func->postprocess ();
+ }
+ }
+}
+
+/* Dump the generated .s file to stderr. */
+
+void
+playback::context::
+dump_generated_code ()
+{
+ char buf[4096];
+ size_t sz;
+ FILE *f_in = fopen (m_path_s_file, "r");
+ if (!f_in)
+ return;
+
+ while ( (sz = fread (buf, 1, sizeof (buf), f_in)) )
+ fwrite (buf, 1, sz, stderr);
+
+ fclose (f_in);
+}
+
+/* qsort comparator for comparing pairs of playback::source_line *,
+ ordering them by line number. */
+
+static int
+line_comparator (const void *lhs, const void *rhs)
+{
+ const playback::source_line *line_lhs = \
+ *static_cast<const playback::source_line * const*> (lhs);
+ const playback::source_line *line_rhs = \
+ *static_cast<const playback::source_line * const*> (rhs);
+ return line_lhs->get_line_num () - line_rhs->get_line_num ();
+}
+
+/* qsort comparator for comparing pairs of playback::location *,
+ ordering them by column number. */
+
+static int
+location_comparator (const void *lhs, const void *rhs)
+{
+ const playback::location *loc_lhs = \
+ *static_cast<const playback::location * const *> (lhs);
+ const playback::location *loc_rhs = \
+ *static_cast<const playback::location * const *> (rhs);
+ return loc_lhs->get_column_num () - loc_rhs->get_column_num ();
+}
+
+/* Our API allows locations to be created in arbitrary orders, but the
+ linemap API requires locations to be created in ascending order
+ as if we were tokenizing files.
+
+ This hook sorts all of the the locations that have been created, and
+ calls into the linemap API, creating linemap entries in sorted order
+ for our locations. */
+
+void
+playback::context::
+handle_locations ()
+{
+ /* Create the source code locations, following the ordering rules
+ imposed by the linemap API.
+
+ line_table is a global. */
+ int i;
+ source_file *file;
+
+ FOR_EACH_VEC_ELT (m_source_files, i, file)
+ {
+ linemap_add (line_table, LC_ENTER, false, file->get_filename (), 0);
+
+ /* Sort lines by ascending line numbers. */
+ file->m_source_lines.qsort (&line_comparator);
+
+ int j;
+ source_line *line;
+ FOR_EACH_VEC_ELT (file->m_source_lines, j, line)
+ {
+ int k;
+ location *loc;
+
+ /* Sort locations in line by ascending column numbers. */
+ line->m_locations.qsort (&location_comparator);
+
+ /* Determine maximum column within this line. */
+ gcc_assert (line->m_locations.length () > 0);
+ location *final_column =
+ line->m_locations[line->m_locations.length () - 1];
+ int max_col = final_column->get_column_num ();
+
+ linemap_line_start (line_table, line->get_line_num (), max_col);
+ FOR_EACH_VEC_ELT (line->m_locations, k, loc)
+ {
+ loc->m_srcloc = \
+ linemap_position_for_column (line_table, loc->get_column_num ());
+ }
+ }
+
+ linemap_add (line_table, LC_LEAVE, false, NULL, 0);
+ }
+
+ /* line_table should now be populated; every playback::location should
+ now have an m_srcloc. */
+
+ /* Now assign them to tree nodes as appropriate. */
+ std::pair<tree, location *> *cached_location;
+
+ FOR_EACH_VEC_ELT (m_cached_locations, i, cached_location)
+ {
+ tree t = cached_location->first;
+ source_location srcloc = cached_location->second->m_srcloc;
+
+ /* This covers expressions: */
+ if (CAN_HAVE_LOCATION_P (t))
+ SET_EXPR_LOCATION (t, srcloc);
+ else if (CODE_CONTAINS_STRUCT(TREE_CODE(t), TS_DECL_MINIMAL))
+ DECL_SOURCE_LOCATION (t) = srcloc;
+ else
+ {
+ /* Don't know how to set location on this node. */
+ }
+ }
+}
+
+/* We handle errors on a playback::context by adding them to the
+ corresponding recording::context. */
+
+void
+playback::context::
+add_error (location *loc, const char *fmt, ...)
+{
+ va_list ap;
+ va_start (ap, fmt);
+ m_recording_ctxt->add_error_va (loc ? loc->get_recording_loc () : NULL,
+ fmt, ap);
+ va_end (ap);
+}
+
+/* We handle errors on a playback::context by adding them to the
+ corresponding recording::context. */
+
+void
+playback::context::
+add_error_va (location *loc, const char *fmt, va_list ap)
+{
+ m_recording_ctxt->add_error_va (loc ? loc->get_recording_loc () : NULL,
+ fmt, ap);
+}
+
+/* Constructor for gcc::jit::playback::result. */
+
+result::
+result(void *dso_handle)
+ : m_dso_handle(dso_handle)
+{
+}
+
+/* gcc::jit::playback::result's destructor.
+
+ Called implicitly by gcc_jit_result_release. */
+
+result::~result()
+{
+ dlclose (m_dso_handle);
+}
+
+/* Attempt to locate the given function by name within the
+ playback::result, using dlsym.
+
+ Implements the post-error-checking part of
+ gcc_jit_result_get_code. */
+
+void *
+result::
+get_code (const char *funcname)
+{
+ void *code;
+ const char *error;
+
+ /* Clear any existing error. */
+ dlerror ();
+
+ code = dlsym (m_dso_handle, funcname);
+
+ if ((error = dlerror()) != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+
+ return code;
+}
+
+/* Dealing with the linemap API. */
+
+/* Construct a playback::location for a recording::location, if it
+ doesn't exist already. */
+
+playback::location *
+playback::context::
+new_location (recording::location *rloc,
+ const char *filename,
+ int line,
+ int column)
+{
+ /* Get the source_file for filename, creating if necessary. */
+ source_file *src_file = get_source_file (filename);
+ /* Likewise for the line within the file. */
+ source_line *src_line = src_file->get_source_line (line);
+ /* Likewise for the column within the line. */
+ location *loc = src_line->get_location (rloc, column);
+ return loc;
+}
+
+/* Deferred setting of the location for a given tree, by adding the
+ (tree, playback::location) pair to a list of deferred associations.
+ We will actually set the location on the tree later on once
+ the source_location for the playback::location exists. */
+
+void
+playback::context::
+set_tree_location (tree t, location *loc)
+{
+ gcc_assert (loc);
+ m_cached_locations.safe_push (std::make_pair (t, loc));
+}
+
+
+/* Construct a playback::source_file for the given source
+ filename, if it doesn't exist already. */
+
+playback::source_file *
+playback::context::
+get_source_file (const char *filename)
+{
+ /* Locate the file.
+ For simplicitly, this is currently a linear search.
+ Replace with a hash if this shows up in the profile. */
+ int i;
+ source_file *file;
+ tree ident_filename = get_identifier (filename);
+
+ FOR_EACH_VEC_ELT (m_source_files, i, file)
+ if (file->filename_as_tree () == ident_filename)
+ return file;
+
+ /* Not found. */
+ file = new source_file (ident_filename);
+ m_source_files.safe_push (file);
+ return file;
+}
+
+/* Constructor for gcc::jit::playback::source_file. */
+
+playback::source_file::source_file (tree filename) :
+ m_source_lines (),
+ m_filename (filename)
+{
+}
+
+/* Construct a playback::source_line for the given line
+ within this source file, if one doesn't exist already. */
+
+playback::source_line *
+playback::source_file::
+get_source_line (int line_num)
+{
+ /* Locate the line.
+ For simplicitly, this is currently a linear search.
+ Replace with a hash if this shows up in the profile. */
+ int i;
+ source_line *line;
+
+ FOR_EACH_VEC_ELT (m_source_lines, i, line)
+ if (line->get_line_num () == line_num)
+ return line;
+
+ /* Not found. */
+ line = new source_line (this, line_num);
+ m_source_lines.safe_push (line);
+ return line;
+}
+
+/* Constructor for gcc::jit::playback::source_line. */
+
+playback::source_line::source_line (source_file *file, int line_num) :
+ m_locations (),
+ m_source_file (file),
+ m_line_num (line_num)
+{
+}
+
+/* Construct a playback::location for the given column
+ within this line of a specific source file, if one doesn't exist
+ already. */
+
+playback::location *
+playback::source_line::
+get_location (recording::location *rloc, int column_num)
+{
+ int i;
+ location *loc;
+
+ /* Another linear search that probably should be a hash table. */
+ FOR_EACH_VEC_ELT (m_locations, i, loc)
+ if (loc->get_column_num () == column_num)
+ return loc;
+
+ /* Not found. */
+ loc = new location (rloc, this, column_num);
+ m_locations.safe_push (loc);
+ return loc;
+}
+
+/* Constructor for gcc::jit::playback::location. */
+
+playback::location::location (recording::location *loc,
+ source_line *line,
+ int column_num) :
+ m_srcloc (UNKNOWN_LOCATION),
+ m_recording_loc (loc),
+ m_line (line),
+ m_column_num(column_num)
+{
+}
+
+/* The active gcc::jit::playback::context instance. This is a singleton,
+ guarded by jit_mutex. */
+
+playback::context *active_playback_ctxt;
+
+} // namespace gcc::jit
+
+} // namespace gcc
--- /dev/null
+/* 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 */
+
--- /dev/null
+/* 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 (),
+ ¶m_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 (),
+ ¶ms,
+ 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
--- /dev/null
+/* 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 */
+
--- /dev/null
+/* 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> ¶ms,
+ 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> ¶ms,
+ int is_variadic,
+ location loc)
+{
+ /* Treat std::vector as an array, relying on it not being resized: */
+ param *as_array_of_wrappers = ¶ms[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 */
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* A pure C API to enable client code to embed GCC as a JIT-compiler.
+ Copyright (C) 2013-2014 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#ifndef LIBGCCJIT_H
+#define LIBGCCJIT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/**********************************************************************
+ Data structures.
+ **********************************************************************/
+/* All structs within the API are opaque. */
+
+/* A gcc_jit_context encapsulates the state of a compilation. It goes
+ through two states:
+
+ (1) "initial", during which you can set up options on it, and add
+ types, functions and code, using the API below.
+ Invoking gcc_jit_context_compile on it transitions it to the
+ "after compilation" state.
+
+ (2) "after compilation", when you can call gcc_jit_context_release to
+ clean up. */
+typedef struct gcc_jit_context gcc_jit_context;
+
+/* A gcc_jit_result encapsulates the result of a compilation. */
+typedef struct gcc_jit_result gcc_jit_result;
+
+/* An object created within a context. Such objects are automatically
+ cleaned up when the context is released.
+
+ The class hierarchy looks like this:
+
+ +- gcc_jit_object
+ +- gcc_jit_location
+ +- gcc_jit_type
+ +- gcc_jit_struct
+ +- gcc_jit_field
+ +- gcc_jit_function
+ +- gcc_jit_block
+ +- gcc_jit_rvalue
+ +- gcc_jit_lvalue
+ +- gcc_jit_param
+*/
+typedef struct gcc_jit_object gcc_jit_object;
+
+/* A gcc_jit_location encapsulates a source code location, so that
+ you can (optionally) associate locations in your language with
+ statements in the JIT-compiled code, allowing the debugger to
+ single-step through your language.
+
+ Note that to do so, you also need to enable
+ GCC_JIT_BOOL_OPTION_DEBUGINFO
+ on the gcc_jit_context.
+
+ gcc_jit_location instances are optional; you can always pass
+ NULL. */
+typedef struct gcc_jit_location gcc_jit_location;
+
+/* A gcc_jit_type encapsulates a type e.g. "int" or a "struct foo*". */
+typedef struct gcc_jit_type gcc_jit_type;
+
+/* A gcc_jit_field encapsulates a field within a struct; it is used
+ when creating a struct type (using gcc_jit_context_new_struct_type).
+ Fields cannot be shared between structs. */
+typedef struct gcc_jit_field gcc_jit_field;
+
+/* A gcc_jit_struct encapsulates a struct type, either one that we have
+ the layout for, or an opaque type. */
+typedef struct gcc_jit_struct gcc_jit_struct;
+
+/* A gcc_jit_function encapsulates a function: either one that you're
+ creating yourself, or a reference to one that you're dynamically
+ linking to within the rest of the process. */
+typedef struct gcc_jit_function gcc_jit_function;
+
+/* A gcc_jit_block encapsulates a "basic block" of statements within a
+ function (i.e. with one entry point and one exit point).
+
+ Every block within a function must be terminated with a conditional,
+ a branch, or a return.
+
+ The blocks within a function form a directed graph.
+
+ The entrypoint to the function is the first block created within
+ it.
+
+ All of the blocks in a function must be reachable via some path from
+ the first block.
+
+ It's OK to have more than one "return" from a function (i.e. multiple
+ blocks that terminate by returning). */
+typedef struct gcc_jit_block gcc_jit_block;
+
+/* A gcc_jit_rvalue is an expression within your code, with some type. */
+typedef struct gcc_jit_rvalue gcc_jit_rvalue;
+
+/* A gcc_jit_lvalue is a storage location within your code (e.g. a
+ variable, a parameter, etc). It is also a gcc_jit_rvalue; use
+ gcc_jit_lvalue_as_rvalue to cast. */
+typedef struct gcc_jit_lvalue gcc_jit_lvalue;
+
+/* A gcc_jit_param is a function parameter, used when creating a
+ gcc_jit_function. It is also a gcc_jit_lvalue (and thus also an
+ rvalue); use gcc_jit_param_as_lvalue to convert. */
+typedef struct gcc_jit_param gcc_jit_param;
+
+/* Acquire a JIT-compilation context. */
+extern gcc_jit_context *
+gcc_jit_context_acquire (void);
+
+/* Release the context. After this call, it's no longer valid to use
+ the ctxt. */
+extern void
+gcc_jit_context_release (gcc_jit_context *ctxt);
+
+/* Options taking string values. */
+enum gcc_jit_str_option
+{
+ /* The name of the program, for use as a prefix when printing error
+ messages to stderr. If NULL, or default, "libgccjit.so" is used. */
+ GCC_JIT_STR_OPTION_PROGNAME,
+
+ GCC_JIT_NUM_STR_OPTIONS
+};
+
+/* Options taking int values. */
+enum gcc_jit_int_option
+{
+ /* How much to optimize the code.
+ Valid values are 0-3, corresponding to GCC's command-line options
+ -O0 through -O3.
+
+ The default value is 0 (unoptimized). */
+ GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL,
+
+ GCC_JIT_NUM_INT_OPTIONS
+};
+
+/* Options taking boolean values.
+ These all default to "false". */
+enum gcc_jit_bool_option
+{
+ /* If true, gcc_jit_context_compile will attempt to do the right
+ thing so that if you attach a debugger to the process, it will
+ be able to inspect variables and step through your code.
+
+ Note that you can't step through code unless you set up source
+ location information for the code (by creating and passing in
+ gcc_jit_location instances). */
+ GCC_JIT_BOOL_OPTION_DEBUGINFO,
+
+ /* If true, gcc_jit_context_compile will dump its initial "tree"
+ representation of your code to stderr (before any
+ optimizations). */
+ GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE,
+
+ /* If true, gcc_jit_context_compile will dump the "gimple"
+ representation of your code to stderr, before any optimizations
+ are performed. The dump resembles C code. */
+ GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE,
+
+ /* If true, gcc_jit_context_compile will dump the final
+ generated code to stderr, in the form of assembly language. */
+ GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE,
+
+ /* If true, gcc_jit_context_compile will print information to stderr
+ on the actions it is performing, followed by a profile showing
+ the time taken and memory usage of each phase.
+ */
+ GCC_JIT_BOOL_OPTION_DUMP_SUMMARY,
+
+ /* If true, gcc_jit_context_compile will dump copious
+ amount of information on what it's doing to various
+ files within a temporary directory. Use
+ GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES (see below) to
+ see the results. The files are intended to be human-readable,
+ but the exact files and their formats are subject to change.
+ */
+ GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING,
+
+ /* If true, libgccjit will aggressively run its garbage collector, to
+ shake out bugs (greatly slowing down the compile). This is likely
+ to only be of interest to developers *of* the library. It is
+ used when running the selftest suite. */
+ GCC_JIT_BOOL_OPTION_SELFCHECK_GC,
+
+ /* If true, gcc_jit_context_release will not clean up
+ intermediate files written to the filesystem, and will display
+ their location on stderr. */
+ GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES,
+
+ GCC_JIT_NUM_BOOL_OPTIONS
+};
+
+/* Set a string option on the given context.
+
+ The context directly stores the (const char *), so the passed string
+ must outlive the context. */
+extern void
+gcc_jit_context_set_str_option (gcc_jit_context *ctxt,
+ enum gcc_jit_str_option opt,
+ const char *value);
+
+/* Set an int option on the given context. */
+extern void
+gcc_jit_context_set_int_option (gcc_jit_context *ctxt,
+ enum gcc_jit_int_option opt,
+ int value);
+
+/* Set a boolean option on the given context.
+
+ Zero is "false" (the default), non-zero is "true". */
+extern void
+gcc_jit_context_set_bool_option (gcc_jit_context *ctxt,
+ enum gcc_jit_bool_option opt,
+ int value);
+
+/* This actually calls into GCC and runs the build, all
+ in a mutex for now. The result is a wrapper around a .so file.
+ It can only be called once on a given context. */
+extern gcc_jit_result *
+gcc_jit_context_compile (gcc_jit_context *ctxt);
+
+/* To help with debugging: dump a C-like representation to the given path,
+ describing what's been set up on the context.
+
+ If "update_locations" is true, then also set up gcc_jit_location
+ information throughout the context, pointing at the dump file as if it
+ were a source file. This may be of use in conjunction with
+ GCC_JIT_BOOL_OPTION_DEBUGINFO to allow stepping through the code in a
+ debugger. */
+extern void
+gcc_jit_context_dump_to_file (gcc_jit_context *ctxt,
+ const char *path,
+ int update_locations);
+
+/* To be called after a compile, this gives the first error message
+ that occurred on the context.
+
+ The returned string is valid for the rest of the lifetime of the
+ context.
+
+ If no errors occurred, this will be NULL. */
+extern const char *
+gcc_jit_context_get_first_error (gcc_jit_context *ctxt);
+
+/* Locate a given function within the built machine code.
+ This will need to be cast to a function pointer of the
+ correct type before it can be called. */
+extern void *
+gcc_jit_result_get_code (gcc_jit_result *result,
+ const char *funcname);
+
+/* Once we're done with the code, this unloads the built .so file.
+ This cleans up the result; after calling this, it's no longer
+ valid to use the result. */
+extern void
+gcc_jit_result_release (gcc_jit_result *result);
+
+
+/**********************************************************************
+ Functions for creating "contextual" objects.
+
+ All objects created by these functions share the lifetime of the context
+ they are created within, and are automatically cleaned up for you when
+ you call gcc_jit_context_release on the context.
+
+ Note that this means you can't use references to them after you've
+ released their context.
+
+ All (const char *) string arguments passed to these functions are
+ copied, so you don't need to keep them around. Note that this *isn't*
+ the case for other parts of the API.
+
+ You create code by adding a sequence of statements to blocks.
+**********************************************************************/
+
+/**********************************************************************
+ The base class of "contextual" object.
+ **********************************************************************/
+/* Which context is "obj" within? */
+extern gcc_jit_context *
+gcc_jit_object_get_context (gcc_jit_object *obj);
+
+/* Get a human-readable description of this object.
+ The string buffer is created the first time this is called on a given
+ object, and persists until the object's context is released. */
+extern const char *
+gcc_jit_object_get_debug_string (gcc_jit_object *obj);
+
+/**********************************************************************
+ Debugging information.
+ **********************************************************************/
+
+/* Creating source code locations for use by the debugger.
+ Line and column numbers are 1-based. */
+extern gcc_jit_location *
+gcc_jit_context_new_location (gcc_jit_context *ctxt,
+ const char *filename,
+ int line,
+ int column);
+
+/* Upcasting from location to object. */
+extern gcc_jit_object *
+gcc_jit_location_as_object (gcc_jit_location *loc);
+
+
+/**********************************************************************
+ Types.
+ **********************************************************************/
+
+/* Upcasting from type to object. */
+extern gcc_jit_object *
+gcc_jit_type_as_object (gcc_jit_type *type);
+
+/* Access to specific types. */
+enum gcc_jit_types
+{
+ /* C's "void" type. */
+ GCC_JIT_TYPE_VOID,
+
+ /* "void *". */
+ GCC_JIT_TYPE_VOID_PTR,
+
+ /* C++'s bool type; also C99's "_Bool" type, aka "bool" if using
+ stdbool.h. */
+ GCC_JIT_TYPE_BOOL,
+
+ /* Various integer types. */
+
+ /* C's "char" (of some signedness) and the variants where the
+ signedness is specified. */
+ GCC_JIT_TYPE_CHAR,
+ GCC_JIT_TYPE_SIGNED_CHAR,
+ GCC_JIT_TYPE_UNSIGNED_CHAR,
+
+ /* C's "short" and "unsigned short". */
+ GCC_JIT_TYPE_SHORT, /* signed */
+ GCC_JIT_TYPE_UNSIGNED_SHORT,
+
+ /* C's "int" and "unsigned int". */
+ GCC_JIT_TYPE_INT, /* signed */
+ GCC_JIT_TYPE_UNSIGNED_INT,
+
+ /* C's "long" and "unsigned long". */
+ GCC_JIT_TYPE_LONG, /* signed */
+ GCC_JIT_TYPE_UNSIGNED_LONG,
+
+ /* C99's "long long" and "unsigned long long". */
+ GCC_JIT_TYPE_LONG_LONG, /* signed */
+ GCC_JIT_TYPE_UNSIGNED_LONG_LONG,
+
+ /* Floating-point types */
+
+ GCC_JIT_TYPE_FLOAT,
+ GCC_JIT_TYPE_DOUBLE,
+ GCC_JIT_TYPE_LONG_DOUBLE,
+
+ /* C type: (const char *). */
+ GCC_JIT_TYPE_CONST_CHAR_PTR,
+
+ /* The C "size_t" type. */
+ GCC_JIT_TYPE_SIZE_T,
+
+ /* C type: (FILE *) */
+ GCC_JIT_TYPE_FILE_PTR
+};
+
+extern gcc_jit_type *
+gcc_jit_context_get_type (gcc_jit_context *ctxt,
+ enum gcc_jit_types type_);
+
+/* Get the integer type of the given size and signedness. */
+extern gcc_jit_type *
+gcc_jit_context_get_int_type (gcc_jit_context *ctxt,
+ int num_bytes, int is_signed);
+
+/* Constructing new types. */
+
+/* Given type "T", get type "T*". */
+extern gcc_jit_type *
+gcc_jit_type_get_pointer (gcc_jit_type *type);
+
+/* Given type "T", get type "const T". */
+extern gcc_jit_type *
+gcc_jit_type_get_const (gcc_jit_type *type);
+
+/* Given type "T", get type "volatile T". */
+extern gcc_jit_type *
+gcc_jit_type_get_volatile (gcc_jit_type *type);
+
+/* Given type "T", get type "T[N]" (for a constant N). */
+extern gcc_jit_type *
+gcc_jit_context_new_array_type (gcc_jit_context *ctxt,
+ gcc_jit_location *loc,
+ gcc_jit_type *element_type,
+ int num_elements);
+
+/* Struct-handling. */
+
+/* Create a field, for use within a struct or union. */
+extern gcc_jit_field *
+gcc_jit_context_new_field (gcc_jit_context *ctxt,
+ gcc_jit_location *loc,
+ gcc_jit_type *type,
+ const char *name);
+
+/* Upcasting from field to object. */
+extern gcc_jit_object *
+gcc_jit_field_as_object (gcc_jit_field *field);
+
+/* Create a struct type from an array of fields. */
+extern gcc_jit_struct *
+gcc_jit_context_new_struct_type (gcc_jit_context *ctxt,
+ gcc_jit_location *loc,
+ const char *name,
+ int num_fields,
+ gcc_jit_field **fields);
+
+/* Create an opaque struct type. */
+extern gcc_jit_struct *
+gcc_jit_context_new_opaque_struct (gcc_jit_context *ctxt,
+ gcc_jit_location *loc,
+ const char *name);
+
+/* Upcast a struct to a type. */
+extern gcc_jit_type *
+gcc_jit_struct_as_type (gcc_jit_struct *struct_type);
+
+/* Populating the fields of a formerly-opaque struct type.
+ This can only be called once on a given struct type. */
+extern void
+gcc_jit_struct_set_fields (gcc_jit_struct *struct_type,
+ gcc_jit_location *loc,
+ int num_fields,
+ gcc_jit_field **fields);
+
+/* Unions work similarly to structs. */
+extern gcc_jit_type *
+gcc_jit_context_new_union_type (gcc_jit_context *ctxt,
+ gcc_jit_location *loc,
+ const char *name,
+ int num_fields,
+ gcc_jit_field **fields);
+
+/* Function pointers. */
+
+extern gcc_jit_type *
+gcc_jit_context_new_function_ptr_type (gcc_jit_context *ctxt,
+ gcc_jit_location *loc,
+ gcc_jit_type *return_type,
+ int num_params,
+ gcc_jit_type **param_types,
+ int is_variadic);
+
+/**********************************************************************
+ Constructing functions.
+ **********************************************************************/
+/* Create a function param. */
+extern gcc_jit_param *
+gcc_jit_context_new_param (gcc_jit_context *ctxt,
+ gcc_jit_location *loc,
+ gcc_jit_type *type,
+ const char *name);
+
+/* Upcasting from param to object. */
+extern gcc_jit_object *
+gcc_jit_param_as_object (gcc_jit_param *param);
+
+/* Upcasting from param to lvalue. */
+extern gcc_jit_lvalue *
+gcc_jit_param_as_lvalue (gcc_jit_param *param);
+
+/* Upcasting from param to rvalue. */
+extern gcc_jit_rvalue *
+gcc_jit_param_as_rvalue (gcc_jit_param *param);
+
+/* Kinds of function. */
+enum gcc_jit_function_kind
+{
+ /* Function is defined by the client code and visible
+ by name outside of the JIT. */
+ GCC_JIT_FUNCTION_EXPORTED,
+
+ /* Function is defined by the client code, but is invisible
+ outside of the JIT. Analogous to a "static" function. */
+ GCC_JIT_FUNCTION_INTERNAL,
+
+ /* Function is not defined by the client code; we're merely
+ referring to it. Analogous to using an "extern" function from a
+ header file. */
+ GCC_JIT_FUNCTION_IMPORTED,
+
+ /* Function is only ever inlined into other functions, and is
+ invisible outside of the JIT.
+
+ Analogous to prefixing with "inline" and adding
+ __attribute__((always_inline)).
+
+ Inlining will only occur when the optimization level is
+ above 0; when optimization is off, this is essentially the
+ same as GCC_JIT_FUNCTION_INTERNAL. */
+ GCC_JIT_FUNCTION_ALWAYS_INLINE
+};
+
+/* Create a function. */
+extern gcc_jit_function *
+gcc_jit_context_new_function (gcc_jit_context *ctxt,
+ gcc_jit_location *loc,
+ enum gcc_jit_function_kind kind,
+ gcc_jit_type *return_type,
+ const char *name,
+ int num_params,
+ gcc_jit_param **params,
+ int is_variadic);
+
+/* Create a reference to a builtin function (sometimes called
+ intrinsic functions). */
+extern gcc_jit_function *
+gcc_jit_context_get_builtin_function (gcc_jit_context *ctxt,
+ const char *name);
+
+/* Upcasting from function to object. */
+extern gcc_jit_object *
+gcc_jit_function_as_object (gcc_jit_function *func);
+
+/* Get a specific param of a function by index. */
+extern gcc_jit_param *
+gcc_jit_function_get_param (gcc_jit_function *func, int index);
+
+/* Emit the function in graphviz format. */
+extern void
+gcc_jit_function_dump_to_dot (gcc_jit_function *func,
+ const char *path);
+
+/* Create a block.
+
+ The name can be NULL, or you can give it a meaningful name, which
+ may show up in dumps of the internal representation, and in error
+ messages. */
+extern gcc_jit_block *
+gcc_jit_function_new_block (gcc_jit_function *func,
+ const char *name);
+
+/* Upcasting from block to object. */
+extern gcc_jit_object *
+gcc_jit_block_as_object (gcc_jit_block *block);
+
+/* Which function is this block within? */
+extern gcc_jit_function *
+gcc_jit_block_get_function (gcc_jit_block *block);
+
+/**********************************************************************
+ lvalues, rvalues and expressions.
+ **********************************************************************/
+
+extern gcc_jit_lvalue *
+gcc_jit_context_new_global (gcc_jit_context *ctxt,
+ gcc_jit_location *loc,
+ gcc_jit_type *type,
+ const char *name);
+
+/* Upcasting. */
+extern gcc_jit_object *
+gcc_jit_lvalue_as_object (gcc_jit_lvalue *lvalue);
+
+extern gcc_jit_rvalue *
+gcc_jit_lvalue_as_rvalue (gcc_jit_lvalue *lvalue);
+
+extern gcc_jit_object *
+gcc_jit_rvalue_as_object (gcc_jit_rvalue *rvalue);
+
+extern gcc_jit_type *
+gcc_jit_rvalue_get_type (gcc_jit_rvalue *rvalue);
+
+/* Integer constants. */
+extern gcc_jit_rvalue *
+gcc_jit_context_new_rvalue_from_int (gcc_jit_context *ctxt,
+ gcc_jit_type *numeric_type,
+ int value);
+
+extern gcc_jit_rvalue *
+gcc_jit_context_zero (gcc_jit_context *ctxt,
+ gcc_jit_type *numeric_type);
+
+extern gcc_jit_rvalue *
+gcc_jit_context_one (gcc_jit_context *ctxt,
+ gcc_jit_type *numeric_type);
+
+/* Floating-point constants. */
+extern gcc_jit_rvalue *
+gcc_jit_context_new_rvalue_from_double (gcc_jit_context *ctxt,
+ gcc_jit_type *numeric_type,
+ double value);
+
+/* Pointers. */
+extern gcc_jit_rvalue *
+gcc_jit_context_new_rvalue_from_ptr (gcc_jit_context *ctxt,
+ gcc_jit_type *pointer_type,
+ void *value);
+
+extern gcc_jit_rvalue *
+gcc_jit_context_null (gcc_jit_context *ctxt,
+ gcc_jit_type *pointer_type);
+
+/* String literals. */
+extern gcc_jit_rvalue *
+gcc_jit_context_new_string_literal (gcc_jit_context *ctxt,
+ const char *value);
+
+enum gcc_jit_unary_op
+{
+ /* Negate an arithmetic value; analogous to:
+ -(EXPR)
+ in C. */
+ GCC_JIT_UNARY_OP_MINUS,
+
+ /* Bitwise negation of an integer value (one's complement); analogous
+ to:
+ ~(EXPR)
+ in C. */
+ GCC_JIT_UNARY_OP_BITWISE_NEGATE,
+
+ /* Logical negation of an arithmetic or pointer value; analogous to:
+ !(EXPR)
+ in C. */
+ GCC_JIT_UNARY_OP_LOGICAL_NEGATE
+};
+
+extern gcc_jit_rvalue *
+gcc_jit_context_new_unary_op (gcc_jit_context *ctxt,
+ gcc_jit_location *loc,
+ enum gcc_jit_unary_op op,
+ gcc_jit_type *result_type,
+ gcc_jit_rvalue *rvalue);
+
+enum gcc_jit_binary_op
+{
+ /* Addition of arithmetic values; analogous to:
+ (EXPR_A) + (EXPR_B)
+ in C.
+ For pointer addition, use gcc_jit_context_new_array_access. */
+ GCC_JIT_BINARY_OP_PLUS,
+
+ /* Subtraction of arithmetic values; analogous to:
+ (EXPR_A) - (EXPR_B)
+ in C. */
+ GCC_JIT_BINARY_OP_MINUS,
+
+ /* Multiplication of a pair of arithmetic values; analogous to:
+ (EXPR_A) * (EXPR_B)
+ in C. */
+ GCC_JIT_BINARY_OP_MULT,
+
+ /* Quotient of division of arithmetic values; analogous to:
+ (EXPR_A) / (EXPR_B)
+ in C.
+ The result type affects the kind of division: if the result type is
+ integer-based, then the result is truncated towards zero, whereas
+ a floating-point result type indicates floating-point division. */
+ GCC_JIT_BINARY_OP_DIVIDE,
+
+ /* Remainder of division of arithmetic values; analogous to:
+ (EXPR_A) % (EXPR_B)
+ in C. */
+ GCC_JIT_BINARY_OP_MODULO,
+
+ /* Bitwise AND; analogous to:
+ (EXPR_A) & (EXPR_B)
+ in C. */
+ GCC_JIT_BINARY_OP_BITWISE_AND,
+
+ /* Bitwise exclusive OR; analogous to:
+ (EXPR_A) ^ (EXPR_B)
+ in C. */
+ GCC_JIT_BINARY_OP_BITWISE_XOR,
+
+ /* Bitwise inclusive OR; analogous to:
+ (EXPR_A) | (EXPR_B)
+ in C. */
+ GCC_JIT_BINARY_OP_BITWISE_OR,
+
+ /* Logical AND; analogous to:
+ (EXPR_A) && (EXPR_B)
+ in C. */
+ GCC_JIT_BINARY_OP_LOGICAL_AND,
+
+ /* Logical OR; analogous to:
+ (EXPR_A) || (EXPR_B)
+ in C. */
+ GCC_JIT_BINARY_OP_LOGICAL_OR,
+
+ /* Left shift; analogous to:
+ (EXPR_A) << (EXPR_B)
+ in C. */
+ GCC_JIT_BINARY_OP_LSHIFT,
+
+ /* Right shift; analogous to:
+ (EXPR_A) >> (EXPR_B)
+ in C. */
+ GCC_JIT_BINARY_OP_RSHIFT
+};
+
+extern gcc_jit_rvalue *
+gcc_jit_context_new_binary_op (gcc_jit_context *ctxt,
+ gcc_jit_location *loc,
+ enum gcc_jit_binary_op op,
+ gcc_jit_type *result_type,
+ gcc_jit_rvalue *a, gcc_jit_rvalue *b);
+
+/* (Comparisons are treated as separate from "binary_op" to save
+ you having to specify the result_type). */
+
+enum gcc_jit_comparison
+{
+ /* (EXPR_A) == (EXPR_B). */
+ GCC_JIT_COMPARISON_EQ,
+
+ /* (EXPR_A) != (EXPR_B). */
+ GCC_JIT_COMPARISON_NE,
+
+ /* (EXPR_A) < (EXPR_B). */
+ GCC_JIT_COMPARISON_LT,
+
+ /* (EXPR_A) <=(EXPR_B). */
+ GCC_JIT_COMPARISON_LE,
+
+ /* (EXPR_A) > (EXPR_B). */
+ GCC_JIT_COMPARISON_GT,
+
+ /* (EXPR_A) >= (EXPR_B). */
+ GCC_JIT_COMPARISON_GE
+};
+
+extern gcc_jit_rvalue *
+gcc_jit_context_new_comparison (gcc_jit_context *ctxt,
+ gcc_jit_location *loc,
+ enum gcc_jit_comparison op,
+ gcc_jit_rvalue *a, gcc_jit_rvalue *b);
+
+/* Function calls. */
+
+/* Call of a specific function. */
+extern gcc_jit_rvalue *
+gcc_jit_context_new_call (gcc_jit_context *ctxt,
+ gcc_jit_location *loc,
+ gcc_jit_function *func,
+ int numargs , gcc_jit_rvalue **args);
+
+/* Call through a function pointer. */
+extern gcc_jit_rvalue *
+gcc_jit_context_new_call_through_ptr (gcc_jit_context *ctxt,
+ gcc_jit_location *loc,
+ gcc_jit_rvalue *fn_ptr,
+ int numargs, gcc_jit_rvalue **args);
+
+/* Type-coercion.
+
+ Currently only a limited set of conversions are possible:
+ int <-> float
+ int <-> bool */
+extern gcc_jit_rvalue *
+gcc_jit_context_new_cast (gcc_jit_context *ctxt,
+ gcc_jit_location *loc,
+ gcc_jit_rvalue *rvalue,
+ gcc_jit_type *type);
+
+extern gcc_jit_lvalue *
+gcc_jit_context_new_array_access (gcc_jit_context *ctxt,
+ gcc_jit_location *loc,
+ gcc_jit_rvalue *ptr,
+ gcc_jit_rvalue *index);
+
+/* Field access is provided separately for both lvalues and rvalues. */
+
+/* Accessing a field of an lvalue of struct type, analogous to:
+ (EXPR).field = ...;
+ in C. */
+extern gcc_jit_lvalue *
+gcc_jit_lvalue_access_field (gcc_jit_lvalue *struct_or_union,
+ gcc_jit_location *loc,
+ gcc_jit_field *field);
+
+/* Accessing a field of an rvalue of struct type, analogous to:
+ (EXPR).field
+ in C. */
+extern gcc_jit_rvalue *
+gcc_jit_rvalue_access_field (gcc_jit_rvalue *struct_or_union,
+ gcc_jit_location *loc,
+ gcc_jit_field *field);
+
+/* Accessing a field of an rvalue of pointer type, analogous to:
+ (EXPR)->field
+ in C, itself equivalent to (*EXPR).FIELD */
+extern gcc_jit_lvalue *
+gcc_jit_rvalue_dereference_field (gcc_jit_rvalue *ptr,
+ gcc_jit_location *loc,
+ gcc_jit_field *field);
+
+/* Dereferencing a pointer; analogous to:
+ *(EXPR)
+*/
+extern gcc_jit_lvalue *
+gcc_jit_rvalue_dereference (gcc_jit_rvalue *rvalue,
+ gcc_jit_location *loc);
+
+/* Taking the address of an lvalue; analogous to:
+ &(EXPR)
+ in C. */
+extern gcc_jit_rvalue *
+gcc_jit_lvalue_get_address (gcc_jit_lvalue *lvalue,
+ gcc_jit_location *loc);
+
+extern gcc_jit_lvalue *
+gcc_jit_function_new_local (gcc_jit_function *func,
+ gcc_jit_location *loc,
+ gcc_jit_type *type,
+ const char *name);
+
+/**********************************************************************
+ Statement-creation.
+ **********************************************************************/
+
+/* Add evaluation of an rvalue, discarding the result
+ (e.g. a function call that "returns" void).
+
+ This is equivalent to this C code:
+
+ (void)expression;
+*/
+extern void
+gcc_jit_block_add_eval (gcc_jit_block *block,
+ gcc_jit_location *loc,
+ gcc_jit_rvalue *rvalue);
+
+/* Add evaluation of an rvalue, assigning the result to the given
+ lvalue.
+
+ This is roughly equivalent to this C code:
+
+ lvalue = rvalue;
+*/
+extern void
+gcc_jit_block_add_assignment (gcc_jit_block *block,
+ gcc_jit_location *loc,
+ gcc_jit_lvalue *lvalue,
+ gcc_jit_rvalue *rvalue);
+
+/* Add evaluation of an rvalue, using the result to modify an
+ lvalue.
+
+ This is analogous to "+=" and friends:
+
+ lvalue += rvalue;
+ lvalue *= rvalue;
+ lvalue /= rvalue;
+ etc */
+extern void
+gcc_jit_block_add_assignment_op (gcc_jit_block *block,
+ gcc_jit_location *loc,
+ gcc_jit_lvalue *lvalue,
+ enum gcc_jit_binary_op op,
+ gcc_jit_rvalue *rvalue);
+
+/* Add a no-op textual comment to the internal representation of the
+ code. It will be optimized away, but will be visible in the dumps
+ seen via
+ GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE
+ and
+ GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE,
+ and thus may be of use when debugging how your project's internal
+ representation gets converted to the libgccjit IR. */
+extern void
+gcc_jit_block_add_comment (gcc_jit_block *block,
+ gcc_jit_location *loc,
+ const char *text);
+
+/* Terminate a block by adding evaluation of an rvalue, branching on the
+ result to the appropriate successor block.
+
+ This is roughly equivalent to this C code:
+
+ if (boolval)
+ goto on_true;
+ else
+ goto on_false;
+
+ block, boolval, on_true, and on_false must be non-NULL. */
+extern void
+gcc_jit_block_end_with_conditional (gcc_jit_block *block,
+ gcc_jit_location *loc,
+ gcc_jit_rvalue *boolval,
+ gcc_jit_block *on_true,
+ gcc_jit_block *on_false);
+
+/* Terminate a block by adding a jump to the given target block.
+
+ This is roughly equivalent to this C code:
+
+ goto target;
+*/
+extern void
+gcc_jit_block_end_with_jump (gcc_jit_block *block,
+ gcc_jit_location *loc,
+ gcc_jit_block *target);
+
+/* Terminate a block by adding evaluation of an rvalue, returning the value.
+
+ This is roughly equivalent to this C code:
+
+ return expression;
+*/
+extern void
+gcc_jit_block_end_with_return (gcc_jit_block *block,
+ gcc_jit_location *loc,
+ gcc_jit_rvalue *rvalue);
+
+/* Terminate a block by adding a valueless return, for use within a function
+ with "void" return type.
+
+ This is equivalent to this C code:
+
+ return;
+*/
+extern void
+gcc_jit_block_end_with_void_return (gcc_jit_block *block,
+ gcc_jit_location *loc);
+
+/**********************************************************************
+ Nested contexts.
+ **********************************************************************/
+
+/* Given an existing JIT context, create a child context.
+
+ The child inherits a copy of all option-settings from the parent.
+
+ The child can reference objects created within the parent, but not
+ vice-versa.
+
+ The lifetime of the child context must be bounded by that of the
+ parent: you should release a child context before releasing the parent
+ context.
+
+ If you use a function from a parent context within a child context,
+ you have to compile the parent context before you can compile the
+ child context, and the gcc_jit_result of the parent context must
+ outlive the gcc_jit_result of the child context.
+
+ This allows caching of shared initializations. For example, you could
+ create types and declarations of global functions in a parent context
+ once within a process, and then create child contexts whenever a
+ function or loop becomes hot. Each such child context can be used for
+ JIT-compiling just one function or loop, but can reference types
+ and helper functions created within the parent context.
+
+ Contexts can be arbitrarily nested, provided the above rules are
+ followed, but it's probably not worth going above 2 or 3 levels, and
+ there will likely be a performance hit for such nesting. */
+
+extern gcc_jit_context *
+gcc_jit_context_new_child_context (gcc_jit_context *parent_ctxt);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* LIBGCCJIT_H */
--- /dev/null
+# 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
--- /dev/null
+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
+2014-11-11 David Malcolm <dmalcolm@redhat.com>
+
+ * ChangeLog.jit: New.
+ * jit.dg/all-non-failing-tests.h: New.
+ * jit.dg/harness.h: New.
+ * jit.dg/jit.exp: New.
+ * jit.dg/test-accessing-struct.c: New.
+ * jit.dg/test-accessing-union.c: New.
+ * jit.dg/test-array-as-pointer.c: New.
+ * jit.dg/test-arrays.c: New.
+ * jit.dg/test-calling-external-function.c: New.
+ * jit.dg/test-calling-function-ptr.c: New.
+ * jit.dg/test-combination.c: New.
+ * jit.dg/test-dot-product.c: New.
+ * jit.dg/test-empty.c: New.
+ * jit.dg/test-error-accessing-field-in-other-struct.c: New.
+ * jit.dg/test-error-adding-to-terminated-block.c: New.
+ * jit.dg/test-error-array-as-pointer.c: New.
+ * jit.dg/test-error-bad-cast.c: New.
+ * jit.dg/test-error-block-in-wrong-function.c: New.
+ * jit.dg/test-error-call-through-ptr-with-mismatching-args.c: New.
+ * jit.dg/test-error-call-through-ptr-with-non-function.c: New.
+ * jit.dg/test-error-call-through-ptr-with-non-pointer.c: New.
+ * jit.dg/test-error-call-through-ptr-with-not-enough-args.c: New.
+ * jit.dg/test-error-call-through-ptr-with-too-many-args.c: New.
+ * jit.dg/test-error-call-with-mismatching-args.c: New.
+ * jit.dg/test-error-call-with-not-enough-args.c: New.
+ * jit.dg/test-error-call-with-too-many-args.c: New.
+ * jit.dg/test-error-dereference-field-of-non-pointer.c: New.
+ * jit.dg/test-error-dereference-read-of-non-pointer.c: New.
+ * jit.dg/test-error-get-type-bad-enum.c: New.
+ * jit.dg/test-error-index-not-a-numeric-type.c: New.
+ * jit.dg/test-error-mismatching-types-in-assignment.c: New.
+ * jit.dg/test-error-mismatching-types-in-call.c: New.
+ * jit.dg/test-error-missing-return.c: New.
+ * jit.dg/test-error-new-binary-op-bad-op.c: New.
+ * jit.dg/test-error-new-function-bad-kind.c: New.
+ * jit.dg/test-error-new-unary-op-bad-op.c: New.
+ * jit.dg/test-error-null-passed-to-api.c: New.
+ * jit.dg/test-error-return-within-void-function.c: New.
+ * jit.dg/test-error-unreachable-block.c: New.
+ * jit.dg/test-error-unterminated-block.c: New.
+ * jit.dg/test-error-value-not-a-numeric-type.c: New.
+ * jit.dg/test-expressions.c: New.
+ * jit.dg/test-factorial.c: New.
+ * jit.dg/test-fibonacci.c: New.
+ * jit.dg/test-functions.c: New.
+ * jit.dg/test-fuzzer.c: New.
+ * jit.dg/test-hello-world.c: New.
+ * jit.dg/test-linked-list.c: New.
+ * jit.dg/test-long-names.c: New.
+ * jit.dg/test-nested-contexts.c: New.
+ * jit.dg/test-nested-loops.c: New.
+ * jit.dg/test-operator-overloading.cc: New.
+ * jit.dg/test-quadratic.c: New.
+ * jit.dg/test-quadratic.cc: New.
+ * jit.dg/test-reading-struct.c: New.
+ * jit.dg/test-string-literal.c: New.
+ * jit.dg/test-sum-of-squares.c: New.
+ * jit.dg/test-threads.c: New.
+ * jit.dg/test-types.c: New.
+ * jit.dg/test-using-global.c: New.
+ * jit.dg/test-volatile.c: New.
+
2014-11-11 James Greenhalgh <james.greenhalgh@arm.com>
* gcc.target/aarch64/vbslq_f64_1.c: New.
--- /dev/null
+2014-11-05 David Malcolm <dmalcolm@redhat.com>
+
+ * jit.dg/test-error-get-type-bad-enum.c: New test case.
+ * jit.dg/test-error-new-binary-op-bad-op.c: Likewise.
+ * jit.dg/test-error-new-function-bad-kind.c: Likewise.
+ * jit.dg/test-error-new-unary-op-bad-op.c: Likewise.
+
+2014-10-22 David Malcolm <dmalcolm@redhat.com>
+
+ * jit.dg/jit.exp (DEFAULT_CFLAGS): Add -fgnu89-inline since
+ dejagnu.h assumes this.
+
+2014-10-17 David Malcolm <dmalcolm@redhat.com>
+
+ * jit.dg/jit.exp (get_path_of_driver): New procedure.
+ (jit-dg-test): Don't unsetenv GCC_EXEC_PREFIX, since jit-playback.c
+ now adds -fno-use-linker-plugin to the driver cmdline sidestepping
+ the builddir/installdir libtto_plugin naming issue.
+ When setting up PATH so that the JIT library can invoke the driver
+ by installation name, don't use the installation "bindir".
+ Instead, simply use the location of xgcc as detected
+ get_path_of_driver. In addition, set up LIBRARY_PATH so that the
+ linker run from inside the JIT library can locate libgcc etc when
+ building the .so, pointing it at the same directory.
+
+2014-10-13 David Malcolm <dmalcolm@redhat.com>
+
+ * jit.dg/jit.exp (fixed_host_execute): New function, taken from
+ "host_execute" in DejaGnu's dejagnu.exp, with one line removed.
+ (jit-dg-test): Use fixed_host_execute, rathern than host_execute.
+
+2014-10-13 David Malcolm <dmalcolm@redhat.com>
+
+ * jit.dg/harness.h [MAKE_DEJAGNU_H_THREADSAFE] (note): Redefine
+ "note" from dejagnu.h to new function dejagnu_note so that we can
+ make "note" be threadsafe.
+ (set_options): Don't enable GCC_JIT_BOOL_OPTION_DUMP_SUMMARY,
+ since it can generate large amounts of output that could overwhelm
+ expect's buffer.
+ * jit.dg/test-dot-product.c (verify_code): Use "note" rather than
+ "printf", to give DejaGnu more chances to parse this log data,
+ rather than overflowing its buffer.
+ * jit.dg/test-factorial.c (verify_code): Likewise.
+ * jit.dg/test-fibonacci.c (verify_code): Likewise.
+ * jit.dg/test-fuzzer.c (main): Likewise.
+ * jit.dg/test-nested-loops.c (verify_code): Likewise.
+ * jit.dg/test-sum-of-squares.c (verify_code): Likewise.
+ * jit.dg/test-threads.c (note): New function, adding thread-safety
+ on top of "dejagnu_note", the latter being the implementation
+ found in dejagnu.h.
+ (run_threaded_test): Use "note" rather than "printf".
+
+2014-10-07 David Malcolm <dmalcolm@redhat.com>
+
+ * jit.dg/jit.exp (jit-dg-test): Prepend the installed bindir to
+ the PATH before invoking built binaries using the library, so that
+ the library can find the driver. Restore the PATH immediately
+ afterwards.
+
+2014-09-24 David Malcolm <dmalcolm@redhat.com>
+
+ * ChangeLog.jit: Add copyright footer.
+
+2014-09-23 David Malcolm <dmalcolm@redhat.com>
+
+ * jit.dg/test-expressions.c (make_tests_of_binary_ops): Add
+ shift operators.
+ (verify_binary_ops): Likewise.
+
+2014-09-18 David Malcolm <dmalcolm@redhat.com>
+
+ * jit.dg/jit.exp: When constructing "tests", add the example files
+ from the documentation, to ensure that they compile.
+
+2014-09-10 David Malcolm <dmalcolm@redhat.com>
+
+ * jit.dg/jit.exp: Load target-supports.exp.
+
+2014-09-09 David Malcolm <dmalcolm@redhat.com>
+
+ * jit.dg/test-nested-loops.c: New test case.
+ * jit.dg/all-non-failing-tests.h: Add test-nested-loops.c.
+ * jit.dg/test-combination.c (create_code): Likewise.
+ (verify_code): Likewise.
+ * jit.dg/test-threads.c (const): Add test-nested-loops.c.
+
+2014-08-11 David Malcolm <dmalcolm@redhat.com>
+
+ * jit.dg/test-threads.c: New test case, running all of the
+ individual test cases in separate threads.
+ * jit.dg/test-combination.c: Move inclusion of the various
+ individual testcases into...
+ * jit.dg/all-non-failing-tests.h: ...this new file, and rename
+ TEST_COMBINATION to COMBINED_TEST.
+ * jit.dg/harness.h: Respond to new macro MAKE_DEJAGNU_H_THREADSAFE
+ by hacking up <dejagnu.h> to be threadsafe. Rename
+ TEST_COMBINATION to COMBINED_TEST.
+ * jit.dg/jit.exp (proc jit-dg-test): Add "-lpthread" when building
+ test-threads.exe.
+
+2014-08-08 David Malcolm <dmalcolm@redhat.com>
+
+ * jit.dg/test-accessing-union.c: New test case.
+ * jit.dg/test-combination.c: Add test-accessing-union.c.
+
+2014-08-08 David Malcolm <dmalcolm@redhat.com>
+
+ * jit.dg/test-combination.c (create_code): Add missing calls to
+ create_code_quadratic and create_code_reading_struct.
+ (verify_code): Add missing calls to verify_code_quadratic and
+ verify_code_reading_struct.
+
+2014-08-08 David Malcolm <dmalcolm@redhat.com>
+
+ * jit.dg/test-calling-function-ptr.c: New test case.
+ * jit.dg/test-combination.c: Add test-calling-function-ptr.c.
+ * jit.dg/test-error-call-through-ptr-with-mismatching-args.c: New
+ test case.
+ * jit.dg/test-error-call-through-ptr-with-non-function.c: New test
+ case.
+ * jit.dg/test-error-call-through-ptr-with-non-pointer.c: New test
+ case.
+ * jit.dg/test-error-call-through-ptr-with-not-enough-args.c: New
+ test case.
+
+2014-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * jit.dg/test-error-index-not-a-numeric-type.c: New test case.
+ * jit.dg/test-error-value-not-a-numeric-type.c: New test case.
+
+2014-03-19 David Malcolm <dmalcolm@redhat.com>
+
+ * jit.dg/test-array-as-pointer.c: New test case, verifying that
+ there's a way to treat arrays as pointers.
+ * jit.dg/test-combination.c: Add test-array-as-pointer.c...
+ (create_code): ...here and...
+ (verify_code): ...here.
+
+ * jit.dg/test-error-array-as-pointer.c: New test case, verifying
+ that bogus casts from array to pointer are caught by the type
+ system, rather than leading to ICEs seen in:
+ https://github.com/davidmalcolm/pygccjit/pull/3#issuecomment-37883129
+
+2014-03-18 David Malcolm <dmalcolm@redhat.com>
+
+ * jit.dg/test-combination.c: Add test-arrays.c and test-volatile.c.
+ Add comment about test-error-*.c. Remove comment about
+ test-failure.c, which was removed in
+ 96b218c9a1d5f39fb649e02c0e77586b180e8516.
+ (create_code): Call into test-arrays.c and test-volatile.c.
+ (verify_code): Likewise.
+
+2014-03-14 David Malcolm <dmalcolm@redhat.com>
+
+ * jit.dg/test-expressions.c (called_pointer_checking_function): New.
+ (make_tests_of_casts): Add test of casting from array to pointer.
+ (verify_casts): Likewise.
+
+2014-03-13 David Malcolm <dmalcolm@redhat.com>
+
+ * jit.dg/test-error-bad-cast.c: New test case.
+
+2014-03-11 David Malcolm <dmalcolm@redhat.com>
+
+ * jit.dg/harness.h (set_options): Increase optimization level from
+ 0 to 3.
+
+2014-03-07 David Malcolm <dmalcolm@redhat.com>
+
+ * jit.dg/test-functions.c (create_test_of_hidden_function): New,
+ adding test coverage for GCC_JIT_FUNCTION_ALWAYS_INLINE and
+ GCC_JIT_FUNCTION_INTERNAL.
+ (create_tests_of_hidden_functions): Likewise.
+ (verify_hidden_functions): Likewise.
+ (create_code): Add call to create_tests_of_hidden_functions.
+ (verify_code): Add call to verify_hidden_functions.
+ * jit.dg/test-quadratic.c (make_calc_discriminant): Convert
+ from GCC_JIT_FUNCTION_EXPORTED to GCC_JIT_FUNCTION_INTERNAL.
+
+2014-03-07 David Malcolm <dmalcolm@redhat.com>
+
+ * jit.dg/test-functions.c: Reorder function definitions, grouping
+ them by subject-matter rather than by create-vs-verify phase.
+
+2014-03-06 David Malcolm <dmalcolm@redhat.com>
+
+ * jit.dg/test-nested-contexts.c (main): Dump the contexts to
+ files, setting up source locations, and adding test coverage for
+ gcc_jit_context_dump_to_file.
+
+2014-03-04 David Malcolm <dmalcolm@redhat.com>
+
+ * jit.dg/test-error-mismatching-types-in-call.c: New test case,
+ to ensure that a (struct foo *) vs (struct foo) type error is
+ gracefully handled.
+
+2014-03-04 David Malcolm <dmalcolm@redhat.com>
+
+ * jit.dg/test-volatile.c: New testcase, to exercise
+ gcc_jit_type_get_volatile, and show a way to work with pre-existing
+ global variables.
+
+2014-02-28 David Malcolm <dmalcolm@redhat.com>
+
+ * jit.dg/test-expressions.c (make_test_of_cast): New, to test new
+ entrypoint gcc_jit_context_new_cast.
+ (make_tests_of_casts): New.
+ (create_code): Add call to make_tests_of_casts.
+ (verify_code): Add call to verify_casts.
+
+2014-02-27 David Malcolm <dmalcolm@redhat.com>
+
+ * jit.dg/test-accessing-struct.c (create_code): Port to
+ block-based API.
+ * jit.dg/test-calling-external-function.c (create_code): Likewise.
+ * jit.dg/test-error-accessing-field-in-other-struct.c (create_code):
+ Likewise.
+ * jit.dg/test-error-call-with-mismatching-args.c (create_code):
+ Likewise.
+ * jit.dg/test-error-call-with-not-enough-args.c (create_code):
+ Likewise.
+ * jit.dg/test-error-call-with-too-many-args.c (create_code):
+ Likewise.
+ * jit.dg/test-error-dereference-field-of-non-pointer.c (create_code):
+ Likewise.
+ * jit.dg/test-error-dereference-read: Likewise.
+ * jit.dg/test-error-mismatching-types-in-assignment.c: Likewise.
+ * jit.dg/test-error-return-within-void-function.c: Likewise.
+ * jit.dg/test-expressions.c: Likewise.
+ * jit.dg/test-factorial.c: Likewise.
+ * jit.dg/test-functions.c: Likewise.
+ * jit.dg/test-fuzzer.c: Likewise.
+ * jit.dg/test-hello-world.c (create_code): Likewise.
+ * jit.dg/test-nested-contexts.c: Likewise.
+ * jit.dg/test-operator-overloading.cc: Likewise.
+ * jit.dg/test-quadratic.c: Likewise.
+ * jit.dg/test-quadratic.cc: Likewise.
+ * jit.dg/test-reading-struct.c (create_code): Likewise.
+ * jit.dg/test-string-literal.c (create_code): Likewise.
+ * jit.dg/test-sum-of-squares.c (create_code): Likewise.
+ * jit.dg/test-types.c (create_code): Likewise.
+ * jit.dg/test-using-global.c (create_code): Likewise.
+
+ * jit.dg/test-arrays.c (create_code): Likewise, eliminating use of
+ loop API.
+ * jit.dg/test-dot-product.c (create_code): Likewise.
+ * jit.dg/test-linked-list.c (create_code): Likewise.
+
+ * jit.dg/test-error-adding-to-terminated-block.c: New testcase.
+ * jit.dg/test-error-block-in-wrong-function.c: Likewise.
+ * jit.dg/test-error-missing-return.c: Likewise.
+ * jit.dg/test-error-unreachable-block.c: Likewise.
+ * jit.dg/test-error-unterminated-block.c: Likewise.
+
+ * jit.dg/test-error-label-already-placed.c: Delete obsolete testcase.
+ * jit.dg/test-error-unplaced-label.c: Likewise.
+
+2014-02-25 David Malcolm <dmalcolm@redhat.com>
+
+ * jit.dg/test-functions.c (create_use_of_void_return): New, to add
+ test coverage for gcc_jit_function_add_void_return.
+ (verify_void_return): Likewise.
+ (create_code): Add call to create_use_of_void_return.
+ (verify_code): Add call to verify_void_return.
+
+2014-02-18 David Malcolm <dmalcolm@redhat.com>
+
+ * jit.dg/test-accessing-struct.c (create_code): Update for change to
+ return type of gcc_jit_context_new_struct_type.
+ * jit.dg/test-arrays.c (create_code): Likewise.
+ * jit.dg/test-error-accessing-field-in-other-struct.c (create_code):
+ Likewise.
+ * jit.dg/test-error-dereference-field-of-non-pointer.c (create_code):
+ Likewise.
+ * jit.dg/test-fuzzer.c (make_random_type): Likewise.
+ * jit.dg/test-nested-contexts.c (make_types): Likewise.
+ * jit.dg/test-quadratic.c (make_types): Likewise.
+ * jit.dg/test-reading-struct.c (create_code): Likewise.
+ * jit.dg/test-types.c (create_code): Likewise.
+
+ * jit.dg/test-linked-list.c: New selftest, exercising
+ gcc_jit_context_new_opaque_struct, gcc_jit_type_get_pointer, and
+ gcc_jit_context_null.
+ * jit.dg/test-combination.c: Add test-linked-list.c
+
+2014-02-14 David Malcolm <dmalcolm@redhat.com>
+
+ * jit.dg/test-operator-overloading.cc (make_test_quadratic): Use
+ the new "zero" and "one" methods of gccjit::type.
+ * jit.dg/test-quadratic.cc (make_test_quadratic): Use the new
+ "add_call" method of gccjit::function.
+
+2014-02-13 David Malcolm <dmalcolm@redhat.com>
+
+ * jit.dg/harness.h (CHECK_DOUBLE_VALUE): New macro.
+ (CHECK): New macro.
+ * jit.dg/test-functions.c: New testcase, exercising
+ gcc_jit_context_get_builtin_function.
+ * jit.dg/test-combination.c: Add test-functions.c to the combined
+ test.
+
+2014-02-11 David Malcolm <dmalcolm@redhat.com>
+
+ * jit.dg/test-types.c: Add test coverage for getting type
+ GCC_JIT_TYPE_BOOL.
+ * jit.dg/test-expressions.c (make_test_of_comparison): Convert
+ return type from int to bool.
+ (verify_comparisons): Likewise.
+
+2014-02-11 David Malcolm <dmalcolm@redhat.com>
+
+ * jit.dg/test-error-unplaced-label.c (verify_code): Update
+ expected error message to reflect commit
+ 6cd4f82c5237cc328aea229cdaaa428ff09d6e98.
+
+2014-02-10 David Malcolm <dmalcolm@redhat.com>
+
+ * jit.dg/test-types.c (struct zoo): Add field m_sized_int_type,
+ to be populated by...
+ (create_code): Use gcc_jit_context_get_int_type.
+ (verify_code): Verify that type from gcc_jit_context_get_int_type
+ works properly.
+ * jit.dg/test-operator-overloading.cc (make_types): Use the
+ template form of get_int_type.
+ * jit.dg/test-quadratic.cc (make_types): Likewise.
+
+2014-02-10 David Malcolm <dmalcolm@redhat.com>
+
+ * jit.dg/test-operator-overloading.cc: New testcase, a
+ rewrite of test-quadratic.cc to use operator overloading.
+
+2014-02-10 David Malcolm <dmalcolm@redhat.com>
+
+ * jit.dg/test-quadratic.cc (make_calc_discriminant): Make use of
+ new methods of the C++ wrapper API to shorten the example code.
+ (make_test_quadratic): Likewise.
+
+2014-02-10 David Malcolm <dmalcolm@redhat.com>
+
+ * jit.dg/test-quadratic.cc (make_test_quadratic): Update for
+ change to gccjit::context::new_call to pass args by reference
+ rather than by value.
+
+2014-02-03 David Malcolm <dmalcolm@redhat.com>
+
+ * jit.dg/harness.h (check_string_value): Add a forward declaration,
+ so that we can use CHECK_STRING_VALUE from within tests used by
+ test-combination.c.
+
+ * jit.dg/test-expressions.c (make_test_of_unary_op): Return a debug
+ stringification of the operation so that it be sanity-checked.
+ (make_test_of_binary_op): Likewise.
+ (make_test_of_comparison): Likewise.
+ (make_tests_of_unary_ops): Verify that said stringifications are
+ indeed sane.
+ (make_tests_of_binary_ops): Likewise.
+ (make_tests_of_comparisons): Likewise.
+
+ * jit.dg/test-quadratic.cc (make_types): Verify that the
+ get_debug_string method works.
+ (make_test_quadratic): Likewise, also, verify that the <<
+ operator works.
+
+2014-01-31 David Malcolm <dmalcolm@redhat.com>
+
+ * jit.dg/test-quadratic.cc: New file - a translation of
+ test-quadratic.c to the libgccjit++.h C++ API.
+
+2014-01-30 David Malcolm <dmalcolm@redhat.com>
+
+ * jit.dg/test-error-label-already-placed.c: New test case.
+ * jit.dg/test-error-unplaced-label.c: New test case.
+
+2014-01-30 David Malcolm <dmalcolm@redhat.com>
+
+ * jit.dg/test-error-call-with-mismatching-args.c: New test case.
+
+2014-01-30 David Malcolm <dmalcolm@redhat.com>
+
+ * jit.dg/test-error-accessing-field-in-other-struct.c: New test
+ case.
+ * jit.dg/test-error-dereference-field-of-non-pointer.c: Likewise.
+ * jit.dg/test-error-dereference-read-of-non-pointer.c: Likewise.
+ * jit.dg/test-error-mismatching-types-in-assignment.c: Likewise.
+ * jit.dg/test-error-return-within-void-function.c: Likewise.
+
+2014-01-29 David Malcolm <dmalcolm@redhat.com>
+
+ * jit.dg/test-accessing-struct.c (create_code): Update for API change
+ for accessing fields in terms of gcc_jit_field pointers rather than
+ by name.
+ * jit.dg/test-nested-contexts.c (make_calc_discriminant): Likewise.
+ (make_test_quadratic): Likewise.
+ * jit.dg/test-quadratic.c (make_calc_discriminant): Likewise.
+ (make_test_quadratic): Likewise.
+ * jit.dg/test-reading-struct.c (create_code): Likewise.
+ * jit.dg/test-types.c: Likewise.
+
+2014-01-28 David Malcolm <dmalcolm@redhat.com>
+
+ * jit.dg/harness.h (test_jit): Add the possibility of turning off
+ this function, if the newly-coined "TEST_ESCHEWS_TEST_JIT" is
+ defined, for use by...
+ * jit.dg/test-nested-contexts.c: New test case, adapting
+ test-quadratic.c, but splitting it into a 3-deep arrangement of
+ nested contexts, to test the implementation of child contexts.
+
+2014-01-28 David Malcolm <dmalcolm@redhat.com>
+
+ * jit.dg/harness.h (test_jit): Move the various calls to set up
+ options on the context into...
+ (set_options): ...this new function.
+
+2014-01-27 David Malcolm <dmalcolm@redhat.com>
+
+ * jit.dg/test-error-call-with-not-enough-args.c: New test case.
+ * jit.dg/test-error-call-with-too-many-args.c: New test case.
+ * jit.dg/test-null-passed-to-api.c: Rename to...
+ * jit.dg/test-error-null-passed-to-api.c: ...this, so that
+ error-handling test cases are consistently named.
+
+2014-01-24 David Malcolm <dmalcolm@redhat.com>
+
+ * jit.dg/test-empty.c: New test case.
+
+2014-01-24 David Malcolm <dmalcolm@redhat.com>
+
+ * jit.dg/harness.h (code_making_callback): Rename to...
+ (create_code): ...this, and eliminate the returned
+ error-handling value: test cases will simply call into the
+ gcc_jit_ API, without needing to be run from a callback.
+ (test_jit): Don't register a callback, simply call the
+ "create_code" function for the testcase before compiling the
+ context.
+
+ * jit.dg/test-accessing-struct.c: Rename "code_making_callback"
+ to "create_code" and eliminate the return code.
+ * jit.dg/test-calling-external-function.c: Likewise.
+ * jit.dg/test-combination.c: Likewise.
+ * jit.dg/test-dot-product.c: Likewise.
+ * jit.dg/test-expressions.c: Likewise.
+ * jit.dg/test-factorial.c: Likewise.
+ * jit.dg/test-fibonacci.c: Likewise.
+ * jit.dg/test-fuzzer.c: Likewise.
+ * jit.dg/test-hello-world.c: Likewise.
+ * jit.dg/test-null-passed-to-api.c: Likewise.
+ * jit.dg/test-quadratic.c: Likewise.
+ * jit.dg/test-reading-struct.c: Likewise.
+ * jit.dg/test-string-literal.c: Likewise.
+ * jit.dg/test-sum-of-squares.c: Likewise.
+ * jit.dg/test-types.c: Likewise.
+ * jit.dg/test-using-global.c: Likewise.
+
+ * jit.dg/test-failure.c: Remove this test case, since it was
+ specifically for testing the now-defunct callback-based API.
+
+2014-01-23 David Malcolm <dmalcolm@redhat.com>
+
+ * jit.dg/test-quadratic.c: New test case, written to achieve test
+ coverage of gcc_jit_rvalue_access_field, but also exercising
+ division of doubles.
+
+ * jit.dg/test-combination.c: Add test-quadratic.c
+
+ * jit.dg/test-expressions.c: Add TODOs.
+
+2014-01-23 David Malcolm <dmalcolm@redhat.com>
+
+ * jit.dg/test-reading-struct.c: New test, to provide test coverage
+ of gcc_jit_type_get_const and gcc_jit_lvalue_access_field, in the
+ process uncovering bugs in how locals were handled.
+ * jit.dg/test-combination.c: Add usage of test-reading-struct.c.
+
+2014-01-21 David Malcolm <dmalcolm@redhat.com>
+
+ * jit.dg/test-hello-world.c (code_making_callback): Add usage of
+ gcc_jit_function_add_comment.
+
+2013-10-24 David Malcolm <dmalcolm@redhat.com>
+
+ * jit.dg/harness.h (main): Wrap with #ifndef TEST_PROVIDES_MAIN
+ * jit.dg/test-fuzzer.c: New.
+
+2013-10-22 David Malcolm <dmalcolm@redhat.com>
+
+ * jit.dg/harness.h (verify_code): Add context param so that
+ test cases of failure can query errors on it.
+ (CHECK_STRING_VALUE): New.
+ (check_string_value): New.
+ (test_jit): Add user_data param and pass it to the code factory.
+ Pass context to verify_code, calling it before releasing said
+ context.
+ (main): Add NULL user_data to test_jit call.
+ * jit.dg/test-accessing-struct.c (verify_code): Add context
+ param.
+ * jit.dg/test-calling-external-function.c (verify_code):
+ Likewise.
+ * jit.dg/test-combination.c (verify_code): Likewise.
+ * jit.dg/test-dot-product.c (verify_code): Likewise.
+ * jit.dg/test-expressions.c (verify_code): Likewise.
+ * jit.dg/test-factorial.c (verify_code): Likewise.
+ * jit.dg/test-failure.c (verify_code): Likewise.
+ * jit.dg/test-fibonacci.c (verify_code): Likewise.
+ * jit.dg/test-hello-world.c (verify_code): Likewise.
+ * jit.dg/test-string-literal.c (verify_code): Likewise.
+ * jit.dg/test-sum-of-squares.c (verify_code): Likewise.
+ * jit.dg/test-types.c (verify_code): Likewise.
+ * jit.dg/test-using-global.c (verify_code): Likewise.
+ * jit.dg/test-null-passed-to-api.c (verify_code): Likewise;
+ use context to verify that the library provides a sane error
+ message to the client code.
+
+2013-10-21 David Malcolm <dmalcolm@redhat.com>
+
+ * jit.dg/test-expressions.c (test_global): New.
+ (make_test_of_get_address): New.
+ (verify_get_address): New.
+ (code_making_callback): Add call to make_test_of_get_address.
+ (verify_code): Add call to verify_get_address.
+
+2013-10-18 David Malcolm <dmalcolm@redhat.com>
+
+ * jit.dg/test-expressions.c: New.
+ * jit.dg/test-combination.c: Add usage of test-expressions.c
+ * jit.dg/test-accessing-struct.c (code_making_callback): Update
+ for changes to field-access API.
+ * jit.dg/test-types.c (code_making_callback): Likewise.
+
+2013-10-18 David Malcolm <dmalcolm@redhat.com>
+
+ * jit.dg/test-null-passed-to-api.c: New.
+
+2013-10-17 David Malcolm <dmalcolm@redhat.com>
+
+ * jit.dg/test-accessing-struct.c (code_making_callback): Update
+ for changes to type API.
+ * jit.dg/test-calling-external-function.c (code_making_callback):
+ Likewise.
+ * jit.dg/test-dot-product.c (code_making_callback): Likewise.
+ * jit.dg/test-factorial.c (code_making_callback): Likewise.
+ * jit.dg/test-fibonacci.c (code_making_callback): Likewise.
+ * jit.dg/test-hello-world.c (code_making_callback): Likewise.
+ * jit.dg/test-string-literal.c (code_making_callback): Likewise.
+ * jit.dg/test-sum-of-squares.c (code_making_callback): Likewise.
+ * jit.dg/test-using-globals.c (code_making_callback): Likewise.
+ * jit.dg/test-types.c: New.
+ * jit.dg/test-combination.c (code_making_callback): Use code
+ from test-types.c.
+ (verify_code): ...and verify it.
+
+2013-10-16 David Malcolm <dmalcolm@redhat.com>
+
+ * jit.dg/test-dot-product.c (code_making_callback): Update for
+ API changes to locals.
+ * jit.dg/test-sum-of-squares.c (code_making_callback): Likewise.
+
+2013-10-14 David Malcolm <dmalcolm@redhat.com>
+
+ * jit.dg/jit.exp (jit-dg-test): Detect compilation errors and
+ make them be test failures.
+
+2013-10-14 David Malcolm <dmalcolm@redhat.com>
+
+ * jit.dg/test-factorial.c (code_making_callback): Update
+ for change to gcc_jit_function_place_forward_label.
+ * jit.dg/test-fibonacci.c (code_making_callback): Add line
+ numbering to comment, and set up source locations throughout)
+ allowing stepping throught the comment in the debugger.
+ * jit.dg/test-sum-of-squares.c (code_making_callback): Update
+ for change to gcc_jit_function_place_forward_label.
+
+2013-10-10 David Malcolm <dmalcolm@redhat.com>
+
+ * jit.dg/harness.h: Set GCC_JIT_BOOL_OPTION_DUMP_SUMMARY when
+ running selftests.
+
+2013-10-08 David Malcolm <dmalcolm@redhat.com>
+
+ * jit.dg/harness.h: Wrap parts of harness within a
+ #ifndef TEST_COMBINATION so that it can be included multiple
+ times.
+ * jit.dg/test-accessing-struct.c (code_making_callback): Rename
+ the generated function from test_fn to test_access to avoid a
+ naming collision in the combined test.
+ (verify_code): Likewise.
+ * jit.dg/test-calling-external-function.c (code_making_callback):
+ Rename the generated function from test_fn to test_caller.
+ (verify_code): Likewise.
+ * jit.dg/test-combination.c: New.
+ * jit.dg/test-string-literal.c (code_making_callback): Rename
+ the generated function from test_fn to test_string_literal.
+ (verify_code): Likewise.
+ * jit.dg/test-using-global.c (code_making_callback): Rename
+ the generated function from test_fn to test_using_global.
+ (verify_code): Likewise.
+
+2013-10-07 David Malcolm <dmalcolm@redhat.com>
+
+ * jit.dg/harness.h (test_jit): Set
+ GCC_JIT_BOOL_OPTION_SELFCHECK_GC when running selftests.
+
+2013-10-04 David Malcolm <dmalcolm@redhat.com>
+
+ * jit.dg/test-using-global.c: New.
+
+2013-10-03 David Malcolm <dmalcolm@redhat.com>
+
+ * jit.dg: New subdirectory
+ * jit.dg/harness.h: New.
+ * jit.dg/jit.exp: New.
+ * jit.dg/test-accessing-struct.c: New.
+ * jit.dg/test-calling-external-function.c: New.
+ * jit.dg/test-dot-product.c: New.
+ * jit.dg/test-factorial.c: New.
+ * jit.dg/test-failure.c: New.
+ * jit.dg/test-fibonacci.c: New.
+ * jit.dg/test-hello-world.c: New.
+ * jit.dg/test-string-literal.c: New.
+ * jit.dg/test-sum-of-squares.c: New.
+
+\f
+Copyright (C) 2013-2014 Free Software Foundation, Inc.
+
+Copying and distribution of this file, with or without modification,
+are permitted in any medium without royalty provided the copyright
+notice and this notice are preserved.
--- /dev/null
+/* This file is used by test-combination.c and test-threads.c to
+ bring all of the non-failing test cases into one source file,
+ renaming each "create_code" and "verify_code" hook so that they
+ each have unique name. */
+
+/* Include various other test cases, defining COMBINED_TEST so that
+ harness.h doesn't duplicate copes of e.g. main, and renaming the
+ hooks provided by each test case. */
+#define COMBINED_TEST
+
+/* test-accessing-struct.c */
+#define create_code create_code_accessing_struct
+#define verify_code verify_code_accessing_struct
+#include "test-accessing-struct.c"
+#undef create_code
+#undef verify_code
+
+/* test-accessing-union.c */
+#define create_code create_code_accessing_union
+#define verify_code verify_code_accessing_union
+#include "test-accessing-union.c"
+#undef create_code
+#undef verify_code
+
+/* test-array-as-pointer.c */
+#define create_code create_code_array_as_pointer
+#define verify_code verify_code_array_as_pointer
+#include "test-array-as-pointer.c"
+#undef create_code
+#undef verify_code
+
+/* test-arrays.c */
+#define create_code create_code_arrays
+#define verify_code verify_code_arrays
+#include "test-arrays.c"
+#undef create_code
+#undef verify_code
+
+/* test-calling-external-function.c */
+#define create_code create_code_calling_external_function
+#define verify_code verify_code_calling_external_function
+#include "test-calling-external-function.c"
+#undef create_code
+#undef verify_code
+
+/* test-calling-function-ptr.c */
+#define create_code create_code_calling_function_ptr
+#define verify_code verify_code_calling_function_ptr
+#include "test-calling-function-ptr.c"
+#undef create_code
+#undef verify_code
+
+/* test-dot-product.c */
+#define create_code create_code_dot_product
+#define verify_code verify_code_dot_product
+#include "test-dot-product.c"
+#undef create_code
+#undef verify_code
+
+/* test-error-*.c: We don't use these test cases, since they deliberately
+ introduce errors, which we don't want here. */
+
+/* test-expressions.c */
+#define create_code create_code_expressions
+#define verify_code verify_code_expressions
+#include "test-expressions.c"
+#undef create_code
+#undef verify_code
+
+/* test-factorial.c */
+#define create_code create_code_factorial
+#define verify_code verify_code_factorial
+#include "test-factorial.c"
+#undef create_code
+#undef verify_code
+
+/* test-fibonacci.c */
+#define create_code create_code_fibonacci
+#define verify_code verify_code_fibonacci
+#include "test-fibonacci.c"
+#undef create_code
+#undef verify_code
+
+/* test-functions.c */
+#define create_code create_code_functions
+#define verify_code verify_code_functions
+#include "test-functions.c"
+#undef create_code
+#undef verify_code
+
+/* test-hello-world.c */
+#define create_code create_code_hello_world
+#define verify_code verify_code_hello_world
+#include "test-hello-world.c"
+#undef create_code
+#undef verify_code
+
+/* test-linked-list.c */
+#define create_code create_code_linked_list
+#define verify_code verify_code_linked_list
+#include "test-linked-list.c"
+#undef create_code
+#undef verify_code
+
+/* test-long-names.c */
+#define create_code create_code_long_names
+#define verify_code verify_code_long_names
+#include "test-long-names.c"
+#undef create_code
+#undef verify_code
+
+/* test-quadratic.c */
+#define create_code create_code_quadratic
+#define verify_code verify_code_quadratic
+#include "test-quadratic.c"
+#undef create_code
+#undef verify_code
+
+/* test-nested-loops.c */
+#define create_code create_code_nested_loop
+#define verify_code verify_code_nested_loop
+#include "test-nested-loops.c"
+#undef create_code
+#undef verify_code
+
+/* test-reading-struct.c */
+#define create_code create_code_reading_struct
+#define verify_code verify_code_reading_struct
+#include "test-reading-struct.c"
+#undef create_code
+#undef verify_code
+
+/* test-string-literal.c */
+#define create_code create_code_string_literal
+#define verify_code verify_code_string_literal
+#include "test-string-literal.c"
+#undef create_code
+#undef verify_code
+
+/* test-sum-of-squares.c */
+#define create_code create_code_sum_of_squares
+#define verify_code verify_code_sum_of_squares
+#include "test-sum-of-squares.c"
+#undef create_code
+#undef verify_code
+
+/* test-types.c */
+#define create_code create_code_types
+#define verify_code verify_code_types
+#include "test-types.c"
+#undef create_code
+#undef verify_code
+
+/* test-using-global.c */
+#define create_code create_code_using_global
+#define verify_code verify_code_using_global
+#include "test-using-global.c"
+#undef create_code
+#undef verify_code
+
+/* test-volatile.c */
+#define create_code create_code_volatile
+#define verify_code verify_code_volatile
+#include "test-volatile.c"
+#undef create_code
+#undef verify_code
--- /dev/null
+/*
+ Code shared between multiple testcases.
+
+ This file contains "main" and support code.
+ Each testcase should implement the following hooks:
+
+ extern void
+ create_code (gcc_jit_context *ctxt, void * user_data);
+
+ extern void
+ verify_code (gcc_jit_context *ctxt, gcc_jit_result *result);
+
+ */
+#include <stdlib.h>
+#include <stdio.h>
+
+/* test-threads.c use threads, but dejagnu.h isn't thread-safe; there's a
+ shared "buffer", and the counts of passed/failed etc are globals.
+
+ The solution is to use macros to rename "pass" and "fail", replacing them
+ with mutex-guarded alternatives. */
+#ifdef MAKE_DEJAGNU_H_THREADSAFE
+#define pass dejagnu_pass
+#define fail dejagnu_fail
+#define note dejagnu_note
+#endif
+
+#include <dejagnu.h>
+
+#ifdef MAKE_DEJAGNU_H_THREADSAFE
+#undef pass
+#undef fail
+#undef note
+#endif
+
+static char test[1024];
+
+#define CHECK_NON_NULL(PTR) \
+ do { \
+ if ((PTR) != NULL) \
+ { \
+ pass ("%s: %s is non-null", test, #PTR); \
+ } \
+ else \
+ { \
+ fail ("%s: %s is NULL", test, #PTR); \
+ abort (); \
+ } \
+ } while (0)
+
+#define CHECK_VALUE(ACTUAL, EXPECTED) \
+ do { \
+ if ((ACTUAL) == (EXPECTED)) \
+ { \
+ pass ("%s: actual: %s == expected: %s", test, #ACTUAL, #EXPECTED); \
+ } \
+ else \
+ { \
+ fail ("%s: actual: %s != expected: %s", test, #ACTUAL, #EXPECTED); \
+ fprintf (stderr, "incorrect value\n"); \
+ abort (); \
+ } \
+ } while (0)
+
+#define CHECK_DOUBLE_VALUE(ACTUAL, EXPECTED) \
+ do { \
+ double expected = (EXPECTED); \
+ double actual = (ACTUAL); \
+ if (abs (actual - expected) < 0.00001) \
+ { \
+ pass ("%s: actual: %s == expected: %s", test, #ACTUAL, #EXPECTED); \
+ } \
+ else \
+ { \
+ fail ("%s: actual: %s != expected: %s", test, #ACTUAL, #EXPECTED); \
+ fprintf (stderr, "incorrect value: %f\n", actual); \
+ abort (); \
+ } \
+ } while (0)
+
+#define CHECK_STRING_VALUE(ACTUAL, EXPECTED) \
+ check_string_value ((ACTUAL), (EXPECTED));
+
+#define CHECK(COND) \
+ do { \
+ if (COND) \
+ { \
+ pass ("%s: %s", test, #COND); \
+ } \
+ else \
+ { \
+ fail ("%s: %s", test, #COND); \
+ abort (); \
+ } \
+ } while (0)
+
+/* Hooks that testcases should provide. */
+extern void
+create_code (gcc_jit_context *ctxt, void * user_data);
+
+extern void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result);
+
+extern void check_string_value (const char *actual, const char *expected);
+
+/* Implement framework needed for turning the testcase hooks into an
+ executable. test-combination.c and test-threads.c each combine multiple
+ testcases into larger testcases, so we have COMBINED_TEST as a way of
+ temporarily turning off this part of harness.h. */
+#ifndef COMBINED_TEST
+
+void check_string_value (const char *actual, const char *expected)
+{
+ if (actual && !expected)
+ {
+ fail ("%s: actual: \"%s\" != expected: NULL", test, actual);
+ fprintf (stderr, "incorrect value\n");
+ abort ();
+ }
+ if (expected && !actual)
+ {
+ fail ("%s: actual: NULL != expected: \"%s\"", test, expected);
+ fprintf (stderr, "incorrect value\n");
+ abort ();
+ }
+ if (actual && expected)
+ {
+ if (strcmp (actual, expected))
+ {
+ fail ("%s: actual: \"%s\" != expected: \"%s\"", test, actual, expected);
+ fprintf (stderr, "incorrect valuen");
+ abort ();
+ }
+ pass ("%s: actual: \"%s\" == expected: \"%s\"", test, actual, expected);
+ }
+ else
+ pass ("%s: actual: NULL == expected: NULL");
+}
+
+static void set_options (gcc_jit_context *ctxt, const char *argv0)
+{
+ /* Set up options. */
+ gcc_jit_context_set_str_option (
+ ctxt,
+ GCC_JIT_STR_OPTION_PROGNAME,
+ argv0);
+ gcc_jit_context_set_int_option (
+ ctxt,
+ GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL,
+ 3);
+ gcc_jit_context_set_bool_option (
+ ctxt,
+ GCC_JIT_BOOL_OPTION_DEBUGINFO,
+ 1);
+ gcc_jit_context_set_bool_option (
+ ctxt,
+ GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE,
+ 0);
+ gcc_jit_context_set_bool_option (
+ ctxt,
+ GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE,
+ 0);
+ gcc_jit_context_set_bool_option (
+ ctxt,
+ GCC_JIT_BOOL_OPTION_SELFCHECK_GC,
+ 1);
+ gcc_jit_context_set_bool_option (
+ ctxt,
+ GCC_JIT_BOOL_OPTION_DUMP_SUMMARY,
+ 0);
+}
+
+#ifndef TEST_ESCHEWS_TEST_JIT
+/* Run one iteration of the test. */
+static void
+test_jit (const char *argv0, void *user_data)
+{
+ gcc_jit_context *ctxt;
+ gcc_jit_result *result;
+
+ ctxt = gcc_jit_context_acquire ();
+ /* FIXME: error-handling */
+
+ set_options (ctxt, argv0);
+
+ create_code (ctxt, user_data);
+
+ /* This actually calls into GCC and runs the build, all
+ in a mutex for now. */
+ result = gcc_jit_context_compile (ctxt);
+
+ verify_code (ctxt, result);
+
+ gcc_jit_context_release (ctxt);
+
+ /* Once we're done with the code, this unloads the built .so file: */
+ gcc_jit_result_release (result);
+}
+#endif /* #ifndef TEST_ESCHEWS_TEST_JIT */
+
+/* We want to prefix all unit test results with the test, but dejagnu.exp's
+ host_execute appears to get confused by the leading "./" of argv0,
+ leading to all tests simply reporting as a single period character ".".
+
+ Hence strip out the final component of the path to the program name,
+ so that we can use that in unittest reports. */
+const char*
+extract_progname (const char *argv0)
+{
+ const char *p;
+
+ p = argv0 + strlen (argv0);
+ while (p != argv0 && p[-1] != '/')
+ --p;
+ return p;
+}
+
+#ifndef TEST_PROVIDES_MAIN
+int
+main (int argc, char **argv)
+{
+ int i;
+
+ for (i = 1; i <= 5; i++)
+ {
+ snprintf (test, sizeof (test),
+ "%s iteration %d of %d",
+ extract_progname (argv[0]),
+ i, 5);
+
+ //printf ("ITERATION %d\n", i);
+ test_jit (argv[0], NULL);
+ //printf ("\n");
+ }
+
+ totals ();
+
+ return 0;
+}
+#endif /* #ifndef TEST_PROVIDES_MAIN */
+
+#endif /* #ifndef COMBINED_TEST */
--- /dev/null
+# Test code for libgccjit.so
+#
+# We will compile each of jit.dg/test-*.c into an executable
+# dynamically linked against libgccjit.so, and then run each
+# such executable.
+#
+# These executables call into the libgccjit.so API to create
+# code, compile it, and run it, verifying that the results
+# are as expected. See harness.h for shared code used by all
+# such executables.
+#
+# The executables call into DejaGnu's unit testing C API to
+# report PASS/FAIL results, which this script gathers back
+# up into the Tcl world, reporting a summary of all results
+# across all of the executables.
+
+load_lib dg.exp
+load_lib prune.exp
+load_lib target-supports.exp
+load_lib gcc-defs.exp
+load_lib timeout.exp
+load_lib target-libpath.exp
+load_lib gcc.exp
+load_lib dejagnu.exp
+
+# This is host_execute from dejagnu.exp commit
+# 126a089777158a7891ff975473939f08c0e31a1c
+# with the following patch applied, and renaming to "fixed_host_execute".
+# See the discussion at
+# http://lists.gnu.org/archive/html/dejagnu/2014-10/msg00000.html
+#
+# --- /usr/share/dejagnu/dejagnu.exp.old 2014-10-08 13:38:57.274068541 -0400
+# +++ /usr/share/dejagnu/dejagnu.exp 2014-10-10 12:27:51.113813659 -0400
+# @@ -113,8 +113,6 @@ proc host_execute {args} {
+# set timetol 0
+# set arguments ""
+#
+# - expect_before buffer_full { perror "Buffer full" }
+# -
+# if { [llength $args] == 0} {
+# set executable $args
+# } else {
+
+
+# Execute the executable file, and anaylyse the output for the
+# test state keywords.
+# Returns:
+# A "" (empty) string if everything worked, or an error message
+# if there was a problem.
+#
+proc fixed_host_execute {args} {
+ global text
+ global spawn_id
+
+ set timeoutmsg "Timed out: Never got started, "
+ set timeout 100
+ set file all
+ set timetol 0
+ set arguments ""
+
+ if { [llength $args] == 0} {
+ set executable $args
+ } else {
+ set executable [string trimleft [lindex [split $args " "] 0] "\{"]
+ set params [string trimleft [lindex [split $args " "] 1] "\{"]
+ set params [string trimright $params "\}"]
+ }
+
+ verbose "The executable is $executable" 2
+ if {![file exists ${executable}]} {
+ perror "The executable, \"$executable\" is missing" 0
+ return "No source file found"
+ }
+
+ # spawn the executable and look for the DejaGnu output messages from the
+ # test case.
+ # spawn -noecho -open [open "|./${executable}" "r"]
+ spawn -noecho "./${executable}" ${params}
+ expect_after full_buffer { error "got full_buffer" }
+
+ set prefix "\[^\r\n\]*"
+ expect {
+ -re "^$prefix\[0-9\]\[0-9\]:..:..:${text}*\r\n" {
+ regsub "\[\n\r\t\]*NOTE: $text\r\n" $expect_out(0,string) "" output
+ verbose "$output" 3
+ set timetol 0
+ exp_continue
+ }
+ -re "^$prefix\tNOTE:${text}*" {
+ regsub "\[\n\r\t\]*NOTE: $text\r\n" $expect_out(0,string) "" output
+ set output [string range $output 6 end]
+ verbose "$output" 2
+ set timetol 0
+ exp_continue
+ }
+ -re "^$prefix\tPASSED:${text}*" {
+ regsub "\[\n\r\t\]*PASSED: $text\r\n" $expect_out(0,string) "" output
+ set output [string range $output 8 end]
+ pass "$output"
+ set timetol 0
+ exp_continue
+ }
+ -re "^$prefix\tFAILED:${text}*" {
+ regsub "\[\n\r\t\]*FAILED: $text\r\n" $expect_out(0,string) "" output
+ set output [string range $output 8 end]
+ fail "$output"
+ set timetol 0
+ exp_continue
+ }
+ -re "^$prefix\tUNTESTED:${text}*" {
+ regsub "\[\n\r\t\]*TESTED: $text\r\n" $expect_out(0,string) "" output
+ set output [string range $output 8 end]
+ untested "$output"
+ set timetol 0
+ exp_continue
+ }
+ -re "^$prefix\tUNRESOLVED:${text}*" {
+ regsub "\[\n\r\t\]*UNRESOLVED: $text\r\n" $expect_out(0,string) "" output
+ set output [string range $output 8 end]
+ unresolved "$output"
+ set timetol 0
+ exp_continue
+ }
+ -re "^Totals" {
+ verbose "All done" 2
+ }
+ eof {
+ # unresolved "${executable} died prematurely"
+ # catch close
+ # return "${executable} died prematurely"
+ }
+ timeout {
+ warning "Timed out executing test case"
+ if { $timetol <= 2 } {
+ incr timetol
+ exp_continue
+ } else {
+ - catch close
+ return "Timed out executing test case"
+ }
+ }
+ -re "^$prefix\r\n" {
+ exp_continue
+ }
+ }
+
+ # force a close of the executable to be safe.
+ catch close
+
+ return ""
+}
+
+# (end of code from dejagnu.exp)
+
+# GCC_UNDER_TEST is needed by gcc_target_compile
+global GCC_UNDER_TEST
+if ![info exists GCC_UNDER_TEST] {
+ set GCC_UNDER_TEST "[find_gcc]"
+}
+
+# Initialize dg.
+dg-init
+
+# Gather a list of all tests.
+
+# Tests within the testsuite: gcc/testsuite/jit.dg/test-*.c
+set tests [lsort [find $srcdir/$subdir test-*.c]]
+
+# We also test the examples within the documentation, to ensure that
+# they compile:
+set tests [lsort [concat $tests [find $srcdir/../jit/docs/examples *.c]]]
+
+verbose "tests: $tests"
+
+# libgloss has found the driver (as "xgcc" or "gcc) and stored
+# its full path as GCC_UNDER_TEST.
+proc get_path_of_driver {} {
+ global GCC_UNDER_TEST
+
+ verbose "GCC_UNDER_TEST: $GCC_UNDER_TEST"
+ set binary [lindex $GCC_UNDER_TEST 0]
+ verbose "binary: $binary"
+
+ return [file dirname $binary]
+}
+
+proc jit-dg-test { prog do_what extra_tool_flags } {
+ verbose "within jit-dg-test..."
+ verbose " prog: $prog"
+ verbose " do_what: $do_what"
+ verbose " extra_tool_flags: $extra_tool_flags"
+
+ # test-threads.c needs to be linked against pthreads
+ if {[string match "*test-threads.c" $prog]} {
+ append extra_tool_flags " -lpthread"
+ }
+
+ # Determine what to name the built executable.
+ set output_file "[file rootname [file tail $prog]].exe"
+ verbose "output_file: $output_file"
+
+ # Create the test executable:
+ set comp_output [gcc_target_compile $prog $output_file $do_what \
+ "{additional_flags=$extra_tool_flags}"]
+ if ![jit_check_compile "$prog" "initial compilation" \
+ $output_file $comp_output] then {
+ return
+ }
+
+ # Run the test executable, capturing the PASS/FAIL textual output
+ # from the C API, converting it into the Tcl API.
+
+ # We need to set LD_LIBRARY_PATH so that the test files can find
+ # libgccjit.so
+ # Do this using set_ld_library_path_env_vars from target-libpath.exp
+ global ld_library_path
+ global base_dir
+ set ld_library_path "$base_dir/../../"
+ set_ld_library_path_env_vars
+
+ # libgccjit uses the driver to convert .s files to .so libraries
+ # via its *installed* name, FULL_DRIVER_NAME
+ # ${target_noncanonical}-gcc-${gcc_BASEVER}${exeext}
+ # e.g. "x86_64-unknown-linux-gnu-gcc-5.0.0"
+ # looking for it on PATH. Hence we need to prepend the location of
+ # that executable to PATH when running the tests
+ set dir_containing_driver [get_path_of_driver ]
+ verbose "dir_containing_driver: $dir_containing_driver"
+ global env
+ set old_path $env(PATH)
+ setenv "PATH" $dir_containing_driver:$old_path
+ verbose -log "PATH=[getenv PATH]"
+
+ # We have:
+ # test-executables
+ # linked to -> libgccjit.so
+ # -> invokes driver:
+ # -> invokes the assembler
+ # -> invokes the linker
+ # We want to be able to run this from the builddir without installing
+ # but the linker needs to be able to locate various libraries, or we
+ # get:
+ # ld: cannot find crtbeginS.o: No such file or directory
+ # ld: cannot find -lgcc
+ # ld: cannot find -lgcc_s
+ # These can be found in the "gcc" subdir of the build.
+ # Hence to be able to run the testsuite without installing, we need
+ # to set or prepend the "gcc" subdir of the build to LIBRARY_PATH:
+ if { [info exists env(LIBRARY_PATH) ] } {
+ set old_library_path $env(LIBRARY_PATH)
+ setenv "LIBRARY_PATH" $dir_containing_driver:$old_library_path
+ } else {
+ setenv "LIBRARY_PATH" $dir_containing_driver
+ }
+ verbose -log "LIBRARY_PATH=[getenv LIBRARY_PATH]"
+
+ # dejagnu.exp's host_execute has code to scrape out test results
+ # from the DejaGnu C API and bring back into the tcl world, so we
+ # use that to invoke the built code.
+ # However, it appears to be buggy; see:
+ # http://lists.gnu.org/archive/html/dejagnu/2014-10/msg00000.html
+ # We instead call a patched local copy, "fixed_host_execute", defined
+ # above.
+ set result [fixed_host_execute $output_file]
+ verbose "result: $result"
+
+ # Restore PATH
+ setenv "PATH" $old_path
+
+ # Restore LIBRARY_PATH
+ if { [info exists old_library_path] } {
+ setenv "LIBRARY_PATH" $old_library_path
+ } else {
+ unsetenv "LIBRARY_PATH"
+ }
+
+ restore_ld_library_path_env_vars
+}
+
+# We need to link with --export-dynamic for test-calling-external-function.c
+# so that the JIT-built code can call into functions from the main program.
+set DEFAULT_CFLAGS "-I$srcdir/../jit -lgccjit -g -Wall -Werror -Wl,--export-dynamic"
+
+# <dejagnu.h> assumes -fgnu89-inline
+# See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63613
+# and http://lists.gnu.org/archive/html/dejagnu/2014-10/msg00011.html
+append DEFAULT_CFLAGS " -fgnu89-inline"
+
+# Main loop. This will invoke jig-dg-test on each test-*.c file.
+dg-runtest $tests "" $DEFAULT_CFLAGS
+
+# All done.
+dg-finish
--- /dev/null
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+struct foo
+{
+ int x;
+ int y;
+ int z;
+};
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ /* Let's try to inject the equivalent of:
+ void
+ test_access (struct foo *f)
+ {
+ f->z = f->x * f->y;
+ }
+ */
+ gcc_jit_type *void_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+ gcc_jit_type *int_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+ gcc_jit_field *x =
+ gcc_jit_context_new_field (ctxt,
+ NULL,
+ int_type,
+ "x");
+ gcc_jit_field *y =
+ gcc_jit_context_new_field (ctxt,
+ NULL,
+ int_type,
+ "y");
+ gcc_jit_field *z =
+ gcc_jit_context_new_field (ctxt,
+ NULL,
+ int_type,
+ "z");
+ gcc_jit_field *fields[] = {x, y, z};
+ gcc_jit_struct *struct_type =
+ gcc_jit_context_new_struct_type (ctxt, NULL, "foo", 3, fields);
+ gcc_jit_type *ptr_type =
+ gcc_jit_type_get_pointer (gcc_jit_struct_as_type (struct_type));
+
+ /* Build the test function. */
+ gcc_jit_param *param_f =
+ gcc_jit_context_new_param (ctxt, NULL, ptr_type, "f");
+ gcc_jit_function *test_fn =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ void_type,
+ "test_access",
+ 1, ¶m_f,
+ 0);
+
+ /* f->x * f->y */
+ gcc_jit_rvalue *sum =
+ gcc_jit_context_new_binary_op (
+ ctxt, NULL,
+ GCC_JIT_BINARY_OP_MULT,
+ int_type,
+ gcc_jit_lvalue_as_rvalue (
+ gcc_jit_rvalue_dereference_field (
+ gcc_jit_param_as_rvalue (param_f),
+ NULL,
+ x)),
+ gcc_jit_lvalue_as_rvalue (
+ gcc_jit_rvalue_dereference_field (
+ gcc_jit_param_as_rvalue (param_f),
+ NULL,
+ y)));
+
+ /* f->z = ... */
+ gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
+ gcc_jit_block_add_assignment (
+ block,
+ NULL,
+ gcc_jit_rvalue_dereference_field (
+ gcc_jit_param_as_rvalue (param_f),
+ NULL,
+ z),
+ sum);
+ gcc_jit_block_end_with_void_return (block, NULL);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ typedef void (*fn_type) (struct foo *);
+ CHECK_NON_NULL (result);
+
+ fn_type test_access =
+ (fn_type)gcc_jit_result_get_code (result, "test_access");
+ CHECK_NON_NULL (test_access);
+
+ struct foo tmp;
+ tmp.x = 5;
+ tmp.y = 7;
+ tmp.z = 0;
+
+ /* Call the JIT-generated function. */
+ test_access (&tmp);
+
+ /* Verify that the code correctly modified the field "z". */
+ CHECK_VALUE (tmp.z, 35);
+}
+
--- /dev/null
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+union int_or_float
+{
+ int as_int;
+ float as_float;
+};
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ /* Let's try to inject the equivalent of:
+ float
+ test_union (int i)
+ {
+ union int_or_float u;
+ u.as_int = i;
+ return u.as_float;
+ }
+ */
+ gcc_jit_type *int_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+ gcc_jit_type *float_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_FLOAT);
+ gcc_jit_field *as_int =
+ gcc_jit_context_new_field (ctxt,
+ NULL,
+ int_type,
+ "as_int");
+ gcc_jit_field *as_float =
+ gcc_jit_context_new_field (ctxt,
+ NULL,
+ float_type,
+ "as_float");
+ gcc_jit_field *fields[] = {as_int, as_float};
+ gcc_jit_type *union_type =
+ gcc_jit_context_new_union_type (ctxt, NULL,
+ "int_or_float", 2, fields);
+
+ /* Build the test function. */
+ gcc_jit_param *param_i =
+ gcc_jit_context_new_param (ctxt, NULL, int_type, "i");
+ gcc_jit_function *test_fn =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ float_type,
+ "test_union",
+ 1, ¶m_i,
+ 0);
+
+ gcc_jit_lvalue *u =
+ gcc_jit_function_new_local (test_fn, NULL,
+ union_type, "u");
+
+ gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
+
+ /* u.as_int = i; */
+ gcc_jit_block_add_assignment (
+ block,
+ NULL,
+ /* "u.as_int = ..." */
+ gcc_jit_lvalue_access_field (u,
+ NULL,
+ as_int),
+ gcc_jit_param_as_rvalue (param_i));
+
+ /* return u.as_float; */
+ gcc_jit_block_end_with_return (
+ block, NULL,
+ gcc_jit_rvalue_access_field (gcc_jit_lvalue_as_rvalue (u),
+ NULL,
+ as_float));
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ typedef float (*fn_type) (int i);
+ CHECK_NON_NULL (result);
+
+ fn_type test_union =
+ (fn_type)gcc_jit_result_get_code (result, "test_union");
+ CHECK_NON_NULL (test_union);
+
+ /* Call the JIT-generated function. */
+ float f_result = test_union (42);
+
+ union int_or_float u;
+ u.as_float = f_result;
+
+ CHECK_VALUE (u.as_int, 42);
+}
--- /dev/null
+#include <stdlib.h>
+#include <stdio.h>
+#include <stddef.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+#define BUFFER_SIZE (1024)
+
+char test_buffer[1024];
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ /* Let's try to inject the equivalent of:
+ void test_of_array_as_pointer (const char *name)
+ {
+ snprintf (test_buffer, sizeof (test_buffer),
+ "hello %s", name);
+ }
+ */
+ gcc_jit_type *void_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+ gcc_jit_type *const_char_ptr_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_CONST_CHAR_PTR);
+ gcc_jit_type *char_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_CHAR);
+ gcc_jit_type *char_ptr_type =
+ gcc_jit_type_get_pointer (char_type);
+ gcc_jit_type *int_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+ gcc_jit_type *size_t_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_SIZE_T);
+ gcc_jit_type *buf_type =
+ gcc_jit_context_new_array_type (ctxt, NULL, char_type, BUFFER_SIZE);
+
+ /* extern int snprintf(char *str, size_t size, const char *format, ...); */
+ gcc_jit_param *param_s =
+ gcc_jit_context_new_param (ctxt, NULL, char_ptr_type, "s");
+ gcc_jit_param *param_n =
+ gcc_jit_context_new_param (ctxt, NULL, size_t_type, "n");
+ gcc_jit_param *param_format =
+ gcc_jit_context_new_param (ctxt, NULL, const_char_ptr_type, "format");
+ gcc_jit_param *snprintf_params[3] = {param_s, param_n, param_format};
+ gcc_jit_function *snprintf =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_IMPORTED,
+ int_type,
+ "snprintf",
+ 3, snprintf_params,
+ 1);
+
+ gcc_jit_param *param_name =
+ gcc_jit_context_new_param (ctxt, NULL, const_char_ptr_type, "name");
+ gcc_jit_function *test_fn =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ void_type,
+ "test_of_array_as_pointer",
+ 1, ¶m_name,
+ 0);
+
+ gcc_jit_lvalue *buffer =
+ gcc_jit_context_new_global (ctxt, NULL, buf_type, "test_buffer");
+
+ gcc_jit_block *block = gcc_jit_function_new_block(test_fn, "entry");
+
+ /* snprintf(buffer, sizeof(buffer), "hello %s", name); */
+ gcc_jit_rvalue *args[4];
+ args[0] = gcc_jit_context_new_cast (
+ ctxt, NULL,
+ /* Here's the difference with test-error-array-as-pointer.c: */
+ gcc_jit_lvalue_get_address (buffer,
+ NULL),
+ char_ptr_type);
+ args[1] = gcc_jit_context_new_rvalue_from_int (ctxt,
+ size_t_type,
+ BUFFER_SIZE);
+ args[2] = gcc_jit_context_new_string_literal (ctxt, "hello %s");
+ args[3] = gcc_jit_param_as_rvalue (param_name);
+
+ gcc_jit_block_add_eval (
+ block, NULL,
+ gcc_jit_context_new_call (ctxt, NULL, snprintf, 4, args));
+ gcc_jit_block_end_with_void_return (block, NULL);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ CHECK_NON_NULL (result);
+
+ typedef void (*fn_type) (const char *);
+ fn_type test_of_array_as_pointer =
+ (fn_type)gcc_jit_result_get_code (result, "test_of_array_as_pointer");
+ CHECK_NON_NULL (test_of_array_as_pointer);
+
+ test_of_array_as_pointer ("world");
+ CHECK_STRING_VALUE (test_buffer, "hello world");
+}
--- /dev/null
+#include <stdlib.h>
+#include <stdio.h>
+#include <stddef.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+#define ARRAY_SIZE (4)
+
+/* Verify that struct layout works properly when adding an array field. */
+struct array_holder
+{
+ float m_before;
+ int m_ints[ARRAY_SIZE];
+ float m_after;
+};
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ /* Let's try to inject the equivalent of:
+
+ void
+ test_array (struct array_holder *ah)
+ {
+ ah->m_before = 4.0f;
+ for i in 0 to (ARRAY_SIZE - 1):
+ ah->m_ints[i] = (i * i);
+ ah->m_after = 2.0f;
+ }
+ */
+ gcc_jit_type *void_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+ gcc_jit_type *float_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_FLOAT);
+ gcc_jit_type *int_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+ gcc_jit_field *field_m_before =
+ gcc_jit_context_new_field (ctxt, NULL, float_type, "m_before");
+ gcc_jit_field *field_m_ints =
+ gcc_jit_context_new_field (
+ ctxt, NULL,
+ gcc_jit_context_new_array_type (ctxt, NULL, int_type, ARRAY_SIZE),
+ "m_ints");
+ gcc_jit_field *field_m_after =
+ gcc_jit_context_new_field (ctxt, NULL, float_type, "m_after");
+
+ gcc_jit_field *fields[] = {
+ field_m_before,
+ field_m_ints,
+ field_m_after,
+ };
+
+ gcc_jit_struct *struct_type =
+ gcc_jit_context_new_struct_type (
+ ctxt,
+ NULL,
+ "array_holder",
+ 3, fields);
+
+ gcc_jit_type *struct_ptr_type =
+ gcc_jit_type_get_pointer (gcc_jit_struct_as_type (struct_type));
+
+ /* Build the test_fn. */
+ gcc_jit_param *param_ah =
+ gcc_jit_context_new_param (ctxt, NULL, struct_ptr_type, "ah");
+ gcc_jit_function *func =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ void_type,
+ "test_array",
+ 1, ¶m_ah,
+ 0);
+
+ gcc_jit_block *initial = gcc_jit_function_new_block (func, "initial");
+ gcc_jit_block *loop_test = gcc_jit_function_new_block (func, "loop_test");
+ gcc_jit_block *loop_body = gcc_jit_function_new_block (func, "loop_body");
+ gcc_jit_block *final = gcc_jit_function_new_block (func, "final");
+
+ /* "ah->m_before = 4.0f;" */
+ gcc_jit_block_add_assignment (
+ initial, NULL,
+ gcc_jit_rvalue_dereference_field (
+ gcc_jit_param_as_rvalue (param_ah), NULL, field_m_before),
+ gcc_jit_context_new_rvalue_from_int (ctxt, float_type, 4));
+
+ gcc_jit_block_add_comment (initial, NULL,
+ "for i in 0 to (ARRAY_SIZE - 1):");
+ gcc_jit_lvalue *i =
+ gcc_jit_function_new_local (func, NULL, int_type, "i");
+ gcc_jit_block_add_assignment (initial, NULL,
+ i,
+ gcc_jit_context_zero (ctxt, int_type));
+
+ gcc_jit_block_end_with_jump (initial, NULL, loop_test);
+
+ gcc_jit_block_end_with_conditional (loop_test, NULL,
+ gcc_jit_context_new_comparison (
+ ctxt, NULL,
+ GCC_JIT_COMPARISON_LT,
+ gcc_jit_lvalue_as_rvalue (i),
+ gcc_jit_context_new_rvalue_from_int (ctxt, int_type, ARRAY_SIZE)),
+ loop_body,
+ final);
+
+ gcc_jit_block_add_comment (loop_body, NULL, "ah->m_ints[i] = (i * i);");
+ gcc_jit_block_add_assignment (
+ loop_body, NULL,
+ gcc_jit_context_new_array_access (
+ ctxt, NULL,
+ gcc_jit_lvalue_as_rvalue (gcc_jit_rvalue_dereference_field (
+ gcc_jit_param_as_rvalue (param_ah),
+ NULL,
+ field_m_ints)),
+ gcc_jit_lvalue_as_rvalue (i)),
+ gcc_jit_context_new_binary_op (
+ ctxt, NULL,
+ GCC_JIT_BINARY_OP_MULT,
+ int_type,
+ gcc_jit_lvalue_as_rvalue (i),
+ gcc_jit_lvalue_as_rvalue (i)));
+
+ /* "i++" */
+ gcc_jit_block_add_assignment_op (
+ loop_body, NULL,
+ i,
+ GCC_JIT_BINARY_OP_PLUS,
+ gcc_jit_context_one (ctxt, int_type));
+
+ gcc_jit_block_end_with_jump (loop_body, NULL, loop_test);
+
+ /* ah->m_after = 2.0f; */
+ gcc_jit_block_add_assignment (
+ final, NULL,
+ gcc_jit_rvalue_dereference_field (
+ gcc_jit_param_as_rvalue (param_ah), NULL, field_m_after),
+ gcc_jit_context_new_rvalue_from_int (ctxt, float_type, 2));
+ gcc_jit_block_end_with_void_return (final, NULL);
+
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ typedef void (*fn_type) (struct array_holder *ah);
+
+ CHECK_NON_NULL (result);
+ fn_type test_array =
+ (fn_type)gcc_jit_result_get_code (result, "test_array");
+ CHECK_NON_NULL (test_array);
+
+ struct array_holder ah;
+ memset (&ah, 0xf0, sizeof (ah));
+
+ test_array (&ah);
+ CHECK_VALUE (ah.m_before, 4.0f);
+ CHECK_VALUE (ah.m_ints[0], 0);
+ CHECK_VALUE (ah.m_ints[1], 1);
+ CHECK_VALUE (ah.m_ints[2], 4);
+ CHECK_VALUE (ah.m_ints[3], 9);
+ CHECK_VALUE (ah.m_after, 2.0f);
+
+}
--- /dev/null
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ extern void
+ called_function (int i, int j, int k);
+
+#ifdef __cplusplus
+}
+#endif
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ /* Let's try to inject the equivalent of:
+ extern void called_function (int i, int j, int k);
+
+ void
+ test_caller (int a)
+ {
+ called_function (a * 3, a * 4, a * 5);
+ }
+ */
+ int i;
+ gcc_jit_type *void_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+ gcc_jit_type *int_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+ /* Declare the imported function. */
+ gcc_jit_param *params[3];
+ params[0] =
+ gcc_jit_context_new_param (ctxt, NULL, int_type, "i");
+ params[1] =
+ gcc_jit_context_new_param (ctxt, NULL, int_type, "j");
+ params[2] =
+ gcc_jit_context_new_param (ctxt, NULL, int_type, "k");
+ gcc_jit_function *called_fn =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_IMPORTED,
+ void_type,
+ "called_function",
+ 3, params,
+ 0);
+
+ /* Build the test_fn. */
+ gcc_jit_param *param_a =
+ gcc_jit_context_new_param (ctxt, NULL, int_type, "a");
+ gcc_jit_function *test_fn =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ void_type,
+ "test_caller",
+ 1, ¶m_a,
+ 0);
+ /* "a * 3, a * 4, a * 5" */
+ gcc_jit_rvalue *args[3];
+ for (i = 0; i < 3; i++)
+ args[i] =
+ gcc_jit_context_new_binary_op (
+ ctxt, NULL,
+ GCC_JIT_BINARY_OP_MULT,
+ int_type,
+ gcc_jit_param_as_rvalue (param_a),
+ gcc_jit_context_new_rvalue_from_int (
+ ctxt,
+ int_type,
+ (i + 3) ));
+ gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
+ gcc_jit_block_add_eval (
+ block, NULL,
+ gcc_jit_context_new_call (ctxt,
+ NULL,
+ called_fn,
+ 3, args));
+ gcc_jit_block_end_with_void_return (block, NULL);
+}
+
+static int called_with[3];
+
+extern void
+called_function (int i, int j, int k)
+{
+ called_with[0] = i;
+ called_with[1] = j;
+ called_with[2] = k;
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ typedef void (*fn_type) (int);
+ CHECK_NON_NULL (result);
+
+ fn_type test_caller =
+ (fn_type)gcc_jit_result_get_code (result, "test_caller");
+ CHECK_NON_NULL (test_caller);
+
+ called_with[0] = 0;
+ called_with[1] = 0;
+ called_with[2] = 0;
+
+ /* Call the JIT-generated function. */
+ test_caller (5);
+
+ /* Verify that it correctly called "called_function". */
+ CHECK_VALUE (called_with[0], 15);
+ CHECK_VALUE (called_with[1], 20);
+ CHECK_VALUE (called_with[2], 25);
+}
+
--- /dev/null
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ /* Let's try to inject the equivalent of:
+
+ void
+ test_calling_function_ptr (void (*fn_ptr) (int, int, int) fn_ptr,
+ int a)
+ {
+ fn_ptr (a * 3, a * 4, a * 5);
+ }
+ */
+
+ int i;
+ gcc_jit_type *void_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+ gcc_jit_type *int_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+ /* Build the function ptr type. */
+ gcc_jit_type *param_types[3];
+ param_types[0] = int_type;
+ param_types[1] = int_type;
+ param_types[2] = int_type;
+
+ gcc_jit_type *fn_ptr_type =
+ gcc_jit_context_new_function_ptr_type (ctxt, NULL,
+ void_type,
+ 3, param_types, 0);
+
+ /* Ensure that function ptr types have sane debug strings. */
+
+ CHECK_STRING_VALUE (
+ gcc_jit_object_get_debug_string (gcc_jit_type_as_object (fn_ptr_type)),
+ "void (*) (int, int, int)");
+
+ /* Build the test_fn. */
+ gcc_jit_param *param_fn_ptr =
+ gcc_jit_context_new_param (ctxt, NULL, fn_ptr_type, "fn_ptr");
+ gcc_jit_param *param_a =
+ gcc_jit_context_new_param (ctxt, NULL, int_type, "a");
+
+ gcc_jit_param *params[2];
+ params[0] = param_fn_ptr;
+ params[1] = param_a;
+
+ gcc_jit_function *test_fn =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ void_type,
+ "test_calling_function_ptr",
+ 2, params,
+ 0);
+ /* "a * 3, a * 4, a * 5" */
+ gcc_jit_rvalue *args[3];
+ for (i = 0; i < 3; i++)
+ args[i] =
+ gcc_jit_context_new_binary_op (
+ ctxt, NULL,
+ GCC_JIT_BINARY_OP_MULT,
+ int_type,
+ gcc_jit_param_as_rvalue (param_a),
+ gcc_jit_context_new_rvalue_from_int (
+ ctxt,
+ int_type,
+ (i + 3) ));
+ gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
+ gcc_jit_block_add_eval (
+ block, NULL,
+ gcc_jit_context_new_call_through_ptr (
+ ctxt,
+ NULL,
+ gcc_jit_param_as_rvalue (param_fn_ptr),
+ 3, args));
+ gcc_jit_block_end_with_void_return (block, NULL);
+}
+
+static int called_through_ptr_with[3];
+
+static void
+function_called_through_fn_ptr (int i, int j, int k)
+{
+ called_through_ptr_with[0] = i;
+ called_through_ptr_with[1] = j;
+ called_through_ptr_with[2] = k;
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ typedef void (*fn_type) (void (*fn_ptr) (int, int, int),
+ int);
+ CHECK_NON_NULL (result);
+
+ fn_type test_caller =
+ (fn_type)gcc_jit_result_get_code (result, "test_calling_function_ptr");
+ CHECK_NON_NULL (test_caller);
+
+ called_through_ptr_with[0] = 0;
+ called_through_ptr_with[1] = 0;
+ called_through_ptr_with[2] = 0;
+
+ /* Call the JIT-generated function. */
+ test_caller (function_called_through_fn_ptr, 5);
+
+ /* Verify that it correctly called "function_called_through_fn_ptr". */
+ CHECK_VALUE (called_through_ptr_with[0], 15);
+ CHECK_VALUE (called_through_ptr_with[1], 20);
+ CHECK_VALUE (called_through_ptr_with[2], 25);
+}
+
--- /dev/null
+/* Construct a test case by combining other test cases, to try to shake
+ out state issues: all of the test cases are run in one process, inside
+ one gcc_jit_context (per iteration). */
+
+#include "all-non-failing-tests.h"
+
+/* Now construct a test case from all the other test cases.
+
+ We undefine COMBINED_TEST so that we can now include harness.h
+ "for real". */
+#undef COMBINED_TEST
+#include "harness.h"
+
+/* Our testing hooks are the combination of the other test cases. */
+void
+create_code (gcc_jit_context *ctxt, void * user_data)
+{
+ create_code_accessing_struct (ctxt, user_data);
+ create_code_accessing_union (ctxt, user_data);
+ create_code_array_as_pointer (ctxt, user_data);
+ create_code_arrays (ctxt, user_data);
+ create_code_calling_external_function (ctxt, user_data);
+ create_code_calling_function_ptr (ctxt, user_data);
+ create_code_dot_product (ctxt, user_data);
+ create_code_expressions (ctxt, user_data);
+ create_code_factorial (ctxt, user_data);
+ create_code_fibonacci (ctxt, user_data);
+ create_code_functions (ctxt, user_data);
+ create_code_hello_world (ctxt, user_data);
+ create_code_linked_list (ctxt, user_data);
+ create_code_long_names (ctxt, user_data);
+ create_code_quadratic (ctxt, user_data);
+ create_code_nested_loop (ctxt, user_data);
+ create_code_reading_struct (ctxt, user_data);
+ create_code_string_literal (ctxt, user_data);
+ create_code_sum_of_squares (ctxt, user_data);
+ create_code_types (ctxt, user_data);
+ create_code_using_global (ctxt, user_data);
+ create_code_volatile (ctxt, user_data);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ verify_code_accessing_struct (ctxt, result);
+ verify_code_accessing_union (ctxt, result);
+ verify_code_array_as_pointer (ctxt, result);
+ verify_code_arrays (ctxt, result);
+ verify_code_calling_external_function (ctxt, result);
+ verify_code_calling_function_ptr (ctxt, result);
+ verify_code_dot_product (ctxt, result);
+ verify_code_expressions (ctxt, result);
+ verify_code_factorial (ctxt, result);
+ verify_code_fibonacci (ctxt, result);
+ verify_code_functions (ctxt, result);
+ verify_code_hello_world (ctxt, result);
+ verify_code_linked_list (ctxt, result);
+ verify_code_long_names (ctxt, result);
+ verify_code_quadratic (ctxt, result);
+ verify_code_nested_loop (ctxt, result);
+ verify_code_reading_struct (ctxt, result);
+ verify_code_string_literal (ctxt, result);
+ verify_code_sum_of_squares (ctxt, result);
+ verify_code_types (ctxt, result);
+ verify_code_using_global (ctxt, result);
+ verify_code_volatile (ctxt, result);
+}
--- /dev/null
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ /* Let's try to inject the equivalent of:
+
+ double
+ my_dot_product (int n, double *a, double *b)
+ {
+ double result = 0.;
+ for (int i = 0; i < n; i++)
+ result += a[i] * b[i];
+ return result
+ }
+
+ and see what the optimizer can do. */
+ gcc_jit_type *val_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_DOUBLE);
+ gcc_jit_type *ptr_type = gcc_jit_type_get_pointer (val_type);
+ gcc_jit_type *int_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+ gcc_jit_type *return_type = val_type;
+ gcc_jit_param *param_n =
+ gcc_jit_context_new_param (ctxt, NULL, int_type, "n");
+ gcc_jit_param *param_a =
+ gcc_jit_context_new_param (ctxt, NULL, ptr_type, "a");
+ gcc_jit_param *param_b =
+ gcc_jit_context_new_param (ctxt, NULL, ptr_type, "b");
+ gcc_jit_param *params[3] = {param_n, param_a, param_b};
+ gcc_jit_function *func =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ return_type,
+ "my_dot_product",
+ 3, params, 0);
+
+ gcc_jit_block *initial = gcc_jit_function_new_block (func, "initial");
+ gcc_jit_block *loop_test = gcc_jit_function_new_block (func, "loop_test");
+ gcc_jit_block *loop_body = gcc_jit_function_new_block (func, "loop_body");
+ gcc_jit_block *final = gcc_jit_function_new_block (func, "final");
+
+ /* Build: "double result = 0.;" */
+ gcc_jit_lvalue *result =
+ gcc_jit_function_new_local (func, NULL, val_type, "result");
+
+ gcc_jit_block_add_assignment (initial, NULL,
+ result, gcc_jit_context_zero (ctxt, val_type));
+
+ /* Build: "for (int i = 0; i < n; i++)" */
+ gcc_jit_lvalue *i =
+ gcc_jit_function_new_local (func, NULL, int_type, "i");
+ gcc_jit_block_add_assignment (initial, NULL,
+ i, gcc_jit_context_zero (ctxt, int_type));
+
+ gcc_jit_block_end_with_jump (initial, NULL, loop_test);
+
+ gcc_jit_block_end_with_conditional (
+ loop_test, NULL,
+
+ /* (i < n) */
+ gcc_jit_context_new_comparison (
+ ctxt, NULL,
+ GCC_JIT_COMPARISON_LT,
+ gcc_jit_lvalue_as_rvalue (i),
+ gcc_jit_param_as_rvalue (param_n)),
+
+ loop_body,
+ final);
+
+ /* Build: "result += a[i] * b[i];" */
+ gcc_jit_block_add_assignment_op (
+ loop_body, NULL,
+ result,
+ GCC_JIT_BINARY_OP_PLUS,
+ gcc_jit_context_new_binary_op (
+ ctxt, NULL,
+ GCC_JIT_BINARY_OP_MULT,
+ val_type,
+ gcc_jit_lvalue_as_rvalue (
+ gcc_jit_context_new_array_access (
+ ctxt, NULL,
+ gcc_jit_param_as_rvalue (param_a),
+ gcc_jit_lvalue_as_rvalue (i))),
+ gcc_jit_lvalue_as_rvalue (
+ gcc_jit_context_new_array_access (
+ ctxt, NULL,
+ gcc_jit_param_as_rvalue (param_b),
+ gcc_jit_lvalue_as_rvalue (i)))));
+
+ /* Build: "i++" */
+ gcc_jit_block_add_assignment_op (
+ loop_body, NULL,
+ i,
+ GCC_JIT_BINARY_OP_PLUS,
+ gcc_jit_context_one (ctxt, int_type));
+
+ gcc_jit_block_end_with_jump (loop_body, NULL, loop_test);
+
+ /* Build: "return result;" */
+ gcc_jit_block_end_with_return (
+ final,
+ NULL,
+ gcc_jit_lvalue_as_rvalue (result));
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ typedef double (*my_dot_product_fn_type) (int n, double *a, double *b);
+ CHECK_NON_NULL (result);
+
+ my_dot_product_fn_type my_dot_product =
+ (my_dot_product_fn_type)gcc_jit_result_get_code (result,
+ "my_dot_product");
+ CHECK_NON_NULL (my_dot_product);
+ double test_array[] = {1., 2., 3., 4., 5., 6., 7., 8., 9., 10.};
+ double val = my_dot_product (10, test_array, test_array);
+ note ("my_dot_product returned: %f", val);
+ CHECK_VALUE (val, 385.0);
+}
+
--- /dev/null
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ /* Do nothing. */
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ /* We should have a non-NULL result, albeit one with nothing in it. */
+ CHECK_NON_NULL (result);
+}
+
--- /dev/null
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+struct foo
+{
+ int x;
+ int y;
+};
+
+struct bar
+{
+ int p;
+ int q;
+};
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ /* Let's try to inject the equivalent of:
+ void
+ test_bogus_access (struct foo *f)
+ {
+ f->p = f->q;
+ }
+ i.e. using the wrong struct.
+ */
+ gcc_jit_type *void_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+ gcc_jit_type *int_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+ /* Map "struct foo". */
+ gcc_jit_field *x =
+ gcc_jit_context_new_field (ctxt,
+ NULL,
+ int_type,
+ "x");
+ gcc_jit_field *y =
+ gcc_jit_context_new_field (ctxt,
+ NULL,
+ int_type,
+ "y");
+ gcc_jit_field *foo_fields[] = {x, y};
+ gcc_jit_struct *struct_foo =
+ gcc_jit_context_new_struct_type (ctxt, NULL, "foo", 2, foo_fields);
+
+ /* Map "struct bar". */
+ gcc_jit_field *p =
+ gcc_jit_context_new_field (ctxt,
+ NULL,
+ int_type,
+ "p");
+ gcc_jit_field *q =
+ gcc_jit_context_new_field (ctxt,
+ NULL,
+ int_type,
+ "q");
+ /* We don't actually need a gcc_jit_type for "struct bar" for the test. */
+ gcc_jit_field *bar_fields[] = {p, q};
+ (void)gcc_jit_context_new_struct_type (ctxt, NULL, "foo", 2, bar_fields);
+
+ gcc_jit_type *foo_ptr =
+ gcc_jit_type_get_pointer (gcc_jit_struct_as_type (struct_foo));
+
+ /* Build the test function. */
+ gcc_jit_param *param_f =
+ gcc_jit_context_new_param (ctxt, NULL, foo_ptr, "f");
+ gcc_jit_function *test_fn =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ void_type,
+ "test_bogus_access",
+ 1, ¶m_f,
+ 0);
+
+ /* Erroneous: f->p = ... */
+ gcc_jit_lvalue *lvalue =
+ gcc_jit_rvalue_dereference_field (
+ gcc_jit_param_as_rvalue (param_f),
+ NULL,
+ p);
+
+ /* Erroneous: ... = f->q; */
+ gcc_jit_rvalue *rvalue =
+ gcc_jit_lvalue_as_rvalue (
+ gcc_jit_rvalue_dereference_field (
+ gcc_jit_param_as_rvalue (param_f),
+ NULL,
+ q));
+
+ gcc_jit_block *block =
+ gcc_jit_function_new_block (test_fn, NULL);
+ gcc_jit_block_add_assignment (
+ block,
+ NULL,
+ lvalue, rvalue);
+ gcc_jit_block_end_with_void_return (block, NULL);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ CHECK_VALUE (result, NULL);
+
+ /* Verify that the correct error message was emitted. */
+ CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+ "gcc_jit_rvalue_dereference_field:"
+ " p is not a field of struct foo");
+}
+
--- /dev/null
+#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ /* Let's try to inject the equivalent of:
+ void
+ test_fn ()
+ {
+ return;
+ return;
+ }
+ */
+ gcc_jit_type *void_t =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+
+ /* Build the test_fn. */
+ gcc_jit_function *test_fn =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ void_t,
+ "test_fn",
+ 0, NULL,
+ 0);
+ gcc_jit_block *initial =
+ gcc_jit_function_new_block (test_fn, "initial");
+
+ gcc_jit_block_end_with_void_return (initial, NULL);
+ /* Error: "initial" has already been terminated. */
+ gcc_jit_block_end_with_void_return (initial, NULL);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ CHECK_VALUE (result, NULL);
+
+ CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+ "gcc_jit_block_end_with_void_return:"
+ " adding to terminated block:"
+ " initial (already terminated by: return;)");
+}
--- /dev/null
+#include <stdlib.h>
+#include <stdio.h>
+#include <stddef.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+#define BUFFER_SIZE (1024)
+
+char test_buffer[1024];
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ /* Let's try to inject the equivalent of:
+ void test_of_array_as_pointer (const char *name)
+ {
+ snprintf (test_buffer, sizeof (test_buffer),
+ "hello %s", name);
+ }
+ */
+ gcc_jit_type *void_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+ gcc_jit_type *const_char_ptr_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_CONST_CHAR_PTR);
+ gcc_jit_type *char_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_CHAR);
+ gcc_jit_type *char_ptr_type =
+ gcc_jit_type_get_pointer (char_type);
+ gcc_jit_type *int_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+ gcc_jit_type *size_t_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_SIZE_T);
+ gcc_jit_type *buf_type =
+ gcc_jit_context_new_array_type (ctxt, NULL, char_type, BUFFER_SIZE);
+
+ /* extern int snprintf(char *str, size_t size, const char *format, ...); */
+ gcc_jit_param *param_s =
+ gcc_jit_context_new_param (ctxt, NULL, char_ptr_type, "s");
+ gcc_jit_param *param_n =
+ gcc_jit_context_new_param (ctxt, NULL, size_t_type, "n");
+ gcc_jit_param *param_format =
+ gcc_jit_context_new_param (ctxt, NULL, const_char_ptr_type, "format");
+ gcc_jit_param *snprintf_params[3] = {param_s, param_n, param_format};
+ gcc_jit_function *snprintf =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_IMPORTED,
+ int_type,
+ "snprintf",
+ 3, snprintf_params,
+ 1);
+
+ gcc_jit_param *param_name =
+ gcc_jit_context_new_param (ctxt, NULL, const_char_ptr_type, "name");
+ gcc_jit_function *test_fn =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ void_type,
+ "test_of_array_as_pointer",
+ 1, ¶m_name,
+ 0);
+
+ gcc_jit_lvalue *buffer =
+ gcc_jit_context_new_global (ctxt, NULL, buf_type, "test_buffer");
+
+ gcc_jit_block *block = gcc_jit_function_new_block(test_fn, "entry");
+
+ /* snprintf(buffer, sizeof(buffer), "hello %s", name); */
+ gcc_jit_rvalue *args[4];
+ args[0] = gcc_jit_context_new_cast (
+ ctxt, NULL,
+ /* Here's the difference with test-array-as-pointer.c: */
+ gcc_jit_lvalue_as_rvalue (buffer),
+ char_ptr_type);
+ args[1] = gcc_jit_context_new_rvalue_from_int (ctxt,
+ size_t_type,
+ BUFFER_SIZE);
+ args[2] = gcc_jit_context_new_string_literal (ctxt, "hello %s");
+ args[3] = gcc_jit_param_as_rvalue (param_name);
+
+ gcc_jit_block_add_eval (
+ block, NULL,
+ gcc_jit_context_new_call (ctxt, NULL, snprintf, 4, args));
+ gcc_jit_block_end_with_void_return (block, NULL);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ CHECK_VALUE (result, NULL);
+
+ /* Verify that the correct error message was emitted. */
+ CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+ "gcc_jit_context_new_cast:"
+ " cannot cast test_buffer"
+ " from type: char[1024]"
+ " to type: char *");
+}
--- /dev/null
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ /* Let's try to inject the equivalent of:
+
+ int
+ test_fn ()
+ {
+ struct foo f;
+ return (int)f;
+ }
+
+ and verify that the API complains about the bad cast.
+ */
+ gcc_jit_type *int_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+
+ gcc_jit_struct *struct_foo =
+ gcc_jit_context_new_struct_type (ctxt, NULL, "foo",
+ 0, NULL);
+
+ gcc_jit_function *test_fn =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ int_type,
+ "test_fn",
+ 0, NULL,
+ 0);
+ gcc_jit_lvalue *f =
+ gcc_jit_function_new_local (
+ test_fn,
+ NULL,
+ gcc_jit_struct_as_type (struct_foo), "f");
+
+ gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
+
+ gcc_jit_block_end_with_return (
+ block, NULL,
+ gcc_jit_context_new_cast (ctxt, NULL,
+ gcc_jit_lvalue_as_rvalue (f),
+ int_type));
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ CHECK_VALUE (result, NULL);
+
+ /* Verify that the correct error message was emitted. */
+ CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+ "gcc_jit_context_new_cast:"
+ " cannot cast f from type: struct foo"
+ " to type: int");
+}
+
--- /dev/null
+#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ /* Let's try to inject the equivalent of:
+ void
+ test_fn ()
+ {
+ goto label;
+ }
+
+ void
+ other_fn ()
+ {
+ label:
+ };
+ where the destination block is in another function.
+ */
+ gcc_jit_type *void_t =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+
+ /* Build the test_fn. */
+ gcc_jit_function *test_fn =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ void_t,
+ "test_fn",
+ 0, NULL,
+ 0);
+ /* Build the other_fn. */
+ gcc_jit_function *other_fn =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ void_t,
+ "other_fn",
+ 0, NULL,
+ 0);
+
+ gcc_jit_block *initial =
+ gcc_jit_function_new_block (test_fn, "initial");
+ gcc_jit_block *block_within_other_fn =
+ gcc_jit_function_new_block (other_fn, "block_within_other_fn");
+
+ gcc_jit_block_end_with_jump (initial, NULL, block_within_other_fn);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ CHECK_VALUE (result, NULL);
+
+ CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+ "gcc_jit_block_end_with_jump:"
+ " target block is not in same function:"
+ " source block initial is in function test_fn"
+ " whereas target block block_within_other_fn"
+ " is in function other_fn");
+}
--- /dev/null
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ /* Let's try to inject the equivalent of:
+
+ void
+ test_fn (void (*some_fn_ptr) (void *))
+ {
+ some_fn_ptr (42);
+ }
+
+ and verify that the API complains about the mismatching argument
+ type ("int" vs "void *"). */
+ gcc_jit_type *void_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+ gcc_jit_type *void_ptr_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID_PTR);
+ gcc_jit_type *int_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+ /* Build the function ptr type. */
+ gcc_jit_type *fn_ptr_type =
+ gcc_jit_context_new_function_ptr_type (ctxt, NULL,
+ void_type,
+ 1, &void_ptr_type, 0);
+
+ /* Build the test_fn. */
+ gcc_jit_param *param_fn_ptr =
+ gcc_jit_context_new_param (ctxt, NULL, fn_ptr_type, "some_fn_ptr");
+
+ gcc_jit_function *test_fn =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ void_type,
+ "test_fn",
+ 1, ¶m_fn_ptr,
+ 0);
+ /* some_fn_ptr (42); */
+ gcc_jit_rvalue *arg =
+ gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 42);
+
+ gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
+ gcc_jit_block_add_eval (
+ block, NULL,
+ gcc_jit_context_new_call_through_ptr (
+ ctxt,
+ NULL,
+ gcc_jit_param_as_rvalue (param_fn_ptr),
+ 1, &arg));
+ /* the above has the wrong type for argument 1. */
+ gcc_jit_block_end_with_void_return (block, NULL);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ CHECK_VALUE (result, NULL);
+
+ /* Verify that the correct error message was emitted. */
+ CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+ ("gcc_jit_context_new_call_through_ptr:"
+ " mismatching types for argument 1 of fn_ptr:"
+ " some_fn_ptr:"
+ " assignment to param 1 (type: void *)"
+ " from (int)42 (type: int)"));
+}
+
--- /dev/null
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ /* Let's try to inject the equivalent of:
+
+ void
+ test_fn (void *some_ptr)
+ {
+ ((some_unspecified_fn_ptr_type)some_ptr) (42);
+ }
+
+ and verify that the API complains about the 42 not being a
+ function pointer. */
+ gcc_jit_type *void_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+ gcc_jit_type *void_ptr_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID_PTR);
+ gcc_jit_type *int_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+ /* Build the test_fn. */
+ gcc_jit_param *some_ptr =
+ gcc_jit_context_new_param (ctxt, NULL, void_ptr_type, "some_ptr");
+
+ gcc_jit_function *test_fn =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ void_type,
+ "test_fn",
+ 1, &some_ptr,
+ 0);
+ gcc_jit_rvalue *arg =
+ gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 42);
+
+ /* ((some_unspecified_fn_ptr_type)some_ptr) (42); */
+ gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
+ gcc_jit_block_add_eval (
+ block, NULL,
+ gcc_jit_context_new_call_through_ptr (
+ ctxt,
+ NULL,
+ /* This is not a function pointer. */
+ gcc_jit_param_as_rvalue (some_ptr),
+ 1, &arg));
+ gcc_jit_block_end_with_void_return (block, NULL);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ CHECK_VALUE (result, NULL);
+
+ /* Verify that the correct error message was emitted. */
+ CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+ ("gcc_jit_context_new_call_through_ptr:"
+ " fn_ptr is not a function ptr: some_ptr type: void *"));
+}
+
--- /dev/null
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ /* Let's try to inject the equivalent of:
+
+ void
+ test_fn ()
+ {
+ ((some_unspecified_fn_ptr_type)42) (43);
+ }
+
+ and verify that the API complains about the 42 not being a
+ function pointer. */
+ gcc_jit_type *void_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+ gcc_jit_type *int_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+ /* Build the test_fn. */
+ gcc_jit_function *test_fn =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ void_type,
+ "test_fn",
+ 0, NULL,
+ 0);
+ gcc_jit_rvalue *not_a_function =
+ gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 42);
+ gcc_jit_rvalue *arg =
+ gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 43);
+
+ /* ((some_unspecified_fn_ptr_type)42) (43); */
+ gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
+ gcc_jit_block_add_eval (
+ block, NULL,
+ gcc_jit_context_new_call_through_ptr (
+ ctxt,
+ NULL,
+ /* This is not even a pointer, let alone a function pointer. */
+ not_a_function,
+ 1, &arg));
+ gcc_jit_block_end_with_void_return (block, NULL);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ CHECK_VALUE (result, NULL);
+
+ /* Verify that the correct error message was emitted. */
+ CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+ ("gcc_jit_context_new_call_through_ptr:"
+ " fn_ptr is not a ptr: (int)42 type: int"));
+}
+
--- /dev/null
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ /* Let's try to inject the equivalent of:
+
+ void
+ test_caller (void (*some_fn_ptr) (int p))
+ {
+ called_function (); // missing arg
+ }
+
+ and verify that the API complains about the missing argument.
+ */
+ gcc_jit_type *void_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+ gcc_jit_type *int_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+ /* Build the function ptr type. */
+ gcc_jit_type *fn_ptr_type =
+ gcc_jit_context_new_function_ptr_type (ctxt, NULL,
+ void_type,
+ 1, &int_type, 0);
+
+ /* Build the test_fn. */
+ gcc_jit_param *param_fn_ptr =
+ gcc_jit_context_new_param (ctxt, NULL, fn_ptr_type, "some_fn_ptr");
+
+ gcc_jit_function *test_fn =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ void_type,
+ "test_caller",
+ 1, ¶m_fn_ptr,
+ 0);
+
+ gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
+ /* called_function (); */
+ gcc_jit_block_add_eval (
+ block, NULL,
+ gcc_jit_context_new_call_through_ptr (
+ ctxt,
+ NULL,
+ gcc_jit_param_as_rvalue (param_fn_ptr),
+ 0, NULL));
+ /* the above has not enough args. */
+ gcc_jit_block_end_with_void_return (block, NULL);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ /* Ensure that mismatching arg count leads to the API giving a NULL
+ result back. */
+ CHECK_VALUE (result, NULL);
+
+ /* Verify that the correct error message was emitted. */
+ CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+ ("gcc_jit_context_new_call_through_ptr:"
+ " not enough arguments to fn_ptr: some_fn_ptr"
+ " (got 0 args, expected 1)"));
+}
+
--- /dev/null
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ extern void
+ called_function (void);
+
+#ifdef __cplusplus
+}
+#endif
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ /* Let's try to inject the equivalent of:
+ void
+ test_caller (void (*some_fn_ptr) (void), int a)
+ {
+ some_fn_ptr (a);
+ }
+
+ and verify that the API complains about the mismatching arg
+ counts.
+ */
+ gcc_jit_type *void_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+ gcc_jit_type *int_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+ /* Build the function ptr type. */
+ gcc_jit_type *fn_ptr_type =
+ gcc_jit_context_new_function_ptr_type (ctxt, NULL,
+ void_type,
+ 0, NULL, 0);
+
+ /* Build the test_fn. */
+ gcc_jit_param *param_fn_ptr =
+ gcc_jit_context_new_param (ctxt, NULL, fn_ptr_type, "some_fn_ptr");
+ gcc_jit_param *param_a =
+ gcc_jit_context_new_param (ctxt, NULL, int_type, "a");
+ gcc_jit_param *params[2];
+ params[0] = param_fn_ptr;
+ params[1] = param_a;
+
+ gcc_jit_function *test_fn =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ void_type,
+ "test_caller",
+ 2, params,
+ 0);
+ gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
+
+ /* some_fn_ptr (a); */
+ gcc_jit_rvalue *arg = gcc_jit_param_as_rvalue (param_a);
+ gcc_jit_block_add_eval (
+ block, NULL,
+ gcc_jit_context_new_call_through_ptr (
+ ctxt,
+ NULL,
+ gcc_jit_param_as_rvalue (param_fn_ptr),
+ 1, &arg));
+ /* the above has too many args. */
+ gcc_jit_block_end_with_void_return (block, NULL);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ /* Ensure that mismatching arg count leads to the API giving a NULL
+ result back. */
+ CHECK_VALUE (result, NULL);
+
+ /* Verify that the correct error message was emitted. */
+ CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+ "gcc_jit_context_new_call_through_ptr:"
+ " too many arguments to fn_ptr:"
+ " some_fn_ptr (got 1 args, expected 0)");
+}
+
--- /dev/null
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ extern void
+ called_function (void *ptr);
+
+#ifdef __cplusplus
+}
+#endif
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ /* Let's try to inject the equivalent of:
+ extern void called_function (void *ptr);
+
+ void
+ test_fn ()
+ {
+ called_function (42);
+ }
+
+ and verify that the API complains about the mismatching argument
+ type ("int" vs "void *"). */
+ gcc_jit_type *void_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+ gcc_jit_type *void_ptr_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID_PTR);
+ gcc_jit_type *int_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+ /* Declare the imported function. */
+ gcc_jit_param *param =
+ gcc_jit_context_new_param (ctxt, NULL, void_ptr_type, "ptr");
+ gcc_jit_function *called_fn =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_IMPORTED,
+ void_type,
+ "called_function",
+ 1, ¶m,
+ 0);
+
+ /* Build the test_fn. */
+ gcc_jit_function *test_fn =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ void_type,
+ "test_fn",
+ 0, NULL,
+ 0);
+ /* called_function (42); */
+ gcc_jit_rvalue *arg =
+ gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 42);
+
+ gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
+ gcc_jit_block_add_eval (
+ block, NULL,
+ gcc_jit_context_new_call (ctxt,
+ NULL,
+ called_fn,
+ 1, &arg));
+ /* the above has the wrong type for argument 1. */
+ gcc_jit_block_end_with_void_return (block, NULL);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ CHECK_VALUE (result, NULL);
+
+ /* Verify that the correct error message was emitted. */
+ CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+ ("gcc_jit_context_new_call:"
+ " mismatching types for argument 1"
+ " of function \"called_function\":"
+ " assignment to param ptr (type: void *)"
+ " from (int)42 (type: int)"));
+}
+
--- /dev/null
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ extern void
+ called_function (void);
+
+#ifdef __cplusplus
+}
+#endif
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ /* Let's try to inject the equivalent of:
+ extern void called_function (int p);
+
+ void
+ test_caller ()
+ {
+ called_function (); // missing arg
+ }
+
+ and verify that the API complains about the missing argument.
+ */
+ gcc_jit_type *void_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+ gcc_jit_type *int_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+ /* Declare the imported function. */
+ gcc_jit_param *param_p =
+ gcc_jit_context_new_param (ctxt, NULL, int_type, "p");
+ gcc_jit_function *called_fn =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_IMPORTED,
+ void_type,
+ "called_function",
+ 1, ¶m_p,
+ 0);
+
+ /* Build the test_fn. */
+ gcc_jit_function *test_fn =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ void_type,
+ "test_caller",
+ 0, NULL,
+ 0);
+ gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
+ /* called_function (); */
+ gcc_jit_block_add_eval (
+ block, NULL,
+ gcc_jit_context_new_call (ctxt,
+ NULL,
+ called_fn,
+ 0, NULL));
+ /* the above has the wrong arg count. */
+ gcc_jit_block_end_with_void_return (block, NULL);
+}
+
+extern void
+called_function (void)
+{
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ /* Ensure that mismatching arg count leads to the API giving a NULL
+ result back. */
+ CHECK_VALUE (result, NULL);
+
+ /* Verify that the correct error message was emitted. */
+ CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+ ("gcc_jit_context_new_call:"
+ " not enough arguments to function \"called_function\""
+ " (got 0 args, expected 1)"));
+}
+
--- /dev/null
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ extern void
+ called_function (void);
+
+#ifdef __cplusplus
+}
+#endif
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ /* Let's try to inject the equivalent of:
+ extern void called_function ();
+
+ void
+ test_caller (int a)
+ {
+ called_function (a);
+ }
+
+ and verify that the API complains about the mismatching arg
+ counts.
+ */
+ gcc_jit_type *void_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+ gcc_jit_type *int_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+ /* Declare the imported function. */
+ gcc_jit_function *called_fn =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_IMPORTED,
+ void_type,
+ "called_function",
+ 0, NULL,
+ 0);
+
+ /* Build the test_fn. */
+ gcc_jit_param *param_a =
+ gcc_jit_context_new_param (ctxt, NULL, int_type, "a");
+ gcc_jit_function *test_fn =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ void_type,
+ "test_caller",
+ 1, ¶m_a,
+ 0);
+ gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
+ /* called_function (a); */
+ gcc_jit_rvalue *arg = gcc_jit_param_as_rvalue (param_a);
+ gcc_jit_block_add_eval (
+ block, NULL,
+ gcc_jit_context_new_call (ctxt,
+ NULL,
+ called_fn,
+ 1, &arg));
+ /* the above has the wrong arg count. */
+ gcc_jit_block_end_with_void_return (block, NULL);
+}
+
+extern void
+called_function (void)
+{
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ /* Ensure that mismatching arg count leads to the API giving a NULL
+ result back. */
+ CHECK_VALUE (result, NULL);
+
+ /* Verify that the correct error message was emitted. */
+ CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+ ("gcc_jit_context_new_call:"
+ " too many arguments to function \"called_function\""
+ " (got 1 args, expected 0)"));
+}
+
--- /dev/null
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+struct foo
+{
+ int x;
+ int y;
+};
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ /* Let's try to inject the equivalent of:
+ void
+ test_bogus_dereference ()
+ {
+ struct foo tmp;
+ tmp->x = tmp->y;
+ }
+ i.e. where tmp is *not* a pointer.
+ */
+ gcc_jit_type *void_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+ gcc_jit_type *int_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+ /* Map "struct foo". */
+ gcc_jit_field *x =
+ gcc_jit_context_new_field (ctxt,
+ NULL,
+ int_type,
+ "x");
+ gcc_jit_field *y =
+ gcc_jit_context_new_field (ctxt,
+ NULL,
+ int_type,
+ "y");
+ gcc_jit_field *foo_fields[] = {x, y};
+ gcc_jit_struct *struct_foo =
+ gcc_jit_context_new_struct_type (ctxt, NULL, "foo", 2, foo_fields);
+
+ /* Build the test function. */
+ gcc_jit_function *test_fn =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ void_type,
+ "test_bogus_dereference",
+ 0, NULL,
+ 0);
+ gcc_jit_lvalue *tmp =
+ gcc_jit_function_new_local (test_fn, NULL,
+ gcc_jit_struct_as_type (struct_foo),
+ "tmp");
+
+ gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
+
+ /* Erroneous: tmp->x = ... */
+ gcc_jit_lvalue *lvalue =
+ gcc_jit_rvalue_dereference_field (
+ gcc_jit_lvalue_as_rvalue (tmp),
+ NULL,
+ x);
+
+ /* Erroneous: ... = tmp->y; */
+ gcc_jit_rvalue *rvalue =
+ gcc_jit_lvalue_as_rvalue (
+ gcc_jit_rvalue_dereference_field (
+ gcc_jit_lvalue_as_rvalue (tmp),
+ NULL,
+ y));
+
+ gcc_jit_block_add_assignment (
+ block,
+ NULL,
+ lvalue, rvalue);
+
+ gcc_jit_block_end_with_void_return (block, NULL);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ CHECK_VALUE (result, NULL);
+
+ /* Verify that the correct error message was emitted. */
+ CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+ ("gcc_jit_rvalue_dereference_field:"
+ " dereference of non-pointer tmp (type: struct foo)"
+ " when accessing ->x"));
+}
+
--- /dev/null
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ /* Let's try to inject the equivalent of:
+ void
+ int test_bogus_dereference_read (int i)
+ {
+ return *i;
+ }
+ i.e. where i is *not* a pointer.
+ */
+ gcc_jit_type *void_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+ gcc_jit_type *int_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+ /* Build the test function. */
+ gcc_jit_param *param_i =
+ gcc_jit_context_new_param (ctxt, NULL, int_type, "i");
+ gcc_jit_function *test_fn =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ void_type,
+ "test_bogus_dereference_read",
+ 1, ¶m_i,
+ 0);
+ gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
+ /* Erroneous: "return *i;" */
+ gcc_jit_block_end_with_return (
+ block,
+ NULL,
+ gcc_jit_lvalue_as_rvalue (
+ gcc_jit_rvalue_dereference (
+ gcc_jit_param_as_rvalue (param_i),
+ NULL)));
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ CHECK_VALUE (result, NULL);
+
+ /* Verify that the correct error message was emitted. */
+ CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+ ("gcc_jit_rvalue_dereference:"
+ " dereference of non-pointer i (type: int)"));
+}
+
--- /dev/null
+#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"));
+}
+
--- /dev/null
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ /* Let's try to access an array at an index that isn't of a numeric
+ type and verify that the API complains about the bad type.
+ */
+ gcc_jit_rvalue *string =
+ gcc_jit_context_new_string_literal (ctxt,
+ "hello world");
+
+ (void)gcc_jit_context_new_array_access (
+ ctxt, NULL,
+ string, /* ptr */
+ string /* index, not of numeric type */);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ CHECK_VALUE (result, NULL);
+
+ /* Verify that the correct error message was emitted. */
+ CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+ "gcc_jit_context_new_array_access:"
+ " index: \"hello world\" (type: const char *)"
+ " is not of numeric type");
+}
--- /dev/null
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ /* Let's try to inject the equivalent of:
+
+ void
+ test_fn ()
+ {
+ int i;
+ i = "this is not an int";
+ }
+
+ and verify that the API complains about the mismatching types
+ in the assignment.
+ */
+ gcc_jit_type *void_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+ gcc_jit_type *int_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+ gcc_jit_function *test_fn =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ void_type,
+ "test_fn",
+ 0, NULL,
+ 0);
+ gcc_jit_lvalue *i =
+ gcc_jit_function_new_local (
+ test_fn, NULL, int_type, "i");
+
+ gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
+
+ gcc_jit_block_add_assignment (
+ block, NULL,
+ i, /* of type int */
+ gcc_jit_context_new_string_literal (
+ ctxt, "this is not an int"));
+ gcc_jit_block_end_with_void_return (block, NULL);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ CHECK_VALUE (result, NULL);
+
+ /* Verify that the correct error message was emitted. */
+ CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+ "gcc_jit_block_add_assignment:"
+ " mismatching types:"
+ " assignment to i (type: int)"
+ " from \"this is not an int\" (type: const char *)");
+}
+
--- /dev/null
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ /* Let's try to inject the equivalent of:
+
+ struct foo;
+
+ extern void called_function (struct foo *ptr);
+
+ void
+ test_fn ()
+ {
+ struct foo f;
+ called_function (f);
+ }
+
+ and verify that we get a type error (foo * vs foo).
+ */
+ gcc_jit_type *void_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+ gcc_jit_struct *struct_foo =
+ gcc_jit_context_new_opaque_struct (ctxt, NULL, "foo");
+ gcc_jit_type *foo_ptr =
+ gcc_jit_type_get_pointer (gcc_jit_struct_as_type (struct_foo));
+ gcc_jit_param *param =
+ gcc_jit_context_new_param (ctxt, NULL, foo_ptr, "ptr");
+
+ gcc_jit_function *called_function =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_IMPORTED,
+ void_type,
+ "called_function",
+ 1, ¶m,
+ 0);
+
+ gcc_jit_function *test_fn =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ void_type,
+ "test_fn",
+ 0, NULL,
+ 0);
+ gcc_jit_lvalue *f =
+ gcc_jit_function_new_local (
+ test_fn, NULL, gcc_jit_struct_as_type (struct_foo), "f");
+
+ gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
+
+ gcc_jit_rvalue *arg = gcc_jit_lvalue_as_rvalue (f);
+
+ gcc_jit_block_add_eval (
+ block, NULL,
+ gcc_jit_context_new_call (
+ ctxt, NULL,
+ called_function,
+ 1, &arg));
+ gcc_jit_block_end_with_void_return (block, NULL);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ CHECK_VALUE (result, NULL);
+
+ /* Verify that the correct error message was emitted. */
+ CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+ "gcc_jit_context_new_call:"
+ " mismatching types for argument 1"
+ " of function \"called_function\":"
+ " assignment to param ptr (type: struct foo *)"
+ " from f (type: struct foo)");
+}
+
--- /dev/null
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ /* Let's try to inject the equivalent of:
+ int
+ test_fn ()
+ {
+ }
+ and verify that the API complains about the lack of
+ a returned value.
+ */
+ gcc_jit_type *int_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+ (void)gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ int_type,
+ "test_fn",
+ 0, NULL,
+ 0);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ CHECK_VALUE (result, NULL);
+
+ /* Verify that the correct error message was emitted. */
+ CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+ "function test_fn returns non-void (type: int)"
+ " but has no blocks");
+}
+
--- /dev/null
+#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"));
+}
+
--- /dev/null
+#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"));
+}
+
--- /dev/null
+#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"));
+}
+
--- /dev/null
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ /* Trigger an API error by passing bad data. */
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ NULL, /* error: this must be non-NULL */
+ "hello_world",
+ 0, NULL,
+ 0);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ /* Ensure that the bad API usage prevents the API giving a bogus
+ result back. */
+ CHECK_VALUE (result, NULL);
+
+ /* Verify that the correct error message was emitted. */
+ CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+ "gcc_jit_context_new_function: NULL return_type");
+}
+
--- /dev/null
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ /* Let's try to inject the equivalent of:
+ void
+ test_fn ()
+ {
+ return 42;
+ }
+
+ and verify that the API complains about the return
+ of a value within a function with "void" return.
+ */
+ gcc_jit_type *void_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+ gcc_jit_type *int_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+ gcc_jit_function *test_fn =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ void_type, /* "void" return */
+ "test_fn",
+ 0, NULL,
+ 0);
+ gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
+
+ /* "return 42;" (i.e. non-void) */
+ gcc_jit_block_end_with_return (
+ block, NULL,
+ gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 42));
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ /* Ensure that the "return 42" leads to the API giving a NULL
+ result back. */
+ CHECK_VALUE (result, NULL);
+
+ /* Verify that the correct error message was emitted. */
+ CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+ "gcc_jit_block_end_with_return:"
+ " mismatching types: return of (int)42 (type: int)"
+ " in function test_fn (return type: void)");
+}
+
--- /dev/null
+#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ /* Let's try to inject the equivalent of:
+ void
+ test_fn ()
+ {
+ return;
+
+ return;
+ }
+ where the second block is unreachable.
+ */
+ gcc_jit_type *void_t =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+
+ /* Build the test_fn. */
+ gcc_jit_function *test_fn =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ void_t,
+ "test_fn",
+ 0, NULL,
+ 0);
+ gcc_jit_block *initial =
+ gcc_jit_function_new_block (test_fn, "a");
+ gcc_jit_block *unreachable =
+ gcc_jit_function_new_block (test_fn, "b");
+
+ gcc_jit_block_end_with_void_return (initial, NULL);
+
+ gcc_jit_block_end_with_void_return (unreachable, NULL);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ CHECK_VALUE (result, NULL);
+
+ CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+ "unreachable block: b");
+}
--- /dev/null
+#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ /* Let's try to inject the equivalent of:
+ void
+ test_fn ()
+ {
+ initial:
+ }
+ with an unterminated block.
+ */
+ gcc_jit_type *void_t =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+
+ /* Build the test_fn. */
+ gcc_jit_function *test_fn =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ void_t,
+ "test_fn",
+ 0, NULL,
+ 0);
+ (void)gcc_jit_function_new_block (test_fn, "initial");
+ /* Error: the above block isn't terminated. */
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ CHECK_VALUE (result, NULL);
+
+ CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+ "unterminated block in test_fn: initial");
+}
--- /dev/null
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ /* Let's try to build an rvalue from a double with a non-numeric type
+ and verify that the API complains about the bad type.
+ */
+ gcc_jit_type *void_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+
+ (void)gcc_jit_context_new_rvalue_from_double (ctxt, void_type, 42.0);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ CHECK_VALUE (result, NULL);
+
+ /* Verify that the correct error message was emitted. */
+ CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+ "gcc_jit_context_new_rvalue_from_double:"
+ " not a numeric type: void");
+}
--- /dev/null
+#include <stdlib.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <stdbool.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+/**********************************************************************
+ Unary ops
+ **********************************************************************/
+
+static const char *
+make_test_of_unary_op (gcc_jit_context *ctxt,
+ gcc_jit_type *type,
+ enum gcc_jit_unary_op op,
+ const char *funcname)
+{
+ /* Make a test function of the form:
+ T test_unary_op (T a)
+ {
+ return OP a;
+ }
+ and return a debug dump of the OP so that
+ the caller can sanity-check the debug dump implementation.
+ */
+ gcc_jit_param *param_a =
+ gcc_jit_context_new_param (ctxt, NULL, type, "a");
+ gcc_jit_function *test_fn =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ type,
+ funcname,
+ 1, ¶m_a,
+ 0);
+ gcc_jit_rvalue *unary_op = gcc_jit_context_new_unary_op (
+ ctxt,
+ NULL,
+ op,
+ type,
+ gcc_jit_param_as_rvalue (param_a));
+
+ gcc_jit_block *initial = gcc_jit_function_new_block (test_fn, "initial");
+ gcc_jit_block_end_with_return (initial, NULL, unary_op);
+
+ return gcc_jit_object_get_debug_string (
+ gcc_jit_rvalue_as_object (unary_op));
+}
+
+
+static void
+make_tests_of_unary_ops (gcc_jit_context *ctxt)
+{
+ gcc_jit_type *int_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+ CHECK_STRING_VALUE (
+ make_test_of_unary_op (ctxt,
+ int_type,
+ GCC_JIT_UNARY_OP_MINUS,
+ "test_UNARY_OP_MINUS_on_int"),
+ "-(a)");
+ CHECK_STRING_VALUE (
+ make_test_of_unary_op (ctxt,
+ int_type,
+ GCC_JIT_UNARY_OP_BITWISE_NEGATE,
+ "test_UNARY_OP_BITWISE_NEGATE_on_int"),
+ "~(a)");
+ CHECK_STRING_VALUE (
+ make_test_of_unary_op (ctxt,
+ int_type,
+ GCC_JIT_UNARY_OP_LOGICAL_NEGATE,
+ "test_UNARY_OP_LOGICAL_NEGATE_on_int"),
+ "!(a)");
+}
+
+static void
+verify_unary_ops (gcc_jit_result *result)
+{
+ typedef int (*test_fn) (int);
+
+ test_fn test_UNARY_OP_MINUS_on_int =
+ (test_fn)gcc_jit_result_get_code (result,
+ "test_UNARY_OP_MINUS_on_int");
+ CHECK_NON_NULL (test_UNARY_OP_MINUS_on_int);
+ CHECK_VALUE (test_UNARY_OP_MINUS_on_int (0), 0);
+ CHECK_VALUE (test_UNARY_OP_MINUS_on_int (42), -42);
+ CHECK_VALUE (test_UNARY_OP_MINUS_on_int (-5), 5);
+
+ test_fn test_UNARY_OP_BITWISE_NEGATE_on_int =
+ (test_fn)gcc_jit_result_get_code (result,
+ "test_UNARY_OP_BITWISE_NEGATE_on_int");
+ CHECK_NON_NULL (test_UNARY_OP_BITWISE_NEGATE_on_int);
+ CHECK_VALUE (test_UNARY_OP_BITWISE_NEGATE_on_int (0), ~0);
+ CHECK_VALUE (test_UNARY_OP_BITWISE_NEGATE_on_int (42), ~42);
+ CHECK_VALUE (test_UNARY_OP_BITWISE_NEGATE_on_int (-5), ~-5);
+
+ test_fn test_UNARY_OP_LOGICAL_NEGATE_on_int =
+ (test_fn)gcc_jit_result_get_code (result,
+ "test_UNARY_OP_LOGICAL_NEGATE_on_int");
+ CHECK_NON_NULL (test_UNARY_OP_LOGICAL_NEGATE_on_int);
+ CHECK_VALUE (test_UNARY_OP_LOGICAL_NEGATE_on_int (0), 1);
+ CHECK_VALUE (test_UNARY_OP_LOGICAL_NEGATE_on_int (42), 0);
+ CHECK_VALUE (test_UNARY_OP_LOGICAL_NEGATE_on_int (-5), 0);
+
+}
+
+/**********************************************************************
+ Binary ops
+ **********************************************************************/
+
+static const char *
+make_test_of_binary_op (gcc_jit_context *ctxt,
+ gcc_jit_type *type,
+ enum gcc_jit_binary_op op,
+ const char *funcname)
+{
+ /* Make a test function of the form:
+ T test_binary_op (T a, T b)
+ {
+ return a OP b;
+ }
+ */
+ gcc_jit_param *param_a =
+ gcc_jit_context_new_param (ctxt, NULL, type, "a");
+ gcc_jit_param *param_b =
+ gcc_jit_context_new_param (ctxt, NULL, type, "b");
+ gcc_jit_param *params[] = {param_a, param_b};
+ gcc_jit_function *test_fn =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ type,
+ funcname,
+ 2, params,
+ 0);
+ gcc_jit_rvalue *binary_op =
+ gcc_jit_context_new_binary_op (
+ ctxt,
+ NULL,
+ op,
+ type,
+ gcc_jit_param_as_rvalue (param_a),
+ gcc_jit_param_as_rvalue (param_b));
+
+ gcc_jit_block *initial = gcc_jit_function_new_block (test_fn, "initial");
+ gcc_jit_block_end_with_return (initial, NULL, binary_op);
+
+ return gcc_jit_object_get_debug_string (
+ gcc_jit_rvalue_as_object (binary_op));
+}
+
+
+static void
+make_tests_of_binary_ops (gcc_jit_context *ctxt)
+{
+ gcc_jit_type *int_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+ /* Test binary ops. */
+ CHECK_STRING_VALUE (
+ make_test_of_binary_op (ctxt,
+ int_type,
+ GCC_JIT_BINARY_OP_PLUS,
+ "test_BINARY_OP_PLUS_on_int"),
+ "a + b");
+ CHECK_STRING_VALUE (
+ make_test_of_binary_op (ctxt,
+ int_type,
+ GCC_JIT_BINARY_OP_MINUS,
+ "test_BINARY_OP_MINUS_on_int"),
+ "a - b");
+ CHECK_STRING_VALUE (
+ make_test_of_binary_op (ctxt,
+ int_type,
+ GCC_JIT_BINARY_OP_MULT,
+ "test_BINARY_OP_MULT_on_int"),
+ "a * b");
+ CHECK_STRING_VALUE (
+ make_test_of_binary_op (ctxt,
+ int_type,
+ GCC_JIT_BINARY_OP_DIVIDE,
+ "test_BINARY_OP_DIVIDE_on_int"),
+ "a / b");
+ /* TODO: test for DIVIDE on float or double */
+ CHECK_STRING_VALUE (
+ make_test_of_binary_op (ctxt,
+ int_type,
+ GCC_JIT_BINARY_OP_MODULO,
+ "test_BINARY_OP_MODULO_on_int"),
+ "a % b");
+ CHECK_STRING_VALUE (
+ make_test_of_binary_op (ctxt,
+ int_type,
+ GCC_JIT_BINARY_OP_BITWISE_AND,
+ "test_BINARY_OP_BITWISE_AND_on_int"),
+ "a & b");
+ CHECK_STRING_VALUE (
+ make_test_of_binary_op (ctxt,
+ int_type,
+ GCC_JIT_BINARY_OP_BITWISE_XOR,
+ "test_BINARY_OP_BITWISE_XOR_on_int"),
+ "a ^ b");
+ CHECK_STRING_VALUE (
+ make_test_of_binary_op (ctxt,
+ int_type,
+ GCC_JIT_BINARY_OP_BITWISE_OR,
+ "test_BINARY_OP_BITWISE_OR_on_int"),
+ "a | b");
+ CHECK_STRING_VALUE (
+ make_test_of_binary_op (ctxt,
+ int_type,
+ GCC_JIT_BINARY_OP_LOGICAL_AND,
+ "test_BINARY_OP_LOGICAL_AND_on_int"),
+ "a && b");
+ CHECK_STRING_VALUE (
+ make_test_of_binary_op (ctxt,
+ int_type,
+ GCC_JIT_BINARY_OP_LOGICAL_OR,
+ "test_BINARY_OP_LOGICAL_OR_on_int"),
+ "a || b");
+ CHECK_STRING_VALUE (
+ make_test_of_binary_op (ctxt,
+ int_type,
+ GCC_JIT_BINARY_OP_LSHIFT,
+ "test_BINARY_OP_LSHIFT_on_int"),
+ "a << b");
+ CHECK_STRING_VALUE (
+ make_test_of_binary_op (ctxt,
+ int_type,
+ GCC_JIT_BINARY_OP_RSHIFT,
+ "test_BINARY_OP_RSHIFT_on_int"),
+ "a >> b");
+}
+
+static void
+verify_binary_ops (gcc_jit_result *result)
+{
+ typedef int (*test_fn) (int, int);
+
+ test_fn test_BINARY_OP_PLUS_on_int =
+ (test_fn)gcc_jit_result_get_code (result,
+ "test_BINARY_OP_PLUS_on_int");
+ CHECK_NON_NULL (test_BINARY_OP_PLUS_on_int);
+ CHECK_VALUE (test_BINARY_OP_PLUS_on_int (0, 0), 0);
+ CHECK_VALUE (test_BINARY_OP_PLUS_on_int (1, 2), 3);
+ CHECK_VALUE (test_BINARY_OP_PLUS_on_int (100, -1), 99);
+ CHECK_VALUE (test_BINARY_OP_PLUS_on_int (-1, -4), -5);
+
+ test_fn test_BINARY_OP_MINUS_on_int =
+ (test_fn)gcc_jit_result_get_code (result,
+ "test_BINARY_OP_MINUS_on_int");
+ CHECK_NON_NULL (test_BINARY_OP_MINUS_on_int);
+ CHECK_VALUE (test_BINARY_OP_MINUS_on_int (0, 0), 0);
+ CHECK_VALUE (test_BINARY_OP_MINUS_on_int (1, 2), -1);
+ CHECK_VALUE (test_BINARY_OP_MINUS_on_int (100, -1), 101);
+ CHECK_VALUE (test_BINARY_OP_MINUS_on_int (-1, -4), 3);
+
+ test_fn test_BINARY_OP_MULT_on_int =
+ (test_fn)gcc_jit_result_get_code (result,
+ "test_BINARY_OP_MULT_on_int");
+ CHECK_NON_NULL (test_BINARY_OP_MULT_on_int);
+ CHECK_VALUE (test_BINARY_OP_MULT_on_int (0, 0), 0);
+ CHECK_VALUE (test_BINARY_OP_MULT_on_int (1, 2), 2);
+ CHECK_VALUE (test_BINARY_OP_MULT_on_int (100, -1), -100);
+ CHECK_VALUE (test_BINARY_OP_MULT_on_int (-1, -4), 4);
+ CHECK_VALUE (test_BINARY_OP_MULT_on_int (7, 10), 70);
+
+ test_fn test_BINARY_OP_DIVIDE_on_int =
+ (test_fn)gcc_jit_result_get_code (result,
+ "test_BINARY_OP_DIVIDE_on_int");
+ CHECK_NON_NULL (test_BINARY_OP_DIVIDE_on_int);
+ CHECK_VALUE (test_BINARY_OP_DIVIDE_on_int (7, 2), 3);
+ CHECK_VALUE (test_BINARY_OP_DIVIDE_on_int (100, -1), (100 / -1));
+ CHECK_VALUE (test_BINARY_OP_DIVIDE_on_int (-1, -4), (-1 / -4));
+ CHECK_VALUE (test_BINARY_OP_DIVIDE_on_int (60, 5), 12);
+
+ /* TODO: test for DIVIDE on float or double */
+
+ test_fn test_BINARY_OP_MODULO_on_int =
+ (test_fn)gcc_jit_result_get_code (result,
+ "test_BINARY_OP_MODULO_on_int");
+ CHECK_NON_NULL (test_BINARY_OP_MODULO_on_int);
+ CHECK_VALUE (test_BINARY_OP_MODULO_on_int (7, 2), 1);
+ CHECK_VALUE (test_BINARY_OP_MODULO_on_int (100, -1), (100 % -1));
+ CHECK_VALUE (test_BINARY_OP_MODULO_on_int (-1, -4), (-1 % -4));
+ CHECK_VALUE (test_BINARY_OP_MODULO_on_int (60, 5), 0);
+
+ test_fn test_BINARY_OP_BITWISE_AND_on_int =
+ (test_fn)gcc_jit_result_get_code (result,
+ "test_BINARY_OP_BITWISE_AND_on_int");
+ CHECK_NON_NULL (test_BINARY_OP_BITWISE_AND_on_int);
+ CHECK_VALUE (test_BINARY_OP_BITWISE_AND_on_int (0xf0f0, 0x7777), 0x7070);
+
+ test_fn test_BINARY_OP_BITWISE_XOR_on_int =
+ (test_fn)gcc_jit_result_get_code (result,
+ "test_BINARY_OP_BITWISE_XOR_on_int");
+ CHECK_NON_NULL (test_BINARY_OP_BITWISE_XOR_on_int);
+ CHECK_VALUE (test_BINARY_OP_BITWISE_XOR_on_int (0xf0f0, 0x7777), 0x8787);
+
+ test_fn test_BINARY_OP_BITWISE_OR_on_int =
+ (test_fn)gcc_jit_result_get_code (result,
+ "test_BINARY_OP_BITWISE_OR_on_int");
+ CHECK_NON_NULL (test_BINARY_OP_BITWISE_OR_on_int);
+ CHECK_VALUE (test_BINARY_OP_BITWISE_OR_on_int (0xf0f0, 0x7777), 0xf7f7);
+
+ test_fn test_BINARY_OP_LOGICAL_AND_on_int =
+ (test_fn)gcc_jit_result_get_code (result,
+ "test_BINARY_OP_LOGICAL_AND_on_int");
+ CHECK_NON_NULL (test_BINARY_OP_LOGICAL_AND_on_int);
+ CHECK_VALUE (test_BINARY_OP_LOGICAL_AND_on_int (0, 0), 0);
+ CHECK_VALUE (test_BINARY_OP_LOGICAL_AND_on_int (42, 0), 0);
+ CHECK_VALUE (test_BINARY_OP_LOGICAL_AND_on_int (0, -13), 0);
+ CHECK_VALUE (test_BINARY_OP_LOGICAL_AND_on_int (1997, 1998), 1);
+
+ test_fn test_BINARY_OP_LOGICAL_OR_on_int =
+ (test_fn)gcc_jit_result_get_code (result,
+ "test_BINARY_OP_LOGICAL_OR_on_int");
+ CHECK_NON_NULL (test_BINARY_OP_LOGICAL_OR_on_int);
+ CHECK_VALUE (test_BINARY_OP_LOGICAL_OR_on_int (0, 0), 0);
+ CHECK_VALUE (test_BINARY_OP_LOGICAL_OR_on_int (42, 0), 1);
+ CHECK_VALUE (test_BINARY_OP_LOGICAL_OR_on_int (0, -13), 1);
+ CHECK_VALUE (test_BINARY_OP_LOGICAL_OR_on_int (1997, 1998), 1);
+
+ test_fn test_BINARY_OP_LSHIFT_on_int =
+ (test_fn)gcc_jit_result_get_code (result,
+ "test_BINARY_OP_LSHIFT_on_int");
+ CHECK_NON_NULL (test_BINARY_OP_LSHIFT_on_int);
+ CHECK_VALUE (test_BINARY_OP_LSHIFT_on_int (0, 0), 0);
+ CHECK_VALUE (test_BINARY_OP_LSHIFT_on_int (0, 1), 0);
+ CHECK_VALUE (test_BINARY_OP_LSHIFT_on_int (0, 2), 0);
+ CHECK_VALUE (test_BINARY_OP_LSHIFT_on_int (1, 0), 1);
+ CHECK_VALUE (test_BINARY_OP_LSHIFT_on_int (1, 1), 2);
+ CHECK_VALUE (test_BINARY_OP_LSHIFT_on_int (1, 2), 4);
+ CHECK_VALUE (test_BINARY_OP_LSHIFT_on_int (1, 3), 8);
+ CHECK_VALUE (test_BINARY_OP_LSHIFT_on_int (3, 0), 3);
+ CHECK_VALUE (test_BINARY_OP_LSHIFT_on_int (3, 1), 6);
+ CHECK_VALUE (test_BINARY_OP_LSHIFT_on_int (3, 5), 3 * 32);
+ CHECK_VALUE (test_BINARY_OP_LSHIFT_on_int (42, 0), 42);
+ CHECK_VALUE (test_BINARY_OP_LSHIFT_on_int (42, 1), 84);
+
+ test_fn test_BINARY_OP_RSHIFT_on_int =
+ (test_fn)gcc_jit_result_get_code (result,
+ "test_BINARY_OP_RSHIFT_on_int");
+ CHECK_NON_NULL (test_BINARY_OP_RSHIFT_on_int);
+ CHECK_VALUE (test_BINARY_OP_RSHIFT_on_int (0, 0), 0);
+ CHECK_VALUE (test_BINARY_OP_RSHIFT_on_int (42, 0), 42);
+ CHECK_VALUE (test_BINARY_OP_RSHIFT_on_int (42, 1), 21);
+ CHECK_VALUE (test_BINARY_OP_RSHIFT_on_int (42, 2), 10);
+}
+
+/**********************************************************************
+ Comparisons
+ **********************************************************************/
+
+static const char *
+make_test_of_comparison (gcc_jit_context *ctxt,
+ gcc_jit_type *type,
+ enum gcc_jit_comparison op,
+ const char *funcname)
+{
+ /* Make a test function of the form:
+ bool test_comparison_op (T a, T b)
+ {
+ return a OP b;
+ }
+ */
+ gcc_jit_param *param_a =
+ gcc_jit_context_new_param (ctxt, NULL, type, "a");
+ gcc_jit_param *param_b =
+ gcc_jit_context_new_param (ctxt, NULL, type, "b");
+ gcc_jit_param *params[] = {param_a, param_b};
+ gcc_jit_type *bool_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_BOOL);
+ gcc_jit_function *test_fn =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ bool_type,
+ funcname,
+ 2, params,
+ 0);
+ gcc_jit_rvalue *comparison =
+ gcc_jit_context_new_comparison (
+ ctxt,
+ NULL,
+ op,
+ gcc_jit_param_as_rvalue (param_a),
+ gcc_jit_param_as_rvalue (param_b));
+
+ gcc_jit_block *initial = gcc_jit_function_new_block (test_fn, "initial");
+ gcc_jit_block_end_with_return (initial, NULL, comparison);
+
+ return gcc_jit_object_get_debug_string (
+ gcc_jit_rvalue_as_object (comparison));
+}
+
+static void
+make_tests_of_comparisons (gcc_jit_context *ctxt)
+{
+ gcc_jit_type *int_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+ CHECK_STRING_VALUE (
+ make_test_of_comparison (ctxt,
+ int_type,
+ GCC_JIT_COMPARISON_EQ,
+ "test_COMPARISON_EQ_on_int"),
+ "a == b");
+ CHECK_STRING_VALUE (
+ make_test_of_comparison (ctxt,
+ int_type,
+ GCC_JIT_COMPARISON_NE,
+ "test_COMPARISON_NE_on_int"),
+ "a != b");
+ CHECK_STRING_VALUE (
+ make_test_of_comparison (ctxt,
+ int_type,
+ GCC_JIT_COMPARISON_LT,
+ "test_COMPARISON_LT_on_int"),
+ "a < b");
+ CHECK_STRING_VALUE (
+ make_test_of_comparison (ctxt,
+ int_type,
+ GCC_JIT_COMPARISON_LE,
+ "test_COMPARISON_LE_on_int"),
+ "a <= b");
+ CHECK_STRING_VALUE (
+ make_test_of_comparison (ctxt,
+ int_type,
+ GCC_JIT_COMPARISON_GT,
+ "test_COMPARISON_GT_on_int"),
+ "a > b");
+ CHECK_STRING_VALUE (
+ make_test_of_comparison (ctxt,
+ int_type,
+ GCC_JIT_COMPARISON_GE,
+ "test_COMPARISON_GE_on_int"),
+ "a >= b");
+}
+
+static void
+verify_comparisons (gcc_jit_result *result)
+{
+ typedef bool (*test_fn) (int, int);
+
+ test_fn test_COMPARISON_EQ_on_int =
+ (test_fn)gcc_jit_result_get_code (result,
+ "test_COMPARISON_EQ_on_int");
+ CHECK_NON_NULL (test_COMPARISON_EQ_on_int);
+ CHECK_VALUE (test_COMPARISON_EQ_on_int (0, 0), 1);
+ CHECK_VALUE (test_COMPARISON_EQ_on_int (1, 2), 0);
+
+ test_fn test_COMPARISON_NE_on_int =
+ (test_fn)gcc_jit_result_get_code (result,
+ "test_COMPARISON_NE_on_int");
+ CHECK_NON_NULL (test_COMPARISON_NE_on_int);
+ CHECK_VALUE (test_COMPARISON_NE_on_int (0, 0), 0);
+ CHECK_VALUE (test_COMPARISON_NE_on_int (1, 2), 1);
+
+ test_fn test_COMPARISON_LT_on_int =
+ (test_fn)gcc_jit_result_get_code (result,
+ "test_COMPARISON_LT_on_int");
+ CHECK_NON_NULL (test_COMPARISON_LT_on_int);
+ CHECK_VALUE (test_COMPARISON_LT_on_int (0, 0), 0);
+ CHECK_VALUE (test_COMPARISON_LT_on_int (1, 2), 1);
+ CHECK_VALUE (test_COMPARISON_LT_on_int (2, 1), 0);
+ CHECK_VALUE (test_COMPARISON_LT_on_int (-2, 1), 1);
+
+ test_fn test_COMPARISON_LE_on_int =
+ (test_fn)gcc_jit_result_get_code (result,
+ "test_COMPARISON_LE_on_int");
+ CHECK_NON_NULL (test_COMPARISON_LE_on_int);
+ CHECK_VALUE (test_COMPARISON_LE_on_int (0, 0), 1);
+ CHECK_VALUE (test_COMPARISON_LE_on_int (1, 2), 1);
+ CHECK_VALUE (test_COMPARISON_LE_on_int (2, 1), 0);
+
+ test_fn test_COMPARISON_GT_on_int =
+ (test_fn)gcc_jit_result_get_code (result,
+ "test_COMPARISON_GT_on_int");
+ CHECK_NON_NULL (test_COMPARISON_GT_on_int);
+ CHECK_VALUE (test_COMPARISON_GT_on_int (0, 0), 0);
+ CHECK_VALUE (test_COMPARISON_GT_on_int (1, 2), 0);
+ CHECK_VALUE (test_COMPARISON_GT_on_int (2, 1), 1);
+
+ test_fn test_COMPARISON_GE_on_int =
+ (test_fn)gcc_jit_result_get_code (result,
+ "test_COMPARISON_GE_on_int");
+ CHECK_NON_NULL (test_COMPARISON_GE_on_int);
+ CHECK_VALUE (test_COMPARISON_GE_on_int (0, 0), 1);
+ CHECK_VALUE (test_COMPARISON_GE_on_int (1, 2), 0);
+ CHECK_VALUE (test_COMPARISON_GE_on_int (2, 1), 1);
+}
+
+/**********************************************************************
+ Casts
+ **********************************************************************/
+
+static const char*
+make_test_of_cast (gcc_jit_context *ctxt,
+ gcc_jit_type *input_type,
+ gcc_jit_type *output_type,
+ const char *funcname)
+{
+ /* Make a test function of the form:
+ OUTPUT_TYPE test_cast_* (INPUT_TYPE a)
+ {
+ return (OUTPUT_TYPE)a;
+ }
+ */
+ gcc_jit_param *param_a =
+ gcc_jit_context_new_param (ctxt, NULL, input_type, "a");
+ gcc_jit_param *params[] = {param_a};
+ gcc_jit_function *test_fn =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ output_type,
+ funcname,
+ 1, params,
+ 0);
+ gcc_jit_rvalue *cast =
+ gcc_jit_context_new_cast (
+ ctxt,
+ NULL,
+ gcc_jit_param_as_rvalue (param_a),
+ output_type);
+ gcc_jit_block *initial = gcc_jit_function_new_block (test_fn, "initial");
+ gcc_jit_block_end_with_return (initial, NULL, cast);
+
+ return gcc_jit_object_get_debug_string (
+ gcc_jit_rvalue_as_object (cast));
+}
+
+/* For use by test_cast_from_array_of_ints_to_int_ptr. */
+extern int called_pointer_checking_function (int *ints)
+{
+ CHECK_VALUE (ints[0], 10);
+ CHECK_VALUE (ints[1], 4);
+ return ints[0] * ints[1];
+}
+
+static void
+make_tests_of_casts (gcc_jit_context *ctxt)
+{
+ gcc_jit_type *int_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+ gcc_jit_type *float_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_FLOAT);
+ gcc_jit_type *bool_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_BOOL);
+ gcc_jit_type *array_int_type =
+ gcc_jit_context_new_array_type (ctxt, NULL,
+ int_type,
+ 2);
+ gcc_jit_type *int_ptr_type =
+ gcc_jit_type_get_pointer (int_type);
+
+ /* float/int conversions */
+ CHECK_STRING_VALUE (
+ make_test_of_cast (ctxt,
+ float_type,
+ int_type,
+ "test_cast_from_float_to_int"),
+ "(int)a");
+ CHECK_STRING_VALUE (
+ make_test_of_cast (ctxt,
+ int_type,
+ float_type,
+ "test_cast_from_int_to_float"),
+ "(float)a");
+
+ /* bool/int conversions */
+ CHECK_STRING_VALUE (
+ make_test_of_cast (ctxt,
+ bool_type,
+ int_type,
+ "test_cast_from_bool_to_int"),
+ "(int)a");
+ CHECK_STRING_VALUE (
+ make_test_of_cast (ctxt,
+ int_type,
+ bool_type,
+ "test_cast_from_int_to_bool"),
+ "(bool)a");
+
+ /* array/ptr conversions */
+ {
+ gcc_jit_function *test_fn =
+ gcc_jit_context_new_function (
+ ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ int_type,
+ "test_cast_from_array_of_ints_to_int_ptr",
+ 0, NULL,
+ 0);
+ /* Equivalent to:
+ int test_cast_from_array_of_ints_to_int_ptr (void)
+ {
+ int array[2];
+ array[0] = 10;
+ array[1] = 4;
+ return called_pointer_checking_function (array);
+ }
+ */
+
+ gcc_jit_param *param_ints =
+ gcc_jit_context_new_param (ctxt, NULL, int_ptr_type, "ints");
+ gcc_jit_function *called_fn =
+ gcc_jit_context_new_function (
+ ctxt, NULL,
+ GCC_JIT_FUNCTION_IMPORTED,
+ int_type,
+ "called_pointer_checking_function",
+ 1, ¶m_ints,
+ 0);
+
+ gcc_jit_lvalue *array =
+ gcc_jit_function_new_local (test_fn, NULL,
+ array_int_type,
+ "array");
+ gcc_jit_block *block =
+ gcc_jit_function_new_block (test_fn, "block");
+ /* array[0] = 10; */
+ gcc_jit_block_add_assignment (
+ block, NULL,
+ gcc_jit_context_new_array_access (
+ ctxt, NULL,
+ gcc_jit_lvalue_as_rvalue (array),
+ gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 0)),
+ gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 10));
+ /* array[1] = 4; */
+ gcc_jit_block_add_assignment (
+ block, NULL,
+ gcc_jit_context_new_array_access (
+ ctxt, NULL,
+ gcc_jit_lvalue_as_rvalue (array),
+ gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 1)),
+ gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 4));
+ gcc_jit_rvalue *cast =
+ gcc_jit_context_new_cast (
+ ctxt,
+ NULL,
+ /* We need a get_address here. */
+ gcc_jit_lvalue_get_address (array, NULL),
+ int_ptr_type);
+ gcc_jit_block_end_with_return (
+ block, NULL,
+ gcc_jit_context_new_call (
+ ctxt, NULL,
+ called_fn,
+ 1, &cast));
+
+ CHECK_STRING_VALUE (
+ gcc_jit_object_get_debug_string (
+ gcc_jit_rvalue_as_object (cast)),
+ "(int *)&array");
+ }
+}
+
+static void
+verify_casts (gcc_jit_result *result)
+{
+ /* float to int */
+ {
+ typedef int (*fn_type) (float);
+ fn_type test_cast_from_float_to_int =
+ (fn_type)gcc_jit_result_get_code (result,
+ "test_cast_from_float_to_int");
+ CHECK_NON_NULL (test_cast_from_float_to_int);
+ CHECK_VALUE (test_cast_from_float_to_int (4.2), 4);
+ }
+
+ /* int to float */
+ {
+ typedef float (*fn_type) (int);
+ fn_type test_cast_from_int_to_float =
+ (fn_type)gcc_jit_result_get_code (result,
+ "test_cast_from_int_to_float");
+ CHECK_NON_NULL (test_cast_from_int_to_float);
+ CHECK_VALUE (test_cast_from_int_to_float (4), 4.0);
+ }
+
+ /* bool to int */
+ {
+ typedef int (*fn_type) (bool);
+ fn_type test_cast_from_bool_to_int =
+ (fn_type)gcc_jit_result_get_code (result,
+ "test_cast_from_bool_to_int");
+ CHECK_NON_NULL (test_cast_from_bool_to_int);
+ CHECK_VALUE (test_cast_from_bool_to_int (0), 0);
+ CHECK_VALUE (test_cast_from_bool_to_int (1), 1);
+ }
+
+ /* int to bool */
+ {
+ typedef bool (*fn_type) (int);
+ fn_type test_cast_from_int_to_bool =
+ (fn_type)gcc_jit_result_get_code (result,
+ "test_cast_from_int_to_bool");
+ CHECK_NON_NULL (test_cast_from_int_to_bool);
+ CHECK_VALUE (test_cast_from_int_to_bool (0), 0);
+ CHECK_VALUE (test_cast_from_int_to_bool (1), 1);
+ }
+
+ /* array to ptr */
+ {
+ typedef int (*fn_type) (void);
+ fn_type test_cast_from_array_of_ints_to_int_ptr =
+ (fn_type)gcc_jit_result_get_code (
+ result,
+ "test_cast_from_array_of_ints_to_int_ptr");
+ CHECK_NON_NULL (test_cast_from_array_of_ints_to_int_ptr);
+ CHECK_VALUE (test_cast_from_array_of_ints_to_int_ptr (), 40);
+ }
+}
+
+/**********************************************************************
+ Dereferences
+ **********************************************************************/
+
+static void
+make_tests_of_dereferences (gcc_jit_context *ctxt)
+{
+ /*
+ int test_dereference_read (int *ptr)
+ {
+ return *ptr;
+ }
+ void test_dereference_write (int *ptr, int i)
+ {
+ *ptr = i;
+ }
+ */
+ gcc_jit_type *void_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+ gcc_jit_type *int_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+ gcc_jit_type *int_ptr_type =
+ gcc_jit_type_get_pointer (int_type);
+ {
+ gcc_jit_param *param_ptr =
+ gcc_jit_context_new_param (ctxt, NULL, int_ptr_type, "ptr");
+ gcc_jit_function *test_dereference_read =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ int_type,
+ "test_dereference_read",
+ 1, ¶m_ptr,
+ 0);
+ gcc_jit_block *initial =
+ gcc_jit_function_new_block (test_dereference_read, "initial");
+ gcc_jit_block_end_with_return (
+ initial,
+ NULL,
+ gcc_jit_lvalue_as_rvalue (
+ gcc_jit_rvalue_dereference (
+ gcc_jit_param_as_rvalue (param_ptr),
+ NULL)));
+ }
+
+ {
+ gcc_jit_param *param_ptr =
+ gcc_jit_context_new_param (ctxt, NULL, int_ptr_type, "ptr");
+ gcc_jit_param *param_i =
+ gcc_jit_context_new_param (ctxt, NULL, int_type, "i");
+ gcc_jit_param *params[] = {param_ptr, param_i};
+ gcc_jit_function *test_dereference_write =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ void_type,
+ "test_dereference_write",
+ 2, params,
+ 0);
+ gcc_jit_block *initial =
+ gcc_jit_function_new_block (test_dereference_write, "initial");
+ gcc_jit_block_add_assignment (
+ initial,
+ NULL,
+ gcc_jit_rvalue_dereference (
+ gcc_jit_param_as_rvalue (param_ptr),
+ NULL),
+ gcc_jit_param_as_rvalue (param_i));
+ gcc_jit_block_end_with_void_return (initial, NULL);
+ }
+}
+
+static void
+verify_dereferences (gcc_jit_result *result)
+{
+ int a = 42;
+ int b = -99;
+
+ {
+ typedef int (*test_read) (int *);
+ test_read test_dereference_read =
+ (test_read)gcc_jit_result_get_code (result,
+ "test_dereference_read");
+ CHECK_NON_NULL (test_dereference_read);
+ CHECK_VALUE (test_dereference_read (&a), 42);
+ CHECK_VALUE (test_dereference_read (&b), -99);
+ }
+
+ {
+ typedef void (*test_write) (int *, int);
+ test_write test_dereference_write =
+ (test_write)gcc_jit_result_get_code (result,
+ "test_dereference_write");
+ CHECK_NON_NULL (test_dereference_write);
+ test_dereference_write (&a, -55);
+ CHECK_VALUE (a, -55);
+
+ test_dereference_write (&b, 404);
+ CHECK_VALUE (b, 404);
+ }
+}
+
+/**********************************************************************
+ gcc_jit_lvalue_get_address
+ **********************************************************************/
+
+int test_global;
+static void
+make_test_of_get_address (gcc_jit_context *ctxt)
+{
+ /*
+ void *test_get_address (void)
+ {
+ return &test_global;
+ }
+ */
+ gcc_jit_type *int_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+ gcc_jit_lvalue *test_global =
+ gcc_jit_context_new_global (
+ ctxt,
+ NULL,
+ int_type,
+ "test_global");
+
+ gcc_jit_type *void_ptr_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID_PTR);
+
+ gcc_jit_function *test_get_address =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ void_ptr_type,
+ "test_get_address",
+ 0, NULL,
+ 0);
+ gcc_jit_block *initial =
+ gcc_jit_function_new_block (test_get_address, "initial");
+ gcc_jit_block_end_with_return (
+ initial,
+ NULL,
+ gcc_jit_lvalue_get_address (
+ test_global,
+ NULL));
+}
+
+static void
+verify_get_address (gcc_jit_result *result)
+{
+ typedef void *(*test_fn) (void);
+ test_fn test_get_address =
+ (test_fn)gcc_jit_result_get_code (result,
+ "test_get_address");
+ CHECK_NON_NULL (test_get_address);
+ CHECK_VALUE (test_get_address (), &test_global);
+}
+
+/**********************************************************************
+ Code for harness
+ **********************************************************************/
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ make_tests_of_unary_ops (ctxt);
+ make_tests_of_binary_ops (ctxt);
+ make_tests_of_comparisons (ctxt);
+ make_tests_of_casts (ctxt);
+ make_tests_of_dereferences (ctxt);
+ make_test_of_get_address (ctxt);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ CHECK_NON_NULL (result);
+
+ verify_unary_ops (result);
+ verify_binary_ops (result);
+ verify_comparisons (result);
+ verify_casts (result);
+ verify_dereferences (result);
+ verify_get_address (result);
+}
--- /dev/null
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ /* Let's try to inject the equivalent of:
+
+ int
+ my_factorial (int x)
+ {
+ if (x < 2)
+ return x;
+ else
+ return x * my_factorial (x - 1);
+ }
+
+ and see if the optimizer eliminates the recursion (it does).
+ */
+ gcc_jit_type *the_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+ gcc_jit_type *return_type = the_type;
+
+ gcc_jit_param *x =
+ gcc_jit_context_new_param (ctxt, NULL, the_type, "x");
+ gcc_jit_param *params[1] = {x};
+ gcc_jit_function *func =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ return_type,
+ "my_factorial",
+ 1, params, 0);
+
+ gcc_jit_block *initial =
+ gcc_jit_function_new_block (func, "initial");
+ gcc_jit_block *on_true =
+ gcc_jit_function_new_block (func, "on_true");
+ gcc_jit_block *on_false =
+ gcc_jit_function_new_block (func, "on_false");
+
+ /* if (x < 2) */
+ gcc_jit_block_end_with_conditional (
+ initial, NULL,
+ gcc_jit_context_new_comparison (
+ ctxt, NULL,
+ GCC_JIT_COMPARISON_LT,
+ gcc_jit_param_as_rvalue (x),
+ gcc_jit_context_new_rvalue_from_int (
+ ctxt,
+ the_type,
+ 2)),
+ on_true,
+ on_false);
+
+ /* true branch: */
+ /* return x */
+ gcc_jit_block_end_with_return (
+ on_true,
+ NULL,
+ gcc_jit_param_as_rvalue (x));
+
+ /* false branch: */
+ gcc_jit_rvalue *x_minus_1 =
+ gcc_jit_context_new_binary_op (
+ ctxt, NULL,
+ GCC_JIT_BINARY_OP_MINUS, the_type,
+ gcc_jit_param_as_rvalue (x),
+ gcc_jit_context_new_rvalue_from_int (
+ ctxt,
+ the_type,
+ 1));
+ gcc_jit_block_end_with_return (
+ on_false,
+ NULL,
+ gcc_jit_context_new_binary_op (
+ ctxt, NULL,
+ GCC_JIT_BINARY_OP_MULT, the_type,
+ gcc_jit_param_as_rvalue (x),
+ /* my_factorial (x - 1) */
+ gcc_jit_context_new_call (
+ ctxt, NULL,
+ func,
+ 1, &x_minus_1)));
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ typedef int (*my_factorial_fn_type) (int);
+ CHECK_NON_NULL (result);
+ my_factorial_fn_type my_factorial =
+ (my_factorial_fn_type)gcc_jit_result_get_code (result, "my_factorial");
+ CHECK_NON_NULL (my_factorial);
+ int val = my_factorial (10);
+ note ("my_factorial returned: %d", val);
+ CHECK_VALUE (val, 3628800);
+}
+
--- /dev/null
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ const int FIRST_LINE = __LINE__ + 4;
+ /* Let's try to inject the equivalent of:
+0000000001111111111222222222233333333334444444444555555555566666666667
+1234567890123456789012345678901234567890123456789012345678901234567890
+FIRST_LINE + 0: int
+FIRST_LINE + 1: my_fibonacci (int x)
+FIRST_LINE + 2: {
+FIRST_LINE + 3: if (x < 2)
+FIRST_LINE + 4: return x;
+FIRST_LINE + 5: else
+FIRST_LINE + 6: return my_fibonacci (x - 1) + my_fibonacci (x - 2);
+FIRST_LINE + 7: }
+0000000001111111111222222222233333333334444444444555555555566666666667
+1234567890123456789012345678901234567890123456789012345678901234567890
+
+ where the source locations are set up to point to the commented-out
+ code above.
+ It should therefore be possible to step through the generated code
+ in the debugger, stepping through the above commented-out code
+ fragement.
+ */
+ gcc_jit_type *the_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+ gcc_jit_type *return_type = the_type;
+
+ gcc_jit_param *x =
+ gcc_jit_context_new_param (
+ ctxt,
+ gcc_jit_context_new_location (
+ ctxt, __FILE__, FIRST_LINE + 1, 35),
+ the_type, "x");
+ gcc_jit_param *params[1] = {x};
+ gcc_jit_function *func =
+ gcc_jit_context_new_function (ctxt,
+ gcc_jit_context_new_location (
+ ctxt, __FILE__, FIRST_LINE, 17),
+ GCC_JIT_FUNCTION_EXPORTED,
+ return_type,
+ "my_fibonacci",
+ 1, params, 0);
+
+ gcc_jit_block *initial =
+ gcc_jit_function_new_block (func, "initial");
+ gcc_jit_block *on_true =
+ gcc_jit_function_new_block (func, "on_true");
+ gcc_jit_block *on_false =
+ gcc_jit_function_new_block (func, "on_false");
+
+ /* if (x < 2) */
+ gcc_jit_block_end_with_conditional (
+ initial,
+ gcc_jit_context_new_location (ctxt, __FILE__, FIRST_LINE + 3, 19),
+ gcc_jit_context_new_comparison (
+ ctxt,
+ gcc_jit_context_new_location (ctxt, __FILE__, FIRST_LINE + 3, 25),
+ GCC_JIT_COMPARISON_LT,
+ gcc_jit_param_as_rvalue (x),
+ gcc_jit_context_new_rvalue_from_int (
+ ctxt,
+ the_type,
+ 2)),
+ on_true,
+ on_false);
+
+ /* true branch: */
+ /* return x */
+ gcc_jit_block_end_with_return (
+ on_true,
+ gcc_jit_context_new_location (ctxt, __FILE__, FIRST_LINE + 4, 21),
+ gcc_jit_param_as_rvalue (x));
+
+ /* false branch: */
+ gcc_jit_rvalue *x_minus_1 =
+ gcc_jit_context_new_binary_op (
+ ctxt,
+ gcc_jit_context_new_location (ctxt, __FILE__, FIRST_LINE + 6, 44),
+ GCC_JIT_BINARY_OP_MINUS, the_type,
+ gcc_jit_param_as_rvalue (x),
+ gcc_jit_context_new_rvalue_from_int (
+ ctxt,
+ the_type,
+ 1));
+ gcc_jit_rvalue *x_minus_2 =
+ gcc_jit_context_new_binary_op (
+ ctxt,
+ gcc_jit_context_new_location (ctxt, __FILE__, FIRST_LINE + 6, 67),
+ GCC_JIT_BINARY_OP_MINUS, the_type,
+ gcc_jit_param_as_rvalue (x),
+ gcc_jit_context_new_rvalue_from_int (
+ ctxt,
+ the_type,
+ 2));
+ gcc_jit_block_end_with_return (
+ on_false,
+ gcc_jit_context_new_location (ctxt, __FILE__, FIRST_LINE + 6, 21),
+ gcc_jit_context_new_binary_op (
+ ctxt,
+ gcc_jit_context_new_location (ctxt, __FILE__, FIRST_LINE + 6, 49),
+ GCC_JIT_BINARY_OP_PLUS, the_type,
+ /* my_fibonacci (x - 1) */
+ gcc_jit_context_new_call (
+ ctxt,
+ gcc_jit_context_new_location (ctxt, __FILE__, FIRST_LINE + 6, 28),
+ func,
+ 1, &x_minus_1),
+ /* my_fibonacci (x - 2) */
+ gcc_jit_context_new_call (
+ ctxt,
+ gcc_jit_context_new_location (ctxt, __FILE__, FIRST_LINE + 6, 51),
+ func,
+ 1, &x_minus_2)));
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ typedef int (*my_fibonacci_fn_type) (int);
+ CHECK_NON_NULL (result);
+ my_fibonacci_fn_type my_fibonacci =
+ (my_fibonacci_fn_type)gcc_jit_result_get_code (result, "my_fibonacci");
+ CHECK_NON_NULL (my_fibonacci);
+ int val = my_fibonacci (10);
+ note ("my_fibonacci returned: %d", val);
+ CHECK_VALUE (val, 55);
+}
--- /dev/null
+#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+/**********************************************************************
+ GCC_JIT_FUNCTION_ALWAYS_INLINE and GCC_JIT_FUNCTION_INTERNAL
+ **********************************************************************/
+static void
+create_test_of_hidden_function (gcc_jit_context *ctxt,
+ enum gcc_jit_function_kind hidden_kind,
+ const char *hidden_func_name,
+ const char *visible_func_name)
+{
+ /* Let's try to inject the equivalent of:
+ static double hidden_mult (double a, double b)
+ {
+ return x * x;
+ }
+ double my_square (double x)
+ {
+ return my_mult (x, x);
+ }
+
+ where hidden_mult can potentially be
+ inline __attribute__((always_inline)). */
+ gcc_jit_type *double_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_DOUBLE);
+
+ /* Create "my_mult" */
+ gcc_jit_param *param_a =
+ gcc_jit_context_new_param (ctxt, NULL, double_type, "a");
+ gcc_jit_param *param_b =
+ gcc_jit_context_new_param (ctxt, NULL, double_type, "b");
+ gcc_jit_param *params[2] = {param_a, param_b};
+ gcc_jit_function *my_mult =
+ gcc_jit_context_new_function (ctxt, NULL,
+ hidden_kind,
+ double_type,
+ hidden_func_name,
+ 2, params,
+ 0);
+ gcc_jit_block *body_of_my_mult =
+ gcc_jit_function_new_block (my_mult, NULL);
+ gcc_jit_block_end_with_return (
+ body_of_my_mult, NULL,
+ gcc_jit_context_new_binary_op (
+ ctxt, NULL,
+ GCC_JIT_BINARY_OP_MULT,
+ double_type,
+ gcc_jit_param_as_rvalue (param_a),
+ gcc_jit_param_as_rvalue (param_b)));
+
+ /* Create "my_square" */
+ gcc_jit_param *param_x =
+ gcc_jit_context_new_param (ctxt, NULL, double_type, "x");
+ gcc_jit_function *my_square =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ double_type,
+ visible_func_name,
+ 1, ¶m_x,
+ 0);
+ gcc_jit_block *body_of_my_square =
+ gcc_jit_function_new_block (my_square, NULL);
+ gcc_jit_rvalue *args[2] = {gcc_jit_param_as_rvalue (param_x),
+ gcc_jit_param_as_rvalue (param_x)};
+ gcc_jit_block_end_with_return (
+ body_of_my_square, NULL,
+ gcc_jit_context_new_call (
+ ctxt, NULL,
+ my_mult,
+ 2, args));
+}
+
+static void
+create_tests_of_hidden_functions (gcc_jit_context *ctxt)
+{
+ create_test_of_hidden_function (ctxt,
+ GCC_JIT_FUNCTION_INTERNAL,
+ "my_internal_mult",
+ "my_square_with_internal");
+ create_test_of_hidden_function (ctxt,
+ GCC_JIT_FUNCTION_ALWAYS_INLINE,
+ "my_always_inline_mult",
+ "my_square_with_always_inline");
+}
+
+static void
+verify_hidden_functions (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ CHECK_NON_NULL (result);
+
+ /* GCC_JIT_FUNCTION_INTERNAL and GCC_JIT_FUNCTION_ALWAYS_INLINE
+ functions should not be accessible in the result. */
+ CHECK_VALUE (NULL, gcc_jit_result_get_code (result, "my_internal_mult"));
+ CHECK_VALUE (NULL, gcc_jit_result_get_code (result, "my_always_inline_mult"));
+
+ typedef double (*fn_type) (double);
+ fn_type my_square_with_internal =
+ (fn_type)gcc_jit_result_get_code (result, "my_square_with_internal");
+ CHECK_NON_NULL (my_square_with_internal);
+ CHECK_VALUE (my_square_with_internal (5.0), 25.0);
+
+ fn_type my_square_with_always_inline =
+ (fn_type)gcc_jit_result_get_code (result, "my_square_with_always_inline");
+ CHECK_NON_NULL (my_square_with_always_inline);
+ CHECK_VALUE (my_square_with_always_inline (5.0), 25.0);
+}
+
+/**********************************************************************
+ Builtin functions
+ **********************************************************************/
+
+static void
+create_test_of_builtin_strcmp (gcc_jit_context *ctxt)
+{
+ /* Let's try to inject the equivalent of:
+ int
+ test_of_builtin_strcmp (const char *a, const char *b)
+ {
+ return __builtin_strcmp (a, b);
+ }
+ */
+ gcc_jit_type *int_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+ gcc_jit_type *const_char_ptr_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_CONST_CHAR_PTR);
+
+ /* Get the built-in function. */
+ gcc_jit_function *builtin_fn =
+ gcc_jit_context_get_builtin_function (ctxt, "strcmp");
+
+ CHECK_STRING_VALUE (
+ gcc_jit_object_get_debug_string (gcc_jit_function_as_object (builtin_fn)),
+ "strcmp");
+
+ /* Build the test_fn. */
+ gcc_jit_param *param_a =
+ gcc_jit_context_new_param (ctxt, NULL, const_char_ptr_type, "a");
+ gcc_jit_param *param_b =
+ gcc_jit_context_new_param (ctxt, NULL, const_char_ptr_type, "b");
+ gcc_jit_param *params[2] = {param_a, param_b};
+ gcc_jit_function *test_fn =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ int_type,
+ "test_of_builtin_strcmp",
+ 2, params,
+ 0);
+ gcc_jit_rvalue *args[2] = {gcc_jit_param_as_rvalue (param_a),
+ gcc_jit_param_as_rvalue (param_b)};
+ gcc_jit_rvalue *call =
+ gcc_jit_context_new_call (ctxt,
+ NULL,
+ builtin_fn,
+ 2, args);
+ CHECK_STRING_VALUE (
+ gcc_jit_object_get_debug_string (gcc_jit_rvalue_as_object (call)),
+ "strcmp (a, b)");
+
+ gcc_jit_block *initial =
+ gcc_jit_function_new_block (test_fn, "initial");
+ gcc_jit_block_end_with_return (initial, NULL, call);
+}
+
+static void
+create_test_of_builtin_trig (gcc_jit_context *ctxt)
+{
+ /* Let's try to inject the equivalent of:
+ int
+ test_of_builtin_trig (double theta)
+ {
+ return 2 * sin (theta) * cos (theta);
+ }
+ (in theory, optimizable to sin (2 * theta))
+ */
+ gcc_jit_type *double_t =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_DOUBLE);
+
+ /* Get the built-in functions. */
+ gcc_jit_function *builtin_sin =
+ gcc_jit_context_get_builtin_function (ctxt, "sin");
+ gcc_jit_function *builtin_cos =
+ gcc_jit_context_get_builtin_function (ctxt, "cos");
+
+ /* Build the test_fn. */
+ gcc_jit_param *param_theta =
+ gcc_jit_context_new_param (ctxt, NULL, double_t, "theta");
+ gcc_jit_function *test_fn =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ double_t,
+ "test_of_builtin_trig",
+ 1, ¶m_theta,
+ 0);
+ gcc_jit_rvalue *args[1] = {gcc_jit_param_as_rvalue (param_theta)};
+ gcc_jit_rvalue *two =
+ gcc_jit_context_new_rvalue_from_int (ctxt, double_t, 2);
+ gcc_jit_rvalue *ret =
+ gcc_jit_context_new_binary_op (
+ ctxt, NULL,
+ GCC_JIT_BINARY_OP_MULT,
+ double_t,
+ two,
+ gcc_jit_context_new_binary_op (
+ ctxt, NULL,
+ GCC_JIT_BINARY_OP_MULT,
+ double_t,
+ gcc_jit_context_new_call (ctxt, NULL,
+ builtin_sin,
+ 1, args),
+ gcc_jit_context_new_call (ctxt, NULL,
+ builtin_cos,
+ 1, args)));
+ CHECK_STRING_VALUE (
+ gcc_jit_object_get_debug_string (gcc_jit_rvalue_as_object (ret)),
+ "(double)2 * sin (theta) * cos (theta)");
+
+ gcc_jit_block *initial =
+ gcc_jit_function_new_block (test_fn, "initial");
+ gcc_jit_block_end_with_return (initial, NULL, ret);
+}
+
+static void
+create_use_of_builtins (gcc_jit_context *ctxt)
+{
+ create_test_of_builtin_strcmp (ctxt);
+ create_test_of_builtin_trig (ctxt);
+}
+
+static void
+verify_test_of_builtin_strcmp (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ typedef int (*fn_type) (const char *, const char *);
+ CHECK_NON_NULL (result);
+
+ fn_type test_of_builtin_strcmp =
+ (fn_type)gcc_jit_result_get_code (result, "test_of_builtin_strcmp");
+ CHECK_NON_NULL (test_of_builtin_strcmp);
+
+ /* Verify that it correctly called strcmp. */
+ CHECK_VALUE (test_of_builtin_strcmp ("foo", "foo"), 0);
+ CHECK (test_of_builtin_strcmp ("foo", "bar") > 0);
+ CHECK (test_of_builtin_strcmp ("bar", "foo") < 0);
+}
+
+static void
+verify_test_of_builtin_trig (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ typedef double (*fn_type) (double);
+ CHECK_NON_NULL (result);
+
+ fn_type test_of_builtin_trig =
+ (fn_type)gcc_jit_result_get_code (result, "test_of_builtin_trig");
+ CHECK_NON_NULL (test_of_builtin_trig);
+
+ /* Verify that it correctly computes
+ sin (2 * theta)
+ (perhaps calling sin and cos). */
+ CHECK_DOUBLE_VALUE (test_of_builtin_trig (0.0 ), 0.0);
+ CHECK_DOUBLE_VALUE (test_of_builtin_trig (M_PI_4 ), 1.0);
+ CHECK_DOUBLE_VALUE (test_of_builtin_trig (M_PI_2 ), 0.0);
+ CHECK_DOUBLE_VALUE (test_of_builtin_trig (M_PI_4 * 3.0), -1.0);
+ CHECK_DOUBLE_VALUE (test_of_builtin_trig (M_PI ), 0.0);
+}
+
+static void
+verify_use_of_builtins (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ verify_test_of_builtin_strcmp (ctxt, result);
+ verify_test_of_builtin_trig (ctxt, result);
+}
+
+/**********************************************************************
+ "void" return
+ **********************************************************************/
+
+static void
+create_use_of_void_return (gcc_jit_context *ctxt)
+{
+ /* Let's try to inject the equivalent of:
+ void
+ test_of_void_return (int *out)
+ {
+ *out = 1;
+ return;
+ }
+ */
+ gcc_jit_type *void_t =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+ gcc_jit_type *int_t =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+ gcc_jit_type *int_ptr_t =
+ gcc_jit_type_get_pointer (int_t);
+
+ /* Build the test_fn. */
+ gcc_jit_param *param_out =
+ gcc_jit_context_new_param (ctxt, NULL, int_ptr_t, "out");
+ gcc_jit_function *test_fn =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ void_t,
+ "test_of_void_return",
+ 1, ¶m_out,
+ 0);
+ gcc_jit_block *initial =
+ gcc_jit_function_new_block (test_fn, "initial");
+
+ gcc_jit_block_add_assignment (
+ initial, NULL,
+ /* "*out = ..." */
+ gcc_jit_rvalue_dereference (gcc_jit_param_as_rvalue (param_out),
+ NULL),
+ gcc_jit_context_one (ctxt, int_t));
+ gcc_jit_block_end_with_void_return (initial, NULL);
+}
+
+static void
+verify_void_return (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ typedef void (*fn_type) (int *);
+ CHECK_NON_NULL (result);
+
+ fn_type test_of_void_return =
+ (fn_type)gcc_jit_result_get_code (result, "test_of_void_return");
+ CHECK_NON_NULL (test_of_void_return);
+
+ int i;
+ test_of_void_return (&i);
+ CHECK_VALUE (i, 1); /* ensure correct value was written back */
+}
+
+/**********************************************************************
+ Code for harness
+ **********************************************************************/
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ create_tests_of_hidden_functions (ctxt);
+ create_use_of_builtins (ctxt);
+ create_use_of_void_return (ctxt);
+}
+
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ verify_hidden_functions (ctxt, result);
+ verify_use_of_builtins (ctxt, result);
+ verify_void_return (ctxt, result);
+}
--- /dev/null
+/* Fuzz-testing of libgccjit API.
+ Currently this triggers internal compiler errors, typically due to type
+ mismatches. */
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+
+#include "libgccjit.h"
+
+#define TEST_PROVIDES_MAIN
+#include "harness.h"
+
+typedef struct fuzzer
+{
+ gcc_jit_context *ctxt;
+
+ unsigned int seed;
+
+ int num_types;
+ gcc_jit_type **types;
+
+ int num_globals;
+ gcc_jit_lvalue **globals;
+
+ int num_funcs;
+ gcc_jit_function **funcs;
+
+} fuzzer;
+
+static void
+fuzzer_init (fuzzer *f, gcc_jit_context *ctxt, unsigned int seed);
+
+static int
+fuzzer_randrange (fuzzer *f, int min, int max);
+
+static gcc_jit_location *
+get_random_location (fuzzer *f);
+
+static gcc_jit_type *
+get_random_type (fuzzer *f);
+
+static gcc_jit_type *
+make_random_type (fuzzer *f);
+
+static gcc_jit_lvalue *
+make_random_global (fuzzer *f);
+
+static gcc_jit_function *
+make_random_function (fuzzer *f);
+
+typedef struct function_fuzzer
+{
+ fuzzer *f;
+
+ int num_params;
+ gcc_jit_param **params;
+
+ gcc_jit_function *fn;
+
+ int num_locals;
+ gcc_jit_lvalue **locals;
+
+ gcc_jit_block *block;
+
+} function_fuzzer;
+
+static void
+function_fuzzer_add_stmt (function_fuzzer *ff);
+
+static gcc_jit_lvalue *
+get_random_lvalue (function_fuzzer *ff, int max_depth);
+
+static gcc_jit_rvalue *
+get_random_rvalue (function_fuzzer *ff, int max_depth);
+
+/* fuzzer defns. */
+
+static void
+fuzzer_init (fuzzer *f, gcc_jit_context *ctxt, unsigned int seed)
+{
+ int i;
+ memset (f, 0, sizeof (*f));
+ f->ctxt = ctxt;
+ f->seed = seed;
+
+ int num_types = fuzzer_randrange (f, 5, 10);
+ f->types = malloc (num_types * sizeof (gcc_jit_type *));
+
+ int num_funcs = fuzzer_randrange (f, 3, 5);
+ f->funcs = malloc (num_funcs * sizeof (gcc_jit_function *));
+
+ int num_globals = fuzzer_randrange (f, 5, 10);
+ f->globals = malloc (num_globals * sizeof (gcc_jit_lvalue *));
+
+ for (i = 0; i < num_types; i++)
+ {
+ gcc_jit_type *type = make_random_type (f);
+ assert (type);
+ f->types[f->num_types++] = type;
+ }
+
+ for (i = 0; i < num_globals; i++)
+ f->globals[f->num_globals++] = make_random_global (f);
+
+ for (i = 0; i < num_funcs; i++)
+ f->funcs[f->num_funcs++] = make_random_function (f);
+}
+
+/* Get random int in inclusive range [min, max]. */
+
+static int fuzzer_randrange (fuzzer *f, int min, int max)
+{
+ assert (min <= max);
+ int i = rand_r (&f->seed);
+ int result = (i % (max + 1 - min)) + min;
+ assert (result >= min);
+ assert (result <= max);
+ return result;
+}
+
+static gcc_jit_location *
+get_random_location (fuzzer *f)
+{
+ const char *filename = NULL;
+
+ if (fuzzer_randrange (f, 0, 1))
+ return NULL;
+
+ switch (fuzzer_randrange (f, 1, 2))
+ {
+ case 1:
+ filename = "foo.c";
+ break;
+ case 2:
+ filename = "bar.c";
+ break;
+ }
+
+ return gcc_jit_context_new_location (f->ctxt,
+ filename,
+ fuzzer_randrange (f, 1, 1000),
+ fuzzer_randrange (f, 1, 1000));
+}
+
+const enum gcc_jit_types types[] = {
+ GCC_JIT_TYPE_VOID,
+
+ GCC_JIT_TYPE_VOID_PTR,
+
+ GCC_JIT_TYPE_CHAR,
+ GCC_JIT_TYPE_SIGNED_CHAR,
+ GCC_JIT_TYPE_UNSIGNED_CHAR,
+
+ GCC_JIT_TYPE_SHORT,
+ GCC_JIT_TYPE_UNSIGNED_SHORT,
+
+ GCC_JIT_TYPE_INT,
+ GCC_JIT_TYPE_UNSIGNED_INT,
+
+ GCC_JIT_TYPE_LONG,
+ GCC_JIT_TYPE_UNSIGNED_LONG,
+
+ GCC_JIT_TYPE_LONG_LONG,
+ GCC_JIT_TYPE_UNSIGNED_LONG_LONG,
+
+ GCC_JIT_TYPE_FLOAT,
+ GCC_JIT_TYPE_DOUBLE,
+ GCC_JIT_TYPE_LONG_DOUBLE,
+
+ GCC_JIT_TYPE_CONST_CHAR_PTR,
+
+ GCC_JIT_TYPE_SIZE_T,
+
+ GCC_JIT_TYPE_FILE_PTR
+};
+#define NUM_TYPES (sizeof(types)/sizeof(types[0]))
+
+static gcc_jit_type *
+get_random_type (fuzzer *f)
+{
+ int i = fuzzer_randrange (f, 0, (NUM_TYPES - 1) + f->num_types);
+ if (i < NUM_TYPES)
+ return gcc_jit_context_get_type (f->ctxt, types[i]);
+ assert ((i - NUM_TYPES) < f->num_types);
+ assert (f->types[i - NUM_TYPES]);
+ return f->types[i - NUM_TYPES];
+}
+
+static gcc_jit_type *
+make_random_type (fuzzer *f)
+{
+ switch (fuzzer_randrange (f, 0, 5))
+ {
+ case 0:
+ return gcc_jit_type_get_pointer (get_random_type (f));
+ case 1:
+ return gcc_jit_type_get_const (get_random_type (f));
+ default:
+ {
+ /* Create a struct. */
+ int num_fields = fuzzer_randrange (f, 0, 10);
+ gcc_jit_field **fields = \
+ malloc (num_fields * sizeof (gcc_jit_field *));
+ int i;
+ for (i = 0; i < num_fields ; i++)
+ {
+ char field_name[256];
+ sprintf (field_name, "field%i", i);
+ fields[i] = gcc_jit_context_new_field (f->ctxt,
+ get_random_location (f),
+ get_random_type (f),
+ field_name);
+ }
+ char struct_name[256];
+ sprintf (struct_name, "s%i", f->num_types);
+ gcc_jit_struct *struct_ = \
+ gcc_jit_context_new_struct_type (f->ctxt,
+ get_random_location (f),
+ struct_name,
+ num_fields,
+ fields);
+ free (fields);
+ return gcc_jit_struct_as_type (struct_);
+ }
+ }
+}
+
+static gcc_jit_lvalue *
+make_random_global (fuzzer *f)
+{
+ char global_name[256];
+ sprintf (global_name, "g%i", f->num_globals);
+ return gcc_jit_context_new_global (f->ctxt,
+ get_random_location (f),
+ get_random_type (f),
+ global_name);
+}
+
+static gcc_jit_function *
+make_random_function (fuzzer *f)
+{
+ char func_name[256];
+ sprintf (func_name, "fn%i", f->num_funcs);
+
+ function_fuzzer *ff = malloc (sizeof (function_fuzzer));
+ memset (ff, 0, sizeof (*ff));
+
+ ff->f = f;
+
+ ff->num_params = fuzzer_randrange (f, 0, 10);
+ ff->params = malloc (ff->num_params * sizeof (gcc_jit_param *));
+ int i;
+ for (i = 0; i < ff->num_params; i++)
+ {
+ char param_name[256];
+ sprintf (param_name, "param%i", i);
+ ff->params[i] = \
+ gcc_jit_context_new_param (f->ctxt,
+ get_random_location (f),
+ get_random_type (f),
+ param_name);
+ }
+
+ enum gcc_jit_function_kind kind =
+ ((enum gcc_jit_function_kind)
+ fuzzer_randrange (f, 0, GCC_JIT_FUNCTION_IMPORTED));
+
+ ff->fn = \
+ gcc_jit_context_new_function (
+ f->ctxt,
+ get_random_location (f),
+ kind,
+ get_random_type (f),
+ func_name,
+ ff->num_params,
+ ff->params,
+ fuzzer_randrange (f, 0, 1));
+ ff->block = gcc_jit_function_new_block (ff->fn, NULL);
+
+ /* Create locals. */
+ if (kind != GCC_JIT_FUNCTION_IMPORTED)
+ {
+ ff->num_locals = fuzzer_randrange (f, 0, 10);
+ ff->locals = malloc (ff->num_locals * sizeof (gcc_jit_lvalue *));
+ for (i = 0; i < ff->num_locals; i++)
+ {
+ char local_name[256];
+ sprintf (local_name, "local%i", i);
+ ff->locals[i] =
+ gcc_jit_function_new_local (ff->fn,
+ get_random_location (f),
+ get_random_type (f),
+ local_name);
+ }
+ }
+ /* TODO: use locals. */
+
+ if (kind != GCC_JIT_FUNCTION_IMPORTED)
+ {
+ /* TODO: create body */
+ int num_stmts = fuzzer_randrange (f, 0, 10);
+ for (i = 0; i < num_stmts; i++)
+ function_fuzzer_add_stmt (ff);
+ }
+
+ gcc_jit_block_end_with_return (ff->block, NULL, get_random_rvalue (ff, 3));
+
+
+ gcc_jit_function *result = ff->fn;
+
+ free (ff->params);
+ free (ff);
+
+ return result;
+}
+
+/* function_fuzzer defns. */
+
+static void function_fuzzer_add_stmt (function_fuzzer *ff)
+{
+ gcc_jit_block_add_eval (ff->block,
+ get_random_location (ff->f),
+ get_random_rvalue (ff, 4));
+ gcc_jit_block_add_assignment (ff->block,
+ get_random_location (ff->f),
+ get_random_lvalue (ff, 4),
+ get_random_rvalue (ff, 4));
+ /* TODO: place more kinds of statement */
+ /* TODO: labels */
+}
+
+static gcc_jit_lvalue *get_random_lvalue (function_fuzzer *ff, int max_depth)
+{
+ int choice = fuzzer_randrange (ff->f, 0,
+ ff->num_params
+ + ff->num_locals
+ + ff->f->num_globals - 1);
+ if (choice < ff->num_params)
+ return gcc_jit_param_as_lvalue (ff->params[choice]);
+ choice -= ff->num_params;
+
+ if (choice < ff->num_locals)
+ return ff->locals[choice];
+ choice -= ff->num_locals;
+
+ assert (choice < ff->f->num_globals);
+ return ff->f->globals[choice];
+}
+
+static gcc_jit_rvalue *get_random_rvalue (function_fuzzer *ff, int max_depth)
+{
+ int use_lvalue = fuzzer_randrange (ff->f, 0, 1);
+ if (use_lvalue)
+ return gcc_jit_lvalue_as_rvalue (get_random_lvalue (ff, max_depth));
+
+ int choice = fuzzer_randrange (ff->f, 0, 1);
+
+ /* Compound op: */
+ switch (choice)
+ {
+ case 0:
+ return gcc_jit_context_new_string_literal (ff->f->ctxt, "hello");
+ case 1:
+ return gcc_jit_context_new_rvalue_from_int (
+ ff->f->ctxt,
+ get_random_type (ff->f),
+ fuzzer_randrange (ff->f, 0, INT_MAX));
+ case 2:
+ return gcc_jit_context_new_rvalue_from_double (
+ ff->f->ctxt,
+ get_random_type (ff->f),
+ ((double)fuzzer_randrange (ff->f, 0, INT_MAX))
+ / (double)fuzzer_randrange (ff->f, 0, INT_MAX));
+ case 3:
+ return gcc_jit_context_new_unary_op (
+ ff->f->ctxt,
+ get_random_location (ff->f),
+ ((enum gcc_jit_unary_op)
+ fuzzer_randrange (ff->f, 0, GCC_JIT_UNARY_OP_LOGICAL_NEGATE)),
+ get_random_type (ff->f),
+ get_random_rvalue (ff, max_depth - 1));
+ case 4:
+ return gcc_jit_context_new_binary_op (
+ ff->f->ctxt,
+ get_random_location (ff->f),
+ ((enum gcc_jit_binary_op)
+ fuzzer_randrange (ff->f, 0, GCC_JIT_BINARY_OP_LOGICAL_OR)),
+ get_random_type (ff->f),
+ get_random_rvalue (ff, max_depth - 1),
+ get_random_rvalue (ff, max_depth - 1));
+ case 5:
+ return gcc_jit_lvalue_get_address (
+ get_random_lvalue (ff, max_depth - 1),
+ get_random_location (ff->f));
+
+ /* TODO:
+ - comparisons
+ - calls
+ - array lookup
+ - fields
+ - dereferencing */
+ }
+ return NULL;
+}
+
+
+/* Top-level defns for use by harness. */
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ fuzzer f;
+ int seed = *(int*)user_data;
+
+ fuzzer_init (&f, ctxt, seed);
+}
+
+static int num_completed_compilations = 0;
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ /* We can make no guarantees about whether we built something
+ valid or not, and the result might have an infinite loop,
+ so we can't execute it.
+
+ If we survive to reach here, note the fact for DejaGnu. */
+ pass ("%s: survived compilation", test);
+ if (result)
+ num_completed_compilations++;
+}
+
+static void
+test_fuzzer (const char *argv0, int seed)
+{
+ test_jit (argv0, &seed);
+}
+
+int
+main (int argc, char **argv)
+{
+ int i, seed;
+ const int NUM_ITERATIONS = 2;
+ const int NUM_SEEDS = 100;
+ for (i = 1; i <= NUM_ITERATIONS; i++)
+ {
+ for (seed = 0; seed < NUM_SEEDS ; seed++)
+ {
+ snprintf (test, sizeof (test),
+ "%s iteration %d of %d; seed %d of %d",
+ extract_progname (argv[0]),
+ i, NUM_ITERATIONS, seed, NUM_SEEDS);
+ test_fuzzer (argv[0], seed);
+ }
+ }
+ pass ("%s: survived running all tests", extract_progname (argv[0]));
+ note ("%s: num completed compilations: %d", extract_progname (argv[0]),
+ num_completed_compilations);
+ totals ();
+
+ return 0;
+}
--- /dev/null
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ /* Let's try to inject the equivalent of:
+ void
+ hello_world (const char *name)
+ {
+ // a test comment
+ printf ("hello %s\n", name);
+ }
+ */
+ gcc_jit_type *void_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+ gcc_jit_type *const_char_ptr_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_CONST_CHAR_PTR);
+ gcc_jit_param *param_name =
+ gcc_jit_context_new_param (ctxt, NULL, const_char_ptr_type, "name");
+ gcc_jit_function *func =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ void_type,
+ "hello_world",
+ 1, ¶m_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, ¶m_format,
+ 1);
+ gcc_jit_rvalue *args[2];
+ args[0] = gcc_jit_context_new_string_literal (ctxt, "hello %s\n");
+ args[1] = gcc_jit_param_as_rvalue (param_name);
+
+ gcc_jit_block *block = gcc_jit_function_new_block (func, NULL);
+
+ gcc_jit_block_add_comment (
+ block, NULL,
+ "a test comment");
+
+ gcc_jit_block_add_eval (
+ block, NULL,
+ gcc_jit_context_new_call (ctxt,
+ NULL,
+ printf_func,
+ 2, args));
+ gcc_jit_block_end_with_void_return (block, NULL);
+}
+
+extern void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ typedef void (*fn_type) (const char *);
+ CHECK_NON_NULL (result);
+ fn_type hello_world =
+ (fn_type)gcc_jit_result_get_code (result, "hello_world");
+ CHECK_NON_NULL (hello_world);
+ hello_world ("world");
+ fflush (stdout);
+}
--- /dev/null
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+/* A doubly-linked list, to ensure that the JIT API can cope with
+ self-referential types. */
+struct node
+{
+ struct node *prev;
+ struct node *next;
+ int value;
+};
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ /* Let's try to inject the equivalent of:
+ int
+ test_linked_list (struct node *n)
+ {
+ int total = 0;
+ while (n)
+ {
+ total += n->value;
+ n = n->next;
+ }
+ return total;
+ }
+ */
+ gcc_jit_type *t_int =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+ gcc_jit_struct *t_node =
+ gcc_jit_context_new_opaque_struct (ctxt, NULL, "node");
+ gcc_jit_type *t_node_ptr =
+ gcc_jit_type_get_pointer (gcc_jit_struct_as_type (t_node));
+
+ gcc_jit_field *f_prev =
+ gcc_jit_context_new_field (ctxt, NULL, t_node_ptr, "prev");
+ gcc_jit_field *f_next =
+ gcc_jit_context_new_field (ctxt, NULL, t_node_ptr, "next");
+ gcc_jit_field *f_value =
+ gcc_jit_context_new_field (ctxt, NULL, t_int, "value");
+ gcc_jit_field *fields[] = {f_prev, f_next, f_value};
+ gcc_jit_struct_set_fields (t_node, NULL, 3, fields);
+
+ /* Build the test function. */
+ gcc_jit_param *param_n =
+ gcc_jit_context_new_param (ctxt, NULL, t_node_ptr, "n");
+ gcc_jit_function *fn =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ t_int,
+ "test_linked_list",
+ 1, ¶m_n,
+ 0);
+ /* int total; */
+ gcc_jit_lvalue *total =
+ gcc_jit_function_new_local (fn, NULL, t_int, "total");
+
+ gcc_jit_block *initial = gcc_jit_function_new_block (fn, "initial");
+ gcc_jit_block *loop_test = gcc_jit_function_new_block (fn, "loop_test");
+ gcc_jit_block *loop_body = gcc_jit_function_new_block (fn, "loop_body");
+ gcc_jit_block *final = gcc_jit_function_new_block (fn, "final");
+
+ /* total = 0; */
+ gcc_jit_block_add_assignment (
+ initial, NULL,
+ total,
+ gcc_jit_context_zero (ctxt, t_int));
+ gcc_jit_block_end_with_jump (initial, NULL, loop_test);
+
+ /* while (n) */
+ gcc_jit_block_end_with_conditional (
+ loop_test, NULL,
+ gcc_jit_context_new_comparison (ctxt, NULL,
+ GCC_JIT_COMPARISON_NE,
+ gcc_jit_param_as_rvalue (param_n),
+ gcc_jit_context_null (ctxt, t_node_ptr)),
+ loop_body,
+ final);
+
+ /* total += n->value; */
+ gcc_jit_block_add_assignment_op (
+ loop_body, NULL,
+ total,
+ GCC_JIT_BINARY_OP_PLUS,
+ gcc_jit_lvalue_as_rvalue (
+ gcc_jit_rvalue_dereference_field (
+ gcc_jit_param_as_rvalue (param_n),
+ NULL,
+ f_value)));
+
+ /* n = n->next; */
+ gcc_jit_block_add_assignment (
+ loop_body, NULL,
+ gcc_jit_param_as_lvalue (param_n),
+ gcc_jit_lvalue_as_rvalue (
+ gcc_jit_rvalue_dereference_field (
+ gcc_jit_param_as_rvalue (param_n),
+ NULL,
+ f_next)));
+
+ gcc_jit_block_end_with_jump (loop_body, NULL, loop_test);
+
+ /* return total; */
+ gcc_jit_block_end_with_return (
+ final, NULL, gcc_jit_lvalue_as_rvalue (total));
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ struct node a, b, c;
+ typedef int (*fn_type) (struct node *n);
+ CHECK_NON_NULL (result);
+
+ fn_type test_linked_list =
+ (fn_type)gcc_jit_result_get_code (result, "test_linked_list");
+ CHECK_NON_NULL (test_linked_list);
+
+ /* Construct a simple linked-list on the stack: a->b->c: */
+ a.prev = NULL;
+ a.next = &b;
+ a.value = 5;
+
+ b.prev = &a;
+ b.next = &c;
+ b.value = 3;
+
+ c.prev = &b;
+ c.next = NULL;
+ c.value = 7;
+
+ CHECK_VALUE (test_linked_list (NULL), 0);
+ CHECK_VALUE (test_linked_list (&a), 15);
+ CHECK_VALUE (test_linked_list (&b), 10);
+ CHECK_VALUE (test_linked_list (&c), 7);
+}
--- /dev/null
+/* Test of using the API with very long names. */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+/* 65KB */
+#define NAME_LENGTH (65 * 1024)
+
+static struct long_names
+{
+ char struct_name[NAME_LENGTH];
+ char fn_name[NAME_LENGTH];
+ char local_name[NAME_LENGTH];
+ char block_name[NAME_LENGTH];
+} long_names;
+
+static void
+populate_name (const char *prefix, char *buffer)
+{
+ int i;
+
+ /* Begin with the given prefix: */
+ sprintf (buffer, prefix);
+
+ /* Populate the rest of the buffer with 0123456789 repeatedly: */
+ for (i = strlen (prefix); i < NAME_LENGTH - 1; i++)
+ buffer[i] = '0' + (i % 10);
+
+ /* NIL-terminate the buffer: */
+ buffer[NAME_LENGTH - 1] = '\0';
+}
+
+static void
+populate_names (void)
+{
+ populate_name ("struct_", long_names.struct_name);
+ populate_name ("test_fn_", long_names.fn_name);
+ populate_name ("local_", long_names.local_name);
+ populate_name ("block_", long_names.block_name);
+}
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ /* Where "ETC" is a very long suffix, let's try to inject the
+ equivalent of:
+
+ struct struct_ETC;
+
+ int
+ test_fn_ETC ()
+ {
+ int local_ETC;
+ local_ETC = 42;
+ return local_ETC;
+ }
+
+ to verify that the API copes with such long names. */
+
+ populate_names ();
+
+ gcc_jit_type *int_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+ /* We don't yet use this struct. */
+ (void)gcc_jit_context_new_opaque_struct (ctxt, NULL,
+ long_names.struct_name);
+
+ gcc_jit_function *test_fn =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ int_type,
+ long_names.fn_name,
+ 0, NULL,
+ 0);
+ gcc_jit_lvalue *local =
+ gcc_jit_function_new_local (test_fn,
+ NULL,
+ int_type,
+ long_names.local_name);
+
+ gcc_jit_block *block =
+ gcc_jit_function_new_block (test_fn, long_names.block_name);
+
+ gcc_jit_block_add_assignment (
+ block,
+ NULL,
+ local,
+ gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 42));
+
+ gcc_jit_block_end_with_return (
+ block, NULL,
+ gcc_jit_lvalue_as_rvalue (local));
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ CHECK_NON_NULL (result);
+
+ typedef int (*my_fn_type) (void);
+ CHECK_NON_NULL (result);
+ my_fn_type my_fn =
+ (my_fn_type)gcc_jit_result_get_code (result, long_names.fn_name);
+ CHECK_NON_NULL (my_fn);
+ int val = my_fn ();
+ CHECK_VALUE (val, 42);
+}
--- /dev/null
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#define TEST_ESCHEWS_TEST_JIT
+#define TEST_PROVIDES_MAIN
+#include "harness.h"
+
+struct quadratic
+{
+ double a;
+ double b;
+ double c;
+ double discriminant;
+};
+
+/* This is an adapted version of test-quadratic.c
+
+ Like that test, we'll try to inject the following code, but we'll
+ split it up into some nested contexts, in 3 levels, to test
+ how nested contexts work.
+
+ ***** In top-level context: *****
+
+ (shared type declarations, for int, double, struct quadratic);
+ extern double sqrt (double);
+
+ ***** In mid-level context: *****
+
+ void
+ calc_discriminant (struct quadratic *q)
+ {
+ // (b^2 - 4ac)
+ q->discriminant = (q->b * q->b) - (4 * q->a * q->c);
+ }
+
+ ***** In bottom context: *****
+
+ int
+ test_quadratic (double a, double b, double c, double *r1, double *r2)
+ {
+ struct quadratic q;
+ q.a = a;
+ q.b = b;
+ q.c = c;
+ calc_discriminant (&q);
+ if (q.discriminant > 0)
+ {
+ double s = sqrt (q.discriminant);
+ *r1 = (-b + s) / (2 * a);
+ *r2 = (-b - s) / (2 * a);
+ return 2;
+ }
+ else if (q.discriminant == 0)
+ {
+ *r1 = -b / (2 * a);
+ return 1;
+ }
+ else return 0;
+ }
+*/
+
+struct top_level
+{
+ gcc_jit_context *ctxt;
+
+ /* "double" and "(double *)". */
+ gcc_jit_type *numeric_type;
+ gcc_jit_type *numeric_type_ptr;
+
+ /* The value (double)0. */
+ gcc_jit_rvalue *zero;
+
+ gcc_jit_type *int_type;
+ gcc_jit_type *void_type;
+
+ /* "struct quadratic" */
+ gcc_jit_type *struct_quadratic;
+ gcc_jit_field *a;
+ gcc_jit_field *b;
+ gcc_jit_field *c;
+ gcc_jit_field *discriminant;
+
+ /* "(struct quadratic *)" */
+ gcc_jit_type *quadratic_ptr;
+
+ gcc_jit_function *sqrt;
+};
+
+struct middle_level
+{
+ gcc_jit_context *ctxt;
+ gcc_jit_function *calc_discriminant;
+};
+
+struct bottom_level
+{
+ gcc_jit_context *ctxt;
+};
+
+static void
+make_types (struct top_level *top_level)
+{
+ top_level->numeric_type =
+ gcc_jit_context_get_type (top_level->ctxt, GCC_JIT_TYPE_DOUBLE);
+ top_level->numeric_type_ptr =
+ gcc_jit_type_get_pointer (top_level->numeric_type);
+ top_level->zero =
+ gcc_jit_context_zero (top_level->ctxt, top_level->numeric_type);
+
+ top_level->int_type =
+ gcc_jit_context_get_type (top_level->ctxt, GCC_JIT_TYPE_INT);
+ top_level->void_type =
+ gcc_jit_context_get_type (top_level->ctxt, GCC_JIT_TYPE_VOID);
+
+ top_level->a =
+ gcc_jit_context_new_field (top_level->ctxt,
+ NULL,
+ top_level->numeric_type,
+ "a");
+ top_level->b =
+ gcc_jit_context_new_field (top_level->ctxt,
+ NULL,
+ top_level->numeric_type,
+ "b");
+ top_level->c =
+ gcc_jit_context_new_field (top_level->ctxt,
+ NULL,
+ top_level->numeric_type,
+ "c");
+ top_level->discriminant =
+ gcc_jit_context_new_field (top_level->ctxt,
+ NULL,
+ top_level->numeric_type,
+ "discriminant");
+ gcc_jit_field *fields[] = {top_level->a,
+ top_level->b,
+ top_level->c,
+ top_level->discriminant};
+ top_level->struct_quadratic =
+ gcc_jit_struct_as_type (
+ gcc_jit_context_new_struct_type (top_level->ctxt, NULL,
+ "quadratic", 4, fields));
+ top_level->quadratic_ptr =
+ gcc_jit_type_get_pointer (top_level->struct_quadratic);
+}
+
+static void
+make_sqrt (struct top_level *top_level)
+{
+ gcc_jit_param *param_x =
+ gcc_jit_context_new_param (top_level->ctxt, NULL,
+ top_level->numeric_type, "x");
+ top_level->sqrt =
+ gcc_jit_context_new_function (top_level->ctxt, NULL,
+ GCC_JIT_FUNCTION_IMPORTED,
+ top_level->numeric_type,
+ "sqrt",
+ 1, ¶m_x,
+ 0);
+}
+
+static void
+make_calc_discriminant (struct top_level *top_level,
+ struct middle_level *middle_level)
+{
+ /* Build "calc_discriminant". */
+ gcc_jit_param *param_q =
+ gcc_jit_context_new_param (middle_level->ctxt, NULL,
+ top_level->quadratic_ptr, "q");
+ middle_level->calc_discriminant =
+ gcc_jit_context_new_function (middle_level->ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ top_level->void_type,
+ "calc_discriminant",
+ 1, ¶m_q,
+ 0);
+ gcc_jit_block *blk =
+ gcc_jit_function_new_block (middle_level->calc_discriminant, NULL);
+ gcc_jit_block_add_comment (
+ blk, NULL,
+ "(b^2 - 4ac)");
+
+ gcc_jit_rvalue *q_a =
+ gcc_jit_lvalue_as_rvalue (
+ gcc_jit_rvalue_dereference_field (
+ gcc_jit_param_as_rvalue (param_q),
+ NULL, top_level->a));
+ gcc_jit_rvalue *q_b =
+ gcc_jit_lvalue_as_rvalue (
+ gcc_jit_rvalue_dereference_field (
+ gcc_jit_param_as_rvalue (param_q),
+ NULL, top_level->b));
+ gcc_jit_rvalue *q_c =
+ gcc_jit_lvalue_as_rvalue (
+ gcc_jit_rvalue_dereference_field (
+ gcc_jit_param_as_rvalue (param_q),
+ NULL, top_level->c));
+
+ gcc_jit_block_add_assignment (
+ blk, NULL,
+
+ /* q->discriminant =... */
+ gcc_jit_rvalue_dereference_field (
+ gcc_jit_param_as_rvalue (param_q),
+ NULL,
+ top_level->discriminant),
+
+ /* (q->b * q->b) - (4 * q->a * q->c) */
+ gcc_jit_context_new_binary_op (
+ middle_level->ctxt, NULL,
+ GCC_JIT_BINARY_OP_MINUS,
+ top_level->numeric_type,
+
+ /* (q->b * q->b) */
+ gcc_jit_context_new_binary_op (
+ middle_level->ctxt, NULL,
+ GCC_JIT_BINARY_OP_MULT,
+ top_level->numeric_type,
+ q_b, q_b),
+
+ /* (4 * (q->a * q->c)) */
+ gcc_jit_context_new_binary_op (
+ middle_level->ctxt, NULL,
+ GCC_JIT_BINARY_OP_MULT,
+ top_level->numeric_type,
+ /* 4.0 */
+ gcc_jit_context_new_rvalue_from_int (
+ middle_level->ctxt,
+ top_level->numeric_type,
+ 4),
+ /* (q->a * q->c) */
+ gcc_jit_context_new_binary_op (
+ middle_level->ctxt, NULL,
+ GCC_JIT_BINARY_OP_MULT,
+ top_level->numeric_type,
+ q_a, q_c)))); /* end of gcc_jit_function_add_assignment call. */
+
+ gcc_jit_block_end_with_void_return (blk, NULL);
+}
+
+static void
+make_test_quadratic (struct top_level *top_level,
+ struct middle_level *middle_level,
+ struct bottom_level *bottom_level)
+{
+ gcc_jit_param *a =
+ gcc_jit_context_new_param (bottom_level->ctxt, NULL,
+ top_level->numeric_type, "a");
+ gcc_jit_param *b =
+ gcc_jit_context_new_param (bottom_level->ctxt, NULL,
+ top_level->numeric_type, "b");
+ gcc_jit_param *c =
+ gcc_jit_context_new_param (bottom_level->ctxt, NULL,
+ top_level->numeric_type, "c");
+ gcc_jit_param *r1 =
+ gcc_jit_context_new_param (bottom_level->ctxt, NULL,
+ top_level->numeric_type_ptr, "r1");
+ gcc_jit_param *r2 =
+ gcc_jit_context_new_param (bottom_level->ctxt, NULL,
+ top_level->numeric_type_ptr, "r2");
+ gcc_jit_param *params[] = {a, b, c, r1, r2};
+ gcc_jit_function *test_quadratic =
+ gcc_jit_context_new_function (bottom_level->ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ top_level->int_type,
+ "test_quadratic",
+ 5, params,
+ 0);
+
+ /* struct quadratic q; */
+ gcc_jit_lvalue *q =
+ gcc_jit_function_new_local (
+ test_quadratic, NULL,
+ top_level->struct_quadratic,
+ "q");
+
+ gcc_jit_block *initial =
+ gcc_jit_function_new_block (test_quadratic,
+ "initial");
+ gcc_jit_block *on_positive_discriminant
+ = gcc_jit_function_new_block (test_quadratic,
+ "positive_discriminant");
+
+ gcc_jit_block *on_nonpositive_discriminant
+ = gcc_jit_function_new_block (test_quadratic,
+ "nonpositive_discriminant");
+
+ gcc_jit_block *on_zero_discriminant
+ = gcc_jit_function_new_block (test_quadratic,
+ "zero_discriminant");
+
+ gcc_jit_block *on_negative_discriminant
+ = gcc_jit_function_new_block (test_quadratic,
+ "negative_discriminant");
+
+ /* Initial block. */
+ /* q.a = a; */
+ gcc_jit_block_add_assignment (
+ initial, NULL,
+ gcc_jit_lvalue_access_field (q, NULL, top_level->a),
+ gcc_jit_param_as_rvalue (a));
+ /* q.b = b; */
+ gcc_jit_block_add_assignment (
+ initial, NULL,
+ gcc_jit_lvalue_access_field (q, NULL, top_level->b),
+ gcc_jit_param_as_rvalue (b));
+ /* q.c = c; */
+ gcc_jit_block_add_assignment (
+ initial, NULL,
+ gcc_jit_lvalue_access_field (q, NULL, top_level->c),
+ gcc_jit_param_as_rvalue (c));
+ /* calc_discriminant (&q); */
+ gcc_jit_rvalue *address_of_q = gcc_jit_lvalue_get_address (q, NULL);
+ gcc_jit_block_add_eval (
+ initial, NULL,
+ gcc_jit_context_new_call (
+ bottom_level->ctxt, NULL,
+ middle_level->calc_discriminant,
+ 1, &address_of_q));
+
+ gcc_jit_block_add_comment (
+ initial, NULL,
+ "if (q.discriminant > 0)");
+ gcc_jit_block_end_with_conditional (
+ initial, NULL,
+ gcc_jit_context_new_comparison (
+ bottom_level->ctxt, NULL,
+ GCC_JIT_COMPARISON_GT,
+ gcc_jit_rvalue_access_field (
+ gcc_jit_lvalue_as_rvalue (q),
+ NULL,
+ top_level->discriminant),
+ top_level->zero),
+ on_positive_discriminant,
+ on_nonpositive_discriminant);
+
+ /* Block: "on_positive_discriminant" */
+ /* double s = sqrt (q.discriminant); */
+ gcc_jit_lvalue *s = gcc_jit_function_new_local (
+ test_quadratic, NULL,
+ top_level->numeric_type,
+ "s");
+ gcc_jit_rvalue *discriminant_of_q =
+ gcc_jit_rvalue_access_field (gcc_jit_lvalue_as_rvalue (q),
+ NULL,
+ top_level->discriminant);
+ gcc_jit_block_add_assignment (
+ on_positive_discriminant, NULL,
+ s,
+ gcc_jit_context_new_call (
+ bottom_level->ctxt, NULL,
+ top_level->sqrt,
+ 1, &discriminant_of_q));
+
+ gcc_jit_rvalue *minus_b =
+ gcc_jit_context_new_unary_op (
+ bottom_level->ctxt, NULL,
+ GCC_JIT_UNARY_OP_MINUS,
+ top_level->numeric_type,
+ gcc_jit_param_as_rvalue (b));
+ gcc_jit_rvalue *two_a =
+ gcc_jit_context_new_binary_op (
+ bottom_level->ctxt, NULL,
+ GCC_JIT_BINARY_OP_MULT,
+ top_level->numeric_type,
+ gcc_jit_context_new_rvalue_from_int (
+ bottom_level->ctxt,
+ top_level->numeric_type,
+ 2),
+ gcc_jit_param_as_rvalue (a));
+
+ gcc_jit_block_add_comment (
+ on_positive_discriminant, NULL,
+ "*r1 = (-b + s) / (2 * a);");
+ gcc_jit_block_add_assignment (
+ on_positive_discriminant, NULL,
+
+ /* "*r1 = ..." */
+ gcc_jit_rvalue_dereference (
+ gcc_jit_param_as_rvalue (r1), NULL),
+
+ /* (-b + s) / (2 * a) */
+ gcc_jit_context_new_binary_op (
+ bottom_level->ctxt, NULL,
+ GCC_JIT_BINARY_OP_DIVIDE,
+ top_level->numeric_type,
+ gcc_jit_context_new_binary_op (
+ bottom_level->ctxt, NULL,
+ GCC_JIT_BINARY_OP_PLUS,
+ top_level->numeric_type,
+ minus_b,
+ gcc_jit_lvalue_as_rvalue (s)),
+ two_a));
+
+ gcc_jit_block_add_comment (
+ on_positive_discriminant, NULL,
+ "*r2 = (-b - s) / (2 * a)");
+ gcc_jit_block_add_assignment (
+ on_positive_discriminant, NULL,
+
+ /* "*r2 = ..." */
+ gcc_jit_rvalue_dereference (
+ gcc_jit_param_as_rvalue (r2), NULL),
+
+ /* (-b - s) / (2 * a) */
+ gcc_jit_context_new_binary_op (
+ bottom_level->ctxt, NULL,
+ GCC_JIT_BINARY_OP_DIVIDE,
+ top_level->numeric_type,
+ gcc_jit_context_new_binary_op (
+ bottom_level->ctxt, NULL,
+ GCC_JIT_BINARY_OP_MINUS,
+ top_level->numeric_type,
+ minus_b,
+ gcc_jit_lvalue_as_rvalue (s)),
+ two_a));
+
+ /* "return 2;" */
+ gcc_jit_block_end_with_return (
+ on_positive_discriminant, NULL,
+ gcc_jit_context_new_rvalue_from_int (
+ bottom_level->ctxt,
+ top_level->int_type,
+ 2));
+
+ /* Block: "on_nonpositive_discriminant" */
+ gcc_jit_block_add_comment (
+ on_nonpositive_discriminant, NULL,
+ "else if (q.discriminant == 0)");
+ gcc_jit_block_end_with_conditional (
+ on_nonpositive_discriminant, NULL,
+ gcc_jit_context_new_comparison (
+ bottom_level->ctxt, NULL,
+ GCC_JIT_COMPARISON_EQ,
+ gcc_jit_rvalue_access_field (
+ gcc_jit_lvalue_as_rvalue (q),
+ NULL,
+ top_level->discriminant),
+ top_level->zero),
+ on_zero_discriminant,
+ on_negative_discriminant);
+
+ /* Block: "on_zero_discriminant" */
+ gcc_jit_block_add_comment (
+ on_zero_discriminant, NULL,
+ "*r1 = -b / (2 * a);");
+ gcc_jit_block_add_assignment (
+ on_zero_discriminant, NULL,
+
+ /* "*r1 = ..." */
+ gcc_jit_rvalue_dereference (
+ gcc_jit_param_as_rvalue (r1), NULL),
+
+ /* -b / (2 * a) */
+ gcc_jit_context_new_binary_op (
+ bottom_level->ctxt, NULL,
+ GCC_JIT_BINARY_OP_DIVIDE,
+ top_level->numeric_type,
+ minus_b,
+ two_a));
+
+ /* "return 1;" */
+ gcc_jit_block_end_with_return (
+ on_zero_discriminant, NULL,
+ gcc_jit_context_one (bottom_level->ctxt, top_level->int_type));
+
+ /* Block: "on_negative_discriminant" */
+ gcc_jit_block_end_with_return (
+ /* else return 0; */
+ on_negative_discriminant, NULL,
+ gcc_jit_context_zero (bottom_level->ctxt, top_level->int_type));
+}
+
+void
+verify_middle_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ struct quadratic q;
+
+ typedef void (*fn_type) (struct quadratic *q);
+ fn_type calc_discriminant =
+ (fn_type)gcc_jit_result_get_code (result,
+ "calc_discriminant");
+ CHECK_NON_NULL (calc_discriminant);
+
+ q.a = 3;
+ q.b = 5;
+ q.c = 7;
+ q.discriminant = 0;
+ calc_discriminant (&q);
+
+ CHECK_VALUE (q.discriminant, -59);
+}
+
+void
+verify_bottom_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ typedef int (*fn_type) (double a, double b, double c,
+ double *r1, double *r2);
+
+ CHECK_NON_NULL (result);
+
+ fn_type test_quadratic =
+ (fn_type)gcc_jit_result_get_code (result, "test_quadratic");
+ CHECK_NON_NULL (test_quadratic);
+
+ /* Verify that the code correctly solves quadratic equations. */
+ double r1, r2;
+
+ /* This one has two solutions: */
+ CHECK_VALUE (test_quadratic (1, 3, -4, &r1, &r2), 2);
+ CHECK_VALUE (r1, 1);
+ CHECK_VALUE (r2, -4);
+
+ /* This one has one solution: */
+ CHECK_VALUE (test_quadratic (4, 4, 1, &r1, &r2), 1);
+ CHECK_VALUE (r1, -0.5);
+
+ /* This one has no real solutions: */
+ CHECK_VALUE (test_quadratic (4, 1, 1, &r1, &r2), 0);
+}
+
+int
+main (int argc, char **argv)
+{
+ int i, j, k;
+ const int NUM_TOP_ITERATIONS = 2;
+ const int NUM_MIDDLE_ITERATIONS = 2;
+ const int NUM_BOTTOM_ITERATIONS = 2;
+
+ /* We do the whole thing multiple times to shake out state-management
+ issues in the underlying code. */
+
+ for (i = 1; i <= NUM_TOP_ITERATIONS; i++)
+ {
+ /* Create the top-level context. */
+ snprintf (test, sizeof (test),
+ "%s iteration %d of %d of top level",
+ extract_progname (argv[0]),
+ i, NUM_TOP_ITERATIONS);
+
+ struct top_level top_level;
+ memset (&top_level, 0, sizeof (top_level));
+
+ top_level.ctxt = gcc_jit_context_acquire ();
+ set_options (top_level.ctxt, argv[0]);
+
+ make_types (&top_level);
+ make_sqrt (&top_level);
+
+ /* No errors should have occurred. */
+ CHECK_VALUE (gcc_jit_context_get_first_error (top_level.ctxt), NULL);
+
+ gcc_jit_context_dump_to_file (top_level.ctxt,
+ "dump-of-test-nested-contexts-top.c",
+ 1);
+
+ for (j = 1; j <= NUM_MIDDLE_ITERATIONS; j++)
+ {
+ /* Create and populate the middle-level context, using
+ objects from the top-level context. */
+ snprintf (test, sizeof (test),
+ ("%s iteration %d of %d of top level;"
+ " %d of %d of middle level"),
+ extract_progname (argv[0]),
+ i, NUM_TOP_ITERATIONS,
+ j, NUM_MIDDLE_ITERATIONS);
+
+ struct middle_level middle_level;
+ memset (&middle_level, 0, sizeof (middle_level));
+
+ middle_level.ctxt =
+ gcc_jit_context_new_child_context (top_level.ctxt);
+ make_calc_discriminant (&top_level,
+ &middle_level);
+
+ /* No errors should have occurred. */
+ CHECK_VALUE (gcc_jit_context_get_first_error (middle_level.ctxt),
+ NULL);
+
+ gcc_jit_context_dump_to_file (middle_level.ctxt,
+ "dump-of-test-nested-contexts-middle.c",
+ 1);
+
+ gcc_jit_result *middle_result =
+ gcc_jit_context_compile (middle_level.ctxt);
+ CHECK_NON_NULL (middle_result);
+
+ verify_middle_code (middle_level.ctxt, middle_result);
+
+ for (k = 1; k <= NUM_BOTTOM_ITERATIONS; k++)
+ {
+ /* Create and populate the innermost context, using
+ objects from the top-level and middle-level contexts. */
+ snprintf (test, sizeof (test),
+ ("%s iteration %d of %d of top level;"
+ " %d of %d of middle level;"
+ " %d of %d of bottom level"),
+ extract_progname (argv[0]),
+ i, NUM_TOP_ITERATIONS,
+ j, NUM_MIDDLE_ITERATIONS,
+ k, NUM_BOTTOM_ITERATIONS);
+
+ struct bottom_level bottom_level;
+ memset (&bottom_level, 0, sizeof (bottom_level));
+
+ bottom_level.ctxt =
+ gcc_jit_context_new_child_context (middle_level.ctxt);
+ make_test_quadratic (&top_level,
+ &middle_level,
+ &bottom_level);
+
+ /* No errors should have occurred. */
+ CHECK_VALUE (gcc_jit_context_get_first_error (bottom_level.ctxt),
+ NULL);
+
+ gcc_jit_context_dump_to_file (bottom_level.ctxt,
+ "dump-of-test-nested-contexts-bottom.c",
+ 1);
+
+ gcc_jit_result *bottom_result =
+ gcc_jit_context_compile (bottom_level.ctxt);
+ verify_bottom_code (bottom_level.ctxt, bottom_result);
+ gcc_jit_result_release (bottom_result);
+ gcc_jit_context_release (bottom_level.ctxt);
+
+ }
+
+ gcc_jit_result_release (middle_result);
+ gcc_jit_context_release (middle_level.ctxt);
+
+ }
+
+ gcc_jit_context_release (top_level.ctxt);
+ }
+
+ totals ();
+
+ return 0;
+}
--- /dev/null
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ /* Let's try to inject the equivalent of:
+
+ double
+ test_nested_loops (int n, double *a, double *b)
+ {
+ double result = 0.;
+ for (int i = 0; i < n; i++)
+ for (int j = 0; j < n; j++)
+ result += a[i] * b[j];
+ return result
+ }
+ */
+ gcc_jit_type *val_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_DOUBLE);
+ gcc_jit_type *ptr_type = gcc_jit_type_get_pointer (val_type);
+ gcc_jit_type *int_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+ gcc_jit_type *return_type = val_type;
+ gcc_jit_param *param_n =
+ gcc_jit_context_new_param (ctxt, NULL, int_type, "n");
+ gcc_jit_param *param_a =
+ gcc_jit_context_new_param (ctxt, NULL, ptr_type, "a");
+ gcc_jit_param *param_b =
+ gcc_jit_context_new_param (ctxt, NULL, ptr_type, "b");
+ gcc_jit_param *params[3] = {param_n, param_a, param_b};
+ gcc_jit_function *func =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ return_type,
+ "test_nested_loops",
+ 3, params, 0);
+
+ /* Create locals. */
+ gcc_jit_lvalue *result =
+ gcc_jit_function_new_local (func, NULL, val_type, "result");
+ gcc_jit_lvalue *i =
+ gcc_jit_function_new_local (func, NULL, int_type, "i");
+ gcc_jit_lvalue *j =
+ gcc_jit_function_new_local (func, NULL, int_type, "j");
+
+ /* Create basic blocks. */
+ gcc_jit_block *b_entry =
+ gcc_jit_function_new_block (func, "b_entry");
+ gcc_jit_block *b_outer_loop_cond =
+ gcc_jit_function_new_block (func, "b_outer_loop_cond");
+ gcc_jit_block *b_outer_loop_head =
+ gcc_jit_function_new_block (func, "b_outer_loop_head");
+ gcc_jit_block *b_outer_loop_tail =
+ gcc_jit_function_new_block (func, "b_outer_loop_tail");
+ gcc_jit_block *b_inner_loop_cond =
+ gcc_jit_function_new_block (func, "b_inner_loop_cond");
+ gcc_jit_block *b_inner_loop_body =
+ gcc_jit_function_new_block (func, "b_inner_loop_body");
+ gcc_jit_block *b_exit =
+ gcc_jit_function_new_block (func, "b_exit");
+
+
+ /* Populate b_entry. */
+
+ /* "result = 0.;" */
+ gcc_jit_block_add_assignment (
+ b_entry, NULL,
+ result,
+ gcc_jit_context_zero (ctxt, val_type));
+ /* "i = 0;" */
+ gcc_jit_block_add_assignment (
+ b_entry, NULL,
+ i,
+ gcc_jit_context_zero (ctxt, int_type));
+ gcc_jit_block_end_with_jump (b_entry, NULL, b_outer_loop_cond);
+
+ /* Populate b_outer_loop_cond. */
+ gcc_jit_block_end_with_conditional (
+ b_outer_loop_cond,
+ NULL,
+ /* (i < n) */
+ gcc_jit_context_new_comparison (
+ ctxt, NULL,
+ GCC_JIT_COMPARISON_LT,
+ gcc_jit_lvalue_as_rvalue (i),
+ gcc_jit_param_as_rvalue (param_n)),
+ b_outer_loop_head,
+ b_exit);
+
+ /* Populate b_outer_loop_head. */
+ /* j = 0; */
+ gcc_jit_block_add_assignment (
+ b_outer_loop_head, NULL,
+ j,
+ gcc_jit_context_zero (ctxt, int_type));
+ gcc_jit_block_end_with_jump (b_outer_loop_head, NULL, b_inner_loop_cond);
+
+ /* Populate b_inner_loop_cond. */
+ gcc_jit_block_end_with_conditional (
+ b_inner_loop_cond,
+ NULL,
+ /* (j < n) */
+ gcc_jit_context_new_comparison (
+ ctxt, NULL,
+ GCC_JIT_COMPARISON_LT,
+ gcc_jit_lvalue_as_rvalue (j),
+ gcc_jit_param_as_rvalue (param_n)),
+ b_inner_loop_body,
+ b_outer_loop_tail);
+
+ /* Populate b_inner_loop_body. */
+ /* "result += a[i] * b[j];" */
+ gcc_jit_block_add_assignment_op (
+ b_inner_loop_body, NULL,
+ result,
+ GCC_JIT_BINARY_OP_PLUS,
+ gcc_jit_context_new_binary_op (
+ ctxt, NULL,
+ GCC_JIT_BINARY_OP_MULT,
+ val_type,
+ gcc_jit_lvalue_as_rvalue (
+ gcc_jit_context_new_array_access(
+ ctxt, NULL,
+ gcc_jit_param_as_rvalue (param_a),
+ gcc_jit_lvalue_as_rvalue (i))),
+ gcc_jit_lvalue_as_rvalue (
+ gcc_jit_context_new_array_access(
+ ctxt, NULL,
+ gcc_jit_param_as_rvalue (param_b),
+ gcc_jit_lvalue_as_rvalue (j)))));
+ /* "j++" */
+ gcc_jit_block_add_assignment_op (
+ b_inner_loop_body, NULL,
+ j,
+ GCC_JIT_BINARY_OP_PLUS,
+ gcc_jit_context_one (ctxt, int_type));
+
+ gcc_jit_block_end_with_jump (b_inner_loop_body, NULL, b_inner_loop_cond);
+
+ /* Populate b_outer_loop_tail. */
+ /* "i++" */
+ gcc_jit_block_add_assignment_op (
+ b_outer_loop_tail, NULL,
+ i,
+ GCC_JIT_BINARY_OP_PLUS,
+ gcc_jit_context_one (ctxt, int_type));
+ gcc_jit_block_end_with_jump (b_outer_loop_tail, NULL, b_outer_loop_cond);
+
+ /* Populate b_exit. */
+ /* "return result;" */
+ gcc_jit_block_end_with_return (
+ b_exit,
+ NULL,
+ gcc_jit_lvalue_as_rvalue (result));
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ typedef double (*test_nested_loops_fn_type) (int n, double *a, double *b);
+ CHECK_NON_NULL (result);
+
+ test_nested_loops_fn_type test_nested_loops =
+ (test_nested_loops_fn_type)gcc_jit_result_get_code (result,
+ "test_nested_loops");
+ CHECK_NON_NULL (test_nested_loops);
+ double test_a[] = {1., 2., 3., 4., 5., 6., 7., 8., 9., 10.};
+ double test_b[] = {5., 6., 7., 8., 9., 10., 1., 2., 3., 4.};
+ double val = test_nested_loops (10, test_a, test_b);
+ note ("test_nested_loops returned: %f", val);
+ CHECK_VALUE (val, 3025.0);
+}
--- /dev/null
+/* Test of C++ API. */
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit++.h"
+
+#include <sstream>
+
+#include "harness.h"
+
+struct quadratic
+{
+ double a;
+ double b;
+ double c;
+ double discriminant;
+};
+
+/* As per test-quadratic.cc, let's try to inject the equivalent of:
+
+ extern double sqrt (double);
+
+ void
+ calc_discriminant (struct quadratic *q)
+ {
+ // (b^2 - 4ac)
+ q->discriminant = (q->b * q->b) - (4 * q->a * q->c);
+ }
+
+ int
+ test_quadratic (double a, double b, double c, double *r1, double *r2)
+ {
+ struct quadratic q;
+ q.a = a;
+ q.b = b;
+ q.c = c;
+ calc_discriminant (&q);
+ if (q.discriminant > 0)
+ {
+ double s = sqrt (q.discriminant);
+ *r1 = (-b + s) / (2 * a);
+ *r2 = (-b - s) / (2 * a);
+ return 2;
+ }
+ else if (q.discriminant == 0)
+ {
+ *r1 = -b / (2 * a);
+ return 1;
+ }
+ else return 0;
+ }
+
+ However, we'll use operator overloading for maxium brevity, at the
+ risk of perhaps being too "magical".
+*/
+
+/****************************************************************************
+ Test case
+ ****************************************************************************/
+
+struct quadratic_test
+{
+ gccjit::context ctxt;
+
+ /* "double" and "(double *)". */
+ gccjit::type numeric_type;
+ gccjit::type numeric_type_ptr;
+
+ /* The value (double)0. */
+ gccjit::rvalue zero;
+
+ gccjit::type int_type;
+ gccjit::type void_type;
+
+ /* "struct quadratic" */
+ gccjit::type quadratic;
+ gccjit::field a;
+ gccjit::field b;
+ gccjit::field c;
+ gccjit::field discriminant;
+
+ /* "(struct quadratic *)" */
+ gccjit::type quadratic_ptr;
+
+ gccjit::function calc_discriminant;
+
+ gccjit::function sqrt;
+
+};
+
+static void
+make_types (quadratic_test &testcase)
+{
+ testcase.numeric_type = testcase.ctxt.get_type (GCC_JIT_TYPE_DOUBLE);
+ testcase.numeric_type_ptr = testcase.numeric_type.get_pointer ();
+ testcase.zero = testcase.ctxt.zero (testcase.numeric_type);
+
+ testcase.int_type = testcase.ctxt.get_int_type <int> ();
+ testcase.void_type = testcase.ctxt.get_type (GCC_JIT_TYPE_VOID);
+
+ testcase.a = testcase.ctxt.new_field (testcase.numeric_type, "a");
+ testcase.b = testcase.ctxt.new_field (testcase.numeric_type, "b");
+ testcase.c = testcase.ctxt.new_field (testcase.numeric_type, "c");
+ testcase.discriminant =
+ testcase.ctxt.new_field (testcase.numeric_type, "discriminant");
+ CHECK_STRING_VALUE (testcase.discriminant.get_debug_string ().c_str (),
+ "discriminant");
+ std::vector<gccjit::field> fields (4);
+ fields[0] = testcase.a;
+ fields[1] = testcase.b;
+ fields[2] = testcase.c;
+ fields[3] = testcase.discriminant;
+ testcase.quadratic =
+ testcase.ctxt.new_struct_type (
+ "quadratic",
+ fields);
+ testcase.quadratic_ptr = testcase.quadratic.get_pointer ();
+}
+
+static void
+make_sqrt (quadratic_test &testcase)
+{
+ std::vector<gccjit::param> params (1);
+ params[0] =
+ testcase.ctxt.new_param (testcase.numeric_type, "x");
+ testcase.sqrt =
+ testcase.ctxt.new_function (GCC_JIT_FUNCTION_IMPORTED,
+ testcase.numeric_type,
+ "sqrt",
+ params,
+ 0);
+}
+
+static void
+make_calc_discriminant (quadratic_test &testcase)
+{
+ /* Build "calc_discriminant". */
+ gccjit::param param_q =
+ testcase.ctxt.new_param (testcase.quadratic_ptr, "q");
+ std::vector <gccjit::param> params (1);
+ params[0] = param_q;
+ testcase.calc_discriminant =
+ testcase.ctxt.new_function (GCC_JIT_FUNCTION_EXPORTED,
+ testcase.void_type,
+ "calc_discriminant",
+ params,
+ 0);
+ gccjit::block block = testcase.calc_discriminant.new_block ();
+ block.add_comment ("(b^2 - 4ac)");
+
+ gccjit::rvalue q_a = param_q.dereference_field (testcase.a);
+ gccjit::rvalue q_b = param_q.dereference_field (testcase.b);
+ gccjit::rvalue q_c = param_q.dereference_field (testcase.c);
+
+ gccjit::rvalue four =
+ testcase.ctxt.new_rvalue (testcase.numeric_type, 4);
+
+ block.add_assignment (
+ /* q->discriminant =... */
+ param_q.dereference_field (testcase.discriminant),
+ /* (q->b * q->b) - (4 * q->a * q->c) */
+ (q_b * q_b) - (four * q_a * q_c));
+ block.end_with_return ();
+}
+
+static void
+make_test_quadratic (quadratic_test &testcase)
+{
+ gccjit::param a = testcase.ctxt.new_param (testcase.numeric_type, "a");
+ gccjit::param b = testcase.ctxt.new_param (testcase.numeric_type, "b");
+ gccjit::param c = testcase.ctxt.new_param (testcase.numeric_type, "c");
+ gccjit::param r1 =
+ testcase.ctxt.new_param (testcase.numeric_type_ptr, "r1");
+ gccjit::param r2 =
+ testcase.ctxt.new_param (testcase.numeric_type_ptr, "r2");
+
+ std::vector<gccjit::param> params (5);
+ params[0] = a;
+ params[1] = b;
+ params[2] = c;
+ params[3] = r1;
+ params[4] = r2;
+
+ gccjit::function test_quadratic =
+ testcase.ctxt.new_function (GCC_JIT_FUNCTION_EXPORTED,
+ testcase.int_type,
+ "test_quadratic",
+ params,
+ 0);
+
+ /* struct quadratic q; */
+ gccjit::lvalue q = test_quadratic.new_local (testcase.quadratic, "q");
+
+ gccjit::block initial = test_quadratic.new_block ("initial");
+ gccjit::block on_positive_discriminant
+ = test_quadratic.new_block ("positive_discriminant");
+ gccjit::block on_nonpositive_discriminant
+ = test_quadratic.new_block ("nonpositive_discriminant");
+ gccjit::block on_zero_discriminant
+ = test_quadratic.new_block ("zero_discriminant");
+ gccjit::block on_negative_discriminant
+ = test_quadratic.new_block ("negative_discriminant");
+
+ CHECK_STRING_VALUE (on_zero_discriminant.get_debug_string ().c_str (),
+ "zero_discriminant");
+
+ /* q.a = a; */
+ initial.add_assignment (q.access_field (testcase.a), a);
+ /* q.b = b; */
+ initial.add_assignment (q.access_field (testcase.b), b);
+ /* q.c = c; */
+ initial.add_assignment (q.access_field (testcase.c), c);
+ /* calc_discriminant (&q); */
+ gccjit::rvalue address_of_q = q.get_address ();
+ initial.add_eval (testcase.calc_discriminant (address_of_q));
+
+ initial.add_comment ("if (q.discriminant > 0)");
+ initial.end_with_conditional (
+ q.access_field (testcase.discriminant) > testcase.zero,
+ on_positive_discriminant,
+ on_nonpositive_discriminant);
+
+ /* Block: "on_positive_discriminant" */
+ /* double s = sqrt (q.discriminant); */
+ gccjit::lvalue s = test_quadratic.new_local (testcase.numeric_type, "s");
+ gccjit::rvalue discriminant_of_q = q.access_field (testcase.discriminant);
+ on_positive_discriminant.add_assignment (s, testcase.sqrt (discriminant_of_q));
+
+ gccjit::rvalue minus_b = -b;
+ gccjit::rvalue two =
+ testcase.ctxt.new_rvalue (testcase.numeric_type, 2);
+ gccjit::rvalue two_a = two * a;
+ CHECK_STRING_VALUE (two_a.get_debug_string ().c_str (),
+ "(double)2 * a");
+
+ on_positive_discriminant.add_comment ("*r1 = (-b + s) / (2 * a);");
+ on_positive_discriminant.add_assignment (*r1, (minus_b + s) / two_a);
+
+ on_positive_discriminant.add_comment ("*r2 = (-b - s) / (2 * a)");
+ on_positive_discriminant.add_assignment (*r2, (minus_b - s) / two_a);
+
+ /* "return 2;" */
+ on_positive_discriminant.end_with_return (
+ testcase.ctxt.new_rvalue (testcase.int_type, 2));
+
+ /* Block: "on_nonpositive_discriminant" */
+ /* "else if (q.discriminant == 0)" */
+ on_nonpositive_discriminant.add_comment ("else if (q.discriminant == 0)");
+ on_nonpositive_discriminant.end_with_conditional (
+ q.access_field (testcase.discriminant) == testcase.zero,
+ on_zero_discriminant,
+ on_negative_discriminant);
+
+ /* Block: "on_zero_discriminant" */
+ /* if (q.discriminant == 0) */
+ on_zero_discriminant.add_comment ("*r1 = -b / (2 * a);");
+ on_zero_discriminant.add_assignment (*r1, minus_b / two_a);
+
+ /* "return 1;" */
+ on_zero_discriminant.end_with_return (testcase.int_type.one ());
+
+ /* Block: "on_negative_discriminant" */
+ /* else return 0; */
+ on_negative_discriminant.end_with_return (testcase.int_type.zero ());
+
+ /* Verify that output stream operator << works. */
+ std::ostringstream os;
+ os << "streamed output: " << address_of_q;
+ CHECK_STRING_VALUE (os.str ().c_str (), "streamed output: &q");
+}
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ struct quadratic_test testcase;
+ memset (&testcase, 0, sizeof (testcase));
+ testcase.ctxt = ctxt;
+ make_types (testcase);
+ make_sqrt (testcase);
+ make_calc_discriminant (testcase);
+ make_test_quadratic (testcase);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ typedef int (*fn_type) (double a, double b, double c,
+ double *r1, double *r2);
+
+ CHECK_NON_NULL (result);
+
+ fn_type test_quadratic =
+ (fn_type)gcc_jit_result_get_code (result, "test_quadratic");
+ CHECK_NON_NULL (test_quadratic);
+
+ /* Verify that the code correctly solves quadratic equations. */
+ double r1, r2;
+
+ /* This one has two solutions: */
+ CHECK_VALUE (test_quadratic (1, 3, -4, &r1, &r2), 2);
+ CHECK_VALUE (r1, 1);
+ CHECK_VALUE (r2, -4);
+
+ /* This one has one solution: */
+ CHECK_VALUE (test_quadratic (4, 4, 1, &r1, &r2), 1);
+ CHECK_VALUE (r1, -0.5);
+
+ /* This one has no real solutions: */
+ CHECK_VALUE (test_quadratic (4, 1, 1, &r1, &r2), 0);
+}
--- /dev/null
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+struct quadratic
+{
+ double a;
+ double b;
+ double c;
+ double discriminant;
+};
+
+/* Let's try to inject the equivalent of:
+
+ extern double sqrt (double);
+
+ static void
+ calc_discriminant (struct quadratic *q)
+ {
+ // (b^2 - 4ac)
+ q->discriminant = (q->b * q->b) - (4 * q->a * q->c);
+ }
+
+ int
+ test_quadratic (double a, double b, double c, double *r1, double *r2)
+ {
+ struct quadratic q;
+ q.a = a;
+ q.b = b;
+ q.c = c;
+ calc_discriminant (&q);
+ if (q.discriminant > 0)
+ {
+ double s = sqrt (q.discriminant);
+ *r1 = (-b + s) / (2 * a);
+ *r2 = (-b - s) / (2 * a);
+ return 2;
+ }
+ else if (q.discriminant == 0)
+ {
+ *r1 = -b / (2 * a);
+ return 1;
+ }
+ else return 0;
+ }
+*/
+
+struct quadratic_test
+{
+ gcc_jit_context *ctxt;
+
+ /* "double" and "(double *)". */
+ gcc_jit_type *numeric_type;
+ gcc_jit_type *numeric_type_ptr;
+
+ /* The value (double)0. */
+ gcc_jit_rvalue *zero;
+
+ gcc_jit_type *int_type;
+ gcc_jit_type *void_type;
+
+ /* "struct quadratic" */
+ gcc_jit_type *quadratic;
+ gcc_jit_field *a;
+ gcc_jit_field *b;
+ gcc_jit_field *c;
+ gcc_jit_field *discriminant;
+
+ /* "(struct quadratic *)" */
+ gcc_jit_type *quadratic_ptr;
+
+ gcc_jit_function *calc_discriminant;
+
+ gcc_jit_function *sqrt;
+
+};
+
+static void
+make_types (struct quadratic_test *testcase)
+{
+ testcase->numeric_type =
+ gcc_jit_context_get_type (testcase->ctxt, GCC_JIT_TYPE_DOUBLE);
+ testcase->numeric_type_ptr =
+ gcc_jit_type_get_pointer (testcase->numeric_type);
+ testcase->zero =
+ gcc_jit_context_zero (testcase->ctxt, testcase->numeric_type);
+
+ testcase->int_type =
+ gcc_jit_context_get_type (testcase->ctxt, GCC_JIT_TYPE_INT);
+
+ testcase->void_type =
+ gcc_jit_context_get_type (testcase->ctxt, GCC_JIT_TYPE_VOID);
+
+ testcase->a =
+ gcc_jit_context_new_field (testcase->ctxt,
+ NULL,
+ testcase->numeric_type,
+ "a");
+ testcase->b =
+ gcc_jit_context_new_field (testcase->ctxt,
+ NULL,
+ testcase->numeric_type,
+ "b");
+ testcase->c =
+ gcc_jit_context_new_field (testcase->ctxt,
+ NULL,
+ testcase->numeric_type,
+ "c");
+ testcase->discriminant =
+ gcc_jit_context_new_field (testcase->ctxt,
+ NULL,
+ testcase->numeric_type,
+ "discriminant");
+ gcc_jit_field *fields[] = {testcase->a,
+ testcase->b,
+ testcase->c,
+ testcase->discriminant};
+ testcase->quadratic =
+ gcc_jit_struct_as_type (
+ gcc_jit_context_new_struct_type (testcase->ctxt, NULL,
+ "quadratic", 4, fields));
+ testcase->quadratic_ptr = gcc_jit_type_get_pointer (testcase->quadratic);
+}
+
+static void
+make_sqrt (struct quadratic_test *testcase)
+{
+ gcc_jit_param *param_x =
+ gcc_jit_context_new_param (testcase->ctxt, NULL,
+ testcase->numeric_type, "x");
+ testcase->sqrt =
+ gcc_jit_context_new_function (testcase->ctxt, NULL,
+ GCC_JIT_FUNCTION_IMPORTED,
+ testcase->numeric_type,
+ "sqrt",
+ 1, ¶m_x,
+ 0);
+}
+
+static void
+make_calc_discriminant (struct quadratic_test *testcase)
+{
+ /* Build "calc_discriminant". */
+ gcc_jit_param *param_q =
+ gcc_jit_context_new_param (testcase->ctxt, NULL,
+ testcase->quadratic_ptr, "q");
+ testcase->calc_discriminant =
+ gcc_jit_context_new_function (testcase->ctxt, NULL,
+ GCC_JIT_FUNCTION_INTERNAL,
+ testcase->void_type,
+ "calc_discriminant",
+ 1, ¶m_q,
+ 0);
+ gcc_jit_block *blk =
+ gcc_jit_function_new_block (testcase->calc_discriminant, NULL);
+ gcc_jit_block_add_comment (
+ blk, NULL,
+ "(b^2 - 4ac)");
+
+ gcc_jit_rvalue *q_a =
+ gcc_jit_lvalue_as_rvalue (
+ gcc_jit_rvalue_dereference_field (
+ gcc_jit_param_as_rvalue (param_q),
+ NULL, testcase->a));
+ gcc_jit_rvalue *q_b =
+ gcc_jit_lvalue_as_rvalue (
+ gcc_jit_rvalue_dereference_field (
+ gcc_jit_param_as_rvalue (param_q),
+ NULL, testcase->b));
+ gcc_jit_rvalue *q_c =
+ gcc_jit_lvalue_as_rvalue (
+ gcc_jit_rvalue_dereference_field (
+ gcc_jit_param_as_rvalue (param_q),
+ NULL, testcase->c));
+
+ gcc_jit_block_add_assignment (
+ blk, NULL,
+
+ /* q->discriminant =... */
+ gcc_jit_rvalue_dereference_field (
+ gcc_jit_param_as_rvalue (param_q),
+ NULL,
+ testcase->discriminant),
+
+ /* (q->b * q->b) - (4 * q->a * q->c) */
+ gcc_jit_context_new_binary_op (
+ testcase->ctxt, NULL,
+ GCC_JIT_BINARY_OP_MINUS,
+ testcase->numeric_type,
+
+ /* (q->b * q->b) */
+ gcc_jit_context_new_binary_op (
+ testcase->ctxt, NULL,
+ GCC_JIT_BINARY_OP_MULT,
+ testcase->numeric_type,
+ q_b, q_b),
+
+ /* (4 * (q->a * q->c)) */
+ gcc_jit_context_new_binary_op (
+ testcase->ctxt, NULL,
+ GCC_JIT_BINARY_OP_MULT,
+ testcase->numeric_type,
+ /* 4.0 */
+ gcc_jit_context_new_rvalue_from_int (
+ testcase->ctxt,
+ testcase->numeric_type,
+ 4),
+ /* (q->a * q->c) */
+ gcc_jit_context_new_binary_op (
+ testcase->ctxt, NULL,
+ GCC_JIT_BINARY_OP_MULT,
+ testcase->numeric_type,
+ q_a, q_c)))); /* end of gcc_jit_function_add_assignment call. */
+
+ gcc_jit_block_end_with_void_return (blk, NULL);
+}
+
+static void
+make_test_quadratic (struct quadratic_test *testcase)
+{
+ gcc_jit_param *a =
+ gcc_jit_context_new_param (testcase->ctxt, NULL,
+ testcase->numeric_type, "a");
+ gcc_jit_param *b =
+ gcc_jit_context_new_param (testcase->ctxt, NULL,
+ testcase->numeric_type, "b");
+ gcc_jit_param *c =
+ gcc_jit_context_new_param (testcase->ctxt, NULL,
+ testcase->numeric_type, "c");
+ gcc_jit_param *r1 =
+ gcc_jit_context_new_param (testcase->ctxt, NULL,
+ testcase->numeric_type_ptr, "r1");
+ gcc_jit_param *r2 =
+ gcc_jit_context_new_param (testcase->ctxt, NULL,
+ testcase->numeric_type_ptr, "r2");
+ gcc_jit_param *params[] = {a, b, c, r1, r2};
+ gcc_jit_function *test_quadratic =
+ gcc_jit_context_new_function (testcase->ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ testcase->int_type,
+ "test_quadratic",
+ 5, params,
+ 0);
+ /* struct quadratic q; */
+ gcc_jit_lvalue *q =
+ gcc_jit_function_new_local (
+ test_quadratic, NULL,
+ testcase->quadratic,
+ "q");
+
+ gcc_jit_block *initial =
+ gcc_jit_function_new_block (test_quadratic,
+ "initial");
+ gcc_jit_block *on_positive_discriminant
+ = gcc_jit_function_new_block (test_quadratic,
+ "positive_discriminant");
+
+ gcc_jit_block *on_nonpositive_discriminant
+ = gcc_jit_function_new_block (test_quadratic,
+ "nonpositive_discriminant");
+
+ gcc_jit_block *on_zero_discriminant
+ = gcc_jit_function_new_block (test_quadratic,
+ "zero_discriminant");
+
+ gcc_jit_block *on_negative_discriminant
+ = gcc_jit_function_new_block (test_quadratic,
+ "negative_discriminant");
+
+ /* Initial block. */
+ /* q.a = a; */
+ gcc_jit_block_add_assignment (
+ initial, NULL,
+ gcc_jit_lvalue_access_field (q, NULL, testcase->a),
+ gcc_jit_param_as_rvalue (a));
+ /* q.b = b; */
+ gcc_jit_block_add_assignment (
+ initial, NULL,
+ gcc_jit_lvalue_access_field (q, NULL, testcase->b),
+ gcc_jit_param_as_rvalue (b));
+ /* q.c = c; */
+ gcc_jit_block_add_assignment (
+ initial, NULL,
+ gcc_jit_lvalue_access_field (q, NULL, testcase->c),
+ gcc_jit_param_as_rvalue (c));
+ /* calc_discriminant (&q); */
+ gcc_jit_rvalue *address_of_q = gcc_jit_lvalue_get_address (q, NULL);
+ gcc_jit_block_add_eval (
+ initial, NULL,
+ gcc_jit_context_new_call (
+ testcase->ctxt, NULL,
+ testcase->calc_discriminant,
+ 1, &address_of_q));
+
+ gcc_jit_block_add_comment (
+ initial, NULL,
+ "if (q.discriminant > 0)");
+ gcc_jit_block_end_with_conditional (
+ initial, NULL,
+ gcc_jit_context_new_comparison (
+ testcase->ctxt, NULL,
+ GCC_JIT_COMPARISON_GT,
+ gcc_jit_rvalue_access_field (
+ gcc_jit_lvalue_as_rvalue (q),
+ NULL,
+ testcase->discriminant),
+ testcase->zero),
+ on_positive_discriminant,
+ on_nonpositive_discriminant);
+
+ /* Block: "on_positive_discriminant" */
+ /* double s = sqrt (q.discriminant); */
+ gcc_jit_lvalue *s = gcc_jit_function_new_local (
+ test_quadratic, NULL,
+ testcase->numeric_type,
+ "s");
+ gcc_jit_rvalue *discriminant_of_q =
+ gcc_jit_rvalue_access_field (gcc_jit_lvalue_as_rvalue (q),
+ NULL,
+ testcase->discriminant);
+ gcc_jit_block_add_assignment (
+ on_positive_discriminant, NULL,
+ s,
+ gcc_jit_context_new_call (
+ testcase->ctxt, NULL,
+ testcase->sqrt,
+ 1, &discriminant_of_q));
+
+ gcc_jit_rvalue *minus_b =
+ gcc_jit_context_new_unary_op (
+ testcase->ctxt, NULL,
+ GCC_JIT_UNARY_OP_MINUS,
+ testcase->numeric_type,
+ gcc_jit_param_as_rvalue (b));
+ gcc_jit_rvalue *two_a =
+ gcc_jit_context_new_binary_op (
+ testcase->ctxt, NULL,
+ GCC_JIT_BINARY_OP_MULT,
+ testcase->numeric_type,
+ gcc_jit_context_new_rvalue_from_int (
+ testcase->ctxt,
+ testcase->numeric_type,
+ 2),
+ gcc_jit_param_as_rvalue (a));
+
+ gcc_jit_block_add_comment (
+ on_positive_discriminant, NULL,
+ "*r1 = (-b + s) / (2 * a);");
+ gcc_jit_block_add_assignment (
+ on_positive_discriminant, NULL,
+
+ /* "*r1 = ..." */
+ gcc_jit_rvalue_dereference (
+ gcc_jit_param_as_rvalue (r1), NULL),
+
+ /* (-b + s) / (2 * a) */
+ gcc_jit_context_new_binary_op (
+ testcase->ctxt, NULL,
+ GCC_JIT_BINARY_OP_DIVIDE,
+ testcase->numeric_type,
+ gcc_jit_context_new_binary_op (
+ testcase->ctxt, NULL,
+ GCC_JIT_BINARY_OP_PLUS,
+ testcase->numeric_type,
+ minus_b,
+ gcc_jit_lvalue_as_rvalue (s)),
+ two_a));
+
+ gcc_jit_block_add_comment (
+ on_positive_discriminant, NULL,
+ "*r2 = (-b - s) / (2 * a)");
+ gcc_jit_block_add_assignment (
+ on_positive_discriminant, NULL,
+
+ /* "*r2 = ..." */
+ gcc_jit_rvalue_dereference (
+ gcc_jit_param_as_rvalue (r2), NULL),
+
+ /* (-b - s) / (2 * a) */
+ gcc_jit_context_new_binary_op (
+ testcase->ctxt, NULL,
+ GCC_JIT_BINARY_OP_DIVIDE,
+ testcase->numeric_type,
+ gcc_jit_context_new_binary_op (
+ testcase->ctxt, NULL,
+ GCC_JIT_BINARY_OP_MINUS,
+ testcase->numeric_type,
+ minus_b,
+ gcc_jit_lvalue_as_rvalue (s)),
+ two_a));
+
+ /* "return 2;" */
+ gcc_jit_block_end_with_return (
+ on_positive_discriminant, NULL,
+ gcc_jit_context_new_rvalue_from_int (
+ testcase->ctxt,
+ testcase->int_type,
+ 2));
+
+ /* Block: "on_nonpositive_discriminant" */
+ gcc_jit_block_add_comment (
+ on_nonpositive_discriminant, NULL,
+ "else if (q.discriminant == 0)");
+ gcc_jit_block_end_with_conditional (
+ on_nonpositive_discriminant, NULL,
+ gcc_jit_context_new_comparison (
+ testcase->ctxt, NULL,
+ GCC_JIT_COMPARISON_EQ,
+ gcc_jit_rvalue_access_field (
+ gcc_jit_lvalue_as_rvalue (q),
+ NULL,
+ testcase->discriminant),
+ testcase->zero),
+ on_zero_discriminant,
+ on_negative_discriminant);
+
+ /* Block: "on_zero_discriminant" */
+ gcc_jit_block_add_comment (
+ on_zero_discriminant, NULL,
+ "*r1 = -b / (2 * a);");
+ gcc_jit_block_add_assignment (
+ on_zero_discriminant, NULL,
+
+ /* "*r1 = ..." */
+ gcc_jit_rvalue_dereference (
+ gcc_jit_param_as_rvalue (r1), NULL),
+
+ /* -b / (2 * a) */
+ gcc_jit_context_new_binary_op (
+ testcase->ctxt, NULL,
+ GCC_JIT_BINARY_OP_DIVIDE,
+ testcase->numeric_type,
+ minus_b,
+ two_a));
+ gcc_jit_block_end_with_return (
+ /* "return 1;" */
+ on_zero_discriminant, NULL,
+ gcc_jit_context_one (testcase->ctxt, testcase->int_type));
+
+ /* Block: "on_negative_discriminant" */
+ gcc_jit_block_end_with_return (
+ /* "else return 0;" */
+ on_negative_discriminant, NULL,
+ gcc_jit_context_zero (testcase->ctxt, testcase->int_type));
+}
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ struct quadratic_test testcase;
+ memset (&testcase, 0, sizeof (testcase));
+ testcase.ctxt = ctxt;
+ make_types (&testcase);
+ make_sqrt (&testcase);
+ make_calc_discriminant (&testcase);
+ make_test_quadratic (&testcase);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ typedef int (*fn_type) (double a, double b, double c,
+ double *r1, double *r2);
+
+ CHECK_NON_NULL (result);
+
+ fn_type test_quadratic =
+ (fn_type)gcc_jit_result_get_code (result, "test_quadratic");
+ CHECK_NON_NULL (test_quadratic);
+
+ /* Verify that the code correctly solves quadratic equations. */
+ double r1, r2;
+
+ /* This one has two solutions: */
+ CHECK_VALUE (test_quadratic (1, 3, -4, &r1, &r2), 2);
+ CHECK_VALUE (r1, 1);
+ CHECK_VALUE (r2, -4);
+
+ /* This one has one solution: */
+ CHECK_VALUE (test_quadratic (4, 4, 1, &r1, &r2), 1);
+ CHECK_VALUE (r1, -0.5);
+
+ /* This one has no real solutions: */
+ CHECK_VALUE (test_quadratic (4, 1, 1, &r1, &r2), 0);
+}
--- /dev/null
+/* Test of C++ API. */
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit++.h"
+
+#include <sstream>
+
+#include "harness.h"
+
+struct quadratic
+{
+ double a;
+ double b;
+ double c;
+ double discriminant;
+};
+
+/* As per test-quadratic.c, let's try to inject the equivalent of:
+
+ extern double sqrt (double);
+
+ void
+ calc_discriminant (struct quadratic *q)
+ {
+ // (b^2 - 4ac)
+ q->discriminant = (q->b * q->b) - (4 * q->a * q->c);
+ }
+
+ int
+ test_quadratic (double a, double b, double c, double *r1, double *r2)
+ {
+ struct quadratic q;
+ q.a = a;
+ q.b = b;
+ q.c = c;
+ calc_discriminant (&q);
+ if (q.discriminant > 0)
+ {
+ double s = sqrt (q.discriminant);
+ *r1 = (-b + s) / (2 * a);
+ *r2 = (-b - s) / (2 * a);
+ return 2;
+ }
+ else if (q.discriminant == 0)
+ {
+ *r1 = -b / (2 * a);
+ return 1;
+ }
+ else return 0;
+ }
+
+ However, we'll use the C++ bindings.
+*/
+
+/****************************************************************************
+ Test case
+ ****************************************************************************/
+
+struct quadratic_test
+{
+ gccjit::context ctxt;
+
+ /* "double" and "(double *)". */
+ gccjit::type numeric_type;
+ gccjit::type numeric_type_ptr;
+
+ /* The value (double)0. */
+ gccjit::rvalue zero;
+
+ gccjit::type int_type;
+ gccjit::type void_type;
+
+ /* "struct quadratic" */
+ gccjit::type quadratic;
+ gccjit::field a;
+ gccjit::field b;
+ gccjit::field c;
+ gccjit::field discriminant;
+
+ /* "(struct quadratic *)" */
+ gccjit::type quadratic_ptr;
+
+ gccjit::function calc_discriminant;
+
+ gccjit::function sqrt;
+
+};
+
+static void
+make_types (quadratic_test &testcase)
+{
+ testcase.numeric_type = testcase.ctxt.get_type (GCC_JIT_TYPE_DOUBLE);
+ testcase.numeric_type_ptr = testcase.numeric_type.get_pointer ();
+ testcase.zero = testcase.ctxt.zero (testcase.numeric_type);
+
+ testcase.int_type = testcase.ctxt.get_int_type <int> ();
+ testcase.void_type = testcase.ctxt.get_type (GCC_JIT_TYPE_VOID);
+
+ testcase.a = testcase.ctxt.new_field (testcase.numeric_type, "a");
+ testcase.b = testcase.ctxt.new_field (testcase.numeric_type, "b");
+ testcase.c = testcase.ctxt.new_field (testcase.numeric_type, "c");
+ testcase.discriminant =
+ testcase.ctxt.new_field (testcase.numeric_type, "discriminant");
+ CHECK_STRING_VALUE (testcase.discriminant.get_debug_string ().c_str (),
+ "discriminant");
+ std::vector<gccjit::field> fields (4);
+ fields[0] = testcase.a;
+ fields[1] = testcase.b;
+ fields[2] = testcase.c;
+ fields[3] = testcase.discriminant;
+ testcase.quadratic =
+ testcase.ctxt.new_struct_type (
+ "quadratic",
+ fields);
+ testcase.quadratic_ptr = testcase.quadratic.get_pointer ();
+}
+
+static void
+make_sqrt (quadratic_test &testcase)
+{
+ std::vector<gccjit::param> params (1);
+ params[0] =
+ testcase.ctxt.new_param (testcase.numeric_type, "x");
+ testcase.sqrt =
+ testcase.ctxt.new_function (GCC_JIT_FUNCTION_IMPORTED,
+ testcase.numeric_type,
+ "sqrt",
+ params,
+ 0);
+}
+
+static void
+make_calc_discriminant (quadratic_test &testcase)
+{
+ /* Build "calc_discriminant". */
+ gccjit::param param_q =
+ testcase.ctxt.new_param (testcase.quadratic_ptr, "q");
+ std::vector <gccjit::param> params (1);
+ params[0] = param_q;
+ testcase.calc_discriminant =
+ testcase.ctxt.new_function (GCC_JIT_FUNCTION_EXPORTED,
+ testcase.void_type,
+ "calc_discriminant",
+ params,
+ 0);
+ gccjit::block block = testcase.calc_discriminant.new_block ();
+ block.add_comment ("(b^2 - 4ac)");
+
+ gccjit::rvalue q_a = param_q.dereference_field (testcase.a);
+ gccjit::rvalue q_b = param_q.dereference_field (testcase.b);
+ gccjit::rvalue q_c = param_q.dereference_field (testcase.c);
+
+ block.add_assignment (
+ /* q->discriminant =... */
+ param_q.dereference_field (testcase.discriminant),
+ /* (q->b * q->b) - (4 * q->a * q->c) */
+ testcase.ctxt.new_minus (
+ testcase.numeric_type,
+
+ /* (q->b * q->b) */
+ testcase.ctxt.new_mult (
+ testcase.numeric_type,
+ q_b, q_b),
+
+ /* (4 * (q->a * q->c)) */
+ testcase.ctxt.new_mult (
+ testcase.numeric_type,
+ /* 4.0 */
+ testcase.ctxt.new_rvalue (
+ testcase.numeric_type,
+ 4),
+ /* (q->a * q->c) */
+ testcase.ctxt.new_mult (
+ testcase.numeric_type,
+ q_a, q_c)))); /* end of add_assignment call. */
+ block.end_with_return ();
+}
+
+static void
+make_test_quadratic (quadratic_test &testcase)
+{
+ gccjit::param a = testcase.ctxt.new_param (testcase.numeric_type, "a");
+ gccjit::param b = testcase.ctxt.new_param (testcase.numeric_type, "b");
+ gccjit::param c = testcase.ctxt.new_param (testcase.numeric_type, "c");
+ gccjit::param r1 =
+ testcase.ctxt.new_param (testcase.numeric_type_ptr, "r1");
+ gccjit::param r2 =
+ testcase.ctxt.new_param (testcase.numeric_type_ptr, "r2");
+
+ std::vector<gccjit::param> params (5);
+ params[0] = a;
+ params[1] = b;
+ params[2] = c;
+ params[3] = r1;
+ params[4] = r2;
+
+ gccjit::function test_quadratic =
+ testcase.ctxt.new_function (GCC_JIT_FUNCTION_EXPORTED,
+ testcase.int_type,
+ "test_quadratic",
+ params,
+ 0);
+
+ /* struct quadratic q; */
+ gccjit::lvalue q = test_quadratic.new_local (testcase.quadratic, "q");
+
+ gccjit::block initial = test_quadratic.new_block ("initial");
+ gccjit::block on_positive_discriminant
+ = test_quadratic.new_block ("positive_discriminant");
+ gccjit::block on_nonpositive_discriminant
+ = test_quadratic.new_block ("nonpositive_discriminant");
+ gccjit::block on_zero_discriminant
+ = test_quadratic.new_block ("zero_discriminant");
+ gccjit::block on_negative_discriminant
+ = test_quadratic.new_block ("negative_discriminant");
+
+ CHECK_STRING_VALUE (on_zero_discriminant.get_debug_string ().c_str (),
+ "zero_discriminant");
+
+ /* q.a = a; */
+ initial.add_assignment (q.access_field (testcase.a), a);
+ /* q.b = b; */
+ initial.add_assignment (q.access_field (testcase.b), b);
+ /* q.c = c; */
+ initial.add_assignment (q.access_field (testcase.c), c);
+ /* calc_discriminant (&q); */
+ gccjit::rvalue address_of_q = q.get_address ();
+ initial.add_call (testcase.calc_discriminant, address_of_q);
+
+ initial.add_comment ("if (q.discriminant > 0)");
+ initial.end_with_conditional (
+ testcase.ctxt.new_gt (
+ q.access_field (testcase.discriminant),
+ testcase.zero),
+ on_positive_discriminant,
+ on_nonpositive_discriminant);
+
+ /* Block: "on_positive_discriminant" */
+ /* double s = sqrt (q.discriminant); */
+ gccjit::lvalue s = test_quadratic.new_local (testcase.numeric_type, "s");
+ gccjit::rvalue discriminant_of_q = q.access_field (testcase.discriminant);
+ on_positive_discriminant.add_assignment (
+ s,
+ testcase.ctxt.new_call (testcase.sqrt, discriminant_of_q));
+
+ gccjit::rvalue minus_b =
+ testcase.ctxt.new_minus (
+ testcase.numeric_type,
+ b);
+ gccjit::rvalue two_a =
+ testcase.ctxt.new_mult (
+ testcase.numeric_type,
+ testcase.ctxt.new_rvalue (testcase.numeric_type, 2),
+ a);
+ CHECK_STRING_VALUE (two_a.get_debug_string ().c_str (),
+ "(double)2 * a");
+
+ on_positive_discriminant.add_comment ("*r1 = (-b + s) / (2 * a);");
+ on_positive_discriminant.add_assignment (
+ /* "*r1 = ..." */
+ r1.dereference (),
+
+ /* (-b + s) / (2 * a) */
+ testcase.ctxt.new_divide (
+ testcase.numeric_type,
+ testcase.ctxt.new_plus (
+ testcase.numeric_type,
+ minus_b,
+ s),
+ two_a));
+
+ on_positive_discriminant.add_comment ("*r2 = (-b - s) / (2 * a)");
+ on_positive_discriminant.add_assignment (
+ /* "*r2 = ..." */
+ r2.dereference (),
+
+ /* (-b - s) / (2 * a) */
+ testcase.ctxt.new_divide (
+ testcase.numeric_type,
+ testcase.ctxt.new_minus (
+ testcase.numeric_type,
+ minus_b,
+ s),
+ two_a));
+
+ /* "return 2;" */
+ on_positive_discriminant.end_with_return (
+ testcase.ctxt.new_rvalue (testcase.int_type, 2));
+
+ /* Block: "on_nonpositive_discriminant" */
+ on_nonpositive_discriminant.add_comment ("else if (q.discriminant == 0)");
+ on_nonpositive_discriminant.end_with_conditional (
+ testcase.ctxt.new_eq (
+ q.access_field (testcase.discriminant),
+ testcase.zero),
+ on_zero_discriminant,
+ on_negative_discriminant);
+
+ /* Block: "on_zero_discriminant" */
+ /* if (q.discriminant == 0) */
+ on_zero_discriminant.add_comment ("*r1 = -b / (2 * a);");
+ on_zero_discriminant.add_assignment (
+ /* "*r1 = ..." */
+ r1.dereference (),
+
+ /* -b / (2 * a) */
+ testcase.ctxt.new_divide (
+ testcase.numeric_type,
+ minus_b,
+ two_a));
+
+ /* "return 1;" */
+ on_zero_discriminant.end_with_return (
+ testcase.ctxt.one (testcase.int_type));
+
+ /* Block: "on_negative_discriminant" */
+ /* else return 0; */
+ on_negative_discriminant.end_with_return (
+ testcase.ctxt.zero (testcase.int_type));
+
+ /* Verify that output stream operator << works. */
+ std::ostringstream os;
+ os << "streamed output: " << address_of_q;
+ CHECK_STRING_VALUE (os.str ().c_str (), "streamed output: &q");
+}
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ struct quadratic_test testcase;
+ memset (&testcase, 0, sizeof (testcase));
+ testcase.ctxt = ctxt;
+ make_types (testcase);
+ make_sqrt (testcase);
+ make_calc_discriminant (testcase);
+ make_test_quadratic (testcase);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ typedef int (*fn_type) (double a, double b, double c,
+ double *r1, double *r2);
+
+ CHECK_NON_NULL (result);
+
+ fn_type test_quadratic =
+ (fn_type)gcc_jit_result_get_code (result, "test_quadratic");
+ CHECK_NON_NULL (test_quadratic);
+
+ /* Verify that the code correctly solves quadratic equations. */
+ double r1, r2;
+
+ /* This one has two solutions: */
+ CHECK_VALUE (test_quadratic (1, 3, -4, &r1, &r2), 2);
+ CHECK_VALUE (r1, 1);
+ CHECK_VALUE (r2, -4);
+
+ /* This one has one solution: */
+ CHECK_VALUE (test_quadratic (4, 4, 1, &r1, &r2), 1);
+ CHECK_VALUE (r1, -0.5);
+
+ /* This one has no real solutions: */
+ CHECK_VALUE (test_quadratic (4, 1, 1, &r1, &r2), 0);
+}
--- /dev/null
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+struct bar
+{
+ int x;
+ int y;
+};
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ /* Let's try to inject the equivalent of:
+
+ int
+ test_reading (const struct bar *f)
+ {
+ return f->x * f->y;
+ }
+
+ int
+ test_writing ()
+ {
+ struct bar tmp;
+ tmp.x = 5;
+ tmp.y = 7;
+ return test_reading (&tmp);
+ }
+ */
+ gcc_jit_type *int_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+ gcc_jit_field *x =
+ gcc_jit_context_new_field (ctxt,
+ NULL,
+ int_type,
+ "x");
+ gcc_jit_field *y =
+ gcc_jit_context_new_field (ctxt,
+ NULL,
+ int_type,
+ "y");
+ gcc_jit_field *fields[] = {x, y};
+ gcc_jit_type *struct_type =
+ gcc_jit_struct_as_type (
+ gcc_jit_context_new_struct_type (ctxt, NULL, "bar", 2, fields));
+ gcc_jit_type *const_struct_type = gcc_jit_type_get_const (struct_type);
+ gcc_jit_type *ptr_type = gcc_jit_type_get_pointer (const_struct_type);
+
+ /* Build "test_reading". */
+ gcc_jit_param *param_f =
+ gcc_jit_context_new_param (ctxt, NULL, ptr_type, "f");
+ gcc_jit_function *fn_test_reading =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ int_type,
+ "test_reading",
+ 1, ¶m_f,
+ 0);
+
+ /* return f->x * f->y; */
+ gcc_jit_block *reading_block = gcc_jit_function_new_block (fn_test_reading, NULL);
+ gcc_jit_block_end_with_return (
+ reading_block,
+ NULL,
+ gcc_jit_context_new_binary_op (
+ ctxt, NULL,
+ GCC_JIT_BINARY_OP_MULT,
+ int_type,
+ gcc_jit_lvalue_as_rvalue (
+ gcc_jit_rvalue_dereference_field (
+ gcc_jit_param_as_rvalue (param_f),
+ NULL,
+ x)),
+ gcc_jit_lvalue_as_rvalue (
+ gcc_jit_rvalue_dereference_field (
+ gcc_jit_param_as_rvalue (param_f),
+ NULL,
+ y))));
+
+ /* Build "test_writing". */
+ gcc_jit_function *fn_test_writing =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ int_type,
+ "test_writing",
+ 0, NULL,
+ 0);
+
+ /* struct bar tmp; */
+ gcc_jit_lvalue *local_tmp =
+ gcc_jit_function_new_local (fn_test_writing, NULL,
+ struct_type,
+ "tmp");
+ /* tmp.x = 5; */
+ gcc_jit_block *writing_block = gcc_jit_function_new_block (fn_test_writing, NULL);
+ gcc_jit_block_add_assignment (
+ writing_block, NULL,
+ gcc_jit_lvalue_access_field (local_tmp, NULL, x),
+ gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 5));
+
+ /* tmp.y = 7; */
+ gcc_jit_block_add_assignment (
+ writing_block, NULL,
+ gcc_jit_lvalue_access_field (local_tmp, NULL, y),
+ gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 7));
+
+ /* return test_reading (&tmp); */
+ gcc_jit_rvalue *arg = gcc_jit_lvalue_get_address (local_tmp, NULL);
+ gcc_jit_block_end_with_return (
+ writing_block,
+ NULL,
+ gcc_jit_context_new_call (
+ ctxt, NULL,
+ fn_test_reading,
+ 1, &arg));
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ typedef int (*fn_type) (void);
+ CHECK_NON_NULL (result);
+
+ fn_type test_writing =
+ (fn_type)gcc_jit_result_get_code (result, "test_writing");
+ CHECK_NON_NULL (test_writing);
+
+ /* Verify that the code correctly returns the product of the fields. */
+ CHECK_VALUE (test_writing (), 35);
+}
+
--- /dev/null
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ /* Let's try to inject the equivalent of:
+
+ const char *
+ test_string_literal (void)
+ {
+ return "hello world";
+ }
+ */
+ gcc_jit_type *const_char_ptr_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_CONST_CHAR_PTR);
+
+ /* Build the test_fn. */
+ gcc_jit_function *test_fn =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ const_char_ptr_type,
+ "test_string_literal",
+ 0, NULL,
+ 0);
+ gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
+
+ gcc_jit_block_end_with_return (
+ block, NULL,
+ gcc_jit_context_new_string_literal (ctxt, "hello world"));
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ typedef const char *(*fn_type) (void);
+ CHECK_NON_NULL (result);
+ fn_type test_string_literal =
+ (fn_type)gcc_jit_result_get_code (result, "test_string_literal");
+ CHECK_NON_NULL (test_string_literal);
+
+ /* Call the JIT-generated function. */
+ const char *str = test_string_literal ();
+ CHECK_NON_NULL (str);
+ CHECK_VALUE (strcmp (str, "hello world"), 0);
+}
+
--- /dev/null
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ /*
+ Simple sum-of-squares, to test conditionals and looping
+
+ int loop_test (int n)
+ {
+ int i;
+ int sum = 0;
+ for (i = 0; i < n ; i ++)
+ {
+ sum += i * i;
+ }
+ return sum;
+ */
+ gcc_jit_type *the_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+ gcc_jit_type *return_type = the_type;
+
+ gcc_jit_param *n =
+ gcc_jit_context_new_param (ctxt, NULL, the_type, "n");
+ gcc_jit_param *params[1] = {n};
+ gcc_jit_function *func =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ return_type,
+ "loop_test",
+ 1, params, 0);
+
+ /* Build locals: */
+ gcc_jit_lvalue *i =
+ gcc_jit_function_new_local (func, NULL, the_type, "i");
+ gcc_jit_lvalue *sum =
+ gcc_jit_function_new_local (func, NULL, the_type, "sum");
+
+ gcc_jit_block *initial =
+ gcc_jit_function_new_block (func, "initial");
+ gcc_jit_block *loop_cond =
+ gcc_jit_function_new_block (func, "loop_cond");
+ gcc_jit_block *loop_body =
+ gcc_jit_function_new_block (func, "loop_body");
+ gcc_jit_block *after_loop =
+ gcc_jit_function_new_block (func, "after_loop");
+
+ /* sum = 0; */
+ gcc_jit_block_add_assignment (
+ initial, NULL,
+ sum,
+ gcc_jit_context_new_rvalue_from_int (ctxt, the_type, 0));
+
+ /* i = 0; */
+ gcc_jit_block_add_assignment (
+ initial, NULL,
+ i,
+ gcc_jit_context_new_rvalue_from_int (ctxt, the_type, 0));
+
+ gcc_jit_block_end_with_jump (initial, NULL, loop_cond);
+
+ /* if (i >= n) */
+ gcc_jit_block_end_with_conditional (
+ loop_cond, NULL,
+ gcc_jit_context_new_comparison (
+ ctxt, NULL,
+ GCC_JIT_COMPARISON_GE,
+ gcc_jit_lvalue_as_rvalue (i),
+ gcc_jit_param_as_rvalue (n)),
+ after_loop,
+ loop_body);
+
+ /* sum += i * i */
+ gcc_jit_block_add_assignment (
+ loop_body, NULL,
+ sum,
+ gcc_jit_context_new_binary_op (
+ ctxt, NULL,
+ GCC_JIT_BINARY_OP_PLUS, the_type,
+ gcc_jit_lvalue_as_rvalue (sum),
+ gcc_jit_context_new_binary_op (
+ ctxt, NULL,
+ GCC_JIT_BINARY_OP_MULT, the_type,
+ gcc_jit_lvalue_as_rvalue (i),
+ gcc_jit_lvalue_as_rvalue (i))));
+
+ /* i++ */
+ gcc_jit_block_add_assignment (
+ loop_body, NULL,
+ i,
+ gcc_jit_context_new_binary_op (
+ ctxt, NULL,
+ GCC_JIT_BINARY_OP_PLUS, the_type,
+ gcc_jit_lvalue_as_rvalue (i),
+ gcc_jit_context_new_rvalue_from_int (
+ ctxt,
+ the_type,
+ 1)));
+
+ gcc_jit_block_end_with_jump (loop_body, NULL, loop_cond);
+
+ /* return sum */
+ gcc_jit_block_end_with_return (
+ after_loop,
+ NULL,
+ gcc_jit_lvalue_as_rvalue (sum));
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ typedef int (*loop_test_fn_type) (int);
+ CHECK_NON_NULL (result);
+ loop_test_fn_type loop_test =
+ (loop_test_fn_type)gcc_jit_result_get_code (result, "loop_test");
+ CHECK_NON_NULL (loop_test);
+ int val = loop_test (10);
+ note ("loop_test returned: %d", val);
+ CHECK_VALUE (val, 285);
+}
--- /dev/null
+/* test-threads.c
+
+ As per test-combination.c, construct a test case by combining other test
+ cases, to try to shake out state issues. However each test runs in a
+ separate thread. */
+
+#include <pthread.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+/* dejagnu.h isn't thread-safe; there's a shared "buffer", and the counts
+ of "passed"/"failed" etc are globals.
+
+ We get around this by putting a mutex around pass/fail calls.
+ */
+
+static pthread_mutex_t dg_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+/* By defining MAKE_DEJAGNU_H_THREADSAFE before we include harness.h,
+ harness.h injects macros before including <dejagnu.h> so that the
+ pass/fail functions become "dejagnu_pass"/"dejagnu_fail" etc. */
+
+void dejagnu_pass (const char* fmt, ...);
+void dejagnu_fail (const char* fmt, ...);
+void dejagnu_note (const char* fmt, ...);
+
+/* We now provide our own implementations of "pass"/"fail"/"note", which
+ call the underlying dejagnu implementations, but with a mutex. */
+
+inline void
+pass (const char* fmt, ...)
+{
+ va_list ap;
+ char buffer[512];
+
+ va_start (ap, fmt);
+ vsnprintf (buffer, sizeof (buffer), fmt, ap);
+ va_end (ap);
+
+ pthread_mutex_lock (&dg_mutex);
+ dejagnu_pass (buffer);
+ pthread_mutex_unlock (&dg_mutex);
+}
+
+inline void
+fail (const char* fmt, ...)
+{
+ va_list ap;
+ char buffer[512];
+
+ va_start (ap, fmt);
+ vsnprintf (buffer, sizeof (buffer), fmt, ap);
+ va_end (ap);
+
+ pthread_mutex_lock (&dg_mutex);
+ dejagnu_fail (buffer);
+ pthread_mutex_unlock (&dg_mutex);
+}
+
+inline void
+note (const char* fmt, ...)
+{
+ va_list ap;
+ char buffer[512];
+
+ va_start (ap, fmt);
+ vsnprintf (buffer, sizeof (buffer), fmt, ap);
+ va_end (ap);
+
+ pthread_mutex_lock (&dg_mutex);
+ dejagnu_note (buffer);
+ pthread_mutex_unlock (&dg_mutex);
+}
+
+#define MAKE_DEJAGNU_H_THREADSAFE
+
+/* We also need to provide our own version of TEST_NAME. */
+#define TEST_NAME
+
+/* We can now include all of the relevant selftests. */
+
+#include "all-non-failing-tests.h"
+
+#define TEST_PROVIDES_MAIN
+#define TEST_ESCHEWS_TEST_JIT
+
+/* Now construct a test case from all the other test cases.
+
+ We undefine COMBINED_TEST so that we can now include harness.h
+ "for real". */
+#undef COMBINED_TEST
+#include "harness.h"
+
+struct testcase
+{
+ const char *m_name;
+ void (*m_hook_to_create_code) (gcc_jit_context *ctxt,
+ void * user_data);
+ void (*m_hook_to_verify_code) (gcc_jit_context *ctxt,
+ gcc_jit_result *result);
+};
+
+const struct testcase testcases[] = {
+ {"accessing_struct",
+ create_code_accessing_struct,
+ verify_code_accessing_struct},
+ {"accessing_union",
+ create_code_accessing_union,
+ verify_code_accessing_union},
+ {"array_as_pointer",
+ create_code_array_as_pointer,
+ verify_code_array_as_pointer},
+ {"arrays",
+ create_code_arrays,
+ verify_code_arrays},
+ {"calling_external_function",
+ create_code_calling_external_function,
+ verify_code_calling_external_function},
+ {"calling_function_ptr",
+ create_code_calling_function_ptr,
+ verify_code_calling_function_ptr},
+ {"dot_product",
+ create_code_dot_product,
+ verify_code_dot_product},
+ {"expressions",
+ create_code_expressions,
+ verify_code_expressions},
+ {"factorial",
+ create_code_factorial,
+ verify_code_factorial},
+ {"fibonacci",
+ create_code_fibonacci,
+ verify_code_fibonacci},
+ {"functions",
+ create_code_functions,
+ verify_code_functions},
+ {"hello_world",
+ create_code_hello_world,
+ verify_code_hello_world},
+ {"linked_list",
+ create_code_linked_list,
+ verify_code_linked_list},
+ {"long_names",
+ create_code_long_names,
+ verify_code_long_names},
+ {"quadratic",
+ create_code_quadratic,
+ verify_code_quadratic},
+ {"nested_loop",
+ create_code_nested_loop,
+ verify_code_nested_loop},
+ {"reading_struct ",
+ create_code_reading_struct ,
+ verify_code_reading_struct },
+ {"string_literal",
+ create_code_string_literal,
+ verify_code_string_literal},
+ {"sum_of_squares",
+ create_code_sum_of_squares,
+ verify_code_sum_of_squares},
+ {"types",
+ create_code_types,
+ verify_code_types},
+ {"using_global",
+ create_code_using_global,
+ verify_code_using_global},
+ {"volatile",
+ create_code_volatile,
+ verify_code_volatile}
+};
+
+const int num_testcases = (sizeof (testcases) / sizeof (testcases[0]));
+
+struct thread_data
+{
+ pthread_t m_tid;
+ const struct testcase *m_testcase;
+};
+
+static const char *argv0;
+
+void *
+run_threaded_test (void *data)
+{
+ struct thread_data *thread = (struct thread_data *)data;
+ int i;
+
+ for (i = 0; i < 5; i++)
+ {
+ gcc_jit_context *ctxt;
+ gcc_jit_result *result;
+
+ note ("run_threaded_test: %s iteration: %d",
+ thread->m_testcase->m_name, i);
+
+ ctxt = gcc_jit_context_acquire ();
+
+ set_options (ctxt, argv0);
+
+ thread->m_testcase->m_hook_to_create_code (ctxt, NULL);
+
+ result = gcc_jit_context_compile (ctxt);
+
+ thread->m_testcase->m_hook_to_verify_code (ctxt, result);
+
+ gcc_jit_context_release (ctxt);
+
+ /* Once we're done with the code, this unloads the built .so file: */
+ gcc_jit_result_release (result);
+ }
+
+ return NULL;
+}
+
+int
+main (int argc, char **argv)
+{
+ int i;
+
+ snprintf (test, sizeof (test),
+ "%s",
+ extract_progname (argv[0]));
+
+ argv0 = argv[0];
+
+ /* The individual testcases are not thread-safe (some have their own
+ global variables), so we have one thread per test-case. */
+ struct thread_data *threads =
+ calloc (num_testcases, sizeof (struct thread_data));
+
+ /* Start a thread per test-case. */
+ for (i = 0; i < num_testcases; i++)
+ {
+ struct thread_data *thread = &threads[i];
+ thread->m_testcase = &testcases[i];
+ pthread_create (&thread->m_tid,
+ NULL,
+ run_threaded_test,
+ thread);
+ }
+
+ /* Wait for all the threads to be done. */
+ for (i = 0; i < num_testcases; i++)
+ {
+ struct thread_data *thread = &threads[i];
+ (void)pthread_join (thread->m_tid, NULL);
+ }
+
+ totals ();
+
+ return 0;
+}
--- /dev/null
+#include <stdlib.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <stdbool.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+struct zoo
+{
+ void *m_void_ptr;
+
+ bool m_bool;
+
+ char m_char;
+ signed char m_signed_char;
+ unsigned char m_unsigned_char;
+
+ short m_short;
+ unsigned short m_unsigned_short;
+
+ int m_int;
+ unsigned int m_unsigned_int;
+
+ long m_long;
+ unsigned long m_unsigned_long;
+
+ long long m_long_long;
+ unsigned long long m_unsigned_long_long;
+
+ int m_sized_int_type;
+
+ float m_float;
+ double m_double;
+ long double m_long_double;
+
+ const char *m_const_char_ptr;
+
+ size_t m_size_t;
+
+ FILE *m_FILE_ptr;
+};
+
+int test_int = 42;
+int *test_ptr = &test_int;
+
+const char *test_string = "test_string";
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ /* Let's try to inject the equivalent of:
+
+ void
+ test_caller (struct zoo *z)
+ {
+ for each fields "m_field":
+ z->m_field = ...some data;
+ }
+ */
+ gcc_jit_type *void_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+
+#define CREATE_FIELD(TYPE, NAME) \
+ gcc_jit_context_new_field ( \
+ ctxt, NULL, \
+ gcc_jit_context_get_type (ctxt, TYPE), \
+ NAME)
+
+ gcc_jit_field *field_m_void_ptr =
+ CREATE_FIELD (GCC_JIT_TYPE_VOID_PTR, "m_void_ptr");
+
+ gcc_jit_field *field_m_bool =
+ CREATE_FIELD (GCC_JIT_TYPE_BOOL, "m_bool");
+
+ gcc_jit_field *field_m_char =
+ CREATE_FIELD (GCC_JIT_TYPE_CHAR, "m_char");
+ gcc_jit_field *field_m_signed_char =
+ CREATE_FIELD (GCC_JIT_TYPE_SIGNED_CHAR, "m_signed_char");
+ gcc_jit_field *field_m_unsigned_char =
+ CREATE_FIELD (GCC_JIT_TYPE_UNSIGNED_CHAR, "m_unsigned_char");
+
+ gcc_jit_field *field_m_short =
+ CREATE_FIELD (GCC_JIT_TYPE_SHORT, "m_short");
+ gcc_jit_field *field_m_unsigned_short =
+ CREATE_FIELD (GCC_JIT_TYPE_UNSIGNED_SHORT, "m_unsigned_short");
+
+ gcc_jit_field *field_m_int =
+ CREATE_FIELD (GCC_JIT_TYPE_INT, "m_int");
+ gcc_jit_field *field_m_unsigned_int =
+ CREATE_FIELD (GCC_JIT_TYPE_UNSIGNED_INT, "m_unsigned_int");
+
+ gcc_jit_field *field_m_long =
+ CREATE_FIELD (GCC_JIT_TYPE_LONG, "m_long");
+ gcc_jit_field *field_m_unsigned_long =
+ CREATE_FIELD (GCC_JIT_TYPE_UNSIGNED_LONG, "m_unsigned_long");
+
+ gcc_jit_field *field_m_long_long =
+ CREATE_FIELD (GCC_JIT_TYPE_LONG_LONG, "m_long_long");
+ gcc_jit_field *field_m_unsigned_long_long =
+ CREATE_FIELD (GCC_JIT_TYPE_UNSIGNED_LONG_LONG, "m_unsigned_long_long");
+
+ /* Signed int type with sizeof (int): */
+ gcc_jit_type *sized_int_type =
+ gcc_jit_context_get_int_type (ctxt, sizeof (int), 1);
+ gcc_jit_field *field_m_sized_int_type =
+ gcc_jit_context_new_field (
+ ctxt, NULL, sized_int_type, "m_sized_int_type");
+
+ gcc_jit_field *field_m_float =
+ CREATE_FIELD (GCC_JIT_TYPE_FLOAT, "m_float");
+ gcc_jit_field *field_m_double =
+ CREATE_FIELD (GCC_JIT_TYPE_DOUBLE, "m_double");
+ gcc_jit_field *field_m_long_double =
+ CREATE_FIELD (GCC_JIT_TYPE_LONG_DOUBLE, "m_long_double");
+
+ gcc_jit_field *field_m_const_char_ptr =
+ CREATE_FIELD (GCC_JIT_TYPE_CONST_CHAR_PTR, "m_const_char_ptr");
+
+ gcc_jit_field *field_m_size_t =
+ CREATE_FIELD (GCC_JIT_TYPE_SIZE_T, "m_size_t");
+
+ gcc_jit_field *field_m_FILE_ptr =
+ CREATE_FIELD (GCC_JIT_TYPE_FILE_PTR, "m_FILE_ptr");
+
+#undef CREATE_FIELD
+
+ gcc_jit_field *zoo_fields[] = {
+ field_m_void_ptr,
+
+ field_m_bool,
+
+ field_m_char,
+ field_m_signed_char,
+ field_m_unsigned_char,
+
+ field_m_short,
+ field_m_unsigned_short,
+
+ field_m_int,
+ field_m_unsigned_int,
+
+ field_m_long,
+ field_m_unsigned_long,
+
+ field_m_long_long,
+ field_m_unsigned_long_long,
+
+ field_m_sized_int_type,
+
+ field_m_float,
+ field_m_double,
+ field_m_long_double,
+
+ field_m_const_char_ptr,
+
+ field_m_size_t,
+
+ field_m_FILE_ptr
+ };
+
+ gcc_jit_type *zoo_type =
+ gcc_jit_struct_as_type (
+ gcc_jit_context_new_struct_type (
+ ctxt,
+ NULL,
+ "zoo",
+ sizeof (zoo_fields) / sizeof (zoo_fields[0]),
+ zoo_fields));
+
+ gcc_jit_type *zoo_ptr_type =
+ gcc_jit_type_get_pointer (zoo_type);
+
+ /* Build the test_fn. */
+ gcc_jit_param *param_z =
+ gcc_jit_context_new_param (ctxt, NULL, zoo_ptr_type, "z");
+ gcc_jit_function *test_fn =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ void_type,
+ "test_types",
+ 1, ¶m_z,
+ 0);
+ gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
+
+ /* Write to the various fields of param "z". */
+#define ASSIGN(FIELD, EXPR) \
+ gcc_jit_block_add_assignment ( \
+ block, NULL, \
+ gcc_jit_rvalue_dereference_field ( \
+ gcc_jit_param_as_rvalue (param_z), \
+ NULL, \
+ (FIELD)), \
+ (EXPR));
+
+ ASSIGN(
+ field_m_void_ptr,
+ gcc_jit_context_new_rvalue_from_ptr (
+ ctxt,
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID_PTR),
+ test_ptr))
+
+ ASSIGN(field_m_bool,
+ gcc_jit_context_new_rvalue_from_int (
+ ctxt,
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_BOOL), 1))
+
+ ASSIGN(field_m_char,
+ gcc_jit_context_new_rvalue_from_int (
+ ctxt,
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_CHAR),
+ 'V'))
+ ASSIGN(field_m_signed_char,
+ gcc_jit_context_new_rvalue_from_int (
+ ctxt,
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_SIGNED_CHAR),
+ -37))
+ ASSIGN(field_m_unsigned_char,
+ gcc_jit_context_new_rvalue_from_int (
+ ctxt,
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_UNSIGNED_CHAR),
+ 200))
+
+ ASSIGN(field_m_short,
+ gcc_jit_context_new_rvalue_from_int (
+ ctxt,
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_SHORT),
+ -900))
+ ASSIGN(field_m_unsigned_short,
+ gcc_jit_context_new_rvalue_from_int (
+ ctxt,
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_UNSIGNED_SHORT),
+ 0x3000))
+
+ ASSIGN(field_m_int,
+ gcc_jit_context_new_rvalue_from_int (
+ ctxt,
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT),
+ -0x2000))
+ ASSIGN(field_m_unsigned_int,
+ gcc_jit_context_new_rvalue_from_int (
+ ctxt,
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_UNSIGNED_INT),
+ 1234567))
+
+ ASSIGN(field_m_long,
+ gcc_jit_context_new_rvalue_from_int (
+ ctxt,
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_LONG),
+ -5))
+ ASSIGN(field_m_unsigned_long,
+ gcc_jit_context_new_rvalue_from_int (
+ ctxt,
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_UNSIGNED_LONG),
+ 12345678))
+
+ ASSIGN(field_m_long_long,
+ gcc_jit_context_new_rvalue_from_int (
+ ctxt,
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_LONG_LONG),
+ -42))
+ ASSIGN(field_m_unsigned_long_long,
+ gcc_jit_context_new_rvalue_from_int (
+ ctxt,
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_UNSIGNED_LONG_LONG),
+ 123456789))
+
+ ASSIGN(field_m_sized_int_type,
+ gcc_jit_context_new_rvalue_from_int (
+ ctxt,
+ sized_int_type, 500))
+
+ ASSIGN(field_m_float,
+ gcc_jit_context_new_rvalue_from_double (
+ ctxt,
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_FLOAT),
+ 3.141))
+ ASSIGN(field_m_double,
+ gcc_jit_context_new_rvalue_from_double (
+ ctxt,
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_DOUBLE),
+ 3.141))
+ ASSIGN(field_m_long_double,
+ gcc_jit_context_new_rvalue_from_double (
+ ctxt,
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_LONG_DOUBLE),
+ 3.141))
+
+ ASSIGN(field_m_const_char_ptr,
+ gcc_jit_context_new_rvalue_from_ptr (
+ ctxt,
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_CONST_CHAR_PTR),
+ (char *)test_string))
+
+ ASSIGN(field_m_size_t,
+ gcc_jit_context_new_rvalue_from_int (
+ ctxt,
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_SIZE_T),
+ sizeof (struct zoo)))
+
+ ASSIGN(field_m_FILE_ptr,
+ gcc_jit_context_new_rvalue_from_ptr (
+ ctxt,
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_FILE_PTR),
+ stderr))
+
+#undef ASSIGN
+
+ gcc_jit_block_end_with_void_return (block, NULL);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ typedef void (*fn_type) (struct zoo *);
+ CHECK_NON_NULL (result);
+
+ fn_type test_types =
+ (fn_type)gcc_jit_result_get_code (result, "test_types");
+ CHECK_NON_NULL (test_types);
+
+ struct zoo z;
+ memset (&z, 0xf0, sizeof (z));
+
+ /* Call the JIT-generated function. */
+ test_types (&z);
+
+ /* Verify that it correctly wrote to the various fields. */
+ CHECK_VALUE (z.m_void_ptr, test_ptr);
+
+ CHECK_VALUE (z.m_bool, true);
+
+ CHECK_VALUE (z.m_char, 'V');
+ CHECK_VALUE (z.m_signed_char, -37);
+ CHECK_VALUE (z.m_unsigned_char, 200);
+
+ CHECK_VALUE (z.m_short, -900);
+ CHECK_VALUE (z.m_unsigned_short, 0x3000);
+
+ CHECK_VALUE (z.m_int, -0x2000);
+ CHECK_VALUE (z.m_unsigned_int, 1234567);
+
+ CHECK_VALUE (z.m_long, -5);
+ CHECK_VALUE (z.m_unsigned_long, 12345678);
+
+ CHECK_VALUE (z.m_long_long, -42);
+ CHECK_VALUE (z.m_unsigned_long_long, 123456789);
+
+ CHECK_VALUE (z.m_sized_int_type, 500);
+
+ CHECK_VALUE (z.m_float, 3.141f);
+ CHECK_VALUE (z.m_double, 3.141);
+ CHECK_VALUE (z.m_long_double, 3.141);
+
+ CHECK_VALUE (z.m_const_char_ptr, test_string);
+
+ CHECK_VALUE (z.m_size_t, sizeof (struct zoo));
+
+ CHECK_VALUE (z.m_FILE_ptr, stderr);
+}
--- /dev/null
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ extern int the_global;
+
+#ifdef __cplusplus
+}
+#endif
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ /* Let's try to inject the equivalent of:
+ extern int the_global;
+
+ void
+ test_using_global (void)
+ {
+ the_global += 1;
+ }
+ */
+ gcc_jit_type *void_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+ gcc_jit_type *int_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+ /* Build the test_fn. */
+ gcc_jit_function *test_fn =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ void_type,
+ "test_using_global",
+ 0, NULL,
+ 0);
+ gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
+
+ gcc_jit_block_add_assignment_op (
+ block, NULL,
+ gcc_jit_context_new_global (ctxt, NULL, int_type, "the_global"),
+ GCC_JIT_BINARY_OP_PLUS,
+ gcc_jit_context_one (ctxt, int_type));
+ gcc_jit_block_end_with_void_return (block, NULL);
+}
+
+int the_global;
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ typedef void (*fn_type) (void);
+ CHECK_NON_NULL (result);
+
+ fn_type test_using_global =
+ (fn_type)gcc_jit_result_get_code (result, "test_using_global");
+ CHECK_NON_NULL (test_using_global);
+
+ the_global = 42;
+
+ /* Call the JIT-generated function. */
+ test_using_global ();
+
+ /* Verify that it correctly modified the_global. */
+ CHECK_VALUE (the_global, 43);
+}
+
--- /dev/null
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+volatile int the_volatile;
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ /* Let's try to inject the equivalent of:
+ extern volatile int the_volatile;
+
+ int
+ test_using_volatile (void)
+ {
+ return the_volatile;
+ }
+ */
+ gcc_jit_type *int_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+ gcc_jit_type *volatile_int_type =
+ gcc_jit_type_get_volatile (int_type);
+
+ /* Build the test_fn. */
+ gcc_jit_function *test_fn =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ int_type,
+ "test_using_volatile",
+ 0, NULL,
+ 0);
+ gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
+ gcc_jit_lvalue *read_of_the_volatile =
+ gcc_jit_rvalue_dereference (
+ gcc_jit_context_new_rvalue_from_ptr (
+ ctxt,
+ gcc_jit_type_get_pointer (volatile_int_type),
+ (void *)&the_volatile),
+ NULL);
+
+ gcc_jit_block_end_with_return (
+ block, NULL,
+ gcc_jit_lvalue_as_rvalue (read_of_the_volatile));
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ typedef int (*fn_type) (void);
+ CHECK_NON_NULL (result);
+
+ fn_type test_using_volatile =
+ (fn_type)gcc_jit_result_get_code (result, "test_using_volatile");
+ CHECK_NON_NULL (test_using_volatile);
+
+ the_volatile = 42;
+
+ /* Call the JIT-generated function. */
+ test_using_volatile ();
+
+ CHECK_VALUE (test_using_volatile (), 42);
+}
+
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")
+2014-11-11 David Malcolm <dmalcolm@redhat.com>
+
+ * ChangeLog.jit: New.
+
2014-10-28 Richard Henderson <rth@redhat.com>
* longlong.h [__alpha] (umul_ppmm): Disable for c++.
--- /dev/null
+2014-09-25 David Malcolm <dmalcolm@redhat.com>
+
+ * libiberty.h (choose_tmpdir): New prototype.
+ * ChangeLog.jit: New.
+
+\f
+Copyright (C) 2014 Free Software Foundation, Inc.
+
+Copying and distribution of this file, with or without modification,
+are permitted in any medium without royalty provided the copyright
+notice and this notice are preserved.
+2014-11-11 David Malcolm <dmalcolm@redhat.com>
+
+ * ChangeLog.jit: New.
+
2014-11-11 Francois-Xavier Coudert <fxcoudert@gcc.gnu.org>
PR target/63610
--- /dev/null
+2014-09-24 David Malcolm <dmalcolm@redhat.com>
+
+ * ChangeLog.jit: Add copyright footer.
+
+2013-10-03 David Malcolm <dmalcolm@redhat.com>
+
+ * configure.ac: Add --enable-host-shared.
+ * configure: Regenerate.
+\f
+Copyright (C) 2013-2014 Free Software Foundation, Inc.
+
+Copying and distribution of this file, with or without modification,
+are permitted in any medium without royalty provided the copyright
+notice and this notice are preserved.
+2014-11-11 David Malcolm <dmalcolm@redhat.com>
+
+ * ChangeLog.jit: New.
+
2014-11-10 Edward Smith-Rowland <3dw4rd@verizon.net>
* include/cpplib.h (cpp_callbacks): Add has_attribute.
--- /dev/null
+2014-09-24 David Malcolm <dmalcolm@redhat.com>
+
+ * ChangeLog.jit: Add copyright footer.
+
+2013-10-07 David Malcolm <dmalcolm@redhat.com>
+
+ * Makefile.in: Set PICFLAG from configure script; add it to
+ ALL_CFLAGS.
+ * configure.ac (--enable-host-shared): Set up PICFLAG rather
+ than attempting to append -fPIC to CFLAGS, CXXFLAGS, LDFLAGS.
+ * configure: Regenerate.
+
+2013-10-03 David Malcolm <dmalcolm@redhat.com>
+
+ * configure.ac: Add --enable-host-shared.
+ * configure: Regenerate.
+\f
+Copyright (C) 2013-2014 Free Software Foundation, Inc.
+
+Copying and distribution of this file, with or without modification,
+are permitted in any medium without royalty provided the copyright
+notice and this notice are preserved.
+2014-11-11 David Malcolm <dmalcolm@redhat.com>
+
+ * ChangeLog.jit: New.
+
2014-01-23 Marek Polacek <polacek@redhat.com>
PR c/59871
--- /dev/null
+2014-09-24 David Malcolm <dmalcolm@redhat.com>
+
+ * ChangeLog.jit: Add copyright footer.
+
+2013-10-07 David Malcolm <dmalcolm@redhat.com>
+
+ * Makefile.in: Set PICFLAG from configure script; add it to
+ ALL_CFLAGS.
+ * configure.ac (--enable-host-shared): Set up PICFLAG rather
+ than attempting to append -fPIC to CFLAGS, CXXFLAGS, LDFLAGS.
+ * configure: Regenerate.
+
+2013-10-03 David Malcolm <dmalcolm@redhat.com>
+
+ * configure.ac: Add --enable-host-shared.
+ * configure: Regenerate.
+\f
+Copyright (C) 2013-2014 Free Software Foundation, Inc.
+
+Copying and distribution of this file, with or without modification,
+are permitted in any medium without royalty provided the copyright
+notice and this notice are preserved.
+2014-11-11 David Malcolm <dmalcolm@redhat.com>
+
+ * ChangeLog.jit: New.
+
2014-11-05 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
* sigsetmask.c (_POSIX_SOURCE): Remove.
--- /dev/null
+2014-09-25 David Malcolm <dmalcolm@redhat.com>
+
+ * choose-temp.c (choose_tmpdir): Remove now-redundant local
+ copy of prototype.
+ * functions.texi: Regenerate.
+ * make-temp-file.c (choose_tmpdir): Convert return type from
+ char * to const char * - given that this returns a pointer to
+ a memoized allocation, the caller must not touch it.
+
+2014-09-24 David Malcolm <dmalcolm@redhat.com>
+
+ * ChangeLog.jit: Add copyright footer.
+
+2013-10-03 David Malcolm <dmalcolm@redhat.com>
+
+ * configure.ac: If --enable-host-shared, use -fPIC.
+ * configure: Regenerate.
+\f
+Copyright (C) 2013-2014 Free Software Foundation, Inc.
+
+Copying and distribution of this file, with or without modification,
+are permitted in any medium without royalty provided the copyright
+notice and this notice are preserved.
--- /dev/null
+2014-09-24 David Malcolm <dmalcolm@redhat.com>
+
+ * ChangeLog.jit: Add copyright footer.
+
+2013-10-07 David Malcolm <dmalcolm@redhat.com>
+
+ * Makefile.am: Add PICFLAG to libz_a_CFLAGS.
+ * configure.ac (--enable-host-shared): Set up PICFLAG rather
+ than attempting to append -fPIC to CFLAGS.
+ * Makefile.in: Regenerate.
+ * configure: Regenerate.
+
+2013-10-03 David Malcolm <dmalcolm@redhat.com>
+
+ * configure.ac: Add --enable-host-shared.
+ * configure: Regenerate.
+\f
+Copyright (C) 2013-2014 Free Software Foundation, Inc.
+
+Copying and distribution of this file, with or without modification,
+are permitted in any medium without royalty provided the copyright
+notice and this notice are preserved.