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