]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: Drop TREE_READONLY on vars (possibly) initialized by tls wrapper [PR109164]
authorJakub Jelinek <jakub@redhat.com>
Mon, 20 Mar 2023 19:29:47 +0000 (20:29 +0100)
committerJakub Jelinek <jakub@redhat.com>
Wed, 3 May 2023 13:07:58 +0000 (15:07 +0200)
The following two testcases are miscompiled, because we keep TREE_READONLY
on the vars even when they are (possibly) dynamically initialized by a TLS
wrapper function.  Normally cp_finish_decl drops TREE_READONLY from vars
which need dynamic initialization, but for TLS we do this kind of
initialization upon every access to those variables.  Keeping them
TREE_READONLY means e.g. PRE can hoist loads from those before loops
which contain the TLS wrapper calls, so we can access the TLS variables
before they are initialized.

2023-03-20  Jakub Jelinek  <jakub@redhat.com>

PR c++/109164
* cp-tree.h (var_needs_tls_wrapper): Declare.
* decl2.c (var_needs_tls_wrapper): No longer static.
* decl.c (cp_finish_decl): Clear TREE_READONLY on TLS variables
for which a TLS wrapper will be needed.

* g++.dg/tls/thread_local13.C: New test.
* g++.dg/tls/thread_local13-aux.cc: New file.
* g++.dg/tls/thread_local14.C: New test.
* g++.dg/tls/thread_local14-aux.cc: New file.

(cherry picked from commit 0a846340b99675d57fc2f2923a0412134eed09d3)

gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/decl2.c
gcc/testsuite/g++.dg/tls/thread_local13-aux.cc [new file with mode: 0644]
gcc/testsuite/g++.dg/tls/thread_local13.C [new file with mode: 0644]
gcc/testsuite/g++.dg/tls/thread_local14-aux.cc [new file with mode: 0644]
gcc/testsuite/g++.dg/tls/thread_local14.C [new file with mode: 0644]

index 15ec4cd199f5b1a3e99f73e680effd143e6de209..36e047ad4c06bf308e1ecb416abf2747b71aba76 100644 (file)
@@ -6683,6 +6683,7 @@ extern void copy_linkage                  (tree, tree);
 extern tree get_guard                          (tree);
 extern tree get_guard_cond                     (tree, bool);
 extern tree set_guard                          (tree);
+extern bool var_needs_tls_wrapper              (tree);
 extern tree maybe_get_tls_wrapper_call         (tree);
 extern void mark_needed                                (tree);
 extern bool decl_needed_p                      (tree);
index 0eb15de734a6d0e851c589428da8cc90e981c32c..1608c0a256051eb2382e6e66f1c4d5b33e156060 100644 (file)
@@ -7941,6 +7941,18 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
          if (!decl_maybe_constant_destruction (decl, type))
            TREE_READONLY (decl) = 0;
        }
+      else if (VAR_P (decl)
+              && CP_DECL_THREAD_LOCAL_P (decl)
+              && (!DECL_EXTERNAL (decl) || flag_extern_tls_init)
+              && (was_readonly || TREE_READONLY (decl))
+              && var_needs_tls_wrapper (decl))
+       {
+         /* TLS variables need dynamic initialization by the TLS wrapper
+            function, we don't want to hoist accesses to it before the
+            wrapper.  */
+         was_readonly = 0;
+         TREE_READONLY (decl) = 0;
+       }
 
       make_rtl_for_nonlocal_decl (decl, init, asmspec);
 
index 7a4e05807e6c893941cdd6b40ac5de1e3bb99df4..577bec362ad184d11eaf0280d3830caddc9620b1 100644 (file)
@@ -3405,7 +3405,7 @@ var_defined_without_dynamic_init (tree var)
 /* Returns true iff VAR is a variable that needs uses to be
    wrapped for possible dynamic initialization.  */
 
-static bool
+bool
 var_needs_tls_wrapper (tree var)
 {
   return (!error_operand_p (var)
diff --git a/gcc/testsuite/g++.dg/tls/thread_local13-aux.cc b/gcc/testsuite/g++.dg/tls/thread_local13-aux.cc
new file mode 100644 (file)
index 0000000..691f308
--- /dev/null
@@ -0,0 +1,35 @@
+// PR c++/109164
+
+struct S { virtual void foo (); int s; };
+extern bool baz ();
+
+void
+S::foo ()
+{
+  if (s != 42)
+    __builtin_abort ();
+}
+
+S s;
+
+S &
+qux ()
+{
+  s.s = 42;
+  return s;
+}
+
+thread_local S &t = qux ();
+
+bool
+bar ()
+{
+  return false;
+}
+
+int
+main ()
+{
+  if (baz ())
+    __builtin_abort ();
+}
diff --git a/gcc/testsuite/g++.dg/tls/thread_local13.C b/gcc/testsuite/g++.dg/tls/thread_local13.C
new file mode 100644 (file)
index 0000000..b424b9f
--- /dev/null
@@ -0,0 +1,21 @@
+// PR c++/109164
+// { dg-do run { target c++11 } }
+// { dg-options "-O2" }
+// { dg-add-options tls }
+// { dg-require-effective-target tls_runtime }
+// { dg-additional-sources "thread_local13-aux.cc" }
+
+struct S { virtual void foo (); int s; };
+extern thread_local S &t;
+bool bar ();
+
+bool
+baz ()
+{
+  while (1)
+    {
+      t.foo ();
+      if (!bar ())
+        return false;
+    }
+}
diff --git a/gcc/testsuite/g++.dg/tls/thread_local14-aux.cc b/gcc/testsuite/g++.dg/tls/thread_local14-aux.cc
new file mode 100644 (file)
index 0000000..e8f2a24
--- /dev/null
@@ -0,0 +1,26 @@
+// PR c++/109164
+
+extern bool baz ();
+
+int
+qux ()
+{
+  return 42;
+}
+
+extern thread_local const int t = qux ();
+
+bool
+bar (int x)
+{
+  if (x != 42)
+    __builtin_abort ();
+  return false;
+}
+
+int
+main ()
+{
+  if (baz ())
+    __builtin_abort ();
+}
diff --git a/gcc/testsuite/g++.dg/tls/thread_local14.C b/gcc/testsuite/g++.dg/tls/thread_local14.C
new file mode 100644 (file)
index 0000000..a7402d0
--- /dev/null
@@ -0,0 +1,19 @@
+// PR c++/109164
+// { dg-do run { target c++11 } }
+// { dg-options "-O2" }
+// { dg-add-options tls }
+// { dg-require-effective-target tls_runtime }
+// { dg-additional-sources "thread_local14-aux.cc" }
+
+extern thread_local const int t;
+bool bar (int);
+
+bool
+baz ()
+{
+  while (1)
+    {
+      if (!bar (t))
+        return false;
+    }
+}