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.
66 lines
2.7 KiB
66 lines
2.7 KiB
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; }
|
|
|