xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===-- WebAssemblyExplicitLocals.cpp - Make Locals Explicit --------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric ///
90b57cec5SDimitry Andric /// \file
100b57cec5SDimitry Andric /// This file converts any remaining registers into WebAssembly locals.
110b57cec5SDimitry Andric ///
120b57cec5SDimitry Andric /// After register stackification and register coloring, convert non-stackified
130b57cec5SDimitry Andric /// registers into locals, inserting explicit local.get and local.set
140b57cec5SDimitry Andric /// instructions.
150b57cec5SDimitry Andric ///
160b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
170b57cec5SDimitry Andric 
180b57cec5SDimitry Andric #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
190b57cec5SDimitry Andric #include "WebAssembly.h"
20480093f4SDimitry Andric #include "WebAssemblyDebugValueManager.h"
210b57cec5SDimitry Andric #include "WebAssemblyMachineFunctionInfo.h"
220b57cec5SDimitry Andric #include "WebAssemblySubtarget.h"
235f757f3fSDimitry Andric #include "WebAssemblyUtilities.h"
240b57cec5SDimitry Andric #include "llvm/CodeGen/MachineBlockFrequencyInfo.h"
250b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h"
260b57cec5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h"
270b57cec5SDimitry Andric #include "llvm/CodeGen/Passes.h"
280b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
290b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
300b57cec5SDimitry Andric using namespace llvm;
310b57cec5SDimitry Andric 
320b57cec5SDimitry Andric #define DEBUG_TYPE "wasm-explicit-locals"
330b57cec5SDimitry Andric 
340b57cec5SDimitry Andric namespace {
350b57cec5SDimitry Andric class WebAssemblyExplicitLocals final : public MachineFunctionPass {
360b57cec5SDimitry Andric   StringRef getPassName() const override {
370b57cec5SDimitry Andric     return "WebAssembly Explicit Locals";
380b57cec5SDimitry Andric   }
390b57cec5SDimitry Andric 
400b57cec5SDimitry Andric   void getAnalysisUsage(AnalysisUsage &AU) const override {
410b57cec5SDimitry Andric     AU.setPreservesCFG();
42*0fca6ea1SDimitry Andric     AU.addPreserved<MachineBlockFrequencyInfoWrapperPass>();
430b57cec5SDimitry Andric     MachineFunctionPass::getAnalysisUsage(AU);
440b57cec5SDimitry Andric   }
450b57cec5SDimitry Andric 
460b57cec5SDimitry Andric   bool runOnMachineFunction(MachineFunction &MF) override;
470b57cec5SDimitry Andric 
480b57cec5SDimitry Andric public:
490b57cec5SDimitry Andric   static char ID; // Pass identification, replacement for typeid
500b57cec5SDimitry Andric   WebAssemblyExplicitLocals() : MachineFunctionPass(ID) {}
510b57cec5SDimitry Andric };
520b57cec5SDimitry Andric } // end anonymous namespace
530b57cec5SDimitry Andric 
540b57cec5SDimitry Andric char WebAssemblyExplicitLocals::ID = 0;
550b57cec5SDimitry Andric INITIALIZE_PASS(WebAssemblyExplicitLocals, DEBUG_TYPE,
560b57cec5SDimitry Andric                 "Convert registers to WebAssembly locals", false, false)
570b57cec5SDimitry Andric 
580b57cec5SDimitry Andric FunctionPass *llvm::createWebAssemblyExplicitLocals() {
590b57cec5SDimitry Andric   return new WebAssemblyExplicitLocals();
600b57cec5SDimitry Andric }
610b57cec5SDimitry Andric 
625ffd83dbSDimitry Andric static void checkFrameBase(WebAssemblyFunctionInfo &MFI, unsigned Local,
635ffd83dbSDimitry Andric                            unsigned Reg) {
645ffd83dbSDimitry Andric   // Mark a local for the frame base vreg.
655ffd83dbSDimitry Andric   if (MFI.isFrameBaseVirtual() && Reg == MFI.getFrameBaseVreg()) {
665ffd83dbSDimitry Andric     LLVM_DEBUG({
675ffd83dbSDimitry Andric       dbgs() << "Allocating local " << Local << "for VReg "
685ffd83dbSDimitry Andric              << Register::virtReg2Index(Reg) << '\n';
695ffd83dbSDimitry Andric     });
705ffd83dbSDimitry Andric     MFI.setFrameBaseLocal(Local);
715ffd83dbSDimitry Andric   }
725ffd83dbSDimitry Andric }
735ffd83dbSDimitry Andric 
740b57cec5SDimitry Andric /// Return a local id number for the given register, assigning it a new one
750b57cec5SDimitry Andric /// if it doesn't yet have one.
760b57cec5SDimitry Andric static unsigned getLocalId(DenseMap<unsigned, unsigned> &Reg2Local,
775ffd83dbSDimitry Andric                            WebAssemblyFunctionInfo &MFI, unsigned &CurLocal,
785ffd83dbSDimitry Andric                            unsigned Reg) {
790b57cec5SDimitry Andric   auto P = Reg2Local.insert(std::make_pair(Reg, CurLocal));
805ffd83dbSDimitry Andric   if (P.second) {
815ffd83dbSDimitry Andric     checkFrameBase(MFI, CurLocal, Reg);
820b57cec5SDimitry Andric     ++CurLocal;
835ffd83dbSDimitry Andric   }
840b57cec5SDimitry Andric   return P.first->second;
850b57cec5SDimitry Andric }
860b57cec5SDimitry Andric 
870b57cec5SDimitry Andric /// Get the appropriate drop opcode for the given register class.
880b57cec5SDimitry Andric static unsigned getDropOpcode(const TargetRegisterClass *RC) {
890b57cec5SDimitry Andric   if (RC == &WebAssembly::I32RegClass)
900b57cec5SDimitry Andric     return WebAssembly::DROP_I32;
910b57cec5SDimitry Andric   if (RC == &WebAssembly::I64RegClass)
920b57cec5SDimitry Andric     return WebAssembly::DROP_I64;
930b57cec5SDimitry Andric   if (RC == &WebAssembly::F32RegClass)
940b57cec5SDimitry Andric     return WebAssembly::DROP_F32;
950b57cec5SDimitry Andric   if (RC == &WebAssembly::F64RegClass)
960b57cec5SDimitry Andric     return WebAssembly::DROP_F64;
970b57cec5SDimitry Andric   if (RC == &WebAssembly::V128RegClass)
980b57cec5SDimitry Andric     return WebAssembly::DROP_V128;
99e8d8bef9SDimitry Andric   if (RC == &WebAssembly::FUNCREFRegClass)
100e8d8bef9SDimitry Andric     return WebAssembly::DROP_FUNCREF;
101e8d8bef9SDimitry Andric   if (RC == &WebAssembly::EXTERNREFRegClass)
102e8d8bef9SDimitry Andric     return WebAssembly::DROP_EXTERNREF;
103*0fca6ea1SDimitry Andric   if (RC == &WebAssembly::EXNREFRegClass)
104*0fca6ea1SDimitry Andric     return WebAssembly::DROP_EXNREF;
1050b57cec5SDimitry Andric   llvm_unreachable("Unexpected register class");
1060b57cec5SDimitry Andric }
1070b57cec5SDimitry Andric 
1080b57cec5SDimitry Andric /// Get the appropriate local.get opcode for the given register class.
1090b57cec5SDimitry Andric static unsigned getLocalGetOpcode(const TargetRegisterClass *RC) {
1100b57cec5SDimitry Andric   if (RC == &WebAssembly::I32RegClass)
1110b57cec5SDimitry Andric     return WebAssembly::LOCAL_GET_I32;
1120b57cec5SDimitry Andric   if (RC == &WebAssembly::I64RegClass)
1130b57cec5SDimitry Andric     return WebAssembly::LOCAL_GET_I64;
1140b57cec5SDimitry Andric   if (RC == &WebAssembly::F32RegClass)
1150b57cec5SDimitry Andric     return WebAssembly::LOCAL_GET_F32;
1160b57cec5SDimitry Andric   if (RC == &WebAssembly::F64RegClass)
1170b57cec5SDimitry Andric     return WebAssembly::LOCAL_GET_F64;
1180b57cec5SDimitry Andric   if (RC == &WebAssembly::V128RegClass)
1190b57cec5SDimitry Andric     return WebAssembly::LOCAL_GET_V128;
120e8d8bef9SDimitry Andric   if (RC == &WebAssembly::FUNCREFRegClass)
121e8d8bef9SDimitry Andric     return WebAssembly::LOCAL_GET_FUNCREF;
122e8d8bef9SDimitry Andric   if (RC == &WebAssembly::EXTERNREFRegClass)
123e8d8bef9SDimitry Andric     return WebAssembly::LOCAL_GET_EXTERNREF;
124*0fca6ea1SDimitry Andric   if (RC == &WebAssembly::EXNREFRegClass)
125*0fca6ea1SDimitry Andric     return WebAssembly::LOCAL_GET_EXNREF;
1260b57cec5SDimitry Andric   llvm_unreachable("Unexpected register class");
1270b57cec5SDimitry Andric }
1280b57cec5SDimitry Andric 
1290b57cec5SDimitry Andric /// Get the appropriate local.set opcode for the given register class.
1300b57cec5SDimitry Andric static unsigned getLocalSetOpcode(const TargetRegisterClass *RC) {
1310b57cec5SDimitry Andric   if (RC == &WebAssembly::I32RegClass)
1320b57cec5SDimitry Andric     return WebAssembly::LOCAL_SET_I32;
1330b57cec5SDimitry Andric   if (RC == &WebAssembly::I64RegClass)
1340b57cec5SDimitry Andric     return WebAssembly::LOCAL_SET_I64;
1350b57cec5SDimitry Andric   if (RC == &WebAssembly::F32RegClass)
1360b57cec5SDimitry Andric     return WebAssembly::LOCAL_SET_F32;
1370b57cec5SDimitry Andric   if (RC == &WebAssembly::F64RegClass)
1380b57cec5SDimitry Andric     return WebAssembly::LOCAL_SET_F64;
1390b57cec5SDimitry Andric   if (RC == &WebAssembly::V128RegClass)
1400b57cec5SDimitry Andric     return WebAssembly::LOCAL_SET_V128;
141e8d8bef9SDimitry Andric   if (RC == &WebAssembly::FUNCREFRegClass)
142e8d8bef9SDimitry Andric     return WebAssembly::LOCAL_SET_FUNCREF;
143e8d8bef9SDimitry Andric   if (RC == &WebAssembly::EXTERNREFRegClass)
144e8d8bef9SDimitry Andric     return WebAssembly::LOCAL_SET_EXTERNREF;
145*0fca6ea1SDimitry Andric   if (RC == &WebAssembly::EXNREFRegClass)
146*0fca6ea1SDimitry Andric     return WebAssembly::LOCAL_SET_EXNREF;
1470b57cec5SDimitry Andric   llvm_unreachable("Unexpected register class");
1480b57cec5SDimitry Andric }
1490b57cec5SDimitry Andric 
1500b57cec5SDimitry Andric /// Get the appropriate local.tee opcode for the given register class.
1510b57cec5SDimitry Andric static unsigned getLocalTeeOpcode(const TargetRegisterClass *RC) {
1520b57cec5SDimitry Andric   if (RC == &WebAssembly::I32RegClass)
1530b57cec5SDimitry Andric     return WebAssembly::LOCAL_TEE_I32;
1540b57cec5SDimitry Andric   if (RC == &WebAssembly::I64RegClass)
1550b57cec5SDimitry Andric     return WebAssembly::LOCAL_TEE_I64;
1560b57cec5SDimitry Andric   if (RC == &WebAssembly::F32RegClass)
1570b57cec5SDimitry Andric     return WebAssembly::LOCAL_TEE_F32;
1580b57cec5SDimitry Andric   if (RC == &WebAssembly::F64RegClass)
1590b57cec5SDimitry Andric     return WebAssembly::LOCAL_TEE_F64;
1600b57cec5SDimitry Andric   if (RC == &WebAssembly::V128RegClass)
1610b57cec5SDimitry Andric     return WebAssembly::LOCAL_TEE_V128;
162e8d8bef9SDimitry Andric   if (RC == &WebAssembly::FUNCREFRegClass)
163e8d8bef9SDimitry Andric     return WebAssembly::LOCAL_TEE_FUNCREF;
164e8d8bef9SDimitry Andric   if (RC == &WebAssembly::EXTERNREFRegClass)
165e8d8bef9SDimitry Andric     return WebAssembly::LOCAL_TEE_EXTERNREF;
166*0fca6ea1SDimitry Andric   if (RC == &WebAssembly::EXNREFRegClass)
167*0fca6ea1SDimitry Andric     return WebAssembly::LOCAL_TEE_EXNREF;
1680b57cec5SDimitry Andric   llvm_unreachable("Unexpected register class");
1690b57cec5SDimitry Andric }
1700b57cec5SDimitry Andric 
1710b57cec5SDimitry Andric /// Get the type associated with the given register class.
1720b57cec5SDimitry Andric static MVT typeForRegClass(const TargetRegisterClass *RC) {
1730b57cec5SDimitry Andric   if (RC == &WebAssembly::I32RegClass)
1740b57cec5SDimitry Andric     return MVT::i32;
1750b57cec5SDimitry Andric   if (RC == &WebAssembly::I64RegClass)
1760b57cec5SDimitry Andric     return MVT::i64;
1770b57cec5SDimitry Andric   if (RC == &WebAssembly::F32RegClass)
1780b57cec5SDimitry Andric     return MVT::f32;
1790b57cec5SDimitry Andric   if (RC == &WebAssembly::F64RegClass)
1800b57cec5SDimitry Andric     return MVT::f64;
1810b57cec5SDimitry Andric   if (RC == &WebAssembly::V128RegClass)
1820b57cec5SDimitry Andric     return MVT::v16i8;
183e8d8bef9SDimitry Andric   if (RC == &WebAssembly::FUNCREFRegClass)
184e8d8bef9SDimitry Andric     return MVT::funcref;
185e8d8bef9SDimitry Andric   if (RC == &WebAssembly::EXTERNREFRegClass)
186e8d8bef9SDimitry Andric     return MVT::externref;
187*0fca6ea1SDimitry Andric   if (RC == &WebAssembly::EXNREFRegClass)
188*0fca6ea1SDimitry Andric     return MVT::exnref;
1890b57cec5SDimitry Andric   llvm_unreachable("unrecognized register class");
1900b57cec5SDimitry Andric }
1910b57cec5SDimitry Andric 
1920b57cec5SDimitry Andric /// Given a MachineOperand of a stackified vreg, return the instruction at the
1930b57cec5SDimitry Andric /// start of the expression tree.
1940b57cec5SDimitry Andric static MachineInstr *findStartOfTree(MachineOperand &MO,
1950b57cec5SDimitry Andric                                      MachineRegisterInfo &MRI,
1965ffd83dbSDimitry Andric                                      const WebAssemblyFunctionInfo &MFI) {
1978bcb0991SDimitry Andric   Register Reg = MO.getReg();
1980b57cec5SDimitry Andric   assert(MFI.isVRegStackified(Reg));
1990b57cec5SDimitry Andric   MachineInstr *Def = MRI.getVRegDef(Reg);
2000b57cec5SDimitry Andric 
2015ffd83dbSDimitry Andric   // If this instruction has any non-stackified defs, it is the start
2025ffd83dbSDimitry Andric   for (auto DefReg : Def->defs()) {
2035ffd83dbSDimitry Andric     if (!MFI.isVRegStackified(DefReg.getReg())) {
2045ffd83dbSDimitry Andric       return Def;
2055ffd83dbSDimitry Andric     }
2065ffd83dbSDimitry Andric   }
2075ffd83dbSDimitry Andric 
2080b57cec5SDimitry Andric   // Find the first stackified use and proceed from there.
2090b57cec5SDimitry Andric   for (MachineOperand &DefMO : Def->explicit_uses()) {
2100b57cec5SDimitry Andric     if (!DefMO.isReg())
2110b57cec5SDimitry Andric       continue;
2120b57cec5SDimitry Andric     return findStartOfTree(DefMO, MRI, MFI);
2130b57cec5SDimitry Andric   }
2140b57cec5SDimitry Andric 
2150b57cec5SDimitry Andric   // If there were no stackified uses, we've reached the start.
2160b57cec5SDimitry Andric   return Def;
2170b57cec5SDimitry Andric }
2180b57cec5SDimitry Andric 
2190b57cec5SDimitry Andric bool WebAssemblyExplicitLocals::runOnMachineFunction(MachineFunction &MF) {
2200b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "********** Make Locals Explicit **********\n"
2210b57cec5SDimitry Andric                        "********** Function: "
2220b57cec5SDimitry Andric                     << MF.getName() << '\n');
2230b57cec5SDimitry Andric 
2240b57cec5SDimitry Andric   bool Changed = false;
2250b57cec5SDimitry Andric   MachineRegisterInfo &MRI = MF.getRegInfo();
2260b57cec5SDimitry Andric   WebAssemblyFunctionInfo &MFI = *MF.getInfo<WebAssemblyFunctionInfo>();
2270b57cec5SDimitry Andric   const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
2280b57cec5SDimitry Andric 
2290b57cec5SDimitry Andric   // Map non-stackified virtual registers to their local ids.
2300b57cec5SDimitry Andric   DenseMap<unsigned, unsigned> Reg2Local;
2310b57cec5SDimitry Andric 
2320b57cec5SDimitry Andric   // Handle ARGUMENTS first to ensure that they get the designated numbers.
2330b57cec5SDimitry Andric   for (MachineBasicBlock::iterator I = MF.begin()->begin(),
2340b57cec5SDimitry Andric                                    E = MF.begin()->end();
2350b57cec5SDimitry Andric        I != E;) {
2360b57cec5SDimitry Andric     MachineInstr &MI = *I++;
2370b57cec5SDimitry Andric     if (!WebAssembly::isArgument(MI.getOpcode()))
2380b57cec5SDimitry Andric       break;
2398bcb0991SDimitry Andric     Register Reg = MI.getOperand(0).getReg();
2400b57cec5SDimitry Andric     assert(!MFI.isVRegStackified(Reg));
2415ffd83dbSDimitry Andric     auto Local = static_cast<unsigned>(MI.getOperand(1).getImm());
2425ffd83dbSDimitry Andric     Reg2Local[Reg] = Local;
2435ffd83dbSDimitry Andric     checkFrameBase(MFI, Local, Reg);
244e8d8bef9SDimitry Andric 
245e8d8bef9SDimitry Andric     // Update debug value to point to the local before removing.
246e8d8bef9SDimitry Andric     WebAssemblyDebugValueManager(&MI).replaceWithLocal(Local);
247e8d8bef9SDimitry Andric 
2480b57cec5SDimitry Andric     MI.eraseFromParent();
2490b57cec5SDimitry Andric     Changed = true;
2500b57cec5SDimitry Andric   }
2510b57cec5SDimitry Andric 
252fe6060f1SDimitry Andric   // Start assigning local numbers after the last parameter and after any
253fe6060f1SDimitry Andric   // already-assigned locals.
2540b57cec5SDimitry Andric   unsigned CurLocal = static_cast<unsigned>(MFI.getParams().size());
255fe6060f1SDimitry Andric   CurLocal += static_cast<unsigned>(MFI.getLocals().size());
2560b57cec5SDimitry Andric 
2570b57cec5SDimitry Andric   // Precompute the set of registers that are unused, so that we can insert
2580b57cec5SDimitry Andric   // drops to their defs.
2590b57cec5SDimitry Andric   BitVector UseEmpty(MRI.getNumVirtRegs());
2600b57cec5SDimitry Andric   for (unsigned I = 0, E = MRI.getNumVirtRegs(); I < E; ++I)
2618bcb0991SDimitry Andric     UseEmpty[I] = MRI.use_empty(Register::index2VirtReg(I));
2620b57cec5SDimitry Andric 
2630b57cec5SDimitry Andric   // Visit each instruction in the function.
2640b57cec5SDimitry Andric   for (MachineBasicBlock &MBB : MF) {
265349cc55cSDimitry Andric     for (MachineInstr &MI : llvm::make_early_inc_range(MBB)) {
2660b57cec5SDimitry Andric       assert(!WebAssembly::isArgument(MI.getOpcode()));
2670b57cec5SDimitry Andric 
2680b57cec5SDimitry Andric       if (MI.isDebugInstr() || MI.isLabel())
2690b57cec5SDimitry Andric         continue;
2700b57cec5SDimitry Andric 
2715ffd83dbSDimitry Andric       if (MI.getOpcode() == WebAssembly::IMPLICIT_DEF) {
2725ffd83dbSDimitry Andric         MI.eraseFromParent();
2735ffd83dbSDimitry Andric         Changed = true;
2745ffd83dbSDimitry Andric         continue;
2755ffd83dbSDimitry Andric       }
2765ffd83dbSDimitry Andric 
2770b57cec5SDimitry Andric       // Replace tee instructions with local.tee. The difference is that tee
2780b57cec5SDimitry Andric       // instructions have two defs, while local.tee instructions have one def
2790b57cec5SDimitry Andric       // and an index of a local to write to.
28006c3fb27SDimitry Andric       //
28106c3fb27SDimitry Andric       // - Before:
28206c3fb27SDimitry Andric       // TeeReg, Reg = TEE DefReg
28306c3fb27SDimitry Andric       // INST ..., TeeReg, ...
28406c3fb27SDimitry Andric       // INST ..., Reg, ...
28506c3fb27SDimitry Andric       // INST ..., Reg, ...
28606c3fb27SDimitry Andric       // * DefReg: may or may not be stackified
28706c3fb27SDimitry Andric       // * Reg: not stackified
28806c3fb27SDimitry Andric       // * TeeReg: stackified
28906c3fb27SDimitry Andric       //
29006c3fb27SDimitry Andric       // - After (when DefReg was already stackified):
29106c3fb27SDimitry Andric       // TeeReg = LOCAL_TEE LocalId1, DefReg
29206c3fb27SDimitry Andric       // INST ..., TeeReg, ...
29306c3fb27SDimitry Andric       // INST ..., Reg, ...
29406c3fb27SDimitry Andric       // INST ..., Reg, ...
29506c3fb27SDimitry Andric       // * Reg: mapped to LocalId1
29606c3fb27SDimitry Andric       // * TeeReg: stackified
29706c3fb27SDimitry Andric       //
29806c3fb27SDimitry Andric       // - After (when DefReg was not already stackified):
29906c3fb27SDimitry Andric       // NewReg = LOCAL_GET LocalId1
30006c3fb27SDimitry Andric       // TeeReg = LOCAL_TEE LocalId2, NewReg
30106c3fb27SDimitry Andric       // INST ..., TeeReg, ...
30206c3fb27SDimitry Andric       // INST ..., Reg, ...
30306c3fb27SDimitry Andric       // INST ..., Reg, ...
30406c3fb27SDimitry Andric       // * DefReg: mapped to LocalId1
30506c3fb27SDimitry Andric       // * Reg: mapped to LocalId2
30606c3fb27SDimitry Andric       // * TeeReg: stackified
3070b57cec5SDimitry Andric       if (WebAssembly::isTee(MI.getOpcode())) {
3080b57cec5SDimitry Andric         assert(MFI.isVRegStackified(MI.getOperand(0).getReg()));
3090b57cec5SDimitry Andric         assert(!MFI.isVRegStackified(MI.getOperand(1).getReg()));
31006c3fb27SDimitry Andric         Register DefReg = MI.getOperand(2).getReg();
31106c3fb27SDimitry Andric         const TargetRegisterClass *RC = MRI.getRegClass(DefReg);
3120b57cec5SDimitry Andric 
3130b57cec5SDimitry Andric         // Stackify the input if it isn't stackified yet.
31406c3fb27SDimitry Andric         if (!MFI.isVRegStackified(DefReg)) {
31506c3fb27SDimitry Andric           unsigned LocalId = getLocalId(Reg2Local, MFI, CurLocal, DefReg);
3168bcb0991SDimitry Andric           Register NewReg = MRI.createVirtualRegister(RC);
3170b57cec5SDimitry Andric           unsigned Opc = getLocalGetOpcode(RC);
3180b57cec5SDimitry Andric           BuildMI(MBB, &MI, MI.getDebugLoc(), TII->get(Opc), NewReg)
3190b57cec5SDimitry Andric               .addImm(LocalId);
3200b57cec5SDimitry Andric           MI.getOperand(2).setReg(NewReg);
3215ffd83dbSDimitry Andric           MFI.stackifyVReg(MRI, NewReg);
3220b57cec5SDimitry Andric         }
3230b57cec5SDimitry Andric 
3240b57cec5SDimitry Andric         // Replace the TEE with a LOCAL_TEE.
3250b57cec5SDimitry Andric         unsigned LocalId =
3265ffd83dbSDimitry Andric             getLocalId(Reg2Local, MFI, CurLocal, MI.getOperand(1).getReg());
3270b57cec5SDimitry Andric         unsigned Opc = getLocalTeeOpcode(RC);
3280b57cec5SDimitry Andric         BuildMI(MBB, &MI, MI.getDebugLoc(), TII->get(Opc),
3290b57cec5SDimitry Andric                 MI.getOperand(0).getReg())
3300b57cec5SDimitry Andric             .addImm(LocalId)
3310b57cec5SDimitry Andric             .addReg(MI.getOperand(2).getReg());
3320b57cec5SDimitry Andric 
333480093f4SDimitry Andric         WebAssemblyDebugValueManager(&MI).replaceWithLocal(LocalId);
334480093f4SDimitry Andric 
3350b57cec5SDimitry Andric         MI.eraseFromParent();
3360b57cec5SDimitry Andric         Changed = true;
3370b57cec5SDimitry Andric         continue;
3380b57cec5SDimitry Andric       }
3390b57cec5SDimitry Andric 
3405ffd83dbSDimitry Andric       // Insert local.sets for any defs that aren't stackified yet.
3415ffd83dbSDimitry Andric       for (auto &Def : MI.defs()) {
3425ffd83dbSDimitry Andric         Register OldReg = Def.getReg();
3430b57cec5SDimitry Andric         if (!MFI.isVRegStackified(OldReg)) {
3440b57cec5SDimitry Andric           const TargetRegisterClass *RC = MRI.getRegClass(OldReg);
3458bcb0991SDimitry Andric           Register NewReg = MRI.createVirtualRegister(RC);
3460b57cec5SDimitry Andric           auto InsertPt = std::next(MI.getIterator());
3478bcb0991SDimitry Andric           if (UseEmpty[Register::virtReg2Index(OldReg)]) {
3480b57cec5SDimitry Andric             unsigned Opc = getDropOpcode(RC);
3490b57cec5SDimitry Andric             MachineInstr *Drop =
3500b57cec5SDimitry Andric                 BuildMI(MBB, InsertPt, MI.getDebugLoc(), TII->get(Opc))
3510b57cec5SDimitry Andric                     .addReg(NewReg);
3520b57cec5SDimitry Andric             // After the drop instruction, this reg operand will not be used
3530b57cec5SDimitry Andric             Drop->getOperand(0).setIsKill();
3545ffd83dbSDimitry Andric             if (MFI.isFrameBaseVirtual() && OldReg == MFI.getFrameBaseVreg())
3555ffd83dbSDimitry Andric               MFI.clearFrameBaseVreg();
3560b57cec5SDimitry Andric           } else {
3575ffd83dbSDimitry Andric             unsigned LocalId = getLocalId(Reg2Local, MFI, CurLocal, OldReg);
3580b57cec5SDimitry Andric             unsigned Opc = getLocalSetOpcode(RC);
359480093f4SDimitry Andric 
360480093f4SDimitry Andric             WebAssemblyDebugValueManager(&MI).replaceWithLocal(LocalId);
361480093f4SDimitry Andric 
3620b57cec5SDimitry Andric             BuildMI(MBB, InsertPt, MI.getDebugLoc(), TII->get(Opc))
3630b57cec5SDimitry Andric                 .addImm(LocalId)
3640b57cec5SDimitry Andric                 .addReg(NewReg);
3650b57cec5SDimitry Andric           }
3660b57cec5SDimitry Andric           // This register operand of the original instruction is now being used
3670b57cec5SDimitry Andric           // by the inserted drop or local.set instruction, so make it not dead
3680b57cec5SDimitry Andric           // yet.
3695ffd83dbSDimitry Andric           Def.setReg(NewReg);
3705ffd83dbSDimitry Andric           Def.setIsDead(false);
3715ffd83dbSDimitry Andric           MFI.stackifyVReg(MRI, NewReg);
3720b57cec5SDimitry Andric           Changed = true;
3730b57cec5SDimitry Andric         }
3740b57cec5SDimitry Andric       }
3750b57cec5SDimitry Andric 
3760b57cec5SDimitry Andric       // Insert local.gets for any uses that aren't stackified yet.
3770b57cec5SDimitry Andric       MachineInstr *InsertPt = &MI;
3780b57cec5SDimitry Andric       for (MachineOperand &MO : reverse(MI.explicit_uses())) {
3790b57cec5SDimitry Andric         if (!MO.isReg())
3800b57cec5SDimitry Andric           continue;
3810b57cec5SDimitry Andric 
3828bcb0991SDimitry Andric         Register OldReg = MO.getReg();
3830b57cec5SDimitry Andric 
3840b57cec5SDimitry Andric         // Inline asm may have a def in the middle of the operands. Our contract
3850b57cec5SDimitry Andric         // with inline asm register operands is to provide local indices as
3860b57cec5SDimitry Andric         // immediates.
3870b57cec5SDimitry Andric         if (MO.isDef()) {
3880b57cec5SDimitry Andric           assert(MI.isInlineAsm());
3895ffd83dbSDimitry Andric           unsigned LocalId = getLocalId(Reg2Local, MFI, CurLocal, OldReg);
3900b57cec5SDimitry Andric           // If this register operand is tied to another operand, we can't
3910b57cec5SDimitry Andric           // change it to an immediate. Untie it first.
39206c3fb27SDimitry Andric           MI.untieRegOperand(MO.getOperandNo());
3930b57cec5SDimitry Andric           MO.ChangeToImmediate(LocalId);
3940b57cec5SDimitry Andric           continue;
3950b57cec5SDimitry Andric         }
3960b57cec5SDimitry Andric 
3970b57cec5SDimitry Andric         // If we see a stackified register, prepare to insert subsequent
3980b57cec5SDimitry Andric         // local.gets before the start of its tree.
3990b57cec5SDimitry Andric         if (MFI.isVRegStackified(OldReg)) {
4000b57cec5SDimitry Andric           InsertPt = findStartOfTree(MO, MRI, MFI);
4010b57cec5SDimitry Andric           continue;
4020b57cec5SDimitry Andric         }
4030b57cec5SDimitry Andric 
4040b57cec5SDimitry Andric         // Our contract with inline asm register operands is to provide local
4050b57cec5SDimitry Andric         // indices as immediates.
4060b57cec5SDimitry Andric         if (MI.isInlineAsm()) {
4075ffd83dbSDimitry Andric           unsigned LocalId = getLocalId(Reg2Local, MFI, CurLocal, OldReg);
4080b57cec5SDimitry Andric           // Untie it first if this reg operand is tied to another operand.
40906c3fb27SDimitry Andric           MI.untieRegOperand(MO.getOperandNo());
4100b57cec5SDimitry Andric           MO.ChangeToImmediate(LocalId);
4110b57cec5SDimitry Andric           continue;
4120b57cec5SDimitry Andric         }
4130b57cec5SDimitry Andric 
4140b57cec5SDimitry Andric         // Insert a local.get.
4155ffd83dbSDimitry Andric         unsigned LocalId = getLocalId(Reg2Local, MFI, CurLocal, OldReg);
4160b57cec5SDimitry Andric         const TargetRegisterClass *RC = MRI.getRegClass(OldReg);
4178bcb0991SDimitry Andric         Register NewReg = MRI.createVirtualRegister(RC);
4180b57cec5SDimitry Andric         unsigned Opc = getLocalGetOpcode(RC);
419349cc55cSDimitry Andric         // Use a InsertPt as our DebugLoc, since MI may be discontinuous from
420349cc55cSDimitry Andric         // the where this local is being inserted, causing non-linear stepping
421349cc55cSDimitry Andric         // in the debugger or function entry points where variables aren't live
422349cc55cSDimitry Andric         // yet. Alternative is previous instruction, but that is strictly worse
423349cc55cSDimitry Andric         // since it can point at the previous statement.
424349cc55cSDimitry Andric         // See crbug.com/1251909, crbug.com/1249745
425349cc55cSDimitry Andric         InsertPt = BuildMI(MBB, InsertPt, InsertPt->getDebugLoc(),
426349cc55cSDimitry Andric                            TII->get(Opc), NewReg).addImm(LocalId);
4270b57cec5SDimitry Andric         MO.setReg(NewReg);
4285ffd83dbSDimitry Andric         MFI.stackifyVReg(MRI, NewReg);
4290b57cec5SDimitry Andric         Changed = true;
4300b57cec5SDimitry Andric       }
4310b57cec5SDimitry Andric 
4320b57cec5SDimitry Andric       // Coalesce and eliminate COPY instructions.
4330b57cec5SDimitry Andric       if (WebAssembly::isCopy(MI.getOpcode())) {
4340b57cec5SDimitry Andric         MRI.replaceRegWith(MI.getOperand(1).getReg(),
4350b57cec5SDimitry Andric                            MI.getOperand(0).getReg());
4360b57cec5SDimitry Andric         MI.eraseFromParent();
4370b57cec5SDimitry Andric         Changed = true;
4380b57cec5SDimitry Andric       }
4390b57cec5SDimitry Andric     }
4400b57cec5SDimitry Andric   }
4410b57cec5SDimitry Andric 
4420b57cec5SDimitry Andric   // Define the locals.
4430b57cec5SDimitry Andric   // TODO: Sort the locals for better compression.
4440b57cec5SDimitry Andric   MFI.setNumLocals(CurLocal - MFI.getParams().size());
4450b57cec5SDimitry Andric   for (unsigned I = 0, E = MRI.getNumVirtRegs(); I < E; ++I) {
44604eeddc0SDimitry Andric     Register Reg = Register::index2VirtReg(I);
4470b57cec5SDimitry Andric     auto RL = Reg2Local.find(Reg);
4480b57cec5SDimitry Andric     if (RL == Reg2Local.end() || RL->second < MFI.getParams().size())
4490b57cec5SDimitry Andric       continue;
4500b57cec5SDimitry Andric 
4510b57cec5SDimitry Andric     MFI.setLocal(RL->second - MFI.getParams().size(),
4520b57cec5SDimitry Andric                  typeForRegClass(MRI.getRegClass(Reg)));
4530b57cec5SDimitry Andric     Changed = true;
4540b57cec5SDimitry Andric   }
4550b57cec5SDimitry Andric 
4560b57cec5SDimitry Andric #ifndef NDEBUG
4570b57cec5SDimitry Andric   // Assert that all registers have been stackified at this point.
4580b57cec5SDimitry Andric   for (const MachineBasicBlock &MBB : MF) {
4590b57cec5SDimitry Andric     for (const MachineInstr &MI : MBB) {
4600b57cec5SDimitry Andric       if (MI.isDebugInstr() || MI.isLabel())
4610b57cec5SDimitry Andric         continue;
4620b57cec5SDimitry Andric       for (const MachineOperand &MO : MI.explicit_operands()) {
4630b57cec5SDimitry Andric         assert(
4640b57cec5SDimitry Andric             (!MO.isReg() || MRI.use_empty(MO.getReg()) ||
4650b57cec5SDimitry Andric              MFI.isVRegStackified(MO.getReg())) &&
4660b57cec5SDimitry Andric             "WebAssemblyExplicitLocals failed to stackify a register operand");
4670b57cec5SDimitry Andric       }
4680b57cec5SDimitry Andric     }
4690b57cec5SDimitry Andric   }
4700b57cec5SDimitry Andric #endif
4710b57cec5SDimitry Andric 
4720b57cec5SDimitry Andric   return Changed;
4730b57cec5SDimitry Andric }
474