blob: acbd4c9921b0e489521b01c18629ea94bf5a2dc9 [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"
Yury Delendikadf7a0a2019-12-20 14:31:56 -080020#include "WebAssemblyDebugValueManager.h"
Dan Gohman4fc4e422016-10-24 19:49:43 +000021#include "WebAssemblyMachineFunctionInfo.h"
22#include "WebAssemblySubtarget.h"
23#include "WebAssemblyUtilities.h"
24#include "llvm/CodeGen/MachineBlockFrequencyInfo.h"
25#include "llvm/CodeGen/MachineInstrBuilder.h"
26#include "llvm/CodeGen/MachineRegisterInfo.h"
27#include "llvm/CodeGen/Passes.h"
28#include "llvm/Support/Debug.h"
29#include "llvm/Support/raw_ostream.h"
30using namespace llvm;
31
32#define DEBUG_TYPE "wasm-explicit-locals"
33
Wouter van Oortmerssen8a9cb242018-08-27 15:45:51 +000034// A command-line option to disable this pass, and keep implicit locals
35// for the purpose of testing with lit/llc ONLY.
36// This produces output which is not valid WebAssembly, and is not supported
37// by assemblers/disassemblers and other MC based tools.
38static cl::opt<bool> WasmDisableExplicitLocals(
39 "wasm-disable-explicit-locals", cl::Hidden,
40 cl::desc("WebAssembly: output implicit locals in"
41 " instruction output for test purposes only."),
Dan Gohman7d7409e2017-02-28 23:37:04 +000042 cl::init(false));
43
Dan Gohman4fc4e422016-10-24 19:49:43 +000044namespace {
45class WebAssemblyExplicitLocals final : public MachineFunctionPass {
46 StringRef getPassName() const override {
47 return "WebAssembly Explicit Locals";
48 }
49
50 void getAnalysisUsage(AnalysisUsage &AU) const override {
51 AU.setPreservesCFG();
52 AU.addPreserved<MachineBlockFrequencyInfo>();
53 MachineFunctionPass::getAnalysisUsage(AU);
54 }
55
56 bool runOnMachineFunction(MachineFunction &MF) override;
57
58public:
59 static char ID; // Pass identification, replacement for typeid
60 WebAssemblyExplicitLocals() : MachineFunctionPass(ID) {}
61};
62} // end anonymous namespace
63
64char WebAssemblyExplicitLocals::ID = 0;
Jacob Gravelle40926452018-03-30 20:36:58 +000065INITIALIZE_PASS(WebAssemblyExplicitLocals, DEBUG_TYPE,
66 "Convert registers to WebAssembly locals", false, false)
67
Dan Gohman4fc4e422016-10-24 19:49:43 +000068FunctionPass *llvm::createWebAssemblyExplicitLocals() {
69 return new WebAssemblyExplicitLocals();
70}
71
72/// Return a local id number for the given register, assigning it a new one
73/// if it doesn't yet have one.
74static unsigned getLocalId(DenseMap<unsigned, unsigned> &Reg2Local,
75 unsigned &CurLocal, unsigned Reg) {
Dan Gohmand934cb82017-02-24 23:18:00 +000076 auto P = Reg2Local.insert(std::make_pair(Reg, CurLocal));
77 if (P.second)
78 ++CurLocal;
79 return P.first->second;
80}
81
82/// Get the appropriate drop opcode for the given register class.
83static unsigned getDropOpcode(const TargetRegisterClass *RC) {
84 if (RC == &WebAssembly::I32RegClass)
85 return WebAssembly::DROP_I32;
86 if (RC == &WebAssembly::I64RegClass)
87 return WebAssembly::DROP_I64;
88 if (RC == &WebAssembly::F32RegClass)
89 return WebAssembly::DROP_F32;
90 if (RC == &WebAssembly::F64RegClass)
91 return WebAssembly::DROP_F64;
92 if (RC == &WebAssembly::V128RegClass)
93 return WebAssembly::DROP_V128;
Heejin Ahn9f96a582019-07-15 22:49:25 +000094 if (RC == &WebAssembly::EXNREFRegClass)
95 return WebAssembly::DROP_EXNREF;
Dan Gohmand934cb82017-02-24 23:18:00 +000096 llvm_unreachable("Unexpected register class");
Dan Gohman4fc4e422016-10-24 19:49:43 +000097}
98
Thomas Lively6a87dda2019-01-08 06:25:55 +000099/// Get the appropriate local.get opcode for the given register class.
Heejin Ahn34dc1f22019-03-19 05:07:33 +0000100static unsigned getLocalGetOpcode(const TargetRegisterClass *RC) {
Dan Gohman4fc4e422016-10-24 19:49:43 +0000101 if (RC == &WebAssembly::I32RegClass)
Thomas Lively6a87dda2019-01-08 06:25:55 +0000102 return WebAssembly::LOCAL_GET_I32;
Dan Gohman4fc4e422016-10-24 19:49:43 +0000103 if (RC == &WebAssembly::I64RegClass)
Thomas Lively6a87dda2019-01-08 06:25:55 +0000104 return WebAssembly::LOCAL_GET_I64;
Dan Gohman4fc4e422016-10-24 19:49:43 +0000105 if (RC == &WebAssembly::F32RegClass)
Thomas Lively6a87dda2019-01-08 06:25:55 +0000106 return WebAssembly::LOCAL_GET_F32;
Dan Gohman4fc4e422016-10-24 19:49:43 +0000107 if (RC == &WebAssembly::F64RegClass)
Thomas Lively6a87dda2019-01-08 06:25:55 +0000108 return WebAssembly::LOCAL_GET_F64;
Dan Gohman4fc4e422016-10-24 19:49:43 +0000109 if (RC == &WebAssembly::V128RegClass)
Thomas Lively6a87dda2019-01-08 06:25:55 +0000110 return WebAssembly::LOCAL_GET_V128;
Heejin Ahn9f96a582019-07-15 22:49:25 +0000111 if (RC == &WebAssembly::EXNREFRegClass)
112 return WebAssembly::LOCAL_GET_EXNREF;
Dan Gohman4fc4e422016-10-24 19:49:43 +0000113 llvm_unreachable("Unexpected register class");
114}
115
Thomas Lively6a87dda2019-01-08 06:25:55 +0000116/// Get the appropriate local.set opcode for the given register class.
Heejin Ahn34dc1f22019-03-19 05:07:33 +0000117static unsigned getLocalSetOpcode(const TargetRegisterClass *RC) {
Dan Gohman4fc4e422016-10-24 19:49:43 +0000118 if (RC == &WebAssembly::I32RegClass)
Thomas Lively6a87dda2019-01-08 06:25:55 +0000119 return WebAssembly::LOCAL_SET_I32;
Dan Gohman4fc4e422016-10-24 19:49:43 +0000120 if (RC == &WebAssembly::I64RegClass)
Thomas Lively6a87dda2019-01-08 06:25:55 +0000121 return WebAssembly::LOCAL_SET_I64;
Dan Gohman4fc4e422016-10-24 19:49:43 +0000122 if (RC == &WebAssembly::F32RegClass)
Thomas Lively6a87dda2019-01-08 06:25:55 +0000123 return WebAssembly::LOCAL_SET_F32;
Dan Gohman4fc4e422016-10-24 19:49:43 +0000124 if (RC == &WebAssembly::F64RegClass)
Thomas Lively6a87dda2019-01-08 06:25:55 +0000125 return WebAssembly::LOCAL_SET_F64;
Dan Gohman4fc4e422016-10-24 19:49:43 +0000126 if (RC == &WebAssembly::V128RegClass)
Thomas Lively6a87dda2019-01-08 06:25:55 +0000127 return WebAssembly::LOCAL_SET_V128;
Heejin Ahn9f96a582019-07-15 22:49:25 +0000128 if (RC == &WebAssembly::EXNREFRegClass)
129 return WebAssembly::LOCAL_SET_EXNREF;
Dan Gohman4fc4e422016-10-24 19:49:43 +0000130 llvm_unreachable("Unexpected register class");
131}
132
Thomas Lively6a87dda2019-01-08 06:25:55 +0000133/// Get the appropriate local.tee opcode for the given register class.
Heejin Ahn34dc1f22019-03-19 05:07:33 +0000134static unsigned getLocalTeeOpcode(const TargetRegisterClass *RC) {
Dan Gohman4fc4e422016-10-24 19:49:43 +0000135 if (RC == &WebAssembly::I32RegClass)
Thomas Lively6a87dda2019-01-08 06:25:55 +0000136 return WebAssembly::LOCAL_TEE_I32;
Dan Gohman4fc4e422016-10-24 19:49:43 +0000137 if (RC == &WebAssembly::I64RegClass)
Thomas Lively6a87dda2019-01-08 06:25:55 +0000138 return WebAssembly::LOCAL_TEE_I64;
Dan Gohman4fc4e422016-10-24 19:49:43 +0000139 if (RC == &WebAssembly::F32RegClass)
Thomas Lively6a87dda2019-01-08 06:25:55 +0000140 return WebAssembly::LOCAL_TEE_F32;
Dan Gohman4fc4e422016-10-24 19:49:43 +0000141 if (RC == &WebAssembly::F64RegClass)
Thomas Lively6a87dda2019-01-08 06:25:55 +0000142 return WebAssembly::LOCAL_TEE_F64;
Dan Gohman4fc4e422016-10-24 19:49:43 +0000143 if (RC == &WebAssembly::V128RegClass)
Thomas Lively6a87dda2019-01-08 06:25:55 +0000144 return WebAssembly::LOCAL_TEE_V128;
Heejin Ahn9f96a582019-07-15 22:49:25 +0000145 if (RC == &WebAssembly::EXNREFRegClass)
146 return WebAssembly::LOCAL_TEE_EXNREF;
Dan Gohman4fc4e422016-10-24 19:49:43 +0000147 llvm_unreachable("Unexpected register class");
148}
149
150/// Get the type associated with the given register class.
Dan Gohman3acb1872016-10-24 23:27:49 +0000151static MVT typeForRegClass(const TargetRegisterClass *RC) {
Dan Gohman4fc4e422016-10-24 19:49:43 +0000152 if (RC == &WebAssembly::I32RegClass)
Dan Gohman3acb1872016-10-24 23:27:49 +0000153 return MVT::i32;
Dan Gohman4fc4e422016-10-24 19:49:43 +0000154 if (RC == &WebAssembly::I64RegClass)
Dan Gohman3acb1872016-10-24 23:27:49 +0000155 return MVT::i64;
Dan Gohman4fc4e422016-10-24 19:49:43 +0000156 if (RC == &WebAssembly::F32RegClass)
Dan Gohman3acb1872016-10-24 23:27:49 +0000157 return MVT::f32;
Dan Gohman4fc4e422016-10-24 19:49:43 +0000158 if (RC == &WebAssembly::F64RegClass)
Dan Gohman3acb1872016-10-24 23:27:49 +0000159 return MVT::f64;
Thomas Lively409f5842018-10-09 23:33:16 +0000160 if (RC == &WebAssembly::V128RegClass)
161 return MVT::v16i8;
Heejin Ahn9f96a582019-07-15 22:49:25 +0000162 if (RC == &WebAssembly::EXNREFRegClass)
163 return MVT::exnref;
Dan Gohman4fc4e422016-10-24 19:49:43 +0000164 llvm_unreachable("unrecognized register class");
165}
166
167/// Given a MachineOperand of a stackified vreg, return the instruction at the
168/// start of the expression tree.
Wouter van Oortmerssen8a9cb242018-08-27 15:45:51 +0000169static MachineInstr *findStartOfTree(MachineOperand &MO,
Dan Gohman4fc4e422016-10-24 19:49:43 +0000170 MachineRegisterInfo &MRI,
171 WebAssemblyFunctionInfo &MFI) {
Daniel Sanders05c145d2019-08-12 22:40:45 +0000172 Register Reg = MO.getReg();
Dan Gohman4fc4e422016-10-24 19:49:43 +0000173 assert(MFI.isVRegStackified(Reg));
174 MachineInstr *Def = MRI.getVRegDef(Reg);
175
176 // Find the first stackified use and proceed from there.
177 for (MachineOperand &DefMO : Def->explicit_uses()) {
178 if (!DefMO.isReg())
179 continue;
Wouter van Oortmerssen8a9cb242018-08-27 15:45:51 +0000180 return findStartOfTree(DefMO, MRI, MFI);
Dan Gohman4fc4e422016-10-24 19:49:43 +0000181 }
182
183 // If there were no stackified uses, we've reached the start.
184 return Def;
185}
186
187bool WebAssemblyExplicitLocals::runOnMachineFunction(MachineFunction &MF) {
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000188 LLVM_DEBUG(dbgs() << "********** Make Locals Explicit **********\n"
189 "********** Function: "
190 << MF.getName() << '\n');
Dan Gohman4fc4e422016-10-24 19:49:43 +0000191
Dan Gohman7d7409e2017-02-28 23:37:04 +0000192 // Disable this pass if directed to do so.
Wouter van Oortmerssen8a9cb242018-08-27 15:45:51 +0000193 if (WasmDisableExplicitLocals)
Dan Gohman7d7409e2017-02-28 23:37:04 +0000194 return false;
195
Dan Gohman4fc4e422016-10-24 19:49:43 +0000196 bool Changed = false;
197 MachineRegisterInfo &MRI = MF.getRegInfo();
198 WebAssemblyFunctionInfo &MFI = *MF.getInfo<WebAssemblyFunctionInfo>();
199 const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
200
201 // Map non-stackified virtual registers to their local ids.
202 DenseMap<unsigned, unsigned> Reg2Local;
203
204 // Handle ARGUMENTS first to ensure that they get the designated numbers.
205 for (MachineBasicBlock::iterator I = MF.begin()->begin(),
206 E = MF.begin()->end();
207 I != E;) {
208 MachineInstr &MI = *I++;
Wouter van Oortmerssend8ddf832019-07-12 22:08:25 +0000209 if (!WebAssembly::isArgument(MI.getOpcode()))
Dan Gohman4fc4e422016-10-24 19:49:43 +0000210 break;
Daniel Sanders05c145d2019-08-12 22:40:45 +0000211 Register Reg = MI.getOperand(0).getReg();
Dan Gohman4fc4e422016-10-24 19:49:43 +0000212 assert(!MFI.isVRegStackified(Reg));
Wouter van Oortmerssen8a9cb242018-08-27 15:45:51 +0000213 Reg2Local[Reg] = static_cast<unsigned>(MI.getOperand(1).getImm());
Dan Gohman4fc4e422016-10-24 19:49:43 +0000214 MI.eraseFromParent();
215 Changed = true;
216 }
217
218 // Start assigning local numbers after the last parameter.
Wouter van Oortmerssen8a9cb242018-08-27 15:45:51 +0000219 unsigned CurLocal = static_cast<unsigned>(MFI.getParams().size());
Dan Gohman4fc4e422016-10-24 19:49:43 +0000220
Dan Gohmand934cb82017-02-24 23:18:00 +0000221 // Precompute the set of registers that are unused, so that we can insert
222 // drops to their defs.
223 BitVector UseEmpty(MRI.getNumVirtRegs());
Wouter van Oortmerssen8a9cb242018-08-27 15:45:51 +0000224 for (unsigned I = 0, E = MRI.getNumVirtRegs(); I < E; ++I)
Daniel Sanders2bea69b2019-08-01 23:27:28 +0000225 UseEmpty[I] = MRI.use_empty(Register::index2VirtReg(I));
Dan Gohmand934cb82017-02-24 23:18:00 +0000226
Dan Gohman4fc4e422016-10-24 19:49:43 +0000227 // Visit each instruction in the function.
228 for (MachineBasicBlock &MBB : MF) {
229 for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end(); I != E;) {
230 MachineInstr &MI = *I++;
Wouter van Oortmerssend8ddf832019-07-12 22:08:25 +0000231 assert(!WebAssembly::isArgument(MI.getOpcode()));
Dan Gohman4fc4e422016-10-24 19:49:43 +0000232
Shiva Chen801bf7e2018-05-09 02:42:00 +0000233 if (MI.isDebugInstr() || MI.isLabel())
Dan Gohman4fc4e422016-10-24 19:49:43 +0000234 continue;
235
Thomas Lively6a87dda2019-01-08 06:25:55 +0000236 // Replace tee instructions with local.tee. The difference is that tee
237 // instructions have two defs, while local.tee instructions have one def
Dan Gohman4fc4e422016-10-24 19:49:43 +0000238 // and an index of a local to write to.
Wouter van Oortmerssend8ddf832019-07-12 22:08:25 +0000239 if (WebAssembly::isTee(MI.getOpcode())) {
Dan Gohman4fc4e422016-10-24 19:49:43 +0000240 assert(MFI.isVRegStackified(MI.getOperand(0).getReg()));
241 assert(!MFI.isVRegStackified(MI.getOperand(1).getReg()));
Daniel Sanders05c145d2019-08-12 22:40:45 +0000242 Register OldReg = MI.getOperand(2).getReg();
Dan Gohman4fc4e422016-10-24 19:49:43 +0000243 const TargetRegisterClass *RC = MRI.getRegClass(OldReg);
244
245 // Stackify the input if it isn't stackified yet.
246 if (!MFI.isVRegStackified(OldReg)) {
247 unsigned LocalId = getLocalId(Reg2Local, CurLocal, OldReg);
Daniel Sanders05c145d2019-08-12 22:40:45 +0000248 Register NewReg = MRI.createVirtualRegister(RC);
Heejin Ahn34dc1f22019-03-19 05:07:33 +0000249 unsigned Opc = getLocalGetOpcode(RC);
Dan Gohman4fc4e422016-10-24 19:49:43 +0000250 BuildMI(MBB, &MI, MI.getDebugLoc(), TII->get(Opc), NewReg)
251 .addImm(LocalId);
252 MI.getOperand(2).setReg(NewReg);
253 MFI.stackifyVReg(NewReg);
254 }
255
Thomas Lively6a87dda2019-01-08 06:25:55 +0000256 // Replace the TEE with a LOCAL_TEE.
Dan Gohman4fc4e422016-10-24 19:49:43 +0000257 unsigned LocalId =
258 getLocalId(Reg2Local, CurLocal, MI.getOperand(1).getReg());
Heejin Ahn34dc1f22019-03-19 05:07:33 +0000259 unsigned Opc = getLocalTeeOpcode(RC);
Dan Gohman4fc4e422016-10-24 19:49:43 +0000260 BuildMI(MBB, &MI, MI.getDebugLoc(), TII->get(Opc),
261 MI.getOperand(0).getReg())
262 .addImm(LocalId)
263 .addReg(MI.getOperand(2).getReg());
264
Yury Delendikadf7a0a2019-12-20 14:31:56 -0800265 WebAssemblyDebugValueManager(&MI).replaceWithLocal(LocalId);
266
Dan Gohman4fc4e422016-10-24 19:49:43 +0000267 MI.eraseFromParent();
268 Changed = true;
269 continue;
270 }
271
Thomas Lively6a87dda2019-01-08 06:25:55 +0000272 // Insert local.sets for any defs that aren't stackified yet. Currently
Dan Gohman4fc4e422016-10-24 19:49:43 +0000273 // we handle at most one def.
274 assert(MI.getDesc().getNumDefs() <= 1);
275 if (MI.getDesc().getNumDefs() == 1) {
Daniel Sanders05c145d2019-08-12 22:40:45 +0000276 Register OldReg = MI.getOperand(0).getReg();
Dan Gohmand934cb82017-02-24 23:18:00 +0000277 if (!MFI.isVRegStackified(OldReg)) {
Dan Gohman4fc4e422016-10-24 19:49:43 +0000278 const TargetRegisterClass *RC = MRI.getRegClass(OldReg);
Daniel Sanders05c145d2019-08-12 22:40:45 +0000279 Register NewReg = MRI.createVirtualRegister(RC);
Heejin Ahn5c644c92019-03-05 21:05:09 +0000280 auto InsertPt = std::next(MI.getIterator());
Dan Gohmand934cb82017-02-24 23:18:00 +0000281 if (MI.getOpcode() == WebAssembly::IMPLICIT_DEF) {
282 MI.eraseFromParent();
283 Changed = true;
284 continue;
285 }
Daniel Sanders2bea69b2019-08-01 23:27:28 +0000286 if (UseEmpty[Register::virtReg2Index(OldReg)]) {
Dan Gohmand934cb82017-02-24 23:18:00 +0000287 unsigned Opc = getDropOpcode(RC);
Heejin Ahn891a7472018-06-19 20:30:42 +0000288 MachineInstr *Drop =
289 BuildMI(MBB, InsertPt, MI.getDebugLoc(), TII->get(Opc))
290 .addReg(NewReg);
291 // After the drop instruction, this reg operand will not be used
292 Drop->getOperand(0).setIsKill();
Dan Gohmand934cb82017-02-24 23:18:00 +0000293 } else {
294 unsigned LocalId = getLocalId(Reg2Local, CurLocal, OldReg);
Heejin Ahn34dc1f22019-03-19 05:07:33 +0000295 unsigned Opc = getLocalSetOpcode(RC);
Yury Delendikadf7a0a2019-12-20 14:31:56 -0800296
297 WebAssemblyDebugValueManager(&MI).replaceWithLocal(LocalId);
298
Dan Gohmand934cb82017-02-24 23:18:00 +0000299 BuildMI(MBB, InsertPt, MI.getDebugLoc(), TII->get(Opc))
300 .addImm(LocalId)
301 .addReg(NewReg);
302 }
Dan Gohman4fc4e422016-10-24 19:49:43 +0000303 MI.getOperand(0).setReg(NewReg);
Heejin Ahn4d98dfb2018-12-29 02:42:04 +0000304 // This register operand of the original instruction is now being used
Thomas Lively6a87dda2019-01-08 06:25:55 +0000305 // by the inserted drop or local.set instruction, so make it not dead
Heejin Ahn4d98dfb2018-12-29 02:42:04 +0000306 // yet.
Heejin Ahn891a7472018-06-19 20:30:42 +0000307 MI.getOperand(0).setIsDead(false);
Dan Gohman4fc4e422016-10-24 19:49:43 +0000308 MFI.stackifyVReg(NewReg);
309 Changed = true;
310 }
311 }
312
Thomas Lively6a87dda2019-01-08 06:25:55 +0000313 // Insert local.gets for any uses that aren't stackified yet.
Dan Gohman4fc4e422016-10-24 19:49:43 +0000314 MachineInstr *InsertPt = &MI;
315 for (MachineOperand &MO : reverse(MI.explicit_uses())) {
316 if (!MO.isReg())
317 continue;
318
Daniel Sanders05c145d2019-08-12 22:40:45 +0000319 Register OldReg = MO.getReg();
Dan Gohman4fc4e422016-10-24 19:49:43 +0000320
Dan Gohmanb465aa02017-11-08 19:18:08 +0000321 // Inline asm may have a def in the middle of the operands. Our contract
322 // with inline asm register operands is to provide local indices as
323 // immediates.
324 if (MO.isDef()) {
Craig Topperc45e39b2019-02-04 21:24:13 +0000325 assert(MI.isInlineAsm());
Dan Gohmanb465aa02017-11-08 19:18:08 +0000326 unsigned LocalId = getLocalId(Reg2Local, CurLocal, OldReg);
Heejin Ahn300f42f2018-09-12 21:34:39 +0000327 // If this register operand is tied to another operand, we can't
328 // change it to an immediate. Untie it first.
329 MI.untieRegOperand(MI.getOperandNo(&MO));
Dan Gohman045a2172018-09-04 17:46:12 +0000330 MO.ChangeToImmediate(LocalId);
Dan Gohmanb465aa02017-11-08 19:18:08 +0000331 continue;
332 }
333
Dan Gohman4fc4e422016-10-24 19:49:43 +0000334 // If we see a stackified register, prepare to insert subsequent
Thomas Lively6a87dda2019-01-08 06:25:55 +0000335 // local.gets before the start of its tree.
Dan Gohman4fc4e422016-10-24 19:49:43 +0000336 if (MFI.isVRegStackified(OldReg)) {
Wouter van Oortmerssen8a9cb242018-08-27 15:45:51 +0000337 InsertPt = findStartOfTree(MO, MRI, MFI);
Dan Gohman4fc4e422016-10-24 19:49:43 +0000338 continue;
339 }
340
Dan Gohmanb465aa02017-11-08 19:18:08 +0000341 // Our contract with inline asm register operands is to provide local
342 // indices as immediates.
Craig Topperc45e39b2019-02-04 21:24:13 +0000343 if (MI.isInlineAsm()) {
Dan Gohmanb465aa02017-11-08 19:18:08 +0000344 unsigned LocalId = getLocalId(Reg2Local, CurLocal, OldReg);
Heejin Ahn300f42f2018-09-12 21:34:39 +0000345 // Untie it first if this reg operand is tied to another operand.
346 MI.untieRegOperand(MI.getOperandNo(&MO));
Dan Gohman045a2172018-09-04 17:46:12 +0000347 MO.ChangeToImmediate(LocalId);
Dan Gohmanb465aa02017-11-08 19:18:08 +0000348 continue;
349 }
350
Thomas Lively6a87dda2019-01-08 06:25:55 +0000351 // Insert a local.get.
Dan Gohman4fc4e422016-10-24 19:49:43 +0000352 unsigned LocalId = getLocalId(Reg2Local, CurLocal, OldReg);
353 const TargetRegisterClass *RC = MRI.getRegClass(OldReg);
Daniel Sanders05c145d2019-08-12 22:40:45 +0000354 Register NewReg = MRI.createVirtualRegister(RC);
Heejin Ahn34dc1f22019-03-19 05:07:33 +0000355 unsigned Opc = getLocalGetOpcode(RC);
Dan Gohman4fc4e422016-10-24 19:49:43 +0000356 InsertPt =
357 BuildMI(MBB, InsertPt, MI.getDebugLoc(), TII->get(Opc), NewReg)
358 .addImm(LocalId);
359 MO.setReg(NewReg);
360 MFI.stackifyVReg(NewReg);
361 Changed = true;
362 }
363
364 // Coalesce and eliminate COPY instructions.
Wouter van Oortmerssend8ddf832019-07-12 22:08:25 +0000365 if (WebAssembly::isCopy(MI.getOpcode())) {
Dan Gohman4fc4e422016-10-24 19:49:43 +0000366 MRI.replaceRegWith(MI.getOperand(1).getReg(),
367 MI.getOperand(0).getReg());
368 MI.eraseFromParent();
369 Changed = true;
370 }
371 }
372 }
373
Dan Gohman3acb1872016-10-24 23:27:49 +0000374 // Define the locals.
Dan Gohmand934cb82017-02-24 23:18:00 +0000375 // TODO: Sort the locals for better compression.
376 MFI.setNumLocals(CurLocal - MFI.getParams().size());
Wouter van Oortmerssen8a9cb242018-08-27 15:45:51 +0000377 for (unsigned I = 0, E = MRI.getNumVirtRegs(); I < E; ++I) {
Daniel Sanders2bea69b2019-08-01 23:27:28 +0000378 unsigned Reg = Register::index2VirtReg(I);
Wouter van Oortmerssen8a9cb242018-08-27 15:45:51 +0000379 auto RL = Reg2Local.find(Reg);
380 if (RL == Reg2Local.end() || RL->second < MFI.getParams().size())
Dan Gohman4fc4e422016-10-24 19:49:43 +0000381 continue;
382
Wouter van Oortmerssen8a9cb242018-08-27 15:45:51 +0000383 MFI.setLocal(RL->second - MFI.getParams().size(),
Dan Gohmand934cb82017-02-24 23:18:00 +0000384 typeForRegClass(MRI.getRegClass(Reg)));
Dan Gohman3acb1872016-10-24 23:27:49 +0000385 Changed = true;
Dan Gohman4fc4e422016-10-24 19:49:43 +0000386 }
387
Wouter van Oortmerssena7be3752018-08-13 23:12:49 +0000388#ifndef NDEBUG
389 // Assert that all registers have been stackified at this point.
390 for (const MachineBasicBlock &MBB : MF) {
391 for (const MachineInstr &MI : MBB) {
392 if (MI.isDebugInstr() || MI.isLabel())
393 continue;
394 for (const MachineOperand &MO : MI.explicit_operands()) {
395 assert(
396 (!MO.isReg() || MRI.use_empty(MO.getReg()) ||
397 MFI.isVRegStackified(MO.getReg())) &&
398 "WebAssemblyExplicitLocals failed to stackify a register operand");
399 }
400 }
Wouter van Oortmerssenab26bd02018-08-10 21:32:47 +0000401 }
Wouter van Oortmerssena7be3752018-08-13 23:12:49 +0000402#endif
403
404 return Changed;
Wouter van Oortmerssenab26bd02018-08-10 21:32:47 +0000405}