mirror of
https://gcc.gnu.org/git/gcc.git
synced 2024-11-23 02:44:18 +08:00
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
|
||||
|
23
ChangeLog.jit
Normal file
23
ChangeLog.jit
Normal file
@ -0,0 +1,23 @@
|
||||
2014-10-02 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* MAINTAINERS: Update jit entry to match formatting change on
|
||||
trunk: "Put all email addresses between '<' and '>'."
|
||||
|
||||
2014-09-24 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* ChangeLog.jit: Add copyright footer.
|
||||
|
||||
2014-09-11 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* MAINTAINERS (Various Maintainers): Add myself as jit maintainer.
|
||||
|
||||
2013-10-03 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* configure.ac: Add --enable-host-shared
|
||||
* configure: Regenerate.
|
||||
|
||||
Copyright (C) 2013-2014 Free Software Foundation, Inc.
|
||||
|
||||
Copying and distribution of this file, with or without modification,
|
||||
are permitted in any medium without royalty provided the copyright
|
||||
notice and this notice are preserved.
|
@ -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.
|
||||
|
14
contrib/ChangeLog.jit
Normal file
14
contrib/ChangeLog.jit
Normal file
@ -0,0 +1,14 @@
|
||||
2014-09-24 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* ChangeLog.jit: Add copyright footer.
|
||||
|
||||
2014-01-23 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* jit-coverage-report.py: New file: a script to print crude
|
||||
code-coverage information for the libgccjit API.
|
||||
|
||||
Copyright (C) 2014 Free Software Foundation, Inc.
|
||||
|
||||
Copying and distribution of this file, with or without modification,
|
||||
are permitted in any medium without royalty provided the copyright
|
||||
notice and this notice are preserved.
|
67
contrib/jit-coverage-report.py
Normal file
67
contrib/jit-coverage-report.py
Normal file
@ -0,0 +1,67 @@
|
||||
#! /usr/bin/python
|
||||
#
|
||||
# Print a report on which libgccjit.so symbols are used in which test
|
||||
# cases, and which lack test coverage. Tested with Python 2.7 and 3.2
|
||||
# To be run from the root directory of the source tree.
|
||||
#
|
||||
# Copyright (C) 2014 Free Software Foundation, Inc.
|
||||
# Written by David Malcolm <dmalcolm@redhat.com>.
|
||||
#
|
||||
# This script is Free Software, and it can be copied, distributed and
|
||||
# modified as defined in the GNU General Public License. A copy of
|
||||
# its license can be downloaded from http://www.gnu.org/copyleft/gpl.html
|
||||
|
||||
from collections import Counter
|
||||
import glob
|
||||
import re
|
||||
import sys
|
||||
|
||||
def parse_map_file(path):
|
||||
"""
|
||||
Parse libgccjit.map, returning the symbols in the API as a list of str.
|
||||
"""
|
||||
syms = []
|
||||
with open(path) as f:
|
||||
for line in f:
|
||||
m = re.match('^\s+([a-z_]+);$', line)
|
||||
if m:
|
||||
syms.append(m.group(1))
|
||||
return syms
|
||||
|
||||
def parse_test_case(path):
|
||||
"""
|
||||
Locate all symbol-like things in a C test case, yielding
|
||||
them as a sequence of str.
|
||||
"""
|
||||
with open(path) as f:
|
||||
for line in f:
|
||||
for m in re.finditer('([_A-Za-z][_A-Za-z0-9]*)', line):
|
||||
yield m.group(1)
|
||||
|
||||
def find_test_cases():
|
||||
for path in glob.glob('gcc/testsuite/jit.dg/*.[ch]'):
|
||||
yield path
|
||||
|
||||
api_syms = parse_map_file('gcc/jit/libgccjit.map')
|
||||
|
||||
syms_in_test_cases = {}
|
||||
for path in find_test_cases():
|
||||
syms_in_test_cases[path] = list(parse_test_case(path))
|
||||
|
||||
uses = Counter()
|
||||
for sym in sorted(api_syms):
|
||||
print('symbol: %s' % sym)
|
||||
uses[sym] = 0
|
||||
for path in syms_in_test_cases:
|
||||
count = syms_in_test_cases[path].count(sym)
|
||||
uses[sym] += count
|
||||
if count:
|
||||
print(' uses in %s: %i' % (path, count))
|
||||
if uses[sym] == 0:
|
||||
print(' NEVER USED')
|
||||
sys.stdout.write('\n')
|
||||
|
||||
layout = '%40s %5s %s'
|
||||
print(layout % ('SYMBOL', 'USES', 'HISTOGRAM'))
|
||||
for sym, count in uses.most_common():
|
||||
print(layout % (sym, count, '*' * count if count else 'UNUSED'))
|
@ -1,3 +1,28 @@
|
||||
2014-11-11 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* ChangeLog.jit: New.
|
||||
* Makefile.in (doc_build_sys): New variable, set to "sphinx" if
|
||||
sphinx is installed, falling back to "texinfo" otherwise.
|
||||
(FULL_DRIVER_NAME): New variable, adapted from the
|
||||
install-driver target. New target, a symlink within the builddir,
|
||||
linked to "xgcc", for use when running the JIT library from the
|
||||
builddir.
|
||||
(MOSTLYCLEANFILES): Add FULL_DRIVER_NAME.
|
||||
(install-driver): Use $(FULL_DRIVER_NAME) rather than spelling it
|
||||
out.
|
||||
* configure.ac (doc_build_sys): New variable, set to "sphinx" if
|
||||
sphinx is installed, falling back to "texinfo" otherwise.
|
||||
(GCC_DRIVER_NAME): Generate a gcc-driver-name.h file containing
|
||||
GCC_DRIVER_NAME for the benefit of jit/internal-api.c.
|
||||
* configure: Regenerate.
|
||||
* doc/install.texi (--enable-host-shared): Specify that this is
|
||||
required when building libgccjit.
|
||||
(Tools/packages necessary for modifying GCC): Add Sphinx.
|
||||
* timevar.def (TV_JIT_REPLAY): New.
|
||||
(TV_ASSEMBLE): New.
|
||||
(TV_LINK): New.
|
||||
(TV_LOAD): New.
|
||||
|
||||
2014-11-11 Francois-Xavier Coudert <fxcoudert@gcc.gnu.org>
|
||||
|
||||
PR target/63610
|
||||
|
360
gcc/ChangeLog.jit
Normal file
360
gcc/ChangeLog.jit
Normal file
@ -0,0 +1,360 @@
|
||||
2014-10-29 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* doc/install.texi (Tools/packages necessary for modifying GCC):
|
||||
Specify that Sphinx version 1.0 or later is required. Wrap .rst
|
||||
inside an @file command.
|
||||
|
||||
2014-10-22 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* cgraph.h: Drop now-redundant prototype of ipa_cp_c_finalize,
|
||||
since trunk added this in ipa-prop.h.
|
||||
* ipa-icf.c (ipa_icf_driver): Set optimizer to NULL when
|
||||
done.
|
||||
|
||||
2014-10-20 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* doc/install.texi (Tools/packages necessary for modifying GCC):
|
||||
Add Sphinx.
|
||||
|
||||
2014-10-20 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* Makefile.in (pkgconfigdir): Drop this.
|
||||
(installdirs): Likewise.
|
||||
* configure.ac (gcc_version): Don't AC_SUBST this.
|
||||
* configure: Regenerate.
|
||||
|
||||
2014-10-17 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* Makefile.in (FULL_DRIVER_NAME): New variable, adapted from the
|
||||
install-driver target. New target, a symlink within the builddir,
|
||||
linked to "xgcc", for use when running the JIT library from the
|
||||
builddir.
|
||||
(MOSTLYCLEANFILES): Add FULL_DRIVER_NAME.
|
||||
(install-driver): Use $(FULL_DRIVER_NAME) rather than spelling it
|
||||
out.
|
||||
(site.exp): Don't set "bindir", as this is no longer needed when
|
||||
running the jit testsuite.
|
||||
|
||||
2014-10-13 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* configure.ac: Update a reference to jit/internal-api.c to
|
||||
jit/jit-playback.c.
|
||||
* configure: Regenerate.
|
||||
|
||||
2014-10-07 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* Makefile.in (site.exp): When constructing site.exp, add a line
|
||||
to set "bindir".
|
||||
* configure.ac: Generate a gcc-driver-name.h file containing
|
||||
GCC_DRIVER_NAME for the benefit of jit/internal-api.c.
|
||||
* configure: Regenerate.
|
||||
|
||||
2014-10-03 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* diagnostic.c (diagnostic_finish): Free the memory for
|
||||
context->classify_diagnostic and context->printer, running the
|
||||
destructor for the latter.
|
||||
|
||||
2014-10-02 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* configure: Regenerate, after merger from trunk.
|
||||
|
||||
2014-10-02 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* configure.ac (doc_build_sys): New variable, set to "sphinx" if
|
||||
sphinx is installed, falling back to "texinfo" otherwise.
|
||||
* configure: Regenerate.
|
||||
* Makefile.in (doc_build_sys): New.
|
||||
|
||||
2014-09-24 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* ChangeLog.jit: Add copyright footer.
|
||||
|
||||
2014-09-24 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* cgraph.h (cgraphbuild_c_finalize): Delete prototype of empty
|
||||
function.
|
||||
(ipa_c_finalize): Likewise.
|
||||
(predict_c_finalize): Likewise.
|
||||
(symtab_c_finalize): Likewise.
|
||||
(varpool_c_finalize): Likewise.
|
||||
|
||||
* cgraph.c (cgraph_c_finalize): Add leading comment. Put return
|
||||
type on line before function name.
|
||||
* cgraphunit.c (cgraphunit_c_finalize): Likewise.
|
||||
* dwarf2out.c (dwarf2out_c_finalize): Likewise.
|
||||
* gcse.c (gcse_c_finalize): Likewise.
|
||||
* ipa-cp.c (ipa_cp_c_finalize): Likewise.
|
||||
* ipa-reference.c (ipa_reference_c_finalize): Likewise.
|
||||
|
||||
* params.c (params_c_finalize): Update leading comment to match
|
||||
format of the others mentioned above.
|
||||
|
||||
* cgraphbuild.c (cgraphbuild_c_finalize): Delete empty function.
|
||||
* ipa.c (ipa_c_finalize): Likewise.
|
||||
* predict.c (predict_c_finalize): Likewise.
|
||||
* symtab.c (symtab_c_finalize): Likewise.
|
||||
* varpool.c (varpool_c_finalize): Likewise.
|
||||
|
||||
* toplev.c (toplev::finalize): Remove calls to empty functions
|
||||
cgraphbuild_c_finalize, ipa_c_finalize, predict_c_finalize,
|
||||
symtab_c_finalize, varpool_c_finalize.
|
||||
|
||||
2014-09-23 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* passes.c (execute_ipa_summary_passes): Fix whitespace when
|
||||
assigning to current_pass.
|
||||
(ipa_write_summaries_2): Assign "pass" to "current_pass" global
|
||||
before calling write_summary hook.
|
||||
(ipa_write_optimization_summaries_1): Likewise when calling
|
||||
write_optimization_summary hook.
|
||||
(ipa_read_summaries_1): Likewise for read_summary hook.
|
||||
(ipa_read_optimization_summaries_1): Likewise for
|
||||
read_optimization_summary hook.
|
||||
(execute_ipa_stmt_fixups): Likewise for stmt_fixup hook.
|
||||
|
||||
2014-09-22 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* cgraph.c (cgraph_c_finalize): Remove FIXME.
|
||||
* timevar.c (timevar_init): Likewise.
|
||||
|
||||
2014-09-18 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* Makefile.in (pkgconfigdir): New.
|
||||
(installdirs): Add creation of $(DESTDIR)$(pkgconfigdir).
|
||||
* configure.ac (gcc_version): Expose this value for use via
|
||||
AC_SUBST, since we need it within the new file libgccjit.pc.in.
|
||||
* configure: Regenerate.
|
||||
|
||||
2014-09-10 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* cgraph.c (cgraph_c_finalize): Update to reflect the movement of
|
||||
many globals into fields of the "symtab" object.
|
||||
* cgraphunit.c (graphunit_c_finalize): Likewise.
|
||||
* symtab.c (symtab_c_finalize): Likewise.
|
||||
|
||||
* toplev.c (initialize_rtl): Move static local "initialized_once"
|
||||
into file scope, and rename to...
|
||||
(rtl_initialized): New variable.
|
||||
(toplev::finalize): Clear rtl_initialized and
|
||||
this_target_rtl->target_specific_initialized so that RTL will be
|
||||
reinitialized when the compiler is run more than once in-process.
|
||||
|
||||
2014-07-14 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* cgraph.h (ipa_cp_c_finalize): Add prototype.
|
||||
* ipa-cp.c (ipa_cp_c_finalize): New.
|
||||
* toplev.c (toplev::finalize): Add call to ipa_cp_c_finalize.
|
||||
|
||||
2014-05-08 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* params.c (global_init_params): Require that params_finished be
|
||||
false, rather than being idempotent, in favor of purging all state
|
||||
between toplev invocations, since in a release build
|
||||
init_ggc_heuristics calls set_param_value_internal, and the
|
||||
latter assumes that params_finished is true.
|
||||
(params_c_finalize): New.
|
||||
* params.h (params_c_finalize): New.
|
||||
* toplev.c (toplev::finalize): Call params_c_finalize.
|
||||
|
||||
2014-03-24 Tom Tromey <tromey@redhat.com>
|
||||
|
||||
* toplev.c (general_init): Initialize input_location.
|
||||
* input.c (input_location): Initialize to UNKNOWN_LOCATION.
|
||||
|
||||
2014-03-19 Tom Tromey <tromey@redhat.com>
|
||||
|
||||
* timevar.h (auto_timevar): New class.
|
||||
|
||||
2014-03-19 Tom Tromey <tromey@redhat.com>
|
||||
|
||||
* diagnostic.c (bt_stop): Use toplev::main.
|
||||
* main.c (main): Update.
|
||||
* toplev.c (do_compile): Remove argument. Don't check
|
||||
use_TV_TOTAL.
|
||||
(toplev::toplev, toplev::~toplev, toplev::start_timevars): New
|
||||
functions.
|
||||
(toplev::main): Rename from toplev_main. Update.
|
||||
(toplev::finalize): Rename from toplev_finalize. Update.
|
||||
* toplev.h (class toplev): New.
|
||||
(struct toplev_options): Remove.
|
||||
(toplev_main, toplev_finalize): Don't declare.
|
||||
|
||||
2014-03-11 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* gcse.c (gcse_c_finalize): New, to clear test_insn between
|
||||
in-process compiles.
|
||||
* gcse.h (gcse_c_finalize): New.
|
||||
* toplev.c: Include "gcse.h" so that we can...
|
||||
(toplev_finalize): Call gcse_c_finalize.
|
||||
|
||||
2014-03-11 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* dwarf2out.c (dwarf2out_c_finalize): Release base_types.
|
||||
|
||||
2014-03-10 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* ipa-reference.c (ipa_init): Move static bool init_p from here
|
||||
to...
|
||||
(ipa_init_p): New file-scope variable, so that it can be reset
|
||||
when repeatedly invoking the compiler within one process by...
|
||||
(ipa_reference_c_finalize): New function.
|
||||
* ipa-reference.h (ipa_reference_c_finalize): New.
|
||||
* toplev.c (toplev_finalize): Invoke new function
|
||||
ipa_reference_c_finalize.
|
||||
|
||||
2014-01-24 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* timevar.def: Replace TV_CLIENT_CALLBACK with TV_JIT_REPLAY.
|
||||
|
||||
2013-10-11 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* doc/install.texi (--enable-shared): Add note contrasting it
|
||||
with...
|
||||
(--enable-host-shared): New option.
|
||||
|
||||
2013-10-11 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* dumpfile.h (gcc::dump_manager): New class, to hold state
|
||||
relating to dumpfile management.
|
||||
(get_dump_file_name): Remove in favor of method of dump_manager.
|
||||
(dump_initialized_p): Likewise.
|
||||
(dump_start): Likewise.
|
||||
(dump_finish): Likewise.
|
||||
(dump_switch_p): Likewise.
|
||||
(dump_register): Likewise.
|
||||
(get_dump_file_info): Likewise.
|
||||
* context.c (gcc::context::context): Construct the dump_manager
|
||||
instance.
|
||||
* context.h (gcc::context::get_dumps): New.
|
||||
(gcc::context::m_dumps): New.
|
||||
* coverage.c (coverage_init): Port to dump_manager API.
|
||||
* dumpfile.c (extra_dump_files): Convert to field of
|
||||
gcc::dump_manager.
|
||||
(extra_dump_files_in_use): Likewise.
|
||||
(extra_dump_files_alloced): Likewise.
|
||||
(gcc::dump_manager::dump_manager): New.
|
||||
(dump_register): Convert to...
|
||||
(gcc::dump_manager::dump_register): ...method, replacing
|
||||
function-static next_dump with m_next_dump field.
|
||||
(get_dump_file_info): Convert to...
|
||||
(gcc::dump_manager::get_dump_file_info): ...method.
|
||||
(get_dump_file_name): Convert to...
|
||||
(gcc::dump_manager::get_dump_file_name): ...method.
|
||||
(dump_start): Convert to...
|
||||
(gcc::dump_manager::dump_start): ...method.
|
||||
(dump_finish): Convert to...
|
||||
(gcc::dump_manager::dump_finish): ...method.
|
||||
(dump_begin): Replace body with...
|
||||
(gcc::dump_manager::dump_begin): ...new method.
|
||||
(dump_phase_enabled_p): Convert to...
|
||||
(gcc::dump_manager::dump_phase_enabled_p): ...method.
|
||||
(dump_phase_enabled_p): Convert to...
|
||||
(gcc::dump_manager::dump_phase_enabled_p): ...method.
|
||||
(dump_initialized_p): Convert to...
|
||||
(gcc::dump_manager::dump_initialized_p): ...method.
|
||||
(dump_flag_name): Replace body with...
|
||||
(gcc::dump_manager::dump_flag_name): ...new method.
|
||||
(dump_enable_all): Convert to...
|
||||
(gcc::dump_manager::dump_enable_all): ...new method.
|
||||
(opt_info_enable_passes): Convert to...
|
||||
(gcc::dump_manager::opt_info_enable_passes): ...new method.
|
||||
(dump_switch_p_1): Convert to...
|
||||
(gcc::dump_manager::dump_switch_p_1): ...new method.
|
||||
(dump_switch_p): Convert to...
|
||||
(gcc::dump_manager::dump_switch_p): ...new method.
|
||||
(opt_info_switch_p): Port to dump_manager API.
|
||||
(enable_rtl_dump_file): Likewise.
|
||||
* opts-global.c (handle_common_deferred_options): Port to new
|
||||
dump_manager API.
|
||||
* passes.c (pass_manager::finish_optimization_passes): Likewise.
|
||||
(pass_manager::register_one_dump_file): Likewise.
|
||||
(pass_manager::register_pass): Likewise.
|
||||
(pass_init_dump_file): Likewise.
|
||||
(pass_fini_dump_file): Likewise.
|
||||
* statistics.c (statistics_early_init): Likewise.
|
||||
|
||||
2013-10-08 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* ipa-inline.c (ipa_inline): Fix leak of "order" when
|
||||
optimizations are disabled.
|
||||
|
||||
2013-10-08 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* coverage.c (coverage_finish): Fix leak of da_file_name.
|
||||
|
||||
2013-10-07 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* Makefile.in: Set PICFLAG from configure script; add it to
|
||||
INTERNAL_CFLAGS.
|
||||
* configure.ac (--enable-host-shared): Set up PICFLAG rather
|
||||
than attempting to append -fPIC to CFLAGS, CXXFLAGS, LDFLAGS.
|
||||
* configure: Regenerate.
|
||||
|
||||
2013-10-03 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* Makefile.in (LIBIBERTY): Use pic build of libiberty.a if
|
||||
configured with --enable-host-shared.
|
||||
(BUILD_LIBIBERTY): Likewise.
|
||||
* cgraph.c (cgraph_c_finalize): New.
|
||||
* cgraph.h (symtab_c_finalize): New declaration.
|
||||
(cgraph_c_finalize): Likewise.
|
||||
(cgraphunit_c_finalize): Likewise.
|
||||
(cgraphbuild_c_finalize): Likewise.
|
||||
(ipa_c_finalize): Likewise.
|
||||
(predict_c_finalize): Likewise.
|
||||
(varpool_c_finalize): Likewise.
|
||||
* cgraphbuild.c (cgraphbuild_c_finalize): New.
|
||||
* cgraphunit.c (first_analyzed): Move from analyze_functions
|
||||
to file-scope.
|
||||
(first_analyzed_var): Likewise.
|
||||
(analyze_functions): Move static variables into file-scope.
|
||||
(cgraphunit_c_finalize): New.
|
||||
* configure.ac: Add --enable-host-shared, adding -fPIC.
|
||||
* configure: Regenerate.
|
||||
* dwarf2out.c (dwarf2out_c_finalize): New.
|
||||
* dwarf2out.h (dwarf2out_c_finalize): Declare.
|
||||
* ggc-page.c (init_ggc): Make idempotent.
|
||||
* ipa-pure-const.c (function_insertion_hook_holder): Move to be
|
||||
a field of class pass_ipa_pure_const.
|
||||
(node_duplication_hook_holder): Likewise.
|
||||
(node_removal_hook_holder): Likewise.
|
||||
(register_hooks): Convert to method...
|
||||
(pass_ipa_pure_const::register_hooks): ...here, converting
|
||||
static variable init_p into...
|
||||
(pass_ipa_pure_const::init_p): ...new field.
|
||||
(pure_const_generate_summary): Update invocation of
|
||||
register_hooks to invoke as a method of current_pass.
|
||||
(pure_const_read_summary): Likewise.
|
||||
(propagate): Convert to...
|
||||
(pass_ipa_pure_const::execute): ...method.
|
||||
* ipa.c (ipa_c_finalize): New.
|
||||
* main.c (main): Update usage of toplev_main.
|
||||
* params.c (global_init_params): Make idempotent.
|
||||
* passes.c (execute_ipa_summary_passes): Set current_pass.
|
||||
* predict.c (predict_c_finalize): New.
|
||||
* stringpool.c (init_stringpool): Clean up if we're called more
|
||||
than once.
|
||||
* symtab.c (symtab_c_finalize): New.
|
||||
* timevar.c (timevar_init): Ignore repeated calls.
|
||||
* timevar.def (TV_CLIENT_CALLBACK): Add.
|
||||
(TV_ASSEMBLE): Add.
|
||||
(TV_LINK): Add.
|
||||
(TV_LOAD): Add.
|
||||
* toplev.c (do_compile) Add parameter (const toplev_options *);
|
||||
use it to avoid starting/stopping/reporting timevar TV_TOTAL
|
||||
for the case where toplev_main does not emcompass all timevars.
|
||||
(toplev_main): Add parameter (const toplev_options *); pass it
|
||||
to do_compile.
|
||||
(toplev_finalize): New.
|
||||
* toplev.h (struct toplev_options): New.
|
||||
(toplev_main): Add parameter (const toplev_options *).
|
||||
(toplev_finalize): New.
|
||||
* varpool.c (varpool_c_finalize): New.
|
||||
|
||||
|
||||
Copyright (C) 2013-2014 Free Software Foundation, Inc.
|
||||
|
||||
Copying and distribution of this file, with or without modification,
|
||||
are permitted in any medium without royalty provided the copyright
|
||||
notice and this notice are preserved.
|
@ -316,6 +316,11 @@ write_entries_to_file = $(shell rm -f $(2) || :) $(shell touch $(2)) \
|
||||
$(shell expr $(range) + $(write_entries_to_file_split) - 1), $(1))" \
|
||||
| tr ' ' '\012' >> $(2)))
|
||||
|
||||
# The jit documentation looks better if built with sphinx, but can be
|
||||
# built with texinfo if sphinx is not available.
|
||||
# configure sets "doc_build_sys" to "sphinx" or "texinfo" accordingly
|
||||
doc_build_sys=@doc_build_sys@
|
||||
|
||||
# --------
|
||||
# UNSORTED
|
||||
# --------
|
||||
@ -1508,6 +1513,9 @@ BACKEND = libbackend.a main.o @TREEBROWSER@ libcommon-target.a libcommon.a \
|
||||
# front-end checking.
|
||||
TREECHECKING = @TREECHECKING@
|
||||
|
||||
# The full name of the driver on installation
|
||||
FULL_DRIVER_NAME=$(target_noncanonical)-gcc-$(version)$(exeext)
|
||||
|
||||
MOSTLYCLEANFILES = insn-flags.h insn-config.h insn-codes.h \
|
||||
insn-output.c insn-recog.c insn-emit.c insn-extract.c insn-peep.c \
|
||||
insn-attr.h insn-attr-common.h insn-attrtab.c insn-dfatab.c \
|
||||
@ -1515,7 +1523,7 @@ MOSTLYCLEANFILES = insn-flags.h insn-config.h insn-codes.h \
|
||||
tm-preds.h tm-constrs.h checksum-options gimple-match.c generic-match.c \
|
||||
tree-check.h min-insn-modes.c insn-modes.c insn-modes.h \
|
||||
genrtl.h gt-*.h gtype-*.h gtype-desc.c gtyp-input.list \
|
||||
xgcc$(exeext) cpp$(exeext) \
|
||||
xgcc$(exeext) cpp$(exeext) $(FULL_DRIVER_NAME) \
|
||||
$(EXTRA_PROGRAMS) gcc-cross$(exeext) \
|
||||
$(SPECS) collect2$(exeext) gcc-ar$(exeext) gcc-nm$(exeext) \
|
||||
gcc-ranlib$(exeext) \
|
||||
@ -1524,6 +1532,12 @@ MOSTLYCLEANFILES = insn-flags.h insn-config.h insn-codes.h \
|
||||
gengtype$(exeext) *.[0-9][0-9].* *.[si] *-checksum.c libbackend.a \
|
||||
libcommon-target.a libcommon.a libgcc.mk
|
||||
|
||||
# This symlink makes the full installation name of the driver be available
|
||||
# from within the *build* directory, for use when running the JIT library
|
||||
# from there (e.g. when running its testsuite).
|
||||
$(FULL_DRIVER_NAME): ./xgcc
|
||||
$(LN) -s $< $@
|
||||
|
||||
#
|
||||
# Language makefile fragments.
|
||||
|
||||
@ -3287,9 +3301,9 @@ install-driver: installdirs xgcc$(exeext)
|
||||
-rm -f $(DESTDIR)$(bindir)/$(GCC_INSTALL_NAME)$(exeext)
|
||||
-$(INSTALL_PROGRAM) xgcc$(exeext) $(DESTDIR)$(bindir)/$(GCC_INSTALL_NAME)$(exeext)
|
||||
-if [ "$(GCC_INSTALL_NAME)" != "$(target_noncanonical)-gcc-$(version)" ]; then \
|
||||
rm -f $(DESTDIR)$(bindir)/$(target_noncanonical)-gcc-$(version)$(exeext); \
|
||||
rm -f $(DESTDIR)$(bindir)/$(FULL_DRIVER_NAME); \
|
||||
( cd $(DESTDIR)$(bindir) && \
|
||||
$(LN) $(GCC_INSTALL_NAME)$(exeext) $(target_noncanonical)-gcc-$(version)$(exeext) ); \
|
||||
$(LN) $(GCC_INSTALL_NAME)$(exeext) $(FULL_DRIVER_NAME) ); \
|
||||
fi
|
||||
-if [ ! -f gcc-cross$(exeext) ] \
|
||||
&& [ "$(GCC_INSTALL_NAME)" != "$(GCC_TARGET_INSTALL_NAME)" ]; then \
|
||||
|
52
gcc/configure
vendored
52
gcc/configure
vendored
@ -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
|
||||
|
14
gcc/java/ChangeLog.jit
Normal file
14
gcc/java/ChangeLog.jit
Normal file
@ -0,0 +1,14 @@
|
||||
2014-09-24 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* ChangeLog.jit: Add copyright footer.
|
||||
|
||||
2013-10-11 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* lang.c (java_handle_option): Update for introduction of
|
||||
gcc::dump_manager.
|
||||
|
||||
Copyright (C) 2013-2014 Free Software Foundation, Inc.
|
||||
|
||||
Copying and distribution of this file, with or without modification,
|
||||
are permitted in any medium without royalty provided the copyright
|
||||
notice and this notice are preserved.
|
60
gcc/jit/ChangeLog
Normal file
60
gcc/jit/ChangeLog
Normal file
@ -0,0 +1,60 @@
|
||||
2014-11-11 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* ChangeLog.jit: New.
|
||||
* ChangeLog: New.
|
||||
* Make-lang.in: New.
|
||||
* TODO.rst: New.
|
||||
* config-lang.in: New.
|
||||
* docs/Makefile: New.
|
||||
* docs/_build/texinfo/Makefile: New.
|
||||
* docs/_build/texinfo/factorial.png: New.
|
||||
* docs/_build/texinfo/libgccjit.texi: New.
|
||||
* docs/_build/texinfo/sum-of-squares.png: New.
|
||||
* docs/conf.py: New.
|
||||
* docs/examples/tut01-hello-world.c: New.
|
||||
* docs/examples/tut02-square.c: New.
|
||||
* docs/examples/tut03-sum-of-squares.c: New.
|
||||
* docs/examples/tut04-toyvm/Makefile: New.
|
||||
* docs/examples/tut04-toyvm/factorial.toy: New.
|
||||
* docs/examples/tut04-toyvm/fibonacci.toy: New.
|
||||
* docs/examples/tut04-toyvm/toyvm.c: New.
|
||||
* docs/index.rst: New.
|
||||
* docs/internals/index.rst: New.
|
||||
* docs/intro/factorial.png: New.
|
||||
* docs/intro/index.rst: New.
|
||||
* docs/intro/sum-of-squares.png: New.
|
||||
* docs/intro/tutorial01.rst: New.
|
||||
* docs/intro/tutorial02.rst: New.
|
||||
* docs/intro/tutorial03.rst: New.
|
||||
* docs/intro/tutorial04.rst: New.
|
||||
* docs/topics/contexts.rst: New.
|
||||
* docs/topics/expressions.rst: New.
|
||||
* docs/topics/functions.rst: New.
|
||||
* docs/topics/index.rst: New.
|
||||
* docs/topics/locations.rst: New.
|
||||
* docs/topics/objects.rst: New.
|
||||
* docs/topics/results.rst: New.
|
||||
* docs/topics/types.rst: New.
|
||||
* dummy-frontend.c: New.
|
||||
* jit-builtins.c: New.
|
||||
* jit-builtins.h: New.
|
||||
* jit-common.h: New.
|
||||
* jit-playback.c: New.
|
||||
* jit-playback.h: New.
|
||||
* jit-recording.c: New.
|
||||
* jit-recording.h: New.
|
||||
* libgccjit++.h: New.
|
||||
* libgccjit.c: New.
|
||||
* libgccjit.h: New.
|
||||
* libgccjit.map: New.
|
||||
* notes.txt: New.
|
||||
|
||||
2013-07-26 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* Initial creation
|
||||
|
||||
Copyright (C) 2013-2014 Free Software Foundation, Inc.
|
||||
|
||||
Copying and distribution of this file, with or without modification,
|
||||
are permitted in any medium without royalty provided the copyright
|
||||
notice and this notice are preserved.
|
3498
gcc/jit/ChangeLog.jit
Normal file
3498
gcc/jit/ChangeLog.jit
Normal file
File diff suppressed because it is too large
Load Diff
298
gcc/jit/Make-lang.in
Normal file
298
gcc/jit/Make-lang.in
Normal file
@ -0,0 +1,298 @@
|
||||
# Top level -*- makefile -*- fragment for libgccjit.so.
|
||||
# Copyright (C) 2013-2014 Free Software Foundation, Inc.
|
||||
|
||||
#This file is part of GCC.
|
||||
|
||||
#GCC is free software; you can redistribute it and/or modify
|
||||
#it under the terms of the GNU General Public License as published by
|
||||
#the Free Software Foundation; either version 3, or (at your option)
|
||||
#any later version.
|
||||
|
||||
#GCC is distributed in the hope that it will be useful,
|
||||
#but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
#GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with GCC; see the file COPYING3. If not see
|
||||
# <http://www.gnu.org/licenses/>.
|
||||
|
||||
# This file provides the language dependent support in the main Makefile.
|
||||
# Each language makefile fragment must provide the following targets:
|
||||
#
|
||||
# foo.all.cross, foo.start.encap, foo.rest.encap,
|
||||
# foo.install-common, foo.install-man, foo.install-info, foo.install-pdf,
|
||||
# foo.install-html, foo.info, foo.dvi, foo.pdf, foo.html, foo.uninstall,
|
||||
# foo.mostlyclean, foo.clean, foo.distclean,
|
||||
# foo.maintainer-clean, foo.stage1, foo.stage2, foo.stage3, foo.stage4
|
||||
#
|
||||
# where `foo' is the name of the language.
|
||||
#
|
||||
# It should also provide rules for:
|
||||
#
|
||||
# - making any compiler driver (eg: g++)
|
||||
# - the compiler proper (eg: cc1plus)
|
||||
# - define the names for selecting the language in LANGUAGES.
|
||||
|
||||
#
|
||||
# Define the names for selecting jit in LANGUAGES.
|
||||
# Note that it would be nice to move the dependency on g++
|
||||
# into the jit rule, but that needs a little bit of work
|
||||
# to do the right thing within all.cross.
|
||||
|
||||
LIBGCCJIT_LINKER_NAME = libgccjit.so
|
||||
LIBGCCJIT_VERSION_NUM = 0
|
||||
LIBGCCJIT_MINOR_NUM = 0
|
||||
LIBGCCJIT_RELEASE_NUM = 1
|
||||
LIBGCCJIT_SONAME = $(LIBGCCJIT_LINKER_NAME).$(LIBGCCJIT_VERSION_NUM)
|
||||
LIBGCCJIT_FILENAME = \
|
||||
$(LIBGCCJIT_SONAME).$(LIBGCCJIT_MINOR_NUM).$(LIBGCCJIT_RELEASE_NUM)
|
||||
|
||||
LIBGCCJIT_LINKER_NAME_SYMLINK = $(LIBGCCJIT_LINKER_NAME)
|
||||
LIBGCCJIT_SONAME_SYMLINK = $(LIBGCCJIT_SONAME)
|
||||
|
||||
jit: $(LIBGCCJIT_FILENAME) \
|
||||
$(LIBGCCJIT_SYMLINK) \
|
||||
$(LIBGCCJIT_LINKER_NAME_SYMLINK) \
|
||||
$(FULL_DRIVER_NAME)
|
||||
|
||||
# Tell GNU make to ignore these if they exist.
|
||||
.PHONY: jit
|
||||
|
||||
jit_OBJS = attribs.o \
|
||||
jit/dummy-frontend.o \
|
||||
jit/libgccjit.o \
|
||||
jit/jit-recording.o \
|
||||
jit/jit-playback.o \
|
||||
jit/jit-builtins.o
|
||||
|
||||
# Use strict warnings for this front end.
|
||||
jit-warn = $(STRICT_WARN)
|
||||
|
||||
# We avoid using $(BACKEND) from Makefile.in in order to avoid pulling
|
||||
# in main.o
|
||||
$(LIBGCCJIT_FILENAME): $(jit_OBJS) \
|
||||
libbackend.a libcommon-target.a libcommon.a \
|
||||
$(CPPLIB) $(LIBDECNUMBER) \
|
||||
$(LIBDEPS) $(srcdir)/jit/libgccjit.map
|
||||
+$(LLINKER) $(ALL_LINKERFLAGS) $(LDFLAGS) -o $@ -shared \
|
||||
$(jit_OBJS) libbackend.a libcommon-target.a libcommon.a \
|
||||
$(CPPLIB) $(LIBDECNUMBER) $(LIBS) $(BACKENDLIBS) \
|
||||
-Wl,--version-script=$(srcdir)/jit/libgccjit.map \
|
||||
-Wl,-soname,$(LIBGCCJIT_SONAME)
|
||||
|
||||
$(LIBGCCJIT_SONAME_SYMLINK): $(LIBGCCJIT_FILENAME)
|
||||
ln -sf $(LIBGCCJIT_FILENAME) $(LIBGCCJIT_SONAME_SYMLINK)
|
||||
|
||||
$(LIBGCCJIT_LINKER_NAME_SYMLINK): $(LIBGCCJIT_SONAME_SYMLINK)
|
||||
ln -sf $(LIBGCCJIT_SONAME_SYMLINK) $(LIBGCCJIT_LINKER_NAME_SYMLINK)
|
||||
|
||||
#
|
||||
# Build hooks:
|
||||
|
||||
jit.all.cross:
|
||||
jit.start.encap:
|
||||
jit.rest.encap:
|
||||
|
||||
# Documentation build hooks.
|
||||
#
|
||||
# The documentation can be built using the texinfo toolchain, or
|
||||
# the sphinx toolchain
|
||||
#
|
||||
# The jit documentation is authored using Sphinx, which has numerous
|
||||
# advantages over Texinfo, including:
|
||||
#
|
||||
# * much faster
|
||||
#
|
||||
# * use of CSS and JS to provide less of a 1990s feel in the generated
|
||||
# HTML.
|
||||
#
|
||||
# * sane, stable HTML page and anchor names
|
||||
#
|
||||
# * sane HTML navigation: ability to move forward and back in the HTML
|
||||
# at every node to read the HTML like a book
|
||||
#
|
||||
# * syntax-coloring of examples
|
||||
#
|
||||
# * the ability to "include" fragments of code inline. This is used
|
||||
# heavily by the jit docs, so that the example code is shared by both
|
||||
# the test suite and the documentation to ensure that the examples
|
||||
# appearing in the docs actually compile and work
|
||||
#
|
||||
# Sphinx is not a "blessed" dependency, and so a prebuilt libgccjit.texinfo
|
||||
# file built by Sphinx is checked into the source tree to avoid requiring
|
||||
# everyone to have Sphinx installed.
|
||||
#
|
||||
# This prebuilt libgccjit.texinfo has the "include" fragments "baked in",
|
||||
# and so contains the content from the sphinx toolchain, but lacks the
|
||||
# syntax-coloring, and the generated HTML is (IMHO) greatly inferior to
|
||||
# that generated by Sphinx.
|
||||
|
||||
# These targets redirect HTML creation and installation to either
|
||||
# jit.sphinx.(install-)html or jit.texinfo.(install-)html.
|
||||
jit.html: jit.$(doc_build_sys).html
|
||||
jit.install-html: jit.$(doc_build_sys).install-html
|
||||
|
||||
# For now, use texinfo for pdf, since the sphinx latex toolchain currently
|
||||
# fails for me deep inside pdflatex (see notes below)
|
||||
jit.pdf: jit.texinfo.pdf
|
||||
jit.install-pdf: jit.texinfo.install-pdf
|
||||
|
||||
# Hooks for building docs using texinfo
|
||||
JIT_TEXI_FILES = $(srcdir)/jit/docs/_build/texinfo/libgccjit.texi
|
||||
|
||||
jit.info: doc/libgccjit.info
|
||||
doc/libgccjit.info: $(JIT_TEXI_FILES)
|
||||
if test "x$(BUILD_INFO)" = xinfo; then \
|
||||
rm -f doc/libgccjit.info*; \
|
||||
$(MAKEINFO) $(MAKEINFOFLAGS) -I $(gcc_docdir) \
|
||||
-I $(gcc_docdir)/include -o $@ $<; \
|
||||
else true; fi
|
||||
|
||||
jit.install-info: $(DESTDIR)$(infodir)/libgccjit.info
|
||||
|
||||
jit.dvi: doc/libgccjit.dvi
|
||||
doc/libgccjit.dvi: $(JIT_TEXI_FILES)
|
||||
$(TEXI2DVI) -I $(abs_docdir) -I $(abs_docdir)/include -o $@ $<
|
||||
|
||||
jit.texinfo.html: $(build_htmldir)/jit/index.html
|
||||
|
||||
$(build_htmldir)/jit/index.html: $(srcdir)/jit/docs/_build/texinfo/libgccjit.texi
|
||||
$(mkinstalldirs) $(@D)
|
||||
rm -f $(@D)/*
|
||||
$(TEXI2HTML) -I $(gcc_docdir)/include -I $(srcdir)/jit -o $(@D) $<
|
||||
|
||||
jit.texinfo.install-html: jit.texinfo.html
|
||||
@$(NORMAL_INSTALL)
|
||||
test -z "$(htmldir)" || $(mkinstalldirs) "$(DESTDIR)$(htmldir)"
|
||||
@for p in $(build_htmldir)/jit; do \
|
||||
if test -f "$$p" || test -d "$$p"; then d=""; else d="$(srcdir)/"; fi; \
|
||||
f=$(html__strip_dir) \
|
||||
if test -d "$$d$$p"; then \
|
||||
echo " $(mkinstalldirs) '$(DESTDIR)$(htmldir)/$$f'"; \
|
||||
$(mkinstalldirs) "$(DESTDIR)$(htmldir)/$$f" || exit 1; \
|
||||
echo " $(INSTALL_DATA) '$$d$$p'/* '$(DESTDIR)$(htmldir)/$$f'"; \
|
||||
$(INSTALL_DATA) "$$d$$p"/* "$(DESTDIR)$(htmldir)/$$f"; \
|
||||
else \
|
||||
echo " $(INSTALL_DATA) '$$d$$p' '$(DESTDIR)$(htmldir)/$$f'"; \
|
||||
$(INSTALL_DATA) "$$d$$p" "$(DESTDIR)$(htmldir)/$$f"; \
|
||||
fi; \
|
||||
done
|
||||
|
||||
jit.texinfo.pdf: doc/libgccjit.pdf
|
||||
|
||||
doc/libgccjit.pdf: $(JIT_TEXI_FILES)
|
||||
$(TEXI2PDF) -I $(abs_docdir) -I $(abs_docdir)/include -o $@ $<
|
||||
|
||||
jit.texinfo.install-pdf: doc/libgccjit.pdf
|
||||
@$(NORMAL_INSTALL)
|
||||
test -z "$(pdfdir)" || $(mkinstalldirs) "$(DESTDIR)$(pdfdir)/gcc"
|
||||
@for p in doc/libgccjit.pdf; do \
|
||||
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
|
||||
f=$(pdf__strip_dir) \
|
||||
echo " $(INSTALL_DATA) '$$d$$p' '$(DESTDIR)$(pdfdir)/gcc/$$f'"; \
|
||||
$(INSTALL_DATA) "$$d$$p" "$(DESTDIR)$(pdfdir)/gcc/$$f"; \
|
||||
done
|
||||
|
||||
# Hooks for building docs using the Sphinx toolchain:
|
||||
|
||||
SPHINX_BUILD_DIR=jit/sphinx-build
|
||||
|
||||
jit.sphinx.html:
|
||||
mkdir -p $(SPHINX_BUILD_DIR)
|
||||
(cd $(srcdir)/jit/docs && \
|
||||
make html BUILDDIR=$(PWD)/$(SPHINX_BUILD_DIR) )
|
||||
|
||||
jit_htmldir=$(htmldir)/jit
|
||||
|
||||
jit.sphinx.install-html: jit.sphinx.html
|
||||
@$(NORMAL_INSTALL)
|
||||
test -z "$(jit_htmldir)" || $(mkinstalldirs) "$(DESTDIR)$(jit_htmldir)"
|
||||
@for f in $(shell cd $(SPHINX_BUILD_DIR)/html && find) ; do \
|
||||
if test -f $(SPHINX_BUILD_DIR)/html/"$$f"; then \
|
||||
$(INSTALL_DATA) $(SPHINX_BUILD_DIR)/html/"$$f" $(DESTDIR)$(jit_htmldir)/"$$f"; \
|
||||
else \
|
||||
mkdir $(DESTDIR)$(jit_htmldir)/"$$f"; \
|
||||
fi; \
|
||||
done
|
||||
|
||||
# (This one is currently failing deep inside pdflatex for me;
|
||||
# see https://bugzilla.redhat.com/show_bug.cgi?id=1148845 )
|
||||
jit.sphinx.pdf: $(SPHINX_BUILD_DIR)/latex/libgccjit.pdf
|
||||
$(SPHINX_BUILD_DIR)/latex/libgccjit.pdf:
|
||||
mkdir -p $(SPHINX_BUILD_DIR)
|
||||
(cd $(srcdir)/jit/docs && \
|
||||
make latexpdf BUILDDIR=$(PWD)/$(SPHINX_BUILD_DIR) )
|
||||
|
||||
jit.sphinx.install-pdf: $(SPHINX_BUILD_DIR)/latex/libgccjit.pdf
|
||||
@$(NORMAL_INSTALL)
|
||||
test -z "$(pdfdir)" || $(mkinstalldirs) "$(DESTDIR)$(pdfdir)/gcc"
|
||||
@for p in $(SPHINX_BUILD_DIR)/latex/libgccjit.pdf; do \
|
||||
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
|
||||
f=$(pdf__strip_dir) \
|
||||
echo " $(INSTALL_DATA) '$$d$$p' '$(DESTDIR)$(pdfdir)/gcc/$$f'"; \
|
||||
$(INSTALL_DATA) "$$d$$p" "$(DESTDIR)$(pdfdir)/gcc/$$f"; \
|
||||
done
|
||||
|
||||
jit.srcinfo:
|
||||
jit.srcextra:
|
||||
|
||||
jit.tags:
|
||||
|
||||
jit.man:
|
||||
|
||||
jit.srcman:
|
||||
|
||||
lang_checks += check-jit
|
||||
|
||||
#
|
||||
# Install hooks:
|
||||
jit.install-common: installdirs
|
||||
$(INSTALL_PROGRAM) $(LIBGCCJIT_FILENAME) \
|
||||
$(DESTDIR)/$(libdir)/$(LIBGCCJIT_FILENAME)
|
||||
ln -sf \
|
||||
$(LIBGCCJIT_FILENAME) \
|
||||
$(DESTDIR)/$(libdir)/$(LIBGCCJIT_SONAME_SYMLINK)
|
||||
ln -sf \
|
||||
$(LIBGCCJIT_SONAME_SYMLINK)\
|
||||
$(DESTDIR)/$(libdir)/$(LIBGCCJIT_LINKER_NAME_SYMLINK)
|
||||
$(INSTALL_PROGRAM) $(srcdir)/jit/libgccjit.h \
|
||||
$(DESTDIR)/$(includedir)/libgccjit.h
|
||||
$(INSTALL_PROGRAM) $(srcdir)/jit/libgccjit++.h \
|
||||
$(DESTDIR)/$(includedir)/libgccjit++.h
|
||||
|
||||
jit.install-man:
|
||||
|
||||
jit.install-plugin:
|
||||
|
||||
jit.uninstall:
|
||||
|
||||
#
|
||||
# Clean hooks:
|
||||
# A lot of the ancillary files are deleted by the main makefile.
|
||||
# We just have to delete files specific to us.
|
||||
|
||||
jit.mostlyclean:
|
||||
|
||||
jit.clean:
|
||||
|
||||
jit.distclean:
|
||||
|
||||
jit.maintainer-clean:
|
||||
|
||||
#
|
||||
# Stage hooks:
|
||||
# The main makefile has already created stage?/jit.
|
||||
|
||||
jit.stage1: stage1-start
|
||||
-mv jit/*$(objext) stage1/jit
|
||||
jit.stage2: stage2-start
|
||||
-mv jit/*$(objext) stage2/jit
|
||||
jit.stage3: stage3-start
|
||||
-mv jit/*$(objext) stage3/jit
|
||||
jit.stage4: stage4-start
|
||||
-mv jit/*$(objext) stage4/jit
|
||||
jit.stageprofile: stageprofile-start
|
||||
-mv jit/*$(objext) stageprofile/jit
|
||||
jit.stagefeedback: stagefeedback-start
|
||||
-mv jit/*$(objext) stagefeedback/jit
|
119
gcc/jit/TODO.rst
Normal file
119
gcc/jit/TODO.rst
Normal file
@ -0,0 +1,119 @@
|
||||
TODOs
|
||||
-----
|
||||
|
||||
API
|
||||
===
|
||||
* error-handling:
|
||||
* have a client-provided error-handling callback for the context, and
|
||||
call it, rather than asserting/crashing etc, to make the API resilient and helpful
|
||||
|
||||
* probably should turn off signal handlers and backtracing, leaving that to
|
||||
the client code
|
||||
|
||||
* enums and ABI: give enums specific numbers, in ranges, to make it
|
||||
possible to maintain a logical ordering whilst preserving ABI.
|
||||
|
||||
* expose the statements in the API? (mostly so they can be stringified?)
|
||||
|
||||
* support more arithmetic ops and comparison modes
|
||||
|
||||
* access to a function by address::
|
||||
|
||||
extern gcc_jit_function *
|
||||
gcc_jit_context_get_function (ctxt,
|
||||
void *); /* need type information */
|
||||
|
||||
so you can access "static" fns in your code.
|
||||
|
||||
* ability to turn a function into a function pointer::
|
||||
|
||||
gcc_jit_function_as_rvalue ()
|
||||
|
||||
* expressing branch probabilies (like __builtin_expect)::
|
||||
|
||||
extern gcc_jit_rvalue *
|
||||
gcc_jit_rvalue_likely (gcc_jit_rvalue *rvalue,
|
||||
int is_likely);
|
||||
|
||||
though would:
|
||||
|
||||
extern void
|
||||
gcc_jit_block_set_likelihood (gcc_jit_block *block,
|
||||
int hotness);
|
||||
|
||||
be better? (for expressing how hot the current location is)
|
||||
|
||||
* add a SONAME to the library (and potentially version the symbols?)
|
||||
|
||||
* do we need alternative forms of division (floor vs rounding)?
|
||||
|
||||
* are we missing any ops?
|
||||
|
||||
* error-checking:
|
||||
|
||||
* gcc_jit_context_new_unary_op: various checks needed
|
||||
|
||||
* gcc_jit_context_new_binary_op: various checks needed
|
||||
|
||||
* gcc_jit_context_new_comparison: must be numeric or pointer types
|
||||
|
||||
* gcc_jit_context_new_array_access: "index" must be of numeric type.
|
||||
|
||||
* gcc_jit_lvalue_access_field: must be field of correct struct
|
||||
|
||||
* gcc_jit_rvalue_access_field: must be field of correct struct
|
||||
|
||||
* gcc_jit_block_add_assignment_op: check the types
|
||||
|
||||
* Implement more kinds of casts e.g. pointers
|
||||
|
||||
Bugs
|
||||
====
|
||||
* fixing all the state issues: make it work repeatedly with optimization
|
||||
turned up to full.
|
||||
|
||||
* make the dirty dirty hacks less egregious...
|
||||
|
||||
* test under valgrind; fix memory leaks
|
||||
|
||||
* re-architect gcc so we don't have to reinitialize everything every time
|
||||
a context is compiled
|
||||
|
||||
Test suite
|
||||
==========
|
||||
* get DejaGnu to build and run C++ testcases
|
||||
|
||||
* measure code coverage in testing of libgccjit.so
|
||||
|
||||
Future milestones
|
||||
=================
|
||||
* try porting llvmpipe to gcc
|
||||
|
||||
* inline assembler?
|
||||
|
||||
* Detect and issue warnings/errors about uses of uninitialized variables
|
||||
|
||||
* Warn about unused objects in a context (e.g. rvalues/lvalues)? (e.g.
|
||||
for gcc_jit_context_new_call vs gcc_jit_block_add_eval)
|
||||
|
||||
Nice to have
|
||||
============
|
||||
* Currently each function has a single stmt_list, which is built in
|
||||
postprocessing by walking the list of blocks. Presumably we could
|
||||
have each block have its own stmt_list, avoiding the need for this
|
||||
traversal, and having the block structure show up within tree dumps.
|
||||
Alternatively, could we skip tree and go straight to gimple?
|
||||
|
||||
* ability to give contexts names, for ease of debugging?
|
||||
|
||||
|
||||
Probably not needed
|
||||
===================
|
||||
* "switch" and "case" ?
|
||||
|
||||
* sizeof (should this be an API hook?) do we even need it? presumably
|
||||
client code can just do the sizeof() in its own code.
|
||||
|
||||
* do we need unary plus?
|
||||
|
||||
etc etc
|
38
gcc/jit/config-lang.in
Normal file
38
gcc/jit/config-lang.in
Normal file
@ -0,0 +1,38 @@
|
||||
# Top level configure fragment for libgccjit.so.
|
||||
# Copyright (C) 2013-2014 Free Software Foundation, Inc.
|
||||
|
||||
#This file is part of GCC.
|
||||
|
||||
#GCC is free software; you can redistribute it and/or modify
|
||||
#it under the terms of the GNU General Public License as published by
|
||||
#the Free Software Foundation; either version 3, or (at your option)
|
||||
#any later version.
|
||||
|
||||
#GCC is distributed in the hope that it will be useful,
|
||||
#but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
#GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with GCC; see the file COPYING3. If not see
|
||||
# <http://www.gnu.org/licenses/>.
|
||||
|
||||
# Configure looks for the existence of this file to auto-config each language.
|
||||
# We define several parameters used by configure:
|
||||
#
|
||||
# language - name of language as it would appear in $(LANGUAGES)
|
||||
# compilers - value to add to $(COMPILERS)
|
||||
|
||||
language="jit"
|
||||
|
||||
compilers="libgccjit.so"
|
||||
|
||||
target_libs=""
|
||||
|
||||
gtfiles="\$(srcdir)/jit/dummy-frontend.c"
|
||||
|
||||
# The configuration requires --enable-host-shared
|
||||
# for jit to be supported.
|
||||
# Hence to get the jit, one must configure with:
|
||||
# --enable-host-shared --enable-languages=jit
|
||||
build_by_default="no"
|
153
gcc/jit/docs/Makefile
Normal file
153
gcc/jit/docs/Makefile
Normal file
@ -0,0 +1,153 @@
|
||||
# Makefile for Sphinx documentation
|
||||
#
|
||||
|
||||
# You can set these variables from the command line.
|
||||
SPHINXOPTS =
|
||||
SPHINXBUILD = sphinx-build
|
||||
PAPER =
|
||||
BUILDDIR = _build
|
||||
|
||||
# Internal variables.
|
||||
PAPEROPT_a4 = -D latex_paper_size=a4
|
||||
PAPEROPT_letter = -D latex_paper_size=letter
|
||||
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
|
||||
# the i18n builder cannot share the environment and doctrees with the others
|
||||
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
|
||||
|
||||
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
|
||||
|
||||
help:
|
||||
@echo "Please use \`make <target>' where <target> is one of"
|
||||
@echo " html to make standalone HTML files"
|
||||
@echo " dirhtml to make HTML files named index.html in directories"
|
||||
@echo " singlehtml to make a single large HTML file"
|
||||
@echo " pickle to make pickle files"
|
||||
@echo " json to make JSON files"
|
||||
@echo " htmlhelp to make HTML files and a HTML help project"
|
||||
@echo " qthelp to make HTML files and a qthelp project"
|
||||
@echo " devhelp to make HTML files and a Devhelp project"
|
||||
@echo " epub to make an epub"
|
||||
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
|
||||
@echo " latexpdf to make LaTeX files and run them through pdflatex"
|
||||
@echo " text to make text files"
|
||||
@echo " man to make manual pages"
|
||||
@echo " texinfo to make Texinfo files"
|
||||
@echo " info to make Texinfo files and run them through makeinfo"
|
||||
@echo " gettext to make PO message catalogs"
|
||||
@echo " changes to make an overview of all changed/added/deprecated items"
|
||||
@echo " linkcheck to check all external links for integrity"
|
||||
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
|
||||
|
||||
clean:
|
||||
-rm -rf $(BUILDDIR)/*
|
||||
|
||||
html:
|
||||
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
|
||||
@echo
|
||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
|
||||
|
||||
dirhtml:
|
||||
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
|
||||
@echo
|
||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
|
||||
|
||||
singlehtml:
|
||||
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
|
||||
@echo
|
||||
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
|
||||
|
||||
pickle:
|
||||
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
|
||||
@echo
|
||||
@echo "Build finished; now you can process the pickle files."
|
||||
|
||||
json:
|
||||
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
|
||||
@echo
|
||||
@echo "Build finished; now you can process the JSON files."
|
||||
|
||||
htmlhelp:
|
||||
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
|
||||
@echo
|
||||
@echo "Build finished; now you can run HTML Help Workshop with the" \
|
||||
".hhp project file in $(BUILDDIR)/htmlhelp."
|
||||
|
||||
qthelp:
|
||||
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
|
||||
@echo
|
||||
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
|
||||
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
|
||||
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/libgccjit.qhcp"
|
||||
@echo "To view the help file:"
|
||||
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/libgccjit.qhc"
|
||||
|
||||
devhelp:
|
||||
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
|
||||
@echo
|
||||
@echo "Build finished."
|
||||
@echo "To view the help file:"
|
||||
@echo "# mkdir -p $$HOME/.local/share/devhelp/libgccjit"
|
||||
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/libgccjit"
|
||||
@echo "# devhelp"
|
||||
|
||||
epub:
|
||||
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
|
||||
@echo
|
||||
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
|
||||
|
||||
latex:
|
||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||
@echo
|
||||
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
|
||||
@echo "Run \`make' in that directory to run these through (pdf)latex" \
|
||||
"(use \`make latexpdf' here to do that automatically)."
|
||||
|
||||
latexpdf:
|
||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||
@echo "Running LaTeX files through pdflatex..."
|
||||
$(MAKE) -C $(BUILDDIR)/latex all-pdf
|
||||
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
|
||||
|
||||
text:
|
||||
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
|
||||
@echo
|
||||
@echo "Build finished. The text files are in $(BUILDDIR)/text."
|
||||
|
||||
man:
|
||||
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
|
||||
@echo
|
||||
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
|
||||
|
||||
texinfo:
|
||||
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
|
||||
@echo
|
||||
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
|
||||
@echo "Run \`make' in that directory to run these through makeinfo" \
|
||||
"(use \`make info' here to do that automatically)."
|
||||
|
||||
info:
|
||||
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
|
||||
@echo "Running Texinfo files through makeinfo..."
|
||||
make -C $(BUILDDIR)/texinfo info
|
||||
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
|
||||
|
||||
gettext:
|
||||
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
|
||||
@echo
|
||||
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
|
||||
|
||||
changes:
|
||||
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
|
||||
@echo
|
||||
@echo "The overview file is in $(BUILDDIR)/changes."
|
||||
|
||||
linkcheck:
|
||||
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
|
||||
@echo
|
||||
@echo "Link check complete; look for any errors in the above output " \
|
||||
"or in $(BUILDDIR)/linkcheck/output.txt."
|
||||
|
||||
doctest:
|
||||
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
|
||||
@echo "Testing of doctests in the sources finished, look at the " \
|
||||
"results in $(BUILDDIR)/doctest/output.txt."
|
50
gcc/jit/docs/_build/texinfo/Makefile
vendored
Normal file
50
gcc/jit/docs/_build/texinfo/Makefile
vendored
Normal file
@ -0,0 +1,50 @@
|
||||
# Makefile for Sphinx Texinfo output
|
||||
|
||||
infodir ?= /usr/share/info
|
||||
|
||||
MAKEINFO = makeinfo --no-split
|
||||
MAKEINFO_html = makeinfo --no-split --html
|
||||
MAKEINFO_plaintext = makeinfo --no-split --plaintext
|
||||
TEXI2PDF = texi2pdf --batch --expand
|
||||
INSTALL_INFO = install-info
|
||||
|
||||
ALLDOCS = $(basename $(wildcard *.texi))
|
||||
|
||||
all: info
|
||||
info: $(addsuffix .info,$(ALLDOCS))
|
||||
plaintext: $(addsuffix .txt,$(ALLDOCS))
|
||||
html: $(addsuffix .html,$(ALLDOCS))
|
||||
pdf: $(addsuffix .pdf,$(ALLDOCS))
|
||||
|
||||
install-info: info
|
||||
for f in *.info; do \
|
||||
cp -t $(infodir) "$$f" && \
|
||||
$(INSTALL_INFO) --info-dir=$(infodir) "$$f" ; \
|
||||
done
|
||||
|
||||
uninstall-info: info
|
||||
for f in *.info; do \
|
||||
rm -f "$(infodir)/$$f" ; \
|
||||
$(INSTALL_INFO) --delete --info-dir=$(infodir) "$$f" ; \
|
||||
done
|
||||
|
||||
%.info: %.texi
|
||||
$(MAKEINFO) -o '$@' '$<'
|
||||
|
||||
%.txt: %.texi
|
||||
$(MAKEINFO_plaintext) -o '$@' '$<'
|
||||
|
||||
%.html: %.texi
|
||||
$(MAKEINFO_html) -o '$@' '$<'
|
||||
|
||||
%.pdf: %.texi
|
||||
-$(TEXI2PDF) '$<'
|
||||
-$(TEXI2PDF) '$<'
|
||||
-$(TEXI2PDF) '$<'
|
||||
|
||||
clean:
|
||||
-rm -f *.info *.pdf *.txt *.html
|
||||
-rm -f *.log *.ind *.aux *.toc *.syn *.idx *.out *.ilg *.pla *.ky *.pg
|
||||
-rm -f *.vr *.tp *.fn *.fns *.def *.defs *.cp *.cps *.ge *.ges *.mo
|
||||
|
||||
.PHONY: all info plaintext html pdf install-info uninstall-info clean
|
BIN
gcc/jit/docs/_build/texinfo/factorial.png
vendored
Normal file
BIN
gcc/jit/docs/_build/texinfo/factorial.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 180 KiB |
6537
gcc/jit/docs/_build/texinfo/libgccjit.texi
vendored
Normal file
6537
gcc/jit/docs/_build/texinfo/libgccjit.texi
vendored
Normal file
File diff suppressed because it is too large
Load Diff
BIN
gcc/jit/docs/_build/texinfo/sum-of-squares.png
vendored
Normal file
BIN
gcc/jit/docs/_build/texinfo/sum-of-squares.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 22 KiB |
258
gcc/jit/docs/conf.py
Normal file
258
gcc/jit/docs/conf.py
Normal file
@ -0,0 +1,258 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# libgccjit documentation build configuration file, created by
|
||||
# sphinx-quickstart on Wed Jul 30 13:39:01 2014.
|
||||
#
|
||||
# This file is execfile()d with the current directory set to its containing dir.
|
||||
#
|
||||
# Note that not all possible configuration values are present in this
|
||||
# autogenerated file.
|
||||
#
|
||||
# All configuration values have a default; values that are commented out
|
||||
# serve to show the default.
|
||||
|
||||
import sys, os
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
#sys.path.insert(0, os.path.abspath('.'))
|
||||
|
||||
# -- General configuration -----------------------------------------------------
|
||||
|
||||
# If your documentation needs a minimal Sphinx version, state it here.
|
||||
#needs_sphinx = '1.0'
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be extensions
|
||||
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
||||
extensions = []
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
||||
# The suffix of source filenames.
|
||||
source_suffix = '.rst'
|
||||
|
||||
# The encoding of source files.
|
||||
#source_encoding = 'utf-8-sig'
|
||||
|
||||
# The master toctree document.
|
||||
master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = u'libgccjit'
|
||||
copyright = u'2014, Free Software Foundation'
|
||||
|
||||
# GCC-specific: extract version information from "gcc" src subdir for
|
||||
# use in "version" and "release" below.
|
||||
def __read_file(name):
|
||||
gcc_srcdir = '../..'
|
||||
path = os.path.join(gcc_srcdir, name)
|
||||
if os.path.exists(path):
|
||||
return open(path).read().strip()
|
||||
else:
|
||||
return ''
|
||||
gcc_BASEVER = __read_file('BASE-VER')
|
||||
gcc_DEVPHASE = __read_file('DEV-PHASE')
|
||||
gcc_DATESTAMP = __read_file('DATESTAMP')
|
||||
gcc_REVISION = __read_file('REVISION')
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = gcc_BASEVER
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = ('%s (%s %s%s)'
|
||||
% (gcc_BASEVER, gcc_DEVPHASE, gcc_DATESTAMP,
|
||||
(' %s' % gcc_REVISION) if gcc_REVISION else ''))
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
#language = None
|
||||
|
||||
# There are two options for replacing |today|: either, you set today to some
|
||||
# non-false value, then it is used:
|
||||
#today = ''
|
||||
# Else, today_fmt is used as the format for a strftime call.
|
||||
#today_fmt = '%B %d, %Y'
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
exclude_patterns = ['_build']
|
||||
|
||||
# The reST default role (used for this markup: `text`) to use for all documents.
|
||||
#default_role = None
|
||||
|
||||
# If true, '()' will be appended to :func: etc. cross-reference text.
|
||||
#add_function_parentheses = True
|
||||
|
||||
# If true, the current module name will be prepended to all description
|
||||
# unit titles (such as .. function::).
|
||||
#add_module_names = True
|
||||
|
||||
# If true, sectionauthor and moduleauthor directives will be shown in the
|
||||
# output. They are ignored by default.
|
||||
#show_authors = False
|
||||
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = 'sphinx'
|
||||
|
||||
# A list of ignored prefixes for module index sorting.
|
||||
#modindex_common_prefix = []
|
||||
|
||||
|
||||
# -- Options for HTML output ---------------------------------------------------
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
html_theme = 'pyramid'
|
||||
|
||||
# Theme options are theme-specific and customize the look and feel of a theme
|
||||
# further. For a list of options available for each theme, see the
|
||||
# documentation.
|
||||
#html_theme_options = {}
|
||||
|
||||
# Add any paths that contain custom themes here, relative to this directory.
|
||||
#html_theme_path = []
|
||||
|
||||
# The name for this set of Sphinx documents. If None, it defaults to
|
||||
# "<project> v<release> documentation".
|
||||
#html_title = None
|
||||
|
||||
# A shorter title for the navigation bar. Default is the same as html_title.
|
||||
#html_short_title = None
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top
|
||||
# of the sidebar.
|
||||
#html_logo = None
|
||||
|
||||
# The name of an image file (within the static path) to use as favicon of the
|
||||
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
|
||||
# pixels large.
|
||||
#html_favicon = None
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ['_static']
|
||||
|
||||
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
|
||||
# using the given strftime format.
|
||||
#html_last_updated_fmt = '%b %d, %Y'
|
||||
|
||||
# If true, SmartyPants will be used to convert quotes and dashes to
|
||||
# typographically correct entities.
|
||||
#html_use_smartypants = True
|
||||
|
||||
# Custom sidebar templates, maps document names to template names.
|
||||
#html_sidebars = {}
|
||||
|
||||
# Additional templates that should be rendered to pages, maps page names to
|
||||
# template names.
|
||||
#html_additional_pages = {}
|
||||
|
||||
# If false, no module index is generated.
|
||||
#html_domain_indices = True
|
||||
|
||||
# If false, no index is generated.
|
||||
#html_use_index = True
|
||||
|
||||
# If true, the index is split into individual pages for each letter.
|
||||
#html_split_index = False
|
||||
|
||||
# If true, links to the reST sources are added to the pages.
|
||||
#html_show_sourcelink = True
|
||||
|
||||
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
|
||||
#html_show_sphinx = True
|
||||
|
||||
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
|
||||
#html_show_copyright = True
|
||||
|
||||
# If true, an OpenSearch description file will be output, and all pages will
|
||||
# contain a <link> tag referring to it. The value of this option must be the
|
||||
# base URL from which the finished HTML is served.
|
||||
#html_use_opensearch = ''
|
||||
|
||||
# This is the file name suffix for HTML files (e.g. ".xhtml").
|
||||
#html_file_suffix = None
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = 'libgccjitdoc'
|
||||
|
||||
|
||||
# -- Options for LaTeX output --------------------------------------------------
|
||||
|
||||
latex_elements = {
|
||||
# The paper size ('letterpaper' or 'a4paper').
|
||||
#'papersize': 'letterpaper',
|
||||
|
||||
# The font size ('10pt', '11pt' or '12pt').
|
||||
#'pointsize': '10pt',
|
||||
|
||||
# Additional stuff for the LaTeX preamble.
|
||||
#'preamble': '',
|
||||
}
|
||||
|
||||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title, author, documentclass [howto/manual]).
|
||||
latex_documents = [
|
||||
('index', 'libgccjit.tex', u'libgccjit Documentation',
|
||||
u'David Malcolm', 'manual'),
|
||||
]
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top of
|
||||
# the title page.
|
||||
#latex_logo = None
|
||||
|
||||
# For "manual" documents, if this is true, then toplevel headings are parts,
|
||||
# not chapters.
|
||||
#latex_use_parts = False
|
||||
|
||||
# If true, show page references after internal links.
|
||||
#latex_show_pagerefs = False
|
||||
|
||||
# If true, show URL addresses after external links.
|
||||
#latex_show_urls = False
|
||||
|
||||
# Documents to append as an appendix to all manuals.
|
||||
#latex_appendices = []
|
||||
|
||||
# If false, no module index is generated.
|
||||
#latex_domain_indices = True
|
||||
|
||||
|
||||
# -- Options for manual page output --------------------------------------------
|
||||
|
||||
# One entry per manual page. List of tuples
|
||||
# (source start file, name, description, authors, manual section).
|
||||
man_pages = [
|
||||
('index', 'libgccjit', u'libgccjit Documentation',
|
||||
[u'David Malcolm'], 1)
|
||||
]
|
||||
|
||||
# If true, show URL addresses after external links.
|
||||
#man_show_urls = False
|
||||
|
||||
|
||||
# -- Options for Texinfo output ------------------------------------------------
|
||||
|
||||
# Grouping the document tree into Texinfo files. List of tuples
|
||||
# (source start file, target name, title, author,
|
||||
# dir menu entry, description, category)
|
||||
texinfo_documents = [
|
||||
('index', 'libgccjit', u'libgccjit Documentation',
|
||||
u'David Malcolm', 'libgccjit', 'One line description of project.',
|
||||
'Miscellaneous'),
|
||||
]
|
||||
|
||||
# Documents to append as an appendix to all manuals.
|
||||
#texinfo_appendices = []
|
||||
|
||||
# If false, no module index is generated.
|
||||
#texinfo_domain_indices = True
|
||||
|
||||
# How to display URL addresses: 'footnote', 'no', or 'inline'.
|
||||
#texinfo_show_urls = 'footnote'
|
123
gcc/jit/docs/examples/tut01-hello-world.c
Normal file
123
gcc/jit/docs/examples/tut01-hello-world.c
Normal file
@ -0,0 +1,123 @@
|
||||
/* Smoketest example for libgccjit.so
|
||||
Copyright (C) 2014 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GCC.
|
||||
|
||||
GCC is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3, or (at your option)
|
||||
any later version.
|
||||
|
||||
GCC is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GCC; see the file COPYING3. If not see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <libgccjit.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static void
|
||||
create_code (gcc_jit_context *ctxt)
|
||||
{
|
||||
/* Let's try to inject the equivalent of:
|
||||
void
|
||||
greet (const char *name)
|
||||
{
|
||||
printf ("hello %s\n", name);
|
||||
}
|
||||
*/
|
||||
gcc_jit_type *void_type =
|
||||
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
|
||||
gcc_jit_type *const_char_ptr_type =
|
||||
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_CONST_CHAR_PTR);
|
||||
gcc_jit_param *param_name =
|
||||
gcc_jit_context_new_param (ctxt, NULL, const_char_ptr_type, "name");
|
||||
gcc_jit_function *func =
|
||||
gcc_jit_context_new_function (ctxt, NULL,
|
||||
GCC_JIT_FUNCTION_EXPORTED,
|
||||
void_type,
|
||||
"greet",
|
||||
1, ¶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;
|
||||
}
|
107
gcc/jit/docs/examples/tut02-square.c
Normal file
107
gcc/jit/docs/examples/tut02-square.c
Normal file
@ -0,0 +1,107 @@
|
||||
/* Usage example for libgccjit.so
|
||||
Copyright (C) 2014 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GCC.
|
||||
|
||||
GCC is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3, or (at your option)
|
||||
any later version.
|
||||
|
||||
GCC is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GCC; see the file COPYING3. If not see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <libgccjit.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
void
|
||||
create_code (gcc_jit_context *ctxt)
|
||||
{
|
||||
/* Let's try to inject the equivalent of:
|
||||
|
||||
int square (int i)
|
||||
{
|
||||
return i * i;
|
||||
}
|
||||
*/
|
||||
gcc_jit_type *int_type =
|
||||
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
|
||||
gcc_jit_param *param_i =
|
||||
gcc_jit_context_new_param (ctxt, NULL, int_type, "i");
|
||||
gcc_jit_function *func =
|
||||
gcc_jit_context_new_function (ctxt, NULL,
|
||||
GCC_JIT_FUNCTION_EXPORTED,
|
||||
int_type,
|
||||
"square",
|
||||
1, ¶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;
|
||||
}
|
172
gcc/jit/docs/examples/tut03-sum-of-squares.c
Normal file
172
gcc/jit/docs/examples/tut03-sum-of-squares.c
Normal file
@ -0,0 +1,172 @@
|
||||
/* Usage example for libgccjit.so
|
||||
Copyright (C) 2014 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GCC.
|
||||
|
||||
GCC is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3, or (at your option)
|
||||
any later version.
|
||||
|
||||
GCC is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GCC; see the file COPYING3. If not see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <libgccjit.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
void
|
||||
create_code (gcc_jit_context *ctxt)
|
||||
{
|
||||
/*
|
||||
Simple sum-of-squares, to test conditionals and looping
|
||||
|
||||
int loop_test (int n)
|
||||
{
|
||||
int i;
|
||||
int sum = 0;
|
||||
for (i = 0; i < n ; i ++)
|
||||
{
|
||||
sum += i * i;
|
||||
}
|
||||
return sum;
|
||||
*/
|
||||
gcc_jit_type *the_type =
|
||||
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
|
||||
gcc_jit_type *return_type = the_type;
|
||||
|
||||
gcc_jit_param *n =
|
||||
gcc_jit_context_new_param (ctxt, NULL, the_type, "n");
|
||||
gcc_jit_param *params[1] = {n};
|
||||
gcc_jit_function *func =
|
||||
gcc_jit_context_new_function (ctxt, NULL,
|
||||
GCC_JIT_FUNCTION_EXPORTED,
|
||||
return_type,
|
||||
"loop_test",
|
||||
1, params, 0);
|
||||
|
||||
/* Build locals: */
|
||||
gcc_jit_lvalue *i =
|
||||
gcc_jit_function_new_local (func, NULL, the_type, "i");
|
||||
gcc_jit_lvalue *sum =
|
||||
gcc_jit_function_new_local (func, NULL, the_type, "sum");
|
||||
|
||||
gcc_jit_block *b_initial =
|
||||
gcc_jit_function_new_block (func, "initial");
|
||||
gcc_jit_block *b_loop_cond =
|
||||
gcc_jit_function_new_block (func, "loop_cond");
|
||||
gcc_jit_block *b_loop_body =
|
||||
gcc_jit_function_new_block (func, "loop_body");
|
||||
gcc_jit_block *b_after_loop =
|
||||
gcc_jit_function_new_block (func, "after_loop");
|
||||
|
||||
/* sum = 0; */
|
||||
gcc_jit_block_add_assignment (
|
||||
b_initial, NULL,
|
||||
sum,
|
||||
gcc_jit_context_zero (ctxt, the_type));
|
||||
|
||||
/* i = 0; */
|
||||
gcc_jit_block_add_assignment (
|
||||
b_initial, NULL,
|
||||
i,
|
||||
gcc_jit_context_zero (ctxt, the_type));
|
||||
|
||||
gcc_jit_block_end_with_jump (b_initial, NULL, b_loop_cond);
|
||||
|
||||
/* if (i >= n) */
|
||||
gcc_jit_block_end_with_conditional (
|
||||
b_loop_cond, NULL,
|
||||
gcc_jit_context_new_comparison (
|
||||
ctxt, NULL,
|
||||
GCC_JIT_COMPARISON_GE,
|
||||
gcc_jit_lvalue_as_rvalue (i),
|
||||
gcc_jit_param_as_rvalue (n)),
|
||||
b_after_loop,
|
||||
b_loop_body);
|
||||
|
||||
/* sum += i * i */
|
||||
gcc_jit_block_add_assignment_op (
|
||||
b_loop_body, NULL,
|
||||
sum,
|
||||
GCC_JIT_BINARY_OP_PLUS,
|
||||
gcc_jit_context_new_binary_op (
|
||||
ctxt, NULL,
|
||||
GCC_JIT_BINARY_OP_MULT, the_type,
|
||||
gcc_jit_lvalue_as_rvalue (i),
|
||||
gcc_jit_lvalue_as_rvalue (i)));
|
||||
|
||||
/* i++ */
|
||||
gcc_jit_block_add_assignment_op (
|
||||
b_loop_body, NULL,
|
||||
i,
|
||||
GCC_JIT_BINARY_OP_PLUS,
|
||||
gcc_jit_context_one (ctxt, the_type));
|
||||
|
||||
gcc_jit_block_end_with_jump (b_loop_body, NULL, b_loop_cond);
|
||||
|
||||
/* return sum */
|
||||
gcc_jit_block_end_with_return (
|
||||
b_after_loop,
|
||||
NULL,
|
||||
gcc_jit_lvalue_as_rvalue (sum));
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
gcc_jit_context *ctxt = NULL;
|
||||
gcc_jit_result *result = NULL;
|
||||
|
||||
/* Get a "context" object for working with the library. */
|
||||
ctxt = gcc_jit_context_acquire ();
|
||||
if (!ctxt)
|
||||
{
|
||||
fprintf (stderr, "NULL ctxt");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Set some options on the context.
|
||||
Let's see the code being generated, in assembler form. */
|
||||
gcc_jit_context_set_bool_option (
|
||||
ctxt,
|
||||
GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE,
|
||||
0);
|
||||
|
||||
/* Populate the context. */
|
||||
create_code (ctxt);
|
||||
|
||||
/* Compile the code. */
|
||||
result = gcc_jit_context_compile (ctxt);
|
||||
if (!result)
|
||||
{
|
||||
fprintf (stderr, "NULL result");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Extract the generated code from "result". */
|
||||
typedef int (*loop_test_fn_type) (int);
|
||||
loop_test_fn_type loop_test =
|
||||
(loop_test_fn_type)gcc_jit_result_get_code (result, "loop_test");
|
||||
if (!loop_test)
|
||||
{
|
||||
fprintf (stderr, "NULL loop_test");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Run the generated code. */
|
||||
int val = loop_test (10);
|
||||
printf("loop_test returned: %d\n", val);
|
||||
|
||||
error:
|
||||
gcc_jit_context_release (ctxt);
|
||||
gcc_jit_result_release (result);
|
||||
return 0;
|
||||
}
|
11
gcc/jit/docs/examples/tut04-toyvm/Makefile
Normal file
11
gcc/jit/docs/examples/tut04-toyvm/Makefile
Normal file
@ -0,0 +1,11 @@
|
||||
factorial: toyvm
|
||||
./toyvm factorial.toy 10
|
||||
|
||||
fibonacci: toyvm
|
||||
./toyvm fibonacci.toy 8
|
||||
|
||||
toyvm: toyvm.c Makefile
|
||||
g++ -Wall -g -o $@ $< $(shell pkg-config --cflags --libs libgccjit)
|
||||
|
||||
clean:
|
||||
rm -f *.o toyvm
|
50
gcc/jit/docs/examples/tut04-toyvm/factorial.toy
Normal file
50
gcc/jit/docs/examples/tut04-toyvm/factorial.toy
Normal file
@ -0,0 +1,50 @@
|
||||
# Simple recursive factorial implementation, roughly equivalent to:
|
||||
#
|
||||
# int factorial (int arg)
|
||||
# {
|
||||
# if (arg < 2)
|
||||
# return arg
|
||||
# return arg * factorial (arg - 1)
|
||||
# }
|
||||
|
||||
# Initial state:
|
||||
# stack: [arg]
|
||||
|
||||
# 0:
|
||||
DUP
|
||||
# stack: [arg, arg]
|
||||
|
||||
# 1:
|
||||
PUSH_CONST 2
|
||||
# stack: [arg, arg, 2]
|
||||
|
||||
# 2:
|
||||
BINARY_COMPARE_LT
|
||||
# stack: [arg, (arg < 2)]
|
||||
|
||||
# 3:
|
||||
JUMP_ABS_IF_TRUE 9
|
||||
# stack: [arg]
|
||||
|
||||
# 4:
|
||||
DUP
|
||||
# stack: [arg, arg]
|
||||
|
||||
# 5:
|
||||
PUSH_CONST 1
|
||||
# stack: [arg, arg, 1]
|
||||
|
||||
# 6:
|
||||
BINARY_SUBTRACT
|
||||
# stack: [arg, (arg - 1)
|
||||
|
||||
# 7:
|
||||
RECURSE
|
||||
# stack: [arg, factorial(arg - 1)]
|
||||
|
||||
# 8:
|
||||
BINARY_MULT
|
||||
# stack: [arg * factorial(arg - 1)]
|
||||
|
||||
# 9:
|
||||
RETURN
|
66
gcc/jit/docs/examples/tut04-toyvm/fibonacci.toy
Normal file
66
gcc/jit/docs/examples/tut04-toyvm/fibonacci.toy
Normal file
@ -0,0 +1,66 @@
|
||||
# Simple recursive fibonacci implementation, roughly equivalent to:
|
||||
#
|
||||
# int fibonacci (int arg)
|
||||
# {
|
||||
# if (arg < 2)
|
||||
# return arg
|
||||
# return fibonacci (arg-1) + fibonacci (arg-2)
|
||||
# }
|
||||
|
||||
# Initial state:
|
||||
# stack: [arg]
|
||||
|
||||
# 0:
|
||||
DUP
|
||||
# stack: [arg, arg]
|
||||
|
||||
# 1:
|
||||
PUSH_CONST 2
|
||||
# stack: [arg, arg, 2]
|
||||
|
||||
# 2:
|
||||
BINARY_COMPARE_LT
|
||||
# stack: [arg, (arg < 2)]
|
||||
|
||||
# 3:
|
||||
JUMP_ABS_IF_TRUE 13
|
||||
# stack: [arg]
|
||||
|
||||
# 4:
|
||||
DUP
|
||||
# stack: [arg, arg]
|
||||
|
||||
# 5:
|
||||
PUSH_CONST 1
|
||||
# stack: [arg, arg, 1]
|
||||
|
||||
# 6:
|
||||
BINARY_SUBTRACT
|
||||
# stack: [arg, (arg - 1)
|
||||
|
||||
# 7:
|
||||
RECURSE
|
||||
# stack: [arg, fib(arg - 1)]
|
||||
|
||||
# 8:
|
||||
ROT
|
||||
# stack: [fib(arg - 1), arg]
|
||||
|
||||
# 9:
|
||||
PUSH_CONST 2
|
||||
# stack: [fib(arg - 1), arg, 2]
|
||||
|
||||
# 10:
|
||||
BINARY_SUBTRACT
|
||||
# stack: [fib(arg - 1), arg, (arg - 2)
|
||||
|
||||
# 11:
|
||||
RECURSE
|
||||
# stack: [fib(arg - 1), fib(arg - 1)]
|
||||
|
||||
# 12:
|
||||
BINARY_ADD
|
||||
# stack: [fib(arg - 1) + fib(arg - 1)]
|
||||
|
||||
# 13:
|
||||
RETURN
|
861
gcc/jit/docs/examples/tut04-toyvm/toyvm.c
Normal file
861
gcc/jit/docs/examples/tut04-toyvm/toyvm.c
Normal file
@ -0,0 +1,861 @@
|
||||
/* A simple stack-based virtual machine to demonstrate
|
||||
JIT-compilation.
|
||||
Copyright (C) 2014 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GCC.
|
||||
|
||||
GCC is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3, or (at your option)
|
||||
any later version.
|
||||
|
||||
GCC is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GCC; see the file COPYING3. If not see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <dejagnu.h>
|
||||
|
||||
#include <libgccjit.h>
|
||||
|
||||
/* Typedefs. */
|
||||
typedef struct toyvm_op toyvm_op;
|
||||
typedef struct toyvm_function toyvm_function;
|
||||
typedef struct toyvm_frame toyvm_frame;
|
||||
typedef struct compilation_state compilation_state;
|
||||
|
||||
/* Functions are compiled to this function ptr type. */
|
||||
typedef int (*toyvm_compiled_func) (int);
|
||||
|
||||
enum opcode {
|
||||
/* Ops taking no operand. */
|
||||
DUP,
|
||||
ROT,
|
||||
BINARY_ADD,
|
||||
BINARY_SUBTRACT,
|
||||
BINARY_MULT,
|
||||
BINARY_COMPARE_LT,
|
||||
RECURSE,
|
||||
RETURN,
|
||||
|
||||
/* Ops taking an operand. */
|
||||
PUSH_CONST,
|
||||
JUMP_ABS_IF_TRUE
|
||||
};
|
||||
|
||||
#define FIRST_UNARY_OPCODE (PUSH_CONST)
|
||||
|
||||
const char * const opcode_names[] = {
|
||||
"DUP",
|
||||
"ROT",
|
||||
"BINARY_ADD",
|
||||
"BINARY_SUBTRACT",
|
||||
"BINARY_MULT",
|
||||
"BINARY_COMPARE_LT",
|
||||
"RECURSE",
|
||||
"RETURN",
|
||||
|
||||
"PUSH_CONST",
|
||||
"JUMP_ABS_IF_TRUE",
|
||||
};
|
||||
|
||||
struct toyvm_op
|
||||
{
|
||||
/* Which operation. */
|
||||
enum opcode op_opcode;
|
||||
|
||||
/* Some opcodes take an argument. */
|
||||
int op_operand;
|
||||
|
||||
/* The line number of the operation within the source file. */
|
||||
int op_linenum;
|
||||
};
|
||||
|
||||
#define MAX_OPS (64)
|
||||
|
||||
struct toyvm_function
|
||||
{
|
||||
const char *fn_filename;
|
||||
int fn_num_ops;
|
||||
toyvm_op fn_ops[MAX_OPS];
|
||||
};
|
||||
|
||||
#define MAX_STACK_DEPTH (8)
|
||||
|
||||
struct toyvm_frame
|
||||
{
|
||||
toyvm_function *frm_function;
|
||||
int frm_pc;
|
||||
int frm_stack[MAX_STACK_DEPTH];
|
||||
int frm_cur_depth;
|
||||
};
|
||||
|
||||
static void
|
||||
add_op (toyvm_function *fn, enum opcode opcode,
|
||||
int operand, int linenum)
|
||||
{
|
||||
toyvm_op *op;
|
||||
assert (fn->fn_num_ops < MAX_OPS);
|
||||
op = &fn->fn_ops[fn->fn_num_ops++];
|
||||
op->op_opcode = opcode;
|
||||
op->op_operand = operand;
|
||||
op->op_linenum = linenum;
|
||||
}
|
||||
|
||||
static void
|
||||
add_unary_op (toyvm_function *fn, enum opcode opcode,
|
||||
const char *rest_of_line, int linenum)
|
||||
{
|
||||
int operand = atoi (rest_of_line);
|
||||
add_op (fn, opcode, operand, linenum);
|
||||
}
|
||||
|
||||
static toyvm_function *
|
||||
toyvm_function_parse (const char *filename, const char *name)
|
||||
{
|
||||
FILE *f = NULL;
|
||||
toyvm_function *fn = NULL;
|
||||
char *line = NULL;
|
||||
ssize_t linelen;
|
||||
size_t bufsize;
|
||||
int linenum = 0;
|
||||
|
||||
assert (filename);
|
||||
assert (name);
|
||||
|
||||
f = fopen (filename, "r");
|
||||
if (!f)
|
||||
{
|
||||
fprintf (stderr,
|
||||
"cannot open file %s: %s\n",
|
||||
filename, strerror (errno));
|
||||
goto error;
|
||||
}
|
||||
|
||||
fn = (toyvm_function *)calloc (1, sizeof (toyvm_function));
|
||||
if (!fn)
|
||||
{
|
||||
fprintf (stderr, "out of memory allocating toyvm_function\n");
|
||||
goto error;
|
||||
}
|
||||
fn->fn_filename = name;
|
||||
|
||||
/* Read the lines of the file. */
|
||||
while ((linelen = getline (&line, &bufsize, f)) != -1)
|
||||
{
|
||||
/* Note that this is a terrible parser, but it avoids the need to
|
||||
bring in lex/yacc as a dependency. */
|
||||
linenum++;
|
||||
|
||||
if (0)
|
||||
fprintf (stdout, "%3d: %s", linenum, line);
|
||||
|
||||
/* Lines beginning with # are comments. */
|
||||
if (line[0] == '#')
|
||||
continue;
|
||||
|
||||
/* Skip blank lines. */
|
||||
if (line[0] == '\n')
|
||||
continue;
|
||||
|
||||
#define LINE_MATCHES(OPCODE) (0 == strncmp ((OPCODE), line, strlen (OPCODE)))
|
||||
if (LINE_MATCHES ("DUP\n"))
|
||||
add_op (fn, DUP, 0, linenum);
|
||||
else if (LINE_MATCHES ("ROT\n"))
|
||||
add_op (fn, ROT, 0, linenum);
|
||||
else if (LINE_MATCHES ("BINARY_ADD\n"))
|
||||
add_op (fn, BINARY_ADD, 0, linenum);
|
||||
else if (LINE_MATCHES ("BINARY_SUBTRACT\n"))
|
||||
add_op (fn, BINARY_SUBTRACT, 0, linenum);
|
||||
else if (LINE_MATCHES ("BINARY_MULT\n"))
|
||||
add_op (fn, BINARY_MULT, 0, linenum);
|
||||
else if (LINE_MATCHES ("BINARY_COMPARE_LT\n"))
|
||||
add_op (fn, BINARY_COMPARE_LT, 0, linenum);
|
||||
else if (LINE_MATCHES ("RECURSE\n"))
|
||||
add_op (fn, RECURSE, 0, linenum);
|
||||
else if (LINE_MATCHES ("RETURN\n"))
|
||||
add_op (fn, RETURN, 0, linenum);
|
||||
else if (LINE_MATCHES ("PUSH_CONST "))
|
||||
add_unary_op (fn, PUSH_CONST,
|
||||
line + strlen ("PUSH_CONST "), linenum);
|
||||
else if (LINE_MATCHES ("JUMP_ABS_IF_TRUE "))
|
||||
add_unary_op (fn, JUMP_ABS_IF_TRUE,
|
||||
line + strlen("JUMP_ABS_IF_TRUE "), linenum);
|
||||
else
|
||||
{
|
||||
fprintf (stderr, "%s:%d: parse error\n", filename, linenum);
|
||||
free (fn);
|
||||
fn = NULL;
|
||||
goto error;
|
||||
}
|
||||
#undef LINE_MATCHES
|
||||
}
|
||||
free (line);
|
||||
fclose (f);
|
||||
|
||||
return fn;
|
||||
|
||||
error:
|
||||
free (line);
|
||||
fclose (f);
|
||||
free (fn);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
toyvm_function_disassemble_op (toyvm_function *fn, toyvm_op *op, int index, FILE *out)
|
||||
{
|
||||
fprintf (out, "%s:%d: index %d: %s",
|
||||
fn->fn_filename, op->op_linenum, index,
|
||||
opcode_names[op->op_opcode]);
|
||||
if (op->op_opcode >= FIRST_UNARY_OPCODE)
|
||||
fprintf (out, " %d", op->op_operand);
|
||||
fprintf (out, "\n");
|
||||
}
|
||||
|
||||
static void
|
||||
toyvm_function_disassemble (toyvm_function *fn, FILE *out)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < fn->fn_num_ops; i++)
|
||||
{
|
||||
toyvm_op *op = &fn->fn_ops[i];
|
||||
toyvm_function_disassemble_op (fn, op, i, out);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
toyvm_frame_push (toyvm_frame *frame, int arg)
|
||||
{
|
||||
assert (frame->frm_cur_depth < MAX_STACK_DEPTH);
|
||||
frame->frm_stack[frame->frm_cur_depth++] = arg;
|
||||
}
|
||||
|
||||
static int
|
||||
toyvm_frame_pop (toyvm_frame *frame)
|
||||
{
|
||||
assert (frame->frm_cur_depth > 0);
|
||||
return frame->frm_stack[--frame->frm_cur_depth];
|
||||
}
|
||||
|
||||
static void
|
||||
toyvm_frame_dump_stack (toyvm_frame *frame, FILE *out)
|
||||
{
|
||||
int i;
|
||||
fprintf (out, "stack:");
|
||||
for (i = 0; i < frame->frm_cur_depth; i++)
|
||||
{
|
||||
fprintf (out, " %d", frame->frm_stack[i]);
|
||||
}
|
||||
fprintf (out, "\n");
|
||||
}
|
||||
|
||||
/* Execute the given function. */
|
||||
|
||||
static int
|
||||
toyvm_function_interpret (toyvm_function *fn, int arg, FILE *trace)
|
||||
{
|
||||
toyvm_frame frame;
|
||||
#define PUSH(ARG) (toyvm_frame_push (&frame, (ARG)))
|
||||
#define POP(ARG) (toyvm_frame_pop (&frame))
|
||||
|
||||
frame.frm_function = fn;
|
||||
frame.frm_pc = 0;
|
||||
frame.frm_cur_depth = 0;
|
||||
|
||||
PUSH (arg);
|
||||
|
||||
while (1)
|
||||
{
|
||||
toyvm_op *op;
|
||||
int x, y;
|
||||
assert (frame.frm_pc < fn->fn_num_ops);
|
||||
op = &fn->fn_ops[frame.frm_pc++];
|
||||
|
||||
if (trace)
|
||||
{
|
||||
toyvm_frame_dump_stack (&frame, trace);
|
||||
toyvm_function_disassemble_op (fn, op, frame.frm_pc, trace);
|
||||
}
|
||||
|
||||
switch (op->op_opcode)
|
||||
{
|
||||
/* Ops taking no operand. */
|
||||
case DUP:
|
||||
x = POP ();
|
||||
PUSH (x);
|
||||
PUSH (x);
|
||||
break;
|
||||
|
||||
case ROT:
|
||||
y = POP ();
|
||||
x = POP ();
|
||||
PUSH (y);
|
||||
PUSH (x);
|
||||
break;
|
||||
|
||||
case BINARY_ADD:
|
||||
y = POP ();
|
||||
x = POP ();
|
||||
PUSH (x + y);
|
||||
break;
|
||||
|
||||
case BINARY_SUBTRACT:
|
||||
y = POP ();
|
||||
x = POP ();
|
||||
PUSH (x - y);
|
||||
break;
|
||||
|
||||
case BINARY_MULT:
|
||||
y = POP ();
|
||||
x = POP ();
|
||||
PUSH (x * y);
|
||||
break;
|
||||
|
||||
case BINARY_COMPARE_LT:
|
||||
y = POP ();
|
||||
x = POP ();
|
||||
PUSH (x < y);
|
||||
break;
|
||||
|
||||
case RECURSE:
|
||||
x = POP ();
|
||||
x = toyvm_function_interpret (fn, x, trace);
|
||||
PUSH (x);
|
||||
break;
|
||||
|
||||
case RETURN:
|
||||
return POP ();
|
||||
|
||||
/* Ops taking an operand. */
|
||||
case PUSH_CONST:
|
||||
PUSH (op->op_operand);
|
||||
break;
|
||||
|
||||
case JUMP_ABS_IF_TRUE:
|
||||
x = POP ();
|
||||
if (x)
|
||||
frame.frm_pc = op->op_operand;
|
||||
break;
|
||||
|
||||
default:
|
||||
assert (0); /* unknown opcode */
|
||||
|
||||
} /* end of switch on opcode */
|
||||
} /* end of while loop */
|
||||
|
||||
#undef PUSH
|
||||
#undef POP
|
||||
}
|
||||
|
||||
/* JIT compilation. */
|
||||
|
||||
struct compilation_state
|
||||
{
|
||||
gcc_jit_context *ctxt;
|
||||
|
||||
gcc_jit_type *int_type;
|
||||
gcc_jit_type *bool_type;
|
||||
gcc_jit_type *stack_type; /* int[MAX_STACK_DEPTH] */
|
||||
|
||||
gcc_jit_rvalue *const_one;
|
||||
|
||||
gcc_jit_function *fn;
|
||||
gcc_jit_param *param_arg;
|
||||
gcc_jit_lvalue *stack;
|
||||
gcc_jit_lvalue *stack_depth;
|
||||
gcc_jit_lvalue *x;
|
||||
gcc_jit_lvalue *y;
|
||||
|
||||
gcc_jit_location *op_locs[MAX_OPS];
|
||||
gcc_jit_block *initial_block;
|
||||
gcc_jit_block *op_blocks[MAX_OPS];
|
||||
|
||||
};
|
||||
|
||||
/* Stack manipulation. */
|
||||
|
||||
static void
|
||||
add_push (compilation_state *state,
|
||||
gcc_jit_block *block,
|
||||
gcc_jit_rvalue *rvalue,
|
||||
gcc_jit_location *loc)
|
||||
{
|
||||
/* stack[stack_depth] = RVALUE */
|
||||
gcc_jit_block_add_assignment (
|
||||
block,
|
||||
loc,
|
||||
/* stack[stack_depth] */
|
||||
gcc_jit_context_new_array_access (
|
||||
state->ctxt,
|
||||
loc,
|
||||
gcc_jit_lvalue_as_rvalue (state->stack),
|
||||
gcc_jit_lvalue_as_rvalue (state->stack_depth)),
|
||||
rvalue);
|
||||
|
||||
/* "stack_depth++;". */
|
||||
gcc_jit_block_add_assignment_op (
|
||||
block,
|
||||
loc,
|
||||
state->stack_depth,
|
||||
GCC_JIT_BINARY_OP_PLUS,
|
||||
state->const_one);
|
||||
}
|
||||
|
||||
static void
|
||||
add_pop (compilation_state *state,
|
||||
gcc_jit_block *block,
|
||||
gcc_jit_lvalue *lvalue,
|
||||
gcc_jit_location *loc)
|
||||
{
|
||||
/* "--stack_depth;". */
|
||||
gcc_jit_block_add_assignment_op (
|
||||
block,
|
||||
loc,
|
||||
state->stack_depth,
|
||||
GCC_JIT_BINARY_OP_MINUS,
|
||||
state->const_one);
|
||||
|
||||
/* "LVALUE = stack[stack_depth];". */
|
||||
gcc_jit_block_add_assignment (
|
||||
block,
|
||||
loc,
|
||||
lvalue,
|
||||
/* stack[stack_depth] */
|
||||
gcc_jit_lvalue_as_rvalue (
|
||||
gcc_jit_context_new_array_access (
|
||||
state->ctxt,
|
||||
loc,
|
||||
gcc_jit_lvalue_as_rvalue (state->stack),
|
||||
gcc_jit_lvalue_as_rvalue (state->stack_depth))));
|
||||
}
|
||||
|
||||
/* The main compilation hook. */
|
||||
|
||||
static toyvm_compiled_func
|
||||
toyvm_function_compile (toyvm_function *fn)
|
||||
{
|
||||
compilation_state state;
|
||||
int pc;
|
||||
char *funcname;
|
||||
|
||||
memset (&state, 0, sizeof (state));
|
||||
|
||||
/* Copy filename to funcname. */
|
||||
funcname = (char *)malloc (strlen (fn->fn_filename) + 1);
|
||||
strcpy (funcname, fn->fn_filename);
|
||||
|
||||
/* Convert "." to NIL terminator. */
|
||||
*(strchr (funcname, '.')) = '\0';
|
||||
|
||||
state.ctxt = gcc_jit_context_acquire ();
|
||||
|
||||
gcc_jit_context_set_bool_option (state.ctxt,
|
||||
GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE,
|
||||
0);
|
||||
gcc_jit_context_set_bool_option (state.ctxt,
|
||||
GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE,
|
||||
0);
|
||||
gcc_jit_context_set_int_option (state.ctxt,
|
||||
GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL,
|
||||
3);
|
||||
gcc_jit_context_set_bool_option (state.ctxt,
|
||||
GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES,
|
||||
0);
|
||||
gcc_jit_context_set_bool_option (state.ctxt,
|
||||
GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING,
|
||||
0);
|
||||
gcc_jit_context_set_bool_option (state.ctxt,
|
||||
GCC_JIT_BOOL_OPTION_DEBUGINFO,
|
||||
1);
|
||||
|
||||
/* Create types. */
|
||||
state.int_type =
|
||||
gcc_jit_context_get_type (state.ctxt, GCC_JIT_TYPE_INT);
|
||||
state.bool_type =
|
||||
gcc_jit_context_get_type (state.ctxt, GCC_JIT_TYPE_BOOL);
|
||||
state.stack_type =
|
||||
gcc_jit_context_new_array_type (state.ctxt, NULL,
|
||||
state.int_type, MAX_STACK_DEPTH);
|
||||
|
||||
/* The constant value 1. */
|
||||
state.const_one = gcc_jit_context_one (state.ctxt, state.int_type);
|
||||
|
||||
/* Create locations. */
|
||||
for (pc = 0; pc < fn->fn_num_ops; pc++)
|
||||
{
|
||||
toyvm_op *op = &fn->fn_ops[pc];
|
||||
|
||||
state.op_locs[pc] = gcc_jit_context_new_location (state.ctxt,
|
||||
fn->fn_filename,
|
||||
op->op_linenum,
|
||||
0); /* column */
|
||||
}
|
||||
|
||||
/* Creating the function. */
|
||||
state.param_arg =
|
||||
gcc_jit_context_new_param (state.ctxt, state.op_locs[0],
|
||||
state.int_type, "arg");
|
||||
state.fn =
|
||||
gcc_jit_context_new_function (state.ctxt,
|
||||
state.op_locs[0],
|
||||
GCC_JIT_FUNCTION_EXPORTED,
|
||||
state.int_type,
|
||||
funcname,
|
||||
1, &state.param_arg, 0);
|
||||
|
||||
/* Create stack lvalues. */
|
||||
state.stack =
|
||||
gcc_jit_function_new_local (state.fn, NULL,
|
||||
state.stack_type, "stack");
|
||||
state.stack_depth =
|
||||
gcc_jit_function_new_local (state.fn, NULL,
|
||||
state.int_type, "stack_depth");
|
||||
state.x =
|
||||
gcc_jit_function_new_local (state.fn, NULL,
|
||||
state.int_type, "x");
|
||||
state.y =
|
||||
gcc_jit_function_new_local (state.fn, NULL,
|
||||
state.int_type, "y");
|
||||
|
||||
/* 1st pass: create blocks, one per opcode. */
|
||||
|
||||
/* We need an entry block to do one-time initialization, so create that
|
||||
first. */
|
||||
state.initial_block = gcc_jit_function_new_block (state.fn, "initial");
|
||||
|
||||
/* Create a block per operation. */
|
||||
for (pc = 0; pc < fn->fn_num_ops; pc++)
|
||||
{
|
||||
char buf[16];
|
||||
sprintf (buf, "instr%i", pc);
|
||||
state.op_blocks[pc] = gcc_jit_function_new_block (state.fn, buf);
|
||||
}
|
||||
|
||||
/* Populate the initial block. */
|
||||
|
||||
/* "stack_depth = 0;". */
|
||||
gcc_jit_block_add_assignment (
|
||||
state.initial_block,
|
||||
state.op_locs[0],
|
||||
state.stack_depth,
|
||||
gcc_jit_context_zero (state.ctxt, state.int_type));
|
||||
|
||||
/* "PUSH (arg);". */
|
||||
add_push (&state,
|
||||
state.initial_block,
|
||||
gcc_jit_param_as_rvalue (state.param_arg),
|
||||
state.op_locs[0]);
|
||||
|
||||
/* ...and jump to insn 0. */
|
||||
gcc_jit_block_end_with_jump (state.initial_block,
|
||||
state.op_locs[0],
|
||||
state.op_blocks[0]);
|
||||
|
||||
/* 2nd pass: fill in instructions. */
|
||||
for (pc = 0; pc < fn->fn_num_ops; pc++)
|
||||
{
|
||||
gcc_jit_location *loc = state.op_locs[pc];
|
||||
|
||||
gcc_jit_block *block = state.op_blocks[pc];
|
||||
gcc_jit_block *next_block = (pc < fn->fn_num_ops
|
||||
? state.op_blocks[pc + 1]
|
||||
: NULL);
|
||||
|
||||
toyvm_op *op;
|
||||
op = &fn->fn_ops[pc];
|
||||
|
||||
/* Helper macros. */
|
||||
|
||||
#define X_EQUALS_POP()\
|
||||
add_pop (&state, block, state.x, loc)
|
||||
#define Y_EQUALS_POP()\
|
||||
add_pop (&state, block, state.y, loc)
|
||||
#define PUSH_RVALUE(RVALUE)\
|
||||
add_push (&state, block, (RVALUE), loc)
|
||||
#define PUSH_X()\
|
||||
PUSH_RVALUE (gcc_jit_lvalue_as_rvalue (state.x))
|
||||
#define PUSH_Y() \
|
||||
PUSH_RVALUE (gcc_jit_lvalue_as_rvalue (state.y))
|
||||
|
||||
gcc_jit_block_add_comment (block, loc, opcode_names[op->op_opcode]);
|
||||
|
||||
/* Handle the individual opcodes. */
|
||||
|
||||
switch (op->op_opcode)
|
||||
{
|
||||
case DUP:
|
||||
X_EQUALS_POP ();
|
||||
PUSH_X ();
|
||||
PUSH_X ();
|
||||
break;
|
||||
|
||||
case ROT:
|
||||
Y_EQUALS_POP ();
|
||||
X_EQUALS_POP ();
|
||||
PUSH_Y ();
|
||||
PUSH_X ();
|
||||
break;
|
||||
|
||||
case BINARY_ADD:
|
||||
Y_EQUALS_POP ();
|
||||
X_EQUALS_POP ();
|
||||
PUSH_RVALUE (
|
||||
gcc_jit_context_new_binary_op (
|
||||
state.ctxt,
|
||||
loc,
|
||||
GCC_JIT_BINARY_OP_PLUS,
|
||||
state.int_type,
|
||||
gcc_jit_lvalue_as_rvalue (state.x),
|
||||
gcc_jit_lvalue_as_rvalue (state.y)));
|
||||
break;
|
||||
|
||||
case BINARY_SUBTRACT:
|
||||
Y_EQUALS_POP ();
|
||||
X_EQUALS_POP ();
|
||||
PUSH_RVALUE (
|
||||
gcc_jit_context_new_binary_op (
|
||||
state.ctxt,
|
||||
loc,
|
||||
GCC_JIT_BINARY_OP_MINUS,
|
||||
state.int_type,
|
||||
gcc_jit_lvalue_as_rvalue (state.x),
|
||||
gcc_jit_lvalue_as_rvalue (state.y)));
|
||||
break;
|
||||
|
||||
case BINARY_MULT:
|
||||
Y_EQUALS_POP ();
|
||||
X_EQUALS_POP ();
|
||||
PUSH_RVALUE (
|
||||
gcc_jit_context_new_binary_op (
|
||||
state.ctxt,
|
||||
loc,
|
||||
GCC_JIT_BINARY_OP_MULT,
|
||||
state.int_type,
|
||||
gcc_jit_lvalue_as_rvalue (state.x),
|
||||
gcc_jit_lvalue_as_rvalue (state.y)));
|
||||
break;
|
||||
|
||||
case BINARY_COMPARE_LT:
|
||||
Y_EQUALS_POP ();
|
||||
X_EQUALS_POP ();
|
||||
PUSH_RVALUE (
|
||||
/* cast of bool to int */
|
||||
gcc_jit_context_new_cast (
|
||||
state.ctxt,
|
||||
loc,
|
||||
/* (x < y) as a bool */
|
||||
gcc_jit_context_new_comparison (
|
||||
state.ctxt,
|
||||
loc,
|
||||
GCC_JIT_COMPARISON_LT,
|
||||
gcc_jit_lvalue_as_rvalue (state.x),
|
||||
gcc_jit_lvalue_as_rvalue (state.y)),
|
||||
state.int_type));
|
||||
break;
|
||||
|
||||
case RECURSE:
|
||||
{
|
||||
X_EQUALS_POP ();
|
||||
gcc_jit_rvalue *arg = gcc_jit_lvalue_as_rvalue (state.x);
|
||||
PUSH_RVALUE (
|
||||
gcc_jit_context_new_call (
|
||||
state.ctxt,
|
||||
loc,
|
||||
state.fn,
|
||||
1, &arg));
|
||||
break;
|
||||
}
|
||||
|
||||
case RETURN:
|
||||
X_EQUALS_POP ();
|
||||
gcc_jit_block_end_with_return (
|
||||
block,
|
||||
loc,
|
||||
gcc_jit_lvalue_as_rvalue (state.x));
|
||||
break;
|
||||
|
||||
/* Ops taking an operand. */
|
||||
case PUSH_CONST:
|
||||
PUSH_RVALUE (
|
||||
gcc_jit_context_new_rvalue_from_int (
|
||||
state.ctxt,
|
||||
state.int_type,
|
||||
op->op_operand));
|
||||
break;
|
||||
|
||||
case JUMP_ABS_IF_TRUE:
|
||||
X_EQUALS_POP ();
|
||||
gcc_jit_block_end_with_conditional (
|
||||
block,
|
||||
loc,
|
||||
/* "(bool)x". */
|
||||
gcc_jit_context_new_cast (
|
||||
state.ctxt,
|
||||
loc,
|
||||
gcc_jit_lvalue_as_rvalue (state.x),
|
||||
state.bool_type),
|
||||
state.op_blocks[op->op_operand], /* on_true */
|
||||
next_block); /* on_false */
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
} /* end of switch on opcode */
|
||||
|
||||
/* Go to the next block. */
|
||||
if (op->op_opcode != JUMP_ABS_IF_TRUE
|
||||
&& op->op_opcode != RETURN)
|
||||
gcc_jit_block_end_with_jump (
|
||||
block,
|
||||
loc,
|
||||
next_block);
|
||||
|
||||
} /* end of loop on PC locations. */
|
||||
|
||||
/* We've now finished populating the context. Compile it. */
|
||||
gcc_jit_result *result = gcc_jit_context_compile (state.ctxt);
|
||||
gcc_jit_context_release (state.ctxt);
|
||||
|
||||
return (toyvm_compiled_func)gcc_jit_result_get_code (result,
|
||||
funcname);
|
||||
/* (this leaks "result" and "funcname") */
|
||||
}
|
||||
|
||||
char test[1024];
|
||||
|
||||
#define CHECK_NON_NULL(PTR) \
|
||||
do { \
|
||||
if ((PTR) != NULL) \
|
||||
{ \
|
||||
pass ("%s: %s is non-null", test, #PTR); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
fail ("%s: %s is NULL", test, #PTR); \
|
||||
abort (); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define CHECK_VALUE(ACTUAL, EXPECTED) \
|
||||
do { \
|
||||
if ((ACTUAL) == (EXPECTED)) \
|
||||
{ \
|
||||
pass ("%s: actual: %s == expected: %s", test, #ACTUAL, #EXPECTED); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
fail ("%s: actual: %s != expected: %s", test, #ACTUAL, #EXPECTED); \
|
||||
fprintf (stderr, "incorrect value\n"); \
|
||||
abort (); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static void
|
||||
test_script (const char *scripts_dir, const char *script_name, int input,
|
||||
int expected_result)
|
||||
{
|
||||
char *script_path;
|
||||
toyvm_function *fn;
|
||||
int interpreted_result;
|
||||
toyvm_compiled_func code;
|
||||
int compiled_result;
|
||||
|
||||
snprintf (test, sizeof (test), "toyvm.c: %s", script_name);
|
||||
|
||||
script_path = (char *)malloc (strlen (scripts_dir)
|
||||
+ strlen (script_name) + 1);
|
||||
CHECK_NON_NULL (script_path);
|
||||
sprintf (script_path, "%s%s", scripts_dir, script_name);
|
||||
|
||||
fn = toyvm_function_parse (script_path, script_name);
|
||||
CHECK_NON_NULL (fn);
|
||||
|
||||
interpreted_result = toyvm_function_interpret (fn, input, NULL);
|
||||
CHECK_VALUE (interpreted_result, expected_result);
|
||||
|
||||
code = toyvm_function_compile (fn);
|
||||
CHECK_NON_NULL (code);
|
||||
|
||||
compiled_result = code (input);
|
||||
CHECK_VALUE (compiled_result, expected_result);
|
||||
|
||||
free (script_path);
|
||||
}
|
||||
|
||||
#define PATH_TO_SCRIPTS ("/jit/docs/examples/tut04-toyvm/")
|
||||
|
||||
static void
|
||||
test_suite (void)
|
||||
{
|
||||
const char *srcdir;
|
||||
char *scripts_dir;
|
||||
|
||||
snprintf (test, sizeof (test), "toyvm.c");
|
||||
|
||||
/* We need to locate the test scripts.
|
||||
Rely on "srcdir" being set in the environment. */
|
||||
|
||||
srcdir = getenv ("srcdir");
|
||||
CHECK_NON_NULL (srcdir);
|
||||
|
||||
scripts_dir = (char *)malloc (strlen (srcdir) + strlen(PATH_TO_SCRIPTS)
|
||||
+ 1);
|
||||
CHECK_NON_NULL (scripts_dir);
|
||||
sprintf (scripts_dir, "%s%s", srcdir, PATH_TO_SCRIPTS);
|
||||
|
||||
test_script (scripts_dir, "factorial.toy", 10, 3628800);
|
||||
test_script (scripts_dir, "fibonacci.toy", 10, 55);
|
||||
|
||||
free (scripts_dir);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
const char *filename = NULL;
|
||||
toyvm_function *fn = NULL;
|
||||
|
||||
/* If called with no args, assume we're being run by the test suite. */
|
||||
if (argc < 3)
|
||||
{
|
||||
test_suite ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (argc != 3)
|
||||
{
|
||||
fprintf (stdout,
|
||||
"%s FILENAME INPUT: Parse and run a .toy file\n",
|
||||
argv[0]);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
filename = argv[1];
|
||||
fn = toyvm_function_parse (filename, filename);
|
||||
if (!fn)
|
||||
exit (1);
|
||||
|
||||
if (0)
|
||||
toyvm_function_disassemble (fn, stdout);
|
||||
|
||||
printf ("interpreter result: %d\n",
|
||||
toyvm_function_interpret (fn, atoi (argv[2]), NULL));
|
||||
|
||||
/* JIT-compilation. */
|
||||
toyvm_compiled_func code = toyvm_function_compile (fn);
|
||||
printf ("compiler result: %d\n",
|
||||
code (atoi (argv[2])));
|
||||
|
||||
return 0;
|
||||
}
|
50
gcc/jit/docs/index.rst
Normal file
50
gcc/jit/docs/index.rst
Normal file
@ -0,0 +1,50 @@
|
||||
.. Copyright (C) 2014 Free Software Foundation, Inc.
|
||||
Originally contributed by David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
This is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
libgccjit
|
||||
=========
|
||||
|
||||
Contents:
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
intro/index.rst
|
||||
topics/index.rst
|
||||
internals/index.rst
|
||||
|
||||
This document describes `libgccjit <http://gcc.gnu.org/wiki/JIT>`_, an API
|
||||
for embedding GCC inside programs and libraries.
|
||||
|
||||
Note that libgccjit is currently of "Alpha" quality;
|
||||
the APIs are not yet set in stone, and they shouldn't be used in
|
||||
production yet.
|
||||
|
||||
|
||||
Indices and tables
|
||||
==================
|
||||
|
||||
* :ref:`genindex`
|
||||
* :ref:`modindex`
|
||||
* :ref:`search`
|
||||
|
||||
.. Some notes:
|
||||
|
||||
The Sphinx C domain appears to lack explicit support for enum values,
|
||||
so I've been using :c:macro: for them.
|
||||
|
||||
See http://sphinx-doc.org/domains.html#the-c-domain
|
216
gcc/jit/docs/internals/index.rst
Normal file
216
gcc/jit/docs/internals/index.rst
Normal file
@ -0,0 +1,216 @@
|
||||
.. Copyright (C) 2014 Free Software Foundation, Inc.
|
||||
Originally contributed by David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
This is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
Internals
|
||||
=========
|
||||
|
||||
Working on the JIT library
|
||||
--------------------------
|
||||
Having checked out the source code (to "src"), you can configure and build
|
||||
the JIT library like this:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
mkdir build
|
||||
mkdir install
|
||||
PREFIX=$(pwd)/install
|
||||
cd build
|
||||
../src/configure \
|
||||
--enable-host-shared \
|
||||
--enable-languages=jit \
|
||||
--disable-bootstrap \
|
||||
--enable-checking=release \
|
||||
--prefix=$PREFIX
|
||||
nice make -j4 # altering the "4" to however many cores you have
|
||||
|
||||
This should build a libgccjit.so within jit/build/gcc:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
[build] $ file gcc/libgccjit.so*
|
||||
gcc/libgccjit.so: symbolic link to `libgccjit.so.0'
|
||||
gcc/libgccjit.so.0: symbolic link to `libgccjit.so.0.0.1'
|
||||
gcc/libgccjit.so.0.0.1: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, not stripped
|
||||
|
||||
Here's what those configuration options mean:
|
||||
|
||||
.. option:: --enable-host-shared
|
||||
|
||||
Configuring with this option means that the compiler is built as
|
||||
position-independent code, which incurs a slight performance hit,
|
||||
but it necessary for a shared library.
|
||||
|
||||
.. option:: --enable-languages=jit
|
||||
|
||||
This specifies which frontends to build. The JIT library looks like
|
||||
a frontend to the rest of the code.
|
||||
|
||||
.. option:: --disable-bootstrap
|
||||
|
||||
For hacking on the "jit" subdirectory, performing a full
|
||||
bootstrap can be overkill, since it's unused by a bootstrap. However,
|
||||
when submitting patches, you should remove this option, to ensure that
|
||||
the compiler can still bootstrap itself.
|
||||
|
||||
.. option:: --enable-checking=release
|
||||
|
||||
The compile can perform extensive self-checking as it runs, useful when
|
||||
debugging, but slowing things down.
|
||||
|
||||
For maximum speed, configure with ``--enable-checking=release`` to
|
||||
disable this self-checking.
|
||||
|
||||
Running the test suite
|
||||
----------------------
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
[build] $ cd gcc
|
||||
[gcc] $ make check-jit RUNTESTFLAGS="-v -v -v"
|
||||
|
||||
A summary of the tests can then be seen in:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
jit/build/gcc/testsuite/jit/jit.sum
|
||||
|
||||
and detailed logs in:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
jit/build/gcc/testsuite/jit/jit.log
|
||||
|
||||
The test executables can be seen as:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
jit/build/gcc/testsuite/jit/*.exe
|
||||
|
||||
which can be run independently.
|
||||
|
||||
You can compile and run individual tests by passing "jit.exp=TESTNAME" to RUNTESTFLAGS e.g.:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
[gcc] $ make check-jit RUNTESTFLAGS="-v -v -v jit.exp=test-factorial.c"
|
||||
|
||||
and once a test has been compiled, you can debug it directly:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
[gcc] $ PATH=.:$PATH \
|
||||
LD_LIBRARY_PATH=. \
|
||||
LIBRARY_PATH=. \
|
||||
gdb --args \
|
||||
testsuite/jit/test-factorial.exe
|
||||
|
||||
Environment variables
|
||||
---------------------
|
||||
When running client code against a locally-built libgccjit, three
|
||||
environment variables need to be set up:
|
||||
|
||||
.. envvar:: LD_LIBRARY_PATH
|
||||
|
||||
`libgccjit.so` is dynamically linked into client code, so if running
|
||||
against a locally-built library, ``LD_LIBRARY_PATH`` needs to be set
|
||||
up appropriately. The library can be found within the "gcc"
|
||||
subdirectory of the build tree:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ file libgccjit.so*
|
||||
libgccjit.so: symbolic link to `libgccjit.so.0'
|
||||
libgccjit.so.0: symbolic link to `libgccjit.so.0.0.1'
|
||||
libgccjit.so.0.0.1: ELF 64-bit LSB shared object, x86-64, version 1 (GNU/Linux), dynamically linked, not stripped
|
||||
|
||||
.. envvar:: PATH
|
||||
|
||||
The library uses a driver executable for converting from .s assembler
|
||||
files to .so shared libraries. Specifically, it looks for a name
|
||||
expanded from
|
||||
``${target_noncanonical}-gcc-${gcc_BASEVER}${exeext}``
|
||||
such as ``x86_64-unknown-linux-gnu-gcc-5.0.0``.
|
||||
|
||||
Hence ``PATH`` needs to include a directory where the library can
|
||||
locate this executable.
|
||||
|
||||
The executable is normally installed to the installation bindir
|
||||
(e.g. /usr/bin), but a copy is also created within the "gcc"
|
||||
subdirectory of the build tree for running the testsuite, and for ease
|
||||
of development.
|
||||
|
||||
.. envvar:: LIBRARY_PATH
|
||||
|
||||
The driver executable invokes the linker, and the latter needs to locate
|
||||
support libraries needed by the generated code, or you will see errors
|
||||
like:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
ld: cannot find crtbeginS.o: No such file or directory
|
||||
ld: cannot find -lgcc
|
||||
ld: cannot find -lgcc_s
|
||||
|
||||
Hence if running directly from a locally-built copy (without installing),
|
||||
``LIBRARY_PATH`` needs to contain the "gcc" subdirectory of the build
|
||||
tree.
|
||||
|
||||
For example, to run a binary that uses the library against a non-installed
|
||||
build of the library in LIBGCCJIT_BUILD_DIR you need an invocation of the
|
||||
client code like this, to preprend the dir to each of the environment
|
||||
variables:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ LD_LIBRARY_PATH=$(LIBGCCJIT_BUILD_DIR):$(LD_LIBRARY_PATH) \
|
||||
PATH=$(LIBGCCJIT_BUILD_DIR):$(PATH) \
|
||||
LIBRARY_PATH=$(LIBGCCJIT_BUILD_DIR):$(LIBRARY_PATH) \
|
||||
./jit-hello-world
|
||||
hello world
|
||||
|
||||
Overview of code structure
|
||||
--------------------------
|
||||
|
||||
* ``libgccjit.c`` implements the API entrypoints. It performs error
|
||||
checking, then calls into classes of the gcc::jit::recording namespace
|
||||
within ``jit-recording.c`` and ``jit-recording.h``.
|
||||
|
||||
* The gcc::jit::recording classes (within ``jit-recording.c`` and
|
||||
``jit-recording.h``) record the API calls that are made:
|
||||
|
||||
.. literalinclude:: ../../jit-common.h
|
||||
:start-after: /* Recording types. */
|
||||
:end-before: /* End of recording types. */
|
||||
:language: c++
|
||||
|
||||
* When the context is compiled, the gcc::jit::playback classes (within
|
||||
``jit-playback.c`` and ``jit-playback.h``) replay the API calls
|
||||
within langhook:parse_file:
|
||||
|
||||
.. literalinclude:: ../../jit-common.h
|
||||
:start-after: /* Playback types. */
|
||||
:end-before: /* End of playback types. */
|
||||
:language: c++
|
||||
|
||||
.. literalinclude:: ../../notes.txt
|
||||
:lines: 1-
|
||||
|
||||
Here is a high-level summary from ``jit-common.h``:
|
||||
|
||||
.. include:: ../../jit-common.h
|
||||
:start-after: This comment is included by the docs.
|
||||
:end-before: End of comment for inclusion in the docs. */
|
BIN
gcc/jit/docs/intro/factorial.png
Normal file
BIN
gcc/jit/docs/intro/factorial.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 180 KiB |
27
gcc/jit/docs/intro/index.rst
Normal file
27
gcc/jit/docs/intro/index.rst
Normal file
@ -0,0 +1,27 @@
|
||||
.. Copyright (C) 2014 Free Software Foundation, Inc.
|
||||
Originally contributed by David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
This is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
Tutorial
|
||||
========
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
tutorial01.rst
|
||||
tutorial02.rst
|
||||
tutorial03.rst
|
||||
tutorial04.rst
|
BIN
gcc/jit/docs/intro/sum-of-squares.png
Normal file
BIN
gcc/jit/docs/intro/sum-of-squares.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 22 KiB |
52
gcc/jit/docs/intro/tutorial01.rst
Normal file
52
gcc/jit/docs/intro/tutorial01.rst
Normal file
@ -0,0 +1,52 @@
|
||||
.. Copyright (C) 2014 Free Software Foundation, Inc.
|
||||
Originally contributed by David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
This is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
.. default-domain:: c
|
||||
|
||||
Tutorial part 1: "Hello world"
|
||||
==============================
|
||||
|
||||
Before we look at the details of the API, let's look at building and
|
||||
running programs that use the library.
|
||||
|
||||
Here's a toy "hello world" program that uses the library to synthesize
|
||||
a call to `printf` and uses it to write a message to stdout.
|
||||
|
||||
Don't worry about the content of the program for now; we'll cover
|
||||
the details in later parts of this tutorial.
|
||||
|
||||
.. literalinclude:: ../examples/tut01-hello-world.c
|
||||
:language: c
|
||||
|
||||
Copy the above to `tut01-hello-world.c`.
|
||||
|
||||
Assuming you have the jit library installed, build the test program
|
||||
using:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ gcc \
|
||||
tut01-hello-world.c \
|
||||
-o tut01-hello-world \
|
||||
-lgccjit
|
||||
|
||||
You should then be able to run the built program:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ ./tut01-hello-world
|
||||
hello world
|
349
gcc/jit/docs/intro/tutorial02.rst
Normal file
349
gcc/jit/docs/intro/tutorial02.rst
Normal file
@ -0,0 +1,349 @@
|
||||
.. Copyright (C) 2014 Free Software Foundation, Inc.
|
||||
Originally contributed by David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
This is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
.. default-domain:: c
|
||||
|
||||
Tutorial part 2: Creating a trivial machine code function
|
||||
---------------------------------------------------------
|
||||
|
||||
Consider this C function:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
int square (int i)
|
||||
{
|
||||
return i * i;
|
||||
}
|
||||
|
||||
How can we construct this at run-time using libgccjit?
|
||||
|
||||
First we need to include the relevant header:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#include <libgccjit.h>
|
||||
|
||||
All state associated with compilation is associated with a
|
||||
:c:type:`gcc_jit_context *`.
|
||||
|
||||
Create one using :c:func:`gcc_jit_context_acquire`:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
gcc_jit_context *ctxt;
|
||||
ctxt = gcc_jit_context_acquire ();
|
||||
|
||||
The JIT library has a system of types. It is statically-typed: every
|
||||
expression is of a specific type, fixed at compile-time. In our example,
|
||||
all of the expressions are of the C `int` type, so let's obtain this from
|
||||
the context, as a :c:type:`gcc_jit_type *`, using
|
||||
:c:func:`gcc_jit_context_get_type`:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
gcc_jit_type *int_type =
|
||||
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
|
||||
|
||||
:c:type:`gcc_jit_type *` is an example of a "contextual" object: every
|
||||
entity in the API is associated with a :c:type:`gcc_jit_context *`.
|
||||
|
||||
Memory management is easy: all such "contextual" objects are automatically
|
||||
cleaned up for you when the context is released, using
|
||||
:c:func:`gcc_jit_context_release`:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
gcc_jit_context_release (ctxt);
|
||||
|
||||
so you don't need to manually track and cleanup all objects, just the
|
||||
contexts.
|
||||
|
||||
Although the API is C-based, there is a form of class hierarchy, which
|
||||
looks like this::
|
||||
|
||||
+- gcc_jit_object
|
||||
+- gcc_jit_location
|
||||
+- gcc_jit_type
|
||||
+- gcc_jit_struct
|
||||
+- gcc_jit_field
|
||||
+- gcc_jit_function
|
||||
+- gcc_jit_block
|
||||
+- gcc_jit_rvalue
|
||||
+- gcc_jit_lvalue
|
||||
+- gcc_jit_param
|
||||
|
||||
There are casting methods for upcasting from subclasses to parent classes.
|
||||
For example, :c:func:`gcc_jit_type_as_object`:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
gcc_jit_object *obj = gcc_jit_type_as_object (int_type);
|
||||
|
||||
One thing you can do with a :c:type:`gcc_jit_object *` is
|
||||
to ask it for a human-readable description, using
|
||||
:c:func:`gcc_jit_object_get_debug_string`:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
printf ("obj: %s\n", gcc_jit_object_get_debug_string (obj));
|
||||
|
||||
giving this text on stdout:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
obj: int
|
||||
|
||||
This is invaluable when debugging.
|
||||
|
||||
Let's create the function. To do so, we first need to construct
|
||||
its single parameter, specifying its type and giving it a name,
|
||||
using :c:func:`gcc_jit_context_new_param`:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
gcc_jit_param *param_i =
|
||||
gcc_jit_context_new_param (ctxt, NULL, int_type, "i");
|
||||
|
||||
Now we can create the function, using
|
||||
:c:func:`gcc_jit_context_new_function`:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
gcc_jit_function *func =
|
||||
gcc_jit_context_new_function (ctxt, NULL,
|
||||
GCC_JIT_FUNCTION_EXPORTED,
|
||||
int_type,
|
||||
"square",
|
||||
1, ¶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
|
378
gcc/jit/docs/intro/tutorial03.rst
Normal file
378
gcc/jit/docs/intro/tutorial03.rst
Normal file
@ -0,0 +1,378 @@
|
||||
.. Copyright (C) 2014 Free Software Foundation, Inc.
|
||||
Originally contributed by David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
This is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
Tutorial part 3: Loops and variables
|
||||
------------------------------------
|
||||
Consider this C function:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
int loop_test (int n)
|
||||
{
|
||||
int sum = 0;
|
||||
for (int i = 0; i < n; i++)
|
||||
sum += i * i;
|
||||
return sum;
|
||||
}
|
||||
|
||||
This example demonstrates some more features of libgccjit, with local
|
||||
variables and a loop.
|
||||
|
||||
To break this down into libgccjit terms, it's usually easier to reword
|
||||
the `for` loop as a `while` loop, giving:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
int loop_test (int n)
|
||||
{
|
||||
int sum = 0;
|
||||
int i = 0;
|
||||
while (i < n)
|
||||
{
|
||||
sum += i * i;
|
||||
i++;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
Here's what the final control flow graph will look like:
|
||||
|
||||
.. figure:: sum-of-squares.png
|
||||
:alt: image of a control flow graph
|
||||
|
||||
As before, we include the libgccjit header and make a
|
||||
:c:type:`gcc_jit_context *`.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#include <libgccjit.h>
|
||||
|
||||
void test (void)
|
||||
{
|
||||
gcc_jit_context *ctxt;
|
||||
ctxt = gcc_jit_context_acquire ();
|
||||
|
||||
The function works with the C `int` type:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
gcc_jit_type *the_type =
|
||||
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
|
||||
gcc_jit_type *return_type = the_type;
|
||||
|
||||
though we could equally well make it work on, say, `double`:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
gcc_jit_type *the_type =
|
||||
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_DOUBLE);
|
||||
|
||||
Let's build the function:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
gcc_jit_param *n =
|
||||
gcc_jit_context_new_param (ctxt, NULL, the_type, "n");
|
||||
gcc_jit_param *params[1] = {n};
|
||||
gcc_jit_function *func =
|
||||
gcc_jit_context_new_function (ctxt, NULL,
|
||||
GCC_JIT_FUNCTION_EXPORTED,
|
||||
return_type,
|
||||
"loop_test",
|
||||
1, params, 0);
|
||||
|
||||
Expressions: lvalues and rvalues
|
||||
********************************
|
||||
|
||||
The base class of expression is the :c:type:`gcc_jit_rvalue *`,
|
||||
representing an expression that can be on the *right*-hand side of
|
||||
an assignment: a value that can be computed somehow, and assigned
|
||||
*to* a storage area (such as a variable). It has a specific
|
||||
:c:type:`gcc_jit_type *`.
|
||||
|
||||
Anothe important class is :c:type:`gcc_jit_lvalue *`.
|
||||
A :c:type:`gcc_jit_lvalue *`. is something that can of the *left*-hand
|
||||
side of an assignment: a storage area (such as a variable).
|
||||
|
||||
In other words, every assignment can be thought of as:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
LVALUE = RVALUE;
|
||||
|
||||
Note that :c:type:`gcc_jit_lvalue *` is a subclass of
|
||||
:c:type:`gcc_jit_rvalue *`, where in an assignment of the form:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
LVALUE_A = LVALUE_B;
|
||||
|
||||
the `LVALUE_B` implies reading the current value of that storage
|
||||
area, assigning it into the `LVALUE_A`.
|
||||
|
||||
So far the only expressions we've seen are `i * i`:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
gcc_jit_rvalue *expr =
|
||||
gcc_jit_context_new_binary_op (
|
||||
ctxt, NULL,
|
||||
GCC_JIT_BINARY_OP_MULT, int_type,
|
||||
gcc_jit_param_as_rvalue (param_i),
|
||||
gcc_jit_param_as_rvalue (param_i));
|
||||
|
||||
which is a :c:type:`gcc_jit_rvalue *`, and the various function
|
||||
parameters: `param_i` and `param_n`, instances of
|
||||
:c:type:`gcc_jit_param *`, which is a subclass of
|
||||
:c:type:`gcc_jit_lvalue *` (and, in turn, of :c:type:`gcc_jit_rvalue *`):
|
||||
we can both read from and write to function parameters within the
|
||||
body of a function.
|
||||
|
||||
Our new example has a couple of local variables. We create them by
|
||||
calling :c:func:`gcc_jit_function_new_local`, supplying a type and a
|
||||
name:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
/* Build locals: */
|
||||
gcc_jit_lvalue *i =
|
||||
gcc_jit_function_new_local (func, NULL, the_type, "i");
|
||||
gcc_jit_lvalue *sum =
|
||||
gcc_jit_function_new_local (func, NULL, the_type, "sum");
|
||||
|
||||
These are instances of :c:type:`gcc_jit_lvalue *` - they can be read from
|
||||
and written to.
|
||||
|
||||
Note that there is no precanned way to create *and* initialize a variable
|
||||
like in C:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
int i = 0;
|
||||
|
||||
Instead, having added the local to the function, we have to separately add
|
||||
an assignment of `0` to `local_i` at the beginning of the function.
|
||||
|
||||
Control flow
|
||||
************
|
||||
|
||||
This function has a loop, so we need to build some basic blocks to
|
||||
handle the control flow. In this case, we need 4 blocks:
|
||||
|
||||
1. before the loop (initializing the locals)
|
||||
2. the conditional at the top of the loop (comparing `i < n`)
|
||||
3. the body of the loop
|
||||
4. after the loop terminates (`return sum`)
|
||||
|
||||
so we create these as :c:type:`gcc_jit_block *` instances within the
|
||||
:c:type:`gcc_jit_function *`:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
gcc_jit_block *b_initial =
|
||||
gcc_jit_function_new_block (func, "initial");
|
||||
gcc_jit_block *b_loop_cond =
|
||||
gcc_jit_function_new_block (func, "loop_cond");
|
||||
gcc_jit_block *b_loop_body =
|
||||
gcc_jit_function_new_block (func, "loop_body");
|
||||
gcc_jit_block *b_after_loop =
|
||||
gcc_jit_function_new_block (func, "after_loop");
|
||||
|
||||
We now populate each block with statements.
|
||||
|
||||
The entry block `b_initial` consists of initializations followed by a jump
|
||||
to the conditional. We assign `0` to `i` and to `sum`, using
|
||||
:c:func:`gcc_jit_block_add_assignment` to add
|
||||
an assignment statement, and using :c:func:`gcc_jit_context_zero` to get
|
||||
the constant value `0` for the relevant type for the right-hand side of
|
||||
the assignment:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
/* sum = 0; */
|
||||
gcc_jit_block_add_assignment (
|
||||
b_initial, NULL,
|
||||
sum,
|
||||
gcc_jit_context_zero (ctxt, the_type));
|
||||
|
||||
/* i = 0; */
|
||||
gcc_jit_block_add_assignment (
|
||||
b_initial, NULL,
|
||||
i,
|
||||
gcc_jit_context_zero (ctxt, the_type));
|
||||
|
||||
We can then terminate the entry block by jumping to the conditional:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
gcc_jit_block_end_with_jump (b_initial, NULL, b_loop_cond);
|
||||
|
||||
The conditional block is equivalent to the line `while (i < n)` from our
|
||||
C example. It contains a single statement: a conditional, which jumps to
|
||||
one of two destination blocks depending on a boolean
|
||||
:c:type:`gcc_jit_rvalue *`, in this case the comparison of `i` and `n`.
|
||||
We build the comparison using :c:func:`gcc_jit_context_new_comparison`:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
gcc_jit_rvalue *guard =
|
||||
gcc_jit_context_new_comparison (
|
||||
ctxt, NULL,
|
||||
GCC_JIT_COMPARISON_GE,
|
||||
gcc_jit_lvalue_as_rvalue (i),
|
||||
gcc_jit_param_as_rvalue (n));
|
||||
|
||||
and can then use this to add `b_loop_cond`'s sole statement, via
|
||||
:c:func:`gcc_jit_block_end_with_conditional`:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
gcc_jit_block_end_with_conditional (b_loop_cond, NULL, guard);
|
||||
|
||||
Next, we populate the body of the loop.
|
||||
|
||||
The C statement `sum += i * i;` is an assignment operation, where an
|
||||
lvalue is modified "in-place". We use
|
||||
:c:func:`gcc_jit_block_add_assignment_op` to handle these operations:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
/* sum += i * i */
|
||||
gcc_jit_block_add_assignment_op (
|
||||
b_loop_body, NULL,
|
||||
sum,
|
||||
GCC_JIT_BINARY_OP_PLUS,
|
||||
gcc_jit_context_new_binary_op (
|
||||
ctxt, NULL,
|
||||
GCC_JIT_BINARY_OP_MULT, the_type,
|
||||
gcc_jit_lvalue_as_rvalue (i),
|
||||
gcc_jit_lvalue_as_rvalue (i)));
|
||||
|
||||
The `i++` can be thought of as `i += 1`, and can thus be handled in
|
||||
a similar way. We use :c:func:`gcc_jit_context_one` to get the constant
|
||||
value `1` (for the relevant type) for the right-hand side
|
||||
of the assignment.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
/* i++ */
|
||||
gcc_jit_block_add_assignment_op (
|
||||
b_loop_body, NULL,
|
||||
i,
|
||||
GCC_JIT_BINARY_OP_PLUS,
|
||||
gcc_jit_context_one (ctxt, the_type));
|
||||
|
||||
.. note::
|
||||
|
||||
For numeric constants other than 0 or 1, we could use
|
||||
:c:func:`gcc_jit_context_new_rvalue_from_int` and
|
||||
:c:func:`gcc_jit_context_new_rvalue_from_double`.
|
||||
|
||||
The loop body completes by jumping back to the conditional:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
gcc_jit_block_end_with_jump (b_loop_body, NULL, b_loop_cond);
|
||||
|
||||
Finally, we populate the `b_after_loop` block, reached when the loop
|
||||
conditional is false. We want to generate the equivalent of:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
return sum;
|
||||
|
||||
so the block is just one statement:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
/* return sum */
|
||||
gcc_jit_block_end_with_return (
|
||||
b_after_loop,
|
||||
NULL,
|
||||
gcc_jit_lvalue_as_rvalue (sum));
|
||||
|
||||
.. note::
|
||||
|
||||
You can intermingle block creation with statement creation,
|
||||
but given that the terminator statements generally include references
|
||||
to other blocks, I find it's clearer to create all the blocks,
|
||||
*then* all the statements.
|
||||
|
||||
We've finished populating the function. As before, we can now compile it
|
||||
to machine code:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
gcc_jit_result *result;
|
||||
result = gcc_jit_context_compile (ctxt);
|
||||
|
||||
typedef int (*loop_test_fn_type) (int);
|
||||
loop_test_fn_type loop_test =
|
||||
(loop_test_fn_type)gcc_jit_result_get_code (result, "loop_test");
|
||||
if (!loop_test)
|
||||
goto error;
|
||||
printf ("result: %d", loop_test (10));
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
result: 285
|
||||
|
||||
|
||||
Visualizing the control flow graph
|
||||
**********************************
|
||||
|
||||
You can see the control flow graph of a function using
|
||||
:c:func:`gcc_jit_function_dump_to_dot`:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
gcc_jit_function_dump_to_dot (func, "/tmp/sum-of-squares.dot");
|
||||
|
||||
giving a .dot file in GraphViz format.
|
||||
|
||||
You can convert this to an image using `dot`:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ dot -Tpng /tmp/sum-of-squares.dot -o /tmp/sum-of-squares.png
|
||||
|
||||
or use a viewer (my preferred one is xdot.py; see
|
||||
https://github.com/jrfonseca/xdot.py; on Fedora you can
|
||||
install it with `yum install python-xdot`):
|
||||
|
||||
.. figure:: sum-of-squares.png
|
||||
:alt: image of a control flow graph
|
||||
|
||||
Full example
|
||||
************
|
||||
|
||||
.. literalinclude:: ../examples/tut03-sum-of-squares.c
|
||||
:lines: 1-
|
||||
:language: c
|
||||
|
||||
Building and running it:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ gcc \
|
||||
tut03-sum-of-squares.c \
|
||||
-o tut03-sum-of-squares \
|
||||
-lgccjit
|
||||
|
||||
# Run the built program:
|
||||
$ ./tut03-sum-of-squares
|
||||
loop_test returned: 285
|
1108
gcc/jit/docs/intro/tutorial04.rst
Normal file
1108
gcc/jit/docs/intro/tutorial04.rst
Normal file
File diff suppressed because it is too large
Load Diff
315
gcc/jit/docs/topics/contexts.rst
Normal file
315
gcc/jit/docs/topics/contexts.rst
Normal file
@ -0,0 +1,315 @@
|
||||
.. Copyright (C) 2014 Free Software Foundation, Inc.
|
||||
Originally contributed by David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
This is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
.. default-domain:: c
|
||||
|
||||
Compilation contexts
|
||||
====================
|
||||
|
||||
.. type:: gcc_jit_context
|
||||
|
||||
The top-level of the API is the :c:type:`gcc_jit_context` type.
|
||||
|
||||
A :c:type:`gcc_jit_context` instance encapsulates the state of a
|
||||
compilation.
|
||||
|
||||
You can set up options on it, and add types, functions and code.
|
||||
Invoking :c:func:`gcc_jit_context_compile` on it gives you a
|
||||
:c:type:`gcc_jit_result`.
|
||||
|
||||
Lifetime-management
|
||||
-------------------
|
||||
Contexts are the unit of lifetime-management within the API: objects
|
||||
have their lifetime bounded by the context they are created within, and
|
||||
cleanup of such objects is done for you when the context is released.
|
||||
|
||||
.. function:: gcc_jit_context *gcc_jit_context_acquire (void)
|
||||
|
||||
This function acquires a new :c:type:`gcc_jit_object *` instance,
|
||||
which is independent of any others that may be present within this
|
||||
process.
|
||||
|
||||
.. function:: void gcc_jit_context_release (gcc_jit_context *ctxt)
|
||||
|
||||
This function releases all resources associated with the given context.
|
||||
Both the context itself and all of its :c:type:`gcc_jit_object *`
|
||||
instances are cleaned up. It should be called exactly once on a given
|
||||
context.
|
||||
|
||||
It is invalid to use the context or any of its "contextual" objects
|
||||
after calling this.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
gcc_jit_context_release (ctxt);
|
||||
|
||||
.. function:: gcc_jit_context * gcc_jit_context_new_child_context (gcc_jit_context *parent_ctxt)
|
||||
|
||||
Given an existing JIT context, create a child context.
|
||||
|
||||
The child inherits a copy of all option-settings from the parent.
|
||||
|
||||
The child can reference objects created within the parent, but not
|
||||
vice-versa.
|
||||
|
||||
The lifetime of the child context must be bounded by that of the
|
||||
parent: you should release a child context before releasing the parent
|
||||
context.
|
||||
|
||||
If you use a function from a parent context within a child context,
|
||||
you have to compile the parent context before you can compile the
|
||||
child context, and the gcc_jit_result of the parent context must
|
||||
outlive the gcc_jit_result of the child context.
|
||||
|
||||
This allows caching of shared initializations. For example, you could
|
||||
create types and declarations of global functions in a parent context
|
||||
once within a process, and then create child contexts whenever a
|
||||
function or loop becomes hot. Each such child context can be used for
|
||||
JIT-compiling just one function or loop, but can reference types
|
||||
and helper functions created within the parent context.
|
||||
|
||||
Contexts can be arbitrarily nested, provided the above rules are
|
||||
followed, but it's probably not worth going above 2 or 3 levels, and
|
||||
there will likely be a performance hit for such nesting.
|
||||
|
||||
|
||||
Thread-safety
|
||||
-------------
|
||||
Instances of :c:type:`gcc_jit_object *` created via
|
||||
:c:func:`gcc_jit_context_acquire` are independent from each other:
|
||||
only one thread may use a given context at once, but multiple threads
|
||||
could each have their own contexts without needing locks.
|
||||
|
||||
Contexts created via :c:func:`gcc_jit_context_new_child_context` are
|
||||
related to their parent context. They can be partitioned by their
|
||||
ultimate ancestor into independent "family trees". Only one thread
|
||||
within a process may use a given "family tree" of such contexts at once,
|
||||
and if you're using multiple threads you should provide your own locking
|
||||
around entire such context partitions.
|
||||
|
||||
|
||||
Error-handling
|
||||
--------------
|
||||
You can only compile and get code from a context if no errors occur.
|
||||
|
||||
In general, if an error occurs when using an API entrypoint, it returns
|
||||
NULL. You don't have to check everywhere for NULL results, since the
|
||||
API gracefully handles a NULL being passed in for any argument.
|
||||
|
||||
Errors are printed on stderr and can be queried using
|
||||
:c:func:`gcc_jit_context_get_first_error`.
|
||||
|
||||
.. function:: const char *\
|
||||
gcc_jit_context_get_first_error (gcc_jit_context *ctxt)
|
||||
|
||||
Returns the first error message that occurred on the context.
|
||||
|
||||
The returned string is valid for the rest of the lifetime of the
|
||||
context.
|
||||
|
||||
If no errors occurred, this will be NULL.
|
||||
|
||||
Debugging
|
||||
---------
|
||||
|
||||
.. function:: void\
|
||||
gcc_jit_context_dump_to_file (gcc_jit_context *ctxt,\
|
||||
const char *path,\
|
||||
int update_locations)
|
||||
|
||||
To help with debugging: dump a C-like representation to the given path,
|
||||
describing what's been set up on the context.
|
||||
|
||||
If "update_locations" is true, then also set up :type:`gcc_jit_location`
|
||||
information throughout the context, pointing at the dump file as if it
|
||||
were a source file. This may be of use in conjunction with
|
||||
:macro:`GCC_JIT_BOOL_OPTION_DEBUGINFO` to allow stepping through the
|
||||
code in a debugger.
|
||||
|
||||
|
||||
Options
|
||||
-------
|
||||
|
||||
String Options
|
||||
**************
|
||||
|
||||
.. function:: void gcc_jit_context_set_str_option(gcc_jit_context *ctxt, \
|
||||
enum gcc_jit_str_option opt, \
|
||||
const char *value)
|
||||
|
||||
Set a string option of the context.
|
||||
|
||||
.. type:: enum gcc_jit_str_option
|
||||
|
||||
There is currently just one string option:
|
||||
|
||||
.. macro:: GCC_JIT_STR_OPTION_PROGNAME
|
||||
|
||||
The name of the program, for use as a prefix when printing error
|
||||
messages to stderr. If `NULL`, or default, "libgccjit.so" is used.
|
||||
|
||||
Boolean options
|
||||
***************
|
||||
|
||||
.. function:: void gcc_jit_context_set_bool_option(gcc_jit_context *ctxt, \
|
||||
enum gcc_jit_bool_option opt, \
|
||||
int value)
|
||||
|
||||
Set a boolean option of the context.
|
||||
Zero is "false" (the default), non-zero is "true".
|
||||
|
||||
.. type:: enum gcc_jit_bool_option
|
||||
|
||||
.. macro:: GCC_JIT_BOOL_OPTION_DEBUGINFO
|
||||
|
||||
If true, :func:`gcc_jit_context_compile` will attempt to do the right
|
||||
thing so that if you attach a debugger to the process, it will
|
||||
be able to inspect variables and step through your code.
|
||||
|
||||
Note that you can't step through code unless you set up source
|
||||
location information for the code (by creating and passing in
|
||||
:type:`gcc_jit_location` instances).
|
||||
|
||||
.. macro:: GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE
|
||||
|
||||
If true, :func:`gcc_jit_context_compile` will dump its initial
|
||||
"tree" representation of your code to stderr (before any
|
||||
optimizations).
|
||||
|
||||
Here's some sample output (from the `square` example)::
|
||||
|
||||
<statement_list 0x7f4875a62cc0
|
||||
type <void_type 0x7f4875a64bd0 VOID
|
||||
align 8 symtab 0 alias set -1 canonical type 0x7f4875a64bd0
|
||||
pointer_to_this <pointer_type 0x7f4875a64c78>>
|
||||
side-effects head 0x7f4875a761e0 tail 0x7f4875a761f8 stmts 0x7f4875a62d20 0x7f4875a62d00
|
||||
|
||||
stmt <label_expr 0x7f4875a62d20 type <void_type 0x7f4875a64bd0>
|
||||
side-effects
|
||||
arg 0 <label_decl 0x7f4875a79080 entry type <void_type 0x7f4875a64bd0>
|
||||
VOID file (null) line 0 col 0
|
||||
align 1 context <function_decl 0x7f4875a77500 square>>>
|
||||
stmt <return_expr 0x7f4875a62d00
|
||||
type <integer_type 0x7f4875a645e8 public SI
|
||||
size <integer_cst 0x7f4875a623a0 constant 32>
|
||||
unit size <integer_cst 0x7f4875a623c0 constant 4>
|
||||
align 32 symtab 0 alias set -1 canonical type 0x7f4875a645e8 precision 32 min <integer_cst 0x7f4875a62340 -2147483648> max <integer_cst 0x7f4875a62360 2147483647>
|
||||
pointer_to_this <pointer_type 0x7f4875a6b348>>
|
||||
side-effects
|
||||
arg 0 <modify_expr 0x7f4875a72a78 type <integer_type 0x7f4875a645e8>
|
||||
side-effects arg 0 <result_decl 0x7f4875a7a000 D.54>
|
||||
arg 1 <mult_expr 0x7f4875a72a50 type <integer_type 0x7f4875a645e8>
|
||||
arg 0 <parm_decl 0x7f4875a79000 i> arg 1 <parm_decl 0x7f4875a79000 i>>>>>
|
||||
|
||||
.. macro:: GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE
|
||||
|
||||
If true, :func:`gcc_jit_context_compile` will dump the "gimple"
|
||||
representation of your code to stderr, before any optimizations
|
||||
are performed. The dump resembles C code:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
square (signed int i)
|
||||
{
|
||||
signed int D.56;
|
||||
|
||||
entry:
|
||||
D.56 = i * i;
|
||||
return D.56;
|
||||
}
|
||||
|
||||
.. macro:: GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE
|
||||
|
||||
If true, :func:`gcc_jit_context_compile` will dump the final
|
||||
generated code to stderr, in the form of assembly language:
|
||||
|
||||
.. code-block:: gas
|
||||
|
||||
.file "fake.c"
|
||||
.text
|
||||
.globl square
|
||||
.type square, @function
|
||||
square:
|
||||
.LFB0:
|
||||
.cfi_startproc
|
||||
pushq %rbp
|
||||
.cfi_def_cfa_offset 16
|
||||
.cfi_offset 6, -16
|
||||
movq %rsp, %rbp
|
||||
.cfi_def_cfa_register 6
|
||||
movl %edi, -4(%rbp)
|
||||
.L2:
|
||||
movl -4(%rbp), %eax
|
||||
imull -4(%rbp), %eax
|
||||
popq %rbp
|
||||
.cfi_def_cfa 7, 8
|
||||
ret
|
||||
.cfi_endproc
|
||||
.LFE0:
|
||||
.size square, .-square
|
||||
.ident "GCC: (GNU) 4.9.0 20131023 (Red Hat 0.1-%{gcc_release})"
|
||||
.section .note.GNU-stack,"",@progbits
|
||||
|
||||
|
||||
.. macro:: GCC_JIT_BOOL_OPTION_DUMP_SUMMARY
|
||||
|
||||
If true, :func:`gcc_jit_context_compile` will print information to stderr
|
||||
on the actions it is performing, followed by a profile showing
|
||||
the time taken and memory usage of each phase.
|
||||
|
||||
.. macro:: GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING
|
||||
|
||||
If true, :func:`gcc_jit_context_compile` will dump copious
|
||||
amount of information on what it's doing to various
|
||||
files within a temporary directory. Use
|
||||
:macro:`GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES` (see below) to
|
||||
see the results. The files are intended to be human-readable,
|
||||
but the exact files and their formats are subject to change.
|
||||
|
||||
.. macro:: GCC_JIT_BOOL_OPTION_SELFCHECK_GC
|
||||
|
||||
If true, libgccjit will aggressively run its garbage collector, to
|
||||
shake out bugs (greatly slowing down the compile). This is likely
|
||||
to only be of interest to developers *of* the library. It is
|
||||
used when running the selftest suite.
|
||||
|
||||
.. macro:: GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES
|
||||
|
||||
If true, the :type:`gcc_jit_context` will not clean up intermediate files
|
||||
written to the filesystem, and will display their location on stderr.
|
||||
|
||||
Integer options
|
||||
***************
|
||||
|
||||
.. function:: void gcc_jit_context_set_int_option (gcc_jit_context *ctxt, \
|
||||
enum gcc_jit_int_option opt, \
|
||||
int value)
|
||||
|
||||
Set an integer option of the context.
|
||||
|
||||
.. type:: enum gcc_jit_int_option
|
||||
|
||||
There is currently just one integer option:
|
||||
|
||||
.. macro:: GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL
|
||||
|
||||
How much to optimize the code.
|
||||
|
||||
Valid values are 0-3, corresponding to GCC's command-line options
|
||||
-O0 through -O3.
|
||||
|
||||
The default value is 0 (unoptimized).
|
525
gcc/jit/docs/topics/expressions.rst
Normal file
525
gcc/jit/docs/topics/expressions.rst
Normal file
@ -0,0 +1,525 @@
|
||||
.. Copyright (C) 2014 Free Software Foundation, Inc.
|
||||
Originally contributed by David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
This is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
.. default-domain:: c
|
||||
|
||||
Expressions
|
||||
===========
|
||||
|
||||
Rvalues
|
||||
-------
|
||||
.. type:: gcc_jit_rvalue
|
||||
|
||||
A :c:type:`gcc_jit_rvalue *` is an expression that can be computed.
|
||||
|
||||
It can be simple, e.g.:
|
||||
|
||||
* an integer value e.g. `0` or `42`
|
||||
* a string literal e.g. `"Hello world"`
|
||||
* a variable e.g. `i`. These are also lvalues (see below).
|
||||
|
||||
or compound e.g.:
|
||||
|
||||
* a unary expression e.g. `!cond`
|
||||
* a binary expression e.g. `(a + b)`
|
||||
* a function call e.g. `get_distance (&player_ship, &target)`
|
||||
* etc.
|
||||
|
||||
Every rvalue has an associated type, and the API will check to ensure
|
||||
that types match up correctly (otherwise the context will emit an error).
|
||||
|
||||
.. function:: gcc_jit_type *gcc_jit_rvalue_get_type (gcc_jit_rvalue *rvalue)
|
||||
|
||||
Get the type of this rvalue.
|
||||
|
||||
.. function:: gcc_jit_object *gcc_jit_rvalue_as_object (gcc_jit_rvalue *rvalue)
|
||||
|
||||
Upcast the given rvalue to be an object.
|
||||
|
||||
|
||||
Simple expressions
|
||||
******************
|
||||
|
||||
.. function:: gcc_jit_rvalue *\
|
||||
gcc_jit_context_new_rvalue_from_int (gcc_jit_context *ctxt, \
|
||||
gcc_jit_type *numeric_type, \
|
||||
int value)
|
||||
|
||||
Given a numeric type (integer or floating point), build an rvalue for
|
||||
the given constant value.
|
||||
|
||||
.. function:: gcc_jit_rvalue *gcc_jit_context_zero (gcc_jit_context *ctxt, \
|
||||
gcc_jit_type *numeric_type)
|
||||
|
||||
Given a numeric type (integer or floating point), get the rvalue for
|
||||
zero. Essentially this is just a shortcut for:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
gcc_jit_context_new_rvalue_from_int (ctxt, numeric_type, 0)
|
||||
|
||||
.. function:: gcc_jit_rvalue *gcc_jit_context_one (gcc_jit_context *ctxt, \
|
||||
gcc_jit_type *numeric_type)
|
||||
|
||||
Given a numeric type (integer or floating point), get the rvalue for
|
||||
zero. Essentially this is just a shortcut for:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
gcc_jit_context_new_rvalue_from_int (ctxt, numeric_type, 1)
|
||||
|
||||
.. function:: gcc_jit_rvalue *\
|
||||
gcc_jit_context_new_rvalue_from_double (gcc_jit_context *ctxt, \
|
||||
gcc_jit_type *numeric_type, \
|
||||
double value)
|
||||
|
||||
Given a numeric type (integer or floating point), build an rvalue for
|
||||
the given constant value.
|
||||
|
||||
.. function:: gcc_jit_rvalue *\
|
||||
gcc_jit_context_new_rvalue_from_ptr (gcc_jit_context *ctxt, \
|
||||
gcc_jit_type *pointer_type, \
|
||||
void *value)
|
||||
|
||||
Given a pointer type, build an rvalue for the given address.
|
||||
|
||||
.. function:: gcc_jit_rvalue *gcc_jit_context_null (gcc_jit_context *ctxt, \
|
||||
gcc_jit_type *pointer_type)
|
||||
|
||||
Given a pointer type, build an rvalue for ``NULL``. Essentially this
|
||||
is just a shortcut for:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
gcc_jit_context_new_rvalue_from_ptr (ctxt, pointer_type, NULL)
|
||||
|
||||
.. function:: gcc_jit_rvalue *\
|
||||
gcc_jit_context_new_string_literal (gcc_jit_context *ctxt, \
|
||||
const char *value)
|
||||
|
||||
Generate an rvalue for the given NIL-terminated string, of type
|
||||
:c:data:`GCC_JIT_TYPE_CONST_CHAR_PTR`.
|
||||
|
||||
|
||||
Unary Operations
|
||||
****************
|
||||
|
||||
.. function:: gcc_jit_rvalue * \
|
||||
gcc_jit_context_new_unary_op (gcc_jit_context *ctxt, \
|
||||
gcc_jit_location *loc, \
|
||||
enum gcc_jit_unary_op op, \
|
||||
gcc_jit_type *result_type, \
|
||||
gcc_jit_rvalue *rvalue)
|
||||
|
||||
Build a unary operation out of an input rvalue.
|
||||
|
||||
.. type:: enum gcc_jit_unary_op
|
||||
|
||||
The available unary operations are:
|
||||
|
||||
========================================== ============
|
||||
Unary Operation C equivalent
|
||||
========================================== ============
|
||||
:c:macro:`GCC_JIT_UNARY_OP_MINUS` `-(EXPR)`
|
||||
:c:macro:`GCC_JIT_UNARY_OP_BITWISE_NEGATE` `~(EXPR)`
|
||||
:c:macro:`GCC_JIT_UNARY_OP_LOGICAL_NEGATE` `!(EXPR)`
|
||||
========================================== ============
|
||||
|
||||
.. c:macro:: GCC_JIT_UNARY_OP_MINUS
|
||||
|
||||
Negate an arithmetic value; analogous to:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
-(EXPR)
|
||||
|
||||
in C.
|
||||
|
||||
.. c:macro:: GCC_JIT_UNARY_OP_BITWISE_NEGATE
|
||||
|
||||
Bitwise negation of an integer value (one's complement); analogous
|
||||
to:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
~(EXPR)
|
||||
|
||||
in C.
|
||||
|
||||
.. c:macro:: GCC_JIT_UNARY_OP_LOGICAL_NEGATE
|
||||
|
||||
Logical negation of an arithmetic or pointer value; analogous to:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
!(EXPR)
|
||||
|
||||
in C.
|
||||
|
||||
Binary Operations
|
||||
*****************
|
||||
|
||||
.. function:: gcc_jit_rvalue *gcc_jit_context_new_binary_op (gcc_jit_context *ctxt, \
|
||||
gcc_jit_location *loc, \
|
||||
enum gcc_jit_binary_op op, \
|
||||
gcc_jit_type *result_type, \
|
||||
gcc_jit_rvalue *a, gcc_jit_rvalue *b)
|
||||
|
||||
Build a binary operation out of two constituent rvalues.
|
||||
|
||||
.. type:: enum gcc_jit_binary_op
|
||||
|
||||
The available binary operations are:
|
||||
|
||||
======================================== ============
|
||||
Binary Operation C equivalent
|
||||
======================================== ============
|
||||
:c:macro:`GCC_JIT_BINARY_OP_PLUS` `x + y`
|
||||
:c:macro:`GCC_JIT_BINARY_OP_MINUS` `x - y`
|
||||
:c:macro:`GCC_JIT_BINARY_OP_MULT` `x * y`
|
||||
:c:macro:`GCC_JIT_BINARY_OP_DIVIDE` `x / y`
|
||||
:c:macro:`GCC_JIT_BINARY_OP_MODULO` `x % y`
|
||||
:c:macro:`GCC_JIT_BINARY_OP_BITWISE_AND` `x & y`
|
||||
:c:macro:`GCC_JIT_BINARY_OP_BITWISE_XOR` `x ^ y`
|
||||
:c:macro:`GCC_JIT_BINARY_OP_BITWISE_OR` `x | y`
|
||||
:c:macro:`GCC_JIT_BINARY_OP_LOGICAL_AND` `x && y`
|
||||
:c:macro:`GCC_JIT_BINARY_OP_LOGICAL_OR` `x || y`
|
||||
:c:macro:`GCC_JIT_BINARY_OP_LSHIFT` `x << y`
|
||||
:c:macro:`GCC_JIT_BINARY_OP_RSHIFT` `x >> y`
|
||||
======================================== ============
|
||||
|
||||
.. c:macro:: GCC_JIT_BINARY_OP_PLUS
|
||||
|
||||
Addition of arithmetic values; analogous to:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
(EXPR_A) + (EXPR_B)
|
||||
|
||||
in C.
|
||||
|
||||
For pointer addition, use :c:func:`gcc_jit_context_new_array_access`.
|
||||
|
||||
.. c:macro:: GCC_JIT_BINARY_OP_MINUS`
|
||||
|
||||
Subtraction of arithmetic values; analogous to:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
(EXPR_A) - (EXPR_B)
|
||||
|
||||
in C.
|
||||
|
||||
.. c:macro:: GCC_JIT_BINARY_OP_MULT
|
||||
|
||||
Multiplication of a pair of arithmetic values; analogous to:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
(EXPR_A) * (EXPR_B)
|
||||
|
||||
in C.
|
||||
|
||||
.. c:macro:: GCC_JIT_BINARY_OP_DIVIDE
|
||||
|
||||
Quotient of division of arithmetic values; analogous to:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
(EXPR_A) / (EXPR_B)
|
||||
|
||||
in C.
|
||||
|
||||
The result type affects the kind of division: if the result type is
|
||||
integer-based, then the result is truncated towards zero, whereas
|
||||
a floating-point result type indicates floating-point division.
|
||||
|
||||
.. c:macro:: GCC_JIT_BINARY_OP_MODULO
|
||||
|
||||
Remainder of division of arithmetic values; analogous to:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
(EXPR_A) % (EXPR_B)
|
||||
|
||||
in C.
|
||||
|
||||
.. c:macro:: GCC_JIT_BINARY_OP_BITWISE_AND
|
||||
|
||||
Bitwise AND; analogous to:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
(EXPR_A) & (EXPR_B)
|
||||
|
||||
in C.
|
||||
|
||||
.. c:macro:: GCC_JIT_BINARY_OP_BITWISE_XOR
|
||||
|
||||
Bitwise exclusive OR; analogous to:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
(EXPR_A) ^ (EXPR_B)
|
||||
|
||||
in C.
|
||||
|
||||
.. c:macro:: GCC_JIT_BINARY_OP_BITWISE_OR
|
||||
|
||||
Bitwise inclusive OR; analogous to:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
(EXPR_A) | (EXPR_B)
|
||||
|
||||
in C.
|
||||
|
||||
.. c:macro:: GCC_JIT_BINARY_OP_LOGICAL_AND
|
||||
|
||||
Logical AND; analogous to:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
(EXPR_A) && (EXPR_B)
|
||||
|
||||
in C.
|
||||
|
||||
.. c:macro:: GCC_JIT_BINARY_OP_LOGICAL_OR
|
||||
|
||||
Logical OR; analogous to:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
(EXPR_A) || (EXPR_B)
|
||||
|
||||
in C.
|
||||
|
||||
.. c:macro:: GCC_JIT_BINARY_OP_LSHIFT
|
||||
|
||||
Left shift; analogous to:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
(EXPR_A) << (EXPR_B)
|
||||
|
||||
in C.
|
||||
|
||||
.. c:macro:: GCC_JIT_BINARY_OP_RSHIFT
|
||||
|
||||
Right shift; analogous to:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
(EXPR_A) >> (EXPR_B)
|
||||
|
||||
in C.
|
||||
|
||||
Comparisons
|
||||
***********
|
||||
|
||||
.. function:: gcc_jit_rvalue *\
|
||||
gcc_jit_context_new_comparison (gcc_jit_context *ctxt,\
|
||||
gcc_jit_location *loc,\
|
||||
enum gcc_jit_comparison op,\
|
||||
gcc_jit_rvalue *a, gcc_jit_rvalue *b)
|
||||
|
||||
Build a boolean rvalue out of the comparison of two other rvalues.
|
||||
|
||||
.. type:: enum gcc_jit_comparison
|
||||
|
||||
======================================= ============
|
||||
Comparison C equivalent
|
||||
======================================= ============
|
||||
:c:macro:`GCC_JIT_COMPARISON_EQ` `x == y`
|
||||
:c:macro:`GCC_JIT_COMPARISON_NE` `x != y`
|
||||
:c:macro:`GCC_JIT_COMPARISON_LT` `x < y`
|
||||
:c:macro:`GCC_JIT_COMPARISON_LE` `x <= y`
|
||||
:c:macro:`GCC_JIT_COMPARISON_GT` `x > y`
|
||||
:c:macro:`GCC_JIT_COMPARISON_GE` `x >= y`
|
||||
======================================= ============
|
||||
|
||||
|
||||
Function calls
|
||||
**************
|
||||
.. function:: gcc_jit_rvalue *\
|
||||
gcc_jit_context_new_call (gcc_jit_context *ctxt,\
|
||||
gcc_jit_location *loc,\
|
||||
gcc_jit_function *func,\
|
||||
int numargs , gcc_jit_rvalue **args)
|
||||
|
||||
Given a function and the given table of argument rvalues, construct a
|
||||
call to the function, with the result as an rvalue.
|
||||
|
||||
.. note::
|
||||
|
||||
:c:func:`gcc_jit_context_new_call` merely builds a
|
||||
:c:type:`gcc_jit_rvalue` i.e. an expression that can be evaluated,
|
||||
perhaps as part of a more complicated expression.
|
||||
The call *won't* happen unless you add a statement to a function
|
||||
that evaluates the expression.
|
||||
|
||||
For example, if you want to call a function and discard the result
|
||||
(or to call a function with ``void`` return type), use
|
||||
:c:func:`gcc_jit_block_add_eval`:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
/* Add "(void)printf (arg0, arg1);". */
|
||||
gcc_jit_block_add_eval (
|
||||
block, NULL,
|
||||
gcc_jit_context_new_call (
|
||||
ctxt,
|
||||
NULL,
|
||||
printf_func,
|
||||
2, args));
|
||||
|
||||
Type-coercion
|
||||
*************
|
||||
|
||||
.. function:: gcc_jit_rvalue *\
|
||||
gcc_jit_context_new_cast (gcc_jit_context *ctxt,\
|
||||
gcc_jit_location *loc,\
|
||||
gcc_jit_rvalue *rvalue,\
|
||||
gcc_jit_type *type)
|
||||
|
||||
Given an rvalue of T, construct another rvalue of another type.
|
||||
|
||||
Currently only a limited set of conversions are possible:
|
||||
|
||||
* int <-> float
|
||||
* int <-> bool
|
||||
* P* <-> Q*, for pointer types P and Q
|
||||
|
||||
Lvalues
|
||||
-------
|
||||
|
||||
.. type:: gcc_jit_lvalue
|
||||
|
||||
An lvalue is something that can of the *left*-hand side of an assignment:
|
||||
a storage area (such as a variable). It is also usable as an rvalue,
|
||||
where the rvalue is computed by reading from the storage area.
|
||||
|
||||
.. function:: gcc_jit_object *\
|
||||
gcc_jit_lvalue_as_object (gcc_jit_lvalue *lvalue)
|
||||
|
||||
Upcast an lvalue to be an object.
|
||||
|
||||
.. function:: gcc_jit_rvalue *\
|
||||
gcc_jit_lvalue_as_rvalue (gcc_jit_lvalue *lvalue)
|
||||
|
||||
Upcast an lvalue to be an rvalue.
|
||||
|
||||
.. function:: gcc_jit_rvalue *\
|
||||
gcc_jit_lvalue_get_address (gcc_jit_lvalue *lvalue,\
|
||||
gcc_jit_location *loc)
|
||||
|
||||
Take the address of an lvalue; analogous to:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
&(EXPR)
|
||||
|
||||
in C.
|
||||
|
||||
Global variables
|
||||
****************
|
||||
|
||||
.. function:: gcc_jit_lvalue *\
|
||||
gcc_jit_context_new_global (gcc_jit_context *ctxt,\
|
||||
gcc_jit_location *loc,\
|
||||
gcc_jit_type *type,\
|
||||
const char *name)
|
||||
|
||||
Add a new global variable of the given type and name to the context.
|
||||
|
||||
|
||||
Working with pointers, structs and unions
|
||||
-----------------------------------------
|
||||
|
||||
.. function:: gcc_jit_lvalue *\
|
||||
gcc_jit_rvalue_dereference (gcc_jit_rvalue *rvalue,\
|
||||
gcc_jit_location *loc)
|
||||
|
||||
Given an rvalue of pointer type ``T *``, dereferencing the pointer,
|
||||
getting an lvalue of type ``T``. Analogous to:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
*(EXPR)
|
||||
|
||||
in C.
|
||||
|
||||
Field access is provided separately for both lvalues and rvalues.
|
||||
|
||||
.. function:: gcc_jit_lvalue *\
|
||||
gcc_jit_lvalue_access_field (gcc_jit_lvalue *struct_,\
|
||||
gcc_jit_location *loc,\
|
||||
gcc_jit_field *field)
|
||||
|
||||
Given an lvalue of struct or union type, access the given field,
|
||||
getting an lvalue of the field's type. Analogous to:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
(EXPR).field = ...;
|
||||
|
||||
in C.
|
||||
|
||||
.. function:: gcc_jit_rvalue *\
|
||||
gcc_jit_rvalue_access_field (gcc_jit_rvalue *struct_,\
|
||||
gcc_jit_location *loc,\
|
||||
gcc_jit_field *field)
|
||||
|
||||
Given an rvalue of struct or union type, access the given field
|
||||
as an rvalue. Analogous to:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
(EXPR).field
|
||||
|
||||
in C.
|
||||
|
||||
.. function:: gcc_jit_lvalue *\
|
||||
gcc_jit_rvalue_dereference_field (gcc_jit_rvalue *ptr,\
|
||||
gcc_jit_location *loc,\
|
||||
gcc_jit_field *field)
|
||||
|
||||
Given an rvalue of pointer type ``T *`` where T is of struct or union
|
||||
type, access the given field as an lvalue. Analogous to:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
(EXPR)->field
|
||||
|
||||
in C, itself equivalent to ``(*EXPR).FIELD``.
|
||||
|
||||
.. function:: gcc_jit_lvalue *\
|
||||
gcc_jit_context_new_array_access (gcc_jit_context *ctxt,\
|
||||
gcc_jit_location *loc,\
|
||||
gcc_jit_rvalue *ptr,\
|
||||
gcc_jit_rvalue *index)
|
||||
|
||||
Given an rvalue of pointer type ``T *``, get at the element `T` at
|
||||
the given index, using standard C array indexing rules i.e. each
|
||||
increment of ``index`` corresponds to ``sizeof(T)`` bytes.
|
||||
Analogous to:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
PTR[INDEX]
|
||||
|
||||
in C (or, indeed, to ``PTR + INDEX``).
|
311
gcc/jit/docs/topics/functions.rst
Normal file
311
gcc/jit/docs/topics/functions.rst
Normal file
@ -0,0 +1,311 @@
|
||||
.. Copyright (C) 2014 Free Software Foundation, Inc.
|
||||
Originally contributed by David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
This is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
.. default-domain:: c
|
||||
|
||||
Creating and using functions
|
||||
============================
|
||||
|
||||
Params
|
||||
------
|
||||
.. type:: gcc_jit_param
|
||||
|
||||
A `gcc_jit_param` represents a parameter to a function.
|
||||
|
||||
.. function:: gcc_jit_param *\
|
||||
gcc_jit_context_new_param (gcc_jit_context *ctxt,\
|
||||
gcc_jit_location *loc,\
|
||||
gcc_jit_type *type,\
|
||||
const char *name)
|
||||
|
||||
In preparation for creating a function, create a new parameter of the
|
||||
given type and name.
|
||||
|
||||
Parameters are lvalues, and thus are also rvalues (and objects), so the
|
||||
following upcasts are available:
|
||||
|
||||
.. function:: gcc_jit_lvalue *\
|
||||
gcc_jit_param_as_lvalue (gcc_jit_param *param)
|
||||
|
||||
Upcasting from param to lvalue.
|
||||
|
||||
.. function:: gcc_jit_rvalue *\
|
||||
gcc_jit_param_as_rvalue (gcc_jit_param *param)
|
||||
|
||||
Upcasting from param to rvalue.
|
||||
|
||||
.. function:: gcc_jit_object *\
|
||||
gcc_jit_param_as_object (gcc_jit_param *param)
|
||||
|
||||
Upcasting from param to object.
|
||||
|
||||
|
||||
Functions
|
||||
---------
|
||||
|
||||
.. type:: gcc_jit_function
|
||||
|
||||
A `gcc_jit_function` represents a function - either one that we're
|
||||
creating ourselves, or one that we're referencing.
|
||||
|
||||
.. function:: gcc_jit_function *\
|
||||
gcc_jit_context_new_function (gcc_jit_context *ctxt,\
|
||||
gcc_jit_location *loc,\
|
||||
enum gcc_jit_function_kind kind,\
|
||||
gcc_jit_type *return_type,\
|
||||
const char *name,\
|
||||
int num_params,\
|
||||
gcc_jit_param **params,\
|
||||
int is_variadic)
|
||||
|
||||
Create a gcc_jit_function with the given name and parameters.
|
||||
|
||||
.. type:: enum gcc_jit_function_kind
|
||||
|
||||
This enum controls the kind of function created, and has the following
|
||||
values:
|
||||
|
||||
.. macro:: GCC_JIT_FUNCTION_EXPORTED
|
||||
|
||||
Function is defined by the client code and visible
|
||||
by name outside of the JIT.
|
||||
|
||||
.. macro:: GCC_JIT_FUNCTION_INTERNAL
|
||||
|
||||
Function is defined by the client code, but is invisible
|
||||
outside of the JIT. Analogous to a "static" function.
|
||||
|
||||
.. macro:: GCC_JIT_FUNCTION_IMPORTED
|
||||
|
||||
Function is not defined by the client code; we're merely
|
||||
referring to it. Analogous to using an "extern" function from a
|
||||
header file.
|
||||
|
||||
.. macro:: GCC_JIT_FUNCTION_ALWAYS_INLINE
|
||||
|
||||
Function is only ever inlined into other functions, and is
|
||||
invisible outside of the JIT.
|
||||
|
||||
Analogous to prefixing with ``inline`` and adding
|
||||
``__attribute__((always_inline))``
|
||||
|
||||
Inlining will only occur when the optimization level is
|
||||
above 0; when optimization is off, this is essentially the
|
||||
same as GCC_JIT_FUNCTION_INTERNAL.
|
||||
|
||||
.. function:: gcc_jit_function *\
|
||||
gcc_jit_context_get_builtin_function (gcc_jit_context *ctxt,\
|
||||
const char *name)
|
||||
|
||||
.. function:: gcc_jit_object *\
|
||||
gcc_jit_function_as_object (gcc_jit_function *func)
|
||||
|
||||
Upcasting from function to object.
|
||||
|
||||
.. function:: gcc_jit_param *\
|
||||
gcc_jit_function_get_param (gcc_jit_function *func, int index)
|
||||
|
||||
Get the param of the given index (0-based).
|
||||
|
||||
.. function:: void \
|
||||
gcc_jit_function_dump_to_dot (gcc_jit_function *func,\
|
||||
const char *path)
|
||||
|
||||
Emit the function in graphviz format to the given path.
|
||||
|
||||
.. function:: gcc_jit_lvalue *\
|
||||
gcc_jit_function_new_local (gcc_jit_function *func,\
|
||||
gcc_jit_location *loc,\
|
||||
gcc_jit_type *type,\
|
||||
const char *name)
|
||||
|
||||
Create a new local variable within the function, of the given type and
|
||||
name.
|
||||
|
||||
|
||||
Blocks
|
||||
------
|
||||
.. type:: gcc_jit_block
|
||||
|
||||
A `gcc_jit_block` represents a basic block within a function i.e. a
|
||||
sequence of statements with a single entry point and a single exit
|
||||
point.
|
||||
|
||||
The first basic block that you create within a function will
|
||||
be the entrypoint.
|
||||
|
||||
Each basic block that you create within a function must be
|
||||
terminated, either with a conditional, a jump, or a return.
|
||||
|
||||
It's legal to have multiple basic blocks that return within
|
||||
one function.
|
||||
|
||||
.. function:: gcc_jit_block *\
|
||||
gcc_jit_function_new_block (gcc_jit_function *func,\
|
||||
const char *name)
|
||||
|
||||
Create a basic block of the given name. The name may be NULL, but
|
||||
providing meaningful names is often helpful when debugging: it may
|
||||
show up in dumps of the internal representation, and in error
|
||||
messages.
|
||||
|
||||
.. function:: gcc_jit_object *\
|
||||
gcc_jit_block_as_object (gcc_jit_block *block)
|
||||
|
||||
Upcast from block to object.
|
||||
|
||||
.. function:: gcc_jit_function *\
|
||||
gcc_jit_block_get_function (gcc_jit_block *block)
|
||||
|
||||
Which function is this block within?
|
||||
|
||||
|
||||
Statements
|
||||
----------
|
||||
|
||||
.. function:: void\
|
||||
gcc_jit_block_add_eval (gcc_jit_block *block,\
|
||||
gcc_jit_location *loc,\
|
||||
gcc_jit_rvalue *rvalue)
|
||||
|
||||
Add evaluation of an rvalue, discarding the result
|
||||
(e.g. a function call that "returns" void).
|
||||
|
||||
This is equivalent to this C code:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
(void)expression;
|
||||
|
||||
.. function:: void\
|
||||
gcc_jit_block_add_assignment (gcc_jit_block *block,\
|
||||
gcc_jit_location *loc,\
|
||||
gcc_jit_lvalue *lvalue,\
|
||||
gcc_jit_rvalue *rvalue)
|
||||
|
||||
Add evaluation of an rvalue, assigning the result to the given
|
||||
lvalue.
|
||||
|
||||
This is roughly equivalent to this C code:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
lvalue = rvalue;
|
||||
|
||||
.. function:: void\
|
||||
gcc_jit_block_add_assignment_op (gcc_jit_block *block,\
|
||||
gcc_jit_location *loc,\
|
||||
gcc_jit_lvalue *lvalue,\
|
||||
enum gcc_jit_binary_op op,\
|
||||
gcc_jit_rvalue *rvalue)
|
||||
|
||||
Add evaluation of an rvalue, using the result to modify an
|
||||
lvalue.
|
||||
|
||||
This is analogous to "+=" and friends:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
lvalue += rvalue;
|
||||
lvalue *= rvalue;
|
||||
lvalue /= rvalue;
|
||||
|
||||
etc. For example:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
/* "i++" */
|
||||
gcc_jit_block_add_assignment_op (
|
||||
loop_body, NULL,
|
||||
i,
|
||||
GCC_JIT_BINARY_OP_PLUS,
|
||||
gcc_jit_context_one (ctxt, int_type));
|
||||
|
||||
.. function:: void\
|
||||
gcc_jit_block_add_comment (gcc_jit_block *block,\
|
||||
gcc_jit_location *loc,\
|
||||
const char *text)
|
||||
|
||||
Add a no-op textual comment to the internal representation of the
|
||||
code. It will be optimized away, but will be visible in the dumps
|
||||
seen via :macro:`GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE`
|
||||
and :macro:`GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE`,
|
||||
and thus may be of use when debugging how your project's internal
|
||||
representation gets converted to the libgccjit IR.
|
||||
|
||||
.. function:: void\
|
||||
gcc_jit_block_end_with_conditional (gcc_jit_block *block,\
|
||||
gcc_jit_location *loc,\
|
||||
gcc_jit_rvalue *boolval,\
|
||||
gcc_jit_block *on_true,\
|
||||
gcc_jit_block *on_false)
|
||||
|
||||
Terminate a block by adding evaluation of an rvalue, branching on the
|
||||
result to the appropriate successor block.
|
||||
|
||||
This is roughly equivalent to this C code:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
if (boolval)
|
||||
goto on_true;
|
||||
else
|
||||
goto on_false;
|
||||
|
||||
block, boolval, on_true, and on_false must be non-NULL.
|
||||
|
||||
.. function:: void\
|
||||
gcc_jit_block_end_with_jump (gcc_jit_block *block,\
|
||||
gcc_jit_location *loc,\
|
||||
gcc_jit_block *target)
|
||||
|
||||
|
||||
Terminate a block by adding a jump to the given target block.
|
||||
|
||||
This is roughly equivalent to this C code:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
goto target;
|
||||
|
||||
.. function:: void\
|
||||
gcc_jit_block_end_with_return (gcc_jit_block *block,\
|
||||
gcc_jit_location *loc,\
|
||||
gcc_jit_rvalue *rvalue)
|
||||
|
||||
|
||||
Terminate a block by adding evaluation of an rvalue, returning the value.
|
||||
|
||||
This is roughly equivalent to this C code:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
return expression;
|
||||
|
||||
.. function:: void\
|
||||
gcc_jit_block_end_with_void_return (gcc_jit_block *block,\
|
||||
gcc_jit_location *loc)
|
||||
|
||||
|
||||
Terminate a block by adding a valueless return, for use within a function
|
||||
with "void" return type.
|
||||
|
||||
This is equivalent to this C code:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
return;
|
30
gcc/jit/docs/topics/index.rst
Normal file
30
gcc/jit/docs/topics/index.rst
Normal file
@ -0,0 +1,30 @@
|
||||
.. Copyright (C) 2014 Free Software Foundation, Inc.
|
||||
Originally contributed by David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
This is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
Topic Reference
|
||||
===============
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
contexts.rst
|
||||
objects.rst
|
||||
types.rst
|
||||
expressions.rst
|
||||
functions.rst
|
||||
locations.rst
|
||||
results.rst
|
69
gcc/jit/docs/topics/locations.rst
Normal file
69
gcc/jit/docs/topics/locations.rst
Normal file
@ -0,0 +1,69 @@
|
||||
.. Copyright (C) 2014 Free Software Foundation, Inc.
|
||||
Originally contributed by David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
This is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
.. default-domain:: c
|
||||
|
||||
Source Locations
|
||||
================
|
||||
|
||||
.. type:: gcc_jit_location
|
||||
|
||||
A `gcc_jit_location` encapsulates a source code location, so that
|
||||
you can (optionally) associate locations in your language with
|
||||
statements in the JIT-compiled code, allowing the debugger to
|
||||
single-step through your language.
|
||||
|
||||
`gcc_jit_location` instances are optional: you can always pass NULL to
|
||||
any API entrypoint accepting one.
|
||||
|
||||
You can construct them using :c:func:`gcc_jit_context_new_location`.
|
||||
|
||||
You need to enable :c:macro:`GCC_JIT_BOOL_OPTION_DEBUGINFO` on the
|
||||
:c:type:`gcc_jit_context` for these locations to actually be usable by
|
||||
the debugger:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
gcc_jit_context_set_bool_option (
|
||||
ctxt,
|
||||
GCC_JIT_BOOL_OPTION_DEBUGINFO,
|
||||
1);
|
||||
|
||||
.. function:: gcc_jit_location *\
|
||||
gcc_jit_context_new_location (gcc_jit_context *ctxt,\
|
||||
const char *filename,\
|
||||
int line,\
|
||||
int column)
|
||||
|
||||
Create a `gcc_jit_location` instance representing the given source
|
||||
location.
|
||||
|
||||
Faking it
|
||||
---------
|
||||
If you don't have source code for your internal representation, but need
|
||||
to debug, you can generate a C-like representation of the functions in
|
||||
your context using :c:func:`gcc_jit_context_dump_to_file()`:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
gcc_jit_context_dump_to_file (ctxt, "/tmp/something.c",
|
||||
1 /* update_locations */);
|
||||
|
||||
This will dump C-like code to the given path. If the `update_locations`
|
||||
argument is true, this will also set up `gcc_jit_location` information
|
||||
throughout the context, pointing at the dump file as if it were a source
|
||||
file, giving you *something* you can step through in the debugger.
|
86
gcc/jit/docs/topics/objects.rst
Normal file
86
gcc/jit/docs/topics/objects.rst
Normal file
@ -0,0 +1,86 @@
|
||||
.. Copyright (C) 2014 Free Software Foundation, Inc.
|
||||
Originally contributed by David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
This is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
.. default-domain:: c
|
||||
|
||||
Objects
|
||||
=======
|
||||
|
||||
.. type:: gcc_jit_object
|
||||
|
||||
Almost every entity in the API (with the exception of
|
||||
:c:type:`gcc_jit_context *` and :c:type:`gcc_jit_result *`) is a
|
||||
"contextual" object, a :c:type:`gcc_jit_object *`
|
||||
|
||||
A JIT object:
|
||||
|
||||
* is associated with a :c:type:`gcc_jit_context *`.
|
||||
|
||||
* is automatically cleaned up for you when its context is released so
|
||||
you don't need to manually track and cleanup all objects, just the
|
||||
contexts.
|
||||
|
||||
Although the API is C-based, there is a form of class hierarchy, which
|
||||
looks like this::
|
||||
|
||||
+- gcc_jit_object
|
||||
+- gcc_jit_location
|
||||
+- gcc_jit_type
|
||||
+- gcc_jit_struct
|
||||
+- gcc_jit_field
|
||||
+- gcc_jit_function
|
||||
+- gcc_jit_block
|
||||
+- gcc_jit_rvalue
|
||||
+- gcc_jit_lvalue
|
||||
+- gcc_jit_param
|
||||
|
||||
There are casting methods for upcasting from subclasses to parent classes.
|
||||
For example, :c:func:`gcc_jit_type_as_object`:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
gcc_jit_object *obj = gcc_jit_type_as_object (int_type);
|
||||
|
||||
The object "base class" has the following operations:
|
||||
|
||||
.. function:: gcc_jit_context *gcc_jit_object_get_context (gcc_jit_object *obj)
|
||||
|
||||
Which context is "obj" within?
|
||||
|
||||
|
||||
.. function:: const char *gcc_jit_object_get_debug_string (gcc_jit_object *obj)
|
||||
|
||||
Generate a human-readable description for the given object.
|
||||
|
||||
For example,
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
printf ("obj: %s\n", gcc_jit_object_get_debug_string (obj));
|
||||
|
||||
might give this text on stdout:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
obj: 4.0 * (float)i
|
||||
|
||||
.. note::
|
||||
|
||||
If you call this on an object, the `const char *` buffer is allocated
|
||||
and generated on the first call for that object, and the buffer will
|
||||
have the same lifetime as the object i.e. it will exist until the
|
||||
object's context is released.
|
48
gcc/jit/docs/topics/results.rst
Normal file
48
gcc/jit/docs/topics/results.rst
Normal file
@ -0,0 +1,48 @@
|
||||
.. Copyright (C) 2014 Free Software Foundation, Inc.
|
||||
Originally contributed by David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
This is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
.. default-domain:: c
|
||||
|
||||
Compilation results
|
||||
===================
|
||||
|
||||
.. type:: gcc_jit_result
|
||||
|
||||
A `gcc_jit_result` encapsulates the result of compiling a context.
|
||||
|
||||
.. function:: gcc_jit_result *\
|
||||
gcc_jit_context_compile (gcc_jit_context *ctxt)
|
||||
|
||||
This calls into GCC and builds the code, returning a
|
||||
`gcc_jit_result *`.
|
||||
|
||||
|
||||
.. function:: void *\
|
||||
gcc_jit_result_get_code (gcc_jit_result *result,\
|
||||
const char *funcname)
|
||||
|
||||
Locate a given function within the built machine code.
|
||||
This will need to be cast to a function pointer of the
|
||||
correct type before it can be called.
|
||||
|
||||
|
||||
.. function:: void\
|
||||
gcc_jit_result_release (gcc_jit_result *result)
|
||||
|
||||
Once we're done with the code, this unloads the built .so file.
|
||||
This cleans up the result; after calling this, it's no longer
|
||||
valid to use the result.
|
217
gcc/jit/docs/topics/types.rst
Normal file
217
gcc/jit/docs/topics/types.rst
Normal file
@ -0,0 +1,217 @@
|
||||
.. Copyright (C) 2014 Free Software Foundation, Inc.
|
||||
Originally contributed by David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
This is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
.. default-domain:: c
|
||||
|
||||
Types
|
||||
=====
|
||||
|
||||
.. c:type:: gcc_jit_type
|
||||
|
||||
gcc_jit_type represents a type within the library.
|
||||
|
||||
.. function:: gcc_jit_object *gcc_jit_type_as_object (gcc_jit_type *type)
|
||||
|
||||
Upcast a type to an object.
|
||||
|
||||
Types can be created in several ways:
|
||||
|
||||
* fundamental types can be accessed using
|
||||
:func:`gcc_jit_context_get_type`:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
gcc_jit_type *int_type = gcc_jit_context_get_type (GCC_JIT_TYPE_INT);
|
||||
|
||||
See :func:`gcc_jit_context_get_type` for the available types.
|
||||
|
||||
* derived types can be accessed by using functions such as
|
||||
:func:`gcc_jit_type_get_pointer` and :func:`gcc_jit_type_get_const`:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
gcc_jit_type *const_int_star = gcc_jit_type_get_pointer (gcc_jit_type_get_const (int_type));
|
||||
gcc_jit_type *int_const_star = gcc_jit_type_get_const (gcc_jit_type_get_pointer (int_type));
|
||||
|
||||
* by creating structures (see below).
|
||||
|
||||
Standard types
|
||||
--------------
|
||||
|
||||
.. function:: gcc_jit_type *gcc_jit_context_get_type (gcc_jit_context *ctxt, \
|
||||
enum gcc_jit_types type_)
|
||||
|
||||
Access a specific type. The available types are:
|
||||
|
||||
========================================= ================================
|
||||
`enum gcc_jit_types` value Meaning
|
||||
========================================= ================================
|
||||
:c:data:`GCC_JIT_TYPE_VOID` C's ``void`` type.
|
||||
:c:data:`GCC_JIT_TYPE_VOID_PTR` C's ``void *``.
|
||||
:c:data:`GCC_JIT_TYPE_BOOL` C++'s ``bool`` type; also C99's
|
||||
``_Bool`` type, aka ``bool`` if
|
||||
using stdbool.h.
|
||||
:c:data:`GCC_JIT_TYPE_CHAR` C's ``char`` (of some signedness)
|
||||
:c:data:`GCC_JIT_TYPE_SIGNED_CHAR` C's ``signed char``
|
||||
:c:data:`GCC_JIT_TYPE_UNSIGNED_CHAR` C's ``unsigned char``
|
||||
:c:data:`GCC_JIT_TYPE_SHORT` C's ``short`` (signed)
|
||||
:c:data:`GCC_JIT_TYPE_UNSIGNED_SHORT` C's ``unsigned short``
|
||||
:c:data:`GCC_JIT_TYPE_INT` C's ``int`` (signed)
|
||||
:c:data:`GCC_JIT_TYPE_UNSIGNED_INT` C's ``unsigned int``
|
||||
:c:data:`GCC_JIT_TYPE_LONG` C's ``long`` (signed)
|
||||
:c:data:`GCC_JIT_TYPE_UNSIGNED_LONG` C's ``unsigned long``
|
||||
:c:data:`GCC_JIT_TYPE_LONG_LONG` C99's ``long long`` (signed)
|
||||
:c:data:`GCC_JIT_TYPE_UNSIGNED_LONG_LONG` C99's ``unsigned long long``
|
||||
:c:data:`GCC_JIT_TYPE_FLOAT`
|
||||
:c:data:`GCC_JIT_TYPE_DOUBLE`
|
||||
:c:data:`GCC_JIT_TYPE_LONG_DOUBLE`
|
||||
:c:data:`GCC_JIT_TYPE_CONST_CHAR_PTR` C type: ``(const char *)``
|
||||
:c:data:`GCC_JIT_TYPE_SIZE_T` C's ``size_t`` type
|
||||
:c:data:`GCC_JIT_TYPE_FILE_PTR` C type: ``(FILE *)``
|
||||
========================================= ================================
|
||||
|
||||
.. function:: gcc_jit_type *\
|
||||
gcc_jit_context_get_int_type (gcc_jit_context *ctxt, \
|
||||
int num_bytes, int is_signed)
|
||||
|
||||
Access the integer type of the given size.
|
||||
|
||||
|
||||
Pointers, `const`, and `volatile`
|
||||
---------------------------------
|
||||
|
||||
.. function:: gcc_jit_type *gcc_jit_type_get_pointer (gcc_jit_type *type)
|
||||
|
||||
Given type "T", get type "T*".
|
||||
|
||||
.. function:: gcc_jit_type *gcc_jit_type_get_const (gcc_jit_type *type)
|
||||
|
||||
Given type "T", get type "const T".
|
||||
|
||||
.. function:: gcc_jit_type *gcc_jit_type_get_volatile (gcc_jit_type *type)
|
||||
|
||||
Given type "T", get type "volatile T".
|
||||
|
||||
.. function:: gcc_jit_type *\
|
||||
gcc_jit_context_new_array_type (gcc_jit_context *ctxt, \
|
||||
gcc_jit_location *loc, \
|
||||
gcc_jit_type *element_type, \
|
||||
int num_elements)
|
||||
|
||||
Given type "T", get type "T[N]" (for a constant N).
|
||||
|
||||
|
||||
Structures and unions
|
||||
---------------------
|
||||
|
||||
.. c:type:: gcc_jit_struct
|
||||
|
||||
A compound type analagous to a C `struct`.
|
||||
|
||||
.. c:type:: gcc_jit_field
|
||||
|
||||
A field within a :c:type:`gcc_jit_struct`.
|
||||
|
||||
You can model C `struct` types by creating :c:type:`gcc_jit_struct *` and
|
||||
:c:type:`gcc_jit_field` instances, in either order:
|
||||
|
||||
* by creating the fields, then the structure. For example, to model:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
struct coord {double x; double y; };
|
||||
|
||||
you could call:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
gcc_jit_field *field_x =
|
||||
gcc_jit_context_new_field (ctxt, NULL, double_type, "x");
|
||||
gcc_jit_field *field_y =
|
||||
gcc_jit_context_new_field (ctxt, NULL, double_type, "y");
|
||||
gcc_jit_field *fields[2] = {field_x, field_y};
|
||||
gcc_jit_struct *coord =
|
||||
gcc_jit_context_new_struct_type (ctxt, NULL, "coord", 2, fields);
|
||||
|
||||
* by creating the structure, then populating it with fields, typically
|
||||
to allow modelling self-referential structs such as:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
struct node { int m_hash; struct node *m_next; };
|
||||
|
||||
like this:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
gcc_jit_type *node =
|
||||
gcc_jit_context_new_opaque_struct (ctxt, NULL, "node");
|
||||
gcc_jit_type *node_ptr =
|
||||
gcc_jit_type_get_pointer (node);
|
||||
gcc_jit_field *field_hash =
|
||||
gcc_jit_context_new_field (ctxt, NULL, int_type, "m_hash");
|
||||
gcc_jit_field *field_next =
|
||||
gcc_jit_context_new_field (ctxt, NULL, node_ptr, "m_next");
|
||||
gcc_jit_field *fields[2] = {field_hash, field_next};
|
||||
gcc_jit_struct_set_fields (node, NULL, 2, fields);
|
||||
|
||||
.. function:: gcc_jit_field *\
|
||||
gcc_jit_context_new_field (gcc_jit_context *ctxt,\
|
||||
gcc_jit_location *loc,\
|
||||
gcc_jit_type *type,\
|
||||
const char *name)
|
||||
|
||||
Construct a new field, with the given type and name.
|
||||
|
||||
.. function:: gcc_jit_object *\
|
||||
gcc_jit_field_as_object (gcc_jit_field *field)
|
||||
|
||||
Upcast from field to object.
|
||||
|
||||
.. function:: gcc_jit_struct *\
|
||||
gcc_jit_context_new_struct_type (gcc_jit_context *ctxt,\
|
||||
gcc_jit_location *loc,\
|
||||
const char *name,\
|
||||
int num_fields,\
|
||||
gcc_jit_field **fields)
|
||||
|
||||
Construct a new struct type, with the given name and fields.
|
||||
|
||||
.. function:: gcc_jit_struct *\
|
||||
gcc_jit_context_new_opaque_struct (gcc_jit_context *ctxt,\
|
||||
gcc_jit_location *loc,\
|
||||
const char *name)
|
||||
|
||||
Construct a new struct type, with the given name, but without
|
||||
specifying the fields. The fields can be omitted (in which case the
|
||||
size of the struct is not known), or later specified using
|
||||
:c:func:`gcc_jit_struct_set_fields`.
|
||||
|
||||
.. function:: gcc_jit_type *\
|
||||
gcc_jit_struct_as_type (gcc_jit_struct *struct_type)
|
||||
|
||||
Upcast from struct to type.
|
||||
|
||||
.. function:: void\
|
||||
gcc_jit_struct_set_fields (gcc_jit_struct *struct_type,\
|
||||
gcc_jit_location *loc,\
|
||||
int num_fields,\
|
||||
gcc_jit_field **fields)
|
||||
|
||||
Populate the fields of a formerly-opaque struct type.
|
||||
|
||||
This can only be called once on a given struct type.
|
252
gcc/jit/dummy-frontend.c
Normal file
252
gcc/jit/dummy-frontend.c
Normal file
@ -0,0 +1,252 @@
|
||||
/* jit.c -- Dummy "frontend" for use during JIT-compilation.
|
||||
Copyright (C) 2013-2014 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GCC.
|
||||
|
||||
GCC is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 3, or (at your option) any later
|
||||
version.
|
||||
|
||||
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GCC; see the file COPYING3. If not see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "config.h"
|
||||
#include "system.h"
|
||||
#include "coretypes.h"
|
||||
#include "opts.h"
|
||||
#include "signop.h"
|
||||
#include "tree-core.h"
|
||||
#include "stor-layout.h"
|
||||
#include "tree.h"
|
||||
#include "debug.h"
|
||||
#include "langhooks.h"
|
||||
#include "langhooks-def.h"
|
||||
#include "hash-map.h"
|
||||
#include "is-a.h"
|
||||
#include "plugin-api.h"
|
||||
#include "vec.h"
|
||||
#include "hashtab.h"
|
||||
#include "hash-set.h"
|
||||
#include "machmode.h"
|
||||
#include "tm.h"
|
||||
#include "hard-reg-set.h"
|
||||
#include "function.h"
|
||||
#include "ipa-ref.h"
|
||||
#include "dumpfile.h"
|
||||
#include "cgraph.h"
|
||||
|
||||
#include "jit-common.h"
|
||||
#include "jit-playback.h"
|
||||
|
||||
#include <mpfr.h>
|
||||
|
||||
/* Language-dependent contents of a type. */
|
||||
|
||||
struct GTY(()) lang_type
|
||||
{
|
||||
char dummy;
|
||||
};
|
||||
|
||||
/* Language-dependent contents of a decl. */
|
||||
|
||||
struct GTY((variable_size)) lang_decl
|
||||
{
|
||||
char dummy;
|
||||
};
|
||||
|
||||
/* Language-dependent contents of an identifier. This must include a
|
||||
tree_identifier. */
|
||||
|
||||
struct GTY(()) lang_identifier
|
||||
{
|
||||
struct tree_identifier common;
|
||||
};
|
||||
|
||||
/* The resulting tree type. */
|
||||
|
||||
union GTY((desc ("TREE_CODE (&%h.generic) == IDENTIFIER_NODE"),
|
||||
chain_next ("CODE_CONTAINS_STRUCT (TREE_CODE (&%h.generic), TS_COMMON) ? ((union lang_tree_node *) TREE_CHAIN (&%h.generic)) : NULL")))
|
||||
lang_tree_node
|
||||
{
|
||||
union tree_node GTY((tag ("0"),
|
||||
desc ("tree_node_structure (&%h)"))) generic;
|
||||
struct lang_identifier GTY((tag ("1"))) identifier;
|
||||
};
|
||||
|
||||
/* We don't use language_function. */
|
||||
|
||||
struct GTY(()) language_function
|
||||
{
|
||||
int dummy;
|
||||
};
|
||||
|
||||
/* GC-marking callback for use from jit_root_tab.
|
||||
|
||||
If there's an active playback context, call its marking method
|
||||
so that it can mark any pointers it references. */
|
||||
|
||||
static void my_ggc_walker (void *)
|
||||
{
|
||||
if (gcc::jit::active_playback_ctxt)
|
||||
gcc::jit::active_playback_ctxt->gt_ggc_mx ();
|
||||
}
|
||||
|
||||
const char *dummy;
|
||||
|
||||
struct ggc_root_tab jit_root_tab[] =
|
||||
{
|
||||
{
|
||||
&dummy, 1, 0, my_ggc_walker, NULL
|
||||
},
|
||||
LAST_GGC_ROOT_TAB
|
||||
};
|
||||
|
||||
/* Language hooks. */
|
||||
|
||||
static bool
|
||||
jit_langhook_init (void)
|
||||
{
|
||||
static bool registered_root_tab = false;
|
||||
if (!registered_root_tab)
|
||||
{
|
||||
ggc_register_root_tab (jit_root_tab);
|
||||
registered_root_tab = true;
|
||||
}
|
||||
|
||||
build_common_tree_nodes (false, false);
|
||||
|
||||
/* I don't know why this has to be done explicitly. */
|
||||
void_list_node = build_tree_list (NULL_TREE, void_type_node);
|
||||
|
||||
build_common_builtin_nodes ();
|
||||
|
||||
/* The default precision for floating point numbers. This is used
|
||||
for floating point constants with abstract type. This may
|
||||
eventually be controllable by a command line option. */
|
||||
mpfr_set_default_prec (256);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
jit_langhook_parse_file (void)
|
||||
{
|
||||
/* Replay the activity by the client, recorded on the context. */
|
||||
gcc_assert (gcc::jit::active_playback_ctxt);
|
||||
gcc::jit::active_playback_ctxt->replay ();
|
||||
}
|
||||
|
||||
static tree
|
||||
jit_langhook_type_for_mode (enum machine_mode mode, int unsignedp)
|
||||
{
|
||||
if (mode == TYPE_MODE (float_type_node))
|
||||
return float_type_node;
|
||||
|
||||
if (mode == TYPE_MODE (double_type_node))
|
||||
return double_type_node;
|
||||
|
||||
if (mode == TYPE_MODE (integer_type_node))
|
||||
return unsignedp ? unsigned_type_node : integer_type_node;
|
||||
|
||||
if (mode == TYPE_MODE (long_integer_type_node))
|
||||
return unsignedp ? long_unsigned_type_node : long_integer_type_node;
|
||||
|
||||
if (COMPLEX_MODE_P (mode))
|
||||
{
|
||||
if (mode == TYPE_MODE (complex_float_type_node))
|
||||
return complex_float_type_node;
|
||||
if (mode == TYPE_MODE (complex_double_type_node))
|
||||
return complex_double_type_node;
|
||||
if (mode == TYPE_MODE (complex_long_double_type_node))
|
||||
return complex_long_double_type_node;
|
||||
if (mode == TYPE_MODE (complex_integer_type_node) && !unsignedp)
|
||||
return complex_integer_type_node;
|
||||
}
|
||||
|
||||
/* gcc_unreachable */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static tree
|
||||
jit_langhook_type_for_size (unsigned int bits ATTRIBUTE_UNUSED,
|
||||
int unsignedp ATTRIBUTE_UNUSED)
|
||||
{
|
||||
gcc_unreachable ();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Record a builtin function. We just ignore builtin functions. */
|
||||
|
||||
static tree
|
||||
jit_langhook_builtin_function (tree decl)
|
||||
{
|
||||
return decl;
|
||||
}
|
||||
|
||||
static bool
|
||||
jit_langhook_global_bindings_p (void)
|
||||
{
|
||||
gcc_unreachable ();
|
||||
return true;
|
||||
}
|
||||
|
||||
static tree
|
||||
jit_langhook_pushdecl (tree decl ATTRIBUTE_UNUSED)
|
||||
{
|
||||
gcc_unreachable ();
|
||||
}
|
||||
|
||||
static tree
|
||||
jit_langhook_getdecls (void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
jit_langhook_write_globals (void)
|
||||
{
|
||||
/* This is the hook that runs the middle and backends: */
|
||||
symtab->finalize_compilation_unit ();
|
||||
}
|
||||
|
||||
#undef LANG_HOOKS_NAME
|
||||
#define LANG_HOOKS_NAME "libgccjit"
|
||||
|
||||
#undef LANG_HOOKS_INIT
|
||||
#define LANG_HOOKS_INIT jit_langhook_init
|
||||
|
||||
#undef LANG_HOOKS_PARSE_FILE
|
||||
#define LANG_HOOKS_PARSE_FILE jit_langhook_parse_file
|
||||
|
||||
#undef LANG_HOOKS_TYPE_FOR_MODE
|
||||
#define LANG_HOOKS_TYPE_FOR_MODE jit_langhook_type_for_mode
|
||||
|
||||
#undef LANG_HOOKS_TYPE_FOR_SIZE
|
||||
#define LANG_HOOKS_TYPE_FOR_SIZE jit_langhook_type_for_size
|
||||
|
||||
#undef LANG_HOOKS_BUILTIN_FUNCTION
|
||||
#define LANG_HOOKS_BUILTIN_FUNCTION jit_langhook_builtin_function
|
||||
|
||||
#undef LANG_HOOKS_GLOBAL_BINDINGS_P
|
||||
#define LANG_HOOKS_GLOBAL_BINDINGS_P jit_langhook_global_bindings_p
|
||||
|
||||
#undef LANG_HOOKS_PUSHDECL
|
||||
#define LANG_HOOKS_PUSHDECL jit_langhook_pushdecl
|
||||
|
||||
#undef LANG_HOOKS_GETDECLS
|
||||
#define LANG_HOOKS_GETDECLS jit_langhook_getdecls
|
||||
|
||||
#undef LANG_HOOKS_WRITE_GLOBALS
|
||||
#define LANG_HOOKS_WRITE_GLOBALS jit_langhook_write_globals
|
||||
|
||||
struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER;
|
||||
|
||||
#include "gt-jit-dummy-frontend.h"
|
||||
#include "gtype-jit.h"
|
424
gcc/jit/jit-builtins.c
Normal file
424
gcc/jit/jit-builtins.c
Normal file
@ -0,0 +1,424 @@
|
||||
/* jit-builtins.c -- Handling of builtin functions during JIT-compilation.
|
||||
Copyright (C) 2014 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GCC.
|
||||
|
||||
GCC is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 3, or (at your option) any later
|
||||
version.
|
||||
|
||||
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GCC; see the file COPYING3. If not see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "config.h"
|
||||
#include "system.h"
|
||||
#include "coretypes.h"
|
||||
#include "opts.h"
|
||||
#include "tree.h"
|
||||
#include "target.h"
|
||||
|
||||
#include "jit-common.h"
|
||||
#include "jit-builtins.h"
|
||||
#include "jit-recording.h"
|
||||
|
||||
namespace gcc {
|
||||
|
||||
namespace jit {
|
||||
|
||||
namespace recording {
|
||||
|
||||
const char *const prefix = "__builtin_";
|
||||
const size_t prefix_len = strlen (prefix);
|
||||
|
||||
/* Create "builtin_data", a const table of the data within builtins.def. */
|
||||
struct builtin_data
|
||||
{
|
||||
const char *name;
|
||||
enum jit_builtin_type type;
|
||||
bool both_p;
|
||||
bool fallback_p;
|
||||
|
||||
const char *get_asm_name () const
|
||||
{
|
||||
if (both_p && fallback_p)
|
||||
return name + prefix_len;
|
||||
else
|
||||
return name;
|
||||
}
|
||||
};
|
||||
|
||||
#define DEF_BUILTIN(X, NAME, C, TYPE, LT, BOTH_P, FALLBACK_P, NA, AT, IM, COND)\
|
||||
{NAME, TYPE, BOTH_P, FALLBACK_P},
|
||||
static const struct builtin_data builtin_data[] =
|
||||
{
|
||||
#include "builtins.def"
|
||||
};
|
||||
#undef DEF_BUILTIN
|
||||
|
||||
/* Helper function for find_builtin_by_name. */
|
||||
|
||||
static bool
|
||||
matches_builtin (const char *in_name,
|
||||
const struct builtin_data& bd)
|
||||
{
|
||||
const bool debug = 0;
|
||||
gcc_assert (bd.name);
|
||||
|
||||
if (debug)
|
||||
fprintf (stderr, "seen builtin: %s\n", bd.name);
|
||||
|
||||
if (0 == strcmp (bd.name, in_name))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (bd.both_p)
|
||||
{
|
||||
/* Then the macros in builtins.def gave a "__builtin_"
|
||||
prefix to bd.name, but we should also recognize the form
|
||||
without the prefix. */
|
||||
gcc_assert (0 == strncmp (bd.name, prefix, prefix_len));
|
||||
if (debug)
|
||||
fprintf (stderr, "testing without prefix as: %s\n",
|
||||
bd.name + prefix_len);
|
||||
if (0 == strcmp (bd.name + prefix_len, in_name))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Locate the built-in function that matches name IN_NAME,
|
||||
writing the result to OUT_ID and returning true if found,
|
||||
or returning false if not found. */
|
||||
|
||||
static bool
|
||||
find_builtin_by_name (const char *in_name,
|
||||
enum built_in_function *out_id)
|
||||
{
|
||||
/* Locate builtin. This currently works by performing repeated
|
||||
strcmp against every possible candidate, which is likely to
|
||||
inefficient.
|
||||
|
||||
We start at index 1 to skip the initial entry (BUILT_IN_NONE), which
|
||||
has a NULL name. */
|
||||
for (unsigned int i = 1;
|
||||
i < sizeof (builtin_data) / sizeof (builtin_data[0]);
|
||||
i++)
|
||||
{
|
||||
const struct builtin_data& bd = builtin_data[i];
|
||||
if (matches_builtin (in_name, bd))
|
||||
{
|
||||
/* Found a match. */
|
||||
*out_id = static_cast<enum built_in_function> (i);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/* Not found. */
|
||||
return false;
|
||||
}
|
||||
|
||||
// class builtins_manager
|
||||
|
||||
/* Constructor for gcc::jit::recording::builtins_manager. */
|
||||
|
||||
builtins_manager::builtins_manager (context *ctxt)
|
||||
: m_ctxt (ctxt)
|
||||
{
|
||||
memset (m_types, 0, sizeof (m_types));
|
||||
memset (m_builtin_functions, 0, sizeof (m_builtin_functions));
|
||||
}
|
||||
|
||||
/* Locate a builtin function by name.
|
||||
Create a recording::function of the appropriate type, reusing them
|
||||
if they've already been seen. */
|
||||
|
||||
function *
|
||||
builtins_manager::get_builtin_function (const char *name)
|
||||
{
|
||||
enum built_in_function builtin_id;
|
||||
if (!find_builtin_by_name (name, &builtin_id))
|
||||
{
|
||||
m_ctxt->add_error (NULL, "builtin \"%s\" not found", name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gcc_assert (builtin_id >= 0);
|
||||
gcc_assert (builtin_id < END_BUILTINS);
|
||||
|
||||
/* Lazily build the functions, caching them so that repeated calls for
|
||||
the same id on a context give back the same object. */
|
||||
if (!m_builtin_functions[builtin_id])
|
||||
{
|
||||
m_builtin_functions[builtin_id] = make_builtin_function (builtin_id);
|
||||
m_ctxt->record (m_builtin_functions[builtin_id]);
|
||||
}
|
||||
|
||||
return m_builtin_functions[builtin_id];
|
||||
}
|
||||
|
||||
/* Create the recording::function for a given builtin function, by ID. */
|
||||
|
||||
function *
|
||||
builtins_manager::make_builtin_function (enum built_in_function builtin_id)
|
||||
{
|
||||
const struct builtin_data& bd = builtin_data[builtin_id];
|
||||
enum jit_builtin_type type_id = bd.type;
|
||||
function_type *func_type = get_type (type_id)->as_a_function_type ();
|
||||
if (!func_type)
|
||||
return NULL;
|
||||
|
||||
vec<type *> param_types = func_type->get_param_types ();
|
||||
recording::param **params = new recording::param *[param_types.length ()];
|
||||
|
||||
int i;
|
||||
type *param_type;
|
||||
FOR_EACH_VEC_ELT (param_types, i, param_type)
|
||||
{
|
||||
char buf[16];
|
||||
snprintf (buf, 16, "arg%d", i);
|
||||
params[i] = m_ctxt->new_param (NULL,
|
||||
param_type,
|
||||
buf);
|
||||
}
|
||||
const char *asm_name = bd.get_asm_name ();
|
||||
function *result =
|
||||
new function (m_ctxt,
|
||||
NULL,
|
||||
GCC_JIT_FUNCTION_IMPORTED, // FIXME
|
||||
func_type->get_return_type (),
|
||||
m_ctxt->new_string (asm_name),
|
||||
param_types.length (),
|
||||
params,
|
||||
func_type->is_variadic (),
|
||||
builtin_id);
|
||||
delete[] params;
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Get the recording::type for a given type of builtin function,
|
||||
by ID, creating it if it doesn't already exist. */
|
||||
|
||||
type *
|
||||
builtins_manager::get_type (enum jit_builtin_type type_id)
|
||||
{
|
||||
if (!m_types[type_id])
|
||||
m_types[type_id] = make_type (type_id);
|
||||
return m_types[type_id];
|
||||
}
|
||||
|
||||
/* Create the recording::type for a given type of builtin function. */
|
||||
|
||||
type *
|
||||
builtins_manager::make_type (enum jit_builtin_type type_id)
|
||||
{
|
||||
/* Use builtin-types.def to construct a switch statement, with each
|
||||
case deferring to one of the methods below:
|
||||
- DEF_PRIMITIVE_TYPE is handled as a call to make_primitive_type.
|
||||
- the various DEF_FUNCTION_TYPE_n are handled by variadic calls
|
||||
to make_fn_type.
|
||||
- similarly for DEF_FUNCTION_TYPE_VAR_n, but setting the
|
||||
"is_variadic" argument.
|
||||
- DEF_POINTER_TYPE is handled by make_ptr_type.
|
||||
That should handle everything, but just in case we also suppy a
|
||||
gcc_unreachable default clause. */
|
||||
switch (type_id)
|
||||
{
|
||||
#define DEF_PRIMITIVE_TYPE(ENUM, VALUE) \
|
||||
case ENUM: return make_primitive_type (ENUM);
|
||||
#define DEF_FUNCTION_TYPE_0(ENUM, RETURN) \
|
||||
case ENUM: return make_fn_type (ENUM, RETURN, 0, 0);
|
||||
#define DEF_FUNCTION_TYPE_1(ENUM, RETURN, ARG1) \
|
||||
case ENUM: return make_fn_type (ENUM, RETURN, 0, 1, ARG1);
|
||||
#define DEF_FUNCTION_TYPE_2(ENUM, RETURN, ARG1, ARG2) \
|
||||
case ENUM: return make_fn_type (ENUM, RETURN, 0, 2, ARG1, ARG2);
|
||||
#define DEF_FUNCTION_TYPE_3(ENUM, RETURN, ARG1, ARG2, ARG3) \
|
||||
case ENUM: return make_fn_type (ENUM, RETURN, 0, 3, ARG1, ARG2, ARG3);
|
||||
#define DEF_FUNCTION_TYPE_4(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4) \
|
||||
case ENUM: return make_fn_type (ENUM, RETURN, 0, 4, ARG1, ARG2, ARG3, ARG4);
|
||||
#define DEF_FUNCTION_TYPE_5(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) \
|
||||
case ENUM: return make_fn_type (ENUM, RETURN, 0, 5, ARG1, ARG2, ARG3, ARG4, ARG5);
|
||||
#define DEF_FUNCTION_TYPE_6(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
|
||||
ARG6) \
|
||||
case ENUM: return make_fn_type (ENUM, RETURN, 0, 6, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6);
|
||||
#define DEF_FUNCTION_TYPE_7(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
|
||||
ARG6, ARG7) \
|
||||
case ENUM: return make_fn_type (ENUM, RETURN, 0, 7, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7);
|
||||
#define DEF_FUNCTION_TYPE_8(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
|
||||
ARG6, ARG7, ARG8) \
|
||||
case ENUM: return make_fn_type (ENUM, RETURN, 0, 8, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, \
|
||||
ARG7, ARG8);
|
||||
#define DEF_FUNCTION_TYPE_VAR_0(ENUM, RETURN) \
|
||||
case ENUM: return make_fn_type (ENUM, RETURN, 1, 0);
|
||||
#define DEF_FUNCTION_TYPE_VAR_1(ENUM, RETURN, ARG1) \
|
||||
case ENUM: return make_fn_type (ENUM, RETURN, 1, 1, ARG1);
|
||||
#define DEF_FUNCTION_TYPE_VAR_2(ENUM, RETURN, ARG1, ARG2) \
|
||||
case ENUM: return make_fn_type (ENUM, RETURN, 1, 2, ARG1, ARG2);
|
||||
#define DEF_FUNCTION_TYPE_VAR_3(ENUM, RETURN, ARG1, ARG2, ARG3) \
|
||||
case ENUM: return make_fn_type (ENUM, RETURN, 1, 3, ARG1, ARG2, ARG3);
|
||||
#define DEF_FUNCTION_TYPE_VAR_4(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4) \
|
||||
case ENUM: return make_fn_type (ENUM, RETURN, 1, 4, ARG1, ARG2, ARG3, ARG4);
|
||||
#define DEF_FUNCTION_TYPE_VAR_5(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) \
|
||||
case ENUM: return make_fn_type (ENUM, RETURN, 1, 5, ARG1, ARG2, ARG3, ARG4, ARG5);
|
||||
#define DEF_POINTER_TYPE(ENUM, TYPE) \
|
||||
case ENUM: return make_ptr_type (ENUM, TYPE);
|
||||
|
||||
#include "builtin-types.def"
|
||||
|
||||
#undef DEF_PRIMITIVE_TYPE
|
||||
#undef DEF_FUNCTION_TYPE_1
|
||||
#undef DEF_FUNCTION_TYPE_2
|
||||
#undef DEF_FUNCTION_TYPE_3
|
||||
#undef DEF_FUNCTION_TYPE_4
|
||||
#undef DEF_FUNCTION_TYPE_5
|
||||
#undef DEF_FUNCTION_TYPE_6
|
||||
#undef DEF_FUNCTION_TYPE_VAR_0
|
||||
#undef DEF_FUNCTION_TYPE_VAR_1
|
||||
#undef DEF_FUNCTION_TYPE_VAR_2
|
||||
#undef DEF_FUNCTION_TYPE_VAR_3
|
||||
#undef DEF_FUNCTION_TYPE_VAR_4
|
||||
#undef DEF_FUNCTION_TYPE_VAR_5
|
||||
#undef DEF_POINTER_TYPE
|
||||
|
||||
default:
|
||||
gcc_unreachable ();
|
||||
}
|
||||
}
|
||||
|
||||
/* Create the recording::type for a given primitive type within the
|
||||
builtin system.
|
||||
|
||||
Only some types are currently supported. */
|
||||
|
||||
type*
|
||||
builtins_manager::make_primitive_type (enum jit_builtin_type type_id)
|
||||
{
|
||||
switch (type_id)
|
||||
{
|
||||
default:
|
||||
// only some of these types are implemented so far:
|
||||
m_ctxt->add_error (NULL,
|
||||
"unimplemented primitive type for builtin: %d", type_id);
|
||||
return NULL;
|
||||
|
||||
case BT_VOID: return m_ctxt->get_type (GCC_JIT_TYPE_VOID);
|
||||
case BT_BOOL: return m_ctxt->get_type (GCC_JIT_TYPE_BOOL);
|
||||
case BT_INT: return m_ctxt->get_type (GCC_JIT_TYPE_INT);
|
||||
case BT_UINT: return m_ctxt->get_type (GCC_JIT_TYPE_UNSIGNED_INT);
|
||||
case BT_LONG: return m_ctxt->get_type (GCC_JIT_TYPE_LONG);
|
||||
case BT_ULONG: return m_ctxt->get_type (GCC_JIT_TYPE_UNSIGNED_LONG);
|
||||
case BT_LONGLONG: return m_ctxt->get_type (GCC_JIT_TYPE_LONG_LONG);
|
||||
case BT_ULONGLONG:
|
||||
return m_ctxt->get_type (GCC_JIT_TYPE_UNSIGNED_LONG_LONG);
|
||||
// case BT_INT128:
|
||||
// case BT_UINT128:
|
||||
// case BT_INTMAX:
|
||||
// case BT_UINTMAX:
|
||||
case BT_UINT16: return m_ctxt->get_int_type (2, false);
|
||||
case BT_UINT32: return m_ctxt->get_int_type (4, false);
|
||||
case BT_UINT64: return m_ctxt->get_int_type (8, false);
|
||||
// case BT_WORD:
|
||||
// case BT_UNWINDWORD:
|
||||
case BT_FLOAT: return m_ctxt->get_type (GCC_JIT_TYPE_FLOAT);
|
||||
case BT_DOUBLE: return m_ctxt->get_type (GCC_JIT_TYPE_DOUBLE);
|
||||
case BT_LONGDOUBLE: return m_ctxt->get_type (GCC_JIT_TYPE_LONG_DOUBLE);
|
||||
// case BT_COMPLEX_FLOAT:
|
||||
// case BT_COMPLEX_DOUBLE:
|
||||
// case BT_COMPLEX_LONGDOUBLE:
|
||||
case BT_PTR: return m_ctxt->get_type (GCC_JIT_TYPE_VOID_PTR);
|
||||
case BT_FILEPTR: return m_ctxt->get_type (GCC_JIT_TYPE_FILE_PTR);
|
||||
// case BT_CONST:
|
||||
// case BT_VOLATILE_PTR:
|
||||
// case BT_CONST_VOLATILE_PTR:
|
||||
// case BT_PTRMODE:
|
||||
// case BT_INT_PTR:
|
||||
// case BT_FLOAT_PTR:
|
||||
// case BT_DOUBLE_PTR:
|
||||
// case BT_CONST_DOUBLE_PTR:
|
||||
// case BT_LONGDOUBLE_PTR:
|
||||
// case BT_PID:
|
||||
// case BT_SIZE:
|
||||
// case BT_SSIZE:
|
||||
// case BT_WINT:
|
||||
// case BT_STRING:
|
||||
case BT_CONST_STRING: return m_ctxt->get_type (GCC_JIT_TYPE_CONST_CHAR_PTR);
|
||||
// case BT_DFLOAT32:
|
||||
// case BT_DFLOAT64:
|
||||
// case BT_DFLOAT128:
|
||||
// case BT_DFLOAT32_PTR:
|
||||
// case BT_DFLOAT64_PTR:
|
||||
// case BT_DFLOAT128_PTR:
|
||||
// case BT_VALIST_REF:
|
||||
// case BT_VALIST_ARG:
|
||||
// case BT_I1:
|
||||
// case BT_I2:
|
||||
// case BT_I4:
|
||||
// case BT_I8:
|
||||
// case BT_I16:
|
||||
}
|
||||
}
|
||||
|
||||
/* Create the recording::function_type for a given function type
|
||||
signature. */
|
||||
|
||||
function_type *
|
||||
builtins_manager::make_fn_type (enum jit_builtin_type,
|
||||
enum jit_builtin_type return_type_id,
|
||||
bool is_variadic,
|
||||
int num_args, ...)
|
||||
{
|
||||
va_list list;
|
||||
int i;
|
||||
type **param_types = new type *[num_args];
|
||||
type *return_type = NULL;
|
||||
function_type *result = NULL;
|
||||
|
||||
va_start (list, num_args);
|
||||
for (i = 0; i < num_args; ++i)
|
||||
{
|
||||
enum jit_builtin_type arg_type_id =
|
||||
(enum jit_builtin_type) va_arg (list, int);
|
||||
param_types[i] = get_type (arg_type_id);
|
||||
if (!param_types[i])
|
||||
goto error;
|
||||
}
|
||||
va_end (list);
|
||||
|
||||
return_type = get_type (return_type_id);
|
||||
if (!return_type)
|
||||
goto error;
|
||||
|
||||
result = new function_type (m_ctxt,
|
||||
return_type,
|
||||
num_args,
|
||||
param_types,
|
||||
is_variadic);
|
||||
|
||||
error:
|
||||
delete[] param_types;
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Handler for DEF_POINTER_TYPE within builtins_manager::make_type. */
|
||||
|
||||
type *
|
||||
builtins_manager::make_ptr_type (enum jit_builtin_type,
|
||||
enum jit_builtin_type other_type_id)
|
||||
{
|
||||
type *base_type = get_type (other_type_id);
|
||||
return base_type->get_pointer ();
|
||||
}
|
||||
|
||||
} // namespace recording
|
||||
} // namespace jit
|
||||
} // namespace gcc
|
114
gcc/jit/jit-builtins.h
Normal file
114
gcc/jit/jit-builtins.h
Normal file
@ -0,0 +1,114 @@
|
||||
/* jit-builtins.h -- Handling of builtin functions during JIT-compilation.
|
||||
Copyright (C) 2014 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GCC.
|
||||
|
||||
GCC is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 3, or (at your option) any later
|
||||
version.
|
||||
|
||||
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GCC; see the file COPYING3. If not see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef JIT_BUILTINS_H
|
||||
#define JIT_BUILTINS_H
|
||||
|
||||
#include "jit-common.h"
|
||||
|
||||
namespace gcc {
|
||||
|
||||
namespace jit {
|
||||
|
||||
namespace recording {
|
||||
|
||||
/* Create an enum of the builtin types. */
|
||||
|
||||
enum jit_builtin_type
|
||||
{
|
||||
#define DEF_PRIMITIVE_TYPE(NAME, VALUE) NAME,
|
||||
#define DEF_FUNCTION_TYPE_0(NAME, RETURN) NAME,
|
||||
#define DEF_FUNCTION_TYPE_1(NAME, RETURN, ARG1) NAME,
|
||||
#define DEF_FUNCTION_TYPE_2(NAME, RETURN, ARG1, ARG2) NAME,
|
||||
#define DEF_FUNCTION_TYPE_3(NAME, RETURN, ARG1, ARG2, ARG3) NAME,
|
||||
#define DEF_FUNCTION_TYPE_4(NAME, RETURN, ARG1, ARG2, ARG3, ARG4) NAME,
|
||||
#define DEF_FUNCTION_TYPE_5(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) NAME,
|
||||
#define DEF_FUNCTION_TYPE_6(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6) NAME,
|
||||
#define DEF_FUNCTION_TYPE_7(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7) NAME,
|
||||
#define DEF_FUNCTION_TYPE_8(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7, ARG8) NAME,
|
||||
#define DEF_FUNCTION_TYPE_VAR_0(NAME, RETURN) NAME,
|
||||
#define DEF_FUNCTION_TYPE_VAR_1(NAME, RETURN, ARG1) NAME,
|
||||
#define DEF_FUNCTION_TYPE_VAR_2(NAME, RETURN, ARG1, ARG2) NAME,
|
||||
#define DEF_FUNCTION_TYPE_VAR_3(NAME, RETURN, ARG1, ARG2, ARG3) NAME,
|
||||
#define DEF_FUNCTION_TYPE_VAR_4(NAME, RETURN, ARG1, ARG2, ARG3, ARG4) NAME,
|
||||
#define DEF_FUNCTION_TYPE_VAR_5(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG6) \
|
||||
NAME,
|
||||
#define DEF_POINTER_TYPE(NAME, TYPE) NAME,
|
||||
#include "builtin-types.def"
|
||||
#undef DEF_PRIMITIVE_TYPE
|
||||
#undef DEF_FUNCTION_TYPE_0
|
||||
#undef DEF_FUNCTION_TYPE_1
|
||||
#undef DEF_FUNCTION_TYPE_2
|
||||
#undef DEF_FUNCTION_TYPE_3
|
||||
#undef DEF_FUNCTION_TYPE_4
|
||||
#undef DEF_FUNCTION_TYPE_5
|
||||
#undef DEF_FUNCTION_TYPE_6
|
||||
#undef DEF_FUNCTION_TYPE_7
|
||||
#undef DEF_FUNCTION_TYPE_8
|
||||
#undef DEF_FUNCTION_TYPE_VAR_0
|
||||
#undef DEF_FUNCTION_TYPE_VAR_1
|
||||
#undef DEF_FUNCTION_TYPE_VAR_2
|
||||
#undef DEF_FUNCTION_TYPE_VAR_3
|
||||
#undef DEF_FUNCTION_TYPE_VAR_4
|
||||
#undef DEF_FUNCTION_TYPE_VAR_5
|
||||
#undef DEF_POINTER_TYPE
|
||||
BT_LAST
|
||||
}; /* enum jit_builtin_type */
|
||||
|
||||
/***********************************************************************/
|
||||
|
||||
class builtins_manager
|
||||
{
|
||||
public:
|
||||
builtins_manager (context *ctxt);
|
||||
|
||||
function *
|
||||
get_builtin_function (const char *name);
|
||||
|
||||
private:
|
||||
function *make_builtin_function (enum built_in_function builtin_id);
|
||||
|
||||
type *get_type (enum jit_builtin_type type_id);
|
||||
|
||||
type *make_type (enum jit_builtin_type type_id);
|
||||
|
||||
type*
|
||||
make_primitive_type (enum jit_builtin_type type_id);
|
||||
|
||||
function_type*
|
||||
make_fn_type (enum jit_builtin_type type_id,
|
||||
enum jit_builtin_type return_type_id,
|
||||
bool is_variadic,
|
||||
int num_args, ...);
|
||||
|
||||
type*
|
||||
make_ptr_type (enum jit_builtin_type type_id,
|
||||
enum jit_builtin_type other_type_id);
|
||||
|
||||
private:
|
||||
context *m_ctxt;
|
||||
type *m_types[BT_LAST];
|
||||
function *m_builtin_functions[END_BUILTINS];
|
||||
};
|
||||
|
||||
} // namespace recording
|
||||
} // namespace jit
|
||||
} // namespace gcc
|
||||
|
||||
#endif /* JIT_BUILTINS_H */
|
182
gcc/jit/jit-common.h
Normal file
182
gcc/jit/jit-common.h
Normal file
@ -0,0 +1,182 @@
|
||||
/* Core of implementation of libgccjit.so
|
||||
Copyright (C) 2013-2014 Free Software Foundation, Inc.
|
||||
Contributed by David Malcolm <dmalcolm@redhat.com>.
|
||||
|
||||
This file is part of GCC.
|
||||
|
||||
GCC is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3, or (at your option)
|
||||
any later version.
|
||||
|
||||
GCC is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GCC; see the file COPYING3. If not see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef JIT_COMMON_H
|
||||
#define JIT_COMMON_H
|
||||
|
||||
#include "libgccjit.h"
|
||||
|
||||
#include "tree.h"
|
||||
#include "tree-iterator.h"
|
||||
|
||||
#ifdef GCC_VERSION
|
||||
#if GCC_VERSION >= 4001
|
||||
#define GNU_PRINTF(M, N) __attribute__ ((format (gnu_printf, (M), (N))))
|
||||
#else
|
||||
#define GNU_PRINTF(M, N)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
const int NUM_GCC_JIT_TYPES = GCC_JIT_TYPE_FILE_PTR + 1;
|
||||
|
||||
/* This comment is included by the docs.
|
||||
|
||||
In order to allow jit objects to be usable outside of a compile
|
||||
whilst working with the existing structure of GCC's code the
|
||||
C API is implemented in terms of a gcc::jit::recording::context,
|
||||
which records the calls made to it.
|
||||
|
||||
When a gcc_jit_context is compiled, the recording context creates a
|
||||
playback context. The playback context invokes the bulk of the GCC
|
||||
code, and within the "frontend" parsing hook, plays back the recorded
|
||||
API calls, creating GCC tree objects.
|
||||
|
||||
So there are two parallel families of classes: those relating to
|
||||
recording, and those relating to playback:
|
||||
|
||||
* Visibility: recording objects are exposed back to client code,
|
||||
whereas playback objects are internal to the library.
|
||||
|
||||
* Lifetime: recording objects have a lifetime equal to that of the
|
||||
recording context that created them, whereas playback objects only
|
||||
exist within the frontend hook.
|
||||
|
||||
* Memory allocation: recording objects are allocated by the recording
|
||||
context, and automatically freed by it when the context is released,
|
||||
whereas playback objects are allocated within the GC heap, and
|
||||
garbage-collected; they can own GC-references.
|
||||
|
||||
* Integration with rest of GCC: recording objects are unrelated to the
|
||||
rest of GCC, whereas playback objects are wrappers around "tree"
|
||||
instances. Hence you can't ask a recording rvalue or lvalue what its
|
||||
type is, whereas you can for a playback rvalue of lvalue (since it
|
||||
can work with the underlying GCC tree nodes).
|
||||
|
||||
* Instancing: There can be multiple recording contexts "alive" at once
|
||||
(albeit it only one compiling at once), whereas there can only be one
|
||||
playback context alive at one time (since it interacts with the GC).
|
||||
|
||||
Ultimately if GCC could support multiple GC heaps and contexts, and
|
||||
finer-grained initialization, then this recording vs playback
|
||||
distinction could be eliminated.
|
||||
|
||||
During a playback, we associate objects from the recording with
|
||||
their counterparts during this playback. For simplicity, we store this
|
||||
within the recording objects, as ``void *m_playback_obj``, casting it to
|
||||
the appropriate playback object subclass. For these casts to make
|
||||
sense, the two class hierarchies need to have the same structure.
|
||||
|
||||
Note that the playback objects that ``m_playback_obj`` points to are
|
||||
GC-allocated, but the recording objects don't own references:
|
||||
these associations only exist within a part of the code where
|
||||
the GC doesn't collect, and are set back to NULL before the GC can
|
||||
run.
|
||||
|
||||
End of comment for inclusion in the docs. */
|
||||
|
||||
namespace gcc {
|
||||
|
||||
namespace jit {
|
||||
|
||||
class result;
|
||||
class dump;
|
||||
|
||||
namespace recording {
|
||||
|
||||
/* Recording types. */
|
||||
|
||||
/* Indentation indicates inheritance: */
|
||||
class context;
|
||||
class builtins_manager; // declared within jit-builtins.h
|
||||
class memento;
|
||||
class string;
|
||||
class location;
|
||||
class type;
|
||||
class function_type;
|
||||
class compound_type;
|
||||
class struct_;
|
||||
class union_;
|
||||
class field;
|
||||
class fields;
|
||||
class function;
|
||||
class block;
|
||||
class rvalue;
|
||||
class lvalue;
|
||||
class local;
|
||||
class global;
|
||||
class param;
|
||||
class statement;
|
||||
|
||||
/* End of recording types. */
|
||||
}
|
||||
|
||||
namespace playback {
|
||||
/* Playback types. */
|
||||
|
||||
/* Indentation indicates inheritance: */
|
||||
class context;
|
||||
class wrapper;
|
||||
class type;
|
||||
class compound_type;
|
||||
class field;
|
||||
class function;
|
||||
class block;
|
||||
class rvalue;
|
||||
class lvalue;
|
||||
class param;
|
||||
class source_file;
|
||||
class source_line;
|
||||
class location;
|
||||
|
||||
/* End of playback types. */
|
||||
}
|
||||
|
||||
typedef playback::context replayer;
|
||||
|
||||
class dump
|
||||
{
|
||||
public:
|
||||
dump (recording::context &ctxt,
|
||||
const char *filename,
|
||||
bool update_locations);
|
||||
~dump ();
|
||||
|
||||
void write (const char *fmt, ...)
|
||||
GNU_PRINTF(2, 3);
|
||||
|
||||
bool update_locations () const { return m_update_locations; }
|
||||
|
||||
recording::location *
|
||||
make_location () const;
|
||||
|
||||
private:
|
||||
recording::context &m_ctxt;
|
||||
const char *m_filename;
|
||||
bool m_update_locations;
|
||||
int m_line;
|
||||
int m_column;
|
||||
FILE *m_file;
|
||||
};
|
||||
|
||||
} // namespace gcc::jit
|
||||
|
||||
} // namespace gcc
|
||||
|
||||
#endif /* JIT_COMMON_H */
|
2100
gcc/jit/jit-playback.c
Normal file
2100
gcc/jit/jit-playback.c
Normal file
File diff suppressed because it is too large
Load Diff
564
gcc/jit/jit-playback.h
Normal file
564
gcc/jit/jit-playback.h
Normal file
@ -0,0 +1,564 @@
|
||||
/* Internals of libgccjit: classes for playing back recorded API calls.
|
||||
Copyright (C) 2013-2014 Free Software Foundation, Inc.
|
||||
Contributed by David Malcolm <dmalcolm@redhat.com>.
|
||||
|
||||
This file is part of GCC.
|
||||
|
||||
GCC is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3, or (at your option)
|
||||
any later version.
|
||||
|
||||
GCC is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GCC; see the file COPYING3. If not see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef JIT_PLAYBACK_H
|
||||
#define JIT_PLAYBACK_H
|
||||
|
||||
#include <utility> // for std::pair
|
||||
|
||||
#include "jit-recording.h"
|
||||
|
||||
namespace gcc {
|
||||
|
||||
namespace jit {
|
||||
|
||||
/**********************************************************************
|
||||
Playback.
|
||||
**********************************************************************/
|
||||
|
||||
namespace playback {
|
||||
|
||||
class context
|
||||
{
|
||||
public:
|
||||
context (::gcc::jit::recording::context *ctxt);
|
||||
~context ();
|
||||
|
||||
void gt_ggc_mx ();
|
||||
|
||||
void replay ();
|
||||
|
||||
location *
|
||||
new_location (recording::location *rloc,
|
||||
const char *filename,
|
||||
int line,
|
||||
int column);
|
||||
|
||||
type *
|
||||
get_type (enum gcc_jit_types type);
|
||||
|
||||
type *
|
||||
new_array_type (location *loc,
|
||||
type *element_type,
|
||||
int num_elements);
|
||||
|
||||
field *
|
||||
new_field (location *loc,
|
||||
type *type,
|
||||
const char *name);
|
||||
|
||||
compound_type *
|
||||
new_compound_type (location *loc,
|
||||
const char *name,
|
||||
bool is_struct); /* else is union */
|
||||
|
||||
type *
|
||||
new_function_type (type *return_type,
|
||||
vec<type *> *param_types,
|
||||
int is_variadic);
|
||||
|
||||
param *
|
||||
new_param (location *loc,
|
||||
type *type,
|
||||
const char *name);
|
||||
|
||||
function *
|
||||
new_function (location *loc,
|
||||
enum gcc_jit_function_kind kind,
|
||||
type *return_type,
|
||||
const char *name,
|
||||
vec<param *> *params,
|
||||
int is_variadic,
|
||||
enum built_in_function builtin_id);
|
||||
|
||||
lvalue *
|
||||
new_global (location *loc,
|
||||
type *type,
|
||||
const char *name);
|
||||
|
||||
rvalue *
|
||||
new_rvalue_from_int (type *type,
|
||||
int value);
|
||||
|
||||
rvalue *
|
||||
new_rvalue_from_double (type *type,
|
||||
double value);
|
||||
|
||||
rvalue *
|
||||
new_rvalue_from_ptr (type *type,
|
||||
void *value);
|
||||
|
||||
rvalue *
|
||||
new_string_literal (const char *value);
|
||||
|
||||
rvalue *
|
||||
new_unary_op (location *loc,
|
||||
enum gcc_jit_unary_op op,
|
||||
type *result_type,
|
||||
rvalue *a);
|
||||
|
||||
rvalue *
|
||||
new_binary_op (location *loc,
|
||||
enum gcc_jit_binary_op op,
|
||||
type *result_type,
|
||||
rvalue *a, rvalue *b);
|
||||
|
||||
rvalue *
|
||||
new_comparison (location *loc,
|
||||
enum gcc_jit_comparison op,
|
||||
rvalue *a, rvalue *b);
|
||||
|
||||
rvalue *
|
||||
new_call (location *loc,
|
||||
function *func,
|
||||
vec<rvalue *> args);
|
||||
|
||||
rvalue *
|
||||
new_call_through_ptr (location *loc,
|
||||
rvalue *fn_ptr,
|
||||
vec<rvalue *> args);
|
||||
|
||||
rvalue *
|
||||
new_cast (location *loc,
|
||||
rvalue *expr,
|
||||
type *type_);
|
||||
|
||||
lvalue *
|
||||
new_array_access (location *loc,
|
||||
rvalue *ptr,
|
||||
rvalue *index);
|
||||
|
||||
void
|
||||
set_str_option (enum gcc_jit_str_option opt,
|
||||
const char *value);
|
||||
|
||||
void
|
||||
set_int_option (enum gcc_jit_int_option opt,
|
||||
int value);
|
||||
|
||||
void
|
||||
set_bool_option (enum gcc_jit_bool_option opt,
|
||||
int value);
|
||||
|
||||
const char *
|
||||
get_str_option (enum gcc_jit_str_option opt) const
|
||||
{
|
||||
return m_recording_ctxt->get_str_option (opt);
|
||||
}
|
||||
|
||||
int
|
||||
get_int_option (enum gcc_jit_int_option opt) const
|
||||
{
|
||||
return m_recording_ctxt->get_int_option (opt);
|
||||
}
|
||||
|
||||
int
|
||||
get_bool_option (enum gcc_jit_bool_option opt) const
|
||||
{
|
||||
return m_recording_ctxt->get_bool_option (opt);
|
||||
}
|
||||
|
||||
result *
|
||||
compile ();
|
||||
|
||||
void
|
||||
add_error (location *loc, const char *fmt, ...)
|
||||
GNU_PRINTF(3, 4);
|
||||
|
||||
void
|
||||
add_error_va (location *loc, const char *fmt, va_list ap)
|
||||
GNU_PRINTF(3, 0);
|
||||
|
||||
const char *
|
||||
get_first_error () const;
|
||||
|
||||
void
|
||||
set_tree_location (tree t, location *loc);
|
||||
|
||||
tree
|
||||
new_field_access (location *loc,
|
||||
tree datum,
|
||||
field *field);
|
||||
|
||||
tree
|
||||
new_dereference (tree ptr, location *loc);
|
||||
|
||||
tree
|
||||
as_truth_value (tree expr, location *loc);
|
||||
|
||||
bool errors_occurred () const
|
||||
{
|
||||
return m_recording_ctxt->errors_occurred ();
|
||||
}
|
||||
|
||||
private:
|
||||
void dump_generated_code ();
|
||||
|
||||
rvalue *
|
||||
build_call (location *loc,
|
||||
tree fn_ptr,
|
||||
vec<rvalue *> args);
|
||||
|
||||
tree
|
||||
build_cast (location *loc,
|
||||
rvalue *expr,
|
||||
type *type_);
|
||||
|
||||
source_file *
|
||||
get_source_file (const char *filename);
|
||||
|
||||
void handle_locations ();
|
||||
|
||||
private:
|
||||
::gcc::jit::recording::context *m_recording_ctxt;
|
||||
|
||||
/* Allocated using xmalloc (by xstrdup). */
|
||||
char *m_path_template;
|
||||
|
||||
/* This either aliases m_path_template, or is NULL. */
|
||||
char *m_path_tempdir;
|
||||
|
||||
/* The following are allocated using xmalloc. */
|
||||
char *m_path_c_file;
|
||||
char *m_path_s_file;
|
||||
char *m_path_so_file;
|
||||
|
||||
vec<function *> m_functions;
|
||||
tree m_char_array_type_node;
|
||||
tree m_const_char_ptr;
|
||||
|
||||
/* Source location handling. */
|
||||
vec<source_file *> m_source_files;
|
||||
|
||||
vec<std::pair<tree, location *> > m_cached_locations;
|
||||
};
|
||||
|
||||
/* A temporary wrapper object.
|
||||
These objects are (mostly) only valid during replay.
|
||||
We allocate them on the GC heap, so that they will be cleaned
|
||||
the next time the GC collects.
|
||||
The exception is the "function" class, which is tracked and marked by
|
||||
the jit::context, since it needs to stay alive during post-processing
|
||||
(when the GC could run). */
|
||||
class wrapper
|
||||
{
|
||||
public:
|
||||
/* Allocate in the GC heap. */
|
||||
void *operator new (size_t sz);
|
||||
|
||||
};
|
||||
|
||||
class type : public wrapper
|
||||
{
|
||||
public:
|
||||
type (tree inner)
|
||||
: m_inner(inner)
|
||||
{}
|
||||
|
||||
tree as_tree () const { return m_inner; }
|
||||
|
||||
type *get_pointer () const { return new type (build_pointer_type (m_inner)); }
|
||||
|
||||
type *get_const () const
|
||||
{
|
||||
return new type (build_qualified_type (m_inner, TYPE_QUAL_CONST));
|
||||
}
|
||||
|
||||
type *get_volatile () const
|
||||
{
|
||||
return new type (build_qualified_type (m_inner, TYPE_QUAL_VOLATILE));
|
||||
}
|
||||
|
||||
private:
|
||||
tree m_inner;
|
||||
};
|
||||
|
||||
class compound_type : public type
|
||||
{
|
||||
public:
|
||||
compound_type (tree inner)
|
||||
: type (inner)
|
||||
{}
|
||||
|
||||
void set_fields (const vec<field *> &fields);
|
||||
};
|
||||
|
||||
class field : public wrapper
|
||||
{
|
||||
public:
|
||||
field (tree inner)
|
||||
: m_inner(inner)
|
||||
{}
|
||||
|
||||
tree as_tree () const { return m_inner; }
|
||||
|
||||
private:
|
||||
tree m_inner;
|
||||
};
|
||||
|
||||
class function : public wrapper
|
||||
{
|
||||
public:
|
||||
function(context *ctxt, tree fndecl, enum gcc_jit_function_kind kind);
|
||||
|
||||
void gt_ggc_mx ();
|
||||
|
||||
tree get_return_type_as_tree () const;
|
||||
|
||||
tree as_fndecl () const { return m_inner_fndecl; }
|
||||
|
||||
enum gcc_jit_function_kind get_kind () const { return m_kind; }
|
||||
|
||||
lvalue *
|
||||
new_local (location *loc,
|
||||
type *type,
|
||||
const char *name);
|
||||
|
||||
block*
|
||||
new_block (const char *name);
|
||||
|
||||
void
|
||||
build_stmt_list ();
|
||||
|
||||
void
|
||||
postprocess ();
|
||||
|
||||
public:
|
||||
context *m_ctxt;
|
||||
|
||||
public:
|
||||
void
|
||||
set_tree_location (tree t, location *loc)
|
||||
{
|
||||
m_ctxt->set_tree_location (t, loc);
|
||||
}
|
||||
|
||||
private:
|
||||
tree m_inner_fndecl;
|
||||
tree m_inner_block;
|
||||
tree m_inner_bind_expr;
|
||||
enum gcc_jit_function_kind m_kind;
|
||||
tree m_stmt_list;
|
||||
tree_stmt_iterator m_stmt_iter;
|
||||
vec<block *> m_blocks;
|
||||
};
|
||||
|
||||
class block : public wrapper
|
||||
{
|
||||
public:
|
||||
block (function *func,
|
||||
const char *name);
|
||||
|
||||
tree as_label_decl () const { return m_label_decl; }
|
||||
|
||||
void
|
||||
add_eval (location *loc,
|
||||
rvalue *rvalue);
|
||||
|
||||
void
|
||||
add_assignment (location *loc,
|
||||
lvalue *lvalue,
|
||||
rvalue *rvalue);
|
||||
|
||||
void
|
||||
add_comment (location *loc,
|
||||
const char *text);
|
||||
|
||||
void
|
||||
add_conditional (location *loc,
|
||||
rvalue *boolval,
|
||||
block *on_true,
|
||||
block *on_false);
|
||||
|
||||
block *
|
||||
add_block (location *loc,
|
||||
const char *name);
|
||||
|
||||
void
|
||||
add_jump (location *loc,
|
||||
block *target);
|
||||
|
||||
void
|
||||
add_return (location *loc,
|
||||
rvalue *rvalue);
|
||||
|
||||
private:
|
||||
void
|
||||
set_tree_location (tree t, location *loc)
|
||||
{
|
||||
m_func->set_tree_location (t, loc);
|
||||
}
|
||||
|
||||
void add_stmt (tree stmt)
|
||||
{
|
||||
/* TODO: use one stmt_list per block. */
|
||||
m_stmts.safe_push (stmt);
|
||||
}
|
||||
|
||||
private:
|
||||
function *m_func;
|
||||
tree m_label_decl;
|
||||
vec<tree> m_stmts;
|
||||
|
||||
public: // for now
|
||||
tree m_label_expr;
|
||||
|
||||
friend class function;
|
||||
};
|
||||
|
||||
class rvalue : public wrapper
|
||||
{
|
||||
public:
|
||||
rvalue (context *ctxt, tree inner)
|
||||
: m_ctxt (ctxt),
|
||||
m_inner (inner)
|
||||
{}
|
||||
|
||||
rvalue *
|
||||
as_rvalue () { return this; }
|
||||
|
||||
tree as_tree () const { return m_inner; }
|
||||
|
||||
context *get_context () const { return m_ctxt; }
|
||||
|
||||
type *
|
||||
get_type () { return new type (TREE_TYPE (m_inner)); }
|
||||
|
||||
rvalue *
|
||||
access_field (location *loc,
|
||||
field *field);
|
||||
|
||||
lvalue *
|
||||
dereference_field (location *loc,
|
||||
field *field);
|
||||
|
||||
lvalue *
|
||||
dereference (location *loc);
|
||||
|
||||
private:
|
||||
context *m_ctxt;
|
||||
tree m_inner;
|
||||
};
|
||||
|
||||
class lvalue : public rvalue
|
||||
{
|
||||
public:
|
||||
lvalue (context *ctxt, tree inner)
|
||||
: rvalue(ctxt, inner)
|
||||
{}
|
||||
|
||||
lvalue *
|
||||
as_lvalue () { return this; }
|
||||
|
||||
lvalue *
|
||||
access_field (location *loc,
|
||||
field *field);
|
||||
|
||||
rvalue *
|
||||
get_address (location *loc);
|
||||
|
||||
};
|
||||
|
||||
class param : public lvalue
|
||||
{
|
||||
public:
|
||||
param (context *ctxt, tree inner)
|
||||
: lvalue(ctxt, inner)
|
||||
{}
|
||||
};
|
||||
|
||||
/* Dealing with the linemap API.
|
||||
|
||||
It appears that libcpp requires locations to be created as if by
|
||||
a tokenizer, creating them by filename, in ascending order of
|
||||
line/column, whereas our API doesn't impose any such constraints:
|
||||
we allow client code to create locations in arbitrary orders.
|
||||
|
||||
To square this circle, we need to cache all location creation,
|
||||
grouping things up by filename/line, and then creating the linemap
|
||||
entries in a post-processing phase. */
|
||||
|
||||
/* A set of locations, all sharing a filename */
|
||||
class source_file : public wrapper
|
||||
{
|
||||
public:
|
||||
source_file (tree filename);
|
||||
|
||||
source_line *
|
||||
get_source_line (int line_num);
|
||||
|
||||
tree filename_as_tree () const { return m_filename; }
|
||||
|
||||
const char*
|
||||
get_filename () const { return IDENTIFIER_POINTER (m_filename); }
|
||||
|
||||
vec<source_line *> m_source_lines;
|
||||
|
||||
private:
|
||||
tree m_filename;
|
||||
};
|
||||
|
||||
/* A source line, with one or more locations of interest. */
|
||||
class source_line : public wrapper
|
||||
{
|
||||
public:
|
||||
source_line (source_file *file, int line_num);
|
||||
|
||||
location *
|
||||
get_location (recording::location *rloc, int column_num);
|
||||
|
||||
int get_line_num () const { return m_line_num; }
|
||||
|
||||
vec<location *> m_locations;
|
||||
|
||||
private:
|
||||
source_file *m_source_file;
|
||||
int m_line_num;
|
||||
};
|
||||
|
||||
/* A specific location on a source line. This is what we expose
|
||||
to the client API. */
|
||||
class location : public wrapper
|
||||
{
|
||||
public:
|
||||
location (recording::location *loc, source_line *line, int column_num);
|
||||
|
||||
int get_column_num () const { return m_column_num; }
|
||||
|
||||
recording::location *get_recording_loc () const { return m_recording_loc; }
|
||||
|
||||
source_location m_srcloc;
|
||||
|
||||
private:
|
||||
recording::location *m_recording_loc;
|
||||
source_line *m_line;
|
||||
int m_column_num;
|
||||
};
|
||||
|
||||
} // namespace gcc::jit::playback
|
||||
|
||||
extern playback::context *active_playback_ctxt;
|
||||
|
||||
} // namespace gcc::jit
|
||||
|
||||
} // namespace gcc
|
||||
|
||||
#endif /* JIT_PLAYBACK_H */
|
||||
|
3434
gcc/jit/jit-recording.c
Normal file
3434
gcc/jit/jit-recording.c
Normal file
File diff suppressed because it is too large
Load Diff
1593
gcc/jit/jit-recording.h
Normal file
1593
gcc/jit/jit-recording.h
Normal file
File diff suppressed because it is too large
Load Diff
1574
gcc/jit/libgccjit++.h
Normal file
1574
gcc/jit/libgccjit++.h
Normal file
File diff suppressed because it is too large
Load Diff
2074
gcc/jit/libgccjit.c
Normal file
2074
gcc/jit/libgccjit.c
Normal file
File diff suppressed because it is too large
Load Diff
986
gcc/jit/libgccjit.h
Normal file
986
gcc/jit/libgccjit.h
Normal file
@ -0,0 +1,986 @@
|
||||
/* A pure C API to enable client code to embed GCC as a JIT-compiler.
|
||||
Copyright (C) 2013-2014 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GCC.
|
||||
|
||||
GCC is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3, or (at your option)
|
||||
any later version.
|
||||
|
||||
GCC is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GCC; see the file COPYING3. If not see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef LIBGCCJIT_H
|
||||
#define LIBGCCJIT_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/**********************************************************************
|
||||
Data structures.
|
||||
**********************************************************************/
|
||||
/* All structs within the API are opaque. */
|
||||
|
||||
/* A gcc_jit_context encapsulates the state of a compilation. It goes
|
||||
through two states:
|
||||
|
||||
(1) "initial", during which you can set up options on it, and add
|
||||
types, functions and code, using the API below.
|
||||
Invoking gcc_jit_context_compile on it transitions it to the
|
||||
"after compilation" state.
|
||||
|
||||
(2) "after compilation", when you can call gcc_jit_context_release to
|
||||
clean up. */
|
||||
typedef struct gcc_jit_context gcc_jit_context;
|
||||
|
||||
/* A gcc_jit_result encapsulates the result of a compilation. */
|
||||
typedef struct gcc_jit_result gcc_jit_result;
|
||||
|
||||
/* An object created within a context. Such objects are automatically
|
||||
cleaned up when the context is released.
|
||||
|
||||
The class hierarchy looks like this:
|
||||
|
||||
+- gcc_jit_object
|
||||
+- gcc_jit_location
|
||||
+- gcc_jit_type
|
||||
+- gcc_jit_struct
|
||||
+- gcc_jit_field
|
||||
+- gcc_jit_function
|
||||
+- gcc_jit_block
|
||||
+- gcc_jit_rvalue
|
||||
+- gcc_jit_lvalue
|
||||
+- gcc_jit_param
|
||||
*/
|
||||
typedef struct gcc_jit_object gcc_jit_object;
|
||||
|
||||
/* A gcc_jit_location encapsulates a source code location, so that
|
||||
you can (optionally) associate locations in your language with
|
||||
statements in the JIT-compiled code, allowing the debugger to
|
||||
single-step through your language.
|
||||
|
||||
Note that to do so, you also need to enable
|
||||
GCC_JIT_BOOL_OPTION_DEBUGINFO
|
||||
on the gcc_jit_context.
|
||||
|
||||
gcc_jit_location instances are optional; you can always pass
|
||||
NULL. */
|
||||
typedef struct gcc_jit_location gcc_jit_location;
|
||||
|
||||
/* A gcc_jit_type encapsulates a type e.g. "int" or a "struct foo*". */
|
||||
typedef struct gcc_jit_type gcc_jit_type;
|
||||
|
||||
/* A gcc_jit_field encapsulates a field within a struct; it is used
|
||||
when creating a struct type (using gcc_jit_context_new_struct_type).
|
||||
Fields cannot be shared between structs. */
|
||||
typedef struct gcc_jit_field gcc_jit_field;
|
||||
|
||||
/* A gcc_jit_struct encapsulates a struct type, either one that we have
|
||||
the layout for, or an opaque type. */
|
||||
typedef struct gcc_jit_struct gcc_jit_struct;
|
||||
|
||||
/* A gcc_jit_function encapsulates a function: either one that you're
|
||||
creating yourself, or a reference to one that you're dynamically
|
||||
linking to within the rest of the process. */
|
||||
typedef struct gcc_jit_function gcc_jit_function;
|
||||
|
||||
/* A gcc_jit_block encapsulates a "basic block" of statements within a
|
||||
function (i.e. with one entry point and one exit point).
|
||||
|
||||
Every block within a function must be terminated with a conditional,
|
||||
a branch, or a return.
|
||||
|
||||
The blocks within a function form a directed graph.
|
||||
|
||||
The entrypoint to the function is the first block created within
|
||||
it.
|
||||
|
||||
All of the blocks in a function must be reachable via some path from
|
||||
the first block.
|
||||
|
||||
It's OK to have more than one "return" from a function (i.e. multiple
|
||||
blocks that terminate by returning). */
|
||||
typedef struct gcc_jit_block gcc_jit_block;
|
||||
|
||||
/* A gcc_jit_rvalue is an expression within your code, with some type. */
|
||||
typedef struct gcc_jit_rvalue gcc_jit_rvalue;
|
||||
|
||||
/* A gcc_jit_lvalue is a storage location within your code (e.g. a
|
||||
variable, a parameter, etc). It is also a gcc_jit_rvalue; use
|
||||
gcc_jit_lvalue_as_rvalue to cast. */
|
||||
typedef struct gcc_jit_lvalue gcc_jit_lvalue;
|
||||
|
||||
/* A gcc_jit_param is a function parameter, used when creating a
|
||||
gcc_jit_function. It is also a gcc_jit_lvalue (and thus also an
|
||||
rvalue); use gcc_jit_param_as_lvalue to convert. */
|
||||
typedef struct gcc_jit_param gcc_jit_param;
|
||||
|
||||
/* Acquire a JIT-compilation context. */
|
||||
extern gcc_jit_context *
|
||||
gcc_jit_context_acquire (void);
|
||||
|
||||
/* Release the context. After this call, it's no longer valid to use
|
||||
the ctxt. */
|
||||
extern void
|
||||
gcc_jit_context_release (gcc_jit_context *ctxt);
|
||||
|
||||
/* Options taking string values. */
|
||||
enum gcc_jit_str_option
|
||||
{
|
||||
/* The name of the program, for use as a prefix when printing error
|
||||
messages to stderr. If NULL, or default, "libgccjit.so" is used. */
|
||||
GCC_JIT_STR_OPTION_PROGNAME,
|
||||
|
||||
GCC_JIT_NUM_STR_OPTIONS
|
||||
};
|
||||
|
||||
/* Options taking int values. */
|
||||
enum gcc_jit_int_option
|
||||
{
|
||||
/* How much to optimize the code.
|
||||
Valid values are 0-3, corresponding to GCC's command-line options
|
||||
-O0 through -O3.
|
||||
|
||||
The default value is 0 (unoptimized). */
|
||||
GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL,
|
||||
|
||||
GCC_JIT_NUM_INT_OPTIONS
|
||||
};
|
||||
|
||||
/* Options taking boolean values.
|
||||
These all default to "false". */
|
||||
enum gcc_jit_bool_option
|
||||
{
|
||||
/* If true, gcc_jit_context_compile will attempt to do the right
|
||||
thing so that if you attach a debugger to the process, it will
|
||||
be able to inspect variables and step through your code.
|
||||
|
||||
Note that you can't step through code unless you set up source
|
||||
location information for the code (by creating and passing in
|
||||
gcc_jit_location instances). */
|
||||
GCC_JIT_BOOL_OPTION_DEBUGINFO,
|
||||
|
||||
/* If true, gcc_jit_context_compile will dump its initial "tree"
|
||||
representation of your code to stderr (before any
|
||||
optimizations). */
|
||||
GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE,
|
||||
|
||||
/* If true, gcc_jit_context_compile will dump the "gimple"
|
||||
representation of your code to stderr, before any optimizations
|
||||
are performed. The dump resembles C code. */
|
||||
GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE,
|
||||
|
||||
/* If true, gcc_jit_context_compile will dump the final
|
||||
generated code to stderr, in the form of assembly language. */
|
||||
GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE,
|
||||
|
||||
/* If true, gcc_jit_context_compile will print information to stderr
|
||||
on the actions it is performing, followed by a profile showing
|
||||
the time taken and memory usage of each phase.
|
||||
*/
|
||||
GCC_JIT_BOOL_OPTION_DUMP_SUMMARY,
|
||||
|
||||
/* If true, gcc_jit_context_compile will dump copious
|
||||
amount of information on what it's doing to various
|
||||
files within a temporary directory. Use
|
||||
GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES (see below) to
|
||||
see the results. The files are intended to be human-readable,
|
||||
but the exact files and their formats are subject to change.
|
||||
*/
|
||||
GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING,
|
||||
|
||||
/* If true, libgccjit will aggressively run its garbage collector, to
|
||||
shake out bugs (greatly slowing down the compile). This is likely
|
||||
to only be of interest to developers *of* the library. It is
|
||||
used when running the selftest suite. */
|
||||
GCC_JIT_BOOL_OPTION_SELFCHECK_GC,
|
||||
|
||||
/* If true, gcc_jit_context_release will not clean up
|
||||
intermediate files written to the filesystem, and will display
|
||||
their location on stderr. */
|
||||
GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES,
|
||||
|
||||
GCC_JIT_NUM_BOOL_OPTIONS
|
||||
};
|
||||
|
||||
/* Set a string option on the given context.
|
||||
|
||||
The context directly stores the (const char *), so the passed string
|
||||
must outlive the context. */
|
||||
extern void
|
||||
gcc_jit_context_set_str_option (gcc_jit_context *ctxt,
|
||||
enum gcc_jit_str_option opt,
|
||||
const char *value);
|
||||
|
||||
/* Set an int option on the given context. */
|
||||
extern void
|
||||
gcc_jit_context_set_int_option (gcc_jit_context *ctxt,
|
||||
enum gcc_jit_int_option opt,
|
||||
int value);
|
||||
|
||||
/* Set a boolean option on the given context.
|
||||
|
||||
Zero is "false" (the default), non-zero is "true". */
|
||||
extern void
|
||||
gcc_jit_context_set_bool_option (gcc_jit_context *ctxt,
|
||||
enum gcc_jit_bool_option opt,
|
||||
int value);
|
||||
|
||||
/* This actually calls into GCC and runs the build, all
|
||||
in a mutex for now. The result is a wrapper around a .so file.
|
||||
It can only be called once on a given context. */
|
||||
extern gcc_jit_result *
|
||||
gcc_jit_context_compile (gcc_jit_context *ctxt);
|
||||
|
||||
/* To help with debugging: dump a C-like representation to the given path,
|
||||
describing what's been set up on the context.
|
||||
|
||||
If "update_locations" is true, then also set up gcc_jit_location
|
||||
information throughout the context, pointing at the dump file as if it
|
||||
were a source file. This may be of use in conjunction with
|
||||
GCC_JIT_BOOL_OPTION_DEBUGINFO to allow stepping through the code in a
|
||||
debugger. */
|
||||
extern void
|
||||
gcc_jit_context_dump_to_file (gcc_jit_context *ctxt,
|
||||
const char *path,
|
||||
int update_locations);
|
||||
|
||||
/* To be called after a compile, this gives the first error message
|
||||
that occurred on the context.
|
||||
|
||||
The returned string is valid for the rest of the lifetime of the
|
||||
context.
|
||||
|
||||
If no errors occurred, this will be NULL. */
|
||||
extern const char *
|
||||
gcc_jit_context_get_first_error (gcc_jit_context *ctxt);
|
||||
|
||||
/* Locate a given function within the built machine code.
|
||||
This will need to be cast to a function pointer of the
|
||||
correct type before it can be called. */
|
||||
extern void *
|
||||
gcc_jit_result_get_code (gcc_jit_result *result,
|
||||
const char *funcname);
|
||||
|
||||
/* Once we're done with the code, this unloads the built .so file.
|
||||
This cleans up the result; after calling this, it's no longer
|
||||
valid to use the result. */
|
||||
extern void
|
||||
gcc_jit_result_release (gcc_jit_result *result);
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
Functions for creating "contextual" objects.
|
||||
|
||||
All objects created by these functions share the lifetime of the context
|
||||
they are created within, and are automatically cleaned up for you when
|
||||
you call gcc_jit_context_release on the context.
|
||||
|
||||
Note that this means you can't use references to them after you've
|
||||
released their context.
|
||||
|
||||
All (const char *) string arguments passed to these functions are
|
||||
copied, so you don't need to keep them around. Note that this *isn't*
|
||||
the case for other parts of the API.
|
||||
|
||||
You create code by adding a sequence of statements to blocks.
|
||||
**********************************************************************/
|
||||
|
||||
/**********************************************************************
|
||||
The base class of "contextual" object.
|
||||
**********************************************************************/
|
||||
/* Which context is "obj" within? */
|
||||
extern gcc_jit_context *
|
||||
gcc_jit_object_get_context (gcc_jit_object *obj);
|
||||
|
||||
/* Get a human-readable description of this object.
|
||||
The string buffer is created the first time this is called on a given
|
||||
object, and persists until the object's context is released. */
|
||||
extern const char *
|
||||
gcc_jit_object_get_debug_string (gcc_jit_object *obj);
|
||||
|
||||
/**********************************************************************
|
||||
Debugging information.
|
||||
**********************************************************************/
|
||||
|
||||
/* Creating source code locations for use by the debugger.
|
||||
Line and column numbers are 1-based. */
|
||||
extern gcc_jit_location *
|
||||
gcc_jit_context_new_location (gcc_jit_context *ctxt,
|
||||
const char *filename,
|
||||
int line,
|
||||
int column);
|
||||
|
||||
/* Upcasting from location to object. */
|
||||
extern gcc_jit_object *
|
||||
gcc_jit_location_as_object (gcc_jit_location *loc);
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
Types.
|
||||
**********************************************************************/
|
||||
|
||||
/* Upcasting from type to object. */
|
||||
extern gcc_jit_object *
|
||||
gcc_jit_type_as_object (gcc_jit_type *type);
|
||||
|
||||
/* Access to specific types. */
|
||||
enum gcc_jit_types
|
||||
{
|
||||
/* C's "void" type. */
|
||||
GCC_JIT_TYPE_VOID,
|
||||
|
||||
/* "void *". */
|
||||
GCC_JIT_TYPE_VOID_PTR,
|
||||
|
||||
/* C++'s bool type; also C99's "_Bool" type, aka "bool" if using
|
||||
stdbool.h. */
|
||||
GCC_JIT_TYPE_BOOL,
|
||||
|
||||
/* Various integer types. */
|
||||
|
||||
/* C's "char" (of some signedness) and the variants where the
|
||||
signedness is specified. */
|
||||
GCC_JIT_TYPE_CHAR,
|
||||
GCC_JIT_TYPE_SIGNED_CHAR,
|
||||
GCC_JIT_TYPE_UNSIGNED_CHAR,
|
||||
|
||||
/* C's "short" and "unsigned short". */
|
||||
GCC_JIT_TYPE_SHORT, /* signed */
|
||||
GCC_JIT_TYPE_UNSIGNED_SHORT,
|
||||
|
||||
/* C's "int" and "unsigned int". */
|
||||
GCC_JIT_TYPE_INT, /* signed */
|
||||
GCC_JIT_TYPE_UNSIGNED_INT,
|
||||
|
||||
/* C's "long" and "unsigned long". */
|
||||
GCC_JIT_TYPE_LONG, /* signed */
|
||||
GCC_JIT_TYPE_UNSIGNED_LONG,
|
||||
|
||||
/* C99's "long long" and "unsigned long long". */
|
||||
GCC_JIT_TYPE_LONG_LONG, /* signed */
|
||||
GCC_JIT_TYPE_UNSIGNED_LONG_LONG,
|
||||
|
||||
/* Floating-point types */
|
||||
|
||||
GCC_JIT_TYPE_FLOAT,
|
||||
GCC_JIT_TYPE_DOUBLE,
|
||||
GCC_JIT_TYPE_LONG_DOUBLE,
|
||||
|
||||
/* C type: (const char *). */
|
||||
GCC_JIT_TYPE_CONST_CHAR_PTR,
|
||||
|
||||
/* The C "size_t" type. */
|
||||
GCC_JIT_TYPE_SIZE_T,
|
||||
|
||||
/* C type: (FILE *) */
|
||||
GCC_JIT_TYPE_FILE_PTR
|
||||
};
|
||||
|
||||
extern gcc_jit_type *
|
||||
gcc_jit_context_get_type (gcc_jit_context *ctxt,
|
||||
enum gcc_jit_types type_);
|
||||
|
||||
/* Get the integer type of the given size and signedness. */
|
||||
extern gcc_jit_type *
|
||||
gcc_jit_context_get_int_type (gcc_jit_context *ctxt,
|
||||
int num_bytes, int is_signed);
|
||||
|
||||
/* Constructing new types. */
|
||||
|
||||
/* Given type "T", get type "T*". */
|
||||
extern gcc_jit_type *
|
||||
gcc_jit_type_get_pointer (gcc_jit_type *type);
|
||||
|
||||
/* Given type "T", get type "const T". */
|
||||
extern gcc_jit_type *
|
||||
gcc_jit_type_get_const (gcc_jit_type *type);
|
||||
|
||||
/* Given type "T", get type "volatile T". */
|
||||
extern gcc_jit_type *
|
||||
gcc_jit_type_get_volatile (gcc_jit_type *type);
|
||||
|
||||
/* Given type "T", get type "T[N]" (for a constant N). */
|
||||
extern gcc_jit_type *
|
||||
gcc_jit_context_new_array_type (gcc_jit_context *ctxt,
|
||||
gcc_jit_location *loc,
|
||||
gcc_jit_type *element_type,
|
||||
int num_elements);
|
||||
|
||||
/* Struct-handling. */
|
||||
|
||||
/* Create a field, for use within a struct or union. */
|
||||
extern gcc_jit_field *
|
||||
gcc_jit_context_new_field (gcc_jit_context *ctxt,
|
||||
gcc_jit_location *loc,
|
||||
gcc_jit_type *type,
|
||||
const char *name);
|
||||
|
||||
/* Upcasting from field to object. */
|
||||
extern gcc_jit_object *
|
||||
gcc_jit_field_as_object (gcc_jit_field *field);
|
||||
|
||||
/* Create a struct type from an array of fields. */
|
||||
extern gcc_jit_struct *
|
||||
gcc_jit_context_new_struct_type (gcc_jit_context *ctxt,
|
||||
gcc_jit_location *loc,
|
||||
const char *name,
|
||||
int num_fields,
|
||||
gcc_jit_field **fields);
|
||||
|
||||
/* Create an opaque struct type. */
|
||||
extern gcc_jit_struct *
|
||||
gcc_jit_context_new_opaque_struct (gcc_jit_context *ctxt,
|
||||
gcc_jit_location *loc,
|
||||
const char *name);
|
||||
|
||||
/* Upcast a struct to a type. */
|
||||
extern gcc_jit_type *
|
||||
gcc_jit_struct_as_type (gcc_jit_struct *struct_type);
|
||||
|
||||
/* Populating the fields of a formerly-opaque struct type.
|
||||
This can only be called once on a given struct type. */
|
||||
extern void
|
||||
gcc_jit_struct_set_fields (gcc_jit_struct *struct_type,
|
||||
gcc_jit_location *loc,
|
||||
int num_fields,
|
||||
gcc_jit_field **fields);
|
||||
|
||||
/* Unions work similarly to structs. */
|
||||
extern gcc_jit_type *
|
||||
gcc_jit_context_new_union_type (gcc_jit_context *ctxt,
|
||||
gcc_jit_location *loc,
|
||||
const char *name,
|
||||
int num_fields,
|
||||
gcc_jit_field **fields);
|
||||
|
||||
/* Function pointers. */
|
||||
|
||||
extern gcc_jit_type *
|
||||
gcc_jit_context_new_function_ptr_type (gcc_jit_context *ctxt,
|
||||
gcc_jit_location *loc,
|
||||
gcc_jit_type *return_type,
|
||||
int num_params,
|
||||
gcc_jit_type **param_types,
|
||||
int is_variadic);
|
||||
|
||||
/**********************************************************************
|
||||
Constructing functions.
|
||||
**********************************************************************/
|
||||
/* Create a function param. */
|
||||
extern gcc_jit_param *
|
||||
gcc_jit_context_new_param (gcc_jit_context *ctxt,
|
||||
gcc_jit_location *loc,
|
||||
gcc_jit_type *type,
|
||||
const char *name);
|
||||
|
||||
/* Upcasting from param to object. */
|
||||
extern gcc_jit_object *
|
||||
gcc_jit_param_as_object (gcc_jit_param *param);
|
||||
|
||||
/* Upcasting from param to lvalue. */
|
||||
extern gcc_jit_lvalue *
|
||||
gcc_jit_param_as_lvalue (gcc_jit_param *param);
|
||||
|
||||
/* Upcasting from param to rvalue. */
|
||||
extern gcc_jit_rvalue *
|
||||
gcc_jit_param_as_rvalue (gcc_jit_param *param);
|
||||
|
||||
/* Kinds of function. */
|
||||
enum gcc_jit_function_kind
|
||||
{
|
||||
/* Function is defined by the client code and visible
|
||||
by name outside of the JIT. */
|
||||
GCC_JIT_FUNCTION_EXPORTED,
|
||||
|
||||
/* Function is defined by the client code, but is invisible
|
||||
outside of the JIT. Analogous to a "static" function. */
|
||||
GCC_JIT_FUNCTION_INTERNAL,
|
||||
|
||||
/* Function is not defined by the client code; we're merely
|
||||
referring to it. Analogous to using an "extern" function from a
|
||||
header file. */
|
||||
GCC_JIT_FUNCTION_IMPORTED,
|
||||
|
||||
/* Function is only ever inlined into other functions, and is
|
||||
invisible outside of the JIT.
|
||||
|
||||
Analogous to prefixing with "inline" and adding
|
||||
__attribute__((always_inline)).
|
||||
|
||||
Inlining will only occur when the optimization level is
|
||||
above 0; when optimization is off, this is essentially the
|
||||
same as GCC_JIT_FUNCTION_INTERNAL. */
|
||||
GCC_JIT_FUNCTION_ALWAYS_INLINE
|
||||
};
|
||||
|
||||
/* Create a function. */
|
||||
extern gcc_jit_function *
|
||||
gcc_jit_context_new_function (gcc_jit_context *ctxt,
|
||||
gcc_jit_location *loc,
|
||||
enum gcc_jit_function_kind kind,
|
||||
gcc_jit_type *return_type,
|
||||
const char *name,
|
||||
int num_params,
|
||||
gcc_jit_param **params,
|
||||
int is_variadic);
|
||||
|
||||
/* Create a reference to a builtin function (sometimes called
|
||||
intrinsic functions). */
|
||||
extern gcc_jit_function *
|
||||
gcc_jit_context_get_builtin_function (gcc_jit_context *ctxt,
|
||||
const char *name);
|
||||
|
||||
/* Upcasting from function to object. */
|
||||
extern gcc_jit_object *
|
||||
gcc_jit_function_as_object (gcc_jit_function *func);
|
||||
|
||||
/* Get a specific param of a function by index. */
|
||||
extern gcc_jit_param *
|
||||
gcc_jit_function_get_param (gcc_jit_function *func, int index);
|
||||
|
||||
/* Emit the function in graphviz format. */
|
||||
extern void
|
||||
gcc_jit_function_dump_to_dot (gcc_jit_function *func,
|
||||
const char *path);
|
||||
|
||||
/* Create a block.
|
||||
|
||||
The name can be NULL, or you can give it a meaningful name, which
|
||||
may show up in dumps of the internal representation, and in error
|
||||
messages. */
|
||||
extern gcc_jit_block *
|
||||
gcc_jit_function_new_block (gcc_jit_function *func,
|
||||
const char *name);
|
||||
|
||||
/* Upcasting from block to object. */
|
||||
extern gcc_jit_object *
|
||||
gcc_jit_block_as_object (gcc_jit_block *block);
|
||||
|
||||
/* Which function is this block within? */
|
||||
extern gcc_jit_function *
|
||||
gcc_jit_block_get_function (gcc_jit_block *block);
|
||||
|
||||
/**********************************************************************
|
||||
lvalues, rvalues and expressions.
|
||||
**********************************************************************/
|
||||
|
||||
extern gcc_jit_lvalue *
|
||||
gcc_jit_context_new_global (gcc_jit_context *ctxt,
|
||||
gcc_jit_location *loc,
|
||||
gcc_jit_type *type,
|
||||
const char *name);
|
||||
|
||||
/* Upcasting. */
|
||||
extern gcc_jit_object *
|
||||
gcc_jit_lvalue_as_object (gcc_jit_lvalue *lvalue);
|
||||
|
||||
extern gcc_jit_rvalue *
|
||||
gcc_jit_lvalue_as_rvalue (gcc_jit_lvalue *lvalue);
|
||||
|
||||
extern gcc_jit_object *
|
||||
gcc_jit_rvalue_as_object (gcc_jit_rvalue *rvalue);
|
||||
|
||||
extern gcc_jit_type *
|
||||
gcc_jit_rvalue_get_type (gcc_jit_rvalue *rvalue);
|
||||
|
||||
/* Integer constants. */
|
||||
extern gcc_jit_rvalue *
|
||||
gcc_jit_context_new_rvalue_from_int (gcc_jit_context *ctxt,
|
||||
gcc_jit_type *numeric_type,
|
||||
int value);
|
||||
|
||||
extern gcc_jit_rvalue *
|
||||
gcc_jit_context_zero (gcc_jit_context *ctxt,
|
||||
gcc_jit_type *numeric_type);
|
||||
|
||||
extern gcc_jit_rvalue *
|
||||
gcc_jit_context_one (gcc_jit_context *ctxt,
|
||||
gcc_jit_type *numeric_type);
|
||||
|
||||
/* Floating-point constants. */
|
||||
extern gcc_jit_rvalue *
|
||||
gcc_jit_context_new_rvalue_from_double (gcc_jit_context *ctxt,
|
||||
gcc_jit_type *numeric_type,
|
||||
double value);
|
||||
|
||||
/* Pointers. */
|
||||
extern gcc_jit_rvalue *
|
||||
gcc_jit_context_new_rvalue_from_ptr (gcc_jit_context *ctxt,
|
||||
gcc_jit_type *pointer_type,
|
||||
void *value);
|
||||
|
||||
extern gcc_jit_rvalue *
|
||||
gcc_jit_context_null (gcc_jit_context *ctxt,
|
||||
gcc_jit_type *pointer_type);
|
||||
|
||||
/* String literals. */
|
||||
extern gcc_jit_rvalue *
|
||||
gcc_jit_context_new_string_literal (gcc_jit_context *ctxt,
|
||||
const char *value);
|
||||
|
||||
enum gcc_jit_unary_op
|
||||
{
|
||||
/* Negate an arithmetic value; analogous to:
|
||||
-(EXPR)
|
||||
in C. */
|
||||
GCC_JIT_UNARY_OP_MINUS,
|
||||
|
||||
/* Bitwise negation of an integer value (one's complement); analogous
|
||||
to:
|
||||
~(EXPR)
|
||||
in C. */
|
||||
GCC_JIT_UNARY_OP_BITWISE_NEGATE,
|
||||
|
||||
/* Logical negation of an arithmetic or pointer value; analogous to:
|
||||
!(EXPR)
|
||||
in C. */
|
||||
GCC_JIT_UNARY_OP_LOGICAL_NEGATE
|
||||
};
|
||||
|
||||
extern gcc_jit_rvalue *
|
||||
gcc_jit_context_new_unary_op (gcc_jit_context *ctxt,
|
||||
gcc_jit_location *loc,
|
||||
enum gcc_jit_unary_op op,
|
||||
gcc_jit_type *result_type,
|
||||
gcc_jit_rvalue *rvalue);
|
||||
|
||||
enum gcc_jit_binary_op
|
||||
{
|
||||
/* Addition of arithmetic values; analogous to:
|
||||
(EXPR_A) + (EXPR_B)
|
||||
in C.
|
||||
For pointer addition, use gcc_jit_context_new_array_access. */
|
||||
GCC_JIT_BINARY_OP_PLUS,
|
||||
|
||||
/* Subtraction of arithmetic values; analogous to:
|
||||
(EXPR_A) - (EXPR_B)
|
||||
in C. */
|
||||
GCC_JIT_BINARY_OP_MINUS,
|
||||
|
||||
/* Multiplication of a pair of arithmetic values; analogous to:
|
||||
(EXPR_A) * (EXPR_B)
|
||||
in C. */
|
||||
GCC_JIT_BINARY_OP_MULT,
|
||||
|
||||
/* Quotient of division of arithmetic values; analogous to:
|
||||
(EXPR_A) / (EXPR_B)
|
||||
in C.
|
||||
The result type affects the kind of division: if the result type is
|
||||
integer-based, then the result is truncated towards zero, whereas
|
||||
a floating-point result type indicates floating-point division. */
|
||||
GCC_JIT_BINARY_OP_DIVIDE,
|
||||
|
||||
/* Remainder of division of arithmetic values; analogous to:
|
||||
(EXPR_A) % (EXPR_B)
|
||||
in C. */
|
||||
GCC_JIT_BINARY_OP_MODULO,
|
||||
|
||||
/* Bitwise AND; analogous to:
|
||||
(EXPR_A) & (EXPR_B)
|
||||
in C. */
|
||||
GCC_JIT_BINARY_OP_BITWISE_AND,
|
||||
|
||||
/* Bitwise exclusive OR; analogous to:
|
||||
(EXPR_A) ^ (EXPR_B)
|
||||
in C. */
|
||||
GCC_JIT_BINARY_OP_BITWISE_XOR,
|
||||
|
||||
/* Bitwise inclusive OR; analogous to:
|
||||
(EXPR_A) | (EXPR_B)
|
||||
in C. */
|
||||
GCC_JIT_BINARY_OP_BITWISE_OR,
|
||||
|
||||
/* Logical AND; analogous to:
|
||||
(EXPR_A) && (EXPR_B)
|
||||
in C. */
|
||||
GCC_JIT_BINARY_OP_LOGICAL_AND,
|
||||
|
||||
/* Logical OR; analogous to:
|
||||
(EXPR_A) || (EXPR_B)
|
||||
in C. */
|
||||
GCC_JIT_BINARY_OP_LOGICAL_OR,
|
||||
|
||||
/* Left shift; analogous to:
|
||||
(EXPR_A) << (EXPR_B)
|
||||
in C. */
|
||||
GCC_JIT_BINARY_OP_LSHIFT,
|
||||
|
||||
/* Right shift; analogous to:
|
||||
(EXPR_A) >> (EXPR_B)
|
||||
in C. */
|
||||
GCC_JIT_BINARY_OP_RSHIFT
|
||||
};
|
||||
|
||||
extern gcc_jit_rvalue *
|
||||
gcc_jit_context_new_binary_op (gcc_jit_context *ctxt,
|
||||
gcc_jit_location *loc,
|
||||
enum gcc_jit_binary_op op,
|
||||
gcc_jit_type *result_type,
|
||||
gcc_jit_rvalue *a, gcc_jit_rvalue *b);
|
||||
|
||||
/* (Comparisons are treated as separate from "binary_op" to save
|
||||
you having to specify the result_type). */
|
||||
|
||||
enum gcc_jit_comparison
|
||||
{
|
||||
/* (EXPR_A) == (EXPR_B). */
|
||||
GCC_JIT_COMPARISON_EQ,
|
||||
|
||||
/* (EXPR_A) != (EXPR_B). */
|
||||
GCC_JIT_COMPARISON_NE,
|
||||
|
||||
/* (EXPR_A) < (EXPR_B). */
|
||||
GCC_JIT_COMPARISON_LT,
|
||||
|
||||
/* (EXPR_A) <=(EXPR_B). */
|
||||
GCC_JIT_COMPARISON_LE,
|
||||
|
||||
/* (EXPR_A) > (EXPR_B). */
|
||||
GCC_JIT_COMPARISON_GT,
|
||||
|
||||
/* (EXPR_A) >= (EXPR_B). */
|
||||
GCC_JIT_COMPARISON_GE
|
||||
};
|
||||
|
||||
extern gcc_jit_rvalue *
|
||||
gcc_jit_context_new_comparison (gcc_jit_context *ctxt,
|
||||
gcc_jit_location *loc,
|
||||
enum gcc_jit_comparison op,
|
||||
gcc_jit_rvalue *a, gcc_jit_rvalue *b);
|
||||
|
||||
/* Function calls. */
|
||||
|
||||
/* Call of a specific function. */
|
||||
extern gcc_jit_rvalue *
|
||||
gcc_jit_context_new_call (gcc_jit_context *ctxt,
|
||||
gcc_jit_location *loc,
|
||||
gcc_jit_function *func,
|
||||
int numargs , gcc_jit_rvalue **args);
|
||||
|
||||
/* Call through a function pointer. */
|
||||
extern gcc_jit_rvalue *
|
||||
gcc_jit_context_new_call_through_ptr (gcc_jit_context *ctxt,
|
||||
gcc_jit_location *loc,
|
||||
gcc_jit_rvalue *fn_ptr,
|
||||
int numargs, gcc_jit_rvalue **args);
|
||||
|
||||
/* Type-coercion.
|
||||
|
||||
Currently only a limited set of conversions are possible:
|
||||
int <-> float
|
||||
int <-> bool */
|
||||
extern gcc_jit_rvalue *
|
||||
gcc_jit_context_new_cast (gcc_jit_context *ctxt,
|
||||
gcc_jit_location *loc,
|
||||
gcc_jit_rvalue *rvalue,
|
||||
gcc_jit_type *type);
|
||||
|
||||
extern gcc_jit_lvalue *
|
||||
gcc_jit_context_new_array_access (gcc_jit_context *ctxt,
|
||||
gcc_jit_location *loc,
|
||||
gcc_jit_rvalue *ptr,
|
||||
gcc_jit_rvalue *index);
|
||||
|
||||
/* Field access is provided separately for both lvalues and rvalues. */
|
||||
|
||||
/* Accessing a field of an lvalue of struct type, analogous to:
|
||||
(EXPR).field = ...;
|
||||
in C. */
|
||||
extern gcc_jit_lvalue *
|
||||
gcc_jit_lvalue_access_field (gcc_jit_lvalue *struct_or_union,
|
||||
gcc_jit_location *loc,
|
||||
gcc_jit_field *field);
|
||||
|
||||
/* Accessing a field of an rvalue of struct type, analogous to:
|
||||
(EXPR).field
|
||||
in C. */
|
||||
extern gcc_jit_rvalue *
|
||||
gcc_jit_rvalue_access_field (gcc_jit_rvalue *struct_or_union,
|
||||
gcc_jit_location *loc,
|
||||
gcc_jit_field *field);
|
||||
|
||||
/* Accessing a field of an rvalue of pointer type, analogous to:
|
||||
(EXPR)->field
|
||||
in C, itself equivalent to (*EXPR).FIELD */
|
||||
extern gcc_jit_lvalue *
|
||||
gcc_jit_rvalue_dereference_field (gcc_jit_rvalue *ptr,
|
||||
gcc_jit_location *loc,
|
||||
gcc_jit_field *field);
|
||||
|
||||
/* Dereferencing a pointer; analogous to:
|
||||
*(EXPR)
|
||||
*/
|
||||
extern gcc_jit_lvalue *
|
||||
gcc_jit_rvalue_dereference (gcc_jit_rvalue *rvalue,
|
||||
gcc_jit_location *loc);
|
||||
|
||||
/* Taking the address of an lvalue; analogous to:
|
||||
&(EXPR)
|
||||
in C. */
|
||||
extern gcc_jit_rvalue *
|
||||
gcc_jit_lvalue_get_address (gcc_jit_lvalue *lvalue,
|
||||
gcc_jit_location *loc);
|
||||
|
||||
extern gcc_jit_lvalue *
|
||||
gcc_jit_function_new_local (gcc_jit_function *func,
|
||||
gcc_jit_location *loc,
|
||||
gcc_jit_type *type,
|
||||
const char *name);
|
||||
|
||||
/**********************************************************************
|
||||
Statement-creation.
|
||||
**********************************************************************/
|
||||
|
||||
/* Add evaluation of an rvalue, discarding the result
|
||||
(e.g. a function call that "returns" void).
|
||||
|
||||
This is equivalent to this C code:
|
||||
|
||||
(void)expression;
|
||||
*/
|
||||
extern void
|
||||
gcc_jit_block_add_eval (gcc_jit_block *block,
|
||||
gcc_jit_location *loc,
|
||||
gcc_jit_rvalue *rvalue);
|
||||
|
||||
/* Add evaluation of an rvalue, assigning the result to the given
|
||||
lvalue.
|
||||
|
||||
This is roughly equivalent to this C code:
|
||||
|
||||
lvalue = rvalue;
|
||||
*/
|
||||
extern void
|
||||
gcc_jit_block_add_assignment (gcc_jit_block *block,
|
||||
gcc_jit_location *loc,
|
||||
gcc_jit_lvalue *lvalue,
|
||||
gcc_jit_rvalue *rvalue);
|
||||
|
||||
/* Add evaluation of an rvalue, using the result to modify an
|
||||
lvalue.
|
||||
|
||||
This is analogous to "+=" and friends:
|
||||
|
||||
lvalue += rvalue;
|
||||
lvalue *= rvalue;
|
||||
lvalue /= rvalue;
|
||||
etc */
|
||||
extern void
|
||||
gcc_jit_block_add_assignment_op (gcc_jit_block *block,
|
||||
gcc_jit_location *loc,
|
||||
gcc_jit_lvalue *lvalue,
|
||||
enum gcc_jit_binary_op op,
|
||||
gcc_jit_rvalue *rvalue);
|
||||
|
||||
/* Add a no-op textual comment to the internal representation of the
|
||||
code. It will be optimized away, but will be visible in the dumps
|
||||
seen via
|
||||
GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE
|
||||
and
|
||||
GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE,
|
||||
and thus may be of use when debugging how your project's internal
|
||||
representation gets converted to the libgccjit IR. */
|
||||
extern void
|
||||
gcc_jit_block_add_comment (gcc_jit_block *block,
|
||||
gcc_jit_location *loc,
|
||||
const char *text);
|
||||
|
||||
/* Terminate a block by adding evaluation of an rvalue, branching on the
|
||||
result to the appropriate successor block.
|
||||
|
||||
This is roughly equivalent to this C code:
|
||||
|
||||
if (boolval)
|
||||
goto on_true;
|
||||
else
|
||||
goto on_false;
|
||||
|
||||
block, boolval, on_true, and on_false must be non-NULL. */
|
||||
extern void
|
||||
gcc_jit_block_end_with_conditional (gcc_jit_block *block,
|
||||
gcc_jit_location *loc,
|
||||
gcc_jit_rvalue *boolval,
|
||||
gcc_jit_block *on_true,
|
||||
gcc_jit_block *on_false);
|
||||
|
||||
/* Terminate a block by adding a jump to the given target block.
|
||||
|
||||
This is roughly equivalent to this C code:
|
||||
|
||||
goto target;
|
||||
*/
|
||||
extern void
|
||||
gcc_jit_block_end_with_jump (gcc_jit_block *block,
|
||||
gcc_jit_location *loc,
|
||||
gcc_jit_block *target);
|
||||
|
||||
/* Terminate a block by adding evaluation of an rvalue, returning the value.
|
||||
|
||||
This is roughly equivalent to this C code:
|
||||
|
||||
return expression;
|
||||
*/
|
||||
extern void
|
||||
gcc_jit_block_end_with_return (gcc_jit_block *block,
|
||||
gcc_jit_location *loc,
|
||||
gcc_jit_rvalue *rvalue);
|
||||
|
||||
/* Terminate a block by adding a valueless return, for use within a function
|
||||
with "void" return type.
|
||||
|
||||
This is equivalent to this C code:
|
||||
|
||||
return;
|
||||
*/
|
||||
extern void
|
||||
gcc_jit_block_end_with_void_return (gcc_jit_block *block,
|
||||
gcc_jit_location *loc);
|
||||
|
||||
/**********************************************************************
|
||||
Nested contexts.
|
||||
**********************************************************************/
|
||||
|
||||
/* Given an existing JIT context, create a child context.
|
||||
|
||||
The child inherits a copy of all option-settings from the parent.
|
||||
|
||||
The child can reference objects created within the parent, but not
|
||||
vice-versa.
|
||||
|
||||
The lifetime of the child context must be bounded by that of the
|
||||
parent: you should release a child context before releasing the parent
|
||||
context.
|
||||
|
||||
If you use a function from a parent context within a child context,
|
||||
you have to compile the parent context before you can compile the
|
||||
child context, and the gcc_jit_result of the parent context must
|
||||
outlive the gcc_jit_result of the child context.
|
||||
|
||||
This allows caching of shared initializations. For example, you could
|
||||
create types and declarations of global functions in a parent context
|
||||
once within a process, and then create child contexts whenever a
|
||||
function or loop becomes hot. Each such child context can be used for
|
||||
JIT-compiling just one function or loop, but can reference types
|
||||
and helper functions created within the parent context.
|
||||
|
||||
Contexts can be arbitrarily nested, provided the above rules are
|
||||
followed, but it's probably not worth going above 2 or 3 levels, and
|
||||
there will likely be a performance hit for such nesting. */
|
||||
|
||||
extern gcc_jit_context *
|
||||
gcc_jit_context_new_child_context (gcc_jit_context *parent_ctxt);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* LIBGCCJIT_H */
|
100
gcc/jit/libgccjit.map
Normal file
100
gcc/jit/libgccjit.map
Normal file
@ -0,0 +1,100 @@
|
||||
# Linker script for libgccjit.so
|
||||
# Copyright (C) 2013-2014 Free Software Foundation, Inc.
|
||||
# Contributed by David Malcolm <dmalcolm@redhat.com>.
|
||||
#
|
||||
# This file is part of GCC.
|
||||
#
|
||||
# GCC is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# GCC is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with GCC; see the file COPYING3. If not see
|
||||
# <http://www.gnu.org/licenses/>. */
|
||||
{
|
||||
global:
|
||||
# Keep this list sorted alphabetically:
|
||||
gcc_jit_block_add_assignment;
|
||||
gcc_jit_block_add_assignment_op;
|
||||
gcc_jit_block_add_comment;
|
||||
gcc_jit_block_add_eval;
|
||||
gcc_jit_block_as_object;
|
||||
gcc_jit_block_end_with_conditional;
|
||||
gcc_jit_block_end_with_jump;
|
||||
gcc_jit_block_end_with_return;
|
||||
gcc_jit_block_end_with_void_return;
|
||||
gcc_jit_block_get_function;
|
||||
gcc_jit_context_acquire;
|
||||
gcc_jit_context_compile;
|
||||
gcc_jit_context_dump_to_file;
|
||||
gcc_jit_context_get_builtin_function;
|
||||
gcc_jit_context_get_first_error;
|
||||
gcc_jit_context_get_type;
|
||||
gcc_jit_context_get_int_type;
|
||||
gcc_jit_context_new_array_access;
|
||||
gcc_jit_context_new_array_type;
|
||||
gcc_jit_context_new_binary_op;
|
||||
gcc_jit_context_new_call;
|
||||
gcc_jit_context_new_call_through_ptr;
|
||||
gcc_jit_context_new_cast;
|
||||
gcc_jit_context_new_child_context;
|
||||
gcc_jit_context_new_comparison;
|
||||
gcc_jit_context_new_field;
|
||||
gcc_jit_context_new_function;
|
||||
gcc_jit_context_new_function_ptr_type;
|
||||
gcc_jit_context_new_global;
|
||||
gcc_jit_context_new_location;
|
||||
gcc_jit_context_new_opaque_struct;
|
||||
gcc_jit_context_new_param;
|
||||
gcc_jit_context_new_rvalue_from_double;
|
||||
gcc_jit_context_new_rvalue_from_int;
|
||||
gcc_jit_context_new_rvalue_from_ptr;
|
||||
gcc_jit_context_new_string_literal;
|
||||
gcc_jit_context_new_struct_type;
|
||||
gcc_jit_context_new_unary_op;
|
||||
gcc_jit_context_new_union_type;
|
||||
gcc_jit_context_null;
|
||||
gcc_jit_context_one;
|
||||
gcc_jit_context_release;
|
||||
gcc_jit_context_set_bool_option;
|
||||
gcc_jit_context_set_int_option;
|
||||
gcc_jit_context_set_str_option;
|
||||
gcc_jit_context_zero;
|
||||
gcc_jit_field_as_object;
|
||||
gcc_jit_function_as_object;
|
||||
gcc_jit_function_dump_to_dot;
|
||||
gcc_jit_function_get_param;
|
||||
gcc_jit_function_new_block;
|
||||
gcc_jit_function_new_local;
|
||||
gcc_jit_location_as_object;
|
||||
gcc_jit_lvalue_as_object;
|
||||
gcc_jit_lvalue_as_rvalue;
|
||||
gcc_jit_lvalue_access_field;
|
||||
gcc_jit_lvalue_get_address;
|
||||
gcc_jit_object_get_context;
|
||||
gcc_jit_object_get_debug_string;
|
||||
gcc_jit_param_as_lvalue;
|
||||
gcc_jit_param_as_object;
|
||||
gcc_jit_param_as_rvalue;
|
||||
gcc_jit_result_get_code;
|
||||
gcc_jit_result_release;
|
||||
gcc_jit_rvalue_access_field;
|
||||
gcc_jit_rvalue_as_object;
|
||||
gcc_jit_rvalue_dereference;
|
||||
gcc_jit_rvalue_dereference_field;
|
||||
gcc_jit_rvalue_get_type;
|
||||
gcc_jit_struct_as_type;
|
||||
gcc_jit_struct_set_fields;
|
||||
gcc_jit_type_as_object;
|
||||
gcc_jit_type_get_const;
|
||||
gcc_jit_type_get_pointer;
|
||||
gcc_jit_type_get_volatile;
|
||||
|
||||
local: *;
|
||||
};
|
84
gcc/jit/notes.txt
Normal file
84
gcc/jit/notes.txt
Normal file
@ -0,0 +1,84 @@
|
||||
Client Code . Generated . libgccjit.so
|
||||
. code .
|
||||
. . JIT API . JIT "Frontend". (libbackend.a)
|
||||
....................................................................................
|
||||
│ . . . .
|
||||
──────────────────────────> . .
|
||||
. . │ . .
|
||||
. . V . .
|
||||
. . ──> libgccjit.c .
|
||||
. . │ (error-checking).
|
||||
. . │ .
|
||||
. . ──> jit-recording.c
|
||||
. . (record API calls)
|
||||
. . <─────── .
|
||||
. . │ . .
|
||||
<─────────────────────────── . .
|
||||
│ . . . .
|
||||
│ . . . .
|
||||
V . . gcc_jit_context_compile .
|
||||
──────────────────────────> . .
|
||||
. . │ . .
|
||||
. . │ ACQUIRE MUTEX .
|
||||
. . │ . .
|
||||
. . V───────────────────────> toplev::main (for now)
|
||||
. . . . │
|
||||
. . . . (various code)
|
||||
. . . . │
|
||||
. . . . V
|
||||
. . . <───────────────── langhook:parse_file
|
||||
. . . │ .
|
||||
. . . │ (jit_langhook_parse_file)
|
||||
. . . │ .
|
||||
..........................................│..................VVVVVVVVVVVVV...
|
||||
. . . │ . No GC in here
|
||||
. . . │ jit-playback.c
|
||||
. . . │ (playback of API calls)
|
||||
. . . ───────────────> creation of functions,
|
||||
. . . . types, expression trees
|
||||
. . . <──────────────── etc
|
||||
. . . │(handle_locations: add locations to
|
||||
. . . │ linemap and associate them with trees)
|
||||
. . . │ .
|
||||
. . . │ . No GC in here
|
||||
..........................................│..................AAAAAAAAAAAAA...
|
||||
. . . │ for each function
|
||||
. . . ──> postprocess
|
||||
. . . │ .
|
||||
. . . ────────────> cgraph_finalize_function
|
||||
. . . <────────────
|
||||
. . . <── .
|
||||
. . . │ .
|
||||
. . . ──────────────────> (end of
|
||||
. . . . │ langhook_parse_file)
|
||||
. . . . │
|
||||
. . . . (various code)
|
||||
. . . . │
|
||||
. . . . ↓
|
||||
. . . <───────────────── langhook:write_globals
|
||||
. . . │ .
|
||||
. . . │ (jit_langhook_write_globals)
|
||||
. . . │ .
|
||||
. . . │ .
|
||||
. . . ──────────────────> finalize_compilation_unit
|
||||
. . . . │
|
||||
. . . . (the middle─end and backend)
|
||||
. . . . ↓
|
||||
. . <───────────────────────────── end of toplev::main
|
||||
. . │ RELEASE MUTEX .
|
||||
. . │ . .
|
||||
. . │ Convert assembler to DSO
|
||||
. . │ . .
|
||||
. . │ Load DSO .
|
||||
<─────────────────────────── . .
|
||||
│ . . . .
|
||||
Get (void*). . . .
|
||||
│ . . . .
|
||||
│ Call it . . . .
|
||||
───────────────> . . .
|
||||
. │ . . .
|
||||
. │ . . .
|
||||
<─────────────── . . .
|
||||
│ . . . .
|
||||
│ . . . .
|
||||
etc
|
@ -1,3 +1,67 @@
|
||||
2014-11-11 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* ChangeLog.jit: New.
|
||||
* jit.dg/all-non-failing-tests.h: New.
|
||||
* jit.dg/harness.h: New.
|
||||
* jit.dg/jit.exp: New.
|
||||
* jit.dg/test-accessing-struct.c: New.
|
||||
* jit.dg/test-accessing-union.c: New.
|
||||
* jit.dg/test-array-as-pointer.c: New.
|
||||
* jit.dg/test-arrays.c: New.
|
||||
* jit.dg/test-calling-external-function.c: New.
|
||||
* jit.dg/test-calling-function-ptr.c: New.
|
||||
* jit.dg/test-combination.c: New.
|
||||
* jit.dg/test-dot-product.c: New.
|
||||
* jit.dg/test-empty.c: New.
|
||||
* jit.dg/test-error-accessing-field-in-other-struct.c: New.
|
||||
* jit.dg/test-error-adding-to-terminated-block.c: New.
|
||||
* jit.dg/test-error-array-as-pointer.c: New.
|
||||
* jit.dg/test-error-bad-cast.c: New.
|
||||
* jit.dg/test-error-block-in-wrong-function.c: New.
|
||||
* jit.dg/test-error-call-through-ptr-with-mismatching-args.c: New.
|
||||
* jit.dg/test-error-call-through-ptr-with-non-function.c: New.
|
||||
* jit.dg/test-error-call-through-ptr-with-non-pointer.c: New.
|
||||
* jit.dg/test-error-call-through-ptr-with-not-enough-args.c: New.
|
||||
* jit.dg/test-error-call-through-ptr-with-too-many-args.c: New.
|
||||
* jit.dg/test-error-call-with-mismatching-args.c: New.
|
||||
* jit.dg/test-error-call-with-not-enough-args.c: New.
|
||||
* jit.dg/test-error-call-with-too-many-args.c: New.
|
||||
* jit.dg/test-error-dereference-field-of-non-pointer.c: New.
|
||||
* jit.dg/test-error-dereference-read-of-non-pointer.c: New.
|
||||
* jit.dg/test-error-get-type-bad-enum.c: New.
|
||||
* jit.dg/test-error-index-not-a-numeric-type.c: New.
|
||||
* jit.dg/test-error-mismatching-types-in-assignment.c: New.
|
||||
* jit.dg/test-error-mismatching-types-in-call.c: New.
|
||||
* jit.dg/test-error-missing-return.c: New.
|
||||
* jit.dg/test-error-new-binary-op-bad-op.c: New.
|
||||
* jit.dg/test-error-new-function-bad-kind.c: New.
|
||||
* jit.dg/test-error-new-unary-op-bad-op.c: New.
|
||||
* jit.dg/test-error-null-passed-to-api.c: New.
|
||||
* jit.dg/test-error-return-within-void-function.c: New.
|
||||
* jit.dg/test-error-unreachable-block.c: New.
|
||||
* jit.dg/test-error-unterminated-block.c: New.
|
||||
* jit.dg/test-error-value-not-a-numeric-type.c: New.
|
||||
* jit.dg/test-expressions.c: New.
|
||||
* jit.dg/test-factorial.c: New.
|
||||
* jit.dg/test-fibonacci.c: New.
|
||||
* jit.dg/test-functions.c: New.
|
||||
* jit.dg/test-fuzzer.c: New.
|
||||
* jit.dg/test-hello-world.c: New.
|
||||
* jit.dg/test-linked-list.c: New.
|
||||
* jit.dg/test-long-names.c: New.
|
||||
* jit.dg/test-nested-contexts.c: New.
|
||||
* jit.dg/test-nested-loops.c: New.
|
||||
* jit.dg/test-operator-overloading.cc: New.
|
||||
* jit.dg/test-quadratic.c: New.
|
||||
* jit.dg/test-quadratic.cc: New.
|
||||
* jit.dg/test-reading-struct.c: New.
|
||||
* jit.dg/test-string-literal.c: New.
|
||||
* jit.dg/test-sum-of-squares.c: New.
|
||||
* jit.dg/test-threads.c: New.
|
||||
* jit.dg/test-types.c: New.
|
||||
* jit.dg/test-using-global.c: New.
|
||||
* jit.dg/test-volatile.c: New.
|
||||
|
||||
2014-11-11 James Greenhalgh <james.greenhalgh@arm.com>
|
||||
|
||||
* gcc.target/aarch64/vbslq_f64_1.c: New.
|
||||
|
626
gcc/testsuite/ChangeLog.jit
Normal file
626
gcc/testsuite/ChangeLog.jit
Normal file
@ -0,0 +1,626 @@
|
||||
2014-11-05 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* jit.dg/test-error-get-type-bad-enum.c: New test case.
|
||||
* jit.dg/test-error-new-binary-op-bad-op.c: Likewise.
|
||||
* jit.dg/test-error-new-function-bad-kind.c: Likewise.
|
||||
* jit.dg/test-error-new-unary-op-bad-op.c: Likewise.
|
||||
|
||||
2014-10-22 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* jit.dg/jit.exp (DEFAULT_CFLAGS): Add -fgnu89-inline since
|
||||
dejagnu.h assumes this.
|
||||
|
||||
2014-10-17 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* jit.dg/jit.exp (get_path_of_driver): New procedure.
|
||||
(jit-dg-test): Don't unsetenv GCC_EXEC_PREFIX, since jit-playback.c
|
||||
now adds -fno-use-linker-plugin to the driver cmdline sidestepping
|
||||
the builddir/installdir libtto_plugin naming issue.
|
||||
When setting up PATH so that the JIT library can invoke the driver
|
||||
by installation name, don't use the installation "bindir".
|
||||
Instead, simply use the location of xgcc as detected
|
||||
get_path_of_driver. In addition, set up LIBRARY_PATH so that the
|
||||
linker run from inside the JIT library can locate libgcc etc when
|
||||
building the .so, pointing it at the same directory.
|
||||
|
||||
2014-10-13 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* jit.dg/jit.exp (fixed_host_execute): New function, taken from
|
||||
"host_execute" in DejaGnu's dejagnu.exp, with one line removed.
|
||||
(jit-dg-test): Use fixed_host_execute, rathern than host_execute.
|
||||
|
||||
2014-10-13 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* jit.dg/harness.h [MAKE_DEJAGNU_H_THREADSAFE] (note): Redefine
|
||||
"note" from dejagnu.h to new function dejagnu_note so that we can
|
||||
make "note" be threadsafe.
|
||||
(set_options): Don't enable GCC_JIT_BOOL_OPTION_DUMP_SUMMARY,
|
||||
since it can generate large amounts of output that could overwhelm
|
||||
expect's buffer.
|
||||
* jit.dg/test-dot-product.c (verify_code): Use "note" rather than
|
||||
"printf", to give DejaGnu more chances to parse this log data,
|
||||
rather than overflowing its buffer.
|
||||
* jit.dg/test-factorial.c (verify_code): Likewise.
|
||||
* jit.dg/test-fibonacci.c (verify_code): Likewise.
|
||||
* jit.dg/test-fuzzer.c (main): Likewise.
|
||||
* jit.dg/test-nested-loops.c (verify_code): Likewise.
|
||||
* jit.dg/test-sum-of-squares.c (verify_code): Likewise.
|
||||
* jit.dg/test-threads.c (note): New function, adding thread-safety
|
||||
on top of "dejagnu_note", the latter being the implementation
|
||||
found in dejagnu.h.
|
||||
(run_threaded_test): Use "note" rather than "printf".
|
||||
|
||||
2014-10-07 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* jit.dg/jit.exp (jit-dg-test): Prepend the installed bindir to
|
||||
the PATH before invoking built binaries using the library, so that
|
||||
the library can find the driver. Restore the PATH immediately
|
||||
afterwards.
|
||||
|
||||
2014-09-24 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* ChangeLog.jit: Add copyright footer.
|
||||
|
||||
2014-09-23 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* jit.dg/test-expressions.c (make_tests_of_binary_ops): Add
|
||||
shift operators.
|
||||
(verify_binary_ops): Likewise.
|
||||
|
||||
2014-09-18 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* jit.dg/jit.exp: When constructing "tests", add the example files
|
||||
from the documentation, to ensure that they compile.
|
||||
|
||||
2014-09-10 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* jit.dg/jit.exp: Load target-supports.exp.
|
||||
|
||||
2014-09-09 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* jit.dg/test-nested-loops.c: New test case.
|
||||
* jit.dg/all-non-failing-tests.h: Add test-nested-loops.c.
|
||||
* jit.dg/test-combination.c (create_code): Likewise.
|
||||
(verify_code): Likewise.
|
||||
* jit.dg/test-threads.c (const): Add test-nested-loops.c.
|
||||
|
||||
2014-08-11 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* jit.dg/test-threads.c: New test case, running all of the
|
||||
individual test cases in separate threads.
|
||||
* jit.dg/test-combination.c: Move inclusion of the various
|
||||
individual testcases into...
|
||||
* jit.dg/all-non-failing-tests.h: ...this new file, and rename
|
||||
TEST_COMBINATION to COMBINED_TEST.
|
||||
* jit.dg/harness.h: Respond to new macro MAKE_DEJAGNU_H_THREADSAFE
|
||||
by hacking up <dejagnu.h> to be threadsafe. Rename
|
||||
TEST_COMBINATION to COMBINED_TEST.
|
||||
* jit.dg/jit.exp (proc jit-dg-test): Add "-lpthread" when building
|
||||
test-threads.exe.
|
||||
|
||||
2014-08-08 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* jit.dg/test-accessing-union.c: New test case.
|
||||
* jit.dg/test-combination.c: Add test-accessing-union.c.
|
||||
|
||||
2014-08-08 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* jit.dg/test-combination.c (create_code): Add missing calls to
|
||||
create_code_quadratic and create_code_reading_struct.
|
||||
(verify_code): Add missing calls to verify_code_quadratic and
|
||||
verify_code_reading_struct.
|
||||
|
||||
2014-08-08 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* jit.dg/test-calling-function-ptr.c: New test case.
|
||||
* jit.dg/test-combination.c: Add test-calling-function-ptr.c.
|
||||
* jit.dg/test-error-call-through-ptr-with-mismatching-args.c: New
|
||||
test case.
|
||||
* jit.dg/test-error-call-through-ptr-with-non-function.c: New test
|
||||
case.
|
||||
* jit.dg/test-error-call-through-ptr-with-non-pointer.c: New test
|
||||
case.
|
||||
* jit.dg/test-error-call-through-ptr-with-not-enough-args.c: New
|
||||
test case.
|
||||
|
||||
2014-07-25 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* jit.dg/test-error-index-not-a-numeric-type.c: New test case.
|
||||
* jit.dg/test-error-value-not-a-numeric-type.c: New test case.
|
||||
|
||||
2014-03-19 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* jit.dg/test-array-as-pointer.c: New test case, verifying that
|
||||
there's a way to treat arrays as pointers.
|
||||
* jit.dg/test-combination.c: Add test-array-as-pointer.c...
|
||||
(create_code): ...here and...
|
||||
(verify_code): ...here.
|
||||
|
||||
* jit.dg/test-error-array-as-pointer.c: New test case, verifying
|
||||
that bogus casts from array to pointer are caught by the type
|
||||
system, rather than leading to ICEs seen in:
|
||||
https://github.com/davidmalcolm/pygccjit/pull/3#issuecomment-37883129
|
||||
|
||||
2014-03-18 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* jit.dg/test-combination.c: Add test-arrays.c and test-volatile.c.
|
||||
Add comment about test-error-*.c. Remove comment about
|
||||
test-failure.c, which was removed in
|
||||
96b218c9a1d5f39fb649e02c0e77586b180e8516.
|
||||
(create_code): Call into test-arrays.c and test-volatile.c.
|
||||
(verify_code): Likewise.
|
||||
|
||||
2014-03-14 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* jit.dg/test-expressions.c (called_pointer_checking_function): New.
|
||||
(make_tests_of_casts): Add test of casting from array to pointer.
|
||||
(verify_casts): Likewise.
|
||||
|
||||
2014-03-13 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* jit.dg/test-error-bad-cast.c: New test case.
|
||||
|
||||
2014-03-11 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* jit.dg/harness.h (set_options): Increase optimization level from
|
||||
0 to 3.
|
||||
|
||||
2014-03-07 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* jit.dg/test-functions.c (create_test_of_hidden_function): New,
|
||||
adding test coverage for GCC_JIT_FUNCTION_ALWAYS_INLINE and
|
||||
GCC_JIT_FUNCTION_INTERNAL.
|
||||
(create_tests_of_hidden_functions): Likewise.
|
||||
(verify_hidden_functions): Likewise.
|
||||
(create_code): Add call to create_tests_of_hidden_functions.
|
||||
(verify_code): Add call to verify_hidden_functions.
|
||||
* jit.dg/test-quadratic.c (make_calc_discriminant): Convert
|
||||
from GCC_JIT_FUNCTION_EXPORTED to GCC_JIT_FUNCTION_INTERNAL.
|
||||
|
||||
2014-03-07 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* jit.dg/test-functions.c: Reorder function definitions, grouping
|
||||
them by subject-matter rather than by create-vs-verify phase.
|
||||
|
||||
2014-03-06 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* jit.dg/test-nested-contexts.c (main): Dump the contexts to
|
||||
files, setting up source locations, and adding test coverage for
|
||||
gcc_jit_context_dump_to_file.
|
||||
|
||||
2014-03-04 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* jit.dg/test-error-mismatching-types-in-call.c: New test case,
|
||||
to ensure that a (struct foo *) vs (struct foo) type error is
|
||||
gracefully handled.
|
||||
|
||||
2014-03-04 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* jit.dg/test-volatile.c: New testcase, to exercise
|
||||
gcc_jit_type_get_volatile, and show a way to work with pre-existing
|
||||
global variables.
|
||||
|
||||
2014-02-28 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* jit.dg/test-expressions.c (make_test_of_cast): New, to test new
|
||||
entrypoint gcc_jit_context_new_cast.
|
||||
(make_tests_of_casts): New.
|
||||
(create_code): Add call to make_tests_of_casts.
|
||||
(verify_code): Add call to verify_casts.
|
||||
|
||||
2014-02-27 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* jit.dg/test-accessing-struct.c (create_code): Port to
|
||||
block-based API.
|
||||
* jit.dg/test-calling-external-function.c (create_code): Likewise.
|
||||
* jit.dg/test-error-accessing-field-in-other-struct.c (create_code):
|
||||
Likewise.
|
||||
* jit.dg/test-error-call-with-mismatching-args.c (create_code):
|
||||
Likewise.
|
||||
* jit.dg/test-error-call-with-not-enough-args.c (create_code):
|
||||
Likewise.
|
||||
* jit.dg/test-error-call-with-too-many-args.c (create_code):
|
||||
Likewise.
|
||||
* jit.dg/test-error-dereference-field-of-non-pointer.c (create_code):
|
||||
Likewise.
|
||||
* jit.dg/test-error-dereference-read: Likewise.
|
||||
* jit.dg/test-error-mismatching-types-in-assignment.c: Likewise.
|
||||
* jit.dg/test-error-return-within-void-function.c: Likewise.
|
||||
* jit.dg/test-expressions.c: Likewise.
|
||||
* jit.dg/test-factorial.c: Likewise.
|
||||
* jit.dg/test-functions.c: Likewise.
|
||||
* jit.dg/test-fuzzer.c: Likewise.
|
||||
* jit.dg/test-hello-world.c (create_code): Likewise.
|
||||
* jit.dg/test-nested-contexts.c: Likewise.
|
||||
* jit.dg/test-operator-overloading.cc: Likewise.
|
||||
* jit.dg/test-quadratic.c: Likewise.
|
||||
* jit.dg/test-quadratic.cc: Likewise.
|
||||
* jit.dg/test-reading-struct.c (create_code): Likewise.
|
||||
* jit.dg/test-string-literal.c (create_code): Likewise.
|
||||
* jit.dg/test-sum-of-squares.c (create_code): Likewise.
|
||||
* jit.dg/test-types.c (create_code): Likewise.
|
||||
* jit.dg/test-using-global.c (create_code): Likewise.
|
||||
|
||||
* jit.dg/test-arrays.c (create_code): Likewise, eliminating use of
|
||||
loop API.
|
||||
* jit.dg/test-dot-product.c (create_code): Likewise.
|
||||
* jit.dg/test-linked-list.c (create_code): Likewise.
|
||||
|
||||
* jit.dg/test-error-adding-to-terminated-block.c: New testcase.
|
||||
* jit.dg/test-error-block-in-wrong-function.c: Likewise.
|
||||
* jit.dg/test-error-missing-return.c: Likewise.
|
||||
* jit.dg/test-error-unreachable-block.c: Likewise.
|
||||
* jit.dg/test-error-unterminated-block.c: Likewise.
|
||||
|
||||
* jit.dg/test-error-label-already-placed.c: Delete obsolete testcase.
|
||||
* jit.dg/test-error-unplaced-label.c: Likewise.
|
||||
|
||||
2014-02-25 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* jit.dg/test-functions.c (create_use_of_void_return): New, to add
|
||||
test coverage for gcc_jit_function_add_void_return.
|
||||
(verify_void_return): Likewise.
|
||||
(create_code): Add call to create_use_of_void_return.
|
||||
(verify_code): Add call to verify_void_return.
|
||||
|
||||
2014-02-18 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* jit.dg/test-accessing-struct.c (create_code): Update for change to
|
||||
return type of gcc_jit_context_new_struct_type.
|
||||
* jit.dg/test-arrays.c (create_code): Likewise.
|
||||
* jit.dg/test-error-accessing-field-in-other-struct.c (create_code):
|
||||
Likewise.
|
||||
* jit.dg/test-error-dereference-field-of-non-pointer.c (create_code):
|
||||
Likewise.
|
||||
* jit.dg/test-fuzzer.c (make_random_type): Likewise.
|
||||
* jit.dg/test-nested-contexts.c (make_types): Likewise.
|
||||
* jit.dg/test-quadratic.c (make_types): Likewise.
|
||||
* jit.dg/test-reading-struct.c (create_code): Likewise.
|
||||
* jit.dg/test-types.c (create_code): Likewise.
|
||||
|
||||
* jit.dg/test-linked-list.c: New selftest, exercising
|
||||
gcc_jit_context_new_opaque_struct, gcc_jit_type_get_pointer, and
|
||||
gcc_jit_context_null.
|
||||
* jit.dg/test-combination.c: Add test-linked-list.c
|
||||
|
||||
2014-02-14 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* jit.dg/test-operator-overloading.cc (make_test_quadratic): Use
|
||||
the new "zero" and "one" methods of gccjit::type.
|
||||
* jit.dg/test-quadratic.cc (make_test_quadratic): Use the new
|
||||
"add_call" method of gccjit::function.
|
||||
|
||||
2014-02-13 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* jit.dg/harness.h (CHECK_DOUBLE_VALUE): New macro.
|
||||
(CHECK): New macro.
|
||||
* jit.dg/test-functions.c: New testcase, exercising
|
||||
gcc_jit_context_get_builtin_function.
|
||||
* jit.dg/test-combination.c: Add test-functions.c to the combined
|
||||
test.
|
||||
|
||||
2014-02-11 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* jit.dg/test-types.c: Add test coverage for getting type
|
||||
GCC_JIT_TYPE_BOOL.
|
||||
* jit.dg/test-expressions.c (make_test_of_comparison): Convert
|
||||
return type from int to bool.
|
||||
(verify_comparisons): Likewise.
|
||||
|
||||
2014-02-11 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* jit.dg/test-error-unplaced-label.c (verify_code): Update
|
||||
expected error message to reflect commit
|
||||
6cd4f82c5237cc328aea229cdaaa428ff09d6e98.
|
||||
|
||||
2014-02-10 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* jit.dg/test-types.c (struct zoo): Add field m_sized_int_type,
|
||||
to be populated by...
|
||||
(create_code): Use gcc_jit_context_get_int_type.
|
||||
(verify_code): Verify that type from gcc_jit_context_get_int_type
|
||||
works properly.
|
||||
* jit.dg/test-operator-overloading.cc (make_types): Use the
|
||||
template form of get_int_type.
|
||||
* jit.dg/test-quadratic.cc (make_types): Likewise.
|
||||
|
||||
2014-02-10 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* jit.dg/test-operator-overloading.cc: New testcase, a
|
||||
rewrite of test-quadratic.cc to use operator overloading.
|
||||
|
||||
2014-02-10 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* jit.dg/test-quadratic.cc (make_calc_discriminant): Make use of
|
||||
new methods of the C++ wrapper API to shorten the example code.
|
||||
(make_test_quadratic): Likewise.
|
||||
|
||||
2014-02-10 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* jit.dg/test-quadratic.cc (make_test_quadratic): Update for
|
||||
change to gccjit::context::new_call to pass args by reference
|
||||
rather than by value.
|
||||
|
||||
2014-02-03 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* jit.dg/harness.h (check_string_value): Add a forward declaration,
|
||||
so that we can use CHECK_STRING_VALUE from within tests used by
|
||||
test-combination.c.
|
||||
|
||||
* jit.dg/test-expressions.c (make_test_of_unary_op): Return a debug
|
||||
stringification of the operation so that it be sanity-checked.
|
||||
(make_test_of_binary_op): Likewise.
|
||||
(make_test_of_comparison): Likewise.
|
||||
(make_tests_of_unary_ops): Verify that said stringifications are
|
||||
indeed sane.
|
||||
(make_tests_of_binary_ops): Likewise.
|
||||
(make_tests_of_comparisons): Likewise.
|
||||
|
||||
* jit.dg/test-quadratic.cc (make_types): Verify that the
|
||||
get_debug_string method works.
|
||||
(make_test_quadratic): Likewise, also, verify that the <<
|
||||
operator works.
|
||||
|
||||
2014-01-31 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* jit.dg/test-quadratic.cc: New file - a translation of
|
||||
test-quadratic.c to the libgccjit++.h C++ API.
|
||||
|
||||
2014-01-30 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* jit.dg/test-error-label-already-placed.c: New test case.
|
||||
* jit.dg/test-error-unplaced-label.c: New test case.
|
||||
|
||||
2014-01-30 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* jit.dg/test-error-call-with-mismatching-args.c: New test case.
|
||||
|
||||
2014-01-30 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* jit.dg/test-error-accessing-field-in-other-struct.c: New test
|
||||
case.
|
||||
* jit.dg/test-error-dereference-field-of-non-pointer.c: Likewise.
|
||||
* jit.dg/test-error-dereference-read-of-non-pointer.c: Likewise.
|
||||
* jit.dg/test-error-mismatching-types-in-assignment.c: Likewise.
|
||||
* jit.dg/test-error-return-within-void-function.c: Likewise.
|
||||
|
||||
2014-01-29 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* jit.dg/test-accessing-struct.c (create_code): Update for API change
|
||||
for accessing fields in terms of gcc_jit_field pointers rather than
|
||||
by name.
|
||||
* jit.dg/test-nested-contexts.c (make_calc_discriminant): Likewise.
|
||||
(make_test_quadratic): Likewise.
|
||||
* jit.dg/test-quadratic.c (make_calc_discriminant): Likewise.
|
||||
(make_test_quadratic): Likewise.
|
||||
* jit.dg/test-reading-struct.c (create_code): Likewise.
|
||||
* jit.dg/test-types.c: Likewise.
|
||||
|
||||
2014-01-28 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* jit.dg/harness.h (test_jit): Add the possibility of turning off
|
||||
this function, if the newly-coined "TEST_ESCHEWS_TEST_JIT" is
|
||||
defined, for use by...
|
||||
* jit.dg/test-nested-contexts.c: New test case, adapting
|
||||
test-quadratic.c, but splitting it into a 3-deep arrangement of
|
||||
nested contexts, to test the implementation of child contexts.
|
||||
|
||||
2014-01-28 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* jit.dg/harness.h (test_jit): Move the various calls to set up
|
||||
options on the context into...
|
||||
(set_options): ...this new function.
|
||||
|
||||
2014-01-27 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* jit.dg/test-error-call-with-not-enough-args.c: New test case.
|
||||
* jit.dg/test-error-call-with-too-many-args.c: New test case.
|
||||
* jit.dg/test-null-passed-to-api.c: Rename to...
|
||||
* jit.dg/test-error-null-passed-to-api.c: ...this, so that
|
||||
error-handling test cases are consistently named.
|
||||
|
||||
2014-01-24 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* jit.dg/test-empty.c: New test case.
|
||||
|
||||
2014-01-24 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* jit.dg/harness.h (code_making_callback): Rename to...
|
||||
(create_code): ...this, and eliminate the returned
|
||||
error-handling value: test cases will simply call into the
|
||||
gcc_jit_ API, without needing to be run from a callback.
|
||||
(test_jit): Don't register a callback, simply call the
|
||||
"create_code" function for the testcase before compiling the
|
||||
context.
|
||||
|
||||
* jit.dg/test-accessing-struct.c: Rename "code_making_callback"
|
||||
to "create_code" and eliminate the return code.
|
||||
* jit.dg/test-calling-external-function.c: Likewise.
|
||||
* jit.dg/test-combination.c: Likewise.
|
||||
* jit.dg/test-dot-product.c: Likewise.
|
||||
* jit.dg/test-expressions.c: Likewise.
|
||||
* jit.dg/test-factorial.c: Likewise.
|
||||
* jit.dg/test-fibonacci.c: Likewise.
|
||||
* jit.dg/test-fuzzer.c: Likewise.
|
||||
* jit.dg/test-hello-world.c: Likewise.
|
||||
* jit.dg/test-null-passed-to-api.c: Likewise.
|
||||
* jit.dg/test-quadratic.c: Likewise.
|
||||
* jit.dg/test-reading-struct.c: Likewise.
|
||||
* jit.dg/test-string-literal.c: Likewise.
|
||||
* jit.dg/test-sum-of-squares.c: Likewise.
|
||||
* jit.dg/test-types.c: Likewise.
|
||||
* jit.dg/test-using-global.c: Likewise.
|
||||
|
||||
* jit.dg/test-failure.c: Remove this test case, since it was
|
||||
specifically for testing the now-defunct callback-based API.
|
||||
|
||||
2014-01-23 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* jit.dg/test-quadratic.c: New test case, written to achieve test
|
||||
coverage of gcc_jit_rvalue_access_field, but also exercising
|
||||
division of doubles.
|
||||
|
||||
* jit.dg/test-combination.c: Add test-quadratic.c
|
||||
|
||||
* jit.dg/test-expressions.c: Add TODOs.
|
||||
|
||||
2014-01-23 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* jit.dg/test-reading-struct.c: New test, to provide test coverage
|
||||
of gcc_jit_type_get_const and gcc_jit_lvalue_access_field, in the
|
||||
process uncovering bugs in how locals were handled.
|
||||
* jit.dg/test-combination.c: Add usage of test-reading-struct.c.
|
||||
|
||||
2014-01-21 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* jit.dg/test-hello-world.c (code_making_callback): Add usage of
|
||||
gcc_jit_function_add_comment.
|
||||
|
||||
2013-10-24 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* jit.dg/harness.h (main): Wrap with #ifndef TEST_PROVIDES_MAIN
|
||||
* jit.dg/test-fuzzer.c: New.
|
||||
|
||||
2013-10-22 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* jit.dg/harness.h (verify_code): Add context param so that
|
||||
test cases of failure can query errors on it.
|
||||
(CHECK_STRING_VALUE): New.
|
||||
(check_string_value): New.
|
||||
(test_jit): Add user_data param and pass it to the code factory.
|
||||
Pass context to verify_code, calling it before releasing said
|
||||
context.
|
||||
(main): Add NULL user_data to test_jit call.
|
||||
* jit.dg/test-accessing-struct.c (verify_code): Add context
|
||||
param.
|
||||
* jit.dg/test-calling-external-function.c (verify_code):
|
||||
Likewise.
|
||||
* jit.dg/test-combination.c (verify_code): Likewise.
|
||||
* jit.dg/test-dot-product.c (verify_code): Likewise.
|
||||
* jit.dg/test-expressions.c (verify_code): Likewise.
|
||||
* jit.dg/test-factorial.c (verify_code): Likewise.
|
||||
* jit.dg/test-failure.c (verify_code): Likewise.
|
||||
* jit.dg/test-fibonacci.c (verify_code): Likewise.
|
||||
* jit.dg/test-hello-world.c (verify_code): Likewise.
|
||||
* jit.dg/test-string-literal.c (verify_code): Likewise.
|
||||
* jit.dg/test-sum-of-squares.c (verify_code): Likewise.
|
||||
* jit.dg/test-types.c (verify_code): Likewise.
|
||||
* jit.dg/test-using-global.c (verify_code): Likewise.
|
||||
* jit.dg/test-null-passed-to-api.c (verify_code): Likewise;
|
||||
use context to verify that the library provides a sane error
|
||||
message to the client code.
|
||||
|
||||
2013-10-21 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* jit.dg/test-expressions.c (test_global): New.
|
||||
(make_test_of_get_address): New.
|
||||
(verify_get_address): New.
|
||||
(code_making_callback): Add call to make_test_of_get_address.
|
||||
(verify_code): Add call to verify_get_address.
|
||||
|
||||
2013-10-18 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* jit.dg/test-expressions.c: New.
|
||||
* jit.dg/test-combination.c: Add usage of test-expressions.c
|
||||
* jit.dg/test-accessing-struct.c (code_making_callback): Update
|
||||
for changes to field-access API.
|
||||
* jit.dg/test-types.c (code_making_callback): Likewise.
|
||||
|
||||
2013-10-18 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* jit.dg/test-null-passed-to-api.c: New.
|
||||
|
||||
2013-10-17 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* jit.dg/test-accessing-struct.c (code_making_callback): Update
|
||||
for changes to type API.
|
||||
* jit.dg/test-calling-external-function.c (code_making_callback):
|
||||
Likewise.
|
||||
* jit.dg/test-dot-product.c (code_making_callback): Likewise.
|
||||
* jit.dg/test-factorial.c (code_making_callback): Likewise.
|
||||
* jit.dg/test-fibonacci.c (code_making_callback): Likewise.
|
||||
* jit.dg/test-hello-world.c (code_making_callback): Likewise.
|
||||
* jit.dg/test-string-literal.c (code_making_callback): Likewise.
|
||||
* jit.dg/test-sum-of-squares.c (code_making_callback): Likewise.
|
||||
* jit.dg/test-using-globals.c (code_making_callback): Likewise.
|
||||
* jit.dg/test-types.c: New.
|
||||
* jit.dg/test-combination.c (code_making_callback): Use code
|
||||
from test-types.c.
|
||||
(verify_code): ...and verify it.
|
||||
|
||||
2013-10-16 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* jit.dg/test-dot-product.c (code_making_callback): Update for
|
||||
API changes to locals.
|
||||
* jit.dg/test-sum-of-squares.c (code_making_callback): Likewise.
|
||||
|
||||
2013-10-14 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* jit.dg/jit.exp (jit-dg-test): Detect compilation errors and
|
||||
make them be test failures.
|
||||
|
||||
2013-10-14 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* jit.dg/test-factorial.c (code_making_callback): Update
|
||||
for change to gcc_jit_function_place_forward_label.
|
||||
* jit.dg/test-fibonacci.c (code_making_callback): Add line
|
||||
numbering to comment, and set up source locations throughout)
|
||||
allowing stepping throught the comment in the debugger.
|
||||
* jit.dg/test-sum-of-squares.c (code_making_callback): Update
|
||||
for change to gcc_jit_function_place_forward_label.
|
||||
|
||||
2013-10-10 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* jit.dg/harness.h: Set GCC_JIT_BOOL_OPTION_DUMP_SUMMARY when
|
||||
running selftests.
|
||||
|
||||
2013-10-08 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* jit.dg/harness.h: Wrap parts of harness within a
|
||||
#ifndef TEST_COMBINATION so that it can be included multiple
|
||||
times.
|
||||
* jit.dg/test-accessing-struct.c (code_making_callback): Rename
|
||||
the generated function from test_fn to test_access to avoid a
|
||||
naming collision in the combined test.
|
||||
(verify_code): Likewise.
|
||||
* jit.dg/test-calling-external-function.c (code_making_callback):
|
||||
Rename the generated function from test_fn to test_caller.
|
||||
(verify_code): Likewise.
|
||||
* jit.dg/test-combination.c: New.
|
||||
* jit.dg/test-string-literal.c (code_making_callback): Rename
|
||||
the generated function from test_fn to test_string_literal.
|
||||
(verify_code): Likewise.
|
||||
* jit.dg/test-using-global.c (code_making_callback): Rename
|
||||
the generated function from test_fn to test_using_global.
|
||||
(verify_code): Likewise.
|
||||
|
||||
2013-10-07 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* jit.dg/harness.h (test_jit): Set
|
||||
GCC_JIT_BOOL_OPTION_SELFCHECK_GC when running selftests.
|
||||
|
||||
2013-10-04 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* jit.dg/test-using-global.c: New.
|
||||
|
||||
2013-10-03 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* jit.dg: New subdirectory
|
||||
* jit.dg/harness.h: New.
|
||||
* jit.dg/jit.exp: New.
|
||||
* jit.dg/test-accessing-struct.c: New.
|
||||
* jit.dg/test-calling-external-function.c: New.
|
||||
* jit.dg/test-dot-product.c: New.
|
||||
* jit.dg/test-factorial.c: New.
|
||||
* jit.dg/test-failure.c: New.
|
||||
* jit.dg/test-fibonacci.c: New.
|
||||
* jit.dg/test-hello-world.c: New.
|
||||
* jit.dg/test-string-literal.c: New.
|
||||
* jit.dg/test-sum-of-squares.c: New.
|
||||
|
||||
|
||||
Copyright (C) 2013-2014 Free Software Foundation, Inc.
|
||||
|
||||
Copying and distribution of this file, with or without modification,
|
||||
are permitted in any medium without royalty provided the copyright
|
||||
notice and this notice are preserved.
|
166
gcc/testsuite/jit.dg/all-non-failing-tests.h
Normal file
166
gcc/testsuite/jit.dg/all-non-failing-tests.h
Normal file
@ -0,0 +1,166 @@
|
||||
/* This file is used by test-combination.c and test-threads.c to
|
||||
bring all of the non-failing test cases into one source file,
|
||||
renaming each "create_code" and "verify_code" hook so that they
|
||||
each have unique name. */
|
||||
|
||||
/* Include various other test cases, defining COMBINED_TEST so that
|
||||
harness.h doesn't duplicate copes of e.g. main, and renaming the
|
||||
hooks provided by each test case. */
|
||||
#define COMBINED_TEST
|
||||
|
||||
/* test-accessing-struct.c */
|
||||
#define create_code create_code_accessing_struct
|
||||
#define verify_code verify_code_accessing_struct
|
||||
#include "test-accessing-struct.c"
|
||||
#undef create_code
|
||||
#undef verify_code
|
||||
|
||||
/* test-accessing-union.c */
|
||||
#define create_code create_code_accessing_union
|
||||
#define verify_code verify_code_accessing_union
|
||||
#include "test-accessing-union.c"
|
||||
#undef create_code
|
||||
#undef verify_code
|
||||
|
||||
/* test-array-as-pointer.c */
|
||||
#define create_code create_code_array_as_pointer
|
||||
#define verify_code verify_code_array_as_pointer
|
||||
#include "test-array-as-pointer.c"
|
||||
#undef create_code
|
||||
#undef verify_code
|
||||
|
||||
/* test-arrays.c */
|
||||
#define create_code create_code_arrays
|
||||
#define verify_code verify_code_arrays
|
||||
#include "test-arrays.c"
|
||||
#undef create_code
|
||||
#undef verify_code
|
||||
|
||||
/* test-calling-external-function.c */
|
||||
#define create_code create_code_calling_external_function
|
||||
#define verify_code verify_code_calling_external_function
|
||||
#include "test-calling-external-function.c"
|
||||
#undef create_code
|
||||
#undef verify_code
|
||||
|
||||
/* test-calling-function-ptr.c */
|
||||
#define create_code create_code_calling_function_ptr
|
||||
#define verify_code verify_code_calling_function_ptr
|
||||
#include "test-calling-function-ptr.c"
|
||||
#undef create_code
|
||||
#undef verify_code
|
||||
|
||||
/* test-dot-product.c */
|
||||
#define create_code create_code_dot_product
|
||||
#define verify_code verify_code_dot_product
|
||||
#include "test-dot-product.c"
|
||||
#undef create_code
|
||||
#undef verify_code
|
||||
|
||||
/* test-error-*.c: We don't use these test cases, since they deliberately
|
||||
introduce errors, which we don't want here. */
|
||||
|
||||
/* test-expressions.c */
|
||||
#define create_code create_code_expressions
|
||||
#define verify_code verify_code_expressions
|
||||
#include "test-expressions.c"
|
||||
#undef create_code
|
||||
#undef verify_code
|
||||
|
||||
/* test-factorial.c */
|
||||
#define create_code create_code_factorial
|
||||
#define verify_code verify_code_factorial
|
||||
#include "test-factorial.c"
|
||||
#undef create_code
|
||||
#undef verify_code
|
||||
|
||||
/* test-fibonacci.c */
|
||||
#define create_code create_code_fibonacci
|
||||
#define verify_code verify_code_fibonacci
|
||||
#include "test-fibonacci.c"
|
||||
#undef create_code
|
||||
#undef verify_code
|
||||
|
||||
/* test-functions.c */
|
||||
#define create_code create_code_functions
|
||||
#define verify_code verify_code_functions
|
||||
#include "test-functions.c"
|
||||
#undef create_code
|
||||
#undef verify_code
|
||||
|
||||
/* test-hello-world.c */
|
||||
#define create_code create_code_hello_world
|
||||
#define verify_code verify_code_hello_world
|
||||
#include "test-hello-world.c"
|
||||
#undef create_code
|
||||
#undef verify_code
|
||||
|
||||
/* test-linked-list.c */
|
||||
#define create_code create_code_linked_list
|
||||
#define verify_code verify_code_linked_list
|
||||
#include "test-linked-list.c"
|
||||
#undef create_code
|
||||
#undef verify_code
|
||||
|
||||
/* test-long-names.c */
|
||||
#define create_code create_code_long_names
|
||||
#define verify_code verify_code_long_names
|
||||
#include "test-long-names.c"
|
||||
#undef create_code
|
||||
#undef verify_code
|
||||
|
||||
/* test-quadratic.c */
|
||||
#define create_code create_code_quadratic
|
||||
#define verify_code verify_code_quadratic
|
||||
#include "test-quadratic.c"
|
||||
#undef create_code
|
||||
#undef verify_code
|
||||
|
||||
/* test-nested-loops.c */
|
||||
#define create_code create_code_nested_loop
|
||||
#define verify_code verify_code_nested_loop
|
||||
#include "test-nested-loops.c"
|
||||
#undef create_code
|
||||
#undef verify_code
|
||||
|
||||
/* test-reading-struct.c */
|
||||
#define create_code create_code_reading_struct
|
||||
#define verify_code verify_code_reading_struct
|
||||
#include "test-reading-struct.c"
|
||||
#undef create_code
|
||||
#undef verify_code
|
||||
|
||||
/* test-string-literal.c */
|
||||
#define create_code create_code_string_literal
|
||||
#define verify_code verify_code_string_literal
|
||||
#include "test-string-literal.c"
|
||||
#undef create_code
|
||||
#undef verify_code
|
||||
|
||||
/* test-sum-of-squares.c */
|
||||
#define create_code create_code_sum_of_squares
|
||||
#define verify_code verify_code_sum_of_squares
|
||||
#include "test-sum-of-squares.c"
|
||||
#undef create_code
|
||||
#undef verify_code
|
||||
|
||||
/* test-types.c */
|
||||
#define create_code create_code_types
|
||||
#define verify_code verify_code_types
|
||||
#include "test-types.c"
|
||||
#undef create_code
|
||||
#undef verify_code
|
||||
|
||||
/* test-using-global.c */
|
||||
#define create_code create_code_using_global
|
||||
#define verify_code verify_code_using_global
|
||||
#include "test-using-global.c"
|
||||
#undef create_code
|
||||
#undef verify_code
|
||||
|
||||
/* test-volatile.c */
|
||||
#define create_code create_code_volatile
|
||||
#define verify_code verify_code_volatile
|
||||
#include "test-volatile.c"
|
||||
#undef create_code
|
||||
#undef verify_code
|
242
gcc/testsuite/jit.dg/harness.h
Normal file
242
gcc/testsuite/jit.dg/harness.h
Normal file
@ -0,0 +1,242 @@
|
||||
/*
|
||||
Code shared between multiple testcases.
|
||||
|
||||
This file contains "main" and support code.
|
||||
Each testcase should implement the following hooks:
|
||||
|
||||
extern void
|
||||
create_code (gcc_jit_context *ctxt, void * user_data);
|
||||
|
||||
extern void
|
||||
verify_code (gcc_jit_context *ctxt, gcc_jit_result *result);
|
||||
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/* test-threads.c use threads, but dejagnu.h isn't thread-safe; there's a
|
||||
shared "buffer", and the counts of passed/failed etc are globals.
|
||||
|
||||
The solution is to use macros to rename "pass" and "fail", replacing them
|
||||
with mutex-guarded alternatives. */
|
||||
#ifdef MAKE_DEJAGNU_H_THREADSAFE
|
||||
#define pass dejagnu_pass
|
||||
#define fail dejagnu_fail
|
||||
#define note dejagnu_note
|
||||
#endif
|
||||
|
||||
#include <dejagnu.h>
|
||||
|
||||
#ifdef MAKE_DEJAGNU_H_THREADSAFE
|
||||
#undef pass
|
||||
#undef fail
|
||||
#undef note
|
||||
#endif
|
||||
|
||||
static char test[1024];
|
||||
|
||||
#define CHECK_NON_NULL(PTR) \
|
||||
do { \
|
||||
if ((PTR) != NULL) \
|
||||
{ \
|
||||
pass ("%s: %s is non-null", test, #PTR); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
fail ("%s: %s is NULL", test, #PTR); \
|
||||
abort (); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define CHECK_VALUE(ACTUAL, EXPECTED) \
|
||||
do { \
|
||||
if ((ACTUAL) == (EXPECTED)) \
|
||||
{ \
|
||||
pass ("%s: actual: %s == expected: %s", test, #ACTUAL, #EXPECTED); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
fail ("%s: actual: %s != expected: %s", test, #ACTUAL, #EXPECTED); \
|
||||
fprintf (stderr, "incorrect value\n"); \
|
||||
abort (); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define CHECK_DOUBLE_VALUE(ACTUAL, EXPECTED) \
|
||||
do { \
|
||||
double expected = (EXPECTED); \
|
||||
double actual = (ACTUAL); \
|
||||
if (abs (actual - expected) < 0.00001) \
|
||||
{ \
|
||||
pass ("%s: actual: %s == expected: %s", test, #ACTUAL, #EXPECTED); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
fail ("%s: actual: %s != expected: %s", test, #ACTUAL, #EXPECTED); \
|
||||
fprintf (stderr, "incorrect value: %f\n", actual); \
|
||||
abort (); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define CHECK_STRING_VALUE(ACTUAL, EXPECTED) \
|
||||
check_string_value ((ACTUAL), (EXPECTED));
|
||||
|
||||
#define CHECK(COND) \
|
||||
do { \
|
||||
if (COND) \
|
||||
{ \
|
||||
pass ("%s: %s", test, #COND); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
fail ("%s: %s", test, #COND); \
|
||||
abort (); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* Hooks that testcases should provide. */
|
||||
extern void
|
||||
create_code (gcc_jit_context *ctxt, void * user_data);
|
||||
|
||||
extern void
|
||||
verify_code (gcc_jit_context *ctxt, gcc_jit_result *result);
|
||||
|
||||
extern void check_string_value (const char *actual, const char *expected);
|
||||
|
||||
/* Implement framework needed for turning the testcase hooks into an
|
||||
executable. test-combination.c and test-threads.c each combine multiple
|
||||
testcases into larger testcases, so we have COMBINED_TEST as a way of
|
||||
temporarily turning off this part of harness.h. */
|
||||
#ifndef COMBINED_TEST
|
||||
|
||||
void check_string_value (const char *actual, const char *expected)
|
||||
{
|
||||
if (actual && !expected)
|
||||
{
|
||||
fail ("%s: actual: \"%s\" != expected: NULL", test, actual);
|
||||
fprintf (stderr, "incorrect value\n");
|
||||
abort ();
|
||||
}
|
||||
if (expected && !actual)
|
||||
{
|
||||
fail ("%s: actual: NULL != expected: \"%s\"", test, expected);
|
||||
fprintf (stderr, "incorrect value\n");
|
||||
abort ();
|
||||
}
|
||||
if (actual && expected)
|
||||
{
|
||||
if (strcmp (actual, expected))
|
||||
{
|
||||
fail ("%s: actual: \"%s\" != expected: \"%s\"", test, actual, expected);
|
||||
fprintf (stderr, "incorrect valuen");
|
||||
abort ();
|
||||
}
|
||||
pass ("%s: actual: \"%s\" == expected: \"%s\"", test, actual, expected);
|
||||
}
|
||||
else
|
||||
pass ("%s: actual: NULL == expected: NULL");
|
||||
}
|
||||
|
||||
static void set_options (gcc_jit_context *ctxt, const char *argv0)
|
||||
{
|
||||
/* Set up options. */
|
||||
gcc_jit_context_set_str_option (
|
||||
ctxt,
|
||||
GCC_JIT_STR_OPTION_PROGNAME,
|
||||
argv0);
|
||||
gcc_jit_context_set_int_option (
|
||||
ctxt,
|
||||
GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL,
|
||||
3);
|
||||
gcc_jit_context_set_bool_option (
|
||||
ctxt,
|
||||
GCC_JIT_BOOL_OPTION_DEBUGINFO,
|
||||
1);
|
||||
gcc_jit_context_set_bool_option (
|
||||
ctxt,
|
||||
GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE,
|
||||
0);
|
||||
gcc_jit_context_set_bool_option (
|
||||
ctxt,
|
||||
GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE,
|
||||
0);
|
||||
gcc_jit_context_set_bool_option (
|
||||
ctxt,
|
||||
GCC_JIT_BOOL_OPTION_SELFCHECK_GC,
|
||||
1);
|
||||
gcc_jit_context_set_bool_option (
|
||||
ctxt,
|
||||
GCC_JIT_BOOL_OPTION_DUMP_SUMMARY,
|
||||
0);
|
||||
}
|
||||
|
||||
#ifndef TEST_ESCHEWS_TEST_JIT
|
||||
/* Run one iteration of the test. */
|
||||
static void
|
||||
test_jit (const char *argv0, void *user_data)
|
||||
{
|
||||
gcc_jit_context *ctxt;
|
||||
gcc_jit_result *result;
|
||||
|
||||
ctxt = gcc_jit_context_acquire ();
|
||||
/* FIXME: error-handling */
|
||||
|
||||
set_options (ctxt, argv0);
|
||||
|
||||
create_code (ctxt, user_data);
|
||||
|
||||
/* This actually calls into GCC and runs the build, all
|
||||
in a mutex for now. */
|
||||
result = gcc_jit_context_compile (ctxt);
|
||||
|
||||
verify_code (ctxt, result);
|
||||
|
||||
gcc_jit_context_release (ctxt);
|
||||
|
||||
/* Once we're done with the code, this unloads the built .so file: */
|
||||
gcc_jit_result_release (result);
|
||||
}
|
||||
#endif /* #ifndef TEST_ESCHEWS_TEST_JIT */
|
||||
|
||||
/* We want to prefix all unit test results with the test, but dejagnu.exp's
|
||||
host_execute appears to get confused by the leading "./" of argv0,
|
||||
leading to all tests simply reporting as a single period character ".".
|
||||
|
||||
Hence strip out the final component of the path to the program name,
|
||||
so that we can use that in unittest reports. */
|
||||
const char*
|
||||
extract_progname (const char *argv0)
|
||||
{
|
||||
const char *p;
|
||||
|
||||
p = argv0 + strlen (argv0);
|
||||
while (p != argv0 && p[-1] != '/')
|
||||
--p;
|
||||
return p;
|
||||
}
|
||||
|
||||
#ifndef TEST_PROVIDES_MAIN
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 1; i <= 5; i++)
|
||||
{
|
||||
snprintf (test, sizeof (test),
|
||||
"%s iteration %d of %d",
|
||||
extract_progname (argv[0]),
|
||||
i, 5);
|
||||
|
||||
//printf ("ITERATION %d\n", i);
|
||||
test_jit (argv[0], NULL);
|
||||
//printf ("\n");
|
||||
}
|
||||
|
||||
totals ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* #ifndef TEST_PROVIDES_MAIN */
|
||||
|
||||
#endif /* #ifndef COMBINED_TEST */
|
293
gcc/testsuite/jit.dg/jit.exp
Normal file
293
gcc/testsuite/jit.dg/jit.exp
Normal file
@ -0,0 +1,293 @@
|
||||
# Test code for libgccjit.so
|
||||
#
|
||||
# We will compile each of jit.dg/test-*.c into an executable
|
||||
# dynamically linked against libgccjit.so, and then run each
|
||||
# such executable.
|
||||
#
|
||||
# These executables call into the libgccjit.so API to create
|
||||
# code, compile it, and run it, verifying that the results
|
||||
# are as expected. See harness.h for shared code used by all
|
||||
# such executables.
|
||||
#
|
||||
# The executables call into DejaGnu's unit testing C API to
|
||||
# report PASS/FAIL results, which this script gathers back
|
||||
# up into the Tcl world, reporting a summary of all results
|
||||
# across all of the executables.
|
||||
|
||||
load_lib dg.exp
|
||||
load_lib prune.exp
|
||||
load_lib target-supports.exp
|
||||
load_lib gcc-defs.exp
|
||||
load_lib timeout.exp
|
||||
load_lib target-libpath.exp
|
||||
load_lib gcc.exp
|
||||
load_lib dejagnu.exp
|
||||
|
||||
# This is host_execute from dejagnu.exp commit
|
||||
# 126a089777158a7891ff975473939f08c0e31a1c
|
||||
# with the following patch applied, and renaming to "fixed_host_execute".
|
||||
# See the discussion at
|
||||
# http://lists.gnu.org/archive/html/dejagnu/2014-10/msg00000.html
|
||||
#
|
||||
# --- /usr/share/dejagnu/dejagnu.exp.old 2014-10-08 13:38:57.274068541 -0400
|
||||
# +++ /usr/share/dejagnu/dejagnu.exp 2014-10-10 12:27:51.113813659 -0400
|
||||
# @@ -113,8 +113,6 @@ proc host_execute {args} {
|
||||
# set timetol 0
|
||||
# set arguments ""
|
||||
#
|
||||
# - expect_before buffer_full { perror "Buffer full" }
|
||||
# -
|
||||
# if { [llength $args] == 0} {
|
||||
# set executable $args
|
||||
# } else {
|
||||
|
||||
|
||||
# Execute the executable file, and anaylyse the output for the
|
||||
# test state keywords.
|
||||
# Returns:
|
||||
# A "" (empty) string if everything worked, or an error message
|
||||
# if there was a problem.
|
||||
#
|
||||
proc fixed_host_execute {args} {
|
||||
global text
|
||||
global spawn_id
|
||||
|
||||
set timeoutmsg "Timed out: Never got started, "
|
||||
set timeout 100
|
||||
set file all
|
||||
set timetol 0
|
||||
set arguments ""
|
||||
|
||||
if { [llength $args] == 0} {
|
||||
set executable $args
|
||||
} else {
|
||||
set executable [string trimleft [lindex [split $args " "] 0] "\{"]
|
||||
set params [string trimleft [lindex [split $args " "] 1] "\{"]
|
||||
set params [string trimright $params "\}"]
|
||||
}
|
||||
|
||||
verbose "The executable is $executable" 2
|
||||
if {![file exists ${executable}]} {
|
||||
perror "The executable, \"$executable\" is missing" 0
|
||||
return "No source file found"
|
||||
}
|
||||
|
||||
# spawn the executable and look for the DejaGnu output messages from the
|
||||
# test case.
|
||||
# spawn -noecho -open [open "|./${executable}" "r"]
|
||||
spawn -noecho "./${executable}" ${params}
|
||||
expect_after full_buffer { error "got full_buffer" }
|
||||
|
||||
set prefix "\[^\r\n\]*"
|
||||
expect {
|
||||
-re "^$prefix\[0-9\]\[0-9\]:..:..:${text}*\r\n" {
|
||||
regsub "\[\n\r\t\]*NOTE: $text\r\n" $expect_out(0,string) "" output
|
||||
verbose "$output" 3
|
||||
set timetol 0
|
||||
exp_continue
|
||||
}
|
||||
-re "^$prefix\tNOTE:${text}*" {
|
||||
regsub "\[\n\r\t\]*NOTE: $text\r\n" $expect_out(0,string) "" output
|
||||
set output [string range $output 6 end]
|
||||
verbose "$output" 2
|
||||
set timetol 0
|
||||
exp_continue
|
||||
}
|
||||
-re "^$prefix\tPASSED:${text}*" {
|
||||
regsub "\[\n\r\t\]*PASSED: $text\r\n" $expect_out(0,string) "" output
|
||||
set output [string range $output 8 end]
|
||||
pass "$output"
|
||||
set timetol 0
|
||||
exp_continue
|
||||
}
|
||||
-re "^$prefix\tFAILED:${text}*" {
|
||||
regsub "\[\n\r\t\]*FAILED: $text\r\n" $expect_out(0,string) "" output
|
||||
set output [string range $output 8 end]
|
||||
fail "$output"
|
||||
set timetol 0
|
||||
exp_continue
|
||||
}
|
||||
-re "^$prefix\tUNTESTED:${text}*" {
|
||||
regsub "\[\n\r\t\]*TESTED: $text\r\n" $expect_out(0,string) "" output
|
||||
set output [string range $output 8 end]
|
||||
untested "$output"
|
||||
set timetol 0
|
||||
exp_continue
|
||||
}
|
||||
-re "^$prefix\tUNRESOLVED:${text}*" {
|
||||
regsub "\[\n\r\t\]*UNRESOLVED: $text\r\n" $expect_out(0,string) "" output
|
||||
set output [string range $output 8 end]
|
||||
unresolved "$output"
|
||||
set timetol 0
|
||||
exp_continue
|
||||
}
|
||||
-re "^Totals" {
|
||||
verbose "All done" 2
|
||||
}
|
||||
eof {
|
||||
# unresolved "${executable} died prematurely"
|
||||
# catch close
|
||||
# return "${executable} died prematurely"
|
||||
}
|
||||
timeout {
|
||||
warning "Timed out executing test case"
|
||||
if { $timetol <= 2 } {
|
||||
incr timetol
|
||||
exp_continue
|
||||
} else {
|
||||
- catch close
|
||||
return "Timed out executing test case"
|
||||
}
|
||||
}
|
||||
-re "^$prefix\r\n" {
|
||||
exp_continue
|
||||
}
|
||||
}
|
||||
|
||||
# force a close of the executable to be safe.
|
||||
catch close
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
# (end of code from dejagnu.exp)
|
||||
|
||||
# GCC_UNDER_TEST is needed by gcc_target_compile
|
||||
global GCC_UNDER_TEST
|
||||
if ![info exists GCC_UNDER_TEST] {
|
||||
set GCC_UNDER_TEST "[find_gcc]"
|
||||
}
|
||||
|
||||
# Initialize dg.
|
||||
dg-init
|
||||
|
||||
# Gather a list of all tests.
|
||||
|
||||
# Tests within the testsuite: gcc/testsuite/jit.dg/test-*.c
|
||||
set tests [lsort [find $srcdir/$subdir test-*.c]]
|
||||
|
||||
# We also test the examples within the documentation, to ensure that
|
||||
# they compile:
|
||||
set tests [lsort [concat $tests [find $srcdir/../jit/docs/examples *.c]]]
|
||||
|
||||
verbose "tests: $tests"
|
||||
|
||||
# libgloss has found the driver (as "xgcc" or "gcc) and stored
|
||||
# its full path as GCC_UNDER_TEST.
|
||||
proc get_path_of_driver {} {
|
||||
global GCC_UNDER_TEST
|
||||
|
||||
verbose "GCC_UNDER_TEST: $GCC_UNDER_TEST"
|
||||
set binary [lindex $GCC_UNDER_TEST 0]
|
||||
verbose "binary: $binary"
|
||||
|
||||
return [file dirname $binary]
|
||||
}
|
||||
|
||||
proc jit-dg-test { prog do_what extra_tool_flags } {
|
||||
verbose "within jit-dg-test..."
|
||||
verbose " prog: $prog"
|
||||
verbose " do_what: $do_what"
|
||||
verbose " extra_tool_flags: $extra_tool_flags"
|
||||
|
||||
# test-threads.c needs to be linked against pthreads
|
||||
if {[string match "*test-threads.c" $prog]} {
|
||||
append extra_tool_flags " -lpthread"
|
||||
}
|
||||
|
||||
# Determine what to name the built executable.
|
||||
set output_file "[file rootname [file tail $prog]].exe"
|
||||
verbose "output_file: $output_file"
|
||||
|
||||
# Create the test executable:
|
||||
set comp_output [gcc_target_compile $prog $output_file $do_what \
|
||||
"{additional_flags=$extra_tool_flags}"]
|
||||
if ![jit_check_compile "$prog" "initial compilation" \
|
||||
$output_file $comp_output] then {
|
||||
return
|
||||
}
|
||||
|
||||
# Run the test executable, capturing the PASS/FAIL textual output
|
||||
# from the C API, converting it into the Tcl API.
|
||||
|
||||
# We need to set LD_LIBRARY_PATH so that the test files can find
|
||||
# libgccjit.so
|
||||
# Do this using set_ld_library_path_env_vars from target-libpath.exp
|
||||
global ld_library_path
|
||||
global base_dir
|
||||
set ld_library_path "$base_dir/../../"
|
||||
set_ld_library_path_env_vars
|
||||
|
||||
# libgccjit uses the driver to convert .s files to .so libraries
|
||||
# via its *installed* name, FULL_DRIVER_NAME
|
||||
# ${target_noncanonical}-gcc-${gcc_BASEVER}${exeext}
|
||||
# e.g. "x86_64-unknown-linux-gnu-gcc-5.0.0"
|
||||
# looking for it on PATH. Hence we need to prepend the location of
|
||||
# that executable to PATH when running the tests
|
||||
set dir_containing_driver [get_path_of_driver ]
|
||||
verbose "dir_containing_driver: $dir_containing_driver"
|
||||
global env
|
||||
set old_path $env(PATH)
|
||||
setenv "PATH" $dir_containing_driver:$old_path
|
||||
verbose -log "PATH=[getenv PATH]"
|
||||
|
||||
# We have:
|
||||
# test-executables
|
||||
# linked to -> libgccjit.so
|
||||
# -> invokes driver:
|
||||
# -> invokes the assembler
|
||||
# -> invokes the linker
|
||||
# We want to be able to run this from the builddir without installing
|
||||
# but the linker needs to be able to locate various libraries, or we
|
||||
# get:
|
||||
# ld: cannot find crtbeginS.o: No such file or directory
|
||||
# ld: cannot find -lgcc
|
||||
# ld: cannot find -lgcc_s
|
||||
# These can be found in the "gcc" subdir of the build.
|
||||
# Hence to be able to run the testsuite without installing, we need
|
||||
# to set or prepend the "gcc" subdir of the build to LIBRARY_PATH:
|
||||
if { [info exists env(LIBRARY_PATH) ] } {
|
||||
set old_library_path $env(LIBRARY_PATH)
|
||||
setenv "LIBRARY_PATH" $dir_containing_driver:$old_library_path
|
||||
} else {
|
||||
setenv "LIBRARY_PATH" $dir_containing_driver
|
||||
}
|
||||
verbose -log "LIBRARY_PATH=[getenv LIBRARY_PATH]"
|
||||
|
||||
# dejagnu.exp's host_execute has code to scrape out test results
|
||||
# from the DejaGnu C API and bring back into the tcl world, so we
|
||||
# use that to invoke the built code.
|
||||
# However, it appears to be buggy; see:
|
||||
# http://lists.gnu.org/archive/html/dejagnu/2014-10/msg00000.html
|
||||
# We instead call a patched local copy, "fixed_host_execute", defined
|
||||
# above.
|
||||
set result [fixed_host_execute $output_file]
|
||||
verbose "result: $result"
|
||||
|
||||
# Restore PATH
|
||||
setenv "PATH" $old_path
|
||||
|
||||
# Restore LIBRARY_PATH
|
||||
if { [info exists old_library_path] } {
|
||||
setenv "LIBRARY_PATH" $old_library_path
|
||||
} else {
|
||||
unsetenv "LIBRARY_PATH"
|
||||
}
|
||||
|
||||
restore_ld_library_path_env_vars
|
||||
}
|
||||
|
||||
# We need to link with --export-dynamic for test-calling-external-function.c
|
||||
# so that the JIT-built code can call into functions from the main program.
|
||||
set DEFAULT_CFLAGS "-I$srcdir/../jit -lgccjit -g -Wall -Werror -Wl,--export-dynamic"
|
||||
|
||||
# <dejagnu.h> assumes -fgnu89-inline
|
||||
# See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63613
|
||||
# and http://lists.gnu.org/archive/html/dejagnu/2014-10/msg00011.html
|
||||
append DEFAULT_CFLAGS " -fgnu89-inline"
|
||||
|
||||
# Main loop. This will invoke jig-dg-test on each test-*.c file.
|
||||
dg-runtest $tests "" $DEFAULT_CFLAGS
|
||||
|
||||
# All done.
|
||||
dg-finish
|
112
gcc/testsuite/jit.dg/test-accessing-struct.c
Normal file
112
gcc/testsuite/jit.dg/test-accessing-struct.c
Normal file
@ -0,0 +1,112 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "libgccjit.h"
|
||||
|
||||
#include "harness.h"
|
||||
|
||||
struct foo
|
||||
{
|
||||
int x;
|
||||
int y;
|
||||
int z;
|
||||
};
|
||||
|
||||
void
|
||||
create_code (gcc_jit_context *ctxt, void *user_data)
|
||||
{
|
||||
/* Let's try to inject the equivalent of:
|
||||
void
|
||||
test_access (struct foo *f)
|
||||
{
|
||||
f->z = f->x * f->y;
|
||||
}
|
||||
*/
|
||||
gcc_jit_type *void_type =
|
||||
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
|
||||
gcc_jit_type *int_type =
|
||||
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
|
||||
gcc_jit_field *x =
|
||||
gcc_jit_context_new_field (ctxt,
|
||||
NULL,
|
||||
int_type,
|
||||
"x");
|
||||
gcc_jit_field *y =
|
||||
gcc_jit_context_new_field (ctxt,
|
||||
NULL,
|
||||
int_type,
|
||||
"y");
|
||||
gcc_jit_field *z =
|
||||
gcc_jit_context_new_field (ctxt,
|
||||
NULL,
|
||||
int_type,
|
||||
"z");
|
||||
gcc_jit_field *fields[] = {x, y, z};
|
||||
gcc_jit_struct *struct_type =
|
||||
gcc_jit_context_new_struct_type (ctxt, NULL, "foo", 3, fields);
|
||||
gcc_jit_type *ptr_type =
|
||||
gcc_jit_type_get_pointer (gcc_jit_struct_as_type (struct_type));
|
||||
|
||||
/* Build the test function. */
|
||||
gcc_jit_param *param_f =
|
||||
gcc_jit_context_new_param (ctxt, NULL, ptr_type, "f");
|
||||
gcc_jit_function *test_fn =
|
||||
gcc_jit_context_new_function (ctxt, NULL,
|
||||
GCC_JIT_FUNCTION_EXPORTED,
|
||||
void_type,
|
||||
"test_access",
|
||||
1, ¶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);
|
||||
}
|
||||
|
97
gcc/testsuite/jit.dg/test-accessing-union.c
Normal file
97
gcc/testsuite/jit.dg/test-accessing-union.c
Normal file
@ -0,0 +1,97 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "libgccjit.h"
|
||||
|
||||
#include "harness.h"
|
||||
|
||||
union int_or_float
|
||||
{
|
||||
int as_int;
|
||||
float as_float;
|
||||
};
|
||||
|
||||
void
|
||||
create_code (gcc_jit_context *ctxt, void *user_data)
|
||||
{
|
||||
/* Let's try to inject the equivalent of:
|
||||
float
|
||||
test_union (int i)
|
||||
{
|
||||
union int_or_float u;
|
||||
u.as_int = i;
|
||||
return u.as_float;
|
||||
}
|
||||
*/
|
||||
gcc_jit_type *int_type =
|
||||
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
|
||||
gcc_jit_type *float_type =
|
||||
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_FLOAT);
|
||||
gcc_jit_field *as_int =
|
||||
gcc_jit_context_new_field (ctxt,
|
||||
NULL,
|
||||
int_type,
|
||||
"as_int");
|
||||
gcc_jit_field *as_float =
|
||||
gcc_jit_context_new_field (ctxt,
|
||||
NULL,
|
||||
float_type,
|
||||
"as_float");
|
||||
gcc_jit_field *fields[] = {as_int, as_float};
|
||||
gcc_jit_type *union_type =
|
||||
gcc_jit_context_new_union_type (ctxt, NULL,
|
||||
"int_or_float", 2, fields);
|
||||
|
||||
/* Build the test function. */
|
||||
gcc_jit_param *param_i =
|
||||
gcc_jit_context_new_param (ctxt, NULL, int_type, "i");
|
||||
gcc_jit_function *test_fn =
|
||||
gcc_jit_context_new_function (ctxt, NULL,
|
||||
GCC_JIT_FUNCTION_EXPORTED,
|
||||
float_type,
|
||||
"test_union",
|
||||
1, ¶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);
|
||||
}
|
101
gcc/testsuite/jit.dg/test-array-as-pointer.c
Normal file
101
gcc/testsuite/jit.dg/test-array-as-pointer.c
Normal file
@ -0,0 +1,101 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "libgccjit.h"
|
||||
|
||||
#include "harness.h"
|
||||
|
||||
#define BUFFER_SIZE (1024)
|
||||
|
||||
char test_buffer[1024];
|
||||
|
||||
void
|
||||
create_code (gcc_jit_context *ctxt, void *user_data)
|
||||
{
|
||||
/* Let's try to inject the equivalent of:
|
||||
void test_of_array_as_pointer (const char *name)
|
||||
{
|
||||
snprintf (test_buffer, sizeof (test_buffer),
|
||||
"hello %s", name);
|
||||
}
|
||||
*/
|
||||
gcc_jit_type *void_type =
|
||||
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
|
||||
gcc_jit_type *const_char_ptr_type =
|
||||
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_CONST_CHAR_PTR);
|
||||
gcc_jit_type *char_type =
|
||||
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_CHAR);
|
||||
gcc_jit_type *char_ptr_type =
|
||||
gcc_jit_type_get_pointer (char_type);
|
||||
gcc_jit_type *int_type =
|
||||
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
|
||||
gcc_jit_type *size_t_type =
|
||||
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_SIZE_T);
|
||||
gcc_jit_type *buf_type =
|
||||
gcc_jit_context_new_array_type (ctxt, NULL, char_type, BUFFER_SIZE);
|
||||
|
||||
/* extern int snprintf(char *str, size_t size, const char *format, ...); */
|
||||
gcc_jit_param *param_s =
|
||||
gcc_jit_context_new_param (ctxt, NULL, char_ptr_type, "s");
|
||||
gcc_jit_param *param_n =
|
||||
gcc_jit_context_new_param (ctxt, NULL, size_t_type, "n");
|
||||
gcc_jit_param *param_format =
|
||||
gcc_jit_context_new_param (ctxt, NULL, const_char_ptr_type, "format");
|
||||
gcc_jit_param *snprintf_params[3] = {param_s, param_n, param_format};
|
||||
gcc_jit_function *snprintf =
|
||||
gcc_jit_context_new_function (ctxt, NULL,
|
||||
GCC_JIT_FUNCTION_IMPORTED,
|
||||
int_type,
|
||||
"snprintf",
|
||||
3, snprintf_params,
|
||||
1);
|
||||
|
||||
gcc_jit_param *param_name =
|
||||
gcc_jit_context_new_param (ctxt, NULL, const_char_ptr_type, "name");
|
||||
gcc_jit_function *test_fn =
|
||||
gcc_jit_context_new_function (ctxt, NULL,
|
||||
GCC_JIT_FUNCTION_EXPORTED,
|
||||
void_type,
|
||||
"test_of_array_as_pointer",
|
||||
1, ¶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");
|
||||
}
|
165
gcc/testsuite/jit.dg/test-arrays.c
Normal file
165
gcc/testsuite/jit.dg/test-arrays.c
Normal file
@ -0,0 +1,165 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "libgccjit.h"
|
||||
|
||||
#include "harness.h"
|
||||
|
||||
#define ARRAY_SIZE (4)
|
||||
|
||||
/* Verify that struct layout works properly when adding an array field. */
|
||||
struct array_holder
|
||||
{
|
||||
float m_before;
|
||||
int m_ints[ARRAY_SIZE];
|
||||
float m_after;
|
||||
};
|
||||
|
||||
void
|
||||
create_code (gcc_jit_context *ctxt, void *user_data)
|
||||
{
|
||||
/* Let's try to inject the equivalent of:
|
||||
|
||||
void
|
||||
test_array (struct array_holder *ah)
|
||||
{
|
||||
ah->m_before = 4.0f;
|
||||
for i in 0 to (ARRAY_SIZE - 1):
|
||||
ah->m_ints[i] = (i * i);
|
||||
ah->m_after = 2.0f;
|
||||
}
|
||||
*/
|
||||
gcc_jit_type *void_type =
|
||||
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
|
||||
gcc_jit_type *float_type =
|
||||
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_FLOAT);
|
||||
gcc_jit_type *int_type =
|
||||
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
|
||||
|
||||
gcc_jit_field *field_m_before =
|
||||
gcc_jit_context_new_field (ctxt, NULL, float_type, "m_before");
|
||||
gcc_jit_field *field_m_ints =
|
||||
gcc_jit_context_new_field (
|
||||
ctxt, NULL,
|
||||
gcc_jit_context_new_array_type (ctxt, NULL, int_type, ARRAY_SIZE),
|
||||
"m_ints");
|
||||
gcc_jit_field *field_m_after =
|
||||
gcc_jit_context_new_field (ctxt, NULL, float_type, "m_after");
|
||||
|
||||
gcc_jit_field *fields[] = {
|
||||
field_m_before,
|
||||
field_m_ints,
|
||||
field_m_after,
|
||||
};
|
||||
|
||||
gcc_jit_struct *struct_type =
|
||||
gcc_jit_context_new_struct_type (
|
||||
ctxt,
|
||||
NULL,
|
||||
"array_holder",
|
||||
3, fields);
|
||||
|
||||
gcc_jit_type *struct_ptr_type =
|
||||
gcc_jit_type_get_pointer (gcc_jit_struct_as_type (struct_type));
|
||||
|
||||
/* Build the test_fn. */
|
||||
gcc_jit_param *param_ah =
|
||||
gcc_jit_context_new_param (ctxt, NULL, struct_ptr_type, "ah");
|
||||
gcc_jit_function *func =
|
||||
gcc_jit_context_new_function (ctxt, NULL,
|
||||
GCC_JIT_FUNCTION_EXPORTED,
|
||||
void_type,
|
||||
"test_array",
|
||||
1, ¶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);
|
||||
|
||||
}
|
118
gcc/testsuite/jit.dg/test-calling-external-function.c
Normal file
118
gcc/testsuite/jit.dg/test-calling-external-function.c
Normal file
@ -0,0 +1,118 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "libgccjit.h"
|
||||
|
||||
#include "harness.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern void
|
||||
called_function (int i, int j, int k);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
create_code (gcc_jit_context *ctxt, void *user_data)
|
||||
{
|
||||
/* Let's try to inject the equivalent of:
|
||||
extern void called_function (int i, int j, int k);
|
||||
|
||||
void
|
||||
test_caller (int a)
|
||||
{
|
||||
called_function (a * 3, a * 4, a * 5);
|
||||
}
|
||||
*/
|
||||
int i;
|
||||
gcc_jit_type *void_type =
|
||||
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
|
||||
gcc_jit_type *int_type =
|
||||
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
|
||||
|
||||
/* Declare the imported function. */
|
||||
gcc_jit_param *params[3];
|
||||
params[0] =
|
||||
gcc_jit_context_new_param (ctxt, NULL, int_type, "i");
|
||||
params[1] =
|
||||
gcc_jit_context_new_param (ctxt, NULL, int_type, "j");
|
||||
params[2] =
|
||||
gcc_jit_context_new_param (ctxt, NULL, int_type, "k");
|
||||
gcc_jit_function *called_fn =
|
||||
gcc_jit_context_new_function (ctxt, NULL,
|
||||
GCC_JIT_FUNCTION_IMPORTED,
|
||||
void_type,
|
||||
"called_function",
|
||||
3, params,
|
||||
0);
|
||||
|
||||
/* Build the test_fn. */
|
||||
gcc_jit_param *param_a =
|
||||
gcc_jit_context_new_param (ctxt, NULL, int_type, "a");
|
||||
gcc_jit_function *test_fn =
|
||||
gcc_jit_context_new_function (ctxt, NULL,
|
||||
GCC_JIT_FUNCTION_EXPORTED,
|
||||
void_type,
|
||||
"test_caller",
|
||||
1, ¶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);
|
||||
}
|
||||
|
118
gcc/testsuite/jit.dg/test-calling-function-ptr.c
Normal file
118
gcc/testsuite/jit.dg/test-calling-function-ptr.c
Normal file
@ -0,0 +1,118 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "libgccjit.h"
|
||||
|
||||
#include "harness.h"
|
||||
|
||||
void
|
||||
create_code (gcc_jit_context *ctxt, void *user_data)
|
||||
{
|
||||
/* Let's try to inject the equivalent of:
|
||||
|
||||
void
|
||||
test_calling_function_ptr (void (*fn_ptr) (int, int, int) fn_ptr,
|
||||
int a)
|
||||
{
|
||||
fn_ptr (a * 3, a * 4, a * 5);
|
||||
}
|
||||
*/
|
||||
|
||||
int i;
|
||||
gcc_jit_type *void_type =
|
||||
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
|
||||
gcc_jit_type *int_type =
|
||||
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
|
||||
|
||||
/* Build the function ptr type. */
|
||||
gcc_jit_type *param_types[3];
|
||||
param_types[0] = int_type;
|
||||
param_types[1] = int_type;
|
||||
param_types[2] = int_type;
|
||||
|
||||
gcc_jit_type *fn_ptr_type =
|
||||
gcc_jit_context_new_function_ptr_type (ctxt, NULL,
|
||||
void_type,
|
||||
3, param_types, 0);
|
||||
|
||||
/* Ensure that function ptr types have sane debug strings. */
|
||||
|
||||
CHECK_STRING_VALUE (
|
||||
gcc_jit_object_get_debug_string (gcc_jit_type_as_object (fn_ptr_type)),
|
||||
"void (*) (int, int, int)");
|
||||
|
||||
/* Build the test_fn. */
|
||||
gcc_jit_param *param_fn_ptr =
|
||||
gcc_jit_context_new_param (ctxt, NULL, fn_ptr_type, "fn_ptr");
|
||||
gcc_jit_param *param_a =
|
||||
gcc_jit_context_new_param (ctxt, NULL, int_type, "a");
|
||||
|
||||
gcc_jit_param *params[2];
|
||||
params[0] = param_fn_ptr;
|
||||
params[1] = param_a;
|
||||
|
||||
gcc_jit_function *test_fn =
|
||||
gcc_jit_context_new_function (ctxt, NULL,
|
||||
GCC_JIT_FUNCTION_EXPORTED,
|
||||
void_type,
|
||||
"test_calling_function_ptr",
|
||||
2, params,
|
||||
0);
|
||||
/* "a * 3, a * 4, a * 5" */
|
||||
gcc_jit_rvalue *args[3];
|
||||
for (i = 0; i < 3; i++)
|
||||
args[i] =
|
||||
gcc_jit_context_new_binary_op (
|
||||
ctxt, NULL,
|
||||
GCC_JIT_BINARY_OP_MULT,
|
||||
int_type,
|
||||
gcc_jit_param_as_rvalue (param_a),
|
||||
gcc_jit_context_new_rvalue_from_int (
|
||||
ctxt,
|
||||
int_type,
|
||||
(i + 3) ));
|
||||
gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
|
||||
gcc_jit_block_add_eval (
|
||||
block, NULL,
|
||||
gcc_jit_context_new_call_through_ptr (
|
||||
ctxt,
|
||||
NULL,
|
||||
gcc_jit_param_as_rvalue (param_fn_ptr),
|
||||
3, args));
|
||||
gcc_jit_block_end_with_void_return (block, NULL);
|
||||
}
|
||||
|
||||
static int called_through_ptr_with[3];
|
||||
|
||||
static void
|
||||
function_called_through_fn_ptr (int i, int j, int k)
|
||||
{
|
||||
called_through_ptr_with[0] = i;
|
||||
called_through_ptr_with[1] = j;
|
||||
called_through_ptr_with[2] = k;
|
||||
}
|
||||
|
||||
void
|
||||
verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
|
||||
{
|
||||
typedef void (*fn_type) (void (*fn_ptr) (int, int, int),
|
||||
int);
|
||||
CHECK_NON_NULL (result);
|
||||
|
||||
fn_type test_caller =
|
||||
(fn_type)gcc_jit_result_get_code (result, "test_calling_function_ptr");
|
||||
CHECK_NON_NULL (test_caller);
|
||||
|
||||
called_through_ptr_with[0] = 0;
|
||||
called_through_ptr_with[1] = 0;
|
||||
called_through_ptr_with[2] = 0;
|
||||
|
||||
/* Call the JIT-generated function. */
|
||||
test_caller (function_called_through_fn_ptr, 5);
|
||||
|
||||
/* Verify that it correctly called "function_called_through_fn_ptr". */
|
||||
CHECK_VALUE (called_through_ptr_with[0], 15);
|
||||
CHECK_VALUE (called_through_ptr_with[1], 20);
|
||||
CHECK_VALUE (called_through_ptr_with[2], 25);
|
||||
}
|
||||
|
67
gcc/testsuite/jit.dg/test-combination.c
Normal file
67
gcc/testsuite/jit.dg/test-combination.c
Normal file
@ -0,0 +1,67 @@
|
||||
/* Construct a test case by combining other test cases, to try to shake
|
||||
out state issues: all of the test cases are run in one process, inside
|
||||
one gcc_jit_context (per iteration). */
|
||||
|
||||
#include "all-non-failing-tests.h"
|
||||
|
||||
/* Now construct a test case from all the other test cases.
|
||||
|
||||
We undefine COMBINED_TEST so that we can now include harness.h
|
||||
"for real". */
|
||||
#undef COMBINED_TEST
|
||||
#include "harness.h"
|
||||
|
||||
/* Our testing hooks are the combination of the other test cases. */
|
||||
void
|
||||
create_code (gcc_jit_context *ctxt, void * user_data)
|
||||
{
|
||||
create_code_accessing_struct (ctxt, user_data);
|
||||
create_code_accessing_union (ctxt, user_data);
|
||||
create_code_array_as_pointer (ctxt, user_data);
|
||||
create_code_arrays (ctxt, user_data);
|
||||
create_code_calling_external_function (ctxt, user_data);
|
||||
create_code_calling_function_ptr (ctxt, user_data);
|
||||
create_code_dot_product (ctxt, user_data);
|
||||
create_code_expressions (ctxt, user_data);
|
||||
create_code_factorial (ctxt, user_data);
|
||||
create_code_fibonacci (ctxt, user_data);
|
||||
create_code_functions (ctxt, user_data);
|
||||
create_code_hello_world (ctxt, user_data);
|
||||
create_code_linked_list (ctxt, user_data);
|
||||
create_code_long_names (ctxt, user_data);
|
||||
create_code_quadratic (ctxt, user_data);
|
||||
create_code_nested_loop (ctxt, user_data);
|
||||
create_code_reading_struct (ctxt, user_data);
|
||||
create_code_string_literal (ctxt, user_data);
|
||||
create_code_sum_of_squares (ctxt, user_data);
|
||||
create_code_types (ctxt, user_data);
|
||||
create_code_using_global (ctxt, user_data);
|
||||
create_code_volatile (ctxt, user_data);
|
||||
}
|
||||
|
||||
void
|
||||
verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
|
||||
{
|
||||
verify_code_accessing_struct (ctxt, result);
|
||||
verify_code_accessing_union (ctxt, result);
|
||||
verify_code_array_as_pointer (ctxt, result);
|
||||
verify_code_arrays (ctxt, result);
|
||||
verify_code_calling_external_function (ctxt, result);
|
||||
verify_code_calling_function_ptr (ctxt, result);
|
||||
verify_code_dot_product (ctxt, result);
|
||||
verify_code_expressions (ctxt, result);
|
||||
verify_code_factorial (ctxt, result);
|
||||
verify_code_fibonacci (ctxt, result);
|
||||
verify_code_functions (ctxt, result);
|
||||
verify_code_hello_world (ctxt, result);
|
||||
verify_code_linked_list (ctxt, result);
|
||||
verify_code_long_names (ctxt, result);
|
||||
verify_code_quadratic (ctxt, result);
|
||||
verify_code_nested_loop (ctxt, result);
|
||||
verify_code_reading_struct (ctxt, result);
|
||||
verify_code_string_literal (ctxt, result);
|
||||
verify_code_sum_of_squares (ctxt, result);
|
||||
verify_code_types (ctxt, result);
|
||||
verify_code_using_global (ctxt, result);
|
||||
verify_code_volatile (ctxt, result);
|
||||
}
|
129
gcc/testsuite/jit.dg/test-dot-product.c
Normal file
129
gcc/testsuite/jit.dg/test-dot-product.c
Normal file
@ -0,0 +1,129 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "libgccjit.h"
|
||||
|
||||
#include "harness.h"
|
||||
|
||||
void
|
||||
create_code (gcc_jit_context *ctxt, void *user_data)
|
||||
{
|
||||
/* Let's try to inject the equivalent of:
|
||||
|
||||
double
|
||||
my_dot_product (int n, double *a, double *b)
|
||||
{
|
||||
double result = 0.;
|
||||
for (int i = 0; i < n; i++)
|
||||
result += a[i] * b[i];
|
||||
return result
|
||||
}
|
||||
|
||||
and see what the optimizer can do. */
|
||||
gcc_jit_type *val_type =
|
||||
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_DOUBLE);
|
||||
gcc_jit_type *ptr_type = gcc_jit_type_get_pointer (val_type);
|
||||
gcc_jit_type *int_type =
|
||||
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
|
||||
|
||||
gcc_jit_type *return_type = val_type;
|
||||
gcc_jit_param *param_n =
|
||||
gcc_jit_context_new_param (ctxt, NULL, int_type, "n");
|
||||
gcc_jit_param *param_a =
|
||||
gcc_jit_context_new_param (ctxt, NULL, ptr_type, "a");
|
||||
gcc_jit_param *param_b =
|
||||
gcc_jit_context_new_param (ctxt, NULL, ptr_type, "b");
|
||||
gcc_jit_param *params[3] = {param_n, param_a, param_b};
|
||||
gcc_jit_function *func =
|
||||
gcc_jit_context_new_function (ctxt, NULL,
|
||||
GCC_JIT_FUNCTION_EXPORTED,
|
||||
return_type,
|
||||
"my_dot_product",
|
||||
3, params, 0);
|
||||
|
||||
gcc_jit_block *initial = gcc_jit_function_new_block (func, "initial");
|
||||
gcc_jit_block *loop_test = gcc_jit_function_new_block (func, "loop_test");
|
||||
gcc_jit_block *loop_body = gcc_jit_function_new_block (func, "loop_body");
|
||||
gcc_jit_block *final = gcc_jit_function_new_block (func, "final");
|
||||
|
||||
/* Build: "double result = 0.;" */
|
||||
gcc_jit_lvalue *result =
|
||||
gcc_jit_function_new_local (func, NULL, val_type, "result");
|
||||
|
||||
gcc_jit_block_add_assignment (initial, NULL,
|
||||
result, gcc_jit_context_zero (ctxt, val_type));
|
||||
|
||||
/* Build: "for (int i = 0; i < n; i++)" */
|
||||
gcc_jit_lvalue *i =
|
||||
gcc_jit_function_new_local (func, NULL, int_type, "i");
|
||||
gcc_jit_block_add_assignment (initial, NULL,
|
||||
i, gcc_jit_context_zero (ctxt, int_type));
|
||||
|
||||
gcc_jit_block_end_with_jump (initial, NULL, loop_test);
|
||||
|
||||
gcc_jit_block_end_with_conditional (
|
||||
loop_test, NULL,
|
||||
|
||||
/* (i < n) */
|
||||
gcc_jit_context_new_comparison (
|
||||
ctxt, NULL,
|
||||
GCC_JIT_COMPARISON_LT,
|
||||
gcc_jit_lvalue_as_rvalue (i),
|
||||
gcc_jit_param_as_rvalue (param_n)),
|
||||
|
||||
loop_body,
|
||||
final);
|
||||
|
||||
/* Build: "result += a[i] * b[i];" */
|
||||
gcc_jit_block_add_assignment_op (
|
||||
loop_body, NULL,
|
||||
result,
|
||||
GCC_JIT_BINARY_OP_PLUS,
|
||||
gcc_jit_context_new_binary_op (
|
||||
ctxt, NULL,
|
||||
GCC_JIT_BINARY_OP_MULT,
|
||||
val_type,
|
||||
gcc_jit_lvalue_as_rvalue (
|
||||
gcc_jit_context_new_array_access (
|
||||
ctxt, NULL,
|
||||
gcc_jit_param_as_rvalue (param_a),
|
||||
gcc_jit_lvalue_as_rvalue (i))),
|
||||
gcc_jit_lvalue_as_rvalue (
|
||||
gcc_jit_context_new_array_access (
|
||||
ctxt, NULL,
|
||||
gcc_jit_param_as_rvalue (param_b),
|
||||
gcc_jit_lvalue_as_rvalue (i)))));
|
||||
|
||||
/* Build: "i++" */
|
||||
gcc_jit_block_add_assignment_op (
|
||||
loop_body, NULL,
|
||||
i,
|
||||
GCC_JIT_BINARY_OP_PLUS,
|
||||
gcc_jit_context_one (ctxt, int_type));
|
||||
|
||||
gcc_jit_block_end_with_jump (loop_body, NULL, loop_test);
|
||||
|
||||
/* Build: "return result;" */
|
||||
gcc_jit_block_end_with_return (
|
||||
final,
|
||||
NULL,
|
||||
gcc_jit_lvalue_as_rvalue (result));
|
||||
}
|
||||
|
||||
void
|
||||
verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
|
||||
{
|
||||
typedef double (*my_dot_product_fn_type) (int n, double *a, double *b);
|
||||
CHECK_NON_NULL (result);
|
||||
|
||||
my_dot_product_fn_type my_dot_product =
|
||||
(my_dot_product_fn_type)gcc_jit_result_get_code (result,
|
||||
"my_dot_product");
|
||||
CHECK_NON_NULL (my_dot_product);
|
||||
double test_array[] = {1., 2., 3., 4., 5., 6., 7., 8., 9., 10.};
|
||||
double val = my_dot_product (10, test_array, test_array);
|
||||
note ("my_dot_product returned: %f", val);
|
||||
CHECK_VALUE (val, 385.0);
|
||||
}
|
||||
|
20
gcc/testsuite/jit.dg/test-empty.c
Normal file
20
gcc/testsuite/jit.dg/test-empty.c
Normal file
@ -0,0 +1,20 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "libgccjit.h"
|
||||
|
||||
#include "harness.h"
|
||||
|
||||
void
|
||||
create_code (gcc_jit_context *ctxt, void *user_data)
|
||||
{
|
||||
/* Do nothing. */
|
||||
}
|
||||
|
||||
void
|
||||
verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
|
||||
{
|
||||
/* We should have a non-NULL result, albeit one with nothing in it. */
|
||||
CHECK_NON_NULL (result);
|
||||
}
|
||||
|
@ -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");
|
||||
}
|
||||
|
48
gcc/testsuite/jit.dg/test-error-adding-to-terminated-block.c
Normal file
48
gcc/testsuite/jit.dg/test-error-adding-to-terminated-block.c
Normal file
@ -0,0 +1,48 @@
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "libgccjit.h"
|
||||
|
||||
#include "harness.h"
|
||||
|
||||
void
|
||||
create_code (gcc_jit_context *ctxt, void *user_data)
|
||||
{
|
||||
/* Let's try to inject the equivalent of:
|
||||
void
|
||||
test_fn ()
|
||||
{
|
||||
return;
|
||||
return;
|
||||
}
|
||||
*/
|
||||
gcc_jit_type *void_t =
|
||||
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
|
||||
|
||||
/* Build the test_fn. */
|
||||
gcc_jit_function *test_fn =
|
||||
gcc_jit_context_new_function (ctxt, NULL,
|
||||
GCC_JIT_FUNCTION_EXPORTED,
|
||||
void_t,
|
||||
"test_fn",
|
||||
0, NULL,
|
||||
0);
|
||||
gcc_jit_block *initial =
|
||||
gcc_jit_function_new_block (test_fn, "initial");
|
||||
|
||||
gcc_jit_block_end_with_void_return (initial, NULL);
|
||||
/* Error: "initial" has already been terminated. */
|
||||
gcc_jit_block_end_with_void_return (initial, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
|
||||
{
|
||||
CHECK_VALUE (result, NULL);
|
||||
|
||||
CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
|
||||
"gcc_jit_block_end_with_void_return:"
|
||||
" adding to terminated block:"
|
||||
" initial (already terminated by: return;)");
|
||||
}
|
99
gcc/testsuite/jit.dg/test-error-array-as-pointer.c
Normal file
99
gcc/testsuite/jit.dg/test-error-array-as-pointer.c
Normal file
@ -0,0 +1,99 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "libgccjit.h"
|
||||
|
||||
#include "harness.h"
|
||||
|
||||
#define BUFFER_SIZE (1024)
|
||||
|
||||
char test_buffer[1024];
|
||||
|
||||
void
|
||||
create_code (gcc_jit_context *ctxt, void *user_data)
|
||||
{
|
||||
/* Let's try to inject the equivalent of:
|
||||
void test_of_array_as_pointer (const char *name)
|
||||
{
|
||||
snprintf (test_buffer, sizeof (test_buffer),
|
||||
"hello %s", name);
|
||||
}
|
||||
*/
|
||||
gcc_jit_type *void_type =
|
||||
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
|
||||
gcc_jit_type *const_char_ptr_type =
|
||||
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_CONST_CHAR_PTR);
|
||||
gcc_jit_type *char_type =
|
||||
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_CHAR);
|
||||
gcc_jit_type *char_ptr_type =
|
||||
gcc_jit_type_get_pointer (char_type);
|
||||
gcc_jit_type *int_type =
|
||||
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
|
||||
gcc_jit_type *size_t_type =
|
||||
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_SIZE_T);
|
||||
gcc_jit_type *buf_type =
|
||||
gcc_jit_context_new_array_type (ctxt, NULL, char_type, BUFFER_SIZE);
|
||||
|
||||
/* extern int snprintf(char *str, size_t size, const char *format, ...); */
|
||||
gcc_jit_param *param_s =
|
||||
gcc_jit_context_new_param (ctxt, NULL, char_ptr_type, "s");
|
||||
gcc_jit_param *param_n =
|
||||
gcc_jit_context_new_param (ctxt, NULL, size_t_type, "n");
|
||||
gcc_jit_param *param_format =
|
||||
gcc_jit_context_new_param (ctxt, NULL, const_char_ptr_type, "format");
|
||||
gcc_jit_param *snprintf_params[3] = {param_s, param_n, param_format};
|
||||
gcc_jit_function *snprintf =
|
||||
gcc_jit_context_new_function (ctxt, NULL,
|
||||
GCC_JIT_FUNCTION_IMPORTED,
|
||||
int_type,
|
||||
"snprintf",
|
||||
3, snprintf_params,
|
||||
1);
|
||||
|
||||
gcc_jit_param *param_name =
|
||||
gcc_jit_context_new_param (ctxt, NULL, const_char_ptr_type, "name");
|
||||
gcc_jit_function *test_fn =
|
||||
gcc_jit_context_new_function (ctxt, NULL,
|
||||
GCC_JIT_FUNCTION_EXPORTED,
|
||||
void_type,
|
||||
"test_of_array_as_pointer",
|
||||
1, ¶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 *");
|
||||
}
|
63
gcc/testsuite/jit.dg/test-error-bad-cast.c
Normal file
63
gcc/testsuite/jit.dg/test-error-bad-cast.c
Normal file
@ -0,0 +1,63 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "libgccjit.h"
|
||||
|
||||
#include "harness.h"
|
||||
|
||||
void
|
||||
create_code (gcc_jit_context *ctxt, void *user_data)
|
||||
{
|
||||
/* Let's try to inject the equivalent of:
|
||||
|
||||
int
|
||||
test_fn ()
|
||||
{
|
||||
struct foo f;
|
||||
return (int)f;
|
||||
}
|
||||
|
||||
and verify that the API complains about the bad cast.
|
||||
*/
|
||||
gcc_jit_type *int_type =
|
||||
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
|
||||
|
||||
|
||||
gcc_jit_struct *struct_foo =
|
||||
gcc_jit_context_new_struct_type (ctxt, NULL, "foo",
|
||||
0, NULL);
|
||||
|
||||
gcc_jit_function *test_fn =
|
||||
gcc_jit_context_new_function (ctxt, NULL,
|
||||
GCC_JIT_FUNCTION_EXPORTED,
|
||||
int_type,
|
||||
"test_fn",
|
||||
0, NULL,
|
||||
0);
|
||||
gcc_jit_lvalue *f =
|
||||
gcc_jit_function_new_local (
|
||||
test_fn,
|
||||
NULL,
|
||||
gcc_jit_struct_as_type (struct_foo), "f");
|
||||
|
||||
gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
|
||||
|
||||
gcc_jit_block_end_with_return (
|
||||
block, NULL,
|
||||
gcc_jit_context_new_cast (ctxt, NULL,
|
||||
gcc_jit_lvalue_as_rvalue (f),
|
||||
int_type));
|
||||
}
|
||||
|
||||
void
|
||||
verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
|
||||
{
|
||||
CHECK_VALUE (result, NULL);
|
||||
|
||||
/* Verify that the correct error message was emitted. */
|
||||
CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
|
||||
"gcc_jit_context_new_cast:"
|
||||
" cannot cast f from type: struct foo"
|
||||
" to type: int");
|
||||
}
|
||||
|
65
gcc/testsuite/jit.dg/test-error-block-in-wrong-function.c
Normal file
65
gcc/testsuite/jit.dg/test-error-block-in-wrong-function.c
Normal file
@ -0,0 +1,65 @@
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "libgccjit.h"
|
||||
|
||||
#include "harness.h"
|
||||
|
||||
void
|
||||
create_code (gcc_jit_context *ctxt, void *user_data)
|
||||
{
|
||||
/* Let's try to inject the equivalent of:
|
||||
void
|
||||
test_fn ()
|
||||
{
|
||||
goto label;
|
||||
}
|
||||
|
||||
void
|
||||
other_fn ()
|
||||
{
|
||||
label:
|
||||
};
|
||||
where the destination block is in another function.
|
||||
*/
|
||||
gcc_jit_type *void_t =
|
||||
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
|
||||
|
||||
/* Build the test_fn. */
|
||||
gcc_jit_function *test_fn =
|
||||
gcc_jit_context_new_function (ctxt, NULL,
|
||||
GCC_JIT_FUNCTION_EXPORTED,
|
||||
void_t,
|
||||
"test_fn",
|
||||
0, NULL,
|
||||
0);
|
||||
/* Build the other_fn. */
|
||||
gcc_jit_function *other_fn =
|
||||
gcc_jit_context_new_function (ctxt, NULL,
|
||||
GCC_JIT_FUNCTION_EXPORTED,
|
||||
void_t,
|
||||
"other_fn",
|
||||
0, NULL,
|
||||
0);
|
||||
|
||||
gcc_jit_block *initial =
|
||||
gcc_jit_function_new_block (test_fn, "initial");
|
||||
gcc_jit_block *block_within_other_fn =
|
||||
gcc_jit_function_new_block (other_fn, "block_within_other_fn");
|
||||
|
||||
gcc_jit_block_end_with_jump (initial, NULL, block_within_other_fn);
|
||||
}
|
||||
|
||||
void
|
||||
verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
|
||||
{
|
||||
CHECK_VALUE (result, NULL);
|
||||
|
||||
CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
|
||||
"gcc_jit_block_end_with_jump:"
|
||||
" target block is not in same function:"
|
||||
" source block initial is in function test_fn"
|
||||
" whereas target block block_within_other_fn"
|
||||
" is in function other_fn");
|
||||
}
|
@ -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)");
|
||||
}
|
||||
|
87
gcc/testsuite/jit.dg/test-error-call-with-mismatching-args.c
Normal file
87
gcc/testsuite/jit.dg/test-error-call-with-mismatching-args.c
Normal file
@ -0,0 +1,87 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "libgccjit.h"
|
||||
|
||||
#include "harness.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern void
|
||||
called_function (void *ptr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
create_code (gcc_jit_context *ctxt, void *user_data)
|
||||
{
|
||||
/* Let's try to inject the equivalent of:
|
||||
extern void called_function (void *ptr);
|
||||
|
||||
void
|
||||
test_fn ()
|
||||
{
|
||||
called_function (42);
|
||||
}
|
||||
|
||||
and verify that the API complains about the mismatching argument
|
||||
type ("int" vs "void *"). */
|
||||
gcc_jit_type *void_type =
|
||||
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
|
||||
gcc_jit_type *void_ptr_type =
|
||||
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID_PTR);
|
||||
gcc_jit_type *int_type =
|
||||
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
|
||||
|
||||
/* Declare the imported function. */
|
||||
gcc_jit_param *param =
|
||||
gcc_jit_context_new_param (ctxt, NULL, void_ptr_type, "ptr");
|
||||
gcc_jit_function *called_fn =
|
||||
gcc_jit_context_new_function (ctxt, NULL,
|
||||
GCC_JIT_FUNCTION_IMPORTED,
|
||||
void_type,
|
||||
"called_function",
|
||||
1, ¶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)"));
|
||||
}
|
||||
|
87
gcc/testsuite/jit.dg/test-error-call-with-not-enough-args.c
Normal file
87
gcc/testsuite/jit.dg/test-error-call-with-not-enough-args.c
Normal file
@ -0,0 +1,87 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "libgccjit.h"
|
||||
|
||||
#include "harness.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern void
|
||||
called_function (void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
create_code (gcc_jit_context *ctxt, void *user_data)
|
||||
{
|
||||
/* Let's try to inject the equivalent of:
|
||||
extern void called_function (int p);
|
||||
|
||||
void
|
||||
test_caller ()
|
||||
{
|
||||
called_function (); // missing arg
|
||||
}
|
||||
|
||||
and verify that the API complains about the missing argument.
|
||||
*/
|
||||
gcc_jit_type *void_type =
|
||||
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
|
||||
gcc_jit_type *int_type =
|
||||
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
|
||||
|
||||
/* Declare the imported function. */
|
||||
gcc_jit_param *param_p =
|
||||
gcc_jit_context_new_param (ctxt, NULL, int_type, "p");
|
||||
gcc_jit_function *called_fn =
|
||||
gcc_jit_context_new_function (ctxt, NULL,
|
||||
GCC_JIT_FUNCTION_IMPORTED,
|
||||
void_type,
|
||||
"called_function",
|
||||
1, ¶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)"));
|
||||
}
|
||||
|
89
gcc/testsuite/jit.dg/test-error-call-with-too-many-args.c
Normal file
89
gcc/testsuite/jit.dg/test-error-call-with-too-many-args.c
Normal file
@ -0,0 +1,89 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "libgccjit.h"
|
||||
|
||||
#include "harness.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern void
|
||||
called_function (void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
create_code (gcc_jit_context *ctxt, void *user_data)
|
||||
{
|
||||
/* Let's try to inject the equivalent of:
|
||||
extern void called_function ();
|
||||
|
||||
void
|
||||
test_caller (int a)
|
||||
{
|
||||
called_function (a);
|
||||
}
|
||||
|
||||
and verify that the API complains about the mismatching arg
|
||||
counts.
|
||||
*/
|
||||
gcc_jit_type *void_type =
|
||||
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
|
||||
gcc_jit_type *int_type =
|
||||
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
|
||||
|
||||
/* Declare the imported function. */
|
||||
gcc_jit_function *called_fn =
|
||||
gcc_jit_context_new_function (ctxt, NULL,
|
||||
GCC_JIT_FUNCTION_IMPORTED,
|
||||
void_type,
|
||||
"called_function",
|
||||
0, NULL,
|
||||
0);
|
||||
|
||||
/* Build the test_fn. */
|
||||
gcc_jit_param *param_a =
|
||||
gcc_jit_context_new_param (ctxt, NULL, int_type, "a");
|
||||
gcc_jit_function *test_fn =
|
||||
gcc_jit_context_new_function (ctxt, NULL,
|
||||
GCC_JIT_FUNCTION_EXPORTED,
|
||||
void_type,
|
||||
"test_caller",
|
||||
1, ¶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)"));
|
||||
}
|
||||
|
27
gcc/testsuite/jit.dg/test-error-get-type-bad-enum.c
Normal file
27
gcc/testsuite/jit.dg/test-error-get-type-bad-enum.c
Normal file
@ -0,0 +1,27 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "libgccjit.h"
|
||||
|
||||
#include "harness.h"
|
||||
|
||||
void
|
||||
create_code (gcc_jit_context *ctxt, void *user_data)
|
||||
{
|
||||
/* Trigger an API error by passing bad data. */
|
||||
gcc_jit_context_get_type (ctxt, 42);
|
||||
}
|
||||
|
||||
void
|
||||
verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
|
||||
{
|
||||
/* Ensure that the bad API usage prevents the API giving a bogus
|
||||
result back. */
|
||||
CHECK_VALUE (result, NULL);
|
||||
|
||||
/* Verify that the correct error message was emitted. */
|
||||
CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
|
||||
("gcc_jit_context_get_type:"
|
||||
" unrecognized value for enum gcc_jit_types: 42"));
|
||||
}
|
||||
|
34
gcc/testsuite/jit.dg/test-error-index-not-a-numeric-type.c
Normal file
34
gcc/testsuite/jit.dg/test-error-index-not-a-numeric-type.c
Normal file
@ -0,0 +1,34 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "libgccjit.h"
|
||||
|
||||
#include "harness.h"
|
||||
|
||||
void
|
||||
create_code (gcc_jit_context *ctxt, void *user_data)
|
||||
{
|
||||
/* Let's try to access an array at an index that isn't of a numeric
|
||||
type and verify that the API complains about the bad type.
|
||||
*/
|
||||
gcc_jit_rvalue *string =
|
||||
gcc_jit_context_new_string_literal (ctxt,
|
||||
"hello world");
|
||||
|
||||
(void)gcc_jit_context_new_array_access (
|
||||
ctxt, NULL,
|
||||
string, /* ptr */
|
||||
string /* index, not of numeric type */);
|
||||
}
|
||||
|
||||
void
|
||||
verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
|
||||
{
|
||||
CHECK_VALUE (result, NULL);
|
||||
|
||||
/* Verify that the correct error message was emitted. */
|
||||
CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
|
||||
"gcc_jit_context_new_array_access:"
|
||||
" index: \"hello world\" (type: const char *)"
|
||||
" is not of numeric type");
|
||||
}
|
@ -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 *)");
|
||||
}
|
||||
|
80
gcc/testsuite/jit.dg/test-error-mismatching-types-in-call.c
Normal file
80
gcc/testsuite/jit.dg/test-error-mismatching-types-in-call.c
Normal file
@ -0,0 +1,80 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "libgccjit.h"
|
||||
|
||||
#include "harness.h"
|
||||
|
||||
void
|
||||
create_code (gcc_jit_context *ctxt, void *user_data)
|
||||
{
|
||||
/* Let's try to inject the equivalent of:
|
||||
|
||||
struct foo;
|
||||
|
||||
extern void called_function (struct foo *ptr);
|
||||
|
||||
void
|
||||
test_fn ()
|
||||
{
|
||||
struct foo f;
|
||||
called_function (f);
|
||||
}
|
||||
|
||||
and verify that we get a type error (foo * vs foo).
|
||||
*/
|
||||
gcc_jit_type *void_type =
|
||||
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
|
||||
gcc_jit_struct *struct_foo =
|
||||
gcc_jit_context_new_opaque_struct (ctxt, NULL, "foo");
|
||||
gcc_jit_type *foo_ptr =
|
||||
gcc_jit_type_get_pointer (gcc_jit_struct_as_type (struct_foo));
|
||||
gcc_jit_param *param =
|
||||
gcc_jit_context_new_param (ctxt, NULL, foo_ptr, "ptr");
|
||||
|
||||
gcc_jit_function *called_function =
|
||||
gcc_jit_context_new_function (ctxt, NULL,
|
||||
GCC_JIT_FUNCTION_IMPORTED,
|
||||
void_type,
|
||||
"called_function",
|
||||
1, ¶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)");
|
||||
}
|
||||
|
40
gcc/testsuite/jit.dg/test-error-missing-return.c
Normal file
40
gcc/testsuite/jit.dg/test-error-missing-return.c
Normal file
@ -0,0 +1,40 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "libgccjit.h"
|
||||
|
||||
#include "harness.h"
|
||||
|
||||
void
|
||||
create_code (gcc_jit_context *ctxt, void *user_data)
|
||||
{
|
||||
/* Let's try to inject the equivalent of:
|
||||
int
|
||||
test_fn ()
|
||||
{
|
||||
}
|
||||
and verify that the API complains about the lack of
|
||||
a returned value.
|
||||
*/
|
||||
gcc_jit_type *int_type =
|
||||
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
|
||||
|
||||
(void)gcc_jit_context_new_function (ctxt, NULL,
|
||||
GCC_JIT_FUNCTION_EXPORTED,
|
||||
int_type,
|
||||
"test_fn",
|
||||
0, NULL,
|
||||
0);
|
||||
}
|
||||
|
||||
void
|
||||
verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
|
||||
{
|
||||
CHECK_VALUE (result, NULL);
|
||||
|
||||
/* Verify that the correct error message was emitted. */
|
||||
CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
|
||||
"function test_fn returns non-void (type: int)"
|
||||
" but has no blocks");
|
||||
}
|
||||
|
37
gcc/testsuite/jit.dg/test-error-new-binary-op-bad-op.c
Normal file
37
gcc/testsuite/jit.dg/test-error-new-binary-op-bad-op.c
Normal file
@ -0,0 +1,37 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "libgccjit.h"
|
||||
|
||||
#include "harness.h"
|
||||
|
||||
void
|
||||
create_code (gcc_jit_context *ctxt, void *user_data)
|
||||
{
|
||||
/* Trigger an API error by passing bad data. */
|
||||
(void)gcc_jit_context_new_binary_op (
|
||||
ctxt,
|
||||
NULL,
|
||||
|
||||
/* Non-valid enum value: */
|
||||
(enum gcc_jit_binary_op) 42,
|
||||
|
||||
/* These aren't valid either: */
|
||||
NULL, /* gcc_jit_type *result_type, */
|
||||
NULL, NULL); /* gcc_jit_rvalue *a, gcc_jit_rvalue *b */
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
|
||||
{
|
||||
/* Ensure that the bad API usage prevents the API giving a bogus
|
||||
result back. */
|
||||
CHECK_VALUE (result, NULL);
|
||||
|
||||
/* Verify that the correct error message was emitted. */
|
||||
CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
|
||||
("gcc_jit_context_new_binary_op:"
|
||||
" unrecognized value for enum gcc_jit_binary_op: 42"));
|
||||
}
|
||||
|
41
gcc/testsuite/jit.dg/test-error-new-function-bad-kind.c
Normal file
41
gcc/testsuite/jit.dg/test-error-new-function-bad-kind.c
Normal file
@ -0,0 +1,41 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "libgccjit.h"
|
||||
|
||||
#include "harness.h"
|
||||
|
||||
void
|
||||
create_code (gcc_jit_context *ctxt, void *user_data)
|
||||
{
|
||||
gcc_jit_type *int_type =
|
||||
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
|
||||
|
||||
/* Trigger an API error by passing bad data. */
|
||||
(void)gcc_jit_context_new_function (
|
||||
ctxt,
|
||||
NULL,
|
||||
|
||||
/* Non-valid enum value: */
|
||||
(enum gcc_jit_function_kind)42,
|
||||
|
||||
int_type, /* gcc_jit_type *return_type, */
|
||||
"foo", /* const char *name, */
|
||||
0, /* int num_params, */
|
||||
NULL, /* gcc_jit_param **params, */
|
||||
0); /* int is_variadic */
|
||||
}
|
||||
|
||||
void
|
||||
verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
|
||||
{
|
||||
/* Ensure that the bad API usage prevents the API giving a bogus
|
||||
result back. */
|
||||
CHECK_VALUE (result, NULL);
|
||||
|
||||
/* Verify that the correct error message was emitted. */
|
||||
CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
|
||||
("gcc_jit_context_new_function:"
|
||||
" unrecognized value for enum gcc_jit_function_kind: 42"));
|
||||
}
|
||||
|
36
gcc/testsuite/jit.dg/test-error-new-unary-op-bad-op.c
Normal file
36
gcc/testsuite/jit.dg/test-error-new-unary-op-bad-op.c
Normal file
@ -0,0 +1,36 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "libgccjit.h"
|
||||
|
||||
#include "harness.h"
|
||||
|
||||
void
|
||||
create_code (gcc_jit_context *ctxt, void *user_data)
|
||||
{
|
||||
/* Trigger an API error by passing bad data. */
|
||||
(void)gcc_jit_context_new_unary_op (
|
||||
ctxt,
|
||||
NULL,
|
||||
|
||||
/* Non-valid enum value: */
|
||||
(enum gcc_jit_unary_op) 42,
|
||||
|
||||
/* These aren't valid either: */
|
||||
NULL, /* gcc_jit_type *result_type, */
|
||||
NULL); /* gcc_jit_rvalue *rvalue */
|
||||
}
|
||||
|
||||
void
|
||||
verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
|
||||
{
|
||||
/* Ensure that the bad API usage prevents the API giving a bogus
|
||||
result back. */
|
||||
CHECK_VALUE (result, NULL);
|
||||
|
||||
/* Verify that the correct error message was emitted. */
|
||||
CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
|
||||
("gcc_jit_context_new_unary_op:"
|
||||
" unrecognized value for enum gcc_jit_unary_op: 42"));
|
||||
}
|
||||
|
31
gcc/testsuite/jit.dg/test-error-null-passed-to-api.c
Normal file
31
gcc/testsuite/jit.dg/test-error-null-passed-to-api.c
Normal file
@ -0,0 +1,31 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "libgccjit.h"
|
||||
|
||||
#include "harness.h"
|
||||
|
||||
void
|
||||
create_code (gcc_jit_context *ctxt, void *user_data)
|
||||
{
|
||||
/* Trigger an API error by passing bad data. */
|
||||
gcc_jit_context_new_function (ctxt, NULL,
|
||||
GCC_JIT_FUNCTION_EXPORTED,
|
||||
NULL, /* error: this must be non-NULL */
|
||||
"hello_world",
|
||||
0, NULL,
|
||||
0);
|
||||
}
|
||||
|
||||
void
|
||||
verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
|
||||
{
|
||||
/* Ensure that the bad API usage prevents the API giving a bogus
|
||||
result back. */
|
||||
CHECK_VALUE (result, NULL);
|
||||
|
||||
/* Verify that the correct error message was emitted. */
|
||||
CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
|
||||
"gcc_jit_context_new_function: NULL return_type");
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user