mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-01-10 05:41:40 +00:00
[WebAssembly] Merge used feature sets, update atomics linkage policy
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 llvm-svn: 357226
This commit is contained in:
parent
99b146d4a0
commit
2f3b03882d
@ -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 {
|
||||
|
||||
|
@ -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());
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -22,11 +22,16 @@
|
||||
#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;
|
||||
|
||||
|
@ -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());
|
||||
|
@ -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; }
|
||||
|
26
test/CodeGen/WebAssembly/target-features-tls.ll
Normal file
26
test/CodeGen/WebAssembly/target-features-tls.ll
Normal file
@ -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,"",@
|
@ -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
|
||||
|
@ -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: ...
|
||||
|
@ -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: ...
|
||||
|
@ -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: ...
|
||||
|
@ -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: ...
|
||||
|
@ -130,12 +130,6 @@
|
||||
; 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 {
|
||||
|
@ -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: ...
|
||||
|
@ -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: ...
|
||||
|
@ -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: ...
|
||||
|
@ -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:
|
||||
|
@ -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: ...
|
||||
|
@ -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";
|
||||
|
Loading…
Reference in New Issue
Block a user