1*4fc4e42dSDan Gohman //===-- WebAssemblyExplicitLocals.cpp - Make Locals Explicit --------------===//
2*4fc4e42dSDan Gohman //
3*4fc4e42dSDan Gohman //                     The LLVM Compiler Infrastructure
4*4fc4e42dSDan Gohman //
5*4fc4e42dSDan Gohman // This file is distributed under the University of Illinois Open Source
6*4fc4e42dSDan Gohman // License. See LICENSE.TXT for details.
7*4fc4e42dSDan Gohman //
8*4fc4e42dSDan Gohman //===----------------------------------------------------------------------===//
9*4fc4e42dSDan Gohman ///
10*4fc4e42dSDan Gohman /// \file
11*4fc4e42dSDan Gohman /// \brief This file converts any remaining registers into WebAssembly locals.
12*4fc4e42dSDan Gohman ///
13*4fc4e42dSDan Gohman /// After register stackification and register coloring, convert non-stackified
14*4fc4e42dSDan Gohman /// registers into locals, inserting explicit get_local and set_local
15*4fc4e42dSDan Gohman /// instructions.
16*4fc4e42dSDan Gohman ///
17*4fc4e42dSDan Gohman //===----------------------------------------------------------------------===//
18*4fc4e42dSDan Gohman 
19*4fc4e42dSDan Gohman #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
20*4fc4e42dSDan Gohman #include "WebAssembly.h"
21*4fc4e42dSDan Gohman #include "WebAssemblyMachineFunctionInfo.h"
22*4fc4e42dSDan Gohman #include "WebAssemblySubtarget.h"
23*4fc4e42dSDan Gohman #include "WebAssemblyUtilities.h"
24*4fc4e42dSDan Gohman #include "llvm/CodeGen/MachineBlockFrequencyInfo.h"
25*4fc4e42dSDan Gohman #include "llvm/CodeGen/MachineInstrBuilder.h"
26*4fc4e42dSDan Gohman #include "llvm/CodeGen/MachineRegisterInfo.h"
27*4fc4e42dSDan Gohman #include "llvm/CodeGen/Passes.h"
28*4fc4e42dSDan Gohman #include "llvm/Support/Debug.h"
29*4fc4e42dSDan Gohman #include "llvm/Support/raw_ostream.h"
30*4fc4e42dSDan Gohman using namespace llvm;
31*4fc4e42dSDan Gohman 
32*4fc4e42dSDan Gohman #define DEBUG_TYPE "wasm-explicit-locals"
33*4fc4e42dSDan Gohman 
34*4fc4e42dSDan Gohman namespace {
35*4fc4e42dSDan Gohman class WebAssemblyExplicitLocals final : public MachineFunctionPass {
36*4fc4e42dSDan Gohman   StringRef getPassName() const override {
37*4fc4e42dSDan Gohman     return "WebAssembly Explicit Locals";
38*4fc4e42dSDan Gohman   }
39*4fc4e42dSDan Gohman 
40*4fc4e42dSDan Gohman   void getAnalysisUsage(AnalysisUsage &AU) const override {
41*4fc4e42dSDan Gohman     AU.setPreservesCFG();
42*4fc4e42dSDan Gohman     AU.addPreserved<MachineBlockFrequencyInfo>();
43*4fc4e42dSDan Gohman     MachineFunctionPass::getAnalysisUsage(AU);
44*4fc4e42dSDan Gohman   }
45*4fc4e42dSDan Gohman 
46*4fc4e42dSDan Gohman   bool runOnMachineFunction(MachineFunction &MF) override;
47*4fc4e42dSDan Gohman 
48*4fc4e42dSDan Gohman public:
49*4fc4e42dSDan Gohman   static char ID; // Pass identification, replacement for typeid
50*4fc4e42dSDan Gohman   WebAssemblyExplicitLocals() : MachineFunctionPass(ID) {}
51*4fc4e42dSDan Gohman };
52*4fc4e42dSDan Gohman } // end anonymous namespace
53*4fc4e42dSDan Gohman 
54*4fc4e42dSDan Gohman char WebAssemblyExplicitLocals::ID = 0;
55*4fc4e42dSDan Gohman FunctionPass *llvm::createWebAssemblyExplicitLocals() {
56*4fc4e42dSDan Gohman   return new WebAssemblyExplicitLocals();
57*4fc4e42dSDan Gohman }
58*4fc4e42dSDan Gohman 
59*4fc4e42dSDan Gohman /// Return a local id number for the given register, assigning it a new one
60*4fc4e42dSDan Gohman /// if it doesn't yet have one.
61*4fc4e42dSDan Gohman static unsigned getLocalId(DenseMap<unsigned, unsigned> &Reg2Local,
62*4fc4e42dSDan Gohman                            unsigned &CurLocal, unsigned Reg) {
63*4fc4e42dSDan Gohman   return Reg2Local.insert(std::make_pair(Reg, CurLocal++)).first->second;
64*4fc4e42dSDan Gohman }
65*4fc4e42dSDan Gohman 
66*4fc4e42dSDan Gohman /// Get the appropriate get_local opcode for the given register class.
67*4fc4e42dSDan Gohman static unsigned getGetLocalOpcode(const TargetRegisterClass *RC) {
68*4fc4e42dSDan Gohman   if (RC == &WebAssembly::I32RegClass)
69*4fc4e42dSDan Gohman     return WebAssembly::GET_LOCAL_I32;
70*4fc4e42dSDan Gohman   if (RC == &WebAssembly::I64RegClass)
71*4fc4e42dSDan Gohman     return WebAssembly::GET_LOCAL_I64;
72*4fc4e42dSDan Gohman   if (RC == &WebAssembly::F32RegClass)
73*4fc4e42dSDan Gohman     return WebAssembly::GET_LOCAL_F32;
74*4fc4e42dSDan Gohman   if (RC == &WebAssembly::F64RegClass)
75*4fc4e42dSDan Gohman     return WebAssembly::GET_LOCAL_F64;
76*4fc4e42dSDan Gohman   if (RC == &WebAssembly::V128RegClass)
77*4fc4e42dSDan Gohman     return WebAssembly::GET_LOCAL_V128;
78*4fc4e42dSDan Gohman   llvm_unreachable("Unexpected register class");
79*4fc4e42dSDan Gohman }
80*4fc4e42dSDan Gohman 
81*4fc4e42dSDan Gohman /// Get the appropriate set_local opcode for the given register class.
82*4fc4e42dSDan Gohman static unsigned getSetLocalOpcode(const TargetRegisterClass *RC) {
83*4fc4e42dSDan Gohman   if (RC == &WebAssembly::I32RegClass)
84*4fc4e42dSDan Gohman     return WebAssembly::SET_LOCAL_I32;
85*4fc4e42dSDan Gohman   if (RC == &WebAssembly::I64RegClass)
86*4fc4e42dSDan Gohman     return WebAssembly::SET_LOCAL_I64;
87*4fc4e42dSDan Gohman   if (RC == &WebAssembly::F32RegClass)
88*4fc4e42dSDan Gohman     return WebAssembly::SET_LOCAL_F32;
89*4fc4e42dSDan Gohman   if (RC == &WebAssembly::F64RegClass)
90*4fc4e42dSDan Gohman     return WebAssembly::SET_LOCAL_F64;
91*4fc4e42dSDan Gohman   if (RC == &WebAssembly::V128RegClass)
92*4fc4e42dSDan Gohman     return WebAssembly::SET_LOCAL_V128;
93*4fc4e42dSDan Gohman   llvm_unreachable("Unexpected register class");
94*4fc4e42dSDan Gohman }
95*4fc4e42dSDan Gohman 
96*4fc4e42dSDan Gohman /// Get the appropriate tee_local opcode for the given register class.
97*4fc4e42dSDan Gohman static unsigned getTeeLocalOpcode(const TargetRegisterClass *RC) {
98*4fc4e42dSDan Gohman   if (RC == &WebAssembly::I32RegClass)
99*4fc4e42dSDan Gohman     return WebAssembly::TEE_LOCAL_I32;
100*4fc4e42dSDan Gohman   if (RC == &WebAssembly::I64RegClass)
101*4fc4e42dSDan Gohman     return WebAssembly::TEE_LOCAL_I64;
102*4fc4e42dSDan Gohman   if (RC == &WebAssembly::F32RegClass)
103*4fc4e42dSDan Gohman     return WebAssembly::TEE_LOCAL_F32;
104*4fc4e42dSDan Gohman   if (RC == &WebAssembly::F64RegClass)
105*4fc4e42dSDan Gohman     return WebAssembly::TEE_LOCAL_F64;
106*4fc4e42dSDan Gohman   if (RC == &WebAssembly::V128RegClass)
107*4fc4e42dSDan Gohman     return WebAssembly::TEE_LOCAL_V128;
108*4fc4e42dSDan Gohman   llvm_unreachable("Unexpected register class");
109*4fc4e42dSDan Gohman }
110*4fc4e42dSDan Gohman 
111*4fc4e42dSDan Gohman /// Get the type associated with the given register class.
112*4fc4e42dSDan Gohman static WebAssembly::ValType typeForRegClass(const TargetRegisterClass *RC) {
113*4fc4e42dSDan Gohman   if (RC == &WebAssembly::I32RegClass)
114*4fc4e42dSDan Gohman     return WebAssembly::ValType::I32;
115*4fc4e42dSDan Gohman   if (RC == &WebAssembly::I64RegClass)
116*4fc4e42dSDan Gohman     return WebAssembly::ValType::I64;
117*4fc4e42dSDan Gohman   if (RC == &WebAssembly::F32RegClass)
118*4fc4e42dSDan Gohman     return WebAssembly::ValType::F32;
119*4fc4e42dSDan Gohman   if (RC == &WebAssembly::F64RegClass)
120*4fc4e42dSDan Gohman     return WebAssembly::ValType::F64;
121*4fc4e42dSDan Gohman   llvm_unreachable("unrecognized register class");
122*4fc4e42dSDan Gohman }
123*4fc4e42dSDan Gohman 
124*4fc4e42dSDan Gohman /// Given a MachineOperand of a stackified vreg, return the instruction at the
125*4fc4e42dSDan Gohman /// start of the expression tree.
126*4fc4e42dSDan Gohman static MachineInstr *FindStartOfTree(MachineOperand &MO,
127*4fc4e42dSDan Gohman                                      MachineRegisterInfo &MRI,
128*4fc4e42dSDan Gohman                                      WebAssemblyFunctionInfo &MFI) {
129*4fc4e42dSDan Gohman   unsigned Reg = MO.getReg();
130*4fc4e42dSDan Gohman   assert(MFI.isVRegStackified(Reg));
131*4fc4e42dSDan Gohman   MachineInstr *Def = MRI.getVRegDef(Reg);
132*4fc4e42dSDan Gohman 
133*4fc4e42dSDan Gohman   // Find the first stackified use and proceed from there.
134*4fc4e42dSDan Gohman   for (MachineOperand &DefMO : Def->explicit_uses()) {
135*4fc4e42dSDan Gohman     if (!DefMO.isReg())
136*4fc4e42dSDan Gohman       continue;
137*4fc4e42dSDan Gohman     return FindStartOfTree(DefMO, MRI, MFI);
138*4fc4e42dSDan Gohman   }
139*4fc4e42dSDan Gohman 
140*4fc4e42dSDan Gohman   // If there were no stackified uses, we've reached the start.
141*4fc4e42dSDan Gohman   return Def;
142*4fc4e42dSDan Gohman }
143*4fc4e42dSDan Gohman 
144*4fc4e42dSDan Gohman bool WebAssemblyExplicitLocals::runOnMachineFunction(MachineFunction &MF) {
145*4fc4e42dSDan Gohman   DEBUG(dbgs() << "********** Make Locals Explicit **********\n"
146*4fc4e42dSDan Gohman                   "********** Function: "
147*4fc4e42dSDan Gohman                << MF.getName() << '\n');
148*4fc4e42dSDan Gohman 
149*4fc4e42dSDan Gohman   bool Changed = false;
150*4fc4e42dSDan Gohman   MachineRegisterInfo &MRI = MF.getRegInfo();
151*4fc4e42dSDan Gohman   WebAssemblyFunctionInfo &MFI = *MF.getInfo<WebAssemblyFunctionInfo>();
152*4fc4e42dSDan Gohman   const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
153*4fc4e42dSDan Gohman 
154*4fc4e42dSDan Gohman   // Map non-stackified virtual registers to their local ids.
155*4fc4e42dSDan Gohman   DenseMap<unsigned, unsigned> Reg2Local;
156*4fc4e42dSDan Gohman 
157*4fc4e42dSDan Gohman   // Handle ARGUMENTS first to ensure that they get the designated numbers.
158*4fc4e42dSDan Gohman   for (MachineBasicBlock::iterator I = MF.begin()->begin(),
159*4fc4e42dSDan Gohman                                    E = MF.begin()->end();
160*4fc4e42dSDan Gohman        I != E;) {
161*4fc4e42dSDan Gohman     MachineInstr &MI = *I++;
162*4fc4e42dSDan Gohman     if (!WebAssembly::isArgument(MI))
163*4fc4e42dSDan Gohman       break;
164*4fc4e42dSDan Gohman     unsigned Reg = MI.getOperand(0).getReg();
165*4fc4e42dSDan Gohman     assert(!MFI.isVRegStackified(Reg));
166*4fc4e42dSDan Gohman     Reg2Local[Reg] = MI.getOperand(1).getImm();
167*4fc4e42dSDan Gohman     MI.eraseFromParent();
168*4fc4e42dSDan Gohman     Changed = true;
169*4fc4e42dSDan Gohman   }
170*4fc4e42dSDan Gohman 
171*4fc4e42dSDan Gohman   // Start assigning local numbers after the last parameter.
172*4fc4e42dSDan Gohman   unsigned CurLocal = MFI.getParams().size();
173*4fc4e42dSDan Gohman 
174*4fc4e42dSDan Gohman   // Visit each instruction in the function.
175*4fc4e42dSDan Gohman   for (MachineBasicBlock &MBB : MF) {
176*4fc4e42dSDan Gohman     for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end(); I != E;) {
177*4fc4e42dSDan Gohman       MachineInstr &MI = *I++;
178*4fc4e42dSDan Gohman       assert(!WebAssembly::isArgument(MI));
179*4fc4e42dSDan Gohman 
180*4fc4e42dSDan Gohman       if (MI.isDebugValue() || MI.isLabel())
181*4fc4e42dSDan Gohman         continue;
182*4fc4e42dSDan Gohman 
183*4fc4e42dSDan Gohman       // Replace tee instructions with tee_local. The difference is that tee
184*4fc4e42dSDan Gohman       // instructins have two defs, while tee_local instructions have one def
185*4fc4e42dSDan Gohman       // and an index of a local to write to.
186*4fc4e42dSDan Gohman       if (WebAssembly::isTee(MI)) {
187*4fc4e42dSDan Gohman         assert(MFI.isVRegStackified(MI.getOperand(0).getReg()));
188*4fc4e42dSDan Gohman         assert(!MFI.isVRegStackified(MI.getOperand(1).getReg()));
189*4fc4e42dSDan Gohman         unsigned OldReg = MI.getOperand(2).getReg();
190*4fc4e42dSDan Gohman         const TargetRegisterClass *RC = MRI.getRegClass(OldReg);
191*4fc4e42dSDan Gohman 
192*4fc4e42dSDan Gohman         // Stackify the input if it isn't stackified yet.
193*4fc4e42dSDan Gohman         if (!MFI.isVRegStackified(OldReg)) {
194*4fc4e42dSDan Gohman           unsigned LocalId = getLocalId(Reg2Local, CurLocal, OldReg);
195*4fc4e42dSDan Gohman           unsigned NewReg = MRI.createVirtualRegister(RC);
196*4fc4e42dSDan Gohman           unsigned Opc = getGetLocalOpcode(RC);
197*4fc4e42dSDan Gohman           BuildMI(MBB, &MI, MI.getDebugLoc(), TII->get(Opc), NewReg)
198*4fc4e42dSDan Gohman               .addImm(LocalId);
199*4fc4e42dSDan Gohman           MI.getOperand(2).setReg(NewReg);
200*4fc4e42dSDan Gohman           MFI.stackifyVReg(NewReg);
201*4fc4e42dSDan Gohman         }
202*4fc4e42dSDan Gohman 
203*4fc4e42dSDan Gohman         // Replace the TEE with a TEE_LOCAL.
204*4fc4e42dSDan Gohman         unsigned LocalId =
205*4fc4e42dSDan Gohman             getLocalId(Reg2Local, CurLocal, MI.getOperand(1).getReg());
206*4fc4e42dSDan Gohman         unsigned Opc = getTeeLocalOpcode(RC);
207*4fc4e42dSDan Gohman         BuildMI(MBB, &MI, MI.getDebugLoc(), TII->get(Opc),
208*4fc4e42dSDan Gohman                 MI.getOperand(0).getReg())
209*4fc4e42dSDan Gohman             .addImm(LocalId)
210*4fc4e42dSDan Gohman             .addReg(MI.getOperand(2).getReg());
211*4fc4e42dSDan Gohman 
212*4fc4e42dSDan Gohman         MI.eraseFromParent();
213*4fc4e42dSDan Gohman         Changed = true;
214*4fc4e42dSDan Gohman         continue;
215*4fc4e42dSDan Gohman       }
216*4fc4e42dSDan Gohman 
217*4fc4e42dSDan Gohman       // Insert set_locals for any defs that aren't stackified yet. Currently
218*4fc4e42dSDan Gohman       // we handle at most one def.
219*4fc4e42dSDan Gohman       assert(MI.getDesc().getNumDefs() <= 1);
220*4fc4e42dSDan Gohman       if (MI.getDesc().getNumDefs() == 1) {
221*4fc4e42dSDan Gohman         unsigned OldReg = MI.getOperand(0).getReg();
222*4fc4e42dSDan Gohman         if (!MFI.isVRegStackified(OldReg) && !MRI.use_empty(OldReg)) {
223*4fc4e42dSDan Gohman           unsigned LocalId = getLocalId(Reg2Local, CurLocal, OldReg);
224*4fc4e42dSDan Gohman           const TargetRegisterClass *RC = MRI.getRegClass(OldReg);
225*4fc4e42dSDan Gohman           unsigned NewReg = MRI.createVirtualRegister(RC);
226*4fc4e42dSDan Gohman           auto InsertPt = std::next(MachineBasicBlock::iterator(&MI));
227*4fc4e42dSDan Gohman           unsigned Opc = getSetLocalOpcode(RC);
228*4fc4e42dSDan Gohman           BuildMI(MBB, InsertPt, MI.getDebugLoc(), TII->get(Opc))
229*4fc4e42dSDan Gohman               .addImm(LocalId)
230*4fc4e42dSDan Gohman               .addReg(NewReg);
231*4fc4e42dSDan Gohman           MI.getOperand(0).setReg(NewReg);
232*4fc4e42dSDan Gohman           MFI.stackifyVReg(NewReg);
233*4fc4e42dSDan Gohman           Changed = true;
234*4fc4e42dSDan Gohman         }
235*4fc4e42dSDan Gohman       }
236*4fc4e42dSDan Gohman 
237*4fc4e42dSDan Gohman       // Insert get_locals for any uses that aren't stackified yet.
238*4fc4e42dSDan Gohman       MachineInstr *InsertPt = &MI;
239*4fc4e42dSDan Gohman       for (MachineOperand &MO : reverse(MI.explicit_uses())) {
240*4fc4e42dSDan Gohman         if (!MO.isReg())
241*4fc4e42dSDan Gohman           continue;
242*4fc4e42dSDan Gohman 
243*4fc4e42dSDan Gohman         unsigned OldReg = MO.getReg();
244*4fc4e42dSDan Gohman 
245*4fc4e42dSDan Gohman         // If we see a stackified register, prepare to insert subsequent
246*4fc4e42dSDan Gohman         // get_locals before the start of its tree.
247*4fc4e42dSDan Gohman         if (MFI.isVRegStackified(OldReg)) {
248*4fc4e42dSDan Gohman           InsertPt = FindStartOfTree(MO, MRI, MFI);
249*4fc4e42dSDan Gohman           continue;
250*4fc4e42dSDan Gohman         }
251*4fc4e42dSDan Gohman 
252*4fc4e42dSDan Gohman         // Insert a get_local.
253*4fc4e42dSDan Gohman         unsigned LocalId = getLocalId(Reg2Local, CurLocal, OldReg);
254*4fc4e42dSDan Gohman         const TargetRegisterClass *RC = MRI.getRegClass(OldReg);
255*4fc4e42dSDan Gohman         unsigned NewReg = MRI.createVirtualRegister(RC);
256*4fc4e42dSDan Gohman         unsigned Opc = getGetLocalOpcode(RC);
257*4fc4e42dSDan Gohman         InsertPt =
258*4fc4e42dSDan Gohman             BuildMI(MBB, InsertPt, MI.getDebugLoc(), TII->get(Opc), NewReg)
259*4fc4e42dSDan Gohman                 .addImm(LocalId);
260*4fc4e42dSDan Gohman         MO.setReg(NewReg);
261*4fc4e42dSDan Gohman         MFI.stackifyVReg(NewReg);
262*4fc4e42dSDan Gohman         Changed = true;
263*4fc4e42dSDan Gohman       }
264*4fc4e42dSDan Gohman 
265*4fc4e42dSDan Gohman       // Coalesce and eliminate COPY instructions.
266*4fc4e42dSDan Gohman       if (WebAssembly::isCopy(MI)) {
267*4fc4e42dSDan Gohman         MRI.replaceRegWith(MI.getOperand(1).getReg(),
268*4fc4e42dSDan Gohman                            MI.getOperand(0).getReg());
269*4fc4e42dSDan Gohman         MI.eraseFromParent();
270*4fc4e42dSDan Gohman         Changed = true;
271*4fc4e42dSDan Gohman       }
272*4fc4e42dSDan Gohman     }
273*4fc4e42dSDan Gohman   }
274*4fc4e42dSDan Gohman 
275*4fc4e42dSDan Gohman   // Insert a .locals directive to declare the locals.
276*4fc4e42dSDan Gohman   MachineInstrBuilder DeclareLocals;
277*4fc4e42dSDan Gohman   for (size_t i = 0, e = MRI.getNumVirtRegs(); i < e; ++i) {
278*4fc4e42dSDan Gohman     unsigned Reg = TargetRegisterInfo::index2VirtReg(i);
279*4fc4e42dSDan Gohman     auto I = Reg2Local.find(Reg);
280*4fc4e42dSDan Gohman     if (I == Reg2Local.end() || I->second < MFI.getParams().size())
281*4fc4e42dSDan Gohman       continue;
282*4fc4e42dSDan Gohman 
283*4fc4e42dSDan Gohman     if (!DeclareLocals) {
284*4fc4e42dSDan Gohman       DeclareLocals = BuildMI(*MF.begin(), MF.begin()->begin(), DebugLoc(),
285*4fc4e42dSDan Gohman                               TII->get(WebAssembly::DECLARE_LOCALS));
286*4fc4e42dSDan Gohman       Changed = true;
287*4fc4e42dSDan Gohman     }
288*4fc4e42dSDan Gohman 
289*4fc4e42dSDan Gohman     DeclareLocals.addImm(int64_t(typeForRegClass(MRI.getRegClass(Reg))));
290*4fc4e42dSDan Gohman   }
291*4fc4e42dSDan Gohman 
292*4fc4e42dSDan Gohman #ifndef NDEBUG
293*4fc4e42dSDan Gohman   // Assert that all registers have been stackified at this point.
294*4fc4e42dSDan Gohman   for (const MachineBasicBlock &MBB : MF) {
295*4fc4e42dSDan Gohman     for (const MachineInstr &MI : MBB) {
296*4fc4e42dSDan Gohman       if (MI.isDebugValue() || MI.isLabel())
297*4fc4e42dSDan Gohman         continue;
298*4fc4e42dSDan Gohman       for (const MachineOperand &MO : MI.explicit_operands()) {
299*4fc4e42dSDan Gohman         assert(
300*4fc4e42dSDan Gohman             (!MO.isReg() || MRI.use_empty(MO.getReg()) ||
301*4fc4e42dSDan Gohman              MFI.isVRegStackified(MO.getReg())) &&
302*4fc4e42dSDan Gohman             "WebAssemblyExplicitLocals failed to stackify a register operand");
303*4fc4e42dSDan Gohman       }
304*4fc4e42dSDan Gohman     }
305*4fc4e42dSDan Gohman   }
306*4fc4e42dSDan Gohman #endif
307*4fc4e42dSDan Gohman 
308*4fc4e42dSDan Gohman   return Changed;
309*4fc4e42dSDan Gohman }
310