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