LLVM 24.0.0git
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
18#include "llvm/ADT/APFloat.h"
19#include "llvm/ADT/SmallSet.h"
21#include "llvm/MC/MCAsmInfo.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"
30using namespace llvm;
31
32#define DEBUG_TYPE "asm-printer"
33
34#include "WebAssemblyGenAsmWriter.inc"
35
40
42 assert(Reg.id() != WebAssembly::UnusedReg);
43 // Note that there's an implicit local.get/local.set here!
44 OS << "$" << Reg.id();
45}
46
48 StringRef Annot,
49 const MCSubtargetInfo &STI,
50 raw_ostream &OS) {
51 unsigned TypeOperand = 0;
52 unsigned TableOperand = 1;
53 switch (MI->getOpcode()) {
54 case WebAssembly::CALL_INDIRECT: {
55 unsigned NumDefs = MI->getOperand(0).getImm();
56 TypeOperand = NumDefs + 1;
57 TableOperand = NumDefs + 2;
58 [[fallthrough]];
59 }
60 case WebAssembly::RET_CALL_INDIRECT:
61 case WebAssembly::CALL_INDIRECT_S:
62 case WebAssembly::RET_CALL_INDIRECT_S: {
63 // A special case for call_indirect (and ret_call_indirect): the order of
64 // the type and table operands is inverted in the text format relative to
65 // the binary format. The table operand is omitted when it refers to the
66 // default table 0 of an MVP compilation unit. Otherwise (a table symbol,
67 // or a non-zero table index from a multi-table module) it is printed
68 // first. A disassembler can also hand us an arbitrary immediate here when
69 // decoding misaligned bytes, so print it rather than asserting.
70 OS << "\t";
71 OS << getMnemonic(*MI).first;
72 OS << " ";
73 const MCOperand &TableOp = MI->getOperand(TableOperand);
74 if (TableOp.isExpr() || (TableOp.isImm() && TableOp.getImm() != 0)) {
75 printOperand(MI, TableOperand, STI, OS);
76 OS << ", ";
77 }
78 printOperand(MI, TypeOperand, STI, OS);
79 if (MI->getOpcode() == WebAssembly::CALL_INDIRECT)
80 OS << ", ";
81 break;
82 }
83 default:
84 // Print the instruction (this uses the AsmStrings from the .td files).
85 printInstruction(MI, Address, STI, OS);
86 break;
87 }
88
89 // Print any additional variadic operands.
90 const MCInstrDesc &Desc = MII.get(MI->getOpcode());
91 if (Desc.isVariadic()) {
92 if ((Desc.getNumOperands() == 0 && MI->getNumOperands() > 0) ||
93 Desc.variadicOpsAreDefs())
94 OS << "\t";
95 unsigned Start = Desc.getNumOperands();
96 unsigned NumVariadicDefs = 0;
97 if (Desc.variadicOpsAreDefs()) {
98 // The number of variadic defs is encoded in an immediate by MCInstLower
99 NumVariadicDefs = MI->getOperand(0).getImm();
100 Start = 1;
101 }
102 bool NeedsComma = Desc.getNumOperands() > 0 && !Desc.variadicOpsAreDefs();
103 for (auto I = Start, E = MI->getNumOperands(); I < E; ++I) {
104 if (MI->getOpcode() == WebAssembly::CALL_INDIRECT &&
105 I - Start == NumVariadicDefs) {
106 // Skip type and table arguments when printing for tests.
107 ++I;
108 continue;
109 }
110 if (NeedsComma)
111 OS << ", ";
112 printOperand(MI, I, STI, OS, I - Start < NumVariadicDefs);
113 NeedsComma = true;
114 }
115 }
116
117 // Print any added annotation.
118 printAnnotation(OS, Annot);
119
120 auto PrintBranchAnnotation = [&](const MCOperand &Op,
121 SmallSet<uint64_t, 8> &Printed) {
122 uint64_t Depth = Op.getImm();
123 if (!Printed.insert(Depth).second)
124 return;
125 if (Depth >= ControlFlowStack.size()) {
126 printAnnotation(OS, "Invalid depth argument!");
127 } else {
128 const auto &Pair = ControlFlowStack.rbegin()[Depth];
129 printAnnotation(OS, utostr(Depth) + ": " + (Pair.second ? "up" : "down") +
130 " to label" + utostr(Pair.first));
131 }
132 };
133
134 if (CommentStream) {
135 // Observe any effects on the control flow stack, for use in annotating
136 // control flow label references.
137 unsigned Opc = MI->getOpcode();
138 switch (Opc) {
139 default:
140 break;
141
142 case WebAssembly::LOOP:
143 case WebAssembly::LOOP_S:
144 printAnnotation(OS, "label" + utostr(ControlFlowCounter) + ':');
145 ControlFlowStack.push_back(std::make_pair(ControlFlowCounter++, true));
146 return;
147
148 case WebAssembly::BLOCK:
149 case WebAssembly::BLOCK_S:
150 ControlFlowStack.push_back(std::make_pair(ControlFlowCounter++, false));
151 return;
152
153 case WebAssembly::TRY:
154 case WebAssembly::TRY_S:
155 ControlFlowStack.push_back(std::make_pair(ControlFlowCounter, false));
156 TryStack.push_back(ControlFlowCounter++);
157 EHInstStack.push_back(TRY);
158 return;
159
160 case WebAssembly::TRY_TABLE:
161 case WebAssembly::TRY_TABLE_S: {
162 SmallSet<uint64_t, 8> Printed;
163 unsigned OpIdx = 1;
164 const MCOperand &Op = MI->getOperand(OpIdx++);
165 unsigned NumCatches = Op.getImm();
166 for (unsigned I = 0; I < NumCatches; I++) {
167 int64_t CatchOpcode = MI->getOperand(OpIdx++).getImm();
168 if (CatchOpcode == wasm::WASM_OPCODE_CATCH ||
169 CatchOpcode == wasm::WASM_OPCODE_CATCH_REF)
170 OpIdx++; // Skip tag
171 PrintBranchAnnotation(MI->getOperand(OpIdx++), Printed);
172 }
173 ControlFlowStack.push_back(std::make_pair(ControlFlowCounter++, false));
174 return;
175 }
176
177 case WebAssembly::SELECT_T:
178 case WebAssembly::SELECT_T_S:
179 // The trailing operands encode a vec of valtypes, not branch targets;
180 // skip the generic branch-annotation pass below.
181 return;
182
183 case WebAssembly::END_LOOP:
184 case WebAssembly::END_LOOP_S:
185 if (ControlFlowStack.empty()) {
186 printAnnotation(OS, "End marker mismatch!");
187 } else {
188 ControlFlowStack.pop_back();
189 }
190 return;
191
192 case WebAssembly::END_BLOCK:
193 case WebAssembly::END_BLOCK_S:
194 case WebAssembly::END_TRY_TABLE:
195 case WebAssembly::END_TRY_TABLE_S:
196 if (ControlFlowStack.empty()) {
197 printAnnotation(OS, "End marker mismatch!");
198 } else {
200 OS, "label" + utostr(ControlFlowStack.pop_back_val().first) + ':');
201 }
202 return;
203
204 case WebAssembly::END_TRY:
205 case WebAssembly::END_TRY_S:
206 if (ControlFlowStack.empty() || EHInstStack.empty()) {
207 printAnnotation(OS, "End marker mismatch!");
208 } else {
210 OS, "label" + utostr(ControlFlowStack.pop_back_val().first) + ':');
211 EHInstStack.pop_back();
212 }
213 return;
214
215 case WebAssembly::CATCH_LEGACY:
216 case WebAssembly::CATCH_LEGACY_S:
217 case WebAssembly::CATCH_ALL_LEGACY:
218 case WebAssembly::CATCH_ALL_LEGACY_S:
219 // There can be multiple catch instructions for one try instruction, so
220 // we print a label only for the first 'catch' label.
221 if (EHInstStack.empty()) {
222 printAnnotation(OS, "try-catch mismatch!");
223 } else if (EHInstStack.back() == CATCH_ALL_LEGACY) {
224 printAnnotation(OS, "catch/catch_all cannot occur after catch_all");
225 } else if (EHInstStack.back() == TRY) {
226 if (TryStack.empty()) {
227 printAnnotation(OS, "try-catch mismatch!");
228 } else {
229 printAnnotation(OS, "catch" + utostr(TryStack.pop_back_val()) + ':');
230 }
231 EHInstStack.pop_back();
232 if (Opc == WebAssembly::CATCH_LEGACY ||
233 Opc == WebAssembly::CATCH_LEGACY_S) {
234 EHInstStack.push_back(CATCH_LEGACY);
235 } else {
236 EHInstStack.push_back(CATCH_ALL_LEGACY);
237 }
238 }
239 return;
240
241 case WebAssembly::RETHROW:
242 case WebAssembly::RETHROW_S:
243 // 'rethrow' rethrows to the nearest enclosing catch scope, if any. If
244 // there's no enclosing catch scope, it throws up to the caller.
245 if (TryStack.empty()) {
246 printAnnotation(OS, "to caller");
247 } else {
248 printAnnotation(OS, "down to catch" + utostr(TryStack.back()));
249 }
250 return;
251
252 case WebAssembly::DELEGATE:
253 case WebAssembly::DELEGATE_S:
254 if (ControlFlowStack.empty() || TryStack.empty() || EHInstStack.empty()) {
255 printAnnotation(OS, "try-delegate mismatch!");
256 } else {
257 // 'delegate' is
258 // 1. A marker for the end of block label
259 // 2. A destination for throwing instructions
260 // 3. An instruction that itself rethrows to another 'catch'
261 assert(ControlFlowStack.back().first == TryStack.back());
262 std::string Label = "label/catch" +
263 utostr(ControlFlowStack.pop_back_val().first) +
264 ": ";
265 TryStack.pop_back();
266 EHInstStack.pop_back();
267 uint64_t Depth = MI->getOperand(0).getImm();
268 if (Depth >= ControlFlowStack.size()) {
269 Label += "to caller";
270 } else {
271 const auto &Pair = ControlFlowStack.rbegin()[Depth];
272 if (Pair.second)
273 printAnnotation(OS, "delegate cannot target a loop");
274 else
275 Label += "down to catch" + utostr(Pair.first);
276 }
277 printAnnotation(OS, Label);
278 }
279 return;
280 }
281
282 // Annotate any control flow label references.
283
284 unsigned NumFixedOperands = Desc.NumOperands;
285 SmallSet<uint64_t, 8> Printed;
286 for (unsigned I = 0, E = MI->getNumOperands(); I < E; ++I) {
287 // See if this operand denotes a basic block target.
288 if (I < NumFixedOperands) {
289 // A non-variable_ops operand, check its type.
290 if (Desc.operands()[I].OperandType != WebAssembly::OPERAND_BASIC_BLOCK)
291 continue;
292 } else {
293 // A variable_ops operand, which currently can be immediates (used in
294 // br_table) which are basic block targets, or for call instructions
295 // when using -wasm-keep-registers (in which case they are registers,
296 // and should not be processed).
297 if (!MI->getOperand(I).isImm())
298 continue;
299 }
300 PrintBranchAnnotation(MI->getOperand(I), Printed);
301 }
302 }
303}
304
305static std::string toString(const APFloat &FP) {
306 // Print NaNs with custom payloads specially.
307 if (FP.isNaN() && !FP.bitwiseIsEqual(APFloat::getQNaN(FP.getSemantics())) &&
308 !FP.bitwiseIsEqual(
309 APFloat::getQNaN(FP.getSemantics(), /*Negative=*/true))) {
310 APInt AI = FP.bitcastToAPInt();
311 return std::string(AI.isNegative() ? "-" : "") + "nan:0x" +
313 (AI.getBitWidth() == 32 ? INT64_C(0x007fffff)
314 : INT64_C(0x000fffffffffffff)),
315 /*LowerCase=*/true);
316 }
317
318 // Use C99's hexadecimal floating-point representation.
319 static const size_t BufBytes = 128;
320 char Buf[BufBytes];
321 auto Written = FP.convertToHexString(
322 Buf, /*HexDigits=*/0, /*UpperCase=*/false, APFloat::rmNearestTiesToEven);
323 (void)Written;
324 assert(Written != 0);
325 assert(Written < BufBytes);
326 return Buf;
327}
328
330 const MCSubtargetInfo &STI,
331 raw_ostream &O, bool IsVariadicDef) {
332 const MCOperand &Op = MI->getOperand(OpNo);
333 if (Op.isReg()) {
334 const MCInstrDesc &Desc = MII.get(MI->getOpcode());
335 MCRegister WAReg = Op.getReg();
336 if (int(WAReg.id()) >= 0)
337 printRegName(O, WAReg);
338 else if (OpNo >= Desc.getNumDefs() && !IsVariadicDef)
339 O << "$pop" << WebAssembly::getWARegStackId(WAReg);
340 else if (WAReg != WebAssembly::UnusedReg)
341 O << "$push" << WebAssembly::getWARegStackId(WAReg);
342 else
343 O << "$drop";
344 // Add a '=' suffix if this is a def.
345 if (OpNo < MII.get(MI->getOpcode()).getNumDefs() || IsVariadicDef)
346 O << '=';
347 } else if (Op.isImm()) {
348 O << Op.getImm();
349 } else if (Op.isSFPImm()) {
350 O << ::toString(APFloat(APFloat::IEEEsingle(), APInt(32, Op.getSFPImm())));
351 } else if (Op.isDFPImm()) {
352 O << ::toString(APFloat(APFloat::IEEEdouble(), APInt(64, Op.getDFPImm())));
353 } else {
354 assert(Op.isExpr() && "unknown operand kind in printOperand");
355 // call_indirect instructions have a TYPEINDEX operand that we print
356 // as a signature here, such that the assembler can recover this
357 // information.
358 auto SRE = static_cast<const MCSymbolRefExpr *>(Op.getExpr());
359 if (SRE->getSpecifier() == WebAssembly::S_TYPEINDEX) {
360 auto &Sym = static_cast<const MCSymbolWasm &>(SRE->getSymbol());
361 O << WebAssembly::signatureToString(Sym.getSignature());
362 } else {
363 MAI.printExpr(O, *Op.getExpr());
364 }
365 }
366}
367
369 const MCSubtargetInfo &STI,
370 raw_ostream &O) {
371 O << "{";
372 for (unsigned I = OpNo, E = MI->getNumOperands(); I != E; ++I) {
373 if (I != OpNo)
374 O << ", ";
375 O << MI->getOperand(I).getImm();
376 }
377 O << "}";
378}
379
381 const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI,
382 raw_ostream &O) {
383 int64_t Imm = MI->getOperand(OpNo).getImm();
384 if (Imm == WebAssembly::GetDefaultP2Align(MI->getOpcode()))
385 return;
386 O << ":p2align=" << Imm;
387}
388
390 const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI,
391 raw_ostream &O) {
392 int64_t Imm = MI->getOperand(OpNo).getImm();
393
394 switch (Imm) {
397 O << "acqrel";
398 break;
400 if (STI.getFeatureBits()[WebAssembly::FeatureRelaxedAtomics])
401 O << "seqcst";
402 break;
403 default:
404 llvm_unreachable("Unknown memory ordering");
405 }
406}
407
409 const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI,
410 raw_ostream &O) {
411 const MCOperand &Op = MI->getOperand(OpNo);
412 if (Op.isImm()) {
413 auto Imm = static_cast<unsigned>(Op.getImm());
414 if (Imm != wasm::WASM_TYPE_NORESULT)
416 } else {
417 auto Expr = cast<MCSymbolRefExpr>(Op.getExpr());
418 auto *Sym = static_cast<const MCSymbolWasm *>(&Expr->getSymbol());
419 if (Sym->getSignature()) {
420 O << WebAssembly::signatureToString(Sym->getSignature());
421 } else {
422 // Disassembler does not currently produce a signature
423 O << "unknown_type";
424 }
425 }
426}
427
429 const MCSubtargetInfo &STI,
430 raw_ostream &O) {
431 unsigned OpIdx = OpNo;
432 const MCOperand &Op = MI->getOperand(OpIdx++);
433 unsigned NumCatches = Op.getImm();
434
435 auto PrintTagOp = [&](const MCOperand &Op) {
436 const MCSymbolRefExpr *TagExpr = nullptr;
437 const MCSymbol *TagSym = nullptr;
438 if (Op.isExpr()) {
439 TagExpr = cast<MCSymbolRefExpr>(Op.getExpr());
440 TagSym = &TagExpr->getSymbol();
441 O << TagSym->getName() << " ";
442 } else {
443 // When instructions are parsed from the disassembler, we have an
444 // immediate tag index and not a tag expr
445 O << Op.getImm() << " ";
446 }
447 };
448
449 for (unsigned I = 0; I < NumCatches; I++) {
450 const MCOperand &Op = MI->getOperand(OpIdx++);
451 O << "(";
452 switch (Op.getImm()) {
454 O << "catch ";
455 PrintTagOp(MI->getOperand(OpIdx++));
456 break;
458 O << "catch_ref ";
459 PrintTagOp(MI->getOperand(OpIdx++));
460 break;
462 O << "catch_all ";
463 break;
465 O << "catch_all_ref ";
466 break;
467 }
468 O << MI->getOperand(OpIdx++).getImm(); // destination
469 O << ")";
470 if (I < NumCatches - 1)
471 O << " ";
472 }
473}
474
476 const MCSubtargetInfo &STI,
477 raw_ostream &O) {
478 unsigned OpIdx = OpNo;
479 uint64_t NumTypes = uint64_t(MI->getOperand(OpIdx++).getImm());
480 uint64_t Remaining = MI->getNumOperands() - OpIdx;
481 if (NumTypes > Remaining)
482 NumTypes = Remaining;
483 for (uint64_t I = 0; I < NumTypes; I++) {
484 if (I != 0)
485 O << ' ';
486 O << WebAssembly::anyTypeToString(MI->getOperand(OpIdx++).getImm());
487 }
488}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
This file declares a class to represent arbitrary precision floating point values and provide a varie...
IRTranslator LLVM IR MI
#define I(x, y, z)
Definition MD5.cpp:57
MachineInstr unsigned OpIdx
This file defines the SmallSet class.
This file contains some functions that are useful when dealing with strings.
This class prints an WebAssembly MCInst to wasm file syntax.
This file contains the declaration of the WebAssemblyMCAsmInfo class.
This file provides WebAssembly-specific target descriptions.
This file contains the declaration of the WebAssembly-specific type parsing utility functions.
static const fltSemantics & IEEEsingle()
Definition APFloat.h:297
static const fltSemantics & IEEEdouble()
Definition APFloat.h:298
static constexpr roundingMode rmNearestTiesToEven
Definition APFloat.h:345
static APFloat getQNaN(const fltSemantics &Sem, bool Negative=false, const APInt *payload=nullptr)
Factory for QNaN values.
Definition APFloat.h:1206
Class for arbitrary precision integers.
Definition APInt.h:78
uint64_t getZExtValue() const
Get zero extended value.
Definition APInt.h:1565
unsigned getBitWidth() const
Return the number of bits in the APInt.
Definition APInt.h:1513
bool isNegative() const
Determine sign of this APInt.
Definition APInt.h:330
This class is intended to be used as a base class for asm properties and features specific to the tar...
Definition MCAsmInfo.h:66
const MCInstrInfo & MII
raw_ostream * CommentStream
A stream that comments can be emitted to if desired.
const MCRegisterInfo & MRI
void printAnnotation(raw_ostream &OS, StringRef Annot)
Utility function for printing annotations.
const MCAsmInfo & MAI
MCInstPrinter(const MCAsmInfo &mai, const MCInstrInfo &mii, const MCRegisterInfo &mri)
Instances of this class represent a single low-level machine instruction.
Definition MCInst.h:188
Describe properties that are true of each instruction in the target description file.
Interface to description of machine instruction set.
Definition MCInstrInfo.h:27
Instances of this class represent operands of the MCInst class.
Definition MCInst.h:40
int64_t getImm() const
Definition MCInst.h:84
bool isImm() const
Definition MCInst.h:66
bool isExpr() const
Definition MCInst.h:69
MCRegisterInfo base class - We assume that the target defines a static array of MCRegisterDesc object...
Wrapper class representing physical registers. Should be passed by value.
Definition MCRegister.h:41
constexpr unsigned id() const
Definition MCRegister.h:82
Generic base class for all target subtargets.
const FeatureBitset & getFeatureBits() const
Represent a reference to a symbol from inside an expression.
Definition MCExpr.h:190
const MCSymbol & getSymbol() const
Definition MCExpr.h:226
MCSymbol - Instances of this class represent a symbol name in the MC file, and MCSymbols are created ...
Definition MCSymbol.h:42
StringRef getName() const
getName - Get the symbol name.
Definition MCSymbol.h:188
SmallSet - This maintains a set of unique values, optimizing for the case when the set is small (less...
Definition SmallSet.h:134
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
void printCatchList(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI, raw_ostream &O)
void printOperand(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI, raw_ostream &O, bool IsVariadicDef=false)
void printWebAssemblyMemOrderOperand(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI, raw_ostream &O)
void printRegName(raw_ostream &OS, MCRegister Reg) override
Print the assembler register name.
void printWebAssemblyP2AlignOperand(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI, raw_ostream &O)
std::pair< const char *, uint64_t > getMnemonic(const MCInst &MI) const override
Returns a pair containing the mnemonic for MI and the number of bits left for further processing by p...
void printInst(const MCInst *MI, uint64_t Address, StringRef Annot, const MCSubtargetInfo &STI, raw_ostream &OS) override
Print the specified MCInst to the specified raw_ostream.
void printBrList(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI, raw_ostream &O)
void printInstruction(const MCInst *MI, uint64_t Address, const MCSubtargetInfo &STI, raw_ostream &O)
void printTypeList(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI, raw_ostream &O)
WebAssemblyInstPrinter(const MCAsmInfo &MAI, const MCInstrInfo &MII, const MCRegisterInfo &MRI)
void printWebAssemblySignatureOperand(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI, raw_ostream &O)
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition raw_ostream.h:53
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
unsigned GetDefaultP2Align(unsigned Opc)
static const unsigned UnusedReg
@ OPERAND_BASIC_BLOCK
Basic block label in a branch construct.
std::string signatureToString(const wasm::WasmSignature *Sig)
unsigned getWARegStackId(MCRegister Reg)
const char * anyTypeToString(unsigned Type)
@ WASM_TYPE_NORESULT
Definition Wasm.h:81
@ WASM_OPCODE_CATCH_ALL_REF
Definition Wasm.h:163
@ WASM_OPCODE_CATCH
Definition Wasm.h:160
@ WASM_OPCODE_CATCH_ALL
Definition Wasm.h:162
@ WASM_OPCODE_CATCH_REF
Definition Wasm.h:161
@ WASM_MEM_ORDER_SEQ_CST
Definition Wasm.h:86
@ WASM_MEM_ORDER_RMW_ACQ_REL
Definition Wasm.h:89
@ WASM_MEM_ORDER_ACQ_REL
Definition Wasm.h:87
This is an optimization pass for GlobalISel generic memory operations.
std::string utohexstr(uint64_t X, bool LowerCase=false, unsigned Width=0)
std::string utostr(uint64_t X, bool isNeg=false)
Op::Description Desc
DWARFExpression::Operation Op
std::string toString(const APInt &I, unsigned Radix, bool Signed, bool formatAsCLiteral=false, bool UpperCase=true, bool InsertSeparators=false)
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559