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"
26b6fd39a3SDan Gohman #include "WebAssemblySubtarget.h"
2781719f85SDan Gohman #include "llvm/Analysis/AliasAnalysis.h"
288887d1faSDan Gohman #include "llvm/CodeGen/LiveIntervalAnalysis.h"
291462faadSDan Gohman #include "llvm/CodeGen/MachineBlockFrequencyInfo.h"
301462faadSDan Gohman #include "llvm/CodeGen/MachineRegisterInfo.h"
311462faadSDan Gohman #include "llvm/CodeGen/Passes.h"
321462faadSDan Gohman #include "llvm/Support/Debug.h"
331462faadSDan Gohman #include "llvm/Support/raw_ostream.h"
341462faadSDan Gohman using namespace llvm;
351462faadSDan Gohman 
361462faadSDan Gohman #define DEBUG_TYPE "wasm-reg-stackify"
371462faadSDan Gohman 
381462faadSDan Gohman namespace {
391462faadSDan Gohman class WebAssemblyRegStackify final : public MachineFunctionPass {
401462faadSDan Gohman   const char *getPassName() const override {
411462faadSDan Gohman     return "WebAssembly Register Stackify";
421462faadSDan Gohman   }
431462faadSDan Gohman 
441462faadSDan Gohman   void getAnalysisUsage(AnalysisUsage &AU) const override {
451462faadSDan Gohman     AU.setPreservesCFG();
4681719f85SDan Gohman     AU.addRequired<AAResultsWrapperPass>();
478887d1faSDan Gohman     AU.addRequired<LiveIntervals>();
481462faadSDan Gohman     AU.addPreserved<MachineBlockFrequencyInfo>();
498887d1faSDan Gohman     AU.addPreserved<SlotIndexes>();
508887d1faSDan Gohman     AU.addPreserved<LiveIntervals>();
511462faadSDan Gohman     AU.addPreservedID(MachineDominatorsID);
528887d1faSDan Gohman     AU.addPreservedID(LiveVariablesID);
531462faadSDan Gohman     MachineFunctionPass::getAnalysisUsage(AU);
541462faadSDan Gohman   }
551462faadSDan Gohman 
561462faadSDan Gohman   bool runOnMachineFunction(MachineFunction &MF) override;
571462faadSDan Gohman 
581462faadSDan Gohman public:
591462faadSDan Gohman   static char ID; // Pass identification, replacement for typeid
601462faadSDan Gohman   WebAssemblyRegStackify() : MachineFunctionPass(ID) {}
611462faadSDan Gohman };
621462faadSDan Gohman } // end anonymous namespace
631462faadSDan Gohman 
641462faadSDan Gohman char WebAssemblyRegStackify::ID = 0;
651462faadSDan Gohman FunctionPass *llvm::createWebAssemblyRegStackify() {
661462faadSDan Gohman   return new WebAssemblyRegStackify();
671462faadSDan Gohman }
681462faadSDan Gohman 
69b0992dafSDan Gohman // Decorate the given instruction with implicit operands that enforce the
708887d1faSDan Gohman // expression stack ordering constraints for an instruction which is on
718887d1faSDan Gohman // the expression stack.
728887d1faSDan Gohman static void ImposeStackOrdering(MachineInstr *MI) {
734da4abd8SDan Gohman   // Write the opaque EXPR_STACK register.
744da4abd8SDan Gohman   if (!MI->definesRegister(WebAssembly::EXPR_STACK))
75b0992dafSDan Gohman     MI->addOperand(MachineOperand::CreateReg(WebAssembly::EXPR_STACK,
76b0992dafSDan Gohman                                              /*isDef=*/true,
77b0992dafSDan Gohman                                              /*isImp=*/true));
784da4abd8SDan Gohman 
794da4abd8SDan Gohman   // Also read the opaque EXPR_STACK register.
80a712a6c4SDan Gohman   if (!MI->readsRegister(WebAssembly::EXPR_STACK))
81b0992dafSDan Gohman     MI->addOperand(MachineOperand::CreateReg(WebAssembly::EXPR_STACK,
82b0992dafSDan Gohman                                              /*isDef=*/false,
83b0992dafSDan Gohman                                              /*isImp=*/true));
84b0992dafSDan Gohman }
85b0992dafSDan Gohman 
868887d1faSDan Gohman // Test whether it's safe to move Def to just before Insert.
8781719f85SDan Gohman // TODO: Compute memory dependencies in a way that doesn't require always
8881719f85SDan Gohman // walking the block.
8981719f85SDan Gohman // TODO: Compute memory dependencies in a way that uses AliasAnalysis to be
9081719f85SDan Gohman // more precise.
9181719f85SDan Gohman static bool IsSafeToMove(const MachineInstr *Def, const MachineInstr *Insert,
928887d1faSDan Gohman                          AliasAnalysis &AA, LiveIntervals &LIS,
938887d1faSDan Gohman                          MachineRegisterInfo &MRI) {
94391a98afSDan Gohman   assert(Def->getParent() == Insert->getParent());
9581719f85SDan Gohman   bool SawStore = false, SawSideEffects = false;
9681719f85SDan Gohman   MachineBasicBlock::const_iterator D(Def), I(Insert);
978887d1faSDan Gohman 
988887d1faSDan Gohman   // Check for register dependencies.
998887d1faSDan Gohman   for (const MachineOperand &MO : Def->operands()) {
1008887d1faSDan Gohman     if (!MO.isReg() || MO.isUndef())
1018887d1faSDan Gohman       continue;
1028887d1faSDan Gohman     unsigned Reg = MO.getReg();
1038887d1faSDan Gohman 
1048887d1faSDan Gohman     // If the register is dead here and at Insert, ignore it.
1058887d1faSDan Gohman     if (MO.isDead() && Insert->definesRegister(Reg) &&
1068887d1faSDan Gohman         !Insert->readsRegister(Reg))
1078887d1faSDan Gohman       continue;
1088887d1faSDan Gohman 
1098887d1faSDan Gohman     if (TargetRegisterInfo::isPhysicalRegister(Reg)) {
1108887d1faSDan Gohman       // If the physical register is never modified, ignore it.
1118887d1faSDan Gohman       if (!MRI.isPhysRegModified(Reg))
1128887d1faSDan Gohman         continue;
1138887d1faSDan Gohman       // Otherwise, it's a physical register with unknown liveness.
1148887d1faSDan Gohman       return false;
1158887d1faSDan Gohman     }
1168887d1faSDan Gohman 
1178887d1faSDan Gohman     // Ask LiveIntervals whether moving this virtual register use or def to
1188887d1faSDan Gohman     // Insert will change value numbers are seen.
1198887d1faSDan Gohman     const LiveInterval &LI = LIS.getInterval(Reg);
120b6fd39a3SDan Gohman     VNInfo *DefVNI =
121b6fd39a3SDan Gohman         MO.isDef() ? LI.getVNInfoAt(LIS.getInstructionIndex(Def).getRegSlot())
122b6fd39a3SDan Gohman                    : LI.getVNInfoBefore(LIS.getInstructionIndex(Def));
1238887d1faSDan Gohman     assert(DefVNI && "Instruction input missing value number");
1248887d1faSDan Gohman     VNInfo *InsVNI = LI.getVNInfoBefore(LIS.getInstructionIndex(Insert));
1258887d1faSDan Gohman     if (InsVNI && DefVNI != InsVNI)
1268887d1faSDan Gohman       return false;
1278887d1faSDan Gohman   }
1288887d1faSDan Gohman 
1298887d1faSDan Gohman   // Check for memory dependencies and side effects.
13081719f85SDan Gohman   for (--I; I != D; --I)
131*7e64917fSDan Gohman     SawSideEffects |= !I->isSafeToMove(&AA, SawStore);
13281719f85SDan Gohman   return !(SawStore && Def->mayLoad() && !Def->isInvariantLoad(&AA)) &&
13381719f85SDan Gohman          !(SawSideEffects && !Def->isSafeToMove(&AA, SawStore));
13481719f85SDan Gohman }
13581719f85SDan Gohman 
1361462faadSDan Gohman bool WebAssemblyRegStackify::runOnMachineFunction(MachineFunction &MF) {
1371462faadSDan Gohman   DEBUG(dbgs() << "********** Register Stackifying **********\n"
1381462faadSDan Gohman                   "********** Function: "
1391462faadSDan Gohman                << MF.getName() << '\n');
1401462faadSDan Gohman 
1411462faadSDan Gohman   bool Changed = false;
1421462faadSDan Gohman   MachineRegisterInfo &MRI = MF.getRegInfo();
1431462faadSDan Gohman   WebAssemblyFunctionInfo &MFI = *MF.getInfo<WebAssemblyFunctionInfo>();
144b6fd39a3SDan Gohman   const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
145b6fd39a3SDan Gohman   const auto *TRI = MF.getSubtarget<WebAssemblySubtarget>().getRegisterInfo();
14681719f85SDan Gohman   AliasAnalysis &AA = getAnalysis<AAResultsWrapperPass>().getAAResults();
1478887d1faSDan Gohman   LiveIntervals &LIS = getAnalysis<LiveIntervals>();
148d70e5907SDan Gohman 
1491462faadSDan Gohman   // Walk the instructions from the bottom up. Currently we don't look past
1501462faadSDan Gohman   // block boundaries, and the blocks aren't ordered so the block visitation
1511462faadSDan Gohman   // order isn't significant, but we may want to change this in the future.
1521462faadSDan Gohman   for (MachineBasicBlock &MBB : MF) {
1538f59cf75SDan Gohman     // Don't use a range-based for loop, because we modify the list as we're
1548f59cf75SDan Gohman     // iterating over it and the end iterator may change.
1558f59cf75SDan Gohman     for (auto MII = MBB.rbegin(); MII != MBB.rend(); ++MII) {
1568f59cf75SDan Gohman       MachineInstr *Insert = &*MII;
1571462faadSDan Gohman       // Don't nest anything inside a phi.
1581462faadSDan Gohman       if (Insert->getOpcode() == TargetOpcode::PHI)
1591462faadSDan Gohman         break;
1601462faadSDan Gohman 
16181719f85SDan Gohman       // Don't nest anything inside an inline asm, because we don't have
16281719f85SDan Gohman       // constraints for $push inputs.
16381719f85SDan Gohman       if (Insert->getOpcode() == TargetOpcode::INLINEASM)
16481719f85SDan Gohman         break;
16581719f85SDan Gohman 
1661462faadSDan Gohman       // Iterate through the inputs in reverse order, since we'll be pulling
16753d13997SDan Gohman       // operands off the stack in LIFO order.
168b0992dafSDan Gohman       bool AnyStackified = false;
1691462faadSDan Gohman       for (MachineOperand &Op : reverse(Insert->uses())) {
1701462faadSDan Gohman         // We're only interested in explicit virtual register operands.
17181719f85SDan Gohman         if (!Op.isReg() || Op.isImplicit() || !Op.isUse())
1721462faadSDan Gohman           continue;
1731462faadSDan Gohman 
1741462faadSDan Gohman         unsigned Reg = Op.getReg();
1751462faadSDan Gohman 
1761462faadSDan Gohman         // Only consider registers with a single definition.
1771462faadSDan Gohman         // TODO: Eventually we may relax this, to stackify phi transfers.
1788887d1faSDan Gohman         MachineInstr *Def = MRI.getUniqueVRegDef(Reg);
1791462faadSDan Gohman         if (!Def)
1801462faadSDan Gohman           continue;
1811462faadSDan Gohman 
18281719f85SDan Gohman         // Don't nest an INLINE_ASM def into anything, because we don't have
18381719f85SDan Gohman         // constraints for $pop outputs.
18481719f85SDan Gohman         if (Def->getOpcode() == TargetOpcode::INLINEASM)
18581719f85SDan Gohman           continue;
18681719f85SDan Gohman 
18781719f85SDan Gohman         // Don't nest PHIs inside of anything.
18881719f85SDan Gohman         if (Def->getOpcode() == TargetOpcode::PHI)
18981719f85SDan Gohman           continue;
19081719f85SDan Gohman 
1914ba4816bSDan Gohman         // Argument instructions represent live-in registers and not real
1924ba4816bSDan Gohman         // instructions.
1934ba4816bSDan Gohman         if (Def->getOpcode() == WebAssembly::ARGUMENT_I32 ||
1944ba4816bSDan Gohman             Def->getOpcode() == WebAssembly::ARGUMENT_I64 ||
1954ba4816bSDan Gohman             Def->getOpcode() == WebAssembly::ARGUMENT_F32 ||
1964ba4816bSDan Gohman             Def->getOpcode() == WebAssembly::ARGUMENT_F64)
1974ba4816bSDan Gohman           continue;
1984ba4816bSDan Gohman 
199b6fd39a3SDan Gohman         if (MRI.hasOneUse(Reg) && Def->getParent() == &MBB &&
200b6fd39a3SDan Gohman             IsSafeToMove(Def, Insert, AA, LIS, MRI)) {
201b6fd39a3SDan Gohman           // A single-use def in the same block with no intervening memory or
202b6fd39a3SDan Gohman           // register dependencies; move the def down and nest it with the
203b6fd39a3SDan Gohman           // current instruction.
204b6fd39a3SDan Gohman           // TODO: Stackify multiple-use values, taking advantage of set_local
2051462faadSDan Gohman           // returning its result.
2061462faadSDan Gohman           Changed = true;
207b0992dafSDan Gohman           AnyStackified = true;
2088887d1faSDan Gohman           MBB.splice(Insert, &MBB, Def);
2098887d1faSDan Gohman           LIS.handleMove(Def);
2101462faadSDan Gohman           MFI.stackifyVReg(Reg);
2118887d1faSDan Gohman           ImposeStackOrdering(Def);
2121462faadSDan Gohman           Insert = Def;
213b6fd39a3SDan Gohman         } else if (Def->isAsCheapAsAMove() &&
214b6fd39a3SDan Gohman                    TII->isTriviallyReMaterializable(Def, &AA)) {
215b6fd39a3SDan Gohman           // A trivially cloneable instruction; clone it and nest the new copy
216b6fd39a3SDan Gohman           // with the current instruction.
217b6fd39a3SDan Gohman           Changed = true;
218b6fd39a3SDan Gohman           AnyStackified = true;
219b6fd39a3SDan Gohman           unsigned OldReg = Def->getOperand(0).getReg();
220b6fd39a3SDan Gohman           unsigned NewReg = MRI.createVirtualRegister(MRI.getRegClass(OldReg));
221b6fd39a3SDan Gohman           TII->reMaterialize(MBB, Insert, NewReg, 0, Def, *TRI);
222b6fd39a3SDan Gohman           Op.setReg(NewReg);
223b6fd39a3SDan Gohman           MachineInstr *Clone =
224b6fd39a3SDan Gohman               &*std::prev(MachineBasicBlock::instr_iterator(Insert));
225b6fd39a3SDan Gohman           LIS.InsertMachineInstrInMaps(Clone);
226b6fd39a3SDan Gohman           LIS.createAndComputeVirtRegInterval(NewReg);
227b6fd39a3SDan Gohman           MFI.stackifyVReg(NewReg);
228b6fd39a3SDan Gohman           ImposeStackOrdering(Clone);
229b6fd39a3SDan Gohman           Insert = Clone;
230b6fd39a3SDan Gohman 
231b6fd39a3SDan Gohman           // If that was the last use of the original, delete the original.
232b6fd39a3SDan Gohman           // Otherwise shrink the LiveInterval.
233b6fd39a3SDan Gohman           if (MRI.use_empty(OldReg)) {
234b6fd39a3SDan Gohman             SlotIndex Idx = LIS.getInstructionIndex(Def).getRegSlot();
235b6fd39a3SDan Gohman             LIS.removePhysRegDefAt(WebAssembly::ARGUMENTS, Idx);
236b6fd39a3SDan Gohman             LIS.removeVRegDefAt(LIS.getInterval(OldReg), Idx);
237b6fd39a3SDan Gohman             LIS.removeInterval(OldReg);
238b6fd39a3SDan Gohman             LIS.RemoveMachineInstrFromMaps(Def);
239b6fd39a3SDan Gohman             Def->eraseFromParent();
240b6fd39a3SDan Gohman           } else {
241b6fd39a3SDan Gohman             LIS.shrinkToUses(&LIS.getInterval(OldReg));
242b6fd39a3SDan Gohman           }
243b6fd39a3SDan Gohman         }
2441462faadSDan Gohman       }
245b0992dafSDan Gohman       if (AnyStackified)
2468f59cf75SDan Gohman         ImposeStackOrdering(&*MII);
2471462faadSDan Gohman     }
2481462faadSDan Gohman   }
2491462faadSDan Gohman 
250b0992dafSDan Gohman   // If we used EXPR_STACK anywhere, add it to the live-in sets everywhere
251b0992dafSDan Gohman   // so that it never looks like a use-before-def.
252b0992dafSDan Gohman   if (Changed) {
253b0992dafSDan Gohman     MF.getRegInfo().addLiveIn(WebAssembly::EXPR_STACK);
254b0992dafSDan Gohman     for (MachineBasicBlock &MBB : MF)
255b0992dafSDan Gohman       MBB.addLiveIn(WebAssembly::EXPR_STACK);
256b0992dafSDan Gohman   }
257b0992dafSDan Gohman 
2587bafa0eaSDan Gohman #ifndef NDEBUG
259b6fd39a3SDan Gohman   // Verify that pushes and pops are performed in LIFO order.
2607bafa0eaSDan Gohman   SmallVector<unsigned, 0> Stack;
2617bafa0eaSDan Gohman   for (MachineBasicBlock &MBB : MF) {
2627bafa0eaSDan Gohman     for (MachineInstr &MI : MBB) {
2637bafa0eaSDan Gohman       for (MachineOperand &MO : reverse(MI.explicit_operands())) {
2647a6b9825SDan Gohman         if (!MO.isReg())
2657a6b9825SDan Gohman           continue;
2667bafa0eaSDan Gohman         unsigned VReg = MO.getReg();
2677bafa0eaSDan Gohman 
26835bfb24cSDan Gohman         // Don't stackify physregs like SP or FP.
26935bfb24cSDan Gohman         if (!TargetRegisterInfo::isVirtualRegister(VReg))
27035bfb24cSDan Gohman           continue;
27135bfb24cSDan Gohman 
2727bafa0eaSDan Gohman         if (MFI.isVRegStackified(VReg)) {
2737bafa0eaSDan Gohman           if (MO.isDef())
2747bafa0eaSDan Gohman             Stack.push_back(VReg);
2757bafa0eaSDan Gohman           else
2767bafa0eaSDan Gohman             assert(Stack.pop_back_val() == VReg);
2777bafa0eaSDan Gohman         }
2787bafa0eaSDan Gohman       }
2797bafa0eaSDan Gohman     }
2807bafa0eaSDan Gohman     // TODO: Generalize this code to support keeping values on the stack across
2817bafa0eaSDan Gohman     // basic block boundaries.
2827bafa0eaSDan Gohman     assert(Stack.empty());
2837bafa0eaSDan Gohman   }
2847bafa0eaSDan Gohman #endif
2857bafa0eaSDan Gohman 
2861462faadSDan Gohman   return Changed;
2871462faadSDan Gohman }
288