================
@@ -1070,13 +1084,20 @@ 
CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn,
       // Mark as initialized before initializing anything else. If the
       // initializers use previously-initialized thread_local vars, that's
       // probably supposed to be OK, but the standard doesn't say.
-      Builder.CreateStore(llvm::ConstantInt::get(GuardVal->getType(),1), 
Guard);
-
-      // The guard variable can't ever change again.
+      // Get the thread-local address via intrinsic.
+      if (IsTLS)
+        GuardAddr = GuardAddr.withPointer(
+            Builder.CreateThreadLocalAddress(Guard.getPointer()),
+            NotKnownNonNull);
+      Builder.CreateStore(llvm::ConstantInt::get(GuardVal->getType(), 1),
+                          GuardAddr);
+
+      // Emit invariant start for TLS guard address.
       EmitInvariantStart(
           Guard.getPointer(),
           CharUnits::fromQuantity(
-              CGM.getDataLayout().getTypeAllocSize(GuardVal->getType())));
+              CGM.getDataLayout().getTypeAllocSize(GuardVal->getType())),
+          IsTLS);
----------------
rjmccall wrote:

I feel like we just need to file a DR with WG21 on this general question.  The 
alternatives I can see:

1. Forbid TLVs in coroutines. Source-breaking.
2. Continue to eagerly initialize local TLVs in coroutines, but bind the name 
permanently to the TLV that was initialized. This means it is potentially a 
cross-thread reference after a suspension. It is the user's responsibility to 
make that not a problem. A semantics change for most (if not at all) existing 
compilers.
3. Like #2, but give references to the TLV undefined behavior if the thread has 
changed. The most compatible option, sadly.
4. Like #2, but make the program statically ill-formed if a suspension 
potentially intervenes between the initialization and a reference to the TLV. 
Source-breaking. Also a significant new implementation burden for compilers.
5. Switch local TLVs in coroutines to the same lazy-initialization model as 
global TLVs.  Every reference to the variable dynamically resolves to the TLV 
for the current thread.  Because of the model change, the variable is always 
initialized. A semantics change for most (if not all) existing compilers.
6. Like #5, but require the initializer to be a constant expression just to try 
to minimize the semantic impact.

Note that a cross-thread reference can race not just with read/write or 
write/write conflicts between threads, but also with the destruction of the 
other thread.  Because of the latter, it will be a potentially-dangling 
reference for most async-like use cases.

https://github.com/llvm/llvm-project/pull/96633
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to