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
64b0992dafSDan Gohman // expression stack ordering constraints.
65b0992dafSDan Gohman static void ImposeStackOrdering(MachineInstr *MI) {
66b0992dafSDan Gohman   // Read and write the opaque EXPR_STACK register.
67b0992dafSDan Gohman   MI->addOperand(MachineOperand::CreateReg(WebAssembly::EXPR_STACK,
68b0992dafSDan Gohman                                            /*isDef=*/true,
69b0992dafSDan Gohman                                            /*isImp=*/true));
70b0992dafSDan Gohman   MI->addOperand(MachineOperand::CreateReg(WebAssembly::EXPR_STACK,
71b0992dafSDan Gohman                                            /*isDef=*/false,
72b0992dafSDan Gohman                                            /*isImp=*/true));
73b0992dafSDan Gohman }
74b0992dafSDan Gohman 
7581719f85SDan Gohman // Test whether it's safe to move Def to just before Insert. Note that this
7681719f85SDan Gohman // doesn't account for physical register dependencies, because WebAssembly
7781719f85SDan Gohman // doesn't have any (other than special ones like EXPR_STACK).
7881719f85SDan Gohman // TODO: Compute memory dependencies in a way that doesn't require always
7981719f85SDan Gohman // walking the block.
8081719f85SDan Gohman // TODO: Compute memory dependencies in a way that uses AliasAnalysis to be
8181719f85SDan Gohman // more precise.
8281719f85SDan Gohman static bool IsSafeToMove(const MachineInstr *Def, const MachineInstr *Insert,
8381719f85SDan Gohman                          AliasAnalysis &AA) {
84*391a98afSDan Gohman   assert(Def->getParent() == Insert->getParent());
8581719f85SDan Gohman   bool SawStore = false, SawSideEffects = false;
8681719f85SDan Gohman   MachineBasicBlock::const_iterator D(Def), I(Insert);
8781719f85SDan Gohman   for (--I; I != D; --I)
8881719f85SDan Gohman     SawSideEffects |= I->isSafeToMove(&AA, SawStore);
8981719f85SDan Gohman 
9081719f85SDan Gohman   return !(SawStore && Def->mayLoad() && !Def->isInvariantLoad(&AA)) &&
9181719f85SDan Gohman          !(SawSideEffects && !Def->isSafeToMove(&AA, SawStore));
9281719f85SDan Gohman }
9381719f85SDan Gohman 
941462faadSDan Gohman bool WebAssemblyRegStackify::runOnMachineFunction(MachineFunction &MF) {
951462faadSDan Gohman   DEBUG(dbgs() << "********** Register Stackifying **********\n"
961462faadSDan Gohman                   "********** Function: "
971462faadSDan Gohman                << MF.getName() << '\n');
981462faadSDan Gohman 
991462faadSDan Gohman   bool Changed = false;
1001462faadSDan Gohman   MachineRegisterInfo &MRI = MF.getRegInfo();
1011462faadSDan Gohman   WebAssemblyFunctionInfo &MFI = *MF.getInfo<WebAssemblyFunctionInfo>();
10281719f85SDan Gohman   AliasAnalysis &AA = getAnalysis<AAResultsWrapperPass>().getAAResults();
1031462faadSDan Gohman 
1041462faadSDan Gohman   // Walk the instructions from the bottom up. Currently we don't look past
1051462faadSDan Gohman   // block boundaries, and the blocks aren't ordered so the block visitation
1061462faadSDan Gohman   // order isn't significant, but we may want to change this in the future.
1071462faadSDan Gohman   for (MachineBasicBlock &MBB : MF) {
1081462faadSDan Gohman     for (MachineInstr &MI : reverse(MBB)) {
1091462faadSDan Gohman       MachineInstr *Insert = &MI;
1101462faadSDan Gohman 
1111462faadSDan Gohman       // Don't nest anything inside a phi.
1121462faadSDan Gohman       if (Insert->getOpcode() == TargetOpcode::PHI)
1131462faadSDan Gohman         break;
1141462faadSDan Gohman 
11581719f85SDan Gohman       // Don't nest anything inside an inline asm, because we don't have
11681719f85SDan Gohman       // constraints for $push inputs.
11781719f85SDan Gohman       if (Insert->getOpcode() == TargetOpcode::INLINEASM)
11881719f85SDan Gohman         break;
11981719f85SDan Gohman 
1201462faadSDan Gohman       // Iterate through the inputs in reverse order, since we'll be pulling
12153d13997SDan Gohman       // operands off the stack in LIFO order.
122b0992dafSDan Gohman       bool AnyStackified = false;
1231462faadSDan Gohman       for (MachineOperand &Op : reverse(Insert->uses())) {
1241462faadSDan Gohman         // We're only interested in explicit virtual register operands.
12581719f85SDan Gohman         if (!Op.isReg() || Op.isImplicit() || !Op.isUse())
1261462faadSDan Gohman           continue;
1271462faadSDan Gohman 
1281462faadSDan Gohman         unsigned Reg = Op.getReg();
1291462faadSDan Gohman         if (!TargetRegisterInfo::isVirtualRegister(Reg))
1301462faadSDan Gohman           continue;
1311462faadSDan Gohman 
1321462faadSDan Gohman         // Only consider registers with a single definition.
1331462faadSDan Gohman         // TODO: Eventually we may relax this, to stackify phi transfers.
1341462faadSDan Gohman         MachineInstr *Def = MRI.getVRegDef(Reg);
1351462faadSDan Gohman         if (!Def)
1361462faadSDan Gohman           continue;
1371462faadSDan Gohman 
1381462faadSDan Gohman         // There's no use in nesting implicit defs inside anything.
1391462faadSDan Gohman         if (Def->getOpcode() == TargetOpcode::IMPLICIT_DEF)
1401462faadSDan Gohman           continue;
1411462faadSDan Gohman 
14281719f85SDan Gohman         // Don't nest an INLINE_ASM def into anything, because we don't have
14381719f85SDan Gohman         // constraints for $pop outputs.
14481719f85SDan Gohman         if (Def->getOpcode() == TargetOpcode::INLINEASM)
14581719f85SDan Gohman           continue;
14681719f85SDan Gohman 
14781719f85SDan Gohman         // Don't nest PHIs inside of anything.
14881719f85SDan Gohman         if (Def->getOpcode() == TargetOpcode::PHI)
14981719f85SDan Gohman           continue;
15081719f85SDan Gohman 
1514ba4816bSDan Gohman         // Argument instructions represent live-in registers and not real
1524ba4816bSDan Gohman         // instructions.
1534ba4816bSDan Gohman         if (Def->getOpcode() == WebAssembly::ARGUMENT_I32 ||
1544ba4816bSDan Gohman             Def->getOpcode() == WebAssembly::ARGUMENT_I64 ||
1554ba4816bSDan Gohman             Def->getOpcode() == WebAssembly::ARGUMENT_F32 ||
1564ba4816bSDan Gohman             Def->getOpcode() == WebAssembly::ARGUMENT_F64)
1574ba4816bSDan Gohman           continue;
1584ba4816bSDan Gohman 
159*391a98afSDan Gohman         // Single-use expression trees require defs that have one use.
1601462faadSDan Gohman         // TODO: Eventually we'll relax this, to take advantage of set_local
1611462faadSDan Gohman         // returning its result.
16281719f85SDan Gohman         if (!MRI.hasOneUse(Reg))
1631462faadSDan Gohman           continue;
1641462faadSDan Gohman 
165*391a98afSDan Gohman         // For now, be conservative and don't look across block boundaries.
1661462faadSDan Gohman         // TODO: Be more aggressive.
167*391a98afSDan Gohman         if (Def->getParent() != &MBB)
1681462faadSDan Gohman           continue;
1691462faadSDan Gohman 
17081719f85SDan Gohman         // Don't move instructions that have side effects or memory dependencies
17181719f85SDan Gohman         // or other complications.
17281719f85SDan Gohman         if (!IsSafeToMove(Def, Insert, AA))
1731462faadSDan Gohman           continue;
1741462faadSDan Gohman 
1751462faadSDan Gohman         Changed = true;
176b0992dafSDan Gohman         AnyStackified = true;
1771462faadSDan Gohman         // Move the def down and nest it in the current instruction.
1781462faadSDan Gohman         MBB.insert(MachineBasicBlock::instr_iterator(Insert),
1791462faadSDan Gohman                    Def->removeFromParent());
1801462faadSDan Gohman         MFI.stackifyVReg(Reg);
181b0992dafSDan Gohman         ImposeStackOrdering(Def);
1821462faadSDan Gohman         Insert = Def;
1831462faadSDan Gohman       }
184b0992dafSDan Gohman       if (AnyStackified)
185b0992dafSDan Gohman         ImposeStackOrdering(&MI);
1861462faadSDan Gohman     }
1871462faadSDan Gohman   }
1881462faadSDan Gohman 
189b0992dafSDan Gohman   // If we used EXPR_STACK anywhere, add it to the live-in sets everywhere
190b0992dafSDan Gohman   // so that it never looks like a use-before-def.
191b0992dafSDan Gohman   if (Changed) {
192b0992dafSDan Gohman     MF.getRegInfo().addLiveIn(WebAssembly::EXPR_STACK);
193b0992dafSDan Gohman     for (MachineBasicBlock &MBB : MF)
194b0992dafSDan Gohman       MBB.addLiveIn(WebAssembly::EXPR_STACK);
195b0992dafSDan Gohman   }
196b0992dafSDan Gohman 
1977bafa0eaSDan Gohman #ifndef NDEBUG
1987bafa0eaSDan Gohman   // Verify that pushes and pops are performed in FIFO order.
1997bafa0eaSDan Gohman   SmallVector<unsigned, 0> Stack;
2007bafa0eaSDan Gohman   for (MachineBasicBlock &MBB : MF) {
2017bafa0eaSDan Gohman     for (MachineInstr &MI : MBB) {
2027bafa0eaSDan Gohman       for (MachineOperand &MO : reverse(MI.explicit_operands())) {
2037a6b9825SDan Gohman         if (!MO.isReg())
2047a6b9825SDan Gohman           continue;
2057bafa0eaSDan Gohman         unsigned VReg = MO.getReg();
2067bafa0eaSDan Gohman 
2077bafa0eaSDan Gohman         if (MFI.isVRegStackified(VReg)) {
2087bafa0eaSDan Gohman           if (MO.isDef())
2097bafa0eaSDan Gohman             Stack.push_back(VReg);
2107bafa0eaSDan Gohman           else
2117bafa0eaSDan Gohman             assert(Stack.pop_back_val() == VReg);
2127bafa0eaSDan Gohman         }
2137bafa0eaSDan Gohman       }
2147bafa0eaSDan Gohman     }
2157bafa0eaSDan Gohman     // TODO: Generalize this code to support keeping values on the stack across
2167bafa0eaSDan Gohman     // basic block boundaries.
2177bafa0eaSDan Gohman     assert(Stack.empty());
2187bafa0eaSDan Gohman   }
2197bafa0eaSDan Gohman #endif
2207bafa0eaSDan Gohman 
2211462faadSDan Gohman   return Changed;
2221462faadSDan Gohman }
223