xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
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