This is an API change to one of the libgccjit.h entrypoints. Although we don't yet guarantee API stability for libgccjit, I'm loathe to break things without strong reasons. I think that in this case the reasons *are* sufficient (see below), and hence I feel that it's best to get this change in now before any official release of gcc 5.
The existing jit API for working with global variables was: extern gcc_jit_lvalue * gcc_jit_context_new_global (gcc_jit_context *ctxt, gcc_jit_location *loc, gcc_jit_type *type, const char *name); This API was misnamed: it didn't create a new global, it instead created a new lvalue referencing an existing global variable (by name). In my PyPy libgccjit experiment I needed to be able to create new global variables, and mistakenly attempted to use the existing API to do this. Given that I wrote the API, my inability to use it (together with missing functionality) is a major red flag for the design :) The following patch adds a new param to the entrypoint: extern gcc_jit_lvalue * gcc_jit_context_new_global (gcc_jit_context *ctxt, gcc_jit_location *loc, + enum gcc_jit_global_kind kind, gcc_jit_type *type, const char *name); with a new enum: enum gcc_jit_global_kind { /* Global is defined by the client code and visible by name outside of this JIT context via gcc_jit_result_get_global. */ GCC_JIT_GLOBAL_EXPORTED, /* Global is defined by the client code, but is invisible outside of this JIT context. Analogous to a "static" global. */ GCC_JIT_GLOBAL_INTERNAL, /* Global is not defined by the client code; we're merely referring to it. Analogous to using an "extern" global from a header file. */ GCC_JIT_GLOBAL_IMPORTED }; This approach is by analogy to the gcc_jit_context_new_function entrypoint. For porting existing code, the old behavior is equivalent to passing in GCC_JIT_GLOBAL_IMPORTED as the new param. There's also a new entrypoint for accessing globals created via GCC_JIT_GLOBAL_EXPORTED: /* Locate a given global within the built machine code. It must have been created using GCC_JIT_GLOBAL_EXPORTED. This is a ptr to the global, so e.g. for an int this is an int *. */ extern void * gcc_jit_result_get_global (gcc_jit_result *result, const char *name); The new test coverage takes jit.sum from 7152 to 7272 passes. Committed to trunk as r219480. gcc/jit/ChangeLog: * docs/cp/topics/expressions.rst (Global variables): Add enum gcc_jit_global_kind param to gccjit::context::new_global. * docs/topics/expressions.rst (Global variables): Likewise. Document the new enum. * docs/topics/results.rst (Compilation results): Document globals-handling. * docs/_build/texinfo/libgccjit.texi: Regenerate. * dummy-frontend.c (jit_langhook_write_globals): Call into the playback context's write_global_decls_1 and write_global_decls_2 before and after calling symtab->finalize_compilation_unit (). * jit-playback.c: Include "debug.h". (gcc::jit::playback::context::new_global): Add "kind" param and use it to set TREE_PUBLIC, TREE_STATIC and DECL_EXTERNAL on the underlying VAR_DECL. Call varpool_node::get_create on the VAR_DECL, and add it to m_globals. (gcc::jit::playback::context::write_global_decls_1): New function. (gcc::jit::playback::context::write_global_decls_2): New function. * jit-playback.h (gcc::jit::playback::context::context): Call create on m_globals. (gcc::jit::playback::context::new_global): Add "kind" param. (gcc::jit::playback::context::write_global_decls_1): New function. (gcc::jit::playback::context::write_global_decls_2): New function. (gcc::jit::playback::context::m_globals): New field. * jit-recording.c (gcc::jit::recording::context::context): Initialize m_globals. (gcc::jit::recording::context::new_global): Add param "kind". Add the new global to m_globals. (gcc::jit::recording::context::dump_to_file): Dump the globals. (gcc::jit::recording::global::replay_into): Add field m_kind. (gcc::jit::recording::global::write_to_dump): New override. * jit-recording.h (gcc::jit::recording::context::new_global): Add param "kind". (gcc::jit::recording::context::m_globals): New field. (gcc::jit::recording::global::global): Add param kind. (gcc::jit::recording::global::write_to_dump): New override. (gcc::jit::recording::global::m_kind): New field. * jit-result.c (gcc::jit::result::get_global): New function. * jit-result.h (gcc::jit::result::get_global): New function. * libgccjit++.h (gccjit::context::new_global): Add "kind" param. * libgccjit.c (gcc_jit_context_new_global): Likewise. (gcc_jit_result_get_global): New API entrypoint. * libgccjit.h (gcc_jit_result_get_global): New API entrypoint. (enum gcc_jit_global_kind): New enum. (gcc_jit_context_new_global): API change: add "kind" param. * libgccjit.map (gcc_jit_result_get_global): New symbol. gcc/testsuite/ChangeLog: * jit.dg/test-array-as-pointer.c (create_code): Update call to gcc_jit_context_new_global by setting "kind" to GCC_JIT_GLOBAL_IMPORTED. * jit.dg/test-error-array-as-pointer.c: Likewise. * jit.dg/test-expressions.c (make_test_of_get_address): Likewise. * jit.dg/test-fuzzer.c (make_random_global): Likewise, but setting kind to GCC_JIT_GLOBAL_EXPORTED. * jit.dg/test-using-global.c (the_global): Rename to... (imported_global): ...this. (create_code): Update to test the three kinds of global. (verify_code): Likewise. --- gcc/jit/docs/cp/topics/expressions.rst | 5 +- gcc/jit/docs/topics/expressions.rst | 25 +++++++ gcc/jit/docs/topics/results.rst | 58 +++++++++++++-- gcc/jit/dummy-frontend.c | 9 ++- gcc/jit/jit-playback.c | 66 +++++++++++++++- gcc/jit/jit-playback.h | 6 ++ gcc/jit/jit-recording.c | 64 +++++++++++++++- gcc/jit/jit-recording.h | 7 ++ gcc/jit/jit-result.c | 27 +++++++ gcc/jit/jit-result.h | 3 + gcc/jit/libgccjit++.h | 7 +- gcc/jit/libgccjit.c | 28 ++++++- gcc/jit/libgccjit.h | 23 ++++++ gcc/jit/libgccjit.map | 1 + gcc/testsuite/jit.dg/test-array-as-pointer.c | 3 +- gcc/testsuite/jit.dg/test-error-array-as-pointer.c | 5 +- gcc/testsuite/jit.dg/test-expressions.c | 1 + gcc/testsuite/jit.dg/test-fuzzer.c | 1 + gcc/testsuite/jit.dg/test-using-global.c | 87 ++++++++++++++++++---- 19 files changed, 394 insertions(+), 32 deletions(-) diff --git a/gcc/jit/docs/cp/topics/expressions.rst b/gcc/jit/docs/cp/topics/expressions.rst index b58eeff..84ff741 100644 --- a/gcc/jit/docs/cp/topics/expressions.rst +++ b/gcc/jit/docs/cp/topics/expressions.rst @@ -504,12 +504,15 @@ Global variables **************** .. function:: gccjit::lvalue \ - gccjit::context::new_global (gccjit::type type, \ + gccjit::context::new_global (enum gcc_jit_global_kind,\ + gccjit::type type, \ const char *name, \ gccjit::location loc) Add a new global variable of the given type and name to the context. + This is a thin wrapper around :c:func:`gcc_jit_context_new_global` from + the C API; the "kind" parameter has the same meaning as there. Working with pointers, structs and unions ----------------------------------------- diff --git a/gcc/jit/docs/topics/expressions.rst b/gcc/jit/docs/topics/expressions.rst index 13a28e8..b56a1db 100644 --- a/gcc/jit/docs/topics/expressions.rst +++ b/gcc/jit/docs/topics/expressions.rst @@ -460,11 +460,36 @@ Global variables .. function:: gcc_jit_lvalue *\ gcc_jit_context_new_global (gcc_jit_context *ctxt,\ gcc_jit_location *loc,\ + enum gcc_jit_global_kind kind,\ gcc_jit_type *type,\ const char *name) Add a new global variable of the given type and name to the context. + The "kind" parameter determines the visibility of the "global" outside + of the :c:type:`gcc_jit_result`: + + .. type:: enum gcc_jit_global_kind + + .. c:macro:: GCC_JIT_GLOBAL_EXPORTED + + Global is defined by the client code and is visible + by name outside of this JIT context via + :c:func:`gcc_jit_result_get_global` (and this value is required for + the global to be accessible via that entrypoint). + + .. c:macro:: GCC_JIT_GLOBAL_INTERNAL + + Global is defined by the client code, but is invisible + outside of it. Analogous to a "static" global within a .c file. + Specifically, the variable will only be visible within this + context and within child contexts. + + .. c:macro:: GCC_JIT_GLOBAL_IMPORTED + + Global is not defined by the client code; we're merely + referring to it. Analogous to using an "extern" global from a + header file. Working with pointers, structs and unions ----------------------------------------- diff --git a/gcc/jit/docs/topics/results.rst b/gcc/jit/docs/topics/results.rst index 9904495..aa5ea8b 100644 --- a/gcc/jit/docs/topics/results.rst +++ b/gcc/jit/docs/topics/results.rst @@ -23,8 +23,8 @@ Compilation results .. type:: gcc_jit_result A `gcc_jit_result` encapsulates the result of compiling a context, - and the lifetimes of any machine code functions that are - returned. + and the lifetimes of any machine code functions or globals that are + within it. .. function:: gcc_jit_result *\ gcc_jit_context_compile (gcc_jit_context *ctxt) @@ -32,6 +32,9 @@ Compilation results This calls into GCC and builds the code, returning a `gcc_jit_result *`. + If this is non-NULL, the caller becomes responsible for + calling :func:`gcc_jit_result_release` on it once they're done + with it. .. function:: void *\ gcc_jit_result_get_code (gcc_jit_result *result,\ @@ -66,14 +69,59 @@ Compilation results Note that the resulting machine code becomes invalid after :func:`gcc_jit_result_release` is called on the - `gcc_jit_result *`; attempting to call it after that may lead + :type:`gcc_jit_result *`; attempting to call it after that may lead to a segmentation fault. +.. function:: void *\ + gcc_jit_result_get_global (gcc_jit_result *result,\ + const char *name) + + Locate a given global within the built machine code. + + Globals are looked up by name. For this to succeed, a global + with a name matching `name` must have been created on + `result`'s context (or a parent context) via a call to + :func:`gcc_jit_context_new_global` with `kind` + :macro:`GCC_JIT_GLOBAL_EXPORTED`. + + If the global is found, the result will need to be cast to a + pointer of the correct type before it can be called. + + This is a *pointer* to the global, so e.g. for an :c:type:`int` this is + an :c:type:`int *`. + + For example, given an ``int foo;`` created this way: + + .. code-block:: c + + gcc_jit_lvalue *exported_global = + gcc_jit_context_new_global (ctxt, + any_location, /* or NULL */ + GCC_JIT_GLOBAL_EXPORTED, + int_type, + "foo"); + + we can access it like this: + + .. code-block:: c + + int *ptr_to_foo = + (int *)gcc_jit_result_get_global (result, "foo"); + + If such a global is not found (or `result` or `name` are + ``NULL``), an error message will be emitted on stderr and + ``NULL`` will be returned. + + Note that the resulting address becomes invalid after + :func:`gcc_jit_result_release` is called on the + :type:`gcc_jit_result *`; attempting to use it after that may lead + to a segmentation fault. .. 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, or any code that was obtained by calling - :func:`gcc_jit_result_get_code` on it. + valid to use the result, or any code or globals that were obtained + by calling :func:`gcc_jit_result_get_code` or + :func:`gcc_jit_result_get_global` on it. diff --git a/gcc/jit/dummy-frontend.c b/gcc/jit/dummy-frontend.c index a4dae3e..9f799d3 100644 --- a/gcc/jit/dummy-frontend.c +++ b/gcc/jit/dummy-frontend.c @@ -221,11 +221,16 @@ jit_langhook_getdecls (void) static void jit_langhook_write_globals (void) { - gcc_assert (gcc::jit::active_playback_ctxt); - JIT_LOG_SCOPE (gcc::jit::active_playback_ctxt->get_logger ()); + gcc::jit::playback::context *ctxt = gcc::jit::active_playback_ctxt; + gcc_assert (ctxt); + JIT_LOG_SCOPE (ctxt->get_logger ()); + + ctxt->write_global_decls_1 (); /* This is the hook that runs the middle and backends: */ symtab->finalize_compilation_unit (); + + ctxt->write_global_decls_2 (); } #undef LANG_HOOKS_NAME diff --git a/gcc/jit/jit-playback.c b/gcc/jit/jit-playback.c index 1baf9c5..0e45e02 100644 --- a/gcc/jit/jit-playback.c +++ b/gcc/jit/jit-playback.c @@ -62,6 +62,7 @@ along with GCC; see the file COPYING3. If not see #include "attribs.h" #include "context.h" #include "fold-const.h" +#include "debug.h" #include "jit-common.h" #include "jit-logging.h" @@ -109,6 +110,7 @@ playback::context::context (recording::context *ctxt) { JIT_LOG_SCOPE (get_logger ()); m_functions.create (0); + m_globals.create (0); m_source_files.create (0); m_cached_locations.create (0); } @@ -482,6 +484,7 @@ new_function (location *loc, playback::lvalue * playback::context:: new_global (location *loc, + enum gcc_jit_global_kind kind, type *type, const char *name) { @@ -490,13 +493,33 @@ new_global (location *loc, tree inner = build_decl (UNKNOWN_LOCATION, VAR_DECL, get_identifier (name), type->as_tree ()); - TREE_PUBLIC (inner) = 1; + TREE_PUBLIC (inner) = (kind != GCC_JIT_GLOBAL_INTERNAL); DECL_COMMON (inner) = 1; - DECL_EXTERNAL (inner) = 1; + switch (kind) + { + default: + gcc_unreachable (); + + case GCC_JIT_GLOBAL_EXPORTED: + TREE_STATIC (inner) = 1; + break; + + case GCC_JIT_GLOBAL_INTERNAL: + TREE_STATIC (inner) = 1; + break; + + case GCC_JIT_GLOBAL_IMPORTED: + DECL_EXTERNAL (inner) = 1; + break; + } if (loc) set_tree_location (inner, loc); + varpool_node::get_create (inner); + + m_globals.safe_push (inner); + return new lvalue (this, inner); } @@ -649,6 +672,45 @@ as_truth_value (tree expr, location *loc) return expr; } +/* For use by jit_langhook_write_globals. + Calls varpool_node::finalize_decl on each global. */ + +void +playback::context:: +write_global_decls_1 () +{ + /* Compare with e.g. the C frontend's c_write_global_declarations. */ + JIT_LOG_SCOPE (get_logger ()); + + int i; + tree decl; + FOR_EACH_VEC_ELT (m_globals, i, decl) + { + gcc_assert (TREE_CODE (decl) == VAR_DECL); + varpool_node::finalize_decl (decl); + } +} + +/* For use by jit_langhook_write_globals. + Calls debug_hooks->global_decl on each global. */ + +void +playback::context:: +write_global_decls_2 () +{ + /* Compare with e.g. the C frontend's c_write_global_declarations_2. */ + JIT_LOG_SCOPE (get_logger ()); + + int i; + tree decl; + FOR_EACH_VEC_ELT (m_globals, i, decl) + { + gcc_assert (TREE_CODE (decl) == VAR_DECL); + debug_hooks->global_decl (decl); + } +} + + /* Construct a playback::rvalue instance (wrapping a tree) for a unary op. */ diff --git a/gcc/jit/jit-playback.h b/gcc/jit/jit-playback.h index 07d030e..8efd506 100644 --- a/gcc/jit/jit-playback.h +++ b/gcc/jit/jit-playback.h @@ -90,6 +90,7 @@ public: lvalue * new_global (location *loc, + enum gcc_jit_global_kind kind, type *type, const char *name); @@ -206,6 +207,10 @@ public: return m_recording_ctxt->errors_occurred (); } + /* For use by jit_langhook_write_globals. */ + void write_global_decls_1 (); + void write_global_decls_2 (); + private: void dump_generated_code (); @@ -259,6 +264,7 @@ private: tempdir *m_tempdir; auto_vec<function *> m_functions; + auto_vec<tree> m_globals; tree m_char_array_type_node; tree m_const_char_ptr; diff --git a/gcc/jit/jit-recording.c b/gcc/jit/jit-recording.c index 8da7f76..20fd2d2 100644 --- a/gcc/jit/jit-recording.c +++ b/gcc/jit/jit-recording.c @@ -177,6 +177,7 @@ recording::context::context (context *parent_ctxt) m_owns_last_error_str (false), m_mementos (), m_compound_types (), + m_globals (), m_functions (), m_FILE_type (NULL), m_builtins_manager(NULL) @@ -636,12 +637,15 @@ recording::context::get_builtin_function (const char *name) recording::lvalue * recording::context::new_global (recording::location *loc, + enum gcc_jit_global_kind kind, recording::type *type, const char *name) { - recording::lvalue *result = - new recording::global (this, loc, type, new_string (name)); + recording::global *result = + new recording::global (this, loc, kind, type, new_string (name)); record (result); + m_globals.safe_push (result); + return result; } @@ -1016,6 +1020,15 @@ recording::context::dump_to_file (const char *path, bool update_locations) d.write ("\n"); } + /* Globals. */ + global *g; + FOR_EACH_VEC_ELT (m_globals, i, g) + { + g->write_to_dump (d); + } + if (!m_globals.is_empty ()) + d.write ("\n"); + function *fn; FOR_EACH_VEC_ELT (m_functions, i, fn) { @@ -2648,10 +2661,57 @@ void recording::global::replay_into (replayer *r) { set_playback_obj (r->new_global (playback_location (r, m_loc), + m_kind, m_type->playback_type (), playback_string (m_name))); } +/* Override the default implementation of + recording::memento::write_to_dump for globals. + This will be of the form: + + GCC_JIT_GLOBAL_EXPORTED: + "TYPE NAME;" + e.g. "int foo;" + + GCC_JIT_GLOBAL_INTERNAL: + "static TYPE NAME;" + e.g. "static int foo;" + + GCC_JIT_GLOBAL_IMPORTED: + "extern TYPE NAME;" + e.g. "extern int foo;" + + These are written to the top of the dump by + recording::context::dump_to_file. */ + +void +recording::global::write_to_dump (dump &d) +{ + if (d.update_locations ()) + m_loc = d.make_location (); + + switch (m_kind) + { + default: + gcc_unreachable (); + + case GCC_JIT_GLOBAL_EXPORTED: + break; + + case GCC_JIT_GLOBAL_INTERNAL: + d.write ("static "); + break; + + case GCC_JIT_GLOBAL_IMPORTED: + d.write ("extern "); + break; + } + d.write ("%s %s;\n", + m_type->get_debug_string (), + get_debug_string ()); +} + /* The implementation of the various const-handling classes: gcc::jit::recording::memento_of_new_rvalue_from_const <HOST_TYPE>. */ diff --git a/gcc/jit/jit-recording.h b/gcc/jit/jit-recording.h index 8d15487..43e99ba 100644 --- a/gcc/jit/jit-recording.h +++ b/gcc/jit/jit-recording.h @@ -132,6 +132,7 @@ public: lvalue * new_global (location *loc, + enum gcc_jit_global_kind kind, type *type, const char *name); @@ -272,6 +273,7 @@ private: /* Specific recordings, for use by dump_to_file. */ auto_vec<compound_type *> m_compound_types; + auto_vec<global *> m_globals; auto_vec<function *> m_functions; type *m_basic_types[NUM_GCC_JIT_TYPES]; @@ -1051,18 +1053,23 @@ class global : public lvalue public: global (context *ctxt, location *loc, + enum gcc_jit_global_kind kind, type *type, string *name) : lvalue (ctxt, loc, type), + m_kind (kind), m_name (name) {} void replay_into (replayer *); + void write_to_dump (dump &d); + private: string * make_debug_string () { return m_name; } private: + enum gcc_jit_global_kind m_kind; string *m_name; }; diff --git a/gcc/jit/jit-result.c b/gcc/jit/jit-result.c index a9330e5..30acdc6 100644 --- a/gcc/jit/jit-result.c +++ b/gcc/jit/jit-result.c @@ -86,6 +86,33 @@ get_code (const char *funcname) return code; } +/* Attempt to locate the given global by name within the + playback::result, using dlsym. + + Implements the post-error-checking part of + gcc_jit_result_get_global. */ + +void * +result:: +get_global (const char *name) +{ + JIT_LOG_SCOPE (get_logger ()); + + void *global; + const char *error; + + /* Clear any existing error. */ + dlerror (); + + global = dlsym (m_dso_handle, name); + + if ((error = dlerror()) != NULL) { + fprintf(stderr, "%s\n", error); + } + + return global; +} + } // namespace gcc::jit } // namespace gcc diff --git a/gcc/jit/jit-result.h b/gcc/jit/jit-result.h index d9073f2..b2d179d 100644 --- a/gcc/jit/jit-result.h +++ b/gcc/jit/jit-result.h @@ -36,6 +36,9 @@ public: void * get_code (const char *funcname); + void * + get_global (const char *name); + private: void *m_dso_handle; tempdir *m_tempdir; diff --git a/gcc/jit/libgccjit++.h b/gcc/jit/libgccjit++.h index 84144e5..79320f6 100644 --- a/gcc/jit/libgccjit++.h +++ b/gcc/jit/libgccjit++.h @@ -155,7 +155,8 @@ namespace gccjit function get_builtin_function (const std::string &name); - lvalue new_global (type type_, + lvalue new_global (enum gcc_jit_global_kind kind, + type type_, const std::string &name, location loc = location ()); @@ -707,12 +708,14 @@ context::get_builtin_function (const std::string &name) } inline lvalue -context::new_global (type type_, +context::new_global (enum gcc_jit_global_kind kind, + type type_, const std::string &name, location loc) { return lvalue (gcc_jit_context_new_global (m_inner_ctxt, loc.get_inner_location (), + kind, type_.get_inner_type (), name.c_str ())); } diff --git a/gcc/jit/libgccjit.c b/gcc/jit/libgccjit.c index 62d3edf..d596d08 100644 --- a/gcc/jit/libgccjit.c +++ b/gcc/jit/libgccjit.c @@ -987,16 +987,23 @@ gcc_jit_block_get_function (gcc_jit_block *block) gcc_jit_lvalue * gcc_jit_context_new_global (gcc_jit_context *ctxt, gcc_jit_location *loc, + enum gcc_jit_global_kind kind, gcc_jit_type *type, const char *name) { RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL context"); JIT_LOG_FUNC (ctxt->get_logger ()); /* LOC can be NULL. */ + RETURN_NULL_IF_FAIL_PRINTF1 ( + ((kind >= GCC_JIT_GLOBAL_EXPORTED) + && (kind <= GCC_JIT_GLOBAL_IMPORTED)), + ctxt, loc, + "unrecognized value for enum gcc_jit_global_kind: %i", + kind); RETURN_NULL_IF_FAIL (type, ctxt, loc, "NULL type"); RETURN_NULL_IF_FAIL (name, ctxt, loc, "NULL name"); - return (gcc_jit_lvalue *)ctxt->new_global (loc, type, name); + return (gcc_jit_lvalue *)ctxt->new_global (loc, kind, type, name); } /* Public entrypoint. See description in libgccjit.h. @@ -2215,6 +2222,25 @@ gcc_jit_result_get_code (gcc_jit_result *result, /* Public entrypoint. See description in libgccjit.h. + After error-checking, the real work is done by the + gcc::jit::result::get_global method in jit-result.c. */ + +void * +gcc_jit_result_get_global (gcc_jit_result *result, + const char *name) +{ + RETURN_NULL_IF_FAIL (result, NULL, NULL, "NULL result"); + JIT_LOG_FUNC (result->get_logger ()); + RETURN_NULL_IF_FAIL (name, NULL, NULL, "NULL name"); + + void *global = result->get_global (name); + result->log ("%s: returning (void *)%p", __func__, global); + + return global; +} + +/* Public entrypoint. See description in libgccjit.h. + After error-checking, this is essentially a wrapper around the destructor for gcc::jit::result in jit-result.c. */ diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h index 92eed37..41c76ea 100644 --- a/gcc/jit/libgccjit.h +++ b/gcc/jit/libgccjit.h @@ -299,6 +299,13 @@ extern void * gcc_jit_result_get_code (gcc_jit_result *result, const char *funcname); +/* Locate a given global within the built machine code. + It must have been created using GCC_JIT_GLOBAL_EXPORTED. + This is a ptr to the global, so e.g. for an int this is an int *. */ +extern void * +gcc_jit_result_get_global (gcc_jit_result *result, + const char *name); + /* 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. */ @@ -606,10 +613,26 @@ gcc_jit_block_get_function (gcc_jit_block *block); /********************************************************************** lvalues, rvalues and expressions. **********************************************************************/ +enum gcc_jit_global_kind +{ + /* Global is defined by the client code and visible + by name outside of this JIT context via gcc_jit_result_get_global. */ + GCC_JIT_GLOBAL_EXPORTED, + + /* Global is defined by the client code, but is invisible + outside of this JIT context. Analogous to a "static" global. */ + GCC_JIT_GLOBAL_INTERNAL, + + /* Global is not defined by the client code; we're merely + referring to it. Analogous to using an "extern" global from a + header file. */ + GCC_JIT_GLOBAL_IMPORTED +}; extern gcc_jit_lvalue * gcc_jit_context_new_global (gcc_jit_context *ctxt, gcc_jit_location *loc, + enum gcc_jit_global_kind kind, gcc_jit_type *type, const char *name); diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map index bc6eb1a..3ab88fd 100644 --- a/gcc/jit/libgccjit.map +++ b/gcc/jit/libgccjit.map @@ -87,6 +87,7 @@ gcc_jit_param_as_object; gcc_jit_param_as_rvalue; gcc_jit_result_get_code; + gcc_jit_result_get_global; gcc_jit_result_release; gcc_jit_rvalue_access_field; gcc_jit_rvalue_as_object; diff --git a/gcc/testsuite/jit.dg/test-array-as-pointer.c b/gcc/testsuite/jit.dg/test-array-as-pointer.c index 1a240ac..6b1f9ad 100644 --- a/gcc/testsuite/jit.dg/test-array-as-pointer.c +++ b/gcc/testsuite/jit.dg/test-array-as-pointer.c @@ -62,7 +62,8 @@ create_code (gcc_jit_context *ctxt, void *user_data) 0); gcc_jit_lvalue *buffer = - gcc_jit_context_new_global (ctxt, NULL, buf_type, "test_buffer"); + gcc_jit_context_new_global (ctxt, NULL, GCC_JIT_GLOBAL_IMPORTED, + buf_type, "test_buffer"); gcc_jit_block *block = gcc_jit_function_new_block(test_fn, "entry"); diff --git a/gcc/testsuite/jit.dg/test-error-array-as-pointer.c b/gcc/testsuite/jit.dg/test-error-array-as-pointer.c index cd2b7f8..d2c07b3 100644 --- a/gcc/testsuite/jit.dg/test-error-array-as-pointer.c +++ b/gcc/testsuite/jit.dg/test-error-array-as-pointer.c @@ -62,7 +62,10 @@ create_code (gcc_jit_context *ctxt, void *user_data) 0); gcc_jit_lvalue *buffer = - gcc_jit_context_new_global (ctxt, NULL, buf_type, "test_buffer"); + gcc_jit_context_new_global (ctxt, NULL, + GCC_JIT_GLOBAL_IMPORTED, + buf_type, + "test_buffer"); gcc_jit_block *block = gcc_jit_function_new_block(test_fn, "entry"); diff --git a/gcc/testsuite/jit.dg/test-expressions.c b/gcc/testsuite/jit.dg/test-expressions.c index 7e33b56..548cfa2 100644 --- a/gcc/testsuite/jit.dg/test-expressions.c +++ b/gcc/testsuite/jit.dg/test-expressions.c @@ -884,6 +884,7 @@ make_test_of_get_address (gcc_jit_context *ctxt) gcc_jit_context_new_global ( ctxt, NULL, + GCC_JIT_GLOBAL_IMPORTED, int_type, "test_global"); diff --git a/gcc/testsuite/jit.dg/test-fuzzer.c b/gcc/testsuite/jit.dg/test-fuzzer.c index b501792..6943d3e 100644 --- a/gcc/testsuite/jit.dg/test-fuzzer.c +++ b/gcc/testsuite/jit.dg/test-fuzzer.c @@ -238,6 +238,7 @@ make_random_global (fuzzer *f) sprintf (global_name, "g%i", f->num_globals); return gcc_jit_context_new_global (f->ctxt, get_random_location (f), + GCC_JIT_GLOBAL_EXPORTED, get_random_type (f), global_name); } diff --git a/gcc/testsuite/jit.dg/test-using-global.c b/gcc/testsuite/jit.dg/test-using-global.c index 3ec949f..8ac9780 100644 --- a/gcc/testsuite/jit.dg/test-using-global.c +++ b/gcc/testsuite/jit.dg/test-using-global.c @@ -9,7 +9,7 @@ extern "C" { #endif - extern int the_global; + extern int imported_global; #ifdef __cplusplus } @@ -19,24 +19,47 @@ void create_code (gcc_jit_context *ctxt, void *user_data) { /* Let's try to inject the equivalent of: - extern int the_global; - void + int exported_global; + extern int imported_global; + static int internal_global; + + int test_using_global (void) { - the_global += 1; + exported_global += 1; + imported_global += 1; + internal_global += 1; + return internal_global; } */ - 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_lvalue *exported_global = + gcc_jit_context_new_global (ctxt, + NULL, + GCC_JIT_GLOBAL_EXPORTED, + int_type, + "exported_global"); + gcc_jit_lvalue *imported_global = + gcc_jit_context_new_global (ctxt, + NULL, + GCC_JIT_GLOBAL_IMPORTED, + int_type, + "imported_global"); + gcc_jit_lvalue *internal_global = + gcc_jit_context_new_global (ctxt, + NULL, + GCC_JIT_GLOBAL_INTERNAL, + int_type, + "internal_global"); + /* Build the test_fn. */ gcc_jit_function *test_fn = gcc_jit_context_new_function (ctxt, NULL, GCC_JIT_FUNCTION_EXPORTED, - void_type, + int_type, "test_using_global", 0, NULL, 0); @@ -44,30 +67,64 @@ create_code (gcc_jit_context *ctxt, void *user_data) gcc_jit_block_add_assignment_op ( block, NULL, - gcc_jit_context_new_global (ctxt, NULL, int_type, "the_global"), + exported_global, + GCC_JIT_BINARY_OP_PLUS, + gcc_jit_context_one (ctxt, int_type)); + gcc_jit_block_add_assignment_op ( + block, NULL, + imported_global, + GCC_JIT_BINARY_OP_PLUS, + gcc_jit_context_one (ctxt, int_type)); + gcc_jit_block_add_assignment_op ( + block, NULL, + internal_global, GCC_JIT_BINARY_OP_PLUS, gcc_jit_context_one (ctxt, int_type)); - gcc_jit_block_end_with_void_return (block, NULL); + gcc_jit_block_end_with_return (block, + NULL, + gcc_jit_lvalue_as_rvalue (internal_global)); } -int the_global; +int imported_global; void verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) { - typedef void (*fn_type) (void); + typedef int (*fn_type) (void); CHECK_NON_NULL (result); fn_type test_using_global = (fn_type)gcc_jit_result_get_code (result, "test_using_global"); CHECK_NON_NULL (test_using_global); - the_global = 42; + /* The exported global should be visible. */ + int *exported_global = (int *)gcc_jit_result_get_global (result, "exported_global"); + CHECK_NON_NULL (exported_global); + /* ...and should be zero-initialized. */ + CHECK_VALUE (*exported_global, 0); + + /* Set some nonzero values. */ + *exported_global = 11; + imported_global = 42; + + /* The internal global shouldn't be visible. */ + int *internal_global = (int *)gcc_jit_result_get_global (result, "internal_global"); + CHECK_VALUE (internal_global, NULL); /* Call the JIT-generated function. */ - test_using_global (); + int call_count = test_using_global (); + + /* Verify that it correctly modified imported_global and exported_global. */ + CHECK_VALUE (*exported_global, 12); + CHECK_VALUE (imported_global, 43); + CHECK_VALUE (call_count, 1); + + /* Try calling it again. */ + call_count = test_using_global (); - /* Verify that it correctly modified the_global. */ - CHECK_VALUE (the_global, 43); + /* Verify the new values. */ + CHECK_VALUE (*exported_global, 13); + CHECK_VALUE (imported_global, 44); + CHECK_VALUE (call_count, 2); } -- 1.8.5.3