LLVM  8.0.1
WebAssemblyInstPrinter.cpp
Go to the documentation of this file.
1 //=- WebAssemblyInstPrinter.cpp - WebAssembly assembly instruction printing -=//
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 /// Print MCInst instructions to wasm format.
12 ///
13 //===----------------------------------------------------------------------===//
14 
17 #include "WebAssembly.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  for (auto i = Desc.getNumOperands(), e = MI->getNumOperands(); i < e; ++i) {
57  // FIXME: For CALL_INDIRECT_VOID, don't print a leading comma, because
58  // we have an extra flags operand which is not currently printed, for
59  // compatiblity reasons.
60  if (i != 0 && ((MI->getOpcode() != WebAssembly::CALL_INDIRECT_VOID &&
61  MI->getOpcode() != WebAssembly::CALL_INDIRECT_VOID_S) ||
62  i != Desc.getNumOperands()))
63  OS << ", ";
64  printOperand(MI, i, OS);
65  }
66 
67  // Print any added annotation.
68  printAnnotation(OS, Annot);
69 
70  if (CommentStream) {
71  // Observe any effects on the control flow stack, for use in annotating
72  // control flow label references.
73  unsigned Opc = MI->getOpcode();
74  switch (Opc) {
75  default:
76  break;
77 
78  case WebAssembly::LOOP:
79  case WebAssembly::LOOP_S:
80  printAnnotation(OS, "label" + utostr(ControlFlowCounter) + ':');
81  ControlFlowStack.push_back(std::make_pair(ControlFlowCounter++, true));
82  break;
83 
84  case WebAssembly::BLOCK:
85  case WebAssembly::BLOCK_S:
86  ControlFlowStack.push_back(std::make_pair(ControlFlowCounter++, false));
87  break;
88 
89  case WebAssembly::TRY:
90  case WebAssembly::TRY_S:
91  ControlFlowStack.push_back(std::make_pair(ControlFlowCounter++, false));
92  EHPadStack.push_back(EHPadStackCounter++);
93  LastSeenEHInst = TRY;
94  break;
95 
96  case WebAssembly::END_LOOP:
97  case WebAssembly::END_LOOP_S:
98  if (ControlFlowStack.empty()) {
99  printAnnotation(OS, "End marker mismatch!");
100  } else {
101  ControlFlowStack.pop_back();
102  }
103  break;
104 
106  case WebAssembly::END_BLOCK_S:
107  if (ControlFlowStack.empty()) {
108  printAnnotation(OS, "End marker mismatch!");
109  } else {
111  OS, "label" + utostr(ControlFlowStack.pop_back_val().first) + ':');
112  }
113  break;
114 
115  case WebAssembly::END_TRY:
116  case WebAssembly::END_TRY_S:
117  if (ControlFlowStack.empty()) {
118  printAnnotation(OS, "End marker mismatch!");
119  } else {
121  OS, "label" + utostr(ControlFlowStack.pop_back_val().first) + ':');
122  LastSeenEHInst = END_TRY;
123  }
124  break;
125 
126  case WebAssembly::CATCH_I32:
127  case WebAssembly::CATCH_I32_S:
128  case WebAssembly::CATCH_I64:
129  case WebAssembly::CATCH_I64_S:
130  case WebAssembly::CATCH_ALL:
131  case WebAssembly::CATCH_ALL_S:
132  // There can be multiple catch instructions for one try instruction, so we
133  // print a label only for the first 'catch' label.
134  if (LastSeenEHInst != CATCH) {
135  if (EHPadStack.empty()) {
136  printAnnotation(OS, "try-catch mismatch!");
137  } else {
138  printAnnotation(OS,
139  "catch" + utostr(EHPadStack.pop_back_val()) + ':');
140  }
141  }
142  LastSeenEHInst = CATCH;
143  break;
144  }
145 
146  // Annotate any control flow label references.
147  unsigned NumFixedOperands = Desc.NumOperands;
148  SmallSet<uint64_t, 8> Printed;
149  for (unsigned i = 0, e = MI->getNumOperands(); i < e; ++i) {
150  // See if this operand denotes a basic block target.
151  if (i < NumFixedOperands) {
152  // A non-variable_ops operand, check its type.
154  continue;
155  } else {
156  // A variable_ops operand, which currently can be immediates (used in
157  // br_table) which are basic block targets, or for call instructions
158  // when using -wasm-keep-registers (in which case they are registers,
159  // and should not be processed).
160  if (!MI->getOperand(i).isImm())
161  continue;
162  }
163  uint64_t Depth = MI->getOperand(i).getImm();
164  if (!Printed.insert(Depth).second)
165  continue;
166 
167  if (Opc == WebAssembly::RETHROW || Opc == WebAssembly::RETHROW_S) {
168  if (Depth > EHPadStack.size()) {
169  printAnnotation(OS, "Invalid depth argument!");
170  } else if (Depth == EHPadStack.size()) {
171  // This can happen when rethrow instruction breaks out of all nests
172  // and throws up to the current function's caller.
173  printAnnotation(OS, utostr(Depth) + ": " + "to caller");
174  } else {
175  uint64_t CatchNo = EHPadStack.rbegin()[Depth];
176  printAnnotation(OS, utostr(Depth) + ": " + "down to catch" +
177  utostr(CatchNo));
178  }
179 
180  } else {
181  if (Depth >= ControlFlowStack.size()) {
182  printAnnotation(OS, "Invalid depth argument!");
183  } else {
184  const auto &Pair = ControlFlowStack.rbegin()[Depth];
185  printAnnotation(OS, utostr(Depth) + ": " +
186  (Pair.second ? "up" : "down") + " to label" +
187  utostr(Pair.first));
188  }
189  }
190  }
191  }
192 }
193 
194 static std::string toString(const APFloat &FP) {
195  // Print NaNs with custom payloads specially.
196  if (FP.isNaN() && !FP.bitwiseIsEqual(APFloat::getQNaN(FP.getSemantics())) &&
197  !FP.bitwiseIsEqual(
198  APFloat::getQNaN(FP.getSemantics(), /*Negative=*/true))) {
199  APInt AI = FP.bitcastToAPInt();
200  return std::string(AI.isNegative() ? "-" : "") + "nan:0x" +
201  utohexstr(AI.getZExtValue() &
202  (AI.getBitWidth() == 32 ? INT64_C(0x007fffff)
203  : INT64_C(0x000fffffffffffff)),
204  /*LowerCase=*/true);
205  }
206 
207  // Use C99's hexadecimal floating-point representation.
208  static const size_t BufBytes = 128;
209  char buf[BufBytes];
210  auto Written = FP.convertToHexString(
211  buf, /*hexDigits=*/0, /*upperCase=*/false, APFloat::rmNearestTiesToEven);
212  (void)Written;
213  assert(Written != 0);
214  assert(Written < BufBytes);
215  return buf;
216 }
217 
218 void WebAssemblyInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
219  raw_ostream &O) {
220  const MCOperand &Op = MI->getOperand(OpNo);
221  if (Op.isReg()) {
222  unsigned WAReg = Op.getReg();
223  if (int(WAReg) >= 0)
224  printRegName(O, WAReg);
225  else if (OpNo >= MII.get(MI->getOpcode()).getNumDefs())
226  O << "$pop" << WebAssemblyFunctionInfo::getWARegStackId(WAReg);
227  else if (WAReg != WebAssemblyFunctionInfo::UnusedReg)
228  O << "$push" << WebAssemblyFunctionInfo::getWARegStackId(WAReg);
229  else
230  O << "$drop";
231  // Add a '=' suffix if this is a def.
232  if (OpNo < MII.get(MI->getOpcode()).getNumDefs())
233  O << '=';
234  } else if (Op.isImm()) {
235  O << Op.getImm();
236  } else if (Op.isFPImm()) {
237  const MCInstrDesc &Desc = MII.get(MI->getOpcode());
238  const MCOperandInfo &Info = Desc.OpInfo[OpNo];
240  // TODO: MC converts all floating point immediate operands to double.
241  // This is fine for numeric values, but may cause NaNs to change bits.
242  O << ::toString(APFloat(float(Op.getFPImm())));
243  } else {
245  O << ::toString(APFloat(Op.getFPImm()));
246  }
247  } else {
248  assert(Op.isExpr() && "unknown operand kind in printOperand");
249  Op.getExpr()->print(O, &MAI);
250  }
251 }
252 
253 void WebAssemblyInstPrinter::printBrList(const MCInst *MI, unsigned OpNo,
254  raw_ostream &O) {
255  O << "{";
256  for (unsigned I = OpNo, E = MI->getNumOperands(); I != E; ++I) {
257  if (I != OpNo)
258  O << ", ";
259  O << MI->getOperand(I).getImm();
260  }
261  O << "}";
262 }
263 
265  unsigned OpNo,
266  raw_ostream &O) {
267  int64_t Imm = MI->getOperand(OpNo).getImm();
268  if (Imm == WebAssembly::GetDefaultP2Align(MI->getOpcode()))
269  return;
270  O << ":p2align=" << Imm;
271 }
272 
274  unsigned OpNo,
275  raw_ostream &O) {
276  auto Imm = static_cast<unsigned>(MI->getOperand(OpNo).getImm());
277  if (Imm != wasm::WASM_TYPE_NORESULT)
279 }
280 
281 // We have various enums representing a subset of these types, use this
282 // function to convert any of them to text.
283 const char *llvm::WebAssembly::anyTypeToString(unsigned Ty) {
284  switch (Ty) {
285  case wasm::WASM_TYPE_I32:
286  return "i32";
287  case wasm::WASM_TYPE_I64:
288  return "i64";
289  case wasm::WASM_TYPE_F32:
290  return "f32";
291  case wasm::WASM_TYPE_F64:
292  return "f64";
294  return "v128";
296  return "funcref";
298  return "func";
300  return "except_ref";
302  return "void";
303  default:
304  return "invalid_type";
305  }
306 }
307 
309  return anyTypeToString(static_cast<unsigned>(Ty));
310 }
32-bit floating-point immediates.
void printWebAssemblySignatureOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O)
bool isImm() const
Definition: MCInst.h:59
uint64_t getZExtValue() const
Get zero extended value.
Definition: APInt.h:1563
void printOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O)
This class represents lattice values for constants.
Definition: AllocatorList.h:24
void push_back(const T &Elt)
Definition: SmallVector.h:218
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:164
void printWebAssemblyP2AlignOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O)
bool isReg() const
Definition: MCInst.h:58
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:1155
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:1509
std::string toString(Error E)
Write all error messages (if any) in E to a string.
Definition: Error.h:967
unsigned getNumOperands() const
Return the number of declared MachineOperands for this MachineInstruction.
Definition: MCInstrDesc.h:211
unsigned getReg() const
Returns the register number.
Definition: MCInst.h:65
uint8_t OperandType
Information about the type of the operand.
Definition: MCInstrDesc.h:79
void printBrList(const MCInst *MI, unsigned OpNo, raw_ostream &O)
const MCExpr * getExpr() const
Definition: MCInst.h:96
Analysis containing CSE Info
Definition: CSEInfo.cpp:21
Instances of this class represent a single low-level machine instruction.
Definition: MCInst.h:161
unsigned short NumOperands
Definition: MCInstrDesc.h:167
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
int64_t getImm() const
Definition: MCInst.h:76
bool isNegative() const
Determine sign of this APInt.
Definition: APInt.h:364
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:235
bool isNaN() const
Definition: APFloat.h:1145
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:135
bool isFPImm() const
Definition: MCInst.h:60
This file provides WebAssembly-specific target descriptions.
Interface to description of machine instruction set.
Definition: MCInstrInfo.h:24
bool isExpr() const
Definition: MCInst.h:61
unsigned getNumOperands() const
Definition: MCInst.h:184
unsigned GetDefaultP2Align(unsigned Opcode)
Return the default p2align value for a load or store with the given opcode.
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:181
size_t size() const
Definition: SmallVector.h:53
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:182
LLVM_NODISCARD T pop_back_val()
Definition: SmallVector.h:381
raw_ostream * CommentStream
A stream that comments can be emitted to if desired.
Definition: MCInstPrinter.h:45
std::string utostr(uint64_t X, bool isNeg=false)
Definition: StringExtras.h:224
Class for arbitrary precision integers.
Definition: APInt.h:70
64-bit floating-point immediates.
unsigned int convertToHexString(char *DST, unsigned int HexDigits, bool UpperCase, roundingMode RM) const
Definition: APFloat.h:1137
const MCAsmInfo & MAI
Definition: MCInstPrinter.h:46
This is an instance of a target assembly language printer that converts an MCInst to valid target ass...
Definition: MCInstPrinter.h:40
LLVM_NODISCARD bool empty() const
Definition: SmallVector.h:56
const MCInstrDesc & get(unsigned Opcode) const
Return the machine instruction descriptor that corresponds to the specified instruction opcode...
Definition: MCInstrInfo.h:45
#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:47
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:1112
const MCOperandInfo * OpInfo
Definition: MCInstrDesc.h:175
This class implements an extremely fast bulk output stream that can only output to a stream...
Definition: raw_ostream.h:46
IRTranslator LLVM IR MI
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:49
APInt bitcastToAPInt() const
Definition: APFloat.h:1094
This holds information about one operand of a machine instruction, indicating the register class for ...
Definition: MCInstrDesc.h:67
unsigned getOpcode() const
Definition: MCInst.h:174
const char * typeToString(wasm::ValType Ty)
Instances of this class represent operands of the MCInst class.
Definition: MCInst.h:35
static APFloat getQNaN(const fltSemantics &Sem, bool Negative=false, const APInt *payload=nullptr)
Factory for QNaN values.
Definition: APFloat.h:886
double getFPImm() const
Definition: MCInst.h:86
std::string utohexstr(uint64_t X, bool LowerCase=false)
Definition: StringExtras.h:125
static unsigned getWARegStackId(unsigned Reg)