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" 241462faadSDan Gohman #include "WebAssemblyMachineFunctionInfo.h" 254ba4816bSDan Gohman #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" // for WebAssembly::ARGUMENT_* 261462faadSDan Gohman #include "llvm/CodeGen/MachineBlockFrequencyInfo.h" 271462faadSDan Gohman #include "llvm/CodeGen/MachineRegisterInfo.h" 281462faadSDan Gohman #include "llvm/CodeGen/Passes.h" 291462faadSDan Gohman #include "llvm/Support/Debug.h" 301462faadSDan Gohman #include "llvm/Support/raw_ostream.h" 311462faadSDan Gohman using namespace llvm; 321462faadSDan Gohman 331462faadSDan Gohman #define DEBUG_TYPE "wasm-reg-stackify" 341462faadSDan Gohman 351462faadSDan Gohman namespace { 361462faadSDan Gohman class WebAssemblyRegStackify final : public MachineFunctionPass { 371462faadSDan Gohman const char *getPassName() const override { 381462faadSDan Gohman return "WebAssembly Register Stackify"; 391462faadSDan Gohman } 401462faadSDan Gohman 411462faadSDan Gohman void getAnalysisUsage(AnalysisUsage &AU) const override { 421462faadSDan Gohman AU.setPreservesCFG(); 431462faadSDan Gohman AU.addPreserved<MachineBlockFrequencyInfo>(); 441462faadSDan Gohman AU.addPreservedID(MachineDominatorsID); 451462faadSDan Gohman MachineFunctionPass::getAnalysisUsage(AU); 461462faadSDan Gohman } 471462faadSDan Gohman 481462faadSDan Gohman bool runOnMachineFunction(MachineFunction &MF) override; 491462faadSDan Gohman 501462faadSDan Gohman public: 511462faadSDan Gohman static char ID; // Pass identification, replacement for typeid 521462faadSDan Gohman WebAssemblyRegStackify() : MachineFunctionPass(ID) {} 531462faadSDan Gohman }; 541462faadSDan Gohman } // end anonymous namespace 551462faadSDan Gohman 561462faadSDan Gohman char WebAssemblyRegStackify::ID = 0; 571462faadSDan Gohman FunctionPass *llvm::createWebAssemblyRegStackify() { 581462faadSDan Gohman return new WebAssemblyRegStackify(); 591462faadSDan Gohman } 601462faadSDan Gohman 61b0992dafSDan Gohman // Decorate the given instruction with implicit operands that enforce the 62b0992dafSDan Gohman // expression stack ordering constraints. 63b0992dafSDan Gohman static void ImposeStackOrdering(MachineInstr *MI) { 64b0992dafSDan Gohman // Read and write the opaque EXPR_STACK register. 65b0992dafSDan Gohman MI->addOperand(MachineOperand::CreateReg(WebAssembly::EXPR_STACK, 66b0992dafSDan Gohman /*isDef=*/true, 67b0992dafSDan Gohman /*isImp=*/true)); 68b0992dafSDan Gohman MI->addOperand(MachineOperand::CreateReg(WebAssembly::EXPR_STACK, 69b0992dafSDan Gohman /*isDef=*/false, 70b0992dafSDan Gohman /*isImp=*/true)); 71b0992dafSDan Gohman } 72b0992dafSDan Gohman 731462faadSDan Gohman bool WebAssemblyRegStackify::runOnMachineFunction(MachineFunction &MF) { 741462faadSDan Gohman DEBUG(dbgs() << "********** Register Stackifying **********\n" 751462faadSDan Gohman "********** Function: " 761462faadSDan Gohman << MF.getName() << '\n'); 771462faadSDan Gohman 781462faadSDan Gohman bool Changed = false; 791462faadSDan Gohman MachineRegisterInfo &MRI = MF.getRegInfo(); 801462faadSDan Gohman WebAssemblyFunctionInfo &MFI = *MF.getInfo<WebAssemblyFunctionInfo>(); 811462faadSDan Gohman 821462faadSDan Gohman // Walk the instructions from the bottom up. Currently we don't look past 831462faadSDan Gohman // block boundaries, and the blocks aren't ordered so the block visitation 841462faadSDan Gohman // order isn't significant, but we may want to change this in the future. 851462faadSDan Gohman for (MachineBasicBlock &MBB : MF) { 861462faadSDan Gohman for (MachineInstr &MI : reverse(MBB)) { 871462faadSDan Gohman MachineInstr *Insert = &MI; 881462faadSDan Gohman 891462faadSDan Gohman // Don't nest anything inside a phi. 901462faadSDan Gohman if (Insert->getOpcode() == TargetOpcode::PHI) 911462faadSDan Gohman break; 921462faadSDan Gohman 931462faadSDan Gohman // Iterate through the inputs in reverse order, since we'll be pulling 941462faadSDan Gohman // operands off the stack in FIFO order. 95b0992dafSDan Gohman bool AnyStackified = false; 961462faadSDan Gohman for (MachineOperand &Op : reverse(Insert->uses())) { 971462faadSDan Gohman // We're only interested in explicit virtual register operands. 981462faadSDan Gohman if (!Op.isReg() || Op.isImplicit()) 991462faadSDan Gohman continue; 1001462faadSDan Gohman 1011462faadSDan Gohman unsigned Reg = Op.getReg(); 1021462faadSDan Gohman if (!TargetRegisterInfo::isVirtualRegister(Reg)) 1031462faadSDan Gohman continue; 1041462faadSDan Gohman 1051462faadSDan Gohman // Only consider registers with a single definition. 1061462faadSDan Gohman // TODO: Eventually we may relax this, to stackify phi transfers. 1071462faadSDan Gohman MachineInstr *Def = MRI.getVRegDef(Reg); 1081462faadSDan Gohman if (!Def) 1091462faadSDan Gohman continue; 1101462faadSDan Gohman 1111462faadSDan Gohman // There's no use in nesting implicit defs inside anything. 1121462faadSDan Gohman if (Def->getOpcode() == TargetOpcode::IMPLICIT_DEF) 1131462faadSDan Gohman continue; 1141462faadSDan Gohman 1154ba4816bSDan Gohman // Argument instructions represent live-in registers and not real 1164ba4816bSDan Gohman // instructions. 1174ba4816bSDan Gohman if (Def->getOpcode() == WebAssembly::ARGUMENT_I32 || 1184ba4816bSDan Gohman Def->getOpcode() == WebAssembly::ARGUMENT_I64 || 1194ba4816bSDan Gohman Def->getOpcode() == WebAssembly::ARGUMENT_F32 || 1204ba4816bSDan Gohman Def->getOpcode() == WebAssembly::ARGUMENT_F64) 1214ba4816bSDan Gohman continue; 1224ba4816bSDan Gohman 1231462faadSDan Gohman // Single-use expression trees require defs that have one use, or that 1241462faadSDan Gohman // they be trivially clonable. 1251462faadSDan Gohman // TODO: Eventually we'll relax this, to take advantage of set_local 1261462faadSDan Gohman // returning its result. 1271462faadSDan Gohman bool OneUse = MRI.hasOneUse(Reg); 1281462faadSDan Gohman if (!OneUse && !Def->isMoveImmediate()) 1291462faadSDan Gohman continue; 1301462faadSDan Gohman 1311462faadSDan Gohman // For now, be conservative and don't look across block boundaries, 1321462faadSDan Gohman // unless we have something trivially clonable. 1331462faadSDan Gohman // TODO: Be more aggressive. 1341462faadSDan Gohman if (Def->getParent() != &MBB && !Def->isMoveImmediate()) 1351462faadSDan Gohman continue; 1361462faadSDan Gohman 1371462faadSDan Gohman // For now, be simple and don't reorder loads, stores, or side effects. 1381462faadSDan Gohman // TODO: Be more aggressive. 1391462faadSDan Gohman if ((Def->mayLoad() || Def->mayStore() || 1401462faadSDan Gohman Def->hasUnmodeledSideEffects())) 1411462faadSDan Gohman continue; 1421462faadSDan Gohman 1431462faadSDan Gohman Changed = true; 144b0992dafSDan Gohman AnyStackified = true; 1451462faadSDan Gohman if (OneUse) { 1461462faadSDan Gohman // Move the def down and nest it in the current instruction. 1471462faadSDan Gohman MBB.insert(MachineBasicBlock::instr_iterator(Insert), 1481462faadSDan Gohman Def->removeFromParent()); 1491462faadSDan Gohman MFI.stackifyVReg(Reg); 150b0992dafSDan Gohman ImposeStackOrdering(Def); 1511462faadSDan Gohman Insert = Def; 1521462faadSDan Gohman } else { 1531462faadSDan Gohman // Clone the def down and nest it in the current instruction. 1541462faadSDan Gohman MachineInstr *Clone = MF.CloneMachineInstr(Def); 1551462faadSDan Gohman unsigned OldReg = Def->getOperand(0).getReg(); 1561462faadSDan Gohman unsigned NewReg = MRI.createVirtualRegister(MRI.getRegClass(OldReg)); 1571462faadSDan Gohman assert(Op.getReg() == OldReg); 1581462faadSDan Gohman assert(Clone->getOperand(0).getReg() == OldReg); 1591462faadSDan Gohman Op.setReg(NewReg); 1601462faadSDan Gohman Clone->getOperand(0).setReg(NewReg); 1611462faadSDan Gohman MBB.insert(MachineBasicBlock::instr_iterator(Insert), Clone); 1621462faadSDan Gohman MFI.stackifyVReg(Reg); 163b0992dafSDan Gohman ImposeStackOrdering(Clone); 1641462faadSDan Gohman Insert = Clone; 1651462faadSDan Gohman } 1661462faadSDan Gohman } 167b0992dafSDan Gohman if (AnyStackified) 168b0992dafSDan Gohman ImposeStackOrdering(&MI); 1691462faadSDan Gohman } 1701462faadSDan Gohman } 1711462faadSDan Gohman 172b0992dafSDan Gohman // If we used EXPR_STACK anywhere, add it to the live-in sets everywhere 173b0992dafSDan Gohman // so that it never looks like a use-before-def. 174b0992dafSDan Gohman if (Changed) { 175b0992dafSDan Gohman MF.getRegInfo().addLiveIn(WebAssembly::EXPR_STACK); 176b0992dafSDan Gohman for (MachineBasicBlock &MBB : MF) 177b0992dafSDan Gohman MBB.addLiveIn(WebAssembly::EXPR_STACK); 178b0992dafSDan Gohman } 179b0992dafSDan Gohman 180*7bafa0eaSDan Gohman #ifndef NDEBUG 181*7bafa0eaSDan Gohman // Verify that pushes and pops are performed in FIFO order. 182*7bafa0eaSDan Gohman SmallVector<unsigned, 0> Stack; 183*7bafa0eaSDan Gohman for (MachineBasicBlock &MBB : MF) { 184*7bafa0eaSDan Gohman for (MachineInstr &MI : MBB) { 185*7bafa0eaSDan Gohman for (MachineOperand &MO : reverse(MI.explicit_operands())) { 186*7bafa0eaSDan Gohman if (!MO.isReg()) continue; 187*7bafa0eaSDan Gohman unsigned VReg = MO.getReg(); 188*7bafa0eaSDan Gohman 189*7bafa0eaSDan Gohman if (MFI.isVRegStackified(VReg)) { 190*7bafa0eaSDan Gohman if (MO.isDef()) 191*7bafa0eaSDan Gohman Stack.push_back(VReg); 192*7bafa0eaSDan Gohman else 193*7bafa0eaSDan Gohman assert(Stack.pop_back_val() == VReg); 194*7bafa0eaSDan Gohman } 195*7bafa0eaSDan Gohman } 196*7bafa0eaSDan Gohman } 197*7bafa0eaSDan Gohman // TODO: Generalize this code to support keeping values on the stack across 198*7bafa0eaSDan Gohman // basic block boundaries. 199*7bafa0eaSDan Gohman assert(Stack.empty()); 200*7bafa0eaSDan Gohman } 201*7bafa0eaSDan Gohman #endif 202*7bafa0eaSDan Gohman 2031462faadSDan Gohman return Changed; 2041462faadSDan Gohman } 205