diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp --- a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp @@ -230,28 +230,25 @@ StringRef Name; }; - FeatureBitset UsedFeatures = - static_cast(TM).getUsedFeatures(); + auto &WasmTM = static_cast(TM); + FeatureBitset UsedFeatures = WasmTM.getUsedFeatures(); // Calculate the features and linkage policies to emit SmallVector EmittedFeatures; for (auto &F : FeaturePairs) { FeatureEntry Entry; Entry.Name = F.second; - if (F.first == WebAssembly::FeatureAtomics) { + if (F.first == WebAssembly::FeatureAtomics && WasmTM.getAtomicsStripped()) { // "atomics" is special: code compiled without atomics may have had its - // atomics lowered to nonatomic operations. Such code would be dangerous - // to mix with proper atomics, so it is always Required or Disallowed. - Entry.Prefix = UsedFeatures[F.first] - ? wasm::WASM_FEATURE_PREFIX_REQUIRED - : wasm::WASM_FEATURE_PREFIX_DISALLOWED; + // atomics lowered to nonatomic operations. In that case, atomics is + // disallowed to prevent unsafe linking with atomics-enabled objects. + assert(!UsedFeatures[F.first]); + Entry.Prefix = wasm::WASM_FEATURE_PREFIX_DISALLOWED; + EmittedFeatures.push_back(Entry); + } else if (UsedFeatures[F.first]) { + // Otherwise features are marked Used or not mentioned + Entry.Prefix = wasm::WASM_FEATURE_PREFIX_USED; EmittedFeatures.push_back(Entry); - } else { - // Other features are marked Used or not mentioned - if (UsedFeatures[F.first]) { - Entry.Prefix = wasm::WASM_FEATURE_PREFIX_USED; - EmittedFeatures.push_back(Entry); - } } } diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.h b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.h --- a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.h +++ b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.h @@ -24,6 +24,7 @@ std::unique_ptr TLOF; mutable StringMap> SubtargetMap; mutable FeatureBitset UsedFeatures; + bool AtomicsStripped = false; public: WebAssemblyTargetMachine(const Target &T, const Triple &TT, StringRef CPU, @@ -47,6 +48,8 @@ } FeatureBitset getUsedFeatures() const { return UsedFeatures; } + void setAtomicsStripped() { AtomicsStripped = true; } + bool getAtomicsStripped() const { return AtomicsStripped; } TargetTransformInfo getTargetTransformInfo(const Function &F) override; 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 @@ -163,17 +163,53 @@ // are identical to regular globals and should be treated the same. So this // pass just converts all GlobalVariables to NotThreadLocal static char ID; + WebAssemblyTargetMachine *WasmTM; public: - StripThreadLocal() : ModulePass(ID) {} + StripThreadLocal(WebAssemblyTargetMachine *WasmTM) + : ModulePass(ID), WasmTM(WasmTM) {} bool runOnModule(Module &M) override { - for (auto &GV : M.globals()) - GV.setThreadLocalMode(GlobalValue::ThreadLocalMode::NotThreadLocal); - return true; + bool Modified = false; + for (auto &GV : M.globals()) { + if (GV.getThreadLocalMode() != + GlobalValue::ThreadLocalMode::NotThreadLocal) { + WasmTM->setAtomicsStripped(); + GV.setThreadLocalMode(GlobalValue::ThreadLocalMode::NotThreadLocal); + Modified = true; + } + } + return Modified; } }; char StripThreadLocal::ID = 0; +class ContainsAtomics final : public ModulePass { + // Detect whether the source module contains atomics before LowerAtomics + // runs. If it does, the resulting object will not be safe to link with + // atomics-enabled objects, but if it does not, such linking should be + // allowed. + static char ID; + WebAssemblyTargetMachine *WasmTM; + +public: + ContainsAtomics(WebAssemblyTargetMachine *WasmTM) + : ModulePass(ID), WasmTM(WasmTM) {} + bool runOnModule(Module &M) override { + for (auto &F : M) + for (auto &B : F) + for (auto &I : B) + if (I.isAtomic()) { + WasmTM->setAtomicsStripped(); + return false; + } + return false; + } + void getAnalysisUsage(AnalysisUsage &Info) const override { + Info.setPreservesAll(); + } +}; +char ContainsAtomics::ID = 0; + /// WebAssembly Code Generator Pass Configuration Options. class WebAssemblyPassConfig final : public TargetPassConfig { public: @@ -220,15 +256,16 @@ //===----------------------------------------------------------------------===// void WebAssemblyPassConfig::addIRPasses() { - if (static_cast(TM) - ->getUsedFeatures()[WebAssembly::FeatureAtomics]) { + auto &WasmTM = getWebAssemblyTargetMachine(); + if (WasmTM.getUsedFeatures()[WebAssembly::FeatureAtomics]) { // Expand some atomic operations. WebAssemblyTargetLowering has hooks which // control specifically what gets lowered. addPass(createAtomicExpandPass()); } else { // If atomics are not enabled, they get lowered to non-atomics. + addPass(new ContainsAtomics(&WasmTM)); addPass(createLowerAtomicPass()); - addPass(new StripThreadLocal()); + addPass(new StripThreadLocal(&WasmTM)); } // Add signatures to prototype-less function declarations diff --git a/llvm/test/CodeGen/WebAssembly/target-features-atomics.ll b/llvm/test/CodeGen/WebAssembly/target-features-atomics.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/WebAssembly/target-features-atomics.ll @@ -0,0 +1,29 @@ +; RUN: llc < %s -mattr=-atomics | FileCheck %s --check-prefixes CHECK,NO-ATOMICS +; RUN: llc < %s -mattr=+atomics | FileCheck %s --check-prefixes CHECK,ATOMICS + +; Test that the target features section contains -atomics or +atomics +; for modules that have atomics in their source. + +target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" +target triple = "wasm32-unknown-unknown" + +define void @foo(i32* %p) { + store atomic i32 0, i32* %p seq_cst, align 4 + ret void +} + +; CHECK-LABEL: .custom_section.target_features,"",@ + +; -atomics +; NO-ATOMICS-NEXT: .int8 1 +; NO-ATOMICS-NEXT: .int8 45 +; NO-ATOMICS-NEXT: .int8 7 +; NO-ATOMICS-NEXT: .ascii "atomics" + +; +atomics +; ATOMICS-NEXT: .int8 1 +; ATOMICS-NEXT: .int8 43 +; ATOMICS-NEXT: .int8 7 +; ATOMICS-NEXT: .ascii "atomics" + +; CHECK-NEXT: .text diff --git a/llvm/test/CodeGen/WebAssembly/target-features-tls.ll b/llvm/test/CodeGen/WebAssembly/target-features-tls.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/WebAssembly/target-features-tls.ll @@ -0,0 +1,26 @@ +; RUN: llc < %s -mattr=-atomics | FileCheck %s --check-prefixes CHECK,NO-ATOMICS +; RUN: llc < %s -mattr=+atomics | FileCheck %s --check-prefixes CHECK,ATOMICS + +; Test that the target features section contains -atomics or +atomics +; for modules that have thread local storage in their source. + +target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" +target triple = "wasm32-unknown-unknown" + +@foo = internal thread_local global i32 0 + +; CHECK-LABEL: .custom_section.target_features,"",@ + +; -atomics +; NO-ATOMICS-NEXT: .int8 1 +; NO-ATOMICS-NEXT: .int8 45 +; NO-ATOMICS-NEXT: .int8 7 +; NO-ATOMICS-NEXT: .ascii "atomics" +; NO-ATOMICS-NEXT: .bss.foo,"",@ + +; +atomics +; ATOMICS-NEXT: .int8 1 +; ATOMICS-NEXT: .int8 43 +; ATOMICS-NEXT: .int8 7 +; ATOMICS-NEXT: .ascii "atomics" +; ATOMICS-NEXT: .tbss.foo,"",@ diff --git a/llvm/test/CodeGen/WebAssembly/target-features.ll b/llvm/test/CodeGen/WebAssembly/target-features.ll --- a/llvm/test/CodeGen/WebAssembly/target-features.ll +++ b/llvm/test/CodeGen/WebAssembly/target-features.ll @@ -22,11 +22,8 @@ ; CHECK-LABEL: .custom_section.target_features,"",@ -; -atomics, +sign_ext -; ATTRS-NEXT: .int8 3 -; ATTRS-NEXT: .int8 45 -; ATTRS-NEXT: .int8 7 -; ATTRS-NEXT: .ascii "atomics" +; +sign_ext +; ATTRS-NEXT: .int8 2 ; ATTRS-NEXT: .int8 43 ; ATTRS-NEXT: .int8 19 ; ATTRS-NEXT: .ascii "nontrapping-fptoint" @@ -34,24 +31,21 @@ ; ATTRS-NEXT: int8 8 ; ATTRS-NEXT: .ascii "sign-ext" -; -atomics, +simd128 -; SIMD128-NEXT: .int8 2 -; SIMD128-NEXT: .int8 45 -; SIMD128-NEXT: .int8 7 -; SIMD128-NEXT: .ascii "atomics" +; +simd128 +; SIMD128-NEXT: .int8 1 ; SIMD128-NEXT: .int8 43 ; SIMD128-NEXT: .int8 7 ; SIMD128-NEXT: .ascii "simd128" -; =atomics +; +atomics ; ATOMICS-NEXT: .int8 1 -; ATOMICS-NEXT: .int8 61 +; ATOMICS-NEXT: .int8 43 ; ATOMICS-NEXT: .int8 7 ; ATOMICS-NEXT: .ascii "atomics" -; =atomics, +nontrapping-fptoint, +sign-ext, +simd128 +; +atomics, +nontrapping-fptoint, +sign-ext, +simd128 ; BLEEDING-EDGE-NEXT: .int8 4 -; BLEEDING-EDGE-NEXT: .int8 61 +; BLEEDING-EDGE-NEXT: .int8 43 ; BLEEDING-EDGE-NEXT: .int8 7 ; BLEEDING-EDGE-NEXT: .ascii "atomics" ; BLEEDING-EDGE-NEXT: .int8 43 diff --git a/llvm/test/MC/WebAssembly/array-fill.ll b/llvm/test/MC/WebAssembly/array-fill.ll --- a/llvm/test/MC/WebAssembly/array-fill.ll +++ b/llvm/test/MC/WebAssembly/array-fill.ll @@ -26,7 +26,5 @@ ; CHECK-NEXT: Flags: [ ] ; CHECK-NEXT: - Type: CUSTOM ; CHECK-NEXT: Name: target_features -; CHECK-NEXT: Features: -; CHECK-NEXT: - Prefix: DISALLOWED -; CHECK-NEXT: Name: atomics +; CHECK-NEXT: Features: [] ; CHECK-NEXT: ... diff --git a/llvm/test/MC/WebAssembly/assembler-binary.ll b/llvm/test/MC/WebAssembly/assembler-binary.ll --- a/llvm/test/MC/WebAssembly/assembler-binary.ll +++ b/llvm/test/MC/WebAssembly/assembler-binary.ll @@ -89,7 +89,5 @@ ; CHECK-NEXT: Function: 0 ; CHECK-NEXT: - Type: CUSTOM ; CHECK-NEXT: Name: target_features -; CHECK-NEXT: Features: -; CHECK-NEXT: - Prefix: DISALLOWED -; CHECK-NEXT: Name: atomics +; CHECK-NEXT: Features: [] ; CHECK-NEXT: ... diff --git a/llvm/test/MC/WebAssembly/bss.ll b/llvm/test/MC/WebAssembly/bss.ll --- a/llvm/test/MC/WebAssembly/bss.ll +++ b/llvm/test/MC/WebAssembly/bss.ll @@ -80,7 +80,5 @@ ; CHECK-NEXT: Flags: [ ] ; CHECK-NEXT: - Type: CUSTOM ; CHECK-NEXT: Name: target_features -; CHECK-NEXT: Features: -; CHECK-NEXT: - Prefix: DISALLOWED -; CHECK-NEXT: Name: atomics +; CHECK-NEXT: Features: [] ; CHECK-NEXT: ... diff --git a/llvm/test/MC/WebAssembly/comdat.ll b/llvm/test/MC/WebAssembly/comdat.ll --- a/llvm/test/MC/WebAssembly/comdat.ll +++ b/llvm/test/MC/WebAssembly/comdat.ll @@ -121,7 +121,5 @@ ; CHECK-NEXT: Index: 0 ; CHECK-NEXT: - Type: CUSTOM ; CHECK-NEXT: Name: target_features -; CHECK-NEXT: Features: -; CHECK-NEXT: - Prefix: DISALLOWED -; CHECK-NEXT: Name: atomics +; CHECK-NEXT: Features: [] ; CHECK-NEXT: ... diff --git a/llvm/test/MC/WebAssembly/debug-info.ll b/llvm/test/MC/WebAssembly/debug-info.ll --- a/llvm/test/MC/WebAssembly/debug-info.ll +++ b/llvm/test/MC/WebAssembly/debug-info.ll @@ -132,7 +132,7 @@ ; CHECK-NEXT: } ; CHECK-NEXT: Section { ; CHECK-NEXT: Type: CUSTOM (0x0) -; CHECK-NEXT: Size: 10 +; CHECK-NEXT: Size: 1 ; CHECK-NEXT: Offset: 1114 ; CHECK-NEXT: Name: target_features ; CHECK-NEXT: } diff --git a/llvm/test/MC/WebAssembly/explicit-sections.ll b/llvm/test/MC/WebAssembly/explicit-sections.ll --- a/llvm/test/MC/WebAssembly/explicit-sections.ll +++ b/llvm/test/MC/WebAssembly/explicit-sections.ll @@ -72,7 +72,5 @@ ; CHECK-NEXT: Flags: [ ] ; CHECK-NEXT: - Type: CUSTOM ; CHECK-NEXT: Name: target_features -; CHECK-NEXT: Features: -; CHECK-NEXT: - Prefix: DISALLOWED -; CHECK-NEXT: Name: atomics +; CHECK-NEXT: Features: [] ; CHECK-NEXT: ... diff --git a/llvm/test/MC/WebAssembly/global-ctor-dtor.ll b/llvm/test/MC/WebAssembly/global-ctor-dtor.ll --- a/llvm/test/MC/WebAssembly/global-ctor-dtor.ll +++ b/llvm/test/MC/WebAssembly/global-ctor-dtor.ll @@ -183,7 +183,5 @@ ; CHECK-NEXT: Symbol: 7 ; CHECK-NEXT: - Type: CUSTOM ; CHECK-NEXT: Name: target_features -; CHECK-NEXT: Features: -; CHECK-NEXT: - Prefix: DISALLOWED -; CHECK-NEXT: Name: atomics +; CHECK-NEXT: Features: [] ; CHECK-NEXT: ... diff --git a/llvm/test/MC/WebAssembly/visibility.ll b/llvm/test/MC/WebAssembly/visibility.ll --- a/llvm/test/MC/WebAssembly/visibility.ll +++ b/llvm/test/MC/WebAssembly/visibility.ll @@ -27,7 +27,5 @@ ; CHECK-NEXT: Function: 1 ; CHECK-NEXT: - Type: CUSTOM ; CHECK-NEXT: Name: target_features -; CHECK-NEXT: Features: -; CHECK-NEXT: - Prefix: DISALLOWED -; CHECK-NEXT: Name: atomics +; CHECK-NEXT: Features: [] ; CHECK-NEXT: ... diff --git a/llvm/test/MC/WebAssembly/weak-alias.ll b/llvm/test/MC/WebAssembly/weak-alias.ll --- a/llvm/test/MC/WebAssembly/weak-alias.ll +++ b/llvm/test/MC/WebAssembly/weak-alias.ll @@ -209,9 +209,7 @@ ; CHECK-NEXT: Flags: [ ] ; CHECK-NEXT: - Type: CUSTOM ; CHECK-NEXT: Name: target_features -; CHECK-NEXT: Features: -; CHECK-NEXT: - Prefix: DISALLOWED -; CHECK-NEXT: Name: atomics +; CHECK-NEXT: Features: [] ; CHECK-NEXT: ... ; CHECK-SYMS: SYMBOL TABLE: diff --git a/llvm/test/MC/WebAssembly/weak.ll b/llvm/test/MC/WebAssembly/weak.ll --- a/llvm/test/MC/WebAssembly/weak.ll +++ b/llvm/test/MC/WebAssembly/weak.ll @@ -32,7 +32,5 @@ ; CHECK-NEXT: Flags: [ BINDING_WEAK, UNDEFINED ] ; CHECK-NEXT: - Type: CUSTOM ; CHECK-NEXT: Name: target_features -; CHECK-NEXT: Features: -; CHECK-NEXT: - Prefix: DISALLOWED -; CHECK-NEXT: Name: atomics +; CHECK-NEXT: Features: [] ; CHECK-NEXT: ...