diff --git a/llvm/lib/CodeGen/WasmEHPrepare.cpp b/llvm/lib/CodeGen/WasmEHPrepare.cpp --- a/llvm/lib/CodeGen/WasmEHPrepare.cpp +++ b/llvm/lib/CodeGen/WasmEHPrepare.cpp @@ -213,19 +213,13 @@ assert(F.hasPersonalityFn() && "Personality function not found"); // __wasm_lpad_context global variable. - // If the target supports TLS, make this thread-local. We can't just - // unconditionally make it thread-local and depend on - // CoalesceFeaturesAndStripAtomics to downgrade it, because stripping TLS has - // the side effect of disallowing the object from being linked into a - // shared-memory module, which we don't want to be responsible for. + // This variable should be thread local. If the target does not support TLS, + // we depend on CoalesceFeaturesAndStripAtomics to downgrade it to + // non-thread-local ones, in which case we don't allow this object to be + // linked with other objects using shared memory. LPadContextGV = cast( M.getOrInsertGlobal("__wasm_lpad_context", LPadContextTy)); - Attribute FSAttr = F.getFnAttribute("target-features"); - if (FSAttr.isValid()) { - StringRef FS = FSAttr.getValueAsString(); - if (FS.contains("+atomics") && FS.contains("+bulk-memory")) - LPadContextGV->setThreadLocalMode(GlobalValue::GeneralDynamicTLSModel); - } + LPadContextGV->setThreadLocalMode(GlobalValue::GeneralDynamicTLSModel); LPadIndexField = IRB.CreateConstGEP2_32(LPadContextTy, LPadContextGV, 0, 0, "lpad_index_gep"); diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp --- a/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp @@ -406,8 +406,9 @@ return true; } -// Get a global variable with the given name. If it doesn't exist declare it, -// which will generate an import and assume that it will exist at link time. +// Get a thread-local global variable with the given name. If it doesn't exist +// declare it, which will generate an import and assume that it will exist at +// link time. static GlobalVariable *getGlobalVariable(Module &M, Type *Ty, WebAssemblyTargetMachine &TM, const char *Name) { @@ -415,16 +416,11 @@ if (!GV) report_fatal_error(Twine("unable to create global: ") + Name); - // If the target supports TLS, make this variable thread-local. We can't just - // unconditionally make it thread-local and depend on - // CoalesceFeaturesAndStripAtomics to downgrade it, because stripping TLS has - // the side effect of disallowing the object from being linked into a - // shared-memory module, which we don't want to be responsible for. - auto *Subtarget = TM.getSubtargetImpl(); - auto TLS = Subtarget->hasAtomics() && Subtarget->hasBulkMemory() - ? GlobalValue::GeneralDynamicTLSModel - : GlobalValue::NotThreadLocal; - GV->setThreadLocalMode(TLS); + // Variables created by this function are thread local. If the target does not + // support TLS, we depend on CoalesceFeaturesAndStripAtomics to downgrade it + // to non-thread-local ones, in which case we don't allow this object to be + // linked with other objects using shared memory. + GV->setThreadLocalMode(GlobalValue::GeneralDynamicTLSModel); return GV; } @@ -1064,22 +1060,16 @@ nullifySetjmp(F); } - if (!Changed) { - // Delete unused global variables and functions - if (ResumeF) - ResumeF->eraseFromParent(); - if (EHTypeIDF) - EHTypeIDF->eraseFromParent(); - if (EmLongjmpF) - EmLongjmpF->eraseFromParent(); - if (SaveSetjmpF) - SaveSetjmpF->eraseFromParent(); - if (TestSetjmpF) - TestSetjmpF->eraseFromParent(); - return false; - } + // Delete unused global variables and functions + for (auto *V : {ThrewGV, ThrewValueGV}) + if (V && V->use_empty()) + V->eraseFromParent(); + for (auto *V : {GetTempRet0F, SetTempRet0F, ResumeF, EHTypeIDF, EmLongjmpF, + SaveSetjmpF, TestSetjmpF, WasmLongjmpF, CatchF}) + if (V && V->use_empty()) + V->eraseFromParent(); - return true; + return Changed; } bool WebAssemblyLowerEmscriptenEHSjLj::runEHOnFunction(Function &F) { @@ -1829,7 +1819,8 @@ if (auto *CPI = dyn_cast(FromPad)) { UnwindDest = CPI->getCatchSwitch()->getUnwindDest(); break; - } else if (auto *CPI = dyn_cast(FromPad)) { + } + if (auto *CPI = dyn_cast(FromPad)) { // getCleanupRetUnwindDest() can return nullptr when // 1. This cleanuppad's matching cleanupret uwninds to caller // 2. There is no matching cleanupret because it ends with diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp --- a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp @@ -320,6 +320,7 @@ FunctionPass *createTargetRegisterAllocator(bool) override; void addIRPasses() override; + void addISelPrepare() override; bool addInstSelector() override; void addPostRegAlloc() override; bool addGCPasses() override { return false; } @@ -407,12 +408,6 @@ //===----------------------------------------------------------------------===// void WebAssemblyPassConfig::addIRPasses() { - // Lower atomics and TLS if necessary - addPass(new CoalesceFeaturesAndStripAtomics(&getWebAssemblyTargetMachine())); - - // This is a no-op if atomics are not used in the module - addPass(createAtomicExpandPass()); - // Add signatures to prototype-less function declarations addPass(createWebAssemblyAddMissingPrototypes()); @@ -455,6 +450,16 @@ TargetPassConfig::addIRPasses(); } +void WebAssemblyPassConfig::addISelPrepare() { + // Lower atomics and TLS if necessary + addPass(new CoalesceFeaturesAndStripAtomics(&getWebAssemblyTargetMachine())); + + // This is a no-op if atomics are not used in the module + addPass(createAtomicExpandPass()); + + TargetPassConfig::addISelPrepare(); +} + bool WebAssemblyPassConfig::addInstSelector() { (void)TargetPassConfig::addInstSelector(); addPass( diff --git a/llvm/test/CodeGen/WebAssembly/lower-em-exceptions.ll b/llvm/test/CodeGen/WebAssembly/lower-em-exceptions.ll --- a/llvm/test/CodeGen/WebAssembly/lower-em-exceptions.ll +++ b/llvm/test/CodeGen/WebAssembly/lower-em-exceptions.ll @@ -1,16 +1,15 @@ -; RUN: opt < %s -wasm-lower-em-ehsjlj -enable-emscripten-cxx-exceptions -S | FileCheck %s --check-prefixes=CHECK,NO-TLS -DPTR=i32 -; RUN: opt < %s -wasm-lower-em-ehsjlj -enable-emscripten-cxx-exceptions -S --mattr=+atomics,+bulk-memory | FileCheck %s --check-prefixes=CHECK,TLS -DPTR=i32 -; RUN: opt < %s -wasm-lower-em-ehsjlj -enable-emscripten-cxx-exceptions --mtriple=wasm64-unknown-unknown -data-layout="e-m:e-p:64:64-i64:64-n32:64-S128" -S | FileCheck %s --check-prefixes=CHECK -DPTR=i64 +; RUN: opt < %s -wasm-lower-em-ehsjlj -enable-emscripten-cxx-exceptions -S | FileCheck %s -DPTR=i32 +; RUN: opt < %s -wasm-lower-em-ehsjlj -enable-emscripten-cxx-exceptions -S --mattr=+atomics,+bulk-memory | FileCheck %s -DPTR=i32 +; RUN: opt < %s -wasm-lower-em-ehsjlj -enable-emscripten-cxx-exceptions --mtriple=wasm64-unknown-unknown -data-layout="e-m:e-p:64:64-i64:64-n32:64-S128" -S | FileCheck %s -DPTR=i64 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" target triple = "wasm32-unknown-unknown" @_ZTIi = external constant i8* @_ZTIc = external constant i8* -; NO-TLS-DAG: __THREW__ = external global [[PTR]] -; NO-TLS-DAG: __threwValue = external global i32 -; TLS-DAG: __THREW__ = external thread_local global [[PTR]] -; TLS-DAG: __threwValue = external thread_local global i32 +; CHECK: @__THREW__ = external thread_local global [[PTR]] +; __threwValue is only used in Emscripten SjLj, so it shouldn't be generated. +; CHECK-NOT: @__threwValue = ; Test invoke instruction with clauses (try-catch block) define void @clause() personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) { @@ -172,7 +171,6 @@ ; JS glue functions and invoke wrappers declaration ; CHECK-DAG: declare i32 @getTempRet0() -; CHECK-DAG: declare void @setTempRet0(i32) ; CHECK-DAG: declare void @__resumeException(i8*) ; CHECK-DAG: declare void @__invoke_void_i32(void (i32)*, i32) ; CHECK-DAG: declare i8* @__cxa_find_matching_catch_4(i8*, i8*) diff --git a/llvm/test/CodeGen/WebAssembly/lower-em-sjlj.ll b/llvm/test/CodeGen/WebAssembly/lower-em-sjlj.ll --- a/llvm/test/CodeGen/WebAssembly/lower-em-sjlj.ll +++ b/llvm/test/CodeGen/WebAssembly/lower-em-sjlj.ll @@ -1,6 +1,6 @@ -; RUN: opt < %s -wasm-lower-em-ehsjlj -enable-emscripten-sjlj -S | FileCheck %s --check-prefixes=CHECK,NO-TLS -DPTR=i32 -; RUN: opt < %s -wasm-lower-em-ehsjlj -enable-emscripten-sjlj -S --mattr=+atomics,+bulk-memory | FileCheck %s --check-prefixes=CHECK,TLS -DPTR=i32 -; RUN: opt < %s -wasm-lower-em-ehsjlj -enable-emscripten-sjlj --mtriple=wasm64-unknown-unknown -data-layout="e-m:e-p:64:64-i64:64-n32:64-S128" -S | FileCheck %s --check-prefixes=CHECK -DPTR=i64 +; RUN: opt < %s -wasm-lower-em-ehsjlj -enable-emscripten-sjlj -S | FileCheck %s -DPTR=i32 +; RUN: opt < %s -wasm-lower-em-ehsjlj -enable-emscripten-sjlj -S --mattr=+atomics,+bulk-memory | FileCheck %s -DPTR=i32 +; RUN: opt < %s -wasm-lower-em-ehsjlj -enable-emscripten-sjlj --mtriple=wasm64-unknown-unknown -data-layout="e-m:e-p:64:64-i64:64-n32:64-S128" -S | FileCheck %s -DPTR=i64 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" target triple = "wasm32-unknown-unknown" @@ -8,11 +8,9 @@ %struct.__jmp_buf_tag = type { [6 x i32], i32, [32 x i32] } @global_var = global i32 0, align 4 -; NO-TLS-DAG: __THREW__ = external global [[PTR]] -; NO-TLS-DAG: __threwValue = external global [[PTR]] -; TLS-DAG: __THREW__ = external thread_local global [[PTR]] -; TLS-DAG: __threwValue = external thread_local global [[PTR]] @global_longjmp_ptr = global void (%struct.__jmp_buf_tag*, i32)* @longjmp, align 4 +; CHECK-DAG: @__THREW__ = external thread_local global [[PTR]] +; CHECK-DAG: @__threwValue = external thread_local global i32 ; CHECK-DAG: @global_longjmp_ptr = global void (%struct.__jmp_buf_tag*, i32)* bitcast (void ([[PTR]], i32)* @emscripten_longjmp to void (%struct.__jmp_buf_tag*, i32)*) ; Test a simple setjmp - longjmp sequence diff --git a/llvm/test/CodeGen/WebAssembly/lower-wasm-sjlj.ll b/llvm/test/CodeGen/WebAssembly/lower-wasm-sjlj.ll --- a/llvm/test/CodeGen/WebAssembly/lower-wasm-sjlj.ll +++ b/llvm/test/CodeGen/WebAssembly/lower-wasm-sjlj.ll @@ -1,16 +1,16 @@ -; RUN: opt < %s -wasm-lower-em-ehsjlj -wasm-enable-sjlj -S | FileCheck %s --check-prefixes=CHECK,NO-TLS -DPTR=i32 -; RUN: opt < %s -wasm-lower-em-ehsjlj -wasm-enable-sjlj -S --mattr=+atomics,+bulk-memory | FileCheck %s --check-prefixes=CHECK,TLS -DPTR=i32 -; RUN: opt < %s -wasm-lower-em-ehsjlj -wasm-enable-sjlj --mtriple=wasm64-unknown-unknown -data-layout="e-m:e-p:64:64-i64:64-n32:64-S128" -S | FileCheck %s --check-prefixes CHECK -DPTR=i64 +; RUN: opt < %s -wasm-lower-em-ehsjlj -wasm-enable-sjlj -S | FileCheck %s -DPTR=i32 +; RUN: opt < %s -wasm-lower-em-ehsjlj -wasm-enable-sjlj -S --mattr=+atomics,+bulk-memory | FileCheck %s -DPTR=i32 +; RUN: opt < %s -wasm-lower-em-ehsjlj -wasm-enable-sjlj --mtriple=wasm64-unknown-unknown -data-layout="e-m:e-p:64:64-i64:64-n32:64-S128" -S | FileCheck %s -DPTR=i64 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" target triple = "wasm32-unknown-unknown" %struct.__jmp_buf_tag = type { [6 x i32], i32, [32 x i32] } -; NO-TLS-DAG: __THREW__ = external global [[PTR]] -; NO-TLS-DAG: __threwValue = external global [[PTR]] -; TLS-DAG: __THREW__ = external thread_local global [[PTR]] -; TLS-DAG: __threwValue = external thread_local global [[PTR]] +; These variables are only used in Emscripten EH/SjLj, so they shouldn't be +; generated. +; CHECK-NOT: @__THREW__ = +; CHECK-NOT: @__threwValue = @global_longjmp_ptr = global void (%struct.__jmp_buf_tag*, i32)* @longjmp, align 4 ; CHECK-DAG: @global_longjmp_ptr = global void (%struct.__jmp_buf_tag*, i32)* bitcast (void (i8*, i32)* @__wasm_longjmp to void (%struct.__jmp_buf_tag*, i32)*) @@ -157,7 +157,6 @@ ; JS glue function declarations ; CHECK-DAG: declare i32 @getTempRet0() -; CHECK-DAG: declare void @setTempRet0(i32) ; CHECK-DAG: declare i32* @saveSetjmp(%struct.__jmp_buf_tag*, i32, i32*, i32) ; CHECK-DAG: declare i32 @testSetjmp([[PTR]], i32*, i32) ; CHECK-DAG: declare void @__wasm_longjmp(i8*, i32) diff --git a/llvm/test/CodeGen/WebAssembly/wasmehprepare.ll b/llvm/test/CodeGen/WebAssembly/wasmehprepare.ll --- a/llvm/test/CodeGen/WebAssembly/wasmehprepare.ll +++ b/llvm/test/CodeGen/WebAssembly/wasmehprepare.ll @@ -1,11 +1,10 @@ -; RUN: opt < %s -winehprepare -demote-catchswitch-only -wasmehprepare -S | FileCheck %s --check-prefixes=CHECK,NO-TLS -; RUN: opt < %s -winehprepare -demote-catchswitch-only -wasmehprepare -S --mattr=+atomics,+bulk-memory | FileCheck %s --check-prefixes=CHECK,TLS +; RUN: opt < %s -winehprepare -demote-catchswitch-only -wasmehprepare -S | FileCheck %s +; RUN: opt < %s -winehprepare -demote-catchswitch-only -wasmehprepare -S --mattr=+atomics,+bulk-memory | FileCheck %s target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" target triple = "wasm32-unknown-unknown" -; NO-TLS: @__wasm_lpad_context = external global { i32, i8*, i32 } -; TLS: @__wasm_lpad_context = external thread_local global { i32, i8*, i32 } +; CHECK: @__wasm_lpad_context = external thread_local global { i32, i8*, i32 } @_ZTIi = external constant i8* %struct.Temp = type { i8 }