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:
parent
970a9caa49
commit
35485da996
|
@ -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
|
||||
|
|
|
@ -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.
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
|
@ -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'))
|
|
@ -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
|
||||
|
|
|
@ -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.
|
|
@ -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 \
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
|
@ -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.
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
|
@ -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
|
|
@ -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"
|
|
@ -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."
|
|
@ -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 |
File diff suppressed because it is too large
Load Diff
Binary file not shown.
After Width: | Height: | Size: 22 KiB |
|
@ -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'
|
|
@ -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, ¶m_name,
|
||||
0);
|
||||
|
||||
gcc_jit_param *param_format =
|
||||
gcc_jit_context_new_param (ctxt, NULL, const_char_ptr_type, "format");
|
||||
gcc_jit_function *printf_func =
|
||||
gcc_jit_context_new_function (ctxt, NULL,
|
||||
GCC_JIT_FUNCTION_IMPORTED,
|
||||
gcc_jit_context_get_type (
|
||||
ctxt, GCC_JIT_TYPE_INT),
|
||||
"printf",
|
||||
1, ¶m_format,
|
||||
1);
|
||||
gcc_jit_rvalue *args[2];
|
||||
args[0] = gcc_jit_context_new_string_literal (ctxt, "hello %s\n");
|
||||
args[1] = gcc_jit_param_as_rvalue (param_name);
|
||||
|
||||
gcc_jit_block *block = gcc_jit_function_new_block (func, NULL);
|
||||
|
||||
gcc_jit_block_add_eval (
|
||||
block, NULL,
|
||||
gcc_jit_context_new_call (ctxt,
|
||||
NULL,
|
||||
printf_func,
|
||||
2, args));
|
||||
gcc_jit_block_end_with_void_return (block, NULL);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
gcc_jit_context *ctxt;
|
||||
gcc_jit_result *result;
|
||||
|
||||
/* Get a "context" object for working with the library. */
|
||||
ctxt = gcc_jit_context_acquire ();
|
||||
if (!ctxt)
|
||||
{
|
||||
fprintf (stderr, "NULL ctxt");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
/* Set some options on the context.
|
||||
Let's see the code being generated, in assembler form. */
|
||||
gcc_jit_context_set_bool_option (
|
||||
ctxt,
|
||||
GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE,
|
||||
0);
|
||||
|
||||
/* Populate the context. */
|
||||
create_code (ctxt);
|
||||
|
||||
/* Compile the code. */
|
||||
result = gcc_jit_context_compile (ctxt);
|
||||
if (!result)
|
||||
{
|
||||
fprintf (stderr, "NULL result");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
/* Extract the generated code from "result". */
|
||||
typedef void (*fn_type) (const char *);
|
||||
fn_type greet =
|
||||
(fn_type)gcc_jit_result_get_code (result, "greet");
|
||||
if (!greet)
|
||||
{
|
||||
fprintf (stderr, "NULL greet");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
/* Now call the generated function: */
|
||||
greet ("world");
|
||||
fflush (stdout);
|
||||
|
||||
gcc_jit_context_release (ctxt);
|
||||
gcc_jit_result_release (result);
|
||||
return 0;
|
||||
}
|
|
@ -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, ¶m_i,
|
||||
0);
|
||||
|
||||
gcc_jit_block *block = gcc_jit_function_new_block (func, NULL);
|
||||
|
||||
gcc_jit_rvalue *expr =
|
||||
gcc_jit_context_new_binary_op (
|
||||
ctxt, NULL,
|
||||
GCC_JIT_BINARY_OP_MULT, int_type,
|
||||
gcc_jit_param_as_rvalue (param_i),
|
||||
gcc_jit_param_as_rvalue (param_i));
|
||||
|
||||
gcc_jit_block_end_with_return (block, NULL, expr);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
gcc_jit_context *ctxt = NULL;
|
||||
gcc_jit_result *result = NULL;
|
||||
|
||||
/* Get a "context" object for working with the library. */
|
||||
ctxt = gcc_jit_context_acquire ();
|
||||
if (!ctxt)
|
||||
{
|
||||
fprintf (stderr, "NULL ctxt");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Set some options on the context.
|
||||
Let's see the code being generated, in assembler form. */
|
||||
gcc_jit_context_set_bool_option (
|
||||
ctxt,
|
||||
GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE,
|
||||
0);
|
||||
|
||||
/* Populate the context. */
|
||||
create_code (ctxt);
|
||||
|
||||
/* Compile the code. */
|
||||
result = gcc_jit_context_compile (ctxt);
|
||||
if (!result)
|
||||
{
|
||||
fprintf (stderr, "NULL result");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Extract the generated code from "result". */
|
||||
void *fn_ptr = gcc_jit_result_get_code (result, "square");
|
||||
if (!fn_ptr)
|
||||
{
|
||||
fprintf (stderr, "NULL fn_ptr");
|
||||
goto error;
|
||||
}
|
||||
|
||||
typedef int (*fn_type) (int);
|
||||
fn_type square = (fn_type)fn_ptr;
|
||||
printf ("result: %d", square (5));
|
||||
|
||||
error:
|
||||
gcc_jit_context_release (ctxt);
|
||||
gcc_jit_result_release (result);
|
||||
return 0;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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 |
|
@ -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 |
|
@ -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
|
|
@ -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, ¶m_i,
|
||||
0);
|
||||
|
||||
To define the code within the function, we must create basic blocks
|
||||
containing statements.
|
||||
|
||||
Every basic block contains a list of statements, eventually terminated
|
||||
by a statement that either returns, or jumps to another basic block.
|
||||
|
||||
Our function has no control-flow, so we just need one basic block:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
gcc_jit_block *block = gcc_jit_function_new_block (func, NULL);
|
||||
|
||||
Our basic block is relatively simple: it immediately terminates by
|
||||
returning the value of an expression.
|
||||
|
||||
We can build the expression using :c:func:`gcc_jit_context_new_binary_op`:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
gcc_jit_rvalue *expr =
|
||||
gcc_jit_context_new_binary_op (
|
||||
ctxt, NULL,
|
||||
GCC_JIT_BINARY_OP_MULT, int_type,
|
||||
gcc_jit_param_as_rvalue (param_i),
|
||||
gcc_jit_param_as_rvalue (param_i));
|
||||
|
||||
A :c:type:`gcc_jit_rvalue *` is another example of a
|
||||
:c:type:`gcc_jit_object *` subclass. We can upcast it using
|
||||
:c:func:`gcc_jit_rvalue_as_object` and as before print it with
|
||||
:c:func:`gcc_jit_object_get_debug_string`.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
printf ("expr: %s\n",
|
||||
gcc_jit_object_get_debug_string (
|
||||
gcc_jit_rvalue_as_object (expr)));
|
||||
|
||||
giving this output:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
expr: i * i
|
||||
|
||||
Creating the expression in itself doesn't do anything; we have to add
|
||||
this expression to a statement within the block. In this case, we use it
|
||||
to build a return statement, which terminates the basic block:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
gcc_jit_block_end_with_return (block, NULL, expr);
|
||||
|
||||
OK, we've populated the context. We can now compile it using
|
||||
:c:func:`gcc_jit_context_compile`:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
gcc_jit_result *result;
|
||||
result = gcc_jit_context_compile (ctxt);
|
||||
|
||||
and get a :c:type:`gcc_jit_result *`.
|
||||
|
||||
We can now use :c:func:`gcc_jit_result_get_code` to look up a specific
|
||||
machine code routine within the result, in this case, the function we
|
||||
created above.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
void *fn_ptr = gcc_jit_result_get_code (result, "square");
|
||||
if (!fn_ptr)
|
||||
{
|
||||
fprintf (stderr, "NULL fn_ptr");
|
||||
goto error;
|
||||
}
|
||||
|
||||
We can now cast the pointer to an appropriate function pointer type, and
|
||||
then call it:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
typedef int (*fn_type) (int);
|
||||
fn_type square = (fn_type)fn_ptr;
|
||||
printf ("result: %d", square (5));
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
result: 25
|
||||
|
||||
|
||||
Options
|
||||
*******
|
||||
|
||||
To get more information on what's going on, you can set debugging flags
|
||||
on the context using :c:func:`gcc_jit_context_set_bool_option`.
|
||||
|
||||
.. (I'm deliberately not mentioning
|
||||
:c:macro:`GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE` here since I think
|
||||
it's probably more of use to implementors than to users)
|
||||
|
||||
Setting :c:macro:`GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE` will dump a
|
||||
C-like representation to stderr when you compile (GCC's "GIMPLE"
|
||||
representation):
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
gcc_jit_context_set_bool_option (
|
||||
ctxt,
|
||||
GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE,
|
||||
1);
|
||||
result = gcc_jit_context_compile (ctxt);
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
square (signed int i)
|
||||
{
|
||||
signed int D.260;
|
||||
|
||||
entry:
|
||||
D.260 = i * i;
|
||||
return D.260;
|
||||
}
|
||||
|
||||
We can see the generated machine code in assembler form (on stderr) by
|
||||
setting :c:macro:`GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE` on the context
|
||||
before compiling:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
gcc_jit_context_set_bool_option (
|
||||
ctxt,
|
||||
GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE,
|
||||
1);
|
||||
result = gcc_jit_context_compile (ctxt);
|
||||
|
||||
.. code-block:: gas
|
||||
|
||||
.file "fake.c"
|
||||
.text
|
||||
.globl square
|
||||
.type square, @function
|
||||
square:
|
||||
.LFB6:
|
||||
.cfi_startproc
|
||||
pushq %rbp
|
||||
.cfi_def_cfa_offset 16
|
||||
.cfi_offset 6, -16
|
||||
movq %rsp, %rbp
|
||||
.cfi_def_cfa_register 6
|
||||
movl %edi, -4(%rbp)
|
||||
.L14:
|
||||
movl -4(%rbp), %eax
|
||||
imull -4(%rbp), %eax
|
||||
popq %rbp
|
||||
.cfi_def_cfa 7, 8
|
||||
ret
|
||||
.cfi_endproc
|
||||
.LFE6:
|
||||
.size square, .-square
|
||||
.ident "GCC: (GNU) 4.9.0 20131023 (Red Hat 0.2-0.5.1920c315ff984892399893b380305ab36e07b455.fc20)"
|
||||
.section .note.GNU-stack,"",@progbits
|
||||
|
||||
By default, no optimizations are performed, the equivalent of GCC's
|
||||
`-O0` option. We can turn things up to e.g. `-O3` by calling
|
||||
:c:func:`gcc_jit_context_set_int_option` with
|
||||
:c:macro:`GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL`:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
gcc_jit_context_set_int_option (
|
||||
ctxt,
|
||||
GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL,
|
||||
3);
|
||||
|
||||
.. code-block:: gas
|
||||
|
||||
.file "fake.c"
|
||||
.text
|
||||
.p2align 4,,15
|
||||
.globl square
|
||||
.type square, @function
|
||||
square:
|
||||
.LFB7:
|
||||
.cfi_startproc
|
||||
.L16:
|
||||
movl %edi, %eax
|
||||
imull %edi, %eax
|
||||
ret
|
||||
.cfi_endproc
|
||||
.LFE7:
|
||||
.size square, .-square
|
||||
.ident "GCC: (GNU) 4.9.0 20131023 (Red Hat 0.2-0.5.1920c315ff984892399893b380305ab36e07b455.fc20)"
|
||||
.section .note.GNU-stack,"",@progbits
|
||||
|
||||
Naturally this has only a small effect on such a trivial function.
|
||||
|
||||
|
||||
Full example
|
||||
************
|
||||
|
||||
Here's what the above looks like as a complete program:
|
||||
|
||||
.. literalinclude:: ../examples/tut02-square.c
|
||||
:lines: 1-
|
||||
:language: c
|
||||
|
||||
Building and running it:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ gcc \
|
||||
tut02-square.c \
|
||||
-o tut02-square \
|
||||
-lgccjit
|
||||
|
||||
# Run the built program:
|
||||
$ ./tut02-square
|
||||
result: 25
|
|
@ -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
|
@ -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).
|
|
@ -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``).
|
|
@ -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;
|
|
@ -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
|
|
@ -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.
|
|
@ -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.
|
|
@ -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.
|
|
@ -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.
|
|
@ -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"
|
|
@ -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
|
|
@ -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 */
|
|
@ -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 */
|
File diff suppressed because it is too large
Load Diff
|
@ -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 */
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -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 */
|
|
@ -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: *;
|
||||
};
|
|
@ -0,0 +1,84 @@
|
|||
Client Code . Generated . libgccjit.so
|
||||
. code .
|
||||
. . JIT API . JIT "Frontend". (libbackend.a)
|
||||
....................................................................................
|
||||
│ . . . .
|
||||
──────────────────────────> . .
|
||||
. . │ . .
|
||||
. . V . .
|
||||
. . ──> libgccjit.c .
|
||||
. . │ (error-checking).
|
||||
. . │ .
|
||||
. . ──> jit-recording.c
|
||||
. . (record API calls)
|
||||
. . <─────── .
|
||||
. . │ . .
|
||||
<─────────────────────────── . .
|
||||
│ . . . .
|
||||
│ . . . .
|
||||
V . . gcc_jit_context_compile .
|
||||
──────────────────────────> . .
|
||||
. . │ . .
|
||||
. . │ ACQUIRE MUTEX .
|
||||
. . │ . .
|
||||
. . V───────────────────────> toplev::main (for now)
|
||||
. . . . │
|
||||
. . . . (various code)
|
||||
. . . . │
|
||||
. . . . V
|
||||
. . . <───────────────── langhook:parse_file
|
||||
. . . │ .
|
||||
. . . │ (jit_langhook_parse_file)
|
||||
. . . │ .
|
||||
..........................................│..................VVVVVVVVVVVVV...
|
||||
. . . │ . No GC in here
|
||||
. . . │ jit-playback.c
|
||||
. . . │ (playback of API calls)
|
||||
. . . ───────────────> creation of functions,
|
||||
. . . . types, expression trees
|
||||
. . . <──────────────── etc
|
||||
. . . │(handle_locations: add locations to
|
||||
. . . │ linemap and associate them with trees)
|
||||
. . . │ .
|
||||
. . . │ . No GC in here
|
||||
..........................................│..................AAAAAAAAAAAAA...
|
||||
. . . │ for each function
|
||||
. . . ──> postprocess
|
||||
. . . │ .
|
||||
. . . ────────────> cgraph_finalize_function
|
||||
. . . <────────────
|
||||
. . . <── .
|
||||
. . . │ .
|
||||
. . . ──────────────────> (end of
|
||||
. . . . │ langhook_parse_file)
|
||||
. . . . │
|
||||
. . . . (various code)
|
||||
. . . . │
|
||||
. . . . ↓
|
||||
. . . <───────────────── langhook:write_globals
|
||||
. . . │ .
|
||||
. . . │ (jit_langhook_write_globals)
|
||||
. . . │ .
|
||||
. . . │ .
|
||||
. . . ──────────────────> finalize_compilation_unit
|
||||
. . . . │
|
||||
. . . . (the middle─end and backend)
|
||||
. . . . ↓
|
||||
. . <───────────────────────────── end of toplev::main
|
||||
. . │ RELEASE MUTEX .
|
||||
. . │ . .
|
||||
. . │ Convert assembler to DSO
|
||||
. . │ . .
|
||||
. . │ Load DSO .
|
||||
<─────────────────────────── . .
|
||||
│ . . . .
|
||||
Get (void*). . . .
|
||||
│ . . . .
|
||||
│ Call it . . . .
|
||||
───────────────> . . .
|
||||
. │ . . .
|
||||
. │ . . .
|
||||
<─────────────── . . .
|
||||
│ . . . .
|
||||
│ . . . .
|
||||
etc
|
|
@ -1,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.
|
||||
|
|
|
@ -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.
|
|
@ -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
|
|
@ -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 */
|
|
@ -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
|
|
@ -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, ¶m_f,
|
||||
0);
|
||||
|
||||
/* f->x * f->y */
|
||||
gcc_jit_rvalue *sum =
|
||||
gcc_jit_context_new_binary_op (
|
||||
ctxt, NULL,
|
||||
GCC_JIT_BINARY_OP_MULT,
|
||||
int_type,
|
||||
gcc_jit_lvalue_as_rvalue (
|
||||
gcc_jit_rvalue_dereference_field (
|
||||
gcc_jit_param_as_rvalue (param_f),
|
||||
NULL,
|
||||
x)),
|
||||
gcc_jit_lvalue_as_rvalue (
|
||||
gcc_jit_rvalue_dereference_field (
|
||||
gcc_jit_param_as_rvalue (param_f),
|
||||
NULL,
|
||||
y)));
|
||||
|
||||
/* f->z = ... */
|
||||
gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
|
||||
gcc_jit_block_add_assignment (
|
||||
block,
|
||||
NULL,
|
||||
gcc_jit_rvalue_dereference_field (
|
||||
gcc_jit_param_as_rvalue (param_f),
|
||||
NULL,
|
||||
z),
|
||||
sum);
|
||||
gcc_jit_block_end_with_void_return (block, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
|
||||
{
|
||||
typedef void (*fn_type) (struct foo *);
|
||||
CHECK_NON_NULL (result);
|
||||
|
||||
fn_type test_access =
|
||||
(fn_type)gcc_jit_result_get_code (result, "test_access");
|
||||
CHECK_NON_NULL (test_access);
|
||||
|
||||
struct foo tmp;
|
||||
tmp.x = 5;
|
||||
tmp.y = 7;
|
||||
tmp.z = 0;
|
||||
|
||||
/* Call the JIT-generated function. */
|
||||
test_access (&tmp);
|
||||
|
||||
/* Verify that the code correctly modified the field "z". */
|
||||
CHECK_VALUE (tmp.z, 35);
|
||||
}
|
||||
|
|
@ -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, ¶m_i,
|
||||
0);
|
||||
|
||||
gcc_jit_lvalue *u =
|
||||
gcc_jit_function_new_local (test_fn, NULL,
|
||||
union_type, "u");
|
||||
|
||||
gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
|
||||
|
||||
/* u.as_int = i; */
|
||||
gcc_jit_block_add_assignment (
|
||||
block,
|
||||
NULL,
|
||||
/* "u.as_int = ..." */
|
||||
gcc_jit_lvalue_access_field (u,
|
||||
NULL,
|
||||
as_int),
|
||||
gcc_jit_param_as_rvalue (param_i));
|
||||
|
||||
/* return u.as_float; */
|
||||
gcc_jit_block_end_with_return (
|
||||
block, NULL,
|
||||
gcc_jit_rvalue_access_field (gcc_jit_lvalue_as_rvalue (u),
|
||||
NULL,
|
||||
as_float));
|
||||
}
|
||||
|
||||
void
|
||||
verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
|
||||
{
|
||||
typedef float (*fn_type) (int i);
|
||||
CHECK_NON_NULL (result);
|
||||
|
||||
fn_type test_union =
|
||||
(fn_type)gcc_jit_result_get_code (result, "test_union");
|
||||
CHECK_NON_NULL (test_union);
|
||||
|
||||
/* Call the JIT-generated function. */
|
||||
float f_result = test_union (42);
|
||||
|
||||
union int_or_float u;
|
||||
u.as_float = f_result;
|
||||
|
||||
CHECK_VALUE (u.as_int, 42);
|
||||
}
|
|
@ -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, ¶m_name,
|
||||
0);
|
||||
|
||||
gcc_jit_lvalue *buffer =
|
||||
gcc_jit_context_new_global (ctxt, NULL, buf_type, "test_buffer");
|
||||
|
||||
gcc_jit_block *block = gcc_jit_function_new_block(test_fn, "entry");
|
||||
|
||||
/* snprintf(buffer, sizeof(buffer), "hello %s", name); */
|
||||
gcc_jit_rvalue *args[4];
|
||||
args[0] = gcc_jit_context_new_cast (
|
||||
ctxt, NULL,
|
||||
/* Here's the difference with test-error-array-as-pointer.c: */
|
||||
gcc_jit_lvalue_get_address (buffer,
|
||||
NULL),
|
||||
char_ptr_type);
|
||||
args[1] = gcc_jit_context_new_rvalue_from_int (ctxt,
|
||||
size_t_type,
|
||||
BUFFER_SIZE);
|
||||
args[2] = gcc_jit_context_new_string_literal (ctxt, "hello %s");
|
||||
args[3] = gcc_jit_param_as_rvalue (param_name);
|
||||
|
||||
gcc_jit_block_add_eval (
|
||||
block, NULL,
|
||||
gcc_jit_context_new_call (ctxt, NULL, snprintf, 4, args));
|
||||
gcc_jit_block_end_with_void_return (block, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
|
||||
{
|
||||
CHECK_NON_NULL (result);
|
||||
|
||||
typedef void (*fn_type) (const char *);
|
||||
fn_type test_of_array_as_pointer =
|
||||
(fn_type)gcc_jit_result_get_code (result, "test_of_array_as_pointer");
|
||||
CHECK_NON_NULL (test_of_array_as_pointer);
|
||||
|
||||
test_of_array_as_pointer ("world");
|
||||
CHECK_STRING_VALUE (test_buffer, "hello world");
|
||||
}
|
|
@ -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, ¶m_ah,
|
||||
0);
|
||||
|
||||
gcc_jit_block *initial = gcc_jit_function_new_block (func, "initial");
|
||||
gcc_jit_block *loop_test = gcc_jit_function_new_block (func, "loop_test");
|
||||
gcc_jit_block *loop_body = gcc_jit_function_new_block (func, "loop_body");
|
||||
gcc_jit_block *final = gcc_jit_function_new_block (func, "final");
|
||||
|
||||
/* "ah->m_before = 4.0f;" */
|
||||
gcc_jit_block_add_assignment (
|
||||
initial, NULL,
|
||||
gcc_jit_rvalue_dereference_field (
|
||||
gcc_jit_param_as_rvalue (param_ah), NULL, field_m_before),
|
||||
gcc_jit_context_new_rvalue_from_int (ctxt, float_type, 4));
|
||||
|
||||
gcc_jit_block_add_comment (initial, NULL,
|
||||
"for i in 0 to (ARRAY_SIZE - 1):");
|
||||
gcc_jit_lvalue *i =
|
||||
gcc_jit_function_new_local (func, NULL, int_type, "i");
|
||||
gcc_jit_block_add_assignment (initial, NULL,
|
||||
i,
|
||||
gcc_jit_context_zero (ctxt, int_type));
|
||||
|
||||
gcc_jit_block_end_with_jump (initial, NULL, loop_test);
|
||||
|
||||
gcc_jit_block_end_with_conditional (loop_test, NULL,
|
||||
gcc_jit_context_new_comparison (
|
||||
ctxt, NULL,
|
||||
GCC_JIT_COMPARISON_LT,
|
||||
gcc_jit_lvalue_as_rvalue (i),
|
||||
gcc_jit_context_new_rvalue_from_int (ctxt, int_type, ARRAY_SIZE)),
|
||||
loop_body,
|
||||
final);
|
||||
|
||||
gcc_jit_block_add_comment (loop_body, NULL, "ah->m_ints[i] = (i * i);");
|
||||
gcc_jit_block_add_assignment (
|
||||
loop_body, NULL,
|
||||
gcc_jit_context_new_array_access (
|
||||
ctxt, NULL,
|
||||
gcc_jit_lvalue_as_rvalue (gcc_jit_rvalue_dereference_field (
|
||||
gcc_jit_param_as_rvalue (param_ah),
|
||||
NULL,
|
||||
field_m_ints)),
|
||||
gcc_jit_lvalue_as_rvalue (i)),
|
||||
gcc_jit_context_new_binary_op (
|
||||
ctxt, NULL,
|
||||
GCC_JIT_BINARY_OP_MULT,
|
||||
int_type,
|
||||
gcc_jit_lvalue_as_rvalue (i),
|
||||
gcc_jit_lvalue_as_rvalue (i)));
|
||||
|
||||
/* "i++" */
|
||||
gcc_jit_block_add_assignment_op (
|
||||
loop_body, NULL,
|
||||
i,
|
||||
GCC_JIT_BINARY_OP_PLUS,
|
||||
gcc_jit_context_one (ctxt, int_type));
|
||||
|
||||
gcc_jit_block_end_with_jump (loop_body, NULL, loop_test);
|
||||
|
||||
/* ah->m_after = 2.0f; */
|
||||
gcc_jit_block_add_assignment (
|
||||
final, NULL,
|
||||
gcc_jit_rvalue_dereference_field (
|
||||
gcc_jit_param_as_rvalue (param_ah), NULL, field_m_after),
|
||||
gcc_jit_context_new_rvalue_from_int (ctxt, float_type, 2));
|
||||
gcc_jit_block_end_with_void_return (final, NULL);
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
|
||||
{
|
||||
typedef void (*fn_type) (struct array_holder *ah);
|
||||
|
||||
CHECK_NON_NULL (result);
|
||||
fn_type test_array =
|
||||
(fn_type)gcc_jit_result_get_code (result, "test_array");
|
||||
CHECK_NON_NULL (test_array);
|
||||
|
||||
struct array_holder ah;
|
||||
memset (&ah, 0xf0, sizeof (ah));
|
||||
|
||||
test_array (&ah);
|
||||
CHECK_VALUE (ah.m_before, 4.0f);
|
||||
CHECK_VALUE (ah.m_ints[0], 0);
|
||||
CHECK_VALUE (ah.m_ints[1], 1);
|
||||
CHECK_VALUE (ah.m_ints[2], 4);
|
||||
CHECK_VALUE (ah.m_ints[3], 9);
|
||||
CHECK_VALUE (ah.m_after, 2.0f);
|
||||
|
||||
}
|
|
@ -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, ¶m_a,
|
||||
0);
|
||||
/* "a * 3, a * 4, a * 5" */
|
||||
gcc_jit_rvalue *args[3];
|
||||
for (i = 0; i < 3; i++)
|
||||
args[i] =
|
||||
gcc_jit_context_new_binary_op (
|
||||
ctxt, NULL,
|
||||
GCC_JIT_BINARY_OP_MULT,
|
||||
int_type,
|
||||
gcc_jit_param_as_rvalue (param_a),
|
||||
gcc_jit_context_new_rvalue_from_int (
|
||||
ctxt,
|
||||
int_type,
|
||||
(i + 3) ));
|
||||
gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
|
||||
gcc_jit_block_add_eval (
|
||||
block, NULL,
|
||||
gcc_jit_context_new_call (ctxt,
|
||||
NULL,
|
||||
called_fn,
|
||||
3, args));
|
||||
gcc_jit_block_end_with_void_return (block, NULL);
|
||||
}
|
||||
|
||||
static int called_with[3];
|
||||
|
||||
extern void
|
||||
called_function (int i, int j, int k)
|
||||
{
|
||||
called_with[0] = i;
|
||||
called_with[1] = j;
|
||||
called_with[2] = k;
|
||||
}
|
||||
|
||||
void
|
||||
verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
|
||||
{
|
||||
typedef void (*fn_type) (int);
|
||||
CHECK_NON_NULL (result);
|
||||
|
||||
fn_type test_caller =
|
||||
(fn_type)gcc_jit_result_get_code (result, "test_caller");
|
||||
CHECK_NON_NULL (test_caller);
|
||||
|
||||
called_with[0] = 0;
|
||||
called_with[1] = 0;
|
||||
called_with[2] = 0;
|
||||
|
||||
/* Call the JIT-generated function. */
|
||||
test_caller (5);
|
||||
|
||||
/* Verify that it correctly called "called_function". */
|
||||
CHECK_VALUE (called_with[0], 15);
|
||||
CHECK_VALUE (called_with[1], 20);
|
||||
CHECK_VALUE (called_with[2], 25);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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, ¶m_f,
|
||||
0);
|
||||
|
||||
/* Erroneous: f->p = ... */
|
||||
gcc_jit_lvalue *lvalue =
|
||||
gcc_jit_rvalue_dereference_field (
|
||||
gcc_jit_param_as_rvalue (param_f),
|
||||
NULL,
|
||||
p);
|
||||
|
||||
/* Erroneous: ... = f->q; */
|
||||
gcc_jit_rvalue *rvalue =
|
||||
gcc_jit_lvalue_as_rvalue (
|
||||
gcc_jit_rvalue_dereference_field (
|
||||
gcc_jit_param_as_rvalue (param_f),
|
||||
NULL,
|
||||
q));
|
||||
|
||||
gcc_jit_block *block =
|
||||
gcc_jit_function_new_block (test_fn, NULL);
|
||||
gcc_jit_block_add_assignment (
|
||||
block,
|
||||
NULL,
|
||||
lvalue, rvalue);
|
||||
gcc_jit_block_end_with_void_return (block, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
|
||||
{
|
||||
CHECK_VALUE (result, NULL);
|
||||
|
||||
/* Verify that the correct error message was emitted. */
|
||||
CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
|
||||
"gcc_jit_rvalue_dereference_field:"
|
||||
" p is not a field of struct foo");
|
||||
}
|
||||
|
|
@ -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;)");
|
||||
}
|
|
@ -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, ¶m_name,
|
||||
0);
|
||||
|
||||
gcc_jit_lvalue *buffer =
|
||||
gcc_jit_context_new_global (ctxt, NULL, buf_type, "test_buffer");
|
||||
|
||||
gcc_jit_block *block = gcc_jit_function_new_block(test_fn, "entry");
|
||||
|
||||
/* snprintf(buffer, sizeof(buffer), "hello %s", name); */
|
||||
gcc_jit_rvalue *args[4];
|
||||
args[0] = gcc_jit_context_new_cast (
|
||||
ctxt, NULL,
|
||||
/* Here's the difference with test-array-as-pointer.c: */
|
||||
gcc_jit_lvalue_as_rvalue (buffer),
|
||||
char_ptr_type);
|
||||
args[1] = gcc_jit_context_new_rvalue_from_int (ctxt,
|
||||
size_t_type,
|
||||
BUFFER_SIZE);
|
||||
args[2] = gcc_jit_context_new_string_literal (ctxt, "hello %s");
|
||||
args[3] = gcc_jit_param_as_rvalue (param_name);
|
||||
|
||||
gcc_jit_block_add_eval (
|
||||
block, NULL,
|
||||
gcc_jit_context_new_call (ctxt, NULL, snprintf, 4, args));
|
||||
gcc_jit_block_end_with_void_return (block, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
|
||||
{
|
||||
CHECK_VALUE (result, NULL);
|
||||
|
||||
/* Verify that the correct error message was emitted. */
|
||||
CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
|
||||
"gcc_jit_context_new_cast:"
|
||||
" cannot cast test_buffer"
|
||||
" from type: char[1024]"
|
||||
" to type: char *");
|
||||
}
|
|
@ -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");
|
||||
}
|
||||
|
|
@ -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");
|
||||
}
|
|
@ -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, ¶m_fn_ptr,
|
||||
0);
|
||||
/* some_fn_ptr (42); */
|
||||
gcc_jit_rvalue *arg =
|
||||
gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 42);
|
||||
|
||||
gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
|
||||
gcc_jit_block_add_eval (
|
||||
block, NULL,
|
||||
gcc_jit_context_new_call_through_ptr (
|
||||
ctxt,
|
||||
NULL,
|
||||
gcc_jit_param_as_rvalue (param_fn_ptr),
|
||||
1, &arg));
|
||||
/* the above has the wrong type for argument 1. */
|
||||
gcc_jit_block_end_with_void_return (block, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
|
||||
{
|
||||
CHECK_VALUE (result, NULL);
|
||||
|
||||
/* Verify that the correct error message was emitted. */
|
||||
CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
|
||||
("gcc_jit_context_new_call_through_ptr:"
|
||||
" mismatching types for argument 1 of fn_ptr:"
|
||||
" some_fn_ptr:"
|
||||
" assignment to param 1 (type: void *)"
|
||||
" from (int)42 (type: int)"));
|
||||
}
|
||||
|
|
@ -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 *"));
|
||||
}
|
||||
|
|
@ -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"));
|
||||
}
|
||||
|
|
@ -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, ¶m_fn_ptr,
|
||||
0);
|
||||
|
||||
gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
|
||||
/* called_function (); */
|
||||
gcc_jit_block_add_eval (
|
||||
block, NULL,
|
||||
gcc_jit_context_new_call_through_ptr (
|
||||
ctxt,
|
||||
NULL,
|
||||
gcc_jit_param_as_rvalue (param_fn_ptr),
|
||||
0, NULL));
|
||||
/* the above has not enough args. */
|
||||
gcc_jit_block_end_with_void_return (block, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
|
||||
{
|
||||
/* Ensure that mismatching arg count leads to the API giving a NULL
|
||||
result back. */
|
||||
CHECK_VALUE (result, NULL);
|
||||
|
||||
/* Verify that the correct error message was emitted. */
|
||||
CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
|
||||
("gcc_jit_context_new_call_through_ptr:"
|
||||
" not enough arguments to fn_ptr: some_fn_ptr"
|
||||
" (got 0 args, expected 1)"));
|
||||
}
|
||||
|
|
@ -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)");
|
||||
}
|
||||
|
|
@ -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, ¶m,
|
||||
0);
|
||||
|
||||
/* Build the test_fn. */
|
||||
gcc_jit_function *test_fn =
|
||||
gcc_jit_context_new_function (ctxt, NULL,
|
||||
GCC_JIT_FUNCTION_EXPORTED,
|
||||
void_type,
|
||||
"test_fn",
|
||||
0, NULL,
|
||||
0);
|
||||
/* called_function (42); */
|
||||
gcc_jit_rvalue *arg =
|
||||
gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 42);
|
||||
|
||||
gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
|
||||
gcc_jit_block_add_eval (
|
||||
block, NULL,
|
||||
gcc_jit_context_new_call (ctxt,
|
||||
NULL,
|
||||
called_fn,
|
||||
1, &arg));
|
||||
/* the above has the wrong type for argument 1. */
|
||||
gcc_jit_block_end_with_void_return (block, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
|
||||
{
|
||||
CHECK_VALUE (result, NULL);
|
||||
|
||||
/* Verify that the correct error message was emitted. */
|
||||
CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
|
||||
("gcc_jit_context_new_call:"
|
||||
" mismatching types for argument 1"
|
||||
" of function \"called_function\":"
|
||||
" assignment to param ptr (type: void *)"
|
||||
" from (int)42 (type: int)"));
|
||||
}
|
||||
|
|
@ -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, ¶m_p,
|
||||
0);
|
||||
|
||||
/* Build the test_fn. */
|
||||
gcc_jit_function *test_fn =
|
||||
gcc_jit_context_new_function (ctxt, NULL,
|
||||
GCC_JIT_FUNCTION_EXPORTED,
|
||||
void_type,
|
||||
"test_caller",
|
||||
0, NULL,
|
||||
0);
|
||||
gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
|
||||
/* called_function (); */
|
||||
gcc_jit_block_add_eval (
|
||||
block, NULL,
|
||||
gcc_jit_context_new_call (ctxt,
|
||||
NULL,
|
||||
called_fn,
|
||||
0, NULL));
|
||||
/* the above has the wrong arg count. */
|
||||
gcc_jit_block_end_with_void_return (block, NULL);
|
||||
}
|
||||
|
||||
extern void
|
||||
called_function (void)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
|
||||
{
|
||||
/* Ensure that mismatching arg count leads to the API giving a NULL
|
||||
result back. */
|
||||
CHECK_VALUE (result, NULL);
|
||||
|
||||
/* Verify that the correct error message was emitted. */
|
||||
CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
|
||||
("gcc_jit_context_new_call:"
|
||||
" not enough arguments to function \"called_function\""
|
||||
" (got 0 args, expected 1)"));
|
||||
}
|
||||
|
|
@ -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, ¶m_a,
|
||||
0);
|
||||
gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
|
||||
/* called_function (a); */
|
||||
gcc_jit_rvalue *arg = gcc_jit_param_as_rvalue (param_a);
|
||||
gcc_jit_block_add_eval (
|
||||
block, NULL,
|
||||
gcc_jit_context_new_call (ctxt,
|
||||
NULL,
|
||||
called_fn,
|
||||
1, &arg));
|
||||
/* the above has the wrong arg count. */
|
||||
gcc_jit_block_end_with_void_return (block, NULL);
|
||||
}
|
||||
|
||||
extern void
|
||||
called_function (void)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
|
||||
{
|
||||
/* Ensure that mismatching arg count leads to the API giving a NULL
|
||||
result back. */
|
||||
CHECK_VALUE (result, NULL);
|
||||
|
||||
/* Verify that the correct error message was emitted. */
|
||||
CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
|
||||
("gcc_jit_context_new_call:"
|
||||
" too many arguments to function \"called_function\""
|
||||
" (got 1 args, expected 0)"));
|
||||
}
|
||||
|
|
@ -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"));
|
||||
}
|
||||
|
|
@ -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, ¶m_i,
|
||||
0);
|
||||
gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
|
||||
/* Erroneous: "return *i;" */
|
||||
gcc_jit_block_end_with_return (
|
||||
block,
|
||||
NULL,
|
||||
gcc_jit_lvalue_as_rvalue (
|
||||
gcc_jit_rvalue_dereference (
|
||||
gcc_jit_param_as_rvalue (param_i),
|
||||
NULL)));
|
||||
}
|
||||
|
||||
void
|
||||
verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
|
||||
{
|
||||
CHECK_VALUE (result, NULL);
|
||||
|
||||
/* Verify that the correct error message was emitted. */
|
||||
CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
|
||||
("gcc_jit_rvalue_dereference:"
|
||||
" dereference of non-pointer i (type: int)"));
|
||||
}
|
||||
|
|
@ -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"));
|
||||
}
|
||||
|
|
@ -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");
|
||||
}
|
|
@ -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 *)");
|
||||
}
|
||||
|
|
@ -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, ¶m,
|
||||
0);
|
||||
|
||||
gcc_jit_function *test_fn =
|
||||
gcc_jit_context_new_function (ctxt, NULL,
|
||||
GCC_JIT_FUNCTION_EXPORTED,
|
||||
void_type,
|
||||
"test_fn",
|
||||
0, NULL,
|
||||
0);
|
||||
gcc_jit_lvalue *f =
|
||||
gcc_jit_function_new_local (
|
||||
test_fn, NULL, gcc_jit_struct_as_type (struct_foo), "f");
|
||||
|
||||
gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
|
||||
|
||||
gcc_jit_rvalue *arg = gcc_jit_lvalue_as_rvalue (f);
|
||||
|
||||
gcc_jit_block_add_eval (
|
||||
block, NULL,
|
||||
gcc_jit_context_new_call (
|
||||
ctxt, NULL,
|
||||
called_function,
|
||||
1, &arg));
|
||||
gcc_jit_block_end_with_void_return (block, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
|
||||
{
|
||||
CHECK_VALUE (result, NULL);
|
||||
|
||||
/* Verify that the correct error message was emitted. */
|
||||
CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
|
||||
"gcc_jit_context_new_call:"
|
||||
" mismatching types for argument 1"
|
||||
" of function \"called_function\":"
|
||||
" assignment to param ptr (type: struct foo *)"
|
||||
" from f (type: struct foo)");
|
||||
}
|
||||
|
|
@ -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");
|
||||
}
|
||||
|
|
@ -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"));
|
||||
}
|
||||
|
|
@ -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"));
|
||||
}
|
||||
|
|
@ -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"));
|
||||
}
|
||||
|
|
@ -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
Loading…
Reference in New Issue