diff --git a/gcc/jit/docs/topics/compatibility.rst b/gcc/jit/docs/topics/compatibility.rst index 38d338b..abefa56 100644 --- a/gcc/jit/docs/topics/compatibility.rst +++ b/gcc/jit/docs/topics/compatibility.rst @@ -168,6 +168,12 @@ entrypoints: ``LIBGCCJIT_ABI_10`` -------------------- - ``LIBGCCJIT_ABI_10`` covers the addition of :func:`gcc_jit_context_new_rvalue_from_vector` + +.. _LIBGCCJIT_ABI_11: + +``LIBGCCJIT_ABI_11`` +-------------------- +``LIBGCCJIT_ABI_11`` covers the addition of +:func:`gcc_jit_context_add_driver_option` diff --git a/gcc/jit/docs/topics/contexts.rst b/gcc/jit/docs/topics/contexts.rst index 95964ca..2f8aeb7 100644 --- a/gcc/jit/docs/topics/contexts.rst +++ b/gcc/jit/docs/topics/contexts.rst @@ -546,3 +546,36 @@ Additional command-line options .. code-block:: c #ifdef LIBGCCJIT_HAVE_gcc_jit_context_add_command_line_option + +.. function:: void gcc_jit_context_add_driver_option (gcc_jit_context *ctxt,\ + const char *optname) + + Add an arbitrary gcc driver 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_driver_option` are + applied *after* all other options 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_driver_option (ctxt, "-lm"); + gcc_jit_context_add_driver_option (ctxt, "-fuse-linker-plugin"); + + Note that only some options are likely to be meaningful; there is no + "frontend" within libgccjit, so typically only those affecting + assembler and linker are likely to be useful. + + This entrypoint was added in :ref:`LIBGCCJIT_ABI_11`; you can test for + its presence using + + .. code-block:: c + + #ifdef LIBGCCJIT_HAVE_gcc_jit_context_add_driver_option diff --git a/gcc/jit/jit-playback.c b/gcc/jit/jit-playback.c index 86f588d..b74495c 100644 --- a/gcc/jit/jit-playback.c +++ b/gcc/jit/jit-playback.c @@ -2459,6 +2459,10 @@ invoke_driver (const char *ctxt_progname, if (0) ADD_ARG ("-v"); + /* Add any user-provided driver extra options. */ + + m_recording_ctxt->append_driver_options (&argvec); + #undef ADD_ARG /* pex_one's error-handling requires pname to be non-NULL. */ diff --git a/gcc/jit/jit-recording.c b/gcc/jit/jit-recording.c index 04cc6a6..8ffd0d4 100644 --- a/gcc/jit/jit-recording.c +++ b/gcc/jit/jit-recording.c @@ -616,6 +616,8 @@ recording::context::~context () char *optname; FOR_EACH_VEC_ELT (m_command_line_options, i, optname) free (optname); + FOR_EACH_VEC_ELT (m_driver_options, i, optname) + free (optname); if (m_builtins_manager) delete m_builtins_manager; @@ -1307,6 +1309,31 @@ recording::context::append_command_line_options (vec *argvec) argvec->safe_push (xstrdup (optname)); } +/* Add the given optname to this context's list of extra driver options. */ + +void +recording::context::add_driver_option (const char *optname) +{ + m_driver_options.safe_push (xstrdup (optname)); +} + +/* Add any user-provided driver options, starting with any from + parent contexts. + Called by playback::context::invoke_driver. */ + +void +recording::context::append_driver_options (auto_string_vec *argvec) +{ + if (m_parent_ctxt) + m_parent_ctxt->append_driver_options (argvec); + + int i; + char *optname; + + FOR_EACH_VEC_ELT (m_driver_options, i, optname) + argvec->safe_push (xstrdup (optname)); +} + /* Add the given dumpname/out_ptr pair to this context's list of requested dumps. @@ -1799,6 +1826,17 @@ recording::context::dump_reproducer_to_file (const char *path) optname); } + if (!m_driver_options.is_empty ()) + { + int i; + char *optname; + r.write (" /* User-provided driver options. */\n"); + FOR_EACH_VEC_ELT (m_driver_options, i, optname) + r.write (" gcc_jit_context_add_driver_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 b9c6544..b9f2250 100644 --- a/gcc/jit/jit-recording.h +++ b/gcc/jit/jit-recording.h @@ -218,6 +218,12 @@ public: append_command_line_options (vec *argvec); void + add_driver_option (const char *optname); + + void + append_driver_options (auto_string_vec *argvec); + + void enable_dump (const char *dumpname, char **out_ptr); @@ -317,6 +323,7 @@ private: bool m_bool_options[GCC_JIT_NUM_BOOL_OPTIONS]; bool m_inner_bool_options[NUM_INNER_BOOL_OPTIONS]; auto_vec m_command_line_options; + auto_vec m_driver_options; /* Dumpfiles that were requested via gcc_jit_context_enable_dump. */ auto_vec m_requested_dumps; diff --git a/gcc/jit/libgccjit++.h b/gcc/jit/libgccjit++.h index 5c2bd2d..55aebca 100644 --- a/gcc/jit/libgccjit++.h +++ b/gcc/jit/libgccjit++.h @@ -127,6 +127,7 @@ namespace gccjit void set_bool_use_external_driver (int bool_value); void add_command_line_option (const char *optname); + void add_driver_option (const char *optname); void set_timer (gccjit::timer t); gccjit::timer get_timer () const; @@ -687,6 +688,12 @@ context::add_command_line_option (const char *optname) } inline void +context::add_driver_option (const char *optname) +{ + gcc_jit_context_add_driver_option (m_inner_ctxt, optname); +} + +inline void context::set_timer (gccjit::timer t) { gcc_jit_context_set_timer (m_inner_ctxt, t.get_inner_timer ()); diff --git a/gcc/jit/libgccjit.c b/gcc/jit/libgccjit.c index de7fb25..e4f17f8 100644 --- a/gcc/jit/libgccjit.c +++ b/gcc/jit/libgccjit.c @@ -2644,6 +2644,25 @@ gcc_jit_context_add_command_line_option (gcc_jit_context *ctxt, /* Public entrypoint. See description in libgccjit.h. + The real work is done by the + gcc::jit::recording::context::add_driver_option method in + jit-recording.c. */ + +void +gcc_jit_context_add_driver_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_driver_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 e872ae7..beeb747 100644 --- a/gcc/jit/libgccjit.h +++ b/gcc/jit/libgccjit.h @@ -325,6 +325,28 @@ gcc_jit_context_add_command_line_option (gcc_jit_context *ctxt, #define LIBGCCJIT_HAVE_gcc_jit_context_add_command_line_option +/* Add an arbitrary gcc driver 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 + assembler and linker are likely to be useful. + + This entrypoint was added in LIBGCCJIT_ABI_11; you can test for + its presence using + #ifdef LIBGCCJIT_HAVE_gcc_jit_context_add_driver_option +*/ +extern void +gcc_jit_context_add_driver_option (gcc_jit_context *ctxt, + const char *optname); + +/* Pre-canned feature-test macro for detecting the presence of + gcc_jit_context_add_driver_option within libgccjit.h. */ + +#define LIBGCCJIT_HAVE_gcc_jit_context_add_driver_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 2826f1c..16f5253 100644 --- a/gcc/jit/libgccjit.map +++ b/gcc/jit/libgccjit.map @@ -170,3 +170,8 @@ LIBGCCJIT_ABI_10 { global: gcc_jit_context_new_rvalue_from_vector; } LIBGCCJIT_ABI_9; + +LIBGCCJIT_ABI_11 { + global: + gcc_jit_context_add_driver_option; +} LIBGCCJIT_ABI_10; \ No newline at end of file diff --git a/gcc/testsuite/jit.dg/add-driver-options-testlib.c b/gcc/testsuite/jit.dg/add-driver-options-testlib.c new file mode 100644 index 0000000..1757bb1 --- /dev/null +++ b/gcc/testsuite/jit.dg/add-driver-options-testlib.c @@ -0,0 +1,6 @@ +/* Used by test-add-driver-options.c */ + +extern int callee_function (void) +{ + return 1978; +} diff --git a/gcc/testsuite/jit.dg/all-non-failing-tests.h b/gcc/testsuite/jit.dg/all-non-failing-tests.h index bf02e12..9a10418 100644 --- a/gcc/testsuite/jit.dg/all-non-failing-tests.h +++ b/gcc/testsuite/jit.dg/all-non-failing-tests.h @@ -22,6 +22,9 @@ #undef create_code #undef verify_code +/* test-add-driver-options.c: We don't use this one, since the extra options + affect the whole context. */ + /* test-alignment.c */ #define create_code create_code_alignment #define verify_code verify_code_alignment diff --git a/gcc/testsuite/jit.dg/jit.exp b/gcc/testsuite/jit.dg/jit.exp index 869d9f6..13e8ab4 100644 --- a/gcc/testsuite/jit.dg/jit.exp +++ b/gcc/testsuite/jit.dg/jit.exp @@ -379,6 +379,19 @@ proc jit-dg-test { prog do_what extra_tool_flags } { append extra_tool_flags " -lpthread" } + # test-add-driver-options.c needs a shared library built from + # add-driver-options-testlib.c + if {[string match "*test-add-driver-options.c" $prog]} { + global srcdir + global subdir + + set comp_output [gcc_target_compile \ + $srcdir/$subdir/add-driver-options-testlib.c \ + "libadd-driver-options-testlib.so" \ + "executable" \ + "additional_flags=-fPIC additional_flags=-shared"] + } + # Any test case that uses jit-verify-output-file-was-created # needs to call jit-setup-compile-to-file here. # (is there a better way to handle setup/finish pairs in dg?) diff --git a/gcc/testsuite/jit.dg/test-add-driver-options.c b/gcc/testsuite/jit.dg/test-add-driver-options.c new file mode 100644 index 0000000..74ac168 --- /dev/null +++ b/gcc/testsuite/jit.dg/test-add-driver-options.c @@ -0,0 +1,68 @@ +#include +#include + +#include "libgccjit.h" +#include "harness.h" + +#ifndef LIBGCCJIT_HAVE_gcc_jit_context_add_driver_option +#error LIBGCCJIT_HAVE_gcc_jit_context_add_driver_option was not defined +#endif + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + + gcc_jit_context_add_driver_option (ctxt, "-L./"); + gcc_jit_context_add_driver_option (ctxt, "-ladd-driver-options-testlib"); + + /* Let's try to inject the equivalent of: + + int caller_function (void) + { + return callee_function (); + } + */ + gcc_jit_type *int_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT); + + gcc_jit_function *caller_func = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + int_type, + "caller_function", + 0, NULL, + 0); + + gcc_jit_block *block = + gcc_jit_function_new_block (caller_func, NULL); + + gcc_jit_function *callee_func = + gcc_jit_context_new_function(ctxt, NULL, + GCC_JIT_FUNCTION_IMPORTED, + int_type, + "callee_function", + 0, NULL, + 1); + + gcc_jit_block_end_with_return (block, NULL, + gcc_jit_context_new_call(ctxt, + NULL, + callee_func, + 0, + 0)); +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + typedef int (*my_caller_fn_type) (void); + + CHECK_NON_NULL (result); + my_caller_fn_type callee_function_ptr = + (my_caller_fn_type)gcc_jit_result_get_code (result, "callee_function"); + CHECK_NON_NULL (callee_function_ptr); + + int res = callee_function_ptr (); + + CHECK_VALUE (res, 1978); +}