10b57cec5SDimitry Andric //=- WebAssemblyInstPrinter.cpp - WebAssembly assembly instruction printing -=//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric ///
90b57cec5SDimitry Andric /// \file
100b57cec5SDimitry Andric /// Print MCInst instructions to wasm format.
110b57cec5SDimitry Andric ///
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric
140b57cec5SDimitry Andric #include "MCTargetDesc/WebAssemblyInstPrinter.h"
150b57cec5SDimitry Andric #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
1606c3fb27SDimitry Andric #include "MCTargetDesc/WebAssemblyMCTypeUtilities.h"
170b57cec5SDimitry Andric #include "WebAssembly.h"
18*5f757f3fSDimitry Andric #include "llvm/ADT/APFloat.h"
190b57cec5SDimitry Andric #include "llvm/ADT/SmallSet.h"
200b57cec5SDimitry Andric #include "llvm/ADT/StringExtras.h"
210b57cec5SDimitry Andric #include "llvm/MC/MCExpr.h"
220b57cec5SDimitry Andric #include "llvm/MC/MCInst.h"
230b57cec5SDimitry Andric #include "llvm/MC/MCInstrInfo.h"
240b57cec5SDimitry Andric #include "llvm/MC/MCSubtargetInfo.h"
250b57cec5SDimitry Andric #include "llvm/MC/MCSymbol.h"
26*5f757f3fSDimitry Andric #include "llvm/MC/MCSymbolWasm.h"
27*5f757f3fSDimitry Andric #include "llvm/Support/Casting.h"
280b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h"
290b57cec5SDimitry Andric #include "llvm/Support/FormattedStream.h"
300b57cec5SDimitry Andric using namespace llvm;
310b57cec5SDimitry Andric
320b57cec5SDimitry Andric #define DEBUG_TYPE "asm-printer"
330b57cec5SDimitry Andric
340b57cec5SDimitry Andric #include "WebAssemblyGenAsmWriter.inc"
350b57cec5SDimitry Andric
WebAssemblyInstPrinter(const MCAsmInfo & MAI,const MCInstrInfo & MII,const MCRegisterInfo & MRI)360b57cec5SDimitry Andric WebAssemblyInstPrinter::WebAssemblyInstPrinter(const MCAsmInfo &MAI,
370b57cec5SDimitry Andric const MCInstrInfo &MII,
380b57cec5SDimitry Andric const MCRegisterInfo &MRI)
390b57cec5SDimitry Andric : MCInstPrinter(MAI, MII, MRI) {}
400b57cec5SDimitry Andric
printRegName(raw_ostream & OS,MCRegister Reg) const410b57cec5SDimitry Andric void WebAssemblyInstPrinter::printRegName(raw_ostream &OS,
42bdd1243dSDimitry Andric MCRegister Reg) const {
43*5f757f3fSDimitry Andric assert(Reg.id() != WebAssembly::UnusedReg);
440b57cec5SDimitry Andric // Note that there's an implicit local.get/local.set here!
45bdd1243dSDimitry Andric OS << "$" << Reg.id();
460b57cec5SDimitry Andric }
470b57cec5SDimitry Andric
printInst(const MCInst * MI,uint64_t Address,StringRef Annot,const MCSubtargetInfo & STI,raw_ostream & OS)48480093f4SDimitry Andric void WebAssemblyInstPrinter::printInst(const MCInst *MI, uint64_t Address,
490b57cec5SDimitry Andric StringRef Annot,
50480093f4SDimitry Andric const MCSubtargetInfo &STI,
51480093f4SDimitry Andric raw_ostream &OS) {
52fe6060f1SDimitry Andric switch (MI->getOpcode()) {
53fe6060f1SDimitry Andric case WebAssembly::CALL_INDIRECT_S:
54fe6060f1SDimitry Andric case WebAssembly::RET_CALL_INDIRECT_S: {
55fe6060f1SDimitry Andric // A special case for call_indirect (and ret_call_indirect), if the table
56fe6060f1SDimitry Andric // operand is a symbol: the order of the type and table operands is inverted
57fe6060f1SDimitry Andric // in the text format relative to the binary format. Otherwise if table the
58fe6060f1SDimitry Andric // operand isn't a symbol, then we have an MVP compilation unit, and the
59fe6060f1SDimitry Andric // table shouldn't appear in the output.
60fe6060f1SDimitry Andric OS << "\t";
61fe6060f1SDimitry Andric OS << getMnemonic(MI).first;
62fe6060f1SDimitry Andric OS << " ";
63fe6060f1SDimitry Andric
64fe6060f1SDimitry Andric assert(MI->getNumOperands() == 2);
65fe6060f1SDimitry Andric const unsigned TypeOperand = 0;
66fe6060f1SDimitry Andric const unsigned TableOperand = 1;
67fe6060f1SDimitry Andric if (MI->getOperand(TableOperand).isExpr()) {
68fe6060f1SDimitry Andric printOperand(MI, TableOperand, OS);
69fe6060f1SDimitry Andric OS << ", ";
70fe6060f1SDimitry Andric } else {
71fe6060f1SDimitry Andric assert(MI->getOperand(TableOperand).getImm() == 0);
72fe6060f1SDimitry Andric }
73fe6060f1SDimitry Andric printOperand(MI, TypeOperand, OS);
74fe6060f1SDimitry Andric break;
75fe6060f1SDimitry Andric }
76fe6060f1SDimitry Andric default:
770b57cec5SDimitry Andric // Print the instruction (this uses the AsmStrings from the .td files).
78480093f4SDimitry Andric printInstruction(MI, Address, OS);
79fe6060f1SDimitry Andric break;
80fe6060f1SDimitry Andric }
810b57cec5SDimitry Andric
820b57cec5SDimitry Andric // Print any additional variadic operands.
830b57cec5SDimitry Andric const MCInstrDesc &Desc = MII.get(MI->getOpcode());
848bcb0991SDimitry Andric if (Desc.isVariadic()) {
855ffd83dbSDimitry Andric if ((Desc.getNumOperands() == 0 && MI->getNumOperands() > 0) ||
865ffd83dbSDimitry Andric Desc.variadicOpsAreDefs())
878bcb0991SDimitry Andric OS << "\t";
885ffd83dbSDimitry Andric unsigned Start = Desc.getNumOperands();
895ffd83dbSDimitry Andric unsigned NumVariadicDefs = 0;
905ffd83dbSDimitry Andric if (Desc.variadicOpsAreDefs()) {
915ffd83dbSDimitry Andric // The number of variadic defs is encoded in an immediate by MCInstLower
925ffd83dbSDimitry Andric NumVariadicDefs = MI->getOperand(0).getImm();
935ffd83dbSDimitry Andric Start = 1;
945ffd83dbSDimitry Andric }
955ffd83dbSDimitry Andric bool NeedsComma = Desc.getNumOperands() > 0 && !Desc.variadicOpsAreDefs();
965ffd83dbSDimitry Andric for (auto I = Start, E = MI->getNumOperands(); I < E; ++I) {
975ffd83dbSDimitry Andric if (MI->getOpcode() == WebAssembly::CALL_INDIRECT &&
985ffd83dbSDimitry Andric I - Start == NumVariadicDefs) {
99fe6060f1SDimitry Andric // Skip type and table arguments when printing for tests.
1005ffd83dbSDimitry Andric ++I;
1015ffd83dbSDimitry Andric continue;
1025ffd83dbSDimitry Andric }
1035ffd83dbSDimitry Andric if (NeedsComma)
1040b57cec5SDimitry Andric OS << ", ";
1055ffd83dbSDimitry Andric printOperand(MI, I, OS, I - Start < NumVariadicDefs);
1065ffd83dbSDimitry Andric NeedsComma = true;
1070b57cec5SDimitry Andric }
1088bcb0991SDimitry Andric }
1090b57cec5SDimitry Andric
1100b57cec5SDimitry Andric // Print any added annotation.
1110b57cec5SDimitry Andric printAnnotation(OS, Annot);
1120b57cec5SDimitry Andric
1130b57cec5SDimitry Andric if (CommentStream) {
1140b57cec5SDimitry Andric // Observe any effects on the control flow stack, for use in annotating
1150b57cec5SDimitry Andric // control flow label references.
1160b57cec5SDimitry Andric unsigned Opc = MI->getOpcode();
1170b57cec5SDimitry Andric switch (Opc) {
1180b57cec5SDimitry Andric default:
1190b57cec5SDimitry Andric break;
1200b57cec5SDimitry Andric
1210b57cec5SDimitry Andric case WebAssembly::LOOP:
1220b57cec5SDimitry Andric case WebAssembly::LOOP_S:
1230b57cec5SDimitry Andric printAnnotation(OS, "label" + utostr(ControlFlowCounter) + ':');
1240b57cec5SDimitry Andric ControlFlowStack.push_back(std::make_pair(ControlFlowCounter++, true));
125e8d8bef9SDimitry Andric return;
1260b57cec5SDimitry Andric
1270b57cec5SDimitry Andric case WebAssembly::BLOCK:
1280b57cec5SDimitry Andric case WebAssembly::BLOCK_S:
1290b57cec5SDimitry Andric ControlFlowStack.push_back(std::make_pair(ControlFlowCounter++, false));
130e8d8bef9SDimitry Andric return;
1310b57cec5SDimitry Andric
1320b57cec5SDimitry Andric case WebAssembly::TRY:
1330b57cec5SDimitry Andric case WebAssembly::TRY_S:
134e8d8bef9SDimitry Andric ControlFlowStack.push_back(std::make_pair(ControlFlowCounter, false));
135fe6060f1SDimitry Andric TryStack.push_back(ControlFlowCounter++);
136fe6060f1SDimitry Andric EHInstStack.push_back(TRY);
137e8d8bef9SDimitry Andric return;
1380b57cec5SDimitry Andric
1390b57cec5SDimitry Andric case WebAssembly::END_LOOP:
1400b57cec5SDimitry Andric case WebAssembly::END_LOOP_S:
1410b57cec5SDimitry Andric if (ControlFlowStack.empty()) {
1420b57cec5SDimitry Andric printAnnotation(OS, "End marker mismatch!");
1430b57cec5SDimitry Andric } else {
1440b57cec5SDimitry Andric ControlFlowStack.pop_back();
1450b57cec5SDimitry Andric }
146e8d8bef9SDimitry Andric return;
1470b57cec5SDimitry Andric
1480b57cec5SDimitry Andric case WebAssembly::END_BLOCK:
1490b57cec5SDimitry Andric case WebAssembly::END_BLOCK_S:
1500b57cec5SDimitry Andric if (ControlFlowStack.empty()) {
1510b57cec5SDimitry Andric printAnnotation(OS, "End marker mismatch!");
1520b57cec5SDimitry Andric } else {
1530b57cec5SDimitry Andric printAnnotation(
1540b57cec5SDimitry Andric OS, "label" + utostr(ControlFlowStack.pop_back_val().first) + ':');
1550b57cec5SDimitry Andric }
156e8d8bef9SDimitry Andric return;
1570b57cec5SDimitry Andric
1580b57cec5SDimitry Andric case WebAssembly::END_TRY:
1590b57cec5SDimitry Andric case WebAssembly::END_TRY_S:
160fe6060f1SDimitry Andric if (ControlFlowStack.empty() || EHInstStack.empty()) {
1610b57cec5SDimitry Andric printAnnotation(OS, "End marker mismatch!");
1620b57cec5SDimitry Andric } else {
1630b57cec5SDimitry Andric printAnnotation(
1640b57cec5SDimitry Andric OS, "label" + utostr(ControlFlowStack.pop_back_val().first) + ':');
165fe6060f1SDimitry Andric EHInstStack.pop_back();
1660b57cec5SDimitry Andric }
167e8d8bef9SDimitry Andric return;
1680b57cec5SDimitry Andric
1690b57cec5SDimitry Andric case WebAssembly::CATCH:
1700b57cec5SDimitry Andric case WebAssembly::CATCH_S:
171e8d8bef9SDimitry Andric case WebAssembly::CATCH_ALL:
172e8d8bef9SDimitry Andric case WebAssembly::CATCH_ALL_S:
173fe6060f1SDimitry Andric // There can be multiple catch instructions for one try instruction, so
174fe6060f1SDimitry Andric // we print a label only for the first 'catch' label.
175fe6060f1SDimitry Andric if (EHInstStack.empty()) {
176fe6060f1SDimitry Andric printAnnotation(OS, "try-catch mismatch!");
177fe6060f1SDimitry Andric } else if (EHInstStack.back() == CATCH_ALL) {
178fe6060f1SDimitry Andric printAnnotation(OS, "catch/catch_all cannot occur after catch_all");
179fe6060f1SDimitry Andric } else if (EHInstStack.back() == TRY) {
180fe6060f1SDimitry Andric if (TryStack.empty()) {
1810b57cec5SDimitry Andric printAnnotation(OS, "try-catch mismatch!");
1820b57cec5SDimitry Andric } else {
183fe6060f1SDimitry Andric printAnnotation(OS, "catch" + utostr(TryStack.pop_back_val()) + ':');
184fe6060f1SDimitry Andric }
185fe6060f1SDimitry Andric EHInstStack.pop_back();
186fe6060f1SDimitry Andric if (Opc == WebAssembly::CATCH || Opc == WebAssembly::CATCH_S) {
187fe6060f1SDimitry Andric EHInstStack.push_back(CATCH);
188fe6060f1SDimitry Andric } else {
189fe6060f1SDimitry Andric EHInstStack.push_back(CATCH_ALL);
190fe6060f1SDimitry Andric }
1910b57cec5SDimitry Andric }
192e8d8bef9SDimitry Andric return;
1930b57cec5SDimitry Andric
194e8d8bef9SDimitry Andric case WebAssembly::RETHROW:
195e8d8bef9SDimitry Andric case WebAssembly::RETHROW_S:
196e8d8bef9SDimitry Andric // 'rethrow' rethrows to the nearest enclosing catch scope, if any. If
197e8d8bef9SDimitry Andric // there's no enclosing catch scope, it throws up to the caller.
198fe6060f1SDimitry Andric if (TryStack.empty()) {
1990b57cec5SDimitry Andric printAnnotation(OS, "to caller");
2000b57cec5SDimitry Andric } else {
201fe6060f1SDimitry Andric printAnnotation(OS, "down to catch" + utostr(TryStack.back()));
202fe6060f1SDimitry Andric }
203fe6060f1SDimitry Andric return;
204fe6060f1SDimitry Andric
205fe6060f1SDimitry Andric case WebAssembly::DELEGATE:
206fe6060f1SDimitry Andric case WebAssembly::DELEGATE_S:
207fe6060f1SDimitry Andric if (ControlFlowStack.empty() || TryStack.empty() || EHInstStack.empty()) {
208fe6060f1SDimitry Andric printAnnotation(OS, "try-delegate mismatch!");
209fe6060f1SDimitry Andric } else {
210fe6060f1SDimitry Andric // 'delegate' is
211fe6060f1SDimitry Andric // 1. A marker for the end of block label
212fe6060f1SDimitry Andric // 2. A destination for throwing instructions
213fe6060f1SDimitry Andric // 3. An instruction that itself rethrows to another 'catch'
214fe6060f1SDimitry Andric assert(ControlFlowStack.back().first == TryStack.back());
215fe6060f1SDimitry Andric std::string Label = "label/catch" +
216fe6060f1SDimitry Andric utostr(ControlFlowStack.pop_back_val().first) +
217fe6060f1SDimitry Andric ": ";
218fe6060f1SDimitry Andric TryStack.pop_back();
219fe6060f1SDimitry Andric EHInstStack.pop_back();
220fe6060f1SDimitry Andric uint64_t Depth = MI->getOperand(0).getImm();
221fe6060f1SDimitry Andric if (Depth >= ControlFlowStack.size()) {
222fe6060f1SDimitry Andric Label += "to caller";
223fe6060f1SDimitry Andric } else {
224fe6060f1SDimitry Andric const auto &Pair = ControlFlowStack.rbegin()[Depth];
225fe6060f1SDimitry Andric if (Pair.second)
226fe6060f1SDimitry Andric printAnnotation(OS, "delegate cannot target a loop");
227fe6060f1SDimitry Andric else
228fe6060f1SDimitry Andric Label += "down to catch" + utostr(Pair.first);
229fe6060f1SDimitry Andric }
230fe6060f1SDimitry Andric printAnnotation(OS, Label);
2310b57cec5SDimitry Andric }
232e8d8bef9SDimitry Andric return;
233e8d8bef9SDimitry Andric }
2340b57cec5SDimitry Andric
235e8d8bef9SDimitry Andric // Annotate any control flow label references.
236e8d8bef9SDimitry Andric
2370b57cec5SDimitry Andric unsigned NumFixedOperands = Desc.NumOperands;
2380b57cec5SDimitry Andric SmallSet<uint64_t, 8> Printed;
2390b57cec5SDimitry Andric for (unsigned I = 0, E = MI->getNumOperands(); I < E; ++I) {
2400b57cec5SDimitry Andric // See if this operand denotes a basic block target.
2410b57cec5SDimitry Andric if (I < NumFixedOperands) {
2420b57cec5SDimitry Andric // A non-variable_ops operand, check its type.
243bdd1243dSDimitry Andric if (Desc.operands()[I].OperandType != WebAssembly::OPERAND_BASIC_BLOCK)
2440b57cec5SDimitry Andric continue;
2450b57cec5SDimitry Andric } else {
2460b57cec5SDimitry Andric // A variable_ops operand, which currently can be immediates (used in
2470b57cec5SDimitry Andric // br_table) which are basic block targets, or for call instructions
2480b57cec5SDimitry Andric // when using -wasm-keep-registers (in which case they are registers,
2490b57cec5SDimitry Andric // and should not be processed).
2500b57cec5SDimitry Andric if (!MI->getOperand(I).isImm())
2510b57cec5SDimitry Andric continue;
2520b57cec5SDimitry Andric }
2530b57cec5SDimitry Andric uint64_t Depth = MI->getOperand(I).getImm();
2540b57cec5SDimitry Andric if (!Printed.insert(Depth).second)
2550b57cec5SDimitry Andric continue;
2560b57cec5SDimitry Andric if (Depth >= ControlFlowStack.size()) {
2570b57cec5SDimitry Andric printAnnotation(OS, "Invalid depth argument!");
2580b57cec5SDimitry Andric } else {
2590b57cec5SDimitry Andric const auto &Pair = ControlFlowStack.rbegin()[Depth];
2600b57cec5SDimitry Andric printAnnotation(OS, utostr(Depth) + ": " +
2610b57cec5SDimitry Andric (Pair.second ? "up" : "down") + " to label" +
2620b57cec5SDimitry Andric utostr(Pair.first));
2630b57cec5SDimitry Andric }
2640b57cec5SDimitry Andric }
2650b57cec5SDimitry Andric }
2660b57cec5SDimitry Andric }
2670b57cec5SDimitry Andric
toString(const APFloat & FP)2680b57cec5SDimitry Andric static std::string toString(const APFloat &FP) {
2690b57cec5SDimitry Andric // Print NaNs with custom payloads specially.
2700b57cec5SDimitry Andric if (FP.isNaN() && !FP.bitwiseIsEqual(APFloat::getQNaN(FP.getSemantics())) &&
2710b57cec5SDimitry Andric !FP.bitwiseIsEqual(
2720b57cec5SDimitry Andric APFloat::getQNaN(FP.getSemantics(), /*Negative=*/true))) {
2730b57cec5SDimitry Andric APInt AI = FP.bitcastToAPInt();
2740b57cec5SDimitry Andric return std::string(AI.isNegative() ? "-" : "") + "nan:0x" +
2750b57cec5SDimitry Andric utohexstr(AI.getZExtValue() &
2760b57cec5SDimitry Andric (AI.getBitWidth() == 32 ? INT64_C(0x007fffff)
2770b57cec5SDimitry Andric : INT64_C(0x000fffffffffffff)),
2780b57cec5SDimitry Andric /*LowerCase=*/true);
2790b57cec5SDimitry Andric }
2800b57cec5SDimitry Andric
2810b57cec5SDimitry Andric // Use C99's hexadecimal floating-point representation.
2820b57cec5SDimitry Andric static const size_t BufBytes = 128;
2830b57cec5SDimitry Andric char Buf[BufBytes];
2840b57cec5SDimitry Andric auto Written = FP.convertToHexString(
2850b57cec5SDimitry Andric Buf, /*HexDigits=*/0, /*UpperCase=*/false, APFloat::rmNearestTiesToEven);
2860b57cec5SDimitry Andric (void)Written;
2870b57cec5SDimitry Andric assert(Written != 0);
2880b57cec5SDimitry Andric assert(Written < BufBytes);
2890b57cec5SDimitry Andric return Buf;
2900b57cec5SDimitry Andric }
2910b57cec5SDimitry Andric
printOperand(const MCInst * MI,unsigned OpNo,raw_ostream & O,bool IsVariadicDef)2920b57cec5SDimitry Andric void WebAssemblyInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
2935ffd83dbSDimitry Andric raw_ostream &O, bool IsVariadicDef) {
2940b57cec5SDimitry Andric const MCOperand &Op = MI->getOperand(OpNo);
2950b57cec5SDimitry Andric if (Op.isReg()) {
2965ffd83dbSDimitry Andric const MCInstrDesc &Desc = MII.get(MI->getOpcode());
2970b57cec5SDimitry Andric unsigned WAReg = Op.getReg();
2980b57cec5SDimitry Andric if (int(WAReg) >= 0)
2990b57cec5SDimitry Andric printRegName(O, WAReg);
3005ffd83dbSDimitry Andric else if (OpNo >= Desc.getNumDefs() && !IsVariadicDef)
301*5f757f3fSDimitry Andric O << "$pop" << WebAssembly::getWARegStackId(WAReg);
302*5f757f3fSDimitry Andric else if (WAReg != WebAssembly::UnusedReg)
303*5f757f3fSDimitry Andric O << "$push" << WebAssembly::getWARegStackId(WAReg);
3040b57cec5SDimitry Andric else
3050b57cec5SDimitry Andric O << "$drop";
3060b57cec5SDimitry Andric // Add a '=' suffix if this is a def.
3075ffd83dbSDimitry Andric if (OpNo < MII.get(MI->getOpcode()).getNumDefs() || IsVariadicDef)
3080b57cec5SDimitry Andric O << '=';
3090b57cec5SDimitry Andric } else if (Op.isImm()) {
3100b57cec5SDimitry Andric O << Op.getImm();
311fe6060f1SDimitry Andric } else if (Op.isSFPImm()) {
312fe6060f1SDimitry Andric O << ::toString(APFloat(APFloat::IEEEsingle(), APInt(32, Op.getSFPImm())));
313fe6060f1SDimitry Andric } else if (Op.isDFPImm()) {
314fe6060f1SDimitry Andric O << ::toString(APFloat(APFloat::IEEEdouble(), APInt(64, Op.getDFPImm())));
3150b57cec5SDimitry Andric } else {
3160b57cec5SDimitry Andric assert(Op.isExpr() && "unknown operand kind in printOperand");
3178bcb0991SDimitry Andric // call_indirect instructions have a TYPEINDEX operand that we print
3188bcb0991SDimitry Andric // as a signature here, such that the assembler can recover this
3198bcb0991SDimitry Andric // information.
3208bcb0991SDimitry Andric auto SRE = static_cast<const MCSymbolRefExpr *>(Op.getExpr());
3218bcb0991SDimitry Andric if (SRE->getKind() == MCSymbolRefExpr::VK_WASM_TYPEINDEX) {
3228bcb0991SDimitry Andric auto &Sym = static_cast<const MCSymbolWasm &>(SRE->getSymbol());
3238bcb0991SDimitry Andric O << WebAssembly::signatureToString(Sym.getSignature());
3248bcb0991SDimitry Andric } else {
3250b57cec5SDimitry Andric Op.getExpr()->print(O, &MAI);
3260b57cec5SDimitry Andric }
3270b57cec5SDimitry Andric }
3288bcb0991SDimitry Andric }
3290b57cec5SDimitry Andric
printBrList(const MCInst * MI,unsigned OpNo,raw_ostream & O)3300b57cec5SDimitry Andric void WebAssemblyInstPrinter::printBrList(const MCInst *MI, unsigned OpNo,
3310b57cec5SDimitry Andric raw_ostream &O) {
3320b57cec5SDimitry Andric O << "{";
3330b57cec5SDimitry Andric for (unsigned I = OpNo, E = MI->getNumOperands(); I != E; ++I) {
3340b57cec5SDimitry Andric if (I != OpNo)
3350b57cec5SDimitry Andric O << ", ";
3360b57cec5SDimitry Andric O << MI->getOperand(I).getImm();
3370b57cec5SDimitry Andric }
3380b57cec5SDimitry Andric O << "}";
3390b57cec5SDimitry Andric }
3400b57cec5SDimitry Andric
printWebAssemblyP2AlignOperand(const MCInst * MI,unsigned OpNo,raw_ostream & O)3410b57cec5SDimitry Andric void WebAssemblyInstPrinter::printWebAssemblyP2AlignOperand(const MCInst *MI,
3420b57cec5SDimitry Andric unsigned OpNo,
3430b57cec5SDimitry Andric raw_ostream &O) {
3440b57cec5SDimitry Andric int64_t Imm = MI->getOperand(OpNo).getImm();
3450b57cec5SDimitry Andric if (Imm == WebAssembly::GetDefaultP2Align(MI->getOpcode()))
3460b57cec5SDimitry Andric return;
3470b57cec5SDimitry Andric O << ":p2align=" << Imm;
3480b57cec5SDimitry Andric }
3490b57cec5SDimitry Andric
printWebAssemblySignatureOperand(const MCInst * MI,unsigned OpNo,raw_ostream & O)3500b57cec5SDimitry Andric void WebAssemblyInstPrinter::printWebAssemblySignatureOperand(const MCInst *MI,
3510b57cec5SDimitry Andric unsigned OpNo,
3520b57cec5SDimitry Andric raw_ostream &O) {
3538bcb0991SDimitry Andric const MCOperand &Op = MI->getOperand(OpNo);
3548bcb0991SDimitry Andric if (Op.isImm()) {
3558bcb0991SDimitry Andric auto Imm = static_cast<unsigned>(Op.getImm());
3560b57cec5SDimitry Andric if (Imm != wasm::WASM_TYPE_NORESULT)
3570b57cec5SDimitry Andric O << WebAssembly::anyTypeToString(Imm);
3588bcb0991SDimitry Andric } else {
3598bcb0991SDimitry Andric auto Expr = cast<MCSymbolRefExpr>(Op.getExpr());
3608bcb0991SDimitry Andric auto *Sym = cast<MCSymbolWasm>(&Expr->getSymbol());
3618bcb0991SDimitry Andric if (Sym->getSignature()) {
3628bcb0991SDimitry Andric O << WebAssembly::signatureToString(Sym->getSignature());
3638bcb0991SDimitry Andric } else {
3648bcb0991SDimitry Andric // Disassembler does not currently produce a signature
3658bcb0991SDimitry Andric O << "unknown_type";
3668bcb0991SDimitry Andric }
3678bcb0991SDimitry Andric }
3680b57cec5SDimitry Andric }
369