1*0b57cec5SDimitry Andric //===- WebAssemblyTargetMachine.cpp - Define TargetMachine for WebAssembly -==// 2*0b57cec5SDimitry Andric // 3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0b57cec5SDimitry Andric // 7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 8*0b57cec5SDimitry Andric /// 9*0b57cec5SDimitry Andric /// \file 10*0b57cec5SDimitry Andric /// This file defines the WebAssembly-specific subclass of TargetMachine. 11*0b57cec5SDimitry Andric /// 12*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 13*0b57cec5SDimitry Andric 14*0b57cec5SDimitry Andric #include "WebAssemblyTargetMachine.h" 15*0b57cec5SDimitry Andric #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" 16*0b57cec5SDimitry Andric #include "TargetInfo/WebAssemblyTargetInfo.h" 17*0b57cec5SDimitry Andric #include "WebAssembly.h" 18*0b57cec5SDimitry Andric #include "WebAssemblyMachineFunctionInfo.h" 19*0b57cec5SDimitry Andric #include "WebAssemblyTargetObjectFile.h" 20*0b57cec5SDimitry Andric #include "WebAssemblyTargetTransformInfo.h" 21*0b57cec5SDimitry Andric #include "llvm/CodeGen/MIRParser/MIParser.h" 22*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h" 23*0b57cec5SDimitry Andric #include "llvm/CodeGen/Passes.h" 24*0b57cec5SDimitry Andric #include "llvm/CodeGen/RegAllocRegistry.h" 25*0b57cec5SDimitry Andric #include "llvm/CodeGen/TargetPassConfig.h" 26*0b57cec5SDimitry Andric #include "llvm/IR/Function.h" 27*0b57cec5SDimitry Andric #include "llvm/Support/TargetRegistry.h" 28*0b57cec5SDimitry Andric #include "llvm/Target/TargetOptions.h" 29*0b57cec5SDimitry Andric #include "llvm/Transforms/Scalar.h" 30*0b57cec5SDimitry Andric #include "llvm/Transforms/Scalar/LowerAtomic.h" 31*0b57cec5SDimitry Andric #include "llvm/Transforms/Utils.h" 32*0b57cec5SDimitry Andric using namespace llvm; 33*0b57cec5SDimitry Andric 34*0b57cec5SDimitry Andric #define DEBUG_TYPE "wasm" 35*0b57cec5SDimitry Andric 36*0b57cec5SDimitry Andric // Emscripten's asm.js-style exception handling 37*0b57cec5SDimitry Andric static cl::opt<bool> EnableEmException( 38*0b57cec5SDimitry Andric "enable-emscripten-cxx-exceptions", 39*0b57cec5SDimitry Andric cl::desc("WebAssembly Emscripten-style exception handling"), 40*0b57cec5SDimitry Andric cl::init(false)); 41*0b57cec5SDimitry Andric 42*0b57cec5SDimitry Andric // Emscripten's asm.js-style setjmp/longjmp handling 43*0b57cec5SDimitry Andric static cl::opt<bool> EnableEmSjLj( 44*0b57cec5SDimitry Andric "enable-emscripten-sjlj", 45*0b57cec5SDimitry Andric cl::desc("WebAssembly Emscripten-style setjmp/longjmp handling"), 46*0b57cec5SDimitry Andric cl::init(false)); 47*0b57cec5SDimitry Andric 48*0b57cec5SDimitry Andric extern "C" void LLVMInitializeWebAssemblyTarget() { 49*0b57cec5SDimitry Andric // Register the target. 50*0b57cec5SDimitry Andric RegisterTargetMachine<WebAssemblyTargetMachine> X( 51*0b57cec5SDimitry Andric getTheWebAssemblyTarget32()); 52*0b57cec5SDimitry Andric RegisterTargetMachine<WebAssemblyTargetMachine> Y( 53*0b57cec5SDimitry Andric getTheWebAssemblyTarget64()); 54*0b57cec5SDimitry Andric 55*0b57cec5SDimitry Andric // Register backend passes 56*0b57cec5SDimitry Andric auto &PR = *PassRegistry::getPassRegistry(); 57*0b57cec5SDimitry Andric initializeWebAssemblyAddMissingPrototypesPass(PR); 58*0b57cec5SDimitry Andric initializeWebAssemblyLowerEmscriptenEHSjLjPass(PR); 59*0b57cec5SDimitry Andric initializeLowerGlobalDtorsPass(PR); 60*0b57cec5SDimitry Andric initializeFixFunctionBitcastsPass(PR); 61*0b57cec5SDimitry Andric initializeOptimizeReturnedPass(PR); 62*0b57cec5SDimitry Andric initializeWebAssemblyArgumentMovePass(PR); 63*0b57cec5SDimitry Andric initializeWebAssemblySetP2AlignOperandsPass(PR); 64*0b57cec5SDimitry Andric initializeWebAssemblyReplacePhysRegsPass(PR); 65*0b57cec5SDimitry Andric initializeWebAssemblyPrepareForLiveIntervalsPass(PR); 66*0b57cec5SDimitry Andric initializeWebAssemblyOptimizeLiveIntervalsPass(PR); 67*0b57cec5SDimitry Andric initializeWebAssemblyMemIntrinsicResultsPass(PR); 68*0b57cec5SDimitry Andric initializeWebAssemblyRegStackifyPass(PR); 69*0b57cec5SDimitry Andric initializeWebAssemblyRegColoringPass(PR); 70*0b57cec5SDimitry Andric initializeWebAssemblyFixIrreducibleControlFlowPass(PR); 71*0b57cec5SDimitry Andric initializeWebAssemblyLateEHPreparePass(PR); 72*0b57cec5SDimitry Andric initializeWebAssemblyExceptionInfoPass(PR); 73*0b57cec5SDimitry Andric initializeWebAssemblyCFGSortPass(PR); 74*0b57cec5SDimitry Andric initializeWebAssemblyCFGStackifyPass(PR); 75*0b57cec5SDimitry Andric initializeWebAssemblyExplicitLocalsPass(PR); 76*0b57cec5SDimitry Andric initializeWebAssemblyLowerBrUnlessPass(PR); 77*0b57cec5SDimitry Andric initializeWebAssemblyRegNumberingPass(PR); 78*0b57cec5SDimitry Andric initializeWebAssemblyPeepholePass(PR); 79*0b57cec5SDimitry Andric initializeWebAssemblyCallIndirectFixupPass(PR); 80*0b57cec5SDimitry Andric } 81*0b57cec5SDimitry Andric 82*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 83*0b57cec5SDimitry Andric // WebAssembly Lowering public interface. 84*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 85*0b57cec5SDimitry Andric 86*0b57cec5SDimitry Andric static Reloc::Model getEffectiveRelocModel(Optional<Reloc::Model> RM, 87*0b57cec5SDimitry Andric const Triple &TT) { 88*0b57cec5SDimitry Andric if (!RM.hasValue()) { 89*0b57cec5SDimitry Andric // Default to static relocation model. This should always be more optimial 90*0b57cec5SDimitry Andric // than PIC since the static linker can determine all global addresses and 91*0b57cec5SDimitry Andric // assume direct function calls. 92*0b57cec5SDimitry Andric return Reloc::Static; 93*0b57cec5SDimitry Andric } 94*0b57cec5SDimitry Andric 95*0b57cec5SDimitry Andric if (!TT.isOSEmscripten()) { 96*0b57cec5SDimitry Andric // Relocation modes other than static are currently implemented in a way 97*0b57cec5SDimitry Andric // that only works for Emscripten, so disable them if we aren't targeting 98*0b57cec5SDimitry Andric // Emscripten. 99*0b57cec5SDimitry Andric return Reloc::Static; 100*0b57cec5SDimitry Andric } 101*0b57cec5SDimitry Andric 102*0b57cec5SDimitry Andric return *RM; 103*0b57cec5SDimitry Andric } 104*0b57cec5SDimitry Andric 105*0b57cec5SDimitry Andric /// Create an WebAssembly architecture model. 106*0b57cec5SDimitry Andric /// 107*0b57cec5SDimitry Andric WebAssemblyTargetMachine::WebAssemblyTargetMachine( 108*0b57cec5SDimitry Andric const Target &T, const Triple &TT, StringRef CPU, StringRef FS, 109*0b57cec5SDimitry Andric const TargetOptions &Options, Optional<Reloc::Model> RM, 110*0b57cec5SDimitry Andric Optional<CodeModel::Model> CM, CodeGenOpt::Level OL, bool JIT) 111*0b57cec5SDimitry Andric : LLVMTargetMachine(T, 112*0b57cec5SDimitry Andric TT.isArch64Bit() ? "e-m:e-p:64:64-i64:64-n32:64-S128" 113*0b57cec5SDimitry Andric : "e-m:e-p:32:32-i64:64-n32:64-S128", 114*0b57cec5SDimitry Andric TT, CPU, FS, Options, getEffectiveRelocModel(RM, TT), 115*0b57cec5SDimitry Andric getEffectiveCodeModel(CM, CodeModel::Large), OL), 116*0b57cec5SDimitry Andric TLOF(new WebAssemblyTargetObjectFile()) { 117*0b57cec5SDimitry Andric // WebAssembly type-checks instructions, but a noreturn function with a return 118*0b57cec5SDimitry Andric // type that doesn't match the context will cause a check failure. So we lower 119*0b57cec5SDimitry Andric // LLVM 'unreachable' to ISD::TRAP and then lower that to WebAssembly's 120*0b57cec5SDimitry Andric // 'unreachable' instructions which is meant for that case. 121*0b57cec5SDimitry Andric this->Options.TrapUnreachable = true; 122*0b57cec5SDimitry Andric 123*0b57cec5SDimitry Andric // WebAssembly treats each function as an independent unit. Force 124*0b57cec5SDimitry Andric // -ffunction-sections, effectively, so that we can emit them independently. 125*0b57cec5SDimitry Andric this->Options.FunctionSections = true; 126*0b57cec5SDimitry Andric this->Options.DataSections = true; 127*0b57cec5SDimitry Andric this->Options.UniqueSectionNames = true; 128*0b57cec5SDimitry Andric 129*0b57cec5SDimitry Andric initAsmInfo(); 130*0b57cec5SDimitry Andric 131*0b57cec5SDimitry Andric // Note that we don't use setRequiresStructuredCFG(true). It disables 132*0b57cec5SDimitry Andric // optimizations than we're ok with, and want, such as critical edge 133*0b57cec5SDimitry Andric // splitting and tail merging. 134*0b57cec5SDimitry Andric } 135*0b57cec5SDimitry Andric 136*0b57cec5SDimitry Andric WebAssemblyTargetMachine::~WebAssemblyTargetMachine() = default; // anchor. 137*0b57cec5SDimitry Andric 138*0b57cec5SDimitry Andric const WebAssemblySubtarget * 139*0b57cec5SDimitry Andric WebAssemblyTargetMachine::getSubtargetImpl(std::string CPU, 140*0b57cec5SDimitry Andric std::string FS) const { 141*0b57cec5SDimitry Andric auto &I = SubtargetMap[CPU + FS]; 142*0b57cec5SDimitry Andric if (!I) { 143*0b57cec5SDimitry Andric I = llvm::make_unique<WebAssemblySubtarget>(TargetTriple, CPU, FS, *this); 144*0b57cec5SDimitry Andric } 145*0b57cec5SDimitry Andric return I.get(); 146*0b57cec5SDimitry Andric } 147*0b57cec5SDimitry Andric 148*0b57cec5SDimitry Andric const WebAssemblySubtarget * 149*0b57cec5SDimitry Andric WebAssemblyTargetMachine::getSubtargetImpl(const Function &F) const { 150*0b57cec5SDimitry Andric Attribute CPUAttr = F.getFnAttribute("target-cpu"); 151*0b57cec5SDimitry Andric Attribute FSAttr = F.getFnAttribute("target-features"); 152*0b57cec5SDimitry Andric 153*0b57cec5SDimitry Andric std::string CPU = !CPUAttr.hasAttribute(Attribute::None) 154*0b57cec5SDimitry Andric ? CPUAttr.getValueAsString().str() 155*0b57cec5SDimitry Andric : TargetCPU; 156*0b57cec5SDimitry Andric std::string FS = !FSAttr.hasAttribute(Attribute::None) 157*0b57cec5SDimitry Andric ? FSAttr.getValueAsString().str() 158*0b57cec5SDimitry Andric : TargetFS; 159*0b57cec5SDimitry Andric 160*0b57cec5SDimitry Andric // This needs to be done before we create a new subtarget since any 161*0b57cec5SDimitry Andric // creation will depend on the TM and the code generation flags on the 162*0b57cec5SDimitry Andric // function that reside in TargetOptions. 163*0b57cec5SDimitry Andric resetTargetOptions(F); 164*0b57cec5SDimitry Andric 165*0b57cec5SDimitry Andric return getSubtargetImpl(CPU, FS); 166*0b57cec5SDimitry Andric } 167*0b57cec5SDimitry Andric 168*0b57cec5SDimitry Andric namespace { 169*0b57cec5SDimitry Andric 170*0b57cec5SDimitry Andric class CoalesceFeaturesAndStripAtomics final : public ModulePass { 171*0b57cec5SDimitry Andric // Take the union of all features used in the module and use it for each 172*0b57cec5SDimitry Andric // function individually, since having multiple feature sets in one module 173*0b57cec5SDimitry Andric // currently does not make sense for WebAssembly. If atomics are not enabled, 174*0b57cec5SDimitry Andric // also strip atomic operations and thread local storage. 175*0b57cec5SDimitry Andric static char ID; 176*0b57cec5SDimitry Andric WebAssemblyTargetMachine *WasmTM; 177*0b57cec5SDimitry Andric 178*0b57cec5SDimitry Andric public: 179*0b57cec5SDimitry Andric CoalesceFeaturesAndStripAtomics(WebAssemblyTargetMachine *WasmTM) 180*0b57cec5SDimitry Andric : ModulePass(ID), WasmTM(WasmTM) {} 181*0b57cec5SDimitry Andric 182*0b57cec5SDimitry Andric bool runOnModule(Module &M) override { 183*0b57cec5SDimitry Andric FeatureBitset Features = coalesceFeatures(M); 184*0b57cec5SDimitry Andric 185*0b57cec5SDimitry Andric std::string FeatureStr = getFeatureString(Features); 186*0b57cec5SDimitry Andric for (auto &F : M) 187*0b57cec5SDimitry Andric replaceFeatures(F, FeatureStr); 188*0b57cec5SDimitry Andric 189*0b57cec5SDimitry Andric bool StrippedAtomics = false; 190*0b57cec5SDimitry Andric bool StrippedTLS = false; 191*0b57cec5SDimitry Andric 192*0b57cec5SDimitry Andric if (!Features[WebAssembly::FeatureAtomics]) 193*0b57cec5SDimitry Andric StrippedAtomics = stripAtomics(M); 194*0b57cec5SDimitry Andric 195*0b57cec5SDimitry Andric if (!Features[WebAssembly::FeatureBulkMemory]) 196*0b57cec5SDimitry Andric StrippedTLS = stripThreadLocals(M); 197*0b57cec5SDimitry Andric 198*0b57cec5SDimitry Andric if (StrippedAtomics && !StrippedTLS) 199*0b57cec5SDimitry Andric stripThreadLocals(M); 200*0b57cec5SDimitry Andric else if (StrippedTLS && !StrippedAtomics) 201*0b57cec5SDimitry Andric stripAtomics(M); 202*0b57cec5SDimitry Andric 203*0b57cec5SDimitry Andric recordFeatures(M, Features, StrippedAtomics || StrippedTLS); 204*0b57cec5SDimitry Andric 205*0b57cec5SDimitry Andric // Conservatively assume we have made some change 206*0b57cec5SDimitry Andric return true; 207*0b57cec5SDimitry Andric } 208*0b57cec5SDimitry Andric 209*0b57cec5SDimitry Andric private: 210*0b57cec5SDimitry Andric FeatureBitset coalesceFeatures(const Module &M) { 211*0b57cec5SDimitry Andric FeatureBitset Features = 212*0b57cec5SDimitry Andric WasmTM 213*0b57cec5SDimitry Andric ->getSubtargetImpl(WasmTM->getTargetCPU(), 214*0b57cec5SDimitry Andric WasmTM->getTargetFeatureString()) 215*0b57cec5SDimitry Andric ->getFeatureBits(); 216*0b57cec5SDimitry Andric for (auto &F : M) 217*0b57cec5SDimitry Andric Features |= WasmTM->getSubtargetImpl(F)->getFeatureBits(); 218*0b57cec5SDimitry Andric return Features; 219*0b57cec5SDimitry Andric } 220*0b57cec5SDimitry Andric 221*0b57cec5SDimitry Andric std::string getFeatureString(const FeatureBitset &Features) { 222*0b57cec5SDimitry Andric std::string Ret; 223*0b57cec5SDimitry Andric for (const SubtargetFeatureKV &KV : WebAssemblyFeatureKV) { 224*0b57cec5SDimitry Andric if (Features[KV.Value]) 225*0b57cec5SDimitry Andric Ret += (StringRef("+") + KV.Key + ",").str(); 226*0b57cec5SDimitry Andric } 227*0b57cec5SDimitry Andric return Ret; 228*0b57cec5SDimitry Andric } 229*0b57cec5SDimitry Andric 230*0b57cec5SDimitry Andric void replaceFeatures(Function &F, const std::string &Features) { 231*0b57cec5SDimitry Andric F.removeFnAttr("target-features"); 232*0b57cec5SDimitry Andric F.removeFnAttr("target-cpu"); 233*0b57cec5SDimitry Andric F.addFnAttr("target-features", Features); 234*0b57cec5SDimitry Andric } 235*0b57cec5SDimitry Andric 236*0b57cec5SDimitry Andric bool stripAtomics(Module &M) { 237*0b57cec5SDimitry Andric // Detect whether any atomics will be lowered, since there is no way to tell 238*0b57cec5SDimitry Andric // whether the LowerAtomic pass lowers e.g. stores. 239*0b57cec5SDimitry Andric bool Stripped = false; 240*0b57cec5SDimitry Andric for (auto &F : M) { 241*0b57cec5SDimitry Andric for (auto &B : F) { 242*0b57cec5SDimitry Andric for (auto &I : B) { 243*0b57cec5SDimitry Andric if (I.isAtomic()) { 244*0b57cec5SDimitry Andric Stripped = true; 245*0b57cec5SDimitry Andric goto done; 246*0b57cec5SDimitry Andric } 247*0b57cec5SDimitry Andric } 248*0b57cec5SDimitry Andric } 249*0b57cec5SDimitry Andric } 250*0b57cec5SDimitry Andric 251*0b57cec5SDimitry Andric done: 252*0b57cec5SDimitry Andric if (!Stripped) 253*0b57cec5SDimitry Andric return false; 254*0b57cec5SDimitry Andric 255*0b57cec5SDimitry Andric LowerAtomicPass Lowerer; 256*0b57cec5SDimitry Andric FunctionAnalysisManager FAM; 257*0b57cec5SDimitry Andric for (auto &F : M) 258*0b57cec5SDimitry Andric Lowerer.run(F, FAM); 259*0b57cec5SDimitry Andric 260*0b57cec5SDimitry Andric return true; 261*0b57cec5SDimitry Andric } 262*0b57cec5SDimitry Andric 263*0b57cec5SDimitry Andric bool stripThreadLocals(Module &M) { 264*0b57cec5SDimitry Andric bool Stripped = false; 265*0b57cec5SDimitry Andric for (auto &GV : M.globals()) { 266*0b57cec5SDimitry Andric if (GV.getThreadLocalMode() != 267*0b57cec5SDimitry Andric GlobalValue::ThreadLocalMode::NotThreadLocal) { 268*0b57cec5SDimitry Andric Stripped = true; 269*0b57cec5SDimitry Andric GV.setThreadLocalMode(GlobalValue::ThreadLocalMode::NotThreadLocal); 270*0b57cec5SDimitry Andric } 271*0b57cec5SDimitry Andric } 272*0b57cec5SDimitry Andric return Stripped; 273*0b57cec5SDimitry Andric } 274*0b57cec5SDimitry Andric 275*0b57cec5SDimitry Andric void recordFeatures(Module &M, const FeatureBitset &Features, bool Stripped) { 276*0b57cec5SDimitry Andric for (const SubtargetFeatureKV &KV : WebAssemblyFeatureKV) { 277*0b57cec5SDimitry Andric std::string MDKey = (StringRef("wasm-feature-") + KV.Key).str(); 278*0b57cec5SDimitry Andric if (KV.Value == WebAssembly::FeatureAtomics && Stripped) { 279*0b57cec5SDimitry Andric // "atomics" is special: code compiled without atomics may have had its 280*0b57cec5SDimitry Andric // atomics lowered to nonatomic operations. In that case, atomics is 281*0b57cec5SDimitry Andric // disallowed to prevent unsafe linking with atomics-enabled objects. 282*0b57cec5SDimitry Andric assert(!Features[WebAssembly::FeatureAtomics] || 283*0b57cec5SDimitry Andric !Features[WebAssembly::FeatureBulkMemory]); 284*0b57cec5SDimitry Andric M.addModuleFlag(Module::ModFlagBehavior::Error, MDKey, 285*0b57cec5SDimitry Andric wasm::WASM_FEATURE_PREFIX_DISALLOWED); 286*0b57cec5SDimitry Andric } else if (Features[KV.Value]) { 287*0b57cec5SDimitry Andric // Otherwise features are marked Used or not mentioned 288*0b57cec5SDimitry Andric M.addModuleFlag(Module::ModFlagBehavior::Error, MDKey, 289*0b57cec5SDimitry Andric wasm::WASM_FEATURE_PREFIX_USED); 290*0b57cec5SDimitry Andric } 291*0b57cec5SDimitry Andric } 292*0b57cec5SDimitry Andric } 293*0b57cec5SDimitry Andric }; 294*0b57cec5SDimitry Andric char CoalesceFeaturesAndStripAtomics::ID = 0; 295*0b57cec5SDimitry Andric 296*0b57cec5SDimitry Andric /// WebAssembly Code Generator Pass Configuration Options. 297*0b57cec5SDimitry Andric class WebAssemblyPassConfig final : public TargetPassConfig { 298*0b57cec5SDimitry Andric public: 299*0b57cec5SDimitry Andric WebAssemblyPassConfig(WebAssemblyTargetMachine &TM, PassManagerBase &PM) 300*0b57cec5SDimitry Andric : TargetPassConfig(TM, PM) {} 301*0b57cec5SDimitry Andric 302*0b57cec5SDimitry Andric WebAssemblyTargetMachine &getWebAssemblyTargetMachine() const { 303*0b57cec5SDimitry Andric return getTM<WebAssemblyTargetMachine>(); 304*0b57cec5SDimitry Andric } 305*0b57cec5SDimitry Andric 306*0b57cec5SDimitry Andric FunctionPass *createTargetRegisterAllocator(bool) override; 307*0b57cec5SDimitry Andric 308*0b57cec5SDimitry Andric void addIRPasses() override; 309*0b57cec5SDimitry Andric bool addInstSelector() override; 310*0b57cec5SDimitry Andric void addPostRegAlloc() override; 311*0b57cec5SDimitry Andric bool addGCPasses() override { return false; } 312*0b57cec5SDimitry Andric void addPreEmitPass() override; 313*0b57cec5SDimitry Andric 314*0b57cec5SDimitry Andric // No reg alloc 315*0b57cec5SDimitry Andric bool addRegAssignmentFast() override { return false; } 316*0b57cec5SDimitry Andric 317*0b57cec5SDimitry Andric // No reg alloc 318*0b57cec5SDimitry Andric bool addRegAssignmentOptimized() override { return false; } 319*0b57cec5SDimitry Andric }; 320*0b57cec5SDimitry Andric } // end anonymous namespace 321*0b57cec5SDimitry Andric 322*0b57cec5SDimitry Andric TargetTransformInfo 323*0b57cec5SDimitry Andric WebAssemblyTargetMachine::getTargetTransformInfo(const Function &F) { 324*0b57cec5SDimitry Andric return TargetTransformInfo(WebAssemblyTTIImpl(this, F)); 325*0b57cec5SDimitry Andric } 326*0b57cec5SDimitry Andric 327*0b57cec5SDimitry Andric TargetPassConfig * 328*0b57cec5SDimitry Andric WebAssemblyTargetMachine::createPassConfig(PassManagerBase &PM) { 329*0b57cec5SDimitry Andric return new WebAssemblyPassConfig(*this, PM); 330*0b57cec5SDimitry Andric } 331*0b57cec5SDimitry Andric 332*0b57cec5SDimitry Andric FunctionPass *WebAssemblyPassConfig::createTargetRegisterAllocator(bool) { 333*0b57cec5SDimitry Andric return nullptr; // No reg alloc 334*0b57cec5SDimitry Andric } 335*0b57cec5SDimitry Andric 336*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 337*0b57cec5SDimitry Andric // The following functions are called from lib/CodeGen/Passes.cpp to modify 338*0b57cec5SDimitry Andric // the CodeGen pass sequence. 339*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 340*0b57cec5SDimitry Andric 341*0b57cec5SDimitry Andric void WebAssemblyPassConfig::addIRPasses() { 342*0b57cec5SDimitry Andric // Runs LowerAtomicPass if necessary 343*0b57cec5SDimitry Andric addPass(new CoalesceFeaturesAndStripAtomics(&getWebAssemblyTargetMachine())); 344*0b57cec5SDimitry Andric 345*0b57cec5SDimitry Andric // This is a no-op if atomics are not used in the module 346*0b57cec5SDimitry Andric addPass(createAtomicExpandPass()); 347*0b57cec5SDimitry Andric 348*0b57cec5SDimitry Andric // Add signatures to prototype-less function declarations 349*0b57cec5SDimitry Andric addPass(createWebAssemblyAddMissingPrototypes()); 350*0b57cec5SDimitry Andric 351*0b57cec5SDimitry Andric // Lower .llvm.global_dtors into .llvm_global_ctors with __cxa_atexit calls. 352*0b57cec5SDimitry Andric addPass(createWebAssemblyLowerGlobalDtors()); 353*0b57cec5SDimitry Andric 354*0b57cec5SDimitry Andric // Fix function bitcasts, as WebAssembly requires caller and callee signatures 355*0b57cec5SDimitry Andric // to match. 356*0b57cec5SDimitry Andric addPass(createWebAssemblyFixFunctionBitcasts()); 357*0b57cec5SDimitry Andric 358*0b57cec5SDimitry Andric // Optimize "returned" function attributes. 359*0b57cec5SDimitry Andric if (getOptLevel() != CodeGenOpt::None) 360*0b57cec5SDimitry Andric addPass(createWebAssemblyOptimizeReturned()); 361*0b57cec5SDimitry Andric 362*0b57cec5SDimitry Andric // If exception handling is not enabled and setjmp/longjmp handling is 363*0b57cec5SDimitry Andric // enabled, we lower invokes into calls and delete unreachable landingpad 364*0b57cec5SDimitry Andric // blocks. Lowering invokes when there is no EH support is done in 365*0b57cec5SDimitry Andric // TargetPassConfig::addPassesToHandleExceptions, but this runs after this 366*0b57cec5SDimitry Andric // function and SjLj handling expects all invokes to be lowered before. 367*0b57cec5SDimitry Andric if (!EnableEmException && 368*0b57cec5SDimitry Andric TM->Options.ExceptionModel == ExceptionHandling::None) { 369*0b57cec5SDimitry Andric addPass(createLowerInvokePass()); 370*0b57cec5SDimitry Andric // The lower invoke pass may create unreachable code. Remove it in order not 371*0b57cec5SDimitry Andric // to process dead blocks in setjmp/longjmp handling. 372*0b57cec5SDimitry Andric addPass(createUnreachableBlockEliminationPass()); 373*0b57cec5SDimitry Andric } 374*0b57cec5SDimitry Andric 375*0b57cec5SDimitry Andric // Handle exceptions and setjmp/longjmp if enabled. 376*0b57cec5SDimitry Andric if (EnableEmException || EnableEmSjLj) 377*0b57cec5SDimitry Andric addPass(createWebAssemblyLowerEmscriptenEHSjLj(EnableEmException, 378*0b57cec5SDimitry Andric EnableEmSjLj)); 379*0b57cec5SDimitry Andric 380*0b57cec5SDimitry Andric // Expand indirectbr instructions to switches. 381*0b57cec5SDimitry Andric addPass(createIndirectBrExpandPass()); 382*0b57cec5SDimitry Andric 383*0b57cec5SDimitry Andric TargetPassConfig::addIRPasses(); 384*0b57cec5SDimitry Andric } 385*0b57cec5SDimitry Andric 386*0b57cec5SDimitry Andric bool WebAssemblyPassConfig::addInstSelector() { 387*0b57cec5SDimitry Andric (void)TargetPassConfig::addInstSelector(); 388*0b57cec5SDimitry Andric addPass( 389*0b57cec5SDimitry Andric createWebAssemblyISelDag(getWebAssemblyTargetMachine(), getOptLevel())); 390*0b57cec5SDimitry Andric // Run the argument-move pass immediately after the ScheduleDAG scheduler 391*0b57cec5SDimitry Andric // so that we can fix up the ARGUMENT instructions before anything else 392*0b57cec5SDimitry Andric // sees them in the wrong place. 393*0b57cec5SDimitry Andric addPass(createWebAssemblyArgumentMove()); 394*0b57cec5SDimitry Andric // Set the p2align operands. This information is present during ISel, however 395*0b57cec5SDimitry Andric // it's inconvenient to collect. Collect it now, and update the immediate 396*0b57cec5SDimitry Andric // operands. 397*0b57cec5SDimitry Andric addPass(createWebAssemblySetP2AlignOperands()); 398*0b57cec5SDimitry Andric return false; 399*0b57cec5SDimitry Andric } 400*0b57cec5SDimitry Andric 401*0b57cec5SDimitry Andric void WebAssemblyPassConfig::addPostRegAlloc() { 402*0b57cec5SDimitry Andric // TODO: The following CodeGen passes don't currently support code containing 403*0b57cec5SDimitry Andric // virtual registers. Consider removing their restrictions and re-enabling 404*0b57cec5SDimitry Andric // them. 405*0b57cec5SDimitry Andric 406*0b57cec5SDimitry Andric // These functions all require the NoVRegs property. 407*0b57cec5SDimitry Andric disablePass(&MachineCopyPropagationID); 408*0b57cec5SDimitry Andric disablePass(&PostRAMachineSinkingID); 409*0b57cec5SDimitry Andric disablePass(&PostRASchedulerID); 410*0b57cec5SDimitry Andric disablePass(&FuncletLayoutID); 411*0b57cec5SDimitry Andric disablePass(&StackMapLivenessID); 412*0b57cec5SDimitry Andric disablePass(&LiveDebugValuesID); 413*0b57cec5SDimitry Andric disablePass(&PatchableFunctionID); 414*0b57cec5SDimitry Andric disablePass(&ShrinkWrapID); 415*0b57cec5SDimitry Andric 416*0b57cec5SDimitry Andric // This pass hurts code size for wasm because it can generate irreducible 417*0b57cec5SDimitry Andric // control flow. 418*0b57cec5SDimitry Andric disablePass(&MachineBlockPlacementID); 419*0b57cec5SDimitry Andric 420*0b57cec5SDimitry Andric TargetPassConfig::addPostRegAlloc(); 421*0b57cec5SDimitry Andric } 422*0b57cec5SDimitry Andric 423*0b57cec5SDimitry Andric void WebAssemblyPassConfig::addPreEmitPass() { 424*0b57cec5SDimitry Andric TargetPassConfig::addPreEmitPass(); 425*0b57cec5SDimitry Andric 426*0b57cec5SDimitry Andric // Rewrite pseudo call_indirect instructions as real instructions. 427*0b57cec5SDimitry Andric // This needs to run before register stackification, because we change the 428*0b57cec5SDimitry Andric // order of the arguments. 429*0b57cec5SDimitry Andric addPass(createWebAssemblyCallIndirectFixup()); 430*0b57cec5SDimitry Andric 431*0b57cec5SDimitry Andric // Eliminate multiple-entry loops. 432*0b57cec5SDimitry Andric addPass(createWebAssemblyFixIrreducibleControlFlow()); 433*0b57cec5SDimitry Andric 434*0b57cec5SDimitry Andric // Do various transformations for exception handling. 435*0b57cec5SDimitry Andric // Every CFG-changing optimizations should come before this. 436*0b57cec5SDimitry Andric addPass(createWebAssemblyLateEHPrepare()); 437*0b57cec5SDimitry Andric 438*0b57cec5SDimitry Andric // Now that we have a prologue and epilogue and all frame indices are 439*0b57cec5SDimitry Andric // rewritten, eliminate SP and FP. This allows them to be stackified, 440*0b57cec5SDimitry Andric // colored, and numbered with the rest of the registers. 441*0b57cec5SDimitry Andric addPass(createWebAssemblyReplacePhysRegs()); 442*0b57cec5SDimitry Andric 443*0b57cec5SDimitry Andric // Preparations and optimizations related to register stackification. 444*0b57cec5SDimitry Andric if (getOptLevel() != CodeGenOpt::None) { 445*0b57cec5SDimitry Andric // LiveIntervals isn't commonly run this late. Re-establish preconditions. 446*0b57cec5SDimitry Andric addPass(createWebAssemblyPrepareForLiveIntervals()); 447*0b57cec5SDimitry Andric 448*0b57cec5SDimitry Andric // Depend on LiveIntervals and perform some optimizations on it. 449*0b57cec5SDimitry Andric addPass(createWebAssemblyOptimizeLiveIntervals()); 450*0b57cec5SDimitry Andric 451*0b57cec5SDimitry Andric // Prepare memory intrinsic calls for register stackifying. 452*0b57cec5SDimitry Andric addPass(createWebAssemblyMemIntrinsicResults()); 453*0b57cec5SDimitry Andric 454*0b57cec5SDimitry Andric // Mark registers as representing wasm's value stack. This is a key 455*0b57cec5SDimitry Andric // code-compression technique in WebAssembly. We run this pass (and 456*0b57cec5SDimitry Andric // MemIntrinsicResults above) very late, so that it sees as much code as 457*0b57cec5SDimitry Andric // possible, including code emitted by PEI and expanded by late tail 458*0b57cec5SDimitry Andric // duplication. 459*0b57cec5SDimitry Andric addPass(createWebAssemblyRegStackify()); 460*0b57cec5SDimitry Andric 461*0b57cec5SDimitry Andric // Run the register coloring pass to reduce the total number of registers. 462*0b57cec5SDimitry Andric // This runs after stackification so that it doesn't consider registers 463*0b57cec5SDimitry Andric // that become stackified. 464*0b57cec5SDimitry Andric addPass(createWebAssemblyRegColoring()); 465*0b57cec5SDimitry Andric } 466*0b57cec5SDimitry Andric 467*0b57cec5SDimitry Andric // Sort the blocks of the CFG into topological order, a prerequisite for 468*0b57cec5SDimitry Andric // BLOCK and LOOP markers. 469*0b57cec5SDimitry Andric addPass(createWebAssemblyCFGSort()); 470*0b57cec5SDimitry Andric 471*0b57cec5SDimitry Andric // Insert BLOCK and LOOP markers. 472*0b57cec5SDimitry Andric addPass(createWebAssemblyCFGStackify()); 473*0b57cec5SDimitry Andric 474*0b57cec5SDimitry Andric // Insert explicit local.get and local.set operators. 475*0b57cec5SDimitry Andric addPass(createWebAssemblyExplicitLocals()); 476*0b57cec5SDimitry Andric 477*0b57cec5SDimitry Andric // Lower br_unless into br_if. 478*0b57cec5SDimitry Andric addPass(createWebAssemblyLowerBrUnless()); 479*0b57cec5SDimitry Andric 480*0b57cec5SDimitry Andric // Perform the very last peephole optimizations on the code. 481*0b57cec5SDimitry Andric if (getOptLevel() != CodeGenOpt::None) 482*0b57cec5SDimitry Andric addPass(createWebAssemblyPeephole()); 483*0b57cec5SDimitry Andric 484*0b57cec5SDimitry Andric // Create a mapping from LLVM CodeGen virtual registers to wasm registers. 485*0b57cec5SDimitry Andric addPass(createWebAssemblyRegNumbering()); 486*0b57cec5SDimitry Andric } 487*0b57cec5SDimitry Andric 488*0b57cec5SDimitry Andric yaml::MachineFunctionInfo * 489*0b57cec5SDimitry Andric WebAssemblyTargetMachine::createDefaultFuncInfoYAML() const { 490*0b57cec5SDimitry Andric return new yaml::WebAssemblyFunctionInfo(); 491*0b57cec5SDimitry Andric } 492*0b57cec5SDimitry Andric 493*0b57cec5SDimitry Andric yaml::MachineFunctionInfo *WebAssemblyTargetMachine::convertFuncInfoToYAML( 494*0b57cec5SDimitry Andric const MachineFunction &MF) const { 495*0b57cec5SDimitry Andric const auto *MFI = MF.getInfo<WebAssemblyFunctionInfo>(); 496*0b57cec5SDimitry Andric return new yaml::WebAssemblyFunctionInfo(*MFI); 497*0b57cec5SDimitry Andric } 498*0b57cec5SDimitry Andric 499*0b57cec5SDimitry Andric bool WebAssemblyTargetMachine::parseMachineFunctionInfo( 500*0b57cec5SDimitry Andric const yaml::MachineFunctionInfo &MFI, PerFunctionMIParsingState &PFS, 501*0b57cec5SDimitry Andric SMDiagnostic &Error, SMRange &SourceRange) const { 502*0b57cec5SDimitry Andric const auto &YamlMFI = 503*0b57cec5SDimitry Andric reinterpret_cast<const yaml::WebAssemblyFunctionInfo &>(MFI); 504*0b57cec5SDimitry Andric MachineFunction &MF = PFS.MF; 505*0b57cec5SDimitry Andric MF.getInfo<WebAssemblyFunctionInfo>()->initializeBaseYamlFields(YamlMFI); 506*0b57cec5SDimitry Andric return false; 507*0b57cec5SDimitry Andric } 508