diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
commit | 26a029d407be480d791972afb5975cf62c9360a6 (patch) | |
tree | f435a8308119effd964b339f76abb83a57c29483 /js/src/jit/riscv64/disasm | |
parent | Initial commit. (diff) | |
download | firefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz firefox-26a029d407be480d791972afb5975cf62c9360a6.zip |
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'js/src/jit/riscv64/disasm')
-rw-r--r-- | js/src/jit/riscv64/disasm/Disasm-riscv64.cpp | 2155 | ||||
-rw-r--r-- | js/src/jit/riscv64/disasm/Disasm-riscv64.h | 74 |
2 files changed, 2229 insertions, 0 deletions
diff --git a/js/src/jit/riscv64/disasm/Disasm-riscv64.cpp b/js/src/jit/riscv64/disasm/Disasm-riscv64.cpp new file mode 100644 index 0000000000..bd9770d074 --- /dev/null +++ b/js/src/jit/riscv64/disasm/Disasm-riscv64.cpp @@ -0,0 +1,2155 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: set ts=8 sts=2 et sw=2 tw=80: + */ +// Copyright 2011 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. +// +// disasm::NameConverter converter; +// disasm::Disassembler d(converter); +// for (uint8_t* pc = begin; pc < end;) { +// disasm::EmbeddedVector<char, disasm::ReasonableBufferSize> buffer; +// uint8_t* 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 "jit/riscv64/disasm/Disasm-riscv64.h" + +#include <stdarg.h> +#include <stdio.h> +#include <string.h> + +#include "jit/riscv64/Assembler-riscv64.h" + +namespace js { +namespace jit { +namespace disasm { + +#define UNSUPPORTED_RISCV() printf("Unsupported instruction %d.\n", __LINE__) +//------------------------------------------------------------------------------ + +// 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, V8Vector<char> out_buffer) + : converter_(converter), out_buffer_(out_buffer), out_buffer_pos_(0) { + out_buffer_[out_buffer_pos_] = '\0'; + } + + ~Decoder() {} + + // Writes one disassembled instruction into 'buffer' (0-terminated). + // Returns the length of the disassembled machine instruction in bytes. + int InstructionDecode(uint8_t* instruction); + + static bool IsConstantPoolAt(uint8_t* instr_ptr); + static int ConstantPoolSizeAt(uint8_t* instr_ptr); + + 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); + + // 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_; + V8Vector<char> out_buffer_; + int out_buffer_pos_; + + // Disallow copy and assign. + Decoder(const Decoder&) = delete; + void operator=(const Decoder&) = delete; +}; + +// 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_ < int(out_buffer_.length() - 1))) { + PrintChar(cur); + cur = *str++; + } + out_buffer_[out_buffer_pos_] = 0; +} + +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; +} + +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; +} + +// Handle all register based formatting in this function to reduce the +// complexity of FormatOption. +int Decoder::FormatRegister(Instruction* instr, const char* format) { + MOZ_ASSERT(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; + } + MOZ_CRASH(); + } else if (format[1] == 'd') { // 'rd: rd register. + int reg = instr->RdValue(); + PrintRegister(reg); + return 2; + } + MOZ_CRASH(); +} + +// Handle all FPUregister based formatting in this function to reduce the +// complexity of FormatOption. +int Decoder::FormatFPURegisterOrRoundMode(Instruction* instr, + const char* format) { + MOZ_ASSERT(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; + } + MOZ_CRASH(); + } else if (format[1] == 'd') { // 'fd: fd register. + int reg = instr->RdValue(); + PrintFPURegister(reg); + return 2; + } else if (format[1] == 'r') { // 'frm + MOZ_ASSERT(STRING_STARTS_WITH(format, "frm")); + PrintRoundingMode(instr); + return 3; + } + MOZ_CRASH(); +} + +// Handle all C extension register based formatting in this function to reduce +// the complexity of FormatOption. +int Decoder::FormatRvcRegister(Instruction* instr, const char* format) { + MOZ_ASSERT(format[0] == 'C'); + MOZ_ASSERT(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; + } + MOZ_CRASH(); + } 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; + } + MOZ_CRASH(); +} + +// 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 + MOZ_ASSERT(STRING_STARTS_WITH(format, "Cimm")); + if (format[4] == '6') { + if (format[5] == 'U') { + MOZ_ASSERT(STRING_STARTS_WITH(format, "Cimm6U")); + PrintRvcImm6U(instr); + return 6; + } else if (format[5] == 'A') { + if (format[9] == '1' && format[10] == '6') { + MOZ_ASSERT(STRING_STARTS_WITH(format, "Cimm6Addi16sp")); + PrintRvcImm6Addi16sp(instr); + return 13; + } + MOZ_CRASH(); + } else if (format[5] == 'L') { + if (format[6] == 'd') { + if (format[7] == 's') { + MOZ_ASSERT(STRING_STARTS_WITH(format, "Cimm6Ldsp")); + PrintRvcImm6Ldsp(instr); + return 9; + } + } else if (format[6] == 'w') { + if (format[7] == 's') { + MOZ_ASSERT(STRING_STARTS_WITH(format, "Cimm6Lwsp")); + PrintRvcImm6Lwsp(instr); + return 9; + } + } + MOZ_CRASH(); + } else if (format[5] == 'S') { + if (format[6] == 'w') { + MOZ_ASSERT(STRING_STARTS_WITH(format, "Cimm6Swsp")); + PrintRvcImm6Swsp(instr); + return 9; + } else if (format[6] == 'd') { + MOZ_ASSERT(STRING_STARTS_WITH(format, "Cimm6Sdsp")); + PrintRvcImm6Sdsp(instr); + return 9; + } + MOZ_CRASH(); + } + PrintRvcImm6(instr); + return 5; + } else if (format[4] == '5') { + MOZ_ASSERT(STRING_STARTS_WITH(format, "Cimm5")); + if (format[5] == 'W') { + MOZ_ASSERT(STRING_STARTS_WITH(format, "Cimm5W")); + PrintRvcImm5W(instr); + return 6; + } else if (format[5] == 'D') { + MOZ_ASSERT(STRING_STARTS_WITH(format, "Cimm5D")); + PrintRvcImm5D(instr); + return 6; + } + MOZ_CRASH(); + } else if (format[4] == '8') { + MOZ_ASSERT(STRING_STARTS_WITH(format, "Cimm8")); + if (format[5] == 'A') { + MOZ_ASSERT(STRING_STARTS_WITH(format, "Cimm8Addi4spn")); + PrintRvcImm8Addi4spn(instr); + return 13; + } else if (format[5] == 'B') { + MOZ_ASSERT(STRING_STARTS_WITH(format, "Cimm8B")); + PrintRvcImm8B(instr); + return 6; + } + MOZ_CRASH(); + } else if (format[4] == '1') { + MOZ_ASSERT(STRING_STARTS_WITH(format, "Cimm1")); + if (format[5] == '1') { + MOZ_ASSERT(STRING_STARTS_WITH(format, "Cimm11CJ")); + PrintRvcImm11CJ(instr); + return 8; + } + MOZ_CRASH(); + } + MOZ_CRASH(); +} + +// 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') { + MOZ_ASSERT(STRING_STARTS_WITH(format, "Cshamt")); + PrintRvcShamt(instr); + return 6; + } + MOZ_CRASH(); + } + case 'c': { // `csr: CSR registers + if (format[1] == 's') { + if (format[2] == 'r') { + PrintCSRReg(instr); + return 3; + } + } + MOZ_CRASH(); + } + case 'i': { // 'imm12, 'imm12x, 'imm20U, or 'imm20J: Immediates. + if (format[3] == '1') { + if (format[4] == '2') { + MOZ_ASSERT(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') { + MOZ_ASSERT(STRING_STARTS_WITH(format, "imm20")); + switch (format[5]) { + case 'U': + MOZ_ASSERT(STRING_STARTS_WITH(format, "imm20U")); + PrintImm20U(instr); + break; + case 'J': + MOZ_ASSERT(STRING_STARTS_WITH(format, "imm20J")); + PrintImm20J(instr); + break; + } + return 6; + } + MOZ_CRASH(); + } + case 'o': { // 'offB or 'offS: Offsets. + if (format[3] == 'B') { + MOZ_ASSERT(STRING_STARTS_WITH(format, "offB")); + PrintBranchOffset(instr); + return 4; + } else if (format[3] == 'S') { + MOZ_ASSERT(STRING_STARTS_WITH(format, "offS")); + PrintStoreOffset(instr); + return 4; + } + MOZ_CRASH(); + } + 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 + MOZ_ASSERT(STRING_STARTS_WITH(format, "pre")); + PrintMemoryOrder(instr, true); + return 3; + } + case 's': { // 's32 or 's64: Shift amount. + if (format[1] == '3') { + MOZ_ASSERT(STRING_STARTS_WITH(format, "s32")); + PrintShamt32(instr); + return 3; + } else if (format[1] == '6') { + MOZ_ASSERT(STRING_STARTS_WITH(format, "s64")); + PrintShamt(instr); + return 3; + } else if (format[1] == 'u') { + MOZ_ASSERT(STRING_STARTS_WITH(format, "suc")); + PrintMemoryOrder(instr, false); + return 3; + } else if (format[1] == 'e') { + MOZ_ASSERT(STRING_STARTS_WITH(format, "sew")); + PrintRvvSEW(instr); + return 3; + } else if (format[1] == 'i') { + MOZ_ASSERT(STRING_STARTS_WITH(format, "simm5")); + PrintRvvSimm5(instr); + return 5; + } + MOZ_CRASH(); + } + case 'v': { + if (format[1] == 'd') { + MOZ_ASSERT(STRING_STARTS_WITH(format, "vd")); + PrintVd(instr); + return 2; + } else if (format[2] == '1') { + MOZ_ASSERT(STRING_STARTS_WITH(format, "vs1")); + PrintVs1(instr); + return 3; + } else if (format[2] == '2') { + MOZ_ASSERT(STRING_STARTS_WITH(format, "vs2")); + PrintVs2(instr); + return 3; + } else { + MOZ_ASSERT(STRING_STARTS_WITH(format, "vm")); + PrintRvvVm(instr); + return 2; + } + } + case 'l': { + MOZ_ASSERT(STRING_STARTS_WITH(format, "lmul")); + PrintRvvLMUL(instr); + return 4; + } + case 'u': { + if (STRING_STARTS_WITH(format, "uimm5")) { + PrintRvvUimm5(instr); + return 5; + } else { + MOZ_ASSERT(STRING_STARTS_WITH(format, "uimm")); + PrintUimm(instr); + return 4; + } + } + case 't': { // 'target: target of branch instructions' + MOZ_ASSERT(STRING_STARTS_WITH(format, "target")); + PrintTarget(instr); + return 6; + } + } + MOZ_CRASH(); +} + +// 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'; +} + +// The disassembler may end up decoding data inlined in the code. We do not want +// it to crash if the data does not ressemble any known instruction. +#define VERIFY(condition) \ + if (!(condition)) { \ + Unknown(instr); \ + return; \ + } + +// 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"); } + +// Print the register name according to the active name converter. +void Decoder::PrintRegister(int reg) { + Print(converter_.NameOfCPURegister(reg)); +} + +void Decoder::PrintVRegister(int reg) { UNSUPPORTED_RISCV(); } + +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_ += 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_ += SNPrintF(out_buffer_ + out_buffer_pos_, "0x%x", imm); +} + +void Decoder::PrintImm12(Instruction* instr) { + int32_t imm = instr->Imm12Value(); + out_buffer_pos_ += 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_ += + // 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_ += + SNPrintF(out_buffer_ + out_buffer_pos_, "%d -> %s", imm, target); +} + +void Decoder::PrintStoreOffset(Instruction* instr) { + int32_t imm = instr->StoreOffset(); + out_buffer_pos_ += 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_ += 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_ += + SNPrintF(out_buffer_ + out_buffer_pos_, "%d -> %s", imm, target); +} + +void Decoder::PrintShamt(Instruction* instr) { + int32_t imm = instr->Shamt(); + out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", imm); +} + +void Decoder::PrintShamt32(Instruction* instr) { + int32_t imm = instr->Shamt32(); + out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", imm); +} + +void Decoder::PrintRvcImm6(Instruction* instr) { + int32_t imm = instr->RvcImm6Value(); + out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", imm); +} + +void Decoder::PrintRvcImm6U(Instruction* instr) { + int32_t imm = instr->RvcImm6Value() & 0xFFFFF; + out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "0x%x", imm); +} + +void Decoder::PrintRvcImm6Addi16sp(Instruction* instr) { + int32_t imm = instr->RvcImm6Addi16spValue(); + out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", imm); +} + +void Decoder::PrintRvcShamt(Instruction* instr) { + int32_t imm = instr->RvcShamt6(); + out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", imm); +} + +void Decoder::PrintRvcImm6Ldsp(Instruction* instr) { + int32_t imm = instr->RvcImm6LdspValue(); + out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", imm); +} + +void Decoder::PrintRvcImm6Lwsp(Instruction* instr) { + int32_t imm = instr->RvcImm6LwspValue(); + out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", imm); +} + +void Decoder::PrintRvcImm6Swsp(Instruction* instr) { + int32_t imm = instr->RvcImm6SwspValue(); + out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", imm); +} + +void Decoder::PrintRvcImm6Sdsp(Instruction* instr) { + int32_t imm = instr->RvcImm6SdspValue(); + out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", imm); +} + +void Decoder::PrintRvcImm5W(Instruction* instr) { + int32_t imm = instr->RvcImm5WValue(); + out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", imm); +} + +void Decoder::PrintRvcImm5D(Instruction* instr) { + int32_t imm = instr->RvcImm5DValue(); + out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", imm); +} + +void Decoder::PrintRvcImm8Addi4spn(Instruction* instr) { + int32_t imm = instr->RvcImm8Addi4spnValue(); + out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", imm); +} + +void Decoder::PrintRvcImm11CJ(Instruction* instr) { + int32_t imm = instr->RvcImm11CJValue(); + out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", imm); +} + +void Decoder::PrintRvcImm8B(Instruction* instr) { + int32_t imm = instr->RvcImm8BValue(); + out_buffer_pos_ += 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_ += SNPrintF(out_buffer_ + out_buffer_pos_, "."); + } + if (aq) { + out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "aq"); + } + if (rl) { + out_buffer_pos_ += 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: + MOZ_CRASH(); + } + out_buffer_pos_ += 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: + MOZ_CRASH(); + } + out_buffer_pos_ += 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_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%s", s.c_str()); +} + +// Printing of instruction name. +void Decoder::PrintInstructionName(Instruction* instr) {} + +// 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.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.code()) + Format(instr, "sltz 'rd, 'rs1"); + else if (instr->Rs1Value() == zero.code()) + Format(instr, "sgtz 'rd, 'rs2"); + else + Format(instr, "slt 'rd, 'rs1, 'rs2"); + break; + case RO_SLTU: + if (instr->Rs1Value() == zero.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 JS_CODEGEN_RISCV64 + case RO_ADDW: + Format(instr, "addw 'rd, 'rs1, 'rs2"); + break; + case RO_SUBW: + if (instr->Rs1Value() == zero.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 /* JS_CODEGEN_RISCV64 */ + // 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 JS_CODEGEN_RISCV64 + 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 /*JS_CODEGEN_RISCV64*/ + // 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 JS_CODEGEN_RISCV64 + 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 /*JS_CODEGEN_RISCV64*/ + // 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 JS_CODEGEN_RISCV64 + 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 /* JS_CODEGEN_RISCV64 */ + 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 JS_CODEGEN_RISCV64 + 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 /* JS_CODEGEN_RISCV64 */ + 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, 'fs1"); + } 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 JS_CODEGEN_RISCV64 + case 0b000: // RO_FMV_X_D + Format(instr, "fmv.x.d 'rd, 'fs1"); + break; +#endif /* JS_CODEGEN_RISCV64 */ + 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 JS_CODEGEN_RISCV64 + 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 /* JS_CODEGEN_RISCV64 */ + 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 JS_CODEGEN_RISCV64 + 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 /* JS_CODEGEN_RISCV64 */ + default: + UNSUPPORTED_RISCV(); + } + break; + } +#ifdef JS_CODEGEN_RISCV64 + case RO_FMV_D_X: { + if (instr->Funct3Value() == 0b000 && instr->Rs2Value() == 0b00000) { + Format(instr, "fmv.d.x 'fd, 'rs1"); + } else { + UNSUPPORTED_RISCV(); + } + break; + } +#endif /* JS_CODEGEN_RISCV64 */ + 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) { + switch (instr->InstructionBits() & kITypeMask) { + case RO_JALR: + if (instr->RdValue() == zero.code() && instr->Rs1Value() == ra.code() && + instr->Imm12Value() == 0) + Format(instr, "ret"); + else if (instr->RdValue() == zero.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 JS_CODEGEN_RISCV64 + case RO_LWU: + Format(instr, "lwu 'rd, 'imm12('rs1)"); + break; + case RO_LD: + Format(instr, "ld 'rd, 'imm12('rs1)"); + break; +#endif /*JS_CODEGEN_RISCV64*/ + case RO_ADDI: + if (instr->Imm12Value() == 0) { + if (instr->RdValue() == zero.code() && instr->Rs1Value() == zero.code()) + Format(instr, "nop"); + else + Format(instr, "mv 'rd, 'rs1"); + } else if (instr->Rs1Value() == zero.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 JS_CODEGEN_RISCV64 + 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 /*JS_CODEGEN_RISCV64*/ + 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.code()) + Format(instr, "fscsr 'rs1"); + else + Format(instr, "fscsr 'rd, 'rs1"); + } else if (instr->CsrValue() == csr_frm) { + if (instr->RdValue() == zero.code()) + Format(instr, "fsrm 'rs1"); + else + Format(instr, "fsrm 'rd, 'rs1"); + } else if (instr->CsrValue() == csr_fflags) { + if (instr->RdValue() == zero.code()) + Format(instr, "fsflags 'rs1"); + else + Format(instr, "fsflags 'rd, 'rs1"); + } else if (instr->RdValue() == zero.code()) { + Format(instr, "csrw 'csr, 'rs1"); + } else { + Format(instr, "csrrw 'rd, 'csr, 'rs1"); + } + break; + case RO_CSRRS: + if (instr->Rs1Value() == zero.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: + MOZ_CRASH(); + } + } else if (instr->Rs1Value() == zero.code()) { + Format(instr, "csrr 'rd, 'csr"); + } else if (instr->RdValue() == zero.code()) { + Format(instr, "csrs 'csr, 'rs1"); + } else { + Format(instr, "csrrs 'rd, 'csr, 'rs1"); + } + break; + case RO_CSRRC: + if (instr->RdValue() == zero.code()) + Format(instr, "csrc 'csr, 'rs1"); + else + Format(instr, "csrrc 'rd, 'csr, 'rs1"); + break; + case RO_CSRRWI: + if (instr->RdValue() == zero.code()) + Format(instr, "csrwi 'csr, 'uimm"); + else + Format(instr, "csrrwi 'rd, 'csr, 'uimm"); + break; + case RO_CSRRSI: + if (instr->RdValue() == zero.code()) + Format(instr, "csrsi 'csr, 'uimm"); + else + Format(instr, "csrrsi 'rd, 'csr, 'uimm"); + break; + case RO_CSRRCI: + if (instr->RdValue() == zero.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: +#ifdef CAN_USE_RVV_INSTRUCTIONS + if (instr->vl_vs_width() != -1) { + DecodeRvvVL(instr); + } else { + UNSUPPORTED_RISCV(); + } + break; +#else + UNSUPPORTED_RISCV(); +#endif + } +} + +void Decoder::DecodeSType(Instruction* instr) { + 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 JS_CODEGEN_RISCV64 + case RO_SD: + Format(instr, "sd 'rs2, 'offS('rs1)"); + break; +#endif /*JS_CODEGEN_RISCV64*/ + // 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: +#ifdef CAN_USE_RVV_INSTRUCTIONS + if (instr->vl_vs_width() != -1) { + DecodeRvvVS(instr); + } else { + UNSUPPORTED_RISCV(); + } + break; +#else + UNSUPPORTED_RISCV(); +#endif + } +} + +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 LUI: + Format(instr, "lui 'rd, 'imm20U"); + break; + case AUIPC: + Format(instr, "auipc 'rd, 'imm20U"); + break; + default: + UNSUPPORTED_RISCV(); + } +} +// namespace jit +void Decoder::DecodeJType(Instruction* instr) { + // J Type doesn't have additional mask + switch (instr->BaseOpcodeValue()) { + case JAL: + if (instr->RdValue() == zero.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; +#ifdef JS_CODEGEN_RISCV64 + case RO_C_SUBW: + Format(instr, "subw 'Crs1s, 'Crs1s, 'Crs2s"); + break; + case RO_C_ADDW: + Format(instr, "addw 'Crs1s, 'Crs1s, 'Crs2s"); + break; +#endif + 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; +#ifdef JS_CODEGEN_RISCV64 + case RO_C_ADDIW: + Format(instr, "addiw 'Crd, 'Crd, 'Cimm6"); + break; +#endif + 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; +#ifdef JS_CODEGEN_RISCV64 + case RO_C_LDSP: + Format(instr, "ld 'Crd, 'Cimm6Ldsp(sp)"); + break; +#elif defined(JS_CODEGEN_RISCV32) + case RO_C_FLWSP: + Format(instr, "flw 'Cfd, 'Cimm6Ldsp(sp)"); + break; +#endif + 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; +#ifdef JS_CODEGEN_RISCV64 + case RO_C_SDSP: + Format(instr, "sd 'Crs2, 'Cimm6Sdsp(sp)"); + break; +#elif defined(JS_CODEGEN_RISCV32) + case RO_C_FSWSP: + Format(instr, "fsw 'Cfs2, 'Cimm6Sdsp(sp)"); + break; +#endif + 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; +#ifdef JS_CODEGEN_RISCV64 + case RO_C_LD: + Format(instr, "ld 'Crs2s, 'Cimm5D('Crs1s)"); + break; +#elif defined(JS_CODEGEN_RISCV32) + case RO_C_FLW: + Format(instr, "fld 'Cfs2s, 'Cimm5D('Crs1s)"); + break; +#endif + + 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; +#ifdef JS_CODEGEN_RISCV64 + case RO_C_SD: + Format(instr, "sd 'Crs2s, 'Cimm5D('Crs1s)"); + break; +#elif defined(JS_CODEGEN_RISCV32) + case RO_C_FSW: + Format(instr, "fsw 'Cfs2s, 'Cimm5D('Crs1s)"); + break; +#endif + 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(); + } +} + +#undef VERIFIY + +bool Decoder::IsConstantPoolAt(uint8_t* instr_ptr) { + UNSUPPORTED_RISCV(); + MOZ_CRASH(); +} + +int Decoder::ConstantPoolSizeAt(uint8_t* instr_ptr) { + UNSUPPORTED_RISCV(); + MOZ_CRASH(); +} + +// Disassemble the instruction at *instr_ptr into the output buffer. +int Decoder::InstructionDecode(byte* instr_ptr) { + Instruction* instr = Instruction::At(instr_ptr); + // Print raw instruction bytes. + out_buffer_pos_ += 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; +#ifdef CAN_USE_RVV_INSTRUCTIONS + case Instruction::kVType: + DecodeVType(instr); + break; +#endif + default: + Format(instr, "UNSUPPORTED"); + UNSUPPORTED_RISCV(); + } + return instr->InstructionSize(); +} + +} // namespace disasm + +#undef STRING_STARTS_WITH +#undef VERIFY + +//------------------------------------------------------------------------------ + +namespace disasm { + +const char* NameConverter::NameOfAddress(uint8_t* addr) const { + SNPrintF(tmp_buffer_, "%p", addr); + return tmp_buffer_.start(); +} + +const char* NameConverter::NameOfConstant(uint8_t* addr) const { + return NameOfAddress(addr); +} + +const char* NameConverter::NameOfCPURegister(int reg) const { + return Registers::GetName(reg); +} + +const char* NameConverter::NameOfByteCPURegister(int reg) const { + MOZ_CRASH(" RISC-V does not have the concept of a byte register."); +} + +const char* NameConverter::NameOfXMMRegister(int reg) const { + return FloatRegisters::GetName(reg); +} + +const char* NameConverter::NameInCode(uint8_t* addr) const { + // The default name converter is called for unknown code. So we will not try + // to access any memory. + return ""; +} + +//------------------------------------------------------------------------------ + +Disassembler::Disassembler(const NameConverter& converter) + : converter_(converter) {} + +Disassembler::~Disassembler() {} + +int Disassembler::InstructionDecode(V8Vector<char> buffer, + uint8_t* instruction) { + Decoder d(converter_, buffer); + return d.InstructionDecode(instruction); +} + +int Disassembler::ConstantPoolSizeAt(uint8_t* instruction) { + return Decoder::ConstantPoolSizeAt(instruction); +} + +void Disassembler::Disassemble(FILE* f, uint8_t* begin, uint8_t* end) { + NameConverter converter; + Disassembler d(converter); + for (uint8_t* pc = begin; pc < end;) { + EmbeddedVector<char, ReasonableBufferSize> buffer; + buffer[0] = '\0'; + uint8_t* prev_pc = pc; + pc += d.InstructionDecode(buffer, pc); + fprintf(f, "%p %08x %s\n", prev_pc, + *reinterpret_cast<int32_t*>(prev_pc), buffer.start()); + } +} + +} // namespace disasm +} // namespace jit +} // namespace js diff --git a/js/src/jit/riscv64/disasm/Disasm-riscv64.h b/js/src/jit/riscv64/disasm/Disasm-riscv64.h new file mode 100644 index 0000000000..0548523f6b --- /dev/null +++ b/js/src/jit/riscv64/disasm/Disasm-riscv64.h @@ -0,0 +1,74 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: set ts=8 sts=2 et sw=2 tw=80: + */ +// Copyright 2007-2008 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. + +#ifndef jit_riscv64_disasm_Disasm_riscv64_h +#define jit_riscv64_disasm_Disasm_riscv64_h + +#include "mozilla/Assertions.h" +#include "mozilla/Types.h" + +#include <stdio.h> + +#include "jit/riscv64/constant/Constant-riscv64.h" +#include "jit/riscv64/constant/util-riscv64.h" +namespace js { +namespace jit { +namespace disasm { + +typedef unsigned char byte; + +// Interface and default implementation for converting addresses and +// register-numbers to text. The default implementation is machine +// specific. +class NameConverter { + public: + virtual ~NameConverter() {} + virtual const char* NameOfCPURegister(int reg) const; + virtual const char* NameOfByteCPURegister(int reg) const; + virtual const char* NameOfXMMRegister(int reg) const; + virtual const char* NameOfAddress(byte* addr) const; + virtual const char* NameOfConstant(byte* addr) const; + virtual const char* NameInCode(byte* addr) const; + + protected: + EmbeddedVector<char, 128> tmp_buffer_; +}; + +// A generic Disassembler interface +class Disassembler { + public: + // Caller deallocates converter. + explicit Disassembler(const NameConverter& converter); + + virtual ~Disassembler(); + + // Writes one disassembled instruction into 'buffer' (0-terminated). + // Returns the length of the disassembled machine instruction in bytes. + int InstructionDecode(V8Vector<char> buffer, uint8_t* instruction); + + // Returns -1 if instruction does not mark the beginning of a constant pool, + // or the number of entries in the constant pool beginning here. + int ConstantPoolSizeAt(byte* instruction); + + // Write disassembly into specified file 'f' using specified NameConverter + // (see constructor). + static void Disassemble(FILE* f, uint8_t* begin, uint8_t* end); + + private: + const NameConverter& converter_; + + // Disallow implicit constructors. + Disassembler() = delete; + Disassembler(const Disassembler&) = delete; + void operator=(const Disassembler&) = delete; +}; + +} // namespace disasm +} // namespace jit +} // namespace js + +#endif // jit_riscv64_disasm_Disasm_riscv64_h |