Merger of dmalcolm/jit branch from git

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

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

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

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

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

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

include/ChangeLog:
	* ChangeLog.jit: New.

libbacktrace/ChangeLog:
	* ChangeLog.jit: New.

libcpp/ChangeLog:
	* ChangeLog.jit: New.

libdecnumber/ChangeLog:
	* ChangeLog.jit: New.

libiberty/ChangeLog:
	* ChangeLog.jit: New.

zlib/ChangeLog:
	* ChangeLog.jit: New.

From-SVN: r217374
This commit is contained in:
David Malcolm 2014-11-11 21:55:52 +00:00
parent 970a9caa49
commit 35485da996
136 changed files with 39772 additions and 6 deletions

View File

@ -1,3 +1,8 @@
2014-11-11 David Malcolm <dmalcolm@redhat.com>
* ChangeLog.jit: New.
* MAINTAINERS (Various Maintainers): Add myself as jit maintainer.
2014-11-11 Francois-Xavier Coudert <fxcoudert@gcc.gnu.org>
PR target/63610

23
ChangeLog.jit Normal file
View File

@ -0,0 +1,23 @@
2014-10-02 David Malcolm <dmalcolm@redhat.com>
* MAINTAINERS: Update jit entry to match formatting change on
trunk: "Put all email addresses between '<' and '>'."
2014-09-24 David Malcolm <dmalcolm@redhat.com>
* ChangeLog.jit: Add copyright footer.
2014-09-11 David Malcolm <dmalcolm@redhat.com>
* MAINTAINERS (Various Maintainers): Add myself as jit maintainer.
2013-10-03 David Malcolm <dmalcolm@redhat.com>
* configure.ac: Add --enable-host-shared
* configure: Regenerate.
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.

View File

@ -260,6 +260,7 @@ testsuite Janis Johnson <janisjo@codesourcery.com>
register allocation Vladimir Makarov <vmakarov@redhat.com>
gdbhooks.py David Malcolm <dmalcolm@redhat.com>
SLSR Bill Schmidt <wschmidt@linux.vnet.ibm.com>
jit David Malcolm <dmalcolm@redhat.com>
Note that individuals who maintain parts of the compiler need approval to
check in changes outside of the parts of the compiler they maintain.

View File

@ -1,3 +1,9 @@
2014-11-11 David Malcolm <dmalcolm@redhat.com>
* ChangeLog.jit: New.
* jit-coverage-report.py: New file: a script to print crude
code-coverage information for the libgccjit API.
2014-11-11 Marat Zakirov <m.zakirov@samsung.com>
* mklog: Symbol '}' stops search for changes.

14
contrib/ChangeLog.jit Normal file
View File

@ -0,0 +1,14 @@
2014-09-24 David Malcolm <dmalcolm@redhat.com>
* ChangeLog.jit: Add copyright footer.
2014-01-23 David Malcolm <dmalcolm@redhat.com>
* jit-coverage-report.py: New file: a script to print crude
code-coverage information for the libgccjit API.
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.

View File

@ -0,0 +1,67 @@
#! /usr/bin/python
#
# Print a report on which libgccjit.so symbols are used in which test
# cases, and which lack test coverage. Tested with Python 2.7 and 3.2
# To be run from the root directory of the source tree.
#
# Copyright (C) 2014 Free Software Foundation, Inc.
# Written by David Malcolm <dmalcolm@redhat.com>.
#
# This script is Free Software, and it can be copied, distributed and
# modified as defined in the GNU General Public License. A copy of
# its license can be downloaded from http://www.gnu.org/copyleft/gpl.html
from collections import Counter
import glob
import re
import sys
def parse_map_file(path):
"""
Parse libgccjit.map, returning the symbols in the API as a list of str.
"""
syms = []
with open(path) as f:
for line in f:
m = re.match('^\s+([a-z_]+);$', line)
if m:
syms.append(m.group(1))
return syms
def parse_test_case(path):
"""
Locate all symbol-like things in a C test case, yielding
them as a sequence of str.
"""
with open(path) as f:
for line in f:
for m in re.finditer('([_A-Za-z][_A-Za-z0-9]*)', line):
yield m.group(1)
def find_test_cases():
for path in glob.glob('gcc/testsuite/jit.dg/*.[ch]'):
yield path
api_syms = parse_map_file('gcc/jit/libgccjit.map')
syms_in_test_cases = {}
for path in find_test_cases():
syms_in_test_cases[path] = list(parse_test_case(path))
uses = Counter()
for sym in sorted(api_syms):
print('symbol: %s' % sym)
uses[sym] = 0
for path in syms_in_test_cases:
count = syms_in_test_cases[path].count(sym)
uses[sym] += count
if count:
print(' uses in %s: %i' % (path, count))
if uses[sym] == 0:
print(' NEVER USED')
sys.stdout.write('\n')
layout = '%40s %5s %s'
print(layout % ('SYMBOL', 'USES', 'HISTOGRAM'))
for sym, count in uses.most_common():
print(layout % (sym, count, '*' * count if count else 'UNUSED'))

View File

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

360
gcc/ChangeLog.jit Normal file
View File

@ -0,0 +1,360 @@
2014-10-29 David Malcolm <dmalcolm@redhat.com>
* doc/install.texi (Tools/packages necessary for modifying GCC):
Specify that Sphinx version 1.0 or later is required. Wrap .rst
inside an @file command.
2014-10-22 David Malcolm <dmalcolm@redhat.com>
* cgraph.h: Drop now-redundant prototype of ipa_cp_c_finalize,
since trunk added this in ipa-prop.h.
* ipa-icf.c (ipa_icf_driver): Set optimizer to NULL when
done.
2014-10-20 David Malcolm <dmalcolm@redhat.com>
* doc/install.texi (Tools/packages necessary for modifying GCC):
Add Sphinx.
2014-10-20 David Malcolm <dmalcolm@redhat.com>
* Makefile.in (pkgconfigdir): Drop this.
(installdirs): Likewise.
* configure.ac (gcc_version): Don't AC_SUBST this.
* configure: Regenerate.
2014-10-17 David Malcolm <dmalcolm@redhat.com>
* Makefile.in (FULL_DRIVER_NAME): New variable, adapted from the
install-driver target. New target, a symlink within the builddir,
linked to "xgcc", for use when running the JIT library from the
builddir.
(MOSTLYCLEANFILES): Add FULL_DRIVER_NAME.
(install-driver): Use $(FULL_DRIVER_NAME) rather than spelling it
out.
(site.exp): Don't set "bindir", as this is no longer needed when
running the jit testsuite.
2014-10-13 David Malcolm <dmalcolm@redhat.com>
* configure.ac: Update a reference to jit/internal-api.c to
jit/jit-playback.c.
* configure: Regenerate.
2014-10-07 David Malcolm <dmalcolm@redhat.com>
* Makefile.in (site.exp): When constructing site.exp, add a line
to set "bindir".
* configure.ac: Generate a gcc-driver-name.h file containing
GCC_DRIVER_NAME for the benefit of jit/internal-api.c.
* configure: Regenerate.
2014-10-03 David Malcolm <dmalcolm@redhat.com>
* diagnostic.c (diagnostic_finish): Free the memory for
context->classify_diagnostic and context->printer, running the
destructor for the latter.
2014-10-02 David Malcolm <dmalcolm@redhat.com>
* configure: Regenerate, after merger from trunk.
2014-10-02 David Malcolm <dmalcolm@redhat.com>
* configure.ac (doc_build_sys): New variable, set to "sphinx" if
sphinx is installed, falling back to "texinfo" otherwise.
* configure: Regenerate.
* Makefile.in (doc_build_sys): New.
2014-09-24 David Malcolm <dmalcolm@redhat.com>
* ChangeLog.jit: Add copyright footer.
2014-09-24 David Malcolm <dmalcolm@redhat.com>
* cgraph.h (cgraphbuild_c_finalize): Delete prototype of empty
function.
(ipa_c_finalize): Likewise.
(predict_c_finalize): Likewise.
(symtab_c_finalize): Likewise.
(varpool_c_finalize): Likewise.
* cgraph.c (cgraph_c_finalize): Add leading comment. Put return
type on line before function name.
* cgraphunit.c (cgraphunit_c_finalize): Likewise.
* dwarf2out.c (dwarf2out_c_finalize): Likewise.
* gcse.c (gcse_c_finalize): Likewise.
* ipa-cp.c (ipa_cp_c_finalize): Likewise.
* ipa-reference.c (ipa_reference_c_finalize): Likewise.
* params.c (params_c_finalize): Update leading comment to match
format of the others mentioned above.
* cgraphbuild.c (cgraphbuild_c_finalize): Delete empty function.
* ipa.c (ipa_c_finalize): Likewise.
* predict.c (predict_c_finalize): Likewise.
* symtab.c (symtab_c_finalize): Likewise.
* varpool.c (varpool_c_finalize): Likewise.
* toplev.c (toplev::finalize): Remove calls to empty functions
cgraphbuild_c_finalize, ipa_c_finalize, predict_c_finalize,
symtab_c_finalize, varpool_c_finalize.
2014-09-23 David Malcolm <dmalcolm@redhat.com>
* passes.c (execute_ipa_summary_passes): Fix whitespace when
assigning to current_pass.
(ipa_write_summaries_2): Assign "pass" to "current_pass" global
before calling write_summary hook.
(ipa_write_optimization_summaries_1): Likewise when calling
write_optimization_summary hook.
(ipa_read_summaries_1): Likewise for read_summary hook.
(ipa_read_optimization_summaries_1): Likewise for
read_optimization_summary hook.
(execute_ipa_stmt_fixups): Likewise for stmt_fixup hook.
2014-09-22 David Malcolm <dmalcolm@redhat.com>
* cgraph.c (cgraph_c_finalize): Remove FIXME.
* timevar.c (timevar_init): Likewise.
2014-09-18 David Malcolm <dmalcolm@redhat.com>
* Makefile.in (pkgconfigdir): New.
(installdirs): Add creation of $(DESTDIR)$(pkgconfigdir).
* configure.ac (gcc_version): Expose this value for use via
AC_SUBST, since we need it within the new file libgccjit.pc.in.
* configure: Regenerate.
2014-09-10 David Malcolm <dmalcolm@redhat.com>
* cgraph.c (cgraph_c_finalize): Update to reflect the movement of
many globals into fields of the "symtab" object.
* cgraphunit.c (graphunit_c_finalize): Likewise.
* symtab.c (symtab_c_finalize): Likewise.
* toplev.c (initialize_rtl): Move static local "initialized_once"
into file scope, and rename to...
(rtl_initialized): New variable.
(toplev::finalize): Clear rtl_initialized and
this_target_rtl->target_specific_initialized so that RTL will be
reinitialized when the compiler is run more than once in-process.
2014-07-14 David Malcolm <dmalcolm@redhat.com>
* cgraph.h (ipa_cp_c_finalize): Add prototype.
* ipa-cp.c (ipa_cp_c_finalize): New.
* toplev.c (toplev::finalize): Add call to ipa_cp_c_finalize.
2014-05-08 David Malcolm <dmalcolm@redhat.com>
* params.c (global_init_params): Require that params_finished be
false, rather than being idempotent, in favor of purging all state
between toplev invocations, since in a release build
init_ggc_heuristics calls set_param_value_internal, and the
latter assumes that params_finished is true.
(params_c_finalize): New.
* params.h (params_c_finalize): New.
* toplev.c (toplev::finalize): Call params_c_finalize.
2014-03-24 Tom Tromey <tromey@redhat.com>
* toplev.c (general_init): Initialize input_location.
* input.c (input_location): Initialize to UNKNOWN_LOCATION.
2014-03-19 Tom Tromey <tromey@redhat.com>
* timevar.h (auto_timevar): New class.
2014-03-19 Tom Tromey <tromey@redhat.com>
* diagnostic.c (bt_stop): Use toplev::main.
* main.c (main): Update.
* toplev.c (do_compile): Remove argument. Don't check
use_TV_TOTAL.
(toplev::toplev, toplev::~toplev, toplev::start_timevars): New
functions.
(toplev::main): Rename from toplev_main. Update.
(toplev::finalize): Rename from toplev_finalize. Update.
* toplev.h (class toplev): New.
(struct toplev_options): Remove.
(toplev_main, toplev_finalize): Don't declare.
2014-03-11 David Malcolm <dmalcolm@redhat.com>
* gcse.c (gcse_c_finalize): New, to clear test_insn between
in-process compiles.
* gcse.h (gcse_c_finalize): New.
* toplev.c: Include "gcse.h" so that we can...
(toplev_finalize): Call gcse_c_finalize.
2014-03-11 David Malcolm <dmalcolm@redhat.com>
* dwarf2out.c (dwarf2out_c_finalize): Release base_types.
2014-03-10 David Malcolm <dmalcolm@redhat.com>
* ipa-reference.c (ipa_init): Move static bool init_p from here
to...
(ipa_init_p): New file-scope variable, so that it can be reset
when repeatedly invoking the compiler within one process by...
(ipa_reference_c_finalize): New function.
* ipa-reference.h (ipa_reference_c_finalize): New.
* toplev.c (toplev_finalize): Invoke new function
ipa_reference_c_finalize.
2014-01-24 David Malcolm <dmalcolm@redhat.com>
* timevar.def: Replace TV_CLIENT_CALLBACK with TV_JIT_REPLAY.
2013-10-11 David Malcolm <dmalcolm@redhat.com>
* doc/install.texi (--enable-shared): Add note contrasting it
with...
(--enable-host-shared): New option.
2013-10-11 David Malcolm <dmalcolm@redhat.com>
* dumpfile.h (gcc::dump_manager): New class, to hold state
relating to dumpfile management.
(get_dump_file_name): Remove in favor of method of dump_manager.
(dump_initialized_p): Likewise.
(dump_start): Likewise.
(dump_finish): Likewise.
(dump_switch_p): Likewise.
(dump_register): Likewise.
(get_dump_file_info): Likewise.
* context.c (gcc::context::context): Construct the dump_manager
instance.
* context.h (gcc::context::get_dumps): New.
(gcc::context::m_dumps): New.
* coverage.c (coverage_init): Port to dump_manager API.
* dumpfile.c (extra_dump_files): Convert to field of
gcc::dump_manager.
(extra_dump_files_in_use): Likewise.
(extra_dump_files_alloced): Likewise.
(gcc::dump_manager::dump_manager): New.
(dump_register): Convert to...
(gcc::dump_manager::dump_register): ...method, replacing
function-static next_dump with m_next_dump field.
(get_dump_file_info): Convert to...
(gcc::dump_manager::get_dump_file_info): ...method.
(get_dump_file_name): Convert to...
(gcc::dump_manager::get_dump_file_name): ...method.
(dump_start): Convert to...
(gcc::dump_manager::dump_start): ...method.
(dump_finish): Convert to...
(gcc::dump_manager::dump_finish): ...method.
(dump_begin): Replace body with...
(gcc::dump_manager::dump_begin): ...new method.
(dump_phase_enabled_p): Convert to...
(gcc::dump_manager::dump_phase_enabled_p): ...method.
(dump_phase_enabled_p): Convert to...
(gcc::dump_manager::dump_phase_enabled_p): ...method.
(dump_initialized_p): Convert to...
(gcc::dump_manager::dump_initialized_p): ...method.
(dump_flag_name): Replace body with...
(gcc::dump_manager::dump_flag_name): ...new method.
(dump_enable_all): Convert to...
(gcc::dump_manager::dump_enable_all): ...new method.
(opt_info_enable_passes): Convert to...
(gcc::dump_manager::opt_info_enable_passes): ...new method.
(dump_switch_p_1): Convert to...
(gcc::dump_manager::dump_switch_p_1): ...new method.
(dump_switch_p): Convert to...
(gcc::dump_manager::dump_switch_p): ...new method.
(opt_info_switch_p): Port to dump_manager API.
(enable_rtl_dump_file): Likewise.
* opts-global.c (handle_common_deferred_options): Port to new
dump_manager API.
* passes.c (pass_manager::finish_optimization_passes): Likewise.
(pass_manager::register_one_dump_file): Likewise.
(pass_manager::register_pass): Likewise.
(pass_init_dump_file): Likewise.
(pass_fini_dump_file): Likewise.
* statistics.c (statistics_early_init): Likewise.
2013-10-08 David Malcolm <dmalcolm@redhat.com>
* ipa-inline.c (ipa_inline): Fix leak of "order" when
optimizations are disabled.
2013-10-08 David Malcolm <dmalcolm@redhat.com>
* coverage.c (coverage_finish): Fix leak of da_file_name.
2013-10-07 David Malcolm <dmalcolm@redhat.com>
* Makefile.in: Set PICFLAG from configure script; add it to
INTERNAL_CFLAGS.
* configure.ac (--enable-host-shared): Set up PICFLAG rather
than attempting to append -fPIC to CFLAGS, CXXFLAGS, LDFLAGS.
* configure: Regenerate.
2013-10-03 David Malcolm <dmalcolm@redhat.com>
* Makefile.in (LIBIBERTY): Use pic build of libiberty.a if
configured with --enable-host-shared.
(BUILD_LIBIBERTY): Likewise.
* cgraph.c (cgraph_c_finalize): New.
* cgraph.h (symtab_c_finalize): New declaration.
(cgraph_c_finalize): Likewise.
(cgraphunit_c_finalize): Likewise.
(cgraphbuild_c_finalize): Likewise.
(ipa_c_finalize): Likewise.
(predict_c_finalize): Likewise.
(varpool_c_finalize): Likewise.
* cgraphbuild.c (cgraphbuild_c_finalize): New.
* cgraphunit.c (first_analyzed): Move from analyze_functions
to file-scope.
(first_analyzed_var): Likewise.
(analyze_functions): Move static variables into file-scope.
(cgraphunit_c_finalize): New.
* configure.ac: Add --enable-host-shared, adding -fPIC.
* configure: Regenerate.
* dwarf2out.c (dwarf2out_c_finalize): New.
* dwarf2out.h (dwarf2out_c_finalize): Declare.
* ggc-page.c (init_ggc): Make idempotent.
* ipa-pure-const.c (function_insertion_hook_holder): Move to be
a field of class pass_ipa_pure_const.
(node_duplication_hook_holder): Likewise.
(node_removal_hook_holder): Likewise.
(register_hooks): Convert to method...
(pass_ipa_pure_const::register_hooks): ...here, converting
static variable init_p into...
(pass_ipa_pure_const::init_p): ...new field.
(pure_const_generate_summary): Update invocation of
register_hooks to invoke as a method of current_pass.
(pure_const_read_summary): Likewise.
(propagate): Convert to...
(pass_ipa_pure_const::execute): ...method.
* ipa.c (ipa_c_finalize): New.
* main.c (main): Update usage of toplev_main.
* params.c (global_init_params): Make idempotent.
* passes.c (execute_ipa_summary_passes): Set current_pass.
* predict.c (predict_c_finalize): New.
* stringpool.c (init_stringpool): Clean up if we're called more
than once.
* symtab.c (symtab_c_finalize): New.
* timevar.c (timevar_init): Ignore repeated calls.
* timevar.def (TV_CLIENT_CALLBACK): Add.
(TV_ASSEMBLE): Add.
(TV_LINK): Add.
(TV_LOAD): Add.
* toplev.c (do_compile) Add parameter (const toplev_options *);
use it to avoid starting/stopping/reporting timevar TV_TOTAL
for the case where toplev_main does not emcompass all timevars.
(toplev_main): Add parameter (const toplev_options *); pass it
to do_compile.
(toplev_finalize): New.
* toplev.h (struct toplev_options): New.
(toplev_main): Add parameter (const toplev_options *).
(toplev_finalize): New.
* varpool.c (varpool_c_finalize): New.
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.

View File

@ -316,6 +316,11 @@ write_entries_to_file = $(shell rm -f $(2) || :) $(shell touch $(2)) \
$(shell expr $(range) + $(write_entries_to_file_split) - 1), $(1))" \
| tr ' ' '\012' >> $(2)))
# The jit documentation looks better if built with sphinx, but can be
# built with texinfo if sphinx is not available.
# configure sets "doc_build_sys" to "sphinx" or "texinfo" accordingly
doc_build_sys=@doc_build_sys@
# --------
# UNSORTED
# --------
@ -1508,6 +1513,9 @@ BACKEND = libbackend.a main.o @TREEBROWSER@ libcommon-target.a libcommon.a \
# front-end checking.
TREECHECKING = @TREECHECKING@
# The full name of the driver on installation
FULL_DRIVER_NAME=$(target_noncanonical)-gcc-$(version)$(exeext)
MOSTLYCLEANFILES = insn-flags.h insn-config.h insn-codes.h \
insn-output.c insn-recog.c insn-emit.c insn-extract.c insn-peep.c \
insn-attr.h insn-attr-common.h insn-attrtab.c insn-dfatab.c \
@ -1515,7 +1523,7 @@ MOSTLYCLEANFILES = insn-flags.h insn-config.h insn-codes.h \
tm-preds.h tm-constrs.h checksum-options gimple-match.c generic-match.c \
tree-check.h min-insn-modes.c insn-modes.c insn-modes.h \
genrtl.h gt-*.h gtype-*.h gtype-desc.c gtyp-input.list \
xgcc$(exeext) cpp$(exeext) \
xgcc$(exeext) cpp$(exeext) $(FULL_DRIVER_NAME) \
$(EXTRA_PROGRAMS) gcc-cross$(exeext) \
$(SPECS) collect2$(exeext) gcc-ar$(exeext) gcc-nm$(exeext) \
gcc-ranlib$(exeext) \
@ -1524,6 +1532,12 @@ MOSTLYCLEANFILES = insn-flags.h insn-config.h insn-codes.h \
gengtype$(exeext) *.[0-9][0-9].* *.[si] *-checksum.c libbackend.a \
libcommon-target.a libcommon.a libgcc.mk
# This symlink makes the full installation name of the driver be available
# from within the *build* directory, for use when running the JIT library
# from there (e.g. when running its testsuite).
$(FULL_DRIVER_NAME): ./xgcc
$(LN) -s $< $@
#
# Language makefile fragments.
@ -3287,9 +3301,9 @@ install-driver: installdirs xgcc$(exeext)
-rm -f $(DESTDIR)$(bindir)/$(GCC_INSTALL_NAME)$(exeext)
-$(INSTALL_PROGRAM) xgcc$(exeext) $(DESTDIR)$(bindir)/$(GCC_INSTALL_NAME)$(exeext)
-if [ "$(GCC_INSTALL_NAME)" != "$(target_noncanonical)-gcc-$(version)" ]; then \
rm -f $(DESTDIR)$(bindir)/$(target_noncanonical)-gcc-$(version)$(exeext); \
rm -f $(DESTDIR)$(bindir)/$(FULL_DRIVER_NAME); \
( cd $(DESTDIR)$(bindir) && \
$(LN) $(GCC_INSTALL_NAME)$(exeext) $(target_noncanonical)-gcc-$(version)$(exeext) ); \
$(LN) $(GCC_INSTALL_NAME)$(exeext) $(FULL_DRIVER_NAME) ); \
fi
-if [ ! -f gcc-cross$(exeext) ] \
&& [ "$(GCC_INSTALL_NAME)" != "$(GCC_TARGET_INSTALL_NAME)" ]; then \

52
gcc/configure vendored
View File

@ -743,6 +743,7 @@ CXXDEPMODE
DEPDIR
am__leading_dot
CXXCPP
doc_build_sys
AR
NM
BISON
@ -8069,6 +8070,47 @@ fi
fi
# The jit documentation looks better if built with sphinx, but can be
# built with texinfo if sphinx is not available.
# Set "doc_build_sys" to "sphinx" or "texinfo" accordingly.
# Extract the first word of "sphinx-build", so it can be a program name with args.
set dummy sphinx-build; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if test "${ac_cv_prog_doc_build_sys+set}" = set; then :
$as_echo_n "(cached) " >&6
else
if test -n "$doc_build_sys"; then
ac_cv_prog_doc_build_sys="$doc_build_sys" # Let the user override the test.
else
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
ac_cv_prog_doc_build_sys="sphinx"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
fi
done
done
IFS=$as_save_IFS
test -z "$ac_cv_prog_doc_build_sys" && ac_cv_prog_doc_build_sys="texinfo"
fi
fi
doc_build_sys=$ac_cv_prog_doc_build_sys
if test -n "$doc_build_sys"; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $doc_build_sys" >&5
$as_echo "$doc_build_sys" >&6; }
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi
# --------------------
# Checks for C headers
@ -18058,7 +18100,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
#line 18061 "configure"
#line 18103 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@ -18164,7 +18206,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
#line 18167 "configure"
#line 18209 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@ -28185,6 +28227,12 @@ _ACEOF
fi
# Generate gcc-driver-name.h containing GCC_DRIVER_NAME for the benefit
# of jit/jit-playback.c.
cat > gcc-driver-name.h <<EOF
#define GCC_DRIVER_NAME "${target_noncanonical}-gcc-${gcc_BASEVER}${exeext}"
EOF
# Configure the subdirectories
# AC_CONFIG_SUBDIRS($subdirs)

View File

@ -971,6 +971,10 @@ else
AC_CHECK_PROG(AR, ar, ar, ${CONFIG_SHELL-/bin/sh} ${srcdir}/../missing ar)
fi
# The jit documentation looks better if built with sphinx, but can be
# built with texinfo if sphinx is not available.
# Set "doc_build_sys" to "sphinx" or "texinfo" accordingly.
AC_CHECK_PROG(doc_build_sys, sphinx-build, sphinx, texinfo)
# --------------------
# Checks for C headers
@ -5604,6 +5608,12 @@ if test x"${LINKER_HASH_STYLE}" != x; then
[The linker hash style])
fi
# Generate gcc-driver-name.h containing GCC_DRIVER_NAME for the benefit
# of jit/jit-playback.c.
cat > gcc-driver-name.h <<EOF
#define GCC_DRIVER_NAME "${target_noncanonical}-gcc-${gcc_BASEVER}${exeext}"
EOF
# Configure the subdirectories
# AC_CONFIG_SUBDIRS($subdirs)

View File

@ -476,6 +476,11 @@ Necessary for running @command{texi2dvi} and @command{texi2pdf}, which
are used when running @command{make dvi} or @command{make pdf} to create
DVI or PDF files, respectively.
@item Sphinx version 1.0 (or later)
Necessary to regenerate @file{jit/docs/_build/texinfo} from the @file{.rst}
files in the directories below @file{jit/docs}.
@item SVN (any version)
@itemx SSH (any version)
@ -939,7 +944,7 @@ Specify that the @emph{host} code should be built into position-independent
machine code (with -fPIC), allowing it to be used within shared libraries,
but yielding a slightly slower compiler.
Currently this option is only of use to people developing GCC itself.
This option is required when building the libgccjit.so library.
Contrast with @option{--enable-shared}, which affects @emph{target}
libraries.

View File

@ -1,3 +1,7 @@
2014-11-11 David Malcolm <dmalcolm@redhat.com>
* gcc/ChangeLog.jit: New.
2014-10-29 Richard Sandiford <richard.sandiford@arm.com>
* builtins.c, java-tree.h, typeck.c: Remove redundant enum from

14
gcc/java/ChangeLog.jit Normal file
View File

@ -0,0 +1,14 @@
2014-09-24 David Malcolm <dmalcolm@redhat.com>
* ChangeLog.jit: Add copyright footer.
2013-10-11 David Malcolm <dmalcolm@redhat.com>
* lang.c (java_handle_option): Update for introduction of
gcc::dump_manager.
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.

60
gcc/jit/ChangeLog Normal file
View File

@ -0,0 +1,60 @@
2014-11-11 David Malcolm <dmalcolm@redhat.com>
* ChangeLog.jit: New.
* ChangeLog: New.
* Make-lang.in: New.
* TODO.rst: New.
* config-lang.in: New.
* docs/Makefile: New.
* docs/_build/texinfo/Makefile: New.
* docs/_build/texinfo/factorial.png: New.
* docs/_build/texinfo/libgccjit.texi: New.
* docs/_build/texinfo/sum-of-squares.png: New.
* docs/conf.py: New.
* docs/examples/tut01-hello-world.c: New.
* docs/examples/tut02-square.c: New.
* docs/examples/tut03-sum-of-squares.c: New.
* docs/examples/tut04-toyvm/Makefile: New.
* docs/examples/tut04-toyvm/factorial.toy: New.
* docs/examples/tut04-toyvm/fibonacci.toy: New.
* docs/examples/tut04-toyvm/toyvm.c: New.
* docs/index.rst: New.
* docs/internals/index.rst: New.
* docs/intro/factorial.png: New.
* docs/intro/index.rst: New.
* docs/intro/sum-of-squares.png: New.
* docs/intro/tutorial01.rst: New.
* docs/intro/tutorial02.rst: New.
* docs/intro/tutorial03.rst: New.
* docs/intro/tutorial04.rst: New.
* docs/topics/contexts.rst: New.
* docs/topics/expressions.rst: New.
* docs/topics/functions.rst: New.
* docs/topics/index.rst: New.
* docs/topics/locations.rst: New.
* docs/topics/objects.rst: New.
* docs/topics/results.rst: New.
* docs/topics/types.rst: New.
* dummy-frontend.c: New.
* jit-builtins.c: New.
* jit-builtins.h: New.
* jit-common.h: New.
* jit-playback.c: New.
* jit-playback.h: New.
* jit-recording.c: New.
* jit-recording.h: New.
* libgccjit++.h: New.
* libgccjit.c: New.
* libgccjit.h: New.
* libgccjit.map: New.
* notes.txt: New.
2013-07-26 David Malcolm <dmalcolm@redhat.com>
* Initial creation
Copyright (C) 2013-2014 Free Software Foundation, Inc.
Copying and distribution of this file, with or without modification,
are permitted in any medium without royalty provided the copyright
notice and this notice are preserved.

3498
gcc/jit/ChangeLog.jit Normal file

File diff suppressed because it is too large Load Diff

298
gcc/jit/Make-lang.in Normal file
View File

@ -0,0 +1,298 @@
# Top level -*- makefile -*- fragment for libgccjit.so.
# Copyright (C) 2013-2014 Free Software Foundation, Inc.
#This file is part of GCC.
#GCC is free software; you can redistribute it and/or modify
#it under the terms of the GNU General Public License as published by
#the Free Software Foundation; either version 3, or (at your option)
#any later version.
#GCC is distributed in the hope that it will be useful,
#but WITHOUT ANY WARRANTY; without even the implied warranty of
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
#GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with GCC; see the file COPYING3. If not see
# <http://www.gnu.org/licenses/>.
# This file provides the language dependent support in the main Makefile.
# Each language makefile fragment must provide the following targets:
#
# foo.all.cross, foo.start.encap, foo.rest.encap,
# foo.install-common, foo.install-man, foo.install-info, foo.install-pdf,
# foo.install-html, foo.info, foo.dvi, foo.pdf, foo.html, foo.uninstall,
# foo.mostlyclean, foo.clean, foo.distclean,
# foo.maintainer-clean, foo.stage1, foo.stage2, foo.stage3, foo.stage4
#
# where `foo' is the name of the language.
#
# It should also provide rules for:
#
# - making any compiler driver (eg: g++)
# - the compiler proper (eg: cc1plus)
# - define the names for selecting the language in LANGUAGES.
#
# 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)
#
# 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
#
# 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:
#
# Clean hooks:
# A lot of the ancillary files are deleted by the main makefile.
# We just have to delete files specific to us.
jit.mostlyclean:
jit.clean:
jit.distclean:
jit.maintainer-clean:
#
# Stage hooks:
# The main makefile has already created stage?/jit.
jit.stage1: stage1-start
-mv jit/*$(objext) stage1/jit
jit.stage2: stage2-start
-mv jit/*$(objext) stage2/jit
jit.stage3: stage3-start
-mv jit/*$(objext) stage3/jit
jit.stage4: stage4-start
-mv jit/*$(objext) stage4/jit
jit.stageprofile: stageprofile-start
-mv jit/*$(objext) stageprofile/jit
jit.stagefeedback: stagefeedback-start
-mv jit/*$(objext) stagefeedback/jit

119
gcc/jit/TODO.rst Normal file
View File

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

38
gcc/jit/config-lang.in Normal file
View File

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

153
gcc/jit/docs/Makefile Normal file
View File

@ -0,0 +1,153 @@
# Makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
PAPER =
BUILDDIR = _build
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
# the i18n builder cannot share the environment and doctrees with the others
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
help:
@echo "Please use \`make <target>' where <target> is one of"
@echo " html to make standalone HTML files"
@echo " dirhtml to make HTML files named index.html in directories"
@echo " singlehtml to make a single large HTML file"
@echo " pickle to make pickle files"
@echo " json to make JSON files"
@echo " htmlhelp to make HTML files and a HTML help project"
@echo " qthelp to make HTML files and a qthelp project"
@echo " devhelp to make HTML files and a Devhelp project"
@echo " epub to make an epub"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
@echo " latexpdf to make LaTeX files and run them through pdflatex"
@echo " text to make text files"
@echo " man to make manual pages"
@echo " texinfo to make Texinfo files"
@echo " info to make Texinfo files and run them through makeinfo"
@echo " gettext to make PO message catalogs"
@echo " changes to make an overview of all changed/added/deprecated items"
@echo " linkcheck to check all external links for integrity"
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
clean:
-rm -rf $(BUILDDIR)/*
html:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
dirhtml:
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
singlehtml:
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
@echo
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
pickle:
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
@echo
@echo "Build finished; now you can process the pickle files."
json:
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
@echo
@echo "Build finished; now you can process the JSON files."
htmlhelp:
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in $(BUILDDIR)/htmlhelp."
qthelp:
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/libgccjit.qhcp"
@echo "To view the help file:"
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/libgccjit.qhc"
devhelp:
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
@echo
@echo "Build finished."
@echo "To view the help file:"
@echo "# mkdir -p $$HOME/.local/share/devhelp/libgccjit"
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/libgccjit"
@echo "# devhelp"
epub:
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
@echo
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
latex:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
@echo "Run \`make' in that directory to run these through (pdf)latex" \
"(use \`make latexpdf' here to do that automatically)."
latexpdf:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through pdflatex..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
text:
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
@echo
@echo "Build finished. The text files are in $(BUILDDIR)/text."
man:
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
@echo
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
texinfo:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
@echo "Run \`make' in that directory to run these through makeinfo" \
"(use \`make info' here to do that automatically)."
info:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo "Running Texinfo files through makeinfo..."
make -C $(BUILDDIR)/texinfo info
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
gettext:
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
@echo
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
changes:
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
@echo
@echo "The overview file is in $(BUILDDIR)/changes."
linkcheck:
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
@echo
@echo "Link check complete; look for any errors in the above output " \
"or in $(BUILDDIR)/linkcheck/output.txt."
doctest:
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
@echo "Testing of doctests in the sources finished, look at the " \
"results in $(BUILDDIR)/doctest/output.txt."

50
gcc/jit/docs/_build/texinfo/Makefile vendored Normal file
View File

@ -0,0 +1,50 @@
# Makefile for Sphinx Texinfo output
infodir ?= /usr/share/info
MAKEINFO = makeinfo --no-split
MAKEINFO_html = makeinfo --no-split --html
MAKEINFO_plaintext = makeinfo --no-split --plaintext
TEXI2PDF = texi2pdf --batch --expand
INSTALL_INFO = install-info
ALLDOCS = $(basename $(wildcard *.texi))
all: info
info: $(addsuffix .info,$(ALLDOCS))
plaintext: $(addsuffix .txt,$(ALLDOCS))
html: $(addsuffix .html,$(ALLDOCS))
pdf: $(addsuffix .pdf,$(ALLDOCS))
install-info: info
for f in *.info; do \
cp -t $(infodir) "$$f" && \
$(INSTALL_INFO) --info-dir=$(infodir) "$$f" ; \
done
uninstall-info: info
for f in *.info; do \
rm -f "$(infodir)/$$f" ; \
$(INSTALL_INFO) --delete --info-dir=$(infodir) "$$f" ; \
done
%.info: %.texi
$(MAKEINFO) -o '$@' '$<'
%.txt: %.texi
$(MAKEINFO_plaintext) -o '$@' '$<'
%.html: %.texi
$(MAKEINFO_html) -o '$@' '$<'
%.pdf: %.texi
-$(TEXI2PDF) '$<'
-$(TEXI2PDF) '$<'
-$(TEXI2PDF) '$<'
clean:
-rm -f *.info *.pdf *.txt *.html
-rm -f *.log *.ind *.aux *.toc *.syn *.idx *.out *.ilg *.pla *.ky *.pg
-rm -f *.vr *.tp *.fn *.fns *.def *.defs *.cp *.cps *.ge *.ges *.mo
.PHONY: all info plaintext html pdf install-info uninstall-info clean

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 KiB

6537
gcc/jit/docs/_build/texinfo/libgccjit.texi vendored Normal file

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

258
gcc/jit/docs/conf.py Normal file
View File

@ -0,0 +1,258 @@
# -*- coding: utf-8 -*-
#
# libgccjit documentation build configuration file, created by
# sphinx-quickstart on Wed Jul 30 13:39:01 2014.
#
# This file is execfile()d with the current directory set to its containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
import sys, os
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#sys.path.insert(0, os.path.abspath('.'))
# -- General configuration -----------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = []
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix of source filenames.
source_suffix = '.rst'
# The encoding of source files.
#source_encoding = 'utf-8-sig'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = u'libgccjit'
copyright = u'2014, Free Software Foundation'
# GCC-specific: extract version information from "gcc" src subdir for
# use in "version" and "release" below.
def __read_file(name):
gcc_srcdir = '../..'
path = os.path.join(gcc_srcdir, name)
if os.path.exists(path):
return open(path).read().strip()
else:
return ''
gcc_BASEVER = __read_file('BASE-VER')
gcc_DEVPHASE = __read_file('DEV-PHASE')
gcc_DATESTAMP = __read_file('DATESTAMP')
gcc_REVISION = __read_file('REVISION')
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = gcc_BASEVER
# The full version, including alpha/beta/rc tags.
release = ('%s (%s %s%s)'
% (gcc_BASEVER, gcc_DEVPHASE, gcc_DATESTAMP,
(' %s' % gcc_REVISION) if gcc_REVISION else ''))
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
#today_fmt = '%B %d, %Y'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ['_build']
# The reST default role (used for this markup: `text`) to use for all documents.
#default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []
# -- Options for HTML output ---------------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
html_theme = 'pyramid'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
#html_theme_path = []
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
#html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
#html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#html_logo = None
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}
# If false, no module index is generated.
#html_domain_indices = True
# If false, no index is generated.
#html_use_index = True
# If true, the index is split into individual pages for each letter.
#html_split_index = False
# If true, links to the reST sources are added to the pages.
#html_show_sourcelink = True
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
#html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
#html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = None
# Output file base name for HTML help builder.
htmlhelp_basename = 'libgccjitdoc'
# -- Options for LaTeX output --------------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#'preamble': '',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual]).
latex_documents = [
('index', 'libgccjit.tex', u'libgccjit Documentation',
u'David Malcolm', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False
# If true, show page references after internal links.
#latex_show_pagerefs = False
# If true, show URL addresses after external links.
#latex_show_urls = False
# Documents to append as an appendix to all manuals.
#latex_appendices = []
# If false, no module index is generated.
#latex_domain_indices = True
# -- Options for manual page output --------------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
('index', 'libgccjit', u'libgccjit Documentation',
[u'David Malcolm'], 1)
]
# If true, show URL addresses after external links.
#man_show_urls = False
# -- Options for Texinfo output ------------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
('index', 'libgccjit', u'libgccjit Documentation',
u'David Malcolm', 'libgccjit', 'One line description of project.',
'Miscellaneous'),
]
# Documents to append as an appendix to all manuals.
#texinfo_appendices = []
# If false, no module index is generated.
#texinfo_domain_indices = True
# How to display URL addresses: 'footnote', 'no', or 'inline'.
#texinfo_show_urls = 'footnote'

View File

@ -0,0 +1,123 @@
/* Smoketest example for libgccjit.so
Copyright (C) 2014 Free Software Foundation, Inc.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
GCC is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#include <libgccjit.h>
#include <stdlib.h>
#include <stdio.h>
static void
create_code (gcc_jit_context *ctxt)
{
/* Let's try to inject the equivalent of:
void
greet (const char *name)
{
printf ("hello %s\n", name);
}
*/
gcc_jit_type *void_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
gcc_jit_type *const_char_ptr_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_CONST_CHAR_PTR);
gcc_jit_param *param_name =
gcc_jit_context_new_param (ctxt, NULL, const_char_ptr_type, "name");
gcc_jit_function *func =
gcc_jit_context_new_function (ctxt, NULL,
GCC_JIT_FUNCTION_EXPORTED,
void_type,
"greet",
1, &param_name,
0);
gcc_jit_param *param_format =
gcc_jit_context_new_param (ctxt, NULL, const_char_ptr_type, "format");
gcc_jit_function *printf_func =
gcc_jit_context_new_function (ctxt, NULL,
GCC_JIT_FUNCTION_IMPORTED,
gcc_jit_context_get_type (
ctxt, GCC_JIT_TYPE_INT),
"printf",
1, &param_format,
1);
gcc_jit_rvalue *args[2];
args[0] = gcc_jit_context_new_string_literal (ctxt, "hello %s\n");
args[1] = gcc_jit_param_as_rvalue (param_name);
gcc_jit_block *block = gcc_jit_function_new_block (func, NULL);
gcc_jit_block_add_eval (
block, NULL,
gcc_jit_context_new_call (ctxt,
NULL,
printf_func,
2, args));
gcc_jit_block_end_with_void_return (block, NULL);
}
int
main (int argc, char **argv)
{
gcc_jit_context *ctxt;
gcc_jit_result *result;
/* Get a "context" object for working with the library. */
ctxt = gcc_jit_context_acquire ();
if (!ctxt)
{
fprintf (stderr, "NULL ctxt");
exit (1);
}
/* Set some options on the context.
Let's see the code being generated, in assembler form. */
gcc_jit_context_set_bool_option (
ctxt,
GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE,
0);
/* Populate the context. */
create_code (ctxt);
/* Compile the code. */
result = gcc_jit_context_compile (ctxt);
if (!result)
{
fprintf (stderr, "NULL result");
exit (1);
}
/* Extract the generated code from "result". */
typedef void (*fn_type) (const char *);
fn_type greet =
(fn_type)gcc_jit_result_get_code (result, "greet");
if (!greet)
{
fprintf (stderr, "NULL greet");
exit (1);
}
/* Now call the generated function: */
greet ("world");
fflush (stdout);
gcc_jit_context_release (ctxt);
gcc_jit_result_release (result);
return 0;
}

View File

@ -0,0 +1,107 @@
/* Usage example for libgccjit.so
Copyright (C) 2014 Free Software Foundation, Inc.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
GCC is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#include <libgccjit.h>
#include <stdlib.h>
#include <stdio.h>
void
create_code (gcc_jit_context *ctxt)
{
/* Let's try to inject the equivalent of:
int square (int i)
{
return i * i;
}
*/
gcc_jit_type *int_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
gcc_jit_param *param_i =
gcc_jit_context_new_param (ctxt, NULL, int_type, "i");
gcc_jit_function *func =
gcc_jit_context_new_function (ctxt, NULL,
GCC_JIT_FUNCTION_EXPORTED,
int_type,
"square",
1, &param_i,
0);
gcc_jit_block *block = gcc_jit_function_new_block (func, NULL);
gcc_jit_rvalue *expr =
gcc_jit_context_new_binary_op (
ctxt, NULL,
GCC_JIT_BINARY_OP_MULT, int_type,
gcc_jit_param_as_rvalue (param_i),
gcc_jit_param_as_rvalue (param_i));
gcc_jit_block_end_with_return (block, NULL, expr);
}
int
main (int argc, char **argv)
{
gcc_jit_context *ctxt = NULL;
gcc_jit_result *result = NULL;
/* Get a "context" object for working with the library. */
ctxt = gcc_jit_context_acquire ();
if (!ctxt)
{
fprintf (stderr, "NULL ctxt");
goto error;
}
/* Set some options on the context.
Let's see the code being generated, in assembler form. */
gcc_jit_context_set_bool_option (
ctxt,
GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE,
0);
/* Populate the context. */
create_code (ctxt);
/* Compile the code. */
result = gcc_jit_context_compile (ctxt);
if (!result)
{
fprintf (stderr, "NULL result");
goto error;
}
/* Extract the generated code from "result". */
void *fn_ptr = gcc_jit_result_get_code (result, "square");
if (!fn_ptr)
{
fprintf (stderr, "NULL fn_ptr");
goto error;
}
typedef int (*fn_type) (int);
fn_type square = (fn_type)fn_ptr;
printf ("result: %d", square (5));
error:
gcc_jit_context_release (ctxt);
gcc_jit_result_release (result);
return 0;
}

View File

@ -0,0 +1,172 @@
/* Usage example for libgccjit.so
Copyright (C) 2014 Free Software Foundation, Inc.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
GCC is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#include <libgccjit.h>
#include <stdlib.h>
#include <stdio.h>
void
create_code (gcc_jit_context *ctxt)
{
/*
Simple sum-of-squares, to test conditionals and looping
int loop_test (int n)
{
int i;
int sum = 0;
for (i = 0; i < n ; i ++)
{
sum += i * i;
}
return sum;
*/
gcc_jit_type *the_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
gcc_jit_type *return_type = the_type;
gcc_jit_param *n =
gcc_jit_context_new_param (ctxt, NULL, the_type, "n");
gcc_jit_param *params[1] = {n};
gcc_jit_function *func =
gcc_jit_context_new_function (ctxt, NULL,
GCC_JIT_FUNCTION_EXPORTED,
return_type,
"loop_test",
1, params, 0);
/* Build locals: */
gcc_jit_lvalue *i =
gcc_jit_function_new_local (func, NULL, the_type, "i");
gcc_jit_lvalue *sum =
gcc_jit_function_new_local (func, NULL, the_type, "sum");
gcc_jit_block *b_initial =
gcc_jit_function_new_block (func, "initial");
gcc_jit_block *b_loop_cond =
gcc_jit_function_new_block (func, "loop_cond");
gcc_jit_block *b_loop_body =
gcc_jit_function_new_block (func, "loop_body");
gcc_jit_block *b_after_loop =
gcc_jit_function_new_block (func, "after_loop");
/* sum = 0; */
gcc_jit_block_add_assignment (
b_initial, NULL,
sum,
gcc_jit_context_zero (ctxt, the_type));
/* i = 0; */
gcc_jit_block_add_assignment (
b_initial, NULL,
i,
gcc_jit_context_zero (ctxt, the_type));
gcc_jit_block_end_with_jump (b_initial, NULL, b_loop_cond);
/* if (i >= n) */
gcc_jit_block_end_with_conditional (
b_loop_cond, NULL,
gcc_jit_context_new_comparison (
ctxt, NULL,
GCC_JIT_COMPARISON_GE,
gcc_jit_lvalue_as_rvalue (i),
gcc_jit_param_as_rvalue (n)),
b_after_loop,
b_loop_body);
/* sum += i * i */
gcc_jit_block_add_assignment_op (
b_loop_body, NULL,
sum,
GCC_JIT_BINARY_OP_PLUS,
gcc_jit_context_new_binary_op (
ctxt, NULL,
GCC_JIT_BINARY_OP_MULT, the_type,
gcc_jit_lvalue_as_rvalue (i),
gcc_jit_lvalue_as_rvalue (i)));
/* i++ */
gcc_jit_block_add_assignment_op (
b_loop_body, NULL,
i,
GCC_JIT_BINARY_OP_PLUS,
gcc_jit_context_one (ctxt, the_type));
gcc_jit_block_end_with_jump (b_loop_body, NULL, b_loop_cond);
/* return sum */
gcc_jit_block_end_with_return (
b_after_loop,
NULL,
gcc_jit_lvalue_as_rvalue (sum));
}
int
main (int argc, char **argv)
{
gcc_jit_context *ctxt = NULL;
gcc_jit_result *result = NULL;
/* Get a "context" object for working with the library. */
ctxt = gcc_jit_context_acquire ();
if (!ctxt)
{
fprintf (stderr, "NULL ctxt");
goto error;
}
/* Set some options on the context.
Let's see the code being generated, in assembler form. */
gcc_jit_context_set_bool_option (
ctxt,
GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE,
0);
/* Populate the context. */
create_code (ctxt);
/* Compile the code. */
result = gcc_jit_context_compile (ctxt);
if (!result)
{
fprintf (stderr, "NULL result");
goto error;
}
/* Extract the generated code from "result". */
typedef int (*loop_test_fn_type) (int);
loop_test_fn_type loop_test =
(loop_test_fn_type)gcc_jit_result_get_code (result, "loop_test");
if (!loop_test)
{
fprintf (stderr, "NULL loop_test");
goto error;
}
/* Run the generated code. */
int val = loop_test (10);
printf("loop_test returned: %d\n", val);
error:
gcc_jit_context_release (ctxt);
gcc_jit_result_release (result);
return 0;
}

View File

@ -0,0 +1,11 @@
factorial: toyvm
./toyvm factorial.toy 10
fibonacci: toyvm
./toyvm fibonacci.toy 8
toyvm: toyvm.c Makefile
g++ -Wall -g -o $@ $< $(shell pkg-config --cflags --libs libgccjit)
clean:
rm -f *.o toyvm

View File

@ -0,0 +1,50 @@
# Simple recursive factorial implementation, roughly equivalent to:
#
# int factorial (int arg)
# {
# if (arg < 2)
# return arg
# return arg * factorial (arg - 1)
# }
# Initial state:
# stack: [arg]
# 0:
DUP
# stack: [arg, arg]
# 1:
PUSH_CONST 2
# stack: [arg, arg, 2]
# 2:
BINARY_COMPARE_LT
# stack: [arg, (arg < 2)]
# 3:
JUMP_ABS_IF_TRUE 9
# stack: [arg]
# 4:
DUP
# stack: [arg, arg]
# 5:
PUSH_CONST 1
# stack: [arg, arg, 1]
# 6:
BINARY_SUBTRACT
# stack: [arg, (arg - 1)
# 7:
RECURSE
# stack: [arg, factorial(arg - 1)]
# 8:
BINARY_MULT
# stack: [arg * factorial(arg - 1)]
# 9:
RETURN

View File

@ -0,0 +1,66 @@
# Simple recursive fibonacci implementation, roughly equivalent to:
#
# int fibonacci (int arg)
# {
# if (arg < 2)
# return arg
# return fibonacci (arg-1) + fibonacci (arg-2)
# }
# Initial state:
# stack: [arg]
# 0:
DUP
# stack: [arg, arg]
# 1:
PUSH_CONST 2
# stack: [arg, arg, 2]
# 2:
BINARY_COMPARE_LT
# stack: [arg, (arg < 2)]
# 3:
JUMP_ABS_IF_TRUE 13
# stack: [arg]
# 4:
DUP
# stack: [arg, arg]
# 5:
PUSH_CONST 1
# stack: [arg, arg, 1]
# 6:
BINARY_SUBTRACT
# stack: [arg, (arg - 1)
# 7:
RECURSE
# stack: [arg, fib(arg - 1)]
# 8:
ROT
# stack: [fib(arg - 1), arg]
# 9:
PUSH_CONST 2
# stack: [fib(arg - 1), arg, 2]
# 10:
BINARY_SUBTRACT
# stack: [fib(arg - 1), arg, (arg - 2)
# 11:
RECURSE
# stack: [fib(arg - 1), fib(arg - 1)]
# 12:
BINARY_ADD
# stack: [fib(arg - 1) + fib(arg - 1)]
# 13:
RETURN

View File

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

50
gcc/jit/docs/index.rst Normal file
View File

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

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 KiB

View File

@ -0,0 +1,27 @@
.. Copyright (C) 2014 Free Software Foundation, Inc.
Originally contributed by David Malcolm <dmalcolm@redhat.com>
This is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see
<http://www.gnu.org/licenses/>.
Tutorial
========
.. toctree::
:maxdepth: 2
tutorial01.rst
tutorial02.rst
tutorial03.rst
tutorial04.rst

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

View File

@ -0,0 +1,52 @@
.. Copyright (C) 2014 Free Software Foundation, Inc.
Originally contributed by David Malcolm <dmalcolm@redhat.com>
This is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see
<http://www.gnu.org/licenses/>.
.. default-domain:: c
Tutorial part 1: "Hello world"
==============================
Before we look at the details of the API, let's look at building and
running programs that use the library.
Here's a toy "hello world" program that uses the library to synthesize
a call to `printf` and uses it to write a message to stdout.
Don't worry about the content of the program for now; we'll cover
the details in later parts of this tutorial.
.. literalinclude:: ../examples/tut01-hello-world.c
:language: c
Copy the above to `tut01-hello-world.c`.
Assuming you have the jit library installed, build the test program
using:
.. code-block:: console
$ gcc \
tut01-hello-world.c \
-o tut01-hello-world \
-lgccjit
You should then be able to run the built program:
.. code-block:: console
$ ./tut01-hello-world
hello world

View File

@ -0,0 +1,349 @@
.. Copyright (C) 2014 Free Software Foundation, Inc.
Originally contributed by David Malcolm <dmalcolm@redhat.com>
This is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see
<http://www.gnu.org/licenses/>.
.. default-domain:: c
Tutorial part 2: Creating a trivial machine code function
---------------------------------------------------------
Consider this C function:
.. code-block:: c
int square (int i)
{
return i * i;
}
How can we construct this at run-time using libgccjit?
First we need to include the relevant header:
.. code-block:: c
#include <libgccjit.h>
All state associated with compilation is associated with a
:c:type:`gcc_jit_context *`.
Create one using :c:func:`gcc_jit_context_acquire`:
.. code-block:: c
gcc_jit_context *ctxt;
ctxt = gcc_jit_context_acquire ();
The JIT library has a system of types. It is statically-typed: every
expression is of a specific type, fixed at compile-time. In our example,
all of the expressions are of the C `int` type, so let's obtain this from
the context, as a :c:type:`gcc_jit_type *`, using
:c:func:`gcc_jit_context_get_type`:
.. code-block:: c
gcc_jit_type *int_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
:c:type:`gcc_jit_type *` is an example of a "contextual" object: every
entity in the API is associated with a :c:type:`gcc_jit_context *`.
Memory management is easy: all such "contextual" objects are automatically
cleaned up for you when the context is released, using
:c:func:`gcc_jit_context_release`:
.. code-block:: c
gcc_jit_context_release (ctxt);
so you don't need to manually track and cleanup all objects, just the
contexts.
Although the API is C-based, there is a form of class hierarchy, which
looks like this::
+- gcc_jit_object
+- gcc_jit_location
+- gcc_jit_type
+- gcc_jit_struct
+- gcc_jit_field
+- gcc_jit_function
+- gcc_jit_block
+- gcc_jit_rvalue
+- gcc_jit_lvalue
+- gcc_jit_param
There are casting methods for upcasting from subclasses to parent classes.
For example, :c:func:`gcc_jit_type_as_object`:
.. code-block:: c
gcc_jit_object *obj = gcc_jit_type_as_object (int_type);
One thing you can do with a :c:type:`gcc_jit_object *` is
to ask it for a human-readable description, using
:c:func:`gcc_jit_object_get_debug_string`:
.. code-block:: c
printf ("obj: %s\n", gcc_jit_object_get_debug_string (obj));
giving this text on stdout:
.. code-block:: bash
obj: int
This is invaluable when debugging.
Let's create the function. To do so, we first need to construct
its single parameter, specifying its type and giving it a name,
using :c:func:`gcc_jit_context_new_param`:
.. code-block:: c
gcc_jit_param *param_i =
gcc_jit_context_new_param (ctxt, NULL, int_type, "i");
Now we can create the function, using
:c:func:`gcc_jit_context_new_function`:
.. code-block:: c
gcc_jit_function *func =
gcc_jit_context_new_function (ctxt, NULL,
GCC_JIT_FUNCTION_EXPORTED,
int_type,
"square",
1, &param_i,
0);
To define the code within the function, we must create basic blocks
containing statements.
Every basic block contains a list of statements, eventually terminated
by a statement that either returns, or jumps to another basic block.
Our function has no control-flow, so we just need one basic block:
.. code-block:: c
gcc_jit_block *block = gcc_jit_function_new_block (func, NULL);
Our basic block is relatively simple: it immediately terminates by
returning the value of an expression.
We can build the expression using :c:func:`gcc_jit_context_new_binary_op`:
.. code-block:: c
gcc_jit_rvalue *expr =
gcc_jit_context_new_binary_op (
ctxt, NULL,
GCC_JIT_BINARY_OP_MULT, int_type,
gcc_jit_param_as_rvalue (param_i),
gcc_jit_param_as_rvalue (param_i));
A :c:type:`gcc_jit_rvalue *` is another example of a
:c:type:`gcc_jit_object *` subclass. We can upcast it using
:c:func:`gcc_jit_rvalue_as_object` and as before print it with
:c:func:`gcc_jit_object_get_debug_string`.
.. code-block:: c
printf ("expr: %s\n",
gcc_jit_object_get_debug_string (
gcc_jit_rvalue_as_object (expr)));
giving this output:
.. code-block:: bash
expr: i * i
Creating the expression in itself doesn't do anything; we have to add
this expression to a statement within the block. In this case, we use it
to build a return statement, which terminates the basic block:
.. code-block:: c
gcc_jit_block_end_with_return (block, NULL, expr);
OK, we've populated the context. We can now compile it using
:c:func:`gcc_jit_context_compile`:
.. code-block:: c
gcc_jit_result *result;
result = gcc_jit_context_compile (ctxt);
and get a :c:type:`gcc_jit_result *`.
We can now use :c:func:`gcc_jit_result_get_code` to look up a specific
machine code routine within the result, in this case, the function we
created above.
.. code-block:: c
void *fn_ptr = gcc_jit_result_get_code (result, "square");
if (!fn_ptr)
{
fprintf (stderr, "NULL fn_ptr");
goto error;
}
We can now cast the pointer to an appropriate function pointer type, and
then call it:
.. code-block:: c
typedef int (*fn_type) (int);
fn_type square = (fn_type)fn_ptr;
printf ("result: %d", square (5));
.. code-block:: bash
result: 25
Options
*******
To get more information on what's going on, you can set debugging flags
on the context using :c:func:`gcc_jit_context_set_bool_option`.
.. (I'm deliberately not mentioning
:c:macro:`GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE` here since I think
it's probably more of use to implementors than to users)
Setting :c:macro:`GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE` will dump a
C-like representation to stderr when you compile (GCC's "GIMPLE"
representation):
.. code-block:: c
gcc_jit_context_set_bool_option (
ctxt,
GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE,
1);
result = gcc_jit_context_compile (ctxt);
.. code-block:: c
square (signed int i)
{
signed int D.260;
entry:
D.260 = i * i;
return D.260;
}
We can see the generated machine code in assembler form (on stderr) by
setting :c:macro:`GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE` on the context
before compiling:
.. code-block:: c
gcc_jit_context_set_bool_option (
ctxt,
GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE,
1);
result = gcc_jit_context_compile (ctxt);
.. code-block:: gas
.file "fake.c"
.text
.globl square
.type square, @function
square:
.LFB6:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl %edi, -4(%rbp)
.L14:
movl -4(%rbp), %eax
imull -4(%rbp), %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE6:
.size square, .-square
.ident "GCC: (GNU) 4.9.0 20131023 (Red Hat 0.2-0.5.1920c315ff984892399893b380305ab36e07b455.fc20)"
.section .note.GNU-stack,"",@progbits
By default, no optimizations are performed, the equivalent of GCC's
`-O0` option. We can turn things up to e.g. `-O3` by calling
:c:func:`gcc_jit_context_set_int_option` with
:c:macro:`GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL`:
.. code-block:: c
gcc_jit_context_set_int_option (
ctxt,
GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL,
3);
.. code-block:: gas
.file "fake.c"
.text
.p2align 4,,15
.globl square
.type square, @function
square:
.LFB7:
.cfi_startproc
.L16:
movl %edi, %eax
imull %edi, %eax
ret
.cfi_endproc
.LFE7:
.size square, .-square
.ident "GCC: (GNU) 4.9.0 20131023 (Red Hat 0.2-0.5.1920c315ff984892399893b380305ab36e07b455.fc20)"
.section .note.GNU-stack,"",@progbits
Naturally this has only a small effect on such a trivial function.
Full example
************
Here's what the above looks like as a complete program:
.. literalinclude:: ../examples/tut02-square.c
:lines: 1-
:language: c
Building and running it:
.. code-block:: console
$ gcc \
tut02-square.c \
-o tut02-square \
-lgccjit
# Run the built program:
$ ./tut02-square
result: 25

View File

@ -0,0 +1,378 @@
.. Copyright (C) 2014 Free Software Foundation, Inc.
Originally contributed by David Malcolm <dmalcolm@redhat.com>
This is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see
<http://www.gnu.org/licenses/>.
Tutorial part 3: Loops and variables
------------------------------------
Consider this C function:
.. code-block:: c
int loop_test (int n)
{
int sum = 0;
for (int i = 0; i < n; i++)
sum += i * i;
return sum;
}
This example demonstrates some more features of libgccjit, with local
variables and a loop.
To break this down into libgccjit terms, it's usually easier to reword
the `for` loop as a `while` loop, giving:
.. code-block:: c
int loop_test (int n)
{
int sum = 0;
int i = 0;
while (i < n)
{
sum += i * i;
i++;
}
return sum;
}
Here's what the final control flow graph will look like:
.. figure:: sum-of-squares.png
:alt: image of a control flow graph
As before, we include the libgccjit header and make a
:c:type:`gcc_jit_context *`.
.. code-block:: c
#include <libgccjit.h>
void test (void)
{
gcc_jit_context *ctxt;
ctxt = gcc_jit_context_acquire ();
The function works with the C `int` type:
.. code-block:: c
gcc_jit_type *the_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
gcc_jit_type *return_type = the_type;
though we could equally well make it work on, say, `double`:
.. code-block:: c
gcc_jit_type *the_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_DOUBLE);
Let's build the function:
.. code-block:: c
gcc_jit_param *n =
gcc_jit_context_new_param (ctxt, NULL, the_type, "n");
gcc_jit_param *params[1] = {n};
gcc_jit_function *func =
gcc_jit_context_new_function (ctxt, NULL,
GCC_JIT_FUNCTION_EXPORTED,
return_type,
"loop_test",
1, params, 0);
Expressions: lvalues and rvalues
********************************
The base class of expression is the :c:type:`gcc_jit_rvalue *`,
representing an expression that can be on the *right*-hand side of
an assignment: a value that can be computed somehow, and assigned
*to* a storage area (such as a variable). It has a specific
:c:type:`gcc_jit_type *`.
Anothe important class is :c:type:`gcc_jit_lvalue *`.
A :c:type:`gcc_jit_lvalue *`. is something that can of the *left*-hand
side of an assignment: a storage area (such as a variable).
In other words, every assignment can be thought of as:
.. code-block:: c
LVALUE = RVALUE;
Note that :c:type:`gcc_jit_lvalue *` is a subclass of
:c:type:`gcc_jit_rvalue *`, where in an assignment of the form:
.. code-block:: c
LVALUE_A = LVALUE_B;
the `LVALUE_B` implies reading the current value of that storage
area, assigning it into the `LVALUE_A`.
So far the only expressions we've seen are `i * i`:
.. code-block:: c
gcc_jit_rvalue *expr =
gcc_jit_context_new_binary_op (
ctxt, NULL,
GCC_JIT_BINARY_OP_MULT, int_type,
gcc_jit_param_as_rvalue (param_i),
gcc_jit_param_as_rvalue (param_i));
which is a :c:type:`gcc_jit_rvalue *`, and the various function
parameters: `param_i` and `param_n`, instances of
:c:type:`gcc_jit_param *`, which is a subclass of
:c:type:`gcc_jit_lvalue *` (and, in turn, of :c:type:`gcc_jit_rvalue *`):
we can both read from and write to function parameters within the
body of a function.
Our new example has a couple of local variables. We create them by
calling :c:func:`gcc_jit_function_new_local`, supplying a type and a
name:
.. code-block:: c
/* Build locals: */
gcc_jit_lvalue *i =
gcc_jit_function_new_local (func, NULL, the_type, "i");
gcc_jit_lvalue *sum =
gcc_jit_function_new_local (func, NULL, the_type, "sum");
These are instances of :c:type:`gcc_jit_lvalue *` - they can be read from
and written to.
Note that there is no precanned way to create *and* initialize a variable
like in C:
.. code-block:: c
int i = 0;
Instead, having added the local to the function, we have to separately add
an assignment of `0` to `local_i` at the beginning of the function.
Control flow
************
This function has a loop, so we need to build some basic blocks to
handle the control flow. In this case, we need 4 blocks:
1. before the loop (initializing the locals)
2. the conditional at the top of the loop (comparing `i < n`)
3. the body of the loop
4. after the loop terminates (`return sum`)
so we create these as :c:type:`gcc_jit_block *` instances within the
:c:type:`gcc_jit_function *`:
.. code-block:: c
gcc_jit_block *b_initial =
gcc_jit_function_new_block (func, "initial");
gcc_jit_block *b_loop_cond =
gcc_jit_function_new_block (func, "loop_cond");
gcc_jit_block *b_loop_body =
gcc_jit_function_new_block (func, "loop_body");
gcc_jit_block *b_after_loop =
gcc_jit_function_new_block (func, "after_loop");
We now populate each block with statements.
The entry block `b_initial` consists of initializations followed by a jump
to the conditional. We assign `0` to `i` and to `sum`, using
:c:func:`gcc_jit_block_add_assignment` to add
an assignment statement, and using :c:func:`gcc_jit_context_zero` to get
the constant value `0` for the relevant type for the right-hand side of
the assignment:
.. code-block:: c
/* sum = 0; */
gcc_jit_block_add_assignment (
b_initial, NULL,
sum,
gcc_jit_context_zero (ctxt, the_type));
/* i = 0; */
gcc_jit_block_add_assignment (
b_initial, NULL,
i,
gcc_jit_context_zero (ctxt, the_type));
We can then terminate the entry block by jumping to the conditional:
.. code-block:: c
gcc_jit_block_end_with_jump (b_initial, NULL, b_loop_cond);
The conditional block is equivalent to the line `while (i < n)` from our
C example. It contains a single statement: a conditional, which jumps to
one of two destination blocks depending on a boolean
:c:type:`gcc_jit_rvalue *`, in this case the comparison of `i` and `n`.
We build the comparison using :c:func:`gcc_jit_context_new_comparison`:
.. code-block:: c
gcc_jit_rvalue *guard =
gcc_jit_context_new_comparison (
ctxt, NULL,
GCC_JIT_COMPARISON_GE,
gcc_jit_lvalue_as_rvalue (i),
gcc_jit_param_as_rvalue (n));
and can then use this to add `b_loop_cond`'s sole statement, via
:c:func:`gcc_jit_block_end_with_conditional`:
.. code-block:: c
gcc_jit_block_end_with_conditional (b_loop_cond, NULL, guard);
Next, we populate the body of the loop.
The C statement `sum += i * i;` is an assignment operation, where an
lvalue is modified "in-place". We use
:c:func:`gcc_jit_block_add_assignment_op` to handle these operations:
.. code-block:: c
/* sum += i * i */
gcc_jit_block_add_assignment_op (
b_loop_body, NULL,
sum,
GCC_JIT_BINARY_OP_PLUS,
gcc_jit_context_new_binary_op (
ctxt, NULL,
GCC_JIT_BINARY_OP_MULT, the_type,
gcc_jit_lvalue_as_rvalue (i),
gcc_jit_lvalue_as_rvalue (i)));
The `i++` can be thought of as `i += 1`, and can thus be handled in
a similar way. We use :c:func:`gcc_jit_context_one` to get the constant
value `1` (for the relevant type) for the right-hand side
of the assignment.
.. code-block:: c
/* i++ */
gcc_jit_block_add_assignment_op (
b_loop_body, NULL,
i,
GCC_JIT_BINARY_OP_PLUS,
gcc_jit_context_one (ctxt, the_type));
.. note::
For numeric constants other than 0 or 1, we could use
:c:func:`gcc_jit_context_new_rvalue_from_int` and
:c:func:`gcc_jit_context_new_rvalue_from_double`.
The loop body completes by jumping back to the conditional:
.. code-block:: c
gcc_jit_block_end_with_jump (b_loop_body, NULL, b_loop_cond);
Finally, we populate the `b_after_loop` block, reached when the loop
conditional is false. We want to generate the equivalent of:
.. code-block:: c
return sum;
so the block is just one statement:
.. code-block:: c
/* return sum */
gcc_jit_block_end_with_return (
b_after_loop,
NULL,
gcc_jit_lvalue_as_rvalue (sum));
.. note::
You can intermingle block creation with statement creation,
but given that the terminator statements generally include references
to other blocks, I find it's clearer to create all the blocks,
*then* all the statements.
We've finished populating the function. As before, we can now compile it
to machine code:
.. code-block:: c
gcc_jit_result *result;
result = gcc_jit_context_compile (ctxt);
typedef int (*loop_test_fn_type) (int);
loop_test_fn_type loop_test =
(loop_test_fn_type)gcc_jit_result_get_code (result, "loop_test");
if (!loop_test)
goto error;
printf ("result: %d", loop_test (10));
.. code-block:: bash
result: 285
Visualizing the control flow graph
**********************************
You can see the control flow graph of a function using
:c:func:`gcc_jit_function_dump_to_dot`:
.. code-block:: c
gcc_jit_function_dump_to_dot (func, "/tmp/sum-of-squares.dot");
giving a .dot file in GraphViz format.
You can convert this to an image using `dot`:
.. code-block:: bash
$ dot -Tpng /tmp/sum-of-squares.dot -o /tmp/sum-of-squares.png
or use a viewer (my preferred one is xdot.py; see
https://github.com/jrfonseca/xdot.py; on Fedora you can
install it with `yum install python-xdot`):
.. figure:: sum-of-squares.png
:alt: image of a control flow graph
Full example
************
.. literalinclude:: ../examples/tut03-sum-of-squares.c
:lines: 1-
:language: c
Building and running it:
.. code-block:: console
$ gcc \
tut03-sum-of-squares.c \
-o tut03-sum-of-squares \
-lgccjit
# Run the built program:
$ ./tut03-sum-of-squares
loop_test returned: 285

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,315 @@
.. Copyright (C) 2014 Free Software Foundation, Inc.
Originally contributed by David Malcolm <dmalcolm@redhat.com>
This is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see
<http://www.gnu.org/licenses/>.
.. default-domain:: c
Compilation contexts
====================
.. type:: gcc_jit_context
The top-level of the API is the :c:type:`gcc_jit_context` type.
A :c:type:`gcc_jit_context` instance encapsulates the state of a
compilation.
You can set up options on it, and add types, functions and code.
Invoking :c:func:`gcc_jit_context_compile` on it gives you a
:c:type:`gcc_jit_result`.
Lifetime-management
-------------------
Contexts are the unit of lifetime-management within the API: objects
have their lifetime bounded by the context they are created within, and
cleanup of such objects is done for you when the context is released.
.. function:: gcc_jit_context *gcc_jit_context_acquire (void)
This function acquires a new :c:type:`gcc_jit_object *` instance,
which is independent of any others that may be present within this
process.
.. function:: void gcc_jit_context_release (gcc_jit_context *ctxt)
This function releases all resources associated with the given context.
Both the context itself and all of its :c:type:`gcc_jit_object *`
instances are cleaned up. It should be called exactly once on a given
context.
It is invalid to use the context or any of its "contextual" objects
after calling this.
.. code-block:: c
gcc_jit_context_release (ctxt);
.. function:: gcc_jit_context * gcc_jit_context_new_child_context (gcc_jit_context *parent_ctxt)
Given an existing JIT context, create a child context.
The child inherits a copy of all option-settings from the parent.
The child can reference objects created within the parent, but not
vice-versa.
The lifetime of the child context must be bounded by that of the
parent: you should release a child context before releasing the parent
context.
If you use a function from a parent context within a child context,
you have to compile the parent context before you can compile the
child context, and the gcc_jit_result of the parent context must
outlive the gcc_jit_result of the child context.
This allows caching of shared initializations. For example, you could
create types and declarations of global functions in a parent context
once within a process, and then create child contexts whenever a
function or loop becomes hot. Each such child context can be used for
JIT-compiling just one function or loop, but can reference types
and helper functions created within the parent context.
Contexts can be arbitrarily nested, provided the above rules are
followed, but it's probably not worth going above 2 or 3 levels, and
there will likely be a performance hit for such nesting.
Thread-safety
-------------
Instances of :c:type:`gcc_jit_object *` created via
:c:func:`gcc_jit_context_acquire` are independent from each other:
only one thread may use a given context at once, but multiple threads
could each have their own contexts without needing locks.
Contexts created via :c:func:`gcc_jit_context_new_child_context` are
related to their parent context. They can be partitioned by their
ultimate ancestor into independent "family trees". Only one thread
within a process may use a given "family tree" of such contexts at once,
and if you're using multiple threads you should provide your own locking
around entire such context partitions.
Error-handling
--------------
You can only compile and get code from a context if no errors occur.
In general, if an error occurs when using an API entrypoint, it returns
NULL. You don't have to check everywhere for NULL results, since the
API gracefully handles a NULL being passed in for any argument.
Errors are printed on stderr and can be queried using
:c:func:`gcc_jit_context_get_first_error`.
.. function:: const char *\
gcc_jit_context_get_first_error (gcc_jit_context *ctxt)
Returns the first error message that occurred on the context.
The returned string is valid for the rest of the lifetime of the
context.
If no errors occurred, this will be NULL.
Debugging
---------
.. function:: void\
gcc_jit_context_dump_to_file (gcc_jit_context *ctxt,\
const char *path,\
int update_locations)
To help with debugging: dump a C-like representation to the given path,
describing what's been set up on the context.
If "update_locations" is true, then also set up :type:`gcc_jit_location`
information throughout the context, pointing at the dump file as if it
were a source file. This may be of use in conjunction with
:macro:`GCC_JIT_BOOL_OPTION_DEBUGINFO` to allow stepping through the
code in a debugger.
Options
-------
String Options
**************
.. function:: void gcc_jit_context_set_str_option(gcc_jit_context *ctxt, \
enum gcc_jit_str_option opt, \
const char *value)
Set a string option of the context.
.. type:: enum gcc_jit_str_option
There is currently just one string option:
.. macro:: GCC_JIT_STR_OPTION_PROGNAME
The name of the program, for use as a prefix when printing error
messages to stderr. If `NULL`, or default, "libgccjit.so" is used.
Boolean options
***************
.. function:: void gcc_jit_context_set_bool_option(gcc_jit_context *ctxt, \
enum gcc_jit_bool_option opt, \
int value)
Set a boolean option of the context.
Zero is "false" (the default), non-zero is "true".
.. type:: enum gcc_jit_bool_option
.. macro:: GCC_JIT_BOOL_OPTION_DEBUGINFO
If true, :func:`gcc_jit_context_compile` will attempt to do the right
thing so that if you attach a debugger to the process, it will
be able to inspect variables and step through your code.
Note that you can't step through code unless you set up source
location information for the code (by creating and passing in
:type:`gcc_jit_location` instances).
.. macro:: GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE
If true, :func:`gcc_jit_context_compile` will dump its initial
"tree" representation of your code to stderr (before any
optimizations).
Here's some sample output (from the `square` example)::
<statement_list 0x7f4875a62cc0
type <void_type 0x7f4875a64bd0 VOID
align 8 symtab 0 alias set -1 canonical type 0x7f4875a64bd0
pointer_to_this <pointer_type 0x7f4875a64c78>>
side-effects head 0x7f4875a761e0 tail 0x7f4875a761f8 stmts 0x7f4875a62d20 0x7f4875a62d00
stmt <label_expr 0x7f4875a62d20 type <void_type 0x7f4875a64bd0>
side-effects
arg 0 <label_decl 0x7f4875a79080 entry type <void_type 0x7f4875a64bd0>
VOID file (null) line 0 col 0
align 1 context <function_decl 0x7f4875a77500 square>>>
stmt <return_expr 0x7f4875a62d00
type <integer_type 0x7f4875a645e8 public SI
size <integer_cst 0x7f4875a623a0 constant 32>
unit size <integer_cst 0x7f4875a623c0 constant 4>
align 32 symtab 0 alias set -1 canonical type 0x7f4875a645e8 precision 32 min <integer_cst 0x7f4875a62340 -2147483648> max <integer_cst 0x7f4875a62360 2147483647>
pointer_to_this <pointer_type 0x7f4875a6b348>>
side-effects
arg 0 <modify_expr 0x7f4875a72a78 type <integer_type 0x7f4875a645e8>
side-effects arg 0 <result_decl 0x7f4875a7a000 D.54>
arg 1 <mult_expr 0x7f4875a72a50 type <integer_type 0x7f4875a645e8>
arg 0 <parm_decl 0x7f4875a79000 i> arg 1 <parm_decl 0x7f4875a79000 i>>>>>
.. macro:: GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE
If true, :func:`gcc_jit_context_compile` will dump the "gimple"
representation of your code to stderr, before any optimizations
are performed. The dump resembles C code:
.. code-block:: c
square (signed int i)
{
signed int D.56;
entry:
D.56 = i * i;
return D.56;
}
.. macro:: GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE
If true, :func:`gcc_jit_context_compile` will dump the final
generated code to stderr, in the form of assembly language:
.. code-block:: gas
.file "fake.c"
.text
.globl square
.type square, @function
square:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl %edi, -4(%rbp)
.L2:
movl -4(%rbp), %eax
imull -4(%rbp), %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size square, .-square
.ident "GCC: (GNU) 4.9.0 20131023 (Red Hat 0.1-%{gcc_release})"
.section .note.GNU-stack,"",@progbits
.. macro:: GCC_JIT_BOOL_OPTION_DUMP_SUMMARY
If true, :func:`gcc_jit_context_compile` will print information to stderr
on the actions it is performing, followed by a profile showing
the time taken and memory usage of each phase.
.. macro:: GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING
If true, :func:`gcc_jit_context_compile` will dump copious
amount of information on what it's doing to various
files within a temporary directory. Use
:macro:`GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES` (see below) to
see the results. The files are intended to be human-readable,
but the exact files and their formats are subject to change.
.. macro:: GCC_JIT_BOOL_OPTION_SELFCHECK_GC
If true, libgccjit will aggressively run its garbage collector, to
shake out bugs (greatly slowing down the compile). This is likely
to only be of interest to developers *of* the library. It is
used when running the selftest suite.
.. macro:: GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES
If true, the :type:`gcc_jit_context` will not clean up intermediate files
written to the filesystem, and will display their location on stderr.
Integer options
***************
.. function:: void gcc_jit_context_set_int_option (gcc_jit_context *ctxt, \
enum gcc_jit_int_option opt, \
int value)
Set an integer option of the context.
.. type:: enum gcc_jit_int_option
There is currently just one integer option:
.. macro:: GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL
How much to optimize the code.
Valid values are 0-3, corresponding to GCC's command-line options
-O0 through -O3.
The default value is 0 (unoptimized).

View File

@ -0,0 +1,525 @@
.. Copyright (C) 2014 Free Software Foundation, Inc.
Originally contributed by David Malcolm <dmalcolm@redhat.com>
This is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see
<http://www.gnu.org/licenses/>.
.. default-domain:: c
Expressions
===========
Rvalues
-------
.. type:: gcc_jit_rvalue
A :c:type:`gcc_jit_rvalue *` is an expression that can be computed.
It can be simple, e.g.:
* an integer value e.g. `0` or `42`
* a string literal e.g. `"Hello world"`
* a variable e.g. `i`. These are also lvalues (see below).
or compound e.g.:
* a unary expression e.g. `!cond`
* a binary expression e.g. `(a + b)`
* a function call e.g. `get_distance (&player_ship, &target)`
* etc.
Every rvalue has an associated type, and the API will check to ensure
that types match up correctly (otherwise the context will emit an error).
.. function:: gcc_jit_type *gcc_jit_rvalue_get_type (gcc_jit_rvalue *rvalue)
Get the type of this rvalue.
.. function:: gcc_jit_object *gcc_jit_rvalue_as_object (gcc_jit_rvalue *rvalue)
Upcast the given rvalue to be an object.
Simple expressions
******************
.. function:: gcc_jit_rvalue *\
gcc_jit_context_new_rvalue_from_int (gcc_jit_context *ctxt, \
gcc_jit_type *numeric_type, \
int value)
Given a numeric type (integer or floating point), build an rvalue for
the given constant value.
.. function:: gcc_jit_rvalue *gcc_jit_context_zero (gcc_jit_context *ctxt, \
gcc_jit_type *numeric_type)
Given a numeric type (integer or floating point), get the rvalue for
zero. Essentially this is just a shortcut for:
.. code-block:: c
gcc_jit_context_new_rvalue_from_int (ctxt, numeric_type, 0)
.. function:: gcc_jit_rvalue *gcc_jit_context_one (gcc_jit_context *ctxt, \
gcc_jit_type *numeric_type)
Given a numeric type (integer or floating point), get the rvalue for
zero. Essentially this is just a shortcut for:
.. code-block:: c
gcc_jit_context_new_rvalue_from_int (ctxt, numeric_type, 1)
.. function:: gcc_jit_rvalue *\
gcc_jit_context_new_rvalue_from_double (gcc_jit_context *ctxt, \
gcc_jit_type *numeric_type, \
double value)
Given a numeric type (integer or floating point), build an rvalue for
the given constant value.
.. function:: gcc_jit_rvalue *\
gcc_jit_context_new_rvalue_from_ptr (gcc_jit_context *ctxt, \
gcc_jit_type *pointer_type, \
void *value)
Given a pointer type, build an rvalue for the given address.
.. function:: gcc_jit_rvalue *gcc_jit_context_null (gcc_jit_context *ctxt, \
gcc_jit_type *pointer_type)
Given a pointer type, build an rvalue for ``NULL``. Essentially this
is just a shortcut for:
.. code-block:: c
gcc_jit_context_new_rvalue_from_ptr (ctxt, pointer_type, NULL)
.. function:: gcc_jit_rvalue *\
gcc_jit_context_new_string_literal (gcc_jit_context *ctxt, \
const char *value)
Generate an rvalue for the given NIL-terminated string, of type
:c:data:`GCC_JIT_TYPE_CONST_CHAR_PTR`.
Unary Operations
****************
.. function:: gcc_jit_rvalue * \
gcc_jit_context_new_unary_op (gcc_jit_context *ctxt, \
gcc_jit_location *loc, \
enum gcc_jit_unary_op op, \
gcc_jit_type *result_type, \
gcc_jit_rvalue *rvalue)
Build a unary operation out of an input rvalue.
.. type:: enum gcc_jit_unary_op
The available unary operations are:
========================================== ============
Unary Operation C equivalent
========================================== ============
:c:macro:`GCC_JIT_UNARY_OP_MINUS` `-(EXPR)`
:c:macro:`GCC_JIT_UNARY_OP_BITWISE_NEGATE` `~(EXPR)`
:c:macro:`GCC_JIT_UNARY_OP_LOGICAL_NEGATE` `!(EXPR)`
========================================== ============
.. c:macro:: GCC_JIT_UNARY_OP_MINUS
Negate an arithmetic value; analogous to:
.. code-block:: c
-(EXPR)
in C.
.. c:macro:: GCC_JIT_UNARY_OP_BITWISE_NEGATE
Bitwise negation of an integer value (one's complement); analogous
to:
.. code-block:: c
~(EXPR)
in C.
.. c:macro:: GCC_JIT_UNARY_OP_LOGICAL_NEGATE
Logical negation of an arithmetic or pointer value; analogous to:
.. code-block:: c
!(EXPR)
in C.
Binary Operations
*****************
.. function:: gcc_jit_rvalue *gcc_jit_context_new_binary_op (gcc_jit_context *ctxt, \
gcc_jit_location *loc, \
enum gcc_jit_binary_op op, \
gcc_jit_type *result_type, \
gcc_jit_rvalue *a, gcc_jit_rvalue *b)
Build a binary operation out of two constituent rvalues.
.. type:: enum gcc_jit_binary_op
The available binary operations are:
======================================== ============
Binary Operation C equivalent
======================================== ============
:c:macro:`GCC_JIT_BINARY_OP_PLUS` `x + y`
:c:macro:`GCC_JIT_BINARY_OP_MINUS` `x - y`
:c:macro:`GCC_JIT_BINARY_OP_MULT` `x * y`
:c:macro:`GCC_JIT_BINARY_OP_DIVIDE` `x / y`
:c:macro:`GCC_JIT_BINARY_OP_MODULO` `x % y`
:c:macro:`GCC_JIT_BINARY_OP_BITWISE_AND` `x & y`
:c:macro:`GCC_JIT_BINARY_OP_BITWISE_XOR` `x ^ y`
:c:macro:`GCC_JIT_BINARY_OP_BITWISE_OR` `x | y`
:c:macro:`GCC_JIT_BINARY_OP_LOGICAL_AND` `x && y`
:c:macro:`GCC_JIT_BINARY_OP_LOGICAL_OR` `x || y`
:c:macro:`GCC_JIT_BINARY_OP_LSHIFT` `x << y`
:c:macro:`GCC_JIT_BINARY_OP_RSHIFT` `x >> y`
======================================== ============
.. c:macro:: GCC_JIT_BINARY_OP_PLUS
Addition of arithmetic values; analogous to:
.. code-block:: c
(EXPR_A) + (EXPR_B)
in C.
For pointer addition, use :c:func:`gcc_jit_context_new_array_access`.
.. c:macro:: GCC_JIT_BINARY_OP_MINUS`
Subtraction of arithmetic values; analogous to:
.. code-block:: c
(EXPR_A) - (EXPR_B)
in C.
.. c:macro:: GCC_JIT_BINARY_OP_MULT
Multiplication of a pair of arithmetic values; analogous to:
.. code-block:: c
(EXPR_A) * (EXPR_B)
in C.
.. c:macro:: GCC_JIT_BINARY_OP_DIVIDE
Quotient of division of arithmetic values; analogous to:
.. code-block:: c
(EXPR_A) / (EXPR_B)
in C.
The result type affects the kind of division: if the result type is
integer-based, then the result is truncated towards zero, whereas
a floating-point result type indicates floating-point division.
.. c:macro:: GCC_JIT_BINARY_OP_MODULO
Remainder of division of arithmetic values; analogous to:
.. code-block:: c
(EXPR_A) % (EXPR_B)
in C.
.. c:macro:: GCC_JIT_BINARY_OP_BITWISE_AND
Bitwise AND; analogous to:
.. code-block:: c
(EXPR_A) & (EXPR_B)
in C.
.. c:macro:: GCC_JIT_BINARY_OP_BITWISE_XOR
Bitwise exclusive OR; analogous to:
.. code-block:: c
(EXPR_A) ^ (EXPR_B)
in C.
.. c:macro:: GCC_JIT_BINARY_OP_BITWISE_OR
Bitwise inclusive OR; analogous to:
.. code-block:: c
(EXPR_A) | (EXPR_B)
in C.
.. c:macro:: GCC_JIT_BINARY_OP_LOGICAL_AND
Logical AND; analogous to:
.. code-block:: c
(EXPR_A) && (EXPR_B)
in C.
.. c:macro:: GCC_JIT_BINARY_OP_LOGICAL_OR
Logical OR; analogous to:
.. code-block:: c
(EXPR_A) || (EXPR_B)
in C.
.. c:macro:: GCC_JIT_BINARY_OP_LSHIFT
Left shift; analogous to:
.. code-block:: c
(EXPR_A) << (EXPR_B)
in C.
.. c:macro:: GCC_JIT_BINARY_OP_RSHIFT
Right shift; analogous to:
.. code-block:: c
(EXPR_A) >> (EXPR_B)
in C.
Comparisons
***********
.. function:: gcc_jit_rvalue *\
gcc_jit_context_new_comparison (gcc_jit_context *ctxt,\
gcc_jit_location *loc,\
enum gcc_jit_comparison op,\
gcc_jit_rvalue *a, gcc_jit_rvalue *b)
Build a boolean rvalue out of the comparison of two other rvalues.
.. type:: enum gcc_jit_comparison
======================================= ============
Comparison C equivalent
======================================= ============
:c:macro:`GCC_JIT_COMPARISON_EQ` `x == y`
:c:macro:`GCC_JIT_COMPARISON_NE` `x != y`
:c:macro:`GCC_JIT_COMPARISON_LT` `x < y`
:c:macro:`GCC_JIT_COMPARISON_LE` `x <= y`
:c:macro:`GCC_JIT_COMPARISON_GT` `x > y`
:c:macro:`GCC_JIT_COMPARISON_GE` `x >= y`
======================================= ============
Function calls
**************
.. function:: gcc_jit_rvalue *\
gcc_jit_context_new_call (gcc_jit_context *ctxt,\
gcc_jit_location *loc,\
gcc_jit_function *func,\
int numargs , gcc_jit_rvalue **args)
Given a function and the given table of argument rvalues, construct a
call to the function, with the result as an rvalue.
.. note::
:c:func:`gcc_jit_context_new_call` merely builds a
:c:type:`gcc_jit_rvalue` i.e. an expression that can be evaluated,
perhaps as part of a more complicated expression.
The call *won't* happen unless you add a statement to a function
that evaluates the expression.
For example, if you want to call a function and discard the result
(or to call a function with ``void`` return type), use
:c:func:`gcc_jit_block_add_eval`:
.. code-block:: c
/* Add "(void)printf (arg0, arg1);". */
gcc_jit_block_add_eval (
block, NULL,
gcc_jit_context_new_call (
ctxt,
NULL,
printf_func,
2, args));
Type-coercion
*************
.. function:: gcc_jit_rvalue *\
gcc_jit_context_new_cast (gcc_jit_context *ctxt,\
gcc_jit_location *loc,\
gcc_jit_rvalue *rvalue,\
gcc_jit_type *type)
Given an rvalue of T, construct another rvalue of another type.
Currently only a limited set of conversions are possible:
* int <-> float
* int <-> bool
* P* <-> Q*, for pointer types P and Q
Lvalues
-------
.. type:: gcc_jit_lvalue
An lvalue is something that can of the *left*-hand side of an assignment:
a storage area (such as a variable). It is also usable as an rvalue,
where the rvalue is computed by reading from the storage area.
.. function:: gcc_jit_object *\
gcc_jit_lvalue_as_object (gcc_jit_lvalue *lvalue)
Upcast an lvalue to be an object.
.. function:: gcc_jit_rvalue *\
gcc_jit_lvalue_as_rvalue (gcc_jit_lvalue *lvalue)
Upcast an lvalue to be an rvalue.
.. function:: gcc_jit_rvalue *\
gcc_jit_lvalue_get_address (gcc_jit_lvalue *lvalue,\
gcc_jit_location *loc)
Take the address of an lvalue; analogous to:
.. code-block:: c
&(EXPR)
in C.
Global variables
****************
.. function:: gcc_jit_lvalue *\
gcc_jit_context_new_global (gcc_jit_context *ctxt,\
gcc_jit_location *loc,\
gcc_jit_type *type,\
const char *name)
Add a new global variable of the given type and name to the context.
Working with pointers, structs and unions
-----------------------------------------
.. function:: gcc_jit_lvalue *\
gcc_jit_rvalue_dereference (gcc_jit_rvalue *rvalue,\
gcc_jit_location *loc)
Given an rvalue of pointer type ``T *``, dereferencing the pointer,
getting an lvalue of type ``T``. Analogous to:
.. code-block:: c
*(EXPR)
in C.
Field access is provided separately for both lvalues and rvalues.
.. function:: gcc_jit_lvalue *\
gcc_jit_lvalue_access_field (gcc_jit_lvalue *struct_,\
gcc_jit_location *loc,\
gcc_jit_field *field)
Given an lvalue of struct or union type, access the given field,
getting an lvalue of the field's type. Analogous to:
.. code-block:: c
(EXPR).field = ...;
in C.
.. function:: gcc_jit_rvalue *\
gcc_jit_rvalue_access_field (gcc_jit_rvalue *struct_,\
gcc_jit_location *loc,\
gcc_jit_field *field)
Given an rvalue of struct or union type, access the given field
as an rvalue. Analogous to:
.. code-block:: c
(EXPR).field
in C.
.. function:: gcc_jit_lvalue *\
gcc_jit_rvalue_dereference_field (gcc_jit_rvalue *ptr,\
gcc_jit_location *loc,\
gcc_jit_field *field)
Given an rvalue of pointer type ``T *`` where T is of struct or union
type, access the given field as an lvalue. Analogous to:
.. code-block:: c
(EXPR)->field
in C, itself equivalent to ``(*EXPR).FIELD``.
.. function:: gcc_jit_lvalue *\
gcc_jit_context_new_array_access (gcc_jit_context *ctxt,\
gcc_jit_location *loc,\
gcc_jit_rvalue *ptr,\
gcc_jit_rvalue *index)
Given an rvalue of pointer type ``T *``, get at the element `T` at
the given index, using standard C array indexing rules i.e. each
increment of ``index`` corresponds to ``sizeof(T)`` bytes.
Analogous to:
.. code-block:: c
PTR[INDEX]
in C (or, indeed, to ``PTR + INDEX``).

View File

@ -0,0 +1,311 @@
.. Copyright (C) 2014 Free Software Foundation, Inc.
Originally contributed by David Malcolm <dmalcolm@redhat.com>
This is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see
<http://www.gnu.org/licenses/>.
.. default-domain:: c
Creating and using functions
============================
Params
------
.. type:: gcc_jit_param
A `gcc_jit_param` represents a parameter to a function.
.. function:: gcc_jit_param *\
gcc_jit_context_new_param (gcc_jit_context *ctxt,\
gcc_jit_location *loc,\
gcc_jit_type *type,\
const char *name)
In preparation for creating a function, create a new parameter of the
given type and name.
Parameters are lvalues, and thus are also rvalues (and objects), so the
following upcasts are available:
.. function:: gcc_jit_lvalue *\
gcc_jit_param_as_lvalue (gcc_jit_param *param)
Upcasting from param to lvalue.
.. function:: gcc_jit_rvalue *\
gcc_jit_param_as_rvalue (gcc_jit_param *param)
Upcasting from param to rvalue.
.. function:: gcc_jit_object *\
gcc_jit_param_as_object (gcc_jit_param *param)
Upcasting from param to object.
Functions
---------
.. type:: gcc_jit_function
A `gcc_jit_function` represents a function - either one that we're
creating ourselves, or one that we're referencing.
.. function:: gcc_jit_function *\
gcc_jit_context_new_function (gcc_jit_context *ctxt,\
gcc_jit_location *loc,\
enum gcc_jit_function_kind kind,\
gcc_jit_type *return_type,\
const char *name,\
int num_params,\
gcc_jit_param **params,\
int is_variadic)
Create a gcc_jit_function with the given name and parameters.
.. type:: enum gcc_jit_function_kind
This enum controls the kind of function created, and has the following
values:
.. macro:: GCC_JIT_FUNCTION_EXPORTED
Function is defined by the client code and visible
by name outside of the JIT.
.. macro:: GCC_JIT_FUNCTION_INTERNAL
Function is defined by the client code, but is invisible
outside of the JIT. Analogous to a "static" function.
.. macro:: GCC_JIT_FUNCTION_IMPORTED
Function is not defined by the client code; we're merely
referring to it. Analogous to using an "extern" function from a
header file.
.. macro:: GCC_JIT_FUNCTION_ALWAYS_INLINE
Function is only ever inlined into other functions, and is
invisible outside of the JIT.
Analogous to prefixing with ``inline`` and adding
``__attribute__((always_inline))``
Inlining will only occur when the optimization level is
above 0; when optimization is off, this is essentially the
same as GCC_JIT_FUNCTION_INTERNAL.
.. function:: gcc_jit_function *\
gcc_jit_context_get_builtin_function (gcc_jit_context *ctxt,\
const char *name)
.. function:: gcc_jit_object *\
gcc_jit_function_as_object (gcc_jit_function *func)
Upcasting from function to object.
.. function:: gcc_jit_param *\
gcc_jit_function_get_param (gcc_jit_function *func, int index)
Get the param of the given index (0-based).
.. function:: void \
gcc_jit_function_dump_to_dot (gcc_jit_function *func,\
const char *path)
Emit the function in graphviz format to the given path.
.. function:: gcc_jit_lvalue *\
gcc_jit_function_new_local (gcc_jit_function *func,\
gcc_jit_location *loc,\
gcc_jit_type *type,\
const char *name)
Create a new local variable within the function, of the given type and
name.
Blocks
------
.. type:: gcc_jit_block
A `gcc_jit_block` represents a basic block within a function i.e. a
sequence of statements with a single entry point and a single exit
point.
The first basic block that you create within a function will
be the entrypoint.
Each basic block that you create within a function must be
terminated, either with a conditional, a jump, or a return.
It's legal to have multiple basic blocks that return within
one function.
.. function:: gcc_jit_block *\
gcc_jit_function_new_block (gcc_jit_function *func,\
const char *name)
Create a basic block of the given name. The name may be NULL, but
providing meaningful names is often helpful when debugging: it may
show up in dumps of the internal representation, and in error
messages.
.. function:: gcc_jit_object *\
gcc_jit_block_as_object (gcc_jit_block *block)
Upcast from block to object.
.. function:: gcc_jit_function *\
gcc_jit_block_get_function (gcc_jit_block *block)
Which function is this block within?
Statements
----------
.. function:: void\
gcc_jit_block_add_eval (gcc_jit_block *block,\
gcc_jit_location *loc,\
gcc_jit_rvalue *rvalue)
Add evaluation of an rvalue, discarding the result
(e.g. a function call that "returns" void).
This is equivalent to this C code:
.. code-block:: c
(void)expression;
.. function:: void\
gcc_jit_block_add_assignment (gcc_jit_block *block,\
gcc_jit_location *loc,\
gcc_jit_lvalue *lvalue,\
gcc_jit_rvalue *rvalue)
Add evaluation of an rvalue, assigning the result to the given
lvalue.
This is roughly equivalent to this C code:
.. code-block:: c
lvalue = rvalue;
.. function:: void\
gcc_jit_block_add_assignment_op (gcc_jit_block *block,\
gcc_jit_location *loc,\
gcc_jit_lvalue *lvalue,\
enum gcc_jit_binary_op op,\
gcc_jit_rvalue *rvalue)
Add evaluation of an rvalue, using the result to modify an
lvalue.
This is analogous to "+=" and friends:
.. code-block:: c
lvalue += rvalue;
lvalue *= rvalue;
lvalue /= rvalue;
etc. For example:
.. code-block:: c
/* "i++" */
gcc_jit_block_add_assignment_op (
loop_body, NULL,
i,
GCC_JIT_BINARY_OP_PLUS,
gcc_jit_context_one (ctxt, int_type));
.. function:: void\
gcc_jit_block_add_comment (gcc_jit_block *block,\
gcc_jit_location *loc,\
const char *text)
Add a no-op textual comment to the internal representation of the
code. It will be optimized away, but will be visible in the dumps
seen via :macro:`GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE`
and :macro:`GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE`,
and thus may be of use when debugging how your project's internal
representation gets converted to the libgccjit IR.
.. function:: void\
gcc_jit_block_end_with_conditional (gcc_jit_block *block,\
gcc_jit_location *loc,\
gcc_jit_rvalue *boolval,\
gcc_jit_block *on_true,\
gcc_jit_block *on_false)
Terminate a block by adding evaluation of an rvalue, branching on the
result to the appropriate successor block.
This is roughly equivalent to this C code:
.. code-block:: c
if (boolval)
goto on_true;
else
goto on_false;
block, boolval, on_true, and on_false must be non-NULL.
.. function:: void\
gcc_jit_block_end_with_jump (gcc_jit_block *block,\
gcc_jit_location *loc,\
gcc_jit_block *target)
Terminate a block by adding a jump to the given target block.
This is roughly equivalent to this C code:
.. code-block:: c
goto target;
.. function:: void\
gcc_jit_block_end_with_return (gcc_jit_block *block,\
gcc_jit_location *loc,\
gcc_jit_rvalue *rvalue)
Terminate a block by adding evaluation of an rvalue, returning the value.
This is roughly equivalent to this C code:
.. code-block:: c
return expression;
.. function:: void\
gcc_jit_block_end_with_void_return (gcc_jit_block *block,\
gcc_jit_location *loc)
Terminate a block by adding a valueless return, for use within a function
with "void" return type.
This is equivalent to this C code:
.. code-block:: c
return;

View File

@ -0,0 +1,30 @@
.. Copyright (C) 2014 Free Software Foundation, Inc.
Originally contributed by David Malcolm <dmalcolm@redhat.com>
This is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see
<http://www.gnu.org/licenses/>.
Topic Reference
===============
.. toctree::
:maxdepth: 2
contexts.rst
objects.rst
types.rst
expressions.rst
functions.rst
locations.rst
results.rst

View File

@ -0,0 +1,69 @@
.. Copyright (C) 2014 Free Software Foundation, Inc.
Originally contributed by David Malcolm <dmalcolm@redhat.com>
This is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see
<http://www.gnu.org/licenses/>.
.. default-domain:: c
Source Locations
================
.. type:: gcc_jit_location
A `gcc_jit_location` encapsulates a source code location, so that
you can (optionally) associate locations in your language with
statements in the JIT-compiled code, allowing the debugger to
single-step through your language.
`gcc_jit_location` instances are optional: you can always pass NULL to
any API entrypoint accepting one.
You can construct them using :c:func:`gcc_jit_context_new_location`.
You need to enable :c:macro:`GCC_JIT_BOOL_OPTION_DEBUGINFO` on the
:c:type:`gcc_jit_context` for these locations to actually be usable by
the debugger:
.. code-block:: c
gcc_jit_context_set_bool_option (
ctxt,
GCC_JIT_BOOL_OPTION_DEBUGINFO,
1);
.. function:: gcc_jit_location *\
gcc_jit_context_new_location (gcc_jit_context *ctxt,\
const char *filename,\
int line,\
int column)
Create a `gcc_jit_location` instance representing the given source
location.
Faking it
---------
If you don't have source code for your internal representation, but need
to debug, you can generate a C-like representation of the functions in
your context using :c:func:`gcc_jit_context_dump_to_file()`:
.. code-block:: c
gcc_jit_context_dump_to_file (ctxt, "/tmp/something.c",
1 /* update_locations */);
This will dump C-like code to the given path. If the `update_locations`
argument is true, this will also set up `gcc_jit_location` information
throughout the context, pointing at the dump file as if it were a source
file, giving you *something* you can step through in the debugger.

View File

@ -0,0 +1,86 @@
.. Copyright (C) 2014 Free Software Foundation, Inc.
Originally contributed by David Malcolm <dmalcolm@redhat.com>
This is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see
<http://www.gnu.org/licenses/>.
.. default-domain:: c
Objects
=======
.. type:: gcc_jit_object
Almost every entity in the API (with the exception of
:c:type:`gcc_jit_context *` and :c:type:`gcc_jit_result *`) is a
"contextual" object, a :c:type:`gcc_jit_object *`
A JIT object:
* is associated with a :c:type:`gcc_jit_context *`.
* is automatically cleaned up for you when its context is released so
you don't need to manually track and cleanup all objects, just the
contexts.
Although the API is C-based, there is a form of class hierarchy, which
looks like this::
+- gcc_jit_object
+- gcc_jit_location
+- gcc_jit_type
+- gcc_jit_struct
+- gcc_jit_field
+- gcc_jit_function
+- gcc_jit_block
+- gcc_jit_rvalue
+- gcc_jit_lvalue
+- gcc_jit_param
There are casting methods for upcasting from subclasses to parent classes.
For example, :c:func:`gcc_jit_type_as_object`:
.. code-block:: c
gcc_jit_object *obj = gcc_jit_type_as_object (int_type);
The object "base class" has the following operations:
.. function:: gcc_jit_context *gcc_jit_object_get_context (gcc_jit_object *obj)
Which context is "obj" within?
.. function:: const char *gcc_jit_object_get_debug_string (gcc_jit_object *obj)
Generate a human-readable description for the given object.
For example,
.. code-block:: c
printf ("obj: %s\n", gcc_jit_object_get_debug_string (obj));
might give this text on stdout:
.. code-block:: bash
obj: 4.0 * (float)i
.. note::
If you call this on an object, the `const char *` buffer is allocated
and generated on the first call for that object, and the buffer will
have the same lifetime as the object i.e. it will exist until the
object's context is released.

View File

@ -0,0 +1,48 @@
.. Copyright (C) 2014 Free Software Foundation, Inc.
Originally contributed by David Malcolm <dmalcolm@redhat.com>
This is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see
<http://www.gnu.org/licenses/>.
.. default-domain:: c
Compilation results
===================
.. type:: gcc_jit_result
A `gcc_jit_result` encapsulates the result of compiling a context.
.. function:: gcc_jit_result *\
gcc_jit_context_compile (gcc_jit_context *ctxt)
This calls into GCC and builds the code, returning a
`gcc_jit_result *`.
.. function:: void *\
gcc_jit_result_get_code (gcc_jit_result *result,\
const char *funcname)
Locate a given function within the built machine code.
This will need to be cast to a function pointer of the
correct type before it can be called.
.. function:: void\
gcc_jit_result_release (gcc_jit_result *result)
Once we're done with the code, this unloads the built .so file.
This cleans up the result; after calling this, it's no longer
valid to use the result.

View File

@ -0,0 +1,217 @@
.. Copyright (C) 2014 Free Software Foundation, Inc.
Originally contributed by David Malcolm <dmalcolm@redhat.com>
This is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see
<http://www.gnu.org/licenses/>.
.. default-domain:: c
Types
=====
.. c:type:: gcc_jit_type
gcc_jit_type represents a type within the library.
.. function:: gcc_jit_object *gcc_jit_type_as_object (gcc_jit_type *type)
Upcast a type to an object.
Types can be created in several ways:
* fundamental types can be accessed using
:func:`gcc_jit_context_get_type`:
.. code-block:: c
gcc_jit_type *int_type = gcc_jit_context_get_type (GCC_JIT_TYPE_INT);
See :func:`gcc_jit_context_get_type` for the available types.
* derived types can be accessed by using functions such as
:func:`gcc_jit_type_get_pointer` and :func:`gcc_jit_type_get_const`:
.. code-block:: c
gcc_jit_type *const_int_star = gcc_jit_type_get_pointer (gcc_jit_type_get_const (int_type));
gcc_jit_type *int_const_star = gcc_jit_type_get_const (gcc_jit_type_get_pointer (int_type));
* by creating structures (see below).
Standard types
--------------
.. function:: gcc_jit_type *gcc_jit_context_get_type (gcc_jit_context *ctxt, \
enum gcc_jit_types type_)
Access a specific type. The available types are:
========================================= ================================
`enum gcc_jit_types` value Meaning
========================================= ================================
:c:data:`GCC_JIT_TYPE_VOID` C's ``void`` type.
:c:data:`GCC_JIT_TYPE_VOID_PTR` C's ``void *``.
:c:data:`GCC_JIT_TYPE_BOOL` C++'s ``bool`` type; also C99's
``_Bool`` type, aka ``bool`` if
using stdbool.h.
:c:data:`GCC_JIT_TYPE_CHAR` C's ``char`` (of some signedness)
:c:data:`GCC_JIT_TYPE_SIGNED_CHAR` C's ``signed char``
:c:data:`GCC_JIT_TYPE_UNSIGNED_CHAR` C's ``unsigned char``
:c:data:`GCC_JIT_TYPE_SHORT` C's ``short`` (signed)
:c:data:`GCC_JIT_TYPE_UNSIGNED_SHORT` C's ``unsigned short``
:c:data:`GCC_JIT_TYPE_INT` C's ``int`` (signed)
:c:data:`GCC_JIT_TYPE_UNSIGNED_INT` C's ``unsigned int``
:c:data:`GCC_JIT_TYPE_LONG` C's ``long`` (signed)
:c:data:`GCC_JIT_TYPE_UNSIGNED_LONG` C's ``unsigned long``
:c:data:`GCC_JIT_TYPE_LONG_LONG` C99's ``long long`` (signed)
:c:data:`GCC_JIT_TYPE_UNSIGNED_LONG_LONG` C99's ``unsigned long long``
:c:data:`GCC_JIT_TYPE_FLOAT`
:c:data:`GCC_JIT_TYPE_DOUBLE`
:c:data:`GCC_JIT_TYPE_LONG_DOUBLE`
:c:data:`GCC_JIT_TYPE_CONST_CHAR_PTR` C type: ``(const char *)``
:c:data:`GCC_JIT_TYPE_SIZE_T` C's ``size_t`` type
:c:data:`GCC_JIT_TYPE_FILE_PTR` C type: ``(FILE *)``
========================================= ================================
.. function:: gcc_jit_type *\
gcc_jit_context_get_int_type (gcc_jit_context *ctxt, \
int num_bytes, int is_signed)
Access the integer type of the given size.
Pointers, `const`, and `volatile`
---------------------------------
.. function:: gcc_jit_type *gcc_jit_type_get_pointer (gcc_jit_type *type)
Given type "T", get type "T*".
.. function:: gcc_jit_type *gcc_jit_type_get_const (gcc_jit_type *type)
Given type "T", get type "const T".
.. function:: gcc_jit_type *gcc_jit_type_get_volatile (gcc_jit_type *type)
Given type "T", get type "volatile T".
.. function:: gcc_jit_type *\
gcc_jit_context_new_array_type (gcc_jit_context *ctxt, \
gcc_jit_location *loc, \
gcc_jit_type *element_type, \
int num_elements)
Given type "T", get type "T[N]" (for a constant N).
Structures and unions
---------------------
.. c:type:: gcc_jit_struct
A compound type analagous to a C `struct`.
.. c:type:: gcc_jit_field
A field within a :c:type:`gcc_jit_struct`.
You can model C `struct` types by creating :c:type:`gcc_jit_struct *` and
:c:type:`gcc_jit_field` instances, in either order:
* by creating the fields, then the structure. For example, to model:
.. code-block:: c
struct coord {double x; double y; };
you could call:
.. code-block:: c
gcc_jit_field *field_x =
gcc_jit_context_new_field (ctxt, NULL, double_type, "x");
gcc_jit_field *field_y =
gcc_jit_context_new_field (ctxt, NULL, double_type, "y");
gcc_jit_field *fields[2] = {field_x, field_y};
gcc_jit_struct *coord =
gcc_jit_context_new_struct_type (ctxt, NULL, "coord", 2, fields);
* by creating the structure, then populating it with fields, typically
to allow modelling self-referential structs such as:
.. code-block:: c
struct node { int m_hash; struct node *m_next; };
like this:
.. code-block:: c
gcc_jit_type *node =
gcc_jit_context_new_opaque_struct (ctxt, NULL, "node");
gcc_jit_type *node_ptr =
gcc_jit_type_get_pointer (node);
gcc_jit_field *field_hash =
gcc_jit_context_new_field (ctxt, NULL, int_type, "m_hash");
gcc_jit_field *field_next =
gcc_jit_context_new_field (ctxt, NULL, node_ptr, "m_next");
gcc_jit_field *fields[2] = {field_hash, field_next};
gcc_jit_struct_set_fields (node, NULL, 2, fields);
.. function:: gcc_jit_field *\
gcc_jit_context_new_field (gcc_jit_context *ctxt,\
gcc_jit_location *loc,\
gcc_jit_type *type,\
const char *name)
Construct a new field, with the given type and name.
.. function:: gcc_jit_object *\
gcc_jit_field_as_object (gcc_jit_field *field)
Upcast from field to object.
.. function:: gcc_jit_struct *\
gcc_jit_context_new_struct_type (gcc_jit_context *ctxt,\
gcc_jit_location *loc,\
const char *name,\
int num_fields,\
gcc_jit_field **fields)
Construct a new struct type, with the given name and fields.
.. function:: gcc_jit_struct *\
gcc_jit_context_new_opaque_struct (gcc_jit_context *ctxt,\
gcc_jit_location *loc,\
const char *name)
Construct a new struct type, with the given name, but without
specifying the fields. The fields can be omitted (in which case the
size of the struct is not known), or later specified using
:c:func:`gcc_jit_struct_set_fields`.
.. function:: gcc_jit_type *\
gcc_jit_struct_as_type (gcc_jit_struct *struct_type)
Upcast from struct to type.
.. function:: void\
gcc_jit_struct_set_fields (gcc_jit_struct *struct_type,\
gcc_jit_location *loc,\
int num_fields,\
gcc_jit_field **fields)
Populate the fields of a formerly-opaque struct type.
This can only be called once on a given struct type.

252
gcc/jit/dummy-frontend.c Normal file
View File

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

424
gcc/jit/jit-builtins.c Normal file
View File

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

114
gcc/jit/jit-builtins.h Normal file
View File

@ -0,0 +1,114 @@
/* jit-builtins.h -- Handling of builtin functions during JIT-compilation.
Copyright (C) 2014 Free Software Foundation, Inc.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#ifndef JIT_BUILTINS_H
#define JIT_BUILTINS_H
#include "jit-common.h"
namespace gcc {
namespace jit {
namespace recording {
/* Create an enum of the builtin types. */
enum jit_builtin_type
{
#define DEF_PRIMITIVE_TYPE(NAME, VALUE) NAME,
#define DEF_FUNCTION_TYPE_0(NAME, RETURN) NAME,
#define DEF_FUNCTION_TYPE_1(NAME, RETURN, ARG1) NAME,
#define DEF_FUNCTION_TYPE_2(NAME, RETURN, ARG1, ARG2) NAME,
#define DEF_FUNCTION_TYPE_3(NAME, RETURN, ARG1, ARG2, ARG3) NAME,
#define DEF_FUNCTION_TYPE_4(NAME, RETURN, ARG1, ARG2, ARG3, ARG4) NAME,
#define DEF_FUNCTION_TYPE_5(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) NAME,
#define DEF_FUNCTION_TYPE_6(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6) NAME,
#define DEF_FUNCTION_TYPE_7(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7) NAME,
#define DEF_FUNCTION_TYPE_8(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7, ARG8) NAME,
#define DEF_FUNCTION_TYPE_VAR_0(NAME, RETURN) NAME,
#define DEF_FUNCTION_TYPE_VAR_1(NAME, RETURN, ARG1) NAME,
#define DEF_FUNCTION_TYPE_VAR_2(NAME, RETURN, ARG1, ARG2) NAME,
#define DEF_FUNCTION_TYPE_VAR_3(NAME, RETURN, ARG1, ARG2, ARG3) NAME,
#define DEF_FUNCTION_TYPE_VAR_4(NAME, RETURN, ARG1, ARG2, ARG3, ARG4) NAME,
#define DEF_FUNCTION_TYPE_VAR_5(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG6) \
NAME,
#define DEF_POINTER_TYPE(NAME, TYPE) NAME,
#include "builtin-types.def"
#undef DEF_PRIMITIVE_TYPE
#undef DEF_FUNCTION_TYPE_0
#undef DEF_FUNCTION_TYPE_1
#undef DEF_FUNCTION_TYPE_2
#undef DEF_FUNCTION_TYPE_3
#undef DEF_FUNCTION_TYPE_4
#undef DEF_FUNCTION_TYPE_5
#undef DEF_FUNCTION_TYPE_6
#undef DEF_FUNCTION_TYPE_7
#undef DEF_FUNCTION_TYPE_8
#undef DEF_FUNCTION_TYPE_VAR_0
#undef DEF_FUNCTION_TYPE_VAR_1
#undef DEF_FUNCTION_TYPE_VAR_2
#undef DEF_FUNCTION_TYPE_VAR_3
#undef DEF_FUNCTION_TYPE_VAR_4
#undef DEF_FUNCTION_TYPE_VAR_5
#undef DEF_POINTER_TYPE
BT_LAST
}; /* enum jit_builtin_type */
/***********************************************************************/
class builtins_manager
{
public:
builtins_manager (context *ctxt);
function *
get_builtin_function (const char *name);
private:
function *make_builtin_function (enum built_in_function builtin_id);
type *get_type (enum jit_builtin_type type_id);
type *make_type (enum jit_builtin_type type_id);
type*
make_primitive_type (enum jit_builtin_type type_id);
function_type*
make_fn_type (enum jit_builtin_type type_id,
enum jit_builtin_type return_type_id,
bool is_variadic,
int num_args, ...);
type*
make_ptr_type (enum jit_builtin_type type_id,
enum jit_builtin_type other_type_id);
private:
context *m_ctxt;
type *m_types[BT_LAST];
function *m_builtin_functions[END_BUILTINS];
};
} // namespace recording
} // namespace jit
} // namespace gcc
#endif /* JIT_BUILTINS_H */

182
gcc/jit/jit-common.h Normal file
View File

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

2100
gcc/jit/jit-playback.c Normal file

File diff suppressed because it is too large Load Diff

564
gcc/jit/jit-playback.h Normal file
View File

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

3434
gcc/jit/jit-recording.c Normal file

File diff suppressed because it is too large Load Diff

1593
gcc/jit/jit-recording.h Normal file

File diff suppressed because it is too large Load Diff

1574
gcc/jit/libgccjit++.h Normal file

File diff suppressed because it is too large Load Diff

2074
gcc/jit/libgccjit.c Normal file

File diff suppressed because it is too large Load Diff

986
gcc/jit/libgccjit.h Normal file
View File

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

100
gcc/jit/libgccjit.map Normal file
View File

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

84
gcc/jit/notes.txt Normal file
View File

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

View File

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

626
gcc/testsuite/ChangeLog.jit Normal file
View File

@ -0,0 +1,626 @@
2014-11-05 David Malcolm <dmalcolm@redhat.com>
* jit.dg/test-error-get-type-bad-enum.c: New test case.
* jit.dg/test-error-new-binary-op-bad-op.c: Likewise.
* jit.dg/test-error-new-function-bad-kind.c: Likewise.
* jit.dg/test-error-new-unary-op-bad-op.c: Likewise.
2014-10-22 David Malcolm <dmalcolm@redhat.com>
* jit.dg/jit.exp (DEFAULT_CFLAGS): Add -fgnu89-inline since
dejagnu.h assumes this.
2014-10-17 David Malcolm <dmalcolm@redhat.com>
* jit.dg/jit.exp (get_path_of_driver): New procedure.
(jit-dg-test): Don't unsetenv GCC_EXEC_PREFIX, since jit-playback.c
now adds -fno-use-linker-plugin to the driver cmdline sidestepping
the builddir/installdir libtto_plugin naming issue.
When setting up PATH so that the JIT library can invoke the driver
by installation name, don't use the installation "bindir".
Instead, simply use the location of xgcc as detected
get_path_of_driver. In addition, set up LIBRARY_PATH so that the
linker run from inside the JIT library can locate libgcc etc when
building the .so, pointing it at the same directory.
2014-10-13 David Malcolm <dmalcolm@redhat.com>
* jit.dg/jit.exp (fixed_host_execute): New function, taken from
"host_execute" in DejaGnu's dejagnu.exp, with one line removed.
(jit-dg-test): Use fixed_host_execute, rathern than host_execute.
2014-10-13 David Malcolm <dmalcolm@redhat.com>
* jit.dg/harness.h [MAKE_DEJAGNU_H_THREADSAFE] (note): Redefine
"note" from dejagnu.h to new function dejagnu_note so that we can
make "note" be threadsafe.
(set_options): Don't enable GCC_JIT_BOOL_OPTION_DUMP_SUMMARY,
since it can generate large amounts of output that could overwhelm
expect's buffer.
* jit.dg/test-dot-product.c (verify_code): Use "note" rather than
"printf", to give DejaGnu more chances to parse this log data,
rather than overflowing its buffer.
* jit.dg/test-factorial.c (verify_code): Likewise.
* jit.dg/test-fibonacci.c (verify_code): Likewise.
* jit.dg/test-fuzzer.c (main): Likewise.
* jit.dg/test-nested-loops.c (verify_code): Likewise.
* jit.dg/test-sum-of-squares.c (verify_code): Likewise.
* jit.dg/test-threads.c (note): New function, adding thread-safety
on top of "dejagnu_note", the latter being the implementation
found in dejagnu.h.
(run_threaded_test): Use "note" rather than "printf".
2014-10-07 David Malcolm <dmalcolm@redhat.com>
* jit.dg/jit.exp (jit-dg-test): Prepend the installed bindir to
the PATH before invoking built binaries using the library, so that
the library can find the driver. Restore the PATH immediately
afterwards.
2014-09-24 David Malcolm <dmalcolm@redhat.com>
* ChangeLog.jit: Add copyright footer.
2014-09-23 David Malcolm <dmalcolm@redhat.com>
* jit.dg/test-expressions.c (make_tests_of_binary_ops): Add
shift operators.
(verify_binary_ops): Likewise.
2014-09-18 David Malcolm <dmalcolm@redhat.com>
* jit.dg/jit.exp: When constructing "tests", add the example files
from the documentation, to ensure that they compile.
2014-09-10 David Malcolm <dmalcolm@redhat.com>
* jit.dg/jit.exp: Load target-supports.exp.
2014-09-09 David Malcolm <dmalcolm@redhat.com>
* jit.dg/test-nested-loops.c: New test case.
* jit.dg/all-non-failing-tests.h: Add test-nested-loops.c.
* jit.dg/test-combination.c (create_code): Likewise.
(verify_code): Likewise.
* jit.dg/test-threads.c (const): Add test-nested-loops.c.
2014-08-11 David Malcolm <dmalcolm@redhat.com>
* jit.dg/test-threads.c: New test case, running all of the
individual test cases in separate threads.
* jit.dg/test-combination.c: Move inclusion of the various
individual testcases into...
* jit.dg/all-non-failing-tests.h: ...this new file, and rename
TEST_COMBINATION to COMBINED_TEST.
* jit.dg/harness.h: Respond to new macro MAKE_DEJAGNU_H_THREADSAFE
by hacking up <dejagnu.h> to be threadsafe. Rename
TEST_COMBINATION to COMBINED_TEST.
* jit.dg/jit.exp (proc jit-dg-test): Add "-lpthread" when building
test-threads.exe.
2014-08-08 David Malcolm <dmalcolm@redhat.com>
* jit.dg/test-accessing-union.c: New test case.
* jit.dg/test-combination.c: Add test-accessing-union.c.
2014-08-08 David Malcolm <dmalcolm@redhat.com>
* jit.dg/test-combination.c (create_code): Add missing calls to
create_code_quadratic and create_code_reading_struct.
(verify_code): Add missing calls to verify_code_quadratic and
verify_code_reading_struct.
2014-08-08 David Malcolm <dmalcolm@redhat.com>
* jit.dg/test-calling-function-ptr.c: New test case.
* jit.dg/test-combination.c: Add test-calling-function-ptr.c.
* jit.dg/test-error-call-through-ptr-with-mismatching-args.c: New
test case.
* jit.dg/test-error-call-through-ptr-with-non-function.c: New test
case.
* jit.dg/test-error-call-through-ptr-with-non-pointer.c: New test
case.
* jit.dg/test-error-call-through-ptr-with-not-enough-args.c: New
test case.
2014-07-25 David Malcolm <dmalcolm@redhat.com>
* jit.dg/test-error-index-not-a-numeric-type.c: New test case.
* jit.dg/test-error-value-not-a-numeric-type.c: New test case.
2014-03-19 David Malcolm <dmalcolm@redhat.com>
* jit.dg/test-array-as-pointer.c: New test case, verifying that
there's a way to treat arrays as pointers.
* jit.dg/test-combination.c: Add test-array-as-pointer.c...
(create_code): ...here and...
(verify_code): ...here.
* jit.dg/test-error-array-as-pointer.c: New test case, verifying
that bogus casts from array to pointer are caught by the type
system, rather than leading to ICEs seen in:
https://github.com/davidmalcolm/pygccjit/pull/3#issuecomment-37883129
2014-03-18 David Malcolm <dmalcolm@redhat.com>
* jit.dg/test-combination.c: Add test-arrays.c and test-volatile.c.
Add comment about test-error-*.c. Remove comment about
test-failure.c, which was removed in
96b218c9a1d5f39fb649e02c0e77586b180e8516.
(create_code): Call into test-arrays.c and test-volatile.c.
(verify_code): Likewise.
2014-03-14 David Malcolm <dmalcolm@redhat.com>
* jit.dg/test-expressions.c (called_pointer_checking_function): New.
(make_tests_of_casts): Add test of casting from array to pointer.
(verify_casts): Likewise.
2014-03-13 David Malcolm <dmalcolm@redhat.com>
* jit.dg/test-error-bad-cast.c: New test case.
2014-03-11 David Malcolm <dmalcolm@redhat.com>
* jit.dg/harness.h (set_options): Increase optimization level from
0 to 3.
2014-03-07 David Malcolm <dmalcolm@redhat.com>
* jit.dg/test-functions.c (create_test_of_hidden_function): New,
adding test coverage for GCC_JIT_FUNCTION_ALWAYS_INLINE and
GCC_JIT_FUNCTION_INTERNAL.
(create_tests_of_hidden_functions): Likewise.
(verify_hidden_functions): Likewise.
(create_code): Add call to create_tests_of_hidden_functions.
(verify_code): Add call to verify_hidden_functions.
* jit.dg/test-quadratic.c (make_calc_discriminant): Convert
from GCC_JIT_FUNCTION_EXPORTED to GCC_JIT_FUNCTION_INTERNAL.
2014-03-07 David Malcolm <dmalcolm@redhat.com>
* jit.dg/test-functions.c: Reorder function definitions, grouping
them by subject-matter rather than by create-vs-verify phase.
2014-03-06 David Malcolm <dmalcolm@redhat.com>
* jit.dg/test-nested-contexts.c (main): Dump the contexts to
files, setting up source locations, and adding test coverage for
gcc_jit_context_dump_to_file.
2014-03-04 David Malcolm <dmalcolm@redhat.com>
* jit.dg/test-error-mismatching-types-in-call.c: New test case,
to ensure that a (struct foo *) vs (struct foo) type error is
gracefully handled.
2014-03-04 David Malcolm <dmalcolm@redhat.com>
* jit.dg/test-volatile.c: New testcase, to exercise
gcc_jit_type_get_volatile, and show a way to work with pre-existing
global variables.
2014-02-28 David Malcolm <dmalcolm@redhat.com>
* jit.dg/test-expressions.c (make_test_of_cast): New, to test new
entrypoint gcc_jit_context_new_cast.
(make_tests_of_casts): New.
(create_code): Add call to make_tests_of_casts.
(verify_code): Add call to verify_casts.
2014-02-27 David Malcolm <dmalcolm@redhat.com>
* jit.dg/test-accessing-struct.c (create_code): Port to
block-based API.
* jit.dg/test-calling-external-function.c (create_code): Likewise.
* jit.dg/test-error-accessing-field-in-other-struct.c (create_code):
Likewise.
* jit.dg/test-error-call-with-mismatching-args.c (create_code):
Likewise.
* jit.dg/test-error-call-with-not-enough-args.c (create_code):
Likewise.
* jit.dg/test-error-call-with-too-many-args.c (create_code):
Likewise.
* jit.dg/test-error-dereference-field-of-non-pointer.c (create_code):
Likewise.
* jit.dg/test-error-dereference-read: Likewise.
* jit.dg/test-error-mismatching-types-in-assignment.c: Likewise.
* jit.dg/test-error-return-within-void-function.c: Likewise.
* jit.dg/test-expressions.c: Likewise.
* jit.dg/test-factorial.c: Likewise.
* jit.dg/test-functions.c: Likewise.
* jit.dg/test-fuzzer.c: Likewise.
* jit.dg/test-hello-world.c (create_code): Likewise.
* jit.dg/test-nested-contexts.c: Likewise.
* jit.dg/test-operator-overloading.cc: Likewise.
* jit.dg/test-quadratic.c: Likewise.
* jit.dg/test-quadratic.cc: Likewise.
* jit.dg/test-reading-struct.c (create_code): Likewise.
* jit.dg/test-string-literal.c (create_code): Likewise.
* jit.dg/test-sum-of-squares.c (create_code): Likewise.
* jit.dg/test-types.c (create_code): Likewise.
* jit.dg/test-using-global.c (create_code): Likewise.
* jit.dg/test-arrays.c (create_code): Likewise, eliminating use of
loop API.
* jit.dg/test-dot-product.c (create_code): Likewise.
* jit.dg/test-linked-list.c (create_code): Likewise.
* jit.dg/test-error-adding-to-terminated-block.c: New testcase.
* jit.dg/test-error-block-in-wrong-function.c: Likewise.
* jit.dg/test-error-missing-return.c: Likewise.
* jit.dg/test-error-unreachable-block.c: Likewise.
* jit.dg/test-error-unterminated-block.c: Likewise.
* jit.dg/test-error-label-already-placed.c: Delete obsolete testcase.
* jit.dg/test-error-unplaced-label.c: Likewise.
2014-02-25 David Malcolm <dmalcolm@redhat.com>
* jit.dg/test-functions.c (create_use_of_void_return): New, to add
test coverage for gcc_jit_function_add_void_return.
(verify_void_return): Likewise.
(create_code): Add call to create_use_of_void_return.
(verify_code): Add call to verify_void_return.
2014-02-18 David Malcolm <dmalcolm@redhat.com>
* jit.dg/test-accessing-struct.c (create_code): Update for change to
return type of gcc_jit_context_new_struct_type.
* jit.dg/test-arrays.c (create_code): Likewise.
* jit.dg/test-error-accessing-field-in-other-struct.c (create_code):
Likewise.
* jit.dg/test-error-dereference-field-of-non-pointer.c (create_code):
Likewise.
* jit.dg/test-fuzzer.c (make_random_type): Likewise.
* jit.dg/test-nested-contexts.c (make_types): Likewise.
* jit.dg/test-quadratic.c (make_types): Likewise.
* jit.dg/test-reading-struct.c (create_code): Likewise.
* jit.dg/test-types.c (create_code): Likewise.
* jit.dg/test-linked-list.c: New selftest, exercising
gcc_jit_context_new_opaque_struct, gcc_jit_type_get_pointer, and
gcc_jit_context_null.
* jit.dg/test-combination.c: Add test-linked-list.c
2014-02-14 David Malcolm <dmalcolm@redhat.com>
* jit.dg/test-operator-overloading.cc (make_test_quadratic): Use
the new "zero" and "one" methods of gccjit::type.
* jit.dg/test-quadratic.cc (make_test_quadratic): Use the new
"add_call" method of gccjit::function.
2014-02-13 David Malcolm <dmalcolm@redhat.com>
* jit.dg/harness.h (CHECK_DOUBLE_VALUE): New macro.
(CHECK): New macro.
* jit.dg/test-functions.c: New testcase, exercising
gcc_jit_context_get_builtin_function.
* jit.dg/test-combination.c: Add test-functions.c to the combined
test.
2014-02-11 David Malcolm <dmalcolm@redhat.com>
* jit.dg/test-types.c: Add test coverage for getting type
GCC_JIT_TYPE_BOOL.
* jit.dg/test-expressions.c (make_test_of_comparison): Convert
return type from int to bool.
(verify_comparisons): Likewise.
2014-02-11 David Malcolm <dmalcolm@redhat.com>
* jit.dg/test-error-unplaced-label.c (verify_code): Update
expected error message to reflect commit
6cd4f82c5237cc328aea229cdaaa428ff09d6e98.
2014-02-10 David Malcolm <dmalcolm@redhat.com>
* jit.dg/test-types.c (struct zoo): Add field m_sized_int_type,
to be populated by...
(create_code): Use gcc_jit_context_get_int_type.
(verify_code): Verify that type from gcc_jit_context_get_int_type
works properly.
* jit.dg/test-operator-overloading.cc (make_types): Use the
template form of get_int_type.
* jit.dg/test-quadratic.cc (make_types): Likewise.
2014-02-10 David Malcolm <dmalcolm@redhat.com>
* jit.dg/test-operator-overloading.cc: New testcase, a
rewrite of test-quadratic.cc to use operator overloading.
2014-02-10 David Malcolm <dmalcolm@redhat.com>
* jit.dg/test-quadratic.cc (make_calc_discriminant): Make use of
new methods of the C++ wrapper API to shorten the example code.
(make_test_quadratic): Likewise.
2014-02-10 David Malcolm <dmalcolm@redhat.com>
* jit.dg/test-quadratic.cc (make_test_quadratic): Update for
change to gccjit::context::new_call to pass args by reference
rather than by value.
2014-02-03 David Malcolm <dmalcolm@redhat.com>
* jit.dg/harness.h (check_string_value): Add a forward declaration,
so that we can use CHECK_STRING_VALUE from within tests used by
test-combination.c.
* jit.dg/test-expressions.c (make_test_of_unary_op): Return a debug
stringification of the operation so that it be sanity-checked.
(make_test_of_binary_op): Likewise.
(make_test_of_comparison): Likewise.
(make_tests_of_unary_ops): Verify that said stringifications are
indeed sane.
(make_tests_of_binary_ops): Likewise.
(make_tests_of_comparisons): Likewise.
* jit.dg/test-quadratic.cc (make_types): Verify that the
get_debug_string method works.
(make_test_quadratic): Likewise, also, verify that the <<
operator works.
2014-01-31 David Malcolm <dmalcolm@redhat.com>
* jit.dg/test-quadratic.cc: New file - a translation of
test-quadratic.c to the libgccjit++.h C++ API.
2014-01-30 David Malcolm <dmalcolm@redhat.com>
* jit.dg/test-error-label-already-placed.c: New test case.
* jit.dg/test-error-unplaced-label.c: New test case.
2014-01-30 David Malcolm <dmalcolm@redhat.com>
* jit.dg/test-error-call-with-mismatching-args.c: New test case.
2014-01-30 David Malcolm <dmalcolm@redhat.com>
* jit.dg/test-error-accessing-field-in-other-struct.c: New test
case.
* jit.dg/test-error-dereference-field-of-non-pointer.c: Likewise.
* jit.dg/test-error-dereference-read-of-non-pointer.c: Likewise.
* jit.dg/test-error-mismatching-types-in-assignment.c: Likewise.
* jit.dg/test-error-return-within-void-function.c: Likewise.
2014-01-29 David Malcolm <dmalcolm@redhat.com>
* jit.dg/test-accessing-struct.c (create_code): Update for API change
for accessing fields in terms of gcc_jit_field pointers rather than
by name.
* jit.dg/test-nested-contexts.c (make_calc_discriminant): Likewise.
(make_test_quadratic): Likewise.
* jit.dg/test-quadratic.c (make_calc_discriminant): Likewise.
(make_test_quadratic): Likewise.
* jit.dg/test-reading-struct.c (create_code): Likewise.
* jit.dg/test-types.c: Likewise.
2014-01-28 David Malcolm <dmalcolm@redhat.com>
* jit.dg/harness.h (test_jit): Add the possibility of turning off
this function, if the newly-coined "TEST_ESCHEWS_TEST_JIT" is
defined, for use by...
* jit.dg/test-nested-contexts.c: New test case, adapting
test-quadratic.c, but splitting it into a 3-deep arrangement of
nested contexts, to test the implementation of child contexts.
2014-01-28 David Malcolm <dmalcolm@redhat.com>
* jit.dg/harness.h (test_jit): Move the various calls to set up
options on the context into...
(set_options): ...this new function.
2014-01-27 David Malcolm <dmalcolm@redhat.com>
* jit.dg/test-error-call-with-not-enough-args.c: New test case.
* jit.dg/test-error-call-with-too-many-args.c: New test case.
* jit.dg/test-null-passed-to-api.c: Rename to...
* jit.dg/test-error-null-passed-to-api.c: ...this, so that
error-handling test cases are consistently named.
2014-01-24 David Malcolm <dmalcolm@redhat.com>
* jit.dg/test-empty.c: New test case.
2014-01-24 David Malcolm <dmalcolm@redhat.com>
* jit.dg/harness.h (code_making_callback): Rename to...
(create_code): ...this, and eliminate the returned
error-handling value: test cases will simply call into the
gcc_jit_ API, without needing to be run from a callback.
(test_jit): Don't register a callback, simply call the
"create_code" function for the testcase before compiling the
context.
* jit.dg/test-accessing-struct.c: Rename "code_making_callback"
to "create_code" and eliminate the return code.
* jit.dg/test-calling-external-function.c: Likewise.
* jit.dg/test-combination.c: Likewise.
* jit.dg/test-dot-product.c: Likewise.
* jit.dg/test-expressions.c: Likewise.
* jit.dg/test-factorial.c: Likewise.
* jit.dg/test-fibonacci.c: Likewise.
* jit.dg/test-fuzzer.c: Likewise.
* jit.dg/test-hello-world.c: Likewise.
* jit.dg/test-null-passed-to-api.c: Likewise.
* jit.dg/test-quadratic.c: Likewise.
* jit.dg/test-reading-struct.c: Likewise.
* jit.dg/test-string-literal.c: Likewise.
* jit.dg/test-sum-of-squares.c: Likewise.
* jit.dg/test-types.c: Likewise.
* jit.dg/test-using-global.c: Likewise.
* jit.dg/test-failure.c: Remove this test case, since it was
specifically for testing the now-defunct callback-based API.
2014-01-23 David Malcolm <dmalcolm@redhat.com>
* jit.dg/test-quadratic.c: New test case, written to achieve test
coverage of gcc_jit_rvalue_access_field, but also exercising
division of doubles.
* jit.dg/test-combination.c: Add test-quadratic.c
* jit.dg/test-expressions.c: Add TODOs.
2014-01-23 David Malcolm <dmalcolm@redhat.com>
* jit.dg/test-reading-struct.c: New test, to provide test coverage
of gcc_jit_type_get_const and gcc_jit_lvalue_access_field, in the
process uncovering bugs in how locals were handled.
* jit.dg/test-combination.c: Add usage of test-reading-struct.c.
2014-01-21 David Malcolm <dmalcolm@redhat.com>
* jit.dg/test-hello-world.c (code_making_callback): Add usage of
gcc_jit_function_add_comment.
2013-10-24 David Malcolm <dmalcolm@redhat.com>
* jit.dg/harness.h (main): Wrap with #ifndef TEST_PROVIDES_MAIN
* jit.dg/test-fuzzer.c: New.
2013-10-22 David Malcolm <dmalcolm@redhat.com>
* jit.dg/harness.h (verify_code): Add context param so that
test cases of failure can query errors on it.
(CHECK_STRING_VALUE): New.
(check_string_value): New.
(test_jit): Add user_data param and pass it to the code factory.
Pass context to verify_code, calling it before releasing said
context.
(main): Add NULL user_data to test_jit call.
* jit.dg/test-accessing-struct.c (verify_code): Add context
param.
* jit.dg/test-calling-external-function.c (verify_code):
Likewise.
* jit.dg/test-combination.c (verify_code): Likewise.
* jit.dg/test-dot-product.c (verify_code): Likewise.
* jit.dg/test-expressions.c (verify_code): Likewise.
* jit.dg/test-factorial.c (verify_code): Likewise.
* jit.dg/test-failure.c (verify_code): Likewise.
* jit.dg/test-fibonacci.c (verify_code): Likewise.
* jit.dg/test-hello-world.c (verify_code): Likewise.
* jit.dg/test-string-literal.c (verify_code): Likewise.
* jit.dg/test-sum-of-squares.c (verify_code): Likewise.
* jit.dg/test-types.c (verify_code): Likewise.
* jit.dg/test-using-global.c (verify_code): Likewise.
* jit.dg/test-null-passed-to-api.c (verify_code): Likewise;
use context to verify that the library provides a sane error
message to the client code.
2013-10-21 David Malcolm <dmalcolm@redhat.com>
* jit.dg/test-expressions.c (test_global): New.
(make_test_of_get_address): New.
(verify_get_address): New.
(code_making_callback): Add call to make_test_of_get_address.
(verify_code): Add call to verify_get_address.
2013-10-18 David Malcolm <dmalcolm@redhat.com>
* jit.dg/test-expressions.c: New.
* jit.dg/test-combination.c: Add usage of test-expressions.c
* jit.dg/test-accessing-struct.c (code_making_callback): Update
for changes to field-access API.
* jit.dg/test-types.c (code_making_callback): Likewise.
2013-10-18 David Malcolm <dmalcolm@redhat.com>
* jit.dg/test-null-passed-to-api.c: New.
2013-10-17 David Malcolm <dmalcolm@redhat.com>
* jit.dg/test-accessing-struct.c (code_making_callback): Update
for changes to type API.
* jit.dg/test-calling-external-function.c (code_making_callback):
Likewise.
* jit.dg/test-dot-product.c (code_making_callback): Likewise.
* jit.dg/test-factorial.c (code_making_callback): Likewise.
* jit.dg/test-fibonacci.c (code_making_callback): Likewise.
* jit.dg/test-hello-world.c (code_making_callback): Likewise.
* jit.dg/test-string-literal.c (code_making_callback): Likewise.
* jit.dg/test-sum-of-squares.c (code_making_callback): Likewise.
* jit.dg/test-using-globals.c (code_making_callback): Likewise.
* jit.dg/test-types.c: New.
* jit.dg/test-combination.c (code_making_callback): Use code
from test-types.c.
(verify_code): ...and verify it.
2013-10-16 David Malcolm <dmalcolm@redhat.com>
* jit.dg/test-dot-product.c (code_making_callback): Update for
API changes to locals.
* jit.dg/test-sum-of-squares.c (code_making_callback): Likewise.
2013-10-14 David Malcolm <dmalcolm@redhat.com>
* jit.dg/jit.exp (jit-dg-test): Detect compilation errors and
make them be test failures.
2013-10-14 David Malcolm <dmalcolm@redhat.com>
* jit.dg/test-factorial.c (code_making_callback): Update
for change to gcc_jit_function_place_forward_label.
* jit.dg/test-fibonacci.c (code_making_callback): Add line
numbering to comment, and set up source locations throughout)
allowing stepping throught the comment in the debugger.
* jit.dg/test-sum-of-squares.c (code_making_callback): Update
for change to gcc_jit_function_place_forward_label.
2013-10-10 David Malcolm <dmalcolm@redhat.com>
* jit.dg/harness.h: Set GCC_JIT_BOOL_OPTION_DUMP_SUMMARY when
running selftests.
2013-10-08 David Malcolm <dmalcolm@redhat.com>
* jit.dg/harness.h: Wrap parts of harness within a
#ifndef TEST_COMBINATION so that it can be included multiple
times.
* jit.dg/test-accessing-struct.c (code_making_callback): Rename
the generated function from test_fn to test_access to avoid a
naming collision in the combined test.
(verify_code): Likewise.
* jit.dg/test-calling-external-function.c (code_making_callback):
Rename the generated function from test_fn to test_caller.
(verify_code): Likewise.
* jit.dg/test-combination.c: New.
* jit.dg/test-string-literal.c (code_making_callback): Rename
the generated function from test_fn to test_string_literal.
(verify_code): Likewise.
* jit.dg/test-using-global.c (code_making_callback): Rename
the generated function from test_fn to test_using_global.
(verify_code): Likewise.
2013-10-07 David Malcolm <dmalcolm@redhat.com>
* jit.dg/harness.h (test_jit): Set
GCC_JIT_BOOL_OPTION_SELFCHECK_GC when running selftests.
2013-10-04 David Malcolm <dmalcolm@redhat.com>
* jit.dg/test-using-global.c: New.
2013-10-03 David Malcolm <dmalcolm@redhat.com>
* jit.dg: New subdirectory
* jit.dg/harness.h: New.
* jit.dg/jit.exp: New.
* jit.dg/test-accessing-struct.c: New.
* jit.dg/test-calling-external-function.c: New.
* jit.dg/test-dot-product.c: New.
* jit.dg/test-factorial.c: New.
* jit.dg/test-failure.c: New.
* jit.dg/test-fibonacci.c: New.
* jit.dg/test-hello-world.c: New.
* jit.dg/test-string-literal.c: New.
* jit.dg/test-sum-of-squares.c: New.
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.

View File

@ -0,0 +1,166 @@
/* This file is used by test-combination.c and test-threads.c to
bring all of the non-failing test cases into one source file,
renaming each "create_code" and "verify_code" hook so that they
each have unique name. */
/* Include various other test cases, defining COMBINED_TEST so that
harness.h doesn't duplicate copes of e.g. main, and renaming the
hooks provided by each test case. */
#define COMBINED_TEST
/* test-accessing-struct.c */
#define create_code create_code_accessing_struct
#define verify_code verify_code_accessing_struct
#include "test-accessing-struct.c"
#undef create_code
#undef verify_code
/* test-accessing-union.c */
#define create_code create_code_accessing_union
#define verify_code verify_code_accessing_union
#include "test-accessing-union.c"
#undef create_code
#undef verify_code
/* test-array-as-pointer.c */
#define create_code create_code_array_as_pointer
#define verify_code verify_code_array_as_pointer
#include "test-array-as-pointer.c"
#undef create_code
#undef verify_code
/* test-arrays.c */
#define create_code create_code_arrays
#define verify_code verify_code_arrays
#include "test-arrays.c"
#undef create_code
#undef verify_code
/* test-calling-external-function.c */
#define create_code create_code_calling_external_function
#define verify_code verify_code_calling_external_function
#include "test-calling-external-function.c"
#undef create_code
#undef verify_code
/* test-calling-function-ptr.c */
#define create_code create_code_calling_function_ptr
#define verify_code verify_code_calling_function_ptr
#include "test-calling-function-ptr.c"
#undef create_code
#undef verify_code
/* test-dot-product.c */
#define create_code create_code_dot_product
#define verify_code verify_code_dot_product
#include "test-dot-product.c"
#undef create_code
#undef verify_code
/* test-error-*.c: We don't use these test cases, since they deliberately
introduce errors, which we don't want here. */
/* test-expressions.c */
#define create_code create_code_expressions
#define verify_code verify_code_expressions
#include "test-expressions.c"
#undef create_code
#undef verify_code
/* test-factorial.c */
#define create_code create_code_factorial
#define verify_code verify_code_factorial
#include "test-factorial.c"
#undef create_code
#undef verify_code
/* test-fibonacci.c */
#define create_code create_code_fibonacci
#define verify_code verify_code_fibonacci
#include "test-fibonacci.c"
#undef create_code
#undef verify_code
/* test-functions.c */
#define create_code create_code_functions
#define verify_code verify_code_functions
#include "test-functions.c"
#undef create_code
#undef verify_code
/* test-hello-world.c */
#define create_code create_code_hello_world
#define verify_code verify_code_hello_world
#include "test-hello-world.c"
#undef create_code
#undef verify_code
/* test-linked-list.c */
#define create_code create_code_linked_list
#define verify_code verify_code_linked_list
#include "test-linked-list.c"
#undef create_code
#undef verify_code
/* test-long-names.c */
#define create_code create_code_long_names
#define verify_code verify_code_long_names
#include "test-long-names.c"
#undef create_code
#undef verify_code
/* test-quadratic.c */
#define create_code create_code_quadratic
#define verify_code verify_code_quadratic
#include "test-quadratic.c"
#undef create_code
#undef verify_code
/* test-nested-loops.c */
#define create_code create_code_nested_loop
#define verify_code verify_code_nested_loop
#include "test-nested-loops.c"
#undef create_code
#undef verify_code
/* test-reading-struct.c */
#define create_code create_code_reading_struct
#define verify_code verify_code_reading_struct
#include "test-reading-struct.c"
#undef create_code
#undef verify_code
/* test-string-literal.c */
#define create_code create_code_string_literal
#define verify_code verify_code_string_literal
#include "test-string-literal.c"
#undef create_code
#undef verify_code
/* test-sum-of-squares.c */
#define create_code create_code_sum_of_squares
#define verify_code verify_code_sum_of_squares
#include "test-sum-of-squares.c"
#undef create_code
#undef verify_code
/* test-types.c */
#define create_code create_code_types
#define verify_code verify_code_types
#include "test-types.c"
#undef create_code
#undef verify_code
/* test-using-global.c */
#define create_code create_code_using_global
#define verify_code verify_code_using_global
#include "test-using-global.c"
#undef create_code
#undef verify_code
/* test-volatile.c */
#define create_code create_code_volatile
#define verify_code verify_code_volatile
#include "test-volatile.c"
#undef create_code
#undef verify_code

View File

@ -0,0 +1,242 @@
/*
Code shared between multiple testcases.
This file contains "main" and support code.
Each testcase should implement the following hooks:
extern void
create_code (gcc_jit_context *ctxt, void * user_data);
extern void
verify_code (gcc_jit_context *ctxt, gcc_jit_result *result);
*/
#include <stdlib.h>
#include <stdio.h>
/* test-threads.c use threads, but dejagnu.h isn't thread-safe; there's a
shared "buffer", and the counts of passed/failed etc are globals.
The solution is to use macros to rename "pass" and "fail", replacing them
with mutex-guarded alternatives. */
#ifdef MAKE_DEJAGNU_H_THREADSAFE
#define pass dejagnu_pass
#define fail dejagnu_fail
#define note dejagnu_note
#endif
#include <dejagnu.h>
#ifdef MAKE_DEJAGNU_H_THREADSAFE
#undef pass
#undef fail
#undef note
#endif
static char test[1024];
#define CHECK_NON_NULL(PTR) \
do { \
if ((PTR) != NULL) \
{ \
pass ("%s: %s is non-null", test, #PTR); \
} \
else \
{ \
fail ("%s: %s is NULL", test, #PTR); \
abort (); \
} \
} while (0)
#define CHECK_VALUE(ACTUAL, EXPECTED) \
do { \
if ((ACTUAL) == (EXPECTED)) \
{ \
pass ("%s: actual: %s == expected: %s", test, #ACTUAL, #EXPECTED); \
} \
else \
{ \
fail ("%s: actual: %s != expected: %s", test, #ACTUAL, #EXPECTED); \
fprintf (stderr, "incorrect value\n"); \
abort (); \
} \
} while (0)
#define CHECK_DOUBLE_VALUE(ACTUAL, EXPECTED) \
do { \
double expected = (EXPECTED); \
double actual = (ACTUAL); \
if (abs (actual - expected) < 0.00001) \
{ \
pass ("%s: actual: %s == expected: %s", test, #ACTUAL, #EXPECTED); \
} \
else \
{ \
fail ("%s: actual: %s != expected: %s", test, #ACTUAL, #EXPECTED); \
fprintf (stderr, "incorrect value: %f\n", actual); \
abort (); \
} \
} while (0)
#define CHECK_STRING_VALUE(ACTUAL, EXPECTED) \
check_string_value ((ACTUAL), (EXPECTED));
#define CHECK(COND) \
do { \
if (COND) \
{ \
pass ("%s: %s", test, #COND); \
} \
else \
{ \
fail ("%s: %s", test, #COND); \
abort (); \
} \
} while (0)
/* Hooks that testcases should provide. */
extern void
create_code (gcc_jit_context *ctxt, void * user_data);
extern void
verify_code (gcc_jit_context *ctxt, gcc_jit_result *result);
extern void check_string_value (const char *actual, const char *expected);
/* Implement framework needed for turning the testcase hooks into an
executable. test-combination.c and test-threads.c each combine multiple
testcases into larger testcases, so we have COMBINED_TEST as a way of
temporarily turning off this part of harness.h. */
#ifndef COMBINED_TEST
void check_string_value (const char *actual, const char *expected)
{
if (actual && !expected)
{
fail ("%s: actual: \"%s\" != expected: NULL", test, actual);
fprintf (stderr, "incorrect value\n");
abort ();
}
if (expected && !actual)
{
fail ("%s: actual: NULL != expected: \"%s\"", test, expected);
fprintf (stderr, "incorrect value\n");
abort ();
}
if (actual && expected)
{
if (strcmp (actual, expected))
{
fail ("%s: actual: \"%s\" != expected: \"%s\"", test, actual, expected);
fprintf (stderr, "incorrect valuen");
abort ();
}
pass ("%s: actual: \"%s\" == expected: \"%s\"", test, actual, expected);
}
else
pass ("%s: actual: NULL == expected: NULL");
}
static void set_options (gcc_jit_context *ctxt, const char *argv0)
{
/* Set up options. */
gcc_jit_context_set_str_option (
ctxt,
GCC_JIT_STR_OPTION_PROGNAME,
argv0);
gcc_jit_context_set_int_option (
ctxt,
GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL,
3);
gcc_jit_context_set_bool_option (
ctxt,
GCC_JIT_BOOL_OPTION_DEBUGINFO,
1);
gcc_jit_context_set_bool_option (
ctxt,
GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE,
0);
gcc_jit_context_set_bool_option (
ctxt,
GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE,
0);
gcc_jit_context_set_bool_option (
ctxt,
GCC_JIT_BOOL_OPTION_SELFCHECK_GC,
1);
gcc_jit_context_set_bool_option (
ctxt,
GCC_JIT_BOOL_OPTION_DUMP_SUMMARY,
0);
}
#ifndef TEST_ESCHEWS_TEST_JIT
/* Run one iteration of the test. */
static void
test_jit (const char *argv0, void *user_data)
{
gcc_jit_context *ctxt;
gcc_jit_result *result;
ctxt = gcc_jit_context_acquire ();
/* FIXME: error-handling */
set_options (ctxt, argv0);
create_code (ctxt, user_data);
/* This actually calls into GCC and runs the build, all
in a mutex for now. */
result = gcc_jit_context_compile (ctxt);
verify_code (ctxt, result);
gcc_jit_context_release (ctxt);
/* Once we're done with the code, this unloads the built .so file: */
gcc_jit_result_release (result);
}
#endif /* #ifndef TEST_ESCHEWS_TEST_JIT */
/* We want to prefix all unit test results with the test, but dejagnu.exp's
host_execute appears to get confused by the leading "./" of argv0,
leading to all tests simply reporting as a single period character ".".
Hence strip out the final component of the path to the program name,
so that we can use that in unittest reports. */
const char*
extract_progname (const char *argv0)
{
const char *p;
p = argv0 + strlen (argv0);
while (p != argv0 && p[-1] != '/')
--p;
return p;
}
#ifndef TEST_PROVIDES_MAIN
int
main (int argc, char **argv)
{
int i;
for (i = 1; i <= 5; i++)
{
snprintf (test, sizeof (test),
"%s iteration %d of %d",
extract_progname (argv[0]),
i, 5);
//printf ("ITERATION %d\n", i);
test_jit (argv[0], NULL);
//printf ("\n");
}
totals ();
return 0;
}
#endif /* #ifndef TEST_PROVIDES_MAIN */
#endif /* #ifndef COMBINED_TEST */

View File

@ -0,0 +1,293 @@
# Test code for libgccjit.so
#
# We will compile each of jit.dg/test-*.c into an executable
# dynamically linked against libgccjit.so, and then run each
# such executable.
#
# These executables call into the libgccjit.so API to create
# code, compile it, and run it, verifying that the results
# are as expected. See harness.h for shared code used by all
# such executables.
#
# The executables call into DejaGnu's unit testing C API to
# report PASS/FAIL results, which this script gathers back
# up into the Tcl world, reporting a summary of all results
# across all of the executables.
load_lib dg.exp
load_lib prune.exp
load_lib target-supports.exp
load_lib gcc-defs.exp
load_lib timeout.exp
load_lib target-libpath.exp
load_lib gcc.exp
load_lib dejagnu.exp
# This is host_execute from dejagnu.exp commit
# 126a089777158a7891ff975473939f08c0e31a1c
# with the following patch applied, and renaming to "fixed_host_execute".
# See the discussion at
# http://lists.gnu.org/archive/html/dejagnu/2014-10/msg00000.html
#
# --- /usr/share/dejagnu/dejagnu.exp.old 2014-10-08 13:38:57.274068541 -0400
# +++ /usr/share/dejagnu/dejagnu.exp 2014-10-10 12:27:51.113813659 -0400
# @@ -113,8 +113,6 @@ proc host_execute {args} {
# set timetol 0
# set arguments ""
#
# - expect_before buffer_full { perror "Buffer full" }
# -
# if { [llength $args] == 0} {
# set executable $args
# } else {
# Execute the executable file, and anaylyse the output for the
# test state keywords.
# Returns:
# A "" (empty) string if everything worked, or an error message
# if there was a problem.
#
proc fixed_host_execute {args} {
global text
global spawn_id
set timeoutmsg "Timed out: Never got started, "
set timeout 100
set file all
set timetol 0
set arguments ""
if { [llength $args] == 0} {
set executable $args
} else {
set executable [string trimleft [lindex [split $args " "] 0] "\{"]
set params [string trimleft [lindex [split $args " "] 1] "\{"]
set params [string trimright $params "\}"]
}
verbose "The executable is $executable" 2
if {![file exists ${executable}]} {
perror "The executable, \"$executable\" is missing" 0
return "No source file found"
}
# spawn the executable and look for the DejaGnu output messages from the
# test case.
# spawn -noecho -open [open "|./${executable}" "r"]
spawn -noecho "./${executable}" ${params}
expect_after full_buffer { error "got full_buffer" }
set prefix "\[^\r\n\]*"
expect {
-re "^$prefix\[0-9\]\[0-9\]:..:..:${text}*\r\n" {
regsub "\[\n\r\t\]*NOTE: $text\r\n" $expect_out(0,string) "" output
verbose "$output" 3
set timetol 0
exp_continue
}
-re "^$prefix\tNOTE:${text}*" {
regsub "\[\n\r\t\]*NOTE: $text\r\n" $expect_out(0,string) "" output
set output [string range $output 6 end]
verbose "$output" 2
set timetol 0
exp_continue
}
-re "^$prefix\tPASSED:${text}*" {
regsub "\[\n\r\t\]*PASSED: $text\r\n" $expect_out(0,string) "" output
set output [string range $output 8 end]
pass "$output"
set timetol 0
exp_continue
}
-re "^$prefix\tFAILED:${text}*" {
regsub "\[\n\r\t\]*FAILED: $text\r\n" $expect_out(0,string) "" output
set output [string range $output 8 end]
fail "$output"
set timetol 0
exp_continue
}
-re "^$prefix\tUNTESTED:${text}*" {
regsub "\[\n\r\t\]*TESTED: $text\r\n" $expect_out(0,string) "" output
set output [string range $output 8 end]
untested "$output"
set timetol 0
exp_continue
}
-re "^$prefix\tUNRESOLVED:${text}*" {
regsub "\[\n\r\t\]*UNRESOLVED: $text\r\n" $expect_out(0,string) "" output
set output [string range $output 8 end]
unresolved "$output"
set timetol 0
exp_continue
}
-re "^Totals" {
verbose "All done" 2
}
eof {
# unresolved "${executable} died prematurely"
# catch close
# return "${executable} died prematurely"
}
timeout {
warning "Timed out executing test case"
if { $timetol <= 2 } {
incr timetol
exp_continue
} else {
- catch close
return "Timed out executing test case"
}
}
-re "^$prefix\r\n" {
exp_continue
}
}
# force a close of the executable to be safe.
catch close
return ""
}
# (end of code from dejagnu.exp)
# GCC_UNDER_TEST is needed by gcc_target_compile
global GCC_UNDER_TEST
if ![info exists GCC_UNDER_TEST] {
set GCC_UNDER_TEST "[find_gcc]"
}
# Initialize dg.
dg-init
# Gather a list of all tests.
# Tests within the testsuite: gcc/testsuite/jit.dg/test-*.c
set tests [lsort [find $srcdir/$subdir test-*.c]]
# We also test the examples within the documentation, to ensure that
# they compile:
set tests [lsort [concat $tests [find $srcdir/../jit/docs/examples *.c]]]
verbose "tests: $tests"
# libgloss has found the driver (as "xgcc" or "gcc) and stored
# its full path as GCC_UNDER_TEST.
proc get_path_of_driver {} {
global GCC_UNDER_TEST
verbose "GCC_UNDER_TEST: $GCC_UNDER_TEST"
set binary [lindex $GCC_UNDER_TEST 0]
verbose "binary: $binary"
return [file dirname $binary]
}
proc jit-dg-test { prog do_what extra_tool_flags } {
verbose "within jit-dg-test..."
verbose " prog: $prog"
verbose " do_what: $do_what"
verbose " extra_tool_flags: $extra_tool_flags"
# test-threads.c needs to be linked against pthreads
if {[string match "*test-threads.c" $prog]} {
append extra_tool_flags " -lpthread"
}
# Determine what to name the built executable.
set output_file "[file rootname [file tail $prog]].exe"
verbose "output_file: $output_file"
# Create the test executable:
set comp_output [gcc_target_compile $prog $output_file $do_what \
"{additional_flags=$extra_tool_flags}"]
if ![jit_check_compile "$prog" "initial compilation" \
$output_file $comp_output] then {
return
}
# Run the test executable, capturing the PASS/FAIL textual output
# from the C API, converting it into the Tcl API.
# We need to set LD_LIBRARY_PATH so that the test files can find
# libgccjit.so
# Do this using set_ld_library_path_env_vars from target-libpath.exp
global ld_library_path
global base_dir
set ld_library_path "$base_dir/../../"
set_ld_library_path_env_vars
# libgccjit uses the driver to convert .s files to .so libraries
# via its *installed* name, FULL_DRIVER_NAME
# ${target_noncanonical}-gcc-${gcc_BASEVER}${exeext}
# e.g. "x86_64-unknown-linux-gnu-gcc-5.0.0"
# looking for it on PATH. Hence we need to prepend the location of
# that executable to PATH when running the tests
set dir_containing_driver [get_path_of_driver ]
verbose "dir_containing_driver: $dir_containing_driver"
global env
set old_path $env(PATH)
setenv "PATH" $dir_containing_driver:$old_path
verbose -log "PATH=[getenv PATH]"
# We have:
# test-executables
# linked to -> libgccjit.so
# -> invokes driver:
# -> invokes the assembler
# -> invokes the linker
# We want to be able to run this from the builddir without installing
# but the linker needs to be able to locate various libraries, or we
# get:
# ld: cannot find crtbeginS.o: No such file or directory
# ld: cannot find -lgcc
# ld: cannot find -lgcc_s
# These can be found in the "gcc" subdir of the build.
# Hence to be able to run the testsuite without installing, we need
# to set or prepend the "gcc" subdir of the build to LIBRARY_PATH:
if { [info exists env(LIBRARY_PATH) ] } {
set old_library_path $env(LIBRARY_PATH)
setenv "LIBRARY_PATH" $dir_containing_driver:$old_library_path
} else {
setenv "LIBRARY_PATH" $dir_containing_driver
}
verbose -log "LIBRARY_PATH=[getenv LIBRARY_PATH]"
# dejagnu.exp's host_execute has code to scrape out test results
# from the DejaGnu C API and bring back into the tcl world, so we
# use that to invoke the built code.
# However, it appears to be buggy; see:
# http://lists.gnu.org/archive/html/dejagnu/2014-10/msg00000.html
# We instead call a patched local copy, "fixed_host_execute", defined
# above.
set result [fixed_host_execute $output_file]
verbose "result: $result"
# Restore PATH
setenv "PATH" $old_path
# Restore LIBRARY_PATH
if { [info exists old_library_path] } {
setenv "LIBRARY_PATH" $old_library_path
} else {
unsetenv "LIBRARY_PATH"
}
restore_ld_library_path_env_vars
}
# We need to link with --export-dynamic for test-calling-external-function.c
# so that the JIT-built code can call into functions from the main program.
set DEFAULT_CFLAGS "-I$srcdir/../jit -lgccjit -g -Wall -Werror -Wl,--export-dynamic"
# <dejagnu.h> assumes -fgnu89-inline
# See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63613
# and http://lists.gnu.org/archive/html/dejagnu/2014-10/msg00011.html
append DEFAULT_CFLAGS " -fgnu89-inline"
# Main loop. This will invoke jig-dg-test on each test-*.c file.
dg-runtest $tests "" $DEFAULT_CFLAGS
# All done.
dg-finish

View File

@ -0,0 +1,112 @@
#include <stdlib.h>
#include <stdio.h>
#include "libgccjit.h"
#include "harness.h"
struct foo
{
int x;
int y;
int z;
};
void
create_code (gcc_jit_context *ctxt, void *user_data)
{
/* Let's try to inject the equivalent of:
void
test_access (struct foo *f)
{
f->z = f->x * f->y;
}
*/
gcc_jit_type *void_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
gcc_jit_type *int_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
gcc_jit_field *x =
gcc_jit_context_new_field (ctxt,
NULL,
int_type,
"x");
gcc_jit_field *y =
gcc_jit_context_new_field (ctxt,
NULL,
int_type,
"y");
gcc_jit_field *z =
gcc_jit_context_new_field (ctxt,
NULL,
int_type,
"z");
gcc_jit_field *fields[] = {x, y, z};
gcc_jit_struct *struct_type =
gcc_jit_context_new_struct_type (ctxt, NULL, "foo", 3, fields);
gcc_jit_type *ptr_type =
gcc_jit_type_get_pointer (gcc_jit_struct_as_type (struct_type));
/* Build the test function. */
gcc_jit_param *param_f =
gcc_jit_context_new_param (ctxt, NULL, ptr_type, "f");
gcc_jit_function *test_fn =
gcc_jit_context_new_function (ctxt, NULL,
GCC_JIT_FUNCTION_EXPORTED,
void_type,
"test_access",
1, &param_f,
0);
/* f->x * f->y */
gcc_jit_rvalue *sum =
gcc_jit_context_new_binary_op (
ctxt, NULL,
GCC_JIT_BINARY_OP_MULT,
int_type,
gcc_jit_lvalue_as_rvalue (
gcc_jit_rvalue_dereference_field (
gcc_jit_param_as_rvalue (param_f),
NULL,
x)),
gcc_jit_lvalue_as_rvalue (
gcc_jit_rvalue_dereference_field (
gcc_jit_param_as_rvalue (param_f),
NULL,
y)));
/* f->z = ... */
gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
gcc_jit_block_add_assignment (
block,
NULL,
gcc_jit_rvalue_dereference_field (
gcc_jit_param_as_rvalue (param_f),
NULL,
z),
sum);
gcc_jit_block_end_with_void_return (block, NULL);
}
void
verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
{
typedef void (*fn_type) (struct foo *);
CHECK_NON_NULL (result);
fn_type test_access =
(fn_type)gcc_jit_result_get_code (result, "test_access");
CHECK_NON_NULL (test_access);
struct foo tmp;
tmp.x = 5;
tmp.y = 7;
tmp.z = 0;
/* Call the JIT-generated function. */
test_access (&tmp);
/* Verify that the code correctly modified the field "z". */
CHECK_VALUE (tmp.z, 35);
}

View File

@ -0,0 +1,97 @@
#include <stdlib.h>
#include <stdio.h>
#include "libgccjit.h"
#include "harness.h"
union int_or_float
{
int as_int;
float as_float;
};
void
create_code (gcc_jit_context *ctxt, void *user_data)
{
/* Let's try to inject the equivalent of:
float
test_union (int i)
{
union int_or_float u;
u.as_int = i;
return u.as_float;
}
*/
gcc_jit_type *int_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
gcc_jit_type *float_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_FLOAT);
gcc_jit_field *as_int =
gcc_jit_context_new_field (ctxt,
NULL,
int_type,
"as_int");
gcc_jit_field *as_float =
gcc_jit_context_new_field (ctxt,
NULL,
float_type,
"as_float");
gcc_jit_field *fields[] = {as_int, as_float};
gcc_jit_type *union_type =
gcc_jit_context_new_union_type (ctxt, NULL,
"int_or_float", 2, fields);
/* Build the test function. */
gcc_jit_param *param_i =
gcc_jit_context_new_param (ctxt, NULL, int_type, "i");
gcc_jit_function *test_fn =
gcc_jit_context_new_function (ctxt, NULL,
GCC_JIT_FUNCTION_EXPORTED,
float_type,
"test_union",
1, &param_i,
0);
gcc_jit_lvalue *u =
gcc_jit_function_new_local (test_fn, NULL,
union_type, "u");
gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
/* u.as_int = i; */
gcc_jit_block_add_assignment (
block,
NULL,
/* "u.as_int = ..." */
gcc_jit_lvalue_access_field (u,
NULL,
as_int),
gcc_jit_param_as_rvalue (param_i));
/* return u.as_float; */
gcc_jit_block_end_with_return (
block, NULL,
gcc_jit_rvalue_access_field (gcc_jit_lvalue_as_rvalue (u),
NULL,
as_float));
}
void
verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
{
typedef float (*fn_type) (int i);
CHECK_NON_NULL (result);
fn_type test_union =
(fn_type)gcc_jit_result_get_code (result, "test_union");
CHECK_NON_NULL (test_union);
/* Call the JIT-generated function. */
float f_result = test_union (42);
union int_or_float u;
u.as_float = f_result;
CHECK_VALUE (u.as_int, 42);
}

View File

@ -0,0 +1,101 @@
#include <stdlib.h>
#include <stdio.h>
#include <stddef.h>
#include "libgccjit.h"
#include "harness.h"
#define BUFFER_SIZE (1024)
char test_buffer[1024];
void
create_code (gcc_jit_context *ctxt, void *user_data)
{
/* Let's try to inject the equivalent of:
void test_of_array_as_pointer (const char *name)
{
snprintf (test_buffer, sizeof (test_buffer),
"hello %s", name);
}
*/
gcc_jit_type *void_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
gcc_jit_type *const_char_ptr_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_CONST_CHAR_PTR);
gcc_jit_type *char_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_CHAR);
gcc_jit_type *char_ptr_type =
gcc_jit_type_get_pointer (char_type);
gcc_jit_type *int_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
gcc_jit_type *size_t_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_SIZE_T);
gcc_jit_type *buf_type =
gcc_jit_context_new_array_type (ctxt, NULL, char_type, BUFFER_SIZE);
/* extern int snprintf(char *str, size_t size, const char *format, ...); */
gcc_jit_param *param_s =
gcc_jit_context_new_param (ctxt, NULL, char_ptr_type, "s");
gcc_jit_param *param_n =
gcc_jit_context_new_param (ctxt, NULL, size_t_type, "n");
gcc_jit_param *param_format =
gcc_jit_context_new_param (ctxt, NULL, const_char_ptr_type, "format");
gcc_jit_param *snprintf_params[3] = {param_s, param_n, param_format};
gcc_jit_function *snprintf =
gcc_jit_context_new_function (ctxt, NULL,
GCC_JIT_FUNCTION_IMPORTED,
int_type,
"snprintf",
3, snprintf_params,
1);
gcc_jit_param *param_name =
gcc_jit_context_new_param (ctxt, NULL, const_char_ptr_type, "name");
gcc_jit_function *test_fn =
gcc_jit_context_new_function (ctxt, NULL,
GCC_JIT_FUNCTION_EXPORTED,
void_type,
"test_of_array_as_pointer",
1, &param_name,
0);
gcc_jit_lvalue *buffer =
gcc_jit_context_new_global (ctxt, NULL, buf_type, "test_buffer");
gcc_jit_block *block = gcc_jit_function_new_block(test_fn, "entry");
/* snprintf(buffer, sizeof(buffer), "hello %s", name); */
gcc_jit_rvalue *args[4];
args[0] = gcc_jit_context_new_cast (
ctxt, NULL,
/* Here's the difference with test-error-array-as-pointer.c: */
gcc_jit_lvalue_get_address (buffer,
NULL),
char_ptr_type);
args[1] = gcc_jit_context_new_rvalue_from_int (ctxt,
size_t_type,
BUFFER_SIZE);
args[2] = gcc_jit_context_new_string_literal (ctxt, "hello %s");
args[3] = gcc_jit_param_as_rvalue (param_name);
gcc_jit_block_add_eval (
block, NULL,
gcc_jit_context_new_call (ctxt, NULL, snprintf, 4, args));
gcc_jit_block_end_with_void_return (block, NULL);
}
void
verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
{
CHECK_NON_NULL (result);
typedef void (*fn_type) (const char *);
fn_type test_of_array_as_pointer =
(fn_type)gcc_jit_result_get_code (result, "test_of_array_as_pointer");
CHECK_NON_NULL (test_of_array_as_pointer);
test_of_array_as_pointer ("world");
CHECK_STRING_VALUE (test_buffer, "hello world");
}

View File

@ -0,0 +1,165 @@
#include <stdlib.h>
#include <stdio.h>
#include <stddef.h>
#include "libgccjit.h"
#include "harness.h"
#define ARRAY_SIZE (4)
/* Verify that struct layout works properly when adding an array field. */
struct array_holder
{
float m_before;
int m_ints[ARRAY_SIZE];
float m_after;
};
void
create_code (gcc_jit_context *ctxt, void *user_data)
{
/* Let's try to inject the equivalent of:
void
test_array (struct array_holder *ah)
{
ah->m_before = 4.0f;
for i in 0 to (ARRAY_SIZE - 1):
ah->m_ints[i] = (i * i);
ah->m_after = 2.0f;
}
*/
gcc_jit_type *void_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
gcc_jit_type *float_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_FLOAT);
gcc_jit_type *int_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
gcc_jit_field *field_m_before =
gcc_jit_context_new_field (ctxt, NULL, float_type, "m_before");
gcc_jit_field *field_m_ints =
gcc_jit_context_new_field (
ctxt, NULL,
gcc_jit_context_new_array_type (ctxt, NULL, int_type, ARRAY_SIZE),
"m_ints");
gcc_jit_field *field_m_after =
gcc_jit_context_new_field (ctxt, NULL, float_type, "m_after");
gcc_jit_field *fields[] = {
field_m_before,
field_m_ints,
field_m_after,
};
gcc_jit_struct *struct_type =
gcc_jit_context_new_struct_type (
ctxt,
NULL,
"array_holder",
3, fields);
gcc_jit_type *struct_ptr_type =
gcc_jit_type_get_pointer (gcc_jit_struct_as_type (struct_type));
/* Build the test_fn. */
gcc_jit_param *param_ah =
gcc_jit_context_new_param (ctxt, NULL, struct_ptr_type, "ah");
gcc_jit_function *func =
gcc_jit_context_new_function (ctxt, NULL,
GCC_JIT_FUNCTION_EXPORTED,
void_type,
"test_array",
1, &param_ah,
0);
gcc_jit_block *initial = gcc_jit_function_new_block (func, "initial");
gcc_jit_block *loop_test = gcc_jit_function_new_block (func, "loop_test");
gcc_jit_block *loop_body = gcc_jit_function_new_block (func, "loop_body");
gcc_jit_block *final = gcc_jit_function_new_block (func, "final");
/* "ah->m_before = 4.0f;" */
gcc_jit_block_add_assignment (
initial, NULL,
gcc_jit_rvalue_dereference_field (
gcc_jit_param_as_rvalue (param_ah), NULL, field_m_before),
gcc_jit_context_new_rvalue_from_int (ctxt, float_type, 4));
gcc_jit_block_add_comment (initial, NULL,
"for i in 0 to (ARRAY_SIZE - 1):");
gcc_jit_lvalue *i =
gcc_jit_function_new_local (func, NULL, int_type, "i");
gcc_jit_block_add_assignment (initial, NULL,
i,
gcc_jit_context_zero (ctxt, int_type));
gcc_jit_block_end_with_jump (initial, NULL, loop_test);
gcc_jit_block_end_with_conditional (loop_test, NULL,
gcc_jit_context_new_comparison (
ctxt, NULL,
GCC_JIT_COMPARISON_LT,
gcc_jit_lvalue_as_rvalue (i),
gcc_jit_context_new_rvalue_from_int (ctxt, int_type, ARRAY_SIZE)),
loop_body,
final);
gcc_jit_block_add_comment (loop_body, NULL, "ah->m_ints[i] = (i * i);");
gcc_jit_block_add_assignment (
loop_body, NULL,
gcc_jit_context_new_array_access (
ctxt, NULL,
gcc_jit_lvalue_as_rvalue (gcc_jit_rvalue_dereference_field (
gcc_jit_param_as_rvalue (param_ah),
NULL,
field_m_ints)),
gcc_jit_lvalue_as_rvalue (i)),
gcc_jit_context_new_binary_op (
ctxt, NULL,
GCC_JIT_BINARY_OP_MULT,
int_type,
gcc_jit_lvalue_as_rvalue (i),
gcc_jit_lvalue_as_rvalue (i)));
/* "i++" */
gcc_jit_block_add_assignment_op (
loop_body, NULL,
i,
GCC_JIT_BINARY_OP_PLUS,
gcc_jit_context_one (ctxt, int_type));
gcc_jit_block_end_with_jump (loop_body, NULL, loop_test);
/* ah->m_after = 2.0f; */
gcc_jit_block_add_assignment (
final, NULL,
gcc_jit_rvalue_dereference_field (
gcc_jit_param_as_rvalue (param_ah), NULL, field_m_after),
gcc_jit_context_new_rvalue_from_int (ctxt, float_type, 2));
gcc_jit_block_end_with_void_return (final, NULL);
}
void
verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
{
typedef void (*fn_type) (struct array_holder *ah);
CHECK_NON_NULL (result);
fn_type test_array =
(fn_type)gcc_jit_result_get_code (result, "test_array");
CHECK_NON_NULL (test_array);
struct array_holder ah;
memset (&ah, 0xf0, sizeof (ah));
test_array (&ah);
CHECK_VALUE (ah.m_before, 4.0f);
CHECK_VALUE (ah.m_ints[0], 0);
CHECK_VALUE (ah.m_ints[1], 1);
CHECK_VALUE (ah.m_ints[2], 4);
CHECK_VALUE (ah.m_ints[3], 9);
CHECK_VALUE (ah.m_after, 2.0f);
}

View File

@ -0,0 +1,118 @@
#include <stdlib.h>
#include <stdio.h>
#include "libgccjit.h"
#include "harness.h"
#ifdef __cplusplus
extern "C" {
#endif
extern void
called_function (int i, int j, int k);
#ifdef __cplusplus
}
#endif
void
create_code (gcc_jit_context *ctxt, void *user_data)
{
/* Let's try to inject the equivalent of:
extern void called_function (int i, int j, int k);
void
test_caller (int a)
{
called_function (a * 3, a * 4, a * 5);
}
*/
int i;
gcc_jit_type *void_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
gcc_jit_type *int_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
/* Declare the imported function. */
gcc_jit_param *params[3];
params[0] =
gcc_jit_context_new_param (ctxt, NULL, int_type, "i");
params[1] =
gcc_jit_context_new_param (ctxt, NULL, int_type, "j");
params[2] =
gcc_jit_context_new_param (ctxt, NULL, int_type, "k");
gcc_jit_function *called_fn =
gcc_jit_context_new_function (ctxt, NULL,
GCC_JIT_FUNCTION_IMPORTED,
void_type,
"called_function",
3, params,
0);
/* Build the test_fn. */
gcc_jit_param *param_a =
gcc_jit_context_new_param (ctxt, NULL, int_type, "a");
gcc_jit_function *test_fn =
gcc_jit_context_new_function (ctxt, NULL,
GCC_JIT_FUNCTION_EXPORTED,
void_type,
"test_caller",
1, &param_a,
0);
/* "a * 3, a * 4, a * 5" */
gcc_jit_rvalue *args[3];
for (i = 0; i < 3; i++)
args[i] =
gcc_jit_context_new_binary_op (
ctxt, NULL,
GCC_JIT_BINARY_OP_MULT,
int_type,
gcc_jit_param_as_rvalue (param_a),
gcc_jit_context_new_rvalue_from_int (
ctxt,
int_type,
(i + 3) ));
gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
gcc_jit_block_add_eval (
block, NULL,
gcc_jit_context_new_call (ctxt,
NULL,
called_fn,
3, args));
gcc_jit_block_end_with_void_return (block, NULL);
}
static int called_with[3];
extern void
called_function (int i, int j, int k)
{
called_with[0] = i;
called_with[1] = j;
called_with[2] = k;
}
void
verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
{
typedef void (*fn_type) (int);
CHECK_NON_NULL (result);
fn_type test_caller =
(fn_type)gcc_jit_result_get_code (result, "test_caller");
CHECK_NON_NULL (test_caller);
called_with[0] = 0;
called_with[1] = 0;
called_with[2] = 0;
/* Call the JIT-generated function. */
test_caller (5);
/* Verify that it correctly called "called_function". */
CHECK_VALUE (called_with[0], 15);
CHECK_VALUE (called_with[1], 20);
CHECK_VALUE (called_with[2], 25);
}

View File

@ -0,0 +1,118 @@
#include <stdlib.h>
#include <stdio.h>
#include "libgccjit.h"
#include "harness.h"
void
create_code (gcc_jit_context *ctxt, void *user_data)
{
/* Let's try to inject the equivalent of:
void
test_calling_function_ptr (void (*fn_ptr) (int, int, int) fn_ptr,
int a)
{
fn_ptr (a * 3, a * 4, a * 5);
}
*/
int i;
gcc_jit_type *void_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
gcc_jit_type *int_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
/* Build the function ptr type. */
gcc_jit_type *param_types[3];
param_types[0] = int_type;
param_types[1] = int_type;
param_types[2] = int_type;
gcc_jit_type *fn_ptr_type =
gcc_jit_context_new_function_ptr_type (ctxt, NULL,
void_type,
3, param_types, 0);
/* Ensure that function ptr types have sane debug strings. */
CHECK_STRING_VALUE (
gcc_jit_object_get_debug_string (gcc_jit_type_as_object (fn_ptr_type)),
"void (*) (int, int, int)");
/* Build the test_fn. */
gcc_jit_param *param_fn_ptr =
gcc_jit_context_new_param (ctxt, NULL, fn_ptr_type, "fn_ptr");
gcc_jit_param *param_a =
gcc_jit_context_new_param (ctxt, NULL, int_type, "a");
gcc_jit_param *params[2];
params[0] = param_fn_ptr;
params[1] = param_a;
gcc_jit_function *test_fn =
gcc_jit_context_new_function (ctxt, NULL,
GCC_JIT_FUNCTION_EXPORTED,
void_type,
"test_calling_function_ptr",
2, params,
0);
/* "a * 3, a * 4, a * 5" */
gcc_jit_rvalue *args[3];
for (i = 0; i < 3; i++)
args[i] =
gcc_jit_context_new_binary_op (
ctxt, NULL,
GCC_JIT_BINARY_OP_MULT,
int_type,
gcc_jit_param_as_rvalue (param_a),
gcc_jit_context_new_rvalue_from_int (
ctxt,
int_type,
(i + 3) ));
gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
gcc_jit_block_add_eval (
block, NULL,
gcc_jit_context_new_call_through_ptr (
ctxt,
NULL,
gcc_jit_param_as_rvalue (param_fn_ptr),
3, args));
gcc_jit_block_end_with_void_return (block, NULL);
}
static int called_through_ptr_with[3];
static void
function_called_through_fn_ptr (int i, int j, int k)
{
called_through_ptr_with[0] = i;
called_through_ptr_with[1] = j;
called_through_ptr_with[2] = k;
}
void
verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
{
typedef void (*fn_type) (void (*fn_ptr) (int, int, int),
int);
CHECK_NON_NULL (result);
fn_type test_caller =
(fn_type)gcc_jit_result_get_code (result, "test_calling_function_ptr");
CHECK_NON_NULL (test_caller);
called_through_ptr_with[0] = 0;
called_through_ptr_with[1] = 0;
called_through_ptr_with[2] = 0;
/* Call the JIT-generated function. */
test_caller (function_called_through_fn_ptr, 5);
/* Verify that it correctly called "function_called_through_fn_ptr". */
CHECK_VALUE (called_through_ptr_with[0], 15);
CHECK_VALUE (called_through_ptr_with[1], 20);
CHECK_VALUE (called_through_ptr_with[2], 25);
}

View File

@ -0,0 +1,67 @@
/* Construct a test case by combining other test cases, to try to shake
out state issues: all of the test cases are run in one process, inside
one gcc_jit_context (per iteration). */
#include "all-non-failing-tests.h"
/* Now construct a test case from all the other test cases.
We undefine COMBINED_TEST so that we can now include harness.h
"for real". */
#undef COMBINED_TEST
#include "harness.h"
/* Our testing hooks are the combination of the other test cases. */
void
create_code (gcc_jit_context *ctxt, void * user_data)
{
create_code_accessing_struct (ctxt, user_data);
create_code_accessing_union (ctxt, user_data);
create_code_array_as_pointer (ctxt, user_data);
create_code_arrays (ctxt, user_data);
create_code_calling_external_function (ctxt, user_data);
create_code_calling_function_ptr (ctxt, user_data);
create_code_dot_product (ctxt, user_data);
create_code_expressions (ctxt, user_data);
create_code_factorial (ctxt, user_data);
create_code_fibonacci (ctxt, user_data);
create_code_functions (ctxt, user_data);
create_code_hello_world (ctxt, user_data);
create_code_linked_list (ctxt, user_data);
create_code_long_names (ctxt, user_data);
create_code_quadratic (ctxt, user_data);
create_code_nested_loop (ctxt, user_data);
create_code_reading_struct (ctxt, user_data);
create_code_string_literal (ctxt, user_data);
create_code_sum_of_squares (ctxt, user_data);
create_code_types (ctxt, user_data);
create_code_using_global (ctxt, user_data);
create_code_volatile (ctxt, user_data);
}
void
verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
{
verify_code_accessing_struct (ctxt, result);
verify_code_accessing_union (ctxt, result);
verify_code_array_as_pointer (ctxt, result);
verify_code_arrays (ctxt, result);
verify_code_calling_external_function (ctxt, result);
verify_code_calling_function_ptr (ctxt, result);
verify_code_dot_product (ctxt, result);
verify_code_expressions (ctxt, result);
verify_code_factorial (ctxt, result);
verify_code_fibonacci (ctxt, result);
verify_code_functions (ctxt, result);
verify_code_hello_world (ctxt, result);
verify_code_linked_list (ctxt, result);
verify_code_long_names (ctxt, result);
verify_code_quadratic (ctxt, result);
verify_code_nested_loop (ctxt, result);
verify_code_reading_struct (ctxt, result);
verify_code_string_literal (ctxt, result);
verify_code_sum_of_squares (ctxt, result);
verify_code_types (ctxt, result);
verify_code_using_global (ctxt, result);
verify_code_volatile (ctxt, result);
}

View File

@ -0,0 +1,129 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "libgccjit.h"
#include "harness.h"
void
create_code (gcc_jit_context *ctxt, void *user_data)
{
/* Let's try to inject the equivalent of:
double
my_dot_product (int n, double *a, double *b)
{
double result = 0.;
for (int i = 0; i < n; i++)
result += a[i] * b[i];
return result
}
and see what the optimizer can do. */
gcc_jit_type *val_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_DOUBLE);
gcc_jit_type *ptr_type = gcc_jit_type_get_pointer (val_type);
gcc_jit_type *int_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
gcc_jit_type *return_type = val_type;
gcc_jit_param *param_n =
gcc_jit_context_new_param (ctxt, NULL, int_type, "n");
gcc_jit_param *param_a =
gcc_jit_context_new_param (ctxt, NULL, ptr_type, "a");
gcc_jit_param *param_b =
gcc_jit_context_new_param (ctxt, NULL, ptr_type, "b");
gcc_jit_param *params[3] = {param_n, param_a, param_b};
gcc_jit_function *func =
gcc_jit_context_new_function (ctxt, NULL,
GCC_JIT_FUNCTION_EXPORTED,
return_type,
"my_dot_product",
3, params, 0);
gcc_jit_block *initial = gcc_jit_function_new_block (func, "initial");
gcc_jit_block *loop_test = gcc_jit_function_new_block (func, "loop_test");
gcc_jit_block *loop_body = gcc_jit_function_new_block (func, "loop_body");
gcc_jit_block *final = gcc_jit_function_new_block (func, "final");
/* Build: "double result = 0.;" */
gcc_jit_lvalue *result =
gcc_jit_function_new_local (func, NULL, val_type, "result");
gcc_jit_block_add_assignment (initial, NULL,
result, gcc_jit_context_zero (ctxt, val_type));
/* Build: "for (int i = 0; i < n; i++)" */
gcc_jit_lvalue *i =
gcc_jit_function_new_local (func, NULL, int_type, "i");
gcc_jit_block_add_assignment (initial, NULL,
i, gcc_jit_context_zero (ctxt, int_type));
gcc_jit_block_end_with_jump (initial, NULL, loop_test);
gcc_jit_block_end_with_conditional (
loop_test, NULL,
/* (i < n) */
gcc_jit_context_new_comparison (
ctxt, NULL,
GCC_JIT_COMPARISON_LT,
gcc_jit_lvalue_as_rvalue (i),
gcc_jit_param_as_rvalue (param_n)),
loop_body,
final);
/* Build: "result += a[i] * b[i];" */
gcc_jit_block_add_assignment_op (
loop_body, NULL,
result,
GCC_JIT_BINARY_OP_PLUS,
gcc_jit_context_new_binary_op (
ctxt, NULL,
GCC_JIT_BINARY_OP_MULT,
val_type,
gcc_jit_lvalue_as_rvalue (
gcc_jit_context_new_array_access (
ctxt, NULL,
gcc_jit_param_as_rvalue (param_a),
gcc_jit_lvalue_as_rvalue (i))),
gcc_jit_lvalue_as_rvalue (
gcc_jit_context_new_array_access (
ctxt, NULL,
gcc_jit_param_as_rvalue (param_b),
gcc_jit_lvalue_as_rvalue (i)))));
/* Build: "i++" */
gcc_jit_block_add_assignment_op (
loop_body, NULL,
i,
GCC_JIT_BINARY_OP_PLUS,
gcc_jit_context_one (ctxt, int_type));
gcc_jit_block_end_with_jump (loop_body, NULL, loop_test);
/* Build: "return result;" */
gcc_jit_block_end_with_return (
final,
NULL,
gcc_jit_lvalue_as_rvalue (result));
}
void
verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
{
typedef double (*my_dot_product_fn_type) (int n, double *a, double *b);
CHECK_NON_NULL (result);
my_dot_product_fn_type my_dot_product =
(my_dot_product_fn_type)gcc_jit_result_get_code (result,
"my_dot_product");
CHECK_NON_NULL (my_dot_product);
double test_array[] = {1., 2., 3., 4., 5., 6., 7., 8., 9., 10.};
double val = my_dot_product (10, test_array, test_array);
note ("my_dot_product returned: %f", val);
CHECK_VALUE (val, 385.0);
}

View File

@ -0,0 +1,20 @@
#include <stdlib.h>
#include <stdio.h>
#include "libgccjit.h"
#include "harness.h"
void
create_code (gcc_jit_context *ctxt, void *user_data)
{
/* Do nothing. */
}
void
verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
{
/* We should have a non-NULL result, albeit one with nothing in it. */
CHECK_NON_NULL (result);
}

View File

@ -0,0 +1,114 @@
#include <stdlib.h>
#include <stdio.h>
#include "libgccjit.h"
#include "harness.h"
struct foo
{
int x;
int y;
};
struct bar
{
int p;
int q;
};
void
create_code (gcc_jit_context *ctxt, void *user_data)
{
/* Let's try to inject the equivalent of:
void
test_bogus_access (struct foo *f)
{
f->p = f->q;
}
i.e. using the wrong struct.
*/
gcc_jit_type *void_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
gcc_jit_type *int_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
/* Map "struct foo". */
gcc_jit_field *x =
gcc_jit_context_new_field (ctxt,
NULL,
int_type,
"x");
gcc_jit_field *y =
gcc_jit_context_new_field (ctxt,
NULL,
int_type,
"y");
gcc_jit_field *foo_fields[] = {x, y};
gcc_jit_struct *struct_foo =
gcc_jit_context_new_struct_type (ctxt, NULL, "foo", 2, foo_fields);
/* Map "struct bar". */
gcc_jit_field *p =
gcc_jit_context_new_field (ctxt,
NULL,
int_type,
"p");
gcc_jit_field *q =
gcc_jit_context_new_field (ctxt,
NULL,
int_type,
"q");
/* We don't actually need a gcc_jit_type for "struct bar" for the test. */
gcc_jit_field *bar_fields[] = {p, q};
(void)gcc_jit_context_new_struct_type (ctxt, NULL, "foo", 2, bar_fields);
gcc_jit_type *foo_ptr =
gcc_jit_type_get_pointer (gcc_jit_struct_as_type (struct_foo));
/* Build the test function. */
gcc_jit_param *param_f =
gcc_jit_context_new_param (ctxt, NULL, foo_ptr, "f");
gcc_jit_function *test_fn =
gcc_jit_context_new_function (ctxt, NULL,
GCC_JIT_FUNCTION_EXPORTED,
void_type,
"test_bogus_access",
1, &param_f,
0);
/* Erroneous: f->p = ... */
gcc_jit_lvalue *lvalue =
gcc_jit_rvalue_dereference_field (
gcc_jit_param_as_rvalue (param_f),
NULL,
p);
/* Erroneous: ... = f->q; */
gcc_jit_rvalue *rvalue =
gcc_jit_lvalue_as_rvalue (
gcc_jit_rvalue_dereference_field (
gcc_jit_param_as_rvalue (param_f),
NULL,
q));
gcc_jit_block *block =
gcc_jit_function_new_block (test_fn, NULL);
gcc_jit_block_add_assignment (
block,
NULL,
lvalue, rvalue);
gcc_jit_block_end_with_void_return (block, NULL);
}
void
verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
{
CHECK_VALUE (result, NULL);
/* Verify that the correct error message was emitted. */
CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
"gcc_jit_rvalue_dereference_field:"
" p is not a field of struct foo");
}

View File

@ -0,0 +1,48 @@
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include "libgccjit.h"
#include "harness.h"
void
create_code (gcc_jit_context *ctxt, void *user_data)
{
/* Let's try to inject the equivalent of:
void
test_fn ()
{
return;
return;
}
*/
gcc_jit_type *void_t =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
/* Build the test_fn. */
gcc_jit_function *test_fn =
gcc_jit_context_new_function (ctxt, NULL,
GCC_JIT_FUNCTION_EXPORTED,
void_t,
"test_fn",
0, NULL,
0);
gcc_jit_block *initial =
gcc_jit_function_new_block (test_fn, "initial");
gcc_jit_block_end_with_void_return (initial, NULL);
/* Error: "initial" has already been terminated. */
gcc_jit_block_end_with_void_return (initial, NULL);
}
void
verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
{
CHECK_VALUE (result, NULL);
CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
"gcc_jit_block_end_with_void_return:"
" adding to terminated block:"
" initial (already terminated by: return;)");
}

View File

@ -0,0 +1,99 @@
#include <stdlib.h>
#include <stdio.h>
#include <stddef.h>
#include "libgccjit.h"
#include "harness.h"
#define BUFFER_SIZE (1024)
char test_buffer[1024];
void
create_code (gcc_jit_context *ctxt, void *user_data)
{
/* Let's try to inject the equivalent of:
void test_of_array_as_pointer (const char *name)
{
snprintf (test_buffer, sizeof (test_buffer),
"hello %s", name);
}
*/
gcc_jit_type *void_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
gcc_jit_type *const_char_ptr_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_CONST_CHAR_PTR);
gcc_jit_type *char_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_CHAR);
gcc_jit_type *char_ptr_type =
gcc_jit_type_get_pointer (char_type);
gcc_jit_type *int_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
gcc_jit_type *size_t_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_SIZE_T);
gcc_jit_type *buf_type =
gcc_jit_context_new_array_type (ctxt, NULL, char_type, BUFFER_SIZE);
/* extern int snprintf(char *str, size_t size, const char *format, ...); */
gcc_jit_param *param_s =
gcc_jit_context_new_param (ctxt, NULL, char_ptr_type, "s");
gcc_jit_param *param_n =
gcc_jit_context_new_param (ctxt, NULL, size_t_type, "n");
gcc_jit_param *param_format =
gcc_jit_context_new_param (ctxt, NULL, const_char_ptr_type, "format");
gcc_jit_param *snprintf_params[3] = {param_s, param_n, param_format};
gcc_jit_function *snprintf =
gcc_jit_context_new_function (ctxt, NULL,
GCC_JIT_FUNCTION_IMPORTED,
int_type,
"snprintf",
3, snprintf_params,
1);
gcc_jit_param *param_name =
gcc_jit_context_new_param (ctxt, NULL, const_char_ptr_type, "name");
gcc_jit_function *test_fn =
gcc_jit_context_new_function (ctxt, NULL,
GCC_JIT_FUNCTION_EXPORTED,
void_type,
"test_of_array_as_pointer",
1, &param_name,
0);
gcc_jit_lvalue *buffer =
gcc_jit_context_new_global (ctxt, NULL, buf_type, "test_buffer");
gcc_jit_block *block = gcc_jit_function_new_block(test_fn, "entry");
/* snprintf(buffer, sizeof(buffer), "hello %s", name); */
gcc_jit_rvalue *args[4];
args[0] = gcc_jit_context_new_cast (
ctxt, NULL,
/* Here's the difference with test-array-as-pointer.c: */
gcc_jit_lvalue_as_rvalue (buffer),
char_ptr_type);
args[1] = gcc_jit_context_new_rvalue_from_int (ctxt,
size_t_type,
BUFFER_SIZE);
args[2] = gcc_jit_context_new_string_literal (ctxt, "hello %s");
args[3] = gcc_jit_param_as_rvalue (param_name);
gcc_jit_block_add_eval (
block, NULL,
gcc_jit_context_new_call (ctxt, NULL, snprintf, 4, args));
gcc_jit_block_end_with_void_return (block, NULL);
}
void
verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
{
CHECK_VALUE (result, NULL);
/* Verify that the correct error message was emitted. */
CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
"gcc_jit_context_new_cast:"
" cannot cast test_buffer"
" from type: char[1024]"
" to type: char *");
}

View File

@ -0,0 +1,63 @@
#include <stdlib.h>
#include <stdio.h>
#include "libgccjit.h"
#include "harness.h"
void
create_code (gcc_jit_context *ctxt, void *user_data)
{
/* Let's try to inject the equivalent of:
int
test_fn ()
{
struct foo f;
return (int)f;
}
and verify that the API complains about the bad cast.
*/
gcc_jit_type *int_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
gcc_jit_struct *struct_foo =
gcc_jit_context_new_struct_type (ctxt, NULL, "foo",
0, NULL);
gcc_jit_function *test_fn =
gcc_jit_context_new_function (ctxt, NULL,
GCC_JIT_FUNCTION_EXPORTED,
int_type,
"test_fn",
0, NULL,
0);
gcc_jit_lvalue *f =
gcc_jit_function_new_local (
test_fn,
NULL,
gcc_jit_struct_as_type (struct_foo), "f");
gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
gcc_jit_block_end_with_return (
block, NULL,
gcc_jit_context_new_cast (ctxt, NULL,
gcc_jit_lvalue_as_rvalue (f),
int_type));
}
void
verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
{
CHECK_VALUE (result, NULL);
/* Verify that the correct error message was emitted. */
CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
"gcc_jit_context_new_cast:"
" cannot cast f from type: struct foo"
" to type: int");
}

View File

@ -0,0 +1,65 @@
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include "libgccjit.h"
#include "harness.h"
void
create_code (gcc_jit_context *ctxt, void *user_data)
{
/* Let's try to inject the equivalent of:
void
test_fn ()
{
goto label;
}
void
other_fn ()
{
label:
};
where the destination block is in another function.
*/
gcc_jit_type *void_t =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
/* Build the test_fn. */
gcc_jit_function *test_fn =
gcc_jit_context_new_function (ctxt, NULL,
GCC_JIT_FUNCTION_EXPORTED,
void_t,
"test_fn",
0, NULL,
0);
/* Build the other_fn. */
gcc_jit_function *other_fn =
gcc_jit_context_new_function (ctxt, NULL,
GCC_JIT_FUNCTION_EXPORTED,
void_t,
"other_fn",
0, NULL,
0);
gcc_jit_block *initial =
gcc_jit_function_new_block (test_fn, "initial");
gcc_jit_block *block_within_other_fn =
gcc_jit_function_new_block (other_fn, "block_within_other_fn");
gcc_jit_block_end_with_jump (initial, NULL, block_within_other_fn);
}
void
verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
{
CHECK_VALUE (result, NULL);
CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
"gcc_jit_block_end_with_jump:"
" target block is not in same function:"
" source block initial is in function test_fn"
" whereas target block block_within_other_fn"
" is in function other_fn");
}

View File

@ -0,0 +1,74 @@
#include <stdlib.h>
#include <stdio.h>
#include "libgccjit.h"
#include "harness.h"
void
create_code (gcc_jit_context *ctxt, void *user_data)
{
/* Let's try to inject the equivalent of:
void
test_fn (void (*some_fn_ptr) (void *))
{
some_fn_ptr (42);
}
and verify that the API complains about the mismatching argument
type ("int" vs "void *"). */
gcc_jit_type *void_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
gcc_jit_type *void_ptr_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID_PTR);
gcc_jit_type *int_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
/* Build the function ptr type. */
gcc_jit_type *fn_ptr_type =
gcc_jit_context_new_function_ptr_type (ctxt, NULL,
void_type,
1, &void_ptr_type, 0);
/* Build the test_fn. */
gcc_jit_param *param_fn_ptr =
gcc_jit_context_new_param (ctxt, NULL, fn_ptr_type, "some_fn_ptr");
gcc_jit_function *test_fn =
gcc_jit_context_new_function (ctxt, NULL,
GCC_JIT_FUNCTION_EXPORTED,
void_type,
"test_fn",
1, &param_fn_ptr,
0);
/* some_fn_ptr (42); */
gcc_jit_rvalue *arg =
gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 42);
gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
gcc_jit_block_add_eval (
block, NULL,
gcc_jit_context_new_call_through_ptr (
ctxt,
NULL,
gcc_jit_param_as_rvalue (param_fn_ptr),
1, &arg));
/* the above has the wrong type for argument 1. */
gcc_jit_block_end_with_void_return (block, NULL);
}
void
verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
{
CHECK_VALUE (result, NULL);
/* Verify that the correct error message was emitted. */
CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
("gcc_jit_context_new_call_through_ptr:"
" mismatching types for argument 1 of fn_ptr:"
" some_fn_ptr:"
" assignment to param 1 (type: void *)"
" from (int)42 (type: int)"));
}

View File

@ -0,0 +1,65 @@
#include <stdlib.h>
#include <stdio.h>
#include "libgccjit.h"
#include "harness.h"
void
create_code (gcc_jit_context *ctxt, void *user_data)
{
/* Let's try to inject the equivalent of:
void
test_fn (void *some_ptr)
{
((some_unspecified_fn_ptr_type)some_ptr) (42);
}
and verify that the API complains about the 42 not being a
function pointer. */
gcc_jit_type *void_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
gcc_jit_type *void_ptr_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID_PTR);
gcc_jit_type *int_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
/* Build the test_fn. */
gcc_jit_param *some_ptr =
gcc_jit_context_new_param (ctxt, NULL, void_ptr_type, "some_ptr");
gcc_jit_function *test_fn =
gcc_jit_context_new_function (ctxt, NULL,
GCC_JIT_FUNCTION_EXPORTED,
void_type,
"test_fn",
1, &some_ptr,
0);
gcc_jit_rvalue *arg =
gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 42);
/* ((some_unspecified_fn_ptr_type)some_ptr) (42); */
gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
gcc_jit_block_add_eval (
block, NULL,
gcc_jit_context_new_call_through_ptr (
ctxt,
NULL,
/* This is not a function pointer. */
gcc_jit_param_as_rvalue (some_ptr),
1, &arg));
gcc_jit_block_end_with_void_return (block, NULL);
}
void
verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
{
CHECK_VALUE (result, NULL);
/* Verify that the correct error message was emitted. */
CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
("gcc_jit_context_new_call_through_ptr:"
" fn_ptr is not a function ptr: some_ptr type: void *"));
}

View File

@ -0,0 +1,62 @@
#include <stdlib.h>
#include <stdio.h>
#include "libgccjit.h"
#include "harness.h"
void
create_code (gcc_jit_context *ctxt, void *user_data)
{
/* Let's try to inject the equivalent of:
void
test_fn ()
{
((some_unspecified_fn_ptr_type)42) (43);
}
and verify that the API complains about the 42 not being a
function pointer. */
gcc_jit_type *void_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
gcc_jit_type *int_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
/* Build the test_fn. */
gcc_jit_function *test_fn =
gcc_jit_context_new_function (ctxt, NULL,
GCC_JIT_FUNCTION_EXPORTED,
void_type,
"test_fn",
0, NULL,
0);
gcc_jit_rvalue *not_a_function =
gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 42);
gcc_jit_rvalue *arg =
gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 43);
/* ((some_unspecified_fn_ptr_type)42) (43); */
gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
gcc_jit_block_add_eval (
block, NULL,
gcc_jit_context_new_call_through_ptr (
ctxt,
NULL,
/* This is not even a pointer, let alone a function pointer. */
not_a_function,
1, &arg));
gcc_jit_block_end_with_void_return (block, NULL);
}
void
verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
{
CHECK_VALUE (result, NULL);
/* Verify that the correct error message was emitted. */
CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
("gcc_jit_context_new_call_through_ptr:"
" fn_ptr is not a ptr: (int)42 type: int"));
}

View File

@ -0,0 +1,70 @@
#include <stdlib.h>
#include <stdio.h>
#include "libgccjit.h"
#include "harness.h"
void
create_code (gcc_jit_context *ctxt, void *user_data)
{
/* Let's try to inject the equivalent of:
void
test_caller (void (*some_fn_ptr) (int p))
{
called_function (); // missing arg
}
and verify that the API complains about the missing argument.
*/
gcc_jit_type *void_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
gcc_jit_type *int_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
/* Build the function ptr type. */
gcc_jit_type *fn_ptr_type =
gcc_jit_context_new_function_ptr_type (ctxt, NULL,
void_type,
1, &int_type, 0);
/* Build the test_fn. */
gcc_jit_param *param_fn_ptr =
gcc_jit_context_new_param (ctxt, NULL, fn_ptr_type, "some_fn_ptr");
gcc_jit_function *test_fn =
gcc_jit_context_new_function (ctxt, NULL,
GCC_JIT_FUNCTION_EXPORTED,
void_type,
"test_caller",
1, &param_fn_ptr,
0);
gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
/* called_function (); */
gcc_jit_block_add_eval (
block, NULL,
gcc_jit_context_new_call_through_ptr (
ctxt,
NULL,
gcc_jit_param_as_rvalue (param_fn_ptr),
0, NULL));
/* the above has not enough args. */
gcc_jit_block_end_with_void_return (block, NULL);
}
void
verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
{
/* Ensure that mismatching arg count leads to the API giving a NULL
result back. */
CHECK_VALUE (result, NULL);
/* Verify that the correct error message was emitted. */
CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
("gcc_jit_context_new_call_through_ptr:"
" not enough arguments to fn_ptr: some_fn_ptr"
" (got 0 args, expected 1)"));
}

View File

@ -0,0 +1,87 @@
#include <stdlib.h>
#include <stdio.h>
#include "libgccjit.h"
#include "harness.h"
#ifdef __cplusplus
extern "C" {
#endif
extern void
called_function (void);
#ifdef __cplusplus
}
#endif
void
create_code (gcc_jit_context *ctxt, void *user_data)
{
/* Let's try to inject the equivalent of:
void
test_caller (void (*some_fn_ptr) (void), int a)
{
some_fn_ptr (a);
}
and verify that the API complains about the mismatching arg
counts.
*/
gcc_jit_type *void_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
gcc_jit_type *int_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
/* Build the function ptr type. */
gcc_jit_type *fn_ptr_type =
gcc_jit_context_new_function_ptr_type (ctxt, NULL,
void_type,
0, NULL, 0);
/* Build the test_fn. */
gcc_jit_param *param_fn_ptr =
gcc_jit_context_new_param (ctxt, NULL, fn_ptr_type, "some_fn_ptr");
gcc_jit_param *param_a =
gcc_jit_context_new_param (ctxt, NULL, int_type, "a");
gcc_jit_param *params[2];
params[0] = param_fn_ptr;
params[1] = param_a;
gcc_jit_function *test_fn =
gcc_jit_context_new_function (ctxt, NULL,
GCC_JIT_FUNCTION_EXPORTED,
void_type,
"test_caller",
2, params,
0);
gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
/* some_fn_ptr (a); */
gcc_jit_rvalue *arg = gcc_jit_param_as_rvalue (param_a);
gcc_jit_block_add_eval (
block, NULL,
gcc_jit_context_new_call_through_ptr (
ctxt,
NULL,
gcc_jit_param_as_rvalue (param_fn_ptr),
1, &arg));
/* the above has too many args. */
gcc_jit_block_end_with_void_return (block, NULL);
}
void
verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
{
/* Ensure that mismatching arg count leads to the API giving a NULL
result back. */
CHECK_VALUE (result, NULL);
/* Verify that the correct error message was emitted. */
CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
"gcc_jit_context_new_call_through_ptr:"
" too many arguments to fn_ptr:"
" some_fn_ptr (got 1 args, expected 0)");
}

View File

@ -0,0 +1,87 @@
#include <stdlib.h>
#include <stdio.h>
#include "libgccjit.h"
#include "harness.h"
#ifdef __cplusplus
extern "C" {
#endif
extern void
called_function (void *ptr);
#ifdef __cplusplus
}
#endif
void
create_code (gcc_jit_context *ctxt, void *user_data)
{
/* Let's try to inject the equivalent of:
extern void called_function (void *ptr);
void
test_fn ()
{
called_function (42);
}
and verify that the API complains about the mismatching argument
type ("int" vs "void *"). */
gcc_jit_type *void_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
gcc_jit_type *void_ptr_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID_PTR);
gcc_jit_type *int_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
/* Declare the imported function. */
gcc_jit_param *param =
gcc_jit_context_new_param (ctxt, NULL, void_ptr_type, "ptr");
gcc_jit_function *called_fn =
gcc_jit_context_new_function (ctxt, NULL,
GCC_JIT_FUNCTION_IMPORTED,
void_type,
"called_function",
1, &param,
0);
/* Build the test_fn. */
gcc_jit_function *test_fn =
gcc_jit_context_new_function (ctxt, NULL,
GCC_JIT_FUNCTION_EXPORTED,
void_type,
"test_fn",
0, NULL,
0);
/* called_function (42); */
gcc_jit_rvalue *arg =
gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 42);
gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
gcc_jit_block_add_eval (
block, NULL,
gcc_jit_context_new_call (ctxt,
NULL,
called_fn,
1, &arg));
/* the above has the wrong type for argument 1. */
gcc_jit_block_end_with_void_return (block, NULL);
}
void
verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
{
CHECK_VALUE (result, NULL);
/* Verify that the correct error message was emitted. */
CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
("gcc_jit_context_new_call:"
" mismatching types for argument 1"
" of function \"called_function\":"
" assignment to param ptr (type: void *)"
" from (int)42 (type: int)"));
}

View File

@ -0,0 +1,87 @@
#include <stdlib.h>
#include <stdio.h>
#include "libgccjit.h"
#include "harness.h"
#ifdef __cplusplus
extern "C" {
#endif
extern void
called_function (void);
#ifdef __cplusplus
}
#endif
void
create_code (gcc_jit_context *ctxt, void *user_data)
{
/* Let's try to inject the equivalent of:
extern void called_function (int p);
void
test_caller ()
{
called_function (); // missing arg
}
and verify that the API complains about the missing argument.
*/
gcc_jit_type *void_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
gcc_jit_type *int_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
/* Declare the imported function. */
gcc_jit_param *param_p =
gcc_jit_context_new_param (ctxt, NULL, int_type, "p");
gcc_jit_function *called_fn =
gcc_jit_context_new_function (ctxt, NULL,
GCC_JIT_FUNCTION_IMPORTED,
void_type,
"called_function",
1, &param_p,
0);
/* Build the test_fn. */
gcc_jit_function *test_fn =
gcc_jit_context_new_function (ctxt, NULL,
GCC_JIT_FUNCTION_EXPORTED,
void_type,
"test_caller",
0, NULL,
0);
gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
/* called_function (); */
gcc_jit_block_add_eval (
block, NULL,
gcc_jit_context_new_call (ctxt,
NULL,
called_fn,
0, NULL));
/* the above has the wrong arg count. */
gcc_jit_block_end_with_void_return (block, NULL);
}
extern void
called_function (void)
{
}
void
verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
{
/* Ensure that mismatching arg count leads to the API giving a NULL
result back. */
CHECK_VALUE (result, NULL);
/* Verify that the correct error message was emitted. */
CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
("gcc_jit_context_new_call:"
" not enough arguments to function \"called_function\""
" (got 0 args, expected 1)"));
}

View File

@ -0,0 +1,89 @@
#include <stdlib.h>
#include <stdio.h>
#include "libgccjit.h"
#include "harness.h"
#ifdef __cplusplus
extern "C" {
#endif
extern void
called_function (void);
#ifdef __cplusplus
}
#endif
void
create_code (gcc_jit_context *ctxt, void *user_data)
{
/* Let's try to inject the equivalent of:
extern void called_function ();
void
test_caller (int a)
{
called_function (a);
}
and verify that the API complains about the mismatching arg
counts.
*/
gcc_jit_type *void_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
gcc_jit_type *int_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
/* Declare the imported function. */
gcc_jit_function *called_fn =
gcc_jit_context_new_function (ctxt, NULL,
GCC_JIT_FUNCTION_IMPORTED,
void_type,
"called_function",
0, NULL,
0);
/* Build the test_fn. */
gcc_jit_param *param_a =
gcc_jit_context_new_param (ctxt, NULL, int_type, "a");
gcc_jit_function *test_fn =
gcc_jit_context_new_function (ctxt, NULL,
GCC_JIT_FUNCTION_EXPORTED,
void_type,
"test_caller",
1, &param_a,
0);
gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
/* called_function (a); */
gcc_jit_rvalue *arg = gcc_jit_param_as_rvalue (param_a);
gcc_jit_block_add_eval (
block, NULL,
gcc_jit_context_new_call (ctxt,
NULL,
called_fn,
1, &arg));
/* the above has the wrong arg count. */
gcc_jit_block_end_with_void_return (block, NULL);
}
extern void
called_function (void)
{
}
void
verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
{
/* Ensure that mismatching arg count leads to the API giving a NULL
result back. */
CHECK_VALUE (result, NULL);
/* Verify that the correct error message was emitted. */
CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
("gcc_jit_context_new_call:"
" too many arguments to function \"called_function\""
" (got 1 args, expected 0)"));
}

View File

@ -0,0 +1,95 @@
#include <stdlib.h>
#include <stdio.h>
#include "libgccjit.h"
#include "harness.h"
struct foo
{
int x;
int y;
};
void
create_code (gcc_jit_context *ctxt, void *user_data)
{
/* Let's try to inject the equivalent of:
void
test_bogus_dereference ()
{
struct foo tmp;
tmp->x = tmp->y;
}
i.e. where tmp is *not* a pointer.
*/
gcc_jit_type *void_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
gcc_jit_type *int_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
/* Map "struct foo". */
gcc_jit_field *x =
gcc_jit_context_new_field (ctxt,
NULL,
int_type,
"x");
gcc_jit_field *y =
gcc_jit_context_new_field (ctxt,
NULL,
int_type,
"y");
gcc_jit_field *foo_fields[] = {x, y};
gcc_jit_struct *struct_foo =
gcc_jit_context_new_struct_type (ctxt, NULL, "foo", 2, foo_fields);
/* Build the test function. */
gcc_jit_function *test_fn =
gcc_jit_context_new_function (ctxt, NULL,
GCC_JIT_FUNCTION_EXPORTED,
void_type,
"test_bogus_dereference",
0, NULL,
0);
gcc_jit_lvalue *tmp =
gcc_jit_function_new_local (test_fn, NULL,
gcc_jit_struct_as_type (struct_foo),
"tmp");
gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
/* Erroneous: tmp->x = ... */
gcc_jit_lvalue *lvalue =
gcc_jit_rvalue_dereference_field (
gcc_jit_lvalue_as_rvalue (tmp),
NULL,
x);
/* Erroneous: ... = tmp->y; */
gcc_jit_rvalue *rvalue =
gcc_jit_lvalue_as_rvalue (
gcc_jit_rvalue_dereference_field (
gcc_jit_lvalue_as_rvalue (tmp),
NULL,
y));
gcc_jit_block_add_assignment (
block,
NULL,
lvalue, rvalue);
gcc_jit_block_end_with_void_return (block, NULL);
}
void
verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
{
CHECK_VALUE (result, NULL);
/* Verify that the correct error message was emitted. */
CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
("gcc_jit_rvalue_dereference_field:"
" dereference of non-pointer tmp (type: struct foo)"
" when accessing ->x"));
}

View File

@ -0,0 +1,55 @@
#include <stdlib.h>
#include <stdio.h>
#include "libgccjit.h"
#include "harness.h"
void
create_code (gcc_jit_context *ctxt, void *user_data)
{
/* Let's try to inject the equivalent of:
void
int test_bogus_dereference_read (int i)
{
return *i;
}
i.e. where i is *not* a pointer.
*/
gcc_jit_type *void_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
gcc_jit_type *int_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
/* Build the test function. */
gcc_jit_param *param_i =
gcc_jit_context_new_param (ctxt, NULL, int_type, "i");
gcc_jit_function *test_fn =
gcc_jit_context_new_function (ctxt, NULL,
GCC_JIT_FUNCTION_EXPORTED,
void_type,
"test_bogus_dereference_read",
1, &param_i,
0);
gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
/* Erroneous: "return *i;" */
gcc_jit_block_end_with_return (
block,
NULL,
gcc_jit_lvalue_as_rvalue (
gcc_jit_rvalue_dereference (
gcc_jit_param_as_rvalue (param_i),
NULL)));
}
void
verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
{
CHECK_VALUE (result, NULL);
/* Verify that the correct error message was emitted. */
CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
("gcc_jit_rvalue_dereference:"
" dereference of non-pointer i (type: int)"));
}

View File

@ -0,0 +1,27 @@
#include <stdlib.h>
#include <stdio.h>
#include "libgccjit.h"
#include "harness.h"
void
create_code (gcc_jit_context *ctxt, void *user_data)
{
/* Trigger an API error by passing bad data. */
gcc_jit_context_get_type (ctxt, 42);
}
void
verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
{
/* Ensure that the bad API usage prevents the API giving a bogus
result back. */
CHECK_VALUE (result, NULL);
/* Verify that the correct error message was emitted. */
CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
("gcc_jit_context_get_type:"
" unrecognized value for enum gcc_jit_types: 42"));
}

View File

@ -0,0 +1,34 @@
#include <stdlib.h>
#include <stdio.h>
#include "libgccjit.h"
#include "harness.h"
void
create_code (gcc_jit_context *ctxt, void *user_data)
{
/* Let's try to access an array at an index that isn't of a numeric
type and verify that the API complains about the bad type.
*/
gcc_jit_rvalue *string =
gcc_jit_context_new_string_literal (ctxt,
"hello world");
(void)gcc_jit_context_new_array_access (
ctxt, NULL,
string, /* ptr */
string /* index, not of numeric type */);
}
void
verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
{
CHECK_VALUE (result, NULL);
/* Verify that the correct error message was emitted. */
CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
"gcc_jit_context_new_array_access:"
" index: \"hello world\" (type: const char *)"
" is not of numeric type");
}

View File

@ -0,0 +1,61 @@
#include <stdlib.h>
#include <stdio.h>
#include "libgccjit.h"
#include "harness.h"
void
create_code (gcc_jit_context *ctxt, void *user_data)
{
/* Let's try to inject the equivalent of:
void
test_fn ()
{
int i;
i = "this is not an int";
}
and verify that the API complains about the mismatching types
in the assignment.
*/
gcc_jit_type *void_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
gcc_jit_type *int_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
gcc_jit_function *test_fn =
gcc_jit_context_new_function (ctxt, NULL,
GCC_JIT_FUNCTION_EXPORTED,
void_type,
"test_fn",
0, NULL,
0);
gcc_jit_lvalue *i =
gcc_jit_function_new_local (
test_fn, NULL, int_type, "i");
gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
gcc_jit_block_add_assignment (
block, NULL,
i, /* of type int */
gcc_jit_context_new_string_literal (
ctxt, "this is not an int"));
gcc_jit_block_end_with_void_return (block, NULL);
}
void
verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
{
CHECK_VALUE (result, NULL);
/* Verify that the correct error message was emitted. */
CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
"gcc_jit_block_add_assignment:"
" mismatching types:"
" assignment to i (type: int)"
" from \"this is not an int\" (type: const char *)");
}

View File

@ -0,0 +1,80 @@
#include <stdlib.h>
#include <stdio.h>
#include "libgccjit.h"
#include "harness.h"
void
create_code (gcc_jit_context *ctxt, void *user_data)
{
/* Let's try to inject the equivalent of:
struct foo;
extern void called_function (struct foo *ptr);
void
test_fn ()
{
struct foo f;
called_function (f);
}
and verify that we get a type error (foo * vs foo).
*/
gcc_jit_type *void_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
gcc_jit_struct *struct_foo =
gcc_jit_context_new_opaque_struct (ctxt, NULL, "foo");
gcc_jit_type *foo_ptr =
gcc_jit_type_get_pointer (gcc_jit_struct_as_type (struct_foo));
gcc_jit_param *param =
gcc_jit_context_new_param (ctxt, NULL, foo_ptr, "ptr");
gcc_jit_function *called_function =
gcc_jit_context_new_function (ctxt, NULL,
GCC_JIT_FUNCTION_IMPORTED,
void_type,
"called_function",
1, &param,
0);
gcc_jit_function *test_fn =
gcc_jit_context_new_function (ctxt, NULL,
GCC_JIT_FUNCTION_EXPORTED,
void_type,
"test_fn",
0, NULL,
0);
gcc_jit_lvalue *f =
gcc_jit_function_new_local (
test_fn, NULL, gcc_jit_struct_as_type (struct_foo), "f");
gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
gcc_jit_rvalue *arg = gcc_jit_lvalue_as_rvalue (f);
gcc_jit_block_add_eval (
block, NULL,
gcc_jit_context_new_call (
ctxt, NULL,
called_function,
1, &arg));
gcc_jit_block_end_with_void_return (block, NULL);
}
void
verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
{
CHECK_VALUE (result, NULL);
/* Verify that the correct error message was emitted. */
CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
"gcc_jit_context_new_call:"
" mismatching types for argument 1"
" of function \"called_function\":"
" assignment to param ptr (type: struct foo *)"
" from f (type: struct foo)");
}

View File

@ -0,0 +1,40 @@
#include <stdlib.h>
#include <stdio.h>
#include "libgccjit.h"
#include "harness.h"
void
create_code (gcc_jit_context *ctxt, void *user_data)
{
/* Let's try to inject the equivalent of:
int
test_fn ()
{
}
and verify that the API complains about the lack of
a returned value.
*/
gcc_jit_type *int_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
(void)gcc_jit_context_new_function (ctxt, NULL,
GCC_JIT_FUNCTION_EXPORTED,
int_type,
"test_fn",
0, NULL,
0);
}
void
verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
{
CHECK_VALUE (result, NULL);
/* Verify that the correct error message was emitted. */
CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
"function test_fn returns non-void (type: int)"
" but has no blocks");
}

View File

@ -0,0 +1,37 @@
#include <stdlib.h>
#include <stdio.h>
#include "libgccjit.h"
#include "harness.h"
void
create_code (gcc_jit_context *ctxt, void *user_data)
{
/* Trigger an API error by passing bad data. */
(void)gcc_jit_context_new_binary_op (
ctxt,
NULL,
/* Non-valid enum value: */
(enum gcc_jit_binary_op) 42,
/* These aren't valid either: */
NULL, /* gcc_jit_type *result_type, */
NULL, NULL); /* gcc_jit_rvalue *a, gcc_jit_rvalue *b */
}
void
verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
{
/* Ensure that the bad API usage prevents the API giving a bogus
result back. */
CHECK_VALUE (result, NULL);
/* Verify that the correct error message was emitted. */
CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
("gcc_jit_context_new_binary_op:"
" unrecognized value for enum gcc_jit_binary_op: 42"));
}

View File

@ -0,0 +1,41 @@
#include <stdlib.h>
#include <stdio.h>
#include "libgccjit.h"
#include "harness.h"
void
create_code (gcc_jit_context *ctxt, void *user_data)
{
gcc_jit_type *int_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
/* Trigger an API error by passing bad data. */
(void)gcc_jit_context_new_function (
ctxt,
NULL,
/* Non-valid enum value: */
(enum gcc_jit_function_kind)42,
int_type, /* gcc_jit_type *return_type, */
"foo", /* const char *name, */
0, /* int num_params, */
NULL, /* gcc_jit_param **params, */
0); /* int is_variadic */
}
void
verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
{
/* Ensure that the bad API usage prevents the API giving a bogus
result back. */
CHECK_VALUE (result, NULL);
/* Verify that the correct error message was emitted. */
CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
("gcc_jit_context_new_function:"
" unrecognized value for enum gcc_jit_function_kind: 42"));
}

View File

@ -0,0 +1,36 @@
#include <stdlib.h>
#include <stdio.h>
#include "libgccjit.h"
#include "harness.h"
void
create_code (gcc_jit_context *ctxt, void *user_data)
{
/* Trigger an API error by passing bad data. */
(void)gcc_jit_context_new_unary_op (
ctxt,
NULL,
/* Non-valid enum value: */
(enum gcc_jit_unary_op) 42,
/* These aren't valid either: */
NULL, /* gcc_jit_type *result_type, */
NULL); /* gcc_jit_rvalue *rvalue */
}
void
verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
{
/* Ensure that the bad API usage prevents the API giving a bogus
result back. */
CHECK_VALUE (result, NULL);
/* Verify that the correct error message was emitted. */
CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
("gcc_jit_context_new_unary_op:"
" unrecognized value for enum gcc_jit_unary_op: 42"));
}

View File

@ -0,0 +1,31 @@
#include <stdlib.h>
#include <stdio.h>
#include "libgccjit.h"
#include "harness.h"
void
create_code (gcc_jit_context *ctxt, void *user_data)
{
/* Trigger an API error by passing bad data. */
gcc_jit_context_new_function (ctxt, NULL,
GCC_JIT_FUNCTION_EXPORTED,
NULL, /* error: this must be non-NULL */
"hello_world",
0, NULL,
0);
}
void
verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
{
/* Ensure that the bad API usage prevents the API giving a bogus
result back. */
CHECK_VALUE (result, NULL);
/* Verify that the correct error message was emitted. */
CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
"gcc_jit_context_new_function: NULL return_type");
}

Some files were not shown because too many files have changed in this diff Show More