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"
15#include "llvm/Pass.h"
17
18using namespace llvm;
19
20#define DEBUG_TYPE "wasm-coalesce-features-and-strip-atomics"
21
22namespace {
23class WebAssemblyCoalesceFeaturesAndStripAtomicsLegacy final
24 : public ModulePass {
25 // Take the union of all features used in the module and use it for each
26 // function individually, since having multiple feature sets in one module
27 // currently does not make sense for WebAssembly. If atomics are not enabled,
28 // also strip atomic operations and thread local storage.
30
31public:
32 static char ID;
33
34 WebAssemblyCoalesceFeaturesAndStripAtomicsLegacy(
36 : ModulePass(ID), WasmTM(WasmTM) {}
37
38 bool runOnModule(Module &M) override;
39};
40} // namespace
41
42char WebAssemblyCoalesceFeaturesAndStripAtomicsLegacy::ID = 0;
43INITIALIZE_PASS(WebAssemblyCoalesceFeaturesAndStripAtomicsLegacy, DEBUG_TYPE,
44 "Coalesce features and strip atomics", true, false)
45
48 return new WebAssemblyCoalesceFeaturesAndStripAtomicsLegacy(&TM);
49}
50
51static std::string getFeatureString(const WebAssemblySubtarget *ST,
52 const FeatureBitset &Features) {
53 std::string Ret;
54 for (const SubtargetFeatureKV &KV : ST->getAllProcessorFeatures()) {
55 if (Features[KV.Value])
56 Ret += (StringRef("+") + KV.key() + ",").str();
57 else
58 Ret += (StringRef("-") + KV.key() + ",").str();
59 }
60 // remove trailing ','
61 Ret.pop_back();
62 return Ret;
63}
64
65static std::pair<FeatureBitset, std::string>
67 // Union the features of all defined functions. Start with an empty set, so
68 // that if a feature is disabled in every function, we'll compute it as
69 // disabled. If any function lacks a target-features attribute, it'll
70 // default to the target CPU from the `TargetMachine`.
71 FeatureBitset Features;
72 // We need any MCSubtargetInfo to access WebAssemblyFeatureKV.
73 const WebAssemblySubtarget *AnyST = nullptr;
74 for (auto &F : M) {
75 if (F.isDeclaration())
76 continue;
77
78 AnyST = WasmTM->getSubtargetImpl(F);
79 Features |= AnyST->getFeatureBits();
80 }
81
82 // If we have no defined functions, use the target CPU from the
83 // `TargetMachine`.
84 if (!AnyST) {
85 AnyST =
86 WasmTM->getSubtargetImpl(std::string(WasmTM->getTargetCPU()),
87 std::string(WasmTM->getTargetFeatureString()));
88 Features = AnyST->getFeatureBits();
89 }
90
91 return {Features, getFeatureString(AnyST, Features)};
92}
93
94static void replaceFeatures(Function &F, const std::string &Features) {
95 F.removeFnAttr("target-features");
96 F.removeFnAttr("target-cpu");
97 F.addFnAttr("target-features", Features);
98}
99
100static bool stripAtomics(Module &M) {
101 // Detect whether any atomics will be lowered, since there is no way to tell
102 // whether the LowerAtomic pass lowers e.g. stores.
103 bool Stripped = false;
104 for (auto &F : M) {
105 for (auto &B : F) {
106 for (auto &I : B) {
107 if (I.isAtomic()) {
108 Stripped = true;
109 goto done;
110 }
111 }
112 }
113 }
114
115done:
116 if (!Stripped)
117 return false;
118
119 LowerAtomicPass Lowerer;
121 for (auto &F : M)
122 Lowerer.run(F, FAM);
123
124 return true;
125}
126
127static bool stripThreadLocals(Module &M) {
128 bool Stripped = false;
129 for (auto &GV : M.globals()) {
130 if (GV.isThreadLocal()) {
131 // replace `@llvm.threadlocal.address.pX(GV)` with `GV`.
132 for (Use &U : make_early_inc_range(GV.uses())) {
133 if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(U.getUser())) {
134 if (II->getIntrinsicID() == Intrinsic::threadlocal_address &&
135 II->getArgOperand(0) == &GV) {
136 II->replaceAllUsesWith(&GV);
137 II->eraseFromParent();
138 }
139 }
140 }
141
142 Stripped = true;
143 GV.setThreadLocal(false);
144 }
145 }
146 return Stripped;
147}
148
150 const FeatureBitset &Features, bool Stripped) {
151 for (const SubtargetFeatureKV &KV : ST->getAllProcessorFeatures()) {
152 if (Features[KV.Value]) {
153 // Mark features as used
154 std::string MDKey = (StringRef("wasm-feature-") + KV.key()).str();
155 M.addModuleFlag(Module::ModFlagBehavior::Error, MDKey,
157 }
158 }
159 // Code compiled without atomics or bulk-memory may have had its atomics or
160 // thread-local data lowered to nonatomic operations or non-thread-local
161 // data. In that case, we mark the pseudo-feature "shared-mem" as disallowed
162 // to tell the linker that it would be unsafe to allow this code to be used
163 // in a module with shared memory.
164 if (Stripped) {
165 M.addModuleFlag(Module::ModFlagBehavior::Error, "wasm-feature-shared-mem",
167 }
168}
169
171 WebAssemblyTargetMachine *WasmTM) {
172 auto [Features, FeatureStr] = coalesceFeatures(M, WasmTM);
173
174 WasmTM->setTargetFeatureString(FeatureStr);
175 for (auto &F : M)
176 replaceFeatures(F, FeatureStr);
177
178 bool StrippedAtomics = false;
179 bool StrippedTLS = false;
180
181 // In cooperative threading mode, thread locals are meaningful even without
182 // atomics.
183 const WebAssemblySubtarget *ST = WasmTM->getSubtargetImpl();
184 bool CooperativeThreading = ST->hasCooperativeMultithreading();
185
186 if (!Features[WebAssembly::FeatureAtomics]) {
187 StrippedAtomics = stripAtomics(M);
188 if (!CooperativeThreading)
189 StrippedTLS = stripThreadLocals(M);
190 }
191 if (!Features[WebAssembly::FeatureBulkMemory] && !StrippedTLS) {
192 StrippedTLS = stripThreadLocals(M);
193 }
194
195 if (StrippedAtomics && !StrippedTLS && !CooperativeThreading)
197 else if (StrippedTLS && !StrippedAtomics)
198 stripAtomics(M);
199
200 recordFeatures(M, ST, Features, StrippedAtomics || StrippedTLS);
201
202 // Conservatively assume we have made some change
203 return true;
204}
205
206bool WebAssemblyCoalesceFeaturesAndStripAtomicsLegacy::runOnModule(Module &M) {
207 return coalesceFeaturesAndStripAtomics(M, WasmTM);
208}
209
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 std::string getFeatureString(const WebAssemblySubtarget *ST, const FeatureBitset &Features)
static bool coalesceFeaturesAndStripAtomics(Module &M, WebAssemblyTargetMachine *WasmTM)
static void recordFeatures(Module &M, const WebAssemblySubtarget *ST, const FeatureBitset &Features, bool Stripped)
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.
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:67
@ Error
Emits an error if two values disagree, otherwise the resulting value is that of the operands.
Definition Module.h:120
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
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() const
Pass manager infrastructure for declaring and invalidating analyses.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition CallingConv.h:24
@ 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:633
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.