https://github.com/erichkeane updated 
https://github.com/llvm/llvm-project/pull/196332

>From b2a06eb13310470affc0717ee885f20548f3cb49 Mon Sep 17 00:00:00 2001
From: erichkeane <[email protected]>
Date: Thu, 7 May 2026 06:53:31 -0700
Subject: [PATCH 1/2] [CIR] Implement Namespace/global TLS CIR CodeGen

Unlike local TLS, global TLS functions need to be initialized upon their
first use in a thread.

First, all attempts to 'get' said TLS global are replaced with calls to
a 'wrapper' function, which calls an 'init' alias function, then returns the
global.  While classic codegen manages to omit this in simple cases
sometimes, this CIR implementation doesn't attempt to do such constant
folding/inlining. The call to the 'init' is omitted if there is no
ctor/dtor setup required, so sometimes the wrapper is just a 'no-op'
(intentionally!).

There are also two types of 'global' TLS functions: unordered, and
ordered.  Unordered are typically variable templates, and their 'init'
function initializes JUST them.  The rest are ordered, which requires
all ordered initializations to happen as soon as any happen.

The Wrapper:
If necessary (omitted in a few places), calls the 'init' alias, then
returns the global.

Global Init Function (__tls_init):
For ordered global TLS, a use of 1 TLS is required to initialize ALL
of them. This function checks the global guard (__tls_guard), and calls
the individual 'init' functions for each global(__cxx_global_var_init).
Unordered ones do not get entered here.

Individual init Functions (__cxx_global_var_init):
Like the rest of our globals, these emit a __cxx_global_var_init
function. However, they are not added to the global constructors list.
These are identically emitted with one exception: Unordered Global TLS
variables wrap said init in a guard check (ordered have their's guarded
by __tls_guard in __tls_init).

Init Alias:
This alias is called by the wrapper function to make sure said variable
is initialized before use.  IN the case of ordered globals, this is an
alias to __tls_init.  IN the case of unordered globals, this goes
directly to the __cxx_global_var_init for that variable.

This patch implements the codegen part of the above by introducing a set
of 3 strings on a GlobalOp in an attribute.  if present, this will cause
the above global tls behavior (with the next patch).  At the moment,
this only generates the attribute, and the lowering-prepare patches will
come in future patches.
---
 .../include/clang/CIR/Dialect/IR/CIRAttrs.td  | 59 +++++++++++++++++
 clang/include/clang/CIR/Dialect/IR/CIROps.td  |  2 +
 clang/lib/CIR/CodeGen/CIRGenCXX.cpp           |  5 +-
 clang/lib/CIR/CodeGen/CIRGenDeclCXX.cpp       | 39 +++++++++++
 clang/lib/CIR/CodeGen/CIRGenExpr.cpp          |  7 +-
 clang/lib/CIR/CodeGen/CIRGenModule.cpp        | 15 +++--
 clang/lib/CIR/CodeGen/CIRGenModule.h          |  1 +
 clang/lib/CIR/Dialect/IR/CIRDialect.cpp       | 15 +++--
 .../test/CIR/CodeGen/global-tls-dyn-init.cpp  | 50 ++++++++++++++
 .../CIR/CodeGen/global-tls-simple-init.cpp    | 65 +++++++++++++++++++
 .../test/CIR/CodeGen/global-tls-templates.cpp | 34 ++++++++++
 clang/test/CIR/IR/invalid-tls.cir             | 18 +++++
 12 files changed, 294 insertions(+), 16 deletions(-)
 create mode 100644 clang/test/CIR/CodeGen/global-tls-dyn-init.cpp
 create mode 100644 clang/test/CIR/CodeGen/global-tls-simple-init.cpp
 create mode 100644 clang/test/CIR/CodeGen/global-tls-templates.cpp

diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td 
b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
index 1520999e3f85f..cb07d87c25e98 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
@@ -1530,6 +1530,65 @@ def CIR_StaticLocalGuardAttr : 
CIR_Attr<"StaticLocalGuard",
   let canHaveIllegalCXXABIType = 0;
 }
 
+//===----------------------------------------------------------------------===//
+// ThreadLocalGlobalWrapperInitAttr
+//===----------------------------------------------------------------------===//
+
+def CIR_ThreadLocalGlobalWrapperInitAttr : CIR_Attr<
+    "ThreadLocalGlobalWrapperInit", "tls_wrapper_init"> {
+    let summary = "Wrapper and Init function names for thread local variables";
+    let description = [{
+      Contains the mangled name of the wrapper function, init function, and
+      guard variable for a namespace/global scope thread local variable. The
+      guard variable is optional, as it is only required for unordered thread
+      local variables, as ordered thread local variables share a guard.
+
+      Unordered global thread local variables (such as variable template
+      instantiations) are individually initialized when first used on a thread.
+      Ordered global thread local variables are ALL initialized together when
+      any that require initialization are referenced.
+
+      This is accomplished by rewriting all calls to these variables as calls 
to
+      the wrapper.  If the variable requires initialization, the wrapper calls
+      the init function, then returns the global variable reference.
+
+      Throughout CIR though, these are just represented as normal `get_global`
+      calls to `global`s with `ctor`/`dtor` regions (if necessary).  The
+      lowering-prepare pass manages the generation of the wrapper,x
+      initialization, and call rewrites.
+
+      Example:
+      ```
+      cir.global tls_dyn tls_wrapper_init<"_ZTW7tls_var", "_ZTH7tls_var"> 
@_ZZZ7tls_var = ...
+      ...
+      cir.get_global thread_local @ZZZ7tls_var : !cir.ptr<!s32i>
+      ```
+    }];
+    let parameters = (ins
+        "mlir::StringAttr" : $wrapper_name,
+        "mlir::StringAttr" : $init_name,
+        OptionalParameter<"mlir::StringAttr">: $guard_name
+        );
+
+    let builders = [
+      AttrBuilder<(ins "llvm::StringRef"
+                   : $wrapper, "llvm::StringRef"
+                   : $init, "llvm::StringRef"
+                   : $guard),
+                  [{
+                    mlir::StringAttr guardAttr;
+                    if (!guard.empty())
+                      guardAttr = mlir::StringAttr::get($_ctxt, guard);
+                    return $_get($_ctxt, mlir::StringAttr::get($_ctxt, 
wrapper),
+                                 mlir::StringAttr::get($_ctxt, init),
+                                 guardAttr);
+                  }]>,
+    ];
+    let assemblyFormat =
+        "`<` $wrapper_name `,` $init_name (`,` $guard_name^)? `>`";
+    let canHaveIllegalCXXABIType = 0;
+}
+
 
//===----------------------------------------------------------------------===//
 // UsualDeleteParamsAttr
 
//===----------------------------------------------------------------------===//
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td 
b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 46ea526eb6021..25c46c27e50b2 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -2863,6 +2863,7 @@ def CIR_GlobalOp : CIR_Op<"global", [
                        CIR_GlobalLinkageKind:$linkage,
                        OptionalAttr<MemorySpaceAttrInterface>:$addr_space,
                        OptionalAttr<CIR_TLSModel>:$tls_model,
+                       
OptionalAttr<CIR_ThreadLocalGlobalWrapperInitAttr>:$dyn_tls_refs,
                        OptionalAttr<AnyAttr>:$initial_value,
                        UnitProp:$comdat,
                        UnitProp:$constant,
@@ -2884,6 +2885,7 @@ def CIR_GlobalOp : CIR_Op<"global", [
     $linkage
     (`comdat` $comdat^)?
     ($tls_model^)?
+    (`dyn_tls_refs` `` $dyn_tls_refs^)?
     (`dso_local` $dso_local^)?
     (`static_local_guard` `` $static_local_guard^)?
     (` ` custom<GlobalAddressSpaceValue>($addr_space)^ )?
diff --git a/clang/lib/CIR/CodeGen/CIRGenCXX.cpp 
b/clang/lib/CIR/CodeGen/CIRGenCXX.cpp
index b12307b124777..d1a9110125af7 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCXX.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenCXX.cpp
@@ -295,7 +295,7 @@ void CIRGenModule::emitCXXSpecialVarDeclInit(const VarDecl 
*varDecl,
                                      builder.getInsertionBlock()};
   scope.setAsGlobalInit();
   builder.setInsertionPointToStart(block);
-  mlir::Value getGlobal = builder.createGetGlobal(addr);
+  mlir::Value getGlobal = builder.createGetGlobal(addr, varDecl->getTLSKind());
   // If we're initializing a static local with a guard variable, set the flag
   // that indicates that.
   getGlobal.getDefiningOp<cir::GetGlobalOp>().setStaticLocal(
@@ -328,8 +328,7 @@ void CIRGenModule::emitCXXSpecialVarDeclInit(const VarDecl 
*varDecl,
 void CIRGenModule::emitCXXGlobalVarDeclInit(const VarDecl *varDecl,
                                             cir::GlobalOp addr,
                                             bool performInit) {
-  assert(!varDecl->isStaticLocal() &&
-         varDecl->getTLSKind() == VarDecl::TLS_None);
+  assert(!varDecl->isStaticLocal());
 
   // Create a CIRGenFunction to emit the initializer. While this isn't a true
   // function, the handling works the same way.
diff --git a/clang/lib/CIR/CodeGen/CIRGenDeclCXX.cpp 
b/clang/lib/CIR/CodeGen/CIRGenDeclCXX.cpp
index 955f3f4815a06..03929e50f44f9 100644
--- a/clang/lib/CIR/CodeGen/CIRGenDeclCXX.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenDeclCXX.cpp
@@ -59,6 +59,45 @@ void CIRGenFunction::emitCXXGuardedInit(const VarDecl 
&varDecl,
   cgm.emitCXXStaticLocalVarDeclInit(&varDecl, globalOp, performInit);
 }
 
+void CIRGenModule::setGlobalTlsReferences(const VarDecl &vd,
+                                          cir::GlobalOp globalOp) {
+  assert(!vd.isStaticLocal() && vd.getTLSKind());
+
+  // C doesn't need guarded thread-local init, because it can't have
+  // non-constant init.
+  if (!getLangOpts().CPlusPlus)
+    return;
+
+  if (globalOp.getTlsModel() != cir::TLS_Model::GeneralDynamic)
+    return;
+
+  llvm::SmallString<256> wrapperFuncName;
+  llvm::SmallString<256> initFuncName;
+  llvm::SmallString<256> guardName;
+
+  if (getCXXABI().getMangleContext().getKind() == MangleContext::MK_Itanium) {
+    llvm::raw_svector_ostream wrapperOut(wrapperFuncName);
+    llvm::raw_svector_ostream initOut(initFuncName);
+    llvm::raw_svector_ostream guardStream(guardName);
+
+    auto &mc = cast<ItaniumMangleContext>(getCXXABI().getMangleContext());
+    mc.mangleItaniumThreadLocalWrapper(&vd, wrapperOut);
+    mc.mangleItaniumThreadLocalInit(&vd, initOut);
+    if (globalOp.hasWeakLinkage() || globalOp.hasLinkOnceLinkage() ||
+        isTemplateInstantiation(vd.getTemplateSpecializationKind())) {
+      getCXXABI().getMangleContext().mangleStaticGuardVariable(&vd,
+                                                               guardStream);
+    }
+
+  } else {
+    errorNYI(vd.getSourceRange(),
+             "setGlobalTlsReferences: non-itanium mangler");
+    return;
+  }
+  globalOp.setDynTlsRefsAttr(cir::ThreadLocalGlobalWrapperInitAttr::get(
+      &getMLIRContext(), wrapperFuncName, initFuncName, guardName));
+}
+
 void CIRGenModule::emitCXXGlobalVarDeclInitFunc(const VarDecl *vd,
                                                 cir::GlobalOp addr,
                                                 bool performInit) {
diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp 
b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
index cb53430438219..b8cfb74fc81e4 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
@@ -425,10 +425,9 @@ static LValue emitGlobalVarDeclLValue(CIRGenFunction &cgf, 
const Expr *e,
                                       const VarDecl *vd) {
   QualType t = e->getType();
 
-  // If it's thread_local, emit a call to its wrapper function instead.
-  if (vd->getTLSKind() == VarDecl::TLS_Dynamic)
-    cgf.cgm.errorNYI(e->getSourceRange(),
-                     "emitGlobalVarDeclLValue: thread_local variable");
+  // In classic codegen, thread-locals get a wrapper function here. Rather than
+  // doing that, we instead treat this as a normal 'global', and leave it to
+  // lowerng-prepare to correctly generate the wrapper/etc.
 
   // Check if the variable is marked as declare target with link clause in
   // device codegen.
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp 
b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
index 0c03375e0d79c..380fc61740c5a 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
@@ -1152,11 +1152,8 @@ CIRGenModule::getOrCreateCIRGlobal(StringRef 
mangledName, mlir::Type ty,
 
     setLinkageForGV(gv, d);
 
-    if (d->getTLSKind()) {
-      if (d->getTLSKind() == VarDecl::TLS_Dynamic)
-        errorNYI(d->getSourceRange(), "getOrCreateCIRGlobal: TLS dynamic");
+    if (d->getTLSKind())
       setTLSMode(gv, *d);
-    }
 
     setGVProperties(gv, d);
 
@@ -1500,7 +1497,8 @@ void CIRGenModule::emitGlobalVarDefinition(const 
clang::VarDecl *vd,
 
   setNonAliasAttributes(vd, gv);
 
-  assert(!cir::MissingFeatures::opGlobalThreadLocal());
+  if (vd->getTLSKind() && !vd->isStaticLocal())
+    setTLSMode(gv, *vd);
 
   maybeSetTrivialComdat(*vd, gv);
 
@@ -2766,6 +2764,13 @@ void CIRGenModule::setTLSMode(mlir::Operation *op, const 
VarDecl &d) {
 
   auto global = cast<cir::GlobalOp>(op);
   global.setTlsModel(tlm);
+
+  // For namespace-scope dyanmic TLS we need to set the wrapper, int, or guard
+  // info.
+  if (d.isStaticLocal() || tlm != cir::TLS_Model::GeneralDynamic)
+    return;
+
+  setGlobalTlsReferences(d, global);
 }
 
 void CIRGenModule::setCIRFunctionAttributes(GlobalDecl globalDecl,
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.h 
b/clang/lib/CIR/CodeGen/CIRGenModule.h
index 2869411015bc5..e7196b4ad7df4 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.h
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.h
@@ -645,6 +645,7 @@ class CIRGenModule : public CIRGenTypeCache {
   void emitCXXGlobalVarDeclInit(const VarDecl *varDecl, cir::GlobalOp addr,
                                 bool performInit);
 
+  void setGlobalTlsReferences(const VarDecl &vd, cir::GlobalOp globalOp);
   void emitCXXGlobalVarDeclInitFunc(const VarDecl *vd, cir::GlobalOp addr,
                                     bool performInit);
 
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp 
b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index 22aaa8602450c..25bbe8c048a5d 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -1903,12 +1903,19 @@ mlir::LogicalResult cir::GlobalOp::verify() {
       return failure();
   }
 
-  if ((getStaticLocalGuard().has_value() || getTlsModel()) &&
+  if ((getStaticLocalGuard().has_value()) &&
       (!getCtorRegion().empty() || !getDtorRegion().empty()))
     return emitOpError(
-        "Cannot have a thread-local or static-local global-op "
-        "with a constructor or destructor, they require in-function "
-        "initialization via LocalInitOp");
+        "Cannot have a static-local global-op with a constructor or "
+        "destructor, they require in-function initialization via LocalInitOp");
+
+  if (getDynTlsRefs()) {
+    if (getStaticLocalGuard().has_value())
+      return emitOpError(
+          "cannot have both static local and dynamic tls references");
+    if (!getTlsModel() || getTlsModel() != TLS_Model::GeneralDynamic)
+      return emitOpError("'dyn_tls_refs' only valid for dynamic tls");
+  }
 
   // TODO(CIR): Many other checks for properties that haven't been upstreamed
   // yet.
diff --git a/clang/test/CIR/CodeGen/global-tls-dyn-init.cpp 
b/clang/test/CIR/CodeGen/global-tls-dyn-init.cpp
new file mode 100644
index 0000000000000..b7551c2b4a342
--- /dev/null
+++ b/clang/test/CIR/CodeGen/global-tls-dyn-init.cpp
@@ -0,0 +1,50 @@
+// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -fclangir 
-emit-cir -mmlir --mlir-print-ir-before=cir-lowering-prepare %s -o %t.cir 2>&1 
| FileCheck %s --check-prefix=CIR-BEFORE-LPP
+
+int get_i();
+struct CtorDtor {
+  constexpr CtorDtor(int i) : i(i){}
+  ~CtorDtor(){}
+    int i;
+};
+
+thread_local CtorDtor tls_cd = 5;
+// CIR-BEFORE-LPP: cir.global external tls_dyn dyn_tls_refs<"_ZTW6tls_cd", 
"_ZTH6tls_cd"> @tls_cd = #cir.const_record<{#cir.int<5> : !s32i}> : 
!rec_CtorDtor dtor {
+// CIR-BEFORE-LPP:   %[[GET_GLOB:.*]] = cir.get_global thread_local @tls_cd : 
!cir.ptr<!rec_CtorDtor>
+// CIR-BEFORE-LPP:   cir.call @_ZN8CtorDtorD1Ev(%[[GET_GLOB]]) : 
(!cir.ptr<!rec_CtorDtor>) -> ()
+// CIR-BEFORE-LPP: }
+
+thread_local CtorDtor tls_cd_dyn = get_i();
+// CIR-BEFORE-LPP:  cir.global external tls_dyn 
dyn_tls_refs<"_ZTW10tls_cd_dyn", "_ZTH10tls_cd_dyn"> @tls_cd_dyn = ctor : 
!rec_CtorDtor {
+// CIR-BEFORE-LPP:    %[[GET_GLOB:.*]] = cir.get_global thread_local 
@tls_cd_dyn : !cir.ptr<!rec_CtorDtor>
+// CIR-BEFORE-LPP:    %[[CALL:.*]] = cir.call @_Z5get_iv() : () -> (!s32i 
{llvm.noundef})
+// CIR-BEFORE-LPP:    cir.call @_ZN8CtorDtorC1Ei(%[[GET_GLOB]], %[[CALL]]) : 
(!cir.ptr<!rec_CtorDtor>
+// CIR-BEFORE-LPP:  } dtor {
+// CIR-BEFORE-LPP:    %[[GET_GLOB:.*]] = cir.get_global thread_local 
@tls_cd_dyn : !cir.ptr<!rec_CtorDtor>
+// CIR-BEFORE-LPP:    cir.call @_ZN8CtorDtorD1Ev(%[[GET_GLOB]]) : 
(!cir.ptr<!rec_CtorDtor>) -> ()
+// CIR-BEFORE-LPP:  }
+
+thread_local CtorDtor &tls_cd_ref = tls_cd_dyn;
+// CIR-BEFORE-LPP: cir.global external tls_dyn 
dyn_tls_refs<"_ZTW10tls_cd_ref", "_ZTH10tls_cd_ref"> @tls_cd_ref = ctor : 
!cir.ptr<!rec_CtorDtor> {
+// CIR-BEFORE-LPP:   %[[GET_GLOB:.*]] = cir.get_global thread_local 
@tls_cd_ref : !cir.ptr<!cir.ptr<!rec_CtorDtor>>
+// CIR-BEFORE-LPP:   %[[CALL:.*]] = cir.get_global thread_local @tls_cd_dyn : 
!cir.ptr<!rec_CtorDtor>
+// CIR-BEFORE-LPP:   cir.store {{.*}}%[[CALL]], %[[GET_GLOB]] : 
!cir.ptr<!rec_CtorDtor>, !cir.ptr<!cir.ptr<!rec_CtorDtor>>
+// CIR-BEFORE-LPP: }
+
+thread_local CtorDtor tls_cd_dyn_not_used = get_i();
+// CIR-BEFORE-LPP: cir.global external tls_dyn 
dyn_tls_refs<"_ZTW19tls_cd_dyn_not_used", "_ZTH19tls_cd_dyn_not_used"> 
@tls_cd_dyn_not_used = ctor : !rec_CtorDtor {
+// CIR-BEFORE-LPP:   %[[GET_GLOB:.*]] = cir.get_global thread_local 
@tls_cd_dyn_not_used : !cir.ptr<!rec_CtorDtor>
+// CIR-BEFORE-LPP:   %[[CALL:.*]] = cir.call @_Z5get_iv() : () -> (!s32i 
{llvm.noundef})
+// CIR-BEFORE-LPP:   cir.call @_ZN8CtorDtorC1Ei(%[[GET_GLOB]], %[[CALL]])
+// CIR-BEFORE-LPP: } dtor {
+// CIR-BEFORE-LPP:   %[[GET_GLOB:.*]] = cir.get_global thread_local 
@tls_cd_dyn_not_used : !cir.ptr<!rec_CtorDtor>
+// CIR-BEFORE-LPP:   cir.call @_ZN8CtorDtorD1Ev(%[[GET_GLOB]]) : 
(!cir.ptr<!rec_CtorDtor>) -> ()
+// CIR-BEFORE-LPP: }
+
+void uses() {
+  auto a = tls_cd;
+// CIR-BEFORE-LPP: cir.get_global thread_local @tls_cd : 
!cir.ptr<!rec_CtorDtor>
+  auto b = tls_cd_dyn;
+// CIR-BEFORE-LPP: cir.get_global thread_local @tls_cd_dyn : 
!cir.ptr<!rec_CtorDtor>
+  auto c = tls_cd_ref;
+// CIR-BEFORE-LPP: cir.get_global thread_local @tls_cd_ref : 
!cir.ptr<!cir.ptr<!rec_CtorDtor>>
+}
diff --git a/clang/test/CIR/CodeGen/global-tls-simple-init.cpp 
b/clang/test/CIR/CodeGen/global-tls-simple-init.cpp
new file mode 100644
index 0000000000000..041858de2a4df
--- /dev/null
+++ b/clang/test/CIR/CodeGen/global-tls-simple-init.cpp
@@ -0,0 +1,65 @@
+// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -fclangir 
-emit-cir -mmlir --mlir-print-ir-before=cir-lowering-prepare %s -o %t.cir 2>&1 
| FileCheck %s --check-prefix=CIR-BEFORE-LPP
+
+int get_i();
+struct CtorDtor {
+  constexpr CtorDtor(int i) : i(i){}
+  ~CtorDtor(){}
+    int i;
+};
+
+thread_local int tls_int = 5;
+// CIR-BEFORE-LPP: cir.global external tls_dyn dyn_tls_refs<"_ZTW7tls_int", 
"_ZTH7tls_int"> @tls_int = #cir.int<5> : !s32i
+
+thread_local int tls_int_dyn = get_i();
+// CIR-BEFORE-LPP: cir.global external tls_dyn 
dyn_tls_refs<"_ZTW11tls_int_dyn", "_ZTH11tls_int_dyn"> @tls_int_dyn = ctor : 
!s32i {
+// CIR-BEFORE-LPP:   %[[GET_GLOB:.*]] = cir.get_global thread_local 
@tls_int_dyn : !cir.ptr<!s32i>
+// CIR-BEFORE-LPP:   %[[CALL:.*]] = cir.call @_Z5get_iv() : () -> (!s32i 
{llvm.noundef})
+// CIR-BEFORE-LPP:   cir.store {{.*}}%[[CALL]], %[[GET_GLOB]] : !s32i, 
!cir.ptr<!s32i>
+// CIR-BEFORE-LPP: }
+
+thread_local int &tls_int_ref = tls_int_dyn;
+// CIR-BEFORE-LPP: cir.global external tls_dyn 
dyn_tls_refs<"_ZTW11tls_int_ref", "_ZTH11tls_int_ref"> @tls_int_ref = ctor : 
!cir.ptr<!s32i> {
+// CIR-BEFORE-LPP:   %[[GET_GLOB:.*]] = cir.get_global thread_local 
@tls_int_ref : !cir.ptr<!cir.ptr<!s32i>>
+// CIR-BEFORE-LPP:   %[[GET_OTHER:.*]] = cir.get_global thread_local 
@tls_int_dyn : !cir.ptr<!s32i>
+// CIR-BEFORE-LPP:   cir.store {{.*}}%[[GET_OTHER]], %[[GET_GLOB]] : 
!cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>>
+// CIR-BEFORE-LPP: }
+
+thread_local int tls_int_self_init = tls_int_self_init + get_i();
+// CIR-BEFORE-LPP:  cir.global external tls_dyn 
dyn_tls_refs<"_ZTW17tls_int_self_init", "_ZTH17tls_int_self_init"> 
@tls_int_self_init = ctor : !s32i {
+// CIR-BEFORE-LPP:    %[[GET_GLOB:.*]] = cir.get_global thread_local 
@tls_int_self_init : !cir.ptr<!s32i>
+// CIR-BEFORE-LPP:    %[[GET_SELF:.*]] = cir.get_global thread_local 
@tls_int_self_init : !cir.ptr<!s32i>
+// CIR-BEFORE-LPP:    %[[LOAD_SELF:.*]] = cir.load {{.*}}%[[GET_SELF]] : 
!cir.ptr<!s32i>, !s32i
+// CIR-BEFORE-LPP:    %[[CALL:.*]] = cir.call @_Z5get_iv() : () -> (!s32i 
{llvm.noundef})
+// CIR-BEFORE-LPP:    %[[ADD:.*]] = cir.add nsw %[[LOAD_SELF]], %[[CALL]] : 
!s32i
+// CIR-BEFORE-LPP:    cir.store {{.*}}%[[ADD]], %[[GET_GLOB]] : !s32i, 
!cir.ptr<!s32i>
+// CIR-BEFORE-LPP:  }
+
+extern thread_local int definitely_inited = 5;
+// CIR-BEFORE-LPP: cir.global external tls_dyn 
dyn_tls_refs<"_ZTW17definitely_inited", "_ZTH17definitely_inited"> 
@definitely_inited = #cir.int<5> : !s32i
+
+extern thread_local int definitely_inited_dyn = get_i();
+// CIR-BEFORE-LPP: cir.global external tls_dyn 
dyn_tls_refs<"_ZTW21definitely_inited_dyn", "_ZTH21definitely_inited_dyn"> 
@definitely_inited_dyn = ctor : !s32i {
+// CIR-BEFORE-LPP:   %[[GET_GLOB:.*]] = cir.get_global thread_local 
@definitely_inited_dyn : !cir.ptr<!s32i>
+// CIR-BEFORE-LPP:   %[[CALL:.*]] = cir.call @_Z5get_iv() : () -> (!s32i 
{llvm.noundef})
+// CIR-BEFORE-LPP:   cir.store {{.*}}%[[CALL]], %[[GET_GLOB]] : !s32i, 
!cir.ptr<!s32i>
+// CIR-BEFORE-LPP: }
+
+extern thread_local int maybe_inited;
+// CIR-BEFORE-LPP: cir.global "private" external tls_dyn 
dyn_tls_refs<"_ZTW12maybe_inited", "_ZTH12maybe_inited"> @maybe_inited : !s32i
+
+void uses() {
+  auto a = tls_int;
+// CIR-BEFORE-LPP: cir.get_global thread_local @tls_int : !cir.ptr<!s32i>
+  auto b = tls_int_dyn;
+// CIR-BEFORE-LPP: cir.get_global thread_local @tls_int_dyn : !cir.ptr<!s32i>
+  auto c = tls_int_ref;
+// CIR-BEFORE-LPP: cir.get_global thread_local @tls_int_ref : 
!cir.ptr<!cir.ptr<!s32i>>
+  auto d = tls_int_self_init;
+// CIR-BEFORE-LPP: cir.get_global thread_local @tls_int_self_init : 
!cir.ptr<!s32i>
+  auto e = maybe_inited;
+// CIR-BEFORE-LPP: cir.get_global thread_local @maybe_inited : !cir.ptr<!s32i>
+  auto f = definitely_inited;
+// CIR-BEFORE-LPP: cir.get_global thread_local @definitely_inited : 
!cir.ptr<!s32i>
+  auto g = definitely_inited_dyn;
+// CIR-BEFORE-LPP: cir.get_global thread_local @definitely_inited_dyn : 
!cir.ptr<!s32i>
+}
diff --git a/clang/test/CIR/CodeGen/global-tls-templates.cpp 
b/clang/test/CIR/CodeGen/global-tls-templates.cpp
new file mode 100644
index 0000000000000..7ce604028ef0a
--- /dev/null
+++ b/clang/test/CIR/CodeGen/global-tls-templates.cpp
@@ -0,0 +1,34 @@
+// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -fclangir 
-emit-cir -mmlir --mlir-print-ir-before=cir-lowering-prepare %s -o %t.cir 2>&1 
| FileCheck %s --check-prefix=CIR-BEFORE-LPP
+
+int get_i();
+struct CtorDtor {
+  constexpr CtorDtor(int i) : i(i){}
+  ~CtorDtor(){}
+    int i;
+};
+
+template<typename T>
+thread_local T tls_templ = {get_i()};
+
+// CIR-BEFORE-LPP-LABEL:  cir.global linkonce_odr comdat tls_dyn 
dyn_tls_refs<"_ZTW9tls_templIiE", "_ZTH9tls_templIiE", "_ZGV9tls_templIiE"> 
@_Z9tls_templIiE = ctor : !s32i {
+// CIR-BEFORE-LPP:    %[[GET_GLOB:.*]] = cir.get_global thread_local 
@_Z9tls_templIiE : !cir.ptr<!s32i>
+// CIR-BEFORE-LPP:    %[[CALL:.*]] = cir.call @_Z5get_iv() : () -> (!s32i 
{llvm.noundef})
+// CIR-BEFORE-LPP:    cir.store{{.*}} %[[CALL]], %[[GET_GLOB]] : !s32i, 
!cir.ptr<!s32i>
+// CIR-BEFORE-LPP:  }
+//
+// CIR-BEFORE-LPP-LABEL:  cir.global linkonce_odr comdat tls_dyn 
dyn_tls_refs<"_ZTW9tls_templI8CtorDtorE", "_ZTH9tls_templI8CtorDtorE", 
"_ZGV9tls_templI8CtorDtorE"> @_Z9tls_templI8CtorDtorE = ctor : !rec_CtorDtor {
+// CIR-BEFORE-LPP:    %[[GET_GLOB:.*]] = cir.get_global thread_local 
@_Z9tls_templI8CtorDtorE : !cir.ptr<!rec_CtorDtor>
+// CIR-BEFORE-LPP:    %[[CALL:.*]] = cir.call @_Z5get_iv() : () -> (!s32i 
{llvm.noundef})
+// CIR-BEFORE-LPP:    cir.call @_ZN8CtorDtorC1Ei(%[[GET_GLOB]], %[[CALL]]) : 
(!cir.ptr<!rec_CtorDtor>
+// CIR-BEFORE-LPP:  } dtor {
+// CIR-BEFORE-LPP:    %[[GET_GLOB:.*]] = cir.get_global thread_local 
@_Z9tls_templI8CtorDtorE : !cir.ptr<!rec_CtorDtor>
+// CIR-BEFORE-LPP:    cir.call @_ZN8CtorDtorD1Ev(%[[GET_GLOB]]) : 
(!cir.ptr<!rec_CtorDtor>) -> ()
+// CIR-BEFORE-LPP:  }
+
+// CIR-BEFORE-LPP-LABEL: cir.func{{.*}}@_Z4usesv
+void uses() {
+  auto x = tls_templ<int>;
+// CIR-BEFORE-LPP: cir.get_global thread_local @_Z9tls_templIiE : 
!cir.ptr<!s32i>
+  auto y = tls_templ<CtorDtor>;
+// CIR-BEFORE-LPP: cir.get_global thread_local @_Z9tls_templI8CtorDtorE : 
!cir.ptr<!rec_CtorDtor>
+}
diff --git a/clang/test/CIR/IR/invalid-tls.cir 
b/clang/test/CIR/IR/invalid-tls.cir
index 36df7fdb1e619..b94352891d3af 100644
--- a/clang/test/CIR/IR/invalid-tls.cir
+++ b/clang/test/CIR/IR/invalid-tls.cir
@@ -11,3 +11,21 @@ module {
   }
 }
 
+// -----
+
+!s32i = !cir.int<s, 32>
+
+module {
+  // expected-error@+1{{op cannot have both static local and dynamic tls 
references}}
+cir.global "private" internal tls_dyn dyn_tls_refs<"asdf", "asdf", "asdf"> 
static_local_guard<"asdf"> @_ZZ1fvE1y : !s32i
+}
+
+// -----
+
+!s32i = !cir.int<s, 32>
+
+module {
+  // expected-error@+1{{'dyn_tls_refs' only valid for dynamic tls}}
+cir.global "private" internal tls_local_dyn dyn_tls_refs<"asdf", "asdf", 
"asdf"> @_ZZ1fvE1y : !s32i
+}
+

>From f6c7cd32d1a15e160baa6fe4f1b835328ddb5cc9 Mon Sep 17 00:00:00 2001
From: erichkeane <[email protected]>
Date: Thu, 7 May 2026 15:42:15 -0700
Subject: [PATCH 2/2] add equal sign to attribute printing, fix .td file
 example

---
 clang/include/clang/CIR/Dialect/IR/CIRAttrs.td    |  2 +-
 clang/include/clang/CIR/Dialect/IR/CIROps.td      |  2 +-
 clang/test/CIR/CodeGen/global-tls-dyn-init.cpp    |  8 ++++----
 clang/test/CIR/CodeGen/global-tls-simple-init.cpp | 14 +++++++-------
 clang/test/CIR/CodeGen/global-tls-templates.cpp   |  4 ++--
 clang/test/CIR/IR/invalid-tls.cir                 |  4 ++--
 6 files changed, 17 insertions(+), 17 deletions(-)

diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td 
b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
index cb07d87c25e98..4032d8219fff3 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
@@ -1559,7 +1559,7 @@ def CIR_ThreadLocalGlobalWrapperInitAttr : CIR_Attr<
 
       Example:
       ```
-      cir.global tls_dyn tls_wrapper_init<"_ZTW7tls_var", "_ZTH7tls_var"> 
@_ZZZ7tls_var = ...
+      cir.global tls_dyn dyn_tls_refs = <"_ZTW7tls_var", "_ZTH7tls_var"> 
@_ZZZ7tls_var = ...
       ...
       cir.get_global thread_local @ZZZ7tls_var : !cir.ptr<!s32i>
       ```
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td 
b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 25c46c27e50b2..078e9e9371f48 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -2885,7 +2885,7 @@ def CIR_GlobalOp : CIR_Op<"global", [
     $linkage
     (`comdat` $comdat^)?
     ($tls_model^)?
-    (`dyn_tls_refs` `` $dyn_tls_refs^)?
+    (`dyn_tls_refs` `=` $dyn_tls_refs^)?
     (`dso_local` $dso_local^)?
     (`static_local_guard` `` $static_local_guard^)?
     (` ` custom<GlobalAddressSpaceValue>($addr_space)^ )?
diff --git a/clang/test/CIR/CodeGen/global-tls-dyn-init.cpp 
b/clang/test/CIR/CodeGen/global-tls-dyn-init.cpp
index b7551c2b4a342..ef3c1e306f62d 100644
--- a/clang/test/CIR/CodeGen/global-tls-dyn-init.cpp
+++ b/clang/test/CIR/CodeGen/global-tls-dyn-init.cpp
@@ -8,13 +8,13 @@ struct CtorDtor {
 };
 
 thread_local CtorDtor tls_cd = 5;
-// CIR-BEFORE-LPP: cir.global external tls_dyn dyn_tls_refs<"_ZTW6tls_cd", 
"_ZTH6tls_cd"> @tls_cd = #cir.const_record<{#cir.int<5> : !s32i}> : 
!rec_CtorDtor dtor {
+// CIR-BEFORE-LPP: cir.global external tls_dyn dyn_tls_refs = <"_ZTW6tls_cd", 
"_ZTH6tls_cd"> @tls_cd = #cir.const_record<{#cir.int<5> : !s32i}> : 
!rec_CtorDtor dtor {
 // CIR-BEFORE-LPP:   %[[GET_GLOB:.*]] = cir.get_global thread_local @tls_cd : 
!cir.ptr<!rec_CtorDtor>
 // CIR-BEFORE-LPP:   cir.call @_ZN8CtorDtorD1Ev(%[[GET_GLOB]]) : 
(!cir.ptr<!rec_CtorDtor>) -> ()
 // CIR-BEFORE-LPP: }
 
 thread_local CtorDtor tls_cd_dyn = get_i();
-// CIR-BEFORE-LPP:  cir.global external tls_dyn 
dyn_tls_refs<"_ZTW10tls_cd_dyn", "_ZTH10tls_cd_dyn"> @tls_cd_dyn = ctor : 
!rec_CtorDtor {
+// CIR-BEFORE-LPP:  cir.global external tls_dyn dyn_tls_refs = 
<"_ZTW10tls_cd_dyn", "_ZTH10tls_cd_dyn"> @tls_cd_dyn = ctor : !rec_CtorDtor {
 // CIR-BEFORE-LPP:    %[[GET_GLOB:.*]] = cir.get_global thread_local 
@tls_cd_dyn : !cir.ptr<!rec_CtorDtor>
 // CIR-BEFORE-LPP:    %[[CALL:.*]] = cir.call @_Z5get_iv() : () -> (!s32i 
{llvm.noundef})
 // CIR-BEFORE-LPP:    cir.call @_ZN8CtorDtorC1Ei(%[[GET_GLOB]], %[[CALL]]) : 
(!cir.ptr<!rec_CtorDtor>
@@ -24,14 +24,14 @@ thread_local CtorDtor tls_cd_dyn = get_i();
 // CIR-BEFORE-LPP:  }
 
 thread_local CtorDtor &tls_cd_ref = tls_cd_dyn;
-// CIR-BEFORE-LPP: cir.global external tls_dyn 
dyn_tls_refs<"_ZTW10tls_cd_ref", "_ZTH10tls_cd_ref"> @tls_cd_ref = ctor : 
!cir.ptr<!rec_CtorDtor> {
+// CIR-BEFORE-LPP: cir.global external tls_dyn dyn_tls_refs = 
<"_ZTW10tls_cd_ref", "_ZTH10tls_cd_ref"> @tls_cd_ref = ctor : 
!cir.ptr<!rec_CtorDtor> {
 // CIR-BEFORE-LPP:   %[[GET_GLOB:.*]] = cir.get_global thread_local 
@tls_cd_ref : !cir.ptr<!cir.ptr<!rec_CtorDtor>>
 // CIR-BEFORE-LPP:   %[[CALL:.*]] = cir.get_global thread_local @tls_cd_dyn : 
!cir.ptr<!rec_CtorDtor>
 // CIR-BEFORE-LPP:   cir.store {{.*}}%[[CALL]], %[[GET_GLOB]] : 
!cir.ptr<!rec_CtorDtor>, !cir.ptr<!cir.ptr<!rec_CtorDtor>>
 // CIR-BEFORE-LPP: }
 
 thread_local CtorDtor tls_cd_dyn_not_used = get_i();
-// CIR-BEFORE-LPP: cir.global external tls_dyn 
dyn_tls_refs<"_ZTW19tls_cd_dyn_not_used", "_ZTH19tls_cd_dyn_not_used"> 
@tls_cd_dyn_not_used = ctor : !rec_CtorDtor {
+// CIR-BEFORE-LPP: cir.global external tls_dyn dyn_tls_refs = 
<"_ZTW19tls_cd_dyn_not_used", "_ZTH19tls_cd_dyn_not_used"> @tls_cd_dyn_not_used 
= ctor : !rec_CtorDtor {
 // CIR-BEFORE-LPP:   %[[GET_GLOB:.*]] = cir.get_global thread_local 
@tls_cd_dyn_not_used : !cir.ptr<!rec_CtorDtor>
 // CIR-BEFORE-LPP:   %[[CALL:.*]] = cir.call @_Z5get_iv() : () -> (!s32i 
{llvm.noundef})
 // CIR-BEFORE-LPP:   cir.call @_ZN8CtorDtorC1Ei(%[[GET_GLOB]], %[[CALL]])
diff --git a/clang/test/CIR/CodeGen/global-tls-simple-init.cpp 
b/clang/test/CIR/CodeGen/global-tls-simple-init.cpp
index 041858de2a4df..fef55b0298c33 100644
--- a/clang/test/CIR/CodeGen/global-tls-simple-init.cpp
+++ b/clang/test/CIR/CodeGen/global-tls-simple-init.cpp
@@ -8,24 +8,24 @@ struct CtorDtor {
 };
 
 thread_local int tls_int = 5;
-// CIR-BEFORE-LPP: cir.global external tls_dyn dyn_tls_refs<"_ZTW7tls_int", 
"_ZTH7tls_int"> @tls_int = #cir.int<5> : !s32i
+// CIR-BEFORE-LPP: cir.global external tls_dyn dyn_tls_refs = <"_ZTW7tls_int", 
"_ZTH7tls_int"> @tls_int = #cir.int<5> : !s32i
 
 thread_local int tls_int_dyn = get_i();
-// CIR-BEFORE-LPP: cir.global external tls_dyn 
dyn_tls_refs<"_ZTW11tls_int_dyn", "_ZTH11tls_int_dyn"> @tls_int_dyn = ctor : 
!s32i {
+// CIR-BEFORE-LPP: cir.global external tls_dyn dyn_tls_refs = 
<"_ZTW11tls_int_dyn", "_ZTH11tls_int_dyn"> @tls_int_dyn = ctor : !s32i {
 // CIR-BEFORE-LPP:   %[[GET_GLOB:.*]] = cir.get_global thread_local 
@tls_int_dyn : !cir.ptr<!s32i>
 // CIR-BEFORE-LPP:   %[[CALL:.*]] = cir.call @_Z5get_iv() : () -> (!s32i 
{llvm.noundef})
 // CIR-BEFORE-LPP:   cir.store {{.*}}%[[CALL]], %[[GET_GLOB]] : !s32i, 
!cir.ptr<!s32i>
 // CIR-BEFORE-LPP: }
 
 thread_local int &tls_int_ref = tls_int_dyn;
-// CIR-BEFORE-LPP: cir.global external tls_dyn 
dyn_tls_refs<"_ZTW11tls_int_ref", "_ZTH11tls_int_ref"> @tls_int_ref = ctor : 
!cir.ptr<!s32i> {
+// CIR-BEFORE-LPP: cir.global external tls_dyn dyn_tls_refs = 
<"_ZTW11tls_int_ref", "_ZTH11tls_int_ref"> @tls_int_ref = ctor : 
!cir.ptr<!s32i> {
 // CIR-BEFORE-LPP:   %[[GET_GLOB:.*]] = cir.get_global thread_local 
@tls_int_ref : !cir.ptr<!cir.ptr<!s32i>>
 // CIR-BEFORE-LPP:   %[[GET_OTHER:.*]] = cir.get_global thread_local 
@tls_int_dyn : !cir.ptr<!s32i>
 // CIR-BEFORE-LPP:   cir.store {{.*}}%[[GET_OTHER]], %[[GET_GLOB]] : 
!cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>>
 // CIR-BEFORE-LPP: }
 
 thread_local int tls_int_self_init = tls_int_self_init + get_i();
-// CIR-BEFORE-LPP:  cir.global external tls_dyn 
dyn_tls_refs<"_ZTW17tls_int_self_init", "_ZTH17tls_int_self_init"> 
@tls_int_self_init = ctor : !s32i {
+// CIR-BEFORE-LPP:  cir.global external tls_dyn dyn_tls_refs = 
<"_ZTW17tls_int_self_init", "_ZTH17tls_int_self_init"> @tls_int_self_init = 
ctor : !s32i {
 // CIR-BEFORE-LPP:    %[[GET_GLOB:.*]] = cir.get_global thread_local 
@tls_int_self_init : !cir.ptr<!s32i>
 // CIR-BEFORE-LPP:    %[[GET_SELF:.*]] = cir.get_global thread_local 
@tls_int_self_init : !cir.ptr<!s32i>
 // CIR-BEFORE-LPP:    %[[LOAD_SELF:.*]] = cir.load {{.*}}%[[GET_SELF]] : 
!cir.ptr<!s32i>, !s32i
@@ -35,17 +35,17 @@ thread_local int tls_int_self_init = tls_int_self_init + 
get_i();
 // CIR-BEFORE-LPP:  }
 
 extern thread_local int definitely_inited = 5;
-// CIR-BEFORE-LPP: cir.global external tls_dyn 
dyn_tls_refs<"_ZTW17definitely_inited", "_ZTH17definitely_inited"> 
@definitely_inited = #cir.int<5> : !s32i
+// CIR-BEFORE-LPP: cir.global external tls_dyn dyn_tls_refs = 
<"_ZTW17definitely_inited", "_ZTH17definitely_inited"> @definitely_inited = 
#cir.int<5> : !s32i
 
 extern thread_local int definitely_inited_dyn = get_i();
-// CIR-BEFORE-LPP: cir.global external tls_dyn 
dyn_tls_refs<"_ZTW21definitely_inited_dyn", "_ZTH21definitely_inited_dyn"> 
@definitely_inited_dyn = ctor : !s32i {
+// CIR-BEFORE-LPP: cir.global external tls_dyn dyn_tls_refs = 
<"_ZTW21definitely_inited_dyn", "_ZTH21definitely_inited_dyn"> 
@definitely_inited_dyn = ctor : !s32i {
 // CIR-BEFORE-LPP:   %[[GET_GLOB:.*]] = cir.get_global thread_local 
@definitely_inited_dyn : !cir.ptr<!s32i>
 // CIR-BEFORE-LPP:   %[[CALL:.*]] = cir.call @_Z5get_iv() : () -> (!s32i 
{llvm.noundef})
 // CIR-BEFORE-LPP:   cir.store {{.*}}%[[CALL]], %[[GET_GLOB]] : !s32i, 
!cir.ptr<!s32i>
 // CIR-BEFORE-LPP: }
 
 extern thread_local int maybe_inited;
-// CIR-BEFORE-LPP: cir.global "private" external tls_dyn 
dyn_tls_refs<"_ZTW12maybe_inited", "_ZTH12maybe_inited"> @maybe_inited : !s32i
+// CIR-BEFORE-LPP: cir.global "private" external tls_dyn dyn_tls_refs = 
<"_ZTW12maybe_inited", "_ZTH12maybe_inited"> @maybe_inited : !s32i
 
 void uses() {
   auto a = tls_int;
diff --git a/clang/test/CIR/CodeGen/global-tls-templates.cpp 
b/clang/test/CIR/CodeGen/global-tls-templates.cpp
index 7ce604028ef0a..bad1f1440dde5 100644
--- a/clang/test/CIR/CodeGen/global-tls-templates.cpp
+++ b/clang/test/CIR/CodeGen/global-tls-templates.cpp
@@ -10,13 +10,13 @@ struct CtorDtor {
 template<typename T>
 thread_local T tls_templ = {get_i()};
 
-// CIR-BEFORE-LPP-LABEL:  cir.global linkonce_odr comdat tls_dyn 
dyn_tls_refs<"_ZTW9tls_templIiE", "_ZTH9tls_templIiE", "_ZGV9tls_templIiE"> 
@_Z9tls_templIiE = ctor : !s32i {
+// CIR-BEFORE-LPP-LABEL:  cir.global linkonce_odr comdat tls_dyn dyn_tls_refs 
= <"_ZTW9tls_templIiE", "_ZTH9tls_templIiE", "_ZGV9tls_templIiE"> 
@_Z9tls_templIiE = ctor : !s32i {
 // CIR-BEFORE-LPP:    %[[GET_GLOB:.*]] = cir.get_global thread_local 
@_Z9tls_templIiE : !cir.ptr<!s32i>
 // CIR-BEFORE-LPP:    %[[CALL:.*]] = cir.call @_Z5get_iv() : () -> (!s32i 
{llvm.noundef})
 // CIR-BEFORE-LPP:    cir.store{{.*}} %[[CALL]], %[[GET_GLOB]] : !s32i, 
!cir.ptr<!s32i>
 // CIR-BEFORE-LPP:  }
 //
-// CIR-BEFORE-LPP-LABEL:  cir.global linkonce_odr comdat tls_dyn 
dyn_tls_refs<"_ZTW9tls_templI8CtorDtorE", "_ZTH9tls_templI8CtorDtorE", 
"_ZGV9tls_templI8CtorDtorE"> @_Z9tls_templI8CtorDtorE = ctor : !rec_CtorDtor {
+// CIR-BEFORE-LPP-LABEL:  cir.global linkonce_odr comdat tls_dyn dyn_tls_refs 
= <"_ZTW9tls_templI8CtorDtorE", "_ZTH9tls_templI8CtorDtorE", 
"_ZGV9tls_templI8CtorDtorE"> @_Z9tls_templI8CtorDtorE = ctor : !rec_CtorDtor {
 // CIR-BEFORE-LPP:    %[[GET_GLOB:.*]] = cir.get_global thread_local 
@_Z9tls_templI8CtorDtorE : !cir.ptr<!rec_CtorDtor>
 // CIR-BEFORE-LPP:    %[[CALL:.*]] = cir.call @_Z5get_iv() : () -> (!s32i 
{llvm.noundef})
 // CIR-BEFORE-LPP:    cir.call @_ZN8CtorDtorC1Ei(%[[GET_GLOB]], %[[CALL]]) : 
(!cir.ptr<!rec_CtorDtor>
diff --git a/clang/test/CIR/IR/invalid-tls.cir 
b/clang/test/CIR/IR/invalid-tls.cir
index b94352891d3af..e33b7070eb790 100644
--- a/clang/test/CIR/IR/invalid-tls.cir
+++ b/clang/test/CIR/IR/invalid-tls.cir
@@ -17,7 +17,7 @@ module {
 
 module {
   // expected-error@+1{{op cannot have both static local and dynamic tls 
references}}
-cir.global "private" internal tls_dyn dyn_tls_refs<"asdf", "asdf", "asdf"> 
static_local_guard<"asdf"> @_ZZ1fvE1y : !s32i
+cir.global "private" internal tls_dyn dyn_tls_refs = <"asdf", "asdf", "asdf"> 
static_local_guard<"asdf"> @_ZZ1fvE1y : !s32i
 }
 
 // -----
@@ -26,6 +26,6 @@ cir.global "private" internal tls_dyn dyn_tls_refs<"asdf", 
"asdf", "asdf"> stati
 
 module {
   // expected-error@+1{{'dyn_tls_refs' only valid for dynamic tls}}
-cir.global "private" internal tls_local_dyn dyn_tls_refs<"asdf", "asdf", 
"asdf"> @_ZZ1fvE1y : !s32i
+cir.global "private" internal tls_local_dyn dyn_tls_refs = <"asdf", "asdf", 
"asdf"> @_ZZ1fvE1y : !s32i
 }
 

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to