This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH, committed] jit: API change to gcc_jit_context_new_global


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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]