diff options
Diffstat (limited to 'lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.cpp')
| -rw-r--r-- | lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.cpp | 243 |
1 files changed, 146 insertions, 97 deletions
diff --git a/lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.cpp b/lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.cpp index 10fa798ac8d7..15532d7ff1a6 100644 --- a/lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.cpp +++ b/lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.cpp @@ -35,12 +35,12 @@ using namespace llvm; WebAssemblyInstPrinter::WebAssemblyInstPrinter(const MCAsmInfo &MAI, const MCInstrInfo &MII, const MCRegisterInfo &MRI) - : MCInstPrinter(MAI, MII, MRI), ControlFlowCounter(0) {} + : MCInstPrinter(MAI, MII, MRI) {} void WebAssemblyInstPrinter::printRegName(raw_ostream &OS, unsigned RegNo) const { assert(RegNo != WebAssemblyFunctionInfo::UnusedReg); - // Note that there's an implicit get_local/set_local here! + // Note that there's an implicit local.get/local.set here! OS << "$" << RegNo; } @@ -57,9 +57,9 @@ void WebAssemblyInstPrinter::printInst(const MCInst *MI, raw_ostream &OS, // FIXME: For CALL_INDIRECT_VOID, don't print a leading comma, because // we have an extra flags operand which is not currently printed, for // compatiblity reasons. - if (i != 0 && - (MI->getOpcode() != WebAssembly::CALL_INDIRECT_VOID || - i != Desc.getNumOperands())) + if (i != 0 && ((MI->getOpcode() != WebAssembly::CALL_INDIRECT_VOID && + MI->getOpcode() != WebAssembly::CALL_INDIRECT_VOID_S) || + i != Desc.getNumOperands())) OS << ", "; printOperand(MI, i, OS); } @@ -70,25 +70,76 @@ void WebAssemblyInstPrinter::printInst(const MCInst *MI, raw_ostream &OS, if (CommentStream) { // Observe any effects on the control flow stack, for use in annotating // control flow label references. - switch (MI->getOpcode()) { + unsigned Opc = MI->getOpcode(); + switch (Opc) { default: break; - case WebAssembly::LOOP: { + + case WebAssembly::LOOP: + case WebAssembly::LOOP_S: printAnnotation(OS, "label" + utostr(ControlFlowCounter) + ':'); ControlFlowStack.push_back(std::make_pair(ControlFlowCounter++, true)); break; - } + case WebAssembly::BLOCK: + case WebAssembly::BLOCK_S: ControlFlowStack.push_back(std::make_pair(ControlFlowCounter++, false)); break; + + case WebAssembly::TRY: + case WebAssembly::TRY_S: + ControlFlowStack.push_back(std::make_pair(ControlFlowCounter++, false)); + EHPadStack.push_back(EHPadStackCounter++); + LastSeenEHInst = TRY; + break; + case WebAssembly::END_LOOP: - // Have to guard against an empty stack, in case of mismatched pairs - // in assembly parsing. - if (!ControlFlowStack.empty()) ControlFlowStack.pop_back(); + case WebAssembly::END_LOOP_S: + if (ControlFlowStack.empty()) { + printAnnotation(OS, "End marker mismatch!"); + } else { + ControlFlowStack.pop_back(); + } break; + case WebAssembly::END_BLOCK: - if (!ControlFlowStack.empty()) printAnnotation( - OS, "label" + utostr(ControlFlowStack.pop_back_val().first) + ':'); + case WebAssembly::END_BLOCK_S: + if (ControlFlowStack.empty()) { + printAnnotation(OS, "End marker mismatch!"); + } else { + printAnnotation( + OS, "label" + utostr(ControlFlowStack.pop_back_val().first) + ':'); + } + break; + + case WebAssembly::END_TRY: + case WebAssembly::END_TRY_S: + if (ControlFlowStack.empty()) { + printAnnotation(OS, "End marker mismatch!"); + } else { + printAnnotation( + OS, "label" + utostr(ControlFlowStack.pop_back_val().first) + ':'); + LastSeenEHInst = END_TRY; + } + break; + + case WebAssembly::CATCH_I32: + case WebAssembly::CATCH_I32_S: + case WebAssembly::CATCH_I64: + case WebAssembly::CATCH_I64_S: + case WebAssembly::CATCH_ALL: + case WebAssembly::CATCH_ALL_S: + // There can be multiple catch instructions for one try instruction, so we + // print a label only for the first 'catch' label. + if (LastSeenEHInst != CATCH) { + if (EHPadStack.empty()) { + printAnnotation(OS, "try-catch mismatch!"); + } else { + printAnnotation(OS, + "catch" + utostr(EHPadStack.pop_back_val()) + ':'); + } + } + LastSeenEHInst = CATCH; break; } @@ -96,34 +147,61 @@ void WebAssemblyInstPrinter::printInst(const MCInst *MI, raw_ostream &OS, unsigned NumFixedOperands = Desc.NumOperands; SmallSet<uint64_t, 8> Printed; for (unsigned i = 0, e = MI->getNumOperands(); i < e; ++i) { - if (!(i < NumFixedOperands - ? (Desc.OpInfo[i].OperandType == - WebAssembly::OPERAND_BASIC_BLOCK) - : (Desc.TSFlags & WebAssemblyII::VariableOpImmediateIsLabel))) - continue; + // See if this operand denotes a basic block target. + if (i < NumFixedOperands) { + // A non-variable_ops operand, check its type. + if (Desc.OpInfo[i].OperandType != WebAssembly::OPERAND_BASIC_BLOCK) + continue; + } else { + // A variable_ops operand, which currently can be immediates (used in + // br_table) which are basic block targets, or for call instructions + // when using -wasm-keep-registers (in which case they are registers, + // and should not be processed). + if (!MI->getOperand(i).isImm()) + continue; + } uint64_t Depth = MI->getOperand(i).getImm(); if (!Printed.insert(Depth).second) continue; - const auto &Pair = ControlFlowStack.rbegin()[Depth]; - printAnnotation(OS, utostr(Depth) + ": " + (Pair.second ? "up" : "down") + - " to label" + utostr(Pair.first)); + + if (Opc == WebAssembly::RETHROW || Opc == WebAssembly::RETHROW_S) { + if (Depth > EHPadStack.size()) { + printAnnotation(OS, "Invalid depth argument!"); + } else if (Depth == EHPadStack.size()) { + // This can happen when rethrow instruction breaks out of all nests + // and throws up to the current function's caller. + printAnnotation(OS, utostr(Depth) + ": " + "to caller"); + } else { + uint64_t CatchNo = EHPadStack.rbegin()[Depth]; + printAnnotation(OS, utostr(Depth) + ": " + "down to catch" + + utostr(CatchNo)); + } + + } else { + if (Depth >= ControlFlowStack.size()) { + printAnnotation(OS, "Invalid depth argument!"); + } else { + const auto &Pair = ControlFlowStack.rbegin()[Depth]; + printAnnotation(OS, utostr(Depth) + ": " + + (Pair.second ? "up" : "down") + " to label" + + utostr(Pair.first)); + } + } } } } static std::string toString(const APFloat &FP) { // Print NaNs with custom payloads specially. - if (FP.isNaN() && - !FP.bitwiseIsEqual(APFloat::getQNaN(FP.getSemantics())) && + if (FP.isNaN() && !FP.bitwiseIsEqual(APFloat::getQNaN(FP.getSemantics())) && !FP.bitwiseIsEqual( APFloat::getQNaN(FP.getSemantics(), /*Negative=*/true))) { APInt AI = FP.bitcastToAPInt(); - return - std::string(AI.isNegative() ? "-" : "") + "nan:0x" + - utohexstr(AI.getZExtValue() & - (AI.getBitWidth() == 32 ? INT64_C(0x007fffff) : - INT64_C(0x000fffffffffffff)), - /*LowerCase=*/true); + return std::string(AI.isNegative() ? "-" : "") + "nan:0x" + + utohexstr(AI.getZExtValue() & + (AI.getBitWidth() == 32 ? INT64_C(0x007fffff) + : INT64_C(0x000fffffffffffff)), + /*LowerCase=*/true); } // Use C99's hexadecimal floating-point representation. @@ -141,9 +219,6 @@ void WebAssemblyInstPrinter::printOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O) { const MCOperand &Op = MI->getOperand(OpNo); if (Op.isReg()) { - assert((OpNo < MII.get(MI->getOpcode()).getNumOperands() || - MII.get(MI->getOpcode()).TSFlags == 0) && - "WebAssembly variable_ops register ops don't use TSFlags"); unsigned WAReg = Op.getReg(); if (int(WAReg) >= 0) printRegName(O, WAReg); @@ -157,23 +232,9 @@ void WebAssemblyInstPrinter::printOperand(const MCInst *MI, unsigned OpNo, if (OpNo < MII.get(MI->getOpcode()).getNumDefs()) O << '='; } else if (Op.isImm()) { - const MCInstrDesc &Desc = MII.get(MI->getOpcode()); - assert((OpNo < Desc.getNumOperands() || - (Desc.TSFlags & WebAssemblyII::VariableOpIsImmediate)) && - "WebAssemblyII::VariableOpIsImmediate should be set for " - "variable_ops immediate ops"); - (void)Desc; - // TODO: (MII.get(MI->getOpcode()).TSFlags & - // WebAssemblyII::VariableOpImmediateIsLabel) - // can tell us whether this is an immediate referencing a label in the - // control flow stack, and it may be nice to pretty-print. O << Op.getImm(); } else if (Op.isFPImm()) { const MCInstrDesc &Desc = MII.get(MI->getOpcode()); - assert(OpNo < Desc.getNumOperands() && - "Unexpected floating-point immediate as a non-fixed operand"); - assert(Desc.TSFlags == 0 && - "WebAssembly variable_ops floating point ops don't use TSFlags"); const MCOperandInfo &Info = Desc.OpInfo[OpNo]; if (Info.OperandType == WebAssembly::OPERAND_F32IMM) { // TODO: MC converts all floating point immediate operands to double. @@ -184,78 +245,66 @@ void WebAssemblyInstPrinter::printOperand(const MCInst *MI, unsigned OpNo, O << ::toString(APFloat(Op.getFPImm())); } } else { - assert((OpNo < MII.get(MI->getOpcode()).getNumOperands() || - (MII.get(MI->getOpcode()).TSFlags & - WebAssemblyII::VariableOpIsImmediate)) && - "WebAssemblyII::VariableOpIsImmediate should be set for " - "variable_ops expr ops"); assert(Op.isExpr() && "unknown operand kind in printOperand"); Op.getExpr()->print(O, &MAI); } } -void WebAssemblyInstPrinter::printWebAssemblyP2AlignOperand( - const MCInst *MI, unsigned OpNo, raw_ostream &O) { +void WebAssemblyInstPrinter::printBrList(const MCInst *MI, unsigned OpNo, + raw_ostream &O) { + O << "{"; + for (unsigned I = OpNo, E = MI->getNumOperands(); I != E; ++I) { + if (I != OpNo) + O << ", "; + O << MI->getOperand(I).getImm(); + } + O << "}"; +} + +void WebAssemblyInstPrinter::printWebAssemblyP2AlignOperand(const MCInst *MI, + unsigned OpNo, + raw_ostream &O) { int64_t Imm = MI->getOperand(OpNo).getImm(); if (Imm == WebAssembly::GetDefaultP2Align(MI->getOpcode())) return; O << ":p2align=" << Imm; } -void WebAssemblyInstPrinter::printWebAssemblySignatureOperand( - const MCInst *MI, unsigned OpNo, raw_ostream &O) { - int64_t Imm = MI->getOperand(OpNo).getImm(); - switch (WebAssembly::ExprType(Imm)) { - case WebAssembly::ExprType::Void: break; - case WebAssembly::ExprType::I32: O << "i32"; break; - case WebAssembly::ExprType::I64: O << "i64"; break; - case WebAssembly::ExprType::F32: O << "f32"; break; - case WebAssembly::ExprType::F64: O << "f64"; break; - case WebAssembly::ExprType::I8x16: O << "i8x16"; break; - case WebAssembly::ExprType::I16x8: O << "i16x8"; break; - case WebAssembly::ExprType::I32x4: O << "i32x4"; break; - case WebAssembly::ExprType::F32x4: O << "f32x4"; break; - case WebAssembly::ExprType::B8x16: O << "b8x16"; break; - case WebAssembly::ExprType::B16x8: O << "b16x8"; break; - case WebAssembly::ExprType::B32x4: O << "b32x4"; break; - case WebAssembly::ExprType::ExceptRef: O << "except_ref"; break; - } +void WebAssemblyInstPrinter::printWebAssemblySignatureOperand(const MCInst *MI, + unsigned OpNo, + raw_ostream &O) { + auto Imm = static_cast<unsigned>(MI->getOperand(OpNo).getImm()); + if (Imm != wasm::WASM_TYPE_NORESULT) + O << WebAssembly::anyTypeToString(Imm); } -const char *llvm::WebAssembly::TypeToString(MVT Ty) { - switch (Ty.SimpleTy) { - case MVT::i32: +// We have various enums representing a subset of these types, use this +// function to convert any of them to text. +const char *llvm::WebAssembly::anyTypeToString(unsigned Ty) { + switch (Ty) { + case wasm::WASM_TYPE_I32: return "i32"; - case MVT::i64: + case wasm::WASM_TYPE_I64: return "i64"; - case MVT::f32: + case wasm::WASM_TYPE_F32: return "f32"; - case MVT::f64: + case wasm::WASM_TYPE_F64: return "f64"; - case MVT::v16i8: - case MVT::v8i16: - case MVT::v4i32: - case MVT::v4f32: + case wasm::WASM_TYPE_V128: return "v128"; - case MVT::ExceptRef: + case wasm::WASM_TYPE_FUNCREF: + return "funcref"; + case wasm::WASM_TYPE_FUNC: + return "func"; + case wasm::WASM_TYPE_EXCEPT_REF: return "except_ref"; + case wasm::WASM_TYPE_NORESULT: + return "void"; default: - llvm_unreachable("unsupported type"); + return "invalid_type"; } } -const char *llvm::WebAssembly::TypeToString(wasm::ValType Type) { - switch (Type) { - case wasm::ValType::I32: - return "i32"; - case wasm::ValType::I64: - return "i64"; - case wasm::ValType::F32: - return "f32"; - case wasm::ValType::F64: - return "f64"; - case wasm::ValType::EXCEPT_REF: - return "except_ref"; - } - llvm_unreachable("unsupported type"); +const char *llvm::WebAssembly::typeToString(wasm::ValType Ty) { + return anyTypeToString(static_cast<unsigned>(Ty)); } |
