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