[clang] [Clang] Access tls_guard via llvm.threadlocal.address (PR #96633)

John McCall via cfe-commits cfe-commits at lists.llvm.org
Fri Jul 5 16:02:22 PDT 2024


================
@@ -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:

That's exactly backwards — it is semantically incorrect to access different guard variables at different points during the initialization; that does not correctly implement the guard pattern.  Fortunately, I've been able to verify that it doesn't matter, because [expr.await]p3 says:

> An *await-expression* shall not appear in the initializer of a block variable with static or thread storage duration.

Therefore, it is fine to just do a single use of `threadlocal.address`, and it's preferable because it's less code and likely easier to optimize.

(Unfortunately, this restriction doesn't completely eliminate the coherence problems with coroutines and `thread_local`.  In particular, a coroutine that declares a `thread_local` local variable can observe it in an uninitialized state if the thread has changed since the initialization, and I don't see anything in the standard that addresses this.)

https://github.com/llvm/llvm-project/pull/96633


More information about the cfe-commits mailing list