diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h --- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h +++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h @@ -14,6 +14,7 @@ #ifndef LLVM_LIB_TARGET_WEBASSEMBLY_MCTARGETDESC_WEBASSEMBLYMCTARGETDESC_H #define LLVM_LIB_TARGET_WEBASSEMBLY_MCTARGETDESC_WEBASSEMBLYMCTARGETDESC_H +#include "../WebAssemblySubtarget.h" #include "llvm/BinaryFormat/Wasm.h" #include "llvm/MC/MCInstrDesc.h" #include "llvm/Support/DataTypes.h" @@ -115,9 +116,6 @@ #define GET_INSTRINFO_ENUM #include "WebAssemblyGenInstrInfo.inc" -#define GET_SUBTARGETINFO_ENUM -#include "WebAssemblyGenSubtargetInfo.inc" - namespace llvm { namespace WebAssembly { diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.h b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.h --- a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.h +++ b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.h @@ -59,7 +59,7 @@ void EmitEndOfAsmFile(Module &M) override; void EmitProducerInfo(Module &M); - void EmitTargetFeatures(); + void EmitTargetFeatures(Module &M); void EmitJumpTableInfo() override; void EmitConstantPool() override; void EmitFunctionBodyStart() override; 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 @@ -33,6 +33,7 @@ #include "llvm/IR/DataLayout.h" #include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/GlobalVariable.h" +#include "llvm/IR/Metadata.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCSectionWasm.h" #include "llvm/MC/MCStreamer.h" @@ -161,7 +162,7 @@ } EmitProducerInfo(M); - EmitTargetFeatures(); + EmitTargetFeatures(M); } void WebAssemblyAsmPrinter::EmitProducerInfo(Module &M) { @@ -215,44 +216,26 @@ } } -void WebAssemblyAsmPrinter::EmitTargetFeatures() { - static const std::pair FeaturePairs[] = { - {WebAssembly::FeatureAtomics, "atomics"}, - {WebAssembly::FeatureBulkMemory, "bulk-memory"}, - {WebAssembly::FeatureExceptionHandling, "exception-handling"}, - {WebAssembly::FeatureNontrappingFPToInt, "nontrapping-fptoint"}, - {WebAssembly::FeatureSignExt, "sign-ext"}, - {WebAssembly::FeatureSIMD128, "simd128"}, - }; - +void WebAssemblyAsmPrinter::EmitTargetFeatures(Module &M) { struct FeatureEntry { uint8_t Prefix; StringRef Name; }; - FeatureBitset UsedFeatures = - static_cast(TM).getUsedFeatures(); - - // Calculate the features and linkage policies to emit + // Read target features and linkage policies from module metadata SmallVector EmittedFeatures; - for (auto &F : FeaturePairs) { + for (const SubtargetFeatureKV &KV : WebAssemblyFeatureKV) { + std::string MDKey = (StringRef("wasm-feature-") + KV.Key).str(); + Metadata *Policy = M.getModuleFlag(MDKey); + if (Policy == nullptr) + continue; + FeatureEntry Entry; - Entry.Name = F.second; - if (F.first == WebAssembly::FeatureAtomics) { - // "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; - 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); - } - } + Entry.Prefix = + cast(cast(Policy)->getValue()) + ->getZExtValue(); + Entry.Name = KV.Key; + EmittedFeatures.push_back(Entry); } // Emit features and linkage policies into the "target_features" section diff --git a/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h b/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h --- a/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h +++ b/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h @@ -22,11 +22,16 @@ #include "llvm/CodeGen/TargetSubtargetInfo.h" #include +#define GET_SUBTARGETINFO_ENUM #define GET_SUBTARGETINFO_HEADER #include "WebAssemblyGenSubtargetInfo.inc" namespace llvm { +// Defined in WebAssemblyGenSubtargetInfo.inc. +extern const SubtargetFeatureKV + WebAssemblyFeatureKV[WebAssembly::NumSubtargetFeatures]; + class WebAssemblySubtarget final : public WebAssemblyGenSubtargetInfo { enum SIMDEnum { NoSIMD, @@ -77,6 +82,7 @@ return &getInstrInfo()->getRegisterInfo(); } const Triple &getTargetTriple() const { return TargetTriple; } + bool enableAtomicExpand() const override; bool enableMachineScheduler() const override; bool useAA() const override; diff --git a/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.cpp b/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.cpp --- a/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.cpp @@ -44,6 +44,11 @@ InstrInfo(initializeSubtargetDependencies(FS)), TSInfo(), TLInfo(TM, *this) {} +bool WebAssemblySubtarget::enableAtomicExpand() const { + // If atomics are disabled, atomic ops are lowered instead of expanded + return hasAtomics(); +} + bool WebAssemblySubtarget::enableMachineScheduler() const { // Disable the MachineScheduler for now. Even with ShouldTrackPressure set and // enableMachineSchedDefaultSched overridden, it appears to have an overall 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 @@ -23,7 +23,6 @@ class WebAssemblyTargetMachine final : public LLVMTargetMachine { std::unique_ptr TLOF; mutable StringMap> SubtargetMap; - mutable FeatureBitset UsedFeatures; public: WebAssemblyTargetMachine(const Target &T, const Triple &TT, StringRef CPU, @@ -46,8 +45,6 @@ return TLOF.get(); } - FeatureBitset getUsedFeatures() const { return UsedFeatures; } - TargetTransformInfo getTargetTransformInfo(const Function &F) override; bool usesPhysRegsForPEI() const override { return false; } 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 @@ -26,6 +26,7 @@ #include "llvm/Support/TargetRegistry.h" #include "llvm/Target/TargetOptions.h" #include "llvm/Transforms/Scalar.h" +#include "llvm/Transforms/Scalar/LowerAtomic.h" #include "llvm/Transforms/Utils.h" using namespace llvm; @@ -117,10 +118,6 @@ initAsmInfo(); - // Create a subtarget using the unmodified target machine features to - // initialize the used feature set with explicitly enabled features. - getSubtargetImpl(getTargetCPU(), getTargetFeatureString()); - // Note that we don't use setRequiresStructuredCFG(true). It disables // optimizations than we're ok with, and want, such as critical edge // splitting and tail merging. @@ -134,7 +131,6 @@ auto &I = SubtargetMap[CPU + FS]; if (!I) { I = llvm::make_unique(TargetTriple, CPU, FS, *this); - UsedFeatures |= I->getFeatureBits(); } return I.get(); } @@ -160,21 +156,120 @@ } namespace { -class StripThreadLocal final : public ModulePass { - // The default thread model for wasm is single, where thread-local variables - // are identical to regular globals and should be treated the same. So this - // pass just converts all GlobalVariables to NotThreadLocal + +class CoalesceFeaturesAndStripAtomics final : public ModulePass { + // Take the union of all features used in the module and use it for each + // function individually, since having multiple feature sets in one module + // currently does not make sense for WebAssembly. If atomics are not enabled, + // also strip atomic operations and thread local storage. static char ID; + WebAssemblyTargetMachine *WasmTM; public: - StripThreadLocal() : ModulePass(ID) {} + CoalesceFeaturesAndStripAtomics(WebAssemblyTargetMachine *WasmTM) + : ModulePass(ID), WasmTM(WasmTM) {} + bool runOnModule(Module &M) override { - for (auto &GV : M.globals()) - GV.setThreadLocalMode(GlobalValue::ThreadLocalMode::NotThreadLocal); + FeatureBitset Features = coalesceFeatures(M); + + std::string FeatureStr = getFeatureString(Features); + for (auto &F : M) + replaceFeatures(F, FeatureStr); + + bool Stripped = false; + if (!Features[WebAssembly::FeatureAtomics]) { + Stripped |= stripAtomics(M); + Stripped |= stripThreadLocals(M); + } + + recordFeatures(M, Features, Stripped); + + // Conservatively assume we have made some change return true; } + +private: + FeatureBitset coalesceFeatures(const Module &M) { + FeatureBitset Features = + WasmTM + ->getSubtargetImpl(WasmTM->getTargetCPU(), + WasmTM->getTargetFeatureString()) + ->getFeatureBits(); + for (auto &F : M) + Features |= WasmTM->getSubtargetImpl(F)->getFeatureBits(); + return Features; + } + + std::string getFeatureString(FeatureBitset Features) { + std::string Ret; + for (const SubtargetFeatureKV &KV : WebAssemblyFeatureKV) { + if (Features[KV.Value]) + Ret += (StringRef("+") + KV.Key + ",").str(); + } + return Ret; + } + + void replaceFeatures(Function &F, const std::string &Features) { + F.removeFnAttr("target-features"); + F.removeFnAttr("target-cpu"); + F.addFnAttr("target-features", Features); + } + + bool stripAtomics(Module &M) { + // Detect whether any atomics will be lowered, since there is no way to tell + // whether the LowerAtomic pass lowers e.g. stores. + bool Stripped = false; + for (auto &F : M) + for (auto &B : F) + for (auto &I : B) + if (I.isAtomic()) { + Stripped = true; + goto done; + } + done: + if (!Stripped) + return false; + + LowerAtomicPass Lowerer; + FunctionAnalysisManager FAM; + for (auto &F : M) + Lowerer.run(F, FAM); + + return true; + } + + bool stripThreadLocals(Module &M) { + bool Stripped = false; + for (auto &GV : M.globals()) { + if (GV.getThreadLocalMode() != + GlobalValue::ThreadLocalMode::NotThreadLocal) { + Stripped = true; + GV.setThreadLocalMode(GlobalValue::ThreadLocalMode::NotThreadLocal); + } + } + return Stripped; + } + + void recordFeatures(Module &M, const FeatureBitset &Features, bool Stripped) { + for (const SubtargetFeatureKV &KV : WebAssemblyFeatureKV) { + if (KV.Value == WebAssembly::FeatureAtomics && Stripped) { + // "atomics" is special: code compiled without atomics may have had its + // atomics lowered to nonatomic operations. In that case, atomics is + // disallowed to prevent unsafe linking with atomics-enabled objects. + assert(!Features[WebAssembly::FeatureAtomics]); + M.addModuleFlag(Module::ModFlagBehavior::Override, + (StringRef("wasm-feature-") + KV.Key).str(), + wasm::WASM_FEATURE_PREFIX_DISALLOWED); + } else if (Features[KV.Value]) { + // Otherwise features are marked Used or not mentioned + M.addModuleFlag(Module::ModFlagBehavior::Error, + (StringRef("wasm-feature-") + KV.Key).str(), + wasm::WASM_FEATURE_PREFIX_USED); + } + } + } }; -char StripThreadLocal::ID = 0; +char CoalesceFeaturesAndStripAtomics::ID = 0; /// WebAssembly Code Generator Pass Configuration Options. class WebAssemblyPassConfig final : public TargetPassConfig { @@ -222,16 +317,11 @@ //===----------------------------------------------------------------------===// void WebAssemblyPassConfig::addIRPasses() { - if (static_cast(TM) - ->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(createLowerAtomicPass()); - addPass(new StripThreadLocal()); - } + // Runs LowerAtomicPass 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()); 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 @@ -1,38 +1,69 @@ ; RUN: llc < %s | FileCheck %s --check-prefixes CHECK,ATTRS ; RUN: llc < %s -mattr=+simd128 | FileCheck %s --check-prefixes CHECK,SIMD128 -; RUN; llc < %s -mattr=+atomics | FileCheck %s --check-prefixes CHECK,ATOMICS ; RUN: llc < %s -mcpu=bleeding-edge | FileCheck %s --check-prefixes CHECK,BLEEDING-EDGE ; Test that codegen emits target features from the command line or -; function attributes correctly. +; function attributes correctly and that features are enabled for the +; entire module if they are enabled for any function in the module. target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" target triple = "wasm32-unknown-unknown" -define void @foo() #0 { +define void @foo(i32* %p1) #0 { + %a = atomicrmw min i32* undef, i32 42 seq_cst + %v = fptoui float undef to i32 + store i32 %v, i32* %p1 ret void } -define void @bar() #1 { +define void @bar(i32* %p1) #1 { + %a = atomicrmw min i32* undef, i32 42 seq_cst + %v = fptoui float undef to i32 + store i32 %v, i32* %p1 ret void } -attributes #0 = { "target-features"="+sign-ext" } +attributes #0 = { "target-features"="+atomics" } attributes #1 = { "target-features"="+nontrapping-fptoint" } + +; CHECK-LABEL: foo: + +; Expanded atomicrmw min +; ATTRS: loop +; ATTRS: i32.atomic.rmw.cmpxchg +; SIMD128-NOT: i32.atomic.rmw.cmpxchg +; ATTRS: end_loop + +; nontrapping fptoint +; ATTRS: i32.trunc_sat_f32_u +; SIMD128-NOT: i32.trunc_sat_f32_u +; ATTRS: i32.store + +; `bar` should be the same as `foo` +; CHECK-LABEL: bar: + +; Expanded atomicrmw min +; ATTRS: loop +; ATTRS: i32.atomic.rmw.cmpxchg +; SIMD128-NOT: i32.atomic.rmw.cmpxchg +; ATTRS: end_loop + +; nontrapping fptoint +; ATTRS: i32.trunc_sat_f32_u +; SIMD128-NOT: i32.trunc_sat_f32_u +; ATTRS: i32.store + ; CHECK-LABEL: .custom_section.target_features,"",@ -; -atomics, +sign_ext -; ATTRS-NEXT: .int8 3 -; ATTRS-NEXT: .int8 45 +; +atomics, +nontrapping-fptoint +; ATTRS-NEXT: .int8 2 +; ATTRS-NEXT: .int8 43 ; ATTRS-NEXT: .int8 7 ; ATTRS-NEXT: .ascii "atomics" ; ATTRS-NEXT: .int8 43 ; ATTRS-NEXT: .int8 19 ; ATTRS-NEXT: .ascii "nontrapping-fptoint" -; ATTRS-NEXT: .int8 43 -; ATTRS-NEXT: int8 8 -; ATTRS-NEXT: .ascii "sign-ext" ; -atomics, +simd128 ; SIMD128-NEXT: .int8 2 @@ -43,15 +74,9 @@ ; SIMD128-NEXT: .int8 7 ; SIMD128-NEXT: .ascii "simd128" -; =atomics -; ATOMICS-NEXT: .int8 1 -; ATOMICS-NEXT: .int8 61 -; 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: ... diff --git a/llvm/utils/TableGen/SubtargetEmitter.cpp b/llvm/utils/TableGen/SubtargetEmitter.cpp --- a/llvm/utils/TableGen/SubtargetEmitter.cpp +++ b/llvm/utils/TableGen/SubtargetEmitter.cpp @@ -149,7 +149,7 @@ unsigned N = DefList.size(); if (N == 0) return; - if (N > MAX_SUBTARGET_FEATURES) + if (N + 1 > MAX_SUBTARGET_FEATURES) PrintFatalError("Too many subtarget features! Bump MAX_SUBTARGET_FEATURES."); OS << "namespace " << Target << " {\n"; @@ -169,6 +169,9 @@ FeatureMap[Def] = i; } + OS << " " + << "NumSubtargetFeatures = " << N << "\n"; + // Close enumeration and namespace OS << "};\n"; OS << "} // end namespace " << Target << "\n";