1//===- WebAssemblyTargetMachine.cpp - Define TargetMachine for WebAssembly -==//
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/// \file
10/// This file defines the WebAssembly-specific subclass of TargetMachine.
11///
12//===----------------------------------------------------------------------===//
13
14#include "WebAssemblyTargetMachine.h"
15#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
16#include "TargetInfo/WebAssemblyTargetInfo.h"
17#include "WebAssembly.h"
18#include "WebAssemblyISelLowering.h"
19#include "WebAssemblyMachineFunctionInfo.h"
20#include "WebAssemblyTargetObjectFile.h"
21#include "WebAssemblyTargetTransformInfo.h"
22#include "WebAssemblyUtilities.h"
23#include "llvm/CodeGen/MIRParser/MIParser.h"
24#include "llvm/CodeGen/Passes.h"
25#include "llvm/CodeGen/RegAllocRegistry.h"
26#include "llvm/CodeGen/TargetPassConfig.h"
27#include "llvm/IR/Function.h"
28#include "llvm/InitializePasses.h"
29#include "llvm/MC/TargetRegistry.h"
30#include "llvm/Support/Compiler.h"
31#include "llvm/Target/TargetOptions.h"
32#include "llvm/Transforms/Scalar.h"
33#include "llvm/Transforms/Scalar/LowerAtomicPass.h"
34#include "llvm/Transforms/Utils.h"
35#include <optional>
36using namespace llvm;
37
38#define DEBUG_TYPE "wasm"
39
40// A command-line option to keep implicit locals
41// for the purpose of testing with lit/llc ONLY.
42// This produces output which is not valid WebAssembly, and is not supported
43// by assemblers/disassemblers and other MC based tools.
44static cl::opt<bool> WasmDisableExplicitLocals(
45 "wasm-disable-explicit-locals", cl::Hidden,
46 cl::desc("WebAssembly: output implicit locals in"
47 " instruction output for test purposes only."),
48 cl::init(Val: false));
49
50static cl::opt<bool> WasmDisableFixIrreducibleControlFlowPass(
51 "wasm-disable-fix-irreducible-control-flow-pass", cl::Hidden,
52 cl::desc("webassembly: disables the fix "
53 " irreducible control flow optimization pass"),
54 cl::init(Val: false));
55
56// Exception handling & setjmp-longjmp handling related options.
57
58// Emscripten's asm.js-style exception handling
59cl::opt<bool> WebAssembly::WasmEnableEmEH(
60 "enable-emscripten-cxx-exceptions",
61 cl::desc("WebAssembly Emscripten-style exception handling"),
62 cl::init(Val: false));
63// Emscripten's asm.js-style setjmp/longjmp handling
64cl::opt<bool> WebAssembly::WasmEnableEmSjLj(
65 "enable-emscripten-sjlj",
66 cl::desc("WebAssembly Emscripten-style setjmp/longjmp handling"),
67 cl::init(Val: false));
68// Exception handling using wasm EH instructions
69cl::opt<bool>
70 WebAssembly::WasmEnableEH("wasm-enable-eh",
71 cl::desc("WebAssembly exception handling"));
72// setjmp/longjmp handling using wasm EH instrutions
73cl::opt<bool> WebAssembly::WasmEnableSjLj(
74 "wasm-enable-sjlj", cl::desc("WebAssembly setjmp/longjmp handling"));
75// If true, use the legacy Wasm EH proposal:
76// https://github.com/WebAssembly/exception-handling/blob/main/proposals/exception-handling/legacy/Exceptions.md
77// And if false, use the standardized Wasm EH proposal:
78// https://github.com/WebAssembly/exception-handling/blob/main/proposals/exception-handling/Exceptions.md
79// Currently set to true by default because not all major web browsers turn on
80// the new standard proposal by default, but will later change to false.
81cl::opt<bool> WebAssembly::WasmUseLegacyEH(
82 "wasm-use-legacy-eh", cl::desc("WebAssembly exception handling (legacy)"),
83 cl::init(Val: true));
84
85extern "C" LLVM_ABI LLVM_EXTERNAL_VISIBILITY void
86LLVMInitializeWebAssemblyTarget() {
87 // Register the target.
88 RegisterTargetMachine<WebAssemblyTargetMachine> X(
89 getTheWebAssemblyTarget32());
90 RegisterTargetMachine<WebAssemblyTargetMachine> Y(
91 getTheWebAssemblyTarget64());
92
93 // Register backend passes
94 auto &PR = *PassRegistry::getPassRegistry();
95 initializeWebAssemblyAddMissingPrototypesPass(PR);
96 initializeWebAssemblyLowerEmscriptenEHSjLjPass(PR);
97 initializeLowerGlobalDtorsLegacyPassPass(PR);
98 initializeFixFunctionBitcastsPass(PR);
99 initializeOptimizeReturnedPass(PR);
100 initializeWebAssemblyRefTypeMem2LocalPass(PR);
101 initializeWebAssemblyArgumentMovePass(PR);
102 initializeWebAssemblyAsmPrinterPass(PR);
103 initializeWebAssemblySetP2AlignOperandsPass(PR);
104 initializeWebAssemblyReplacePhysRegsPass(PR);
105 initializeWebAssemblyOptimizeLiveIntervalsPass(PR);
106 initializeWebAssemblyMemIntrinsicResultsPass(PR);
107 initializeWebAssemblyRegStackifyPass(PR);
108 initializeWebAssemblyRegColoringPass(PR);
109 initializeWebAssemblyNullifyDebugValueListsPass(PR);
110 initializeWebAssemblyFixIrreducibleControlFlowPass(PR);
111 initializeWebAssemblyLateEHPreparePass(PR);
112 initializeWebAssemblyExceptionInfoPass(PR);
113 initializeWebAssemblyCFGSortPass(PR);
114 initializeWebAssemblyCFGStackifyPass(PR);
115 initializeWebAssemblyExplicitLocalsPass(PR);
116 initializeWebAssemblyLowerBrUnlessPass(PR);
117 initializeWebAssemblyRegNumberingPass(PR);
118 initializeWebAssemblyDebugFixupPass(PR);
119 initializeWebAssemblyPeepholePass(PR);
120 initializeWebAssemblyMCLowerPrePassPass(PR);
121 initializeWebAssemblyLowerRefTypesIntPtrConvPass(PR);
122 initializeWebAssemblyFixBrTableDefaultsPass(PR);
123 initializeWebAssemblyDAGToDAGISelLegacyPass(PR);
124}
125
126//===----------------------------------------------------------------------===//
127// WebAssembly Lowering public interface.
128//===----------------------------------------------------------------------===//
129
130static Reloc::Model getEffectiveRelocModel(std::optional<Reloc::Model> RM) {
131 // Default to static relocation model. This should always be more optimial
132 // than PIC since the static linker can determine all global addresses and
133 // assume direct function calls.
134 return RM.value_or(u: Reloc::Static);
135}
136
137using WebAssembly::WasmEnableEH;
138using WebAssembly::WasmEnableEmEH;
139using WebAssembly::WasmEnableEmSjLj;
140using WebAssembly::WasmEnableSjLj;
141
142static void basicCheckForEHAndSjLj(TargetMachine *TM) {
143
144 // You can't enable two modes of EH at the same time
145 if (WasmEnableEmEH && WasmEnableEH)
146 report_fatal_error(
147 reason: "-enable-emscripten-cxx-exceptions not allowed with -wasm-enable-eh");
148 // You can't enable two modes of SjLj at the same time
149 if (WasmEnableEmSjLj && WasmEnableSjLj)
150 report_fatal_error(
151 reason: "-enable-emscripten-sjlj not allowed with -wasm-enable-sjlj");
152 // You can't mix Emscripten EH with Wasm SjLj.
153 if (WasmEnableEmEH && WasmEnableSjLj)
154 report_fatal_error(
155 reason: "-enable-emscripten-cxx-exceptions not allowed with -wasm-enable-sjlj");
156
157 if (TM->Options.ExceptionModel == ExceptionHandling::None) {
158 // FIXME: These flags should be removed in favor of directly using the
159 // generically configured ExceptionsType
160 if (WebAssembly::WasmEnableEH || WebAssembly::WasmEnableSjLj)
161 TM->Options.ExceptionModel = ExceptionHandling::Wasm;
162 }
163
164 // Basic Correctness checking related to -exception-model
165 if (TM->Options.ExceptionModel != ExceptionHandling::None &&
166 TM->Options.ExceptionModel != ExceptionHandling::Wasm)
167 report_fatal_error(reason: "-exception-model should be either 'none' or 'wasm'");
168 if (WasmEnableEmEH && TM->Options.ExceptionModel == ExceptionHandling::Wasm)
169 report_fatal_error(reason: "-exception-model=wasm not allowed with "
170 "-enable-emscripten-cxx-exceptions");
171 if (WasmEnableEH && TM->Options.ExceptionModel != ExceptionHandling::Wasm)
172 report_fatal_error(
173 reason: "-wasm-enable-eh only allowed with -exception-model=wasm");
174 if (WasmEnableSjLj && TM->Options.ExceptionModel != ExceptionHandling::Wasm)
175 report_fatal_error(
176 reason: "-wasm-enable-sjlj only allowed with -exception-model=wasm");
177 if ((!WasmEnableEH && !WasmEnableSjLj) &&
178 TM->Options.ExceptionModel == ExceptionHandling::Wasm)
179 report_fatal_error(
180 reason: "-exception-model=wasm only allowed with at least one of "
181 "-wasm-enable-eh or -wasm-enable-sjlj");
182
183 // Currently it is allowed to mix Wasm EH with Emscripten SjLj as an interim
184 // measure, but some code will error out at compile time in this combination.
185 // See WebAssemblyLowerEmscriptenEHSjLj pass for details.
186}
187
188/// Create an WebAssembly architecture model.
189///
190WebAssemblyTargetMachine::WebAssemblyTargetMachine(
191 const Target &T, const Triple &TT, StringRef CPU, StringRef FS,
192 const TargetOptions &Options, std::optional<Reloc::Model> RM,
193 std::optional<CodeModel::Model> CM, CodeGenOptLevel OL, bool JIT)
194 : CodeGenTargetMachineImpl(T, TT.computeDataLayout(), TT, CPU, FS, Options,
195 getEffectiveRelocModel(RM),
196 getEffectiveCodeModel(CM, Default: CodeModel::Large), OL),
197 TLOF(new WebAssemblyTargetObjectFile()),
198 UsesMultivalueABI(Options.MCOptions.getABIName() == "experimental-mv") {
199 // WebAssembly type-checks instructions, but a noreturn function with a return
200 // type that doesn't match the context will cause a check failure. So we lower
201 // LLVM 'unreachable' to ISD::TRAP and then lower that to WebAssembly's
202 // 'unreachable' instructions which is meant for that case. Formerly, we also
203 // needed to add checks to SP failure emission in the instruction selection
204 // backends, but this has since been tied to TrapUnreachable and is no longer
205 // necessary.
206 this->Options.TrapUnreachable = true;
207 this->Options.NoTrapAfterNoreturn = false;
208
209 // WebAssembly treats each function as an independent unit. Force
210 // -ffunction-sections, effectively, so that we can emit them independently.
211 this->Options.FunctionSections = true;
212 this->Options.DataSections = true;
213 this->Options.UniqueSectionNames = true;
214
215 basicCheckForEHAndSjLj(TM: this);
216 initAsmInfo();
217 // Note that we don't use setRequiresStructuredCFG(true). It disables
218 // optimizations than we're ok with, and want, such as critical edge
219 // splitting and tail merging.
220}
221
222WebAssemblyTargetMachine::~WebAssemblyTargetMachine() = default; // anchor.
223
224const WebAssemblySubtarget *WebAssemblyTargetMachine::getSubtargetImpl() const {
225 return getSubtargetImpl(CPU: std::string(getTargetCPU()),
226 FS: std::string(getTargetFeatureString()));
227}
228
229const WebAssemblySubtarget *
230WebAssemblyTargetMachine::getSubtargetImpl(std::string CPU,
231 std::string FS) const {
232 auto &I = SubtargetMap[CPU + FS];
233 if (!I) {
234 I = std::make_unique<WebAssemblySubtarget>(args: TargetTriple, args&: CPU, args&: FS, args: *this);
235 }
236 return I.get();
237}
238
239const WebAssemblySubtarget *
240WebAssemblyTargetMachine::getSubtargetImpl(const Function &F) const {
241 Attribute CPUAttr = F.getFnAttribute(Kind: "target-cpu");
242 Attribute FSAttr = F.getFnAttribute(Kind: "target-features");
243
244 std::string CPU =
245 CPUAttr.isValid() ? CPUAttr.getValueAsString().str() : TargetCPU;
246 std::string FS =
247 FSAttr.isValid() ? FSAttr.getValueAsString().str() : TargetFS;
248
249 // This needs to be done before we create a new subtarget since any
250 // creation will depend on the TM and the code generation flags on the
251 // function that reside in TargetOptions.
252 resetTargetOptions(F);
253
254 return getSubtargetImpl(CPU, FS);
255}
256
257namespace {
258
259class CoalesceFeaturesAndStripAtomics final : public ModulePass {
260 // Take the union of all features used in the module and use it for each
261 // function individually, since having multiple feature sets in one module
262 // currently does not make sense for WebAssembly. If atomics are not enabled,
263 // also strip atomic operations and thread local storage.
264 static char ID;
265 WebAssemblyTargetMachine *WasmTM;
266
267public:
268 CoalesceFeaturesAndStripAtomics(WebAssemblyTargetMachine *WasmTM)
269 : ModulePass(ID), WasmTM(WasmTM) {}
270
271 bool runOnModule(Module &M) override {
272 FeatureBitset Features = coalesceFeatures(M);
273
274 std::string FeatureStr = getFeatureString(Features);
275 WasmTM->setTargetFeatureString(FeatureStr);
276 for (auto &F : M)
277 replaceFeatures(F, Features: FeatureStr);
278
279 bool StrippedAtomics = false;
280 bool StrippedTLS = false;
281
282 if (!Features[WebAssembly::FeatureAtomics]) {
283 StrippedAtomics = stripAtomics(M);
284 StrippedTLS = stripThreadLocals(M);
285 } else if (!Features[WebAssembly::FeatureBulkMemory]) {
286 StrippedTLS |= stripThreadLocals(M);
287 }
288
289 if (StrippedAtomics && !StrippedTLS)
290 stripThreadLocals(M);
291 else if (StrippedTLS && !StrippedAtomics)
292 stripAtomics(M);
293
294 recordFeatures(M, Features, Stripped: StrippedAtomics || StrippedTLS);
295
296 // Conservatively assume we have made some change
297 return true;
298 }
299
300private:
301 FeatureBitset coalesceFeatures(const Module &M) {
302 // Union the features of all defined functions. Start with an empty set, so
303 // that if a feature is disabled in every function, we'll compute it as
304 // disabled. If any function lacks a target-features attribute, it'll
305 // default to the target CPU from the `TargetMachine`.
306 FeatureBitset Features;
307 bool AnyDefinedFuncs = false;
308 for (auto &F : M) {
309 if (F.isDeclaration())
310 continue;
311
312 Features |= WasmTM->getSubtargetImpl(F)->getFeatureBits();
313 AnyDefinedFuncs = true;
314 }
315
316 // If we have no defined functions, use the target CPU from the
317 // `TargetMachine`.
318 if (!AnyDefinedFuncs) {
319 Features =
320 WasmTM
321 ->getSubtargetImpl(CPU: std::string(WasmTM->getTargetCPU()),
322 FS: std::string(WasmTM->getTargetFeatureString()))
323 ->getFeatureBits();
324 }
325
326 return Features;
327 }
328
329 static std::string getFeatureString(const FeatureBitset &Features) {
330 std::string Ret;
331 for (const SubtargetFeatureKV &KV : WebAssemblyFeatureKV) {
332 if (Features[KV.Value])
333 Ret += (StringRef("+") + KV.Key + ",").str();
334 else
335 Ret += (StringRef("-") + KV.Key + ",").str();
336 }
337 // remove trailing ','
338 Ret.pop_back();
339 return Ret;
340 }
341
342 void replaceFeatures(Function &F, const std::string &Features) {
343 F.removeFnAttr(Kind: "target-features");
344 F.removeFnAttr(Kind: "target-cpu");
345 F.addFnAttr(Kind: "target-features", Val: Features);
346 }
347
348 bool stripAtomics(Module &M) {
349 // Detect whether any atomics will be lowered, since there is no way to tell
350 // whether the LowerAtomic pass lowers e.g. stores.
351 bool Stripped = false;
352 for (auto &F : M) {
353 for (auto &B : F) {
354 for (auto &I : B) {
355 if (I.isAtomic()) {
356 Stripped = true;
357 goto done;
358 }
359 }
360 }
361 }
362
363 done:
364 if (!Stripped)
365 return false;
366
367 LowerAtomicPass Lowerer;
368 FunctionAnalysisManager FAM;
369 for (auto &F : M)
370 Lowerer.run(F, FAM);
371
372 return true;
373 }
374
375 bool stripThreadLocals(Module &M) {
376 bool Stripped = false;
377 for (auto &GV : M.globals()) {
378 if (GV.isThreadLocal()) {
379 // replace `@llvm.threadlocal.address.pX(GV)` with `GV`.
380 for (Use &U : make_early_inc_range(Range: GV.uses())) {
381 if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(Val: U.getUser())) {
382 if (II->getIntrinsicID() == Intrinsic::threadlocal_address &&
383 II->getArgOperand(i: 0) == &GV) {
384 II->replaceAllUsesWith(V: &GV);
385 II->eraseFromParent();
386 }
387 }
388 }
389
390 Stripped = true;
391 GV.setThreadLocal(false);
392 }
393 }
394 return Stripped;
395 }
396
397 void recordFeatures(Module &M, const FeatureBitset &Features, bool Stripped) {
398 for (const SubtargetFeatureKV &KV : WebAssemblyFeatureKV) {
399 if (Features[KV.Value]) {
400 // Mark features as used
401 std::string MDKey = (StringRef("wasm-feature-") + KV.Key).str();
402 M.addModuleFlag(Behavior: Module::ModFlagBehavior::Error, Key: MDKey,
403 Val: wasm::WASM_FEATURE_PREFIX_USED);
404 }
405 }
406 // Code compiled without atomics or bulk-memory may have had its atomics or
407 // thread-local data lowered to nonatomic operations or non-thread-local
408 // data. In that case, we mark the pseudo-feature "shared-mem" as disallowed
409 // to tell the linker that it would be unsafe to allow this code ot be used
410 // in a module with shared memory.
411 if (Stripped) {
412 M.addModuleFlag(Behavior: Module::ModFlagBehavior::Error, Key: "wasm-feature-shared-mem",
413 Val: wasm::WASM_FEATURE_PREFIX_DISALLOWED);
414 }
415 }
416};
417char CoalesceFeaturesAndStripAtomics::ID = 0;
418
419/// WebAssembly Code Generator Pass Configuration Options.
420class WebAssemblyPassConfig final : public TargetPassConfig {
421public:
422 WebAssemblyPassConfig(WebAssemblyTargetMachine &TM, PassManagerBase &PM)
423 : TargetPassConfig(TM, PM) {}
424
425 WebAssemblyTargetMachine &getWebAssemblyTargetMachine() const {
426 return getTM<WebAssemblyTargetMachine>();
427 }
428
429 FunctionPass *createTargetRegisterAllocator(bool) override;
430
431 void addIRPasses() override;
432 void addISelPrepare() override;
433 bool addInstSelector() override;
434 void addOptimizedRegAlloc() override;
435 void addPostRegAlloc() override;
436 bool addGCPasses() override { return false; }
437 void addPreEmitPass() override;
438 bool addPreISel() override;
439
440 // No reg alloc
441 bool addRegAssignAndRewriteFast() override { return false; }
442
443 // No reg alloc
444 bool addRegAssignAndRewriteOptimized() override { return false; }
445};
446} // end anonymous namespace
447
448MachineFunctionInfo *WebAssemblyTargetMachine::createMachineFunctionInfo(
449 BumpPtrAllocator &Allocator, const Function &F,
450 const TargetSubtargetInfo *STI) const {
451 return WebAssemblyFunctionInfo::create<WebAssemblyFunctionInfo>(Allocator, F,
452 STI);
453}
454
455TargetTransformInfo
456WebAssemblyTargetMachine::getTargetTransformInfo(const Function &F) const {
457 return TargetTransformInfo(std::make_unique<WebAssemblyTTIImpl>(args: this, args: F));
458}
459
460TargetPassConfig *
461WebAssemblyTargetMachine::createPassConfig(PassManagerBase &PM) {
462 return new WebAssemblyPassConfig(*this, PM);
463}
464
465FunctionPass *WebAssemblyPassConfig::createTargetRegisterAllocator(bool) {
466 return nullptr; // No reg alloc
467}
468
469//===----------------------------------------------------------------------===//
470// The following functions are called from lib/CodeGen/Passes.cpp to modify
471// the CodeGen pass sequence.
472//===----------------------------------------------------------------------===//
473
474void WebAssemblyPassConfig::addIRPasses() {
475 // Add signatures to prototype-less function declarations
476 addPass(P: createWebAssemblyAddMissingPrototypes());
477
478 // Lower .llvm.global_dtors into .llvm.global_ctors with __cxa_atexit calls.
479 addPass(P: createLowerGlobalDtorsLegacyPass());
480
481 // Fix function bitcasts, as WebAssembly requires caller and callee signatures
482 // to match.
483 addPass(P: createWebAssemblyFixFunctionBitcasts());
484
485 // Optimize "returned" function attributes.
486 if (getOptLevel() != CodeGenOptLevel::None)
487 addPass(P: createWebAssemblyOptimizeReturned());
488
489 // If exception handling is not enabled and setjmp/longjmp handling is
490 // enabled, we lower invokes into calls and delete unreachable landingpad
491 // blocks. Lowering invokes when there is no EH support is done in
492 // TargetPassConfig::addPassesToHandleExceptions, but that runs after these IR
493 // passes and Emscripten SjLj handling expects all invokes to be lowered
494 // before.
495 if (!WasmEnableEmEH && !WasmEnableEH) {
496 addPass(P: createLowerInvokePass());
497 // The lower invoke pass may create unreachable code. Remove it in order not
498 // to process dead blocks in setjmp/longjmp handling.
499 addPass(P: createUnreachableBlockEliminationPass());
500 }
501
502 // Handle exceptions and setjmp/longjmp if enabled. Unlike Wasm EH preparation
503 // done in WasmEHPrepare pass, Wasm SjLj preparation shares libraries and
504 // transformation algorithms with Emscripten SjLj, so we run
505 // LowerEmscriptenEHSjLj pass also when Wasm SjLj is enabled.
506 if (WasmEnableEmEH || WasmEnableEmSjLj || WasmEnableSjLj)
507 addPass(P: createWebAssemblyLowerEmscriptenEHSjLj());
508
509 // Expand indirectbr instructions to switches.
510 addPass(P: createIndirectBrExpandPass());
511
512 TargetPassConfig::addIRPasses();
513}
514
515void WebAssemblyPassConfig::addISelPrepare() {
516 // We need to move reference type allocas to WASM_ADDRESS_SPACE_VAR so that
517 // loads and stores are promoted to local.gets/local.sets.
518 addPass(P: createWebAssemblyRefTypeMem2Local());
519 // Lower atomics and TLS if necessary
520 addPass(P: new CoalesceFeaturesAndStripAtomics(&getWebAssemblyTargetMachine()));
521
522 // This is a no-op if atomics are not used in the module
523 addPass(P: createAtomicExpandLegacyPass());
524
525 TargetPassConfig::addISelPrepare();
526}
527
528bool WebAssemblyPassConfig::addInstSelector() {
529 (void)TargetPassConfig::addInstSelector();
530 addPass(
531 P: createWebAssemblyISelDag(TM&: getWebAssemblyTargetMachine(), OptLevel: getOptLevel()));
532 // Run the argument-move pass immediately after the ScheduleDAG scheduler
533 // so that we can fix up the ARGUMENT instructions before anything else
534 // sees them in the wrong place.
535 addPass(P: createWebAssemblyArgumentMove());
536 // Set the p2align operands. This information is present during ISel, however
537 // it's inconvenient to collect. Collect it now, and update the immediate
538 // operands.
539 addPass(P: createWebAssemblySetP2AlignOperands());
540
541 // Eliminate range checks and add default targets to br_table instructions.
542 addPass(P: createWebAssemblyFixBrTableDefaults());
543
544 // unreachable is terminator, non-terminator instruction after it is not
545 // allowed.
546 addPass(P: createWebAssemblyCleanCodeAfterTrap());
547
548 return false;
549}
550
551void WebAssemblyPassConfig::addOptimizedRegAlloc() {
552 // Currently RegisterCoalesce degrades wasm debug info quality by a
553 // significant margin. As a quick fix, disable this for -O1, which is often
554 // used for debugging large applications. Disabling this increases code size
555 // of Emscripten core benchmarks by ~5%, which is acceptable for -O1, which is
556 // usually not used for production builds.
557 // TODO Investigate why RegisterCoalesce degrades debug info quality and fix
558 // it properly
559 if (getOptLevel() == CodeGenOptLevel::Less)
560 disablePass(PassID: &RegisterCoalescerID);
561 TargetPassConfig::addOptimizedRegAlloc();
562}
563
564void WebAssemblyPassConfig::addPostRegAlloc() {
565 // TODO: The following CodeGen passes don't currently support code containing
566 // virtual registers. Consider removing their restrictions and re-enabling
567 // them.
568
569 // These functions all require the NoVRegs property.
570 disablePass(PassID: &MachineLateInstrsCleanupID);
571 disablePass(PassID: &MachineCopyPropagationID);
572 disablePass(PassID: &PostRAMachineSinkingID);
573 disablePass(PassID: &PostRASchedulerID);
574 disablePass(PassID: &FuncletLayoutID);
575 disablePass(PassID: &StackMapLivenessID);
576 disablePass(PassID: &PatchableFunctionID);
577 disablePass(PassID: &ShrinkWrapID);
578 disablePass(PassID: &RemoveLoadsIntoFakeUsesID);
579
580 // This pass hurts code size for wasm because it can generate irreducible
581 // control flow.
582 disablePass(PassID: &MachineBlockPlacementID);
583
584 TargetPassConfig::addPostRegAlloc();
585}
586
587void WebAssemblyPassConfig::addPreEmitPass() {
588 TargetPassConfig::addPreEmitPass();
589
590 // Nullify DBG_VALUE_LISTs that we cannot handle.
591 addPass(P: createWebAssemblyNullifyDebugValueLists());
592
593 // Eliminate multiple-entry loops.
594 if (!WasmDisableFixIrreducibleControlFlowPass)
595 addPass(P: createWebAssemblyFixIrreducibleControlFlow());
596
597 // Do various transformations for exception handling.
598 // Every CFG-changing optimizations should come before this.
599 if (TM->Options.ExceptionModel == ExceptionHandling::Wasm)
600 addPass(P: createWebAssemblyLateEHPrepare());
601
602 // Now that we have a prologue and epilogue and all frame indices are
603 // rewritten, eliminate SP and FP. This allows them to be stackified,
604 // colored, and numbered with the rest of the registers.
605 addPass(P: createWebAssemblyReplacePhysRegs());
606
607 // Preparations and optimizations related to register stackification.
608 if (getOptLevel() != CodeGenOptLevel::None) {
609 // Depend on LiveIntervals and perform some optimizations on it.
610 addPass(P: createWebAssemblyOptimizeLiveIntervals());
611
612 // Prepare memory intrinsic calls for register stackifying.
613 addPass(P: createWebAssemblyMemIntrinsicResults());
614 }
615
616 // Mark registers as representing wasm's value stack. This is a key
617 // code-compression technique in WebAssembly. We run this pass (and
618 // MemIntrinsicResults above) very late, so that it sees as much code as
619 // possible, including code emitted by PEI and expanded by late tail
620 // duplication.
621 addPass(P: createWebAssemblyRegStackify(OptLevel: getOptLevel()));
622
623 if (getOptLevel() != CodeGenOptLevel::None) {
624 // Run the register coloring pass to reduce the total number of registers.
625 // This runs after stackification so that it doesn't consider registers
626 // that become stackified.
627 addPass(P: createWebAssemblyRegColoring());
628 }
629
630 // Sort the blocks of the CFG into topological order, a prerequisite for
631 // BLOCK and LOOP markers.
632 addPass(P: createWebAssemblyCFGSort());
633
634 // Insert BLOCK and LOOP markers.
635 addPass(P: createWebAssemblyCFGStackify());
636
637 // Insert explicit local.get and local.set operators.
638 if (!WasmDisableExplicitLocals)
639 addPass(P: createWebAssemblyExplicitLocals());
640
641 // Lower br_unless into br_if.
642 addPass(P: createWebAssemblyLowerBrUnless());
643
644 // Perform the very last peephole optimizations on the code.
645 if (getOptLevel() != CodeGenOptLevel::None)
646 addPass(P: createWebAssemblyPeephole());
647
648 // Create a mapping from LLVM CodeGen virtual registers to wasm registers.
649 addPass(P: createWebAssemblyRegNumbering());
650
651 // Fix debug_values whose defs have been stackified.
652 if (!WasmDisableExplicitLocals)
653 addPass(P: createWebAssemblyDebugFixup());
654
655 // Collect information to prepare for MC lowering / asm printing.
656 addPass(P: createWebAssemblyMCLowerPrePass());
657}
658
659bool WebAssemblyPassConfig::addPreISel() {
660 TargetPassConfig::addPreISel();
661 addPass(P: createWebAssemblyLowerRefTypesIntPtrConv());
662 return false;
663}
664
665yaml::MachineFunctionInfo *
666WebAssemblyTargetMachine::createDefaultFuncInfoYAML() const {
667 return new yaml::WebAssemblyFunctionInfo();
668}
669
670yaml::MachineFunctionInfo *WebAssemblyTargetMachine::convertFuncInfoToYAML(
671 const MachineFunction &MF) const {
672 const auto *MFI = MF.getInfo<WebAssemblyFunctionInfo>();
673 return new yaml::WebAssemblyFunctionInfo(MF, *MFI);
674}
675
676bool WebAssemblyTargetMachine::parseMachineFunctionInfo(
677 const yaml::MachineFunctionInfo &MFI, PerFunctionMIParsingState &PFS,
678 SMDiagnostic &Error, SMRange &SourceRange) const {
679 const auto &YamlMFI = static_cast<const yaml::WebAssemblyFunctionInfo &>(MFI);
680 MachineFunction &MF = PFS.MF;
681 MF.getInfo<WebAssemblyFunctionInfo>()->initializeBaseYamlFields(MF, YamlMFI);
682 return false;
683}
684