Index: clang/lib/CodeGen/MicrosoftCXXABI.cpp =================================================================== --- clang/lib/CodeGen/MicrosoftCXXABI.cpp +++ clang/lib/CodeGen/MicrosoftCXXABI.cpp @@ -401,7 +401,7 @@ ArrayRef CXXThreadLocalInitVars) override; bool usesThreadWrapperFunction(const VarDecl *VD) const override { - return false; + return true; } LValue EmitThreadLocalVarDeclLValue(CodeGenFunction &CGF, const VarDecl *VD, QualType LValType) override; @@ -2397,11 +2397,83 @@ } } +static llvm::GlobalValue *getTlsGuardVar(CodeGenModule &CGM) { + llvm::Type *VTy = llvm::Type::getInt8Ty(CGM.getLLVMContext()); + llvm::Constant *TlsGuardConstant = + CGM.CreateRuntimeVariable(VTy, "__tls_guard"); + llvm::GlobalValue *TlsGuard = cast(TlsGuardConstant); + + TlsGuard->setThreadLocal(true); + + return TlsGuard; +} + +static llvm::FunctionCallee getDynTlsOnDemandInitFn(CodeGenModule &CGM) { + 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 emitDynamicTlsInitialization(CodeGenFunction &CGF, + llvm::GlobalValue *TlsGuard, + llvm::BasicBlock *ContinueBB) { + CGF.Builder.CreateStore(CGF.Builder.getInt8(1), + Address(TlsGuard, CharUnits::One())); + + llvm::FunctionCallee Initializer = getDynTlsOnDemandInitFn(CGF.CGM); + llvm::Function *InitializerFunction = + cast(Initializer.getCallee()); + llvm::CallInst *CallVal = CGF.Builder.CreateCall(InitializerFunction); + CallVal->setCallingConv(InitializerFunction->getCallingConv()); + + CGF.Builder.CreateBr(ContinueBB); +} + LValue MicrosoftCXXABI::EmitThreadLocalVarDeclLValue(CodeGenFunction &CGF, const VarDecl *VD, QualType LValType) { - CGF.CGM.ErrorUnsupported(VD, "thread wrappers"); - return LValue(); + 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); + emitDynamicTlsInitialization(CGF, TlsGuard, ContinueBB); + CGF.Builder.SetInsertPoint(ContinueBB); + + llvm::Value *V = CGF.CGM.GetAddrOfGlobalVar(VD); + llvm::Type *RealVarTy = CGF.getTypes().ConvertTypeForMem(VD->getType()); + + unsigned AS = cast(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/test/CodeGenCXX/ms-thread_local.cpp =================================================================== --- clang/test/CodeGenCXX/ms-thread_local.cpp +++ clang/test/CodeGenCXX/ms-thread_local.cpp @@ -17,10 +17,20 @@ // 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 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-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-LABEL: define internal void @__tls_init() // CHECK: call void @"??__Eb@@YAXXZ" // CHECK-LD-LABEL: define internal void @__tls_init()