13dac3a9bSDimitry Andric //===- WebAssemblyTargetMachine.cpp - Define TargetMachine for WebAssembly -==//
23dac3a9bSDimitry Andric //
33dac3a9bSDimitry Andric //                     The LLVM Compiler Infrastructure
43dac3a9bSDimitry Andric //
53dac3a9bSDimitry Andric // This file is distributed under the University of Illinois Open Source
63dac3a9bSDimitry Andric // License. See LICENSE.TXT for details.
73dac3a9bSDimitry Andric //
83dac3a9bSDimitry Andric //===----------------------------------------------------------------------===//
93dac3a9bSDimitry Andric ///
103dac3a9bSDimitry Andric /// \file
114ba319b5SDimitry Andric /// This file defines the WebAssembly-specific subclass of TargetMachine.
123dac3a9bSDimitry Andric ///
133dac3a9bSDimitry Andric //===----------------------------------------------------------------------===//
143dac3a9bSDimitry Andric 
153dac3a9bSDimitry Andric #include "WebAssemblyTargetMachine.h"
16db17bf38SDimitry Andric #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
17db17bf38SDimitry Andric #include "WebAssembly.h"
183dac3a9bSDimitry Andric #include "WebAssemblyTargetObjectFile.h"
193dac3a9bSDimitry Andric #include "WebAssemblyTargetTransformInfo.h"
203dac3a9bSDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h"
213dac3a9bSDimitry Andric #include "llvm/CodeGen/Passes.h"
223dac3a9bSDimitry Andric #include "llvm/CodeGen/RegAllocRegistry.h"
233ca95b02SDimitry Andric #include "llvm/CodeGen/TargetPassConfig.h"
243dac3a9bSDimitry Andric #include "llvm/IR/Function.h"
253dac3a9bSDimitry Andric #include "llvm/Support/TargetRegistry.h"
263dac3a9bSDimitry Andric #include "llvm/Target/TargetOptions.h"
273dac3a9bSDimitry Andric #include "llvm/Transforms/Scalar.h"
284ba319b5SDimitry Andric #include "llvm/Transforms/Utils.h"
293dac3a9bSDimitry Andric using namespace llvm;
303dac3a9bSDimitry Andric 
313dac3a9bSDimitry Andric #define DEBUG_TYPE "wasm"
323dac3a9bSDimitry Andric 
33d88c1a5aSDimitry Andric // Emscripten's asm.js-style exception handling
34d88c1a5aSDimitry Andric static cl::opt<bool> EnableEmException(
35d88c1a5aSDimitry Andric     "enable-emscripten-cxx-exceptions",
36d88c1a5aSDimitry Andric     cl::desc("WebAssembly Emscripten-style exception handling"),
37d88c1a5aSDimitry Andric     cl::init(false));
38d88c1a5aSDimitry Andric 
39d88c1a5aSDimitry Andric // Emscripten's asm.js-style setjmp/longjmp handling
40d88c1a5aSDimitry Andric static cl::opt<bool> EnableEmSjLj(
41d88c1a5aSDimitry Andric     "enable-emscripten-sjlj",
42d88c1a5aSDimitry Andric     cl::desc("WebAssembly Emscripten-style setjmp/longjmp handling"),
43d88c1a5aSDimitry Andric     cl::init(false));
44d88c1a5aSDimitry Andric 
LLVMInitializeWebAssemblyTarget()453dac3a9bSDimitry Andric extern "C" void LLVMInitializeWebAssemblyTarget() {
463dac3a9bSDimitry Andric   // Register the target.
47d88c1a5aSDimitry Andric   RegisterTargetMachine<WebAssemblyTargetMachine> X(
48d88c1a5aSDimitry Andric       getTheWebAssemblyTarget32());
49d88c1a5aSDimitry Andric   RegisterTargetMachine<WebAssemblyTargetMachine> Y(
50d88c1a5aSDimitry Andric       getTheWebAssemblyTarget64());
51d88c1a5aSDimitry Andric 
524ba319b5SDimitry Andric   // Register backend passes
534ba319b5SDimitry Andric   auto &PR = *PassRegistry::getPassRegistry();
544ba319b5SDimitry Andric   initializeWebAssemblyAddMissingPrototypesPass(PR);
554ba319b5SDimitry Andric   initializeWebAssemblyLowerEmscriptenEHSjLjPass(PR);
564ba319b5SDimitry Andric   initializeLowerGlobalDtorsPass(PR);
574ba319b5SDimitry Andric   initializeFixFunctionBitcastsPass(PR);
584ba319b5SDimitry Andric   initializeOptimizeReturnedPass(PR);
594ba319b5SDimitry Andric   initializeWebAssemblyArgumentMovePass(PR);
604ba319b5SDimitry Andric   initializeWebAssemblySetP2AlignOperandsPass(PR);
61*b5893f02SDimitry Andric   initializeWebAssemblyEHRestoreStackPointerPass(PR);
624ba319b5SDimitry Andric   initializeWebAssemblyReplacePhysRegsPass(PR);
634ba319b5SDimitry Andric   initializeWebAssemblyPrepareForLiveIntervalsPass(PR);
644ba319b5SDimitry Andric   initializeWebAssemblyOptimizeLiveIntervalsPass(PR);
65*b5893f02SDimitry Andric   initializeWebAssemblyMemIntrinsicResultsPass(PR);
664ba319b5SDimitry Andric   initializeWebAssemblyRegStackifyPass(PR);
674ba319b5SDimitry Andric   initializeWebAssemblyRegColoringPass(PR);
684ba319b5SDimitry Andric   initializeWebAssemblyExplicitLocalsPass(PR);
694ba319b5SDimitry Andric   initializeWebAssemblyFixIrreducibleControlFlowPass(PR);
704ba319b5SDimitry Andric   initializeWebAssemblyLateEHPreparePass(PR);
714ba319b5SDimitry Andric   initializeWebAssemblyExceptionInfoPass(PR);
724ba319b5SDimitry Andric   initializeWebAssemblyCFGSortPass(PR);
734ba319b5SDimitry Andric   initializeWebAssemblyCFGStackifyPass(PR);
744ba319b5SDimitry Andric   initializeWebAssemblyLowerBrUnlessPass(PR);
754ba319b5SDimitry Andric   initializeWebAssemblyRegNumberingPass(PR);
764ba319b5SDimitry Andric   initializeWebAssemblyPeepholePass(PR);
774ba319b5SDimitry Andric   initializeWebAssemblyCallIndirectFixupPass(PR);
783dac3a9bSDimitry Andric }
793dac3a9bSDimitry Andric 
803dac3a9bSDimitry Andric //===----------------------------------------------------------------------===//
813dac3a9bSDimitry Andric // WebAssembly Lowering public interface.
823dac3a9bSDimitry Andric //===----------------------------------------------------------------------===//
833dac3a9bSDimitry Andric 
getEffectiveRelocModel(Optional<Reloc::Model> RM)843ca95b02SDimitry Andric static Reloc::Model getEffectiveRelocModel(Optional<Reloc::Model> RM) {
85*b5893f02SDimitry Andric   if (!RM.hasValue()) {
86*b5893f02SDimitry Andric     // Default to static relocation model.  This should always be more optimial
87*b5893f02SDimitry Andric     // than PIC since the static linker can determine all global addresses and
88*b5893f02SDimitry Andric     // assume direct function calls.
89*b5893f02SDimitry Andric     return Reloc::Static;
90*b5893f02SDimitry Andric   }
913ca95b02SDimitry Andric   return *RM;
923ca95b02SDimitry Andric }
933ca95b02SDimitry Andric 
943dac3a9bSDimitry Andric /// Create an WebAssembly architecture model.
953dac3a9bSDimitry Andric ///
WebAssemblyTargetMachine(const Target & T,const Triple & TT,StringRef CPU,StringRef FS,const TargetOptions & Options,Optional<Reloc::Model> RM,Optional<CodeModel::Model> CM,CodeGenOpt::Level OL,bool JIT)963dac3a9bSDimitry Andric WebAssemblyTargetMachine::WebAssemblyTargetMachine(
973dac3a9bSDimitry Andric     const Target &T, const Triple &TT, StringRef CPU, StringRef FS,
983ca95b02SDimitry Andric     const TargetOptions &Options, Optional<Reloc::Model> RM,
992cab237bSDimitry Andric     Optional<CodeModel::Model> CM, CodeGenOpt::Level OL, bool JIT)
100444ed5c5SDimitry Andric     : LLVMTargetMachine(T,
101444ed5c5SDimitry Andric                         TT.isArch64Bit() ? "e-m:e-p:64:64-i64:64-n32:64-S128"
102444ed5c5SDimitry Andric                                          : "e-m:e-p:32:32-i64:64-n32:64-S128",
1033ca95b02SDimitry Andric                         TT, CPU, FS, Options, getEffectiveRelocModel(RM),
104*b5893f02SDimitry Andric                         getEffectiveCodeModel(CM, CodeModel::Large), OL),
1054ba319b5SDimitry Andric       TLOF(new WebAssemblyTargetObjectFile()) {
106d88c1a5aSDimitry Andric   // WebAssembly type-checks instructions, but a noreturn function with a return
1077d523365SDimitry Andric   // type that doesn't match the context will cause a check failure. So we lower
1087d523365SDimitry Andric   // LLVM 'unreachable' to ISD::TRAP and then lower that to WebAssembly's
109d88c1a5aSDimitry Andric   // 'unreachable' instructions which is meant for that case.
1107d523365SDimitry Andric   this->Options.TrapUnreachable = true;
1117d523365SDimitry Andric 
1127a7e6055SDimitry Andric   // WebAssembly treats each function as an independent unit. Force
1137a7e6055SDimitry Andric   // -ffunction-sections, effectively, so that we can emit them independently.
1147a7e6055SDimitry Andric   this->Options.FunctionSections = true;
1157a7e6055SDimitry Andric   this->Options.DataSections = true;
1167a7e6055SDimitry Andric   this->Options.UniqueSectionNames = true;
1177a7e6055SDimitry Andric 
1183dac3a9bSDimitry Andric   initAsmInfo();
1193dac3a9bSDimitry Andric 
1203ca95b02SDimitry Andric   // Note that we don't use setRequiresStructuredCFG(true). It disables
1213ca95b02SDimitry Andric   // optimizations than we're ok with, and want, such as critical edge
1223ca95b02SDimitry Andric   // splitting and tail merging.
1233dac3a9bSDimitry Andric }
1243dac3a9bSDimitry Andric 
~WebAssemblyTargetMachine()1253dac3a9bSDimitry Andric WebAssemblyTargetMachine::~WebAssemblyTargetMachine() {}
1263dac3a9bSDimitry Andric 
1273dac3a9bSDimitry Andric const WebAssemblySubtarget *
getSubtargetImpl(const Function & F) const1283dac3a9bSDimitry Andric WebAssemblyTargetMachine::getSubtargetImpl(const Function &F) const {
1293dac3a9bSDimitry Andric   Attribute CPUAttr = F.getFnAttribute("target-cpu");
1303dac3a9bSDimitry Andric   Attribute FSAttr = F.getFnAttribute("target-features");
1313dac3a9bSDimitry Andric 
1323dac3a9bSDimitry Andric   std::string CPU = !CPUAttr.hasAttribute(Attribute::None)
1333dac3a9bSDimitry Andric                         ? CPUAttr.getValueAsString().str()
1343dac3a9bSDimitry Andric                         : TargetCPU;
1353dac3a9bSDimitry Andric   std::string FS = !FSAttr.hasAttribute(Attribute::None)
1363dac3a9bSDimitry Andric                        ? FSAttr.getValueAsString().str()
1373dac3a9bSDimitry Andric                        : TargetFS;
1383dac3a9bSDimitry Andric 
1393dac3a9bSDimitry Andric   auto &I = SubtargetMap[CPU + FS];
1403dac3a9bSDimitry Andric   if (!I) {
1413dac3a9bSDimitry Andric     // This needs to be done before we create a new subtarget since any
1423dac3a9bSDimitry Andric     // creation will depend on the TM and the code generation flags on the
1433dac3a9bSDimitry Andric     // function that reside in TargetOptions.
1443dac3a9bSDimitry Andric     resetTargetOptions(F);
1457d523365SDimitry Andric     I = llvm::make_unique<WebAssemblySubtarget>(TargetTriple, CPU, FS, *this);
1463dac3a9bSDimitry Andric   }
1473dac3a9bSDimitry Andric   return I.get();
1483dac3a9bSDimitry Andric }
1493dac3a9bSDimitry Andric 
1503dac3a9bSDimitry Andric namespace {
1514ba319b5SDimitry Andric class StripThreadLocal final : public ModulePass {
1524ba319b5SDimitry Andric   // The default thread model for wasm is single, where thread-local variables
1534ba319b5SDimitry Andric   // are identical to regular globals and should be treated the same. So this
1544ba319b5SDimitry Andric   // pass just converts all GlobalVariables to NotThreadLocal
1554ba319b5SDimitry Andric   static char ID;
1564ba319b5SDimitry Andric 
1574ba319b5SDimitry Andric public:
StripThreadLocal()1584ba319b5SDimitry Andric   StripThreadLocal() : ModulePass(ID) {}
runOnModule(Module & M)1594ba319b5SDimitry Andric   bool runOnModule(Module &M) override {
1604ba319b5SDimitry Andric     for (auto &GV : M.globals())
1614ba319b5SDimitry Andric       GV.setThreadLocalMode(GlobalValue::ThreadLocalMode::NotThreadLocal);
1624ba319b5SDimitry Andric     return true;
1634ba319b5SDimitry Andric   }
1644ba319b5SDimitry Andric };
1654ba319b5SDimitry Andric char StripThreadLocal::ID = 0;
1664ba319b5SDimitry Andric 
1673dac3a9bSDimitry Andric /// WebAssembly Code Generator Pass Configuration Options.
1683dac3a9bSDimitry Andric class WebAssemblyPassConfig final : public TargetPassConfig {
1693dac3a9bSDimitry Andric public:
WebAssemblyPassConfig(WebAssemblyTargetMachine & TM,PassManagerBase & PM)170f9448bf3SDimitry Andric   WebAssemblyPassConfig(WebAssemblyTargetMachine &TM, PassManagerBase &PM)
1713dac3a9bSDimitry Andric       : TargetPassConfig(TM, PM) {}
1723dac3a9bSDimitry Andric 
getWebAssemblyTargetMachine() const1733dac3a9bSDimitry Andric   WebAssemblyTargetMachine &getWebAssemblyTargetMachine() const {
1743dac3a9bSDimitry Andric     return getTM<WebAssemblyTargetMachine>();
1753dac3a9bSDimitry Andric   }
1763dac3a9bSDimitry Andric 
1773dac3a9bSDimitry Andric   FunctionPass *createTargetRegisterAllocator(bool) override;
1783dac3a9bSDimitry Andric 
1793dac3a9bSDimitry Andric   void addIRPasses() override;
1803dac3a9bSDimitry Andric   bool addInstSelector() override;
1813dac3a9bSDimitry Andric   void addPostRegAlloc() override;
addGCPasses()1823ca95b02SDimitry Andric   bool addGCPasses() override { return false; }
1833dac3a9bSDimitry Andric   void addPreEmitPass() override;
1843dac3a9bSDimitry Andric };
1853dac3a9bSDimitry Andric } // end anonymous namespace
1863dac3a9bSDimitry Andric 
187da09e106SDimitry Andric TargetTransformInfo
getTargetTransformInfo(const Function & F)188da09e106SDimitry Andric WebAssemblyTargetMachine::getTargetTransformInfo(const Function &F) {
1893dac3a9bSDimitry Andric   return TargetTransformInfo(WebAssemblyTTIImpl(this, F));
1903dac3a9bSDimitry Andric }
1913dac3a9bSDimitry Andric 
1923dac3a9bSDimitry Andric TargetPassConfig *
createPassConfig(PassManagerBase & PM)1933dac3a9bSDimitry Andric WebAssemblyTargetMachine::createPassConfig(PassManagerBase &PM) {
194f9448bf3SDimitry Andric   return new WebAssemblyPassConfig(*this, PM);
1953dac3a9bSDimitry Andric }
1963dac3a9bSDimitry Andric 
createTargetRegisterAllocator(bool)1973dac3a9bSDimitry Andric FunctionPass *WebAssemblyPassConfig::createTargetRegisterAllocator(bool) {
1983dac3a9bSDimitry Andric   return nullptr; // No reg alloc
1993dac3a9bSDimitry Andric }
2003dac3a9bSDimitry Andric 
2013dac3a9bSDimitry Andric //===----------------------------------------------------------------------===//
2023dac3a9bSDimitry Andric // The following functions are called from lib/CodeGen/Passes.cpp to modify
2033dac3a9bSDimitry Andric // the CodeGen pass sequence.
2043dac3a9bSDimitry Andric //===----------------------------------------------------------------------===//
2053dac3a9bSDimitry Andric 
addIRPasses()2063dac3a9bSDimitry Andric void WebAssemblyPassConfig::addIRPasses() {
2074ba319b5SDimitry Andric   if (TM->Options.ThreadModel == ThreadModel::Single) {
2087d523365SDimitry Andric     // In "single" mode, atomics get lowered to non-atomics.
2093dac3a9bSDimitry Andric     addPass(createLowerAtomicPass());
2104ba319b5SDimitry Andric     addPass(new StripThreadLocal());
2114ba319b5SDimitry Andric   } else {
2123dac3a9bSDimitry Andric     // Expand some atomic operations. WebAssemblyTargetLowering has hooks which
2133dac3a9bSDimitry Andric     // control specifically what gets lowered.
214d8866befSDimitry Andric     addPass(createAtomicExpandPass());
2154ba319b5SDimitry Andric   }
2164ba319b5SDimitry Andric 
2174ba319b5SDimitry Andric   // Add signatures to prototype-less function declarations
2184ba319b5SDimitry Andric   addPass(createWebAssemblyAddMissingPrototypes());
2193dac3a9bSDimitry Andric 
2202cab237bSDimitry Andric   // Lower .llvm.global_dtors into .llvm_global_ctors with __cxa_atexit calls.
2212cab237bSDimitry Andric   addPass(createWebAssemblyLowerGlobalDtors());
2222cab237bSDimitry Andric 
22324e2fe98SDimitry Andric   // Fix function bitcasts, as WebAssembly requires caller and callee signatures
22424e2fe98SDimitry Andric   // to match.
22524e2fe98SDimitry Andric   addPass(createWebAssemblyFixFunctionBitcasts());
22624e2fe98SDimitry Andric 
2277d523365SDimitry Andric   // Optimize "returned" function attributes.
2283ca95b02SDimitry Andric   if (getOptLevel() != CodeGenOpt::None)
2297d523365SDimitry Andric     addPass(createWebAssemblyOptimizeReturned());
2307d523365SDimitry Andric 
231d88c1a5aSDimitry Andric   // If exception handling is not enabled and setjmp/longjmp handling is
232d88c1a5aSDimitry Andric   // enabled, we lower invokes into calls and delete unreachable landingpad
233d88c1a5aSDimitry Andric   // blocks. Lowering invokes when there is no EH support is done in
234d88c1a5aSDimitry Andric   // TargetPassConfig::addPassesToHandleExceptions, but this runs after this
235d88c1a5aSDimitry Andric   // function and SjLj handling expects all invokes to be lowered before.
2364ba319b5SDimitry Andric   if (!EnableEmException &&
2374ba319b5SDimitry Andric       TM->Options.ExceptionModel == ExceptionHandling::None) {
238d88c1a5aSDimitry Andric     addPass(createLowerInvokePass());
239d88c1a5aSDimitry Andric     // The lower invoke pass may create unreachable code. Remove it in order not
240d88c1a5aSDimitry Andric     // to process dead blocks in setjmp/longjmp handling.
241d88c1a5aSDimitry Andric     addPass(createUnreachableBlockEliminationPass());
242d88c1a5aSDimitry Andric   }
243d88c1a5aSDimitry Andric 
244d88c1a5aSDimitry Andric   // Handle exceptions and setjmp/longjmp if enabled.
245d88c1a5aSDimitry Andric   if (EnableEmException || EnableEmSjLj)
246d88c1a5aSDimitry Andric     addPass(createWebAssemblyLowerEmscriptenEHSjLj(EnableEmException,
247d88c1a5aSDimitry Andric                                                    EnableEmSjLj));
248d88c1a5aSDimitry Andric 
2493dac3a9bSDimitry Andric   TargetPassConfig::addIRPasses();
2503dac3a9bSDimitry Andric }
2513dac3a9bSDimitry Andric 
addInstSelector()2523dac3a9bSDimitry Andric bool WebAssemblyPassConfig::addInstSelector() {
2537d523365SDimitry Andric   (void)TargetPassConfig::addInstSelector();
2543dac3a9bSDimitry Andric   addPass(
2553dac3a9bSDimitry Andric       createWebAssemblyISelDag(getWebAssemblyTargetMachine(), getOptLevel()));
2567d523365SDimitry Andric   // Run the argument-move pass immediately after the ScheduleDAG scheduler
2577d523365SDimitry Andric   // so that we can fix up the ARGUMENT instructions before anything else
2587d523365SDimitry Andric   // sees them in the wrong place.
2597d523365SDimitry Andric   addPass(createWebAssemblyArgumentMove());
2603ca95b02SDimitry Andric   // Set the p2align operands. This information is present during ISel, however
2613ca95b02SDimitry Andric   // it's inconvenient to collect. Collect it now, and update the immediate
2623ca95b02SDimitry Andric   // operands.
2633ca95b02SDimitry Andric   addPass(createWebAssemblySetP2AlignOperands());
2643dac3a9bSDimitry Andric   return false;
2653dac3a9bSDimitry Andric }
2663dac3a9bSDimitry Andric 
addPostRegAlloc()2677d523365SDimitry Andric void WebAssemblyPassConfig::addPostRegAlloc() {
2687d523365SDimitry Andric   // TODO: The following CodeGen passes don't currently support code containing
2697d523365SDimitry Andric   // virtual registers. Consider removing their restrictions and re-enabling
2707d523365SDimitry Andric   // them.
2713ca95b02SDimitry Andric 
272d88c1a5aSDimitry Andric   // These functions all require the NoVRegs property.
2737d523365SDimitry Andric   disablePass(&MachineCopyPropagationID);
2744ba319b5SDimitry Andric   disablePass(&PostRAMachineSinkingID);
2753ca95b02SDimitry Andric   disablePass(&PostRASchedulerID);
2763ca95b02SDimitry Andric   disablePass(&FuncletLayoutID);
2773ca95b02SDimitry Andric   disablePass(&StackMapLivenessID);
2783ca95b02SDimitry Andric   disablePass(&LiveDebugValuesID);
2793ca95b02SDimitry Andric   disablePass(&PatchableFunctionID);
2804ba319b5SDimitry Andric   disablePass(&ShrinkWrapID);
2817d523365SDimitry Andric 
2827d523365SDimitry Andric   TargetPassConfig::addPostRegAlloc();
2837d523365SDimitry Andric }
2847d523365SDimitry Andric 
addPreEmitPass()2857d523365SDimitry Andric void WebAssemblyPassConfig::addPreEmitPass() {
2867d523365SDimitry Andric   TargetPassConfig::addPreEmitPass();
2877d523365SDimitry Andric 
288*b5893f02SDimitry Andric   // Restore __stack_pointer global after an exception is thrown.
289*b5893f02SDimitry Andric   addPass(createWebAssemblyEHRestoreStackPointer());
290*b5893f02SDimitry Andric 
2913ca95b02SDimitry Andric   // Now that we have a prologue and epilogue and all frame indices are
2923ca95b02SDimitry Andric   // rewritten, eliminate SP and FP. This allows them to be stackified,
2933ca95b02SDimitry Andric   // colored, and numbered with the rest of the registers.
2943ca95b02SDimitry Andric   addPass(createWebAssemblyReplacePhysRegs());
2953ca95b02SDimitry Andric 
296d88c1a5aSDimitry Andric   // Rewrite pseudo call_indirect instructions as real instructions.
297d88c1a5aSDimitry Andric   // This needs to run before register stackification, because we change the
298d88c1a5aSDimitry Andric   // order of the arguments.
299d88c1a5aSDimitry Andric   addPass(createWebAssemblyCallIndirectFixup());
300d88c1a5aSDimitry Andric 
301*b5893f02SDimitry Andric   // Eliminate multiple-entry loops.
302*b5893f02SDimitry Andric   addPass(createWebAssemblyFixIrreducibleControlFlow());
303*b5893f02SDimitry Andric 
304*b5893f02SDimitry Andric   // Do various transformations for exception handling.
305*b5893f02SDimitry Andric   addPass(createWebAssemblyLateEHPrepare());
306*b5893f02SDimitry Andric 
3073ca95b02SDimitry Andric   if (getOptLevel() != CodeGenOpt::None) {
3083ca95b02SDimitry Andric     // LiveIntervals isn't commonly run this late. Re-establish preconditions.
3093ca95b02SDimitry Andric     addPass(createWebAssemblyPrepareForLiveIntervals());
3103ca95b02SDimitry Andric 
3113ca95b02SDimitry Andric     // Depend on LiveIntervals and perform some optimizations on it.
3123ca95b02SDimitry Andric     addPass(createWebAssemblyOptimizeLiveIntervals());
3133ca95b02SDimitry Andric 
314*b5893f02SDimitry Andric     // Prepare memory intrinsic calls for register stackifying.
315*b5893f02SDimitry Andric     addPass(createWebAssemblyMemIntrinsicResults());
3163ca95b02SDimitry Andric 
317d88c1a5aSDimitry Andric     // Mark registers as representing wasm's value stack. This is a key
3183ca95b02SDimitry Andric     // code-compression technique in WebAssembly. We run this pass (and
319*b5893f02SDimitry Andric     // MemIntrinsicResults above) very late, so that it sees as much code as
320*b5893f02SDimitry Andric     // possible, including code emitted by PEI and expanded by late tail
321*b5893f02SDimitry Andric     // duplication.
3223ca95b02SDimitry Andric     addPass(createWebAssemblyRegStackify());
3233ca95b02SDimitry Andric 
3243ca95b02SDimitry Andric     // Run the register coloring pass to reduce the total number of registers.
3253ca95b02SDimitry Andric     // This runs after stackification so that it doesn't consider registers
3263ca95b02SDimitry Andric     // that become stackified.
3273ca95b02SDimitry Andric     addPass(createWebAssemblyRegColoring());
3283ca95b02SDimitry Andric   }
3293ca95b02SDimitry Andric 
330*b5893f02SDimitry Andric   // Insert explicit local.get and local.set operators.
331d88c1a5aSDimitry Andric   addPass(createWebAssemblyExplicitLocals());
332d88c1a5aSDimitry Andric 
3337a7e6055SDimitry Andric   // Sort the blocks of the CFG into topological order, a prerequisite for
3347a7e6055SDimitry Andric   // BLOCK and LOOP markers.
3357a7e6055SDimitry Andric   addPass(createWebAssemblyCFGSort());
3363ca95b02SDimitry Andric 
3377a7e6055SDimitry Andric   // Insert BLOCK and LOOP markers.
3387d523365SDimitry Andric   addPass(createWebAssemblyCFGStackify());
3397d523365SDimitry Andric 
3407d523365SDimitry Andric   // Lower br_unless into br_if.
3417d523365SDimitry Andric   addPass(createWebAssemblyLowerBrUnless());
3427d523365SDimitry Andric 
3433ca95b02SDimitry Andric   // Perform the very last peephole optimizations on the code.
3443ca95b02SDimitry Andric   if (getOptLevel() != CodeGenOpt::None)
3453ca95b02SDimitry Andric     addPass(createWebAssemblyPeephole());
3463ca95b02SDimitry Andric 
3477d523365SDimitry Andric   // Create a mapping from LLVM CodeGen virtual registers to wasm registers.
3487d523365SDimitry Andric   addPass(createWebAssemblyRegNumbering());
3497d523365SDimitry Andric }
350