xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp (revision 0b57cec536236d46e3dba9bd041533462f33dbb7)
1*0b57cec5SDimitry Andric //===-- WebAssemblyExplicitLocals.cpp - Make Locals Explicit --------------===//
2*0b57cec5SDimitry Andric //
3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0b57cec5SDimitry Andric //
7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8*0b57cec5SDimitry Andric ///
9*0b57cec5SDimitry Andric /// \file
10*0b57cec5SDimitry Andric /// This file converts any remaining registers into WebAssembly locals.
11*0b57cec5SDimitry Andric ///
12*0b57cec5SDimitry Andric /// After register stackification and register coloring, convert non-stackified
13*0b57cec5SDimitry Andric /// registers into locals, inserting explicit local.get and local.set
14*0b57cec5SDimitry Andric /// instructions.
15*0b57cec5SDimitry Andric ///
16*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
17*0b57cec5SDimitry Andric 
18*0b57cec5SDimitry Andric #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
19*0b57cec5SDimitry Andric #include "WebAssembly.h"
20*0b57cec5SDimitry Andric #include "WebAssemblyMachineFunctionInfo.h"
21*0b57cec5SDimitry Andric #include "WebAssemblySubtarget.h"
22*0b57cec5SDimitry Andric #include "WebAssemblyUtilities.h"
23*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineBlockFrequencyInfo.h"
24*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h"
25*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h"
26*0b57cec5SDimitry Andric #include "llvm/CodeGen/Passes.h"
27*0b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
28*0b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
29*0b57cec5SDimitry Andric using namespace llvm;
30*0b57cec5SDimitry Andric 
31*0b57cec5SDimitry Andric #define DEBUG_TYPE "wasm-explicit-locals"
32*0b57cec5SDimitry Andric 
33*0b57cec5SDimitry Andric // A command-line option to disable this pass, and keep implicit locals
34*0b57cec5SDimitry Andric // for the purpose of testing with lit/llc ONLY.
35*0b57cec5SDimitry Andric // This produces output which is not valid WebAssembly, and is not supported
36*0b57cec5SDimitry Andric // by assemblers/disassemblers and other MC based tools.
37*0b57cec5SDimitry Andric static cl::opt<bool> WasmDisableExplicitLocals(
38*0b57cec5SDimitry Andric     "wasm-disable-explicit-locals", cl::Hidden,
39*0b57cec5SDimitry Andric     cl::desc("WebAssembly: output implicit locals in"
40*0b57cec5SDimitry Andric              " instruction output for test purposes only."),
41*0b57cec5SDimitry Andric     cl::init(false));
42*0b57cec5SDimitry Andric 
43*0b57cec5SDimitry Andric namespace {
44*0b57cec5SDimitry Andric class WebAssemblyExplicitLocals final : public MachineFunctionPass {
45*0b57cec5SDimitry Andric   StringRef getPassName() const override {
46*0b57cec5SDimitry Andric     return "WebAssembly Explicit Locals";
47*0b57cec5SDimitry Andric   }
48*0b57cec5SDimitry Andric 
49*0b57cec5SDimitry Andric   void getAnalysisUsage(AnalysisUsage &AU) const override {
50*0b57cec5SDimitry Andric     AU.setPreservesCFG();
51*0b57cec5SDimitry Andric     AU.addPreserved<MachineBlockFrequencyInfo>();
52*0b57cec5SDimitry Andric     MachineFunctionPass::getAnalysisUsage(AU);
53*0b57cec5SDimitry Andric   }
54*0b57cec5SDimitry Andric 
55*0b57cec5SDimitry Andric   bool runOnMachineFunction(MachineFunction &MF) override;
56*0b57cec5SDimitry Andric 
57*0b57cec5SDimitry Andric public:
58*0b57cec5SDimitry Andric   static char ID; // Pass identification, replacement for typeid
59*0b57cec5SDimitry Andric   WebAssemblyExplicitLocals() : MachineFunctionPass(ID) {}
60*0b57cec5SDimitry Andric };
61*0b57cec5SDimitry Andric } // end anonymous namespace
62*0b57cec5SDimitry Andric 
63*0b57cec5SDimitry Andric char WebAssemblyExplicitLocals::ID = 0;
64*0b57cec5SDimitry Andric INITIALIZE_PASS(WebAssemblyExplicitLocals, DEBUG_TYPE,
65*0b57cec5SDimitry Andric                 "Convert registers to WebAssembly locals", false, false)
66*0b57cec5SDimitry Andric 
67*0b57cec5SDimitry Andric FunctionPass *llvm::createWebAssemblyExplicitLocals() {
68*0b57cec5SDimitry Andric   return new WebAssemblyExplicitLocals();
69*0b57cec5SDimitry Andric }
70*0b57cec5SDimitry Andric 
71*0b57cec5SDimitry Andric /// Return a local id number for the given register, assigning it a new one
72*0b57cec5SDimitry Andric /// if it doesn't yet have one.
73*0b57cec5SDimitry Andric static unsigned getLocalId(DenseMap<unsigned, unsigned> &Reg2Local,
74*0b57cec5SDimitry Andric                            unsigned &CurLocal, unsigned Reg) {
75*0b57cec5SDimitry Andric   auto P = Reg2Local.insert(std::make_pair(Reg, CurLocal));
76*0b57cec5SDimitry Andric   if (P.second)
77*0b57cec5SDimitry Andric     ++CurLocal;
78*0b57cec5SDimitry Andric   return P.first->second;
79*0b57cec5SDimitry Andric }
80*0b57cec5SDimitry Andric 
81*0b57cec5SDimitry Andric /// Get the appropriate drop opcode for the given register class.
82*0b57cec5SDimitry Andric static unsigned getDropOpcode(const TargetRegisterClass *RC) {
83*0b57cec5SDimitry Andric   if (RC == &WebAssembly::I32RegClass)
84*0b57cec5SDimitry Andric     return WebAssembly::DROP_I32;
85*0b57cec5SDimitry Andric   if (RC == &WebAssembly::I64RegClass)
86*0b57cec5SDimitry Andric     return WebAssembly::DROP_I64;
87*0b57cec5SDimitry Andric   if (RC == &WebAssembly::F32RegClass)
88*0b57cec5SDimitry Andric     return WebAssembly::DROP_F32;
89*0b57cec5SDimitry Andric   if (RC == &WebAssembly::F64RegClass)
90*0b57cec5SDimitry Andric     return WebAssembly::DROP_F64;
91*0b57cec5SDimitry Andric   if (RC == &WebAssembly::V128RegClass)
92*0b57cec5SDimitry Andric     return WebAssembly::DROP_V128;
93*0b57cec5SDimitry Andric   if (RC == &WebAssembly::EXNREFRegClass)
94*0b57cec5SDimitry Andric     return WebAssembly::DROP_EXNREF;
95*0b57cec5SDimitry Andric   llvm_unreachable("Unexpected register class");
96*0b57cec5SDimitry Andric }
97*0b57cec5SDimitry Andric 
98*0b57cec5SDimitry Andric /// Get the appropriate local.get opcode for the given register class.
99*0b57cec5SDimitry Andric static unsigned getLocalGetOpcode(const TargetRegisterClass *RC) {
100*0b57cec5SDimitry Andric   if (RC == &WebAssembly::I32RegClass)
101*0b57cec5SDimitry Andric     return WebAssembly::LOCAL_GET_I32;
102*0b57cec5SDimitry Andric   if (RC == &WebAssembly::I64RegClass)
103*0b57cec5SDimitry Andric     return WebAssembly::LOCAL_GET_I64;
104*0b57cec5SDimitry Andric   if (RC == &WebAssembly::F32RegClass)
105*0b57cec5SDimitry Andric     return WebAssembly::LOCAL_GET_F32;
106*0b57cec5SDimitry Andric   if (RC == &WebAssembly::F64RegClass)
107*0b57cec5SDimitry Andric     return WebAssembly::LOCAL_GET_F64;
108*0b57cec5SDimitry Andric   if (RC == &WebAssembly::V128RegClass)
109*0b57cec5SDimitry Andric     return WebAssembly::LOCAL_GET_V128;
110*0b57cec5SDimitry Andric   if (RC == &WebAssembly::EXNREFRegClass)
111*0b57cec5SDimitry Andric     return WebAssembly::LOCAL_GET_EXNREF;
112*0b57cec5SDimitry Andric   llvm_unreachable("Unexpected register class");
113*0b57cec5SDimitry Andric }
114*0b57cec5SDimitry Andric 
115*0b57cec5SDimitry Andric /// Get the appropriate local.set opcode for the given register class.
116*0b57cec5SDimitry Andric static unsigned getLocalSetOpcode(const TargetRegisterClass *RC) {
117*0b57cec5SDimitry Andric   if (RC == &WebAssembly::I32RegClass)
118*0b57cec5SDimitry Andric     return WebAssembly::LOCAL_SET_I32;
119*0b57cec5SDimitry Andric   if (RC == &WebAssembly::I64RegClass)
120*0b57cec5SDimitry Andric     return WebAssembly::LOCAL_SET_I64;
121*0b57cec5SDimitry Andric   if (RC == &WebAssembly::F32RegClass)
122*0b57cec5SDimitry Andric     return WebAssembly::LOCAL_SET_F32;
123*0b57cec5SDimitry Andric   if (RC == &WebAssembly::F64RegClass)
124*0b57cec5SDimitry Andric     return WebAssembly::LOCAL_SET_F64;
125*0b57cec5SDimitry Andric   if (RC == &WebAssembly::V128RegClass)
126*0b57cec5SDimitry Andric     return WebAssembly::LOCAL_SET_V128;
127*0b57cec5SDimitry Andric   if (RC == &WebAssembly::EXNREFRegClass)
128*0b57cec5SDimitry Andric     return WebAssembly::LOCAL_SET_EXNREF;
129*0b57cec5SDimitry Andric   llvm_unreachable("Unexpected register class");
130*0b57cec5SDimitry Andric }
131*0b57cec5SDimitry Andric 
132*0b57cec5SDimitry Andric /// Get the appropriate local.tee opcode for the given register class.
133*0b57cec5SDimitry Andric static unsigned getLocalTeeOpcode(const TargetRegisterClass *RC) {
134*0b57cec5SDimitry Andric   if (RC == &WebAssembly::I32RegClass)
135*0b57cec5SDimitry Andric     return WebAssembly::LOCAL_TEE_I32;
136*0b57cec5SDimitry Andric   if (RC == &WebAssembly::I64RegClass)
137*0b57cec5SDimitry Andric     return WebAssembly::LOCAL_TEE_I64;
138*0b57cec5SDimitry Andric   if (RC == &WebAssembly::F32RegClass)
139*0b57cec5SDimitry Andric     return WebAssembly::LOCAL_TEE_F32;
140*0b57cec5SDimitry Andric   if (RC == &WebAssembly::F64RegClass)
141*0b57cec5SDimitry Andric     return WebAssembly::LOCAL_TEE_F64;
142*0b57cec5SDimitry Andric   if (RC == &WebAssembly::V128RegClass)
143*0b57cec5SDimitry Andric     return WebAssembly::LOCAL_TEE_V128;
144*0b57cec5SDimitry Andric   if (RC == &WebAssembly::EXNREFRegClass)
145*0b57cec5SDimitry Andric     return WebAssembly::LOCAL_TEE_EXNREF;
146*0b57cec5SDimitry Andric   llvm_unreachable("Unexpected register class");
147*0b57cec5SDimitry Andric }
148*0b57cec5SDimitry Andric 
149*0b57cec5SDimitry Andric /// Get the type associated with the given register class.
150*0b57cec5SDimitry Andric static MVT typeForRegClass(const TargetRegisterClass *RC) {
151*0b57cec5SDimitry Andric   if (RC == &WebAssembly::I32RegClass)
152*0b57cec5SDimitry Andric     return MVT::i32;
153*0b57cec5SDimitry Andric   if (RC == &WebAssembly::I64RegClass)
154*0b57cec5SDimitry Andric     return MVT::i64;
155*0b57cec5SDimitry Andric   if (RC == &WebAssembly::F32RegClass)
156*0b57cec5SDimitry Andric     return MVT::f32;
157*0b57cec5SDimitry Andric   if (RC == &WebAssembly::F64RegClass)
158*0b57cec5SDimitry Andric     return MVT::f64;
159*0b57cec5SDimitry Andric   if (RC == &WebAssembly::V128RegClass)
160*0b57cec5SDimitry Andric     return MVT::v16i8;
161*0b57cec5SDimitry Andric   if (RC == &WebAssembly::EXNREFRegClass)
162*0b57cec5SDimitry Andric     return MVT::exnref;
163*0b57cec5SDimitry Andric   llvm_unreachable("unrecognized register class");
164*0b57cec5SDimitry Andric }
165*0b57cec5SDimitry Andric 
166*0b57cec5SDimitry Andric /// Given a MachineOperand of a stackified vreg, return the instruction at the
167*0b57cec5SDimitry Andric /// start of the expression tree.
168*0b57cec5SDimitry Andric static MachineInstr *findStartOfTree(MachineOperand &MO,
169*0b57cec5SDimitry Andric                                      MachineRegisterInfo &MRI,
170*0b57cec5SDimitry Andric                                      WebAssemblyFunctionInfo &MFI) {
171*0b57cec5SDimitry Andric   unsigned Reg = MO.getReg();
172*0b57cec5SDimitry Andric   assert(MFI.isVRegStackified(Reg));
173*0b57cec5SDimitry Andric   MachineInstr *Def = MRI.getVRegDef(Reg);
174*0b57cec5SDimitry Andric 
175*0b57cec5SDimitry Andric   // Find the first stackified use and proceed from there.
176*0b57cec5SDimitry Andric   for (MachineOperand &DefMO : Def->explicit_uses()) {
177*0b57cec5SDimitry Andric     if (!DefMO.isReg())
178*0b57cec5SDimitry Andric       continue;
179*0b57cec5SDimitry Andric     return findStartOfTree(DefMO, MRI, MFI);
180*0b57cec5SDimitry Andric   }
181*0b57cec5SDimitry Andric 
182*0b57cec5SDimitry Andric   // If there were no stackified uses, we've reached the start.
183*0b57cec5SDimitry Andric   return Def;
184*0b57cec5SDimitry Andric }
185*0b57cec5SDimitry Andric 
186*0b57cec5SDimitry Andric bool WebAssemblyExplicitLocals::runOnMachineFunction(MachineFunction &MF) {
187*0b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "********** Make Locals Explicit **********\n"
188*0b57cec5SDimitry Andric                        "********** Function: "
189*0b57cec5SDimitry Andric                     << MF.getName() << '\n');
190*0b57cec5SDimitry Andric 
191*0b57cec5SDimitry Andric   // Disable this pass if directed to do so.
192*0b57cec5SDimitry Andric   if (WasmDisableExplicitLocals)
193*0b57cec5SDimitry Andric     return false;
194*0b57cec5SDimitry Andric 
195*0b57cec5SDimitry Andric   bool Changed = false;
196*0b57cec5SDimitry Andric   MachineRegisterInfo &MRI = MF.getRegInfo();
197*0b57cec5SDimitry Andric   WebAssemblyFunctionInfo &MFI = *MF.getInfo<WebAssemblyFunctionInfo>();
198*0b57cec5SDimitry Andric   const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
199*0b57cec5SDimitry Andric 
200*0b57cec5SDimitry Andric   // Map non-stackified virtual registers to their local ids.
201*0b57cec5SDimitry Andric   DenseMap<unsigned, unsigned> Reg2Local;
202*0b57cec5SDimitry Andric 
203*0b57cec5SDimitry Andric   // Handle ARGUMENTS first to ensure that they get the designated numbers.
204*0b57cec5SDimitry Andric   for (MachineBasicBlock::iterator I = MF.begin()->begin(),
205*0b57cec5SDimitry Andric                                    E = MF.begin()->end();
206*0b57cec5SDimitry Andric        I != E;) {
207*0b57cec5SDimitry Andric     MachineInstr &MI = *I++;
208*0b57cec5SDimitry Andric     if (!WebAssembly::isArgument(MI.getOpcode()))
209*0b57cec5SDimitry Andric       break;
210*0b57cec5SDimitry Andric     unsigned Reg = MI.getOperand(0).getReg();
211*0b57cec5SDimitry Andric     assert(!MFI.isVRegStackified(Reg));
212*0b57cec5SDimitry Andric     Reg2Local[Reg] = static_cast<unsigned>(MI.getOperand(1).getImm());
213*0b57cec5SDimitry Andric     MI.eraseFromParent();
214*0b57cec5SDimitry Andric     Changed = true;
215*0b57cec5SDimitry Andric   }
216*0b57cec5SDimitry Andric 
217*0b57cec5SDimitry Andric   // Start assigning local numbers after the last parameter.
218*0b57cec5SDimitry Andric   unsigned CurLocal = static_cast<unsigned>(MFI.getParams().size());
219*0b57cec5SDimitry Andric 
220*0b57cec5SDimitry Andric   // Precompute the set of registers that are unused, so that we can insert
221*0b57cec5SDimitry Andric   // drops to their defs.
222*0b57cec5SDimitry Andric   BitVector UseEmpty(MRI.getNumVirtRegs());
223*0b57cec5SDimitry Andric   for (unsigned I = 0, E = MRI.getNumVirtRegs(); I < E; ++I)
224*0b57cec5SDimitry Andric     UseEmpty[I] = MRI.use_empty(TargetRegisterInfo::index2VirtReg(I));
225*0b57cec5SDimitry Andric 
226*0b57cec5SDimitry Andric   // Visit each instruction in the function.
227*0b57cec5SDimitry Andric   for (MachineBasicBlock &MBB : MF) {
228*0b57cec5SDimitry Andric     for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end(); I != E;) {
229*0b57cec5SDimitry Andric       MachineInstr &MI = *I++;
230*0b57cec5SDimitry Andric       assert(!WebAssembly::isArgument(MI.getOpcode()));
231*0b57cec5SDimitry Andric 
232*0b57cec5SDimitry Andric       if (MI.isDebugInstr() || MI.isLabel())
233*0b57cec5SDimitry Andric         continue;
234*0b57cec5SDimitry Andric 
235*0b57cec5SDimitry Andric       // Replace tee instructions with local.tee. The difference is that tee
236*0b57cec5SDimitry Andric       // instructions have two defs, while local.tee instructions have one def
237*0b57cec5SDimitry Andric       // and an index of a local to write to.
238*0b57cec5SDimitry Andric       if (WebAssembly::isTee(MI.getOpcode())) {
239*0b57cec5SDimitry Andric         assert(MFI.isVRegStackified(MI.getOperand(0).getReg()));
240*0b57cec5SDimitry Andric         assert(!MFI.isVRegStackified(MI.getOperand(1).getReg()));
241*0b57cec5SDimitry Andric         unsigned OldReg = MI.getOperand(2).getReg();
242*0b57cec5SDimitry Andric         const TargetRegisterClass *RC = MRI.getRegClass(OldReg);
243*0b57cec5SDimitry Andric 
244*0b57cec5SDimitry Andric         // Stackify the input if it isn't stackified yet.
245*0b57cec5SDimitry Andric         if (!MFI.isVRegStackified(OldReg)) {
246*0b57cec5SDimitry Andric           unsigned LocalId = getLocalId(Reg2Local, CurLocal, OldReg);
247*0b57cec5SDimitry Andric           unsigned NewReg = MRI.createVirtualRegister(RC);
248*0b57cec5SDimitry Andric           unsigned Opc = getLocalGetOpcode(RC);
249*0b57cec5SDimitry Andric           BuildMI(MBB, &MI, MI.getDebugLoc(), TII->get(Opc), NewReg)
250*0b57cec5SDimitry Andric               .addImm(LocalId);
251*0b57cec5SDimitry Andric           MI.getOperand(2).setReg(NewReg);
252*0b57cec5SDimitry Andric           MFI.stackifyVReg(NewReg);
253*0b57cec5SDimitry Andric         }
254*0b57cec5SDimitry Andric 
255*0b57cec5SDimitry Andric         // Replace the TEE with a LOCAL_TEE.
256*0b57cec5SDimitry Andric         unsigned LocalId =
257*0b57cec5SDimitry Andric             getLocalId(Reg2Local, CurLocal, MI.getOperand(1).getReg());
258*0b57cec5SDimitry Andric         unsigned Opc = getLocalTeeOpcode(RC);
259*0b57cec5SDimitry Andric         BuildMI(MBB, &MI, MI.getDebugLoc(), TII->get(Opc),
260*0b57cec5SDimitry Andric                 MI.getOperand(0).getReg())
261*0b57cec5SDimitry Andric             .addImm(LocalId)
262*0b57cec5SDimitry Andric             .addReg(MI.getOperand(2).getReg());
263*0b57cec5SDimitry Andric 
264*0b57cec5SDimitry Andric         MI.eraseFromParent();
265*0b57cec5SDimitry Andric         Changed = true;
266*0b57cec5SDimitry Andric         continue;
267*0b57cec5SDimitry Andric       }
268*0b57cec5SDimitry Andric 
269*0b57cec5SDimitry Andric       // Insert local.sets for any defs that aren't stackified yet. Currently
270*0b57cec5SDimitry Andric       // we handle at most one def.
271*0b57cec5SDimitry Andric       assert(MI.getDesc().getNumDefs() <= 1);
272*0b57cec5SDimitry Andric       if (MI.getDesc().getNumDefs() == 1) {
273*0b57cec5SDimitry Andric         unsigned OldReg = MI.getOperand(0).getReg();
274*0b57cec5SDimitry Andric         if (!MFI.isVRegStackified(OldReg)) {
275*0b57cec5SDimitry Andric           const TargetRegisterClass *RC = MRI.getRegClass(OldReg);
276*0b57cec5SDimitry Andric           unsigned NewReg = MRI.createVirtualRegister(RC);
277*0b57cec5SDimitry Andric           auto InsertPt = std::next(MI.getIterator());
278*0b57cec5SDimitry Andric           if (MI.getOpcode() == WebAssembly::IMPLICIT_DEF) {
279*0b57cec5SDimitry Andric             MI.eraseFromParent();
280*0b57cec5SDimitry Andric             Changed = true;
281*0b57cec5SDimitry Andric             continue;
282*0b57cec5SDimitry Andric           }
283*0b57cec5SDimitry Andric           if (UseEmpty[TargetRegisterInfo::virtReg2Index(OldReg)]) {
284*0b57cec5SDimitry Andric             unsigned Opc = getDropOpcode(RC);
285*0b57cec5SDimitry Andric             MachineInstr *Drop =
286*0b57cec5SDimitry Andric                 BuildMI(MBB, InsertPt, MI.getDebugLoc(), TII->get(Opc))
287*0b57cec5SDimitry Andric                     .addReg(NewReg);
288*0b57cec5SDimitry Andric             // After the drop instruction, this reg operand will not be used
289*0b57cec5SDimitry Andric             Drop->getOperand(0).setIsKill();
290*0b57cec5SDimitry Andric           } else {
291*0b57cec5SDimitry Andric             unsigned LocalId = getLocalId(Reg2Local, CurLocal, OldReg);
292*0b57cec5SDimitry Andric             unsigned Opc = getLocalSetOpcode(RC);
293*0b57cec5SDimitry Andric             BuildMI(MBB, InsertPt, MI.getDebugLoc(), TII->get(Opc))
294*0b57cec5SDimitry Andric                 .addImm(LocalId)
295*0b57cec5SDimitry Andric                 .addReg(NewReg);
296*0b57cec5SDimitry Andric           }
297*0b57cec5SDimitry Andric           MI.getOperand(0).setReg(NewReg);
298*0b57cec5SDimitry Andric           // This register operand of the original instruction is now being used
299*0b57cec5SDimitry Andric           // by the inserted drop or local.set instruction, so make it not dead
300*0b57cec5SDimitry Andric           // yet.
301*0b57cec5SDimitry Andric           MI.getOperand(0).setIsDead(false);
302*0b57cec5SDimitry Andric           MFI.stackifyVReg(NewReg);
303*0b57cec5SDimitry Andric           Changed = true;
304*0b57cec5SDimitry Andric         }
305*0b57cec5SDimitry Andric       }
306*0b57cec5SDimitry Andric 
307*0b57cec5SDimitry Andric       // Insert local.gets for any uses that aren't stackified yet.
308*0b57cec5SDimitry Andric       MachineInstr *InsertPt = &MI;
309*0b57cec5SDimitry Andric       for (MachineOperand &MO : reverse(MI.explicit_uses())) {
310*0b57cec5SDimitry Andric         if (!MO.isReg())
311*0b57cec5SDimitry Andric           continue;
312*0b57cec5SDimitry Andric 
313*0b57cec5SDimitry Andric         unsigned OldReg = MO.getReg();
314*0b57cec5SDimitry Andric 
315*0b57cec5SDimitry Andric         // Inline asm may have a def in the middle of the operands. Our contract
316*0b57cec5SDimitry Andric         // with inline asm register operands is to provide local indices as
317*0b57cec5SDimitry Andric         // immediates.
318*0b57cec5SDimitry Andric         if (MO.isDef()) {
319*0b57cec5SDimitry Andric           assert(MI.isInlineAsm());
320*0b57cec5SDimitry Andric           unsigned LocalId = getLocalId(Reg2Local, CurLocal, OldReg);
321*0b57cec5SDimitry Andric           // If this register operand is tied to another operand, we can't
322*0b57cec5SDimitry Andric           // change it to an immediate. Untie it first.
323*0b57cec5SDimitry Andric           MI.untieRegOperand(MI.getOperandNo(&MO));
324*0b57cec5SDimitry Andric           MO.ChangeToImmediate(LocalId);
325*0b57cec5SDimitry Andric           continue;
326*0b57cec5SDimitry Andric         }
327*0b57cec5SDimitry Andric 
328*0b57cec5SDimitry Andric         // If we see a stackified register, prepare to insert subsequent
329*0b57cec5SDimitry Andric         // local.gets before the start of its tree.
330*0b57cec5SDimitry Andric         if (MFI.isVRegStackified(OldReg)) {
331*0b57cec5SDimitry Andric           InsertPt = findStartOfTree(MO, MRI, MFI);
332*0b57cec5SDimitry Andric           continue;
333*0b57cec5SDimitry Andric         }
334*0b57cec5SDimitry Andric 
335*0b57cec5SDimitry Andric         // Our contract with inline asm register operands is to provide local
336*0b57cec5SDimitry Andric         // indices as immediates.
337*0b57cec5SDimitry Andric         if (MI.isInlineAsm()) {
338*0b57cec5SDimitry Andric           unsigned LocalId = getLocalId(Reg2Local, CurLocal, OldReg);
339*0b57cec5SDimitry Andric           // Untie it first if this reg operand is tied to another operand.
340*0b57cec5SDimitry Andric           MI.untieRegOperand(MI.getOperandNo(&MO));
341*0b57cec5SDimitry Andric           MO.ChangeToImmediate(LocalId);
342*0b57cec5SDimitry Andric           continue;
343*0b57cec5SDimitry Andric         }
344*0b57cec5SDimitry Andric 
345*0b57cec5SDimitry Andric         // Insert a local.get.
346*0b57cec5SDimitry Andric         unsigned LocalId = getLocalId(Reg2Local, CurLocal, OldReg);
347*0b57cec5SDimitry Andric         const TargetRegisterClass *RC = MRI.getRegClass(OldReg);
348*0b57cec5SDimitry Andric         unsigned NewReg = MRI.createVirtualRegister(RC);
349*0b57cec5SDimitry Andric         unsigned Opc = getLocalGetOpcode(RC);
350*0b57cec5SDimitry Andric         InsertPt =
351*0b57cec5SDimitry Andric             BuildMI(MBB, InsertPt, MI.getDebugLoc(), TII->get(Opc), NewReg)
352*0b57cec5SDimitry Andric                 .addImm(LocalId);
353*0b57cec5SDimitry Andric         MO.setReg(NewReg);
354*0b57cec5SDimitry Andric         MFI.stackifyVReg(NewReg);
355*0b57cec5SDimitry Andric         Changed = true;
356*0b57cec5SDimitry Andric       }
357*0b57cec5SDimitry Andric 
358*0b57cec5SDimitry Andric       // Coalesce and eliminate COPY instructions.
359*0b57cec5SDimitry Andric       if (WebAssembly::isCopy(MI.getOpcode())) {
360*0b57cec5SDimitry Andric         MRI.replaceRegWith(MI.getOperand(1).getReg(),
361*0b57cec5SDimitry Andric                            MI.getOperand(0).getReg());
362*0b57cec5SDimitry Andric         MI.eraseFromParent();
363*0b57cec5SDimitry Andric         Changed = true;
364*0b57cec5SDimitry Andric       }
365*0b57cec5SDimitry Andric     }
366*0b57cec5SDimitry Andric   }
367*0b57cec5SDimitry Andric 
368*0b57cec5SDimitry Andric   // Define the locals.
369*0b57cec5SDimitry Andric   // TODO: Sort the locals for better compression.
370*0b57cec5SDimitry Andric   MFI.setNumLocals(CurLocal - MFI.getParams().size());
371*0b57cec5SDimitry Andric   for (unsigned I = 0, E = MRI.getNumVirtRegs(); I < E; ++I) {
372*0b57cec5SDimitry Andric     unsigned Reg = TargetRegisterInfo::index2VirtReg(I);
373*0b57cec5SDimitry Andric     auto RL = Reg2Local.find(Reg);
374*0b57cec5SDimitry Andric     if (RL == Reg2Local.end() || RL->second < MFI.getParams().size())
375*0b57cec5SDimitry Andric       continue;
376*0b57cec5SDimitry Andric 
377*0b57cec5SDimitry Andric     MFI.setLocal(RL->second - MFI.getParams().size(),
378*0b57cec5SDimitry Andric                  typeForRegClass(MRI.getRegClass(Reg)));
379*0b57cec5SDimitry Andric     Changed = true;
380*0b57cec5SDimitry Andric   }
381*0b57cec5SDimitry Andric 
382*0b57cec5SDimitry Andric #ifndef NDEBUG
383*0b57cec5SDimitry Andric   // Assert that all registers have been stackified at this point.
384*0b57cec5SDimitry Andric   for (const MachineBasicBlock &MBB : MF) {
385*0b57cec5SDimitry Andric     for (const MachineInstr &MI : MBB) {
386*0b57cec5SDimitry Andric       if (MI.isDebugInstr() || MI.isLabel())
387*0b57cec5SDimitry Andric         continue;
388*0b57cec5SDimitry Andric       for (const MachineOperand &MO : MI.explicit_operands()) {
389*0b57cec5SDimitry Andric         assert(
390*0b57cec5SDimitry Andric             (!MO.isReg() || MRI.use_empty(MO.getReg()) ||
391*0b57cec5SDimitry Andric              MFI.isVRegStackified(MO.getReg())) &&
392*0b57cec5SDimitry Andric             "WebAssemblyExplicitLocals failed to stackify a register operand");
393*0b57cec5SDimitry Andric       }
394*0b57cec5SDimitry Andric     }
395*0b57cec5SDimitry Andric   }
396*0b57cec5SDimitry Andric #endif
397*0b57cec5SDimitry Andric 
398*0b57cec5SDimitry Andric   return Changed;
399*0b57cec5SDimitry Andric }
400