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 323dac3a9bSDimitry Andric extern "C" void LLVMInitializeWebAssemblyTarget() { 333dac3a9bSDimitry Andric // Register the target. 343dac3a9bSDimitry Andric RegisterTargetMachine<WebAssemblyTargetMachine> X(TheWebAssemblyTarget32); 353dac3a9bSDimitry Andric RegisterTargetMachine<WebAssemblyTargetMachine> Y(TheWebAssemblyTarget64); 363dac3a9bSDimitry Andric } 373dac3a9bSDimitry Andric 383dac3a9bSDimitry Andric //===----------------------------------------------------------------------===// 393dac3a9bSDimitry Andric // WebAssembly Lowering public interface. 403dac3a9bSDimitry Andric //===----------------------------------------------------------------------===// 413dac3a9bSDimitry Andric 423ca95b02SDimitry Andric static Reloc::Model getEffectiveRelocModel(Optional<Reloc::Model> RM) { 433ca95b02SDimitry Andric if (!RM.hasValue()) 443ca95b02SDimitry Andric return Reloc::PIC_; 453ca95b02SDimitry Andric return *RM; 463ca95b02SDimitry Andric } 473ca95b02SDimitry Andric 483dac3a9bSDimitry Andric /// Create an WebAssembly architecture model. 493dac3a9bSDimitry Andric /// 503dac3a9bSDimitry Andric WebAssemblyTargetMachine::WebAssemblyTargetMachine( 513dac3a9bSDimitry Andric const Target &T, const Triple &TT, StringRef CPU, StringRef FS, 523ca95b02SDimitry Andric const TargetOptions &Options, Optional<Reloc::Model> RM, 533ca95b02SDimitry Andric CodeModel::Model CM, CodeGenOpt::Level OL) 54444ed5c5SDimitry Andric : LLVMTargetMachine(T, 55444ed5c5SDimitry Andric TT.isArch64Bit() ? "e-m:e-p:64:64-i64:64-n32:64-S128" 56444ed5c5SDimitry Andric : "e-m:e-p:32:32-i64:64-n32:64-S128", 573ca95b02SDimitry Andric TT, CPU, FS, Options, getEffectiveRelocModel(RM), 583ca95b02SDimitry Andric CM, OL), 593dac3a9bSDimitry Andric TLOF(make_unique<WebAssemblyTargetObjectFile>()) { 607d523365SDimitry Andric // WebAssembly type-checks expressions, but a noreturn function with a return 617d523365SDimitry Andric // type that doesn't match the context will cause a check failure. So we lower 627d523365SDimitry Andric // LLVM 'unreachable' to ISD::TRAP and then lower that to WebAssembly's 637d523365SDimitry Andric // 'unreachable' expression which is meant for that case. 647d523365SDimitry Andric this->Options.TrapUnreachable = true; 657d523365SDimitry Andric 663dac3a9bSDimitry Andric initAsmInfo(); 673dac3a9bSDimitry Andric 683ca95b02SDimitry Andric // Note that we don't use setRequiresStructuredCFG(true). It disables 693ca95b02SDimitry Andric // optimizations than we're ok with, and want, such as critical edge 703ca95b02SDimitry Andric // splitting and tail merging. 713dac3a9bSDimitry Andric } 723dac3a9bSDimitry Andric 733dac3a9bSDimitry Andric WebAssemblyTargetMachine::~WebAssemblyTargetMachine() {} 743dac3a9bSDimitry Andric 753dac3a9bSDimitry Andric const WebAssemblySubtarget * 763dac3a9bSDimitry Andric WebAssemblyTargetMachine::getSubtargetImpl(const Function &F) const { 773dac3a9bSDimitry Andric Attribute CPUAttr = F.getFnAttribute("target-cpu"); 783dac3a9bSDimitry Andric Attribute FSAttr = F.getFnAttribute("target-features"); 793dac3a9bSDimitry Andric 803dac3a9bSDimitry Andric std::string CPU = !CPUAttr.hasAttribute(Attribute::None) 813dac3a9bSDimitry Andric ? CPUAttr.getValueAsString().str() 823dac3a9bSDimitry Andric : TargetCPU; 833dac3a9bSDimitry Andric std::string FS = !FSAttr.hasAttribute(Attribute::None) 843dac3a9bSDimitry Andric ? FSAttr.getValueAsString().str() 853dac3a9bSDimitry Andric : TargetFS; 863dac3a9bSDimitry Andric 873dac3a9bSDimitry Andric auto &I = SubtargetMap[CPU + FS]; 883dac3a9bSDimitry Andric if (!I) { 893dac3a9bSDimitry Andric // This needs to be done before we create a new subtarget since any 903dac3a9bSDimitry Andric // creation will depend on the TM and the code generation flags on the 913dac3a9bSDimitry Andric // function that reside in TargetOptions. 923dac3a9bSDimitry Andric resetTargetOptions(F); 937d523365SDimitry Andric I = llvm::make_unique<WebAssemblySubtarget>(TargetTriple, CPU, FS, *this); 943dac3a9bSDimitry Andric } 953dac3a9bSDimitry Andric return I.get(); 963dac3a9bSDimitry Andric } 973dac3a9bSDimitry Andric 983dac3a9bSDimitry Andric namespace { 993dac3a9bSDimitry Andric /// WebAssembly Code Generator Pass Configuration Options. 1003dac3a9bSDimitry Andric class WebAssemblyPassConfig final : public TargetPassConfig { 1013dac3a9bSDimitry Andric public: 1023dac3a9bSDimitry Andric WebAssemblyPassConfig(WebAssemblyTargetMachine *TM, PassManagerBase &PM) 1033dac3a9bSDimitry Andric : TargetPassConfig(TM, PM) {} 1043dac3a9bSDimitry Andric 1053dac3a9bSDimitry Andric WebAssemblyTargetMachine &getWebAssemblyTargetMachine() const { 1063dac3a9bSDimitry Andric return getTM<WebAssemblyTargetMachine>(); 1073dac3a9bSDimitry Andric } 1083dac3a9bSDimitry Andric 1093dac3a9bSDimitry Andric FunctionPass *createTargetRegisterAllocator(bool) override; 1103dac3a9bSDimitry Andric 1113dac3a9bSDimitry Andric void addIRPasses() override; 1123dac3a9bSDimitry Andric bool addInstSelector() override; 1133dac3a9bSDimitry Andric void addPostRegAlloc() override; 1143ca95b02SDimitry Andric bool addGCPasses() override { return false; } 1153dac3a9bSDimitry Andric void addPreEmitPass() override; 1163dac3a9bSDimitry Andric }; 1173dac3a9bSDimitry Andric } // end anonymous namespace 1183dac3a9bSDimitry Andric 1193dac3a9bSDimitry Andric TargetIRAnalysis WebAssemblyTargetMachine::getTargetIRAnalysis() { 1207d523365SDimitry Andric return TargetIRAnalysis([this](const Function &F) { 1213dac3a9bSDimitry Andric return TargetTransformInfo(WebAssemblyTTIImpl(this, F)); 1223dac3a9bSDimitry Andric }); 1233dac3a9bSDimitry Andric } 1243dac3a9bSDimitry Andric 1253dac3a9bSDimitry Andric TargetPassConfig * 1263dac3a9bSDimitry Andric WebAssemblyTargetMachine::createPassConfig(PassManagerBase &PM) { 1273dac3a9bSDimitry Andric return new WebAssemblyPassConfig(this, PM); 1283dac3a9bSDimitry Andric } 1293dac3a9bSDimitry Andric 1303dac3a9bSDimitry Andric FunctionPass *WebAssemblyPassConfig::createTargetRegisterAllocator(bool) { 1313dac3a9bSDimitry Andric return nullptr; // No reg alloc 1323dac3a9bSDimitry Andric } 1333dac3a9bSDimitry Andric 1343dac3a9bSDimitry Andric //===----------------------------------------------------------------------===// 1353dac3a9bSDimitry Andric // The following functions are called from lib/CodeGen/Passes.cpp to modify 1363dac3a9bSDimitry Andric // the CodeGen pass sequence. 1373dac3a9bSDimitry Andric //===----------------------------------------------------------------------===// 1383dac3a9bSDimitry Andric 1393dac3a9bSDimitry Andric void WebAssemblyPassConfig::addIRPasses() { 1403dac3a9bSDimitry Andric if (TM->Options.ThreadModel == ThreadModel::Single) 1417d523365SDimitry Andric // In "single" mode, atomics get lowered to non-atomics. 1423dac3a9bSDimitry Andric addPass(createLowerAtomicPass()); 1433dac3a9bSDimitry Andric else 1443dac3a9bSDimitry Andric // Expand some atomic operations. WebAssemblyTargetLowering has hooks which 1453dac3a9bSDimitry Andric // control specifically what gets lowered. 1463dac3a9bSDimitry Andric addPass(createAtomicExpandPass(TM)); 1473dac3a9bSDimitry Andric 1487d523365SDimitry Andric // Optimize "returned" function attributes. 1493ca95b02SDimitry Andric if (getOptLevel() != CodeGenOpt::None) 1507d523365SDimitry Andric addPass(createWebAssemblyOptimizeReturned()); 1517d523365SDimitry Andric 1523dac3a9bSDimitry Andric TargetPassConfig::addIRPasses(); 1533dac3a9bSDimitry Andric } 1543dac3a9bSDimitry Andric 1553dac3a9bSDimitry Andric bool WebAssemblyPassConfig::addInstSelector() { 1567d523365SDimitry Andric (void)TargetPassConfig::addInstSelector(); 1573dac3a9bSDimitry Andric addPass( 1583dac3a9bSDimitry Andric createWebAssemblyISelDag(getWebAssemblyTargetMachine(), getOptLevel())); 1597d523365SDimitry Andric // Run the argument-move pass immediately after the ScheduleDAG scheduler 1607d523365SDimitry Andric // so that we can fix up the ARGUMENT instructions before anything else 1617d523365SDimitry Andric // sees them in the wrong place. 1627d523365SDimitry Andric addPass(createWebAssemblyArgumentMove()); 1633ca95b02SDimitry Andric // Set the p2align operands. This information is present during ISel, however 1643ca95b02SDimitry Andric // it's inconvenient to collect. Collect it now, and update the immediate 1653ca95b02SDimitry Andric // operands. 1663ca95b02SDimitry Andric addPass(createWebAssemblySetP2AlignOperands()); 1673dac3a9bSDimitry Andric return false; 1683dac3a9bSDimitry Andric } 1693dac3a9bSDimitry Andric 1707d523365SDimitry Andric void WebAssemblyPassConfig::addPostRegAlloc() { 1717d523365SDimitry Andric // TODO: The following CodeGen passes don't currently support code containing 1727d523365SDimitry Andric // virtual registers. Consider removing their restrictions and re-enabling 1737d523365SDimitry Andric // them. 1743ca95b02SDimitry Andric 1753ca95b02SDimitry Andric // Has no asserts of its own, but was not written to handle virtual regs. 1763ca95b02SDimitry Andric disablePass(&ShrinkWrapID); 1773ca95b02SDimitry Andric 1783ca95b02SDimitry Andric // These functions all require the AllVRegsAllocated property. 1797d523365SDimitry Andric disablePass(&MachineCopyPropagationID); 1803ca95b02SDimitry Andric disablePass(&PostRASchedulerID); 1813ca95b02SDimitry Andric disablePass(&FuncletLayoutID); 1823ca95b02SDimitry Andric disablePass(&StackMapLivenessID); 1833ca95b02SDimitry Andric disablePass(&LiveDebugValuesID); 1843ca95b02SDimitry Andric disablePass(&PatchableFunctionID); 1857d523365SDimitry Andric 1867d523365SDimitry Andric TargetPassConfig::addPostRegAlloc(); 1877d523365SDimitry Andric } 1887d523365SDimitry Andric 1897d523365SDimitry Andric void WebAssemblyPassConfig::addPreEmitPass() { 1907d523365SDimitry Andric TargetPassConfig::addPreEmitPass(); 1917d523365SDimitry Andric 1923ca95b02SDimitry Andric // Now that we have a prologue and epilogue and all frame indices are 1933ca95b02SDimitry Andric // rewritten, eliminate SP and FP. This allows them to be stackified, 1943ca95b02SDimitry Andric // colored, and numbered with the rest of the registers. 1953ca95b02SDimitry Andric addPass(createWebAssemblyReplacePhysRegs()); 1963ca95b02SDimitry Andric 1973ca95b02SDimitry Andric if (getOptLevel() != CodeGenOpt::None) { 1983ca95b02SDimitry Andric // LiveIntervals isn't commonly run this late. Re-establish preconditions. 1993ca95b02SDimitry Andric addPass(createWebAssemblyPrepareForLiveIntervals()); 2003ca95b02SDimitry Andric 2013ca95b02SDimitry Andric // Depend on LiveIntervals and perform some optimizations on it. 2023ca95b02SDimitry Andric addPass(createWebAssemblyOptimizeLiveIntervals()); 2033ca95b02SDimitry Andric 2043ca95b02SDimitry Andric // Prepare store instructions for register stackifying. 2053ca95b02SDimitry Andric addPass(createWebAssemblyStoreResults()); 2063ca95b02SDimitry Andric 2073ca95b02SDimitry Andric // Mark registers as representing wasm's expression stack. This is a key 2083ca95b02SDimitry Andric // code-compression technique in WebAssembly. We run this pass (and 2093ca95b02SDimitry Andric // StoreResults above) very late, so that it sees as much code as possible, 2103ca95b02SDimitry Andric // including code emitted by PEI and expanded by late tail duplication. 2113ca95b02SDimitry Andric addPass(createWebAssemblyRegStackify()); 2123ca95b02SDimitry Andric 2133ca95b02SDimitry Andric // Run the register coloring pass to reduce the total number of registers. 2143ca95b02SDimitry Andric // This runs after stackification so that it doesn't consider registers 2153ca95b02SDimitry Andric // that become stackified. 2163ca95b02SDimitry Andric addPass(createWebAssemblyRegColoring()); 2173ca95b02SDimitry Andric } 2183ca95b02SDimitry Andric 2193ca95b02SDimitry Andric // Eliminate multiple-entry loops. 2203ca95b02SDimitry Andric addPass(createWebAssemblyFixIrreducibleControlFlow()); 2213ca95b02SDimitry Andric 2227d523365SDimitry Andric // Put the CFG in structured form; insert BLOCK and LOOP markers. 2237d523365SDimitry Andric addPass(createWebAssemblyCFGStackify()); 2247d523365SDimitry Andric 2257d523365SDimitry Andric // Lower br_unless into br_if. 2267d523365SDimitry Andric addPass(createWebAssemblyLowerBrUnless()); 2277d523365SDimitry Andric 2283ca95b02SDimitry Andric // Perform the very last peephole optimizations on the code. 2293ca95b02SDimitry Andric if (getOptLevel() != CodeGenOpt::None) 2303ca95b02SDimitry Andric addPass(createWebAssemblyPeephole()); 2313ca95b02SDimitry Andric 2327d523365SDimitry Andric // Create a mapping from LLVM CodeGen virtual registers to wasm registers. 2337d523365SDimitry Andric addPass(createWebAssemblyRegNumbering()); 2347d523365SDimitry Andric } 235