summaryrefslogtreecommitdiffstats
path: root/js/src/jit/riscv64/disasm
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /js/src/jit/riscv64/disasm
parentInitial commit. (diff)
downloadfirefox-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.cpp2155
-rw-r--r--js/src/jit/riscv64/disasm/Disasm-riscv64.h74
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