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 /// 181462faadSDan Gohman /// This is primarily a code size optimiation, 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" 271462faadSDan Gohman #include "llvm/CodeGen/MachineBlockFrequencyInfo.h" 281462faadSDan Gohman #include "llvm/CodeGen/MachineRegisterInfo.h" 291462faadSDan Gohman #include "llvm/CodeGen/Passes.h" 301462faadSDan Gohman #include "llvm/Support/Debug.h" 311462faadSDan Gohman #include "llvm/Support/raw_ostream.h" 321462faadSDan Gohman using namespace llvm; 331462faadSDan Gohman 341462faadSDan Gohman #define DEBUG_TYPE "wasm-reg-stackify" 351462faadSDan Gohman 361462faadSDan Gohman namespace { 371462faadSDan Gohman class WebAssemblyRegStackify final : public MachineFunctionPass { 381462faadSDan Gohman const char *getPassName() const override { 391462faadSDan Gohman return "WebAssembly Register Stackify"; 401462faadSDan Gohman } 411462faadSDan Gohman 421462faadSDan Gohman void getAnalysisUsage(AnalysisUsage &AU) const override { 431462faadSDan Gohman AU.setPreservesCFG(); 4481719f85SDan Gohman AU.addRequired<AAResultsWrapperPass>(); 451462faadSDan Gohman AU.addPreserved<MachineBlockFrequencyInfo>(); 461462faadSDan Gohman AU.addPreservedID(MachineDominatorsID); 471462faadSDan Gohman MachineFunctionPass::getAnalysisUsage(AU); 481462faadSDan Gohman } 491462faadSDan Gohman 501462faadSDan Gohman bool runOnMachineFunction(MachineFunction &MF) override; 511462faadSDan Gohman 521462faadSDan Gohman public: 531462faadSDan Gohman static char ID; // Pass identification, replacement for typeid 541462faadSDan Gohman WebAssemblyRegStackify() : MachineFunctionPass(ID) {} 551462faadSDan Gohman }; 561462faadSDan Gohman } // end anonymous namespace 571462faadSDan Gohman 581462faadSDan Gohman char WebAssemblyRegStackify::ID = 0; 591462faadSDan Gohman FunctionPass *llvm::createWebAssemblyRegStackify() { 601462faadSDan Gohman return new WebAssemblyRegStackify(); 611462faadSDan Gohman } 621462faadSDan Gohman 63b0992dafSDan Gohman // Decorate the given instruction with implicit operands that enforce the 644da4abd8SDan Gohman // expression stack ordering constraints needed for an instruction which is 654da4abd8SDan Gohman // consumed by an instruction using the expression stack. 664da4abd8SDan Gohman static void ImposeStackInputOrdering(MachineInstr *MI) { 674da4abd8SDan Gohman // Write the opaque EXPR_STACK register. 684da4abd8SDan Gohman if (!MI->definesRegister(WebAssembly::EXPR_STACK)) 69b0992dafSDan Gohman MI->addOperand(MachineOperand::CreateReg(WebAssembly::EXPR_STACK, 70b0992dafSDan Gohman /*isDef=*/true, 71b0992dafSDan Gohman /*isImp=*/true)); 724da4abd8SDan Gohman } 734da4abd8SDan Gohman 744da4abd8SDan Gohman // Decorate the given instruction with implicit operands that enforce the 754da4abd8SDan Gohman // expression stack ordering constraints for an instruction which is on 764da4abd8SDan Gohman // the expression stack. 774da4abd8SDan Gohman static void ImposeStackOrdering(MachineInstr *MI, MachineRegisterInfo &MRI) { 784da4abd8SDan Gohman ImposeStackInputOrdering(MI); 794da4abd8SDan Gohman 804da4abd8SDan Gohman // Also read the opaque EXPR_STACK register. 81b0992dafSDan Gohman MI->addOperand(MachineOperand::CreateReg(WebAssembly::EXPR_STACK, 82b0992dafSDan Gohman /*isDef=*/false, 83b0992dafSDan Gohman /*isImp=*/true)); 844da4abd8SDan Gohman 854da4abd8SDan Gohman // Also, mark any inputs to this instruction as being consumed by an 864da4abd8SDan Gohman // instruction on the expression stack. 874da4abd8SDan Gohman // TODO: Find a lighter way to describe the appropriate constraints. 884da4abd8SDan Gohman for (MachineOperand &MO : MI->uses()) { 894da4abd8SDan Gohman if (!MO.isReg()) 904da4abd8SDan Gohman continue; 914da4abd8SDan Gohman unsigned Reg = MO.getReg(); 924da4abd8SDan Gohman if (!TargetRegisterInfo::isVirtualRegister(Reg)) 934da4abd8SDan Gohman continue; 944da4abd8SDan Gohman MachineInstr *Def = MRI.getVRegDef(Reg); 954da4abd8SDan Gohman if (Def->getOpcode() == TargetOpcode::PHI) 964da4abd8SDan Gohman continue; 974da4abd8SDan Gohman ImposeStackInputOrdering(Def); 984da4abd8SDan Gohman } 99b0992dafSDan Gohman } 100b0992dafSDan Gohman 10181719f85SDan Gohman // Test whether it's safe to move Def to just before Insert. Note that this 10281719f85SDan Gohman // doesn't account for physical register dependencies, because WebAssembly 10381719f85SDan Gohman // doesn't have any (other than special ones like EXPR_STACK). 10481719f85SDan Gohman // TODO: Compute memory dependencies in a way that doesn't require always 10581719f85SDan Gohman // walking the block. 10681719f85SDan Gohman // TODO: Compute memory dependencies in a way that uses AliasAnalysis to be 10781719f85SDan Gohman // more precise. 10881719f85SDan Gohman static bool IsSafeToMove(const MachineInstr *Def, const MachineInstr *Insert, 10981719f85SDan Gohman AliasAnalysis &AA) { 110391a98afSDan Gohman assert(Def->getParent() == Insert->getParent()); 11181719f85SDan Gohman bool SawStore = false, SawSideEffects = false; 11281719f85SDan Gohman MachineBasicBlock::const_iterator D(Def), I(Insert); 11381719f85SDan Gohman for (--I; I != D; --I) 11481719f85SDan Gohman SawSideEffects |= I->isSafeToMove(&AA, SawStore); 11581719f85SDan Gohman 11681719f85SDan Gohman return !(SawStore && Def->mayLoad() && !Def->isInvariantLoad(&AA)) && 11781719f85SDan Gohman !(SawSideEffects && !Def->isSafeToMove(&AA, SawStore)); 11881719f85SDan Gohman } 11981719f85SDan Gohman 1201462faadSDan Gohman bool WebAssemblyRegStackify::runOnMachineFunction(MachineFunction &MF) { 1211462faadSDan Gohman DEBUG(dbgs() << "********** Register Stackifying **********\n" 1221462faadSDan Gohman "********** Function: " 1231462faadSDan Gohman << MF.getName() << '\n'); 1241462faadSDan Gohman 1251462faadSDan Gohman bool Changed = false; 1261462faadSDan Gohman MachineRegisterInfo &MRI = MF.getRegInfo(); 1271462faadSDan Gohman WebAssemblyFunctionInfo &MFI = *MF.getInfo<WebAssemblyFunctionInfo>(); 12881719f85SDan Gohman AliasAnalysis &AA = getAnalysis<AAResultsWrapperPass>().getAAResults(); 1291462faadSDan Gohman 130*d70e5907SDan Gohman assert(MRI.isSSA() && "RegStackify depends on SSA form"); 131*d70e5907SDan Gohman 1321462faadSDan Gohman // Walk the instructions from the bottom up. Currently we don't look past 1331462faadSDan Gohman // block boundaries, and the blocks aren't ordered so the block visitation 1341462faadSDan Gohman // order isn't significant, but we may want to change this in the future. 1351462faadSDan Gohman for (MachineBasicBlock &MBB : MF) { 1361462faadSDan Gohman for (MachineInstr &MI : reverse(MBB)) { 1371462faadSDan Gohman MachineInstr *Insert = &MI; 1381462faadSDan Gohman 1391462faadSDan Gohman // Don't nest anything inside a phi. 1401462faadSDan Gohman if (Insert->getOpcode() == TargetOpcode::PHI) 1411462faadSDan Gohman break; 1421462faadSDan Gohman 14381719f85SDan Gohman // Don't nest anything inside an inline asm, because we don't have 14481719f85SDan Gohman // constraints for $push inputs. 14581719f85SDan Gohman if (Insert->getOpcode() == TargetOpcode::INLINEASM) 14681719f85SDan Gohman break; 14781719f85SDan Gohman 1481462faadSDan Gohman // Iterate through the inputs in reverse order, since we'll be pulling 14953d13997SDan Gohman // operands off the stack in LIFO order. 150b0992dafSDan Gohman bool AnyStackified = false; 1511462faadSDan Gohman for (MachineOperand &Op : reverse(Insert->uses())) { 1521462faadSDan Gohman // We're only interested in explicit virtual register operands. 15381719f85SDan Gohman if (!Op.isReg() || Op.isImplicit() || !Op.isUse()) 1541462faadSDan Gohman continue; 1551462faadSDan Gohman 1561462faadSDan Gohman unsigned Reg = Op.getReg(); 1574da4abd8SDan Gohman if (TargetRegisterInfo::isPhysicalRegister(Reg)) { 1584da4abd8SDan Gohman // An instruction with a physical register. Conservatively mark it as 1594da4abd8SDan Gohman // an expression stack input so that it isn't reordered with anything 1604da4abd8SDan Gohman // in an expression stack which might use it (physical registers 1614da4abd8SDan Gohman // aren't in SSA form so it's not trivial to determine this). 1624da4abd8SDan Gohman // TODO: Be less conservative. 1634da4abd8SDan Gohman ImposeStackInputOrdering(Insert); 1641462faadSDan Gohman continue; 1654da4abd8SDan Gohman } 1661462faadSDan Gohman 1671462faadSDan Gohman // Only consider registers with a single definition. 1681462faadSDan Gohman // TODO: Eventually we may relax this, to stackify phi transfers. 1691462faadSDan Gohman MachineInstr *Def = MRI.getVRegDef(Reg); 1701462faadSDan Gohman if (!Def) 1711462faadSDan Gohman continue; 1721462faadSDan Gohman 1731462faadSDan Gohman // There's no use in nesting implicit defs inside anything. 1741462faadSDan Gohman if (Def->getOpcode() == TargetOpcode::IMPLICIT_DEF) 1751462faadSDan Gohman continue; 1761462faadSDan Gohman 17781719f85SDan Gohman // Don't nest an INLINE_ASM def into anything, because we don't have 17881719f85SDan Gohman // constraints for $pop outputs. 17981719f85SDan Gohman if (Def->getOpcode() == TargetOpcode::INLINEASM) 18081719f85SDan Gohman continue; 18181719f85SDan Gohman 18281719f85SDan Gohman // Don't nest PHIs inside of anything. 18381719f85SDan Gohman if (Def->getOpcode() == TargetOpcode::PHI) 18481719f85SDan Gohman continue; 18581719f85SDan Gohman 1864ba4816bSDan Gohman // Argument instructions represent live-in registers and not real 1874ba4816bSDan Gohman // instructions. 1884ba4816bSDan Gohman if (Def->getOpcode() == WebAssembly::ARGUMENT_I32 || 1894ba4816bSDan Gohman Def->getOpcode() == WebAssembly::ARGUMENT_I64 || 1904ba4816bSDan Gohman Def->getOpcode() == WebAssembly::ARGUMENT_F32 || 1914ba4816bSDan Gohman Def->getOpcode() == WebAssembly::ARGUMENT_F64) 1924ba4816bSDan Gohman continue; 1934ba4816bSDan Gohman 194391a98afSDan Gohman // Single-use expression trees require defs that have one use. 1951462faadSDan Gohman // TODO: Eventually we'll relax this, to take advantage of set_local 1961462faadSDan Gohman // returning its result. 19781719f85SDan Gohman if (!MRI.hasOneUse(Reg)) 1981462faadSDan Gohman continue; 1991462faadSDan Gohman 200391a98afSDan Gohman // For now, be conservative and don't look across block boundaries. 2011462faadSDan Gohman // TODO: Be more aggressive. 202391a98afSDan Gohman if (Def->getParent() != &MBB) 2031462faadSDan Gohman continue; 2041462faadSDan Gohman 20581719f85SDan Gohman // Don't move instructions that have side effects or memory dependencies 20681719f85SDan Gohman // or other complications. 20781719f85SDan Gohman if (!IsSafeToMove(Def, Insert, AA)) 2081462faadSDan Gohman continue; 2091462faadSDan Gohman 2101462faadSDan Gohman Changed = true; 211b0992dafSDan Gohman AnyStackified = true; 2121462faadSDan Gohman // Move the def down and nest it in the current instruction. 2131462faadSDan Gohman MBB.insert(MachineBasicBlock::instr_iterator(Insert), 2141462faadSDan Gohman Def->removeFromParent()); 2151462faadSDan Gohman MFI.stackifyVReg(Reg); 2164da4abd8SDan Gohman ImposeStackOrdering(Def, MRI); 2171462faadSDan Gohman Insert = Def; 2181462faadSDan Gohman } 219b0992dafSDan Gohman if (AnyStackified) 2204da4abd8SDan Gohman ImposeStackOrdering(&MI, MRI); 2211462faadSDan Gohman } 2221462faadSDan Gohman } 2231462faadSDan Gohman 224b0992dafSDan Gohman // If we used EXPR_STACK anywhere, add it to the live-in sets everywhere 225b0992dafSDan Gohman // so that it never looks like a use-before-def. 226b0992dafSDan Gohman if (Changed) { 227b0992dafSDan Gohman MF.getRegInfo().addLiveIn(WebAssembly::EXPR_STACK); 228b0992dafSDan Gohman for (MachineBasicBlock &MBB : MF) 229b0992dafSDan Gohman MBB.addLiveIn(WebAssembly::EXPR_STACK); 230b0992dafSDan Gohman } 231b0992dafSDan Gohman 2327bafa0eaSDan Gohman #ifndef NDEBUG 2337bafa0eaSDan Gohman // Verify that pushes and pops are performed in FIFO order. 2347bafa0eaSDan Gohman SmallVector<unsigned, 0> Stack; 2357bafa0eaSDan Gohman for (MachineBasicBlock &MBB : MF) { 2367bafa0eaSDan Gohman for (MachineInstr &MI : MBB) { 2377bafa0eaSDan Gohman for (MachineOperand &MO : reverse(MI.explicit_operands())) { 2387a6b9825SDan Gohman if (!MO.isReg()) 2397a6b9825SDan Gohman continue; 2407bafa0eaSDan Gohman unsigned VReg = MO.getReg(); 2417bafa0eaSDan Gohman 24235bfb24cSDan Gohman // Don't stackify physregs like SP or FP. 24335bfb24cSDan Gohman if (!TargetRegisterInfo::isVirtualRegister(VReg)) 24435bfb24cSDan Gohman continue; 24535bfb24cSDan Gohman 2467bafa0eaSDan Gohman if (MFI.isVRegStackified(VReg)) { 2477bafa0eaSDan Gohman if (MO.isDef()) 2487bafa0eaSDan Gohman Stack.push_back(VReg); 2497bafa0eaSDan Gohman else 2507bafa0eaSDan Gohman assert(Stack.pop_back_val() == VReg); 2517bafa0eaSDan Gohman } 2527bafa0eaSDan Gohman } 2537bafa0eaSDan Gohman } 2547bafa0eaSDan Gohman // TODO: Generalize this code to support keeping values on the stack across 2557bafa0eaSDan Gohman // basic block boundaries. 2567bafa0eaSDan Gohman assert(Stack.empty()); 2577bafa0eaSDan Gohman } 2587bafa0eaSDan Gohman #endif 2597bafa0eaSDan Gohman 2601462faadSDan Gohman return Changed; 2611462faadSDan Gohman } 262