11462faadSDan Gohman //===-- WebAssemblyRegStackify.cpp - Register Stackification --------------===// 21462faadSDan Gohman // 31462faadSDan Gohman // The LLVM Compiler Infrastructure 41462faadSDan Gohman // 51462faadSDan Gohman // This file is distributed under the University of Illinois Open Source 61462faadSDan Gohman // License. See LICENSE.TXT for details. 71462faadSDan Gohman // 81462faadSDan Gohman //===----------------------------------------------------------------------===// 91462faadSDan Gohman /// 101462faadSDan Gohman /// \file 111462faadSDan Gohman /// \brief This file implements a register stacking pass. 121462faadSDan Gohman /// 131462faadSDan Gohman /// This pass reorders instructions to put register uses and defs in an order 141462faadSDan Gohman /// such that they form single-use expression trees. Registers fitting this form 151462faadSDan Gohman /// are then marked as "stackified", meaning references to them are replaced by 161462faadSDan Gohman /// "push" and "pop" from the stack. 171462faadSDan Gohman /// 1831448f16SDan Gohman /// This is primarily a code size optimization, since temporary values on the 191462faadSDan Gohman /// expression don't need to be named. 201462faadSDan Gohman /// 211462faadSDan Gohman //===----------------------------------------------------------------------===// 221462faadSDan Gohman 231462faadSDan Gohman #include "WebAssembly.h" 244ba4816bSDan Gohman #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" // for WebAssembly::ARGUMENT_* 257a6b9825SDan Gohman #include "WebAssemblyMachineFunctionInfo.h" 26b6fd39a3SDan Gohman #include "WebAssemblySubtarget.h" 2781719f85SDan Gohman #include "llvm/Analysis/AliasAnalysis.h" 288887d1faSDan Gohman #include "llvm/CodeGen/LiveIntervalAnalysis.h" 291462faadSDan Gohman #include "llvm/CodeGen/MachineBlockFrequencyInfo.h" 30adf28177SDan Gohman #include "llvm/CodeGen/MachineDominators.h" 31adf28177SDan Gohman #include "llvm/CodeGen/MachineInstrBuilder.h" 321462faadSDan Gohman #include "llvm/CodeGen/MachineRegisterInfo.h" 331462faadSDan Gohman #include "llvm/CodeGen/Passes.h" 341462faadSDan Gohman #include "llvm/Support/Debug.h" 351462faadSDan Gohman #include "llvm/Support/raw_ostream.h" 361462faadSDan Gohman using namespace llvm; 371462faadSDan Gohman 381462faadSDan Gohman #define DEBUG_TYPE "wasm-reg-stackify" 391462faadSDan Gohman 401462faadSDan Gohman namespace { 411462faadSDan Gohman class WebAssemblyRegStackify final : public MachineFunctionPass { 421462faadSDan Gohman const char *getPassName() const override { 431462faadSDan Gohman return "WebAssembly Register Stackify"; 441462faadSDan Gohman } 451462faadSDan Gohman 461462faadSDan Gohman void getAnalysisUsage(AnalysisUsage &AU) const override { 471462faadSDan Gohman AU.setPreservesCFG(); 4881719f85SDan Gohman AU.addRequired<AAResultsWrapperPass>(); 49adf28177SDan Gohman AU.addRequired<MachineDominatorTree>(); 508887d1faSDan Gohman AU.addRequired<LiveIntervals>(); 511462faadSDan Gohman AU.addPreserved<MachineBlockFrequencyInfo>(); 528887d1faSDan Gohman AU.addPreserved<SlotIndexes>(); 538887d1faSDan Gohman AU.addPreserved<LiveIntervals>(); 548887d1faSDan Gohman AU.addPreservedID(LiveVariablesID); 55adf28177SDan Gohman AU.addPreserved<MachineDominatorTree>(); 561462faadSDan Gohman MachineFunctionPass::getAnalysisUsage(AU); 571462faadSDan Gohman } 581462faadSDan Gohman 591462faadSDan Gohman bool runOnMachineFunction(MachineFunction &MF) override; 601462faadSDan Gohman 611462faadSDan Gohman public: 621462faadSDan Gohman static char ID; // Pass identification, replacement for typeid 631462faadSDan Gohman WebAssemblyRegStackify() : MachineFunctionPass(ID) {} 641462faadSDan Gohman }; 651462faadSDan Gohman } // end anonymous namespace 661462faadSDan Gohman 671462faadSDan Gohman char WebAssemblyRegStackify::ID = 0; 681462faadSDan Gohman FunctionPass *llvm::createWebAssemblyRegStackify() { 691462faadSDan Gohman return new WebAssemblyRegStackify(); 701462faadSDan Gohman } 711462faadSDan Gohman 72b0992dafSDan Gohman // Decorate the given instruction with implicit operands that enforce the 738887d1faSDan Gohman // expression stack ordering constraints for an instruction which is on 748887d1faSDan Gohman // the expression stack. 758887d1faSDan Gohman static void ImposeStackOrdering(MachineInstr *MI) { 764da4abd8SDan Gohman // Write the opaque EXPR_STACK register. 774da4abd8SDan Gohman if (!MI->definesRegister(WebAssembly::EXPR_STACK)) 78b0992dafSDan Gohman MI->addOperand(MachineOperand::CreateReg(WebAssembly::EXPR_STACK, 79b0992dafSDan Gohman /*isDef=*/true, 80b0992dafSDan Gohman /*isImp=*/true)); 814da4abd8SDan Gohman 824da4abd8SDan Gohman // Also read the opaque EXPR_STACK register. 83a712a6c4SDan Gohman if (!MI->readsRegister(WebAssembly::EXPR_STACK)) 84b0992dafSDan Gohman MI->addOperand(MachineOperand::CreateReg(WebAssembly::EXPR_STACK, 85b0992dafSDan Gohman /*isDef=*/false, 86b0992dafSDan Gohman /*isImp=*/true)); 87b0992dafSDan Gohman } 88b0992dafSDan Gohman 898887d1faSDan Gohman // Test whether it's safe to move Def to just before Insert. 9081719f85SDan Gohman // TODO: Compute memory dependencies in a way that doesn't require always 9181719f85SDan Gohman // walking the block. 9281719f85SDan Gohman // TODO: Compute memory dependencies in a way that uses AliasAnalysis to be 9381719f85SDan Gohman // more precise. 9481719f85SDan Gohman static bool IsSafeToMove(const MachineInstr *Def, const MachineInstr *Insert, 95adf28177SDan Gohman AliasAnalysis &AA, const LiveIntervals &LIS, 96adf28177SDan Gohman const MachineRegisterInfo &MRI) { 97391a98afSDan Gohman assert(Def->getParent() == Insert->getParent()); 9881719f85SDan Gohman bool SawStore = false, SawSideEffects = false; 9981719f85SDan Gohman MachineBasicBlock::const_iterator D(Def), I(Insert); 1008887d1faSDan Gohman 1018887d1faSDan Gohman // Check for register dependencies. 1028887d1faSDan Gohman for (const MachineOperand &MO : Def->operands()) { 1038887d1faSDan Gohman if (!MO.isReg() || MO.isUndef()) 1048887d1faSDan Gohman continue; 1058887d1faSDan Gohman unsigned Reg = MO.getReg(); 1068887d1faSDan Gohman 1078887d1faSDan Gohman // If the register is dead here and at Insert, ignore it. 1088887d1faSDan Gohman if (MO.isDead() && Insert->definesRegister(Reg) && 1098887d1faSDan Gohman !Insert->readsRegister(Reg)) 1108887d1faSDan Gohman continue; 1118887d1faSDan Gohman 1128887d1faSDan Gohman if (TargetRegisterInfo::isPhysicalRegister(Reg)) { 1138887d1faSDan Gohman // If the physical register is never modified, ignore it. 1148887d1faSDan Gohman if (!MRI.isPhysRegModified(Reg)) 1158887d1faSDan Gohman continue; 1168887d1faSDan Gohman // Otherwise, it's a physical register with unknown liveness. 1178887d1faSDan Gohman return false; 1188887d1faSDan Gohman } 1198887d1faSDan Gohman 1208887d1faSDan Gohman // Ask LiveIntervals whether moving this virtual register use or def to 1218887d1faSDan Gohman // Insert will change value numbers are seen. 1228887d1faSDan Gohman const LiveInterval &LI = LIS.getInterval(Reg); 123b6fd39a3SDan Gohman VNInfo *DefVNI = 12413d3b9b7SJF Bastien MO.isDef() ? LI.getVNInfoAt(LIS.getInstructionIndex(*Def).getRegSlot()) 12513d3b9b7SJF Bastien : LI.getVNInfoBefore(LIS.getInstructionIndex(*Def)); 1268887d1faSDan Gohman assert(DefVNI && "Instruction input missing value number"); 12713d3b9b7SJF Bastien VNInfo *InsVNI = LI.getVNInfoBefore(LIS.getInstructionIndex(*Insert)); 1288887d1faSDan Gohman if (InsVNI && DefVNI != InsVNI) 1298887d1faSDan Gohman return false; 1308887d1faSDan Gohman } 1318887d1faSDan Gohman 132f8f8f093SDerek Schuff SawStore = Def->isCall() || Def->mayStore(); 1338887d1faSDan Gohman // Check for memory dependencies and side effects. 13481719f85SDan Gohman for (--I; I != D; --I) 1357e64917fSDan Gohman SawSideEffects |= !I->isSafeToMove(&AA, SawStore); 13681719f85SDan Gohman return !(SawStore && Def->mayLoad() && !Def->isInvariantLoad(&AA)) && 13781719f85SDan Gohman !(SawSideEffects && !Def->isSafeToMove(&AA, SawStore)); 13881719f85SDan Gohman } 13981719f85SDan Gohman 140adf28177SDan Gohman /// Test whether OneUse, a use of Reg, dominates all of Reg's other uses. 141adf28177SDan Gohman static bool OneUseDominatesOtherUses(unsigned Reg, const MachineOperand &OneUse, 142adf28177SDan Gohman const MachineBasicBlock &MBB, 143adf28177SDan Gohman const MachineRegisterInfo &MRI, 144adf28177SDan Gohman const MachineDominatorTree &MDT) { 145adf28177SDan Gohman for (const MachineOperand &Use : MRI.use_operands(Reg)) { 146adf28177SDan Gohman if (&Use == &OneUse) 147adf28177SDan Gohman continue; 148adf28177SDan Gohman const MachineInstr *UseInst = Use.getParent(); 149adf28177SDan Gohman const MachineInstr *OneUseInst = OneUse.getParent(); 150adf28177SDan Gohman if (UseInst->getOpcode() == TargetOpcode::PHI) { 151adf28177SDan Gohman // Test that the PHI use, which happens on the CFG edge rather than 152adf28177SDan Gohman // within the PHI's own block, is dominated by the one selected use. 153adf28177SDan Gohman const MachineBasicBlock *Pred = 154adf28177SDan Gohman UseInst->getOperand(&Use - &UseInst->getOperand(0) + 1).getMBB(); 155adf28177SDan Gohman if (!MDT.dominates(&MBB, Pred)) 156adf28177SDan Gohman return false; 157adf28177SDan Gohman } else if (UseInst == OneUseInst) { 158adf28177SDan Gohman // Another use in the same instruction. We need to ensure that the one 159adf28177SDan Gohman // selected use happens "before" it. 160adf28177SDan Gohman if (&OneUse > &Use) 161adf28177SDan Gohman return false; 162adf28177SDan Gohman } else { 163adf28177SDan Gohman // Test that the use is dominated by the one selected use. 164adf28177SDan Gohman if (!MDT.dominates(OneUseInst, UseInst)) 165adf28177SDan Gohman return false; 166adf28177SDan Gohman } 167adf28177SDan Gohman } 168adf28177SDan Gohman return true; 169adf28177SDan Gohman } 170adf28177SDan Gohman 171adf28177SDan Gohman /// Get the appropriate tee_local opcode for the given register class. 172adf28177SDan Gohman static unsigned GetTeeLocalOpcode(const TargetRegisterClass *RC) { 173adf28177SDan Gohman if (RC == &WebAssembly::I32RegClass) 174adf28177SDan Gohman return WebAssembly::TEE_LOCAL_I32; 175adf28177SDan Gohman if (RC == &WebAssembly::I64RegClass) 176adf28177SDan Gohman return WebAssembly::TEE_LOCAL_I64; 177adf28177SDan Gohman if (RC == &WebAssembly::F32RegClass) 178adf28177SDan Gohman return WebAssembly::TEE_LOCAL_F32; 179adf28177SDan Gohman if (RC == &WebAssembly::F64RegClass) 180adf28177SDan Gohman return WebAssembly::TEE_LOCAL_F64; 181adf28177SDan Gohman llvm_unreachable("Unexpected register class"); 182adf28177SDan Gohman } 183adf28177SDan Gohman 184adf28177SDan Gohman /// A single-use def in the same block with no intervening memory or register 185adf28177SDan Gohman /// dependencies; move the def down and nest it with the current instruction. 186adf28177SDan Gohman static MachineInstr *MoveForSingleUse(unsigned Reg, MachineInstr *Def, 187adf28177SDan Gohman MachineBasicBlock &MBB, 188adf28177SDan Gohman MachineInstr *Insert, LiveIntervals &LIS, 189adf28177SDan Gohman WebAssemblyFunctionInfo &MFI) { 190adf28177SDan Gohman MBB.splice(Insert, &MBB, Def); 1911afd1e2bSJF Bastien LIS.handleMove(*Def); 192adf28177SDan Gohman MFI.stackifyVReg(Reg); 193adf28177SDan Gohman ImposeStackOrdering(Def); 194adf28177SDan Gohman return Def; 195adf28177SDan Gohman } 196adf28177SDan Gohman 197adf28177SDan Gohman /// A trivially cloneable instruction; clone it and nest the new copy with the 198adf28177SDan Gohman /// current instruction. 199adf28177SDan Gohman static MachineInstr * 200adf28177SDan Gohman RematerializeCheapDef(unsigned Reg, MachineOperand &Op, MachineInstr *Def, 201adf28177SDan Gohman MachineBasicBlock &MBB, MachineInstr *Insert, 202adf28177SDan Gohman LiveIntervals &LIS, WebAssemblyFunctionInfo &MFI, 203adf28177SDan Gohman MachineRegisterInfo &MRI, const WebAssemblyInstrInfo *TII, 204adf28177SDan Gohman const WebAssemblyRegisterInfo *TRI) { 205adf28177SDan Gohman unsigned NewReg = MRI.createVirtualRegister(MRI.getRegClass(Reg)); 206adf28177SDan Gohman TII->reMaterialize(MBB, Insert, NewReg, 0, Def, *TRI); 207adf28177SDan Gohman Op.setReg(NewReg); 208adf28177SDan Gohman MachineInstr *Clone = &*std::prev(MachineBasicBlock::instr_iterator(Insert)); 20913d3b9b7SJF Bastien LIS.InsertMachineInstrInMaps(*Clone); 210adf28177SDan Gohman LIS.createAndComputeVirtRegInterval(NewReg); 211adf28177SDan Gohman MFI.stackifyVReg(NewReg); 212adf28177SDan Gohman ImposeStackOrdering(Clone); 213adf28177SDan Gohman 214adf28177SDan Gohman // If that was the last use of the original, delete the original. 215adf28177SDan Gohman // Otherwise shrink the LiveInterval. 216adf28177SDan Gohman if (MRI.use_empty(Reg)) { 21713d3b9b7SJF Bastien SlotIndex Idx = LIS.getInstructionIndex(*Def).getRegSlot(); 218adf28177SDan Gohman LIS.removePhysRegDefAt(WebAssembly::ARGUMENTS, Idx); 219adf28177SDan Gohman LIS.removeVRegDefAt(LIS.getInterval(Reg), Idx); 220adf28177SDan Gohman LIS.removeInterval(Reg); 22113d3b9b7SJF Bastien LIS.RemoveMachineInstrFromMaps(*Def); 222adf28177SDan Gohman Def->eraseFromParent(); 223adf28177SDan Gohman } else { 224adf28177SDan Gohman LIS.shrinkToUses(&LIS.getInterval(Reg)); 225adf28177SDan Gohman } 226adf28177SDan Gohman return Clone; 227adf28177SDan Gohman } 228adf28177SDan Gohman 229adf28177SDan Gohman /// A multiple-use def in the same block with no intervening memory or register 230adf28177SDan Gohman /// dependencies; move the def down, nest it with the current instruction, and 231adf28177SDan Gohman /// insert a tee_local to satisfy the rest of the uses. As an illustration, 232adf28177SDan Gohman /// rewrite this: 233adf28177SDan Gohman /// 234adf28177SDan Gohman /// Reg = INST ... // Def 235adf28177SDan Gohman /// INST ..., Reg, ... // Insert 236adf28177SDan Gohman /// INST ..., Reg, ... 237adf28177SDan Gohman /// INST ..., Reg, ... 238adf28177SDan Gohman /// 239adf28177SDan Gohman /// to this: 240adf28177SDan Gohman /// 2418aa237c3SDan Gohman /// DefReg = INST ... // Def (to become the new Insert) 2428aa237c3SDan Gohman /// TeeReg, NewReg = TEE_LOCAL_... DefReg 243adf28177SDan Gohman /// INST ..., TeeReg, ... // Insert 244adf28177SDan Gohman /// INST ..., NewReg, ... 245adf28177SDan Gohman /// INST ..., NewReg, ... 246adf28177SDan Gohman /// 2478aa237c3SDan Gohman /// with DefReg and TeeReg stackified. This eliminates a get_local from the 248adf28177SDan Gohman /// resulting code. 249adf28177SDan Gohman static MachineInstr *MoveAndTeeForMultiUse( 250adf28177SDan Gohman unsigned Reg, MachineOperand &Op, MachineInstr *Def, MachineBasicBlock &MBB, 251adf28177SDan Gohman MachineInstr *Insert, LiveIntervals &LIS, WebAssemblyFunctionInfo &MFI, 252adf28177SDan Gohman MachineRegisterInfo &MRI, const WebAssemblyInstrInfo *TII) { 253adf28177SDan Gohman MBB.splice(Insert, &MBB, Def); 2541afd1e2bSJF Bastien LIS.handleMove(*Def); 255adf28177SDan Gohman const auto *RegClass = MRI.getRegClass(Reg); 256adf28177SDan Gohman unsigned NewReg = MRI.createVirtualRegister(RegClass); 257adf28177SDan Gohman unsigned TeeReg = MRI.createVirtualRegister(RegClass); 2588aa237c3SDan Gohman unsigned DefReg = MRI.createVirtualRegister(RegClass); 259adf28177SDan Gohman MRI.replaceRegWith(Reg, NewReg); 260adf28177SDan Gohman MachineInstr *Tee = BuildMI(MBB, Insert, Insert->getDebugLoc(), 261adf28177SDan Gohman TII->get(GetTeeLocalOpcode(RegClass)), TeeReg) 262adf28177SDan Gohman .addReg(NewReg, RegState::Define) 2638aa237c3SDan Gohman .addReg(DefReg); 264adf28177SDan Gohman Op.setReg(TeeReg); 2658aa237c3SDan Gohman Def->getOperand(0).setReg(DefReg); 26613d3b9b7SJF Bastien LIS.InsertMachineInstrInMaps(*Tee); 2678aa237c3SDan Gohman LIS.removeInterval(Reg); 268adf28177SDan Gohman LIS.createAndComputeVirtRegInterval(NewReg); 269adf28177SDan Gohman LIS.createAndComputeVirtRegInterval(TeeReg); 2708aa237c3SDan Gohman LIS.createAndComputeVirtRegInterval(DefReg); 2718aa237c3SDan Gohman MFI.stackifyVReg(DefReg); 272adf28177SDan Gohman MFI.stackifyVReg(TeeReg); 273adf28177SDan Gohman ImposeStackOrdering(Def); 274adf28177SDan Gohman ImposeStackOrdering(Tee); 275adf28177SDan Gohman return Def; 276adf28177SDan Gohman } 277adf28177SDan Gohman 278adf28177SDan Gohman namespace { 279adf28177SDan Gohman /// A stack for walking the tree of instructions being built, visiting the 280adf28177SDan Gohman /// MachineOperands in DFS order. 281adf28177SDan Gohman class TreeWalkerState { 282adf28177SDan Gohman typedef MachineInstr::mop_iterator mop_iterator; 283adf28177SDan Gohman typedef std::reverse_iterator<mop_iterator> mop_reverse_iterator; 284adf28177SDan Gohman typedef iterator_range<mop_reverse_iterator> RangeTy; 285adf28177SDan Gohman SmallVector<RangeTy, 4> Worklist; 286adf28177SDan Gohman 287adf28177SDan Gohman public: 288adf28177SDan Gohman explicit TreeWalkerState(MachineInstr *Insert) { 289adf28177SDan Gohman const iterator_range<mop_iterator> &Range = Insert->explicit_uses(); 290adf28177SDan Gohman if (Range.begin() != Range.end()) 291adf28177SDan Gohman Worklist.push_back(reverse(Range)); 292adf28177SDan Gohman } 293adf28177SDan Gohman 294adf28177SDan Gohman bool Done() const { return Worklist.empty(); } 295adf28177SDan Gohman 296adf28177SDan Gohman MachineOperand &Pop() { 297adf28177SDan Gohman RangeTy &Range = Worklist.back(); 298adf28177SDan Gohman MachineOperand &Op = *Range.begin(); 299adf28177SDan Gohman Range = drop_begin(Range, 1); 300adf28177SDan Gohman if (Range.begin() == Range.end()) 301adf28177SDan Gohman Worklist.pop_back(); 302adf28177SDan Gohman assert((Worklist.empty() || 303adf28177SDan Gohman Worklist.back().begin() != Worklist.back().end()) && 304adf28177SDan Gohman "Empty ranges shouldn't remain in the worklist"); 305adf28177SDan Gohman return Op; 306adf28177SDan Gohman } 307adf28177SDan Gohman 308adf28177SDan Gohman /// Push Instr's operands onto the stack to be visited. 309adf28177SDan Gohman void PushOperands(MachineInstr *Instr) { 310adf28177SDan Gohman const iterator_range<mop_iterator> &Range(Instr->explicit_uses()); 311adf28177SDan Gohman if (Range.begin() != Range.end()) 312adf28177SDan Gohman Worklist.push_back(reverse(Range)); 313adf28177SDan Gohman } 314adf28177SDan Gohman 315adf28177SDan Gohman /// Some of Instr's operands are on the top of the stack; remove them and 316adf28177SDan Gohman /// re-insert them starting from the beginning (because we've commuted them). 317adf28177SDan Gohman void ResetTopOperands(MachineInstr *Instr) { 318adf28177SDan Gohman assert(HasRemainingOperands(Instr) && 319adf28177SDan Gohman "Reseting operands should only be done when the instruction has " 320adf28177SDan Gohman "an operand still on the stack"); 321adf28177SDan Gohman Worklist.back() = reverse(Instr->explicit_uses()); 322adf28177SDan Gohman } 323adf28177SDan Gohman 324adf28177SDan Gohman /// Test whether Instr has operands remaining to be visited at the top of 325adf28177SDan Gohman /// the stack. 326adf28177SDan Gohman bool HasRemainingOperands(const MachineInstr *Instr) const { 327adf28177SDan Gohman if (Worklist.empty()) 328adf28177SDan Gohman return false; 329adf28177SDan Gohman const RangeTy &Range = Worklist.back(); 330adf28177SDan Gohman return Range.begin() != Range.end() && Range.begin()->getParent() == Instr; 331adf28177SDan Gohman } 332fbfe5ec4SDan Gohman 333fbfe5ec4SDan Gohman /// Test whether the given register is present on the stack, indicating an 334fbfe5ec4SDan Gohman /// operand in the tree that we haven't visited yet. Moving a definition of 335fbfe5ec4SDan Gohman /// Reg to a point in the tree after that would change its value. 336fbfe5ec4SDan Gohman bool IsOnStack(unsigned Reg) const { 337fbfe5ec4SDan Gohman for (const RangeTy &Range : Worklist) 338fbfe5ec4SDan Gohman for (const MachineOperand &MO : Range) 339fbfe5ec4SDan Gohman if (MO.isReg() && MO.getReg() == Reg) 340fbfe5ec4SDan Gohman return true; 341fbfe5ec4SDan Gohman return false; 342fbfe5ec4SDan Gohman } 343adf28177SDan Gohman }; 344adf28177SDan Gohman 345adf28177SDan Gohman /// State to keep track of whether commuting is in flight or whether it's been 346adf28177SDan Gohman /// tried for the current instruction and didn't work. 347adf28177SDan Gohman class CommutingState { 348adf28177SDan Gohman /// There are effectively three states: the initial state where we haven't 349adf28177SDan Gohman /// started commuting anything and we don't know anything yet, the tenative 350adf28177SDan Gohman /// state where we've commuted the operands of the current instruction and are 351adf28177SDan Gohman /// revisting it, and the declined state where we've reverted the operands 352adf28177SDan Gohman /// back to their original order and will no longer commute it further. 353adf28177SDan Gohman bool TentativelyCommuting; 354adf28177SDan Gohman bool Declined; 355adf28177SDan Gohman 356adf28177SDan Gohman /// During the tentative state, these hold the operand indices of the commuted 357adf28177SDan Gohman /// operands. 358adf28177SDan Gohman unsigned Operand0, Operand1; 359adf28177SDan Gohman 360adf28177SDan Gohman public: 361adf28177SDan Gohman CommutingState() : TentativelyCommuting(false), Declined(false) {} 362adf28177SDan Gohman 363adf28177SDan Gohman /// Stackification for an operand was not successful due to ordering 364adf28177SDan Gohman /// constraints. If possible, and if we haven't already tried it and declined 365adf28177SDan Gohman /// it, commute Insert's operands and prepare to revisit it. 366adf28177SDan Gohman void MaybeCommute(MachineInstr *Insert, TreeWalkerState &TreeWalker, 367adf28177SDan Gohman const WebAssemblyInstrInfo *TII) { 368adf28177SDan Gohman if (TentativelyCommuting) { 369adf28177SDan Gohman assert(!Declined && 370adf28177SDan Gohman "Don't decline commuting until you've finished trying it"); 371adf28177SDan Gohman // Commuting didn't help. Revert it. 372adf28177SDan Gohman TII->commuteInstruction(Insert, /*NewMI=*/false, Operand0, Operand1); 373adf28177SDan Gohman TentativelyCommuting = false; 374adf28177SDan Gohman Declined = true; 375adf28177SDan Gohman } else if (!Declined && TreeWalker.HasRemainingOperands(Insert)) { 376adf28177SDan Gohman Operand0 = TargetInstrInfo::CommuteAnyOperandIndex; 377adf28177SDan Gohman Operand1 = TargetInstrInfo::CommuteAnyOperandIndex; 378adf28177SDan Gohman if (TII->findCommutedOpIndices(Insert, Operand0, Operand1)) { 379adf28177SDan Gohman // Tentatively commute the operands and try again. 380adf28177SDan Gohman TII->commuteInstruction(Insert, /*NewMI=*/false, Operand0, Operand1); 381adf28177SDan Gohman TreeWalker.ResetTopOperands(Insert); 382adf28177SDan Gohman TentativelyCommuting = true; 383adf28177SDan Gohman Declined = false; 384adf28177SDan Gohman } 385adf28177SDan Gohman } 386adf28177SDan Gohman } 387adf28177SDan Gohman 388adf28177SDan Gohman /// Stackification for some operand was successful. Reset to the default 389adf28177SDan Gohman /// state. 390adf28177SDan Gohman void Reset() { 391adf28177SDan Gohman TentativelyCommuting = false; 392adf28177SDan Gohman Declined = false; 393adf28177SDan Gohman } 394adf28177SDan Gohman }; 395adf28177SDan Gohman } // end anonymous namespace 396adf28177SDan Gohman 3971462faadSDan Gohman bool WebAssemblyRegStackify::runOnMachineFunction(MachineFunction &MF) { 3981462faadSDan Gohman DEBUG(dbgs() << "********** Register Stackifying **********\n" 3991462faadSDan Gohman "********** Function: " 4001462faadSDan Gohman << MF.getName() << '\n'); 4011462faadSDan Gohman 4021462faadSDan Gohman bool Changed = false; 4031462faadSDan Gohman MachineRegisterInfo &MRI = MF.getRegInfo(); 4041462faadSDan Gohman WebAssemblyFunctionInfo &MFI = *MF.getInfo<WebAssemblyFunctionInfo>(); 405b6fd39a3SDan Gohman const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 406b6fd39a3SDan Gohman const auto *TRI = MF.getSubtarget<WebAssemblySubtarget>().getRegisterInfo(); 40781719f85SDan Gohman AliasAnalysis &AA = getAnalysis<AAResultsWrapperPass>().getAAResults(); 408adf28177SDan Gohman MachineDominatorTree &MDT = getAnalysis<MachineDominatorTree>(); 4098887d1faSDan Gohman LiveIntervals &LIS = getAnalysis<LiveIntervals>(); 410d70e5907SDan Gohman 4111462faadSDan Gohman // Walk the instructions from the bottom up. Currently we don't look past 4121462faadSDan Gohman // block boundaries, and the blocks aren't ordered so the block visitation 4131462faadSDan Gohman // order isn't significant, but we may want to change this in the future. 4141462faadSDan Gohman for (MachineBasicBlock &MBB : MF) { 4158f59cf75SDan Gohman // Don't use a range-based for loop, because we modify the list as we're 4168f59cf75SDan Gohman // iterating over it and the end iterator may change. 4178f59cf75SDan Gohman for (auto MII = MBB.rbegin(); MII != MBB.rend(); ++MII) { 4188f59cf75SDan Gohman MachineInstr *Insert = &*MII; 4191462faadSDan Gohman // Don't nest anything inside a phi. 4201462faadSDan Gohman if (Insert->getOpcode() == TargetOpcode::PHI) 4211462faadSDan Gohman break; 4221462faadSDan Gohman 42381719f85SDan Gohman // Don't nest anything inside an inline asm, because we don't have 42481719f85SDan Gohman // constraints for $push inputs. 42581719f85SDan Gohman if (Insert->getOpcode() == TargetOpcode::INLINEASM) 426595e8ab2SDan Gohman continue; 427595e8ab2SDan Gohman 428595e8ab2SDan Gohman // Ignore debugging intrinsics. 429595e8ab2SDan Gohman if (Insert->getOpcode() == TargetOpcode::DBG_VALUE) 430595e8ab2SDan Gohman continue; 43181719f85SDan Gohman 4321462faadSDan Gohman // Iterate through the inputs in reverse order, since we'll be pulling 43353d13997SDan Gohman // operands off the stack in LIFO order. 434adf28177SDan Gohman CommutingState Commuting; 435adf28177SDan Gohman TreeWalkerState TreeWalker(Insert); 436adf28177SDan Gohman while (!TreeWalker.Done()) { 437adf28177SDan Gohman MachineOperand &Op = TreeWalker.Pop(); 438adf28177SDan Gohman 4391462faadSDan Gohman // We're only interested in explicit virtual register operands. 440adf28177SDan Gohman if (!Op.isReg()) 4411462faadSDan Gohman continue; 4421462faadSDan Gohman 4431462faadSDan Gohman unsigned Reg = Op.getReg(); 444adf28177SDan Gohman assert(Op.isUse() && "explicit_uses() should only iterate over uses"); 445adf28177SDan Gohman assert(!Op.isImplicit() && 446adf28177SDan Gohman "explicit_uses() should only iterate over explicit operands"); 447adf28177SDan Gohman if (TargetRegisterInfo::isPhysicalRegister(Reg)) 448adf28177SDan Gohman continue; 4491462faadSDan Gohman 450adf28177SDan Gohman // Identify the definition for this register at this point. Most 451adf28177SDan Gohman // registers are in SSA form here so we try a quick MRI query first. 4528887d1faSDan Gohman MachineInstr *Def = MRI.getUniqueVRegDef(Reg); 453adf28177SDan Gohman if (!Def) { 454adf28177SDan Gohman // MRI doesn't know what the Def is. Try asking LIS. 455adf28177SDan Gohman const VNInfo *ValNo = LIS.getInterval(Reg).getVNInfoBefore( 45613d3b9b7SJF Bastien LIS.getInstructionIndex(*Insert)); 457adf28177SDan Gohman if (!ValNo) 458adf28177SDan Gohman continue; 459adf28177SDan Gohman Def = LIS.getInstructionFromIndex(ValNo->def); 4601462faadSDan Gohman if (!Def) 4611462faadSDan Gohman continue; 462adf28177SDan Gohman } 4631462faadSDan Gohman 46481719f85SDan Gohman // Don't nest an INLINE_ASM def into anything, because we don't have 46581719f85SDan Gohman // constraints for $pop outputs. 46681719f85SDan Gohman if (Def->getOpcode() == TargetOpcode::INLINEASM) 46781719f85SDan Gohman continue; 46881719f85SDan Gohman 46981719f85SDan Gohman // Don't nest PHIs inside of anything. 47081719f85SDan Gohman if (Def->getOpcode() == TargetOpcode::PHI) 47181719f85SDan Gohman continue; 47281719f85SDan Gohman 4734ba4816bSDan Gohman // Argument instructions represent live-in registers and not real 4744ba4816bSDan Gohman // instructions. 4754ba4816bSDan Gohman if (Def->getOpcode() == WebAssembly::ARGUMENT_I32 || 4764ba4816bSDan Gohman Def->getOpcode() == WebAssembly::ARGUMENT_I64 || 4774ba4816bSDan Gohman Def->getOpcode() == WebAssembly::ARGUMENT_F32 || 4784ba4816bSDan Gohman Def->getOpcode() == WebAssembly::ARGUMENT_F64) 4794ba4816bSDan Gohman continue; 4804ba4816bSDan Gohman 481adf28177SDan Gohman // Decide which strategy to take. Prefer to move a single-use value 482adf28177SDan Gohman // over cloning it, and prefer cloning over introducing a tee_local. 483adf28177SDan Gohman // For moving, we require the def to be in the same block as the use; 484adf28177SDan Gohman // this makes things simpler (LiveIntervals' handleMove function only 485adf28177SDan Gohman // supports intra-block moves) and it's MachineSink's job to catch all 486adf28177SDan Gohman // the sinking opportunities anyway. 487adf28177SDan Gohman bool SameBlock = Def->getParent() == &MBB; 488fbfe5ec4SDan Gohman bool CanMove = SameBlock && IsSafeToMove(Def, Insert, AA, LIS, MRI) && 489fbfe5ec4SDan Gohman !TreeWalker.IsOnStack(Reg); 490adf28177SDan Gohman if (CanMove && MRI.hasOneUse(Reg)) { 491adf28177SDan Gohman Insert = MoveForSingleUse(Reg, Def, MBB, Insert, LIS, MFI); 492b6fd39a3SDan Gohman } else if (Def->isAsCheapAsAMove() && 493b6fd39a3SDan Gohman TII->isTriviallyReMaterializable(Def, &AA)) { 494adf28177SDan Gohman Insert = RematerializeCheapDef(Reg, Op, Def, MBB, Insert, LIS, MFI, 495adf28177SDan Gohman MRI, TII, TRI); 496adf28177SDan Gohman } else if (CanMove && 497adf28177SDan Gohman OneUseDominatesOtherUses(Reg, Op, MBB, MRI, MDT)) { 498adf28177SDan Gohman Insert = MoveAndTeeForMultiUse(Reg, Op, Def, MBB, Insert, LIS, MFI, 499adf28177SDan Gohman MRI, TII); 500b6fd39a3SDan Gohman } else { 501adf28177SDan Gohman // We failed to stackify the operand. If the problem was ordering 502adf28177SDan Gohman // constraints, Commuting may be able to help. 503adf28177SDan Gohman if (!CanMove && SameBlock) 504adf28177SDan Gohman Commuting.MaybeCommute(Insert, TreeWalker, TII); 505adf28177SDan Gohman // Proceed to the next operand. 506adf28177SDan Gohman continue; 507b6fd39a3SDan Gohman } 508adf28177SDan Gohman 509adf28177SDan Gohman // We stackified an operand. Add the defining instruction's operands to 510adf28177SDan Gohman // the worklist stack now to continue to build an ever deeper tree. 511adf28177SDan Gohman Commuting.Reset(); 512adf28177SDan Gohman TreeWalker.PushOperands(Insert); 513b6fd39a3SDan Gohman } 514adf28177SDan Gohman 515adf28177SDan Gohman // If we stackified any operands, skip over the tree to start looking for 516adf28177SDan Gohman // the next instruction we can build a tree on. 517adf28177SDan Gohman if (Insert != &*MII) { 5188f59cf75SDan Gohman ImposeStackOrdering(&*MII); 519adf28177SDan Gohman MII = std::prev( 520*369ebfe4SHans Wennborg llvm::make_reverse_iterator(MachineBasicBlock::iterator(Insert))); 521adf28177SDan Gohman Changed = true; 522adf28177SDan Gohman } 5231462faadSDan Gohman } 5241462faadSDan Gohman } 5251462faadSDan Gohman 526adf28177SDan Gohman // If we used EXPR_STACK anywhere, add it to the live-in sets everywhere so 527adf28177SDan Gohman // that it never looks like a use-before-def. 528b0992dafSDan Gohman if (Changed) { 529b0992dafSDan Gohman MF.getRegInfo().addLiveIn(WebAssembly::EXPR_STACK); 530b0992dafSDan Gohman for (MachineBasicBlock &MBB : MF) 531b0992dafSDan Gohman MBB.addLiveIn(WebAssembly::EXPR_STACK); 532b0992dafSDan Gohman } 533b0992dafSDan Gohman 5347bafa0eaSDan Gohman #ifndef NDEBUG 535b6fd39a3SDan Gohman // Verify that pushes and pops are performed in LIFO order. 5367bafa0eaSDan Gohman SmallVector<unsigned, 0> Stack; 5377bafa0eaSDan Gohman for (MachineBasicBlock &MBB : MF) { 5387bafa0eaSDan Gohman for (MachineInstr &MI : MBB) { 5397bafa0eaSDan Gohman for (MachineOperand &MO : reverse(MI.explicit_operands())) { 5407a6b9825SDan Gohman if (!MO.isReg()) 5417a6b9825SDan Gohman continue; 542adf28177SDan Gohman unsigned Reg = MO.getReg(); 5437bafa0eaSDan Gohman 54435bfb24cSDan Gohman // Don't stackify physregs like SP or FP. 545adf28177SDan Gohman if (!TargetRegisterInfo::isVirtualRegister(Reg)) 54635bfb24cSDan Gohman continue; 54735bfb24cSDan Gohman 548adf28177SDan Gohman if (MFI.isVRegStackified(Reg)) { 5497bafa0eaSDan Gohman if (MO.isDef()) 550adf28177SDan Gohman Stack.push_back(Reg); 5517bafa0eaSDan Gohman else 552adf28177SDan Gohman assert(Stack.pop_back_val() == Reg && 553adf28177SDan Gohman "Register stack pop should be paired with a push"); 5547bafa0eaSDan Gohman } 5557bafa0eaSDan Gohman } 5567bafa0eaSDan Gohman } 5577bafa0eaSDan Gohman // TODO: Generalize this code to support keeping values on the stack across 5587bafa0eaSDan Gohman // basic block boundaries. 559adf28177SDan Gohman assert(Stack.empty() && 560adf28177SDan Gohman "Register stack pushes and pops should be balanced"); 5617bafa0eaSDan Gohman } 5627bafa0eaSDan Gohman #endif 5637bafa0eaSDan Gohman 5641462faadSDan Gohman return Changed; 5651462faadSDan Gohman } 566