// Copyright 2021 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // A Disassembler object is used to disassemble a block of code instruction by // instruction. The default implementation of the NameConverter object can be // overriden to modify register names or to do symbol lookup on addresses. // // The example below will disassemble a block of code and print it to stdout. // // NameConverter converter; // Disassembler d(converter); // for (byte* pc = begin; pc < end;) { // v8::base::EmbeddedVector<char, 256> buffer; // byte* prev_pc = pc; // pc += d.InstructionDecode(buffer, pc); // printf("%p %08x %s\n", // prev_pc, *reinterpret_cast<int32_t*>(prev_pc), buffer); // } // // The Disassembler class also has a convenience method to disassemble a block // of code into a FILE*, meaning that the above functionality could also be // achieved by just calling Disassembler::Disassemble(stdout, begin, end); #include <assert.h> #include <stdarg.h> #include <stdio.h> #include <string.h> #if V8_TARGET_ARCH_RISCV64 #include "src/base/platform/platform.h" #include "src/base/strings.h" #include "src/base/vector.h" #include "src/codegen/macro-assembler.h" #include "src/codegen/riscv64/constants-riscv64.h" #include "src/diagnostics/disasm.h" namespace v8 { namespace internal { //------------------------------------------------------------------------------ // Decoder decodes and disassembles instructions into an output buffer. // It uses the converter to convert register names and call destinations into // more informative description. class Decoder { public: Decoder(const disasm::NameConverter& converter, v8::base::Vector<char> out_buffer) : converter_(converter), out_buffer_(out_buffer), out_buffer_pos_(0) { out_buffer_[out_buffer_pos_] = '\0'; } ~Decoder() {} Decoder(const Decoder&) = delete; Decoder& operator=(const Decoder&) = delete; // Writes one disassembled instruction into 'buffer' (0-terminated). // Returns the length of the disassembled machine instruction in bytes. int InstructionDecode(byte* instruction); private: // Bottleneck functions to print into the out_buffer. void PrintChar(const char ch); void Print(const char* str); // Printing of common values. void PrintRegister(int reg); void PrintFPURegister(int freg); void PrintVRegister(int reg); void PrintFPUStatusRegister(int freg); void PrintRs1(Instruction* instr); void PrintRs2(Instruction* instr); void PrintRd(Instruction* instr); void PrintUimm(Instruction* instr); void PrintVs1(Instruction* instr); void PrintVs2(Instruction* instr); void PrintVd(Instruction* instr); void PrintFRs1(Instruction* instr); void PrintFRs2(Instruction* instr); void PrintFRs3(Instruction* instr); void PrintFRd(Instruction* instr); void PrintImm12(Instruction* instr); void PrintImm12X(Instruction* instr); void PrintImm20U(Instruction* instr); void PrintImm20J(Instruction* instr); void PrintShamt(Instruction* instr); void PrintShamt32(Instruction* instr); void PrintRvcImm6(Instruction* instr); void PrintRvcImm6U(Instruction* instr); void PrintRvcImm6Addi16sp(Instruction* instr); void PrintRvcShamt(Instruction* instr); void PrintRvcImm6Ldsp(Instruction* instr); void PrintRvcImm6Lwsp(Instruction* instr); void PrintRvcImm6Sdsp(Instruction* instr); void PrintRvcImm6Swsp(Instruction* instr); void PrintRvcImm5W(Instruction* instr); void PrintRvcImm5D(Instruction* instr); void PrintRvcImm8Addi4spn(Instruction* instr); void PrintRvcImm11CJ(Instruction* instr); void PrintRvcImm8B(Instruction* instr); void PrintRvvVm(Instruction* instr); void PrintAcquireRelease(Instruction* instr); void PrintBranchOffset(Instruction* instr); void PrintStoreOffset(Instruction* instr); void PrintCSRReg(Instruction* instr); void PrintRvvSEW(Instruction* instr); void PrintRvvLMUL(Instruction* instr); void PrintRvvSimm5(Instruction* instr); void PrintRvvUimm5(Instruction* instr); void PrintRoundingMode(Instruction* instr); void PrintMemoryOrder(Instruction* instr, bool is_pred); // Each of these functions decodes one particular instruction type. void DecodeRType(Instruction* instr); void DecodeR4Type(Instruction* instr); void DecodeRAType(Instruction* instr); void DecodeRFPType(Instruction* instr); void DecodeIType(Instruction* instr); void DecodeSType(Instruction* instr); void DecodeBType(Instruction* instr); void DecodeUType(Instruction* instr); void DecodeJType(Instruction* instr); void DecodeCRType(Instruction* instr); void DecodeCAType(Instruction* instr); void DecodeCIType(Instruction* instr); void DecodeCIWType(Instruction* instr); void DecodeCSSType(Instruction* instr); void DecodeCLType(Instruction* instr); void DecodeCSType(Instruction* instr); void DecodeCJType(Instruction* instr); void DecodeCBType(Instruction* instr); void DecodeVType(Instruction* instr); void DecodeRvvIVV(Instruction* instr); void DecodeRvvFVV(Instruction* instr); void DecodeRvvFVF(Instruction* instr); void DecodeRvvIVI(Instruction* instr); void DecodeRvvIVX(Instruction* instr); void DecodeRvvVL(Instruction* instr); void DecodeRvvVS(Instruction* instr); void DecodeRvvMVV(Instruction* instr); void DecodeRvvMVX(Instruction* instr); // Printing of instruction name. void PrintInstructionName(Instruction* instr); void PrintTarget(Instruction* instr); // Handle formatting of instructions and their options. int FormatRegister(Instruction* instr, const char* option); int FormatFPURegisterOrRoundMode(Instruction* instr, const char* option); int FormatRvcRegister(Instruction* instr, const char* option); int FormatRvcImm(Instruction* instr, const char* option); int FormatOption(Instruction* instr, const char* option); void Format(Instruction* instr, const char* format); void Unknown(Instruction* instr); int switch_sew(Instruction* instr); int switch_nf(Instruction* instr); const disasm::NameConverter& converter_; v8::base::Vector<char> out_buffer_; int out_buffer_pos_; }; // Support for assertions in the Decoder formatting functions. #define STRING_STARTS_WITH(string, compare_string) \ (strncmp(string, compare_string, strlen(compare_string)) == 0) // Append the ch to the output buffer. void Decoder::PrintChar(const char ch) { out_buffer_[out_buffer_pos_++] = ch; } // Append the str to the output buffer. void Decoder::Print(const char* str) { char cur = *str++; while (cur != '\0' && (out_buffer_pos_ < (out_buffer_.length() - 1))) { PrintChar(cur); cur = *str++; } out_buffer_[out_buffer_pos_] = 0; } // Print the register name according to the active name converter. void Decoder::PrintRegister(int reg) { Print(converter_.NameOfCPURegister(reg)); } void Decoder::PrintVRegister(int reg) { Print(v8::internal::VRegisters::Name(reg)); } void Decoder::PrintRs1(Instruction* instr) { int reg = instr->Rs1Value(); PrintRegister(reg); } void Decoder::PrintRs2(Instruction* instr) { int reg = instr->Rs2Value(); PrintRegister(reg); } void Decoder::PrintRd(Instruction* instr) { int reg = instr->RdValue(); PrintRegister(reg); } void Decoder::PrintUimm(Instruction* instr) { int val = instr->Rs1Value(); out_buffer_pos_ += base::SNPrintF(out_buffer_ + out_buffer_pos_, "0x%x", val); } void Decoder::PrintVs1(Instruction* instr) { int reg = instr->Vs1Value(); PrintVRegister(reg); } void Decoder::PrintVs2(Instruction* instr) { int reg = instr->Vs2Value(); PrintVRegister(reg); } void Decoder::PrintVd(Instruction* instr) { int reg = instr->VdValue(); PrintVRegister(reg); } // Print the FPUregister name according to the active name converter. void Decoder::PrintFPURegister(int freg) { Print(converter_.NameOfXMMRegister(freg)); } void Decoder::PrintFRs1(Instruction* instr) { int reg = instr->Rs1Value(); PrintFPURegister(reg); } void Decoder::PrintFRs2(Instruction* instr) { int reg = instr->Rs2Value(); PrintFPURegister(reg); } void Decoder::PrintFRs3(Instruction* instr) { int reg = instr->Rs3Value(); PrintFPURegister(reg); } void Decoder::PrintFRd(Instruction* instr) { int reg = instr->RdValue(); PrintFPURegister(reg); } void Decoder::PrintImm12X(Instruction* instr) { int32_t imm = instr->Imm12Value(); out_buffer_pos_ += base::SNPrintF(out_buffer_ + out_buffer_pos_, "0x%x", imm); } void Decoder::PrintImm12(Instruction* instr) { int32_t imm = instr->Imm12Value(); out_buffer_pos_ += base::SNPrintF(out_buffer_ + out_buffer_pos_, "%d", imm); } void Decoder::PrintTarget(Instruction* instr) { if (Assembler::IsJalr(instr->InstructionBits())) { if (Assembler::IsAuipc((instr - 4)->InstructionBits()) && (instr - 4)->RdValue() == instr->Rs1Value()) { int32_t imm = Assembler::BrachlongOffset((instr - 4)->InstructionBits(), instr->InstructionBits()); const char* target = converter_.NameOfAddress(reinterpret_cast<byte*>(instr - 4) + imm); out_buffer_pos_ += base::SNPrintF(out_buffer_ + out_buffer_pos_, " -> %s", target); return; } } } void Decoder::PrintBranchOffset(Instruction* instr) { int32_t imm = instr->BranchOffset(); const char* target = converter_.NameOfAddress(reinterpret_cast<byte*>(instr) + imm); out_buffer_pos_ += base::SNPrintF(out_buffer_ + out_buffer_pos_, "%d -> %s", imm, target); } void Decoder::PrintStoreOffset(Instruction* instr) { int32_t imm = instr->StoreOffset(); out_buffer_pos_ += base::SNPrintF(out_buffer_ + out_buffer_pos_, "%d", imm); } void Decoder::PrintRvvSEW(Instruction* instr) { const char* sew = instr->RvvSEW(); out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%s", sew); } void Decoder::PrintRvvLMUL(Instruction* instr) { const char* lmul = instr->RvvLMUL(); out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%s", lmul); } void Decoder::PrintRvvSimm5(Instruction* instr) { const int simm5 = instr->RvvSimm5(); out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", simm5); } void Decoder::PrintRvvUimm5(Instruction* instr) { const uint32_t uimm5 = instr->RvvUimm5(); out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%u", uimm5); } void Decoder::PrintImm20U(Instruction* instr) { int32_t imm = instr->Imm20UValue(); out_buffer_pos_ += base::SNPrintF(out_buffer_ + out_buffer_pos_, "0x%x", imm); } void Decoder::PrintImm20J(Instruction* instr) { int32_t imm = instr->Imm20JValue(); const char* target = converter_.NameOfAddress(reinterpret_cast<byte*>(instr) + imm); out_buffer_pos_ += base::SNPrintF(out_buffer_ + out_buffer_pos_, "%d -> %s", imm, target); } void Decoder::PrintShamt(Instruction* instr) { int32_t imm = instr->Shamt(); out_buffer_pos_ += base::SNPrintF(out_buffer_ + out_buffer_pos_, "%d", imm); } void Decoder::PrintShamt32(Instruction* instr) { int32_t imm = instr->Shamt32(); out_buffer_pos_ += base::SNPrintF(out_buffer_ + out_buffer_pos_, "%d", imm); } void Decoder::PrintRvcImm6(Instruction* instr) { int32_t imm = instr->RvcImm6Value(); out_buffer_pos_ += base::SNPrintF(out_buffer_ + out_buffer_pos_, "%d", imm); } void Decoder::PrintRvcImm6U(Instruction* instr) { int32_t imm = instr->RvcImm6Value() & 0xFFFFF; out_buffer_pos_ += base::SNPrintF(out_buffer_ + out_buffer_pos_, "0x%x", imm); } void Decoder::PrintRvcImm6Addi16sp(Instruction* instr) { int32_t imm = instr->RvcImm6Addi16spValue(); out_buffer_pos_ += base::SNPrintF(out_buffer_ + out_buffer_pos_, "%d", imm); } void Decoder::PrintRvcShamt(Instruction* instr) { int32_t imm = instr->RvcShamt6(); out_buffer_pos_ += base::SNPrintF(out_buffer_ + out_buffer_pos_, "%d", imm); } void Decoder::PrintRvcImm6Ldsp(Instruction* instr) { int32_t imm = instr->RvcImm6LdspValue(); out_buffer_pos_ += base::SNPrintF(out_buffer_ + out_buffer_pos_, "%d", imm); } void Decoder::PrintRvcImm6Lwsp(Instruction* instr) { int32_t imm = instr->RvcImm6LwspValue(); out_buffer_pos_ += base::SNPrintF(out_buffer_ + out_buffer_pos_, "%d", imm); } void Decoder::PrintRvcImm6Swsp(Instruction* instr) { int32_t imm = instr->RvcImm6SwspValue(); out_buffer_pos_ += base::SNPrintF(out_buffer_ + out_buffer_pos_, "%d", imm); } void Decoder::PrintRvcImm6Sdsp(Instruction* instr) { int32_t imm = instr->RvcImm6SdspValue(); out_buffer_pos_ += base::SNPrintF(out_buffer_ + out_buffer_pos_, "%d", imm); } void Decoder::PrintRvcImm5W(Instruction* instr) { int32_t imm = instr->RvcImm5WValue(); out_buffer_pos_ += base::SNPrintF(out_buffer_ + out_buffer_pos_, "%d", imm); } void Decoder::PrintRvcImm5D(Instruction* instr) { int32_t imm = instr->RvcImm5DValue(); out_buffer_pos_ += base::SNPrintF(out_buffer_ + out_buffer_pos_, "%d", imm); } void Decoder::PrintRvcImm8Addi4spn(Instruction* instr) { int32_t imm = instr->RvcImm8Addi4spnValue(); out_buffer_pos_ += base::SNPrintF(out_buffer_ + out_buffer_pos_, "%d", imm); } void Decoder::PrintRvcImm11CJ(Instruction* instr) { int32_t imm = instr->RvcImm11CJValue(); out_buffer_pos_ += base::SNPrintF(out_buffer_ + out_buffer_pos_, "%d", imm); } void Decoder::PrintRvcImm8B(Instruction* instr) { int32_t imm = instr->RvcImm8BValue(); out_buffer_pos_ += base::SNPrintF(out_buffer_ + out_buffer_pos_, "%d", imm); } void Decoder::PrintRvvVm(Instruction* instr) { uint8_t imm = instr->RvvVM(); if (imm == 0) { out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, " v0.t"); } } void Decoder::PrintAcquireRelease(Instruction* instr) { bool aq = instr->AqValue(); bool rl = instr->RlValue(); if (aq || rl) { out_buffer_pos_ += base::SNPrintF(out_buffer_ + out_buffer_pos_, "."); } if (aq) { out_buffer_pos_ += base::SNPrintF(out_buffer_ + out_buffer_pos_, "aq"); } if (rl) { out_buffer_pos_ += base::SNPrintF(out_buffer_ + out_buffer_pos_, "rl"); } } void Decoder::PrintCSRReg(Instruction* instr) { int32_t csr_reg = instr->CsrValue(); std::string s; switch (csr_reg) { case csr_fflags: // Floating-Point Accrued Exceptions (RW) s = "csr_fflags"; break; case csr_frm: // Floating-Point Dynamic Rounding Mode (RW) s = "csr_frm"; break; case csr_fcsr: // Floating-Point Control and Status Register (RW) s = "csr_fcsr"; break; case csr_cycle: s = "csr_cycle"; break; case csr_time: s = "csr_time"; break; case csr_instret: s = "csr_instret"; break; case csr_cycleh: s = "csr_cycleh"; break; case csr_timeh: s = "csr_timeh"; break; case csr_instreth: s = "csr_instreth"; break; default: UNREACHABLE(); } out_buffer_pos_ += base::SNPrintF(out_buffer_ + out_buffer_pos_, "%s", s.c_str()); } void Decoder::PrintRoundingMode(Instruction* instr) { int frm = instr->RoundMode(); std::string s; switch (frm) { case RNE: s = "RNE"; break; case RTZ: s = "RTZ"; break; case RDN: s = "RDN"; break; case RUP: s = "RUP"; break; case RMM: s = "RMM"; break; case DYN: s = "DYN"; break; default: UNREACHABLE(); } out_buffer_pos_ += base::SNPrintF(out_buffer_ + out_buffer_pos_, "%s", s.c_str()); } void Decoder::PrintMemoryOrder(Instruction* instr, bool is_pred) { int memOrder = instr->MemoryOrder(is_pred); std::string s; if ((memOrder & PSI) == PSI) { s += "i"; } if ((memOrder & PSO) == PSO) { s += "o"; } if ((memOrder & PSR) == PSR) { s += "r"; } if ((memOrder & PSW) == PSW) { s += "w"; } out_buffer_pos_ += base::SNPrintF(out_buffer_ + out_buffer_pos_, "%s", s.c_str()); } // Printing of instruction name. void Decoder::PrintInstructionName(Instruction* instr) {} // Handle all register based formatting in this function to reduce the // complexity of FormatOption. int Decoder::FormatRegister(Instruction* instr, const char* format) { DCHECK_EQ(format[0], 'r'); if (format[1] == 's') { // 'rs[12]: Rs register. if (format[2] == '1') { int reg = instr->Rs1Value(); PrintRegister(reg); return 3; } else if (format[2] == '2') { int reg = instr->Rs2Value(); PrintRegister(reg); return 3; } UNREACHABLE(); } else if (format[1] == 'd') { // 'rd: rd register. int reg = instr->RdValue(); PrintRegister(reg); return 2; } UNREACHABLE(); } // Handle all FPUregister based formatting in this function to reduce the // complexity of FormatOption. int Decoder::FormatFPURegisterOrRoundMode(Instruction* instr, const char* format) { DCHECK_EQ(format[0], 'f'); if (format[1] == 's') { // 'fs[1-3]: Rs register. if (format[2] == '1') { int reg = instr->Rs1Value(); PrintFPURegister(reg); return 3; } else if (format[2] == '2') { int reg = instr->Rs2Value(); PrintFPURegister(reg); return 3; } else if (format[2] == '3') { int reg = instr->Rs3Value(); PrintFPURegister(reg); return 3; } UNREACHABLE(); } else if (format[1] == 'd') { // 'fd: fd register. int reg = instr->RdValue(); PrintFPURegister(reg); return 2; } else if (format[1] == 'r') { // 'frm DCHECK(STRING_STARTS_WITH(format, "frm")); PrintRoundingMode(instr); return 3; } UNREACHABLE(); } // Handle all C extension register based formatting in this function to reduce // the complexity of FormatOption. int Decoder::FormatRvcRegister(Instruction* instr, const char* format) { DCHECK_EQ(format[0], 'C'); DCHECK(format[1] == 'r' || format[1] == 'f'); if (format[2] == 's') { // 'Crs[12]: Rs register. if (format[3] == '1') { if (format[4] == 's') { // 'Crs1s: 3-bits register int reg = instr->RvcRs1sValue(); if (format[1] == 'r') { PrintRegister(reg); } else if (format[1] == 'f') { PrintFPURegister(reg); } return 5; } int reg = instr->RvcRs1Value(); if (format[1] == 'r') { PrintRegister(reg); } else if (format[1] == 'f') { PrintFPURegister(reg); } return 4; } else if (format[3] == '2') { if (format[4] == 's') { // 'Crs2s: 3-bits register int reg = instr->RvcRs2sValue(); if (format[1] == 'r') { PrintRegister(reg); } else if (format[1] == 'f') { PrintFPURegister(reg); } return 5; } int reg = instr->RvcRs2Value(); if (format[1] == 'r') { PrintRegister(reg); } else if (format[1] == 'f') { PrintFPURegister(reg); } return 4; } UNREACHABLE(); } else if (format[2] == 'd') { // 'Crd: rd register. int reg = instr->RvcRdValue(); if (format[1] == 'r') { PrintRegister(reg); } else if (format[1] == 'f') { PrintFPURegister(reg); } return 3; } UNREACHABLE(); } // Handle all C extension immediates based formatting in this function to reduce // the complexity of FormatOption. int Decoder::FormatRvcImm(Instruction* instr, const char* format) { // TODO(riscv): add other rvc imm format DCHECK(STRING_STARTS_WITH(format, "Cimm")); if (format[4] == '6') { if (format[5] == 'U') { DCHECK(STRING_STARTS_WITH(format, "Cimm6U")); PrintRvcImm6U(instr); return 6; } else if (format[5] == 'A') { if (format[9] == '1' && format[10] == '6') { DCHECK(STRING_STARTS_WITH(format, "Cimm6Addi16sp")); PrintRvcImm6Addi16sp(instr); return 13; } UNREACHABLE(); } else if (format[5] == 'L') { if (format[6] == 'd') { if (format[7] == 's') { DCHECK(STRING_STARTS_WITH(format, "Cimm6Ldsp")); PrintRvcImm6Ldsp(instr); return 9; } } else if (format[6] == 'w') { if (format[7] == 's') { DCHECK(STRING_STARTS_WITH(format, "Cimm6Lwsp")); PrintRvcImm6Lwsp(instr); return 9; } } UNREACHABLE(); } else if (format[5] == 'S') { if (format[6] == 'w') { DCHECK(STRING_STARTS_WITH(format, "Cimm6Swsp")); PrintRvcImm6Swsp(instr); return 9; } else if (format[6] == 'd') { DCHECK(STRING_STARTS_WITH(format, "Cimm6Sdsp")); PrintRvcImm6Sdsp(instr); return 9; } UNREACHABLE(); } PrintRvcImm6(instr); return 5; } else if (format[4] == '5') { DCHECK(STRING_STARTS_WITH(format, "Cimm5")); if (format[5] == 'W') { DCHECK(STRING_STARTS_WITH(format, "Cimm5W")); PrintRvcImm5W(instr); return 6; } else if (format[5] == 'D') { DCHECK(STRING_STARTS_WITH(format, "Cimm5D")); PrintRvcImm5D(instr); return 6; } UNREACHABLE(); } else if (format[4] == '8') { DCHECK(STRING_STARTS_WITH(format, "Cimm8")); if (format[5] == 'A') { DCHECK(STRING_STARTS_WITH(format, "Cimm8Addi4spn")); PrintRvcImm8Addi4spn(instr); return 13; } else if (format[5] == 'B') { DCHECK(STRING_STARTS_WITH(format, "Cimm8B")); PrintRvcImm8B(instr); return 6; } UNREACHABLE(); } else if (format[4] == '1') { DCHECK(STRING_STARTS_WITH(format, "Cimm1")); if (format[5] == '1') { DCHECK(STRING_STARTS_WITH(format, "Cimm11CJ")); PrintRvcImm11CJ(instr); return 8; } UNREACHABLE(); } UNREACHABLE(); } // FormatOption takes a formatting string and interprets it based on // the current instructions. The format string points to the first // character of the option string (the option escape has already been // consumed by the caller.) FormatOption returns the number of // characters that were consumed from the formatting string. int Decoder::FormatOption(Instruction* instr, const char* format) { switch (format[0]) { case 'C': { // `C extension if (format[1] == 'r' || format[1] == 'f') { return FormatRvcRegister(instr, format); } else if (format[1] == 'i') { return FormatRvcImm(instr, format); } else if (format[1] == 's') { DCHECK(STRING_STARTS_WITH(format, "Cshamt")); PrintRvcShamt(instr); return 6; } UNREACHABLE(); } case 'c': { // `csr: CSR registers if (format[1] == 's') { if (format[2] == 'r') { PrintCSRReg(instr); return 3; } } UNREACHABLE(); } case 'i': { // 'imm12, 'imm12x, 'imm20U, or 'imm20J: Immediates. if (format[3] == '1') { if (format[4] == '2') { DCHECK(STRING_STARTS_WITH(format, "imm12")); if (format[5] == 'x') { PrintImm12X(instr); return 6; } PrintImm12(instr); return 5; } } else if (format[3] == '2' && format[4] == '0') { DCHECK(STRING_STARTS_WITH(format, "imm20")); switch (format[5]) { case 'U': DCHECK(STRING_STARTS_WITH(format, "imm20U")); PrintImm20U(instr); break; case 'J': DCHECK(STRING_STARTS_WITH(format, "imm20J")); PrintImm20J(instr); break; } return 6; } UNREACHABLE(); } case 'o': { // 'offB or 'offS: Offsets. if (format[3] == 'B') { DCHECK(STRING_STARTS_WITH(format, "offB")); PrintBranchOffset(instr); return 4; } else if (format[3] == 'S') { DCHECK(STRING_STARTS_WITH(format, "offS")); PrintStoreOffset(instr); return 4; } UNREACHABLE(); } case 'r': { // 'r: registers. return FormatRegister(instr, format); } case 'f': { // 'f: FPUregisters or `frm return FormatFPURegisterOrRoundMode(instr, format); } case 'a': { // 'a: Atomic acquire and release. PrintAcquireRelease(instr); return 1; } case 'p': { // `pre DCHECK(STRING_STARTS_WITH(format, "pre")); PrintMemoryOrder(instr, true); return 3; } case 's': { // 's32 or 's64: Shift amount. if (format[1] == '3') { DCHECK(STRING_STARTS_WITH(format, "s32")); PrintShamt32(instr); return 3; } else if (format[1] == '6') { DCHECK(STRING_STARTS_WITH(format, "s64")); PrintShamt(instr); return 3; } else if (format[1] == 'u') { DCHECK(STRING_STARTS_WITH(format, "suc")); PrintMemoryOrder(instr, false); return 3; } else if (format[1] == 'e') { DCHECK(STRING_STARTS_WITH(format, "sew")); PrintRvvSEW(instr); return 3; } else if (format[1] == 'i') { DCHECK(STRING_STARTS_WITH(format, "simm5")); PrintRvvSimm5(instr); return 5; } UNREACHABLE(); } case 'v': { if (format[1] == 'd') { DCHECK(STRING_STARTS_WITH(format, "vd")); PrintVd(instr); return 2; } else if (format[2] == '1') { DCHECK(STRING_STARTS_WITH(format, "vs1")); PrintVs1(instr); return 3; } else if (format[2] == '2') { DCHECK(STRING_STARTS_WITH(format, "vs2")); PrintVs2(instr); return 3; } else { DCHECK(STRING_STARTS_WITH(format, "vm")); PrintRvvVm(instr); return 2; } } case 'l': { DCHECK(STRING_STARTS_WITH(format, "lmul")); PrintRvvLMUL(instr); return 4; } case 'u': { if (STRING_STARTS_WITH(format, "uimm5")) { PrintRvvUimm5(instr); return 5; } else { DCHECK(STRING_STARTS_WITH(format, "uimm")); PrintUimm(instr); return 4; } } case 't': { // 'target: target of branch instructions' DCHECK(STRING_STARTS_WITH(format, "target")); PrintTarget(instr); return 6; } } UNREACHABLE(); } // Format takes a formatting string for a whole instruction and prints it into // the output buffer. All escaped options are handed to FormatOption to be // parsed further. void Decoder::Format(Instruction* instr, const char* format) { char cur = *format++; while ((cur != 0) && (out_buffer_pos_ < (out_buffer_.length() - 1))) { if (cur == '\'') { // Single quote is used as the formatting escape. format += FormatOption(instr, format); } else { out_buffer_[out_buffer_pos_++] = cur; } cur = *format++; } out_buffer_[out_buffer_pos_] = '\0'; } // For currently unimplemented decodings the disassembler calls Unknown(instr) // which will just print "unknown" of the instruction bits. void Decoder::Unknown(Instruction* instr) { Format(instr, "unknown"); } // RISCV Instruction Decode Routine void Decoder::DecodeRType(Instruction* instr) { switch (instr->InstructionBits() & kRTypeMask) { case RO_ADD: Format(instr, "add 'rd, 'rs1, 'rs2"); break; case RO_SUB: if (instr->Rs1Value() == zero_reg.code()) Format(instr, "neg 'rd, 'rs2"); else Format(instr, "sub 'rd, 'rs1, 'rs2"); break; case RO_SLL: Format(instr, "sll 'rd, 'rs1, 'rs2"); break; case RO_SLT: if (instr->Rs2Value() == zero_reg.code()) Format(instr, "sltz 'rd, 'rs1"); else if (instr->Rs1Value() == zero_reg.code()) Format(instr, "sgtz 'rd, 'rs2"); else Format(instr, "slt 'rd, 'rs1, 'rs2"); break; case RO_SLTU: if (instr->Rs1Value() == zero_reg.code()) Format(instr, "snez 'rd, 'rs2"); else Format(instr, "sltu 'rd, 'rs1, 'rs2"); break; case RO_XOR: Format(instr, "xor 'rd, 'rs1, 'rs2"); break; case RO_SRL: Format(instr, "srl 'rd, 'rs1, 'rs2"); break; case RO_SRA: Format(instr, "sra 'rd, 'rs1, 'rs2"); break; case RO_OR: Format(instr, "or 'rd, 'rs1, 'rs2"); break; case RO_AND: Format(instr, "and 'rd, 'rs1, 'rs2"); break; #ifdef V8_TARGET_ARCH_64_BIT case RO_ADDW: Format(instr, "addw 'rd, 'rs1, 'rs2"); break; case RO_SUBW: if (instr->Rs1Value() == zero_reg.code()) Format(instr, "negw 'rd, 'rs2"); else Format(instr, "subw 'rd, 'rs1, 'rs2"); break; case RO_SLLW: Format(instr, "sllw 'rd, 'rs1, 'rs2"); break; case RO_SRLW: Format(instr, "srlw 'rd, 'rs1, 'rs2"); break; case RO_SRAW: Format(instr, "sraw 'rd, 'rs1, 'rs2"); break; #endif /* V8_TARGET_ARCH_64_BIT */ // TODO(riscv): Add RISCV M extension macro case RO_MUL: Format(instr, "mul 'rd, 'rs1, 'rs2"); break; case RO_MULH: Format(instr, "mulh 'rd, 'rs1, 'rs2"); break; case RO_MULHSU: Format(instr, "mulhsu 'rd, 'rs1, 'rs2"); break; case RO_MULHU: Format(instr, "mulhu 'rd, 'rs1, 'rs2"); break; case RO_DIV: Format(instr, "div 'rd, 'rs1, 'rs2"); break; case RO_DIVU: Format(instr, "divu 'rd, 'rs1, 'rs2"); break; case RO_REM: Format(instr, "rem 'rd, 'rs1, 'rs2"); break; case RO_REMU: Format(instr, "remu 'rd, 'rs1, 'rs2"); break; #ifdef V8_TARGET_ARCH_64_BIT case RO_MULW: Format(instr, "mulw 'rd, 'rs1, 'rs2"); break; case RO_DIVW: Format(instr, "divw 'rd, 'rs1, 'rs2"); break; case RO_DIVUW: Format(instr, "divuw 'rd, 'rs1, 'rs2"); break; case RO_REMW: Format(instr, "remw 'rd, 'rs1, 'rs2"); break; case RO_REMUW: Format(instr, "remuw 'rd, 'rs1, 'rs2"); break; #endif /*V8_TARGET_ARCH_64_BIT*/ // TODO(riscv): End Add RISCV M extension macro default: { switch (instr->BaseOpcode()) { case AMO: DecodeRAType(instr); break; case OP_FP: DecodeRFPType(instr); break; default: UNSUPPORTED_RISCV(); } } } } void Decoder::DecodeRAType(Instruction* instr) { // TODO(riscv): Add macro for RISCV A extension // Special handling for A extension instructions because it uses func5 // For all A extension instruction, V8 simulator is pure sequential. No // Memory address lock or other synchronizaiton behaviors. switch (instr->InstructionBits() & kRATypeMask) { case RO_LR_W: Format(instr, "lr.w'a 'rd, ('rs1)"); break; case RO_SC_W: Format(instr, "sc.w'a 'rd, 'rs2, ('rs1)"); break; case RO_AMOSWAP_W: Format(instr, "amoswap.w'a 'rd, 'rs2, ('rs1)"); break; case RO_AMOADD_W: Format(instr, "amoadd.w'a 'rd, 'rs2, ('rs1)"); break; case RO_AMOXOR_W: Format(instr, "amoxor.w'a 'rd, 'rs2, ('rs1)"); break; case RO_AMOAND_W: Format(instr, "amoand.w'a 'rd, 'rs2, ('rs1)"); break; case RO_AMOOR_W: Format(instr, "amoor.w'a 'rd, 'rs2, ('rs1)"); break; case RO_AMOMIN_W: Format(instr, "amomin.w'a 'rd, 'rs2, ('rs1)"); break; case RO_AMOMAX_W: Format(instr, "amomax.w'a 'rd, 'rs2, ('rs1)"); break; case RO_AMOMINU_W: Format(instr, "amominu.w'a 'rd, 'rs2, ('rs1)"); break; case RO_AMOMAXU_W: Format(instr, "amomaxu.w'a 'rd, 'rs2, ('rs1)"); break; #ifdef V8_TARGET_ARCH_64_BIT case RO_LR_D: Format(instr, "lr.d'a 'rd, ('rs1)"); break; case RO_SC_D: Format(instr, "sc.d'a 'rd, 'rs2, ('rs1)"); break; case RO_AMOSWAP_D: Format(instr, "amoswap.d'a 'rd, 'rs2, ('rs1)"); break; case RO_AMOADD_D: Format(instr, "amoadd.d'a 'rd, 'rs2, ('rs1)"); break; case RO_AMOXOR_D: Format(instr, "amoxor.d'a 'rd, 'rs2, ('rs1)"); break; case RO_AMOAND_D: Format(instr, "amoand.d'a 'rd, 'rs2, ('rs1)"); break; case RO_AMOOR_D: Format(instr, "amoor.d'a 'rd, 'rs2, ('rs1)"); break; case RO_AMOMIN_D: Format(instr, "amomin.d'a 'rd, 'rs2, ('rs1)"); break; case RO_AMOMAX_D: Format(instr, "amoswap.d'a 'rd, 'rs2, ('rs1)"); break; case RO_AMOMINU_D: Format(instr, "amominu.d'a 'rd, 'rs2, ('rs1)"); break; case RO_AMOMAXU_D: Format(instr, "amomaxu.d'a 'rd, 'rs2, ('rs1)"); break; #endif /*V8_TARGET_ARCH_64_BIT*/ // TODO(riscv): End Add macro for RISCV A extension default: { UNSUPPORTED_RISCV(); } } } void Decoder::DecodeRFPType(Instruction* instr) { // OP_FP instructions (F/D) uses func7 first. Some further uses fun3 and rs2() // kRATypeMask is only for func7 switch (instr->InstructionBits() & kRFPTypeMask) { // TODO(riscv): Add macro for RISCV F extension case RO_FADD_S: Format(instr, "fadd.s 'fd, 'fs1, 'fs2"); break; case RO_FSUB_S: Format(instr, "fsub.s 'fd, 'fs1, 'fs2"); break; case RO_FMUL_S: Format(instr, "fmul.s 'fd, 'fs1, 'fs2"); break; case RO_FDIV_S: Format(instr, "fdiv.s 'fd, 'fs1, 'fs2"); break; case RO_FSQRT_S: Format(instr, "fsqrt.s 'fd, 'fs1"); break; case RO_FSGNJ_S: { // RO_FSGNJN_S RO_FSGNJX_S switch (instr->Funct3Value()) { case 0b000: // RO_FSGNJ_S if (instr->Rs1Value() == instr->Rs2Value()) Format(instr, "fmv.s 'fd, 'fs1"); else Format(instr, "fsgnj.s 'fd, 'fs1, 'fs2"); break; case 0b001: // RO_FSGNJN_S if (instr->Rs1Value() == instr->Rs2Value()) Format(instr, "fneg.s 'fd, 'fs1"); else Format(instr, "fsgnjn.s 'fd, 'fs1, 'fs2"); break; case 0b010: // RO_FSGNJX_S if (instr->Rs1Value() == instr->Rs2Value()) Format(instr, "fabs.s 'fd, 'fs1"); else Format(instr, "fsgnjx.s 'fd, 'fs1, 'fs2"); break; default: UNSUPPORTED_RISCV(); } break; } case RO_FMIN_S: { // RO_FMAX_S switch (instr->Funct3Value()) { case 0b000: // RO_FMIN_S Format(instr, "fmin.s 'fd, 'fs1, 'fs2"); break; case 0b001: // RO_FMAX_S Format(instr, "fmax.s 'fd, 'fs1, 'fs2"); break; default: UNSUPPORTED_RISCV(); } break; } case RO_FCVT_W_S: { // RO_FCVT_WU_S , 64F RO_FCVT_L_S RO_FCVT_LU_S switch (instr->Rs2Value()) { case 0b00000: // RO_FCVT_W_S Format(instr, "fcvt.w.s ['frm] 'rd, 'fs1"); break; case 0b00001: // RO_FCVT_WU_S Format(instr, "fcvt.wu.s ['frm] 'rd, 'fs1"); break; #ifdef V8_TARGET_ARCH_64_BIT case 0b00010: // RO_FCVT_L_S Format(instr, "fcvt.l.s ['frm] 'rd, 'fs1"); break; case 0b00011: // RO_FCVT_LU_S Format(instr, "fcvt.lu.s ['frm] 'rd, 'fs1"); break; #endif /* V8_TARGET_ARCH_64_BIT */ default: UNSUPPORTED_RISCV(); } break; } case RO_FMV: { // RO_FCLASS_S if (instr->Rs2Value() != 0b00000) { UNSUPPORTED_RISCV(); } switch (instr->Funct3Value()) { case 0b000: // RO_FMV_X_W Format(instr, "fmv.x.w 'rd, 'fs1"); break; case 0b001: // RO_FCLASS_S Format(instr, "fclass.s 'rd, 'fs1"); break; default: UNSUPPORTED_RISCV(); } break; } case RO_FLE_S: { // RO_FEQ_S RO_FLT_S RO_FLE_S switch (instr->Funct3Value()) { case 0b010: // RO_FEQ_S Format(instr, "feq.s 'rd, 'fs1, 'fs2"); break; case 0b001: // RO_FLT_S Format(instr, "flt.s 'rd, 'fs1, 'fs2"); break; case 0b000: // RO_FLE_S Format(instr, "fle.s 'rd, 'fs1, 'fs2"); break; default: UNSUPPORTED_RISCV(); } break; } case RO_FCVT_S_W: { // RO_FCVT_S_WU , 64F RO_FCVT_S_L RO_FCVT_S_LU switch (instr->Rs2Value()) { case 0b00000: // RO_FCVT_S_W Format(instr, "fcvt.s.w 'fd, 'rs1"); break; case 0b00001: // RO_FCVT_S_WU Format(instr, "fcvt.s.wu 'fd, 'rs1"); break; #ifdef V8_TARGET_ARCH_64_BIT case 0b00010: // RO_FCVT_S_L Format(instr, "fcvt.s.l 'fd, 'rs1"); break; case 0b00011: // RO_FCVT_S_LU Format(instr, "fcvt.s.lu 'fd, 'rs1"); break; #endif /* V8_TARGET_ARCH_64_BIT */ default: { UNSUPPORTED_RISCV(); } } break; } case RO_FMV_W_X: { if (instr->Funct3Value() == 0b000) { Format(instr, "fmv.w.x 'fd, 'rs1"); } else { UNSUPPORTED_RISCV(); } break; } // TODO(riscv): Add macro for RISCV D extension case RO_FADD_D: Format(instr, "fadd.d 'fd, 'fs1, 'fs2"); break; case RO_FSUB_D: Format(instr, "fsub.d 'fd, 'fs1, 'fs2"); break; case RO_FMUL_D: Format(instr, "fmul.d 'fd, 'fs1, 'fs2"); break; case RO_FDIV_D: Format(instr, "fdiv.d 'fd, 'fs1, 'fs2"); break; case RO_FSQRT_D: { if (instr->Rs2Value() == 0b00000) { Format(instr, "fsqrt.d 'fd, 'fs1"); } else { UNSUPPORTED_RISCV(); } break; } case RO_FSGNJ_D: { // RO_FSGNJN_D RO_FSGNJX_D switch (instr->Funct3Value()) { case 0b000: // RO_FSGNJ_D if (instr->Rs1Value() == instr->Rs2Value()) Format(instr, "fmv.d 'fd, 'fs1"); else Format(instr, "fsgnj.d 'fd, 'fs1, 'fs2"); break; case 0b001: // RO_FSGNJN_D if (instr->Rs1Value() == instr->Rs2Value()) Format(instr, "fneg.d 'fd, 'fs1"); else Format(instr, "fsgnjn.d 'fd, 'fs1, 'fs2"); break; case 0b010: // RO_FSGNJX_D if (instr->Rs1Value() == instr->Rs2Value()) Format(instr, "fabs.d 'fd, 'fs1"); else Format(instr, "fsgnjx.d 'fd, 'fs1, 'fs2"); break; default: UNSUPPORTED_RISCV(); } break; } case RO_FMIN_D: { // RO_FMAX_D switch (instr->Funct3Value()) { case 0b000: // RO_FMIN_D Format(instr, "fmin.d 'fd, 'fs1, 'fs2"); break; case 0b001: // RO_FMAX_D Format(instr, "fmax.d 'fd, 'fs1, 'fs2"); break; default: UNSUPPORTED_RISCV(); } break; } case (RO_FCVT_S_D & kRFPTypeMask): { if (instr->Rs2Value() == 0b00001) { Format(instr, "fcvt.s.d ['frm] 'fd, 'rs1"); } else { UNSUPPORTED_RISCV(); } break; } case RO_FCVT_D_S: { if (instr->Rs2Value() == 0b00000) { Format(instr, "fcvt.d.s 'fd, 'fs1"); } else { UNSUPPORTED_RISCV(); } break; } case RO_FLE_D: { // RO_FEQ_D RO_FLT_D RO_FLE_D switch (instr->Funct3Value()) { case 0b010: // RO_FEQ_S Format(instr, "feq.d 'rd, 'fs1, 'fs2"); break; case 0b001: // RO_FLT_D Format(instr, "flt.d 'rd, 'fs1, 'fs2"); break; case 0b000: // RO_FLE_D Format(instr, "fle.d 'rd, 'fs1, 'fs2"); break; default: UNSUPPORTED_RISCV(); } break; } case (RO_FCLASS_D & kRFPTypeMask): { // RO_FCLASS_D , 64D RO_FMV_X_D if (instr->Rs2Value() != 0b00000) { UNSUPPORTED_RISCV(); break; } switch (instr->Funct3Value()) { case 0b001: // RO_FCLASS_D Format(instr, "fclass.d 'rd, 'fs1"); break; #ifdef V8_TARGET_ARCH_64_BIT case 0b000: // RO_FMV_X_D Format(instr, "fmv.x.d 'rd, 'fs1"); break; #endif /* V8_TARGET_ARCH_64_BIT */ default: UNSUPPORTED_RISCV(); } break; } case RO_FCVT_W_D: { // RO_FCVT_WU_D , 64F RO_FCVT_L_D RO_FCVT_LU_D switch (instr->Rs2Value()) { case 0b00000: // RO_FCVT_W_D Format(instr, "fcvt.w.d ['frm] 'rd, 'fs1"); break; case 0b00001: // RO_FCVT_WU_D Format(instr, "fcvt.wu.d ['frm] 'rd, 'fs1"); break; #ifdef V8_TARGET_ARCH_64_BIT case 0b00010: // RO_FCVT_L_D Format(instr, "fcvt.l.d ['frm] 'rd, 'fs1"); break; case 0b00011: // RO_FCVT_LU_D Format(instr, "fcvt.lu.d ['frm] 'rd, 'fs1"); break; #endif /* V8_TARGET_ARCH_64_BIT */ default: UNSUPPORTED_RISCV(); } break; } case RO_FCVT_D_W: { // RO_FCVT_D_WU , 64F RO_FCVT_D_L RO_FCVT_D_LU switch (instr->Rs2Value()) { case 0b00000: // RO_FCVT_D_W Format(instr, "fcvt.d.w 'fd, 'rs1"); break; case 0b00001: // RO_FCVT_D_WU Format(instr, "fcvt.d.wu 'fd, 'rs1"); break; #ifdef V8_TARGET_ARCH_64_BIT case 0b00010: // RO_FCVT_D_L Format(instr, "fcvt.d.l 'fd, 'rs1"); break; case 0b00011: // RO_FCVT_D_LU Format(instr, "fcvt.d.lu 'fd, 'rs1"); break; #endif /* V8_TARGET_ARCH_64_BIT */ default: UNSUPPORTED_RISCV(); } break; } #ifdef V8_TARGET_ARCH_64_BIT case RO_FMV_D_X: { if (instr->Funct3Value() == 0b000 && instr->Rs2Value() == 0b00000) { Format(instr, "fmv.d.x 'fd, 'rs1"); } else { UNSUPPORTED_RISCV(); } break; } #endif /* V8_TARGET_ARCH_64_BIT */ default: { UNSUPPORTED_RISCV(); } } } void Decoder::DecodeR4Type(Instruction* instr) { switch (instr->InstructionBits() & kR4TypeMask) { // TODO(riscv): use F Extension macro block case RO_FMADD_S: Format(instr, "fmadd.s 'fd, 'fs1, 'fs2, 'fs3"); break; case RO_FMSUB_S: Format(instr, "fmsub.s 'fd, 'fs1, 'fs2, 'fs3"); break; case RO_FNMSUB_S: Format(instr, "fnmsub.s 'fd, 'fs1, 'fs2, 'fs3"); break; case RO_FNMADD_S: Format(instr, "fnmadd.s 'fd, 'fs1, 'fs2, 'fs3"); break; // TODO(riscv): use F Extension macro block case RO_FMADD_D: Format(instr, "fmadd.d 'fd, 'fs1, 'fs2, 'fs3"); break; case RO_FMSUB_D: Format(instr, "fmsub.d 'fd, 'fs1, 'fs2, 'fs3"); break; case RO_FNMSUB_D: Format(instr, "fnmsub.d 'fd, 'fs1, 'fs2, 'fs3"); break; case RO_FNMADD_D: Format(instr, "fnmadd.d 'fd, 'fs1, 'fs2, 'fs3"); break; default: UNSUPPORTED_RISCV(); } } void Decoder::DecodeIType(Instruction* instr) { if (instr->vl_vs_width() != -1) { DecodeRvvVL(instr); } else { switch (instr->InstructionBits() & kITypeMask) { case RO_JALR: if (instr->RdValue() == zero_reg.code() && instr->Rs1Value() == ra.code() && instr->Imm12Value() == 0) Format(instr, "ret"); else if (instr->RdValue() == zero_reg.code() && instr->Imm12Value() == 0) Format(instr, "jr 'rs1"); else if (instr->RdValue() == ra.code() && instr->Imm12Value() == 0) Format(instr, "jalr 'rs1"); else Format(instr, "jalr 'rd, 'imm12('rs1)"); break; case RO_LB: Format(instr, "lb 'rd, 'imm12('rs1)"); break; case RO_LH: Format(instr, "lh 'rd, 'imm12('rs1)"); break; case RO_LW: Format(instr, "lw 'rd, 'imm12('rs1)"); break; case RO_LBU: Format(instr, "lbu 'rd, 'imm12('rs1)"); break; case RO_LHU: Format(instr, "lhu 'rd, 'imm12('rs1)"); break; #ifdef V8_TARGET_ARCH_64_BIT case RO_LWU: Format(instr, "lwu 'rd, 'imm12('rs1)"); break; case RO_LD: Format(instr, "ld 'rd, 'imm12('rs1)"); break; #endif /*V8_TARGET_ARCH_64_BIT*/ case RO_ADDI: if (instr->Imm12Value() == 0) { if (instr->RdValue() == zero_reg.code() && instr->Rs1Value() == zero_reg.code()) Format(instr, "nop"); else Format(instr, "mv 'rd, 'rs1"); } else if (instr->Rs1Value() == zero_reg.code()) { Format(instr, "li 'rd, 'imm12"); } else { Format(instr, "addi 'rd, 'rs1, 'imm12"); } break; case RO_SLTI: Format(instr, "slti 'rd, 'rs1, 'imm12"); break; case RO_SLTIU: if (instr->Imm12Value() == 1) Format(instr, "seqz 'rd, 'rs1"); else Format(instr, "sltiu 'rd, 'rs1, 'imm12"); break; case RO_XORI: if (instr->Imm12Value() == -1) Format(instr, "not 'rd, 'rs1"); else Format(instr, "xori 'rd, 'rs1, 'imm12x"); break; case RO_ORI: Format(instr, "ori 'rd, 'rs1, 'imm12x"); break; case RO_ANDI: Format(instr, "andi 'rd, 'rs1, 'imm12x"); break; case RO_SLLI: Format(instr, "slli 'rd, 'rs1, 's64"); break; case RO_SRLI: { // RO_SRAI if (!instr->IsArithShift()) { Format(instr, "srli 'rd, 'rs1, 's64"); } else { Format(instr, "srai 'rd, 'rs1, 's64"); } break; } #ifdef V8_TARGET_ARCH_64_BIT case RO_ADDIW: if (instr->Imm12Value() == 0) Format(instr, "sext.w 'rd, 'rs1"); else Format(instr, "addiw 'rd, 'rs1, 'imm12"); break; case RO_SLLIW: Format(instr, "slliw 'rd, 'rs1, 's32"); break; case RO_SRLIW: { // RO_SRAIW if (!instr->IsArithShift()) { Format(instr, "srliw 'rd, 'rs1, 's32"); } else { Format(instr, "sraiw 'rd, 'rs1, 's32"); } break; } #endif /*V8_TARGET_ARCH_64_BIT*/ case RO_FENCE: if (instr->MemoryOrder(true) == PSIORW && instr->MemoryOrder(false) == PSIORW) Format(instr, "fence"); else Format(instr, "fence 'pre, 'suc"); break; case RO_ECALL: { // RO_EBREAK if (instr->Imm12Value() == 0) { // ECALL Format(instr, "ecall"); } else if (instr->Imm12Value() == 1) { // EBREAK Format(instr, "ebreak"); } else { UNSUPPORTED_RISCV(); } break; } // TODO(riscv): use Zifencei Standard Extension macro block case RO_FENCE_I: Format(instr, "fence.i"); break; // TODO(riscv): use Zicsr Standard Extension macro block // FIXME(RISC-V): Add special formatting for CSR registers case RO_CSRRW: if (instr->CsrValue() == csr_fcsr) { if (instr->RdValue() == zero_reg.code()) Format(instr, "fscsr 'rs1"); else Format(instr, "fscsr 'rd, 'rs1"); } else if (instr->CsrValue() == csr_frm) { if (instr->RdValue() == zero_reg.code()) Format(instr, "fsrm 'rs1"); else Format(instr, "fsrm 'rd, 'rs1"); } else if (instr->CsrValue() == csr_fflags) { if (instr->RdValue() == zero_reg.code()) Format(instr, "fsflags 'rs1"); else Format(instr, "fsflags 'rd, 'rs1"); } else if (instr->RdValue() == zero_reg.code()) { Format(instr, "csrw 'csr, 'rs1"); } else { Format(instr, "csrrw 'rd, 'csr, 'rs1"); } break; case RO_CSRRS: if (instr->Rs1Value() == zero_reg.code()) { switch (instr->CsrValue()) { case csr_instret: Format(instr, "rdinstret 'rd"); break; case csr_instreth: Format(instr, "rdinstreth 'rd"); break; case csr_time: Format(instr, "rdtime 'rd"); break; case csr_timeh: Format(instr, "rdtimeh 'rd"); break; case csr_cycle: Format(instr, "rdcycle 'rd"); break; case csr_cycleh: Format(instr, "rdcycleh 'rd"); break; case csr_fflags: Format(instr, "frflags 'rd"); break; case csr_frm: Format(instr, "frrm 'rd"); break; case csr_fcsr: Format(instr, "frcsr 'rd"); break; default: UNREACHABLE(); } } else if (instr->Rs1Value() == zero_reg.code()) { Format(instr, "csrr 'rd, 'csr"); } else if (instr->RdValue() == zero_reg.code()) { Format(instr, "csrs 'csr, 'rs1"); } else { Format(instr, "csrrs 'rd, 'csr, 'rs1"); } break; case RO_CSRRC: if (instr->RdValue() == zero_reg.code()) Format(instr, "csrc 'csr, 'rs1"); else Format(instr, "csrrc 'rd, 'csr, 'rs1"); break; case RO_CSRRWI: if (instr->RdValue() == zero_reg.code()) Format(instr, "csrwi 'csr, 'uimm"); else Format(instr, "csrrwi 'rd, 'csr, 'uimm"); break; case RO_CSRRSI: if (instr->RdValue() == zero_reg.code()) Format(instr, "csrsi 'csr, 'uimm"); else Format(instr, "csrrsi 'rd, 'csr, 'uimm"); break; case RO_CSRRCI: if (instr->RdValue() == zero_reg.code()) Format(instr, "csrci 'csr, 'uimm"); else Format(instr, "csrrci 'rd, 'csr, 'uimm"); break; // TODO(riscv): use F Extension macro block case RO_FLW: Format(instr, "flw 'fd, 'imm12('rs1)"); break; // TODO(riscv): use D Extension macro block case RO_FLD: Format(instr, "fld 'fd, 'imm12('rs1)"); break; default: UNSUPPORTED_RISCV(); } } } void Decoder::DecodeSType(Instruction* instr) { if (instr->vl_vs_width() != -1) { DecodeRvvVS(instr); } else { switch (instr->InstructionBits() & kSTypeMask) { case RO_SB: Format(instr, "sb 'rs2, 'offS('rs1)"); break; case RO_SH: Format(instr, "sh 'rs2, 'offS('rs1)"); break; case RO_SW: Format(instr, "sw 'rs2, 'offS('rs1)"); break; #ifdef V8_TARGET_ARCH_64_BIT case RO_SD: Format(instr, "sd 'rs2, 'offS('rs1)"); break; #endif /*V8_TARGET_ARCH_64_BIT*/ // TODO(riscv): use F Extension macro block case RO_FSW: Format(instr, "fsw 'fs2, 'offS('rs1)"); break; // TODO(riscv): use D Extension macro block case RO_FSD: Format(instr, "fsd 'fs2, 'offS('rs1)"); break; default: UNSUPPORTED_RISCV(); } } } void Decoder::DecodeBType(Instruction* instr) { switch (instr->InstructionBits() & kBTypeMask) { case RO_BEQ: Format(instr, "beq 'rs1, 'rs2, 'offB"); break; case RO_BNE: Format(instr, "bne 'rs1, 'rs2, 'offB"); break; case RO_BLT: Format(instr, "blt 'rs1, 'rs2, 'offB"); break; case RO_BGE: Format(instr, "bge 'rs1, 'rs2, 'offB"); break; case RO_BLTU: Format(instr, "bltu 'rs1, 'rs2, 'offB"); break; case RO_BGEU: Format(instr, "bgeu 'rs1, 'rs2, 'offB"); break; default: UNSUPPORTED_RISCV(); } } void Decoder::DecodeUType(Instruction* instr) { // U Type doesn't have additional mask switch (instr->BaseOpcodeFieldRaw()) { case RO_LUI: Format(instr, "lui 'rd, 'imm20U"); break; case RO_AUIPC: Format(instr, "auipc 'rd, 'imm20U"); break; default: UNSUPPORTED_RISCV(); } } // namespace internal void Decoder::DecodeJType(Instruction* instr) { // J Type doesn't have additional mask switch (instr->BaseOpcodeValue()) { case RO_JAL: if (instr->RdValue() == zero_reg.code()) Format(instr, "j 'imm20J"); else if (instr->RdValue() == ra.code()) Format(instr, "jal 'imm20J"); else Format(instr, "jal 'rd, 'imm20J"); break; default: UNSUPPORTED_RISCV(); } } void Decoder::DecodeCRType(Instruction* instr) { switch (instr->RvcFunct4Value()) { case 0b1000: if (instr->RvcRs1Value() != 0 && instr->RvcRs2Value() == 0) Format(instr, "jr 'Crs1"); else if (instr->RvcRdValue() != 0 && instr->RvcRs2Value() != 0) Format(instr, "mv 'Crd, 'Crs2"); else UNSUPPORTED_RISCV(); break; case 0b1001: if (instr->RvcRs1Value() == 0 && instr->RvcRs2Value() == 0) Format(instr, "ebreak"); else if (instr->RvcRdValue() != 0 && instr->RvcRs2Value() == 0) Format(instr, "jalr 'Crs1"); else if (instr->RvcRdValue() != 0 && instr->RvcRs2Value() != 0) Format(instr, "add 'Crd, 'Crd, 'Crs2"); else UNSUPPORTED_RISCV(); break; default: UNSUPPORTED_RISCV(); } } void Decoder::DecodeCAType(Instruction* instr) { switch (instr->InstructionBits() & kCATypeMask) { case RO_C_SUB: Format(instr, "sub 'Crs1s, 'Crs1s, 'Crs2s"); break; case RO_C_XOR: Format(instr, "xor 'Crs1s, 'Crs1s, 'Crs2s"); break; case RO_C_OR: Format(instr, "or 'Crs1s, 'Crs1s, 'Crs2s"); break; case RO_C_AND: Format(instr, "and 'Crs1s, 'Crs1s, 'Crs2s"); break; case RO_C_SUBW: Format(instr, "subw 'Crs1s, 'Crs1s, 'Crs2s"); break; case RO_C_ADDW: Format(instr, "addw 'Crs1s, 'Crs1s, 'Crs2s"); break; default: UNSUPPORTED_RISCV(); } } void Decoder::DecodeCIType(Instruction* instr) { switch (instr->RvcOpcode()) { case RO_C_NOP_ADDI: if (instr->RvcRdValue() == 0) Format(instr, "nop"); else Format(instr, "addi 'Crd, 'Crd, 'Cimm6"); break; case RO_C_ADDIW: Format(instr, "addiw 'Crd, 'Crd, 'Cimm6"); break; case RO_C_LI: Format(instr, "li 'Crd, 'Cimm6"); break; case RO_C_LUI_ADD: if (instr->RvcRdValue() == 2) Format(instr, "addi sp, sp, 'Cimm6Addi16sp"); else if (instr->RvcRdValue() != 0 && instr->RvcRdValue() != 2) Format(instr, "lui 'Crd, 'Cimm6U"); else UNSUPPORTED_RISCV(); break; case RO_C_SLLI: Format(instr, "slli 'Crd, 'Crd, 'Cshamt"); break; case RO_C_FLDSP: Format(instr, "fld 'Cfd, 'Cimm6Ldsp(sp)"); break; case RO_C_LWSP: Format(instr, "lw 'Crd, 'Cimm6Lwsp(sp)"); break; case RO_C_LDSP: Format(instr, "ld 'Crd, 'Cimm6Ldsp(sp)"); break; default: UNSUPPORTED_RISCV(); } } void Decoder::DecodeCIWType(Instruction* instr) { switch (instr->RvcOpcode()) { case RO_C_ADDI4SPN: Format(instr, "addi 'Crs2s, sp, 'Cimm8Addi4spn"); break; default: UNSUPPORTED_RISCV(); } } void Decoder::DecodeCSSType(Instruction* instr) { switch (instr->RvcOpcode()) { case RO_C_SWSP: Format(instr, "sw 'Crs2, 'Cimm6Swsp(sp)"); break; case RO_C_SDSP: Format(instr, "sd 'Crs2, 'Cimm6Sdsp(sp)"); break; case RO_C_FSDSP: Format(instr, "fsd 'Cfs2, 'Cimm6Sdsp(sp)"); break; default: UNSUPPORTED_RISCV(); } } void Decoder::DecodeCLType(Instruction* instr) { switch (instr->RvcOpcode()) { case RO_C_FLD: Format(instr, "fld 'Cfs2s, 'Cimm5D('Crs1s)"); break; case RO_C_LW: Format(instr, "lw 'Crs2s, 'Cimm5W('Crs1s)"); break; case RO_C_LD: Format(instr, "ld 'Crs2s, 'Cimm5D('Crs1s)"); break; default: UNSUPPORTED_RISCV(); } } void Decoder::DecodeCSType(Instruction* instr) { switch (instr->RvcOpcode()) { case RO_C_FSD: Format(instr, "fsd 'Cfs2s, 'Cimm5D('Crs1s)"); break; case RO_C_SW: Format(instr, "sw 'Crs2s, 'Cimm5W('Crs1s)"); break; case RO_C_SD: Format(instr, "sd 'Crs2s, 'Cimm5D('Crs1s)"); break; default: UNSUPPORTED_RISCV(); } } void Decoder::DecodeCJType(Instruction* instr) { switch (instr->RvcOpcode()) { case RO_C_J: Format(instr, "j 'Cimm11CJ"); break; default: UNSUPPORTED_RISCV(); } } void Decoder::DecodeCBType(Instruction* instr) { switch (instr->RvcOpcode()) { case RO_C_BNEZ: Format(instr, "bnez 'Crs1s, x0, 'Cimm8B"); break; case RO_C_BEQZ: Format(instr, "beqz 'Crs1s, x0, 'Cimm8B"); break; case RO_C_MISC_ALU: if (instr->RvcFunct2BValue() == 0b00) Format(instr, "srli 'Crs1s, 'Crs1s, 'Cshamt"); else if (instr->RvcFunct2BValue() == 0b01) Format(instr, "srai 'Crs1s, 'Crs1s, 'Cshamt"); else if (instr->RvcFunct2BValue() == 0b10) Format(instr, "andi 'Crs1s, 'Crs1s, 'Cimm6"); else UNSUPPORTED_RISCV(); break; default: UNSUPPORTED_RISCV(); } } void Decoder::DecodeRvvIVV(Instruction* instr) { DCHECK_EQ(instr->InstructionBits() & (kBaseOpcodeMask | kFunct3Mask), OP_IVV); switch (instr->InstructionBits() & kVTypeMask) { case RO_V_VADD_VV: Format(instr, "vadd.vv 'vd, 'vs2, 'vs1'vm"); break; case RO_V_VSADD_VV: Format(instr, "vsadd.vv 'vd, 'vs2, 'vs1'vm"); break; case RO_V_VSADDU_VV: Format(instr, "vsaddu.vv 'vd, 'vs2, 'vs1'vm"); break; case RO_V_VSUB_VV: Format(instr, "vsub.vv 'vd, 'vs2, 'vs1'vm"); break; case RO_V_VSSUB_VV: Format(instr, "vssub.vv 'vd, 'vs2, 'vs1'vm"); break; case RO_V_VSSUBU_VV: Format(instr, "vssubu.vv 'vd, 'vs2, 'vs1'vm"); break; case RO_V_VMIN_VV: Format(instr, "vmin.vv 'vd, 'vs2, 'vs1'vm"); break; case RO_V_VMINU_VV: Format(instr, "vminu.vv 'vd, 'vs2, 'vs1'vm"); break; case RO_V_VMAX_VV: Format(instr, "vmax.vv 'vd, 'vs2, 'vs1'vm"); break; case RO_V_VMAXU_VV: Format(instr, "vmaxu.vv 'vd, 'vs2, 'vs1'vm"); break; case RO_V_VAND_VV: Format(instr, "vand.vv 'vd, 'vs2, 'vs1'vm"); break; case RO_V_VOR_VV: Format(instr, "vor.vv 'vd, 'vs2, 'vs1'vm"); break; case RO_V_VXOR_VV: Format(instr, "vxor.vv 'vd, 'vs2, 'vs1'vm"); break; case RO_V_VRGATHER_VV: Format(instr, "vrgather.vv 'vd, 'vs2, 'vs1'vm"); break; case RO_V_VMSEQ_VV: Format(instr, "vmseq.vv 'vd, 'vs2, 'vs1'vm"); break; case RO_V_VMSNE_VV: Format(instr, "vmsne.vv 'vd, 'vs2, 'vs1'vm"); break; case RO_V_VMSLT_VV: Format(instr, "vmslt.vv 'vd, 'vs2, 'vs1'vm"); break; case RO_V_VMSLTU_VV: Format(instr, "vmsltu.vv 'vd, 'vs2, 'vs1'vm"); break; case RO_V_VMSLE_VV: Format(instr, "vmsle.vv 'vd, 'vs2, 'vs1'vm"); break; case RO_V_VMSLEU_VV: Format(instr, "vmsleu.vv 'vd, 'vs2, 'vs1'vm"); break; case RO_V_VMV_VV: if (instr->RvvVM()) { Format(instr, "vmv.vv 'vd, 'vs1"); } else { Format(instr, "vmerge.vvm 'vd, 'vs2, 'vs1, v0"); } break; case RO_V_VADC_VV: if (!instr->RvvVM()) { Format(instr, "vadc.vvm 'vd, 'vs2, 'vs1"); } else { UNREACHABLE(); } break; case RO_V_VMADC_VV: if (!instr->RvvVM()) { Format(instr, "vmadc.vvm 'vd, 'vs2, 'vs1"); } else { UNREACHABLE(); } break; case RO_V_VNCLIP_WV: Format(instr, "vnclip.wv 'vd, 'vs2, 'vs1"); break; case RO_V_VNCLIPU_WV: Format(instr, "vnclipu.wv 'vd, 'vs2, 'vs1"); break; case RO_V_VSLL_VV: Format(instr, "vsll.vv 'vd, 'vs2, 'vs1"); break; case RO_V_VSRL_VV: Format(instr, "vsrl.vv 'vd, 'vs2, 'vs1"); break; case RO_V_VSRA_VV: Format(instr, "vsra.vv 'vd, 'vs2, 'vs1"); break; case RO_V_VSMUL_VV: Format(instr, "vsmul.vv 'vd, 'vs2, 'vs1"); break; default: UNSUPPORTED_RISCV(); break; } } void Decoder::DecodeRvvIVI(Instruction* instr) { DCHECK_EQ(instr->InstructionBits() & (kBaseOpcodeMask | kFunct3Mask), OP_IVI); switch (instr->InstructionBits() & kVTypeMask) { case RO_V_VADD_VI: Format(instr, "vadd.vi 'vd, 'vs2, 'simm5'vm"); break; case RO_V_VSADD_VI: Format(instr, "vsadd.vi 'vd, 'vs2, 'simm5'vm"); break; case RO_V_VSADDU_VI: Format(instr, "vsaddu.vi 'vd, 'vs2, 'simm5'vm"); break; case RO_V_VRSUB_VI: Format(instr, "vrsub.vi 'vd, 'vs2, 'simm5'vm"); break; case RO_V_VAND_VI: Format(instr, "vand.vi 'vd, 'vs2, 'simm5'vm"); break; case RO_V_VOR_VI: Format(instr, "vor.vi 'vd, 'vs2, 'simm5'vm"); break; case RO_V_VXOR_VI: Format(instr, "vxor.vi 'vd, 'vs2, 'simm5'vm"); break; case RO_V_VRGATHER_VI: Format(instr, "vrgather.vi 'vd, 'vs2, 'simm5'vm"); break; case RO_V_VMV_VI: if (instr->RvvVM()) { Format(instr, "vmv.vi 'vd, 'simm5"); } else { Format(instr, "vmerge.vim 'vd, 'vs2, 'simm5, v0"); } break; case RO_V_VMSEQ_VI: Format(instr, "vmseq.vi 'vd, 'vs2, 'simm5'vm"); break; case RO_V_VMSNE_VI: Format(instr, "vmsne.vi 'vd, 'vs2, 'simm5'vm"); break; case RO_V_VMSLEU_VI: Format(instr, "vmsleu.vi 'vd, 'vs2, 'simm5'vm"); break; case RO_V_VMSLE_VI: Format(instr, "vmsle.vi 'vd, 'vs2, 'simm5'vm"); break; case RO_V_VMSGTU_VI: Format(instr, "vmsgtu.vi 'vd, 'vs2, 'simm5'vm"); break; case RO_V_VMSGT_VI: Format(instr, "vmsgt.vi 'vd, 'vs2, 'simm5'vm"); break; case RO_V_VSLIDEDOWN_VI: Format(instr, "vslidedown.vi 'vd, 'vs2, 'uimm5'vm"); break; case RO_V_VSLIDEUP_VI: Format(instr, "vslideup.vi 'vd, 'vs2, 'uimm5'vm"); break; case RO_V_VSRL_VI: Format(instr, "vsrl.vi 'vd, 'vs2, 'uimm5'vm"); break; case RO_V_VSRA_VI: Format(instr, "vsra.vi 'vd, 'vs2, 'uimm5'vm"); break; case RO_V_VSLL_VI: Format(instr, "vsll.vi 'vd, 'vs2, 'uimm5'vm"); break; case RO_V_VADC_VI: if (!instr->RvvVM()) { Format(instr, "vadc.vim 'vd, 'vs2, 'uimm5"); } else { UNREACHABLE(); } break; case RO_V_VMADC_VI: if (!instr->RvvVM()) { Format(instr, "vmadc.vim 'vd, 'vs2, 'uimm5"); } else { UNREACHABLE(); } break; case RO_V_VNCLIP_WI: Format(instr, "vnclip.wi 'vd, 'vs2, 'uimm5"); break; case RO_V_VNCLIPU_WI: Format(instr, "vnclipu.wi 'vd, 'vs2, 'uimm5"); break; default: UNSUPPORTED_RISCV(); break; } } void Decoder::DecodeRvvIVX(Instruction* instr) { DCHECK_EQ(instr->InstructionBits() & (kBaseOpcodeMask | kFunct3Mask), OP_IVX); switch (instr->InstructionBits() & kVTypeMask) { case RO_V_VADD_VX: Format(instr, "vadd.vx 'vd, 'vs2, 'rs1'vm"); break; case RO_V_VSADD_VX: Format(instr, "vsadd.vx 'vd, 'vs2, 'rs1'vm"); break; case RO_V_VSADDU_VX: Format(instr, "vsaddu.vx 'vd, 'vs2, 'rs1'vm"); break; case RO_V_VSUB_VX: Format(instr, "vsub.vx 'vd, 'vs2, 'rs1'vm"); break; case RO_V_VSSUB_VX: Format(instr, "vssub.vx 'vd, 'vs2, 'rs1'vm"); break; case RO_V_VRSUB_VX: Format(instr, "vrsub.vx 'vd, 'vs2, 'rs1'vm"); break; case RO_V_VMIN_VX: Format(instr, "vmin.vx 'vd, 'vs2, 'rs1'vm"); break; case RO_V_VMINU_VX: Format(instr, "vminu.vx 'vd, 'vs2, 'rs1'vm"); break; case RO_V_VMAX_VX: Format(instr, "vmax.vx 'vd, 'vs2, 'rs1'vm"); break; case RO_V_VMAXU_VX: Format(instr, "vmaxu.vx 'vd, 'vs2, 'rs1'vm"); break; case RO_V_VAND_VX: Format(instr, "vand.vx 'vd, 'vs2, 'rs1'vm"); break; case RO_V_VOR_VX: Format(instr, "vor.vx 'vd, 'vs2, 'rs1'vm"); break; case RO_V_VXOR_VX: Format(instr, "vxor.vx 'vd, 'vs2, 'rs1'vm"); break; case RO_V_VRGATHER_VX: Format(instr, "vrgather.vx 'vd, 'vs2, 'rs1'vm"); break; case RO_V_VMV_VX: if (instr->RvvVM()) { Format(instr, "vmv.vx 'vd, 'rs1"); } else { Format(instr, "vmerge.vxm 'vd, 'vs2, 'rs1, v0"); } break; case RO_V_VMSEQ_VX: Format(instr, "vmseq.vx 'vd, 'vs2, 'rs1'vm"); break; case RO_V_VMSNE_VX: Format(instr, "vmsne.vx 'vd, 'vs2, 'rs1'vm"); break; case RO_V_VMSLT_VX: Format(instr, "vmslt.vx 'vd, 'vs2, 'rs1'vm"); break; case RO_V_VMSLTU_VX: Format(instr, "vmsltu.vx 'vd, 'vs2, 'rs1'vm"); break; case RO_V_VMSLE_VX: Format(instr, "vmsle.vx 'vd, 'vs2, 'rs1'vm"); break; case RO_V_VMSLEU_VX: Format(instr, "vmsleu.vx 'vd, 'vs2, 'rs1'vm"); break; case RO_V_VMSGT_VX: Format(instr, "vmsgt.vx 'vd, 'vs2, 'rs1'vm"); break; case RO_V_VMSGTU_VX: Format(instr, "vmsgtu.vx 'vd, 'vs2, 'rs1'vm"); break; case RO_V_VSLIDEDOWN_VX: Format(instr, "vslidedown.vx 'vd, 'vs2, 'rs1'vm"); break; case RO_V_VADC_VX: if (!instr->RvvVM()) { Format(instr, "vadc.vxm 'vd, 'vs2, 'rs1"); } else { UNREACHABLE(); } break; case RO_V_VMADC_VX: if (!instr->RvvVM()) { Format(instr, "vmadc.vxm 'vd, 'vs2, 'rs1"); } else { UNREACHABLE(); } break; case RO_V_VSLL_VX: Format(instr, "vsll.vx 'vd, 'vs2, 'rs1"); break; case RO_V_VSRL_VX: Format(instr, "vsrl.vx 'vd, 'vs2, 'rs1"); break; case RO_V_VSRA_VX: Format(instr, "vsra.vx 'vd, 'vs2, 'rs1"); break; case RO_V_VNCLIP_WX: Format(instr, "vnclip.wx 'vd, 'vs2, 'rs1"); break; case RO_V_VNCLIPU_WX: Format(instr, "vnclipu.wx 'vd, 'vs2, 'rs1"); break; case RO_V_VSMUL_VX: Format(instr, "vsmul.vx 'vd, 'vs2, 'vs1"); break; default: UNSUPPORTED_RISCV(); break; } } void Decoder::DecodeRvvMVV(Instruction* instr) { DCHECK_EQ(instr->InstructionBits() & (kBaseOpcodeMask | kFunct3Mask), OP_MVV); switch (instr->InstructionBits() & kVTypeMask) { case RO_V_VMUNARY0: { if (instr->Vs1Value() == VID_V) { Format(instr, "vid.v 'rd, 'vs2'vm"); } else { UNSUPPORTED_RISCV(); } break; } case RO_V_VWXUNARY0: if (instr->Vs1Value() == 0x0) { Format(instr, "vmv.x.s 'rd, 'vs2"); } else if (instr->Vs1Value() == 0b10001) { Format(instr, "vfirst.m 'rd, 'vs2"); } else if (instr->Vs1Value() == 0b10000) { Format(instr, "vcpop.m 'rd, 'vs2"); } else { UNSUPPORTED_RISCV(); } break; case RO_V_VREDMAXU: Format(instr, "vredmaxu.vs 'vd, 'vs2, 'vs1'vm"); break; case RO_V_VREDMAX: Format(instr, "vredmax.vs 'vd, 'vs2, 'vs1'vm"); break; case RO_V_VREDMIN: Format(instr, "vredmin.vs 'vd, 'vs2, 'vs1'vm"); break; case RO_V_VREDMINU: Format(instr, "vredminu.vs 'vd, 'vs2, 'vs1'vm"); break; case RO_V_VXUNARY0: if (instr->Vs1Value() == 0b00010) { Format(instr, "vzext.vf8 'vd, 'vs2'vm"); } else if (instr->Vs1Value() == 0b00011) { Format(instr, "vsext.vf8 'vd, 'vs2'vm"); } else if (instr->Vs1Value() == 0b00100) { Format(instr, "vzext.vf4 'vd, 'vs2'vm"); } else if (instr->Vs1Value() == 0b00101) { Format(instr, "vsext.vf4 'vd, 'vs2'vm"); } else if (instr->Vs1Value() == 0b00110) { Format(instr, "vzext.vf2 'vd, 'vs2'vm"); } else if (instr->Vs1Value() == 0b00111) { Format(instr, "vsext.vf2 'vd, 'vs2'vm"); } else { UNSUPPORTED_RISCV(); } break; case RO_V_VWMUL_VV: Format(instr, "vwmul.vv 'vd, 'vs2, 'vs1'vm"); break; case RO_V_VWMULU_VV: Format(instr, "vwmulu.vv 'vd, 'vs2, 'vs1'vm"); break; case RO_V_VMUL_VV: Format(instr, "vmul.vv 'vd, 'vs2, 'vs1'vm"); break; case RO_V_VMULHU_VV: Format(instr, "vmulhu.vv 'vd, 'vs2, 'vs1'vm"); break; case RO_V_VDIV_VV: Format(instr, "vdiv.vv 'vd, 'vs2, 'vs1'vm"); break; case RO_V_VDIVU_VV: Format(instr, "vdivu.vv 'vd, 'vs2, 'vs1'vm"); break; case RO_V_VWADDU_VV: Format(instr, "vwaddu.vv 'vd, 'vs2, 'vs1'vm"); break; case RO_V_VWADD_VV: Format(instr, "vwadd.vv 'vd, 'vs2, 'vs1'vm"); break; case RO_V_VCOMPRESS_VV: Format(instr, "vcompress.vm 'vd, 'vs2, 'vs1'vm"); break; default: UNSUPPORTED_RISCV(); break; } } void Decoder::DecodeRvvMVX(Instruction* instr) { DCHECK_EQ(instr->InstructionBits() & (kBaseOpcodeMask | kFunct3Mask), OP_MVX); switch (instr->InstructionBits() & kVTypeMask) { case RO_V_VRXUNARY0: if (instr->Vs2Value() == 0x0) { Format(instr, "vmv.s.x 'vd, 'rs1"); } else { UNSUPPORTED_RISCV(); } break; case RO_V_VWMUL_VX: Format(instr, "vwmul.vx 'vd, 'vs2, 'rs1'vm"); break; case RO_V_VWMULU_VX: Format(instr, "vwmulu.vx 'vd, 'vs2, 'rs1'vm"); break; case RO_V_VMUL_VX: Format(instr, "vmul.vx 'vd, 'vs2, 'rs1'vm"); break; case RO_V_VMULHU_VX: Format(instr, "vmulhu.vx 'vd, 'vs2, 'rs1'vm"); break; case RO_V_VDIV_VX: Format(instr, "vdiv.vx 'vd, 'vs2, 'rs1'vm"); break; case RO_V_VDIVU_VX: Format(instr, "vdivu.vx 'vd, 'vs2, 'rs1'vm"); break; case RO_V_VWADDUW_VX: Format(instr, "vwaddu.wx 'vd, 'vs2, 'rs1'vm"); break; case RO_V_VWADDU_VX: Format(instr, "vwaddu.vx 'vd, 'vs2, 'rs1'vm"); break; case RO_V_VWADD_VX: Format(instr, "vwadd.vx 'vd, 'vs2, 'rs1'vm"); break; default: UNSUPPORTED_RISCV(); break; } } void Decoder::DecodeRvvFVV(Instruction* instr) { DCHECK_EQ(instr->InstructionBits() & (kBaseOpcodeMask | kFunct3Mask), OP_FVV); switch (instr->InstructionBits() & kVTypeMask) { case RO_V_VFUNARY0: switch (instr->Vs1Value()) { case VFCVT_XU_F_V: Format(instr, "vfcvt.xu.f.v 'vd, 'vs2'vm"); break; case VFCVT_X_F_V: Format(instr, "vfcvt.x.f.v 'vd, 'vs2'vm"); break; case VFNCVT_F_F_W: Format(instr, "vfncvt.f.f.w 'vd, 'vs2'vm"); break; case VFNCVT_X_F_W: Format(instr, "vfncvt.x.f.w 'vd, 'vs2'vm"); break; case VFNCVT_XU_F_W: Format(instr, "vfncvt.xu.f.w 'vd, 'vs2'vm"); break; case VFCVT_F_X_V: Format(instr, "vfcvt.f.x.v 'vd, 'vs2'vm"); break; case VFCVT_F_XU_V: Format(instr, "vfcvt.f.xu.v 'vd, 'vs2'vm"); break; case VFWCVT_XU_F_V: Format(instr, "vfwcvt.xu.f.v 'vd, 'vs2'vm"); break; case VFWCVT_X_F_V: Format(instr, "vfwcvt.x.f.v 'vd, 'vs2'vm"); break; case VFWCVT_F_X_V: Format(instr, "vfwcvt.f.x.v 'vd, 'vs2'vm"); break; case VFWCVT_F_XU_V: Format(instr, "vfwcvt.f.xu.v 'vd, 'vs2'vm"); break; case VFWCVT_F_F_V: Format(instr, "vfwcvt.f.f.v 'vd, 'vs2'vm"); break; default: UNSUPPORTED_RISCV(); break; } break; case RO_V_VFUNARY1: switch (instr->Vs1Value()) { case VFCLASS_V: Format(instr, "vfclass.v 'vd, 'vs2'vm"); break; case VFSQRT_V: Format(instr, "vfsqrt.v 'vd, 'vs2'vm"); break; case VFRSQRT7_V: Format(instr, "vfrsqrt7.v 'vd, 'vs2'vm"); break; case VFREC7_V: Format(instr, "vfrec7.v 'vd, 'vs2'vm"); break; default: break; } break; case RO_V_VMFEQ_VV: Format(instr, "vmfeq.vv 'vd, 'vs2, 'vs1'vm"); break; case RO_V_VMFNE_VV: Format(instr, "vmfne.vv 'vd, 'vs2, 'vs1'vm"); break; case RO_V_VMFLT_VV: Format(instr, "vmflt.vv 'vd, 'vs2, 'vs1'vm"); break; case RO_V_VMFLE_VV: Format(instr, "vmfle.vv 'vd, 'vs2, 'vs1'vm"); break; case RO_V_VFMAX_VV: Format(instr, "vfmax.vv 'vd, 'vs2, 'vs1'vm"); break; case RO_V_VFREDMAX_VV: Format(instr, "vfredmax.vs 'vd, 'vs2, 'vs1'vm"); break; case RO_V_VFMIN_VV: Format(instr, "vfmin.vv 'vd, 'vs2, 'vs1'vm"); break; case RO_V_VFSGNJ_VV: Format(instr, "vfsgnj.vv 'vd, 'vs2, 'vs1'vm"); break; case RO_V_VFSGNJN_VV: if (instr->Vs1Value() == instr->Vs2Value()) { Format(instr, "vneg.vv 'vd, 'vs1'vm"); } else { Format(instr, "vfsgnjn.vv 'vd, 'vs2, 'vs1'vm"); } break; case RO_V_VFSGNJX_VV: if (instr->Vs1Value() == instr->Vs2Value()) { Format(instr, "vabs.vv 'vd, 'vs1'vm"); } else { Format(instr, "vfsgnjn.vv 'vd, 'vs2, 'vs1'vm"); } break; case RO_V_VFADD_VV: Format(instr, "vfadd.vv 'vd, 'vs2, 'vs1'vm"); break; case RO_V_VFSUB_VV: Format(instr, "vfsub.vv 'vd, 'vs2, 'vs1'vm"); break; case RO_V_VFDIV_VV: Format(instr, "vfdiv.vv 'vd, 'vs2, 'vs1'vm"); break; case RO_V_VFMUL_VV: Format(instr, "vfmul.vv 'vd, 'vs2, 'vs1'vm"); break; case RO_V_VFMADD_VV: Format(instr, "vfmadd.vv 'vd, 'vs1, 'vs2'vm"); break; case RO_V_VFNMADD_VV: Format(instr, "vfnmadd.vv 'vd, 'vs1, 'vs2'vm"); break; case RO_V_VFMSUB_VV: Format(instr, "vfmsub.vv 'vd, 'vs1, 'vs2'vm"); break; case RO_V_VFNMSUB_VV: Format(instr, "vfnmsub.vv 'vd, 'vs1, 'vs2'vm"); break; case RO_V_VFMACC_VV: Format(instr, "vfmacc.vv 'vd, 'vs1, 'vs2'vm"); break; case RO_V_VFNMACC_VV: Format(instr, "vfnmacc.vv 'vd, 'vs1, 'vs2'vm"); break; case RO_V_VFMSAC_VV: Format(instr, "vfmsac.vv 'vd, 'vs1, 'vs2'vm"); break; case RO_V_VFNMSAC_VV: Format(instr, "vfnmsac.vv 'vd, 'vs1, 'vs2'vm"); break; case RO_V_VFMV_FS: if (instr->Vs1Value() == 0x0) { Format(instr, "vfmv.f.s 'fd, 'vs2"); } else { UNSUPPORTED_RISCV(); } break; case RO_V_VFWADD_VV: Format(instr, "vfwadd.vv 'vd, 'vs2, 'vs1'vm"); break; case RO_V_VFWSUB_VV: Format(instr, "vfwsub.vv 'vd, 'vs2, 'vs1'vm"); break; case RO_V_VFWADD_W_VV: Format(instr, "vfwadd.wv 'vd, 'vs2, 'vs1'vm"); break; case RO_V_VFWSUB_W_VV: Format(instr, "vfwsub.wv 'vd, 'vs2, 'vs1'vm"); break; case RO_V_VFWREDUSUM_VV: Format(instr, "vfwredusum.vs 'vd, 'vs2, 'vs1'vm"); break; case RO_V_VFWREDOSUM_VV: Format(instr, "vfwredosum.vs 'vd, 'vs2, 'vs1'vm"); break; case RO_V_VFWMUL_VV: Format(instr, "vfwmul.vv 'vd, 'vs2, 'vs1'vm"); break; case RO_V_VFWMACC_VV: Format(instr, "vfwmacc.vv 'vd, 'vs1, 'vs2'vm"); break; case RO_V_VFWNMACC_VV: Format(instr, "vfwnmacc.vv 'vd, 'vs1, 'vs2'vm"); break; case RO_V_VFWMSAC_VV: Format(instr, "vfwmsac.vv 'vd, 'vs1, 'vs2'vm"); break; case RO_V_VFWNMSAC_VV: Format(instr, "vfwnmsac.vv 'vd, 'vs1, 'vs2'vm"); break; default: UNSUPPORTED_RISCV(); break; } } void Decoder::DecodeRvvFVF(Instruction* instr) { DCHECK_EQ(instr->InstructionBits() & (kBaseOpcodeMask | kFunct3Mask), OP_FVF); switch (instr->InstructionBits() & kVTypeMask) { case RO_V_VFSGNJ_VF: Format(instr, "vfsgnj.vf 'vd, 'vs2, 'fs1'vm"); break; case RO_V_VFSGNJN_VF: Format(instr, "vfsgnjn.vf 'vd, 'vs2, 'fs1'vm"); break; case RO_V_VFSGNJX_VF: Format(instr, "vfsgnjn.vf 'vd, 'vs2, 'fs1'vm"); break; case RO_V_VFMV_VF: Format(instr, "vfmv.v.f 'vd, 'fs1"); break; case RO_V_VFMADD_VF: Format(instr, "vfmadd.vf 'vd, 'fs1, 'vs2'vm"); break; case RO_V_VFNMADD_VF: Format(instr, "vfnmadd.vf 'vd, 'fs1, 'vs2'vm"); break; case RO_V_VFMSUB_VF: Format(instr, "vfmsub.vf 'vd, 'fs1, 'vs2'vm"); break; case RO_V_VFNMSUB_VF: Format(instr, "vfnmsub.vf 'vd, 'fs1, 'vs2'vm"); break; case RO_V_VFMACC_VF: Format(instr, "vfmacc.vf 'vd, 'fs1, 'vs2'vm"); break; case RO_V_VFNMACC_VF: Format(instr, "vfnmacc.vf 'vd, 'fs1, 'vs2'vm"); break; case RO_V_VFMSAC_VF: Format(instr, "vfmsac.vf 'vd, 'fs1, 'vs2'vm"); break; case RO_V_VFNMSAC_VF: Format(instr, "vfnmsac.vf 'vd, 'fs1, 'vs2'vm"); break; case RO_V_VFWADD_VF: Format(instr, "vfwadd.vf 'vd, 'vs2, 'fs1'vm"); break; case RO_V_VFWSUB_VF: Format(instr, "vfwsub.vf 'vd, 'vs2, 'fs1'vm"); break; case RO_V_VFWADD_W_VF: Format(instr, "vfwadd.wf 'vd, 'vs2, 'fs1'vm"); break; case RO_V_VFWSUB_W_VF: Format(instr, "vfwsub.wf 'vd, 'vs2, 'fs1'vm"); break; case RO_V_VFWMUL_VF: Format(instr, "vfwmul.vf 'vd, 'vs2, 'fs1'vm"); break; case RO_V_VFWMACC_VF: Format(instr, "vfwmacc.vf 'vd, 'fs1, 'vs2'vm"); break; case RO_V_VFWNMACC_VF: Format(instr, "vfwnmacc.vf 'vd, 'fs1, 'vs2'vm"); break; case RO_V_VFWMSAC_VF: Format(instr, "vfwmsac.vf 'vd, 'fs1, 'vs2'vm"); break; case RO_V_VFWNMSAC_VF: Format(instr, "vfwnmsac.vf 'vd, 'fs1, 'vs2'vm"); break; default: UNSUPPORTED_RISCV(); break; } } void Decoder::DecodeVType(Instruction* instr) { switch (instr->InstructionBits() & (kBaseOpcodeMask | kFunct3Mask)) { case OP_IVV: DecodeRvvIVV(instr); return; case OP_FVV: DecodeRvvFVV(instr); return; case OP_MVV: DecodeRvvMVV(instr); return; case OP_IVI: DecodeRvvIVI(instr); return; case OP_IVX: DecodeRvvIVX(instr); return; case OP_FVF: DecodeRvvFVF(instr); return; case OP_MVX: DecodeRvvMVX(instr); return; } switch (instr->InstructionBits() & (kBaseOpcodeMask | kFunct3Mask | 0x80000000)) { case RO_V_VSETVLI: Format(instr, "vsetvli 'rd, 'rs1, 'sew, 'lmul"); break; case RO_V_VSETVL: if (!(instr->InstructionBits() & 0x40000000)) { Format(instr, "vsetvl 'rd, 'rs1, 'rs2"); } else { Format(instr, "vsetivli 'rd, 'uimm, 'sew, 'lmul"); } break; default: UNSUPPORTED_RISCV(); break; } } int Decoder::switch_nf(Instruction* instr) { int nf = 0; switch (instr->InstructionBits() & kRvvNfMask) { case 0x20000000: nf = 2; break; case 0x40000000: nf = 3; break; case 0x60000000: nf = 4; break; case 0x80000000: nf = 5; break; case 0xa0000000: nf = 6; break; case 0xc0000000: nf = 7; break; case 0xe0000000: nf = 8; break; } return nf; } void Decoder::DecodeRvvVL(Instruction* instr) { char str[50]; uint32_t instr_temp = instr->InstructionBits() & (kRvvMopMask | kRvvNfMask | kBaseOpcodeMask); // switch (instr->InstructionBits() & // (kRvvMopMask | kRvvNfMask | kBaseOpcodeMask)) { if (RO_V_VL == instr_temp) { if (!(instr->InstructionBits() & (kRvvRs2Mask))) { snprintf(str, sizeof(str), "vle%d.v 'vd, ('rs1)'vm", instr->vl_vs_width()); Format(instr, str); } else { snprintf(str, sizeof(str), "vle%dff.v 'vd, ('rs1)'vm", instr->vl_vs_width()); Format(instr, str); } } else if (RO_V_VLS == instr_temp) { snprintf(str, sizeof(str), "vlse%d.v 'vd, ('rs1), 'rs2'vm", instr->vl_vs_width()); Format(instr, str); } else if (RO_V_VLX == instr_temp) { snprintf(str, sizeof(str), "vlxei%d.v 'vd, ('rs1), 'vs2'vm", instr->vl_vs_width()); Format(instr, str); } else if (RO_V_VLSEG2 == instr_temp || RO_V_VLSEG3 == instr_temp || RO_V_VLSEG4 == instr_temp || RO_V_VLSEG5 == instr_temp || RO_V_VLSEG6 == instr_temp || RO_V_VLSEG7 == instr_temp || RO_V_VLSEG8 == instr_temp) { if (!(instr->InstructionBits() & (kRvvRs2Mask))) { snprintf(str, sizeof(str), "vlseg%de%d.v 'vd, ('rs1)'vm", switch_nf(instr), instr->vl_vs_width()); } else { snprintf(str, sizeof(str), "vlseg%de%dff.v 'vd, ('rs1)'vm", switch_nf(instr), instr->vl_vs_width()); } Format(instr, str); } else if (RO_V_VLSSEG2 == instr_temp || RO_V_VLSSEG3 == instr_temp || RO_V_VLSSEG4 == instr_temp || RO_V_VLSSEG5 == instr_temp || RO_V_VLSSEG6 == instr_temp || RO_V_VLSSEG7 == instr_temp || RO_V_VLSSEG8 == instr_temp) { snprintf(str, sizeof(str), "vlsseg%de%d.v 'vd, ('rs1), 'rs2'vm", switch_nf(instr), instr->vl_vs_width()); Format(instr, str); } else if (RO_V_VLXSEG2 == instr_temp || RO_V_VLXSEG3 == instr_temp || RO_V_VLXSEG4 == instr_temp || RO_V_VLXSEG5 == instr_temp || RO_V_VLXSEG6 == instr_temp || RO_V_VLXSEG7 == instr_temp || RO_V_VLXSEG8 == instr_temp) { snprintf(str, sizeof(str), "vlxseg%dei%d.v 'vd, ('rs1), 'vs2'vm", switch_nf(instr), instr->vl_vs_width()); Format(instr, str); } } int Decoder::switch_sew(Instruction* instr) { int width = 0; if ((instr->InstructionBits() & kBaseOpcodeMask) != LOAD_FP && (instr->InstructionBits() & kBaseOpcodeMask) != STORE_FP) return -1; switch (instr->InstructionBits() & (kRvvWidthMask | kRvvMewMask)) { case 0x0: width = 8; break; case 0x00005000: width = 16; break; case 0x00006000: width = 32; break; case 0x00007000: width = 64; break; case 0x10000000: width = 128; break; case 0x10005000: width = 256; break; case 0x10006000: width = 512; break; case 0x10007000: width = 1024; break; default: width = -1; break; } return width; } void Decoder::DecodeRvvVS(Instruction* instr) { char str[50]; uint32_t instr_temp = instr->InstructionBits() & (kRvvMopMask | kRvvNfMask | kBaseOpcodeMask); if (RO_V_VS == instr_temp) { snprintf(str, sizeof(str), "vse%d.v 'vd, ('rs1)'vm", instr->vl_vs_width()); Format(instr, str); } else if (RO_V_VSS == instr_temp) { snprintf(str, sizeof(str), "vsse%d.v 'vd, ('rs1), 'rs2'vm", instr->vl_vs_width()); Format(instr, str); } else if (RO_V_VSX == instr_temp) { snprintf(str, sizeof(str), "vsxei%d.v 'vd, ('rs1), 'vs2'vm", instr->vl_vs_width()); Format(instr, str); } else if (RO_V_VSU == instr_temp) { snprintf(str, sizeof(str), "vsuxei%d.v 'vd, ('rs1), 'vs2'vm", instr->vl_vs_width()); Format(instr, str); } else if (RO_V_VSSEG2 == instr_temp || RO_V_VSSEG3 == instr_temp || RO_V_VSSEG4 == instr_temp || RO_V_VSSEG5 == instr_temp || RO_V_VSSEG6 == instr_temp || RO_V_VSSEG7 == instr_temp || RO_V_VSSEG8 == instr_temp) { snprintf(str, sizeof(str), "vsseg%de%d.v 'vd, ('rs1)'vm", switch_nf(instr), instr->vl_vs_width()); Format(instr, str); } else if (RO_V_VSSSEG2 == instr_temp || RO_V_VSSSEG3 == instr_temp || RO_V_VSSSEG4 == instr_temp || RO_V_VSSSEG5 == instr_temp || RO_V_VSSSEG6 == instr_temp || RO_V_VSSSEG7 == instr_temp || RO_V_VSSSEG8 == instr_temp) { snprintf(str, sizeof(str), "vssseg%de%d.v 'vd, ('rs1), 'rs2'vm", switch_nf(instr), instr->vl_vs_width()); Format(instr, str); } else if (RO_V_VSXSEG2 == instr_temp || RO_V_VSXSEG3 == instr_temp || RO_V_VSXSEG4 == instr_temp || RO_V_VSXSEG5 == instr_temp || RO_V_VSXSEG6 == instr_temp || RO_V_VSXSEG7 == instr_temp || RO_V_VSXSEG8 == instr_temp) { snprintf(str, sizeof(str), "vsxseg%dei%d.v 'vd, ('rs1), 'vs2'vm", switch_nf(instr), instr->vl_vs_width()); Format(instr, str); } } // Disassemble the instruction at *instr_ptr into the output buffer. // All instructions are one word long, except for the simulator // pseudo-instruction stop(msg). For that one special case, we return // size larger than one kInstrSize. int Decoder::InstructionDecode(byte* instr_ptr) { Instruction* instr = Instruction::At(instr_ptr); // Print raw instruction bytes. out_buffer_pos_ += base::SNPrintF(out_buffer_ + out_buffer_pos_, "%08x ", instr->InstructionBits()); switch (instr->InstructionType()) { case Instruction::kRType: DecodeRType(instr); break; case Instruction::kR4Type: DecodeR4Type(instr); break; case Instruction::kIType: DecodeIType(instr); break; case Instruction::kSType: DecodeSType(instr); break; case Instruction::kBType: DecodeBType(instr); break; case Instruction::kUType: DecodeUType(instr); break; case Instruction::kJType: DecodeJType(instr); break; case Instruction::kCRType: DecodeCRType(instr); break; case Instruction::kCAType: DecodeCAType(instr); break; case Instruction::kCJType: DecodeCJType(instr); break; case Instruction::kCIType: DecodeCIType(instr); break; case Instruction::kCIWType: DecodeCIWType(instr); break; case Instruction::kCSSType: DecodeCSSType(instr); break; case Instruction::kCLType: DecodeCLType(instr); break; case Instruction::kCSType: DecodeCSType(instr); break; case Instruction::kCBType: DecodeCBType(instr); break; case Instruction::kVType: DecodeVType(instr); break; default: Format(instr, "UNSUPPORTED"); UNSUPPORTED_RISCV(); } return instr->InstructionSize(); } } // namespace internal } // namespace v8 //------------------------------------------------------------------------------ namespace disasm { const char* NameConverter::NameOfAddress(byte* addr) const { v8::base::SNPrintF(tmp_buffer_, "%p", static_cast<void*>(addr)); return tmp_buffer_.begin(); } const char* NameConverter::NameOfConstant(byte* addr) const { return NameOfAddress(addr); } const char* NameConverter::NameOfCPURegister(int reg) const { return v8::internal::Registers::Name(reg); } const char* NameConverter::NameOfXMMRegister(int reg) const { return v8::internal::FPURegisters::Name(reg); } const char* NameConverter::NameOfByteCPURegister(int reg) const { UNREACHABLE(); // RISC-V does not have the concept of a byte register. // return "nobytereg"; } const char* NameConverter::NameInCode(byte* addr) const { // The default name converter is called for unknown code. So we will not try // to access any memory. return ""; } //------------------------------------------------------------------------------ int Disassembler::InstructionDecode(v8::base::Vector<char> buffer, byte* instruction) { v8::internal::Decoder d(converter_, buffer); return d.InstructionDecode(instruction); } int Disassembler::ConstantPoolSizeAt(byte* instruction) { return v8::internal::Assembler::ConstantPoolSizeAt( reinterpret_cast<v8::internal::Instruction*>(instruction)); } void Disassembler::Disassemble(FILE* f, byte* begin, byte* end, UnimplementedOpcodeAction unimplemented_action) { NameConverter converter; Disassembler d(converter, unimplemented_action); for (byte* pc = begin; pc < end;) { v8::base::EmbeddedVector<char, 128> buffer; buffer[0] = '\0'; byte* prev_pc = pc; pc += d.InstructionDecode(buffer, pc); v8::internal::PrintF(f, "%p %08x %s\n", static_cast<void*>(prev_pc), *reinterpret_cast<uint32_t*>(prev_pc), buffer.begin()); } } #undef STRING_STARTS_WITH } // namespace disasm #endif // V8_TARGET_ARCH_RISCV64