1*0b57cec5SDimitry Andric //===-- WebAssemblyRegStackify.cpp - Register Stackification --------------===// 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 implements a register stacking pass. 11*0b57cec5SDimitry Andric /// 12*0b57cec5SDimitry Andric /// This pass reorders instructions to put register uses and defs in an order 13*0b57cec5SDimitry Andric /// such that they form single-use expression trees. Registers fitting this form 14*0b57cec5SDimitry Andric /// are then marked as "stackified", meaning references to them are replaced by 15*0b57cec5SDimitry Andric /// "push" and "pop" from the value stack. 16*0b57cec5SDimitry Andric /// 17*0b57cec5SDimitry Andric /// This is primarily a code size optimization, since temporary values on the 18*0b57cec5SDimitry Andric /// value stack don't need to be named. 19*0b57cec5SDimitry Andric /// 20*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 21*0b57cec5SDimitry Andric 22*0b57cec5SDimitry Andric #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" // for WebAssembly::ARGUMENT_* 23*0b57cec5SDimitry Andric #include "WebAssembly.h" 24*0b57cec5SDimitry Andric #include "WebAssemblyDebugValueManager.h" 25*0b57cec5SDimitry Andric #include "WebAssemblyMachineFunctionInfo.h" 26*0b57cec5SDimitry Andric #include "WebAssemblySubtarget.h" 27*0b57cec5SDimitry Andric #include "WebAssemblyUtilities.h" 28*0b57cec5SDimitry Andric #include "llvm/ADT/SmallPtrSet.h" 29*0b57cec5SDimitry Andric #include "llvm/Analysis/AliasAnalysis.h" 30*0b57cec5SDimitry Andric #include "llvm/CodeGen/LiveIntervals.h" 31*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineBlockFrequencyInfo.h" 32*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineDominators.h" 33*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h" 34*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineModuleInfoImpls.h" 35*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h" 36*0b57cec5SDimitry Andric #include "llvm/CodeGen/Passes.h" 37*0b57cec5SDimitry Andric #include "llvm/Support/Debug.h" 38*0b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 39*0b57cec5SDimitry Andric using namespace llvm; 40*0b57cec5SDimitry Andric 41*0b57cec5SDimitry Andric #define DEBUG_TYPE "wasm-reg-stackify" 42*0b57cec5SDimitry Andric 43*0b57cec5SDimitry Andric namespace { 44*0b57cec5SDimitry Andric class WebAssemblyRegStackify final : public MachineFunctionPass { 45*0b57cec5SDimitry Andric StringRef getPassName() const override { 46*0b57cec5SDimitry Andric return "WebAssembly Register Stackify"; 47*0b57cec5SDimitry Andric } 48*0b57cec5SDimitry Andric 49*0b57cec5SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override { 50*0b57cec5SDimitry Andric AU.setPreservesCFG(); 51*0b57cec5SDimitry Andric AU.addRequired<AAResultsWrapperPass>(); 52*0b57cec5SDimitry Andric AU.addRequired<MachineDominatorTree>(); 53*0b57cec5SDimitry Andric AU.addRequired<LiveIntervals>(); 54*0b57cec5SDimitry Andric AU.addPreserved<MachineBlockFrequencyInfo>(); 55*0b57cec5SDimitry Andric AU.addPreserved<SlotIndexes>(); 56*0b57cec5SDimitry Andric AU.addPreserved<LiveIntervals>(); 57*0b57cec5SDimitry Andric AU.addPreservedID(LiveVariablesID); 58*0b57cec5SDimitry Andric AU.addPreserved<MachineDominatorTree>(); 59*0b57cec5SDimitry Andric MachineFunctionPass::getAnalysisUsage(AU); 60*0b57cec5SDimitry Andric } 61*0b57cec5SDimitry Andric 62*0b57cec5SDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override; 63*0b57cec5SDimitry Andric 64*0b57cec5SDimitry Andric public: 65*0b57cec5SDimitry Andric static char ID; // Pass identification, replacement for typeid 66*0b57cec5SDimitry Andric WebAssemblyRegStackify() : MachineFunctionPass(ID) {} 67*0b57cec5SDimitry Andric }; 68*0b57cec5SDimitry Andric } // end anonymous namespace 69*0b57cec5SDimitry Andric 70*0b57cec5SDimitry Andric char WebAssemblyRegStackify::ID = 0; 71*0b57cec5SDimitry Andric INITIALIZE_PASS(WebAssemblyRegStackify, DEBUG_TYPE, 72*0b57cec5SDimitry Andric "Reorder instructions to use the WebAssembly value stack", 73*0b57cec5SDimitry Andric false, false) 74*0b57cec5SDimitry Andric 75*0b57cec5SDimitry Andric FunctionPass *llvm::createWebAssemblyRegStackify() { 76*0b57cec5SDimitry Andric return new WebAssemblyRegStackify(); 77*0b57cec5SDimitry Andric } 78*0b57cec5SDimitry Andric 79*0b57cec5SDimitry Andric // Decorate the given instruction with implicit operands that enforce the 80*0b57cec5SDimitry Andric // expression stack ordering constraints for an instruction which is on 81*0b57cec5SDimitry Andric // the expression stack. 82*0b57cec5SDimitry Andric static void imposeStackOrdering(MachineInstr *MI) { 83*0b57cec5SDimitry Andric // Write the opaque VALUE_STACK register. 84*0b57cec5SDimitry Andric if (!MI->definesRegister(WebAssembly::VALUE_STACK)) 85*0b57cec5SDimitry Andric MI->addOperand(MachineOperand::CreateReg(WebAssembly::VALUE_STACK, 86*0b57cec5SDimitry Andric /*isDef=*/true, 87*0b57cec5SDimitry Andric /*isImp=*/true)); 88*0b57cec5SDimitry Andric 89*0b57cec5SDimitry Andric // Also read the opaque VALUE_STACK register. 90*0b57cec5SDimitry Andric if (!MI->readsRegister(WebAssembly::VALUE_STACK)) 91*0b57cec5SDimitry Andric MI->addOperand(MachineOperand::CreateReg(WebAssembly::VALUE_STACK, 92*0b57cec5SDimitry Andric /*isDef=*/false, 93*0b57cec5SDimitry Andric /*isImp=*/true)); 94*0b57cec5SDimitry Andric } 95*0b57cec5SDimitry Andric 96*0b57cec5SDimitry Andric // Convert an IMPLICIT_DEF instruction into an instruction which defines 97*0b57cec5SDimitry Andric // a constant zero value. 98*0b57cec5SDimitry Andric static void convertImplicitDefToConstZero(MachineInstr *MI, 99*0b57cec5SDimitry Andric MachineRegisterInfo &MRI, 100*0b57cec5SDimitry Andric const TargetInstrInfo *TII, 101*0b57cec5SDimitry Andric MachineFunction &MF, 102*0b57cec5SDimitry Andric LiveIntervals &LIS) { 103*0b57cec5SDimitry Andric assert(MI->getOpcode() == TargetOpcode::IMPLICIT_DEF); 104*0b57cec5SDimitry Andric 105*0b57cec5SDimitry Andric const auto *RegClass = MRI.getRegClass(MI->getOperand(0).getReg()); 106*0b57cec5SDimitry Andric if (RegClass == &WebAssembly::I32RegClass) { 107*0b57cec5SDimitry Andric MI->setDesc(TII->get(WebAssembly::CONST_I32)); 108*0b57cec5SDimitry Andric MI->addOperand(MachineOperand::CreateImm(0)); 109*0b57cec5SDimitry Andric } else if (RegClass == &WebAssembly::I64RegClass) { 110*0b57cec5SDimitry Andric MI->setDesc(TII->get(WebAssembly::CONST_I64)); 111*0b57cec5SDimitry Andric MI->addOperand(MachineOperand::CreateImm(0)); 112*0b57cec5SDimitry Andric } else if (RegClass == &WebAssembly::F32RegClass) { 113*0b57cec5SDimitry Andric MI->setDesc(TII->get(WebAssembly::CONST_F32)); 114*0b57cec5SDimitry Andric auto *Val = cast<ConstantFP>(Constant::getNullValue( 115*0b57cec5SDimitry Andric Type::getFloatTy(MF.getFunction().getContext()))); 116*0b57cec5SDimitry Andric MI->addOperand(MachineOperand::CreateFPImm(Val)); 117*0b57cec5SDimitry Andric } else if (RegClass == &WebAssembly::F64RegClass) { 118*0b57cec5SDimitry Andric MI->setDesc(TII->get(WebAssembly::CONST_F64)); 119*0b57cec5SDimitry Andric auto *Val = cast<ConstantFP>(Constant::getNullValue( 120*0b57cec5SDimitry Andric Type::getDoubleTy(MF.getFunction().getContext()))); 121*0b57cec5SDimitry Andric MI->addOperand(MachineOperand::CreateFPImm(Val)); 122*0b57cec5SDimitry Andric } else if (RegClass == &WebAssembly::V128RegClass) { 123*0b57cec5SDimitry Andric unsigned TempReg = MRI.createVirtualRegister(&WebAssembly::I32RegClass); 124*0b57cec5SDimitry Andric MI->setDesc(TII->get(WebAssembly::SPLAT_v4i32)); 125*0b57cec5SDimitry Andric MI->addOperand(MachineOperand::CreateReg(TempReg, false)); 126*0b57cec5SDimitry Andric MachineInstr *Const = BuildMI(*MI->getParent(), MI, MI->getDebugLoc(), 127*0b57cec5SDimitry Andric TII->get(WebAssembly::CONST_I32), TempReg) 128*0b57cec5SDimitry Andric .addImm(0); 129*0b57cec5SDimitry Andric LIS.InsertMachineInstrInMaps(*Const); 130*0b57cec5SDimitry Andric } else { 131*0b57cec5SDimitry Andric llvm_unreachable("Unexpected reg class"); 132*0b57cec5SDimitry Andric } 133*0b57cec5SDimitry Andric } 134*0b57cec5SDimitry Andric 135*0b57cec5SDimitry Andric // Determine whether a call to the callee referenced by 136*0b57cec5SDimitry Andric // MI->getOperand(CalleeOpNo) reads memory, writes memory, and/or has side 137*0b57cec5SDimitry Andric // effects. 138*0b57cec5SDimitry Andric static void queryCallee(const MachineInstr &MI, unsigned CalleeOpNo, bool &Read, 139*0b57cec5SDimitry Andric bool &Write, bool &Effects, bool &StackPointer) { 140*0b57cec5SDimitry Andric // All calls can use the stack pointer. 141*0b57cec5SDimitry Andric StackPointer = true; 142*0b57cec5SDimitry Andric 143*0b57cec5SDimitry Andric const MachineOperand &MO = MI.getOperand(CalleeOpNo); 144*0b57cec5SDimitry Andric if (MO.isGlobal()) { 145*0b57cec5SDimitry Andric const Constant *GV = MO.getGlobal(); 146*0b57cec5SDimitry Andric if (const auto *GA = dyn_cast<GlobalAlias>(GV)) 147*0b57cec5SDimitry Andric if (!GA->isInterposable()) 148*0b57cec5SDimitry Andric GV = GA->getAliasee(); 149*0b57cec5SDimitry Andric 150*0b57cec5SDimitry Andric if (const auto *F = dyn_cast<Function>(GV)) { 151*0b57cec5SDimitry Andric if (!F->doesNotThrow()) 152*0b57cec5SDimitry Andric Effects = true; 153*0b57cec5SDimitry Andric if (F->doesNotAccessMemory()) 154*0b57cec5SDimitry Andric return; 155*0b57cec5SDimitry Andric if (F->onlyReadsMemory()) { 156*0b57cec5SDimitry Andric Read = true; 157*0b57cec5SDimitry Andric return; 158*0b57cec5SDimitry Andric } 159*0b57cec5SDimitry Andric } 160*0b57cec5SDimitry Andric } 161*0b57cec5SDimitry Andric 162*0b57cec5SDimitry Andric // Assume the worst. 163*0b57cec5SDimitry Andric Write = true; 164*0b57cec5SDimitry Andric Read = true; 165*0b57cec5SDimitry Andric Effects = true; 166*0b57cec5SDimitry Andric } 167*0b57cec5SDimitry Andric 168*0b57cec5SDimitry Andric // Determine whether MI reads memory, writes memory, has side effects, 169*0b57cec5SDimitry Andric // and/or uses the stack pointer value. 170*0b57cec5SDimitry Andric static void query(const MachineInstr &MI, AliasAnalysis &AA, bool &Read, 171*0b57cec5SDimitry Andric bool &Write, bool &Effects, bool &StackPointer) { 172*0b57cec5SDimitry Andric assert(!MI.isTerminator()); 173*0b57cec5SDimitry Andric 174*0b57cec5SDimitry Andric if (MI.isDebugInstr() || MI.isPosition()) 175*0b57cec5SDimitry Andric return; 176*0b57cec5SDimitry Andric 177*0b57cec5SDimitry Andric // Check for loads. 178*0b57cec5SDimitry Andric if (MI.mayLoad() && !MI.isDereferenceableInvariantLoad(&AA)) 179*0b57cec5SDimitry Andric Read = true; 180*0b57cec5SDimitry Andric 181*0b57cec5SDimitry Andric // Check for stores. 182*0b57cec5SDimitry Andric if (MI.mayStore()) { 183*0b57cec5SDimitry Andric Write = true; 184*0b57cec5SDimitry Andric } else if (MI.hasOrderedMemoryRef()) { 185*0b57cec5SDimitry Andric switch (MI.getOpcode()) { 186*0b57cec5SDimitry Andric case WebAssembly::DIV_S_I32: 187*0b57cec5SDimitry Andric case WebAssembly::DIV_S_I64: 188*0b57cec5SDimitry Andric case WebAssembly::REM_S_I32: 189*0b57cec5SDimitry Andric case WebAssembly::REM_S_I64: 190*0b57cec5SDimitry Andric case WebAssembly::DIV_U_I32: 191*0b57cec5SDimitry Andric case WebAssembly::DIV_U_I64: 192*0b57cec5SDimitry Andric case WebAssembly::REM_U_I32: 193*0b57cec5SDimitry Andric case WebAssembly::REM_U_I64: 194*0b57cec5SDimitry Andric case WebAssembly::I32_TRUNC_S_F32: 195*0b57cec5SDimitry Andric case WebAssembly::I64_TRUNC_S_F32: 196*0b57cec5SDimitry Andric case WebAssembly::I32_TRUNC_S_F64: 197*0b57cec5SDimitry Andric case WebAssembly::I64_TRUNC_S_F64: 198*0b57cec5SDimitry Andric case WebAssembly::I32_TRUNC_U_F32: 199*0b57cec5SDimitry Andric case WebAssembly::I64_TRUNC_U_F32: 200*0b57cec5SDimitry Andric case WebAssembly::I32_TRUNC_U_F64: 201*0b57cec5SDimitry Andric case WebAssembly::I64_TRUNC_U_F64: 202*0b57cec5SDimitry Andric // These instruction have hasUnmodeledSideEffects() returning true 203*0b57cec5SDimitry Andric // because they trap on overflow and invalid so they can't be arbitrarily 204*0b57cec5SDimitry Andric // moved, however hasOrderedMemoryRef() interprets this plus their lack 205*0b57cec5SDimitry Andric // of memoperands as having a potential unknown memory reference. 206*0b57cec5SDimitry Andric break; 207*0b57cec5SDimitry Andric default: 208*0b57cec5SDimitry Andric // Record volatile accesses, unless it's a call, as calls are handled 209*0b57cec5SDimitry Andric // specially below. 210*0b57cec5SDimitry Andric if (!MI.isCall()) { 211*0b57cec5SDimitry Andric Write = true; 212*0b57cec5SDimitry Andric Effects = true; 213*0b57cec5SDimitry Andric } 214*0b57cec5SDimitry Andric break; 215*0b57cec5SDimitry Andric } 216*0b57cec5SDimitry Andric } 217*0b57cec5SDimitry Andric 218*0b57cec5SDimitry Andric // Check for side effects. 219*0b57cec5SDimitry Andric if (MI.hasUnmodeledSideEffects()) { 220*0b57cec5SDimitry Andric switch (MI.getOpcode()) { 221*0b57cec5SDimitry Andric case WebAssembly::DIV_S_I32: 222*0b57cec5SDimitry Andric case WebAssembly::DIV_S_I64: 223*0b57cec5SDimitry Andric case WebAssembly::REM_S_I32: 224*0b57cec5SDimitry Andric case WebAssembly::REM_S_I64: 225*0b57cec5SDimitry Andric case WebAssembly::DIV_U_I32: 226*0b57cec5SDimitry Andric case WebAssembly::DIV_U_I64: 227*0b57cec5SDimitry Andric case WebAssembly::REM_U_I32: 228*0b57cec5SDimitry Andric case WebAssembly::REM_U_I64: 229*0b57cec5SDimitry Andric case WebAssembly::I32_TRUNC_S_F32: 230*0b57cec5SDimitry Andric case WebAssembly::I64_TRUNC_S_F32: 231*0b57cec5SDimitry Andric case WebAssembly::I32_TRUNC_S_F64: 232*0b57cec5SDimitry Andric case WebAssembly::I64_TRUNC_S_F64: 233*0b57cec5SDimitry Andric case WebAssembly::I32_TRUNC_U_F32: 234*0b57cec5SDimitry Andric case WebAssembly::I64_TRUNC_U_F32: 235*0b57cec5SDimitry Andric case WebAssembly::I32_TRUNC_U_F64: 236*0b57cec5SDimitry Andric case WebAssembly::I64_TRUNC_U_F64: 237*0b57cec5SDimitry Andric // These instructions have hasUnmodeledSideEffects() returning true 238*0b57cec5SDimitry Andric // because they trap on overflow and invalid so they can't be arbitrarily 239*0b57cec5SDimitry Andric // moved, however in the specific case of register stackifying, it is safe 240*0b57cec5SDimitry Andric // to move them because overflow and invalid are Undefined Behavior. 241*0b57cec5SDimitry Andric break; 242*0b57cec5SDimitry Andric default: 243*0b57cec5SDimitry Andric Effects = true; 244*0b57cec5SDimitry Andric break; 245*0b57cec5SDimitry Andric } 246*0b57cec5SDimitry Andric } 247*0b57cec5SDimitry Andric 248*0b57cec5SDimitry Andric // Check for writes to __stack_pointer global. 249*0b57cec5SDimitry Andric if (MI.getOpcode() == WebAssembly::GLOBAL_SET_I32 && 250*0b57cec5SDimitry Andric strcmp(MI.getOperand(0).getSymbolName(), "__stack_pointer") == 0) 251*0b57cec5SDimitry Andric StackPointer = true; 252*0b57cec5SDimitry Andric 253*0b57cec5SDimitry Andric // Analyze calls. 254*0b57cec5SDimitry Andric if (MI.isCall()) { 255*0b57cec5SDimitry Andric unsigned CalleeOpNo = WebAssembly::getCalleeOpNo(MI.getOpcode()); 256*0b57cec5SDimitry Andric queryCallee(MI, CalleeOpNo, Read, Write, Effects, StackPointer); 257*0b57cec5SDimitry Andric } 258*0b57cec5SDimitry Andric } 259*0b57cec5SDimitry Andric 260*0b57cec5SDimitry Andric // Test whether Def is safe and profitable to rematerialize. 261*0b57cec5SDimitry Andric static bool shouldRematerialize(const MachineInstr &Def, AliasAnalysis &AA, 262*0b57cec5SDimitry Andric const WebAssemblyInstrInfo *TII) { 263*0b57cec5SDimitry Andric return Def.isAsCheapAsAMove() && TII->isTriviallyReMaterializable(Def, &AA); 264*0b57cec5SDimitry Andric } 265*0b57cec5SDimitry Andric 266*0b57cec5SDimitry Andric // Identify the definition for this register at this point. This is a 267*0b57cec5SDimitry Andric // generalization of MachineRegisterInfo::getUniqueVRegDef that uses 268*0b57cec5SDimitry Andric // LiveIntervals to handle complex cases. 269*0b57cec5SDimitry Andric static MachineInstr *getVRegDef(unsigned Reg, const MachineInstr *Insert, 270*0b57cec5SDimitry Andric const MachineRegisterInfo &MRI, 271*0b57cec5SDimitry Andric const LiveIntervals &LIS) { 272*0b57cec5SDimitry Andric // Most registers are in SSA form here so we try a quick MRI query first. 273*0b57cec5SDimitry Andric if (MachineInstr *Def = MRI.getUniqueVRegDef(Reg)) 274*0b57cec5SDimitry Andric return Def; 275*0b57cec5SDimitry Andric 276*0b57cec5SDimitry Andric // MRI doesn't know what the Def is. Try asking LIS. 277*0b57cec5SDimitry Andric if (const VNInfo *ValNo = LIS.getInterval(Reg).getVNInfoBefore( 278*0b57cec5SDimitry Andric LIS.getInstructionIndex(*Insert))) 279*0b57cec5SDimitry Andric return LIS.getInstructionFromIndex(ValNo->def); 280*0b57cec5SDimitry Andric 281*0b57cec5SDimitry Andric return nullptr; 282*0b57cec5SDimitry Andric } 283*0b57cec5SDimitry Andric 284*0b57cec5SDimitry Andric // Test whether Reg, as defined at Def, has exactly one use. This is a 285*0b57cec5SDimitry Andric // generalization of MachineRegisterInfo::hasOneUse that uses LiveIntervals 286*0b57cec5SDimitry Andric // to handle complex cases. 287*0b57cec5SDimitry Andric static bool hasOneUse(unsigned Reg, MachineInstr *Def, MachineRegisterInfo &MRI, 288*0b57cec5SDimitry Andric MachineDominatorTree &MDT, LiveIntervals &LIS) { 289*0b57cec5SDimitry Andric // Most registers are in SSA form here so we try a quick MRI query first. 290*0b57cec5SDimitry Andric if (MRI.hasOneUse(Reg)) 291*0b57cec5SDimitry Andric return true; 292*0b57cec5SDimitry Andric 293*0b57cec5SDimitry Andric bool HasOne = false; 294*0b57cec5SDimitry Andric const LiveInterval &LI = LIS.getInterval(Reg); 295*0b57cec5SDimitry Andric const VNInfo *DefVNI = 296*0b57cec5SDimitry Andric LI.getVNInfoAt(LIS.getInstructionIndex(*Def).getRegSlot()); 297*0b57cec5SDimitry Andric assert(DefVNI); 298*0b57cec5SDimitry Andric for (auto &I : MRI.use_nodbg_operands(Reg)) { 299*0b57cec5SDimitry Andric const auto &Result = LI.Query(LIS.getInstructionIndex(*I.getParent())); 300*0b57cec5SDimitry Andric if (Result.valueIn() == DefVNI) { 301*0b57cec5SDimitry Andric if (!Result.isKill()) 302*0b57cec5SDimitry Andric return false; 303*0b57cec5SDimitry Andric if (HasOne) 304*0b57cec5SDimitry Andric return false; 305*0b57cec5SDimitry Andric HasOne = true; 306*0b57cec5SDimitry Andric } 307*0b57cec5SDimitry Andric } 308*0b57cec5SDimitry Andric return HasOne; 309*0b57cec5SDimitry Andric } 310*0b57cec5SDimitry Andric 311*0b57cec5SDimitry Andric // Test whether it's safe to move Def to just before Insert. 312*0b57cec5SDimitry Andric // TODO: Compute memory dependencies in a way that doesn't require always 313*0b57cec5SDimitry Andric // walking the block. 314*0b57cec5SDimitry Andric // TODO: Compute memory dependencies in a way that uses AliasAnalysis to be 315*0b57cec5SDimitry Andric // more precise. 316*0b57cec5SDimitry Andric static bool isSafeToMove(const MachineInstr *Def, const MachineInstr *Insert, 317*0b57cec5SDimitry Andric AliasAnalysis &AA, const MachineRegisterInfo &MRI) { 318*0b57cec5SDimitry Andric assert(Def->getParent() == Insert->getParent()); 319*0b57cec5SDimitry Andric 320*0b57cec5SDimitry Andric // 'catch' and 'extract_exception' should be the first instruction of a BB and 321*0b57cec5SDimitry Andric // cannot move. 322*0b57cec5SDimitry Andric if (Def->getOpcode() == WebAssembly::CATCH || 323*0b57cec5SDimitry Andric Def->getOpcode() == WebAssembly::EXTRACT_EXCEPTION_I32) { 324*0b57cec5SDimitry Andric const MachineBasicBlock *MBB = Def->getParent(); 325*0b57cec5SDimitry Andric auto NextI = std::next(MachineBasicBlock::const_iterator(Def)); 326*0b57cec5SDimitry Andric for (auto E = MBB->end(); NextI != E && NextI->isDebugInstr(); ++NextI) 327*0b57cec5SDimitry Andric ; 328*0b57cec5SDimitry Andric if (NextI != Insert) 329*0b57cec5SDimitry Andric return false; 330*0b57cec5SDimitry Andric } 331*0b57cec5SDimitry Andric 332*0b57cec5SDimitry Andric // Check for register dependencies. 333*0b57cec5SDimitry Andric SmallVector<unsigned, 4> MutableRegisters; 334*0b57cec5SDimitry Andric for (const MachineOperand &MO : Def->operands()) { 335*0b57cec5SDimitry Andric if (!MO.isReg() || MO.isUndef()) 336*0b57cec5SDimitry Andric continue; 337*0b57cec5SDimitry Andric unsigned Reg = MO.getReg(); 338*0b57cec5SDimitry Andric 339*0b57cec5SDimitry Andric // If the register is dead here and at Insert, ignore it. 340*0b57cec5SDimitry Andric if (MO.isDead() && Insert->definesRegister(Reg) && 341*0b57cec5SDimitry Andric !Insert->readsRegister(Reg)) 342*0b57cec5SDimitry Andric continue; 343*0b57cec5SDimitry Andric 344*0b57cec5SDimitry Andric if (TargetRegisterInfo::isPhysicalRegister(Reg)) { 345*0b57cec5SDimitry Andric // Ignore ARGUMENTS; it's just used to keep the ARGUMENT_* instructions 346*0b57cec5SDimitry Andric // from moving down, and we've already checked for that. 347*0b57cec5SDimitry Andric if (Reg == WebAssembly::ARGUMENTS) 348*0b57cec5SDimitry Andric continue; 349*0b57cec5SDimitry Andric // If the physical register is never modified, ignore it. 350*0b57cec5SDimitry Andric if (!MRI.isPhysRegModified(Reg)) 351*0b57cec5SDimitry Andric continue; 352*0b57cec5SDimitry Andric // Otherwise, it's a physical register with unknown liveness. 353*0b57cec5SDimitry Andric return false; 354*0b57cec5SDimitry Andric } 355*0b57cec5SDimitry Andric 356*0b57cec5SDimitry Andric // If one of the operands isn't in SSA form, it has different values at 357*0b57cec5SDimitry Andric // different times, and we need to make sure we don't move our use across 358*0b57cec5SDimitry Andric // a different def. 359*0b57cec5SDimitry Andric if (!MO.isDef() && !MRI.hasOneDef(Reg)) 360*0b57cec5SDimitry Andric MutableRegisters.push_back(Reg); 361*0b57cec5SDimitry Andric } 362*0b57cec5SDimitry Andric 363*0b57cec5SDimitry Andric bool Read = false, Write = false, Effects = false, StackPointer = false; 364*0b57cec5SDimitry Andric query(*Def, AA, Read, Write, Effects, StackPointer); 365*0b57cec5SDimitry Andric 366*0b57cec5SDimitry Andric // If the instruction does not access memory and has no side effects, it has 367*0b57cec5SDimitry Andric // no additional dependencies. 368*0b57cec5SDimitry Andric bool HasMutableRegisters = !MutableRegisters.empty(); 369*0b57cec5SDimitry Andric if (!Read && !Write && !Effects && !StackPointer && !HasMutableRegisters) 370*0b57cec5SDimitry Andric return true; 371*0b57cec5SDimitry Andric 372*0b57cec5SDimitry Andric // Scan through the intervening instructions between Def and Insert. 373*0b57cec5SDimitry Andric MachineBasicBlock::const_iterator D(Def), I(Insert); 374*0b57cec5SDimitry Andric for (--I; I != D; --I) { 375*0b57cec5SDimitry Andric bool InterveningRead = false; 376*0b57cec5SDimitry Andric bool InterveningWrite = false; 377*0b57cec5SDimitry Andric bool InterveningEffects = false; 378*0b57cec5SDimitry Andric bool InterveningStackPointer = false; 379*0b57cec5SDimitry Andric query(*I, AA, InterveningRead, InterveningWrite, InterveningEffects, 380*0b57cec5SDimitry Andric InterveningStackPointer); 381*0b57cec5SDimitry Andric if (Effects && InterveningEffects) 382*0b57cec5SDimitry Andric return false; 383*0b57cec5SDimitry Andric if (Read && InterveningWrite) 384*0b57cec5SDimitry Andric return false; 385*0b57cec5SDimitry Andric if (Write && (InterveningRead || InterveningWrite)) 386*0b57cec5SDimitry Andric return false; 387*0b57cec5SDimitry Andric if (StackPointer && InterveningStackPointer) 388*0b57cec5SDimitry Andric return false; 389*0b57cec5SDimitry Andric 390*0b57cec5SDimitry Andric for (unsigned Reg : MutableRegisters) 391*0b57cec5SDimitry Andric for (const MachineOperand &MO : I->operands()) 392*0b57cec5SDimitry Andric if (MO.isReg() && MO.isDef() && MO.getReg() == Reg) 393*0b57cec5SDimitry Andric return false; 394*0b57cec5SDimitry Andric } 395*0b57cec5SDimitry Andric 396*0b57cec5SDimitry Andric return true; 397*0b57cec5SDimitry Andric } 398*0b57cec5SDimitry Andric 399*0b57cec5SDimitry Andric /// Test whether OneUse, a use of Reg, dominates all of Reg's other uses. 400*0b57cec5SDimitry Andric static bool oneUseDominatesOtherUses(unsigned Reg, const MachineOperand &OneUse, 401*0b57cec5SDimitry Andric const MachineBasicBlock &MBB, 402*0b57cec5SDimitry Andric const MachineRegisterInfo &MRI, 403*0b57cec5SDimitry Andric const MachineDominatorTree &MDT, 404*0b57cec5SDimitry Andric LiveIntervals &LIS, 405*0b57cec5SDimitry Andric WebAssemblyFunctionInfo &MFI) { 406*0b57cec5SDimitry Andric const LiveInterval &LI = LIS.getInterval(Reg); 407*0b57cec5SDimitry Andric 408*0b57cec5SDimitry Andric const MachineInstr *OneUseInst = OneUse.getParent(); 409*0b57cec5SDimitry Andric VNInfo *OneUseVNI = LI.getVNInfoBefore(LIS.getInstructionIndex(*OneUseInst)); 410*0b57cec5SDimitry Andric 411*0b57cec5SDimitry Andric for (const MachineOperand &Use : MRI.use_nodbg_operands(Reg)) { 412*0b57cec5SDimitry Andric if (&Use == &OneUse) 413*0b57cec5SDimitry Andric continue; 414*0b57cec5SDimitry Andric 415*0b57cec5SDimitry Andric const MachineInstr *UseInst = Use.getParent(); 416*0b57cec5SDimitry Andric VNInfo *UseVNI = LI.getVNInfoBefore(LIS.getInstructionIndex(*UseInst)); 417*0b57cec5SDimitry Andric 418*0b57cec5SDimitry Andric if (UseVNI != OneUseVNI) 419*0b57cec5SDimitry Andric continue; 420*0b57cec5SDimitry Andric 421*0b57cec5SDimitry Andric if (UseInst == OneUseInst) { 422*0b57cec5SDimitry Andric // Another use in the same instruction. We need to ensure that the one 423*0b57cec5SDimitry Andric // selected use happens "before" it. 424*0b57cec5SDimitry Andric if (&OneUse > &Use) 425*0b57cec5SDimitry Andric return false; 426*0b57cec5SDimitry Andric } else { 427*0b57cec5SDimitry Andric // Test that the use is dominated by the one selected use. 428*0b57cec5SDimitry Andric while (!MDT.dominates(OneUseInst, UseInst)) { 429*0b57cec5SDimitry Andric // Actually, dominating is over-conservative. Test that the use would 430*0b57cec5SDimitry Andric // happen after the one selected use in the stack evaluation order. 431*0b57cec5SDimitry Andric // 432*0b57cec5SDimitry Andric // This is needed as a consequence of using implicit local.gets for 433*0b57cec5SDimitry Andric // uses and implicit local.sets for defs. 434*0b57cec5SDimitry Andric if (UseInst->getDesc().getNumDefs() == 0) 435*0b57cec5SDimitry Andric return false; 436*0b57cec5SDimitry Andric const MachineOperand &MO = UseInst->getOperand(0); 437*0b57cec5SDimitry Andric if (!MO.isReg()) 438*0b57cec5SDimitry Andric return false; 439*0b57cec5SDimitry Andric unsigned DefReg = MO.getReg(); 440*0b57cec5SDimitry Andric if (!TargetRegisterInfo::isVirtualRegister(DefReg) || 441*0b57cec5SDimitry Andric !MFI.isVRegStackified(DefReg)) 442*0b57cec5SDimitry Andric return false; 443*0b57cec5SDimitry Andric assert(MRI.hasOneNonDBGUse(DefReg)); 444*0b57cec5SDimitry Andric const MachineOperand &NewUse = *MRI.use_nodbg_begin(DefReg); 445*0b57cec5SDimitry Andric const MachineInstr *NewUseInst = NewUse.getParent(); 446*0b57cec5SDimitry Andric if (NewUseInst == OneUseInst) { 447*0b57cec5SDimitry Andric if (&OneUse > &NewUse) 448*0b57cec5SDimitry Andric return false; 449*0b57cec5SDimitry Andric break; 450*0b57cec5SDimitry Andric } 451*0b57cec5SDimitry Andric UseInst = NewUseInst; 452*0b57cec5SDimitry Andric } 453*0b57cec5SDimitry Andric } 454*0b57cec5SDimitry Andric } 455*0b57cec5SDimitry Andric return true; 456*0b57cec5SDimitry Andric } 457*0b57cec5SDimitry Andric 458*0b57cec5SDimitry Andric /// Get the appropriate tee opcode for the given register class. 459*0b57cec5SDimitry Andric static unsigned getTeeOpcode(const TargetRegisterClass *RC) { 460*0b57cec5SDimitry Andric if (RC == &WebAssembly::I32RegClass) 461*0b57cec5SDimitry Andric return WebAssembly::TEE_I32; 462*0b57cec5SDimitry Andric if (RC == &WebAssembly::I64RegClass) 463*0b57cec5SDimitry Andric return WebAssembly::TEE_I64; 464*0b57cec5SDimitry Andric if (RC == &WebAssembly::F32RegClass) 465*0b57cec5SDimitry Andric return WebAssembly::TEE_F32; 466*0b57cec5SDimitry Andric if (RC == &WebAssembly::F64RegClass) 467*0b57cec5SDimitry Andric return WebAssembly::TEE_F64; 468*0b57cec5SDimitry Andric if (RC == &WebAssembly::V128RegClass) 469*0b57cec5SDimitry Andric return WebAssembly::TEE_V128; 470*0b57cec5SDimitry Andric llvm_unreachable("Unexpected register class"); 471*0b57cec5SDimitry Andric } 472*0b57cec5SDimitry Andric 473*0b57cec5SDimitry Andric // Shrink LI to its uses, cleaning up LI. 474*0b57cec5SDimitry Andric static void shrinkToUses(LiveInterval &LI, LiveIntervals &LIS) { 475*0b57cec5SDimitry Andric if (LIS.shrinkToUses(&LI)) { 476*0b57cec5SDimitry Andric SmallVector<LiveInterval *, 4> SplitLIs; 477*0b57cec5SDimitry Andric LIS.splitSeparateComponents(LI, SplitLIs); 478*0b57cec5SDimitry Andric } 479*0b57cec5SDimitry Andric } 480*0b57cec5SDimitry Andric 481*0b57cec5SDimitry Andric /// A single-use def in the same block with no intervening memory or register 482*0b57cec5SDimitry Andric /// dependencies; move the def down and nest it with the current instruction. 483*0b57cec5SDimitry Andric static MachineInstr *moveForSingleUse(unsigned Reg, MachineOperand &Op, 484*0b57cec5SDimitry Andric MachineInstr *Def, MachineBasicBlock &MBB, 485*0b57cec5SDimitry Andric MachineInstr *Insert, LiveIntervals &LIS, 486*0b57cec5SDimitry Andric WebAssemblyFunctionInfo &MFI, 487*0b57cec5SDimitry Andric MachineRegisterInfo &MRI) { 488*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Move for single use: "; Def->dump()); 489*0b57cec5SDimitry Andric 490*0b57cec5SDimitry Andric WebAssemblyDebugValueManager DefDIs(Def); 491*0b57cec5SDimitry Andric MBB.splice(Insert, &MBB, Def); 492*0b57cec5SDimitry Andric DefDIs.move(Insert); 493*0b57cec5SDimitry Andric LIS.handleMove(*Def); 494*0b57cec5SDimitry Andric 495*0b57cec5SDimitry Andric if (MRI.hasOneDef(Reg) && MRI.hasOneUse(Reg)) { 496*0b57cec5SDimitry Andric // No one else is using this register for anything so we can just stackify 497*0b57cec5SDimitry Andric // it in place. 498*0b57cec5SDimitry Andric MFI.stackifyVReg(Reg); 499*0b57cec5SDimitry Andric } else { 500*0b57cec5SDimitry Andric // The register may have unrelated uses or defs; create a new register for 501*0b57cec5SDimitry Andric // just our one def and use so that we can stackify it. 502*0b57cec5SDimitry Andric unsigned NewReg = MRI.createVirtualRegister(MRI.getRegClass(Reg)); 503*0b57cec5SDimitry Andric Def->getOperand(0).setReg(NewReg); 504*0b57cec5SDimitry Andric Op.setReg(NewReg); 505*0b57cec5SDimitry Andric 506*0b57cec5SDimitry Andric // Tell LiveIntervals about the new register. 507*0b57cec5SDimitry Andric LIS.createAndComputeVirtRegInterval(NewReg); 508*0b57cec5SDimitry Andric 509*0b57cec5SDimitry Andric // Tell LiveIntervals about the changes to the old register. 510*0b57cec5SDimitry Andric LiveInterval &LI = LIS.getInterval(Reg); 511*0b57cec5SDimitry Andric LI.removeSegment(LIS.getInstructionIndex(*Def).getRegSlot(), 512*0b57cec5SDimitry Andric LIS.getInstructionIndex(*Op.getParent()).getRegSlot(), 513*0b57cec5SDimitry Andric /*RemoveDeadValNo=*/true); 514*0b57cec5SDimitry Andric 515*0b57cec5SDimitry Andric MFI.stackifyVReg(NewReg); 516*0b57cec5SDimitry Andric 517*0b57cec5SDimitry Andric DefDIs.updateReg(NewReg); 518*0b57cec5SDimitry Andric 519*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " - Replaced register: "; Def->dump()); 520*0b57cec5SDimitry Andric } 521*0b57cec5SDimitry Andric 522*0b57cec5SDimitry Andric imposeStackOrdering(Def); 523*0b57cec5SDimitry Andric return Def; 524*0b57cec5SDimitry Andric } 525*0b57cec5SDimitry Andric 526*0b57cec5SDimitry Andric /// A trivially cloneable instruction; clone it and nest the new copy with the 527*0b57cec5SDimitry Andric /// current instruction. 528*0b57cec5SDimitry Andric static MachineInstr *rematerializeCheapDef( 529*0b57cec5SDimitry Andric unsigned Reg, MachineOperand &Op, MachineInstr &Def, MachineBasicBlock &MBB, 530*0b57cec5SDimitry Andric MachineBasicBlock::instr_iterator Insert, LiveIntervals &LIS, 531*0b57cec5SDimitry Andric WebAssemblyFunctionInfo &MFI, MachineRegisterInfo &MRI, 532*0b57cec5SDimitry Andric const WebAssemblyInstrInfo *TII, const WebAssemblyRegisterInfo *TRI) { 533*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Rematerializing cheap def: "; Def.dump()); 534*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " - for use in "; Op.getParent()->dump()); 535*0b57cec5SDimitry Andric 536*0b57cec5SDimitry Andric WebAssemblyDebugValueManager DefDIs(&Def); 537*0b57cec5SDimitry Andric 538*0b57cec5SDimitry Andric unsigned NewReg = MRI.createVirtualRegister(MRI.getRegClass(Reg)); 539*0b57cec5SDimitry Andric TII->reMaterialize(MBB, Insert, NewReg, 0, Def, *TRI); 540*0b57cec5SDimitry Andric Op.setReg(NewReg); 541*0b57cec5SDimitry Andric MachineInstr *Clone = &*std::prev(Insert); 542*0b57cec5SDimitry Andric LIS.InsertMachineInstrInMaps(*Clone); 543*0b57cec5SDimitry Andric LIS.createAndComputeVirtRegInterval(NewReg); 544*0b57cec5SDimitry Andric MFI.stackifyVReg(NewReg); 545*0b57cec5SDimitry Andric imposeStackOrdering(Clone); 546*0b57cec5SDimitry Andric 547*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " - Cloned to "; Clone->dump()); 548*0b57cec5SDimitry Andric 549*0b57cec5SDimitry Andric // Shrink the interval. 550*0b57cec5SDimitry Andric bool IsDead = MRI.use_empty(Reg); 551*0b57cec5SDimitry Andric if (!IsDead) { 552*0b57cec5SDimitry Andric LiveInterval &LI = LIS.getInterval(Reg); 553*0b57cec5SDimitry Andric shrinkToUses(LI, LIS); 554*0b57cec5SDimitry Andric IsDead = !LI.liveAt(LIS.getInstructionIndex(Def).getDeadSlot()); 555*0b57cec5SDimitry Andric } 556*0b57cec5SDimitry Andric 557*0b57cec5SDimitry Andric // If that was the last use of the original, delete the original. 558*0b57cec5SDimitry Andric // Move or clone corresponding DBG_VALUEs to the 'Insert' location. 559*0b57cec5SDimitry Andric if (IsDead) { 560*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " - Deleting original\n"); 561*0b57cec5SDimitry Andric SlotIndex Idx = LIS.getInstructionIndex(Def).getRegSlot(); 562*0b57cec5SDimitry Andric LIS.removePhysRegDefAt(WebAssembly::ARGUMENTS, Idx); 563*0b57cec5SDimitry Andric LIS.removeInterval(Reg); 564*0b57cec5SDimitry Andric LIS.RemoveMachineInstrFromMaps(Def); 565*0b57cec5SDimitry Andric Def.eraseFromParent(); 566*0b57cec5SDimitry Andric 567*0b57cec5SDimitry Andric DefDIs.move(&*Insert); 568*0b57cec5SDimitry Andric DefDIs.updateReg(NewReg); 569*0b57cec5SDimitry Andric } else { 570*0b57cec5SDimitry Andric DefDIs.clone(&*Insert, NewReg); 571*0b57cec5SDimitry Andric } 572*0b57cec5SDimitry Andric 573*0b57cec5SDimitry Andric return Clone; 574*0b57cec5SDimitry Andric } 575*0b57cec5SDimitry Andric 576*0b57cec5SDimitry Andric /// A multiple-use def in the same block with no intervening memory or register 577*0b57cec5SDimitry Andric /// dependencies; move the def down, nest it with the current instruction, and 578*0b57cec5SDimitry Andric /// insert a tee to satisfy the rest of the uses. As an illustration, rewrite 579*0b57cec5SDimitry Andric /// this: 580*0b57cec5SDimitry Andric /// 581*0b57cec5SDimitry Andric /// Reg = INST ... // Def 582*0b57cec5SDimitry Andric /// INST ..., Reg, ... // Insert 583*0b57cec5SDimitry Andric /// INST ..., Reg, ... 584*0b57cec5SDimitry Andric /// INST ..., Reg, ... 585*0b57cec5SDimitry Andric /// 586*0b57cec5SDimitry Andric /// to this: 587*0b57cec5SDimitry Andric /// 588*0b57cec5SDimitry Andric /// DefReg = INST ... // Def (to become the new Insert) 589*0b57cec5SDimitry Andric /// TeeReg, Reg = TEE_... DefReg 590*0b57cec5SDimitry Andric /// INST ..., TeeReg, ... // Insert 591*0b57cec5SDimitry Andric /// INST ..., Reg, ... 592*0b57cec5SDimitry Andric /// INST ..., Reg, ... 593*0b57cec5SDimitry Andric /// 594*0b57cec5SDimitry Andric /// with DefReg and TeeReg stackified. This eliminates a local.get from the 595*0b57cec5SDimitry Andric /// resulting code. 596*0b57cec5SDimitry Andric static MachineInstr *moveAndTeeForMultiUse( 597*0b57cec5SDimitry Andric unsigned Reg, MachineOperand &Op, MachineInstr *Def, MachineBasicBlock &MBB, 598*0b57cec5SDimitry Andric MachineInstr *Insert, LiveIntervals &LIS, WebAssemblyFunctionInfo &MFI, 599*0b57cec5SDimitry Andric MachineRegisterInfo &MRI, const WebAssemblyInstrInfo *TII) { 600*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Move and tee for multi-use:"; Def->dump()); 601*0b57cec5SDimitry Andric 602*0b57cec5SDimitry Andric WebAssemblyDebugValueManager DefDIs(Def); 603*0b57cec5SDimitry Andric 604*0b57cec5SDimitry Andric // Move Def into place. 605*0b57cec5SDimitry Andric MBB.splice(Insert, &MBB, Def); 606*0b57cec5SDimitry Andric LIS.handleMove(*Def); 607*0b57cec5SDimitry Andric 608*0b57cec5SDimitry Andric // Create the Tee and attach the registers. 609*0b57cec5SDimitry Andric const auto *RegClass = MRI.getRegClass(Reg); 610*0b57cec5SDimitry Andric unsigned TeeReg = MRI.createVirtualRegister(RegClass); 611*0b57cec5SDimitry Andric unsigned DefReg = MRI.createVirtualRegister(RegClass); 612*0b57cec5SDimitry Andric MachineOperand &DefMO = Def->getOperand(0); 613*0b57cec5SDimitry Andric MachineInstr *Tee = BuildMI(MBB, Insert, Insert->getDebugLoc(), 614*0b57cec5SDimitry Andric TII->get(getTeeOpcode(RegClass)), TeeReg) 615*0b57cec5SDimitry Andric .addReg(Reg, RegState::Define) 616*0b57cec5SDimitry Andric .addReg(DefReg, getUndefRegState(DefMO.isDead())); 617*0b57cec5SDimitry Andric Op.setReg(TeeReg); 618*0b57cec5SDimitry Andric DefMO.setReg(DefReg); 619*0b57cec5SDimitry Andric SlotIndex TeeIdx = LIS.InsertMachineInstrInMaps(*Tee).getRegSlot(); 620*0b57cec5SDimitry Andric SlotIndex DefIdx = LIS.getInstructionIndex(*Def).getRegSlot(); 621*0b57cec5SDimitry Andric 622*0b57cec5SDimitry Andric DefDIs.move(Insert); 623*0b57cec5SDimitry Andric 624*0b57cec5SDimitry Andric // Tell LiveIntervals we moved the original vreg def from Def to Tee. 625*0b57cec5SDimitry Andric LiveInterval &LI = LIS.getInterval(Reg); 626*0b57cec5SDimitry Andric LiveInterval::iterator I = LI.FindSegmentContaining(DefIdx); 627*0b57cec5SDimitry Andric VNInfo *ValNo = LI.getVNInfoAt(DefIdx); 628*0b57cec5SDimitry Andric I->start = TeeIdx; 629*0b57cec5SDimitry Andric ValNo->def = TeeIdx; 630*0b57cec5SDimitry Andric shrinkToUses(LI, LIS); 631*0b57cec5SDimitry Andric 632*0b57cec5SDimitry Andric // Finish stackifying the new regs. 633*0b57cec5SDimitry Andric LIS.createAndComputeVirtRegInterval(TeeReg); 634*0b57cec5SDimitry Andric LIS.createAndComputeVirtRegInterval(DefReg); 635*0b57cec5SDimitry Andric MFI.stackifyVReg(DefReg); 636*0b57cec5SDimitry Andric MFI.stackifyVReg(TeeReg); 637*0b57cec5SDimitry Andric imposeStackOrdering(Def); 638*0b57cec5SDimitry Andric imposeStackOrdering(Tee); 639*0b57cec5SDimitry Andric 640*0b57cec5SDimitry Andric DefDIs.clone(Tee, DefReg); 641*0b57cec5SDimitry Andric DefDIs.clone(Insert, TeeReg); 642*0b57cec5SDimitry Andric 643*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " - Replaced register: "; Def->dump()); 644*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " - Tee instruction: "; Tee->dump()); 645*0b57cec5SDimitry Andric return Def; 646*0b57cec5SDimitry Andric } 647*0b57cec5SDimitry Andric 648*0b57cec5SDimitry Andric namespace { 649*0b57cec5SDimitry Andric /// A stack for walking the tree of instructions being built, visiting the 650*0b57cec5SDimitry Andric /// MachineOperands in DFS order. 651*0b57cec5SDimitry Andric class TreeWalkerState { 652*0b57cec5SDimitry Andric using mop_iterator = MachineInstr::mop_iterator; 653*0b57cec5SDimitry Andric using mop_reverse_iterator = std::reverse_iterator<mop_iterator>; 654*0b57cec5SDimitry Andric using RangeTy = iterator_range<mop_reverse_iterator>; 655*0b57cec5SDimitry Andric SmallVector<RangeTy, 4> Worklist; 656*0b57cec5SDimitry Andric 657*0b57cec5SDimitry Andric public: 658*0b57cec5SDimitry Andric explicit TreeWalkerState(MachineInstr *Insert) { 659*0b57cec5SDimitry Andric const iterator_range<mop_iterator> &Range = Insert->explicit_uses(); 660*0b57cec5SDimitry Andric if (Range.begin() != Range.end()) 661*0b57cec5SDimitry Andric Worklist.push_back(reverse(Range)); 662*0b57cec5SDimitry Andric } 663*0b57cec5SDimitry Andric 664*0b57cec5SDimitry Andric bool done() const { return Worklist.empty(); } 665*0b57cec5SDimitry Andric 666*0b57cec5SDimitry Andric MachineOperand &pop() { 667*0b57cec5SDimitry Andric RangeTy &Range = Worklist.back(); 668*0b57cec5SDimitry Andric MachineOperand &Op = *Range.begin(); 669*0b57cec5SDimitry Andric Range = drop_begin(Range, 1); 670*0b57cec5SDimitry Andric if (Range.begin() == Range.end()) 671*0b57cec5SDimitry Andric Worklist.pop_back(); 672*0b57cec5SDimitry Andric assert((Worklist.empty() || 673*0b57cec5SDimitry Andric Worklist.back().begin() != Worklist.back().end()) && 674*0b57cec5SDimitry Andric "Empty ranges shouldn't remain in the worklist"); 675*0b57cec5SDimitry Andric return Op; 676*0b57cec5SDimitry Andric } 677*0b57cec5SDimitry Andric 678*0b57cec5SDimitry Andric /// Push Instr's operands onto the stack to be visited. 679*0b57cec5SDimitry Andric void pushOperands(MachineInstr *Instr) { 680*0b57cec5SDimitry Andric const iterator_range<mop_iterator> &Range(Instr->explicit_uses()); 681*0b57cec5SDimitry Andric if (Range.begin() != Range.end()) 682*0b57cec5SDimitry Andric Worklist.push_back(reverse(Range)); 683*0b57cec5SDimitry Andric } 684*0b57cec5SDimitry Andric 685*0b57cec5SDimitry Andric /// Some of Instr's operands are on the top of the stack; remove them and 686*0b57cec5SDimitry Andric /// re-insert them starting from the beginning (because we've commuted them). 687*0b57cec5SDimitry Andric void resetTopOperands(MachineInstr *Instr) { 688*0b57cec5SDimitry Andric assert(hasRemainingOperands(Instr) && 689*0b57cec5SDimitry Andric "Reseting operands should only be done when the instruction has " 690*0b57cec5SDimitry Andric "an operand still on the stack"); 691*0b57cec5SDimitry Andric Worklist.back() = reverse(Instr->explicit_uses()); 692*0b57cec5SDimitry Andric } 693*0b57cec5SDimitry Andric 694*0b57cec5SDimitry Andric /// Test whether Instr has operands remaining to be visited at the top of 695*0b57cec5SDimitry Andric /// the stack. 696*0b57cec5SDimitry Andric bool hasRemainingOperands(const MachineInstr *Instr) const { 697*0b57cec5SDimitry Andric if (Worklist.empty()) 698*0b57cec5SDimitry Andric return false; 699*0b57cec5SDimitry Andric const RangeTy &Range = Worklist.back(); 700*0b57cec5SDimitry Andric return Range.begin() != Range.end() && Range.begin()->getParent() == Instr; 701*0b57cec5SDimitry Andric } 702*0b57cec5SDimitry Andric 703*0b57cec5SDimitry Andric /// Test whether the given register is present on the stack, indicating an 704*0b57cec5SDimitry Andric /// operand in the tree that we haven't visited yet. Moving a definition of 705*0b57cec5SDimitry Andric /// Reg to a point in the tree after that would change its value. 706*0b57cec5SDimitry Andric /// 707*0b57cec5SDimitry Andric /// This is needed as a consequence of using implicit local.gets for 708*0b57cec5SDimitry Andric /// uses and implicit local.sets for defs. 709*0b57cec5SDimitry Andric bool isOnStack(unsigned Reg) const { 710*0b57cec5SDimitry Andric for (const RangeTy &Range : Worklist) 711*0b57cec5SDimitry Andric for (const MachineOperand &MO : Range) 712*0b57cec5SDimitry Andric if (MO.isReg() && MO.getReg() == Reg) 713*0b57cec5SDimitry Andric return true; 714*0b57cec5SDimitry Andric return false; 715*0b57cec5SDimitry Andric } 716*0b57cec5SDimitry Andric }; 717*0b57cec5SDimitry Andric 718*0b57cec5SDimitry Andric /// State to keep track of whether commuting is in flight or whether it's been 719*0b57cec5SDimitry Andric /// tried for the current instruction and didn't work. 720*0b57cec5SDimitry Andric class CommutingState { 721*0b57cec5SDimitry Andric /// There are effectively three states: the initial state where we haven't 722*0b57cec5SDimitry Andric /// started commuting anything and we don't know anything yet, the tentative 723*0b57cec5SDimitry Andric /// state where we've commuted the operands of the current instruction and are 724*0b57cec5SDimitry Andric /// revisiting it, and the declined state where we've reverted the operands 725*0b57cec5SDimitry Andric /// back to their original order and will no longer commute it further. 726*0b57cec5SDimitry Andric bool TentativelyCommuting = false; 727*0b57cec5SDimitry Andric bool Declined = false; 728*0b57cec5SDimitry Andric 729*0b57cec5SDimitry Andric /// During the tentative state, these hold the operand indices of the commuted 730*0b57cec5SDimitry Andric /// operands. 731*0b57cec5SDimitry Andric unsigned Operand0, Operand1; 732*0b57cec5SDimitry Andric 733*0b57cec5SDimitry Andric public: 734*0b57cec5SDimitry Andric /// Stackification for an operand was not successful due to ordering 735*0b57cec5SDimitry Andric /// constraints. If possible, and if we haven't already tried it and declined 736*0b57cec5SDimitry Andric /// it, commute Insert's operands and prepare to revisit it. 737*0b57cec5SDimitry Andric void maybeCommute(MachineInstr *Insert, TreeWalkerState &TreeWalker, 738*0b57cec5SDimitry Andric const WebAssemblyInstrInfo *TII) { 739*0b57cec5SDimitry Andric if (TentativelyCommuting) { 740*0b57cec5SDimitry Andric assert(!Declined && 741*0b57cec5SDimitry Andric "Don't decline commuting until you've finished trying it"); 742*0b57cec5SDimitry Andric // Commuting didn't help. Revert it. 743*0b57cec5SDimitry Andric TII->commuteInstruction(*Insert, /*NewMI=*/false, Operand0, Operand1); 744*0b57cec5SDimitry Andric TentativelyCommuting = false; 745*0b57cec5SDimitry Andric Declined = true; 746*0b57cec5SDimitry Andric } else if (!Declined && TreeWalker.hasRemainingOperands(Insert)) { 747*0b57cec5SDimitry Andric Operand0 = TargetInstrInfo::CommuteAnyOperandIndex; 748*0b57cec5SDimitry Andric Operand1 = TargetInstrInfo::CommuteAnyOperandIndex; 749*0b57cec5SDimitry Andric if (TII->findCommutedOpIndices(*Insert, Operand0, Operand1)) { 750*0b57cec5SDimitry Andric // Tentatively commute the operands and try again. 751*0b57cec5SDimitry Andric TII->commuteInstruction(*Insert, /*NewMI=*/false, Operand0, Operand1); 752*0b57cec5SDimitry Andric TreeWalker.resetTopOperands(Insert); 753*0b57cec5SDimitry Andric TentativelyCommuting = true; 754*0b57cec5SDimitry Andric Declined = false; 755*0b57cec5SDimitry Andric } 756*0b57cec5SDimitry Andric } 757*0b57cec5SDimitry Andric } 758*0b57cec5SDimitry Andric 759*0b57cec5SDimitry Andric /// Stackification for some operand was successful. Reset to the default 760*0b57cec5SDimitry Andric /// state. 761*0b57cec5SDimitry Andric void reset() { 762*0b57cec5SDimitry Andric TentativelyCommuting = false; 763*0b57cec5SDimitry Andric Declined = false; 764*0b57cec5SDimitry Andric } 765*0b57cec5SDimitry Andric }; 766*0b57cec5SDimitry Andric } // end anonymous namespace 767*0b57cec5SDimitry Andric 768*0b57cec5SDimitry Andric bool WebAssemblyRegStackify::runOnMachineFunction(MachineFunction &MF) { 769*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "********** Register Stackifying **********\n" 770*0b57cec5SDimitry Andric "********** Function: " 771*0b57cec5SDimitry Andric << MF.getName() << '\n'); 772*0b57cec5SDimitry Andric 773*0b57cec5SDimitry Andric bool Changed = false; 774*0b57cec5SDimitry Andric MachineRegisterInfo &MRI = MF.getRegInfo(); 775*0b57cec5SDimitry Andric WebAssemblyFunctionInfo &MFI = *MF.getInfo<WebAssemblyFunctionInfo>(); 776*0b57cec5SDimitry Andric const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 777*0b57cec5SDimitry Andric const auto *TRI = MF.getSubtarget<WebAssemblySubtarget>().getRegisterInfo(); 778*0b57cec5SDimitry Andric AliasAnalysis &AA = getAnalysis<AAResultsWrapperPass>().getAAResults(); 779*0b57cec5SDimitry Andric auto &MDT = getAnalysis<MachineDominatorTree>(); 780*0b57cec5SDimitry Andric auto &LIS = getAnalysis<LiveIntervals>(); 781*0b57cec5SDimitry Andric 782*0b57cec5SDimitry Andric // Walk the instructions from the bottom up. Currently we don't look past 783*0b57cec5SDimitry Andric // block boundaries, and the blocks aren't ordered so the block visitation 784*0b57cec5SDimitry Andric // order isn't significant, but we may want to change this in the future. 785*0b57cec5SDimitry Andric for (MachineBasicBlock &MBB : MF) { 786*0b57cec5SDimitry Andric // Don't use a range-based for loop, because we modify the list as we're 787*0b57cec5SDimitry Andric // iterating over it and the end iterator may change. 788*0b57cec5SDimitry Andric for (auto MII = MBB.rbegin(); MII != MBB.rend(); ++MII) { 789*0b57cec5SDimitry Andric MachineInstr *Insert = &*MII; 790*0b57cec5SDimitry Andric // Don't nest anything inside an inline asm, because we don't have 791*0b57cec5SDimitry Andric // constraints for $push inputs. 792*0b57cec5SDimitry Andric if (Insert->isInlineAsm()) 793*0b57cec5SDimitry Andric continue; 794*0b57cec5SDimitry Andric 795*0b57cec5SDimitry Andric // Ignore debugging intrinsics. 796*0b57cec5SDimitry Andric if (Insert->isDebugValue()) 797*0b57cec5SDimitry Andric continue; 798*0b57cec5SDimitry Andric 799*0b57cec5SDimitry Andric // Iterate through the inputs in reverse order, since we'll be pulling 800*0b57cec5SDimitry Andric // operands off the stack in LIFO order. 801*0b57cec5SDimitry Andric CommutingState Commuting; 802*0b57cec5SDimitry Andric TreeWalkerState TreeWalker(Insert); 803*0b57cec5SDimitry Andric while (!TreeWalker.done()) { 804*0b57cec5SDimitry Andric MachineOperand &Op = TreeWalker.pop(); 805*0b57cec5SDimitry Andric 806*0b57cec5SDimitry Andric // We're only interested in explicit virtual register operands. 807*0b57cec5SDimitry Andric if (!Op.isReg()) 808*0b57cec5SDimitry Andric continue; 809*0b57cec5SDimitry Andric 810*0b57cec5SDimitry Andric unsigned Reg = Op.getReg(); 811*0b57cec5SDimitry Andric assert(Op.isUse() && "explicit_uses() should only iterate over uses"); 812*0b57cec5SDimitry Andric assert(!Op.isImplicit() && 813*0b57cec5SDimitry Andric "explicit_uses() should only iterate over explicit operands"); 814*0b57cec5SDimitry Andric if (TargetRegisterInfo::isPhysicalRegister(Reg)) 815*0b57cec5SDimitry Andric continue; 816*0b57cec5SDimitry Andric 817*0b57cec5SDimitry Andric // Identify the definition for this register at this point. 818*0b57cec5SDimitry Andric MachineInstr *Def = getVRegDef(Reg, Insert, MRI, LIS); 819*0b57cec5SDimitry Andric if (!Def) 820*0b57cec5SDimitry Andric continue; 821*0b57cec5SDimitry Andric 822*0b57cec5SDimitry Andric // Don't nest an INLINE_ASM def into anything, because we don't have 823*0b57cec5SDimitry Andric // constraints for $pop outputs. 824*0b57cec5SDimitry Andric if (Def->isInlineAsm()) 825*0b57cec5SDimitry Andric continue; 826*0b57cec5SDimitry Andric 827*0b57cec5SDimitry Andric // Argument instructions represent live-in registers and not real 828*0b57cec5SDimitry Andric // instructions. 829*0b57cec5SDimitry Andric if (WebAssembly::isArgument(Def->getOpcode())) 830*0b57cec5SDimitry Andric continue; 831*0b57cec5SDimitry Andric 832*0b57cec5SDimitry Andric // Currently catch's return value register cannot be stackified, because 833*0b57cec5SDimitry Andric // the wasm LLVM backend currently does not support live-in values 834*0b57cec5SDimitry Andric // entering blocks, which is a part of multi-value proposal. 835*0b57cec5SDimitry Andric // 836*0b57cec5SDimitry Andric // Once we support live-in values of wasm blocks, this can be: 837*0b57cec5SDimitry Andric // catch ; push exnref value onto stack 838*0b57cec5SDimitry Andric // block exnref -> i32 839*0b57cec5SDimitry Andric // br_on_exn $__cpp_exception ; pop the exnref value 840*0b57cec5SDimitry Andric // end_block 841*0b57cec5SDimitry Andric // 842*0b57cec5SDimitry Andric // But because we don't support it yet, the catch instruction's dst 843*0b57cec5SDimitry Andric // register should be assigned to a local to be propagated across 844*0b57cec5SDimitry Andric // 'block' boundary now. 845*0b57cec5SDimitry Andric // 846*0b57cec5SDimitry Andric // TODO Fix this once we support the multi-value proposal. 847*0b57cec5SDimitry Andric if (Def->getOpcode() == WebAssembly::CATCH) 848*0b57cec5SDimitry Andric continue; 849*0b57cec5SDimitry Andric 850*0b57cec5SDimitry Andric // Decide which strategy to take. Prefer to move a single-use value 851*0b57cec5SDimitry Andric // over cloning it, and prefer cloning over introducing a tee. 852*0b57cec5SDimitry Andric // For moving, we require the def to be in the same block as the use; 853*0b57cec5SDimitry Andric // this makes things simpler (LiveIntervals' handleMove function only 854*0b57cec5SDimitry Andric // supports intra-block moves) and it's MachineSink's job to catch all 855*0b57cec5SDimitry Andric // the sinking opportunities anyway. 856*0b57cec5SDimitry Andric bool SameBlock = Def->getParent() == &MBB; 857*0b57cec5SDimitry Andric bool CanMove = SameBlock && isSafeToMove(Def, Insert, AA, MRI) && 858*0b57cec5SDimitry Andric !TreeWalker.isOnStack(Reg); 859*0b57cec5SDimitry Andric if (CanMove && hasOneUse(Reg, Def, MRI, MDT, LIS)) { 860*0b57cec5SDimitry Andric Insert = moveForSingleUse(Reg, Op, Def, MBB, Insert, LIS, MFI, MRI); 861*0b57cec5SDimitry Andric } else if (shouldRematerialize(*Def, AA, TII)) { 862*0b57cec5SDimitry Andric Insert = 863*0b57cec5SDimitry Andric rematerializeCheapDef(Reg, Op, *Def, MBB, Insert->getIterator(), 864*0b57cec5SDimitry Andric LIS, MFI, MRI, TII, TRI); 865*0b57cec5SDimitry Andric } else if (CanMove && 866*0b57cec5SDimitry Andric oneUseDominatesOtherUses(Reg, Op, MBB, MRI, MDT, LIS, MFI)) { 867*0b57cec5SDimitry Andric Insert = moveAndTeeForMultiUse(Reg, Op, Def, MBB, Insert, LIS, MFI, 868*0b57cec5SDimitry Andric MRI, TII); 869*0b57cec5SDimitry Andric } else { 870*0b57cec5SDimitry Andric // We failed to stackify the operand. If the problem was ordering 871*0b57cec5SDimitry Andric // constraints, Commuting may be able to help. 872*0b57cec5SDimitry Andric if (!CanMove && SameBlock) 873*0b57cec5SDimitry Andric Commuting.maybeCommute(Insert, TreeWalker, TII); 874*0b57cec5SDimitry Andric // Proceed to the next operand. 875*0b57cec5SDimitry Andric continue; 876*0b57cec5SDimitry Andric } 877*0b57cec5SDimitry Andric 878*0b57cec5SDimitry Andric // If the instruction we just stackified is an IMPLICIT_DEF, convert it 879*0b57cec5SDimitry Andric // to a constant 0 so that the def is explicit, and the push/pop 880*0b57cec5SDimitry Andric // correspondence is maintained. 881*0b57cec5SDimitry Andric if (Insert->getOpcode() == TargetOpcode::IMPLICIT_DEF) 882*0b57cec5SDimitry Andric convertImplicitDefToConstZero(Insert, MRI, TII, MF, LIS); 883*0b57cec5SDimitry Andric 884*0b57cec5SDimitry Andric // We stackified an operand. Add the defining instruction's operands to 885*0b57cec5SDimitry Andric // the worklist stack now to continue to build an ever deeper tree. 886*0b57cec5SDimitry Andric Commuting.reset(); 887*0b57cec5SDimitry Andric TreeWalker.pushOperands(Insert); 888*0b57cec5SDimitry Andric } 889*0b57cec5SDimitry Andric 890*0b57cec5SDimitry Andric // If we stackified any operands, skip over the tree to start looking for 891*0b57cec5SDimitry Andric // the next instruction we can build a tree on. 892*0b57cec5SDimitry Andric if (Insert != &*MII) { 893*0b57cec5SDimitry Andric imposeStackOrdering(&*MII); 894*0b57cec5SDimitry Andric MII = MachineBasicBlock::iterator(Insert).getReverse(); 895*0b57cec5SDimitry Andric Changed = true; 896*0b57cec5SDimitry Andric } 897*0b57cec5SDimitry Andric } 898*0b57cec5SDimitry Andric } 899*0b57cec5SDimitry Andric 900*0b57cec5SDimitry Andric // If we used VALUE_STACK anywhere, add it to the live-in sets everywhere so 901*0b57cec5SDimitry Andric // that it never looks like a use-before-def. 902*0b57cec5SDimitry Andric if (Changed) { 903*0b57cec5SDimitry Andric MF.getRegInfo().addLiveIn(WebAssembly::VALUE_STACK); 904*0b57cec5SDimitry Andric for (MachineBasicBlock &MBB : MF) 905*0b57cec5SDimitry Andric MBB.addLiveIn(WebAssembly::VALUE_STACK); 906*0b57cec5SDimitry Andric } 907*0b57cec5SDimitry Andric 908*0b57cec5SDimitry Andric #ifndef NDEBUG 909*0b57cec5SDimitry Andric // Verify that pushes and pops are performed in LIFO order. 910*0b57cec5SDimitry Andric SmallVector<unsigned, 0> Stack; 911*0b57cec5SDimitry Andric for (MachineBasicBlock &MBB : MF) { 912*0b57cec5SDimitry Andric for (MachineInstr &MI : MBB) { 913*0b57cec5SDimitry Andric if (MI.isDebugInstr()) 914*0b57cec5SDimitry Andric continue; 915*0b57cec5SDimitry Andric for (MachineOperand &MO : reverse(MI.explicit_operands())) { 916*0b57cec5SDimitry Andric if (!MO.isReg()) 917*0b57cec5SDimitry Andric continue; 918*0b57cec5SDimitry Andric unsigned Reg = MO.getReg(); 919*0b57cec5SDimitry Andric 920*0b57cec5SDimitry Andric if (MFI.isVRegStackified(Reg)) { 921*0b57cec5SDimitry Andric if (MO.isDef()) 922*0b57cec5SDimitry Andric Stack.push_back(Reg); 923*0b57cec5SDimitry Andric else 924*0b57cec5SDimitry Andric assert(Stack.pop_back_val() == Reg && 925*0b57cec5SDimitry Andric "Register stack pop should be paired with a push"); 926*0b57cec5SDimitry Andric } 927*0b57cec5SDimitry Andric } 928*0b57cec5SDimitry Andric } 929*0b57cec5SDimitry Andric // TODO: Generalize this code to support keeping values on the stack across 930*0b57cec5SDimitry Andric // basic block boundaries. 931*0b57cec5SDimitry Andric assert(Stack.empty() && 932*0b57cec5SDimitry Andric "Register stack pushes and pops should be balanced"); 933*0b57cec5SDimitry Andric } 934*0b57cec5SDimitry Andric #endif 935*0b57cec5SDimitry Andric 936*0b57cec5SDimitry Andric return Changed; 937*0b57cec5SDimitry Andric } 938