LLVM 23.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), if the table
64 // operand is a symbol: the order of the type and table operands is inverted
65 // in the text format relative to the binary format. Otherwise if table the
66 // operand isn't a symbol, then we have an MVP compilation unit, and the
67 // table shouldn't appear in the output.
68 OS << "\t";
69 OS << getMnemonic(*MI).first;
70 OS << " ";
71 if (MI->getOperand(TableOperand).isExpr()) {
72 printOperand(MI, TableOperand, STI, OS);
73 OS << ", ";
74 } else {
75 assert(MI->getOperand(TableOperand).getImm() == 0);
76 }
77 printOperand(MI, TypeOperand, STI, OS);
78 if (MI->getOpcode() == WebAssembly::CALL_INDIRECT)
79 OS << ", ";
80 break;
81 }
82 default:
83 // Print the instruction (this uses the AsmStrings from the .td files).
84 printInstruction(MI, Address, STI, OS);
85 break;
86 }
87
88 // Print any additional variadic operands.
89 const MCInstrDesc &Desc = MII.get(MI->getOpcode());
90 if (Desc.isVariadic()) {
91 if ((Desc.getNumOperands() == 0 && MI->getNumOperands() > 0) ||
92 Desc.variadicOpsAreDefs())
93 OS << "\t";
94 unsigned Start = Desc.getNumOperands();
95 unsigned NumVariadicDefs = 0;
96 if (Desc.variadicOpsAreDefs()) {
97 // The number of variadic defs is encoded in an immediate by MCInstLower
98 NumVariadicDefs = MI->getOperand(0).getImm();
99 Start = 1;
100 }
101 bool NeedsComma = Desc.getNumOperands() > 0 && !Desc.variadicOpsAreDefs();
102 for (auto I = Start, E = MI->getNumOperands(); I < E; ++I) {
103 if (MI->getOpcode() == WebAssembly::CALL_INDIRECT &&
104 I - Start == NumVariadicDefs) {
105 // Skip type and table arguments when printing for tests.
106 ++I;
107 continue;
108 }
109 if (NeedsComma)
110 OS << ", ";
111 printOperand(MI, I, STI, OS, I - Start < NumVariadicDefs);
112 NeedsComma = true;
113 }
114 }
115
116 // Print any added annotation.
117 printAnnotation(OS, Annot);
118
119 auto PrintBranchAnnotation = [&](const MCOperand &Op,
120 SmallSet<uint64_t, 8> &Printed) {
121 uint64_t Depth = Op.getImm();
122 if (!Printed.insert(Depth).second)
123 return;
124 if (Depth >= ControlFlowStack.size()) {
125 printAnnotation(OS, "Invalid depth argument!");
126 } else {
127 const auto &Pair = ControlFlowStack.rbegin()[Depth];
128 printAnnotation(OS, utostr(Depth) + ": " + (Pair.second ? "up" : "down") +
129 " to label" + utostr(Pair.first));
130 }
131 };
132
133 if (CommentStream) {
134 // Observe any effects on the control flow stack, for use in annotating
135 // control flow label references.
136 unsigned Opc = MI->getOpcode();
137 switch (Opc) {
138 default:
139 break;
140
141 case WebAssembly::LOOP:
142 case WebAssembly::LOOP_S:
143 printAnnotation(OS, "label" + utostr(ControlFlowCounter) + ':');
144 ControlFlowStack.push_back(std::make_pair(ControlFlowCounter++, true));
145 return;
146
147 case WebAssembly::BLOCK:
148 case WebAssembly::BLOCK_S:
149 ControlFlowStack.push_back(std::make_pair(ControlFlowCounter++, false));
150 return;
151
152 case WebAssembly::TRY:
153 case WebAssembly::TRY_S:
154 ControlFlowStack.push_back(std::make_pair(ControlFlowCounter, false));
155 TryStack.push_back(ControlFlowCounter++);
156 EHInstStack.push_back(TRY);
157 return;
158
159 case WebAssembly::TRY_TABLE:
160 case WebAssembly::TRY_TABLE_S: {
161 SmallSet<uint64_t, 8> Printed;
162 unsigned OpIdx = 1;
163 const MCOperand &Op = MI->getOperand(OpIdx++);
164 unsigned NumCatches = Op.getImm();
165 for (unsigned I = 0; I < NumCatches; I++) {
166 int64_t CatchOpcode = MI->getOperand(OpIdx++).getImm();
167 if (CatchOpcode == wasm::WASM_OPCODE_CATCH ||
168 CatchOpcode == wasm::WASM_OPCODE_CATCH_REF)
169 OpIdx++; // Skip tag
170 PrintBranchAnnotation(MI->getOperand(OpIdx++), Printed);
171 }
172 ControlFlowStack.push_back(std::make_pair(ControlFlowCounter++, false));
173 return;
174 }
175
176 case WebAssembly::SELECT_T:
177 case WebAssembly::SELECT_T_S:
178 // The trailing operands encode a vec of valtypes, not branch targets;
179 // skip the generic branch-annotation pass below.
180 return;
181
182 case WebAssembly::END_LOOP:
183 case WebAssembly::END_LOOP_S:
184 if (ControlFlowStack.empty()) {
185 printAnnotation(OS, "End marker mismatch!");
186 } else {
187 ControlFlowStack.pop_back();
188 }
189 return;
190
191 case WebAssembly::END_BLOCK:
192 case WebAssembly::END_BLOCK_S:
193 case WebAssembly::END_TRY_TABLE:
194 case WebAssembly::END_TRY_TABLE_S:
195 if (ControlFlowStack.empty()) {
196 printAnnotation(OS, "End marker mismatch!");
197 } else {
199 OS, "label" + utostr(ControlFlowStack.pop_back_val().first) + ':');
200 }
201 return;
202
203 case WebAssembly::END_TRY:
204 case WebAssembly::END_TRY_S:
205 if (ControlFlowStack.empty() || EHInstStack.empty()) {
206 printAnnotation(OS, "End marker mismatch!");
207 } else {
209 OS, "label" + utostr(ControlFlowStack.pop_back_val().first) + ':');
210 EHInstStack.pop_back();
211 }
212 return;
213
214 case WebAssembly::CATCH_LEGACY:
215 case WebAssembly::CATCH_LEGACY_S:
216 case WebAssembly::CATCH_ALL_LEGACY:
217 case WebAssembly::CATCH_ALL_LEGACY_S:
218 // There can be multiple catch instructions for one try instruction, so
219 // we print a label only for the first 'catch' label.
220 if (EHInstStack.empty()) {
221 printAnnotation(OS, "try-catch mismatch!");
222 } else if (EHInstStack.back() == CATCH_ALL_LEGACY) {
223 printAnnotation(OS, "catch/catch_all cannot occur after catch_all");
224 } else if (EHInstStack.back() == TRY) {
225 if (TryStack.empty()) {
226 printAnnotation(OS, "try-catch mismatch!");
227 } else {
228 printAnnotation(OS, "catch" + utostr(TryStack.pop_back_val()) + ':');
229 }
230 EHInstStack.pop_back();
231 if (Opc == WebAssembly::CATCH_LEGACY ||
232 Opc == WebAssembly::CATCH_LEGACY_S) {
233 EHInstStack.push_back(CATCH_LEGACY);
234 } else {
235 EHInstStack.push_back(CATCH_ALL_LEGACY);
236 }
237 }
238 return;
239
240 case WebAssembly::RETHROW:
241 case WebAssembly::RETHROW_S:
242 // 'rethrow' rethrows to the nearest enclosing catch scope, if any. If
243 // there's no enclosing catch scope, it throws up to the caller.
244 if (TryStack.empty()) {
245 printAnnotation(OS, "to caller");
246 } else {
247 printAnnotation(OS, "down to catch" + utostr(TryStack.back()));
248 }
249 return;
250
251 case WebAssembly::DELEGATE:
252 case WebAssembly::DELEGATE_S:
253 if (ControlFlowStack.empty() || TryStack.empty() || EHInstStack.empty()) {
254 printAnnotation(OS, "try-delegate mismatch!");
255 } else {
256 // 'delegate' is
257 // 1. A marker for the end of block label
258 // 2. A destination for throwing instructions
259 // 3. An instruction that itself rethrows to another 'catch'
260 assert(ControlFlowStack.back().first == TryStack.back());
261 std::string Label = "label/catch" +
262 utostr(ControlFlowStack.pop_back_val().first) +
263 ": ";
264 TryStack.pop_back();
265 EHInstStack.pop_back();
266 uint64_t Depth = MI->getOperand(0).getImm();
267 if (Depth >= ControlFlowStack.size()) {
268 Label += "to caller";
269 } else {
270 const auto &Pair = ControlFlowStack.rbegin()[Depth];
271 if (Pair.second)
272 printAnnotation(OS, "delegate cannot target a loop");
273 else
274 Label += "down to catch" + utostr(Pair.first);
275 }
276 printAnnotation(OS, Label);
277 }
278 return;
279 }
280
281 // Annotate any control flow label references.
282
283 unsigned NumFixedOperands = Desc.NumOperands;
284 SmallSet<uint64_t, 8> Printed;
285 for (unsigned I = 0, E = MI->getNumOperands(); I < E; ++I) {
286 // See if this operand denotes a basic block target.
287 if (I < NumFixedOperands) {
288 // A non-variable_ops operand, check its type.
289 if (Desc.operands()[I].OperandType != WebAssembly::OPERAND_BASIC_BLOCK)
290 continue;
291 } else {
292 // A variable_ops operand, which currently can be immediates (used in
293 // br_table) which are basic block targets, or for call instructions
294 // when using -wasm-keep-registers (in which case they are registers,
295 // and should not be processed).
296 if (!MI->getOperand(I).isImm())
297 continue;
298 }
299 PrintBranchAnnotation(MI->getOperand(I), Printed);
300 }
301 }
302}
303
304static std::string toString(const APFloat &FP) {
305 // Print NaNs with custom payloads specially.
306 if (FP.isNaN() && !FP.bitwiseIsEqual(APFloat::getQNaN(FP.getSemantics())) &&
307 !FP.bitwiseIsEqual(
308 APFloat::getQNaN(FP.getSemantics(), /*Negative=*/true))) {
309 APInt AI = FP.bitcastToAPInt();
310 return std::string(AI.isNegative() ? "-" : "") + "nan:0x" +
312 (AI.getBitWidth() == 32 ? INT64_C(0x007fffff)
313 : INT64_C(0x000fffffffffffff)),
314 /*LowerCase=*/true);
315 }
316
317 // Use C99's hexadecimal floating-point representation.
318 static const size_t BufBytes = 128;
319 char Buf[BufBytes];
320 auto Written = FP.convertToHexString(
321 Buf, /*HexDigits=*/0, /*UpperCase=*/false, APFloat::rmNearestTiesToEven);
322 (void)Written;
323 assert(Written != 0);
324 assert(Written < BufBytes);
325 return Buf;
326}
327
329 const MCSubtargetInfo &STI,
330 raw_ostream &O, bool IsVariadicDef) {
331 const MCOperand &Op = MI->getOperand(OpNo);
332 if (Op.isReg()) {
333 const MCInstrDesc &Desc = MII.get(MI->getOpcode());
334 MCRegister WAReg = Op.getReg();
335 if (int(WAReg.id()) >= 0)
336 printRegName(O, WAReg);
337 else if (OpNo >= Desc.getNumDefs() && !IsVariadicDef)
338 O << "$pop" << WebAssembly::getWARegStackId(WAReg);
339 else if (WAReg != WebAssembly::UnusedReg)
340 O << "$push" << WebAssembly::getWARegStackId(WAReg);
341 else
342 O << "$drop";
343 // Add a '=' suffix if this is a def.
344 if (OpNo < MII.get(MI->getOpcode()).getNumDefs() || IsVariadicDef)
345 O << '=';
346 } else if (Op.isImm()) {
347 O << Op.getImm();
348 } else if (Op.isSFPImm()) {
349 O << ::toString(APFloat(APFloat::IEEEsingle(), APInt(32, Op.getSFPImm())));
350 } else if (Op.isDFPImm()) {
351 O << ::toString(APFloat(APFloat::IEEEdouble(), APInt(64, Op.getDFPImm())));
352 } else {
353 assert(Op.isExpr() && "unknown operand kind in printOperand");
354 // call_indirect instructions have a TYPEINDEX operand that we print
355 // as a signature here, such that the assembler can recover this
356 // information.
357 auto SRE = static_cast<const MCSymbolRefExpr *>(Op.getExpr());
358 if (SRE->getSpecifier() == WebAssembly::S_TYPEINDEX) {
359 auto &Sym = static_cast<const MCSymbolWasm &>(SRE->getSymbol());
360 O << WebAssembly::signatureToString(Sym.getSignature());
361 } else {
362 MAI.printExpr(O, *Op.getExpr());
363 }
364 }
365}
366
368 const MCSubtargetInfo &STI,
369 raw_ostream &O) {
370 O << "{";
371 for (unsigned I = OpNo, E = MI->getNumOperands(); I != E; ++I) {
372 if (I != OpNo)
373 O << ", ";
374 O << MI->getOperand(I).getImm();
375 }
376 O << "}";
377}
378
380 const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI,
381 raw_ostream &O) {
382 int64_t Imm = MI->getOperand(OpNo).getImm();
383 if (Imm == WebAssembly::GetDefaultP2Align(MI->getOpcode()))
384 return;
385 O << ":p2align=" << Imm;
386}
387
389 const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI,
390 raw_ostream &O) {
391 int64_t Imm = MI->getOperand(OpNo).getImm();
392
393 switch (Imm) {
396 O << "acqrel";
397 break;
399 if (STI.getFeatureBits()[WebAssembly::FeatureRelaxedAtomics])
400 O << "seqcst";
401 break;
402 default:
403 llvm_unreachable("Unknown memory ordering");
404 }
405}
406
408 const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI,
409 raw_ostream &O) {
410 const MCOperand &Op = MI->getOperand(OpNo);
411 if (Op.isImm()) {
412 auto Imm = static_cast<unsigned>(Op.getImm());
413 if (Imm != wasm::WASM_TYPE_NORESULT)
415 } else {
416 auto Expr = cast<MCSymbolRefExpr>(Op.getExpr());
417 auto *Sym = static_cast<const MCSymbolWasm *>(&Expr->getSymbol());
418 if (Sym->getSignature()) {
419 O << WebAssembly::signatureToString(Sym->getSignature());
420 } else {
421 // Disassembler does not currently produce a signature
422 O << "unknown_type";
423 }
424 }
425}
426
428 const MCSubtargetInfo &STI,
429 raw_ostream &O) {
430 unsigned OpIdx = OpNo;
431 const MCOperand &Op = MI->getOperand(OpIdx++);
432 unsigned NumCatches = Op.getImm();
433
434 auto PrintTagOp = [&](const MCOperand &Op) {
435 const MCSymbolRefExpr *TagExpr = nullptr;
436 const MCSymbol *TagSym = nullptr;
437 if (Op.isExpr()) {
438 TagExpr = cast<MCSymbolRefExpr>(Op.getExpr());
439 TagSym = &TagExpr->getSymbol();
440 O << TagSym->getName() << " ";
441 } else {
442 // When instructions are parsed from the disassembler, we have an
443 // immediate tag index and not a tag expr
444 O << Op.getImm() << " ";
445 }
446 };
447
448 for (unsigned I = 0; I < NumCatches; I++) {
449 const MCOperand &Op = MI->getOperand(OpIdx++);
450 O << "(";
451 switch (Op.getImm()) {
453 O << "catch ";
454 PrintTagOp(MI->getOperand(OpIdx++));
455 break;
457 O << "catch_ref ";
458 PrintTagOp(MI->getOperand(OpIdx++));
459 break;
461 O << "catch_all ";
462 break;
464 O << "catch_all_ref ";
465 break;
466 }
467 O << MI->getOperand(OpIdx++).getImm(); // destination
468 O << ")";
469 if (I < NumCatches - 1)
470 O << " ";
471 }
472}
473
475 const MCSubtargetInfo &STI,
476 raw_ostream &O) {
477 unsigned OpIdx = OpNo;
478 uint64_t NumTypes = uint64_t(MI->getOperand(OpIdx++).getImm());
479 uint64_t Remaining = MI->getNumOperands() - OpIdx;
480 if (NumTypes > Remaining)
481 NumTypes = Remaining;
482 for (uint64_t I = 0; I < NumTypes; I++) {
483 if (I != 0)
484 O << ' ';
485 O << WebAssembly::anyTypeToString(MI->getOperand(OpIdx++).getImm());
486 }
487}
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:296
static const fltSemantics & IEEEdouble()
Definition APFloat.h:297
static constexpr roundingMode rmNearestTiesToEven
Definition APFloat.h:344
static APFloat getQNaN(const fltSemantics &Sem, bool Negative=false, const APInt *payload=nullptr)
Factory for QNaN values.
Definition APFloat.h:1179
Class for arbitrary precision integers.
Definition APInt.h:78
uint64_t getZExtValue() const
Get zero extended value.
Definition APInt.h:1563
unsigned getBitWidth() const
Return the number of bits in the APInt.
Definition APInt.h:1511
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
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:227
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