r371767 - Improve code generation for thread_local variables:

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Thu Sep 12 13:00:24 PDT 2019


Author: rsmith
Date: Thu Sep 12 13:00:24 2019
New Revision: 371767

URL: http://llvm.org/viewvc/llvm-project?rev=371767&view=rev
Log:
Improve code generation for thread_local variables:

Summary:
 * Don't bother using a thread wrapper when the variable is known to
   have constant initialization.
 * Emit the thread wrapper as discardable-if-unused in TUs that don't
   contain a definition of the thread_local variable.
 * Don't emit the thread wrapper at all if the thread_local variable
   is unused and discardable; it will be emitted by all TUs that need
   it.

Reviewers: rjmccall, jdoerfert

Subscribers: cfe-commits

Tags: #clang

Differential Revision: https://reviews.llvm.org/D67429

Added:
    cfe/trunk/test/CodeGenCXX/cxx2a-thread-local-constinit.cpp
    cfe/trunk/test/CodeGenCXX/windows-on-arm-itanium-thread-local.cpp
      - copied, changed from r371766, cfe/trunk/test/CodeGen/windows-on-arm-itanium-thread-local.c
Removed:
    cfe/trunk/test/CodeGen/windows-on-arm-itanium-thread-local.c
Modified:
    cfe/trunk/include/clang/Basic/Linkage.h
    cfe/trunk/lib/CodeGen/CGCXXABI.h
    cfe/trunk/lib/CodeGen/CGExpr.cpp
    cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp
    cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp
    cfe/trunk/test/CodeGenCXX/cxx11-thread-local.cpp
    cfe/trunk/test/CodeGenCXX/tls-init-funcs.cpp
    cfe/trunk/test/OpenMP/parallel_copyin_codegen.cpp

Modified: cfe/trunk/include/clang/Basic/Linkage.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Linkage.h?rev=371767&r1=371766&r2=371767&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/Linkage.h (original)
+++ cfe/trunk/include/clang/Basic/Linkage.h Thu Sep 12 13:00:24 2019
@@ -82,6 +82,12 @@ inline bool isDiscardableGVALinkage(GVAL
   return L <= GVA_DiscardableODR;
 }
 
+/// Do we know that this will be the only definition of this symbol (excluding
+/// inlining-only definitions)?
+inline bool isUniqueGVALinkage(GVALinkage L) {
+  return L == GVA_Internal || L == GVA_StrongExternal;
+}
+
 inline bool isExternallyVisible(Linkage L) {
   return L >= VisibleNoLinkage;
 }

Modified: cfe/trunk/lib/CodeGen/CGCXXABI.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCXXABI.h?rev=371767&r1=371766&r2=371767&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGCXXABI.h (original)
+++ cfe/trunk/lib/CodeGen/CGCXXABI.h Thu Sep 12 13:00:24 2019
@@ -577,7 +577,7 @@ public:
 
   // Determine if references to thread_local global variables can be made
   // directly or require access through a thread wrapper function.
-  virtual bool usesThreadWrapperFunction() const = 0;
+  virtual bool usesThreadWrapperFunction(const VarDecl *VD) const = 0;
 
   /// Emit a reference to a non-local thread_local variable (including
   /// triggering the initialization of all thread_local variables in its

Modified: cfe/trunk/lib/CodeGen/CGExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExpr.cpp?rev=371767&r1=371766&r2=371767&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExpr.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExpr.cpp Thu Sep 12 13:00:24 2019
@@ -2361,7 +2361,7 @@ static LValue EmitGlobalVarDeclLValue(Co
 
   // If it's thread_local, emit a call to its wrapper function instead.
   if (VD->getTLSKind() == VarDecl::TLS_Dynamic &&
-      CGF.CGM.getCXXABI().usesThreadWrapperFunction())
+      CGF.CGM.getCXXABI().usesThreadWrapperFunction(VD))
     return CGF.CGM.getCXXABI().EmitThreadLocalVarDeclLValue(CGF, VD, T);
   // Check if the variable is marked as declare target with link clause in
   // device codegen.

Modified: cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp?rev=371767&r1=371766&r2=371767&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp (original)
+++ cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp Thu Sep 12 13:00:24 2019
@@ -43,6 +43,10 @@ class ItaniumCXXABI : public CodeGen::CG
   /// VTables - All the vtables which have been defined.
   llvm::DenseMap<const CXXRecordDecl *, llvm::GlobalVariable *> VTables;
 
+  /// All the thread wrapper functions that have been used.
+  llvm::SmallVector<std::pair<const VarDecl *, llvm::Function *>, 8>
+      ThreadWrappers;
+
 protected:
   bool UseARMMethodPtrABI;
   bool UseARMGuardVarABI;
@@ -322,7 +326,42 @@ public:
       ArrayRef<llvm::Function *> CXXThreadLocalInits,
       ArrayRef<const VarDecl *> CXXThreadLocalInitVars) override;
 
-  bool usesThreadWrapperFunction() const override { return true; }
+  /// Determine whether we will definitely emit this variable with a constant
+  /// initializer, either because the language semantics demand it or because
+  /// we know that the initializer is a constant.
+  bool isEmittedWithConstantInitializer(const VarDecl *VD) const {
+    VD = VD->getMostRecentDecl();
+    if (VD->hasAttr<ConstInitAttr>())
+      return true;
+
+    // All later checks examine the initializer specified on the variable. If
+    // the variable is weak, such examination would not be correct.
+    if (VD->isWeak() || VD->hasAttr<SelectAnyAttr>())
+      return false;
+
+    const VarDecl *InitDecl = VD->getInitializingDeclaration();
+    if (!InitDecl)
+      return false;
+
+    // If there's no initializer to run, this is constant initialization.
+    if (!InitDecl->hasInit())
+      return true;
+
+    // If we have the only definition, we don't need a thread wrapper if we
+    // will emit the value as a constant.
+    if (isUniqueGVALinkage(getContext().GetGVALinkageForVariable(VD)))
+      return !VD->getType().isDestructedType() && InitDecl->evaluateValue();
+
+    // Otherwise, we need a thread wrapper unless we know that every
+    // translation unit will emit the value as a constant. We rely on
+    // ICE-ness not varying between translation units, which isn't actually
+    // guaranteed by the standard but is necessary for sanity.
+    return InitDecl->isInitKnownICE() && InitDecl->isInitICE();
+  }
+
+  bool usesThreadWrapperFunction(const VarDecl *VD) const override {
+    return !isEmittedWithConstantInitializer(VD);
+  }
   LValue EmitThreadLocalVarDeclLValue(CodeGenFunction &CGF, const VarDecl *VD,
                                       QualType LValType) override;
 
@@ -2456,9 +2495,6 @@ ItaniumCXXABI::getOrCreateThreadLocalWra
 
   CGM.SetLLVMFunctionAttributes(GlobalDecl(), FI, Wrapper);
 
-  if (VD->hasDefinition())
-    CGM.SetLLVMFunctionAttributesForDefinition(nullptr, Wrapper);
-
   // Always resolve references to the wrapper at link time.
   if (!Wrapper->hasLocalLinkage())
     if (!isThreadWrapperReplaceable(VD, CGM) ||
@@ -2471,6 +2507,8 @@ ItaniumCXXABI::getOrCreateThreadLocalWra
     Wrapper->setCallingConv(llvm::CallingConv::CXX_FAST_TLS);
     Wrapper->addFnAttr(llvm::Attribute::NoUnwind);
   }
+
+  ThreadWrappers.push_back({VD, Wrapper});
   return Wrapper;
 }
 
@@ -2519,20 +2557,40 @@ void ItaniumCXXABI::EmitThreadLocalInitF
     }
   }
 
-  // Emit thread wrappers.
+  // Create declarations for thread wrappers for all thread-local variables
+  // with non-discardable definitions in this translation unit.
   for (const VarDecl *VD : CXXThreadLocals) {
+    if (VD->hasDefinition() &&
+        !isDiscardableGVALinkage(getContext().GetGVALinkageForVariable(VD))) {
+      llvm::GlobalValue *GV = CGM.GetGlobalValue(CGM.getMangledName(VD));
+      getOrCreateThreadLocalWrapper(VD, GV);
+    }
+  }
+
+  // Emit all referenced thread wrappers.
+  for (auto VDAndWrapper : ThreadWrappers) {
+    const VarDecl *VD = VDAndWrapper.first;
     llvm::GlobalVariable *Var =
         cast<llvm::GlobalVariable>(CGM.GetGlobalValue(CGM.getMangledName(VD)));
-    llvm::Function *Wrapper = getOrCreateThreadLocalWrapper(VD, Var);
+    llvm::Function *Wrapper = VDAndWrapper.second;
 
     // Some targets require that all access to thread local variables go through
     // the thread wrapper.  This means that we cannot attempt to create a thread
     // wrapper or a thread helper.
-    if (isThreadWrapperReplaceable(VD, CGM) && !VD->hasDefinition()) {
-      Wrapper->setLinkage(llvm::Function::ExternalLinkage);
-      continue;
+    if (!VD->hasDefinition()) {
+      if (isThreadWrapperReplaceable(VD, CGM)) {
+        Wrapper->setLinkage(llvm::Function::ExternalLinkage);
+        continue;
+      }
+
+      // If this isn't a TU in which this variable is defined, the thread
+      // wrapper is discardable.
+      if (Wrapper->getLinkage() == llvm::Function::WeakODRLinkage)
+        Wrapper->setLinkage(llvm::Function::LinkOnceODRLinkage);
     }
 
+    CGM.SetLLVMFunctionAttributesForDefinition(nullptr, Wrapper);
+
     // Mangle the name for the thread_local initialization function.
     SmallString<256> InitFnName;
     {
@@ -2547,7 +2605,10 @@ void ItaniumCXXABI::EmitThreadLocalInitF
     // produce a declaration of the initialization function.
     llvm::GlobalValue *Init = nullptr;
     bool InitIsInitFunc = false;
-    if (VD->hasDefinition()) {
+    bool HasConstantInitialization = false;
+    if (isEmittedWithConstantInitializer(VD)) {
+      HasConstantInitialization = true;
+    } else if (VD->hasDefinition()) {
       InitIsInitFunc = true;
       llvm::Function *InitFuncToUse = InitFunc;
       if (isTemplateInstantiation(VD->getTemplateSpecializationKind()))
@@ -2576,7 +2637,9 @@ void ItaniumCXXABI::EmitThreadLocalInitF
     llvm::LLVMContext &Context = CGM.getModule().getContext();
     llvm::BasicBlock *Entry = llvm::BasicBlock::Create(Context, "", Wrapper);
     CGBuilderTy Builder(CGM, Entry);
-    if (InitIsInitFunc) {
+    if (HasConstantInitialization) {
+      // No dynamic initialization to invoke.
+    } else if (InitIsInitFunc) {
       if (Init) {
         llvm::CallInst *CallVal = Builder.CreateCall(InitFnTy, Init);
         if (isThreadWrapperReplaceable(VD, CGM)) {

Modified: cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp?rev=371767&r1=371766&r2=371767&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp (original)
+++ cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp Thu Sep 12 13:00:24 2019
@@ -386,7 +386,9 @@ public:
       ArrayRef<llvm::Function *> CXXThreadLocalInits,
       ArrayRef<const VarDecl *> CXXThreadLocalInitVars) override;
 
-  bool usesThreadWrapperFunction() const override { return false; }
+  bool usesThreadWrapperFunction(const VarDecl *VD) const override {
+    return false;
+  }
   LValue EmitThreadLocalVarDeclLValue(CodeGenFunction &CGF, const VarDecl *VD,
                                       QualType LValType) override;
 

Removed: cfe/trunk/test/CodeGen/windows-on-arm-itanium-thread-local.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/windows-on-arm-itanium-thread-local.c?rev=371766&view=auto
==============================================================================
--- cfe/trunk/test/CodeGen/windows-on-arm-itanium-thread-local.c (original)
+++ cfe/trunk/test/CodeGen/windows-on-arm-itanium-thread-local.c (removed)
@@ -1,11 +0,0 @@
-// RUN: %clang_cc1 -triple thumbv7--windows-itanium -fdeclspec -fms-compatibility -fms-compatibility-version=19.0 -S -emit-llvm -o - %s | FileCheck %s
-
-__declspec(thread) static void *c;
-void f(void *p) {
-  c = p;
-}
-
-// CHECK-LABEL: @f(i8* %p)
-// CHECK-NOT: call i8** @_ZTWL1c()
-// CHECK: call arm_aapcs_vfpcc i8** @_ZTWL1c()
-

Modified: cfe/trunk/test/CodeGenCXX/cxx11-thread-local.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/cxx11-thread-local.cpp?rev=371767&r1=371766&r2=371767&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/cxx11-thread-local.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/cxx11-thread-local.cpp Thu Sep 12 13:00:24 2019
@@ -91,15 +91,16 @@ void *e2 = V<char>::m + W<char>::m + &X<
 
 // LINUX-DAG: @_ZTH1a = alias void (), void ()* @__tls_init
 // DARWIN-DAG: @_ZTH1a = internal alias void (), void ()* @__tls_init
-// CHECK-DAG: @_ZTHL1d = internal alias void (), void ()* @__tls_init
 // LINUX-DAG: @_ZTHN1U1mE = alias void (), void ()* @__tls_init
 // DARWIN-DAG: @_ZTHN1U1mE = internal alias void (), void ()* @__tls_init
 // CHECK-DAG: @_ZTHN1VIiE1mE = linkonce_odr alias void (), void ()* @[[V_M_INIT:[^, ]*]]
-// CHECK-NOT: @_ZTHN1WIiE1mE =
 // CHECK-DAG: @_ZTHN1XIiE1mE = linkonce_odr alias void (), void ()* @[[X_M_INIT:[^, ]*]]
 // CHECK-DAG: @_ZTHN1VIfE1mE = weak_odr alias void (), void ()* @[[VF_M_INIT:[^, ]*]]
-// CHECK-NOT: @_ZTHN1WIfE1mE =
 // CHECK-DAG: @_ZTHN1XIfE1mE = weak_odr alias void (), void ()* @[[XF_M_INIT:[^, ]*]]
+// FIXME: We really want a CHECK-DAG-NOT for these.
+// CHECK-NOT: @_ZTHN1WIiE1mE =
+// CHECK-NOT: @_ZTHN1WIfE1mE =
+// CHECK-NOT: @_ZTHL1d =
 
 
 // Individual variable initialization functions:
@@ -130,7 +131,7 @@ int f() {
 // CHECK-NEXT: load i32, i32* %{{.*}}, align 4
 // CHECK-NEXT: store i32 %{{.*}}, i32* @c, align 4
 
-// LINUX-LABEL: define weak_odr hidden i32* @_ZTW1b()
+// LINUX-LABEL: define linkonce_odr hidden i32* @_ZTW1b()
 // LINUX: br i1 icmp ne (void ()* @_ZTH1b, void ()* null),
 // not null:
 // LINUX: call void @_ZTH1b()
@@ -203,21 +204,21 @@ int f() {
 // DARWIN: declare i32 @_tlv_atexit(void (i8*)*, i8*, i8*)
 
 // DARWIN: declare cxx_fast_tlscc i32* @_ZTWN1VIcE1mE()
-// LINUX: define weak_odr hidden i32* @_ZTWN1VIcE1mE()
+// LINUX: define linkonce_odr hidden i32* @_ZTWN1VIcE1mE()
 // LINUX-NOT: comdat
 // LINUX: br i1 icmp ne (void ()* @_ZTHN1VIcE1mE,
 // LINUX: call void @_ZTHN1VIcE1mE()
 // LINUX: ret i32* @_ZN1VIcE1mE
 
 // DARWIN: declare cxx_fast_tlscc i32* @_ZTWN1WIcE1mE()
-// LINUX: define weak_odr hidden i32* @_ZTWN1WIcE1mE()
+// LINUX: define linkonce_odr hidden i32* @_ZTWN1WIcE1mE()
 // LINUX-NOT: comdat
 // LINUX: br i1 icmp ne (void ()* @_ZTHN1WIcE1mE,
 // LINUX: call void @_ZTHN1WIcE1mE()
 // LINUX: ret i32* @_ZN1WIcE1mE
 
 // DARWIN: declare cxx_fast_tlscc {{.*}}* @_ZTWN1XIcE1mE()
-// LINUX: define weak_odr hidden {{.*}}* @_ZTWN1XIcE1mE()
+// LINUX: define linkonce_odr hidden {{.*}}* @_ZTWN1XIcE1mE()
 // LINUX-NOT: comdat
 // LINUX: br i1 icmp ne (void ()* @_ZTHN1XIcE1mE,
 // LINUX: call void @_ZTHN1XIcE1mE()
@@ -269,7 +270,7 @@ int PR19254::f() {
 }
 
 namespace {
-thread_local int anon_i{1};
+thread_local int anon_i{f()};
 }
 void set_anon_i() {
   anon_i = 2;
@@ -332,14 +333,10 @@ void set_anon_i() {
 // CHECK: }
 
 
-// LINUX: declare extern_weak void @_ZTH1b() [[ATTR:#[0-9]+]]
-
-
-// LINUX-LABEL: define internal i32* @_ZTWL1d()
-// DARWIN-LABEL: define internal cxx_fast_tlscc i32* @_ZTWL1d()
-// LINUX: call void @_ZTHL1d()
-// DARWIN: call cxx_fast_tlscc void @_ZTHL1d()
-// CHECK: ret i32* @_ZL1d
+// Should not emit a thread wrapper for internal-linkage unused variable 'd'.
+// We separately check that 'd' does in fact get initialized with the other
+// thread-local variables in this TU.
+// CHECK-NOT: define {{.*}} @_ZTWL1d()
 
 // LINUX-LABEL: define weak_odr hidden i32* @_ZTWN1U1mE()
 // DARWIN-LABEL: define cxx_fast_tlscc i32* @_ZTWN1U1mE()
@@ -347,4 +344,6 @@ void set_anon_i() {
 // DARWIN: call cxx_fast_tlscc void @_ZTHN1U1mE()
 // CHECK: ret i32* @_ZN1U1mE
 
+// LINUX: declare extern_weak void @_ZTH1b() [[ATTR:#[0-9]+]]
+
 // LINUX: attributes [[ATTR]] = { {{.+}} }

Added: cfe/trunk/test/CodeGenCXX/cxx2a-thread-local-constinit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/cxx2a-thread-local-constinit.cpp?rev=371767&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenCXX/cxx2a-thread-local-constinit.cpp (added)
+++ cfe/trunk/test/CodeGenCXX/cxx2a-thread-local-constinit.cpp Thu Sep 12 13:00:24 2019
@@ -0,0 +1,47 @@
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++2a %s -emit-llvm -o - | FileCheck %s
+
+// CHECK-DAG: @a = external thread_local global i32
+extern thread_local int a;
+
+// CHECK-DAG: @b = external thread_local global i32
+extern thread_local constinit int b;
+
+// CHECK-LABEL: define i32 @_Z1fv()
+// CHECK: call i32* @_ZTW1a()
+// CHECK: }
+int f() { return a; }
+
+// CHECK-LABEL: define linkonce_odr {{.*}} @_ZTW1a()
+// CHECK: br i1
+// CHECK: call void @_ZTH1a()
+// CHECK: }
+
+// CHECK-LABEL: define i32 @_Z1gv()
+// CHECK-NOT: call
+// CHECK: load i32, i32* @b
+// CHECK-NOT: call
+// CHECK: }
+int g() { return b; }
+
+// CHECK-NOT: define {{.*}} @_ZTW1b()
+
+extern thread_local int c;
+
+// CHECK-LABEL: define i32 @_Z1hv()
+// CHECK: call i32* @_ZTW1c()
+// CHECK: load i32, i32* %
+// CHECK: }
+int h() { return c; }
+
+thread_local int c = 0;
+
+int d_init();
+thread_local int d = d_init();
+
+// Note: use of 'c' does not trigger initialization of 'd', because 'c' has a
+// constant initializer.
+// CHECK-LABEL: define weak_odr {{.*}} @_ZTW1c()
+// CHECK-NOT: br i1
+// CHECK-NOT: call
+// CHECK: ret i32* @c
+// CHECK: }

Modified: cfe/trunk/test/CodeGenCXX/tls-init-funcs.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/tls-init-funcs.cpp?rev=371767&r1=371766&r2=371767&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/tls-init-funcs.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/tls-init-funcs.cpp Thu Sep 12 13:00:24 2019
@@ -6,9 +6,9 @@
 // CHECK: @_tlv_atexit({{.*}}@_ZN1AD1Ev
 // CHECK: call cxx_fast_tlscc i32* @_ZTW3ext()
 // CHECK: declare cxx_fast_tlscc i32* @_ZTW3ext()
-// CHECK: define weak_odr hidden cxx_fast_tlscc i32* @_ZTW2vtIiE()
-// CHECK: define weak_odr hidden cxx_fast_tlscc i32* @_ZTW2vtIvE()
-// CHECK: define {{.*}} @_ZTW1a
+// CHECK-DAG: define weak_odr hidden cxx_fast_tlscc i32* @_ZTW2vtIiE()
+// CHECK-DAG: define weak_odr hidden cxx_fast_tlscc i32* @_ZTW2vtIvE()
+// CHECK-DAG: define {{.*}} @_ZTW1a
 
 struct A {
   ~A();

Copied: cfe/trunk/test/CodeGenCXX/windows-on-arm-itanium-thread-local.cpp (from r371766, cfe/trunk/test/CodeGen/windows-on-arm-itanium-thread-local.c)
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/windows-on-arm-itanium-thread-local.cpp?p2=cfe/trunk/test/CodeGenCXX/windows-on-arm-itanium-thread-local.cpp&p1=cfe/trunk/test/CodeGen/windows-on-arm-itanium-thread-local.c&r1=371766&r2=371767&rev=371767&view=diff
==============================================================================
--- cfe/trunk/test/CodeGen/windows-on-arm-itanium-thread-local.c (original)
+++ cfe/trunk/test/CodeGenCXX/windows-on-arm-itanium-thread-local.cpp Thu Sep 12 13:00:24 2019
@@ -1,11 +1,12 @@
-// RUN: %clang_cc1 -triple thumbv7--windows-itanium -fdeclspec -fms-compatibility -fms-compatibility-version=19.0 -S -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple thumbv7--windows-itanium -fdeclspec -fms-compatibility -fms-compatibility-version=19.0 -emit-llvm -o - %s | FileCheck %s
 
-__declspec(thread) static void *c;
+void *g();
+thread_local static void *c = g();
 void f(void *p) {
   c = p;
 }
 
-// CHECK-LABEL: @f(i8* %p)
+// CHECK-LABEL: @_Z1fPv(i8* %p)
 // CHECK-NOT: call i8** @_ZTWL1c()
 // CHECK: call arm_aapcs_vfpcc i8** @_ZTWL1c()
 

Modified: cfe/trunk/test/OpenMP/parallel_copyin_codegen.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/OpenMP/parallel_copyin_codegen.cpp?rev=371767&r1=371766&r2=371767&view=diff
==============================================================================
--- cfe/trunk/test/OpenMP/parallel_copyin_codegen.cpp (original)
+++ cfe/trunk/test/OpenMP/parallel_copyin_codegen.cpp Thu Sep 12 13:00:24 2019
@@ -101,8 +101,7 @@ int main() {
   // LAMBDA: define{{.*}} internal{{.*}} void [[OUTER_LAMBDA]](
   // LAMBDA: call {{.*}}void {{.+}} @__kmpc_fork_call({{.+}}, i32 0, {{.+}}* [[OMP_REGION:@.+]] to {{.+}})
 
-  // TLS-LAMBDA:     [[G_CPY_VAL:%.+]] = call{{( cxx_fast_tlscc)?}} i{{[0-9]+}}* [[G_CTOR:@.+]]()
-  // TLS-LAMBDA:     call {{.*}}void {{.+}} @__kmpc_fork_call({{.+}}, i32 1, {{.+}}* [[OMP_REGION:@.+]] to {{.+}}, i32* [[G_CPY_VAL]])
+  // TLS-LAMBDA:     call {{.*}}void {{.+}} @__kmpc_fork_call({{.+}}, i32 1, {{.+}}* [[OMP_REGION:@.+]] to {{.+}}, i32* @g)
 
 #pragma omp parallel copyin(g)
   {
@@ -120,14 +119,12 @@ int main() {
     // LAMBDA: [[DONE]]
 
     // TLS-LAMBDA-DAG: [[G_CAPTURE_SRC:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** %
-    // TLS-LAMBDA-DAG: [[G_CAPTURE_DST:%.+]] = call{{( cxx_fast_tlscc)?}} i{{[0-9]+}}* [[G_CTOR]]()
     // TLS-LAMBDA-DAG: [[G_CAPTURE_SRCC:%.+]] = ptrtoint i{{[0-9]+}}* [[G_CAPTURE_SRC]] to i{{[0-9]+}}
-    // TLS-LAMBDA-DAG: [[G_CAPTURE_DSTC:%.+]] = ptrtoint i{{[0-9]+}}* [[G_CAPTURE_DST]] to i{{[0-9]+}}
-    // TLS-LAMBDA: icmp ne i{{[0-9]+}} {{%.+}}, {{%.+}}
+    // TLS-LAMBDA: icmp ne i{{[0-9]+}} {{%.+}}, ptrtoint (i{{[0-9]+}}* @g to i{{[0-9]+}})
     // TLS-LAMBDA: br i1 %{{.+}}, label %[[NOT_MASTER:.+]], label %[[DONE:.+]]
     // TLS-LAMBDA: [[NOT_MASTER]]
     // TLS-LAMBDA: load i{{[0-9]+}}, i{{[0-9]+}}* [[G_CAPTURE_SRC]],
-    // TLS-LAMBDA: store volatile i{{[0-9]+}} %{{.+}}, i{{[0-9]+}}* [[G_CAPTURE_DST]], align 128
+    // TLS-LAMBDA: store volatile i{{[0-9]+}} %{{.+}}, i{{[0-9]+}}* @g, align 128
     // TLS-LAMBDA: [[DONE]]
 
     // LAMBDA: call {{.*}}void @__kmpc_barrier(
@@ -136,18 +133,13 @@ int main() {
     // LAMBDA: call{{.*}} void [[INNER_LAMBDA:@.+]](%{{.+}}*
     // TLS-LAMBDA: call{{.*}} void [[INNER_LAMBDA:@.+]](%{{.+}}*
 
-    // TLS-LAMBDA:     define {{.*}}i{{[0-9]+}}* [[G_CTOR]]()
-    // TLS-LAMBDA:     ret i{{[0-9]+}}* [[G]]
-    // TLS-LAMBDA:     }
-
     [&]() {
       // LAMBDA: define {{.+}} void [[INNER_LAMBDA]](%{{.+}}* [[ARG_PTR:%.+]])
       // LAMBDA: store %{{.+}}* [[ARG_PTR]], %{{.+}}** [[ARG_PTR_REF:%.+]],
       g = 2;
       // LAMBDA: [[ARG_PTR:%.+]] = load %{{.+}}*, %{{.+}}** [[ARG_PTR_REF]]
 
-      // TLS-LAMBDA: [[G_CAPTURE_DST:%.+]] = call{{( cxx_fast_tlscc)?}} i{{[0-9]+}}* [[G_CTOR]]()
-      // TLS-LAMBDA: store volatile i{{[0-9]+}} 2, i{{[0-9]+}}* [[G_CAPTURE_DST]], align 128
+      // TLS-LAMBDA: store volatile i{{[0-9]+}} 2, i{{[0-9]+}}* @g, align 128
     }();
   }
   }();
@@ -164,8 +156,7 @@ int main() {
   // BLOCKS: define{{.*}} internal{{.*}} void {{.+}}(i8*
   // BLOCKS: call {{.*}}void {{.+}} @__kmpc_fork_call({{.+}}, i32 0, {{.+}}* [[OMP_REGION:@.+]] to {{.+}})
 
-  // TLS-BLOCKS:     [[G_CPY_VAL:%.+]] = call{{( cxx_fast_tlscc)?}} i{{[0-9]+}}* [[G_CTOR:@.+]]()
-  // TLS-BLOCKS:     call {{.*}}void {{.+}} @__kmpc_fork_call({{.+}}, i32 1, {{.+}}* [[OMP_REGION:@.+]] to {{.+}}, i32* [[G_CPY_VAL]])
+  // TLS-BLOCKS:     call {{.*}}void {{.+}} @__kmpc_fork_call({{.+}}, i32 1, {{.+}}* [[OMP_REGION:@.+]] to {{.+}}, i32* @g)
 
 #pragma omp parallel copyin(g)
   {
@@ -183,14 +174,12 @@ int main() {
     // BLOCKS: [[DONE]]
 
     // TLS-BLOCKS-DAG: [[G_CAPTURE_SRC:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** %
-    // TLS-BLOCKS-DAG: [[G_CAPTURE_DST:%.+]] = call{{( cxx_fast_tlscc)?}} i{{[0-9]+}}* [[G_CTOR]]()
     // TLS-BLOCKS-DAG: [[G_CAPTURE_SRCC:%.+]] = ptrtoint i{{[0-9]+}}* [[G_CAPTURE_SRC]] to i{{[0-9]+}}
-    // TLS-BLOCKS-DAG: [[G_CAPTURE_DSTC:%.+]] = ptrtoint i{{[0-9]+}}* [[G_CAPTURE_DST]] to i{{[0-9]+}}
-    // TLS-BLOCKS: icmp ne i{{[0-9]+}} {{%.+}}, {{%.+}}
+    // TLS-BLOCKS: icmp ne i{{[0-9]+}} {{%.+}}, ptrtoint (i{{[0-9]+}}* @g to i{{[0-9]+}})
     // TLS-BLOCKS: br i1 %{{.+}}, label %[[NOT_MASTER:.+]], label %[[DONE:.+]]
     // TLS-BLOCKS: [[NOT_MASTER]]
     // TLS-BLOCKS: load i{{[0-9]+}}, i{{[0-9]+}}* [[G_CAPTURE_SRC]],
-    // TLS-BLOCKS: store volatile i{{[0-9]+}} %{{.+}}, i{{[0-9]+}}* [[G_CAPTURE_DST]], align 128
+    // TLS-BLOCKS: store volatile i{{[0-9]+}} %{{.+}}, i{{[0-9]+}}* @g, align 128
     // TLS-BLOCKS: [[DONE]]
 
     // BLOCKS: call {{.*}}void @__kmpc_barrier(
@@ -200,14 +189,10 @@ int main() {
     // BLOCKS-NOT: [[G]]{{[[^:word:]]}}
     // BLOCKS: call {{.*}}void {{%.+}}(i8
 
-    // TLS-BLOCKS: [[G_CAPTURE_DST:%.+]] = call{{( cxx_fast_tlscc)?}} i{{[0-9]+}}* [[G_CTOR]]()
-    // TLS-BLOCKS: store volatile i{{[0-9]+}} 1, i{{[0-9]+}}* [[G_CAPTURE_DST]]
+    // TLS-BLOCKS: store volatile i{{[0-9]+}} 1, i{{[0-9]+}}* @g
     // TLS-BLOCKS-NOT: [[G]]{{[[^:word:]]}}
     // TLS-BLOCKS: call {{.*}}void {{%.+}}(i8
 
-    // TLS-BLOCKS:     define {{.*}}i{{[0-9]+}}* [[G_CTOR]]()
-    // TLS-BLOCKS:     ret i{{[0-9]+}}* [[G]]
-    // TLS-BLOCKS:     }
     ^{
       // BLOCKS: define {{.+}} void {{@.+}}(i8*
       // TLS-BLOCKS: define {{.+}} void {{@.+}}(i8*
@@ -219,8 +204,7 @@ int main() {
       // BLOCKS: ret
 
       // TLS-BLOCKS-NOT: [[G]]{{[[^:word:]]}}
-      // TLS-BLOCKS: [[G_CAPTURE_DST:%.+]] = call{{( cxx_fast_tlscc)?}} i{{[0-9]+}}* [[G_CTOR]]()
-      // TLS-BLOCKS: store volatile i{{[0-9]+}} 2, i{{[0-9]+}}* [[G_CAPTURE_DST]]
+      // TLS-BLOCKS: store volatile i{{[0-9]+}} 2, i{{[0-9]+}}* @g
       // TLS-BLOCKS-NOT: [[G]]{{[[^:word:]]}}
       // TLS-BLOCKS: ret
     }();
@@ -524,7 +508,8 @@ void array_func() {
   ;
 }
 #elif defined(NESTED)
-int t;
+int t_init();
+int t = t_init();
 #pragma omp threadprivate(t)
 // NESTED: foo
 void foo() {




More information about the cfe-commits mailing list