blob: dfd33b99aef9550f2d877248c2a099770057281b [file] [log] [blame]
Dan Gohman4fc4e422016-10-24 19:49:43 +00001//===-- WebAssemblyExplicitLocals.cpp - Make Locals Explicit --------------===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
Dan Gohman4fc4e422016-10-24 19:49:43 +00006//
7//===----------------------------------------------------------------------===//
8///
9/// \file
Adrian Prantl5f8f34e42018-05-01 15:54:18 +000010/// This file converts any remaining registers into WebAssembly locals.
Dan Gohman4fc4e422016-10-24 19:49:43 +000011///
12/// After register stackification and register coloring, convert non-stackified
Thomas Lively6a87dda2019-01-08 06:25:55 +000013/// registers into locals, inserting explicit local.get and local.set
Dan Gohman4fc4e422016-10-24 19:49:43 +000014/// instructions.
15///
16//===----------------------------------------------------------------------===//
17
18#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
19#include "WebAssembly.h"
20#include "WebAssemblyMachineFunctionInfo.h"
21#include "WebAssemblySubtarget.h"
22#include "WebAssemblyUtilities.h"
23#include "llvm/CodeGen/MachineBlockFrequencyInfo.h"
24#include "llvm/CodeGen/MachineInstrBuilder.h"
25#include "llvm/CodeGen/MachineRegisterInfo.h"
26#include "llvm/CodeGen/Passes.h"
27#include "llvm/Support/Debug.h"
28#include "llvm/Support/raw_ostream.h"
29using namespace llvm;
30
31#define DEBUG_TYPE "wasm-explicit-locals"
32
Wouter van Oortmerssen8a9cb242018-08-27 15:45:51 +000033// A command-line option to disable this pass, and keep implicit locals
34// for the purpose of testing with lit/llc ONLY.
35// This produces output which is not valid WebAssembly, and is not supported
36// by assemblers/disassemblers and other MC based tools.
37static cl::opt<bool> WasmDisableExplicitLocals(
38 "wasm-disable-explicit-locals", cl::Hidden,
39 cl::desc("WebAssembly: output implicit locals in"
40 " instruction output for test purposes only."),
Dan Gohman7d7409e2017-02-28 23:37:04 +000041 cl::init(false));
42
Dan Gohman4fc4e422016-10-24 19:49:43 +000043namespace {
44class WebAssemblyExplicitLocals final : public MachineFunctionPass {
45 StringRef getPassName() const override {
46 return "WebAssembly Explicit Locals";
47 }
48
49 void getAnalysisUsage(AnalysisUsage &AU) const override {
50 AU.setPreservesCFG();
51 AU.addPreserved<MachineBlockFrequencyInfo>();
52 MachineFunctionPass::getAnalysisUsage(AU);
53 }
54
55 bool runOnMachineFunction(MachineFunction &MF) override;
56
57public:
58 static char ID; // Pass identification, replacement for typeid
59 WebAssemblyExplicitLocals() : MachineFunctionPass(ID) {}
60};
61} // end anonymous namespace
62
63char WebAssemblyExplicitLocals::ID = 0;
Jacob Gravelle40926452018-03-30 20:36:58 +000064INITIALIZE_PASS(WebAssemblyExplicitLocals, DEBUG_TYPE,
65 "Convert registers to WebAssembly locals", false, false)
66
Dan Gohman4fc4e422016-10-24 19:49:43 +000067FunctionPass *llvm::createWebAssemblyExplicitLocals() {
68 return new WebAssemblyExplicitLocals();
69}
70
71/// Return a local id number for the given register, assigning it a new one
72/// if it doesn't yet have one.
73static unsigned getLocalId(DenseMap<unsigned, unsigned> &Reg2Local,
74 unsigned &CurLocal, unsigned Reg) {
Dan Gohmand934cb82017-02-24 23:18:00 +000075 auto P = Reg2Local.insert(std::make_pair(Reg, CurLocal));
76 if (P.second)
77 ++CurLocal;
78 return P.first->second;
79}
80
81/// Get the appropriate drop opcode for the given register class.
82static unsigned getDropOpcode(const TargetRegisterClass *RC) {
83 if (RC == &WebAssembly::I32RegClass)
84 return WebAssembly::DROP_I32;
85 if (RC == &WebAssembly::I64RegClass)
86 return WebAssembly::DROP_I64;
87 if (RC == &WebAssembly::F32RegClass)
88 return WebAssembly::DROP_F32;
89 if (RC == &WebAssembly::F64RegClass)
90 return WebAssembly::DROP_F64;
91 if (RC == &WebAssembly::V128RegClass)
92 return WebAssembly::DROP_V128;
Heejin Ahn0de58722018-03-08 04:05:37 +000093 if (RC == &WebAssembly::EXCEPT_REFRegClass)
94 return WebAssembly::DROP_EXCEPT_REF;
Dan Gohmand934cb82017-02-24 23:18:00 +000095 llvm_unreachable("Unexpected register class");
Dan Gohman4fc4e422016-10-24 19:49:43 +000096}
97
Thomas Lively6a87dda2019-01-08 06:25:55 +000098/// Get the appropriate local.get opcode for the given register class.
Dan Gohman4fc4e422016-10-24 19:49:43 +000099static unsigned getGetLocalOpcode(const TargetRegisterClass *RC) {
100 if (RC == &WebAssembly::I32RegClass)
Thomas Lively6a87dda2019-01-08 06:25:55 +0000101 return WebAssembly::LOCAL_GET_I32;
Dan Gohman4fc4e422016-10-24 19:49:43 +0000102 if (RC == &WebAssembly::I64RegClass)
Thomas Lively6a87dda2019-01-08 06:25:55 +0000103 return WebAssembly::LOCAL_GET_I64;
Dan Gohman4fc4e422016-10-24 19:49:43 +0000104 if (RC == &WebAssembly::F32RegClass)
Thomas Lively6a87dda2019-01-08 06:25:55 +0000105 return WebAssembly::LOCAL_GET_F32;
Dan Gohman4fc4e422016-10-24 19:49:43 +0000106 if (RC == &WebAssembly::F64RegClass)
Thomas Lively6a87dda2019-01-08 06:25:55 +0000107 return WebAssembly::LOCAL_GET_F64;
Dan Gohman4fc4e422016-10-24 19:49:43 +0000108 if (RC == &WebAssembly::V128RegClass)
Thomas Lively6a87dda2019-01-08 06:25:55 +0000109 return WebAssembly::LOCAL_GET_V128;
Heejin Ahn0de58722018-03-08 04:05:37 +0000110 if (RC == &WebAssembly::EXCEPT_REFRegClass)
Thomas Lively6a87dda2019-01-08 06:25:55 +0000111 return WebAssembly::LOCAL_GET_EXCEPT_REF;
Dan Gohman4fc4e422016-10-24 19:49:43 +0000112 llvm_unreachable("Unexpected register class");
113}
114
Thomas Lively6a87dda2019-01-08 06:25:55 +0000115/// Get the appropriate local.set opcode for the given register class.
Dan Gohman4fc4e422016-10-24 19:49:43 +0000116static unsigned getSetLocalOpcode(const TargetRegisterClass *RC) {
117 if (RC == &WebAssembly::I32RegClass)
Thomas Lively6a87dda2019-01-08 06:25:55 +0000118 return WebAssembly::LOCAL_SET_I32;
Dan Gohman4fc4e422016-10-24 19:49:43 +0000119 if (RC == &WebAssembly::I64RegClass)
Thomas Lively6a87dda2019-01-08 06:25:55 +0000120 return WebAssembly::LOCAL_SET_I64;
Dan Gohman4fc4e422016-10-24 19:49:43 +0000121 if (RC == &WebAssembly::F32RegClass)
Thomas Lively6a87dda2019-01-08 06:25:55 +0000122 return WebAssembly::LOCAL_SET_F32;
Dan Gohman4fc4e422016-10-24 19:49:43 +0000123 if (RC == &WebAssembly::F64RegClass)
Thomas Lively6a87dda2019-01-08 06:25:55 +0000124 return WebAssembly::LOCAL_SET_F64;
Dan Gohman4fc4e422016-10-24 19:49:43 +0000125 if (RC == &WebAssembly::V128RegClass)
Thomas Lively6a87dda2019-01-08 06:25:55 +0000126 return WebAssembly::LOCAL_SET_V128;
Heejin Ahn0de58722018-03-08 04:05:37 +0000127 if (RC == &WebAssembly::EXCEPT_REFRegClass)
Thomas Lively6a87dda2019-01-08 06:25:55 +0000128 return WebAssembly::LOCAL_SET_EXCEPT_REF;
Dan Gohman4fc4e422016-10-24 19:49:43 +0000129 llvm_unreachable("Unexpected register class");
130}
131
Thomas Lively6a87dda2019-01-08 06:25:55 +0000132/// Get the appropriate local.tee opcode for the given register class.
Dan Gohman4fc4e422016-10-24 19:49:43 +0000133static unsigned getTeeLocalOpcode(const TargetRegisterClass *RC) {
134 if (RC == &WebAssembly::I32RegClass)
Thomas Lively6a87dda2019-01-08 06:25:55 +0000135 return WebAssembly::LOCAL_TEE_I32;
Dan Gohman4fc4e422016-10-24 19:49:43 +0000136 if (RC == &WebAssembly::I64RegClass)
Thomas Lively6a87dda2019-01-08 06:25:55 +0000137 return WebAssembly::LOCAL_TEE_I64;
Dan Gohman4fc4e422016-10-24 19:49:43 +0000138 if (RC == &WebAssembly::F32RegClass)
Thomas Lively6a87dda2019-01-08 06:25:55 +0000139 return WebAssembly::LOCAL_TEE_F32;
Dan Gohman4fc4e422016-10-24 19:49:43 +0000140 if (RC == &WebAssembly::F64RegClass)
Thomas Lively6a87dda2019-01-08 06:25:55 +0000141 return WebAssembly::LOCAL_TEE_F64;
Dan Gohman4fc4e422016-10-24 19:49:43 +0000142 if (RC == &WebAssembly::V128RegClass)
Thomas Lively6a87dda2019-01-08 06:25:55 +0000143 return WebAssembly::LOCAL_TEE_V128;
Heejin Ahn0de58722018-03-08 04:05:37 +0000144 if (RC == &WebAssembly::EXCEPT_REFRegClass)
Thomas Lively6a87dda2019-01-08 06:25:55 +0000145 return WebAssembly::LOCAL_TEE_EXCEPT_REF;
Dan Gohman4fc4e422016-10-24 19:49:43 +0000146 llvm_unreachable("Unexpected register class");
147}
148
149/// Get the type associated with the given register class.
Dan Gohman3acb1872016-10-24 23:27:49 +0000150static MVT typeForRegClass(const TargetRegisterClass *RC) {
Dan Gohman4fc4e422016-10-24 19:49:43 +0000151 if (RC == &WebAssembly::I32RegClass)
Dan Gohman3acb1872016-10-24 23:27:49 +0000152 return MVT::i32;
Dan Gohman4fc4e422016-10-24 19:49:43 +0000153 if (RC == &WebAssembly::I64RegClass)
Dan Gohman3acb1872016-10-24 23:27:49 +0000154 return MVT::i64;
Dan Gohman4fc4e422016-10-24 19:49:43 +0000155 if (RC == &WebAssembly::F32RegClass)
Dan Gohman3acb1872016-10-24 23:27:49 +0000156 return MVT::f32;
Dan Gohman4fc4e422016-10-24 19:49:43 +0000157 if (RC == &WebAssembly::F64RegClass)
Dan Gohman3acb1872016-10-24 23:27:49 +0000158 return MVT::f64;
Thomas Lively409f5842018-10-09 23:33:16 +0000159 if (RC == &WebAssembly::V128RegClass)
160 return MVT::v16i8;
Heejin Ahn0de58722018-03-08 04:05:37 +0000161 if (RC == &WebAssembly::EXCEPT_REFRegClass)
162 return MVT::ExceptRef;
Dan Gohman4fc4e422016-10-24 19:49:43 +0000163 llvm_unreachable("unrecognized register class");
164}
165
166/// Given a MachineOperand of a stackified vreg, return the instruction at the
167/// start of the expression tree.
Wouter van Oortmerssen8a9cb242018-08-27 15:45:51 +0000168static MachineInstr *findStartOfTree(MachineOperand &MO,
Dan Gohman4fc4e422016-10-24 19:49:43 +0000169 MachineRegisterInfo &MRI,
170 WebAssemblyFunctionInfo &MFI) {
171 unsigned Reg = MO.getReg();
172 assert(MFI.isVRegStackified(Reg));
173 MachineInstr *Def = MRI.getVRegDef(Reg);
174
175 // Find the first stackified use and proceed from there.
176 for (MachineOperand &DefMO : Def->explicit_uses()) {
177 if (!DefMO.isReg())
178 continue;
Wouter van Oortmerssen8a9cb242018-08-27 15:45:51 +0000179 return findStartOfTree(DefMO, MRI, MFI);
Dan Gohman4fc4e422016-10-24 19:49:43 +0000180 }
181
182 // If there were no stackified uses, we've reached the start.
183 return Def;
184}
185
186bool WebAssemblyExplicitLocals::runOnMachineFunction(MachineFunction &MF) {
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000187 LLVM_DEBUG(dbgs() << "********** Make Locals Explicit **********\n"
188 "********** Function: "
189 << MF.getName() << '\n');
Dan Gohman4fc4e422016-10-24 19:49:43 +0000190
Dan Gohman7d7409e2017-02-28 23:37:04 +0000191 // Disable this pass if directed to do so.
Wouter van Oortmerssen8a9cb242018-08-27 15:45:51 +0000192 if (WasmDisableExplicitLocals)
Dan Gohman7d7409e2017-02-28 23:37:04 +0000193 return false;
194
Dan Gohman4fc4e422016-10-24 19:49:43 +0000195 bool Changed = false;
196 MachineRegisterInfo &MRI = MF.getRegInfo();
197 WebAssemblyFunctionInfo &MFI = *MF.getInfo<WebAssemblyFunctionInfo>();
198 const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
199
200 // Map non-stackified virtual registers to their local ids.
201 DenseMap<unsigned, unsigned> Reg2Local;
202
203 // Handle ARGUMENTS first to ensure that they get the designated numbers.
204 for (MachineBasicBlock::iterator I = MF.begin()->begin(),
205 E = MF.begin()->end();
206 I != E;) {
207 MachineInstr &MI = *I++;
208 if (!WebAssembly::isArgument(MI))
209 break;
210 unsigned Reg = MI.getOperand(0).getReg();
211 assert(!MFI.isVRegStackified(Reg));
Wouter van Oortmerssen8a9cb242018-08-27 15:45:51 +0000212 Reg2Local[Reg] = static_cast<unsigned>(MI.getOperand(1).getImm());
Dan Gohman4fc4e422016-10-24 19:49:43 +0000213 MI.eraseFromParent();
214 Changed = true;
215 }
216
217 // Start assigning local numbers after the last parameter.
Wouter van Oortmerssen8a9cb242018-08-27 15:45:51 +0000218 unsigned CurLocal = static_cast<unsigned>(MFI.getParams().size());
Dan Gohman4fc4e422016-10-24 19:49:43 +0000219
Dan Gohmand934cb82017-02-24 23:18:00 +0000220 // Precompute the set of registers that are unused, so that we can insert
221 // drops to their defs.
222 BitVector UseEmpty(MRI.getNumVirtRegs());
Wouter van Oortmerssen8a9cb242018-08-27 15:45:51 +0000223 for (unsigned I = 0, E = MRI.getNumVirtRegs(); I < E; ++I)
224 UseEmpty[I] = MRI.use_empty(TargetRegisterInfo::index2VirtReg(I));
Dan Gohmand934cb82017-02-24 23:18:00 +0000225
Dan Gohman4fc4e422016-10-24 19:49:43 +0000226 // Visit each instruction in the function.
227 for (MachineBasicBlock &MBB : MF) {
228 for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end(); I != E;) {
229 MachineInstr &MI = *I++;
230 assert(!WebAssembly::isArgument(MI));
231
Shiva Chen801bf7e2018-05-09 02:42:00 +0000232 if (MI.isDebugInstr() || MI.isLabel())
Dan Gohman4fc4e422016-10-24 19:49:43 +0000233 continue;
234
Thomas Lively6a87dda2019-01-08 06:25:55 +0000235 // Replace tee instructions with local.tee. The difference is that tee
236 // instructions have two defs, while local.tee instructions have one def
Dan Gohman4fc4e422016-10-24 19:49:43 +0000237 // and an index of a local to write to.
238 if (WebAssembly::isTee(MI)) {
239 assert(MFI.isVRegStackified(MI.getOperand(0).getReg()));
240 assert(!MFI.isVRegStackified(MI.getOperand(1).getReg()));
241 unsigned OldReg = MI.getOperand(2).getReg();
242 const TargetRegisterClass *RC = MRI.getRegClass(OldReg);
243
244 // Stackify the input if it isn't stackified yet.
245 if (!MFI.isVRegStackified(OldReg)) {
246 unsigned LocalId = getLocalId(Reg2Local, CurLocal, OldReg);
247 unsigned NewReg = MRI.createVirtualRegister(RC);
248 unsigned Opc = getGetLocalOpcode(RC);
249 BuildMI(MBB, &MI, MI.getDebugLoc(), TII->get(Opc), NewReg)
250 .addImm(LocalId);
251 MI.getOperand(2).setReg(NewReg);
252 MFI.stackifyVReg(NewReg);
253 }
254
Thomas Lively6a87dda2019-01-08 06:25:55 +0000255 // Replace the TEE with a LOCAL_TEE.
Dan Gohman4fc4e422016-10-24 19:49:43 +0000256 unsigned LocalId =
257 getLocalId(Reg2Local, CurLocal, MI.getOperand(1).getReg());
258 unsigned Opc = getTeeLocalOpcode(RC);
259 BuildMI(MBB, &MI, MI.getDebugLoc(), TII->get(Opc),
260 MI.getOperand(0).getReg())
261 .addImm(LocalId)
262 .addReg(MI.getOperand(2).getReg());
263
264 MI.eraseFromParent();
265 Changed = true;
266 continue;
267 }
268
Thomas Lively6a87dda2019-01-08 06:25:55 +0000269 // Insert local.sets for any defs that aren't stackified yet. Currently
Dan Gohman4fc4e422016-10-24 19:49:43 +0000270 // we handle at most one def.
271 assert(MI.getDesc().getNumDefs() <= 1);
272 if (MI.getDesc().getNumDefs() == 1) {
273 unsigned OldReg = MI.getOperand(0).getReg();
Dan Gohmand934cb82017-02-24 23:18:00 +0000274 if (!MFI.isVRegStackified(OldReg)) {
Dan Gohman4fc4e422016-10-24 19:49:43 +0000275 const TargetRegisterClass *RC = MRI.getRegClass(OldReg);
276 unsigned NewReg = MRI.createVirtualRegister(RC);
277 auto InsertPt = std::next(MachineBasicBlock::iterator(&MI));
Dan Gohmand934cb82017-02-24 23:18:00 +0000278 if (MI.getOpcode() == WebAssembly::IMPLICIT_DEF) {
279 MI.eraseFromParent();
280 Changed = true;
281 continue;
282 }
283 if (UseEmpty[TargetRegisterInfo::virtReg2Index(OldReg)]) {
284 unsigned Opc = getDropOpcode(RC);
Heejin Ahn891a7472018-06-19 20:30:42 +0000285 MachineInstr *Drop =
286 BuildMI(MBB, InsertPt, MI.getDebugLoc(), TII->get(Opc))
287 .addReg(NewReg);
288 // After the drop instruction, this reg operand will not be used
289 Drop->getOperand(0).setIsKill();
Dan Gohmand934cb82017-02-24 23:18:00 +0000290 } else {
291 unsigned LocalId = getLocalId(Reg2Local, CurLocal, OldReg);
292 unsigned Opc = getSetLocalOpcode(RC);
293 BuildMI(MBB, InsertPt, MI.getDebugLoc(), TII->get(Opc))
294 .addImm(LocalId)
295 .addReg(NewReg);
296 }
Dan Gohman4fc4e422016-10-24 19:49:43 +0000297 MI.getOperand(0).setReg(NewReg);
Heejin Ahn4d98dfb2018-12-29 02:42:04 +0000298 // This register operand of the original instruction is now being used
Thomas Lively6a87dda2019-01-08 06:25:55 +0000299 // by the inserted drop or local.set instruction, so make it not dead
Heejin Ahn4d98dfb2018-12-29 02:42:04 +0000300 // yet.
Heejin Ahn891a7472018-06-19 20:30:42 +0000301 MI.getOperand(0).setIsDead(false);
Dan Gohman4fc4e422016-10-24 19:49:43 +0000302 MFI.stackifyVReg(NewReg);
303 Changed = true;
304 }
305 }
306
Thomas Lively6a87dda2019-01-08 06:25:55 +0000307 // Insert local.gets for any uses that aren't stackified yet.
Dan Gohman4fc4e422016-10-24 19:49:43 +0000308 MachineInstr *InsertPt = &MI;
309 for (MachineOperand &MO : reverse(MI.explicit_uses())) {
310 if (!MO.isReg())
311 continue;
312
313 unsigned OldReg = MO.getReg();
314
Dan Gohmanb465aa02017-11-08 19:18:08 +0000315 // Inline asm may have a def in the middle of the operands. Our contract
316 // with inline asm register operands is to provide local indices as
317 // immediates.
318 if (MO.isDef()) {
319 assert(MI.getOpcode() == TargetOpcode::INLINEASM);
320 unsigned LocalId = getLocalId(Reg2Local, CurLocal, OldReg);
Heejin Ahn300f42f2018-09-12 21:34:39 +0000321 // If this register operand is tied to another operand, we can't
322 // change it to an immediate. Untie it first.
323 MI.untieRegOperand(MI.getOperandNo(&MO));
Dan Gohman045a2172018-09-04 17:46:12 +0000324 MO.ChangeToImmediate(LocalId);
Dan Gohmanb465aa02017-11-08 19:18:08 +0000325 continue;
326 }
327
Dan Gohman4fc4e422016-10-24 19:49:43 +0000328 // If we see a stackified register, prepare to insert subsequent
Thomas Lively6a87dda2019-01-08 06:25:55 +0000329 // local.gets before the start of its tree.
Dan Gohman4fc4e422016-10-24 19:49:43 +0000330 if (MFI.isVRegStackified(OldReg)) {
Wouter van Oortmerssen8a9cb242018-08-27 15:45:51 +0000331 InsertPt = findStartOfTree(MO, MRI, MFI);
Dan Gohman4fc4e422016-10-24 19:49:43 +0000332 continue;
333 }
334
Dan Gohmanb465aa02017-11-08 19:18:08 +0000335 // Our contract with inline asm register operands is to provide local
336 // indices as immediates.
337 if (MI.getOpcode() == TargetOpcode::INLINEASM) {
338 unsigned LocalId = getLocalId(Reg2Local, CurLocal, OldReg);
Heejin Ahn300f42f2018-09-12 21:34:39 +0000339 // Untie it first if this reg operand is tied to another operand.
340 MI.untieRegOperand(MI.getOperandNo(&MO));
Dan Gohman045a2172018-09-04 17:46:12 +0000341 MO.ChangeToImmediate(LocalId);
Dan Gohmanb465aa02017-11-08 19:18:08 +0000342 continue;
343 }
344
Thomas Lively6a87dda2019-01-08 06:25:55 +0000345 // Insert a local.get.
Dan Gohman4fc4e422016-10-24 19:49:43 +0000346 unsigned LocalId = getLocalId(Reg2Local, CurLocal, OldReg);
347 const TargetRegisterClass *RC = MRI.getRegClass(OldReg);
348 unsigned NewReg = MRI.createVirtualRegister(RC);
349 unsigned Opc = getGetLocalOpcode(RC);
350 InsertPt =
351 BuildMI(MBB, InsertPt, MI.getDebugLoc(), TII->get(Opc), NewReg)
352 .addImm(LocalId);
353 MO.setReg(NewReg);
354 MFI.stackifyVReg(NewReg);
355 Changed = true;
356 }
357
358 // Coalesce and eliminate COPY instructions.
359 if (WebAssembly::isCopy(MI)) {
360 MRI.replaceRegWith(MI.getOperand(1).getReg(),
361 MI.getOperand(0).getReg());
362 MI.eraseFromParent();
363 Changed = true;
364 }
365 }
366 }
367
Dan Gohman3acb1872016-10-24 23:27:49 +0000368 // Define the locals.
Dan Gohmand934cb82017-02-24 23:18:00 +0000369 // TODO: Sort the locals for better compression.
370 MFI.setNumLocals(CurLocal - MFI.getParams().size());
Wouter van Oortmerssen8a9cb242018-08-27 15:45:51 +0000371 for (unsigned I = 0, E = MRI.getNumVirtRegs(); I < E; ++I) {
372 unsigned Reg = TargetRegisterInfo::index2VirtReg(I);
373 auto RL = Reg2Local.find(Reg);
374 if (RL == Reg2Local.end() || RL->second < MFI.getParams().size())
Dan Gohman4fc4e422016-10-24 19:49:43 +0000375 continue;
376
Wouter van Oortmerssen8a9cb242018-08-27 15:45:51 +0000377 MFI.setLocal(RL->second - MFI.getParams().size(),
Dan Gohmand934cb82017-02-24 23:18:00 +0000378 typeForRegClass(MRI.getRegClass(Reg)));
Dan Gohman3acb1872016-10-24 23:27:49 +0000379 Changed = true;
Dan Gohman4fc4e422016-10-24 19:49:43 +0000380 }
381
Wouter van Oortmerssena7be3752018-08-13 23:12:49 +0000382#ifndef NDEBUG
383 // Assert that all registers have been stackified at this point.
384 for (const MachineBasicBlock &MBB : MF) {
385 for (const MachineInstr &MI : MBB) {
386 if (MI.isDebugInstr() || MI.isLabel())
387 continue;
388 for (const MachineOperand &MO : MI.explicit_operands()) {
389 assert(
390 (!MO.isReg() || MRI.use_empty(MO.getReg()) ||
391 MFI.isVRegStackified(MO.getReg())) &&
392 "WebAssemblyExplicitLocals failed to stackify a register operand");
393 }
394 }
Wouter van Oortmerssenab26bd02018-08-10 21:32:47 +0000395 }
Wouter van Oortmerssena7be3752018-08-13 23:12:49 +0000396#endif
397
398 return Changed;
Wouter van Oortmerssenab26bd02018-08-10 21:32:47 +0000399}