This patch adds a new entrypoint to libgccjit: gcc_jit_context_add_command_line_option allowing client code to add arbitrary command-line options without needing to recompile libgccjit.so
This is the first new entrypoint since the initial release of libgccjit, so the patch also adds symbol-versioning to libgccjit.so, putting all existing symbols within LIBGCCJIT_ABI_0, adding the new symbol within LIBGCCJIT_ABI_1. It adds a discussion of API/ABI stability to the documentation. Tested with manually running old client binaries against a new libgccjit.so, and via "make check-jit"; jit.sum goes from 8014 to 8039 passes. Committed to trunk as r225205. gcc/jit/ChangeLog: PR jit/66628 * docs/cp/topics/contexts.rst (Additional command-line options): New section. * docs/topics/compatibility.rst: New file. * docs/topics/contexts.rst (Additional command-line options): New section. * docs/topics/index.rst: Add compatibility.rst. * docs/_build/texinfo/libgccjit.texi: Regenerate. * jit-playback.c (make_fake_args): Add call to append_command_line_options. * jit-recording.c: Within namespace gcc::jit... (recording::context::~context): Free the optnames within m_command_line_options. (recording::context::set_bool_option): Likewise. (recording::context::add_command_line_option): New method. (recording::context::append_command_line_options): New method. (recording::context::dump_reproducer_to_file): Add command-line options. * jit-recording.h: Within namespace gcc::jit... (recording::context::add_command_line_option): New method. (recording::context::append_command_line_options): New method. (recording::context::m_command_line_options): New field. * libgccjit++.h (gccjit::context::add_command_line_option): New method. * libgccjit.c (gcc_jit_context_add_command_line_option): New API entrypoint. * libgccjit.h (gcc_jit_context_add_command_line_option): New API entrypoint. (LIBGCCJIT_HAVE_gcc_jit_context_add_command_line_option): New macro. * libgccjit.map: Put existing symbols within LIBGCCJIT_ABI_0; add LIBGCCJIT_ABI_1 and gcc_jit_context_add_command_line_option. gcc/testsuite/ChangeLog: PR jit/66628 * jit.dg/all-non-failing-tests.h: Add note about test-extra-options.c. * jit.dg/test-extra-options.c: New testcase. --- gcc/jit/docs/cp/topics/contexts.rst | 19 ++++ gcc/jit/docs/topics/compatibility.rst | 90 ++++++++++++++++++ gcc/jit/docs/topics/contexts.rst | 36 +++++++ gcc/jit/docs/topics/index.rst | 1 + gcc/jit/jit-playback.c | 4 + gcc/jit/jit-recording.c | 42 +++++++++ gcc/jit/jit-recording.h | 7 ++ gcc/jit/libgccjit++.h | 8 ++ gcc/jit/libgccjit.c | 19 ++++ gcc/jit/libgccjit.h | 23 +++++ gcc/jit/libgccjit.map | 11 ++- gcc/testsuite/jit.dg/all-non-failing-tests.h | 3 + gcc/testsuite/jit.dg/test-extra-options.c | 136 +++++++++++++++++++++++++++ 13 files changed, 398 insertions(+), 1 deletion(-) create mode 100644 gcc/jit/docs/topics/compatibility.rst create mode 100644 gcc/testsuite/jit.dg/test-extra-options.c diff --git a/gcc/jit/docs/cp/topics/contexts.rst b/gcc/jit/docs/cp/topics/contexts.rst index 12a4e50..b26a29d 100644 --- a/gcc/jit/docs/cp/topics/contexts.rst +++ b/gcc/jit/docs/cp/topics/contexts.rst @@ -196,3 +196,22 @@ Integer options This is a thin wrapper around the C API :c:func:`gcc_jit_context_set_int_option`; the options have the same meaning. + +Additional command-line options +******************************* + +.. function:: void \ + gccjit::context::add_command_line_option (const char *optname) + + Add an arbitrary gcc command-line option to the context for use + when compiling. + + This is a thin wrapper around the C API + :c:func:`gcc_jit_context_add_command_line_option`. + + This entrypoint was added in :ref:`LIBGCCJIT_ABI_1`; you can test for + its presence using + + .. code-block:: c + + #ifdef LIBGCCJIT_HAVE_gcc_jit_context_add_command_line_option diff --git a/gcc/jit/docs/topics/compatibility.rst b/gcc/jit/docs/topics/compatibility.rst new file mode 100644 index 0000000..dff1d0b --- /dev/null +++ b/gcc/jit/docs/topics/compatibility.rst @@ -0,0 +1,90 @@ +.. Copyright (C) 2015 Free Software Foundation, Inc. + Originally contributed by David Malcolm <dmalc...@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 + +ABI and API compatibility +========================= + +The libgccjit developers strive for ABI and API backward-compatibility: +programs built against libgccjit.so stand a good chance of running +without recompilation against newer versions of libgccjit.so, and +ought to recompile without modification against newer versions of +libgccjit.h. + +.. note:: The libgccjit++.h C++ API is more experimental, and less + locked-down at this time. + +API compatibility is achieved by extending the API rather than changing +it. For ABI compatiblity, we avoid bumping the SONAME, and instead use +symbol versioning to tag each symbol, so that a binary linked against +libgccjit.so is tagged according to the symbols that it uses. + +For example, :func:`gcc_jit_context_add_command_line_option` was added in +``LIBGCCJIT_ABI_1``. If a client program uses it, this can be detected +from metadata by using ``objdump``: + +.. code-block:: bash + + $ objdump -p testsuite/jit/test-extra-options.c.exe | tail -n 8 + + Version References: + required from libgccjit.so.0: + 0x00824161 0x00 04 LIBGCCJIT_ABI_1 + 0x00824160 0x00 03 LIBGCCJIT_ABI_0 + required from libc.so.6: + 0x09691a75 0x00 02 GLIBC_2.2.5 + +You can see the symbol tags provided by libgccjit.so using ``objdump``: + +.. code-block:: bash + + $ objdump -p libgccjit.so | less + [...snip...] + Version definitions: + 1 0x01 0x0ff81f20 libgccjit.so.0 + 2 0x00 0x00824160 LIBGCCJIT_ABI_0 + 3 0x00 0x00824161 LIBGCCJIT_ABI_1 + LIBGCCJIT_ABI_0 + [...snip...] + +ABI symbol tags +*************** + +The initial release of libgccjit (in gcc 5.1) did not use symbol versioning. + +Newer releases use the following tags. + +.. _LIBGCCJIT_ABI_0: + +``LIBGCCJIT_ABI_0`` +------------------- + +All entrypoints in the initial release of libgccjit are tagged with +``LIBGCCJIT_ABI_0``, to signify the transition to symbol versioning. + +Binaries built against older copies of ``libgccjit.so`` should +continue to work, with this being handled transparently by the linker +(see `this post +<https://gcc.gnu.org/ml/gcc-patches/2015-06/msg02126.html>`_) + +.. _LIBGCCJIT_ABI_1: + +``LIBGCCJIT_ABI_1`` +------------------- +``LIBGCCJIT_ABI_1`` covers the addition of +:func:`gcc_jit_context_add_command_line_option` diff --git a/gcc/jit/docs/topics/contexts.rst b/gcc/jit/docs/topics/contexts.rst index b3d42d9..401cbf1 100644 --- a/gcc/jit/docs/topics/contexts.rst +++ b/gcc/jit/docs/topics/contexts.rst @@ -465,3 +465,39 @@ Integer options -O0 through -O3. The default value is 0 (unoptimized). + +Additional command-line options +******************************* + +.. function:: void gcc_jit_context_add_command_line_option (gcc_jit_context *ctxt,\ + const char *optname) + + Add an arbitrary gcc command-line option to the context, for use + by :func:`gcc_jit_context_compile` and + :func:`gcc_jit_context_compile_to_file`. + + The parameter ``optname`` must be non-NULL. The underlying buffer is + copied, so that it does not need to outlive the call. + + Extra options added by `gcc_jit_context_add_command_line_option` are + applied *after* the regular options above, potentially overriding them. + Options from parent contexts are inherited by child contexts; options + from the parent are applied *before* those from the child. + + For example: + + .. code-block:: c + + gcc_jit_context_add_command_line_option (ctxt, "-ffast-math"); + gcc_jit_context_add_command_line_option (ctxt, "-fverbose-asm"); + + Note that only some options are likely to be meaningful; there is no + "frontend" within libgccjit, so typically only those affecting + optimization and code-generation are likely to be useful. + + This entrypoint was added in :ref:`LIBGCCJIT_ABI_1`; you can test for + its presence using + + .. code-block:: c + + #ifdef LIBGCCJIT_HAVE_gcc_jit_context_add_command_line_option diff --git a/gcc/jit/docs/topics/index.rst b/gcc/jit/docs/topics/index.rst index 4ebb623..76b3d0b 100644 --- a/gcc/jit/docs/topics/index.rst +++ b/gcc/jit/docs/topics/index.rst @@ -28,3 +28,4 @@ Topic Reference functions.rst locations.rst compilation.rst + compatibility.rst diff --git a/gcc/jit/jit-playback.c b/gcc/jit/jit-playback.c index 0f5013c..95ebfe0 100644 --- a/gcc/jit/jit-playback.c +++ b/gcc/jit/jit-playback.c @@ -2141,6 +2141,10 @@ make_fake_args (vec <char *> *argvec, } } + /* Add any user-provided extra options, starting with any from + parent contexts. */ + m_recording_ctxt->append_command_line_options (argvec); + #undef ADD_ARG #undef ADD_ARG_TAKE_OWNERSHIP } diff --git a/gcc/jit/jit-recording.c b/gcc/jit/jit-recording.c index 11b9739..3d7d571 100644 --- a/gcc/jit/jit-recording.c +++ b/gcc/jit/jit-recording.c @@ -517,6 +517,10 @@ recording::context::~context () for (i = 0; i < GCC_JIT_NUM_STR_OPTIONS; ++i) free (m_str_options[i]); + char *optname; + FOR_EACH_VEC_ELT (m_command_line_options, i, optname) + free (optname); + if (m_builtins_manager) delete m_builtins_manager; @@ -1137,6 +1141,33 @@ recording::context::set_bool_option (enum gcc_jit_bool_option opt, log_bool_option (opt); } +/* Add the given optname to this context's list of extra options. + + Implements the post-error-checking part of + gcc_jit_context_add_command_line_option. */ + +void +recording::context::add_command_line_option (const char *optname) +{ + m_command_line_options.safe_push (xstrdup (optname)); +} + +/* Add any user-provided extra options, starting with any from + parent contexts. + Called by playback::context::make_fake_args. */ + +void +recording::context::append_command_line_options (vec <char *> *argvec) +{ + if (m_parent_ctxt) + m_parent_ctxt->append_command_line_options (argvec); + + int i; + char *optname; + FOR_EACH_VEC_ELT (m_command_line_options, i, optname) + argvec->safe_push (xstrdup (optname)); +} + /* Add the given dumpname/out_ptr pair to this context's list of requested dumps. @@ -1593,6 +1624,17 @@ recording::context::dump_reproducer_to_file (const char *path) bool_option_reproducer_strings[opt_idx], m_bool_options[opt_idx]); + if (!m_command_line_options.is_empty ()) + { + int i; + char *optname; + r.write (" /* User-provided command-line options. */\n"); + FOR_EACH_VEC_ELT (m_command_line_options, i, optname) + r.write (" gcc_jit_context_add_command_line_option (%s, \"%s\");\n", + r.get_identifier (contexts[ctxt_idx]), + optname); + } + if (m_requested_dumps.length ()) { r.write (" /* Requested dumps. */\n"); diff --git a/gcc/jit/jit-recording.h b/gcc/jit/jit-recording.h index d3170fe..8cd2289 100644 --- a/gcc/jit/jit-recording.h +++ b/gcc/jit/jit-recording.h @@ -196,6 +196,12 @@ public: int value); void + add_command_line_option (const char *optname); + + void + append_command_line_options (vec <char *> *argvec); + + void enable_dump (const char *dumpname, char **out_ptr); @@ -281,6 +287,7 @@ private: char *m_str_options[GCC_JIT_NUM_STR_OPTIONS]; int m_int_options[GCC_JIT_NUM_INT_OPTIONS]; bool m_bool_options[GCC_JIT_NUM_BOOL_OPTIONS]; + auto_vec <char *> m_command_line_options; /* Dumpfiles that were requested via gcc_jit_context_enable_dump. */ auto_vec<requested_dump> m_requested_dumps; diff --git a/gcc/jit/libgccjit++.h b/gcc/jit/libgccjit++.h index 62ef6a4..a5353ca 100644 --- a/gcc/jit/libgccjit++.h +++ b/gcc/jit/libgccjit++.h @@ -120,6 +120,8 @@ namespace gccjit void set_bool_option (enum gcc_jit_bool_option opt, int value); + void add_command_line_option (const char *optname); + location new_location (const std::string &filename, int line, @@ -603,6 +605,12 @@ context::set_bool_option (enum gcc_jit_bool_option opt, } +inline void +context::add_command_line_option (const char *optname) +{ + gcc_jit_context_add_command_line_option (m_inner_ctxt, optname); +} + inline location context::new_location (const std::string &filename, int line, diff --git a/gcc/jit/libgccjit.c b/gcc/jit/libgccjit.c index dedf942..44791ab 100644 --- a/gcc/jit/libgccjit.c +++ b/gcc/jit/libgccjit.c @@ -2185,6 +2185,25 @@ gcc_jit_context_set_bool_option (gcc_jit_context *ctxt, /* Public entrypoint. See description in libgccjit.h. After error-checking, the real work is done by the + gcc::jit::recording::context::add_command_line_option method in + jit-recording.c. */ + +void +gcc_jit_context_add_command_line_option (gcc_jit_context *ctxt, + const char *optname) +{ + RETURN_IF_FAIL (ctxt, NULL, NULL, "NULL context"); + JIT_LOG_FUNC (ctxt->get_logger ()); + RETURN_IF_FAIL (optname, ctxt, NULL, "NULL optname"); + if (ctxt->get_logger ()) + ctxt->get_logger ()->log ("optname: %s", optname); + + ctxt->add_command_line_option (optname); +} + +/* Public entrypoint. See description in libgccjit.h. + + After error-checking, the real work is done by the gcc::jit::recording::context::enable_dump method in jit-recording.c. */ diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h index 767e9e3..2c1a99a 100644 --- a/gcc/jit/libgccjit.h +++ b/gcc/jit/libgccjit.h @@ -243,6 +243,29 @@ gcc_jit_context_set_bool_option (gcc_jit_context *ctxt, enum gcc_jit_bool_option opt, int value); +/* Add an arbitrary gcc command-line option to the context. + The context takes a copy of the string, so the + (const char *) optname is not needed anymore after the call + returns. + + Note that only some options are likely to be meaningful; there is no + "frontend" within libgccjit, so typically only those affecting + optimization and code-generation are likely to be useful. + + This entrypoint was added in LIBGCCJIT_ABI_1; you can test for + its presence using + #ifdef LIBGCCJIT_HAVE_gcc_jit_context_add_command_line_option +*/ + +extern void +gcc_jit_context_add_command_line_option (gcc_jit_context *ctxt, + const char *optname); + +/* Pre-canned feature-test macro for detecting the presence of + gcc_jit_context_add_command_line_option within libgccjit.h. */ + +#define LIBGCCJIT_HAVE_gcc_jit_context_add_command_line_option + /* Compile the context to in-memory machine code. This can be called more that once on a given context, diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map index 89bd57be4..a42bc74 100644 --- a/gcc/jit/libgccjit.map +++ b/gcc/jit/libgccjit.map @@ -17,6 +17,9 @@ # 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/>. */ + +# The initial release of the library. +LIBGCCJIT_ABI_0 { global: # Keep this list sorted alphabetically: @@ -104,4 +107,10 @@ gcc_jit_type_get_volatile; local: *; -}; \ No newline at end of file +}; + +# Add support for adding arbitrary command-line options (PR jit/66628). +LIBGCCJIT_ABI_1 { + global: + gcc_jit_context_add_command_line_option; +} LIBGCCJIT_ABI_0; diff --git a/gcc/testsuite/jit.dg/all-non-failing-tests.h b/gcc/testsuite/jit.dg/all-non-failing-tests.h index c9bbb34..8584555 100644 --- a/gcc/testsuite/jit.dg/all-non-failing-tests.h +++ b/gcc/testsuite/jit.dg/all-non-failing-tests.h @@ -95,6 +95,9 @@ #undef create_code #undef verify_code +/* test-extra-options.c: We don't use this one, since the extra options + affect the whole context. */ + /* test-factorial.c */ #define create_code create_code_factorial #define verify_code verify_code_factorial diff --git a/gcc/testsuite/jit.dg/test-extra-options.c b/gcc/testsuite/jit.dg/test-extra-options.c new file mode 100644 index 0000000..3739834 --- /dev/null +++ b/gcc/testsuite/jit.dg/test-extra-options.c @@ -0,0 +1,136 @@ +/* Testcase for gcc_jit_context_add_command_line_option (PR jit/66628). */ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "libgccjit.h" + +#include "harness.h" + +#ifndef LIBGCCJIT_HAVE_gcc_jit_context_add_command_line_option +#error LIBGCCJIT_HAVE_gcc_jit_context_add_command_line_option was not defined +#endif + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + gcc_jit_context_add_command_line_option (ctxt, "-ffast-math"); + gcc_jit_context_add_command_line_option (ctxt, "-fverbose-asm"); + + /* 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); +} -- 1.8.5.3