products/Sources/formale Sprachen/JAVA/openjdk-20-36_src/src/hotspot/cpu/riscv image not shown  

Quellcode-Bibliothek

© Kompilation durch diese Firma

[Weder Korrektheit noch Funktionsfähigkeit der Software werden zugesichert.]

Datei: methodHandles_arm.cpp   Sprache: C

/*
 * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
 * Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved.
 * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 *
 */


#ifndef CPU_RISCV_ASSEMBLER_RISCV_HPP
#define CPU_RISCV_ASSEMBLER_RISCV_HPP

#include "asm/register.hpp"
#include "assembler_riscv.inline.hpp"
#include "metaprogramming/enableIf.hpp"

#define XLEN 64

// definitions of various symbolic names for machine registers

// First intercalls between C and Java which use 8 general registers
// and 8 floating registers

class Argument {
 public:
  enum {
    n_int_register_parameters_c   = 8, // x10, x11, ... x17 (c_rarg0, c_rarg1, ...)
    n_float_register_parameters_c = 8, // f10, f11, ... f17 (c_farg0, c_farg1, ... )

    n_int_register_parameters_j   = 8, // x11, ... x17, x10 (j_rarg0, j_rarg1, ...)
    n_float_register_parameters_j = 8  // f10, f11, ... f17 (j_farg0, j_farg1, ...)
  };
};

// function argument(caller-save registers)
constexpr Register c_rarg0 = x10;
constexpr Register c_rarg1 = x11;
constexpr Register c_rarg2 = x12;
constexpr Register c_rarg3 = x13;
constexpr Register c_rarg4 = x14;
constexpr Register c_rarg5 = x15;
constexpr Register c_rarg6 = x16;
constexpr Register c_rarg7 = x17;

constexpr FloatRegister c_farg0 = f10;
constexpr FloatRegister c_farg1 = f11;
constexpr FloatRegister c_farg2 = f12;
constexpr FloatRegister c_farg3 = f13;
constexpr FloatRegister c_farg4 = f14;
constexpr FloatRegister c_farg5 = f15;
constexpr FloatRegister c_farg6 = f16;
constexpr FloatRegister c_farg7 = f17;

// Symbolically name the register arguments used by the Java calling convention.
// We have control over the convention for java so we can do what we please.
// What pleases us is to offset the java calling convention so that when
// we call a suitable jni method the arguments are lined up and we don't
// have to do much shuffling. A suitable jni method is non-static and a
// small number of arguments.
//
// |------------------------------------------------------------------------|
// | c_rarg0  c_rarg1  c_rarg2  c_rarg3  c_rarg4  c_rarg5  c_rarg6  c_rarg7 |
// |------------------------------------------------------------------------|
// | x10      x11      x12      x13      x14      x15      x16      x17     |
// |------------------------------------------------------------------------|
// | j_rarg7  j_rarg0  j_rarg1  j_rarg2  j_rarg3  j_rarg4  j_rarg5  j_rarg6 |
// |------------------------------------------------------------------------|

constexpr Register j_rarg0 = c_rarg1;
constexpr Register j_rarg1 = c_rarg2;
constexpr Register j_rarg2 = c_rarg3;
constexpr Register j_rarg3 = c_rarg4;
constexpr Register j_rarg4 = c_rarg5;
constexpr Register j_rarg5 = c_rarg6;
constexpr Register j_rarg6 = c_rarg7;
constexpr Register j_rarg7 = c_rarg0;

// Java floating args are passed as per C

constexpr FloatRegister j_farg0 = f10;
constexpr FloatRegister j_farg1 = f11;
constexpr FloatRegister j_farg2 = f12;
constexpr FloatRegister j_farg3 = f13;
constexpr FloatRegister j_farg4 = f14;
constexpr FloatRegister j_farg5 = f15;
constexpr FloatRegister j_farg6 = f16;
constexpr FloatRegister j_farg7 = f17;

// zero rigster
constexpr Register zr = x0;
// global pointer
constexpr Register gp = x3;
// thread pointer
constexpr Register tp = x4;

// registers used to hold VM data either temporarily within a method
// or across method calls

// volatile (caller-save) registers

// current method -- must be in a call-clobbered register
constexpr Register xmethod =  x31;
// return address
constexpr Register ra      =  x1;

// non-volatile (callee-save) registers

constexpr Register sp            = x2; // stack pointer
constexpr Register fp            = x8; // frame pointer
constexpr Register xheapbase     = x27; // base of heap
constexpr Register xcpool        = x26; // constant pool cache
constexpr Register xmonitors     = x25; // monitors allocated on stack
constexpr Register xlocals       = x24; // locals on stack
constexpr Register xthread       = x23; // java thread pointer
constexpr Register xbcp          = x22; // bytecode pointer
constexpr Register xdispatch     = x21; // Dispatch table base
constexpr Register esp           = x20; // Java expression stack pointer
constexpr Register x19_sender_sp = x19; // Sender's SP while in interpreter

// temporary register(caller-save registers)
constexpr Register t0 = x5;
constexpr Register t1 = x6;
constexpr Register t2 = x7;

const Register g_INTArgReg[Argument::n_int_register_parameters_c] = {
  c_rarg0, c_rarg1, c_rarg2, c_rarg3, c_rarg4, c_rarg5, c_rarg6, c_rarg7
};

const FloatRegister g_FPArgReg[Argument::n_float_register_parameters_c] = {
  c_farg0, c_farg1, c_farg2, c_farg3, c_farg4, c_farg5, c_farg6, c_farg7
};

#define assert_cond(ARG1) assert(ARG1, #ARG1)

// Addressing modes
class Address {
 public:

  enum mode { no_mode, base_plus_offset, pcrel, literal };

 private:
  Register _base;
  Register _index;
  int64_t _offset;
  enum mode _mode;

  RelocationHolder _rspec;

  // If the target is far we'll need to load the ea of this to a
  // register to reach it. Otherwise if near we can do PC-relative
  // addressing.
  address          _target;

 public:
  Address()
    : _base(noreg), _index(noreg), _offset(0), _mode(no_mode), _target(NULL) { }

  Address(Register r)
    : _base(r), _index(noreg), _offset(0), _mode(base_plus_offset), _target(NULL) { }

  template<typename T, ENABLE_IF(std::is_integral<T>::value)>
  Address(Register r, T o)
    : _base(r), _index(noreg), _offset(o), _mode(base_plus_offset), _target(NULL) {}

  Address(Register r, ByteSize disp)
    : Address(r, in_bytes(disp)) {}

  Address(address target, RelocationHolder const& rspec)
    : _base(noreg),
      _index(noreg),
      _offset(0),
      _mode(literal),
      _rspec(rspec),
      _target(target) { }

  Address(address target, relocInfo::relocType rtype = relocInfo::external_word_type);

  const Register base() const {
    guarantee((_mode == base_plus_offset | _mode == pcrel | _mode == literal), "wrong mode");
    return _base;
  }
  long offset() const {
    return _offset;
  }
  Register index() const {
    return _index;
  }
  mode getMode() const {
    return _mode;
  }

  bool uses(Register reg) const { return _base == reg; }
  const address target() const { return _target; }
  const RelocationHolder& rspec() const { return _rspec; }
};

// Convenience classes
class RuntimeAddress: public Address {

  public:

  RuntimeAddress(address target) : Address(target, relocInfo::runtime_call_type) {}
  ~RuntimeAddress() {}
};

class OopAddress: public Address {

  public:

  OopAddress(address target) : Address(target, relocInfo::oop_type) {}
  ~OopAddress() {}
};

class ExternalAddress: public Address {
 private:
  static relocInfo::relocType reloc_for_target(address target) {
    // Sometimes ExternalAddress is used for values which aren't
    // exactly addresses, like the card table base.
    // external_word_type can't be used for values in the first page
    // so just skip the reloc in that case.
    return external_word_Relocation::can_be_relocated(target) ? relocInfo::external_word_type : relocInfo::none;
  }

 public:

  ExternalAddress(address target) : Address(target, reloc_for_target(target)) {}
  ~ExternalAddress() {}
};

class InternalAddress: public Address {

  public:

  InternalAddress(address target) : Address(target, relocInfo::internal_word_type) {}
  ~InternalAddress() {}
};

class Assembler : public AbstractAssembler {
public:

  enum {
    instruction_size = 4,
    compressed_instruction_size = 2,
  };

  // instruction must start at passed address
  static bool is_compressed_instr(address instr) {
    // The RISC-V ISA Manual, Section 'Base Instruction-Length Encoding':
    // Instructions are stored in memory as a sequence of 16-bit little-endian parcels, regardless of
    // memory system endianness. Parcels forming one instruction are stored at increasing halfword
    // addresses, with the lowest-addressed parcel holding the lowest-numbered bits in the instruction
    // specification.
    if (UseRVC && (((uint16_t *)instr)[0] & 0b11) != 0b11) {
      // 16-bit instructions have their lowest two bits equal to 0b00, 0b01, or 0b10
      return true;
    }
    // 32-bit instructions have their lowest two bits set to 0b11
    return false;
  }

  //---<  calculate length of instruction  >---
  // We just use the values set above.
  // instruction must start at passed address
  static unsigned int instr_len(address instr) {
    return is_compressed_instr(instr) ? compressed_instruction_size : instruction_size;
  }

  //---<  longest instructions  >---
  static unsigned int instr_maxlen() { return instruction_size; }

  enum RoundingMode {
    rne = 0b000,     // round to Nearest, ties to Even
    rtz = 0b001,     // round towards Zero
    rdn = 0b010,     // round Down (towards eegative infinity)
    rup = 0b011,     // round Up (towards infinity)
    rmm = 0b100,     // round to Nearest, ties to Max Magnitude
    rdy = 0b111,     // in instruction's rm field, selects dynamic rounding mode.In Rounding Mode register, Invalid.
  };

  static inline uint32_t extract(uint32_t val, unsigned msb, unsigned lsb) {
    assert_cond(msb >= lsb && msb <= 31);
    unsigned nbits = msb - lsb + 1;
    uint32_t mask = (1U << nbits) - 1;
    uint32_t result = val >> lsb;
    result &= mask;
    return result;
  }

  static inline int32_t sextract(uint32_t val, unsigned msb, unsigned lsb) {
    assert_cond(msb >= lsb && msb <= 31);
    int32_t result = val << (31 - msb);
    result >>= (31 - msb + lsb);
    return result;
  }

  static void patch(address a, unsigned msb, unsigned lsb, unsigned val) {
    assert_cond(a != NULL);
    assert_cond(msb >= lsb && msb <= 31);
    unsigned nbits = msb - lsb + 1;
    guarantee(val < (1U << nbits), "Field too big for insn");
    unsigned mask = (1U << nbits) - 1;
    val <<= lsb;
    mask <<= lsb;
    unsigned target = *(unsigned *)a;
    target &= ~mask;
    target |= val;
    *(unsigned *)a = target;
  }

  static void patch(address a, unsigned bit, unsigned val) {
    patch(a, bit, bit, val);
  }

  static void patch_reg(address a, unsigned lsb, Register reg) {
    patch(a, lsb + 4, lsb, reg->raw_encoding());
  }

  static void patch_reg(address a, unsigned lsb, FloatRegister reg) {
    patch(a, lsb + 4, lsb, reg->raw_encoding());
  }

  static void patch_reg(address a, unsigned lsb, VectorRegister reg) {
    patch(a, lsb + 4, lsb, reg->raw_encoding());
  }

  void emit(unsigned insn) {
    emit_int32((jint)insn);
  }

  enum csr {
    cycle = 0xc00,
    time,
    instret,
    hpmcounter3,
    hpmcounter4,
    hpmcounter5,
    hpmcounter6,
    hpmcounter7,
    hpmcounter8,
    hpmcounter9,
    hpmcounter10,
    hpmcounter11,
    hpmcounter12,
    hpmcounter13,
    hpmcounter14,
    hpmcounter15,
    hpmcounter16,
    hpmcounter17,
    hpmcounter18,
    hpmcounter19,
    hpmcounter20,
    hpmcounter21,
    hpmcounter22,
    hpmcounter23,
    hpmcounter24,
    hpmcounter25,
    hpmcounter26,
    hpmcounter27,
    hpmcounter28,
    hpmcounter29,
    hpmcounter30,
    hpmcounter31 = 0xc1f
  };

  // Emit an illegal instruction that's known to trap, with 32 read-only CSR
  // to choose as the input operand.
  // According to the RISC-V Assembly Programmer's Manual, a de facto implementation
  // of this instruction is the UNIMP pseduo-instruction, 'CSRRW x0, cycle, x0',
  // attempting to write zero to a read-only CSR 'cycle' (0xC00).
  // RISC-V ISAs provide a set of up to 32 read-only CSR registers 0xC00-0xC1F,
  // and an attempt to write into any read-only CSR (whether it exists or not)
  // will generate an illegal instruction exception.
  void illegal_instruction(csr csr_reg) {
    csrrw(x0, (unsigned)csr_reg, x0);
  }

// Register Instruction
#define INSN(NAME, op, funct3, funct7)                          \
  void NAME(Register Rd, Register Rs1, Register Rs2) {          \
    unsigned insn = 0;                                          \
    patch((address)&insn, 6,  0, op);                           \
    patch((address)&insn, 14, 12, funct3);                      \
    patch((address)&insn, 31, 25, funct7);                      \
    patch_reg((address)&insn, 7, Rd);                           \
    patch_reg((address)&insn, 15, Rs1);                         \
    patch_reg((address)&insn, 20, Rs2);                         \
    emit(insn);                                                 \
  }

  INSN(_add,  0b0110011, 0b000, 0b0000000);
  INSN(_sub,  0b0110011, 0b000, 0b0100000);
  INSN(_andr, 0b0110011, 0b111, 0b0000000);
  INSN(_orr,  0b0110011, 0b110, 0b0000000);
  INSN(_xorr, 0b0110011, 0b100, 0b0000000);
  INSN(sll,   0b0110011, 0b001, 0b0000000);
  INSN(sra,   0b0110011, 0b101, 0b0100000);
  INSN(srl,   0b0110011, 0b101, 0b0000000);
  INSN(slt,   0b0110011, 0b010, 0b0000000);
  INSN(sltu,  0b0110011, 0b011, 0b0000000);
  INSN(_addw, 0b0111011, 0b000, 0b0000000);
  INSN(_subw, 0b0111011, 0b000, 0b0100000);
  INSN(sllw,  0b0111011, 0b001, 0b0000000);
  INSN(sraw,  0b0111011, 0b101, 0b0100000);
  INSN(srlw,  0b0111011, 0b101, 0b0000000);
  INSN(mul,   0b0110011, 0b000, 0b0000001);
  INSN(mulh,  0b0110011, 0b001, 0b0000001);
  INSN(mulhsu,0b0110011, 0b010, 0b0000001);
  INSN(mulhu, 0b0110011, 0b011, 0b0000001);
  INSN(mulw,  0b0111011, 0b000, 0b0000001);
  INSN(div,   0b0110011, 0b100, 0b0000001);
  INSN(divu,  0b0110011, 0b101, 0b0000001);
  INSN(divw,  0b0111011, 0b100, 0b0000001);
  INSN(divuw, 0b0111011, 0b101, 0b0000001);
  INSN(rem,   0b0110011, 0b110, 0b0000001);
  INSN(remu,  0b0110011, 0b111, 0b0000001);
  INSN(remw,  0b0111011, 0b110, 0b0000001);
  INSN(remuw, 0b0111011, 0b111, 0b0000001);

#undef INSN

// Load/store register (all modes)
#define INSN(NAME, op, funct3)                                                                     \
  void NAME(Register Rd, Register Rs, const int32_t offset) {                                      \
    guarantee(is_offset_in_range(offset, 12), "offset is invalid.");                               \
    unsigned insn = 0;                                                                             \
    int32_t val = offset & 0xfff;                                                                  \
    patch((address)&insn, 6, 0, op);                                                               \
    patch((address)&insn, 14, 12, funct3);                                                         \
    patch_reg((address)&insn, 15, Rs);                                                             \
    patch_reg((address)&insn, 7, Rd);                                                              \
    patch((address)&insn, 31, 20, val);                                                            \
    emit(insn);                                                                                    \
  }

  INSN(lb,  0b0000011, 0b000);
  INSN(lbu, 0b0000011, 0b100);
  INSN(lh,  0b0000011, 0b001);
  INSN(lhu, 0b0000011, 0b101);
  INSN(_lw, 0b0000011, 0b010);
  INSN(lwu, 0b0000011, 0b110);
  INSN(_ld, 0b0000011, 0b011);

#undef INSN

#define INSN(NAME, op, funct3)                                                                     \
  void NAME(FloatRegister Rd, Register Rs, const int32_t offset) {                                 \
    guarantee(is_offset_in_range(offset, 12), "offset is invalid.");                               \
    unsigned insn = 0;                                                                             \
    uint32_t val = offset & 0xfff;                                                                 \
    patch((address)&insn, 6, 0, op);                                                               \
    patch((address)&insn, 14, 12, funct3);                                                         \
    patch_reg((address)&insn, 15, Rs);                                                             \
    patch_reg((address)&insn, 7, Rd);                                                              \
    patch((address)&insn, 31, 20, val);                                                            \
    emit(insn);                                                                                    \
  }

  INSN(flw,  0b0000111, 0b010);
  INSN(_fld, 0b0000111, 0b011);

#undef INSN

#define INSN(NAME, op, funct3)                                                                           \
  void NAME(Register Rs1, Register Rs2, const int64_t offset) {                                          \
    guarantee(is_imm_in_range(offset, 12, 1), "offset is invalid.");                                     \
    unsigned insn = 0;                                                                                   \
    uint32_t val  = offset & 0x1fff;                                                                     \
    uint32_t val11 = (val >> 11) & 0x1;                                                                  \
    uint32_t val12 = (val >> 12) & 0x1;                                                                  \
    uint32_t low  = (val >> 1) & 0xf;                                                                    \
    uint32_t high = (val >> 5) & 0x3f;                                                                   \
    patch((address)&insn, 6, 0, op);                                                                     \
    patch((address)&insn, 14, 12, funct3);                                                               \
    patch_reg((address)&insn, 15, Rs1);                                                                  \
    patch_reg((address)&insn, 20, Rs2);                                                                  \
    patch((address)&insn, 7, val11);                                                                     \
    patch((address)&insn, 11, 8, low);                                                                   \
    patch((address)&insn, 30, 25, high);                                                                 \
    patch((address)&insn, 31, val12);                                                                    \
    emit(insn);                                                                                          \
  }

  INSN(beq,  0b1100011, 0b000);
  INSN(bne,  0b1100011, 0b001);
  INSN(bge,  0b1100011, 0b101);
  INSN(bgeu, 0b1100011, 0b111);
  INSN(blt,  0b1100011, 0b100);
  INSN(bltu, 0b1100011, 0b110);

#undef INSN

#define INSN(NAME, REGISTER, op, funct3)                                                                    \
  void NAME(REGISTER Rs1, Register Rs2, const int32_t offset) {                                             \
    guarantee(is_offset_in_range(offset, 12), "offset is invalid.");                                        \
    unsigned insn = 0;                                                                                      \
    uint32_t val  = offset & 0xfff;                                                                         \
    uint32_t low  = val & 0x1f;                                                                             \
    uint32_t high = (val >> 5) & 0x7f;                                                                      \
    patch((address)&insn, 6, 0, op);                                                                        \
    patch((address)&insn, 14, 12, funct3);                                                                  \
    patch_reg((address)&insn, 15, Rs2);                                                                     \
    patch_reg((address)&insn, 20, Rs1);                                                                     \
    patch((address)&insn, 11, 7, low);                                                                      \
    patch((address)&insn, 31, 25, high);                                                                    \
    emit(insn);                                                                                             \
  }                                                                                                         \

  INSN(sb,   Register,      0b0100011, 0b000);
  INSN(sh,   Register,      0b0100011, 0b001);
  INSN(_sw,  Register,      0b0100011, 0b010);
  INSN(_sd,  Register,      0b0100011, 0b011);
  INSN(fsw,  FloatRegister, 0b0100111, 0b010);
  INSN(_fsd, FloatRegister, 0b0100111, 0b011);

#undef INSN

#define INSN(NAME, op, funct3)                                                        \
  void NAME(Register Rd, const uint32_t csr, Register Rs1) {                          \
    guarantee(is_unsigned_imm_in_range(csr, 12, 0), "csr is invalid");                \
    unsigned insn = 0;                                                                \
    patch((address)&insn, 6, 0, op);                                                  \
    patch((address)&insn, 14, 12, funct3);                                            \
    patch_reg((address)&insn, 7, Rd);                                                 \
    patch_reg((address)&insn, 15, Rs1);                                               \
    patch((address)&insn, 31, 20, csr);                                               \
    emit(insn);                                                                       \
  }

  INSN(csrrw, 0b1110011, 0b001);
  INSN(csrrs, 0b1110011, 0b010);
  INSN(csrrc, 0b1110011, 0b011);

#undef INSN

#define INSN(NAME, op, funct3)                                                        \
  void NAME(Register Rd, const uint32_t csr, const uint32_t uimm) {                   \
    guarantee(is_unsigned_imm_in_range(csr, 12, 0), "csr is invalid");                \
    guarantee(is_unsigned_imm_in_range(uimm, 5, 0), "uimm is invalid");               \
    unsigned insn = 0;                                                                \
    uint32_t val  = uimm & 0x1f;                                                      \
    patch((address)&insn, 6, 0, op);                                                  \
    patch((address)&insn, 14, 12, funct3);                                            \
    patch_reg((address)&insn, 7, Rd);                                                 \
    patch((address)&insn, 19, 15, val);                                               \
    patch((address)&insn, 31, 20, csr);                                               \
    emit(insn);                                                                       \
  }

  INSN(csrrwi, 0b1110011, 0b101);
  INSN(csrrsi, 0b1110011, 0b110);
  INSN(csrrci, 0b1110011, 0b111);

#undef INSN

#define INSN(NAME, op)                                                                \
  void NAME(Register Rd, const int32_t offset) {                                      \
    guarantee(is_imm_in_range(offset, 20, 1), "offset is invalid.");                  \
    unsigned insn = 0;                                                                \
    patch((address)&insn, 6, 0, op);                                                  \
    patch_reg((address)&insn, 7, Rd);                                                 \
    patch((address)&insn, 19, 12, (uint32_t)((offset >> 12) & 0xff));                 \
    patch((address)&insn, 20, (uint32_t)((offset >> 11) & 0x1));                      \
    patch((address)&insn, 30, 21, (uint32_t)((offset >> 1) & 0x3ff));                 \
    patch((address)&insn, 31, (uint32_t)((offset >> 20) & 0x1));                      \
    emit(insn);                                                                       \
  }

  INSN(jal, 0b1101111);

#undef INSN

#define INSN(NAME, op, funct)                                                         \
  void NAME(Register Rd, Register Rs, const int32_t offset) {                         \
    guarantee(is_offset_in_range(offset, 12), "offset is invalid.");                  \
    unsigned insn = 0;                                                                \
    patch((address)&insn, 6, 0, op);                                                  \
    patch_reg((address)&insn, 7, Rd);                                                 \
    patch((address)&insn, 14, 12, funct);                                             \
    patch_reg((address)&insn, 15, Rs);                                                \
    int32_t val = offset & 0xfff;                                                     \
    patch((address)&insn, 31, 20, val);                                               \
    emit(insn);                                                                       \
  }

  INSN(_jalr, 0b1100111, 0b000);

#undef INSN

  enum barrier {
    i = 0b1000, o = 0b0100, r = 0b0010, w = 0b0001,
    ir = i | r, ow = o | w, iorw = i | o | r | w
  };

  void fence(const uint32_t predecessor, const uint32_t successor) {
    unsigned insn = 0;
    guarantee(predecessor < 16, "predecessor is invalid");
    guarantee(successor < 16, "successor is invalid");
    patch((address)&insn, 6, 0, 0b001111);
    patch((address)&insn, 11, 7, 0b00000);
    patch((address)&insn, 14, 12, 0b000);
    patch((address)&insn, 19, 15, 0b00000);
    patch((address)&insn, 23, 20, successor);
    patch((address)&insn, 27, 24, predecessor);
    patch((address)&insn, 31, 28, 0b0000);
    emit(insn);
  }

#define INSN(NAME, op, funct3, funct7)                      \
  void NAME() {                                             \
    unsigned insn = 0;                                      \
    patch((address)&insn, 6, 0, op);                        \
    patch((address)&insn, 11, 7, 0b00000);                  \
    patch((address)&insn, 14, 12, funct3);                  \
    patch((address)&insn, 19, 15, 0b00000);                 \
    patch((address)&insn, 31, 20, funct7);                  \
    emit(insn);                                             \
  }

  INSN(ecall,   0b1110011, 0b000, 0b000000000000);
  INSN(_ebreak, 0b1110011, 0b000, 0b000000000001);

#undef INSN

enum Aqrl {relaxed = 0b00, rl = 0b01, aq = 0b10, aqrl = 0b11};

#define INSN(NAME, op, funct3, funct7)                                                  \
  void NAME(Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) {        \
    unsigned insn = 0;                                                                  \
    patch((address)&insn, 6, 0, op);                                                    \
    patch((address)&insn, 14, 12, funct3);                                              \
    patch_reg((address)&insn, 7, Rd);                                                   \
    patch_reg((address)&insn, 15, Rs1);                                                 \
    patch_reg((address)&insn, 20, Rs2);                                                 \
    patch((address)&insn, 31, 27, funct7);                                              \
    patch((address)&insn, 26, 25, memory_order);                                        \
    emit(insn);                                                                         \
  }

  INSN(amoswap_w, 0b0101111, 0b010, 0b00001);
  INSN(amoadd_w,  0b0101111, 0b010, 0b00000);
  INSN(amoxor_w,  0b0101111, 0b010, 0b00100);
  INSN(amoand_w,  0b0101111, 0b010, 0b01100);
  INSN(amoor_w,   0b0101111, 0b010, 0b01000);
  INSN(amomin_w,  0b0101111, 0b010, 0b10000);
  INSN(amomax_w,  0b0101111, 0b010, 0b10100);
  INSN(amominu_w, 0b0101111, 0b010, 0b11000);
  INSN(amomaxu_w, 0b0101111, 0b010, 0b11100);
  INSN(amoswap_d, 0b0101111, 0b011, 0b00001);
  INSN(amoadd_d,  0b0101111, 0b011, 0b00000);
  INSN(amoxor_d,  0b0101111, 0b011, 0b00100);
  INSN(amoand_d,  0b0101111, 0b011, 0b01100);
  INSN(amoor_d,   0b0101111, 0b011, 0b01000);
  INSN(amomin_d,  0b0101111, 0b011, 0b10000);
  INSN(amomax_d , 0b0101111, 0b011, 0b10100);
  INSN(amominu_d, 0b0101111, 0b011, 0b11000);
  INSN(amomaxu_d, 0b0101111, 0b011, 0b11100);
#undef INSN

enum operand_size { int8, int16, int32, uint32, int64 };

#define INSN(NAME, op, funct3, funct7)                                              \
  void NAME(Register Rd, Register Rs1, Aqrl memory_order = relaxed) {               \
    unsigned insn = 0;                                                              \
    uint32_t val = memory_order & 0x3;                                              \
    patch((address)&insn, 6, 0, op);                                                \
    patch((address)&insn, 14, 12, funct3);                                          \
    patch_reg((address)&insn, 7, Rd);                                               \
    patch_reg((address)&insn, 15, Rs1);                                             \
    patch((address)&insn, 25, 20, 0b00000);                                         \
    patch((address)&insn, 31, 27, funct7);                                          \
    patch((address)&insn, 26, 25, val);                                             \
    emit(insn);                                                                     \
  }

  INSN(lr_w, 0b0101111, 0b010, 0b00010);
  INSN(lr_d, 0b0101111, 0b011, 0b00010);

#undef INSN

#define INSN(NAME, op, funct3, funct7)                                                      \
  void NAME(Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = relaxed) {         \
    unsigned insn = 0;                                                                      \
    uint32_t val = memory_order & 0x3;                                                      \
    patch((address)&insn, 6, 0, op);                                                        \
    patch((address)&insn, 14, 12, funct3);                                                  \
    patch_reg((address)&insn, 7, Rd);                                                       \
    patch_reg((address)&insn, 15, Rs2);                                                     \
    patch_reg((address)&insn, 20, Rs1);                                                     \
    patch((address)&insn, 31, 27, funct7);                                                  \
    patch((address)&insn, 26, 25, val);                                                     \
    emit(insn);                                                                             \
  }

  INSN(sc_w, 0b0101111, 0b010, 0b00011);
  INSN(sc_d, 0b0101111, 0b011, 0b00011);
#undef INSN

#define INSN(NAME, op, funct5, funct7)                                                      \
  void NAME(FloatRegister Rd, FloatRegister Rs1, RoundingMode rm = rne) {                   \
    unsigned insn = 0;                                                                      \
    patch((address)&insn, 6, 0, op);                                                        \
    patch((address)&insn, 14, 12, rm);                                                      \
    patch((address)&insn, 24, 20, funct5);                                                  \
    patch((address)&insn, 31, 25, funct7);                                                  \
    patch_reg((address)&insn, 7, Rd);                                                       \
    patch_reg((address)&insn, 15, Rs1);                                                     \
    emit(insn);                                                                             \
  }

  INSN(fsqrt_s,  0b1010011, 0b00000, 0b0101100);
  INSN(fsqrt_d,  0b1010011, 0b00000, 0b0101101);
  INSN(fcvt_s_d, 0b1010011, 0b00001, 0b0100000);
  INSN(fcvt_d_s, 0b1010011, 0b00000, 0b0100001);
#undef INSN

// Immediate Instruction
#define INSN(NAME, op, funct3)                                                              \
  void NAME(Register Rd, Register Rs1, int32_t imm) {                                       \
    guarantee(is_imm_in_range(imm, 12, 0), "Immediate is out of validity");                 \
    unsigned insn = 0;                                                                      \
    patch((address)&insn, 6, 0, op);                                                        \
    patch((address)&insn, 14, 12, funct3);                                                  \
    patch((address)&insn, 31, 20, imm & 0x00000fff);                                        \
    patch_reg((address)&insn, 7, Rd);                                                       \
    patch_reg((address)&insn, 15, Rs1);                                                     \
    emit(insn);                                                                             \
  }

  INSN(_addi,      0b0010011, 0b000);
  INSN(slti,       0b0010011, 0b010);
  INSN(_addiw,     0b0011011, 0b000);
  INSN(_and_imm12, 0b0010011, 0b111);
  INSN(ori,        0b0010011, 0b110);
  INSN(xori,       0b0010011, 0b100);

#undef INSN

#define INSN(NAME, op, funct3)                                                              \
  void NAME(Register Rd, Register Rs1, uint32_t imm) {                                      \
    guarantee(is_unsigned_imm_in_range(imm, 12, 0), "Immediate is out of validity");        \
    unsigned insn = 0;                                                                      \
    patch((address)&insn,6, 0,  op);                                                        \
    patch((address)&insn, 14, 12, funct3);                                                  \
    patch((address)&insn, 31, 20, imm & 0x00000fff);                                        \
    patch_reg((address)&insn, 7, Rd);                                                       \
    patch_reg((address)&insn, 15, Rs1);                                                     \
    emit(insn);                                                                             \
  }

  INSN(sltiu, 0b0010011, 0b011);

#undef INSN

// Shift Immediate Instruction
#define INSN(NAME, op, funct3, funct6)                                   \
  void NAME(Register Rd, Register Rs1, unsigned shamt) {                 \
    guarantee(shamt <= 0x3f, "Shamt is invalid");                        \
    unsigned insn = 0;                                                   \
    patch((address)&insn, 6, 0, op);                                     \
    patch((address)&insn, 14, 12, funct3);                               \
    patch((address)&insn, 25, 20, shamt);                                \
    patch((address)&insn, 31, 26, funct6);                               \
    patch_reg((address)&insn, 7, Rd);                                    \
    patch_reg((address)&insn, 15, Rs1);                                  \
    emit(insn);                                                          \
  }

  INSN(_slli, 0b0010011, 0b001, 0b000000);
  INSN(_srai, 0b0010011, 0b101, 0b010000);
  INSN(_srli, 0b0010011, 0b101, 0b000000);

#undef INSN

// Shift Word Immediate Instruction
#define INSN(NAME, op, funct3, funct7)                                  \
  void NAME(Register Rd, Register Rs1, unsigned shamt) {                \
    guarantee(shamt <= 0x1f, "Shamt is invalid");                       \
    unsigned insn = 0;                                                  \
    patch((address)&insn, 6, 0, op);                                    \
    patch((address)&insn, 14, 12, funct3);                              \
    patch((address)&insn, 24, 20, shamt);                               \
    patch((address)&insn, 31, 25, funct7);                              \
    patch_reg((address)&insn, 7, Rd);                                   \
    patch_reg((address)&insn, 15, Rs1);                                 \
    emit(insn);                                                         \
  }

  INSN(slliw, 0b0011011, 0b001, 0b0000000);
  INSN(sraiw, 0b0011011, 0b101, 0b0100000);
  INSN(srliw, 0b0011011, 0b101, 0b0000000);

#undef INSN

// Upper Immediate Instruction
#define INSN(NAME, op)                                                  \
  void NAME(Register Rd, int32_t imm) {                                 \
    int32_t upperImm = imm >> 12;                                       \
    unsigned insn = 0;                                                  \
    patch((address)&insn, 6, 0, op);                                    \
    patch_reg((address)&insn, 7, Rd);                                   \
    upperImm &= 0x000fffff;                                             \
    patch((address)&insn, 31, 12, upperImm);                            \
    emit(insn);                                                         \
  }

  INSN(_lui,  0b0110111);
  INSN(auipc, 0b0010111);

#undef INSN

// Float and Double Rigster Instruction
#define INSN(NAME, op, funct2)                                                                                     \
  void NAME(FloatRegister Rd, FloatRegister Rs1, FloatRegister Rs2, FloatRegister Rs3, RoundingMode rm = rne) {    \
    unsigned insn = 0;                                                                                             \
    patch((address)&insn, 6, 0, op);                                                                               \
    patch((address)&insn, 14, 12, rm);                                                                             \
    patch((address)&insn, 26, 25, funct2);                                                                         \
    patch_reg((address)&insn, 7, Rd);                                                                              \
    patch_reg((address)&insn, 15, Rs1);                                                                            \
    patch_reg((address)&insn, 20, Rs2);                                                                            \
    patch_reg((address)&insn, 27, Rs3);                                                                            \
    emit(insn);                                                                                                    \
  }

  INSN(fmadd_s,   0b1000011,  0b00);
  INSN(fmsub_s,   0b1000111,  0b00);
  INSN(fnmsub_s,  0b1001011,  0b00);
  INSN(fnmadd_s,  0b1001111,  0b00);
  INSN(fmadd_d,   0b1000011,  0b01);
  INSN(fmsub_d,   0b1000111,  0b01);
  INSN(fnmsub_d,  0b1001011,  0b01);
  INSN(fnmadd_d,  0b1001111,  0b01);

#undef INSN

// Float and Double Rigster Instruction
#define INSN(NAME, op, funct3, funct7)                                        \
  void NAME(FloatRegister Rd, FloatRegister Rs1, FloatRegister Rs2) {         \
    unsigned insn = 0;                                                        \
    patch((address)&insn, 6, 0, op);                                          \
    patch((address)&insn, 14, 12, funct3);                                    \
    patch((address)&insn, 31, 25, funct7);                                    \
    patch_reg((address)&insn, 7, Rd);                                         \
    patch_reg((address)&insn, 15, Rs1);                                       \
    patch_reg((address)&insn, 20, Rs2);                                       \
    emit(insn);                                                               \
  }

  INSN(fsgnj_s,  0b1010011, 0b000, 0b0010000);
  INSN(fsgnjn_s, 0b1010011, 0b001, 0b0010000);
  INSN(fsgnjx_s, 0b1010011, 0b010, 0b0010000);
  INSN(fmin_s,   0b1010011, 0b000, 0b0010100);
  INSN(fmax_s,   0b1010011, 0b001, 0b0010100);
  INSN(fsgnj_d,  0b1010011, 0b000, 0b0010001);
  INSN(fsgnjn_d, 0b1010011, 0b001, 0b0010001);
  INSN(fsgnjx_d, 0b1010011, 0b010, 0b0010001);
  INSN(fmin_d,   0b1010011, 0b000, 0b0010101);
  INSN(fmax_d,   0b1010011, 0b001, 0b0010101);

#undef INSN

// Float and Double Rigster Arith Instruction
#define INSN(NAME, op, funct3, funct7)                                    \
  void NAME(Register Rd, FloatRegister Rs1, FloatRegister Rs2) {          \
    unsigned insn = 0;                                                    \
    patch((address)&insn, 6, 0, op);                                      \
    patch((address)&insn, 14, 12, funct3);                                \
    patch((address)&insn, 31, 25, funct7);                                \
    patch_reg((address)&insn, 7, Rd);                                     \
    patch_reg((address)&insn, 15, Rs1);                                   \
    patch_reg((address)&insn, 20, Rs2);                                   \
    emit(insn);                                                           \
  }

  INSN(feq_s,    0b1010011, 0b010, 0b1010000);
  INSN(flt_s,    0b1010011, 0b001, 0b1010000);
  INSN(fle_s,    0b1010011, 0b000, 0b1010000);
  INSN(feq_d,    0b1010011, 0b010, 0b1010001);
  INSN(fle_d,    0b1010011, 0b000, 0b1010001);
  INSN(flt_d,    0b1010011, 0b001, 0b1010001);
#undef INSN

// Float and Double Arith Instruction
#define INSN(NAME, op, funct7)                                                                  \
  void NAME(FloatRegister Rd, FloatRegister Rs1, FloatRegister Rs2, RoundingMode rm = rne) {    \
    unsigned insn = 0;                                                                          \
    patch((address)&insn, 6, 0, op);                                                            \
    patch((address)&insn, 14, 12, rm);                                                          \
    patch((address)&insn, 31, 25, funct7);                                                      \
    patch_reg((address)&insn, 7, Rd);                                                           \
    patch_reg((address)&insn, 15, Rs1);                                                         \
    patch_reg((address)&insn, 20, Rs2);                                                         \
    emit(insn);                                                                                 \
  }

  INSN(fadd_s,   0b1010011, 0b0000000);
  INSN(fsub_s,   0b1010011, 0b0000100);
  INSN(fmul_s,   0b1010011, 0b0001000);
  INSN(fdiv_s,   0b1010011, 0b0001100);
  INSN(fadd_d,   0b1010011, 0b0000001);
  INSN(fsub_d,   0b1010011, 0b0000101);
  INSN(fmul_d,   0b1010011, 0b0001001);
  INSN(fdiv_d,   0b1010011, 0b0001101);

#undef INSN

// Whole Float and Double Conversion Instruction
#define INSN(NAME, op, funct5, funct7)                                  \
  void NAME(FloatRegister Rd, Register Rs1, RoundingMode rm = rne) {    \
    unsigned insn = 0;                                                  \
    patch((address)&insn, 6, 0, op);                                    \
    patch((address)&insn, 14, 12, rm);                                  \
    patch((address)&insn, 24, 20, funct5);                              \
    patch((address)&insn, 31, 25, funct7);                              \
    patch_reg((address)&insn, 7, Rd);                                   \
    patch_reg((address)&insn, 15, Rs1);                                 \
    emit(insn);                                                         \
  }

  INSN(fcvt_s_w,   0b1010011, 0b00000, 0b1101000);
  INSN(fcvt_s_wu,  0b1010011, 0b00001, 0b1101000);
  INSN(fcvt_s_l,   0b1010011, 0b00010, 0b1101000);
  INSN(fcvt_s_lu,  0b1010011, 0b00011, 0b1101000);
  INSN(fcvt_d_w,   0b1010011, 0b00000, 0b1101001);
  INSN(fcvt_d_wu,  0b1010011, 0b00001, 0b1101001);
  INSN(fcvt_d_l,   0b1010011, 0b00010, 0b1101001);
  INSN(fcvt_d_lu,  0b1010011, 0b00011, 0b1101001);

#undef INSN

// Float and Double Conversion Instruction
#define INSN(NAME, op, funct5, funct7)                                  \
  void NAME(Register Rd, FloatRegister Rs1, RoundingMode rm = rtz) {    \
    unsigned insn = 0;                                                  \
    patch((address)&insn, 6, 0, op);                                    \
    patch((address)&insn, 14, 12, rm);                                  \
    patch((address)&insn, 24, 20, funct5);                              \
    patch((address)&insn, 31, 25, funct7);                              \
    patch_reg((address)&insn, 7, Rd);                                   \
    patch_reg((address)&insn, 15, Rs1);                                 \
    emit(insn);                                                         \
  }

  INSN(fcvt_w_s,   0b1010011, 0b00000, 0b1100000);
  INSN(fcvt_l_s,   0b1010011, 0b00010, 0b1100000);
  INSN(fcvt_wu_s,  0b1010011, 0b00001, 0b1100000);
  INSN(fcvt_lu_s,  0b1010011, 0b00011, 0b1100000);
  INSN(fcvt_w_d,   0b1010011, 0b00000, 0b1100001);
  INSN(fcvt_wu_d,  0b1010011, 0b00001, 0b1100001);
  INSN(fcvt_l_d,   0b1010011, 0b00010, 0b1100001);
  INSN(fcvt_lu_d,  0b1010011, 0b00011, 0b1100001);

#undef INSN

// Float and Double Move Instruction
#define INSN(NAME, op, funct3, funct5, funct7)       \
  void NAME(FloatRegister Rd, Register Rs1) {        \
    unsigned insn = 0;                               \
    patch((address)&insn, 6, 0, op);                 \
    patch((address)&insn, 14, 12, funct3);           \
    patch((address)&insn, 20, funct5);               \
    patch((address)&insn, 31, 25, funct7);           \
    patch_reg((address)&insn, 7, Rd);                \
    patch_reg((address)&insn, 15, Rs1);              \
    emit(insn);                                      \
  }

  INSN(fmv_w_x,  0b1010011, 0b000, 0b00000, 0b1111000);
  INSN(fmv_d_x,  0b1010011, 0b000, 0b00000, 0b1111001);

#undef INSN

// Float and Double Conversion Instruction
#define INSN(NAME, op, funct3, funct5, funct7)            \
  void NAME(Register Rd, FloatRegister Rs1) {             \
    unsigned insn = 0;                                    \
    patch((address)&insn, 6, 0, op);                      \
    patch((address)&insn, 14, 12, funct3);                \
    patch((address)&insn, 20, funct5);                    \
    patch((address)&insn, 31, 25, funct7);                \
    patch_reg((address)&insn, 7, Rd);                     \
    patch_reg((address)&insn, 15, Rs1);                   \
    emit(insn);                                           \
  }

  INSN(fclass_s, 0b1010011, 0b001, 0b00000, 0b1110000);
  INSN(fclass_d, 0b1010011, 0b001, 0b00000, 0b1110001);
  INSN(fmv_x_w,  0b1010011, 0b000, 0b00000, 0b1110000);
  INSN(fmv_x_d,  0b1010011, 0b000, 0b00000, 0b1110001);

#undef INSN

// ==========================
// RISC-V Vector Extension
// ==========================
enum SEW {
  e8,
  e16,
  e32,
  e64,
  RESERVED,
};

enum LMUL {
  mf8 = 0b101,
  mf4 = 0b110,
  mf2 = 0b111,
  m1  = 0b000,
  m2  = 0b001,
  m4  = 0b010,
  m8  = 0b011,
};

enum VMA {
  mu, // undisturbed
  ma, // agnostic
};

enum VTA {
  tu, // undisturbed
  ta, // agnostic
};

static Assembler::SEW elembytes_to_sew(int ebytes) {
  assert(ebytes > 0 && ebytes <= 8, "unsupported element size");
  return (Assembler::SEW) exact_log2(ebytes);
}

static Assembler::SEW elemtype_to_sew(BasicType etype) {
  return Assembler::elembytes_to_sew(type2aelembytes(etype));
}

#define patch_vtype(hsb, lsb, vlmul, vsew, vta, vma, vill)   \
    if (vill == 1) {                                         \
      guarantee((vlmul | vsew | vta | vma == 0),             \
                "the other bits in vtype shall be zero");    \
    }                                                        \
    patch((address)&insn, lsb + 2, lsb, vlmul);              \
    patch((address)&insn, lsb + 5, lsb + 3, vsew);           \
    patch((address)&insn, lsb + 6, vta);                     \
    patch((address)&insn, lsb + 7, vma);                     \
    patch((address)&insn, hsb - 1, lsb + 8, 0);              \
    patch((address)&insn, hsb, vill)

#define INSN(NAME, op, funct3)                                            \
  void NAME(Register Rd, Register Rs1, SEW sew, LMUL lmul = m1,           \
            VMA vma = mu, VTA vta = tu, bool vill = false) {              \
    unsigned insn = 0;                                                    \
    patch((address)&insn, 6, 0, op);                                      \
    patch((address)&insn, 14, 12, funct3);                                \
    patch_vtype(30, 20, lmul, sew, vta, vma, vill);                       \
    patch((address)&insn, 31, 0);                                         \
    patch_reg((address)&insn, 7, Rd);                                     \
    patch_reg((address)&insn, 15, Rs1);                                   \
    emit(insn);                                                           \
  }

  INSN(vsetvli, 0b1010111, 0b111);

#undef INSN

#define INSN(NAME, op, funct3)                                            \
  void NAME(Register Rd, uint32_t imm, SEW sew, LMUL lmul = m1,           \
            VMA vma = mu, VTA vta = tu, bool vill = false) {              \
    unsigned insn = 0;                                                    \
    guarantee(is_unsigned_imm_in_range(imm, 5, 0), "imm is invalid");     \
    patch((address)&insn, 6, 0, op);                                      \
    patch((address)&insn, 14, 12, funct3);                                \
    patch((address)&insn, 19, 15, imm);                                   \
    patch_vtype(29, 20, lmul, sew, vta, vma, vill);                       \
    patch((address)&insn, 31, 30, 0b11);                                  \
    patch_reg((address)&insn, 7, Rd);                                     \
    emit(insn);                                                           \
  }

  INSN(vsetivli, 0b1010111, 0b111);

#undef INSN

#undef patch_vtype

#define INSN(NAME, op, funct3, funct7)                          \
  void NAME(Register Rd, Register Rs1, Register Rs2) {          \
    unsigned insn = 0;                                          \
    patch((address)&insn, 6,  0, op);                           \
    patch((address)&insn, 14, 12, funct3);                      \
    patch((address)&insn, 31, 25, funct7);                      \
    patch_reg((address)&insn, 7, Rd);                           \
    patch_reg((address)&insn, 15, Rs1);                         \
    patch_reg((address)&insn, 20, Rs2);                         \
    emit(insn);                                                 \
  }

  // Vector Configuration Instruction
  INSN(vsetvl, 0b1010111, 0b111, 0b1000000);

#undef INSN

enum VectorMask {
  v0_t = 0b0,
  unmasked = 0b1
};

#define patch_VArith(op, Reg, funct3, Reg_or_Imm5, Vs2, vm, funct6)            \
    unsigned insn = 0;                                                         \
    patch((address)&insn, 6, 0, op);                                           \
    patch((address)&insn, 14, 12, funct3);                                     \
    patch((address)&insn, 19, 15, Reg_or_Imm5);                                \
    patch((address)&insn, 25, vm);                                             \
    patch((address)&insn, 31, 26, funct6);                                     \
    patch_reg((address)&insn, 7, Reg);                                         \
    patch_reg((address)&insn, 20, Vs2);                                        \
    emit(insn)

// r2_vm
#define INSN(NAME, op, funct3, Vs1, funct6)                                    \
  void NAME(Register Rd, VectorRegister Vs2, VectorMask vm = unmasked) {       \
    patch_VArith(op, Rd, funct3, Vs1, Vs2, vm, funct6);                        \
  }

  // Vector Mask
  INSN(vcpop_m,  0b1010111, 0b010, 0b10000, 0b010000);
  INSN(vfirst_m, 0b1010111, 0b010, 0b10001, 0b010000);
#undef INSN

#define INSN(NAME, op, funct3, Vs1, funct6)                                    \
  void NAME(VectorRegister Vd, VectorRegister Vs2, VectorMask vm = unmasked) { \
    patch_VArith(op, Vd, funct3, Vs1, Vs2, vm, funct6);                        \
  }

  // Vector Integer Extension
  INSN(vzext_vf2, 0b1010111, 0b010, 0b00110, 0b010010);
  INSN(vzext_vf4, 0b1010111, 0b010, 0b00100, 0b010010);
  INSN(vzext_vf8, 0b1010111, 0b010, 0b00010, 0b010010);
  INSN(vsext_vf2, 0b1010111, 0b010, 0b00111, 0b010010);
  INSN(vsext_vf4, 0b1010111, 0b010, 0b00101, 0b010010);
  INSN(vsext_vf8, 0b1010111, 0b010, 0b00011, 0b010010);

  // Vector Mask
  INSN(vmsbf_m,   0b1010111, 0b010, 0b00001, 0b010100);
  INSN(vmsif_m,   0b1010111, 0b010, 0b00011, 0b010100);
  INSN(vmsof_m,   0b1010111, 0b010, 0b00010, 0b010100);
  INSN(viota_m,   0b1010111, 0b010, 0b10000, 0b010100);

  // Vector Single-Width Floating-Point/Integer Type-Convert Instructions
  INSN(vfcvt_xu_f_v, 0b1010111, 0b001, 0b00000, 0b010010);
  INSN(vfcvt_x_f_v,  0b1010111, 0b001, 0b00001, 0b010010);
  INSN(vfcvt_f_xu_v, 0b1010111, 0b001, 0b00010, 0b010010);
  INSN(vfcvt_f_x_v,  0b1010111, 0b001, 0b00011, 0b010010);
  INSN(vfcvt_rtz_xu_f_v, 0b1010111, 0b001, 0b00110, 0b010010);
  INSN(vfcvt_rtz_x_f_v,  0b1010111, 0b001, 0b00111, 0b010010);

  // Vector Floating-Point Instruction
  INSN(vfsqrt_v,  0b1010111, 0b001, 0b00000, 0b010011);
  INSN(vfclass_v, 0b1010111, 0b001, 0b10000, 0b010011);

#undef INSN

// r2rd
#define INSN(NAME, op, funct3, simm5, vm, funct6)         \
  void NAME(VectorRegister Vd, VectorRegister Vs2) {      \
    patch_VArith(op, Vd, funct3, simm5, Vs2, vm, funct6); \
  }

  // Vector Whole Vector Register Move
  INSN(vmv1r_v, 0b1010111, 0b011, 0b00000, 0b1, 0b100111);
  INSN(vmv2r_v, 0b1010111, 0b011, 0b00001, 0b1, 0b100111);
  INSN(vmv4r_v, 0b1010111, 0b011, 0b00011, 0b1, 0b100111);
  INSN(vmv8r_v, 0b1010111, 0b011, 0b00111, 0b1, 0b100111);

#undef INSN

#define INSN(NAME, op, funct3, Vs1, vm, funct6)           \
  void NAME(FloatRegister Rd, VectorRegister Vs2) {       \
    patch_VArith(op, Rd, funct3, Vs1, Vs2, vm, funct6);   \
  }

  // Vector Floating-Point Move Instruction
  INSN(vfmv_f_s, 0b1010111, 0b001, 0b00000, 0b1, 0b010000);

#undef INSN

#define INSN(NAME, op, funct3, Vs1, vm, funct6)          \
  void NAME(Register Rd, VectorRegister Vs2) {           \
    patch_VArith(op, Rd, funct3, Vs1, Vs2, vm, funct6);  \
  }

  // Vector Integer Scalar Move Instructions
  INSN(vmv_x_s, 0b1010111, 0b010, 0b00000, 0b1, 0b010000);

#undef INSN

// r_vm
#define INSN(NAME, op, funct3, funct6)                                                             \
  void NAME(VectorRegister Vd, VectorRegister Vs2, uint32_t imm, VectorMask vm = unmasked) {       \
    guarantee(is_unsigned_imm_in_range(imm, 5, 0), "imm is invalid");                              \
    patch_VArith(op, Vd, funct3, (uint32_t)(imm & 0x1f), Vs2, vm, funct6);                         \
  }

  // Vector Single-Width Bit Shift Instructions
  INSN(vsra_vi,    0b1010111, 0b011, 0b101001);
  INSN(vsrl_vi,    0b1010111, 0b011, 0b101000);
  INSN(vsll_vi,    0b1010111, 0b011, 0b100101);

#undef INSN

#define INSN(NAME, op, funct3, funct6)                                                             \
  void NAME(VectorRegister Vd, VectorRegister Vs1, VectorRegister Vs2, VectorMask vm = unmasked) { \
    patch_VArith(op, Vd, funct3, Vs1->raw_encoding(), Vs2, vm, funct6);                            \
  }

  // Vector Single-Width Floating-Point Fused Multiply-Add Instructions
  INSN(vfnmsub_vv, 0b1010111, 0b001, 0b101011);
  INSN(vfmsub_vv,  0b1010111, 0b001, 0b101010);
  INSN(vfnmadd_vv, 0b1010111, 0b001, 0b101001);
  INSN(vfmadd_vv,  0b1010111, 0b001, 0b101000);
  INSN(vfnmsac_vv, 0b1010111, 0b001, 0b101111);
  INSN(vfmsac_vv,  0b1010111, 0b001, 0b101110);
  INSN(vfmacc_vv,  0b1010111, 0b001, 0b101100);
  INSN(vfnmacc_vv, 0b1010111, 0b001, 0b101101);

  // Vector Single-Width Integer Multiply-Add Instructions
  INSN(vnmsub_vv, 0b1010111, 0b010, 0b101011);
  INSN(vmadd_vv,  0b1010111, 0b010, 0b101001);
  INSN(vnmsac_vv, 0b1010111, 0b010, 0b101111);
  INSN(vmacc_vv,  0b1010111, 0b010, 0b101101);

#undef INSN

#define INSN(NAME, op, funct3, funct6)                                                             \
  void NAME(VectorRegister Vd, Register Rs1, VectorRegister Vs2, VectorMask vm = unmasked) {       \
    patch_VArith(op, Vd, funct3, Rs1->raw_encoding(), Vs2, vm, funct6);                            \
  }

  // Vector Single-Width Integer Multiply-Add Instructions
  INSN(vnmsub_vx, 0b1010111, 0b110, 0b101011);
  INSN(vmadd_vx,  0b1010111, 0b110, 0b101001);
  INSN(vnmsac_vx, 0b1010111, 0b110, 0b101111);
  INSN(vmacc_vx,  0b1010111, 0b110, 0b101101);

#undef INSN

#define INSN(NAME, op, funct3, funct6)                                                             \
  void NAME(VectorRegister Vd, FloatRegister Rs1, VectorRegister Vs2, VectorMask vm = unmasked) {  \
    patch_VArith(op, Vd, funct3, Rs1->raw_encoding(), Vs2, vm, funct6);                            \
  }

  // Vector Single-Width Floating-Point Fused Multiply-Add Instructions
  INSN(vfnmsub_vf, 0b1010111, 0b101, 0b101011);
  INSN(vfmsub_vf,  0b1010111, 0b101, 0b101010);
  INSN(vfnmadd_vf, 0b1010111, 0b101, 0b101001);
  INSN(vfmadd_vf,  0b1010111, 0b101, 0b101000);
  INSN(vfnmsac_vf, 0b1010111, 0b101, 0b101111);
  INSN(vfmsac_vf,  0b1010111, 0b101, 0b101110);
  INSN(vfmacc_vf,  0b1010111, 0b101, 0b101100);
  INSN(vfnmacc_vf, 0b1010111, 0b101, 0b101101);

#undef INSN

#define INSN(NAME, op, funct3, funct6)                                                             \
  void NAME(VectorRegister Vd, VectorRegister Vs2, VectorRegister Vs1, VectorMask vm = unmasked) { \
    patch_VArith(op, Vd, funct3, Vs1->raw_encoding(), Vs2, vm, funct6);                            \
  }

  // Vector Single-Width Floating-Point Reduction Instructions
  INSN(vfredusum_vs,  0b1010111, 0b001, 0b000001);
  INSN(vfredosum_vs,  0b1010111, 0b001, 0b000011);
  INSN(vfredmin_vs,   0b1010111, 0b001, 0b000101);
  INSN(vfredmax_vs,   0b1010111, 0b001, 0b000111);

  // Vector Single-Width Integer Reduction Instructions
  INSN(vredsum_vs,    0b1010111, 0b010, 0b000000);
  INSN(vredand_vs,    0b1010111, 0b010, 0b000001);
  INSN(vredor_vs,     0b1010111, 0b010, 0b000010);
  INSN(vredxor_vs,    0b1010111, 0b010, 0b000011);
  INSN(vredminu_vs,   0b1010111, 0b010, 0b000100);
  INSN(vredmin_vs,    0b1010111, 0b010, 0b000101);
  INSN(vredmaxu_vs,   0b1010111, 0b010, 0b000110);
  INSN(vredmax_vs,    0b1010111, 0b010, 0b000111);

  // Vector Floating-Point Compare Instructions
  INSN(vmfle_vv, 0b1010111, 0b001, 0b011001);
  INSN(vmflt_vv, 0b1010111, 0b001, 0b011011);
  INSN(vmfne_vv, 0b1010111, 0b001, 0b011100);
  INSN(vmfeq_vv, 0b1010111, 0b001, 0b011000);

  // Vector Floating-Point Sign-Injection Instructions
  INSN(vfsgnjx_vv, 0b1010111, 0b001, 0b001010);
  INSN(vfsgnjn_vv, 0b1010111, 0b001, 0b001001);
  INSN(vfsgnj_vv,  0b1010111, 0b001, 0b001000);

  // Vector Floating-Point MIN/MAX Instructions
  INSN(vfmax_vv,   0b1010111, 0b001, 0b000110);
  INSN(vfmin_vv,   0b1010111, 0b001, 0b000100);

  // Vector Single-Width Floating-Point Multiply/Divide Instructions
  INSN(vfdiv_vv,   0b1010111, 0b001, 0b100000);
  INSN(vfmul_vv,   0b1010111, 0b001, 0b100100);

  // Vector Single-Width Floating-Point Add/Subtract Instructions
  INSN(vfsub_vv, 0b1010111, 0b001, 0b000010);
  INSN(vfadd_vv, 0b1010111, 0b001, 0b000000);

  // Vector Single-Width Fractional Multiply with Rounding and Saturation
  INSN(vsmul_vv, 0b1010111, 0b000, 0b100111);

  // Vector Integer Divide Instructions
  INSN(vrem_vv,  0b1010111, 0b010, 0b100011);
  INSN(vremu_vv, 0b1010111, 0b010, 0b100010);
  INSN(vdiv_vv,  0b1010111, 0b010, 0b100001);
  INSN(vdivu_vv, 0b1010111, 0b010, 0b100000);

  // Vector Single-Width Integer Multiply Instructions
  INSN(vmulhsu_vv, 0b1010111, 0b010, 0b100110);
  INSN(vmulhu_vv,  0b1010111, 0b010, 0b100100);
  INSN(vmulh_vv,   0b1010111, 0b010, 0b100111);
  INSN(vmul_vv,    0b1010111, 0b010, 0b100101);

  // Vector Integer Min/Max Instructions
  INSN(vmax_vv,  0b1010111, 0b000, 0b000111);
  INSN(vmaxu_vv, 0b1010111, 0b000, 0b000110);
  INSN(vmin_vv,  0b1010111, 0b000, 0b000101);
  INSN(vminu_vv, 0b1010111, 0b000, 0b000100);

  // Vector Integer Comparison Instructions
  INSN(vmsle_vv,  0b1010111, 0b000, 0b011101);
  INSN(vmsleu_vv, 0b1010111, 0b000, 0b011100);
  INSN(vmslt_vv,  0b1010111, 0b000, 0b011011);
  INSN(vmsltu_vv, 0b1010111, 0b000, 0b011010);
  INSN(vmsne_vv,  0b1010111, 0b000, 0b011001);
  INSN(vmseq_vv,  0b1010111, 0b000, 0b011000);

  // Vector Single-Width Bit Shift Instructions
  INSN(vsra_vv, 0b1010111, 0b000, 0b101001);
  INSN(vsrl_vv, 0b1010111, 0b000, 0b101000);
  INSN(vsll_vv, 0b1010111, 0b000, 0b100101);

  // Vector Bitwise Logical Instructions
  INSN(vxor_vv, 0b1010111, 0b000, 0b001011);
  INSN(vor_vv,  0b1010111, 0b000, 0b001010);
  INSN(vand_vv, 0b1010111, 0b000, 0b001001);

  // Vector Single-Width Integer Add and Subtract
  INSN(vsub_vv, 0b1010111, 0b000, 0b000010);
  INSN(vadd_vv, 0b1010111, 0b000, 0b000000);

#undef INSN


#define INSN(NAME, op, funct3, funct6)                                                             \
  void NAME(VectorRegister Vd, VectorRegister Vs2, Register Rs1, VectorMask vm = unmasked) {       \
    patch_VArith(op, Vd, funct3, Rs1->raw_encoding(), Vs2, vm, funct6);                            \
  }

  // Vector Integer Divide Instructions
  INSN(vrem_vx,  0b1010111, 0b110, 0b100011);
  INSN(vremu_vx, 0b1010111, 0b110, 0b100010);
  INSN(vdiv_vx,  0b1010111, 0b110, 0b100001);
  INSN(vdivu_vx, 0b1010111, 0b110, 0b100000);

  // Vector Single-Width Integer Multiply Instructions
  INSN(vmulhsu_vx, 0b1010111, 0b110, 0b100110);
  INSN(vmulhu_vx,  0b1010111, 0b110, 0b100100);
  INSN(vmulh_vx,   0b1010111, 0b110, 0b100111);
  INSN(vmul_vx,    0b1010111, 0b110, 0b100101);

  // Vector Integer Min/Max Instructions
  INSN(vmax_vx,  0b1010111, 0b100, 0b000111);
  INSN(vmaxu_vx, 0b1010111, 0b100, 0b000110);
  INSN(vmin_vx,  0b1010111, 0b100, 0b000101);
  INSN(vminu_vx, 0b1010111, 0b100, 0b000100);

  // Vector Integer Comparison Instructions
  INSN(vmsgt_vx,  0b1010111, 0b100, 0b011111);
  INSN(vmsgtu_vx, 0b1010111, 0b100, 0b011110);
  INSN(vmsle_vx,  0b1010111, 0b100, 0b011101);
  INSN(vmsleu_vx, 0b1010111, 0b100, 0b011100);
  INSN(vmslt_vx,  0b1010111, 0b100, 0b011011);
  INSN(vmsltu_vx, 0b1010111, 0b100, 0b011010);
  INSN(vmsne_vx,  0b1010111, 0b100, 0b011001);
  INSN(vmseq_vx,  0b1010111, 0b100, 0b011000);

  // Vector Narrowing Integer Right Shift Instructions
  INSN(vnsra_wx, 0b1010111, 0b100, 0b101101);
  INSN(vnsrl_wx, 0b1010111, 0b100, 0b101100);

  // Vector Single-Width Bit Shift Instructions
  INSN(vsra_vx, 0b1010111, 0b100, 0b101001);
  INSN(vsrl_vx, 0b1010111, 0b100, 0b101000);
  INSN(vsll_vx, 0b1010111, 0b100, 0b100101);

  // Vector Bitwise Logical Instructions
  INSN(vxor_vx, 0b1010111, 0b100, 0b001011);
  INSN(vor_vx,  0b1010111, 0b100, 0b001010);
  INSN(vand_vx, 0b1010111, 0b100, 0b001001);

  // Vector Single-Width Integer Add and Subtract
  INSN(vsub_vx,  0b1010111, 0b100, 0b000010);
  INSN(vadd_vx,  0b1010111, 0b100, 0b000000);
  INSN(vrsub_vx, 0b1010111, 0b100, 0b000011);

#undef INSN

#define INSN(NAME, op, funct3, funct6)                                                             \
  void NAME(VectorRegister Vd, VectorRegister Vs2, FloatRegister Rs1, VectorMask vm = unmasked) {  \
    patch_VArith(op, Vd, funct3, Rs1->raw_encoding(), Vs2, vm, funct6);                            \
  }

  // Vector Floating-Point Compare Instructions
  INSN(vmfge_vf, 0b1010111, 0b101, 0b011111);
  INSN(vmfgt_vf, 0b1010111, 0b101, 0b011101);
  INSN(vmfle_vf, 0b1010111, 0b101, 0b011001);
  INSN(vmflt_vf, 0b1010111, 0b101, 0b011011);
  INSN(vmfne_vf, 0b1010111, 0b101, 0b011100);
  INSN(vmfeq_vf, 0b1010111, 0b101, 0b011000);

  // Vector Floating-Point Sign-Injection Instructions
  INSN(vfsgnjx_vf, 0b1010111, 0b101, 0b001010);
  INSN(vfsgnjn_vf, 0b1010111, 0b101, 0b001001);
  INSN(vfsgnj_vf,  0b1010111, 0b101, 0b001000);

  // Vector Floating-Point MIN/MAX Instructions
  INSN(vfmax_vf, 0b1010111, 0b101, 0b000110);
  INSN(vfmin_vf, 0b1010111, 0b101, 0b000100);

  // Vector Single-Width Floating-Point Multiply/Divide Instructions
  INSN(vfdiv_vf,  0b1010111, 0b101, 0b100000);
  INSN(vfmul_vf,  0b1010111, 0b101, 0b100100);
  INSN(vfrdiv_vf, 0b1010111, 0b101, 0b100001);

  // Vector Single-Width Floating-Point Add/Subtract Instructions
  INSN(vfsub_vf,  0b1010111, 0b101, 0b000010);
  INSN(vfadd_vf,  0b1010111, 0b101, 0b000000);
  INSN(vfrsub_vf, 0b1010111, 0b101, 0b100111);

#undef INSN

#define INSN(NAME, op, funct3, funct6)                                                             \
  void NAME(VectorRegister Vd, VectorRegister Vs2, int32_t imm, VectorMask vm = unmasked) {        \
    guarantee(is_imm_in_range(imm, 5, 0), "imm is invalid");                                       \
    patch_VArith(op, Vd, funct3, (uint32_t)(imm & 0x1f), Vs2, vm, funct6);                         \
  }

  INSN(vmsgt_vi,  0b1010111, 0b011, 0b011111);
  INSN(vmsgtu_vi, 0b1010111, 0b011, 0b011110);
  INSN(vmsle_vi,  0b1010111, 0b011, 0b011101);
  INSN(vmsleu_vi, 0b1010111, 0b011, 0b011100);
  INSN(vmsne_vi,  0b1010111, 0b011, 0b011001);
  INSN(vmseq_vi,  0b1010111, 0b011, 0b011000);
  INSN(vxor_vi,   0b1010111, 0b011, 0b001011);
--> --------------------

--> maximum size reached

--> --------------------

¤ Dauer der Verarbeitung: 0.60 Sekunden  (vorverarbeitet)  ¤





Download des
Quellennavigators
Download des
sprechenden Kalenders

Eigene Datei ansehen




Lebenszyklus

Die hierunter aufgelisteten Ziele sind für diese Firma wichtig


Ziele

Entwicklung einer Software für die statische Quellcodeanalyse


Bot Zugriff