26
26
#include " llvm/Support/TargetRegistry.h"
27
27
#include " llvm/Target/TargetOptions.h"
28
28
#include " llvm/Transforms/Scalar.h"
29
+ #include " llvm/Transforms/Scalar/LowerAtomic.h"
29
30
#include " llvm/Transforms/Utils.h"
30
31
using namespace llvm ;
31
32
@@ -117,10 +118,6 @@ WebAssemblyTargetMachine::WebAssemblyTargetMachine(
117
118
118
119
initAsmInfo ();
119
120
120
- // Create a subtarget using the unmodified target machine features to
121
- // initialize the used feature set with explicitly enabled features.
122
- getSubtargetImpl (getTargetCPU (), getTargetFeatureString ());
123
-
124
121
// Note that we don't use setRequiresStructuredCFG(true). It disables
125
122
// optimizations than we're ok with, and want, such as critical edge
126
123
// splitting and tail merging.
@@ -134,7 +131,6 @@ WebAssemblyTargetMachine::getSubtargetImpl(std::string CPU,
134
131
auto &I = SubtargetMap[CPU + FS];
135
132
if (!I) {
136
133
I = llvm::make_unique<WebAssemblySubtarget>(TargetTriple, CPU, FS, *this );
137
- UsedFeatures |= I->getFeatureBits ();
138
134
}
139
135
return I.get ();
140
136
}
@@ -160,21 +156,123 @@ WebAssemblyTargetMachine::getSubtargetImpl(const Function &F) const {
160
156
}
161
157
162
158
namespace {
163
- class StripThreadLocal final : public ModulePass {
164
- // The default thread model for wasm is single, where thread-local variables
165
- // are identical to regular globals and should be treated the same. So this
166
- // pass just converts all GlobalVariables to NotThreadLocal
159
+
160
+ class CoalesceFeaturesAndStripAtomics final : public ModulePass {
161
+ // Take the union of all features used in the module and use it for each
162
+ // function individually, since having multiple feature sets in one module
163
+ // currently does not make sense for WebAssembly. If atomics are not enabled,
164
+ // also strip atomic operations and thread local storage.
167
165
static char ID;
166
+ WebAssemblyTargetMachine *WasmTM;
168
167
169
168
public:
170
- StripThreadLocal () : ModulePass(ID) {}
169
+ CoalesceFeaturesAndStripAtomics (WebAssemblyTargetMachine *WasmTM)
170
+ : ModulePass(ID), WasmTM(WasmTM) {}
171
+
171
172
bool runOnModule (Module &M) override {
172
- for (auto &GV : M.globals ())
173
- GV.setThreadLocalMode (GlobalValue::ThreadLocalMode::NotThreadLocal);
173
+ FeatureBitset Features = coalesceFeatures (M);
174
+
175
+ std::string FeatureStr = getFeatureString (Features);
176
+ for (auto &F : M)
177
+ replaceFeatures (F, FeatureStr);
178
+
179
+ bool Stripped = false ;
180
+ if (!Features[WebAssembly::FeatureAtomics]) {
181
+ Stripped |= stripAtomics (M);
182
+ Stripped |= stripThreadLocals (M);
183
+ }
184
+
185
+ recordFeatures (M, Features, Stripped);
186
+
187
+ // Conservatively assume we have made some change
174
188
return true ;
175
189
}
190
+
191
+ private:
192
+ FeatureBitset coalesceFeatures (const Module &M) {
193
+ FeatureBitset Features =
194
+ WasmTM
195
+ ->getSubtargetImpl (WasmTM->getTargetCPU (),
196
+ WasmTM->getTargetFeatureString ())
197
+ ->getFeatureBits ();
198
+ for (auto &F : M)
199
+ Features |= WasmTM->getSubtargetImpl (F)->getFeatureBits ();
200
+ return Features;
201
+ }
202
+
203
+ std::string getFeatureString (const FeatureBitset &Features) {
204
+ std::string Ret;
205
+ for (const SubtargetFeatureKV &KV : WebAssemblyFeatureKV) {
206
+ if (Features[KV.Value ])
207
+ Ret += (StringRef (" +" ) + KV.Key + " ," ).str ();
208
+ }
209
+ return Ret;
210
+ }
211
+
212
+ void replaceFeatures (Function &F, const std::string &Features) {
213
+ F.removeFnAttr (" target-features" );
214
+ F.removeFnAttr (" target-cpu" );
215
+ F.addFnAttr (" target-features" , Features);
216
+ }
217
+
218
+ bool stripAtomics (Module &M) {
219
+ // Detect whether any atomics will be lowered, since there is no way to tell
220
+ // whether the LowerAtomic pass lowers e.g. stores.
221
+ bool Stripped = false ;
222
+ for (auto &F : M) {
223
+ for (auto &B : F) {
224
+ for (auto &I : B) {
225
+ if (I.isAtomic ()) {
226
+ Stripped = true ;
227
+ goto done;
228
+ }
229
+ }
230
+ }
231
+ }
232
+
233
+ done:
234
+ if (!Stripped)
235
+ return false ;
236
+
237
+ LowerAtomicPass Lowerer;
238
+ FunctionAnalysisManager FAM;
239
+ for (auto &F : M)
240
+ Lowerer.run (F, FAM);
241
+
242
+ return true ;
243
+ }
244
+
245
+ bool stripThreadLocals (Module &M) {
246
+ bool Stripped = false ;
247
+ for (auto &GV : M.globals ()) {
248
+ if (GV.getThreadLocalMode () !=
249
+ GlobalValue::ThreadLocalMode::NotThreadLocal) {
250
+ Stripped = true ;
251
+ GV.setThreadLocalMode (GlobalValue::ThreadLocalMode::NotThreadLocal);
252
+ }
253
+ }
254
+ return Stripped;
255
+ }
256
+
257
+ void recordFeatures (Module &M, const FeatureBitset &Features, bool Stripped) {
258
+ for (const SubtargetFeatureKV &KV : WebAssemblyFeatureKV) {
259
+ std::string MDKey = (StringRef (" wasm-feature-" ) + KV.Key ).str ();
260
+ if (KV.Value == WebAssembly::FeatureAtomics && Stripped) {
261
+ // "atomics" is special: code compiled without atomics may have had its
262
+ // atomics lowered to nonatomic operations. In that case, atomics is
263
+ // disallowed to prevent unsafe linking with atomics-enabled objects.
264
+ assert (!Features[WebAssembly::FeatureAtomics]);
265
+ M.addModuleFlag (Module::ModFlagBehavior::Error, MDKey,
266
+ wasm::WASM_FEATURE_PREFIX_DISALLOWED);
267
+ } else if (Features[KV.Value ]) {
268
+ // Otherwise features are marked Used or not mentioned
269
+ M.addModuleFlag (Module::ModFlagBehavior::Error, MDKey,
270
+ wasm::WASM_FEATURE_PREFIX_USED);
271
+ }
272
+ }
273
+ }
176
274
};
177
- char StripThreadLocal ::ID = 0 ;
275
+ char CoalesceFeaturesAndStripAtomics ::ID = 0 ;
178
276
179
277
// / WebAssembly Code Generator Pass Configuration Options.
180
278
class WebAssemblyPassConfig final : public TargetPassConfig {
@@ -222,16 +320,11 @@ FunctionPass *WebAssemblyPassConfig::createTargetRegisterAllocator(bool) {
222
320
// ===----------------------------------------------------------------------===//
223
321
224
322
void WebAssemblyPassConfig::addIRPasses () {
225
- if (static_cast <WebAssemblyTargetMachine *>(TM)
226
- ->getUsedFeatures ()[WebAssembly::FeatureAtomics]) {
227
- // Expand some atomic operations. WebAssemblyTargetLowering has hooks which
228
- // control specifically what gets lowered.
229
- addPass (createAtomicExpandPass ());
230
- } else {
231
- // If atomics are not enabled, they get lowered to non-atomics.
232
- addPass (createLowerAtomicPass ());
233
- addPass (new StripThreadLocal ());
234
- }
323
+ // Runs LowerAtomicPass if necessary
324
+ addPass (new CoalesceFeaturesAndStripAtomics (&getWebAssemblyTargetMachine ()));
325
+
326
+ // This is a no-op if atomics are not used in the module
327
+ addPass (createAtomicExpandPass ());
235
328
236
329
// Add signatures to prototype-less function declarations
237
330
addPass (createWebAssemblyAddMissingPrototypes ());
0 commit comments