This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH, committed] jit: API change to gcc_jit_context_new_global
- From: David Malcolm <dmalcolm at redhat dot com>
- To: jit at gcc dot gnu dot org, gcc-patches at gcc dot gnu dot org
- Cc: David Malcolm <dmalcolm at redhat dot com>
- Date: Mon, 12 Jan 2015 12:28:46 -0500
- Subject: [PATCH, committed] jit: API change to gcc_jit_context_new_global
- Authentication-results: sourceware.org; auth=none
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