You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
67 lines
2.7 KiB
67 lines
2.7 KiB
3 years ago
|
c++: Optimize constinit thread_local vars [PR101786]
|
||
|
|
||
|
The paper that introduced constinit mentioned in rationale that constinit
|
||
|
can be used on externs as well and that it can be used to avoid the
|
||
|
thread_local initialization wrappers, because the standard requires that
|
||
|
if constinit is present on any declaration, it is also present on the
|
||
|
initialization declaration, even if it is in some other TU etc.
|
||
|
|
||
|
There is a small problem though, we use the tls wrappers not just if
|
||
|
the thread_local variable needs dynamic initialization, but also when
|
||
|
it has static initialization, but non-trivial destructor, as the
|
||
|
"dynamic initialization" in that case needs to register the destructor.
|
||
|
|
||
|
So, the following patch optimizes constinit thread_local vars only
|
||
|
if we can prove they will not have non-trivial destructors. That includes
|
||
|
the case where we have incomplete type where we don't know and need to
|
||
|
conservatively assume the type will have non-trivial destructor at the
|
||
|
initializing declaration side.
|
||
|
|
||
|
2021-08-11 Jakub Jelinek <jakub@redhat.com>
|
||
|
|
||
|
PR c++/101786
|
||
|
* decl2.c (var_defined_without_dynamic_init): Return true for
|
||
|
DECL_DECLARED_CONSTINIT_P with complete type and trivial destructor.
|
||
|
|
||
|
* g++.dg/cpp2a/constinit16.C: New test.
|
||
|
|
||
|
--- gcc/cp/decl2.c
|
||
|
+++ gcc/cp/decl2.c
|
||
|
@@ -3447,6 +3447,12 @@ set_guard (tree guard)
|
||
|
static bool
|
||
|
var_defined_without_dynamic_init (tree var)
|
||
|
{
|
||
|
+ /* constinit vars are guaranteed to not have dynamic initializer,
|
||
|
+ but still registering the destructor counts as dynamic initialization. */
|
||
|
+ if (DECL_DECLARED_CONSTINIT_P (var)
|
||
|
+ && COMPLETE_TYPE_P (TREE_TYPE (var))
|
||
|
+ && !TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (var)))
|
||
|
+ return true;
|
||
|
/* If it's defined in another TU, we can't tell. */
|
||
|
if (DECL_EXTERNAL (var))
|
||
|
return false;
|
||
|
--- gcc/testsuite/g++.dg/cpp2a/constinit16.C
|
||
|
+++ gcc/testsuite/g++.dg/cpp2a/constinit16.C
|
||
|
@@ -0,0 +1,21 @@
|
||
|
+// PR c++/101786
|
||
|
+// { dg-do compile { target c++20 } }
|
||
|
+// { dg-add-options tls }
|
||
|
+// { dg-require-alias "" }
|
||
|
+// { dg-require-effective-target tls_runtime }
|
||
|
+// { dg-final { scan-assembler-not "_ZTH17mythreadlocalvar1" } }
|
||
|
+// { dg-final { scan-assembler "_ZTH17mythreadlocalvar2" } }
|
||
|
+// { dg-final { scan-assembler-not "_ZTH17mythreadlocalvar3" } }
|
||
|
+// { dg-final { scan-assembler "_ZTH17mythreadlocalvar4" } }
|
||
|
+
|
||
|
+extern thread_local constinit int mythreadlocalvar1;
|
||
|
+struct S;
|
||
|
+extern thread_local constinit S mythreadlocalvar2;
|
||
|
+struct T { int t; };
|
||
|
+extern thread_local constinit T mythreadlocalvar3;
|
||
|
+struct U { int u; ~U (); };
|
||
|
+extern thread_local constinit U mythreadlocalvar4;
|
||
|
+int foo () { return mythreadlocalvar1; }
|
||
|
+S *bar () { return &mythreadlocalvar2; }
|
||
|
+T *baz () { return &mythreadlocalvar3; }
|
||
|
+U *qux () { return &mythreadlocalvar4; }
|