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 113dac3a9bSDimitry Andric /// \brief This file defines the WebAssembly-specific subclass of TargetMachine. 123dac3a9bSDimitry Andric /// 133dac3a9bSDimitry Andric //===----------------------------------------------------------------------===// 143dac3a9bSDimitry Andric 153dac3a9bSDimitry Andric #include "WebAssembly.h" 163dac3a9bSDimitry Andric #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" 173dac3a9bSDimitry Andric #include "WebAssemblyTargetMachine.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" 283dac3a9bSDimitry Andric using namespace llvm; 293dac3a9bSDimitry Andric 303dac3a9bSDimitry Andric #define DEBUG_TYPE "wasm" 313dac3a9bSDimitry Andric 32d88c1a5aSDimitry Andric // Emscripten's asm.js-style exception handling 33d88c1a5aSDimitry Andric static cl::opt<bool> EnableEmException( 34d88c1a5aSDimitry Andric "enable-emscripten-cxx-exceptions", 35d88c1a5aSDimitry Andric cl::desc("WebAssembly Emscripten-style exception handling"), 36d88c1a5aSDimitry Andric cl::init(false)); 37d88c1a5aSDimitry Andric 38d88c1a5aSDimitry Andric // Emscripten's asm.js-style setjmp/longjmp handling 39d88c1a5aSDimitry Andric static cl::opt<bool> EnableEmSjLj( 40d88c1a5aSDimitry Andric "enable-emscripten-sjlj", 41d88c1a5aSDimitry Andric cl::desc("WebAssembly Emscripten-style setjmp/longjmp handling"), 42d88c1a5aSDimitry Andric cl::init(false)); 43d88c1a5aSDimitry Andric 443dac3a9bSDimitry Andric extern "C" void LLVMInitializeWebAssemblyTarget() { 453dac3a9bSDimitry Andric // Register the target. 46d88c1a5aSDimitry Andric RegisterTargetMachine<WebAssemblyTargetMachine> X( 47d88c1a5aSDimitry Andric getTheWebAssemblyTarget32()); 48d88c1a5aSDimitry Andric RegisterTargetMachine<WebAssemblyTargetMachine> Y( 49d88c1a5aSDimitry Andric getTheWebAssemblyTarget64()); 50d88c1a5aSDimitry Andric 51d88c1a5aSDimitry Andric // Register exception handling pass to opt 52d88c1a5aSDimitry Andric initializeWebAssemblyLowerEmscriptenEHSjLjPass( 53d88c1a5aSDimitry Andric *PassRegistry::getPassRegistry()); 543dac3a9bSDimitry Andric } 553dac3a9bSDimitry Andric 563dac3a9bSDimitry Andric //===----------------------------------------------------------------------===// 573dac3a9bSDimitry Andric // WebAssembly Lowering public interface. 583dac3a9bSDimitry Andric //===----------------------------------------------------------------------===// 593dac3a9bSDimitry Andric 603ca95b02SDimitry Andric static Reloc::Model getEffectiveRelocModel(Optional<Reloc::Model> RM) { 613ca95b02SDimitry Andric if (!RM.hasValue()) 623ca95b02SDimitry Andric return Reloc::PIC_; 633ca95b02SDimitry Andric return *RM; 643ca95b02SDimitry Andric } 653ca95b02SDimitry Andric 663dac3a9bSDimitry Andric /// Create an WebAssembly architecture model. 673dac3a9bSDimitry Andric /// 683dac3a9bSDimitry Andric WebAssemblyTargetMachine::WebAssemblyTargetMachine( 693dac3a9bSDimitry Andric const Target &T, const Triple &TT, StringRef CPU, StringRef FS, 703ca95b02SDimitry Andric const TargetOptions &Options, Optional<Reloc::Model> RM, 713ca95b02SDimitry Andric CodeModel::Model CM, CodeGenOpt::Level OL) 72444ed5c5SDimitry Andric : LLVMTargetMachine(T, 73444ed5c5SDimitry Andric TT.isArch64Bit() ? "e-m:e-p:64:64-i64:64-n32:64-S128" 74444ed5c5SDimitry Andric : "e-m:e-p:32:32-i64:64-n32:64-S128", 753ca95b02SDimitry Andric TT, CPU, FS, Options, getEffectiveRelocModel(RM), 763ca95b02SDimitry Andric CM, OL), 773dac3a9bSDimitry Andric TLOF(make_unique<WebAssemblyTargetObjectFile>()) { 78d88c1a5aSDimitry Andric // WebAssembly type-checks instructions, but a noreturn function with a return 797d523365SDimitry Andric // type that doesn't match the context will cause a check failure. So we lower 807d523365SDimitry Andric // LLVM 'unreachable' to ISD::TRAP and then lower that to WebAssembly's 81d88c1a5aSDimitry Andric // 'unreachable' instructions which is meant for that case. 827d523365SDimitry Andric this->Options.TrapUnreachable = true; 837d523365SDimitry Andric 843dac3a9bSDimitry Andric initAsmInfo(); 853dac3a9bSDimitry Andric 863ca95b02SDimitry Andric // Note that we don't use setRequiresStructuredCFG(true). It disables 873ca95b02SDimitry Andric // optimizations than we're ok with, and want, such as critical edge 883ca95b02SDimitry Andric // splitting and tail merging. 893dac3a9bSDimitry Andric } 903dac3a9bSDimitry Andric 913dac3a9bSDimitry Andric WebAssemblyTargetMachine::~WebAssemblyTargetMachine() {} 923dac3a9bSDimitry Andric 933dac3a9bSDimitry Andric const WebAssemblySubtarget * 943dac3a9bSDimitry Andric WebAssemblyTargetMachine::getSubtargetImpl(const Function &F) const { 953dac3a9bSDimitry Andric Attribute CPUAttr = F.getFnAttribute("target-cpu"); 963dac3a9bSDimitry Andric Attribute FSAttr = F.getFnAttribute("target-features"); 973dac3a9bSDimitry Andric 983dac3a9bSDimitry Andric std::string CPU = !CPUAttr.hasAttribute(Attribute::None) 993dac3a9bSDimitry Andric ? CPUAttr.getValueAsString().str() 1003dac3a9bSDimitry Andric : TargetCPU; 1013dac3a9bSDimitry Andric std::string FS = !FSAttr.hasAttribute(Attribute::None) 1023dac3a9bSDimitry Andric ? FSAttr.getValueAsString().str() 1033dac3a9bSDimitry Andric : TargetFS; 1043dac3a9bSDimitry Andric 1053dac3a9bSDimitry Andric auto &I = SubtargetMap[CPU + FS]; 1063dac3a9bSDimitry Andric if (!I) { 1073dac3a9bSDimitry Andric // This needs to be done before we create a new subtarget since any 1083dac3a9bSDimitry Andric // creation will depend on the TM and the code generation flags on the 1093dac3a9bSDimitry Andric // function that reside in TargetOptions. 1103dac3a9bSDimitry Andric resetTargetOptions(F); 1117d523365SDimitry Andric I = llvm::make_unique<WebAssemblySubtarget>(TargetTriple, CPU, FS, *this); 1123dac3a9bSDimitry Andric } 1133dac3a9bSDimitry Andric return I.get(); 1143dac3a9bSDimitry Andric } 1153dac3a9bSDimitry Andric 1163dac3a9bSDimitry Andric namespace { 1173dac3a9bSDimitry Andric /// WebAssembly Code Generator Pass Configuration Options. 1183dac3a9bSDimitry Andric class WebAssemblyPassConfig final : public TargetPassConfig { 1193dac3a9bSDimitry Andric public: 1203dac3a9bSDimitry Andric WebAssemblyPassConfig(WebAssemblyTargetMachine *TM, PassManagerBase &PM) 1213dac3a9bSDimitry Andric : TargetPassConfig(TM, PM) {} 1223dac3a9bSDimitry Andric 1233dac3a9bSDimitry Andric WebAssemblyTargetMachine &getWebAssemblyTargetMachine() const { 1243dac3a9bSDimitry Andric return getTM<WebAssemblyTargetMachine>(); 1253dac3a9bSDimitry Andric } 1263dac3a9bSDimitry Andric 1273dac3a9bSDimitry Andric FunctionPass *createTargetRegisterAllocator(bool) override; 1283dac3a9bSDimitry Andric 1293dac3a9bSDimitry Andric void addIRPasses() override; 1303dac3a9bSDimitry Andric bool addInstSelector() override; 1313dac3a9bSDimitry Andric void addPostRegAlloc() override; 1323ca95b02SDimitry Andric bool addGCPasses() override { return false; } 1333dac3a9bSDimitry Andric void addPreEmitPass() override; 1343dac3a9bSDimitry Andric }; 1353dac3a9bSDimitry Andric } // end anonymous namespace 1363dac3a9bSDimitry Andric 1373dac3a9bSDimitry Andric TargetIRAnalysis WebAssemblyTargetMachine::getTargetIRAnalysis() { 1387d523365SDimitry Andric return TargetIRAnalysis([this](const Function &F) { 1393dac3a9bSDimitry Andric return TargetTransformInfo(WebAssemblyTTIImpl(this, F)); 1403dac3a9bSDimitry Andric }); 1413dac3a9bSDimitry Andric } 1423dac3a9bSDimitry Andric 1433dac3a9bSDimitry Andric TargetPassConfig * 1443dac3a9bSDimitry Andric WebAssemblyTargetMachine::createPassConfig(PassManagerBase &PM) { 1453dac3a9bSDimitry Andric return new WebAssemblyPassConfig(this, PM); 1463dac3a9bSDimitry Andric } 1473dac3a9bSDimitry Andric 1483dac3a9bSDimitry Andric FunctionPass *WebAssemblyPassConfig::createTargetRegisterAllocator(bool) { 1493dac3a9bSDimitry Andric return nullptr; // No reg alloc 1503dac3a9bSDimitry Andric } 1513dac3a9bSDimitry Andric 1523dac3a9bSDimitry Andric //===----------------------------------------------------------------------===// 1533dac3a9bSDimitry Andric // The following functions are called from lib/CodeGen/Passes.cpp to modify 1543dac3a9bSDimitry Andric // the CodeGen pass sequence. 1553dac3a9bSDimitry Andric //===----------------------------------------------------------------------===// 1563dac3a9bSDimitry Andric 1573dac3a9bSDimitry Andric void WebAssemblyPassConfig::addIRPasses() { 1583dac3a9bSDimitry Andric if (TM->Options.ThreadModel == ThreadModel::Single) 1597d523365SDimitry Andric // In "single" mode, atomics get lowered to non-atomics. 1603dac3a9bSDimitry Andric addPass(createLowerAtomicPass()); 1613dac3a9bSDimitry Andric else 1623dac3a9bSDimitry Andric // Expand some atomic operations. WebAssemblyTargetLowering has hooks which 1633dac3a9bSDimitry Andric // control specifically what gets lowered. 1643dac3a9bSDimitry Andric addPass(createAtomicExpandPass(TM)); 1653dac3a9bSDimitry Andric 16624e2fe98SDimitry Andric // Fix function bitcasts, as WebAssembly requires caller and callee signatures 16724e2fe98SDimitry Andric // to match. 16824e2fe98SDimitry Andric addPass(createWebAssemblyFixFunctionBitcasts()); 16924e2fe98SDimitry Andric 1707d523365SDimitry Andric // Optimize "returned" function attributes. 1713ca95b02SDimitry Andric if (getOptLevel() != CodeGenOpt::None) 1727d523365SDimitry Andric addPass(createWebAssemblyOptimizeReturned()); 1737d523365SDimitry Andric 174d88c1a5aSDimitry Andric // If exception handling is not enabled and setjmp/longjmp handling is 175d88c1a5aSDimitry Andric // enabled, we lower invokes into calls and delete unreachable landingpad 176d88c1a5aSDimitry Andric // blocks. Lowering invokes when there is no EH support is done in 177d88c1a5aSDimitry Andric // TargetPassConfig::addPassesToHandleExceptions, but this runs after this 178d88c1a5aSDimitry Andric // function and SjLj handling expects all invokes to be lowered before. 179d88c1a5aSDimitry Andric if (!EnableEmException) { 180d88c1a5aSDimitry Andric addPass(createLowerInvokePass()); 181d88c1a5aSDimitry Andric // The lower invoke pass may create unreachable code. Remove it in order not 182d88c1a5aSDimitry Andric // to process dead blocks in setjmp/longjmp handling. 183d88c1a5aSDimitry Andric addPass(createUnreachableBlockEliminationPass()); 184d88c1a5aSDimitry Andric } 185d88c1a5aSDimitry Andric 186d88c1a5aSDimitry Andric // Handle exceptions and setjmp/longjmp if enabled. 187d88c1a5aSDimitry Andric if (EnableEmException || EnableEmSjLj) 188d88c1a5aSDimitry Andric addPass(createWebAssemblyLowerEmscriptenEHSjLj(EnableEmException, 189d88c1a5aSDimitry Andric EnableEmSjLj)); 190d88c1a5aSDimitry Andric 1913dac3a9bSDimitry Andric TargetPassConfig::addIRPasses(); 1923dac3a9bSDimitry Andric } 1933dac3a9bSDimitry Andric 1943dac3a9bSDimitry Andric bool WebAssemblyPassConfig::addInstSelector() { 1957d523365SDimitry Andric (void)TargetPassConfig::addInstSelector(); 1963dac3a9bSDimitry Andric addPass( 1973dac3a9bSDimitry Andric createWebAssemblyISelDag(getWebAssemblyTargetMachine(), getOptLevel())); 1987d523365SDimitry Andric // Run the argument-move pass immediately after the ScheduleDAG scheduler 1997d523365SDimitry Andric // so that we can fix up the ARGUMENT instructions before anything else 2007d523365SDimitry Andric // sees them in the wrong place. 2017d523365SDimitry Andric addPass(createWebAssemblyArgumentMove()); 2023ca95b02SDimitry Andric // Set the p2align operands. This information is present during ISel, however 2033ca95b02SDimitry Andric // it's inconvenient to collect. Collect it now, and update the immediate 2043ca95b02SDimitry Andric // operands. 2053ca95b02SDimitry Andric addPass(createWebAssemblySetP2AlignOperands()); 2063dac3a9bSDimitry Andric return false; 2073dac3a9bSDimitry Andric } 2083dac3a9bSDimitry Andric 2097d523365SDimitry Andric void WebAssemblyPassConfig::addPostRegAlloc() { 2107d523365SDimitry Andric // TODO: The following CodeGen passes don't currently support code containing 2117d523365SDimitry Andric // virtual registers. Consider removing their restrictions and re-enabling 2127d523365SDimitry Andric // them. 2133ca95b02SDimitry Andric 2143ca95b02SDimitry Andric // Has no asserts of its own, but was not written to handle virtual regs. 2153ca95b02SDimitry Andric disablePass(&ShrinkWrapID); 2163ca95b02SDimitry Andric 217d88c1a5aSDimitry Andric // These functions all require the NoVRegs property. 2187d523365SDimitry Andric disablePass(&MachineCopyPropagationID); 2193ca95b02SDimitry Andric disablePass(&PostRASchedulerID); 2203ca95b02SDimitry Andric disablePass(&FuncletLayoutID); 2213ca95b02SDimitry Andric disablePass(&StackMapLivenessID); 2223ca95b02SDimitry Andric disablePass(&LiveDebugValuesID); 2233ca95b02SDimitry Andric disablePass(&PatchableFunctionID); 2247d523365SDimitry Andric 2257d523365SDimitry Andric TargetPassConfig::addPostRegAlloc(); 2267d523365SDimitry Andric } 2277d523365SDimitry Andric 2287d523365SDimitry Andric void WebAssemblyPassConfig::addPreEmitPass() { 2297d523365SDimitry Andric TargetPassConfig::addPreEmitPass(); 2307d523365SDimitry Andric 2313ca95b02SDimitry Andric // Now that we have a prologue and epilogue and all frame indices are 2323ca95b02SDimitry Andric // rewritten, eliminate SP and FP. This allows them to be stackified, 2333ca95b02SDimitry Andric // colored, and numbered with the rest of the registers. 2343ca95b02SDimitry Andric addPass(createWebAssemblyReplacePhysRegs()); 2353ca95b02SDimitry Andric 236d88c1a5aSDimitry Andric // Rewrite pseudo call_indirect instructions as real instructions. 237d88c1a5aSDimitry Andric // This needs to run before register stackification, because we change the 238d88c1a5aSDimitry Andric // order of the arguments. 239d88c1a5aSDimitry Andric addPass(createWebAssemblyCallIndirectFixup()); 240d88c1a5aSDimitry Andric 2413ca95b02SDimitry Andric if (getOptLevel() != CodeGenOpt::None) { 2423ca95b02SDimitry Andric // LiveIntervals isn't commonly run this late. Re-establish preconditions. 2433ca95b02SDimitry Andric addPass(createWebAssemblyPrepareForLiveIntervals()); 2443ca95b02SDimitry Andric 2453ca95b02SDimitry Andric // Depend on LiveIntervals and perform some optimizations on it. 2463ca95b02SDimitry Andric addPass(createWebAssemblyOptimizeLiveIntervals()); 2473ca95b02SDimitry Andric 2483ca95b02SDimitry Andric // Prepare store instructions for register stackifying. 2493ca95b02SDimitry Andric addPass(createWebAssemblyStoreResults()); 2503ca95b02SDimitry Andric 251d88c1a5aSDimitry Andric // Mark registers as representing wasm's value stack. This is a key 2523ca95b02SDimitry Andric // code-compression technique in WebAssembly. We run this pass (and 2533ca95b02SDimitry Andric // StoreResults above) very late, so that it sees as much code as possible, 2543ca95b02SDimitry Andric // including code emitted by PEI and expanded by late tail duplication. 2553ca95b02SDimitry Andric addPass(createWebAssemblyRegStackify()); 2563ca95b02SDimitry Andric 2573ca95b02SDimitry Andric // Run the register coloring pass to reduce the total number of registers. 2583ca95b02SDimitry Andric // This runs after stackification so that it doesn't consider registers 2593ca95b02SDimitry Andric // that become stackified. 2603ca95b02SDimitry Andric addPass(createWebAssemblyRegColoring()); 2613ca95b02SDimitry Andric } 2623ca95b02SDimitry Andric 263d88c1a5aSDimitry Andric // Insert explicit get_local and set_local operators. 264d88c1a5aSDimitry Andric addPass(createWebAssemblyExplicitLocals()); 265d88c1a5aSDimitry Andric 2663ca95b02SDimitry Andric // Eliminate multiple-entry loops. 2673ca95b02SDimitry Andric addPass(createWebAssemblyFixIrreducibleControlFlow()); 2683ca95b02SDimitry Andric 2697d523365SDimitry Andric // Put the CFG in structured form; insert BLOCK and LOOP markers. 2707d523365SDimitry Andric addPass(createWebAssemblyCFGStackify()); 2717d523365SDimitry Andric 2727d523365SDimitry Andric // Lower br_unless into br_if. 2737d523365SDimitry Andric addPass(createWebAssemblyLowerBrUnless()); 2747d523365SDimitry Andric 2753ca95b02SDimitry Andric // Perform the very last peephole optimizations on the code. 2763ca95b02SDimitry Andric if (getOptLevel() != CodeGenOpt::None) 2773ca95b02SDimitry Andric addPass(createWebAssemblyPeephole()); 2783ca95b02SDimitry Andric 2797d523365SDimitry Andric // Create a mapping from LLVM CodeGen virtual registers to wasm registers. 2807d523365SDimitry Andric addPass(createWebAssemblyRegNumbering()); 2817d523365SDimitry Andric } 282