1 //===-- WebAssemblyRegStackify.cpp - Register Stackification --------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 ///
10 /// \file
11 /// \brief This file implements a register stacking pass.
12 ///
13 /// This pass reorders instructions to put register uses and defs in an order
14 /// such that they form single-use expression trees. Registers fitting this form
15 /// are then marked as "stackified", meaning references to them are replaced by
16 /// "push" and "pop" from the stack.
17 ///
18 /// This is primarily a code size optimization, since temporary values on the
19 /// expression don't need to be named.
20 ///
21 //===----------------------------------------------------------------------===//
22 
23 #include "WebAssembly.h"
24 #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" // for WebAssembly::ARGUMENT_*
25 #include "WebAssemblyMachineFunctionInfo.h"
26 #include "WebAssemblySubtarget.h"
27 #include "llvm/Analysis/AliasAnalysis.h"
28 #include "llvm/CodeGen/LiveIntervalAnalysis.h"
29 #include "llvm/CodeGen/MachineBlockFrequencyInfo.h"
30 #include "llvm/CodeGen/MachineRegisterInfo.h"
31 #include "llvm/CodeGen/Passes.h"
32 #include "llvm/Support/Debug.h"
33 #include "llvm/Support/raw_ostream.h"
34 using namespace llvm;
35 
36 #define DEBUG_TYPE "wasm-reg-stackify"
37 
38 namespace {
39 class WebAssemblyRegStackify final : public MachineFunctionPass {
40   const char *getPassName() const override {
41     return "WebAssembly Register Stackify";
42   }
43 
44   void getAnalysisUsage(AnalysisUsage &AU) const override {
45     AU.setPreservesCFG();
46     AU.addRequired<AAResultsWrapperPass>();
47     AU.addRequired<LiveIntervals>();
48     AU.addPreserved<MachineBlockFrequencyInfo>();
49     AU.addPreserved<SlotIndexes>();
50     AU.addPreserved<LiveIntervals>();
51     AU.addPreservedID(MachineDominatorsID);
52     AU.addPreservedID(LiveVariablesID);
53     MachineFunctionPass::getAnalysisUsage(AU);
54   }
55 
56   bool runOnMachineFunction(MachineFunction &MF) override;
57 
58 public:
59   static char ID; // Pass identification, replacement for typeid
60   WebAssemblyRegStackify() : MachineFunctionPass(ID) {}
61 };
62 } // end anonymous namespace
63 
64 char WebAssemblyRegStackify::ID = 0;
65 FunctionPass *llvm::createWebAssemblyRegStackify() {
66   return new WebAssemblyRegStackify();
67 }
68 
69 // Decorate the given instruction with implicit operands that enforce the
70 // expression stack ordering constraints for an instruction which is on
71 // the expression stack.
72 static void ImposeStackOrdering(MachineInstr *MI) {
73   // Write the opaque EXPR_STACK register.
74   if (!MI->definesRegister(WebAssembly::EXPR_STACK))
75     MI->addOperand(MachineOperand::CreateReg(WebAssembly::EXPR_STACK,
76                                              /*isDef=*/true,
77                                              /*isImp=*/true));
78 
79   // Also read the opaque EXPR_STACK register.
80   if (!MI->readsRegister(WebAssembly::EXPR_STACK))
81     MI->addOperand(MachineOperand::CreateReg(WebAssembly::EXPR_STACK,
82                                              /*isDef=*/false,
83                                              /*isImp=*/true));
84 }
85 
86 // Test whether it's safe to move Def to just before Insert.
87 // TODO: Compute memory dependencies in a way that doesn't require always
88 // walking the block.
89 // TODO: Compute memory dependencies in a way that uses AliasAnalysis to be
90 // more precise.
91 static bool IsSafeToMove(const MachineInstr *Def, const MachineInstr *Insert,
92                          AliasAnalysis &AA, LiveIntervals &LIS,
93                          MachineRegisterInfo &MRI) {
94   assert(Def->getParent() == Insert->getParent());
95   bool SawStore = false, SawSideEffects = false;
96   MachineBasicBlock::const_iterator D(Def), I(Insert);
97 
98   // Check for register dependencies.
99   for (const MachineOperand &MO : Def->operands()) {
100     if (!MO.isReg() || MO.isUndef())
101       continue;
102     unsigned Reg = MO.getReg();
103 
104     // If the register is dead here and at Insert, ignore it.
105     if (MO.isDead() && Insert->definesRegister(Reg) &&
106         !Insert->readsRegister(Reg))
107       continue;
108 
109     if (TargetRegisterInfo::isPhysicalRegister(Reg)) {
110       // If the physical register is never modified, ignore it.
111       if (!MRI.isPhysRegModified(Reg))
112         continue;
113       // Otherwise, it's a physical register with unknown liveness.
114       return false;
115     }
116 
117     // Ask LiveIntervals whether moving this virtual register use or def to
118     // Insert will change value numbers are seen.
119     const LiveInterval &LI = LIS.getInterval(Reg);
120     VNInfo *DefVNI =
121         MO.isDef() ? LI.getVNInfoAt(LIS.getInstructionIndex(Def).getRegSlot())
122                    : LI.getVNInfoBefore(LIS.getInstructionIndex(Def));
123     assert(DefVNI && "Instruction input missing value number");
124     VNInfo *InsVNI = LI.getVNInfoBefore(LIS.getInstructionIndex(Insert));
125     if (InsVNI && DefVNI != InsVNI)
126       return false;
127   }
128 
129   // Check for memory dependencies and side effects.
130   for (--I; I != D; --I)
131     SawSideEffects |= !I->isSafeToMove(&AA, SawStore);
132   return !(SawStore && Def->mayLoad() && !Def->isInvariantLoad(&AA)) &&
133          !(SawSideEffects && !Def->isSafeToMove(&AA, SawStore));
134 }
135 
136 bool WebAssemblyRegStackify::runOnMachineFunction(MachineFunction &MF) {
137   DEBUG(dbgs() << "********** Register Stackifying **********\n"
138                   "********** Function: "
139                << MF.getName() << '\n');
140 
141   bool Changed = false;
142   MachineRegisterInfo &MRI = MF.getRegInfo();
143   WebAssemblyFunctionInfo &MFI = *MF.getInfo<WebAssemblyFunctionInfo>();
144   const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
145   const auto *TRI = MF.getSubtarget<WebAssemblySubtarget>().getRegisterInfo();
146   AliasAnalysis &AA = getAnalysis<AAResultsWrapperPass>().getAAResults();
147   LiveIntervals &LIS = getAnalysis<LiveIntervals>();
148 
149   // Walk the instructions from the bottom up. Currently we don't look past
150   // block boundaries, and the blocks aren't ordered so the block visitation
151   // order isn't significant, but we may want to change this in the future.
152   for (MachineBasicBlock &MBB : MF) {
153     // Don't use a range-based for loop, because we modify the list as we're
154     // iterating over it and the end iterator may change.
155     for (auto MII = MBB.rbegin(); MII != MBB.rend(); ++MII) {
156       MachineInstr *Insert = &*MII;
157       // Don't nest anything inside a phi.
158       if (Insert->getOpcode() == TargetOpcode::PHI)
159         break;
160 
161       // Don't nest anything inside an inline asm, because we don't have
162       // constraints for $push inputs.
163       if (Insert->getOpcode() == TargetOpcode::INLINEASM)
164         break;
165 
166       // Iterate through the inputs in reverse order, since we'll be pulling
167       // operands off the stack in LIFO order.
168       bool AnyStackified = false;
169       for (MachineOperand &Op : reverse(Insert->uses())) {
170         // We're only interested in explicit virtual register operands.
171         if (!Op.isReg() || Op.isImplicit() || !Op.isUse())
172           continue;
173 
174         unsigned Reg = Op.getReg();
175 
176         // Only consider registers with a single definition.
177         // TODO: Eventually we may relax this, to stackify phi transfers.
178         MachineInstr *Def = MRI.getUniqueVRegDef(Reg);
179         if (!Def)
180           continue;
181 
182         // Don't nest an INLINE_ASM def into anything, because we don't have
183         // constraints for $pop outputs.
184         if (Def->getOpcode() == TargetOpcode::INLINEASM)
185           continue;
186 
187         // Don't nest PHIs inside of anything.
188         if (Def->getOpcode() == TargetOpcode::PHI)
189           continue;
190 
191         // Argument instructions represent live-in registers and not real
192         // instructions.
193         if (Def->getOpcode() == WebAssembly::ARGUMENT_I32 ||
194             Def->getOpcode() == WebAssembly::ARGUMENT_I64 ||
195             Def->getOpcode() == WebAssembly::ARGUMENT_F32 ||
196             Def->getOpcode() == WebAssembly::ARGUMENT_F64)
197           continue;
198 
199         if (MRI.hasOneUse(Reg) && Def->getParent() == &MBB &&
200             IsSafeToMove(Def, Insert, AA, LIS, MRI)) {
201           // A single-use def in the same block with no intervening memory or
202           // register dependencies; move the def down and nest it with the
203           // current instruction.
204           // TODO: Stackify multiple-use values, taking advantage of set_local
205           // returning its result.
206           Changed = true;
207           AnyStackified = true;
208           MBB.splice(Insert, &MBB, Def);
209           LIS.handleMove(Def);
210           MFI.stackifyVReg(Reg);
211           ImposeStackOrdering(Def);
212           Insert = Def;
213         } else if (Def->isAsCheapAsAMove() &&
214                    TII->isTriviallyReMaterializable(Def, &AA)) {
215           // A trivially cloneable instruction; clone it and nest the new copy
216           // with the current instruction.
217           Changed = true;
218           AnyStackified = true;
219           unsigned OldReg = Def->getOperand(0).getReg();
220           unsigned NewReg = MRI.createVirtualRegister(MRI.getRegClass(OldReg));
221           TII->reMaterialize(MBB, Insert, NewReg, 0, Def, *TRI);
222           Op.setReg(NewReg);
223           MachineInstr *Clone =
224               &*std::prev(MachineBasicBlock::instr_iterator(Insert));
225           LIS.InsertMachineInstrInMaps(Clone);
226           LIS.createAndComputeVirtRegInterval(NewReg);
227           MFI.stackifyVReg(NewReg);
228           ImposeStackOrdering(Clone);
229           Insert = Clone;
230 
231           // If that was the last use of the original, delete the original.
232           // Otherwise shrink the LiveInterval.
233           if (MRI.use_empty(OldReg)) {
234             SlotIndex Idx = LIS.getInstructionIndex(Def).getRegSlot();
235             LIS.removePhysRegDefAt(WebAssembly::ARGUMENTS, Idx);
236             LIS.removeVRegDefAt(LIS.getInterval(OldReg), Idx);
237             LIS.removeInterval(OldReg);
238             LIS.RemoveMachineInstrFromMaps(Def);
239             Def->eraseFromParent();
240           } else {
241             LIS.shrinkToUses(&LIS.getInterval(OldReg));
242           }
243         }
244       }
245       if (AnyStackified)
246         ImposeStackOrdering(&*MII);
247     }
248   }
249 
250   // If we used EXPR_STACK anywhere, add it to the live-in sets everywhere
251   // so that it never looks like a use-before-def.
252   if (Changed) {
253     MF.getRegInfo().addLiveIn(WebAssembly::EXPR_STACK);
254     for (MachineBasicBlock &MBB : MF)
255       MBB.addLiveIn(WebAssembly::EXPR_STACK);
256   }
257 
258 #ifndef NDEBUG
259   // Verify that pushes and pops are performed in LIFO order.
260   SmallVector<unsigned, 0> Stack;
261   for (MachineBasicBlock &MBB : MF) {
262     for (MachineInstr &MI : MBB) {
263       for (MachineOperand &MO : reverse(MI.explicit_operands())) {
264         if (!MO.isReg())
265           continue;
266         unsigned VReg = MO.getReg();
267 
268         // Don't stackify physregs like SP or FP.
269         if (!TargetRegisterInfo::isVirtualRegister(VReg))
270           continue;
271 
272         if (MFI.isVRegStackified(VReg)) {
273           if (MO.isDef())
274             Stack.push_back(VReg);
275           else
276             assert(Stack.pop_back_val() == VReg);
277         }
278       }
279     }
280     // TODO: Generalize this code to support keeping values on the stack across
281     // basic block boundaries.
282     assert(Stack.empty());
283   }
284 #endif
285 
286   return Changed;
287 }
288