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