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