libgccjit: Add support for TLS variable [PR95415]
authorAntoni Boucher <bouanto@zoho.com>
Sun, 12 Dec 2021 00:01:15 +0000 (19:01 -0500)
committerAntoni Boucher <bouanto@zoho.com>
Sun, 12 Dec 2021 00:01:15 +0000 (19:01 -0500)
2021-12-11  Antoni Boucher  <bouanto@zoho.com>

gcc/jit/
PR target/95415
* docs/topics/compatibility.rst (LIBGCCJIT_ABI_17): New ABI
tag.
* docs/topics/expressions.rst: Add document for the function
gcc_jit_lvalue_set_tls_model.
* jit-playback.h: New function (set_tls_model).
* jit-recording.c: New function (set_tls_model), new
variables (tls_models and tls_model_enum_strings) and support
for setting the tls model.
* jit-recording.h: New function (set_tls_model) and new
field m_tls_model.
* libgccjit.c: New function (gcc_jit_lvalue_set_tls_model).
* libgccjit.h: New function (gcc_jit_lvalue_set_tls_model)
and new enum (gcc_jit_tls_model).
* libgccjit.map (LIBGCCJIT_ABI_17): New ABI tag.

gcc/testsuite/
PR target/95415
* jit.dg/all-non-failing-tests.h: Add test-tls.c.
* jit.dg/test-tls.c: New test.

gcc/jit/docs/topics/compatibility.rst
gcc/jit/docs/topics/expressions.rst
gcc/jit/jit-playback.h
gcc/jit/jit-recording.c
gcc/jit/jit-recording.h
gcc/jit/libgccjit.c
gcc/jit/libgccjit.h
gcc/jit/libgccjit.map
gcc/testsuite/jit.dg/all-non-failing-tests.h
gcc/testsuite/jit.dg/test-tls.c [new file with mode: 0644]

index 52ee3f8..2ad6e42 100644 (file)
@@ -284,3 +284,12 @@ entrypoints:
   * :func:`gcc_jit_struct_get_field`
 
   * :func:`gcc_jit_struct_get_field_count`
+
+.. _LIBGCCJIT_ABI_17:
+
+``LIBGCCJIT_ABI_17``
+-----------------------
+``LIBGCCJIT_ABI_17`` covers the addition of an API entrypoint to set the
+thread-local storage model of a variable:
+
+  * :func:`gcc_jit_lvalue_set_tls_model`
index 396259e..386b80d 100644 (file)
@@ -539,6 +539,43 @@ where the rvalue is computed by reading from the storage area.
 
    in C.
 
+.. function:: void\
+              gcc_jit_lvalue_set_tls_model (gcc_jit_lvalue *lvalue,\
+                                            enum gcc_jit_tls_model model)
+
+   Make a variable a thread-local variable.
+
+   The "model" parameter determines the thread-local storage model of the "lvalue":
+
+   .. type:: enum gcc_jit_tls_model
+
+   .. c:macro:: GCC_JIT_TLS_MODEL_NONE
+
+      Don't set the TLS model.
+
+   .. c:macro:: GCC_JIT_TLS_MODEL_GLOBAL_DYNAMIC
+
+   .. c:macro:: GCC_JIT_TLS_MODEL_LOCAL_DYNAMIC
+
+   .. c:macro:: GCC_JIT_TLS_MODEL_INITIAL_EXEC
+
+   .. c:macro:: GCC_JIT_TLS_MODEL_LOCAL_EXEC
+
+   This is analogous to:
+
+   .. code-block:: c
+
+     _Thread_local int foo __attribute__ ((tls_model("MODEL")));
+
+   in C.
+
+   This entrypoint was added in :ref:`LIBGCCJIT_ABI_17`; you can test for
+   its presence using
+
+   .. code-block:: c
+
+      #ifdef LIBGCCJIT_HAVE_gcc_jit_lvalue_set_tls_model
+
 Global variables
 ****************
 
index f670c9e..c9839c2 100644 (file)
@@ -675,6 +675,12 @@ public:
   rvalue *
   get_address (location *loc);
 
+  void
+  set_tls_model (enum tls_model tls_model)
+  {
+    set_decl_tls_model (as_tree (), tls_model);
+  }
+
 private:
   bool mark_addressable (location *loc);
 };
index 2eecf44..5ba35bd 100644 (file)
@@ -3718,6 +3718,12 @@ recording::lvalue::get_address (recording::location *loc)
   return result;
 }
 
+void
+recording::lvalue::set_tls_model (enum gcc_jit_tls_model model)
+{
+    m_tls_model = model;
+}
+
 /* The implementation of class gcc::jit::recording::param.  */
 
 /* Implementation of pure virtual hook recording::memento::replay_into
@@ -4544,6 +4550,16 @@ recording::block::dump_edges_to_dot (pretty_printer *pp)
 #  pragma GCC diagnostic pop
 #endif
 
+namespace recording {
+static const enum tls_model tls_models[] = {
+  TLS_MODEL_NONE, /* GCC_JIT_TLS_MODEL_NONE */
+  TLS_MODEL_GLOBAL_DYNAMIC, /* GCC_JIT_TLS_MODEL_GLOBAL_DYNAMIC */
+  TLS_MODEL_LOCAL_DYNAMIC, /* GCC_JIT_TLS_MODEL_LOCAL_DYNAMIC */
+  TLS_MODEL_INITIAL_EXEC, /* GCC_JIT_TLS_MODEL_INITIAL_EXEC */
+  TLS_MODEL_LOCAL_EXEC, /* GCC_JIT_TLS_MODEL_LOCAL_EXEC */
+};
+} /* namespace recording */
+
 /* The implementation of class gcc::jit::recording::global.  */
 
 /* Implementation of pure virtual hook recording::memento::replay_into
@@ -4552,8 +4568,7 @@ recording::block::dump_edges_to_dot (pretty_printer *pp)
 void
 recording::global::replay_into (replayer *r)
 {
-  set_playback_obj (
-    m_initializer
+    playback::lvalue *global = m_initializer
     ? r->new_global_initialized (playback_location (r, m_loc),
                                 m_kind,
                                 m_type->playback_type (),
@@ -4565,7 +4580,11 @@ recording::global::replay_into (replayer *r)
     : r->new_global (playback_location (r, m_loc),
                     m_kind,
                     m_type->playback_type (),
-                    playback_string (m_name)));
+                    playback_string (m_name));
+  if (m_tls_model != GCC_JIT_TLS_MODEL_NONE)
+    global->set_tls_model (recording::tls_models[m_tls_model]);
+
+  set_playback_obj (global);
 }
 
 /* Override the default implementation of
@@ -4663,6 +4682,14 @@ recording::global::write_initializer_reproducer (const char *id, reproducer &r)
 
 /* Implementation of recording::memento::write_reproducer for globals. */
 
+static const char * const tls_model_enum_strings[] = {
+  "GCC_JIT_TLS_MODEL_NONE",
+  "GCC_JIT_TLS_MODEL_GLOBAL_DYNAMIC",
+  "GCC_JIT_TLS_MODEL_LOCAL_DYNAMIC",
+  "GCC_JIT_TLS_MODEL_INITIAL_EXEC",
+  "GCC_JIT_TLS_MODEL_LOCAL_EXEC",
+};
+
 void
 recording::global::write_reproducer (reproducer &r)
 {
@@ -4680,6 +4707,12 @@ recording::global::write_reproducer (reproducer &r)
     r.get_identifier_as_type (get_type ()),
     m_name->get_debug_string ());
 
+  if (m_tls_model != GCC_JIT_TLS_MODEL_NONE)
+    r.write ("  gcc_jit_lvalue_set_tls_model (%s, /* gcc_jit_lvalue *lvalue */\n"
+            "                                %s); /* enum gcc_jit_tls_model model */\n",
+            id,
+            tls_model_enum_strings[m_tls_model]);
+
   if (m_initializer)
     switch (m_type->dereference ()->get_size ())
       {
index 3163ff6..72fa30c 100644 (file)
@@ -1132,7 +1132,8 @@ public:
   lvalue (context *ctxt,
          location *loc,
          type *type_)
-    : rvalue (ctxt, loc, type_)
+    : rvalue (ctxt, loc, type_),
+    m_tls_model (GCC_JIT_TLS_MODEL_NONE)
     {}
 
   playback::lvalue *
@@ -1154,6 +1155,10 @@ public:
   const char *access_as_rvalue (reproducer &r) OVERRIDE;
   virtual const char *access_as_lvalue (reproducer &r);
   virtual bool is_global () const { return false; }
+  void set_tls_model (enum gcc_jit_tls_model model);
+
+protected:
+  enum gcc_jit_tls_model m_tls_model;
 };
 
 class param : public lvalue
index 5d051e4..7ccb76a 100644 (file)
@@ -2220,6 +2220,24 @@ gcc_jit_lvalue_get_address (gcc_jit_lvalue *lvalue,
 /* Public entrypoint.  See description in libgccjit.h.
 
    After error-checking, the real work is done by the
+   gcc::jit::recording::lvalue::set_tls_model method in jit-recording.c.  */
+
+void
+gcc_jit_lvalue_set_tls_model (gcc_jit_lvalue *lvalue,
+                           enum gcc_jit_tls_model model)
+{
+  RETURN_IF_FAIL (lvalue, NULL, NULL, "NULL lvalue");
+  JIT_LOG_FUNC (lvalue->get_context ()->get_logger ());
+  RETURN_IF_FAIL_PRINTF1 (lvalue->is_global (), lvalue->get_context (), NULL,
+                              "lvalue \"%s\" not a global",
+                              lvalue->get_debug_string ());
+
+  lvalue->set_tls_model (model);
+}
+
+/* Public entrypoint.  See description in libgccjit.h.
+
+   After error-checking, the real work is done by the
    gcc::jit::recording::function::new_local method in jit-recording.c.  */
 
 gcc_jit_lvalue *
index a1c9436..5aa2e40 100644 (file)
@@ -739,6 +739,16 @@ enum gcc_jit_function_kind
   GCC_JIT_FUNCTION_ALWAYS_INLINE
 };
 
+/* Thread local storage model.  */
+enum gcc_jit_tls_model
+{
+  GCC_JIT_TLS_MODEL_NONE,
+  GCC_JIT_TLS_MODEL_GLOBAL_DYNAMIC,
+  GCC_JIT_TLS_MODEL_LOCAL_DYNAMIC,
+  GCC_JIT_TLS_MODEL_INITIAL_EXEC,
+  GCC_JIT_TLS_MODEL_LOCAL_EXEC,
+};
+
 /* Create a function.  */
 extern gcc_jit_function *
 gcc_jit_context_new_function (gcc_jit_context *ctxt,
@@ -1089,6 +1099,17 @@ extern gcc_jit_rvalue *
 gcc_jit_lvalue_get_address (gcc_jit_lvalue *lvalue,
                            gcc_jit_location *loc);
 
+#define LIBGCCJIT_HAVE_gcc_jit_lvalue_set_tls_model
+
+/* Set the thread-local storage model of a global variable
+
+   This API entrypoint was added in LIBGCCJIT_ABI_17; you can test for its
+   presence using
+     #ifdef LIBGCCJIT_HAVE_gcc_jit_lvalue_set_tls_model  */
+extern void
+gcc_jit_lvalue_set_tls_model (gcc_jit_lvalue *lvalue,
+                           enum gcc_jit_tls_model model);
+
 extern gcc_jit_lvalue *
 gcc_jit_function_new_local (gcc_jit_function *func,
                            gcc_jit_location *loc,
index 64e7909..98d693f 100644 (file)
@@ -226,3 +226,8 @@ LIBGCCJIT_ABI_16 {
     gcc_jit_type_is_struct;
     gcc_jit_struct_get_field_count;
 } LIBGCCJIT_ABI_15;
+
+LIBGCCJIT_ABI_17 {
+  global:
+    gcc_jit_lvalue_set_tls_model;
+} LIBGCCJIT_ABI_16;
index 5ff427c..350a30b 100644 (file)
 #undef create_code
 #undef verify_code
 
+/* test-tls.c */
+#define create_code create_code_tls
+#define verify_code verify_code_tls
+#include "test-tls.c"
+#undef create_code
+#undef verify_code
+
 /* test-hello-world.c */
 #define create_code create_code_hello_world
 #define verify_code verify_code_hello_world
@@ -466,6 +473,9 @@ const struct testcase testcases[] = {
   {"switch",
    create_code_switch,
    verify_code_switch},
+  {"tls",
+   create_code_tls,
+   verify_code_tls},
   {"types",
    create_code_types,
    verify_code_types},
diff --git a/gcc/testsuite/jit.dg/test-tls.c b/gcc/testsuite/jit.dg/test-tls.c
new file mode 100644 (file)
index 0000000..3b20182
--- /dev/null
@@ -0,0 +1,64 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  /* Let's try to inject the equivalent of:
+
+     _Thread_local int foo;
+
+     int test_using_tls()
+     {
+      foo = 42;
+      return foo;
+     }
+  */
+  gcc_jit_type *int_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+  gcc_jit_lvalue *foo =
+    gcc_jit_context_new_global (
+      ctxt, NULL, GCC_JIT_GLOBAL_EXPORTED, int_type, "foo");
+  gcc_jit_lvalue_set_tls_model (foo, GCC_JIT_TLS_MODEL_GLOBAL_DYNAMIC);
+
+  /* Build the test_fn.  */
+  gcc_jit_function *test_fn =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                 GCC_JIT_FUNCTION_EXPORTED,
+                                 int_type,
+                                 "test_using_tls",
+                                 0, NULL,
+                                 0);
+  gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
+  gcc_jit_block_add_assignment (
+    block, NULL,
+    foo,
+    gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 42));
+  gcc_jit_block_end_with_return (block,
+                                NULL,
+                                gcc_jit_lvalue_as_rvalue (foo));
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  typedef int (*fn_type) (void);
+  CHECK_NON_NULL (result);
+
+  fn_type test_using_tls =
+    (fn_type)gcc_jit_result_get_code (result, "test_using_tls");
+  CHECK_NON_NULL (test_using_tls);
+  int return_value = test_using_tls();
+  CHECK_VALUE (return_value, 42);
+
+  int *foo = (int *)gcc_jit_result_get_global (result, "foo");
+  CHECK_NON_NULL (foo);
+  CHECK_VALUE (*foo, 42);
+}