1d88c1a5aSDimitry Andric //===-- WebAssemblyExplicitLocals.cpp - Make Locals Explicit --------------===//
2d88c1a5aSDimitry Andric //
3d88c1a5aSDimitry Andric //                     The LLVM Compiler Infrastructure
4d88c1a5aSDimitry Andric //
5d88c1a5aSDimitry Andric // This file is distributed under the University of Illinois Open Source
6d88c1a5aSDimitry Andric // License. See LICENSE.TXT for details.
7d88c1a5aSDimitry Andric //
8d88c1a5aSDimitry Andric //===----------------------------------------------------------------------===//
9d88c1a5aSDimitry Andric ///
10d88c1a5aSDimitry Andric /// \file
114ba319b5SDimitry Andric /// This file converts any remaining registers into WebAssembly locals.
12d88c1a5aSDimitry Andric ///
13d88c1a5aSDimitry Andric /// After register stackification and register coloring, convert non-stackified
14*b5893f02SDimitry Andric /// registers into locals, inserting explicit local.get and local.set
15d88c1a5aSDimitry Andric /// instructions.
16d88c1a5aSDimitry Andric ///
17d88c1a5aSDimitry Andric //===----------------------------------------------------------------------===//
18d88c1a5aSDimitry Andric 
19d88c1a5aSDimitry Andric #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
20d88c1a5aSDimitry Andric #include "WebAssembly.h"
21d88c1a5aSDimitry Andric #include "WebAssemblyMachineFunctionInfo.h"
22d88c1a5aSDimitry Andric #include "WebAssemblySubtarget.h"
23d88c1a5aSDimitry Andric #include "WebAssemblyUtilities.h"
24d88c1a5aSDimitry Andric #include "llvm/CodeGen/MachineBlockFrequencyInfo.h"
25d88c1a5aSDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h"
26d88c1a5aSDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h"
27d88c1a5aSDimitry Andric #include "llvm/CodeGen/Passes.h"
28d88c1a5aSDimitry Andric #include "llvm/Support/Debug.h"
29d88c1a5aSDimitry Andric #include "llvm/Support/raw_ostream.h"
30d88c1a5aSDimitry Andric using namespace llvm;
31d88c1a5aSDimitry Andric 
32d88c1a5aSDimitry Andric #define DEBUG_TYPE "wasm-explicit-locals"
33d88c1a5aSDimitry Andric 
34*b5893f02SDimitry Andric // A command-line option to disable this pass, and keep implicit locals
35*b5893f02SDimitry Andric // for the purpose of testing with lit/llc ONLY.
36*b5893f02SDimitry Andric // This produces output which is not valid WebAssembly, and is not supported
37*b5893f02SDimitry Andric // by assemblers/disassemblers and other MC based tools.
38*b5893f02SDimitry Andric static cl::opt<bool> WasmDisableExplicitLocals(
39*b5893f02SDimitry Andric     "wasm-disable-explicit-locals", cl::Hidden,
40*b5893f02SDimitry Andric     cl::desc("WebAssembly: output implicit locals in"
41*b5893f02SDimitry Andric              " instruction output for test purposes only."),
427a7e6055SDimitry Andric     cl::init(false));
437a7e6055SDimitry Andric 
44d88c1a5aSDimitry Andric namespace {
45d88c1a5aSDimitry Andric class WebAssemblyExplicitLocals final : public MachineFunctionPass {
getPassName() const46d88c1a5aSDimitry Andric   StringRef getPassName() const override {
47d88c1a5aSDimitry Andric     return "WebAssembly Explicit Locals";
48d88c1a5aSDimitry Andric   }
49d88c1a5aSDimitry Andric 
getAnalysisUsage(AnalysisUsage & AU) const50d88c1a5aSDimitry Andric   void getAnalysisUsage(AnalysisUsage &AU) const override {
51d88c1a5aSDimitry Andric     AU.setPreservesCFG();
52d88c1a5aSDimitry Andric     AU.addPreserved<MachineBlockFrequencyInfo>();
53d88c1a5aSDimitry Andric     MachineFunctionPass::getAnalysisUsage(AU);
54d88c1a5aSDimitry Andric   }
55d88c1a5aSDimitry Andric 
56d88c1a5aSDimitry Andric   bool runOnMachineFunction(MachineFunction &MF) override;
57d88c1a5aSDimitry Andric 
58d88c1a5aSDimitry Andric public:
59d88c1a5aSDimitry Andric   static char ID; // Pass identification, replacement for typeid
WebAssemblyExplicitLocals()60d88c1a5aSDimitry Andric   WebAssemblyExplicitLocals() : MachineFunctionPass(ID) {}
61d88c1a5aSDimitry Andric };
62d88c1a5aSDimitry Andric } // end anonymous namespace
63d88c1a5aSDimitry Andric 
64d88c1a5aSDimitry Andric char WebAssemblyExplicitLocals::ID = 0;
654ba319b5SDimitry Andric INITIALIZE_PASS(WebAssemblyExplicitLocals, DEBUG_TYPE,
664ba319b5SDimitry Andric                 "Convert registers to WebAssembly locals", false, false)
674ba319b5SDimitry Andric 
createWebAssemblyExplicitLocals()68d88c1a5aSDimitry Andric FunctionPass *llvm::createWebAssemblyExplicitLocals() {
69d88c1a5aSDimitry Andric   return new WebAssemblyExplicitLocals();
70d88c1a5aSDimitry Andric }
71d88c1a5aSDimitry Andric 
72d88c1a5aSDimitry Andric /// Return a local id number for the given register, assigning it a new one
73d88c1a5aSDimitry Andric /// if it doesn't yet have one.
getLocalId(DenseMap<unsigned,unsigned> & Reg2Local,unsigned & CurLocal,unsigned Reg)74d88c1a5aSDimitry Andric static unsigned getLocalId(DenseMap<unsigned, unsigned> &Reg2Local,
75d88c1a5aSDimitry Andric                            unsigned &CurLocal, unsigned Reg) {
767a7e6055SDimitry Andric   auto P = Reg2Local.insert(std::make_pair(Reg, CurLocal));
777a7e6055SDimitry Andric   if (P.second)
787a7e6055SDimitry Andric     ++CurLocal;
797a7e6055SDimitry Andric   return P.first->second;
807a7e6055SDimitry Andric }
817a7e6055SDimitry Andric 
827a7e6055SDimitry Andric /// Get the appropriate drop opcode for the given register class.
getDropOpcode(const TargetRegisterClass * RC)837a7e6055SDimitry Andric static unsigned getDropOpcode(const TargetRegisterClass *RC) {
847a7e6055SDimitry Andric   if (RC == &WebAssembly::I32RegClass)
857a7e6055SDimitry Andric     return WebAssembly::DROP_I32;
867a7e6055SDimitry Andric   if (RC == &WebAssembly::I64RegClass)
877a7e6055SDimitry Andric     return WebAssembly::DROP_I64;
887a7e6055SDimitry Andric   if (RC == &WebAssembly::F32RegClass)
897a7e6055SDimitry Andric     return WebAssembly::DROP_F32;
907a7e6055SDimitry Andric   if (RC == &WebAssembly::F64RegClass)
917a7e6055SDimitry Andric     return WebAssembly::DROP_F64;
927a7e6055SDimitry Andric   if (RC == &WebAssembly::V128RegClass)
937a7e6055SDimitry Andric     return WebAssembly::DROP_V128;
944ba319b5SDimitry Andric   if (RC == &WebAssembly::EXCEPT_REFRegClass)
954ba319b5SDimitry Andric     return WebAssembly::DROP_EXCEPT_REF;
967a7e6055SDimitry Andric   llvm_unreachable("Unexpected register class");
97d88c1a5aSDimitry Andric }
98d88c1a5aSDimitry Andric 
99*b5893f02SDimitry Andric /// Get the appropriate local.get opcode for the given register class.
getGetLocalOpcode(const TargetRegisterClass * RC)100d88c1a5aSDimitry Andric static unsigned getGetLocalOpcode(const TargetRegisterClass *RC) {
101d88c1a5aSDimitry Andric   if (RC == &WebAssembly::I32RegClass)
102*b5893f02SDimitry Andric     return WebAssembly::LOCAL_GET_I32;
103d88c1a5aSDimitry Andric   if (RC == &WebAssembly::I64RegClass)
104*b5893f02SDimitry Andric     return WebAssembly::LOCAL_GET_I64;
105d88c1a5aSDimitry Andric   if (RC == &WebAssembly::F32RegClass)
106*b5893f02SDimitry Andric     return WebAssembly::LOCAL_GET_F32;
107d88c1a5aSDimitry Andric   if (RC == &WebAssembly::F64RegClass)
108*b5893f02SDimitry Andric     return WebAssembly::LOCAL_GET_F64;
109d88c1a5aSDimitry Andric   if (RC == &WebAssembly::V128RegClass)
110*b5893f02SDimitry Andric     return WebAssembly::LOCAL_GET_V128;
1114ba319b5SDimitry Andric   if (RC == &WebAssembly::EXCEPT_REFRegClass)
112*b5893f02SDimitry Andric     return WebAssembly::LOCAL_GET_EXCEPT_REF;
113d88c1a5aSDimitry Andric   llvm_unreachable("Unexpected register class");
114d88c1a5aSDimitry Andric }
115d88c1a5aSDimitry Andric 
116*b5893f02SDimitry Andric /// Get the appropriate local.set opcode for the given register class.
getSetLocalOpcode(const TargetRegisterClass * RC)117d88c1a5aSDimitry Andric static unsigned getSetLocalOpcode(const TargetRegisterClass *RC) {
118d88c1a5aSDimitry Andric   if (RC == &WebAssembly::I32RegClass)
119*b5893f02SDimitry Andric     return WebAssembly::LOCAL_SET_I32;
120d88c1a5aSDimitry Andric   if (RC == &WebAssembly::I64RegClass)
121*b5893f02SDimitry Andric     return WebAssembly::LOCAL_SET_I64;
122d88c1a5aSDimitry Andric   if (RC == &WebAssembly::F32RegClass)
123*b5893f02SDimitry Andric     return WebAssembly::LOCAL_SET_F32;
124d88c1a5aSDimitry Andric   if (RC == &WebAssembly::F64RegClass)
125*b5893f02SDimitry Andric     return WebAssembly::LOCAL_SET_F64;
126d88c1a5aSDimitry Andric   if (RC == &WebAssembly::V128RegClass)
127*b5893f02SDimitry Andric     return WebAssembly::LOCAL_SET_V128;
1284ba319b5SDimitry Andric   if (RC == &WebAssembly::EXCEPT_REFRegClass)
129*b5893f02SDimitry Andric     return WebAssembly::LOCAL_SET_EXCEPT_REF;
130d88c1a5aSDimitry Andric   llvm_unreachable("Unexpected register class");
131d88c1a5aSDimitry Andric }
132d88c1a5aSDimitry Andric 
133*b5893f02SDimitry Andric /// Get the appropriate local.tee opcode for the given register class.
getTeeLocalOpcode(const TargetRegisterClass * RC)134d88c1a5aSDimitry Andric static unsigned getTeeLocalOpcode(const TargetRegisterClass *RC) {
135d88c1a5aSDimitry Andric   if (RC == &WebAssembly::I32RegClass)
136*b5893f02SDimitry Andric     return WebAssembly::LOCAL_TEE_I32;
137d88c1a5aSDimitry Andric   if (RC == &WebAssembly::I64RegClass)
138*b5893f02SDimitry Andric     return WebAssembly::LOCAL_TEE_I64;
139d88c1a5aSDimitry Andric   if (RC == &WebAssembly::F32RegClass)
140*b5893f02SDimitry Andric     return WebAssembly::LOCAL_TEE_F32;
141d88c1a5aSDimitry Andric   if (RC == &WebAssembly::F64RegClass)
142*b5893f02SDimitry Andric     return WebAssembly::LOCAL_TEE_F64;
143d88c1a5aSDimitry Andric   if (RC == &WebAssembly::V128RegClass)
144*b5893f02SDimitry Andric     return WebAssembly::LOCAL_TEE_V128;
1454ba319b5SDimitry Andric   if (RC == &WebAssembly::EXCEPT_REFRegClass)
146*b5893f02SDimitry Andric     return WebAssembly::LOCAL_TEE_EXCEPT_REF;
147d88c1a5aSDimitry Andric   llvm_unreachable("Unexpected register class");
148d88c1a5aSDimitry Andric }
149d88c1a5aSDimitry Andric 
150d88c1a5aSDimitry Andric /// Get the type associated with the given register class.
typeForRegClass(const TargetRegisterClass * RC)151d88c1a5aSDimitry Andric static MVT typeForRegClass(const TargetRegisterClass *RC) {
152d88c1a5aSDimitry Andric   if (RC == &WebAssembly::I32RegClass)
153d88c1a5aSDimitry Andric     return MVT::i32;
154d88c1a5aSDimitry Andric   if (RC == &WebAssembly::I64RegClass)
155d88c1a5aSDimitry Andric     return MVT::i64;
156d88c1a5aSDimitry Andric   if (RC == &WebAssembly::F32RegClass)
157d88c1a5aSDimitry Andric     return MVT::f32;
158d88c1a5aSDimitry Andric   if (RC == &WebAssembly::F64RegClass)
159d88c1a5aSDimitry Andric     return MVT::f64;
160*b5893f02SDimitry Andric   if (RC == &WebAssembly::V128RegClass)
161*b5893f02SDimitry Andric     return MVT::v16i8;
1624ba319b5SDimitry Andric   if (RC == &WebAssembly::EXCEPT_REFRegClass)
1634ba319b5SDimitry Andric     return MVT::ExceptRef;
164d88c1a5aSDimitry Andric   llvm_unreachable("unrecognized register class");
165d88c1a5aSDimitry Andric }
166d88c1a5aSDimitry Andric 
167d88c1a5aSDimitry Andric /// Given a MachineOperand of a stackified vreg, return the instruction at the
168d88c1a5aSDimitry Andric /// start of the expression tree.
findStartOfTree(MachineOperand & MO,MachineRegisterInfo & MRI,WebAssemblyFunctionInfo & MFI)169*b5893f02SDimitry Andric static MachineInstr *findStartOfTree(MachineOperand &MO,
170d88c1a5aSDimitry Andric                                      MachineRegisterInfo &MRI,
171d88c1a5aSDimitry Andric                                      WebAssemblyFunctionInfo &MFI) {
172d88c1a5aSDimitry Andric   unsigned Reg = MO.getReg();
173d88c1a5aSDimitry Andric   assert(MFI.isVRegStackified(Reg));
174d88c1a5aSDimitry Andric   MachineInstr *Def = MRI.getVRegDef(Reg);
175d88c1a5aSDimitry Andric 
176d88c1a5aSDimitry Andric   // Find the first stackified use and proceed from there.
177d88c1a5aSDimitry Andric   for (MachineOperand &DefMO : Def->explicit_uses()) {
178d88c1a5aSDimitry Andric     if (!DefMO.isReg())
179d88c1a5aSDimitry Andric       continue;
180*b5893f02SDimitry Andric     return findStartOfTree(DefMO, MRI, MFI);
181d88c1a5aSDimitry Andric   }
182d88c1a5aSDimitry Andric 
183d88c1a5aSDimitry Andric   // If there were no stackified uses, we've reached the start.
184d88c1a5aSDimitry Andric   return Def;
185d88c1a5aSDimitry Andric }
186d88c1a5aSDimitry Andric 
runOnMachineFunction(MachineFunction & MF)187d88c1a5aSDimitry Andric bool WebAssemblyExplicitLocals::runOnMachineFunction(MachineFunction &MF) {
1884ba319b5SDimitry Andric   LLVM_DEBUG(dbgs() << "********** Make Locals Explicit **********\n"
189d88c1a5aSDimitry Andric                        "********** Function: "
190d88c1a5aSDimitry Andric                     << MF.getName() << '\n');
191d88c1a5aSDimitry Andric 
1927a7e6055SDimitry Andric   // Disable this pass if directed to do so.
193*b5893f02SDimitry Andric   if (WasmDisableExplicitLocals)
1947a7e6055SDimitry Andric     return false;
1957a7e6055SDimitry Andric 
196d88c1a5aSDimitry Andric   bool Changed = false;
197d88c1a5aSDimitry Andric   MachineRegisterInfo &MRI = MF.getRegInfo();
198d88c1a5aSDimitry Andric   WebAssemblyFunctionInfo &MFI = *MF.getInfo<WebAssemblyFunctionInfo>();
199d88c1a5aSDimitry Andric   const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
200d88c1a5aSDimitry Andric 
201d88c1a5aSDimitry Andric   // Map non-stackified virtual registers to their local ids.
202d88c1a5aSDimitry Andric   DenseMap<unsigned, unsigned> Reg2Local;
203d88c1a5aSDimitry Andric 
204d88c1a5aSDimitry Andric   // Handle ARGUMENTS first to ensure that they get the designated numbers.
205d88c1a5aSDimitry Andric   for (MachineBasicBlock::iterator I = MF.begin()->begin(),
206d88c1a5aSDimitry Andric                                    E = MF.begin()->end();
207d88c1a5aSDimitry Andric        I != E;) {
208d88c1a5aSDimitry Andric     MachineInstr &MI = *I++;
209d88c1a5aSDimitry Andric     if (!WebAssembly::isArgument(MI))
210d88c1a5aSDimitry Andric       break;
211d88c1a5aSDimitry Andric     unsigned Reg = MI.getOperand(0).getReg();
212d88c1a5aSDimitry Andric     assert(!MFI.isVRegStackified(Reg));
213*b5893f02SDimitry Andric     Reg2Local[Reg] = static_cast<unsigned>(MI.getOperand(1).getImm());
214d88c1a5aSDimitry Andric     MI.eraseFromParent();
215d88c1a5aSDimitry Andric     Changed = true;
216d88c1a5aSDimitry Andric   }
217d88c1a5aSDimitry Andric 
218d88c1a5aSDimitry Andric   // Start assigning local numbers after the last parameter.
219*b5893f02SDimitry Andric   unsigned CurLocal = static_cast<unsigned>(MFI.getParams().size());
220d88c1a5aSDimitry Andric 
2217a7e6055SDimitry Andric   // Precompute the set of registers that are unused, so that we can insert
2227a7e6055SDimitry Andric   // drops to their defs.
2237a7e6055SDimitry Andric   BitVector UseEmpty(MRI.getNumVirtRegs());
224*b5893f02SDimitry Andric   for (unsigned I = 0, E = MRI.getNumVirtRegs(); I < E; ++I)
225*b5893f02SDimitry Andric     UseEmpty[I] = MRI.use_empty(TargetRegisterInfo::index2VirtReg(I));
2267a7e6055SDimitry Andric 
227d88c1a5aSDimitry Andric   // Visit each instruction in the function.
228d88c1a5aSDimitry Andric   for (MachineBasicBlock &MBB : MF) {
229d88c1a5aSDimitry Andric     for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end(); I != E;) {
230d88c1a5aSDimitry Andric       MachineInstr &MI = *I++;
231d88c1a5aSDimitry Andric       assert(!WebAssembly::isArgument(MI));
232d88c1a5aSDimitry Andric 
2334ba319b5SDimitry Andric       if (MI.isDebugInstr() || MI.isLabel())
234d88c1a5aSDimitry Andric         continue;
235d88c1a5aSDimitry Andric 
236*b5893f02SDimitry Andric       // Replace tee instructions with local.tee. The difference is that tee
237*b5893f02SDimitry Andric       // instructions have two defs, while local.tee instructions have one def
238d88c1a5aSDimitry Andric       // and an index of a local to write to.
239d88c1a5aSDimitry Andric       if (WebAssembly::isTee(MI)) {
240d88c1a5aSDimitry Andric         assert(MFI.isVRegStackified(MI.getOperand(0).getReg()));
241d88c1a5aSDimitry Andric         assert(!MFI.isVRegStackified(MI.getOperand(1).getReg()));
242d88c1a5aSDimitry Andric         unsigned OldReg = MI.getOperand(2).getReg();
243d88c1a5aSDimitry Andric         const TargetRegisterClass *RC = MRI.getRegClass(OldReg);
244d88c1a5aSDimitry Andric 
245d88c1a5aSDimitry Andric         // Stackify the input if it isn't stackified yet.
246d88c1a5aSDimitry Andric         if (!MFI.isVRegStackified(OldReg)) {
247d88c1a5aSDimitry Andric           unsigned LocalId = getLocalId(Reg2Local, CurLocal, OldReg);
248d88c1a5aSDimitry Andric           unsigned NewReg = MRI.createVirtualRegister(RC);
249d88c1a5aSDimitry Andric           unsigned Opc = getGetLocalOpcode(RC);
250d88c1a5aSDimitry Andric           BuildMI(MBB, &MI, MI.getDebugLoc(), TII->get(Opc), NewReg)
251d88c1a5aSDimitry Andric               .addImm(LocalId);
252d88c1a5aSDimitry Andric           MI.getOperand(2).setReg(NewReg);
253d88c1a5aSDimitry Andric           MFI.stackifyVReg(NewReg);
254d88c1a5aSDimitry Andric         }
255d88c1a5aSDimitry Andric 
256*b5893f02SDimitry Andric         // Replace the TEE with a LOCAL_TEE.
257d88c1a5aSDimitry Andric         unsigned LocalId =
258d88c1a5aSDimitry Andric             getLocalId(Reg2Local, CurLocal, MI.getOperand(1).getReg());
259d88c1a5aSDimitry Andric         unsigned Opc = getTeeLocalOpcode(RC);
260d88c1a5aSDimitry Andric         BuildMI(MBB, &MI, MI.getDebugLoc(), TII->get(Opc),
261d88c1a5aSDimitry Andric                 MI.getOperand(0).getReg())
262d88c1a5aSDimitry Andric             .addImm(LocalId)
263d88c1a5aSDimitry Andric             .addReg(MI.getOperand(2).getReg());
264d88c1a5aSDimitry Andric 
265d88c1a5aSDimitry Andric         MI.eraseFromParent();
266d88c1a5aSDimitry Andric         Changed = true;
267d88c1a5aSDimitry Andric         continue;
268d88c1a5aSDimitry Andric       }
269d88c1a5aSDimitry Andric 
270*b5893f02SDimitry Andric       // Insert local.sets for any defs that aren't stackified yet. Currently
271d88c1a5aSDimitry Andric       // we handle at most one def.
272d88c1a5aSDimitry Andric       assert(MI.getDesc().getNumDefs() <= 1);
273d88c1a5aSDimitry Andric       if (MI.getDesc().getNumDefs() == 1) {
274d88c1a5aSDimitry Andric         unsigned OldReg = MI.getOperand(0).getReg();
2757a7e6055SDimitry Andric         if (!MFI.isVRegStackified(OldReg)) {
276d88c1a5aSDimitry Andric           const TargetRegisterClass *RC = MRI.getRegClass(OldReg);
277d88c1a5aSDimitry Andric           unsigned NewReg = MRI.createVirtualRegister(RC);
278d88c1a5aSDimitry Andric           auto InsertPt = std::next(MachineBasicBlock::iterator(&MI));
2797a7e6055SDimitry Andric           if (MI.getOpcode() == WebAssembly::IMPLICIT_DEF) {
2807a7e6055SDimitry Andric             MI.eraseFromParent();
2817a7e6055SDimitry Andric             Changed = true;
2827a7e6055SDimitry Andric             continue;
2837a7e6055SDimitry Andric           }
2847a7e6055SDimitry Andric           if (UseEmpty[TargetRegisterInfo::virtReg2Index(OldReg)]) {
2857a7e6055SDimitry Andric             unsigned Opc = getDropOpcode(RC);
2864ba319b5SDimitry Andric             MachineInstr *Drop =
2877a7e6055SDimitry Andric                 BuildMI(MBB, InsertPt, MI.getDebugLoc(), TII->get(Opc))
2887a7e6055SDimitry Andric                     .addReg(NewReg);
2894ba319b5SDimitry Andric             // After the drop instruction, this reg operand will not be used
2904ba319b5SDimitry Andric             Drop->getOperand(0).setIsKill();
2917a7e6055SDimitry Andric           } else {
2927a7e6055SDimitry Andric             unsigned LocalId = getLocalId(Reg2Local, CurLocal, OldReg);
293d88c1a5aSDimitry Andric             unsigned Opc = getSetLocalOpcode(RC);
294d88c1a5aSDimitry Andric             BuildMI(MBB, InsertPt, MI.getDebugLoc(), TII->get(Opc))
295d88c1a5aSDimitry Andric                 .addImm(LocalId)
296d88c1a5aSDimitry Andric                 .addReg(NewReg);
2977a7e6055SDimitry Andric           }
298d88c1a5aSDimitry Andric           MI.getOperand(0).setReg(NewReg);
299*b5893f02SDimitry Andric           // This register operand of the original instruction is now being used
300*b5893f02SDimitry Andric           // by the inserted drop or local.set instruction, so make it not dead
301*b5893f02SDimitry Andric           // yet.
3024ba319b5SDimitry Andric           MI.getOperand(0).setIsDead(false);
303d88c1a5aSDimitry Andric           MFI.stackifyVReg(NewReg);
304d88c1a5aSDimitry Andric           Changed = true;
305d88c1a5aSDimitry Andric         }
306d88c1a5aSDimitry Andric       }
307d88c1a5aSDimitry Andric 
308*b5893f02SDimitry Andric       // Insert local.gets for any uses that aren't stackified yet.
309d88c1a5aSDimitry Andric       MachineInstr *InsertPt = &MI;
310d88c1a5aSDimitry Andric       for (MachineOperand &MO : reverse(MI.explicit_uses())) {
311d88c1a5aSDimitry Andric         if (!MO.isReg())
312d88c1a5aSDimitry Andric           continue;
313d88c1a5aSDimitry Andric 
314d88c1a5aSDimitry Andric         unsigned OldReg = MO.getReg();
315d88c1a5aSDimitry Andric 
3162cab237bSDimitry Andric         // Inline asm may have a def in the middle of the operands. Our contract
3172cab237bSDimitry Andric         // with inline asm register operands is to provide local indices as
3182cab237bSDimitry Andric         // immediates.
3192cab237bSDimitry Andric         if (MO.isDef()) {
3202cab237bSDimitry Andric           assert(MI.getOpcode() == TargetOpcode::INLINEASM);
3212cab237bSDimitry Andric           unsigned LocalId = getLocalId(Reg2Local, CurLocal, OldReg);
322*b5893f02SDimitry Andric           // If this register operand is tied to another operand, we can't
323*b5893f02SDimitry Andric           // change it to an immediate. Untie it first.
324*b5893f02SDimitry Andric           MI.untieRegOperand(MI.getOperandNo(&MO));
325*b5893f02SDimitry Andric           MO.ChangeToImmediate(LocalId);
3262cab237bSDimitry Andric           continue;
3272cab237bSDimitry Andric         }
3282cab237bSDimitry Andric 
329d88c1a5aSDimitry Andric         // If we see a stackified register, prepare to insert subsequent
330*b5893f02SDimitry Andric         // local.gets before the start of its tree.
331d88c1a5aSDimitry Andric         if (MFI.isVRegStackified(OldReg)) {
332*b5893f02SDimitry Andric           InsertPt = findStartOfTree(MO, MRI, MFI);
333d88c1a5aSDimitry Andric           continue;
334d88c1a5aSDimitry Andric         }
335d88c1a5aSDimitry Andric 
3362cab237bSDimitry Andric         // Our contract with inline asm register operands is to provide local
3372cab237bSDimitry Andric         // indices as immediates.
3382cab237bSDimitry Andric         if (MI.getOpcode() == TargetOpcode::INLINEASM) {
3392cab237bSDimitry Andric           unsigned LocalId = getLocalId(Reg2Local, CurLocal, OldReg);
340*b5893f02SDimitry Andric           // Untie it first if this reg operand is tied to another operand.
341*b5893f02SDimitry Andric           MI.untieRegOperand(MI.getOperandNo(&MO));
342*b5893f02SDimitry Andric           MO.ChangeToImmediate(LocalId);
3432cab237bSDimitry Andric           continue;
3442cab237bSDimitry Andric         }
3452cab237bSDimitry Andric 
346*b5893f02SDimitry Andric         // Insert a local.get.
347d88c1a5aSDimitry Andric         unsigned LocalId = getLocalId(Reg2Local, CurLocal, OldReg);
348d88c1a5aSDimitry Andric         const TargetRegisterClass *RC = MRI.getRegClass(OldReg);
349d88c1a5aSDimitry Andric         unsigned NewReg = MRI.createVirtualRegister(RC);
350d88c1a5aSDimitry Andric         unsigned Opc = getGetLocalOpcode(RC);
351d88c1a5aSDimitry Andric         InsertPt =
352d88c1a5aSDimitry Andric             BuildMI(MBB, InsertPt, MI.getDebugLoc(), TII->get(Opc), NewReg)
353d88c1a5aSDimitry Andric                 .addImm(LocalId);
354d88c1a5aSDimitry Andric         MO.setReg(NewReg);
355d88c1a5aSDimitry Andric         MFI.stackifyVReg(NewReg);
356d88c1a5aSDimitry Andric         Changed = true;
357d88c1a5aSDimitry Andric       }
358d88c1a5aSDimitry Andric 
359d88c1a5aSDimitry Andric       // Coalesce and eliminate COPY instructions.
360d88c1a5aSDimitry Andric       if (WebAssembly::isCopy(MI)) {
361d88c1a5aSDimitry Andric         MRI.replaceRegWith(MI.getOperand(1).getReg(),
362d88c1a5aSDimitry Andric                            MI.getOperand(0).getReg());
363d88c1a5aSDimitry Andric         MI.eraseFromParent();
364d88c1a5aSDimitry Andric         Changed = true;
365d88c1a5aSDimitry Andric       }
366d88c1a5aSDimitry Andric     }
367d88c1a5aSDimitry Andric   }
368d88c1a5aSDimitry Andric 
369d88c1a5aSDimitry Andric   // Define the locals.
3707a7e6055SDimitry Andric   // TODO: Sort the locals for better compression.
3717a7e6055SDimitry Andric   MFI.setNumLocals(CurLocal - MFI.getParams().size());
372*b5893f02SDimitry Andric   for (unsigned I = 0, E = MRI.getNumVirtRegs(); I < E; ++I) {
373*b5893f02SDimitry Andric     unsigned Reg = TargetRegisterInfo::index2VirtReg(I);
374*b5893f02SDimitry Andric     auto RL = Reg2Local.find(Reg);
375*b5893f02SDimitry Andric     if (RL == Reg2Local.end() || RL->second < MFI.getParams().size())
376d88c1a5aSDimitry Andric       continue;
377d88c1a5aSDimitry Andric 
378*b5893f02SDimitry Andric     MFI.setLocal(RL->second - MFI.getParams().size(),
3797a7e6055SDimitry Andric                  typeForRegClass(MRI.getRegClass(Reg)));
380d88c1a5aSDimitry Andric     Changed = true;
381d88c1a5aSDimitry Andric   }
382d88c1a5aSDimitry Andric 
383d88c1a5aSDimitry Andric #ifndef NDEBUG
384d88c1a5aSDimitry Andric   // Assert that all registers have been stackified at this point.
385d88c1a5aSDimitry Andric   for (const MachineBasicBlock &MBB : MF) {
386d88c1a5aSDimitry Andric     for (const MachineInstr &MI : MBB) {
3874ba319b5SDimitry Andric       if (MI.isDebugInstr() || MI.isLabel())
388d88c1a5aSDimitry Andric         continue;
389d88c1a5aSDimitry Andric       for (const MachineOperand &MO : MI.explicit_operands()) {
390d88c1a5aSDimitry Andric         assert(
391d88c1a5aSDimitry Andric             (!MO.isReg() || MRI.use_empty(MO.getReg()) ||
392d88c1a5aSDimitry Andric              MFI.isVRegStackified(MO.getReg())) &&
393d88c1a5aSDimitry Andric             "WebAssemblyExplicitLocals failed to stackify a register operand");
394d88c1a5aSDimitry Andric       }
395d88c1a5aSDimitry Andric     }
396d88c1a5aSDimitry Andric   }
397d88c1a5aSDimitry Andric #endif
398d88c1a5aSDimitry Andric 
399d88c1a5aSDimitry Andric   return Changed;
400d88c1a5aSDimitry Andric }
401