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" 301462faadSDan Gohman #include "llvm/CodeGen/MachineRegisterInfo.h" 311462faadSDan Gohman #include "llvm/CodeGen/Passes.h" 321462faadSDan Gohman #include "llvm/Support/Debug.h" 331462faadSDan Gohman #include "llvm/Support/raw_ostream.h" 341462faadSDan Gohman using namespace llvm; 351462faadSDan Gohman 361462faadSDan Gohman #define DEBUG_TYPE "wasm-reg-stackify" 371462faadSDan Gohman 381462faadSDan Gohman namespace { 391462faadSDan Gohman class WebAssemblyRegStackify final : public MachineFunctionPass { 401462faadSDan Gohman const char *getPassName() const override { 411462faadSDan Gohman return "WebAssembly Register Stackify"; 421462faadSDan Gohman } 431462faadSDan Gohman 441462faadSDan Gohman void getAnalysisUsage(AnalysisUsage &AU) const override { 451462faadSDan Gohman AU.setPreservesCFG(); 4681719f85SDan Gohman AU.addRequired<AAResultsWrapperPass>(); 478887d1faSDan Gohman AU.addRequired<LiveIntervals>(); 481462faadSDan Gohman AU.addPreserved<MachineBlockFrequencyInfo>(); 498887d1faSDan Gohman AU.addPreserved<SlotIndexes>(); 508887d1faSDan Gohman AU.addPreserved<LiveIntervals>(); 511462faadSDan Gohman AU.addPreservedID(MachineDominatorsID); 528887d1faSDan Gohman AU.addPreservedID(LiveVariablesID); 531462faadSDan Gohman MachineFunctionPass::getAnalysisUsage(AU); 541462faadSDan Gohman } 551462faadSDan Gohman 561462faadSDan Gohman bool runOnMachineFunction(MachineFunction &MF) override; 571462faadSDan Gohman 581462faadSDan Gohman public: 591462faadSDan Gohman static char ID; // Pass identification, replacement for typeid 601462faadSDan Gohman WebAssemblyRegStackify() : MachineFunctionPass(ID) {} 611462faadSDan Gohman }; 621462faadSDan Gohman } // end anonymous namespace 631462faadSDan Gohman 641462faadSDan Gohman char WebAssemblyRegStackify::ID = 0; 651462faadSDan Gohman FunctionPass *llvm::createWebAssemblyRegStackify() { 661462faadSDan Gohman return new WebAssemblyRegStackify(); 671462faadSDan Gohman } 681462faadSDan Gohman 69b0992dafSDan Gohman // Decorate the given instruction with implicit operands that enforce the 708887d1faSDan Gohman // expression stack ordering constraints for an instruction which is on 718887d1faSDan Gohman // the expression stack. 728887d1faSDan Gohman static void ImposeStackOrdering(MachineInstr *MI) { 734da4abd8SDan Gohman // Write the opaque EXPR_STACK register. 744da4abd8SDan Gohman if (!MI->definesRegister(WebAssembly::EXPR_STACK)) 75b0992dafSDan Gohman MI->addOperand(MachineOperand::CreateReg(WebAssembly::EXPR_STACK, 76b0992dafSDan Gohman /*isDef=*/true, 77b0992dafSDan Gohman /*isImp=*/true)); 784da4abd8SDan Gohman 794da4abd8SDan Gohman // Also read the opaque EXPR_STACK register. 80a712a6c4SDan Gohman if (!MI->readsRegister(WebAssembly::EXPR_STACK)) 81b0992dafSDan Gohman MI->addOperand(MachineOperand::CreateReg(WebAssembly::EXPR_STACK, 82b0992dafSDan Gohman /*isDef=*/false, 83b0992dafSDan Gohman /*isImp=*/true)); 84b0992dafSDan Gohman } 85b0992dafSDan Gohman 868887d1faSDan Gohman // Test whether it's safe to move Def to just before Insert. 8781719f85SDan Gohman // TODO: Compute memory dependencies in a way that doesn't require always 8881719f85SDan Gohman // walking the block. 8981719f85SDan Gohman // TODO: Compute memory dependencies in a way that uses AliasAnalysis to be 9081719f85SDan Gohman // more precise. 9181719f85SDan Gohman static bool IsSafeToMove(const MachineInstr *Def, const MachineInstr *Insert, 928887d1faSDan Gohman AliasAnalysis &AA, LiveIntervals &LIS, 938887d1faSDan Gohman MachineRegisterInfo &MRI) { 94391a98afSDan Gohman assert(Def->getParent() == Insert->getParent()); 9581719f85SDan Gohman bool SawStore = false, SawSideEffects = false; 9681719f85SDan Gohman MachineBasicBlock::const_iterator D(Def), I(Insert); 978887d1faSDan Gohman 988887d1faSDan Gohman // Check for register dependencies. 998887d1faSDan Gohman for (const MachineOperand &MO : Def->operands()) { 1008887d1faSDan Gohman if (!MO.isReg() || MO.isUndef()) 1018887d1faSDan Gohman continue; 1028887d1faSDan Gohman unsigned Reg = MO.getReg(); 1038887d1faSDan Gohman 1048887d1faSDan Gohman // If the register is dead here and at Insert, ignore it. 1058887d1faSDan Gohman if (MO.isDead() && Insert->definesRegister(Reg) && 1068887d1faSDan Gohman !Insert->readsRegister(Reg)) 1078887d1faSDan Gohman continue; 1088887d1faSDan Gohman 1098887d1faSDan Gohman if (TargetRegisterInfo::isPhysicalRegister(Reg)) { 1108887d1faSDan Gohman // If the physical register is never modified, ignore it. 1118887d1faSDan Gohman if (!MRI.isPhysRegModified(Reg)) 1128887d1faSDan Gohman continue; 1138887d1faSDan Gohman // Otherwise, it's a physical register with unknown liveness. 1148887d1faSDan Gohman return false; 1158887d1faSDan Gohman } 1168887d1faSDan Gohman 1178887d1faSDan Gohman // Ask LiveIntervals whether moving this virtual register use or def to 1188887d1faSDan Gohman // Insert will change value numbers are seen. 1198887d1faSDan Gohman const LiveInterval &LI = LIS.getInterval(Reg); 120b6fd39a3SDan Gohman VNInfo *DefVNI = 121b6fd39a3SDan Gohman MO.isDef() ? LI.getVNInfoAt(LIS.getInstructionIndex(Def).getRegSlot()) 122b6fd39a3SDan Gohman : LI.getVNInfoBefore(LIS.getInstructionIndex(Def)); 1238887d1faSDan Gohman assert(DefVNI && "Instruction input missing value number"); 1248887d1faSDan Gohman VNInfo *InsVNI = LI.getVNInfoBefore(LIS.getInstructionIndex(Insert)); 1258887d1faSDan Gohman if (InsVNI && DefVNI != InsVNI) 1268887d1faSDan Gohman return false; 1278887d1faSDan Gohman } 1288887d1faSDan Gohman 1298887d1faSDan Gohman // Check for memory dependencies and side effects. 13081719f85SDan Gohman for (--I; I != D; --I) 131*7e64917fSDan Gohman SawSideEffects |= !I->isSafeToMove(&AA, SawStore); 13281719f85SDan Gohman return !(SawStore && Def->mayLoad() && !Def->isInvariantLoad(&AA)) && 13381719f85SDan Gohman !(SawSideEffects && !Def->isSafeToMove(&AA, SawStore)); 13481719f85SDan Gohman } 13581719f85SDan Gohman 1361462faadSDan Gohman bool WebAssemblyRegStackify::runOnMachineFunction(MachineFunction &MF) { 1371462faadSDan Gohman DEBUG(dbgs() << "********** Register Stackifying **********\n" 1381462faadSDan Gohman "********** Function: " 1391462faadSDan Gohman << MF.getName() << '\n'); 1401462faadSDan Gohman 1411462faadSDan Gohman bool Changed = false; 1421462faadSDan Gohman MachineRegisterInfo &MRI = MF.getRegInfo(); 1431462faadSDan Gohman WebAssemblyFunctionInfo &MFI = *MF.getInfo<WebAssemblyFunctionInfo>(); 144b6fd39a3SDan Gohman const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 145b6fd39a3SDan Gohman const auto *TRI = MF.getSubtarget<WebAssemblySubtarget>().getRegisterInfo(); 14681719f85SDan Gohman AliasAnalysis &AA = getAnalysis<AAResultsWrapperPass>().getAAResults(); 1478887d1faSDan Gohman LiveIntervals &LIS = getAnalysis<LiveIntervals>(); 148d70e5907SDan Gohman 1491462faadSDan Gohman // Walk the instructions from the bottom up. Currently we don't look past 1501462faadSDan Gohman // block boundaries, and the blocks aren't ordered so the block visitation 1511462faadSDan Gohman // order isn't significant, but we may want to change this in the future. 1521462faadSDan Gohman for (MachineBasicBlock &MBB : MF) { 1538f59cf75SDan Gohman // Don't use a range-based for loop, because we modify the list as we're 1548f59cf75SDan Gohman // iterating over it and the end iterator may change. 1558f59cf75SDan Gohman for (auto MII = MBB.rbegin(); MII != MBB.rend(); ++MII) { 1568f59cf75SDan Gohman MachineInstr *Insert = &*MII; 1571462faadSDan Gohman // Don't nest anything inside a phi. 1581462faadSDan Gohman if (Insert->getOpcode() == TargetOpcode::PHI) 1591462faadSDan Gohman break; 1601462faadSDan Gohman 16181719f85SDan Gohman // Don't nest anything inside an inline asm, because we don't have 16281719f85SDan Gohman // constraints for $push inputs. 16381719f85SDan Gohman if (Insert->getOpcode() == TargetOpcode::INLINEASM) 16481719f85SDan Gohman break; 16581719f85SDan Gohman 1661462faadSDan Gohman // Iterate through the inputs in reverse order, since we'll be pulling 16753d13997SDan Gohman // operands off the stack in LIFO order. 168b0992dafSDan Gohman bool AnyStackified = false; 1691462faadSDan Gohman for (MachineOperand &Op : reverse(Insert->uses())) { 1701462faadSDan Gohman // We're only interested in explicit virtual register operands. 17181719f85SDan Gohman if (!Op.isReg() || Op.isImplicit() || !Op.isUse()) 1721462faadSDan Gohman continue; 1731462faadSDan Gohman 1741462faadSDan Gohman unsigned Reg = Op.getReg(); 1751462faadSDan Gohman 1761462faadSDan Gohman // Only consider registers with a single definition. 1771462faadSDan Gohman // TODO: Eventually we may relax this, to stackify phi transfers. 1788887d1faSDan Gohman MachineInstr *Def = MRI.getUniqueVRegDef(Reg); 1791462faadSDan Gohman if (!Def) 1801462faadSDan Gohman continue; 1811462faadSDan Gohman 18281719f85SDan Gohman // Don't nest an INLINE_ASM def into anything, because we don't have 18381719f85SDan Gohman // constraints for $pop outputs. 18481719f85SDan Gohman if (Def->getOpcode() == TargetOpcode::INLINEASM) 18581719f85SDan Gohman continue; 18681719f85SDan Gohman 18781719f85SDan Gohman // Don't nest PHIs inside of anything. 18881719f85SDan Gohman if (Def->getOpcode() == TargetOpcode::PHI) 18981719f85SDan Gohman continue; 19081719f85SDan Gohman 1914ba4816bSDan Gohman // Argument instructions represent live-in registers and not real 1924ba4816bSDan Gohman // instructions. 1934ba4816bSDan Gohman if (Def->getOpcode() == WebAssembly::ARGUMENT_I32 || 1944ba4816bSDan Gohman Def->getOpcode() == WebAssembly::ARGUMENT_I64 || 1954ba4816bSDan Gohman Def->getOpcode() == WebAssembly::ARGUMENT_F32 || 1964ba4816bSDan Gohman Def->getOpcode() == WebAssembly::ARGUMENT_F64) 1974ba4816bSDan Gohman continue; 1984ba4816bSDan Gohman 199b6fd39a3SDan Gohman if (MRI.hasOneUse(Reg) && Def->getParent() == &MBB && 200b6fd39a3SDan Gohman IsSafeToMove(Def, Insert, AA, LIS, MRI)) { 201b6fd39a3SDan Gohman // A single-use def in the same block with no intervening memory or 202b6fd39a3SDan Gohman // register dependencies; move the def down and nest it with the 203b6fd39a3SDan Gohman // current instruction. 204b6fd39a3SDan Gohman // TODO: Stackify multiple-use values, taking advantage of set_local 2051462faadSDan Gohman // returning its result. 2061462faadSDan Gohman Changed = true; 207b0992dafSDan Gohman AnyStackified = true; 2088887d1faSDan Gohman MBB.splice(Insert, &MBB, Def); 2098887d1faSDan Gohman LIS.handleMove(Def); 2101462faadSDan Gohman MFI.stackifyVReg(Reg); 2118887d1faSDan Gohman ImposeStackOrdering(Def); 2121462faadSDan Gohman Insert = Def; 213b6fd39a3SDan Gohman } else if (Def->isAsCheapAsAMove() && 214b6fd39a3SDan Gohman TII->isTriviallyReMaterializable(Def, &AA)) { 215b6fd39a3SDan Gohman // A trivially cloneable instruction; clone it and nest the new copy 216b6fd39a3SDan Gohman // with the current instruction. 217b6fd39a3SDan Gohman Changed = true; 218b6fd39a3SDan Gohman AnyStackified = true; 219b6fd39a3SDan Gohman unsigned OldReg = Def->getOperand(0).getReg(); 220b6fd39a3SDan Gohman unsigned NewReg = MRI.createVirtualRegister(MRI.getRegClass(OldReg)); 221b6fd39a3SDan Gohman TII->reMaterialize(MBB, Insert, NewReg, 0, Def, *TRI); 222b6fd39a3SDan Gohman Op.setReg(NewReg); 223b6fd39a3SDan Gohman MachineInstr *Clone = 224b6fd39a3SDan Gohman &*std::prev(MachineBasicBlock::instr_iterator(Insert)); 225b6fd39a3SDan Gohman LIS.InsertMachineInstrInMaps(Clone); 226b6fd39a3SDan Gohman LIS.createAndComputeVirtRegInterval(NewReg); 227b6fd39a3SDan Gohman MFI.stackifyVReg(NewReg); 228b6fd39a3SDan Gohman ImposeStackOrdering(Clone); 229b6fd39a3SDan Gohman Insert = Clone; 230b6fd39a3SDan Gohman 231b6fd39a3SDan Gohman // If that was the last use of the original, delete the original. 232b6fd39a3SDan Gohman // Otherwise shrink the LiveInterval. 233b6fd39a3SDan Gohman if (MRI.use_empty(OldReg)) { 234b6fd39a3SDan Gohman SlotIndex Idx = LIS.getInstructionIndex(Def).getRegSlot(); 235b6fd39a3SDan Gohman LIS.removePhysRegDefAt(WebAssembly::ARGUMENTS, Idx); 236b6fd39a3SDan Gohman LIS.removeVRegDefAt(LIS.getInterval(OldReg), Idx); 237b6fd39a3SDan Gohman LIS.removeInterval(OldReg); 238b6fd39a3SDan Gohman LIS.RemoveMachineInstrFromMaps(Def); 239b6fd39a3SDan Gohman Def->eraseFromParent(); 240b6fd39a3SDan Gohman } else { 241b6fd39a3SDan Gohman LIS.shrinkToUses(&LIS.getInterval(OldReg)); 242b6fd39a3SDan Gohman } 243b6fd39a3SDan Gohman } 2441462faadSDan Gohman } 245b0992dafSDan Gohman if (AnyStackified) 2468f59cf75SDan Gohman ImposeStackOrdering(&*MII); 2471462faadSDan Gohman } 2481462faadSDan Gohman } 2491462faadSDan Gohman 250b0992dafSDan Gohman // If we used EXPR_STACK anywhere, add it to the live-in sets everywhere 251b0992dafSDan Gohman // so that it never looks like a use-before-def. 252b0992dafSDan Gohman if (Changed) { 253b0992dafSDan Gohman MF.getRegInfo().addLiveIn(WebAssembly::EXPR_STACK); 254b0992dafSDan Gohman for (MachineBasicBlock &MBB : MF) 255b0992dafSDan Gohman MBB.addLiveIn(WebAssembly::EXPR_STACK); 256b0992dafSDan Gohman } 257b0992dafSDan Gohman 2587bafa0eaSDan Gohman #ifndef NDEBUG 259b6fd39a3SDan Gohman // Verify that pushes and pops are performed in LIFO order. 2607bafa0eaSDan Gohman SmallVector<unsigned, 0> Stack; 2617bafa0eaSDan Gohman for (MachineBasicBlock &MBB : MF) { 2627bafa0eaSDan Gohman for (MachineInstr &MI : MBB) { 2637bafa0eaSDan Gohman for (MachineOperand &MO : reverse(MI.explicit_operands())) { 2647a6b9825SDan Gohman if (!MO.isReg()) 2657a6b9825SDan Gohman continue; 2667bafa0eaSDan Gohman unsigned VReg = MO.getReg(); 2677bafa0eaSDan Gohman 26835bfb24cSDan Gohman // Don't stackify physregs like SP or FP. 26935bfb24cSDan Gohman if (!TargetRegisterInfo::isVirtualRegister(VReg)) 27035bfb24cSDan Gohman continue; 27135bfb24cSDan Gohman 2727bafa0eaSDan Gohman if (MFI.isVRegStackified(VReg)) { 2737bafa0eaSDan Gohman if (MO.isDef()) 2747bafa0eaSDan Gohman Stack.push_back(VReg); 2757bafa0eaSDan Gohman else 2767bafa0eaSDan Gohman assert(Stack.pop_back_val() == VReg); 2777bafa0eaSDan Gohman } 2787bafa0eaSDan Gohman } 2797bafa0eaSDan Gohman } 2807bafa0eaSDan Gohman // TODO: Generalize this code to support keeping values on the stack across 2817bafa0eaSDan Gohman // basic block boundaries. 2827bafa0eaSDan Gohman assert(Stack.empty()); 2837bafa0eaSDan Gohman } 2847bafa0eaSDan Gohman #endif 2857bafa0eaSDan Gohman 2861462faadSDan Gohman return Changed; 2871462faadSDan Gohman } 288