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 "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" 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, 712cab237bSDimitry Andric Optional<CodeModel::Model> CM, CodeGenOpt::Level OL, bool JIT) 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), 762cab237bSDimitry Andric CM ? *CM : CodeModel::Large, OL), 777a7e6055SDimitry Andric TLOF(TT.isOSBinFormatELF() ? 787a7e6055SDimitry Andric static_cast<TargetLoweringObjectFile*>( 797a7e6055SDimitry Andric new WebAssemblyTargetObjectFileELF()) : 807a7e6055SDimitry Andric static_cast<TargetLoweringObjectFile*>( 817a7e6055SDimitry Andric new WebAssemblyTargetObjectFile())) { 82d88c1a5aSDimitry Andric // WebAssembly type-checks instructions, but a noreturn function with a return 837d523365SDimitry Andric // type that doesn't match the context will cause a check failure. So we lower 847d523365SDimitry Andric // LLVM 'unreachable' to ISD::TRAP and then lower that to WebAssembly's 85d88c1a5aSDimitry Andric // 'unreachable' instructions which is meant for that case. 867d523365SDimitry Andric this->Options.TrapUnreachable = true; 877d523365SDimitry Andric 887a7e6055SDimitry Andric // WebAssembly treats each function as an independent unit. Force 897a7e6055SDimitry Andric // -ffunction-sections, effectively, so that we can emit them independently. 907a7e6055SDimitry Andric if (!TT.isOSBinFormatELF()) { 917a7e6055SDimitry Andric this->Options.FunctionSections = true; 927a7e6055SDimitry Andric this->Options.DataSections = true; 937a7e6055SDimitry Andric this->Options.UniqueSectionNames = true; 947a7e6055SDimitry Andric } 957a7e6055SDimitry Andric 963dac3a9bSDimitry Andric initAsmInfo(); 973dac3a9bSDimitry Andric 983ca95b02SDimitry Andric // Note that we don't use setRequiresStructuredCFG(true). It disables 993ca95b02SDimitry Andric // optimizations than we're ok with, and want, such as critical edge 1003ca95b02SDimitry Andric // splitting and tail merging. 1013dac3a9bSDimitry Andric } 1023dac3a9bSDimitry Andric 1033dac3a9bSDimitry Andric WebAssemblyTargetMachine::~WebAssemblyTargetMachine() {} 1043dac3a9bSDimitry Andric 1053dac3a9bSDimitry Andric const WebAssemblySubtarget * 1063dac3a9bSDimitry Andric WebAssemblyTargetMachine::getSubtargetImpl(const Function &F) const { 1073dac3a9bSDimitry Andric Attribute CPUAttr = F.getFnAttribute("target-cpu"); 1083dac3a9bSDimitry Andric Attribute FSAttr = F.getFnAttribute("target-features"); 1093dac3a9bSDimitry Andric 1103dac3a9bSDimitry Andric std::string CPU = !CPUAttr.hasAttribute(Attribute::None) 1113dac3a9bSDimitry Andric ? CPUAttr.getValueAsString().str() 1123dac3a9bSDimitry Andric : TargetCPU; 1133dac3a9bSDimitry Andric std::string FS = !FSAttr.hasAttribute(Attribute::None) 1143dac3a9bSDimitry Andric ? FSAttr.getValueAsString().str() 1153dac3a9bSDimitry Andric : TargetFS; 1163dac3a9bSDimitry Andric 1173dac3a9bSDimitry Andric auto &I = SubtargetMap[CPU + FS]; 1183dac3a9bSDimitry Andric if (!I) { 1193dac3a9bSDimitry Andric // This needs to be done before we create a new subtarget since any 1203dac3a9bSDimitry Andric // creation will depend on the TM and the code generation flags on the 1213dac3a9bSDimitry Andric // function that reside in TargetOptions. 1223dac3a9bSDimitry Andric resetTargetOptions(F); 1237d523365SDimitry Andric I = llvm::make_unique<WebAssemblySubtarget>(TargetTriple, CPU, FS, *this); 1243dac3a9bSDimitry Andric } 1253dac3a9bSDimitry Andric return I.get(); 1263dac3a9bSDimitry Andric } 1273dac3a9bSDimitry Andric 1283dac3a9bSDimitry Andric namespace { 1293dac3a9bSDimitry Andric /// WebAssembly Code Generator Pass Configuration Options. 1303dac3a9bSDimitry Andric class WebAssemblyPassConfig final : public TargetPassConfig { 1313dac3a9bSDimitry Andric public: 132f9448bf3SDimitry Andric WebAssemblyPassConfig(WebAssemblyTargetMachine &TM, PassManagerBase &PM) 1333dac3a9bSDimitry Andric : TargetPassConfig(TM, PM) {} 1343dac3a9bSDimitry Andric 1353dac3a9bSDimitry Andric WebAssemblyTargetMachine &getWebAssemblyTargetMachine() const { 1363dac3a9bSDimitry Andric return getTM<WebAssemblyTargetMachine>(); 1373dac3a9bSDimitry Andric } 1383dac3a9bSDimitry Andric 1393dac3a9bSDimitry Andric FunctionPass *createTargetRegisterAllocator(bool) override; 1403dac3a9bSDimitry Andric 1413dac3a9bSDimitry Andric void addIRPasses() override; 1423dac3a9bSDimitry Andric bool addInstSelector() override; 1433dac3a9bSDimitry Andric void addPostRegAlloc() override; 1443ca95b02SDimitry Andric bool addGCPasses() override { return false; } 1453dac3a9bSDimitry Andric void addPreEmitPass() override; 1463dac3a9bSDimitry Andric }; 1473dac3a9bSDimitry Andric } // end anonymous namespace 1483dac3a9bSDimitry Andric 1493dac3a9bSDimitry Andric TargetIRAnalysis WebAssemblyTargetMachine::getTargetIRAnalysis() { 1507d523365SDimitry Andric return TargetIRAnalysis([this](const Function &F) { 1513dac3a9bSDimitry Andric return TargetTransformInfo(WebAssemblyTTIImpl(this, F)); 1523dac3a9bSDimitry Andric }); 1533dac3a9bSDimitry Andric } 1543dac3a9bSDimitry Andric 1553dac3a9bSDimitry Andric TargetPassConfig * 1563dac3a9bSDimitry Andric WebAssemblyTargetMachine::createPassConfig(PassManagerBase &PM) { 157f9448bf3SDimitry Andric return new WebAssemblyPassConfig(*this, PM); 1583dac3a9bSDimitry Andric } 1593dac3a9bSDimitry Andric 1603dac3a9bSDimitry Andric FunctionPass *WebAssemblyPassConfig::createTargetRegisterAllocator(bool) { 1613dac3a9bSDimitry Andric return nullptr; // No reg alloc 1623dac3a9bSDimitry Andric } 1633dac3a9bSDimitry Andric 1643dac3a9bSDimitry Andric //===----------------------------------------------------------------------===// 1653dac3a9bSDimitry Andric // The following functions are called from lib/CodeGen/Passes.cpp to modify 1663dac3a9bSDimitry Andric // the CodeGen pass sequence. 1673dac3a9bSDimitry Andric //===----------------------------------------------------------------------===// 1683dac3a9bSDimitry Andric 1693dac3a9bSDimitry Andric void WebAssemblyPassConfig::addIRPasses() { 1703dac3a9bSDimitry Andric if (TM->Options.ThreadModel == ThreadModel::Single) 1717d523365SDimitry Andric // In "single" mode, atomics get lowered to non-atomics. 1723dac3a9bSDimitry Andric addPass(createLowerAtomicPass()); 1733dac3a9bSDimitry Andric else 1743dac3a9bSDimitry Andric // Expand some atomic operations. WebAssemblyTargetLowering has hooks which 1753dac3a9bSDimitry Andric // control specifically what gets lowered. 176d8866befSDimitry Andric addPass(createAtomicExpandPass()); 1773dac3a9bSDimitry Andric 1782cab237bSDimitry Andric // Lower .llvm.global_dtors into .llvm_global_ctors with __cxa_atexit calls. 1792cab237bSDimitry Andric addPass(createWebAssemblyLowerGlobalDtors()); 1802cab237bSDimitry Andric 18124e2fe98SDimitry Andric // Fix function bitcasts, as WebAssembly requires caller and callee signatures 18224e2fe98SDimitry Andric // to match. 18324e2fe98SDimitry Andric addPass(createWebAssemblyFixFunctionBitcasts()); 18424e2fe98SDimitry Andric 1857d523365SDimitry Andric // Optimize "returned" function attributes. 1863ca95b02SDimitry Andric if (getOptLevel() != CodeGenOpt::None) 1877d523365SDimitry Andric addPass(createWebAssemblyOptimizeReturned()); 1887d523365SDimitry Andric 189d88c1a5aSDimitry Andric // If exception handling is not enabled and setjmp/longjmp handling is 190d88c1a5aSDimitry Andric // enabled, we lower invokes into calls and delete unreachable landingpad 191d88c1a5aSDimitry Andric // blocks. Lowering invokes when there is no EH support is done in 192d88c1a5aSDimitry Andric // TargetPassConfig::addPassesToHandleExceptions, but this runs after this 193d88c1a5aSDimitry Andric // function and SjLj handling expects all invokes to be lowered before. 194d88c1a5aSDimitry Andric if (!EnableEmException) { 195d88c1a5aSDimitry Andric addPass(createLowerInvokePass()); 196d88c1a5aSDimitry Andric // The lower invoke pass may create unreachable code. Remove it in order not 197d88c1a5aSDimitry Andric // to process dead blocks in setjmp/longjmp handling. 198d88c1a5aSDimitry Andric addPass(createUnreachableBlockEliminationPass()); 199d88c1a5aSDimitry Andric } 200d88c1a5aSDimitry Andric 201d88c1a5aSDimitry Andric // Handle exceptions and setjmp/longjmp if enabled. 202d88c1a5aSDimitry Andric if (EnableEmException || EnableEmSjLj) 203d88c1a5aSDimitry Andric addPass(createWebAssemblyLowerEmscriptenEHSjLj(EnableEmException, 204d88c1a5aSDimitry Andric EnableEmSjLj)); 205d88c1a5aSDimitry Andric 2063dac3a9bSDimitry Andric TargetPassConfig::addIRPasses(); 2073dac3a9bSDimitry Andric } 2083dac3a9bSDimitry Andric 2093dac3a9bSDimitry Andric bool WebAssemblyPassConfig::addInstSelector() { 2107d523365SDimitry Andric (void)TargetPassConfig::addInstSelector(); 2113dac3a9bSDimitry Andric addPass( 2123dac3a9bSDimitry Andric createWebAssemblyISelDag(getWebAssemblyTargetMachine(), getOptLevel())); 2137d523365SDimitry Andric // Run the argument-move pass immediately after the ScheduleDAG scheduler 2147d523365SDimitry Andric // so that we can fix up the ARGUMENT instructions before anything else 2157d523365SDimitry Andric // sees them in the wrong place. 2167d523365SDimitry Andric addPass(createWebAssemblyArgumentMove()); 2173ca95b02SDimitry Andric // Set the p2align operands. This information is present during ISel, however 2183ca95b02SDimitry Andric // it's inconvenient to collect. Collect it now, and update the immediate 2193ca95b02SDimitry Andric // operands. 2203ca95b02SDimitry Andric addPass(createWebAssemblySetP2AlignOperands()); 2213dac3a9bSDimitry Andric return false; 2223dac3a9bSDimitry Andric } 2233dac3a9bSDimitry Andric 2247d523365SDimitry Andric void WebAssemblyPassConfig::addPostRegAlloc() { 2257d523365SDimitry Andric // TODO: The following CodeGen passes don't currently support code containing 2267d523365SDimitry Andric // virtual registers. Consider removing their restrictions and re-enabling 2277d523365SDimitry Andric // them. 2283ca95b02SDimitry Andric 2293ca95b02SDimitry Andric // Has no asserts of its own, but was not written to handle virtual regs. 2303ca95b02SDimitry Andric disablePass(&ShrinkWrapID); 2313ca95b02SDimitry Andric 232d88c1a5aSDimitry Andric // These functions all require the NoVRegs property. 2337d523365SDimitry Andric disablePass(&MachineCopyPropagationID); 2343ca95b02SDimitry Andric disablePass(&PostRASchedulerID); 2353ca95b02SDimitry Andric disablePass(&FuncletLayoutID); 2363ca95b02SDimitry Andric disablePass(&StackMapLivenessID); 2373ca95b02SDimitry Andric disablePass(&LiveDebugValuesID); 2383ca95b02SDimitry Andric disablePass(&PatchableFunctionID); 2397d523365SDimitry Andric 2407d523365SDimitry Andric TargetPassConfig::addPostRegAlloc(); 2417d523365SDimitry Andric } 2427d523365SDimitry Andric 2437d523365SDimitry Andric void WebAssemblyPassConfig::addPreEmitPass() { 2447d523365SDimitry Andric TargetPassConfig::addPreEmitPass(); 2457d523365SDimitry Andric 2463ca95b02SDimitry Andric // Now that we have a prologue and epilogue and all frame indices are 2473ca95b02SDimitry Andric // rewritten, eliminate SP and FP. This allows them to be stackified, 2483ca95b02SDimitry Andric // colored, and numbered with the rest of the registers. 2493ca95b02SDimitry Andric addPass(createWebAssemblyReplacePhysRegs()); 2503ca95b02SDimitry Andric 251d88c1a5aSDimitry Andric // Rewrite pseudo call_indirect instructions as real instructions. 252d88c1a5aSDimitry Andric // This needs to run before register stackification, because we change the 253d88c1a5aSDimitry Andric // order of the arguments. 254d88c1a5aSDimitry Andric addPass(createWebAssemblyCallIndirectFixup()); 255d88c1a5aSDimitry Andric 2563ca95b02SDimitry Andric if (getOptLevel() != CodeGenOpt::None) { 2573ca95b02SDimitry Andric // LiveIntervals isn't commonly run this late. Re-establish preconditions. 2583ca95b02SDimitry Andric addPass(createWebAssemblyPrepareForLiveIntervals()); 2593ca95b02SDimitry Andric 2603ca95b02SDimitry Andric // Depend on LiveIntervals and perform some optimizations on it. 2613ca95b02SDimitry Andric addPass(createWebAssemblyOptimizeLiveIntervals()); 2623ca95b02SDimitry Andric 2633ca95b02SDimitry Andric // Prepare store instructions for register stackifying. 2643ca95b02SDimitry Andric addPass(createWebAssemblyStoreResults()); 2653ca95b02SDimitry Andric 266d88c1a5aSDimitry Andric // Mark registers as representing wasm's value stack. This is a key 2673ca95b02SDimitry Andric // code-compression technique in WebAssembly. We run this pass (and 2683ca95b02SDimitry Andric // StoreResults above) very late, so that it sees as much code as possible, 2693ca95b02SDimitry Andric // including code emitted by PEI and expanded by late tail duplication. 2703ca95b02SDimitry Andric addPass(createWebAssemblyRegStackify()); 2713ca95b02SDimitry Andric 2723ca95b02SDimitry Andric // Run the register coloring pass to reduce the total number of registers. 2733ca95b02SDimitry Andric // This runs after stackification so that it doesn't consider registers 2743ca95b02SDimitry Andric // that become stackified. 2753ca95b02SDimitry Andric addPass(createWebAssemblyRegColoring()); 2763ca95b02SDimitry Andric } 2773ca95b02SDimitry Andric 2787a7e6055SDimitry Andric // Eliminate multiple-entry loops. Do this before inserting explicit get_local 2797a7e6055SDimitry Andric // and set_local operators because we create a new variable that we want 2807a7e6055SDimitry Andric // converted into a local. 2817a7e6055SDimitry Andric addPass(createWebAssemblyFixIrreducibleControlFlow()); 2827a7e6055SDimitry Andric 283d88c1a5aSDimitry Andric // Insert explicit get_local and set_local operators. 284d88c1a5aSDimitry Andric addPass(createWebAssemblyExplicitLocals()); 285d88c1a5aSDimitry Andric 2867a7e6055SDimitry Andric // Sort the blocks of the CFG into topological order, a prerequisite for 2877a7e6055SDimitry Andric // BLOCK and LOOP markers. 2887a7e6055SDimitry Andric addPass(createWebAssemblyCFGSort()); 2893ca95b02SDimitry Andric 2907a7e6055SDimitry Andric // Insert BLOCK and LOOP markers. 2917d523365SDimitry Andric addPass(createWebAssemblyCFGStackify()); 2927d523365SDimitry Andric 2937d523365SDimitry Andric // Lower br_unless into br_if. 2947d523365SDimitry Andric addPass(createWebAssemblyLowerBrUnless()); 2957d523365SDimitry Andric 2963ca95b02SDimitry Andric // Perform the very last peephole optimizations on the code. 2973ca95b02SDimitry Andric if (getOptLevel() != CodeGenOpt::None) 2983ca95b02SDimitry Andric addPass(createWebAssemblyPeephole()); 2993ca95b02SDimitry Andric 3007d523365SDimitry Andric // Create a mapping from LLVM CodeGen virtual registers to wasm registers. 3017d523365SDimitry Andric addPass(createWebAssemblyRegNumbering()); 3027d523365SDimitry Andric } 303