]> granicus.if.org Git - llvm/commitdiff
[WebAssembly] Merge used feature sets, update atomics linkage policy
authorThomas Lively <tlively@google.com>
Fri, 29 Mar 2019 00:14:01 +0000 (00:14 +0000)
committerThomas Lively <tlively@google.com>
Fri, 29 Mar 2019 00:14:01 +0000 (00:14 +0000)
Summary:
It does not currently make sense to use WebAssembly features in some functions
but not others, so this CL adds an IR pass that takes the union of all used
feature sets and applies it to each function in the module. This allows us to
prevent atomics from being lowered away if some function has opted in to using
them. When atomics is not enabled anywhere, we detect whether there exists any
atomic operations or thread local storage that would be stripped and disallow
linking with objects that contain atomics if and only if atomics or tls are
stripped. When atomics is enabled, mark it as used but do not require it of
other objects in the link. These changes allow libraries that do not use atomics
to be built once and linked into both single-threaded and multithreaded
binaries.

Reviewers: aheejin, sbc100, dschuff

Subscribers: jgravelle-google, hiraditya, sunfish, jfb, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D59625

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@357226 91177308-0d34-0410-b5e6-96231b3b80d8

20 files changed:
lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h
lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
lib/Target/WebAssembly/WebAssemblyAsmPrinter.h
lib/Target/WebAssembly/WebAssemblySubtarget.cpp
lib/Target/WebAssembly/WebAssemblySubtarget.h
lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
lib/Target/WebAssembly/WebAssemblyTargetMachine.h
test/CodeGen/WebAssembly/target-features-tls.ll [new file with mode: 0644]
test/CodeGen/WebAssembly/target-features.ll
test/MC/WebAssembly/array-fill.ll
test/MC/WebAssembly/assembler-binary.ll
test/MC/WebAssembly/bss.ll
test/MC/WebAssembly/comdat.ll
test/MC/WebAssembly/debug-info.ll
test/MC/WebAssembly/explicit-sections.ll
test/MC/WebAssembly/global-ctor-dtor.ll
test/MC/WebAssembly/visibility.ll
test/MC/WebAssembly/weak-alias.ll
test/MC/WebAssembly/weak.ll
utils/TableGen/SubtargetEmitter.cpp

index 303fd3ed265a79a56a809527b3ccaeb6baec2ce9..7d12dd7633ac9eb104275771ceaf28c6ff1e113b 100644 (file)
@@ -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 @@ enum TOF {
 #define GET_INSTRINFO_ENUM
 #include "WebAssemblyGenInstrInfo.inc"
 
-#define GET_SUBTARGETINFO_ENUM
-#include "WebAssemblyGenSubtargetInfo.inc"
-
 namespace llvm {
 namespace WebAssembly {
 
index e4129276b8465643fe3d3afb59f1999c5102ce83..2e6de3cd9f2ad565863751be853387b09a4da8a2 100644 (file)
@@ -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 @@ void WebAssemblyAsmPrinter::EmitEndOfAsmFile(Module &M) {
   }
 
   EmitProducerInfo(M);
-  EmitTargetFeatures();
+  EmitTargetFeatures(M);
 }
 
 void WebAssemblyAsmPrinter::EmitProducerInfo(Module &M) {
@@ -215,46 +216,40 @@ void WebAssemblyAsmPrinter::EmitProducerInfo(Module &M) {
   }
 }
 
-void WebAssemblyAsmPrinter::EmitTargetFeatures() {
-  static const std::pair<unsigned, const char *> 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<WebAssemblyTargetMachine &>(TM).getUsedFeatures();
-
-  // Calculate the features and linkage policies to emit
+  // Read target features and linkage policies from module metadata
   SmallVector<FeatureEntry, 4> 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 = 0;
+    Entry.Name = KV.Key;
+
+    if (auto *MD = cast<ConstantAsMetadata>(Policy))
+      if (auto *I = cast<ConstantInt>(MD->getValue()))
+        Entry.Prefix = I->getZExtValue();
+
+    // Silently ignore invalid metadata
+    if (Entry.Prefix != wasm::WASM_FEATURE_PREFIX_USED &&
+        Entry.Prefix != wasm::WASM_FEATURE_PREFIX_REQUIRED &&
+        Entry.Prefix != wasm::WASM_FEATURE_PREFIX_DISALLOWED)
+      continue;
+
+    EmittedFeatures.push_back(Entry);
   }
 
+  if (EmittedFeatures.size() == 0)
+    return;
+
   // Emit features and linkage policies into the "target_features" section
   MCSectionWasm *FeaturesSection = OutContext.getWasmSection(
       ".custom_section.target_features", SectionKind::getMetadata());
index 35e7d8d0f669118c4eca5ba177c06f0e108bbb0b..963bfbd0d827fd98b5ac4594b595636ee504a577 100644 (file)
@@ -59,7 +59,7 @@ public:
 
   void EmitEndOfAsmFile(Module &M) override;
   void EmitProducerInfo(Module &M);
-  void EmitTargetFeatures();
+  void EmitTargetFeatures(Module &M);
   void EmitJumpTableInfo() override;
   void EmitConstantPool() override;
   void EmitFunctionBodyStart() override;
index bf2f70ca2000258704d1310dae7546227e92486c..196a74565285eef06841068106a4db19114c3c8f 100644 (file)
@@ -44,6 +44,11 @@ WebAssemblySubtarget::WebAssemblySubtarget(const Triple &TT,
       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
index b6f3e6b4a108483cb4af736293b710dfb1e8ab5a..ae1f3fe39468f20500501f538c75d203568fdd1b 100644 (file)
 #include "llvm/CodeGen/TargetSubtargetInfo.h"
 #include <string>
 
+#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 @@ public:
     return &getInstrInfo()->getRegisterInfo();
   }
   const Triple &getTargetTriple() const { return TargetTriple; }
+  bool enableAtomicExpand() const override;
   bool enableMachineScheduler() const override;
   bool useAA() const override;
 
index 6d9fd0016ce496afbdbf2e28d928ee1cef3c00b8..8a768dbc1046e69bc415840456aea4163523c1b4 100644 (file)
@@ -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 @@ WebAssemblyTargetMachine::WebAssemblyTargetMachine(
 
   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 @@ WebAssemblyTargetMachine::getSubtargetImpl(std::string CPU,
   auto &I = SubtargetMap[CPU + FS];
   if (!I) {
     I = llvm::make_unique<WebAssemblySubtarget>(TargetTriple, CPU, FS, *this);
-    UsedFeatures |= I->getFeatureBits();
   }
   return I.get();
 }
@@ -160,21 +156,123 @@ WebAssemblyTargetMachine::getSubtargetImpl(const Function &F) const {
 }
 
 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(const 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) {
+      std::string MDKey = (StringRef("wasm-feature-") + KV.Key).str();
+      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::Error, MDKey,
+                        wasm::WASM_FEATURE_PREFIX_DISALLOWED);
+      } else if (Features[KV.Value]) {
+        // Otherwise features are marked Used or not mentioned
+        M.addModuleFlag(Module::ModFlagBehavior::Error, MDKey,
+                        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 +320,11 @@ FunctionPass *WebAssemblyPassConfig::createTargetRegisterAllocator(bool) {
 //===----------------------------------------------------------------------===//
 
 void WebAssemblyPassConfig::addIRPasses() {
-  if (static_cast<WebAssemblyTargetMachine *>(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());
index 0f1901020b5c4cab4d775844fa3491c94c6e9d05..850e6b9a9e9e0e29f4e8744b06c11d98958d0447 100644 (file)
@@ -23,7 +23,6 @@ namespace llvm {
 class WebAssemblyTargetMachine final : public LLVMTargetMachine {
   std::unique_ptr<TargetLoweringObjectFile> TLOF;
   mutable StringMap<std::unique_ptr<WebAssemblySubtarget>> SubtargetMap;
-  mutable FeatureBitset UsedFeatures;
 
 public:
   WebAssemblyTargetMachine(const Target &T, const Triple &TT, StringRef CPU,
@@ -46,8 +45,6 @@ public:
     return TLOF.get();
   }
 
-  FeatureBitset getUsedFeatures() const { return UsedFeatures; }
-
   TargetTransformInfo getTargetTransformInfo(const Function &F) override;
 
   bool usesPhysRegsForPEI() const override { return false; }
diff --git a/test/CodeGen/WebAssembly/target-features-tls.ll b/test/CodeGen/WebAssembly/target-features-tls.ll
new file mode 100644 (file)
index 0000000..a5c08f8
--- /dev/null
@@ -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,"",@
index f262657a56d0bcc0bf2f96085e1005a7aeff1e40..7ce7fcf0b7c0d6e1b672813ccfd9bc6cab81e5fc 100644 (file)
@@ -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 @@ attributes #1 = { "target-features"="+nontrapping-fptoint" }
 ; 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
index 9e2eba4a3f2e22b1a60dcb191f5e854d631352d0..61cdb91368cf86d2b7368bf03fb6629354e7707f 100644 (file)
@@ -24,9 +24,4 @@ target triple = "wasm32-unknown-unknown"
 ; CHECK-NEXT:         Name:            .data
 ; CHECK-NEXT:         Alignment:       0
 ; 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: ...
index d838320aeedd4d1275d0236c79ad85349c9085ea..3683d63e435bf3e0940022e785101b9eec3c5c66 100644 (file)
@@ -87,9 +87,4 @@ entry:
 ; CHECK-NEXT:         Name:            bar
 ; CHECK-NEXT:         Flags:           [ UNDEFINED ]
 ; 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: ...
index de8b9f88ec33f245ebe350337ff9c5723b11087a..b3d95a161d1f051b52cd4b01f317a8425d5ec675 100644 (file)
@@ -78,9 +78,4 @@ target triple = "wasm32-unknown-unknown"
 ; CHECK-NEXT:         Name:            .bss.bar
 ; CHECK-NEXT:         Alignment:       0
 ; 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: ...
index 0327a8bed3fb8ce68d3111013e01e4e0cb381ea5..1890589077690cf19882f08510a96a933afc1351 100644 (file)
@@ -119,9 +119,4 @@ define linkonce_odr i32 @sharedFn() #1 comdat($sharedComdat) {
 ; CHECK-NEXT:            Index:           3
 ; CHECK-NEXT:          - Kind:            DATA
 ; 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: ...
index f76bba93c9ba83e13f4075288f332296dadb784d..fe4a4cf698319773543f31baaf27101ced305ff0 100644 (file)
 ; CHECK-NEXT:    Offset: 1021
 ; CHECK-NEXT:    Name: producers
 ; CHECK-NEXT:  }
-; CHECK-NEXT:  Section {
-; CHECK-NEXT:    Type: CUSTOM (0x0)
-; CHECK-NEXT:    Size: 10
-; CHECK-NEXT:    Offset: 1114
-; CHECK-NEXT:    Name: target_features
-; CHECK-NEXT:  }
 ; CHECK-NEXT:]
 ; CHECK-NEXT:Relocations [
 ; CHECK-NEXT:  Section (6) DATA {
index f43189ad2478e20f2932055c324cb75eede156ad..b94190f81436baf325bd17cfbff711f931ccbae6 100644 (file)
@@ -70,9 +70,4 @@ target triple = "wasm32-unknown-unknown"
 ; CHECK-NEXT:         Name:            .sec2
 ; CHECK-NEXT:         Alignment:       3
 ; 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: ...
index 9b384e3ad0f6c7193a9a24eb856ea485855a2f16..df7ff92acffa95db7c5b2008dead4d0f7fbca7e5 100644 (file)
@@ -181,9 +181,4 @@ declare void @func3()
 ; CHECK-NEXT:         Symbol: 10
 ; CHECK-NEXT:       - Priority: 65535
 ; 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: ...
index 63b46ebf2e039543a1d02a330b5fc1e818bd9197..5bb757b28f18a605203e3fded5776d1acf1f484d 100644 (file)
@@ -25,9 +25,4 @@ entry:
 ; CHECK-NEXT:         Name:            hiddenVis
 ; CHECK-NEXT:         Flags:           [ VISIBILITY_HIDDEN ]
 ; 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: ...
index cf5783a017e408c9b3061127e0ca88de0f19a382..7abdc79b5691b68cd388e43b0def7b041d953900 100644 (file)
@@ -207,11 +207,6 @@ entry:
 ; CHECK-NEXT:         Name:            .data.alias_address
 ; CHECK-NEXT:         Alignment:       3
 ; 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: ...
 
 ; CHECK-SYMS: SYMBOL TABLE:
index 2278f97c89d77da59e44bbf7a04b205a9e7e1be6..6a94ee627b6db489b7d841012f0faa45af5e50aa 100644 (file)
@@ -30,9 +30,4 @@ entry:
 ; CHECK-NEXT:         Kind:            DATA
 ; CHECK-NEXT:         Name:            weak_external_data
 ; 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: ...
index 9d134675fea044c9e567028cf0cee1b8b8e328b7..9ce2b3b275c8560e845b73ab18d849407df0d73a 100644 (file)
@@ -149,7 +149,7 @@ void SubtargetEmitter::Enumeration(raw_ostream &OS,
   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 @@ void SubtargetEmitter::Enumeration(raw_ostream &OS,
     FeatureMap[Def] = i;
   }
 
+  OS << "  "
+     << "NumSubtargetFeatures = " << N << "\n";
+
   // Close enumeration and namespace
   OS << "};\n";
   OS << "} // end namespace " << Target << "\n";