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"
278887d1faSDan Gohman #include "llvm/CodeGen/LiveIntervalAnalysis.h"
281462faadSDan Gohman #include "llvm/CodeGen/MachineBlockFrequencyInfo.h"
291462faadSDan Gohman #include "llvm/CodeGen/MachineRegisterInfo.h"
301462faadSDan Gohman #include "llvm/CodeGen/Passes.h"
311462faadSDan Gohman #include "llvm/Support/Debug.h"
321462faadSDan Gohman #include "llvm/Support/raw_ostream.h"
331462faadSDan Gohman using namespace llvm;
341462faadSDan Gohman 
351462faadSDan Gohman #define DEBUG_TYPE "wasm-reg-stackify"
361462faadSDan Gohman 
371462faadSDan Gohman namespace {
381462faadSDan Gohman class WebAssemblyRegStackify final : public MachineFunctionPass {
391462faadSDan Gohman   const char *getPassName() const override {
401462faadSDan Gohman     return "WebAssembly Register Stackify";
411462faadSDan Gohman   }
421462faadSDan Gohman 
431462faadSDan Gohman   void getAnalysisUsage(AnalysisUsage &AU) const override {
441462faadSDan Gohman     AU.setPreservesCFG();
4581719f85SDan Gohman     AU.addRequired<AAResultsWrapperPass>();
468887d1faSDan Gohman     AU.addRequired<LiveIntervals>();
471462faadSDan Gohman     AU.addPreserved<MachineBlockFrequencyInfo>();
488887d1faSDan Gohman     AU.addPreserved<SlotIndexes>();
498887d1faSDan Gohman     AU.addPreserved<LiveIntervals>();
501462faadSDan Gohman     AU.addPreservedID(MachineDominatorsID);
518887d1faSDan Gohman     AU.addPreservedID(LiveVariablesID);
521462faadSDan Gohman     MachineFunctionPass::getAnalysisUsage(AU);
531462faadSDan Gohman   }
541462faadSDan Gohman 
551462faadSDan Gohman   bool runOnMachineFunction(MachineFunction &MF) override;
561462faadSDan Gohman 
571462faadSDan Gohman public:
581462faadSDan Gohman   static char ID; // Pass identification, replacement for typeid
591462faadSDan Gohman   WebAssemblyRegStackify() : MachineFunctionPass(ID) {}
601462faadSDan Gohman };
611462faadSDan Gohman } // end anonymous namespace
621462faadSDan Gohman 
631462faadSDan Gohman char WebAssemblyRegStackify::ID = 0;
641462faadSDan Gohman FunctionPass *llvm::createWebAssemblyRegStackify() {
651462faadSDan Gohman   return new WebAssemblyRegStackify();
661462faadSDan Gohman }
671462faadSDan Gohman 
68b0992dafSDan Gohman // Decorate the given instruction with implicit operands that enforce the
698887d1faSDan Gohman // expression stack ordering constraints for an instruction which is on
708887d1faSDan Gohman // the expression stack.
718887d1faSDan Gohman static void ImposeStackOrdering(MachineInstr *MI) {
724da4abd8SDan Gohman   // Write the opaque EXPR_STACK register.
734da4abd8SDan Gohman   if (!MI->definesRegister(WebAssembly::EXPR_STACK))
74b0992dafSDan Gohman     MI->addOperand(MachineOperand::CreateReg(WebAssembly::EXPR_STACK,
75b0992dafSDan Gohman                                              /*isDef=*/true,
76b0992dafSDan Gohman                                              /*isImp=*/true));
774da4abd8SDan Gohman 
784da4abd8SDan Gohman   // Also read the opaque EXPR_STACK register.
79a712a6c4SDan Gohman   if (!MI->readsRegister(WebAssembly::EXPR_STACK))
80b0992dafSDan Gohman     MI->addOperand(MachineOperand::CreateReg(WebAssembly::EXPR_STACK,
81b0992dafSDan Gohman                                              /*isDef=*/false,
82b0992dafSDan Gohman                                              /*isImp=*/true));
83b0992dafSDan Gohman }
84b0992dafSDan Gohman 
858887d1faSDan Gohman // Test whether it's safe to move Def to just before Insert.
8681719f85SDan Gohman // TODO: Compute memory dependencies in a way that doesn't require always
8781719f85SDan Gohman // walking the block.
8881719f85SDan Gohman // TODO: Compute memory dependencies in a way that uses AliasAnalysis to be
8981719f85SDan Gohman // more precise.
9081719f85SDan Gohman static bool IsSafeToMove(const MachineInstr *Def, const MachineInstr *Insert,
918887d1faSDan Gohman                          AliasAnalysis &AA, LiveIntervals &LIS,
928887d1faSDan Gohman                          MachineRegisterInfo &MRI) {
93391a98afSDan Gohman   assert(Def->getParent() == Insert->getParent());
9481719f85SDan Gohman   bool SawStore = false, SawSideEffects = false;
9581719f85SDan Gohman   MachineBasicBlock::const_iterator D(Def), I(Insert);
968887d1faSDan Gohman 
978887d1faSDan Gohman   // Check for register dependencies.
988887d1faSDan Gohman   for (const MachineOperand &MO : Def->operands()) {
998887d1faSDan Gohman     if (!MO.isReg() || MO.isUndef())
1008887d1faSDan Gohman       continue;
1018887d1faSDan Gohman     unsigned Reg = MO.getReg();
1028887d1faSDan Gohman 
1038887d1faSDan Gohman     // If the register is dead here and at Insert, ignore it.
1048887d1faSDan Gohman     if (MO.isDead() && Insert->definesRegister(Reg) &&
1058887d1faSDan Gohman         !Insert->readsRegister(Reg))
1068887d1faSDan Gohman       continue;
1078887d1faSDan Gohman 
1088887d1faSDan Gohman     if (TargetRegisterInfo::isPhysicalRegister(Reg)) {
1098887d1faSDan Gohman       // If the physical register is never modified, ignore it.
1108887d1faSDan Gohman       if (!MRI.isPhysRegModified(Reg))
1118887d1faSDan Gohman         continue;
1128887d1faSDan Gohman       // Otherwise, it's a physical register with unknown liveness.
1138887d1faSDan Gohman       return false;
1148887d1faSDan Gohman     }
1158887d1faSDan Gohman 
1168887d1faSDan Gohman     // Ask LiveIntervals whether moving this virtual register use or def to
1178887d1faSDan Gohman     // Insert will change value numbers are seen.
1188887d1faSDan Gohman     const LiveInterval &LI = LIS.getInterval(Reg);
1198887d1faSDan Gohman     VNInfo *DefVNI = MO.isDef() ?
1208887d1faSDan Gohman         LI.getVNInfoAt(LIS.getInstructionIndex(Def).getRegSlot()) :
1218887d1faSDan Gohman         LI.getVNInfoBefore(LIS.getInstructionIndex(Def));
1228887d1faSDan Gohman     assert(DefVNI && "Instruction input missing value number");
1238887d1faSDan Gohman     VNInfo *InsVNI = LI.getVNInfoBefore(LIS.getInstructionIndex(Insert));
1248887d1faSDan Gohman     if (InsVNI && DefVNI != InsVNI)
1258887d1faSDan Gohman       return false;
1268887d1faSDan Gohman   }
1278887d1faSDan Gohman 
1288887d1faSDan Gohman   // Check for memory dependencies and side effects.
12981719f85SDan Gohman   for (--I; I != D; --I)
13081719f85SDan Gohman     SawSideEffects |= I->isSafeToMove(&AA, SawStore);
13181719f85SDan Gohman   return !(SawStore && Def->mayLoad() && !Def->isInvariantLoad(&AA)) &&
13281719f85SDan Gohman          !(SawSideEffects && !Def->isSafeToMove(&AA, SawStore));
13381719f85SDan Gohman }
13481719f85SDan Gohman 
1351462faadSDan Gohman bool WebAssemblyRegStackify::runOnMachineFunction(MachineFunction &MF) {
1361462faadSDan Gohman   DEBUG(dbgs() << "********** Register Stackifying **********\n"
1371462faadSDan Gohman                   "********** Function: "
1381462faadSDan Gohman                << MF.getName() << '\n');
1391462faadSDan Gohman 
1401462faadSDan Gohman   bool Changed = false;
1411462faadSDan Gohman   MachineRegisterInfo &MRI = MF.getRegInfo();
1421462faadSDan Gohman   WebAssemblyFunctionInfo &MFI = *MF.getInfo<WebAssemblyFunctionInfo>();
14381719f85SDan Gohman   AliasAnalysis &AA = getAnalysis<AAResultsWrapperPass>().getAAResults();
1448887d1faSDan Gohman   LiveIntervals &LIS = getAnalysis<LiveIntervals>();
145d70e5907SDan Gohman 
1461462faadSDan Gohman   // Walk the instructions from the bottom up. Currently we don't look past
1471462faadSDan Gohman   // block boundaries, and the blocks aren't ordered so the block visitation
1481462faadSDan Gohman   // order isn't significant, but we may want to change this in the future.
1491462faadSDan Gohman   for (MachineBasicBlock &MBB : MF) {
150*8f59cf75SDan Gohman     // Don't use a range-based for loop, because we modify the list as we're
151*8f59cf75SDan Gohman     // iterating over it and the end iterator may change.
152*8f59cf75SDan Gohman     for (auto MII = MBB.rbegin(); MII != MBB.rend(); ++MII) {
153*8f59cf75SDan Gohman       MachineInstr *Insert = &*MII;
1541462faadSDan Gohman       // Don't nest anything inside a phi.
1551462faadSDan Gohman       if (Insert->getOpcode() == TargetOpcode::PHI)
1561462faadSDan Gohman         break;
1571462faadSDan Gohman 
15881719f85SDan Gohman       // Don't nest anything inside an inline asm, because we don't have
15981719f85SDan Gohman       // constraints for $push inputs.
16081719f85SDan Gohman       if (Insert->getOpcode() == TargetOpcode::INLINEASM)
16181719f85SDan Gohman         break;
16281719f85SDan Gohman 
1631462faadSDan Gohman       // Iterate through the inputs in reverse order, since we'll be pulling
16453d13997SDan Gohman       // operands off the stack in LIFO order.
165b0992dafSDan Gohman       bool AnyStackified = false;
1661462faadSDan Gohman       for (MachineOperand &Op : reverse(Insert->uses())) {
1671462faadSDan Gohman         // We're only interested in explicit virtual register operands.
16881719f85SDan Gohman         if (!Op.isReg() || Op.isImplicit() || !Op.isUse())
1691462faadSDan Gohman           continue;
1701462faadSDan Gohman 
1711462faadSDan Gohman         unsigned Reg = Op.getReg();
1721462faadSDan Gohman 
1731462faadSDan Gohman         // Only consider registers with a single definition.
1741462faadSDan Gohman         // TODO: Eventually we may relax this, to stackify phi transfers.
1758887d1faSDan Gohman         MachineInstr *Def = MRI.getUniqueVRegDef(Reg);
1761462faadSDan Gohman         if (!Def)
1771462faadSDan Gohman           continue;
1781462faadSDan Gohman 
1791462faadSDan Gohman         // There's no use in nesting implicit defs inside anything.
1801462faadSDan Gohman         if (Def->getOpcode() == TargetOpcode::IMPLICIT_DEF)
1811462faadSDan Gohman           continue;
1821462faadSDan Gohman 
18381719f85SDan Gohman         // Don't nest an INLINE_ASM def into anything, because we don't have
18481719f85SDan Gohman         // constraints for $pop outputs.
18581719f85SDan Gohman         if (Def->getOpcode() == TargetOpcode::INLINEASM)
18681719f85SDan Gohman           continue;
18781719f85SDan Gohman 
18881719f85SDan Gohman         // Don't nest PHIs inside of anything.
18981719f85SDan Gohman         if (Def->getOpcode() == TargetOpcode::PHI)
19081719f85SDan Gohman           continue;
19181719f85SDan Gohman 
1924ba4816bSDan Gohman         // Argument instructions represent live-in registers and not real
1934ba4816bSDan Gohman         // instructions.
1944ba4816bSDan Gohman         if (Def->getOpcode() == WebAssembly::ARGUMENT_I32 ||
1954ba4816bSDan Gohman             Def->getOpcode() == WebAssembly::ARGUMENT_I64 ||
1964ba4816bSDan Gohman             Def->getOpcode() == WebAssembly::ARGUMENT_F32 ||
1974ba4816bSDan Gohman             Def->getOpcode() == WebAssembly::ARGUMENT_F64)
1984ba4816bSDan Gohman           continue;
1994ba4816bSDan Gohman 
200391a98afSDan Gohman         // Single-use expression trees require defs that have one use.
2011462faadSDan Gohman         // TODO: Eventually we'll relax this, to take advantage of set_local
2021462faadSDan Gohman         // returning its result.
20381719f85SDan Gohman         if (!MRI.hasOneUse(Reg))
2041462faadSDan Gohman           continue;
2051462faadSDan Gohman 
206391a98afSDan Gohman         // For now, be conservative and don't look across block boundaries.
2078887d1faSDan Gohman         // TODO: Be more aggressive?
208391a98afSDan Gohman         if (Def->getParent() != &MBB)
2091462faadSDan Gohman           continue;
2101462faadSDan Gohman 
21181719f85SDan Gohman         // Don't move instructions that have side effects or memory dependencies
21281719f85SDan Gohman         // or other complications.
2138887d1faSDan Gohman         if (!IsSafeToMove(Def, Insert, AA, LIS, MRI))
2141462faadSDan Gohman           continue;
2151462faadSDan Gohman 
2161462faadSDan Gohman         Changed = true;
217b0992dafSDan Gohman         AnyStackified = true;
2181462faadSDan Gohman         // Move the def down and nest it in the current instruction.
2198887d1faSDan Gohman         MBB.splice(Insert, &MBB, Def);
2208887d1faSDan Gohman         LIS.handleMove(Def);
2211462faadSDan Gohman         MFI.stackifyVReg(Reg);
2228887d1faSDan Gohman         ImposeStackOrdering(Def);
2231462faadSDan Gohman         Insert = Def;
2241462faadSDan Gohman       }
225b0992dafSDan Gohman       if (AnyStackified)
226*8f59cf75SDan Gohman         ImposeStackOrdering(&*MII);
2271462faadSDan Gohman     }
2281462faadSDan Gohman   }
2291462faadSDan Gohman 
230b0992dafSDan Gohman   // If we used EXPR_STACK anywhere, add it to the live-in sets everywhere
231b0992dafSDan Gohman   // so that it never looks like a use-before-def.
232b0992dafSDan Gohman   if (Changed) {
233b0992dafSDan Gohman     MF.getRegInfo().addLiveIn(WebAssembly::EXPR_STACK);
234b0992dafSDan Gohman     for (MachineBasicBlock &MBB : MF)
235b0992dafSDan Gohman       MBB.addLiveIn(WebAssembly::EXPR_STACK);
236b0992dafSDan Gohman   }
237b0992dafSDan Gohman 
2387bafa0eaSDan Gohman #ifndef NDEBUG
2397bafa0eaSDan Gohman   // Verify that pushes and pops are performed in FIFO order.
2407bafa0eaSDan Gohman   SmallVector<unsigned, 0> Stack;
2417bafa0eaSDan Gohman   for (MachineBasicBlock &MBB : MF) {
2427bafa0eaSDan Gohman     for (MachineInstr &MI : MBB) {
2437bafa0eaSDan Gohman       for (MachineOperand &MO : reverse(MI.explicit_operands())) {
2447a6b9825SDan Gohman         if (!MO.isReg())
2457a6b9825SDan Gohman           continue;
2467bafa0eaSDan Gohman         unsigned VReg = MO.getReg();
2477bafa0eaSDan Gohman 
24835bfb24cSDan Gohman         // Don't stackify physregs like SP or FP.
24935bfb24cSDan Gohman         if (!TargetRegisterInfo::isVirtualRegister(VReg))
25035bfb24cSDan Gohman           continue;
25135bfb24cSDan Gohman 
2527bafa0eaSDan Gohman         if (MFI.isVRegStackified(VReg)) {
2537bafa0eaSDan Gohman           if (MO.isDef())
2547bafa0eaSDan Gohman             Stack.push_back(VReg);
2557bafa0eaSDan Gohman           else
2567bafa0eaSDan Gohman             assert(Stack.pop_back_val() == VReg);
2577bafa0eaSDan Gohman         }
2587bafa0eaSDan Gohman       }
2597bafa0eaSDan Gohman     }
2607bafa0eaSDan Gohman     // TODO: Generalize this code to support keeping values on the stack across
2617bafa0eaSDan Gohman     // basic block boundaries.
2627bafa0eaSDan Gohman     assert(Stack.empty());
2637bafa0eaSDan Gohman   }
2647bafa0eaSDan Gohman #endif
2657bafa0eaSDan Gohman 
2661462faadSDan Gohman   return Changed;
2671462faadSDan Gohman }
268