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"
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.
81*a712a6c4SDan Gohman   if (!MI->readsRegister(WebAssembly::EXPR_STACK))
82b0992dafSDan Gohman     MI->addOperand(MachineOperand::CreateReg(WebAssembly::EXPR_STACK,
83b0992dafSDan Gohman                                              /*isDef=*/false,
84b0992dafSDan Gohman                                              /*isImp=*/true));
854da4abd8SDan Gohman 
864da4abd8SDan Gohman   // Also, mark any inputs to this instruction as being consumed by an
874da4abd8SDan Gohman   // instruction on the expression stack.
884da4abd8SDan Gohman   // TODO: Find a lighter way to describe the appropriate constraints.
894da4abd8SDan Gohman   for (MachineOperand &MO : MI->uses()) {
904da4abd8SDan Gohman     if (!MO.isReg())
914da4abd8SDan Gohman       continue;
924da4abd8SDan Gohman     unsigned Reg = MO.getReg();
934da4abd8SDan Gohman     if (!TargetRegisterInfo::isVirtualRegister(Reg))
944da4abd8SDan Gohman       continue;
954da4abd8SDan Gohman     MachineInstr *Def = MRI.getVRegDef(Reg);
964da4abd8SDan Gohman     if (Def->getOpcode() == TargetOpcode::PHI)
974da4abd8SDan Gohman       continue;
984da4abd8SDan Gohman     ImposeStackInputOrdering(Def);
994da4abd8SDan Gohman   }
100b0992dafSDan Gohman }
101b0992dafSDan Gohman 
10281719f85SDan Gohman // Test whether it's safe to move Def to just before Insert. Note that this
10381719f85SDan Gohman // doesn't account for physical register dependencies, because WebAssembly
10481719f85SDan Gohman // doesn't have any (other than special ones like EXPR_STACK).
10581719f85SDan Gohman // TODO: Compute memory dependencies in a way that doesn't require always
10681719f85SDan Gohman // walking the block.
10781719f85SDan Gohman // TODO: Compute memory dependencies in a way that uses AliasAnalysis to be
10881719f85SDan Gohman // more precise.
10981719f85SDan Gohman static bool IsSafeToMove(const MachineInstr *Def, const MachineInstr *Insert,
11081719f85SDan Gohman                          AliasAnalysis &AA) {
111391a98afSDan Gohman   assert(Def->getParent() == Insert->getParent());
11281719f85SDan Gohman   bool SawStore = false, SawSideEffects = false;
11381719f85SDan Gohman   MachineBasicBlock::const_iterator D(Def), I(Insert);
11481719f85SDan Gohman   for (--I; I != D; --I)
11581719f85SDan Gohman     SawSideEffects |= I->isSafeToMove(&AA, SawStore);
11681719f85SDan Gohman 
11781719f85SDan Gohman   return !(SawStore && Def->mayLoad() && !Def->isInvariantLoad(&AA)) &&
11881719f85SDan Gohman          !(SawSideEffects && !Def->isSafeToMove(&AA, SawStore));
11981719f85SDan Gohman }
12081719f85SDan Gohman 
1211462faadSDan Gohman bool WebAssemblyRegStackify::runOnMachineFunction(MachineFunction &MF) {
1221462faadSDan Gohman   DEBUG(dbgs() << "********** Register Stackifying **********\n"
1231462faadSDan Gohman                   "********** Function: "
1241462faadSDan Gohman                << MF.getName() << '\n');
1251462faadSDan Gohman 
1261462faadSDan Gohman   bool Changed = false;
1271462faadSDan Gohman   MachineRegisterInfo &MRI = MF.getRegInfo();
1281462faadSDan Gohman   WebAssemblyFunctionInfo &MFI = *MF.getInfo<WebAssemblyFunctionInfo>();
12981719f85SDan Gohman   AliasAnalysis &AA = getAnalysis<AAResultsWrapperPass>().getAAResults();
1301462faadSDan Gohman 
131d70e5907SDan Gohman   assert(MRI.isSSA() && "RegStackify depends on SSA form");
132d70e5907SDan Gohman 
1331462faadSDan Gohman   // Walk the instructions from the bottom up. Currently we don't look past
1341462faadSDan Gohman   // block boundaries, and the blocks aren't ordered so the block visitation
1351462faadSDan Gohman   // order isn't significant, but we may want to change this in the future.
1361462faadSDan Gohman   for (MachineBasicBlock &MBB : MF) {
1371462faadSDan Gohman     for (MachineInstr &MI : reverse(MBB)) {
1381462faadSDan Gohman       MachineInstr *Insert = &MI;
1391462faadSDan Gohman 
1401462faadSDan Gohman       // Don't nest anything inside a phi.
1411462faadSDan Gohman       if (Insert->getOpcode() == TargetOpcode::PHI)
1421462faadSDan Gohman         break;
1431462faadSDan Gohman 
14481719f85SDan Gohman       // Don't nest anything inside an inline asm, because we don't have
14581719f85SDan Gohman       // constraints for $push inputs.
14681719f85SDan Gohman       if (Insert->getOpcode() == TargetOpcode::INLINEASM)
14781719f85SDan Gohman         break;
14881719f85SDan Gohman 
1491462faadSDan Gohman       // Iterate through the inputs in reverse order, since we'll be pulling
15053d13997SDan Gohman       // operands off the stack in LIFO order.
151b0992dafSDan Gohman       bool AnyStackified = false;
1521462faadSDan Gohman       for (MachineOperand &Op : reverse(Insert->uses())) {
1531462faadSDan Gohman         // We're only interested in explicit virtual register operands.
15481719f85SDan Gohman         if (!Op.isReg() || Op.isImplicit() || !Op.isUse())
1551462faadSDan Gohman           continue;
1561462faadSDan Gohman 
1571462faadSDan Gohman         unsigned Reg = Op.getReg();
1584da4abd8SDan Gohman         if (TargetRegisterInfo::isPhysicalRegister(Reg)) {
1594da4abd8SDan Gohman           // An instruction with a physical register. Conservatively mark it as
1604da4abd8SDan Gohman           // an expression stack input so that it isn't reordered with anything
1614da4abd8SDan Gohman           // in an expression stack which might use it (physical registers
1624da4abd8SDan Gohman           // aren't in SSA form so it's not trivial to determine this).
1634da4abd8SDan Gohman           // TODO: Be less conservative.
1644da4abd8SDan Gohman           ImposeStackInputOrdering(Insert);
1651462faadSDan Gohman           continue;
1664da4abd8SDan Gohman         }
1671462faadSDan Gohman 
1681462faadSDan Gohman         // Only consider registers with a single definition.
1691462faadSDan Gohman         // TODO: Eventually we may relax this, to stackify phi transfers.
1701462faadSDan Gohman         MachineInstr *Def = MRI.getVRegDef(Reg);
1711462faadSDan Gohman         if (!Def)
1721462faadSDan Gohman           continue;
1731462faadSDan Gohman 
1741462faadSDan Gohman         // There's no use in nesting implicit defs inside anything.
1751462faadSDan Gohman         if (Def->getOpcode() == TargetOpcode::IMPLICIT_DEF)
1761462faadSDan Gohman           continue;
1771462faadSDan Gohman 
17881719f85SDan Gohman         // Don't nest an INLINE_ASM def into anything, because we don't have
17981719f85SDan Gohman         // constraints for $pop outputs.
18081719f85SDan Gohman         if (Def->getOpcode() == TargetOpcode::INLINEASM)
18181719f85SDan Gohman           continue;
18281719f85SDan Gohman 
18381719f85SDan Gohman         // Don't nest PHIs inside of anything.
18481719f85SDan Gohman         if (Def->getOpcode() == TargetOpcode::PHI)
18581719f85SDan Gohman           continue;
18681719f85SDan Gohman 
1874ba4816bSDan Gohman         // Argument instructions represent live-in registers and not real
1884ba4816bSDan Gohman         // instructions.
1894ba4816bSDan Gohman         if (Def->getOpcode() == WebAssembly::ARGUMENT_I32 ||
1904ba4816bSDan Gohman             Def->getOpcode() == WebAssembly::ARGUMENT_I64 ||
1914ba4816bSDan Gohman             Def->getOpcode() == WebAssembly::ARGUMENT_F32 ||
1924ba4816bSDan Gohman             Def->getOpcode() == WebAssembly::ARGUMENT_F64)
1934ba4816bSDan Gohman           continue;
1944ba4816bSDan Gohman 
195391a98afSDan Gohman         // Single-use expression trees require defs that have one use.
1961462faadSDan Gohman         // TODO: Eventually we'll relax this, to take advantage of set_local
1971462faadSDan Gohman         // returning its result.
19881719f85SDan Gohman         if (!MRI.hasOneUse(Reg))
1991462faadSDan Gohman           continue;
2001462faadSDan Gohman 
201391a98afSDan Gohman         // For now, be conservative and don't look across block boundaries.
2021462faadSDan Gohman         // TODO: Be more aggressive.
203391a98afSDan Gohman         if (Def->getParent() != &MBB)
2041462faadSDan Gohman           continue;
2051462faadSDan Gohman 
20681719f85SDan Gohman         // Don't move instructions that have side effects or memory dependencies
20781719f85SDan Gohman         // or other complications.
20881719f85SDan Gohman         if (!IsSafeToMove(Def, Insert, AA))
2091462faadSDan Gohman           continue;
2101462faadSDan Gohman 
2111462faadSDan Gohman         Changed = true;
212b0992dafSDan Gohman         AnyStackified = true;
2131462faadSDan Gohman         // Move the def down and nest it in the current instruction.
2141462faadSDan Gohman         MBB.insert(MachineBasicBlock::instr_iterator(Insert),
2151462faadSDan Gohman                    Def->removeFromParent());
2161462faadSDan Gohman         MFI.stackifyVReg(Reg);
2174da4abd8SDan Gohman         ImposeStackOrdering(Def, MRI);
2181462faadSDan Gohman         Insert = Def;
2191462faadSDan Gohman       }
220b0992dafSDan Gohman       if (AnyStackified)
2214da4abd8SDan Gohman         ImposeStackOrdering(&MI, MRI);
2221462faadSDan Gohman     }
2231462faadSDan Gohman   }
2241462faadSDan Gohman 
225b0992dafSDan Gohman   // If we used EXPR_STACK anywhere, add it to the live-in sets everywhere
226b0992dafSDan Gohman   // so that it never looks like a use-before-def.
227b0992dafSDan Gohman   if (Changed) {
228b0992dafSDan Gohman     MF.getRegInfo().addLiveIn(WebAssembly::EXPR_STACK);
229b0992dafSDan Gohman     for (MachineBasicBlock &MBB : MF)
230b0992dafSDan Gohman       MBB.addLiveIn(WebAssembly::EXPR_STACK);
231b0992dafSDan Gohman   }
232b0992dafSDan Gohman 
2337bafa0eaSDan Gohman #ifndef NDEBUG
2347bafa0eaSDan Gohman   // Verify that pushes and pops are performed in FIFO order.
2357bafa0eaSDan Gohman   SmallVector<unsigned, 0> Stack;
2367bafa0eaSDan Gohman   for (MachineBasicBlock &MBB : MF) {
2377bafa0eaSDan Gohman     for (MachineInstr &MI : MBB) {
2387bafa0eaSDan Gohman       for (MachineOperand &MO : reverse(MI.explicit_operands())) {
2397a6b9825SDan Gohman         if (!MO.isReg())
2407a6b9825SDan Gohman           continue;
2417bafa0eaSDan Gohman         unsigned VReg = MO.getReg();
2427bafa0eaSDan Gohman 
24335bfb24cSDan Gohman         // Don't stackify physregs like SP or FP.
24435bfb24cSDan Gohman         if (!TargetRegisterInfo::isVirtualRegister(VReg))
24535bfb24cSDan Gohman           continue;
24635bfb24cSDan Gohman 
2477bafa0eaSDan Gohman         if (MFI.isVRegStackified(VReg)) {
2487bafa0eaSDan Gohman           if (MO.isDef())
2497bafa0eaSDan Gohman             Stack.push_back(VReg);
2507bafa0eaSDan Gohman           else
2517bafa0eaSDan Gohman             assert(Stack.pop_back_val() == VReg);
2527bafa0eaSDan Gohman         }
2537bafa0eaSDan Gohman       }
2547bafa0eaSDan Gohman     }
2557bafa0eaSDan Gohman     // TODO: Generalize this code to support keeping values on the stack across
2567bafa0eaSDan Gohman     // basic block boundaries.
2577bafa0eaSDan Gohman     assert(Stack.empty());
2587bafa0eaSDan Gohman   }
2597bafa0eaSDan Gohman #endif
2607bafa0eaSDan Gohman 
2611462faadSDan Gohman   return Changed;
2621462faadSDan Gohman }
263