LLVM  8.0.1
WebAssemblyExplicitLocals.cpp
Go to the documentation of this file.
1 //===-- WebAssemblyExplicitLocals.cpp - Make Locals Explicit --------------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 ///
10 /// \file
11 /// This file converts any remaining registers into WebAssembly locals.
12 ///
13 /// After register stackification and register coloring, convert non-stackified
14 /// registers into locals, inserting explicit local.get and local.set
15 /// instructions.
16 ///
17 //===----------------------------------------------------------------------===//
18 
20 #include "WebAssembly.h"
22 #include "WebAssemblySubtarget.h"
23 #include "WebAssemblyUtilities.h"
27 #include "llvm/CodeGen/Passes.h"
28 #include "llvm/Support/Debug.h"
30 using namespace llvm;
31 
32 #define DEBUG_TYPE "wasm-explicit-locals"
33 
34 // 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.
39  "wasm-disable-explicit-locals", cl::Hidden,
40  cl::desc("WebAssembly: output implicit locals in"
41  " instruction output for test purposes only."),
42  cl::init(false));
43 
44 namespace {
45 class 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();
54  }
55 
56  bool runOnMachineFunction(MachineFunction &MF) override;
57 
58 public:
59  static char ID; // Pass identification, replacement for typeid
60  WebAssemblyExplicitLocals() : MachineFunctionPass(ID) {}
61 };
62 } // end anonymous namespace
63 
65 INITIALIZE_PASS(WebAssemblyExplicitLocals, DEBUG_TYPE,
66  "Convert registers to WebAssembly locals", false, false)
67 
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.
74 static unsigned getLocalId(DenseMap<unsigned, unsigned> &Reg2Local,
75  unsigned &CurLocal, unsigned Reg) {
76  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.
83 static 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;
94  if (RC == &WebAssembly::EXCEPT_REFRegClass)
95  return WebAssembly::DROP_EXCEPT_REF;
96  llvm_unreachable("Unexpected register class");
97 }
98 
99 /// Get the appropriate local.get opcode for the given register class.
100 static unsigned getGetLocalOpcode(const TargetRegisterClass *RC) {
101  if (RC == &WebAssembly::I32RegClass)
102  return WebAssembly::LOCAL_GET_I32;
103  if (RC == &WebAssembly::I64RegClass)
104  return WebAssembly::LOCAL_GET_I64;
105  if (RC == &WebAssembly::F32RegClass)
106  return WebAssembly::LOCAL_GET_F32;
107  if (RC == &WebAssembly::F64RegClass)
108  return WebAssembly::LOCAL_GET_F64;
109  if (RC == &WebAssembly::V128RegClass)
110  return WebAssembly::LOCAL_GET_V128;
111  if (RC == &WebAssembly::EXCEPT_REFRegClass)
112  return WebAssembly::LOCAL_GET_EXCEPT_REF;
113  llvm_unreachable("Unexpected register class");
114 }
115 
116 /// Get the appropriate local.set opcode for the given register class.
117 static unsigned getSetLocalOpcode(const TargetRegisterClass *RC) {
118  if (RC == &WebAssembly::I32RegClass)
119  return WebAssembly::LOCAL_SET_I32;
120  if (RC == &WebAssembly::I64RegClass)
121  return WebAssembly::LOCAL_SET_I64;
122  if (RC == &WebAssembly::F32RegClass)
123  return WebAssembly::LOCAL_SET_F32;
124  if (RC == &WebAssembly::F64RegClass)
125  return WebAssembly::LOCAL_SET_F64;
126  if (RC == &WebAssembly::V128RegClass)
127  return WebAssembly::LOCAL_SET_V128;
128  if (RC == &WebAssembly::EXCEPT_REFRegClass)
129  return WebAssembly::LOCAL_SET_EXCEPT_REF;
130  llvm_unreachable("Unexpected register class");
131 }
132 
133 /// Get the appropriate local.tee opcode for the given register class.
134 static unsigned getTeeLocalOpcode(const TargetRegisterClass *RC) {
135  if (RC == &WebAssembly::I32RegClass)
136  return WebAssembly::LOCAL_TEE_I32;
137  if (RC == &WebAssembly::I64RegClass)
138  return WebAssembly::LOCAL_TEE_I64;
139  if (RC == &WebAssembly::F32RegClass)
140  return WebAssembly::LOCAL_TEE_F32;
141  if (RC == &WebAssembly::F64RegClass)
142  return WebAssembly::LOCAL_TEE_F64;
143  if (RC == &WebAssembly::V128RegClass)
144  return WebAssembly::LOCAL_TEE_V128;
145  if (RC == &WebAssembly::EXCEPT_REFRegClass)
146  return WebAssembly::LOCAL_TEE_EXCEPT_REF;
147  llvm_unreachable("Unexpected register class");
148 }
149 
150 /// Get the type associated with the given register class.
152  if (RC == &WebAssembly::I32RegClass)
153  return MVT::i32;
154  if (RC == &WebAssembly::I64RegClass)
155  return MVT::i64;
156  if (RC == &WebAssembly::F32RegClass)
157  return MVT::f32;
158  if (RC == &WebAssembly::F64RegClass)
159  return MVT::f64;
160  if (RC == &WebAssembly::V128RegClass)
161  return MVT::v16i8;
162  if (RC == &WebAssembly::EXCEPT_REFRegClass)
163  return MVT::ExceptRef;
164  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.
172  unsigned Reg = MO.getReg();
173  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;
180  return findStartOfTree(DefMO, MRI, MFI);
181  }
182 
183  // If there were no stackified uses, we've reached the start.
184  return Def;
185 }
186 
187 bool WebAssemblyExplicitLocals::runOnMachineFunction(MachineFunction &MF) {
188  LLVM_DEBUG(dbgs() << "********** Make Locals Explicit **********\n"
189  "********** Function: "
190  << MF.getName() << '\n');
191 
192  // Disable this pass if directed to do so.
194  return false;
195 
196  bool Changed = false;
199  const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
200 
201  // Map non-stackified virtual registers to their local ids.
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++;
209  if (!WebAssembly::isArgument(MI))
210  break;
211  unsigned Reg = MI.getOperand(0).getReg();
212  assert(!MFI.isVRegStackified(Reg));
213  Reg2Local[Reg] = static_cast<unsigned>(MI.getOperand(1).getImm());
214  MI.eraseFromParent();
215  Changed = true;
216  }
217 
218  // Start assigning local numbers after the last parameter.
219  unsigned CurLocal = static_cast<unsigned>(MFI.getParams().size());
220 
221  // Precompute the set of registers that are unused, so that we can insert
222  // drops to their defs.
223  BitVector UseEmpty(MRI.getNumVirtRegs());
224  for (unsigned I = 0, E = MRI.getNumVirtRegs(); I < E; ++I)
226 
227  // 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++;
232 
233  if (MI.isDebugInstr() || MI.isLabel())
234  continue;
235 
236  // Replace tee instructions with local.tee. The difference is that tee
237  // instructions have two defs, while local.tee instructions have one def
238  // and an index of a local to write to.
239  if (WebAssembly::isTee(MI)) {
241  assert(!MFI.isVRegStackified(MI.getOperand(1).getReg()));
242  unsigned OldReg = MI.getOperand(2).getReg();
243  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);
248  unsigned NewReg = MRI.createVirtualRegister(RC);
249  unsigned Opc = getGetLocalOpcode(RC);
250  BuildMI(MBB, &MI, MI.getDebugLoc(), TII->get(Opc), NewReg)
251  .addImm(LocalId);
252  MI.getOperand(2).setReg(NewReg);
253  MFI.stackifyVReg(NewReg);
254  }
255 
256  // Replace the TEE with a LOCAL_TEE.
257  unsigned LocalId =
258  getLocalId(Reg2Local, CurLocal, MI.getOperand(1).getReg());
259  unsigned Opc = getTeeLocalOpcode(RC);
260  BuildMI(MBB, &MI, MI.getDebugLoc(), TII->get(Opc),
261  MI.getOperand(0).getReg())
262  .addImm(LocalId)
263  .addReg(MI.getOperand(2).getReg());
264 
265  MI.eraseFromParent();
266  Changed = true;
267  continue;
268  }
269 
270  // Insert local.sets for any defs that aren't stackified yet. Currently
271  // we handle at most one def.
272  assert(MI.getDesc().getNumDefs() <= 1);
273  if (MI.getDesc().getNumDefs() == 1) {
274  unsigned OldReg = MI.getOperand(0).getReg();
275  if (!MFI.isVRegStackified(OldReg)) {
276  const TargetRegisterClass *RC = MRI.getRegClass(OldReg);
277  unsigned NewReg = MRI.createVirtualRegister(RC);
278  auto InsertPt = std::next(MachineBasicBlock::iterator(&MI));
279  if (MI.getOpcode() == WebAssembly::IMPLICIT_DEF) {
280  MI.eraseFromParent();
281  Changed = true;
282  continue;
283  }
284  if (UseEmpty[TargetRegisterInfo::virtReg2Index(OldReg)]) {
285  unsigned Opc = getDropOpcode(RC);
286  MachineInstr *Drop =
287  BuildMI(MBB, InsertPt, MI.getDebugLoc(), TII->get(Opc))
288  .addReg(NewReg);
289  // After the drop instruction, this reg operand will not be used
290  Drop->getOperand(0).setIsKill();
291  } else {
292  unsigned LocalId = getLocalId(Reg2Local, CurLocal, OldReg);
293  unsigned Opc = getSetLocalOpcode(RC);
294  BuildMI(MBB, InsertPt, MI.getDebugLoc(), TII->get(Opc))
295  .addImm(LocalId)
296  .addReg(NewReg);
297  }
298  MI.getOperand(0).setReg(NewReg);
299  // This register operand of the original instruction is now being used
300  // by the inserted drop or local.set instruction, so make it not dead
301  // yet.
302  MI.getOperand(0).setIsDead(false);
303  MFI.stackifyVReg(NewReg);
304  Changed = true;
305  }
306  }
307 
308  // Insert local.gets for any uses that aren't stackified yet.
309  MachineInstr *InsertPt = &MI;
310  for (MachineOperand &MO : reverse(MI.explicit_uses())) {
311  if (!MO.isReg())
312  continue;
313 
314  unsigned OldReg = MO.getReg();
315 
316  // Inline asm may have a def in the middle of the operands. Our contract
317  // with inline asm register operands is to provide local indices as
318  // immediates.
319  if (MO.isDef()) {
321  unsigned LocalId = getLocalId(Reg2Local, CurLocal, OldReg);
322  // If this register operand is tied to another operand, we can't
323  // change it to an immediate. Untie it first.
324  MI.untieRegOperand(MI.getOperandNo(&MO));
325  MO.ChangeToImmediate(LocalId);
326  continue;
327  }
328 
329  // If we see a stackified register, prepare to insert subsequent
330  // local.gets before the start of its tree.
331  if (MFI.isVRegStackified(OldReg)) {
332  InsertPt = findStartOfTree(MO, MRI, MFI);
333  continue;
334  }
335 
336  // Our contract with inline asm register operands is to provide local
337  // indices as immediates.
338  if (MI.getOpcode() == TargetOpcode::INLINEASM) {
339  unsigned LocalId = getLocalId(Reg2Local, CurLocal, OldReg);
340  // Untie it first if this reg operand is tied to another operand.
341  MI.untieRegOperand(MI.getOperandNo(&MO));
342  MO.ChangeToImmediate(LocalId);
343  continue;
344  }
345 
346  // Insert a local.get.
347  unsigned LocalId = getLocalId(Reg2Local, CurLocal, OldReg);
348  const TargetRegisterClass *RC = MRI.getRegClass(OldReg);
349  unsigned NewReg = MRI.createVirtualRegister(RC);
350  unsigned Opc = getGetLocalOpcode(RC);
351  InsertPt =
352  BuildMI(MBB, InsertPt, MI.getDebugLoc(), TII->get(Opc), NewReg)
353  .addImm(LocalId);
354  MO.setReg(NewReg);
355  MFI.stackifyVReg(NewReg);
356  Changed = true;
357  }
358 
359  // Coalesce and eliminate COPY instructions.
360  if (WebAssembly::isCopy(MI)) {
361  MRI.replaceRegWith(MI.getOperand(1).getReg(),
362  MI.getOperand(0).getReg());
363  MI.eraseFromParent();
364  Changed = true;
365  }
366  }
367  }
368 
369  // Define the locals.
370  // TODO: Sort the locals for better compression.
371  MFI.setNumLocals(CurLocal - MFI.getParams().size());
372  for (unsigned I = 0, E = MRI.getNumVirtRegs(); I < E; ++I) {
374  auto RL = Reg2Local.find(Reg);
375  if (RL == Reg2Local.end() || RL->second < MFI.getParams().size())
376  continue;
377 
378  MFI.setLocal(RL->second - MFI.getParams().size(),
379  typeForRegClass(MRI.getRegClass(Reg)));
380  Changed = true;
381  }
382 
383 #ifndef NDEBUG
384  // Assert that all registers have been stackified at this point.
385  for (const MachineBasicBlock &MBB : MF) {
386  for (const MachineInstr &MI : MBB) {
387  if (MI.isDebugInstr() || MI.isLabel())
388  continue;
389  for (const MachineOperand &MO : MI.explicit_operands()) {
390  assert(
391  (!MO.isReg() || MRI.use_empty(MO.getReg()) ||
392  MFI.isVRegStackified(MO.getReg())) &&
393  "WebAssemblyExplicitLocals failed to stackify a register operand");
394  }
395  }
396  }
397 #endif
398 
399  return Changed;
400 }
static unsigned getLocalId(DenseMap< unsigned, unsigned > &Reg2Local, unsigned &CurLocal, unsigned Reg)
Return a local id number for the given register, assigning it a new one if it doesn&#39;t yet have one...
AnalysisUsage & addPreserved()
Add the specified Pass class to the set of analyses preserved by this pass.
bool isLabel() const
Returns true if the MachineInstr represents a label.
Definition: MachineInstr.h:986
const TargetRegisterClass * getRegClass(unsigned Reg) const
Return the register class of the specified virtual register.
static unsigned virtReg2Index(unsigned Reg)
Convert a virtual register number to a 0-based index.
This class represents lattice values for constants.
Definition: AllocatorList.h:24
static unsigned index2VirtReg(unsigned Index)
Convert a 0-based index to a virtual register number.
const DebugLoc & getDebugLoc() const
Returns the debug location id of this MachineInstr.
Definition: MachineInstr.h:383
unsigned getReg() const
getReg - Returns the register number.
unsigned getOperandNo(const_mop_iterator I) const
Returns the number of the operand iterator I points to.
Definition: MachineInstr.h:509
unsigned Reg
MachineBlockFrequencyInfo pass uses BlockFrequencyInfoImpl implementation to estimate machine basic b...
void setIsDead(bool Val=true)
static unsigned getSetLocalOpcode(const TargetRegisterClass *RC)
Get the appropriate local.set opcode for the given register class.
This file contains the entry points for global functions defined in the LLVM WebAssembly back-end...
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
Definition: DenseMap.h:221
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
const HexagonInstrInfo * TII
void eraseFromParent()
Unlink &#39;this&#39; from the containing basic block and delete it.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
Definition: MachineInstr.h:409
INLINEASM - Represents an inline asm block.
Definition: ISDOpcodes.h:667
MachineInstr * getVRegDef(unsigned Reg) const
getVRegDef - Return the machine instr that defines the specified virtual register or null if none is ...
auto reverse(ContainerTy &&C, typename std::enable_if< has_rbegin< ContainerTy >::value >::type *=nullptr) -> decltype(make_range(C.rbegin(), C.rend()))
Definition: STLExtras.h:267
static unsigned getDropOpcode(const TargetRegisterClass *RC)
Get the appropriate drop opcode for the given register class.
const MCInstrDesc & getDesc() const
Returns the target instruction descriptor of this MachineInstr.
Definition: MachineInstr.h:406
void untieRegOperand(unsigned OpIdx)
Break any tie involving OpIdx.
bool isCopy(const MachineInstr &MI)
StringRef getName() const
getName - Return the name of the corresponding LLVM function.
iterator find(const_arg_type_t< KeyT > Val)
Definition: DenseMap.h:176
This file contains the declaration of the WebAssembly-specific utility functions. ...
MachineInstrBuilder BuildMI(MachineFunction &MF, const DebugLoc &DL, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
#define P(N)
initializer< Ty > init(const Ty &Val)
Definition: CommandLine.h:423
unsigned const MachineRegisterInfo * MRI
#define DEBUG_TYPE
Machine Value Type.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
This file provides WebAssembly-specific target descriptions.
Represent the analysis usage information of a pass.
Ty * getInfo()
getInfo - Keep track of various per-function pieces of information for backends that would like to do...
static unsigned getGetLocalOpcode(const TargetRegisterClass *RC)
Get the appropriate local.get opcode for the given register class.
FunctionPass class - This class is used to implement most global optimizations.
Definition: Pass.h:285
unsigned getNumVirtRegs() const
getNumVirtRegs - Return the number of virtual registers created.
bool isDebugInstr() const
Definition: MachineInstr.h:999
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
iterator_range< mop_iterator > explicit_uses()
Definition: MachineInstr.h:499
void setIsKill(bool Val=true)
This file declares the WebAssembly-specific subclass of TargetSubtarget.
bool isTee(const MachineInstr &MI)
bool isArgument(const MachineInstr &MI)
MachineOperand class - Representation of each machine instruction operand.
unsigned getNumDefs() const
Return the number of MachineOperands that are register definitions.
Definition: MCInstrDesc.h:226
void setPreservesCFG()
This function should be called by the pass, iff they do not:
Definition: Pass.cpp:286
int64_t getImm() const
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:133
static unsigned getTeeLocalOpcode(const TargetRegisterClass *RC)
Get the appropriate local.tee opcode for the given register class.
INITIALIZE_PASS(WebAssemblyExplicitLocals, DEBUG_TYPE, "Convert registers to WebAssembly locals", false, false) FunctionPass *llvm
bool use_empty(unsigned RegNo) const
use_empty - Return true if there are no instructions using the specified register.
static MachineInstr * findStartOfTree(MachineOperand &MO, MachineRegisterInfo &MRI, WebAssemblyFunctionInfo &MFI)
Given a MachineOperand of a stackified vreg, return the instruction at the start of the expression tr...
void replaceRegWith(unsigned FromReg, unsigned ToReg)
replaceRegWith - Replace all instances of FromReg with ToReg in the machine function.
MachineRegisterInfo - Keep track of information for virtual and physical registers, including vreg register classes, use/def chains for registers, etc.
Representation of each machine instruction.
Definition: MachineInstr.h:64
This class is derived from MachineFunctionInfo and contains private WebAssembly-specific information ...
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
void setReg(unsigned Reg)
Change the register this operand corresponds to.
#define I(x, y, z)
Definition: MD5.cpp:58
This file declares WebAssembly-specific per-machine-function information.
iterator end()
Definition: DenseMap.h:109
const MachineInstrBuilder & addReg(unsigned RegNo, unsigned flags=0, unsigned SubReg=0) const
Add a new virtual register operand.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
static MVT typeForRegClass(const TargetRegisterClass *RC)
Get the type associated with the given register class.
IRTranslator LLVM IR MI
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:49
const std::vector< MVT > & getParams() const
static cl::opt< bool > WasmDisableExplicitLocals("wasm-disable-explicit-locals", cl::Hidden, cl::desc("WebAssembly: output implicit locals in" " instruction output for test purposes only."), cl::init(false))
#define LLVM_DEBUG(X)
Definition: Debug.h:123
const MachineOperand & getOperand(unsigned i) const
Definition: MachineInstr.h:414
FunctionPass * createWebAssemblyExplicitLocals()
unsigned createVirtualRegister(const TargetRegisterClass *RegClass, StringRef Name="")
createVirtualRegister - Create and return a new virtual register in the function with the specified r...