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" 2681719f85SDan Gohman #include "llvm/Analysis/AliasAnalysis.h" 278887d1faSDan Gohman #include "llvm/CodeGen/LiveIntervalAnalysis.h" 281462faadSDan Gohman #include "llvm/CodeGen/MachineBlockFrequencyInfo.h" 291462faadSDan Gohman #include "llvm/CodeGen/MachineRegisterInfo.h" 301462faadSDan Gohman #include "llvm/CodeGen/Passes.h" 311462faadSDan Gohman #include "llvm/Support/Debug.h" 321462faadSDan Gohman #include "llvm/Support/raw_ostream.h" 331462faadSDan Gohman using namespace llvm; 341462faadSDan Gohman 351462faadSDan Gohman #define DEBUG_TYPE "wasm-reg-stackify" 361462faadSDan Gohman 371462faadSDan Gohman namespace { 381462faadSDan Gohman class WebAssemblyRegStackify final : public MachineFunctionPass { 391462faadSDan Gohman const char *getPassName() const override { 401462faadSDan Gohman return "WebAssembly Register Stackify"; 411462faadSDan Gohman } 421462faadSDan Gohman 431462faadSDan Gohman void getAnalysisUsage(AnalysisUsage &AU) const override { 441462faadSDan Gohman AU.setPreservesCFG(); 4581719f85SDan Gohman AU.addRequired<AAResultsWrapperPass>(); 468887d1faSDan Gohman AU.addRequired<LiveIntervals>(); 471462faadSDan Gohman AU.addPreserved<MachineBlockFrequencyInfo>(); 488887d1faSDan Gohman AU.addPreserved<SlotIndexes>(); 498887d1faSDan Gohman AU.addPreserved<LiveIntervals>(); 501462faadSDan Gohman AU.addPreservedID(MachineDominatorsID); 518887d1faSDan Gohman AU.addPreservedID(LiveVariablesID); 521462faadSDan Gohman MachineFunctionPass::getAnalysisUsage(AU); 531462faadSDan Gohman } 541462faadSDan Gohman 551462faadSDan Gohman bool runOnMachineFunction(MachineFunction &MF) override; 561462faadSDan Gohman 571462faadSDan Gohman public: 581462faadSDan Gohman static char ID; // Pass identification, replacement for typeid 591462faadSDan Gohman WebAssemblyRegStackify() : MachineFunctionPass(ID) {} 601462faadSDan Gohman }; 611462faadSDan Gohman } // end anonymous namespace 621462faadSDan Gohman 631462faadSDan Gohman char WebAssemblyRegStackify::ID = 0; 641462faadSDan Gohman FunctionPass *llvm::createWebAssemblyRegStackify() { 651462faadSDan Gohman return new WebAssemblyRegStackify(); 661462faadSDan Gohman } 671462faadSDan Gohman 68b0992dafSDan Gohman // Decorate the given instruction with implicit operands that enforce the 698887d1faSDan Gohman // expression stack ordering constraints for an instruction which is on 708887d1faSDan Gohman // the expression stack. 718887d1faSDan Gohman static void ImposeStackOrdering(MachineInstr *MI) { 724da4abd8SDan Gohman // Write the opaque EXPR_STACK register. 734da4abd8SDan Gohman if (!MI->definesRegister(WebAssembly::EXPR_STACK)) 74b0992dafSDan Gohman MI->addOperand(MachineOperand::CreateReg(WebAssembly::EXPR_STACK, 75b0992dafSDan Gohman /*isDef=*/true, 76b0992dafSDan Gohman /*isImp=*/true)); 774da4abd8SDan Gohman 784da4abd8SDan Gohman // Also read the opaque EXPR_STACK register. 79a712a6c4SDan Gohman if (!MI->readsRegister(WebAssembly::EXPR_STACK)) 80b0992dafSDan Gohman MI->addOperand(MachineOperand::CreateReg(WebAssembly::EXPR_STACK, 81b0992dafSDan Gohman /*isDef=*/false, 82b0992dafSDan Gohman /*isImp=*/true)); 83b0992dafSDan Gohman } 84b0992dafSDan Gohman 858887d1faSDan Gohman // Test whether it's safe to move Def to just before Insert. 8681719f85SDan Gohman // TODO: Compute memory dependencies in a way that doesn't require always 8781719f85SDan Gohman // walking the block. 8881719f85SDan Gohman // TODO: Compute memory dependencies in a way that uses AliasAnalysis to be 8981719f85SDan Gohman // more precise. 9081719f85SDan Gohman static bool IsSafeToMove(const MachineInstr *Def, const MachineInstr *Insert, 918887d1faSDan Gohman AliasAnalysis &AA, LiveIntervals &LIS, 928887d1faSDan Gohman MachineRegisterInfo &MRI) { 93391a98afSDan Gohman assert(Def->getParent() == Insert->getParent()); 9481719f85SDan Gohman bool SawStore = false, SawSideEffects = false; 9581719f85SDan Gohman MachineBasicBlock::const_iterator D(Def), I(Insert); 968887d1faSDan Gohman 978887d1faSDan Gohman // Check for register dependencies. 988887d1faSDan Gohman for (const MachineOperand &MO : Def->operands()) { 998887d1faSDan Gohman if (!MO.isReg() || MO.isUndef()) 1008887d1faSDan Gohman continue; 1018887d1faSDan Gohman unsigned Reg = MO.getReg(); 1028887d1faSDan Gohman 1038887d1faSDan Gohman // If the register is dead here and at Insert, ignore it. 1048887d1faSDan Gohman if (MO.isDead() && Insert->definesRegister(Reg) && 1058887d1faSDan Gohman !Insert->readsRegister(Reg)) 1068887d1faSDan Gohman continue; 1078887d1faSDan Gohman 1088887d1faSDan Gohman if (TargetRegisterInfo::isPhysicalRegister(Reg)) { 1098887d1faSDan Gohman // If the physical register is never modified, ignore it. 1108887d1faSDan Gohman if (!MRI.isPhysRegModified(Reg)) 1118887d1faSDan Gohman continue; 1128887d1faSDan Gohman // Otherwise, it's a physical register with unknown liveness. 1138887d1faSDan Gohman return false; 1148887d1faSDan Gohman } 1158887d1faSDan Gohman 1168887d1faSDan Gohman // Ask LiveIntervals whether moving this virtual register use or def to 1178887d1faSDan Gohman // Insert will change value numbers are seen. 1188887d1faSDan Gohman const LiveInterval &LI = LIS.getInterval(Reg); 1198887d1faSDan Gohman VNInfo *DefVNI = MO.isDef() ? 1208887d1faSDan Gohman LI.getVNInfoAt(LIS.getInstructionIndex(Def).getRegSlot()) : 1218887d1faSDan Gohman LI.getVNInfoBefore(LIS.getInstructionIndex(Def)); 1228887d1faSDan Gohman assert(DefVNI && "Instruction input missing value number"); 1238887d1faSDan Gohman VNInfo *InsVNI = LI.getVNInfoBefore(LIS.getInstructionIndex(Insert)); 1248887d1faSDan Gohman if (InsVNI && DefVNI != InsVNI) 1258887d1faSDan Gohman return false; 1268887d1faSDan Gohman } 1278887d1faSDan Gohman 1288887d1faSDan Gohman // Check for memory dependencies and side effects. 12981719f85SDan Gohman for (--I; I != D; --I) 13081719f85SDan Gohman SawSideEffects |= I->isSafeToMove(&AA, SawStore); 13181719f85SDan Gohman return !(SawStore && Def->mayLoad() && !Def->isInvariantLoad(&AA)) && 13281719f85SDan Gohman !(SawSideEffects && !Def->isSafeToMove(&AA, SawStore)); 13381719f85SDan Gohman } 13481719f85SDan Gohman 1351462faadSDan Gohman bool WebAssemblyRegStackify::runOnMachineFunction(MachineFunction &MF) { 1361462faadSDan Gohman DEBUG(dbgs() << "********** Register Stackifying **********\n" 1371462faadSDan Gohman "********** Function: " 1381462faadSDan Gohman << MF.getName() << '\n'); 1391462faadSDan Gohman 1401462faadSDan Gohman bool Changed = false; 1411462faadSDan Gohman MachineRegisterInfo &MRI = MF.getRegInfo(); 1421462faadSDan Gohman WebAssemblyFunctionInfo &MFI = *MF.getInfo<WebAssemblyFunctionInfo>(); 14381719f85SDan Gohman AliasAnalysis &AA = getAnalysis<AAResultsWrapperPass>().getAAResults(); 1448887d1faSDan Gohman LiveIntervals &LIS = getAnalysis<LiveIntervals>(); 145d70e5907SDan Gohman 1461462faadSDan Gohman // Walk the instructions from the bottom up. Currently we don't look past 1471462faadSDan Gohman // block boundaries, and the blocks aren't ordered so the block visitation 1481462faadSDan Gohman // order isn't significant, but we may want to change this in the future. 1491462faadSDan Gohman for (MachineBasicBlock &MBB : MF) { 150*8f59cf75SDan Gohman // Don't use a range-based for loop, because we modify the list as we're 151*8f59cf75SDan Gohman // iterating over it and the end iterator may change. 152*8f59cf75SDan Gohman for (auto MII = MBB.rbegin(); MII != MBB.rend(); ++MII) { 153*8f59cf75SDan Gohman MachineInstr *Insert = &*MII; 1541462faadSDan Gohman // Don't nest anything inside a phi. 1551462faadSDan Gohman if (Insert->getOpcode() == TargetOpcode::PHI) 1561462faadSDan Gohman break; 1571462faadSDan Gohman 15881719f85SDan Gohman // Don't nest anything inside an inline asm, because we don't have 15981719f85SDan Gohman // constraints for $push inputs. 16081719f85SDan Gohman if (Insert->getOpcode() == TargetOpcode::INLINEASM) 16181719f85SDan Gohman break; 16281719f85SDan Gohman 1631462faadSDan Gohman // Iterate through the inputs in reverse order, since we'll be pulling 16453d13997SDan Gohman // operands off the stack in LIFO order. 165b0992dafSDan Gohman bool AnyStackified = false; 1661462faadSDan Gohman for (MachineOperand &Op : reverse(Insert->uses())) { 1671462faadSDan Gohman // We're only interested in explicit virtual register operands. 16881719f85SDan Gohman if (!Op.isReg() || Op.isImplicit() || !Op.isUse()) 1691462faadSDan Gohman continue; 1701462faadSDan Gohman 1711462faadSDan Gohman unsigned Reg = Op.getReg(); 1721462faadSDan Gohman 1731462faadSDan Gohman // Only consider registers with a single definition. 1741462faadSDan Gohman // TODO: Eventually we may relax this, to stackify phi transfers. 1758887d1faSDan Gohman MachineInstr *Def = MRI.getUniqueVRegDef(Reg); 1761462faadSDan Gohman if (!Def) 1771462faadSDan Gohman continue; 1781462faadSDan Gohman 1791462faadSDan Gohman // There's no use in nesting implicit defs inside anything. 1801462faadSDan Gohman if (Def->getOpcode() == TargetOpcode::IMPLICIT_DEF) 1811462faadSDan Gohman continue; 1821462faadSDan Gohman 18381719f85SDan Gohman // Don't nest an INLINE_ASM def into anything, because we don't have 18481719f85SDan Gohman // constraints for $pop outputs. 18581719f85SDan Gohman if (Def->getOpcode() == TargetOpcode::INLINEASM) 18681719f85SDan Gohman continue; 18781719f85SDan Gohman 18881719f85SDan Gohman // Don't nest PHIs inside of anything. 18981719f85SDan Gohman if (Def->getOpcode() == TargetOpcode::PHI) 19081719f85SDan Gohman continue; 19181719f85SDan Gohman 1924ba4816bSDan Gohman // Argument instructions represent live-in registers and not real 1934ba4816bSDan Gohman // instructions. 1944ba4816bSDan Gohman if (Def->getOpcode() == WebAssembly::ARGUMENT_I32 || 1954ba4816bSDan Gohman Def->getOpcode() == WebAssembly::ARGUMENT_I64 || 1964ba4816bSDan Gohman Def->getOpcode() == WebAssembly::ARGUMENT_F32 || 1974ba4816bSDan Gohman Def->getOpcode() == WebAssembly::ARGUMENT_F64) 1984ba4816bSDan Gohman continue; 1994ba4816bSDan Gohman 200391a98afSDan Gohman // Single-use expression trees require defs that have one use. 2011462faadSDan Gohman // TODO: Eventually we'll relax this, to take advantage of set_local 2021462faadSDan Gohman // returning its result. 20381719f85SDan Gohman if (!MRI.hasOneUse(Reg)) 2041462faadSDan Gohman continue; 2051462faadSDan Gohman 206391a98afSDan Gohman // For now, be conservative and don't look across block boundaries. 2078887d1faSDan Gohman // TODO: Be more aggressive? 208391a98afSDan Gohman if (Def->getParent() != &MBB) 2091462faadSDan Gohman continue; 2101462faadSDan Gohman 21181719f85SDan Gohman // Don't move instructions that have side effects or memory dependencies 21281719f85SDan Gohman // or other complications. 2138887d1faSDan Gohman if (!IsSafeToMove(Def, Insert, AA, LIS, MRI)) 2141462faadSDan Gohman continue; 2151462faadSDan Gohman 2161462faadSDan Gohman Changed = true; 217b0992dafSDan Gohman AnyStackified = true; 2181462faadSDan Gohman // Move the def down and nest it in the current instruction. 2198887d1faSDan Gohman MBB.splice(Insert, &MBB, Def); 2208887d1faSDan Gohman LIS.handleMove(Def); 2211462faadSDan Gohman MFI.stackifyVReg(Reg); 2228887d1faSDan Gohman ImposeStackOrdering(Def); 2231462faadSDan Gohman Insert = Def; 2241462faadSDan Gohman } 225b0992dafSDan Gohman if (AnyStackified) 226*8f59cf75SDan Gohman ImposeStackOrdering(&*MII); 2271462faadSDan Gohman } 2281462faadSDan Gohman } 2291462faadSDan Gohman 230b0992dafSDan Gohman // If we used EXPR_STACK anywhere, add it to the live-in sets everywhere 231b0992dafSDan Gohman // so that it never looks like a use-before-def. 232b0992dafSDan Gohman if (Changed) { 233b0992dafSDan Gohman MF.getRegInfo().addLiveIn(WebAssembly::EXPR_STACK); 234b0992dafSDan Gohman for (MachineBasicBlock &MBB : MF) 235b0992dafSDan Gohman MBB.addLiveIn(WebAssembly::EXPR_STACK); 236b0992dafSDan Gohman } 237b0992dafSDan Gohman 2387bafa0eaSDan Gohman #ifndef NDEBUG 2397bafa0eaSDan Gohman // Verify that pushes and pops are performed in FIFO order. 2407bafa0eaSDan Gohman SmallVector<unsigned, 0> Stack; 2417bafa0eaSDan Gohman for (MachineBasicBlock &MBB : MF) { 2427bafa0eaSDan Gohman for (MachineInstr &MI : MBB) { 2437bafa0eaSDan Gohman for (MachineOperand &MO : reverse(MI.explicit_operands())) { 2447a6b9825SDan Gohman if (!MO.isReg()) 2457a6b9825SDan Gohman continue; 2467bafa0eaSDan Gohman unsigned VReg = MO.getReg(); 2477bafa0eaSDan Gohman 24835bfb24cSDan Gohman // Don't stackify physregs like SP or FP. 24935bfb24cSDan Gohman if (!TargetRegisterInfo::isVirtualRegister(VReg)) 25035bfb24cSDan Gohman continue; 25135bfb24cSDan Gohman 2527bafa0eaSDan Gohman if (MFI.isVRegStackified(VReg)) { 2537bafa0eaSDan Gohman if (MO.isDef()) 2547bafa0eaSDan Gohman Stack.push_back(VReg); 2557bafa0eaSDan Gohman else 2567bafa0eaSDan Gohman assert(Stack.pop_back_val() == VReg); 2577bafa0eaSDan Gohman } 2587bafa0eaSDan Gohman } 2597bafa0eaSDan Gohman } 2607bafa0eaSDan Gohman // TODO: Generalize this code to support keeping values on the stack across 2617bafa0eaSDan Gohman // basic block boundaries. 2627bafa0eaSDan Gohman assert(Stack.empty()); 2637bafa0eaSDan Gohman } 2647bafa0eaSDan Gohman #endif 2657bafa0eaSDan Gohman 2661462faadSDan Gohman return Changed; 2671462faadSDan Gohman } 268