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