llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-backend-webassembly Author: Aiden Grossman (boomanaiden154) <details> <summary>Changes</summary> Standard NewPM pass porting. --- Full diff: https://github.com/llvm/llvm-project/pull/209054.diff 5 Files Affected: - (modified) llvm/lib/Target/WebAssembly/WebAssembly.h (+16-3) - (modified) llvm/lib/Target/WebAssembly/WebAssemblyCoalesceFeaturesAndStripAtomics.cpp (+155-138) - (modified) llvm/lib/Target/WebAssembly/WebAssemblyCodeGenPassBuilder.cpp (+2-1) - (modified) llvm/lib/Target/WebAssembly/WebAssemblyPassRegistry.def (+2) - (modified) llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp (+1-1) ``````````diff diff --git a/llvm/lib/Target/WebAssembly/WebAssembly.h b/llvm/lib/Target/WebAssembly/WebAssembly.h index 6f84ff8adb4c0..c4820ce7b330a 100644 --- a/llvm/lib/Target/WebAssembly/WebAssembly.h +++ b/llvm/lib/Target/WebAssembly/WebAssembly.h @@ -85,8 +85,20 @@ class WebAssemblyReduceToAnyAllTruePass FunctionPass * createWebAssemblyReduceToAnyAllTrueLegacyPass(WebAssemblyTargetMachine &TM); -ModulePass * -createWebAssemblyCoalesceFeaturesAndStripAtomics(WebAssemblyTargetMachine &TM); + +class WebAssemblyCoalesceFeaturesAndStripAtomicsPass + : public RequiredPassInfoMixin< + WebAssemblyCoalesceFeaturesAndStripAtomicsPass> { + WebAssemblyTargetMachine &TM; + +public: + WebAssemblyCoalesceFeaturesAndStripAtomicsPass(WebAssemblyTargetMachine &TM) + : TM(TM) {} + PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM); +}; + +ModulePass *createWebAssemblyCoalesceFeaturesAndStripAtomicsLegacyPass( + WebAssemblyTargetMachine &TM); // GlobalISel InstructionSelector * @@ -162,7 +174,8 @@ void initializeWebAssemblyRegNumberingPass(PassRegistry &); void initializeWebAssemblyRegStackifyPass(PassRegistry &); void initializeWebAssemblyReplacePhysRegsPass(PassRegistry &); void initializeWebAssemblySetP2AlignOperandsPass(PassRegistry &); -void initializeWebAssemblyCoalesceFeaturesAndStripAtomicsPass(PassRegistry &); +void initializeWebAssemblyCoalesceFeaturesAndStripAtomicsLegacyPass( + PassRegistry &); namespace WebAssembly { enum TargetIndex { diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyCoalesceFeaturesAndStripAtomics.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyCoalesceFeaturesAndStripAtomics.cpp index 89c3842241bf7..a040e531ee020 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyCoalesceFeaturesAndStripAtomics.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyCoalesceFeaturesAndStripAtomics.cpp @@ -8,8 +8,10 @@ #include "WebAssembly.h" #include "WebAssemblyTargetMachine.h" +#include "llvm/IR/Analysis.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/Module.h" +#include "llvm/IR/PassManager.h" #include "llvm/Pass.h" #include "llvm/Transforms/Scalar/LowerAtomicPass.h" @@ -18,7 +20,8 @@ using namespace llvm; #define DEBUG_TYPE "wasm-coalesce-features-and-strip-atomics" namespace { -class WebAssemblyCoalesceFeaturesAndStripAtomics final : public ModulePass { +class WebAssemblyCoalesceFeaturesAndStripAtomicsLegacy 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, @@ -28,170 +31,184 @@ class WebAssemblyCoalesceFeaturesAndStripAtomics final : public ModulePass { public: static char ID; - WebAssemblyCoalesceFeaturesAndStripAtomics(WebAssemblyTargetMachine *WasmTM) + WebAssemblyCoalesceFeaturesAndStripAtomicsLegacy( + WebAssemblyTargetMachine *WasmTM) : ModulePass(ID), WasmTM(WasmTM) {} - bool runOnModule(Module &M) override { - auto [Features, FeatureStr] = coalesceFeatures(M); - - WasmTM->setTargetFeatureString(FeatureStr); - for (auto &F : M) - replaceFeatures(F, FeatureStr); - - bool StrippedAtomics = false; - bool StrippedTLS = false; - - // In cooperative threading mode, thread locals are meaningful even without - // atomics. - const WebAssemblySubtarget *ST = WasmTM->getSubtargetImpl(); - bool CooperativeThreading = ST->hasCooperativeMultithreading(); - - if (!Features[WebAssembly::FeatureAtomics]) { - StrippedAtomics = stripAtomics(M); - if (!CooperativeThreading) - StrippedTLS = stripThreadLocals(M); - } - if (!Features[WebAssembly::FeatureBulkMemory] && !StrippedTLS) { - StrippedTLS = stripThreadLocals(M); - } + bool runOnModule(Module &M) override; +}; +} // namespace - if (StrippedAtomics && !StrippedTLS && !CooperativeThreading) - stripThreadLocals(M); - else if (StrippedTLS && !StrippedAtomics) - stripAtomics(M); +char WebAssemblyCoalesceFeaturesAndStripAtomicsLegacy::ID = 0; +INITIALIZE_PASS(WebAssemblyCoalesceFeaturesAndStripAtomicsLegacy, DEBUG_TYPE, + "Coalesce features and strip atomics", true, false) - recordFeatures(M, ST, Features, StrippedAtomics || StrippedTLS); +ModulePass *llvm::createWebAssemblyCoalesceFeaturesAndStripAtomicsLegacyPass( + WebAssemblyTargetMachine &TM) { + return new WebAssemblyCoalesceFeaturesAndStripAtomicsLegacy(&TM); +} - // Conservatively assume we have made some change - return true; +static std::string getFeatureString(const WebAssemblySubtarget *ST, + const FeatureBitset &Features) { + std::string Ret; + for (const SubtargetFeatureKV &KV : ST->getAllProcessorFeatures()) { + if (Features[KV.Value]) + Ret += (StringRef("+") + KV.key() + ",").str(); + else + Ret += (StringRef("-") + KV.key() + ",").str(); } + // remove trailing ',' + Ret.pop_back(); + return Ret; +} -private: - std::pair<FeatureBitset, std::string> coalesceFeatures(const Module &M) { - // Union the features of all defined functions. Start with an empty set, so - // that if a feature is disabled in every function, we'll compute it as - // disabled. If any function lacks a target-features attribute, it'll - // default to the target CPU from the `TargetMachine`. - FeatureBitset Features; - // We need any MCSubtargetInfo to access WebAssemblyFeatureKV. - const WebAssemblySubtarget *AnyST = nullptr; - for (auto &F : M) { - if (F.isDeclaration()) - continue; - - AnyST = WasmTM->getSubtargetImpl(F); - Features |= AnyST->getFeatureBits(); - } - - // If we have no defined functions, use the target CPU from the - // `TargetMachine`. - if (!AnyST) { - AnyST = WasmTM->getSubtargetImpl( - std::string(WasmTM->getTargetCPU()), - std::string(WasmTM->getTargetFeatureString())); - Features = AnyST->getFeatureBits(); - } - - return {Features, getFeatureString(AnyST, Features)}; +static std::pair<FeatureBitset, std::string> +coalesceFeatures(const Module &M, WebAssemblyTargetMachine *WasmTM) { + // Union the features of all defined functions. Start with an empty set, so + // that if a feature is disabled in every function, we'll compute it as + // disabled. If any function lacks a target-features attribute, it'll + // default to the target CPU from the `TargetMachine`. + FeatureBitset Features; + // We need any MCSubtargetInfo to access WebAssemblyFeatureKV. + const WebAssemblySubtarget *AnyST = nullptr; + for (auto &F : M) { + if (F.isDeclaration()) + continue; + + AnyST = WasmTM->getSubtargetImpl(F); + Features |= AnyST->getFeatureBits(); } - static std::string getFeatureString(const WebAssemblySubtarget *ST, - const FeatureBitset &Features) { - std::string Ret; - for (const SubtargetFeatureKV &KV : ST->getAllProcessorFeatures()) { - if (Features[KV.Value]) - Ret += (StringRef("+") + KV.key() + ",").str(); - else - Ret += (StringRef("-") + KV.key() + ",").str(); - } - // remove trailing ',' - Ret.pop_back(); - return Ret; + // If we have no defined functions, use the target CPU from the + // `TargetMachine`. + if (!AnyST) { + AnyST = + WasmTM->getSubtargetImpl(std::string(WasmTM->getTargetCPU()), + std::string(WasmTM->getTargetFeatureString())); + Features = AnyST->getFeatureBits(); } - void replaceFeatures(Function &F, const std::string &Features) { - F.removeFnAttr("target-features"); - F.removeFnAttr("target-cpu"); - F.addFnAttr("target-features", Features); - } + return {Features, getFeatureString(AnyST, 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; - } +static void replaceFeatures(Function &F, const std::string &Features) { + F.removeFnAttr("target-features"); + F.removeFnAttr("target-cpu"); + F.addFnAttr("target-features", Features); +} + +static 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; +done: + if (!Stripped) + return false; - LowerAtomicPass Lowerer; - FunctionAnalysisManager FAM; - for (auto &F : M) - Lowerer.run(F, FAM); + LowerAtomicPass Lowerer; + FunctionAnalysisManager FAM; + for (auto &F : M) + Lowerer.run(F, FAM); - return true; - } + return true; +} - bool stripThreadLocals(Module &M) { - bool Stripped = false; - for (auto &GV : M.globals()) { - if (GV.isThreadLocal()) { - // replace `@llvm.threadlocal.address.pX(GV)` with `GV`. - for (Use &U : make_early_inc_range(GV.uses())) { - if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(U.getUser())) { - if (II->getIntrinsicID() == Intrinsic::threadlocal_address && - II->getArgOperand(0) == &GV) { - II->replaceAllUsesWith(&GV); - II->eraseFromParent(); - } +static bool stripThreadLocals(Module &M) { + bool Stripped = false; + for (auto &GV : M.globals()) { + if (GV.isThreadLocal()) { + // replace `@llvm.threadlocal.address.pX(GV)` with `GV`. + for (Use &U : make_early_inc_range(GV.uses())) { + if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(U.getUser())) { + if (II->getIntrinsicID() == Intrinsic::threadlocal_address && + II->getArgOperand(0) == &GV) { + II->replaceAllUsesWith(&GV); + II->eraseFromParent(); } } - - Stripped = true; - GV.setThreadLocal(false); } + + Stripped = true; + GV.setThreadLocal(false); } - return Stripped; } + return Stripped; +} - void recordFeatures(Module &M, const WebAssemblySubtarget *ST, - const FeatureBitset &Features, bool Stripped) { - for (const SubtargetFeatureKV &KV : ST->getAllProcessorFeatures()) { - if (Features[KV.Value]) { - // Mark features as used - std::string MDKey = (StringRef("wasm-feature-") + KV.key()).str(); - M.addModuleFlag(Module::ModFlagBehavior::Error, MDKey, - wasm::WASM_FEATURE_PREFIX_USED); - } - } - // Code compiled without atomics or bulk-memory may have had its atomics or - // thread-local data lowered to nonatomic operations or non-thread-local - // data. In that case, we mark the pseudo-feature "shared-mem" as disallowed - // to tell the linker that it would be unsafe to allow this code to be used - // in a module with shared memory. - if (Stripped) { - M.addModuleFlag(Module::ModFlagBehavior::Error, "wasm-feature-shared-mem", - wasm::WASM_FEATURE_PREFIX_DISALLOWED); +static void recordFeatures(Module &M, const WebAssemblySubtarget *ST, + const FeatureBitset &Features, bool Stripped) { + for (const SubtargetFeatureKV &KV : ST->getAllProcessorFeatures()) { + if (Features[KV.Value]) { + // Mark features as used + std::string MDKey = (StringRef("wasm-feature-") + KV.key()).str(); + M.addModuleFlag(Module::ModFlagBehavior::Error, MDKey, + wasm::WASM_FEATURE_PREFIX_USED); } } -}; -} // namespace + // Code compiled without atomics or bulk-memory may have had its atomics or + // thread-local data lowered to nonatomic operations or non-thread-local + // data. In that case, we mark the pseudo-feature "shared-mem" as disallowed + // to tell the linker that it would be unsafe to allow this code to be used + // in a module with shared memory. + if (Stripped) { + M.addModuleFlag(Module::ModFlagBehavior::Error, "wasm-feature-shared-mem", + wasm::WASM_FEATURE_PREFIX_DISALLOWED); + } +} -char WebAssemblyCoalesceFeaturesAndStripAtomics::ID = 0; -INITIALIZE_PASS(WebAssemblyCoalesceFeaturesAndStripAtomics, DEBUG_TYPE, - "Coalesce features and strip atomics", true, false) +static bool coalesceFeaturesAndStripAtomics(Module &M, + WebAssemblyTargetMachine *WasmTM) { + auto [Features, FeatureStr] = coalesceFeatures(M, WasmTM); -ModulePass *llvm::createWebAssemblyCoalesceFeaturesAndStripAtomics( - WebAssemblyTargetMachine &TM) { - return new WebAssemblyCoalesceFeaturesAndStripAtomics(&TM); + WasmTM->setTargetFeatureString(FeatureStr); + for (auto &F : M) + replaceFeatures(F, FeatureStr); + + bool StrippedAtomics = false; + bool StrippedTLS = false; + + // In cooperative threading mode, thread locals are meaningful even without + // atomics. + const WebAssemblySubtarget *ST = WasmTM->getSubtargetImpl(); + bool CooperativeThreading = ST->hasCooperativeMultithreading(); + + if (!Features[WebAssembly::FeatureAtomics]) { + StrippedAtomics = stripAtomics(M); + if (!CooperativeThreading) + StrippedTLS = stripThreadLocals(M); + } + if (!Features[WebAssembly::FeatureBulkMemory] && !StrippedTLS) { + StrippedTLS = stripThreadLocals(M); + } + + if (StrippedAtomics && !StrippedTLS && !CooperativeThreading) + stripThreadLocals(M); + else if (StrippedTLS && !StrippedAtomics) + stripAtomics(M); + + recordFeatures(M, ST, Features, StrippedAtomics || StrippedTLS); + + // Conservatively assume we have made some change + return true; +} + +bool WebAssemblyCoalesceFeaturesAndStripAtomicsLegacy::runOnModule(Module &M) { + return coalesceFeaturesAndStripAtomics(M, WasmTM); +} + +PreservedAnalyses WebAssemblyCoalesceFeaturesAndStripAtomicsPass::run( + Module &M, ModuleAnalysisManager &MAM) { + return coalesceFeaturesAndStripAtomics(M, &TM) ? PreservedAnalyses::none() + : PreservedAnalyses::all(); } diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyCodeGenPassBuilder.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyCodeGenPassBuilder.cpp index 48713ecacba0b..b5384b3e005c7 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyCodeGenPassBuilder.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyCodeGenPassBuilder.cpp @@ -123,7 +123,8 @@ void WebAssemblyCodeGenPassBuilder::addISelPrepare( // loads and stores are promoted to local.gets/local.sets. addFunctionPass(WebAssemblyRefTypeMem2LocalPass(), PMW); // Lower atomics and TLS if necessary - // TODO(boomanaiden154): CoalesceFeaturesAndStripAtomics + flushFPMsToMPM(PMW); + addModulePass(WebAssemblyCoalesceFeaturesAndStripAtomicsPass(TM), PMW); // This is a no-op if atomics are not used in the module addFunctionPass(AtomicExpandPass(TM), PMW); diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyPassRegistry.def b/llvm/lib/Target/WebAssembly/WebAssemblyPassRegistry.def index 6767f7a6a6b77..a6da272bf3ba7 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyPassRegistry.def +++ b/llvm/lib/Target/WebAssembly/WebAssemblyPassRegistry.def @@ -15,6 +15,8 @@ #define MODULE_PASS(NAME, CREATE_PASS) #endif MODULE_PASS("wasm-add-missing-prototypes", WebAssemblyAddMissingPrototypesPass()) +MODULE_PASS("wasm-coalesce-features-and-strip-atomics", + WebAssemblyCoalesceFeaturesAndStripAtomicsPass(*this)) MODULE_PASS("wasm-fix-function-bitcasts", WebAssemblyFixFunctionBitcastsPass()) MODULE_PASS("wasm-lower-em-ehsjlj", WebAssemblyLowerEmscriptenEHSjLjPass()) #undef MODULE_PASS diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp index d5b51c4233afb..9d382451f5123 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp @@ -367,7 +367,7 @@ void WebAssemblyPassConfig::addISelPrepare() { // loads and stores are promoted to local.gets/local.sets. addPass(createWebAssemblyRefTypeMem2LocalLegacyPass()); // Lower atomics and TLS if necessary - addPass(createWebAssemblyCoalesceFeaturesAndStripAtomics( + addPass(createWebAssemblyCoalesceFeaturesAndStripAtomicsLegacyPass( getWebAssemblyTargetMachine())); // This is a no-op if atomics are not used in the module `````````` </details> https://github.com/llvm/llvm-project/pull/209054 _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
