momo5502 updated this revision to Diff 396783.
momo5502 marked 4 inline comments as done.
momo5502 added a comment.
Comments were addressed
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D115456/new/
https://reviews.llvm.org/D115456
Files:
clang/include/clang/Basic/LangOptions.h
clang/lib/CodeGen/MicrosoftCXXABI.cpp
clang/test/CodeGenCXX/ms-thread_local.cpp
Index: clang/test/CodeGenCXX/ms-thread_local.cpp
===================================================================
--- clang/test/CodeGenCXX/ms-thread_local.cpp
+++ clang/test/CodeGenCXX/ms-thread_local.cpp
@@ -1,5 +1,6 @@
-// RUN: %clang_cc1 %s -std=c++1y -triple=i686-pc-win32 -emit-llvm -o - | FileCheck %s
-// RUN: %clang_cc1 %s -std=c++1y -triple=i686-pc-win32 -ftls-model=local-dynamic -emit-llvm -o - | FileCheck %s -check-prefix=CHECK-LD
+// RUN: %clang_cc1 %s -std=c++1y -triple=i686-pc-win32 -fms-compatibility-version=19.25 -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 %s -std=c++1y -triple=i686-pc-win32 -fms-compatibility-version=19.20 -emit-llvm -o - | FileCheck %s -check-prefix=CHECK-LEGACY
+// RUN: %clang_cc1 %s -std=c++1y -triple=i686-pc-win32 -fms-compatibility-version=19.25 -ftls-model=local-dynamic -emit-llvm -o - | FileCheck %s -check-prefix=CHECK-LD
struct A {
A();
@@ -17,10 +18,23 @@
// CHECK-DAG: @"?b@@3UA@@A" = dso_local thread_local global %struct.A zeroinitializer, align 1
// CHECK-DAG: @"__tls_init$initializer$" = internal constant void ()* @__tls_init, section ".CRT$XDU"
+// CHECK-DAG: @__tls_guard = external dso_local thread_local global i8
// CHECK-LD-DAG: @"?b@@3UA@@A" = dso_local thread_local(localdynamic) global %struct.A zeroinitializer, align 1
// CHECK-LD-DAG: @"__tls_init$initializer$" = internal constant void ()* @__tls_init, section ".CRT$XDU"
+// CHECK-LD-DAG: @__tls_guard = external dso_local thread_local global i8
+// CHECK-LEGACY-NOT: @__tls_guard = external dso_local thread_local global i8
thread_local A b;
+// CHECK-LABEL: declare dso_local void @__dyn_tls_on_demand_init()
+// CHECK-LD-LABEL: declare dso_local void @__dyn_tls_on_demand_init()
+// CHECK-LEGACY-NOT: declare dso_local void @__dyn_tls_on_demand_init()
+
+// CHECK-LABEL: define dso_local void @"?f@@YA?AUA@@XZ"(%struct.A* noalias sret(%struct.A) align 1 %agg.result)
+// CHECK: call void @__dyn_tls_on_demand_init()
+// CHECK-LD-LABEL: define dso_local void @"?f@@YA?AUA@@XZ"(%struct.A* noalias sret(%struct.A) align 1 %agg.result)
+// CHECK-LD: call void @__dyn_tls_on_demand_init()
+// CHECK-LEGACY-NOT: call void @__dyn_tls_on_demand_init()
+
// CHECK-LABEL: define internal void @__tls_init()
// CHECK: call void @"??__Eb@@YAXXZ"
// CHECK-LD-LABEL: define internal void @__tls_init()
Index: clang/lib/CodeGen/MicrosoftCXXABI.cpp
===================================================================
--- clang/lib/CodeGen/MicrosoftCXXABI.cpp
+++ clang/lib/CodeGen/MicrosoftCXXABI.cpp
@@ -401,7 +401,8 @@
ArrayRef<const VarDecl *> CXXThreadLocalInitVars) override;
bool usesThreadWrapperFunction(const VarDecl *VD) const override {
- return false;
+ return getContext().getLangOpts().isCompatibleWithMSVC(
+ LangOptions::MSVC2019_5);
}
LValue EmitThreadLocalVarDeclLValue(CodeGenFunction &CGF, const VarDecl *VD,
QualType LValType) override;
@@ -2397,11 +2398,97 @@
}
}
+static llvm::GlobalValue *getTlsGuardVar(CodeGenModule &CGM) {
+ // __tls_guard comes from the MSVC runtime and reflects
+ // whether TLS has been initialized for a particular thread.
+ // It is set from within __dyn_tls_init by the runtime.
+ // Every library and executable has its own variable.
+ llvm::Type *VTy = llvm::Type::getInt8Ty(CGM.getLLVMContext());
+ llvm::Constant *TlsGuardConstant =
+ CGM.CreateRuntimeVariable(VTy, "__tls_guard");
+ llvm::GlobalValue *TlsGuard = cast<llvm::GlobalValue>(TlsGuardConstant);
+
+ TlsGuard->setThreadLocal(true);
+
+ return TlsGuard;
+}
+
+static llvm::FunctionCallee getDynTlsOnDemandInitFn(CodeGenModule &CGM) {
+ // __dyn_tls_on_demand_init comes from the MSVC runtime and triggers
+ // dynamic TLS initialization by calling __dyn_tls_init internally.
+ llvm::FunctionType *FTy =
+ llvm::FunctionType::get(llvm::Type::getVoidTy(CGM.getLLVMContext()), {},
+ /*isVarArg=*/false);
+ return CGM.CreateRuntimeFunction(
+ FTy, "__dyn_tls_on_demand_init",
+ llvm::AttributeList::get(CGM.getLLVMContext(),
+ llvm::AttributeList::FunctionIndex,
+ llvm::Attribute::NoUnwind),
+ /*Local=*/true);
+}
+
+static void emitTlsGuardCheck(CodeGenFunction &CGF, llvm::GlobalValue *TlsGuard,
+ llvm::BasicBlock *DynInitBB,
+ llvm::BasicBlock *ContinueBB) {
+ llvm::LoadInst *TlsGuardValue =
+ CGF.Builder.CreateLoad(Address(TlsGuard, CharUnits::One()));
+ llvm::Value *CmpResult =
+ CGF.Builder.CreateICmpEQ(TlsGuardValue, CGF.Builder.getInt8(0));
+ CGF.Builder.CreateCondBr(CmpResult, DynInitBB, ContinueBB);
+}
+
+static void emitDynamicTlsInitializationCall(CodeGenFunction &CGF,
+ llvm::GlobalValue *TlsGuard,
+ llvm::BasicBlock *ContinueBB) {
+ llvm::FunctionCallee Initializer = getDynTlsOnDemandInitFn(CGF.CGM);
+ llvm::Function *InitializerFunction =
+ cast<llvm::Function>(Initializer.getCallee());
+ llvm::CallInst *CallVal = CGF.Builder.CreateCall(InitializerFunction);
+ CallVal->setCallingConv(InitializerFunction->getCallingConv());
+
+ CGF.Builder.CreateBr(ContinueBB);
+}
+
+static void emitDynamicTlsInitialization(CodeGenFunction &CGF) {
+ llvm::BasicBlock *DynInitBB =
+ CGF.createBasicBlock("dyntls.dyn_init", CGF.CurFn);
+ llvm::BasicBlock *ContinueBB =
+ CGF.createBasicBlock("dyntls.continue", CGF.CurFn);
+
+ llvm::GlobalValue *TlsGuard = getTlsGuardVar(CGF.CGM);
+
+ emitTlsGuardCheck(CGF, TlsGuard, DynInitBB, ContinueBB);
+ CGF.Builder.SetInsertPoint(DynInitBB);
+ emitDynamicTlsInitializationCall(CGF, TlsGuard, ContinueBB);
+ CGF.Builder.SetInsertPoint(ContinueBB);
+}
+
LValue MicrosoftCXXABI::EmitThreadLocalVarDeclLValue(CodeGenFunction &CGF,
const VarDecl *VD,
QualType LValType) {
- CGF.CGM.ErrorUnsupported(VD, "thread wrappers");
- return LValue();
+ // Dynamic TLS initialization works by checking the state of a
+ // guard variable (__tls_guard) to see whether TLS initialization
+ // for a thread has happend yet.
+ // If not, the initialization is triggered on-demand
+ // by calling __dyn_tls_on_demand_init.
+ emitDynamicTlsInitialization(CGF);
+
+ // Emit the variable just like any regular global variable.
+
+ llvm::Value *V = CGF.CGM.GetAddrOfGlobalVar(VD);
+ llvm::Type *RealVarTy = CGF.getTypes().ConvertTypeForMem(VD->getType());
+
+ unsigned AS = cast<llvm::PointerType>(V->getType())->getAddressSpace();
+ V = CGF.Builder.CreateBitCast(V, RealVarTy->getPointerTo(AS));
+
+ CharUnits Alignment = CGF.getContext().getDeclAlign(VD);
+ Address Addr(V, Alignment);
+
+ LValue LV = VD->getType()->isReferenceType()
+ ? CGF.EmitLoadOfReferenceLValue(Addr, VD->getType(),
+ AlignmentSource::Decl)
+ : CGF.MakeAddrLValue(Addr, LValType, AlignmentSource::Decl);
+ return LV;
}
static ConstantAddress getInitThreadEpochPtr(CodeGenModule &CGM) {
Index: clang/include/clang/Basic/LangOptions.h
===================================================================
--- clang/include/clang/Basic/LangOptions.h
+++ clang/include/clang/Basic/LangOptions.h
@@ -124,6 +124,7 @@
MSVC2017_5 = 1912,
MSVC2017_7 = 1914,
MSVC2019 = 1920,
+ MSVC2019_5 = 1925,
MSVC2019_8 = 1928,
};
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits