Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  Disasm-riscv64.cpp   Sprache: C

 
/* -*- 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

Messung V0.5
C=91 H=100 G=95

¤ Dauer der Verarbeitung: 0.30 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge