Dear David,
thank you very much for your timely response and for talking a thorough
look at my proposed patch.
Am 07.01.19 um 21:34 schrieb David Malcolm:
Have you done the legal paperwork with the FSF for contributing to GCC?
See https://gcc.gnu.org/contribute.html#legal
Not yet; this is my first patch I would like to contribute to GCC. You
should have received a private email to get the legal matters done.
ChangeLog
2019-01-05 Marc Nieper-Wißkirchen <m...@nieper-wisskirchen.de>
* docs/topics/compatibility.rst: Add LIBGCCJIT_ABI_11.
* docs/topics/expressions.rst (Global variables): Add
documentation of gcc_jit_lvalue_set_bool_thread_local.
* docs/_build/texinfo/libgccjit.texi: Regenerate.
* jit-playback.c: Include "varasm.h".
Within namespace gcc::jit::playback...
(context::new_global) Add "thread_local_p" param and use it
to set DECL_TLS_MODEL.
* jit-playback.h: Within namespace gcc::jit::playback...
(context::new_global: Add "thread_local_p" param.
* jit-recording.c: Within namespace gcc::jit::recording...
(global::replay_into): Provide m_thread_local to call to
new_global.
(global::write_reproducer): Call write_reproducer_thread_local.
(global::write_reproducer_thread_local): New method.
* jit-recording.h: Within namespace gcc::jit::recording...
(lvalue::dyn_cast_global): New virtual function.
(global::m_thread_local): New field.
* libgccjit.c (gcc_jit_lvalue_set_bool_thread_local): New
function.
* libgccjit.h
(LIBGCCJIT_HAVE_gcc_jit_lvalue_set_bool_thread_local): New
macro.
(gcc_jit_lvalue_set_bool_thread_local): New function.
* libgccjit.map (LIBGCCJIT_ABI_11): New.
(gcc_jit_lvalue_set_bool_thread_local): Add.
Testing
The result of `make check-jit' is (the failing test in
`test-sum-squares.c` is also failing without this patch on my
machine):
Native configuration is x86_64-pc-linux-gnu
[...]
FAIL: test-combination.c.exe iteration 1 of 5:
verify_code_sum_of_squares: dump_vrp1: actual: "
FAIL: test-combination.c.exe killed: 20233 exp6 0 0 CHILDKILLED
SIGABRT SIGABRT
FAIL: test-sum-of-squares.c.exe iteration 1 of 5: verify_code:
dump_vrp1: actual: "
FAIL: test-sum-of-squares.c.exe killed: 22698 exp6 0 0 CHILDKILLED
SIGABRT SIGABRT
FAIL: test-threads.c.exe: verify_code_sum_of_squares: dump_vrp1:
actual: "
FAIL: test-threads.c.exe killed: 22840 exp6 0 0 CHILDKILLED SIGABRT
SIGABRT
That one's failing for me as well. I'm investigating (I've filed it as
PR jit/88747).
I have applied your recent patch. With the patch, there are no more
failures.
Including the new test case for thread-local globals (see below), the
final output of `make check-jit' is now as follows:
Test run by mnieper on Tue Jan 8 14:18:27 2019
Native configuration is x86_64-pc-linux-gnu
=== jit tests ===
Schedule of variations:
unix
Running target unix
Using /usr/share/dejagnu/baseboards/unix.exp as board description file for
target.
Using /usr/share/dejagnu/config/unix.exp as generic interface file for target.
Using /home/mnieper/gcc/src/gcc/testsuite/config/default.exp as
tool-and-target-specific interface file.
Running /home/mnieper/gcc/src/gcc/testsuite/jit.dg/jit.exp ...
=== jit Summary ===
# of expected passes 10394
diff --git a/gcc/testsuite/jit.dg/all-non-failing-tests.h
b/gcc/testsuite/jit.dg/all-non-failing-tests.h
index bf02e1258..c2654ff09 100644
--- a/gcc/testsuite/jit.dg/all-non-failing-tests.h
+++ b/gcc/testsuite/jit.dg/all-non-failing-tests.h
@@ -224,6 +224,13 @@
#undef create_code
#undef verify_code
+/* test-factorial-must-tail-call.c */
Looks like a cut&paste error: presumably the above comment is meant to
refer to the new test...
Yep.
+#define create_code create_code_thread_local
+#define verify_code verify_code_thread_local
+#include "test-thread-local.c"
...but it looks like the new test file is missing from the patch.
My fault. I supplied the wrong arguments to `git diff'.
At the end of this email, you'll find the updated ChangeLog and the
amended patch.
Thanks again,
Marc
2019-01-08 Marc Nieper-Wißkirchen <m...@nieper-wisskirchen.de>
* docs/topics/compatibility.rst: Add LIBGCCJIT_ABI_11.
* docs/topics/expressions.rst (Global variables): Add
documentation of gcc_jit_lvalue_set_bool_thread_local.
* docs/_build/texinfo/libgccjit.texi: Regenerate.
* jit-playback.c: Include "varasm.h".
Within namespace gcc::jit::playback...
(context::new_global) Add "thread_local_p" param and use it
to set DECL_TLS_MODEL.
* jit-playback.h: Within namespace gcc::jit::playback...
(context::new_global): Add "thread_local_p" param.
* jit-recording.c: Within namespace gcc::jit::recording...
(global::replay_into): Provide m_thread_local to call to
new_global.
(global::write_reproducer): Call write_reproducer_thread_local.
(global::write_reproducer_thread_local): New method.
* jit-recording.h: Within namespace gcc::jit::recording...
(lvalue::dyn_cast_global): New virtual function.
(global::m_thread_local): New field.
* libgccjit.c (gcc_jit_lvalue_set_bool_thread_local): New
function.
* libgccjit.h
(LIBGCCJIT_HAVE_gcc_jit_lvalue_set_bool_thread_local): New
macro.
(gcc_jit_lvalue_set_bool_thread_local): New function.
* libgccjit.map (LIBGCCJIT_ABI_11): New.
(gcc_jit_lvalue_set_bool_thread_local): Add.
* ../testsuite/jit.dg/all-non-failing-tests.h: Include new test.
* ../testsuite/jit.dg/jit.exp: Load pthread for tests involving
thread-local globals.
* ../testsuite/jit.dg/test-thread-local.c: New test case for
thread-local globals.
diff --git a/gcc/jit/docs/topics/compatibility.rst
b/gcc/jit/docs/topics/compatibility.rst
index 38d338b1f..10926537d 100644
--- a/gcc/jit/docs/topics/compatibility.rst
+++ b/gcc/jit/docs/topics/compatibility.rst
@@ -171,3 +171,9 @@ entrypoints:
``LIBGCCJIT_ABI_10`` covers the addition of
:func:`gcc_jit_context_new_rvalue_from_vector`
+
+``LIBGCCJIT_ABI_11``
+--------------------
+
+``LIBGCCJIT_ABI_11`` covers the addition of
+:func:`gcc_jit_lvalue_set_bool_thread_local`
diff --git a/gcc/jit/docs/topics/expressions.rst
b/gcc/jit/docs/topics/expressions.rst
index 9dee2d87a..984d02cc8 100644
--- a/gcc/jit/docs/topics/expressions.rst
+++ b/gcc/jit/docs/topics/expressions.rst
@@ -576,6 +576,21 @@ Global variables
referring to it. Analogous to using an "extern" global from a
header file.
+.. function:: void\
+ gcc_jit_lvalue_set_bool_thread_local (gcc_jit_lvalue *global,\
+ int thread_local_p)
+
+ Given a :c:type:`gcc_jit_lvalue *` for a global created through
+ :c:func:`gcc_jit_context_new_global`, mark/clear the global as being
+ thread-local. Analogous to a global with thread storage duration in C11.
+
+ This entrypoint was added in :ref:`LIBGCCJIT_ABI_11`; you can test for
+ its presence using
+
+ .. code-block:: c
+
+ #ifdef LIBGCCJIT_HAVE_gcc_jit_lvalue_set_bool_thread_local
+
Working with pointers, structs and unions
-----------------------------------------
diff --git a/gcc/jit/jit-playback.c b/gcc/jit/jit-playback.c
index 86f588db9..6c00a98c0 100644
--- a/gcc/jit/jit-playback.c
+++ b/gcc/jit/jit-playback.c
@@ -39,6 +39,7 @@ along with GCC; see the file COPYING3. If not see
#include "opt-suggestions.h"
#include "gcc.h"
#include "diagnostic.h"
+#include "varasm.h"
#include <pthread.h>
@@ -461,7 +462,8 @@ playback::context::
new_global (location *loc,
enum gcc_jit_global_kind kind,
type *type,
- const char *name)
+ const char *name,
+ bool thread_local_p)
{
gcc_assert (type);
gcc_assert (name);
@@ -487,6 +489,8 @@ new_global (location *loc,
DECL_EXTERNAL (inner) = 1;
break;
}
+ if (thread_local_p)
+ set_decl_tls_model (inner, decl_default_tls_model (inner));
if (loc)
set_tree_location (inner, loc);
diff --git a/gcc/jit/jit-playback.h b/gcc/jit/jit-playback.h
index bc4de9c03..fc0843f58 100644
--- a/gcc/jit/jit-playback.h
+++ b/gcc/jit/jit-playback.h
@@ -103,7 +103,8 @@ public:
new_global (location *loc,
enum gcc_jit_global_kind kind,
type *type,
- const char *name);
+ const char *name,
+ bool thread_local_p);
template <typename HOST_TYPE>
rvalue *
diff --git a/gcc/jit/jit-recording.c b/gcc/jit/jit-recording.c
index 04cc6a690..75557af19 100644
--- a/gcc/jit/jit-recording.c
+++ b/gcc/jit/jit-recording.c
@@ -4280,7 +4280,8 @@ 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)));
+ playback_string (m_name),
+ m_thread_local));
}
/* Override the default implementation of
@@ -4356,6 +4357,22 @@ recording::global::write_reproducer (reproducer &r)
global_kind_reproducer_strings[m_kind],
r.get_identifier_as_type (get_type ()),
m_name->get_debug_string ());
+ write_reproducer_thread_local (r, id);
+}
+
+/* Subroutine for use by global's write_reproducer methods. */
+
+void
+recording::global::write_reproducer_thread_local (reproducer &r,
+ const char *id)
+{
+ if (m_thread_local)
+ {
+ r.write (" gcc_jit_lvalue_set_bool_thread_local (%s, /* gcc_jit_lvalue
*global*/\n"
+ " %i); /* int
thread_local_p*/\n",
+ id,
+ 1);
+ }
}
/* The implementation of the various const-handling classes:
diff --git a/gcc/jit/jit-recording.h b/gcc/jit/jit-recording.h
index b9c6544d0..6a3d32dd6 100644
--- a/gcc/jit/jit-recording.h
+++ b/gcc/jit/jit-recording.h
@@ -1054,6 +1054,8 @@ public:
return static_cast <playback::lvalue *> (m_playback_obj);
}
+ virtual global *dyn_cast_global () { return NULL; }
+
lvalue *
access_field (location *loc,
field *field);
@@ -1285,7 +1287,8 @@ public:
string *name)
: lvalue (ctxt, loc, type),
m_kind (kind),
- m_name (name)
+ m_name (name),
+ m_thread_local (false)
{}
void replay_into (replayer *) FINAL OVERRIDE;
@@ -1294,7 +1297,17 @@ public:
void write_to_dump (dump &d) FINAL OVERRIDE;
-private:
+ global *dyn_cast_global () FINAL OVERRIDE { return this; }
+
+ void set_thread_local (bool thread_local_p)
+ {
+ m_thread_local = thread_local_p;
+ }
+
+ protected:
+ void write_reproducer_thread_local (reproducer &r, const char *id);
+
+ private:
string * make_debug_string () FINAL OVERRIDE { return m_name; }
void write_reproducer (reproducer &r) FINAL OVERRIDE;
enum precedence get_precedence () const FINAL OVERRIDE
@@ -1305,6 +1318,7 @@ private:
private:
enum gcc_jit_global_kind m_kind;
string *m_name;
+ bool m_thread_local;
};
template <typename HOST_TYPE>
diff --git a/gcc/jit/libgccjit.c b/gcc/jit/libgccjit.c
index de7fb2579..2b643c63f 100644
--- a/gcc/jit/libgccjit.c
+++ b/gcc/jit/libgccjit.c
@@ -3102,3 +3102,23 @@ gcc_jit_context_new_rvalue_from_vector (gcc_jit_context
*ctxt,
as_vec_type,
(gcc::jit::recording::rvalue **)elements);
}
+
+/* Public entrypoint. See description in libgccjit.h.
+
+ After error-checking, the real work is effectively done by the
+ gcc::jit::global::set_thread_local setter in jit-recording.h. */
+
+void
+gcc_jit_lvalue_set_bool_thread_local (gcc_jit_lvalue *lvalue,
+ int thread_local_p)
+{
+ RETURN_IF_FAIL (lvalue, NULL, NULL, "NULL global");
+ JIT_LOG_FUNC (lvalue->get_context ()->get_logger ());
+
+ /* Verify that it's a global. */
+ gcc::jit::recording::global *global = lvalue->dyn_cast_global ();
+ RETURN_IF_FAIL_PRINTF1 (global, NULL, NULL, "not a global: %s",
+ lvalue->get_debug_string ());
+
+ global->set_thread_local (thread_local_p);
+}
diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h
index e872ae789..d64d05a8d 100644
--- a/gcc/jit/libgccjit.h
+++ b/gcc/jit/libgccjit.h
@@ -1450,6 +1450,18 @@ gcc_jit_context_new_rvalue_from_vector (gcc_jit_context
*ctxt,
size_t num_elements,
gcc_jit_rvalue **elements);
+#define LIBGCCJIT_HAVE_gcc_jit_lvalue_set_bool_thread_local
+
+/* Mark/clear a global as thread-local.
+
+ This API entrypoint was added in LIBGCCJIT_ABI_11; you can test for its
+ presence using
+ #ifdef LIBGCCJIT_HAVE_gcc_jit_lvalue_set_bool_thread_local
+*/
+extern void
+gcc_jit_lvalue_set_bool_thread_local (gcc_jit_lvalue *global,
+ int thread_local_p);
+
#ifdef __cplusplus
}
#endif /* __cplusplus */
diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map
index 2826f1ca6..741320bbe 100644
--- a/gcc/jit/libgccjit.map
+++ b/gcc/jit/libgccjit.map
@@ -170,3 +170,8 @@ LIBGCCJIT_ABI_10 {
global:
gcc_jit_context_new_rvalue_from_vector;
} LIBGCCJIT_ABI_9;
+
+LIBGCCJIT_ABI_11 {
+ global:
+ gcc_jit_lvalue_set_bool_thread_local;
+} LIBGCCJIT_ABI_10;
diff --git a/gcc/testsuite/jit.dg/all-non-failing-tests.h
b/gcc/testsuite/jit.dg/all-non-failing-tests.h
index bf02e1258..c91687182 100644
--- a/gcc/testsuite/jit.dg/all-non-failing-tests.h
+++ b/gcc/testsuite/jit.dg/all-non-failing-tests.h
@@ -224,6 +224,13 @@
#undef create_code
#undef verify_code
+/* test-thread-local.c */
+#define create_code create_code_thread_local
+#define verify_code verify_code_thread_local
+#include "test-thread-local.c"
+#undef create_code
+#undef verify_code
+
/* test-types.c */
#define create_code create_code_types
#define verify_code verify_code_types
@@ -353,6 +360,9 @@ const struct testcase testcases[] = {
{"switch",
create_code_switch,
verify_code_switch},
+ {"thread_local",
+ create_code_thread_local,
+ verify_code_thread_local},
{"types",
create_code_types,
verify_code_types},
diff --git a/gcc/testsuite/jit.dg/jit.exp b/gcc/testsuite/jit.dg/jit.exp
index 869d9f693..3be4f2c18 100644
--- a/gcc/testsuite/jit.dg/jit.exp
+++ b/gcc/testsuite/jit.dg/jit.exp
@@ -379,6 +379,16 @@ proc jit-dg-test { prog do_what extra_tool_flags } {
append extra_tool_flags " -lpthread"
}
+ # test-thread-local.c needs to be linked against pthreads
+ if {[string match "*test-thread-local.c" $prog]} {
+ append extra_tool_flags " -lpthread"
+ }
+
+ # test-combination.c needs to be linked against pthreads
+ if {[string match "*test-combination.c" $prog]} {
+ append extra_tool_flags " -lpthread"
+ }
+
# Any test case that uses jit-verify-output-file-was-created
# needs to call jit-setup-compile-to-file here.
# (is there a better way to handle setup/finish pairs in dg?)
diff --git a/gcc/testsuite/jit.dg/test-thread-local.c
b/gcc/testsuite/jit.dg/test-thread-local.c
new file mode 100644
index 000000000..287ba85e4
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-thread-local.c
@@ -0,0 +1,99 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <pthread.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:
+
+ static thread_local int tl;
+ set_tl (int v)
+ {
+ tl = v;
+ }
+
+ int
+ get_tl (void)
+ {
+ return tl;
+ }
+
+ */
+ gcc_jit_type *the_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+ gcc_jit_type *void_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+
+ gcc_jit_lvalue *tl =
+ gcc_jit_context_new_global (ctxt, NULL, GCC_JIT_GLOBAL_INTERNAL,
+ the_type, "tl");
+ gcc_jit_lvalue_set_bool_thread_local (tl, 1);
+
+ gcc_jit_param *v =
+ gcc_jit_context_new_param (ctxt, NULL, the_type, "v");
+ gcc_jit_param *params[1] = {v};
+ gcc_jit_function *func =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ void_type,
+ "set_tl",
+ 1, params, 0);
+ gcc_jit_block *block =
+ gcc_jit_function_new_block (func, "initial");
+ gcc_jit_block_add_assignment (block, NULL, tl,
+ gcc_jit_param_as_rvalue (v));
+ gcc_jit_block_end_with_void_return (block, NULL);
+
+ func =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ the_type,
+ "get_tl",
+ 0, NULL, 0);
+ block =
+ gcc_jit_function_new_block (func, "initial");
+ gcc_jit_block_end_with_return (block, NULL,
+ gcc_jit_lvalue_as_rvalue (tl));
+}
+
+static void *
+test_thread_local_run (void *arg)
+{
+ void (*set_tl) (int) = arg;
+ set_tl (43);
+ return NULL;
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ typedef void (*set_tl_fn_type) (int);
+ typedef int (*get_tl_fn_type) (void);
+
+ CHECK_NON_NULL (result);
+
+ set_tl_fn_type set_tl =
+ (set_tl_fn_type) gcc_jit_result_get_code (result, "set_tl");
+ get_tl_fn_type get_tl =
+ (get_tl_fn_type) gcc_jit_result_get_code (result, "get_tl");
+
+ CHECK_NON_NULL (set_tl);
+ CHECK_NON_NULL (get_tl);
+
+ set_tl (42);
+
+ pthread_t thread;
+ CHECK_VALUE (pthread_create(&thread, NULL, test_thread_local_run, set_tl),
0);
+ CHECK_VALUE (pthread_join(thread, NULL), 0);
+
+ int val = get_tl ();
+
+ note ("get_tl returned: %d", val);
+ CHECK_VALUE (val, 42);
+}