LLVM  10.0.0svn
WebAssemblyInstPrinter.cpp
Go to the documentation of this file.
1 //=- WebAssemblyInstPrinter.cpp - WebAssembly assembly instruction printing -=//
2 //
3 // 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
6 //
7 //===----------------------------------------------------------------------===//
8 ///
9 /// \file
10 /// Print MCInst instructions to wasm format.
11 ///
12 //===----------------------------------------------------------------------===//
13 
16 #include "WebAssembly.h"
18 #include "WebAssemblyUtilities.h"
19 #include "llvm/ADT/SmallSet.h"
20 #include "llvm/ADT/StringExtras.h"
22 #include "llvm/MC/MCExpr.h"
23 #include "llvm/MC/MCInst.h"
24 #include "llvm/MC/MCInstrInfo.h"
26 #include "llvm/MC/MCSymbol.h"
29 using namespace llvm;
30 
31 #define DEBUG_TYPE "asm-printer"
32 
33 #include "WebAssemblyGenAsmWriter.inc"
34 
36  const MCInstrInfo &MII,
37  const MCRegisterInfo &MRI)
38  : MCInstPrinter(MAI, MII, MRI) {}
39 
41  unsigned RegNo) const {
43  // Note that there's an implicit local.get/local.set here!
44  OS << "$" << RegNo;
45 }
46 
48  StringRef Annot,
49  const MCSubtargetInfo &STI) {
50  // Print the instruction (this uses the AsmStrings from the .td files).
51  printInstruction(MI, OS);
52 
53  // Print any additional variadic operands.
54  const MCInstrDesc &Desc = MII.get(MI->getOpcode());
55  if (Desc.isVariadic()) {
56  if (Desc.getNumOperands() == 0 && MI->getNumOperands() > 0)
57  OS << "\t";
58  for (auto I = Desc.getNumOperands(), E = MI->getNumOperands(); I < E; ++I) {
59  // FIXME: For CALL_INDIRECT_VOID, don't print a leading comma, because
60  // we have an extra flags operand which is not currently printed, for
61  // compatiblity reasons.
62  if (I != 0 && ((MI->getOpcode() != WebAssembly::CALL_INDIRECT_VOID &&
63  MI->getOpcode() != WebAssembly::CALL_INDIRECT_VOID_S) ||
64  I != Desc.getNumOperands()))
65  OS << ", ";
66  printOperand(MI, I, OS);
67  }
68  }
69 
70  // Print any added annotation.
71  printAnnotation(OS, Annot);
72 
73  if (CommentStream) {
74  // Observe any effects on the control flow stack, for use in annotating
75  // control flow label references.
76  unsigned Opc = MI->getOpcode();
77  switch (Opc) {
78  default:
79  break;
80 
81  case WebAssembly::LOOP:
82  case WebAssembly::LOOP_S:
83  printAnnotation(OS, "label" + utostr(ControlFlowCounter) + ':');
84  ControlFlowStack.push_back(std::make_pair(ControlFlowCounter++, true));
85  break;
86 
87  case WebAssembly::BLOCK:
88  case WebAssembly::BLOCK_S:
89  ControlFlowStack.push_back(std::make_pair(ControlFlowCounter++, false));
90  break;
91 
92  case WebAssembly::TRY:
93  case WebAssembly::TRY_S:
94  ControlFlowStack.push_back(std::make_pair(ControlFlowCounter++, false));
95  EHPadStack.push_back(EHPadStackCounter++);
96  LastSeenEHInst = TRY;
97  break;
98 
99  case WebAssembly::END_LOOP:
100  case WebAssembly::END_LOOP_S:
101  if (ControlFlowStack.empty()) {
102  printAnnotation(OS, "End marker mismatch!");
103  } else {
104  ControlFlowStack.pop_back();
105  }
106  break;
107 
109  case WebAssembly::END_BLOCK_S:
110  if (ControlFlowStack.empty()) {
111  printAnnotation(OS, "End marker mismatch!");
112  } else {
114  OS, "label" + utostr(ControlFlowStack.pop_back_val().first) + ':');
115  }
116  break;
117 
118  case WebAssembly::END_TRY:
119  case WebAssembly::END_TRY_S:
120  if (ControlFlowStack.empty()) {
121  printAnnotation(OS, "End marker mismatch!");
122  } else {
124  OS, "label" + utostr(ControlFlowStack.pop_back_val().first) + ':');
125  LastSeenEHInst = END_TRY;
126  }
127  break;
128 
129  case WebAssembly::CATCH:
130  case WebAssembly::CATCH_S:
131  if (EHPadStack.empty()) {
132  printAnnotation(OS, "try-catch mismatch!");
133  } else {
134  printAnnotation(OS, "catch" + utostr(EHPadStack.pop_back_val()) + ':');
135  }
136  break;
137  }
138 
139  // Annotate any control flow label references.
140 
141  // rethrow instruction does not take any depth argument and rethrows to the
142  // nearest enclosing catch scope, if any. If there's no enclosing catch
143  // scope, it throws up to the caller.
144  if (Opc == WebAssembly::RETHROW || Opc == WebAssembly::RETHROW_S) {
145  if (EHPadStack.empty()) {
146  printAnnotation(OS, "to caller");
147  } else {
148  printAnnotation(OS, "down to catch" + utostr(EHPadStack.back()));
149  }
150 
151  } else {
152  unsigned NumFixedOperands = Desc.NumOperands;
153  SmallSet<uint64_t, 8> Printed;
154  for (unsigned I = 0, E = MI->getNumOperands(); I < E; ++I) {
155  // See if this operand denotes a basic block target.
156  if (I < NumFixedOperands) {
157  // A non-variable_ops operand, check its type.
159  continue;
160  } else {
161  // A variable_ops operand, which currently can be immediates (used in
162  // br_table) which are basic block targets, or for call instructions
163  // when using -wasm-keep-registers (in which case they are registers,
164  // and should not be processed).
165  if (!MI->getOperand(I).isImm())
166  continue;
167  }
168  uint64_t Depth = MI->getOperand(I).getImm();
169  if (!Printed.insert(Depth).second)
170  continue;
171  if (Depth >= ControlFlowStack.size()) {
172  printAnnotation(OS, "Invalid depth argument!");
173  } else {
174  const auto &Pair = ControlFlowStack.rbegin()[Depth];
175  printAnnotation(OS, utostr(Depth) + ": " +
176  (Pair.second ? "up" : "down") + " to label" +
177  utostr(Pair.first));
178  }
179  }
180  }
181  }
182 }
183 
184 static std::string toString(const APFloat &FP) {
185  // Print NaNs with custom payloads specially.
186  if (FP.isNaN() && !FP.bitwiseIsEqual(APFloat::getQNaN(FP.getSemantics())) &&
187  !FP.bitwiseIsEqual(
188  APFloat::getQNaN(FP.getSemantics(), /*Negative=*/true))) {
189  APInt AI = FP.bitcastToAPInt();
190  return std::string(AI.isNegative() ? "-" : "") + "nan:0x" +
191  utohexstr(AI.getZExtValue() &
192  (AI.getBitWidth() == 32 ? INT64_C(0x007fffff)
193  : INT64_C(0x000fffffffffffff)),
194  /*LowerCase=*/true);
195  }
196 
197  // Use C99's hexadecimal floating-point representation.
198  static const size_t BufBytes = 128;
199  char Buf[BufBytes];
200  auto Written = FP.convertToHexString(
201  Buf, /*HexDigits=*/0, /*UpperCase=*/false, APFloat::rmNearestTiesToEven);
202  (void)Written;
203  assert(Written != 0);
204  assert(Written < BufBytes);
205  return Buf;
206 }
207 
208 void WebAssemblyInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
209  raw_ostream &O) {
210  const MCOperand &Op = MI->getOperand(OpNo);
211  if (Op.isReg()) {
212  unsigned WAReg = Op.getReg();
213  if (int(WAReg) >= 0)
214  printRegName(O, WAReg);
215  else if (OpNo >= MII.get(MI->getOpcode()).getNumDefs())
216  O << "$pop" << WebAssemblyFunctionInfo::getWARegStackId(WAReg);
217  else if (WAReg != WebAssemblyFunctionInfo::UnusedReg)
218  O << "$push" << WebAssemblyFunctionInfo::getWARegStackId(WAReg);
219  else
220  O << "$drop";
221  // Add a '=' suffix if this is a def.
222  if (OpNo < MII.get(MI->getOpcode()).getNumDefs())
223  O << '=';
224  } else if (Op.isImm()) {
225  O << Op.getImm();
226  } else if (Op.isFPImm()) {
227  const MCInstrDesc &Desc = MII.get(MI->getOpcode());
228  const MCOperandInfo &Info = Desc.OpInfo[OpNo];
230  // TODO: MC converts all floating point immediate operands to double.
231  // This is fine for numeric values, but may cause NaNs to change bits.
232  O << ::toString(APFloat(float(Op.getFPImm())));
233  } else {
235  O << ::toString(APFloat(Op.getFPImm()));
236  }
237  } else {
238  assert(Op.isExpr() && "unknown operand kind in printOperand");
239  // call_indirect instructions have a TYPEINDEX operand that we print
240  // as a signature here, such that the assembler can recover this
241  // information.
242  auto SRE = static_cast<const MCSymbolRefExpr *>(Op.getExpr());
243  if (SRE->getKind() == MCSymbolRefExpr::VK_WASM_TYPEINDEX) {
244  auto &Sym = static_cast<const MCSymbolWasm &>(SRE->getSymbol());
245  O << WebAssembly::signatureToString(Sym.getSignature());
246  } else {
247  Op.getExpr()->print(O, &MAI);
248  }
249  }
250 }
251 
252 void WebAssemblyInstPrinter::printBrList(const MCInst *MI, unsigned OpNo,
253  raw_ostream &O) {
254  O << "{";
255  for (unsigned I = OpNo, E = MI->getNumOperands(); I != E; ++I) {
256  if (I != OpNo)
257  O << ", ";
258  O << MI->getOperand(I).getImm();
259  }
260  O << "}";
261 }
262 
264  unsigned OpNo,
265  raw_ostream &O) {
266  int64_t Imm = MI->getOperand(OpNo).getImm();
267  if (Imm == WebAssembly::GetDefaultP2Align(MI->getOpcode()))
268  return;
269  O << ":p2align=" << Imm;
270 }
271 
273  unsigned OpNo,
274  raw_ostream &O) {
275  const MCOperand &Op = MI->getOperand(OpNo);
276  if (Op.isImm()) {
277  auto Imm = static_cast<unsigned>(Op.getImm());
278  if (Imm != wasm::WASM_TYPE_NORESULT)
280  } else {
281  auto Expr = cast<MCSymbolRefExpr>(Op.getExpr());
282  auto *Sym = cast<MCSymbolWasm>(&Expr->getSymbol());
283  if (Sym->getSignature()) {
284  O << WebAssembly::signatureToString(Sym->getSignature());
285  } else {
286  // Disassembler does not currently produce a signature
287  O << "unknown_type";
288  }
289  }
290 }
291 
292 // We have various enums representing a subset of these types, use this
293 // function to convert any of them to text.
294 const char *WebAssembly::anyTypeToString(unsigned Ty) {
295  switch (Ty) {
296  case wasm::WASM_TYPE_I32:
297  return "i32";
298  case wasm::WASM_TYPE_I64:
299  return "i64";
300  case wasm::WASM_TYPE_F32:
301  return "f32";
302  case wasm::WASM_TYPE_F64:
303  return "f64";
305  return "v128";
307  return "funcref";
309  return "func";
311  return "exnref";
313  return "void";
314  default:
315  return "invalid_type";
316  }
317 }
318 
320  return anyTypeToString(static_cast<unsigned>(Ty));
321 }
322 
324  std::string S;
325  for (auto &Ty : List) {
326  if (&Ty != &List[0]) S += ", ";
327  S += WebAssembly::typeToString(Ty);
328  }
329  return S;
330 }
331 
333  std::string S("(");
334  S += typeListToString(Sig->Params);
335  S += ") -> (";
336  S += typeListToString(Sig->Returns);
337  S += ")";
338  return S;
339 }
32-bit floating-point immediates.
void printWebAssemblySignatureOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O)
bool isImm() const
Definition: MCInst.h:58
uint64_t getZExtValue() const
Get zero extended value.
Definition: APInt.h:1571
void printOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O)
This class represents lattice values for constants.
Definition: AllocatorList.h:23
void push_back(const T &Elt)
Definition: SmallVector.h:211
This class prints an WebAssembly MCInst to wasm file syntax.
Describe properties that are true of each instruction in the target description file.
Definition: MCInstrDesc.h:179
void printWebAssemblyP2AlignOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O)
unsigned GetDefaultP2Align(unsigned Opc)
bool isReg() const
Definition: MCInst.h:57
void printRegName(raw_ostream &OS, unsigned RegNo) const override
Print the assembler register name.
Basic block label in a branch construct.
const char * anyTypeToString(unsigned Ty)
const fltSemantics & getSemantics() const
Definition: APFloat.h:1170
This file contains the entry points for global functions defined in the LLVM WebAssembly back-end...
WebAssemblyInstPrinter(const MCAsmInfo &MAI, const MCInstrInfo &MII, const MCRegisterInfo &MRI)
unsigned getBitWidth() const
Return the number of bits in the APInt.
Definition: APInt.h:1517
std::string toString(Error E)
Write all error messages (if any) in E to a string.
Definition: Error.h:986
unsigned getNumOperands() const
Return the number of declared MachineOperands for this MachineInstruction.
Definition: MCInstrDesc.h:226
SmallVector< ValType, 1 > Returns
Definition: Wasm.h:355
std::string signatureToString(const wasm::WasmSignature *Sig)
Represent a reference to a symbol from inside an expression.
Definition: MCExpr.h:169
unsigned getReg() const
Returns the register number.
Definition: MCInst.h:64
SmallVector< ValType, 4 > Params
Definition: Wasm.h:356
uint8_t OperandType
Information about the type of the operand.
Definition: MCInstrDesc.h:82
void printBrList(const MCInst *MI, unsigned OpNo, raw_ostream &O)
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory)...
Definition: APInt.h:32
const MCExpr * getExpr() const
Definition: MCInst.h:95
Analysis containing CSE Info
Definition: CSEInfo.cpp:20
Instances of this class represent a single low-level machine instruction.
Definition: MCInst.h:158
unsigned short NumOperands
Definition: MCInstrDesc.h:182
MCRegisterInfo base class - We assume that the target defines a static array of MCRegisterDesc object...
This class is intended to be used as a base class for asm properties and features specific to the tar...
Definition: MCAsmInfo.h:56
This file contains the declaration of the WebAssembly-specific utility functions. ...
int64_t getImm() const
Definition: MCInst.h:75
bool isNegative() const
Determine sign of this APInt.
Definition: APInt.h:363
void print(raw_ostream &OS, const MCAsmInfo *MAI, bool InParens=false) const
Definition: MCExpr.cpp:42
unsigned const MachineRegisterInfo * MRI
bool isVariadic() const
Return true if this instruction can have a variable number of operands.
Definition: MCInstrDesc.h:254
bool isNaN() const
Definition: APFloat.h:1160
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
SmallSet - This maintains a set of unique values, optimizing for the case when the set is small (less...
Definition: SmallSet.h:134
bool isFPImm() const
Definition: MCInst.h:59
This file provides WebAssembly-specific target descriptions.
std::string typeListToString(ArrayRef< wasm::ValType > List)
Interface to description of machine instruction set.
Definition: MCInstrInfo.h:23
bool isExpr() const
Definition: MCInst.h:60
unsigned getNumOperands() const
Definition: MCInst.h:181
std::pair< NoneType, bool > insert(const T &V)
insert - Insert an element into the set if it isn&#39;t already there.
Definition: SmallSet.h:180
size_t size() const
Definition: SmallVector.h:52
void printInst(const MCInst *MI, raw_ostream &OS, StringRef Annot, const MCSubtargetInfo &STI) override
Print the specified MCInst to the specified raw_ostream.
const MCOperand & getOperand(unsigned i) const
Definition: MCInst.h:179
LLVM_NODISCARD T pop_back_val()
Definition: SmallVector.h:374
raw_ostream * CommentStream
A stream that comments can be emitted to if desired.
Definition: MCInstPrinter.h:44
std::string utostr(uint64_t X, bool isNeg=false)
Definition: StringExtras.h:223
Class for arbitrary precision integers.
Definition: APInt.h:69
64-bit floating-point immediates.
unsigned int convertToHexString(char *DST, unsigned int HexDigits, bool UpperCase, roundingMode RM) const
Definition: APFloat.h:1152
const MCAsmInfo & MAI
Definition: MCInstPrinter.h:45
This is an instance of a target assembly language printer that converts an MCInst to valid target ass...
Definition: MCInstPrinter.h:39
LLVM_NODISCARD bool empty() const
Definition: SmallVector.h:55
const MCInstrDesc & get(unsigned Opcode) const
Return the machine instruction descriptor that corresponds to the specified instruction opcode...
Definition: MCInstrInfo.h:44
const NodeList & List
Definition: RDFGraph.cpp:201
#define I(x, y, z)
Definition: MD5.cpp:58
This file declares WebAssembly-specific per-machine-function information.
Generic base class for all target subtargets.
const MCInstrInfo & MII
Definition: MCInstPrinter.h:46
void printInstruction(const MCInst *MI, raw_ostream &O)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
void printAnnotation(raw_ostream &OS, StringRef Annot)
Utility function for printing annotations.
bool bitwiseIsEqual(const APFloat &RHS) const
Definition: APFloat.h:1127
const MCOperandInfo * OpInfo
Definition: MCInstrDesc.h:190
This class implements an extremely fast bulk output stream that can only output to a stream...
Definition: raw_ostream.h:45
IRTranslator LLVM IR MI
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:48
APInt bitcastToAPInt() const
Definition: APFloat.h:1109
This holds information about one operand of a machine instruction, indicating the register class for ...
Definition: MCInstrDesc.h:70
unsigned getOpcode() const
Definition: MCInst.h:171
const char * typeToString(wasm::ValType Ty)
Instances of this class represent operands of the MCInst class.
Definition: MCInst.h:34
static APFloat getQNaN(const fltSemantics &Sem, bool Negative=false, const APInt *payload=nullptr)
Factory for QNaN values.
Definition: APFloat.h:901
double getFPImm() const
Definition: MCInst.h:85
std::string utohexstr(uint64_t X, bool LowerCase=false)
Definition: StringExtras.h:124
static unsigned getWARegStackId(unsigned Reg)