summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Target/WebAssembly
diff options
context:
space:
mode:
authorThomas Lively <tlively@google.com>2019-03-29 00:14:01 +0000
committerThomas Lively <tlively@google.com>2019-03-29 00:14:01 +0000
commit3f34e1b883351c7d98426b084386a7aa762aa366 (patch)
tree04c234c41b653cc23f751e4c711e8a66a78f51a6 /llvm/lib/Target/WebAssembly
parent0c9ea1053058be474a58859be2ab212aaf33ea31 (diff)
downloadbcm5719-llvm-3f34e1b883351c7d98426b084386a7aa762aa366.tar.gz
bcm5719-llvm-3f34e1b883351c7d98426b084386a7aa762aa366.zip
[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
Diffstat (limited to 'llvm/lib/Target/WebAssembly')
-rw-r--r--llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h4
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp59
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.h2
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblySubtarget.cpp5
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h6
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp139
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.h3
7 files changed, 156 insertions, 62 deletions
diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h
index 303fd3ed265..7d12dd7633a 100644
--- 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 @@ enum TOF {
#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.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
index e4129276b84..2e6de3cd9f2 100644
--- 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 @@ 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());
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.h b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.h
index 35e7d8d0f66..963bfbd0d82 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.h
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.h
@@ -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;
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.cpp b/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.cpp
index bf2f70ca200..196a7456528 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.cpp
@@ -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
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h b/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h
index b6f3e6b4a10..ae1f3fe3946 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h
+++ b/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h
@@ -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;
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
index 6d9fd0016ce..8a768dbc104 100644
--- 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 @@ 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());
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.h b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.h
index 0f1901020b5..850e6b9a9e9 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.h
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.h
@@ -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; }
OpenPOWER on IntegriCloud