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 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 410b57cec5SDimitry 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 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 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 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 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 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 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