https://github.com/Sp0tless updated https://github.com/llvm/llvm-project/pull/220215
>From 90b512b3c85b0d12e3b22264122b7d43652ea1f4 Mon Sep 17 00:00:00 2001 From: Sp0tless <[email protected]> Date: Mon, 31 Aug 2026 20:00:25 +0800 Subject: [PATCH] [Clang][MSVC] Avoid native CRT TLS accesses with emulated TLS --- clang/lib/CodeGen/MicrosoftCXXABI.cpp | 38 ++++++++++++------- .../CodeGenCXX/microsoft-abi-emulated-tls.cpp | 28 ++++++++++++++ 2 files changed, 53 insertions(+), 13 deletions(-) create mode 100644 clang/test/CodeGenCXX/microsoft-abi-emulated-tls.cpp diff --git a/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/clang/lib/CodeGen/MicrosoftCXXABI.cpp index 8b43dd887573d..4ae9ea7ec18c9 100644 --- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp @@ -2531,19 +2531,23 @@ static void emitTlsGuardCheck(CodeGenFunction &CGF, llvm::GlobalValue *TlsGuard, CGF.Builder.CreateCondBr(CmpResult, DynInitBB, ContinueBB); } -static void emitDynamicTlsInitializationCall(CodeGenFunction &CGF, - llvm::GlobalValue *TlsGuard, - llvm::BasicBlock *ContinueBB) { +static void emitDynamicTlsInitializationCall(CodeGenFunction &CGF) { 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) { + if (CGF.CGM.getCodeGenOpts().EmulatedTLS) { + // __tls_guard is native TLS owned by the MSVC runtime and does not have an + // emutls descriptor. The runtime helper performs the same guard check, so + // call it directly rather than emitting a reference to __tls_guard. + emitDynamicTlsInitializationCall(CGF); + return; + } + llvm::BasicBlock *DynInitBB = CGF.createBasicBlock("dyntls.dyn_init", CGF.CurFn); llvm::BasicBlock *ContinueBB = @@ -2553,7 +2557,8 @@ static void emitDynamicTlsInitialization(CodeGenFunction &CGF) { emitTlsGuardCheck(CGF, TlsGuard, DynInitBB, ContinueBB); CGF.Builder.SetInsertPoint(DynInitBB); - emitDynamicTlsInitializationCall(CGF, TlsGuard, ContinueBB); + emitDynamicTlsInitializationCall(CGF); + CGF.Builder.CreateBr(ContinueBB); CGF.Builder.SetInsertPoint(ContinueBB); } @@ -2791,13 +2796,20 @@ void MicrosoftCXXABI::EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D, // The algorithm is almost identical to what can be found in the appendix // found in N2325. - // This BasicBLock determines whether or not we have any work to do. - llvm::LoadInst *FirstGuardLoad = Builder.CreateLoad(GuardAddr); - FirstGuardLoad->setOrdering(llvm::AtomicOrdering::Unordered); - llvm::LoadInst *InitThreadEpoch = - Builder.CreateLoad(getInitThreadEpochPtr(CGM)); - llvm::Value *IsUninitialized = - Builder.CreateICmpSGT(FirstGuardLoad, InitThreadEpoch); + llvm::Value *IsUninitialized; + if (CGM.getCodeGenOpts().EmulatedTLS) { + // _Init_thread_epoch is native TLS owned by the MSVC runtime. It does + // not have an emutls descriptor. Without its per-thread epoch, enter the + // runtime on every access to preserve its synchronization guarantees. + IsUninitialized = Builder.getTrue(); + } else { + // This test determines whether or not we have any work to do. + llvm::LoadInst *FirstGuardLoad = Builder.CreateLoad(GuardAddr); + FirstGuardLoad->setOrdering(llvm::AtomicOrdering::Unordered); + llvm::LoadInst *InitThreadEpoch = + Builder.CreateLoad(getInitThreadEpochPtr(CGM)); + IsUninitialized = Builder.CreateICmpSGT(FirstGuardLoad, InitThreadEpoch); + } llvm::BasicBlock *AttemptInitBlock = CGF.createBasicBlock("init.attempt"); llvm::BasicBlock *EndBlock = CGF.createBasicBlock("init.end"); CGF.EmitCXXGuardedInitBranch(IsUninitialized, AttemptInitBlock, EndBlock, diff --git a/clang/test/CodeGenCXX/microsoft-abi-emulated-tls.cpp b/clang/test/CodeGenCXX/microsoft-abi-emulated-tls.cpp new file mode 100644 index 0000000000000..0579660dbf5c2 --- /dev/null +++ b/clang/test/CodeGenCXX/microsoft-abi-emulated-tls.cpp @@ -0,0 +1,28 @@ +// RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -std=c++11 \ +// RUN: -fms-compatibility-version=19.25 -femulated-tls \ +// RUN: -emit-llvm -o - %s | FileCheck \ +// RUN: --implicit-check-not=_Init_thread_epoch \ +// RUN: --implicit-check-not=__tls_guard %s + +int make_value(); + +// CHECK-DAG: @"__tls_init$initializer$" = internal constant ptr @__tls_init, section ".CRT$XDU" +// CHECK-LABEL: define dso_local noundef i32 @"?guarded_value@@YAHXZ"() +// CHECK: br i1 true, label %[[ATTEMPT:[a-z.]+]], label %[[END:[a-z.]+]] +// CHECK: [[ATTEMPT]]: +// CHECK: call void @_Init_thread_header +// CHECK: call void @_Init_thread_footer +// CHECK: [[END]]: +int guarded_value() { + static int value = make_value(); + return value; +} + +int make_tls_value(); +thread_local int dynamic_tls = make_tls_value(); + +// CHECK-LABEL: define dso_local noundef i32 @"?read_dynamic_tls@@YAHXZ"() +// CHECK-NEXT: entry: +// CHECK-NEXT: call void @__dyn_tls_on_demand_init() +// CHECK: call align 4 ptr @llvm.threadlocal.address.p0(ptr align 4 @"?dynamic_tls@@3HA") +int read_dynamic_tls() { return dynamic_tls; } _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
