LLVM 24.0.0git
WebAssemblyCoalesceFeaturesAndStripAtomics.cpp
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "WebAssembly.h"
11#include "llvm/IR/Analysis.h"
13#include "llvm/IR/Module.h"
14#include "llvm/IR/PassManager.h"
16#include "llvm/Pass.h"
18
19using namespace llvm;
20
21#define DEBUG_TYPE "wasm-coalesce-features-and-strip-atomics"
22
23namespace {
24class WebAssemblyCoalesceFeaturesAndStripAtomicsLegacy final
25 : public ModulePass {
26 // Take the union of all features used in the module and use it for each
27 // function individually, since having multiple feature sets in one module
28 // currently does not make sense for WebAssembly. If atomics are not enabled,
29 // also strip atomic operations and thread local storage.
31
32public:
33 static char ID;
34
35 WebAssemblyCoalesceFeaturesAndStripAtomicsLegacy(
37 : ModulePass(ID), WasmTM(WasmTM) {}
38
39 bool runOnModule(Module &M) override;
40};
41} // namespace
42
43char WebAssemblyCoalesceFeaturesAndStripAtomicsLegacy::ID = 0;
44INITIALIZE_PASS(WebAssemblyCoalesceFeaturesAndStripAtomicsLegacy, DEBUG_TYPE,
45 "Coalesce features and strip atomics", true, false)
46
49 return new WebAssemblyCoalesceFeaturesAndStripAtomicsLegacy(&TM);
50}
51
52static std::string getFeatureString(const MCSubtargetInfo &STI,
53 const FeatureBitset &Features) {
54 std::string Ret;
55 for (const SubtargetFeatureKV &KV : STI.getAllProcessorFeatures()) {
56 if (Features[KV.Value])
57 Ret += (StringRef("+") + KV.key() + ",").str();
58 else
59 Ret += (StringRef("-") + KV.key() + ",").str();
60 }
61 // remove trailing ','
62 Ret.pop_back();
63 return Ret;
64}
65
66static std::pair<FeatureBitset, std::string>
68 // Union the features of all defined functions. Start with an empty set, so
69 // that if a feature is disabled in every function, we'll compute it as
70 // disabled. If any function lacks a target-features attribute, it'll
71 // default to the target CPU from the `TargetMachine`.
72 FeatureBitset Features;
73 bool AnyDefined = false;
74 for (auto &F : M) {
75 if (F.isDeclaration())
76 continue;
77
78 Features |= WasmTM->getSubtargetImpl(F)->getFeatureBits();
79 AnyDefined = true;
80 }
81
82 // If we have no defined functions, use the module-wide feature bits from the
83 // `TargetMachine`.
84 if (!AnyDefined)
85 Features = WasmTM->getMCSubtargetInfo().getFeatureBits();
86
87 return {Features, getFeatureString(WasmTM->getMCSubtargetInfo(), Features)};
88}
89
90static void replaceFeatures(Function &F, const std::string &Features) {
91 F.removeFnAttr("target-features");
92 F.removeFnAttr("target-cpu");
93 F.addFnAttr("target-features", Features);
94}
95
96static bool stripAtomics(Module &M) {
97 // Detect whether any atomics will be lowered, since there is no way to tell
98 // whether the LowerAtomic pass lowers e.g. stores.
99 bool Stripped = false;
100 for (auto &F : M) {
101 for (auto &B : F) {
102 for (auto &I : B) {
103 if (I.isAtomic()) {
104 Stripped = true;
105 goto done;
106 }
107 }
108 }
109 }
110
111done:
112 if (!Stripped)
113 return false;
114
115 LowerAtomicPass Lowerer;
117 for (auto &F : M)
118 Lowerer.run(F, FAM);
119
120 return true;
121}
122
123static bool stripThreadLocals(Module &M) {
124 bool Stripped = false;
125 for (auto &GV : M.globals()) {
126 if (GV.isThreadLocal()) {
127 // replace `@llvm.threadlocal.address.pX(GV)` with `GV`.
128 for (Use &U : make_early_inc_range(GV.uses())) {
129 if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(U.getUser())) {
130 if (II->getIntrinsicID() == Intrinsic::threadlocal_address &&
131 II->getArgOperand(0) == &GV) {
132 II->replaceAllUsesWith(&GV);
133 II->eraseFromParent();
134 }
135 }
136 }
137
138 Stripped = true;
139 GV.setThreadLocal(false);
140 }
141 }
142 return Stripped;
143}
144
146 const FeatureBitset &Features, bool Stripped) {
147 for (const SubtargetFeatureKV &KV : ST->getAllProcessorFeatures()) {
148 if (Features[KV.Value]) {
149 // Mark features as used
150 std::string MDKey = (StringRef("wasm-feature-") + KV.key()).str();
151 M.addModuleFlag(Module::ModFlagBehavior::Error, MDKey,
153 }
154 }
155 // Code compiled without atomics or bulk-memory may have had its atomics or
156 // thread-local data lowered to nonatomic operations or non-thread-local
157 // data. In that case, we mark the pseudo-feature "shared-mem" as disallowed
158 // to tell the linker that it would be unsafe to allow this code to be used
159 // in a module with shared memory.
160 if (Stripped) {
161 M.addModuleFlag(Module::ModFlagBehavior::Error, "wasm-feature-shared-mem",
163 }
164}
165
167 WebAssemblyTargetMachine *WasmTM) {
168 auto [Features, FeatureStr] = coalesceFeatures(M, WasmTM);
169
170 WasmTM->setTargetFeatureString(FeatureStr);
171 for (auto &F : M)
172 replaceFeatures(F, FeatureStr);
173
174 bool StrippedAtomics = false;
175 bool StrippedTLS = false;
176
177 // In cooperative threading mode, thread locals are meaningful even without
178 // atomics.
179 const WebAssemblySubtarget *ST = WasmTM->getSubtargetImpl(
180 WasmTM->getTargetCPU(), WasmTM->getTargetFeatureString());
181 bool CooperativeThreading = ST->hasCooperativeMultithreading();
182
183 if (!Features[WebAssembly::FeatureAtomics]) {
184 StrippedAtomics = stripAtomics(M);
185 if (!CooperativeThreading)
186 StrippedTLS = stripThreadLocals(M);
187 }
188 if (!Features[WebAssembly::FeatureBulkMemory] && !StrippedTLS) {
189 StrippedTLS = stripThreadLocals(M);
190 }
191
192 if (StrippedAtomics && !StrippedTLS && !CooperativeThreading)
194 else if (StrippedTLS && !StrippedAtomics)
195 stripAtomics(M);
196
197 bool Stripped = StrippedAtomics || StrippedTLS;
198 if (!Stripped &&
199 (Features[WebAssembly::FeatureAtomics] ||
200 (CooperativeThreading && Features[WebAssembly::FeatureBulkMemory])) &&
201 !M.getModuleFlag("thread-model")) {
202 M.setThreadModel(ThreadModel::POSIX);
203 }
204
205 recordFeatures(M, ST, Features, Stripped);
206
207 // Conservatively assume we have made some change
208 return true;
209}
210
211bool WebAssemblyCoalesceFeaturesAndStripAtomicsLegacy::runOnModule(Module &M) {
212 return coalesceFeaturesAndStripAtomics(M, WasmTM);
213}
214
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
#define DEBUG_TYPE
Module.h This file contains the declarations for the Module class.
This header defines various interfaces for pass management in LLVM.
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
uint64_t IntrinsicInst * II
FunctionAnalysisManager FAM
ModuleAnalysisManager MAM
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition PassSupport.h:56
static bool coalesceFeaturesAndStripAtomics(Module &M, WebAssemblyTargetMachine *WasmTM)
static void recordFeatures(Module &M, const WebAssemblySubtarget *ST, const FeatureBitset &Features, bool Stripped)
static std::string getFeatureString(const MCSubtargetInfo &STI, const FeatureBitset &Features)
static bool stripAtomics(Module &M)
static void replaceFeatures(Function &F, const std::string &Features)
static bool stripThreadLocals(Module &M)
static std::pair< FeatureBitset, std::string > coalesceFeatures(const Module &M, WebAssemblyTargetMachine *WasmTM)
This file declares the WebAssembly-specific subclass of TargetMachine.
This file contains the entry points for global functions defined in the LLVM WebAssembly back-end.
Container class for subtarget features.
A wrapper class for inspecting calls to intrinsic functions.
A pass that lowers atomic intrinsic into non-atomic intrinsics.
Generic base class for all target subtargets.
const FeatureBitset & getFeatureBits() const
ArrayRef< SubtargetFeatureKV > getAllProcessorFeatures() const
Return processor features.
ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...
Definition Pass.h:255
A Module instance is used to store all the information related to an LLVM module.
Definition Module.h:68
@ Error
Emits an error if two values disagree, otherwise the resulting value is that of the operands.
Definition Module.h:121
A set of analyses that are preserved following a run of a transformation pass.
Definition Analysis.h:112
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
Definition Analysis.h:115
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition Analysis.h:118
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
const MCSubtargetInfo & getMCSubtargetInfo() const
StringRef getTargetFeatureString() const
StringRef getTargetCPU() const
void setTargetFeatureString(StringRef FS)
A Use represents the edge between a Value definition and its users.
Definition Use.h:35
const WebAssemblySubtarget * getSubtargetImpl(StringRef CPU, StringRef FS) const
Pass manager infrastructure for declaring and invalidating analyses.
@ WASM_FEATURE_PREFIX_USED
Definition Wasm.h:189
@ WASM_FEATURE_PREFIX_DISALLOWED
Definition Wasm.h:190
This is an optimization pass for GlobalISel generic memory operations.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
Definition STLExtras.h:649
ModulePass * createWebAssemblyCoalesceFeaturesAndStripAtomicsLegacyPass(WebAssemblyTargetMachine &TM)
AnalysisManager< Function > FunctionAnalysisManager
Convenience typedef for the Function analysis manager.
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.
Definition MIRParser.h:39
Used to provide key value pairs for feature and CPU bit flags.