// Copyright 2022 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef jit_riscv64_base_Instruction_h
#define jit_riscv64_base_Instruction_h
#include "mozilla/Assertions.h"
#include <stdint.h>
#include "jit/riscv64/base/Integer.h"
#include "jit/riscv64/constant/Constant-riscv64.h"
namespace js::jit {
// On RISCV all instructions are 32 bits, except for RVC.
using Instr = int32_t;
using ShortInstr = int16_t;
// -----------------------------------------------------------------------------
// Specific instructions, constants, and masks.
// These constants are declared in assembler-riscv64.cc, as they use named
// registers and other constants.
// An Illegal instruction
const Instr kIllegalInstr = 0 ; // All other bits are 0s (i.e., ecall)
// An ECALL instruction, used for redirected real time call
const Instr rtCallRedirInstr = SYSTEM; // All other bits are 0s (i.e., ecall)
// An EBreak instruction, used for debugging and semi-hosting
const Instr kBreakInstr = SYSTEM | 1 << kImm12Shift; // ebreak
constexpr uint8_t kInstrSize = 4 ;
constexpr uint8_t kShortInstrSize = 2 ;
class InstructionBase {
// Sign-extend a |len|-bits integer.
static constexpr int32_t sext(int32_t x, uint32_t len) {
MOZ_ASSERT(0 < len && len <= 32 );
return ((x << (32 - len)) >> (32 - len));
}
// Zero-extend a |len|-bits integer.
static constexpr uint32_t zext(uint32_t x, uint32_t len) {
MOZ_ASSERT(0 < len && len <= 32 );
return ((x << (32 - len)) >> (32 - len));
}
public:
enum {
// On RISC-V, PC cannot actually be directly accessed. We behave as if PC
// was always the value of the current instruction being executed.
kPCReadOffset = 0
};
// Instruction type.
enum Type {
kRType,
kR4Type, // Special R4 for Q extension
kIType,
kSType,
kBType,
kUType,
kJType,
// C extension
kCRType,
kCIType,
kCSSType,
kCIWType,
kCLType,
kCSType,
kCAType,
kCBType,
kCJType,
// V extension
kVType,
kVLType,
kVSType,
kVAMOType,
kVIVVType,
kVFVVType,
kVMVVType,
kVIVIType,
kVIVXType,
kVFVFType,
kVMVXType,
kVSETType,
kUnsupported = -1
};
inline bool IsIllegalInstruction() const {
uint16_t FirstHalfWord = *reinterpret_cast<const uint16_t*>(this);
return FirstHalfWord == 0 ;
}
inline bool IsShortInstruction() const {
uint8_t FirstByte = *reinterpret_cast<const uint8_t*>(this);
return (FirstByte & 0 x03) <= C2;
}
inline uint8_t InstructionSize() const {
return IsShortInstruction() ? kShortInstrSize : kInstrSize;
}
// Get the raw instruction bits.
inline Instr InstructionBits() const {
if (IsShortInstruction()) {
return 0 x0000FFFF & (*reinterpret_cast<const ShortInstr*>(this));
}
return *reinterpret_cast<const Instr*>(this);
}
// Set the raw instruction bits to value.
inline void SetInstructionBits(Instr value) {
*reinterpret_cast<Instr*>(this) = value;
}
// Read one particular bit out of the instruction bits.
inline int Bit(int nr) const { return (InstructionBits() >> nr) & 1 ; }
// Read a bit field out of the instruction bits.
inline int Bits(int hi, int lo) const {
return (InstructionBits() >> lo) & ((2 U << (hi - lo)) - 1 );
}
// Accessors for the different named fields used in the RISC-V encoding.
inline enum BaseOpcode BaseOpcodeValue() const {
return static_cast<enum BaseOpcode>(
Bits(kBaseOpcodeShift + kBaseOpcodeBits - 1 , kBaseOpcodeShift));
}
// Return the fields at their original place in the instruction encoding.
inline enum BaseOpcode BaseOpcodeFieldRaw() const {
return static_cast<enum BaseOpcode>(InstructionBits() & kBaseOpcodeMask);
}
// Safe to call within R-type instructions
inline int Funct7FieldRaw() const { return InstructionBits() & kFunct7Mask; }
// Safe to call within R-type instructions
inline int Funct6FieldRaw() const { return InstructionBits() & kFunct6Mask; }
// Safe to call within R-, I-, S-, or B-type instructions
inline int Funct3FieldRaw() const { return InstructionBits() & kFunct3Mask; }
// Safe to call within R-, I-, S-, or B-type instructions
inline int Rs1FieldRawNoAssert() const {
return InstructionBits() & kRs1FieldMask;
}
// Safe to call within R-, S-, or B-type instructions
inline int Rs2FieldRawNoAssert() const {
return InstructionBits() & kRs2FieldMask;
}
// Safe to call within R4-type instructions
inline int Rs3FieldRawNoAssert() const {
return InstructionBits() & kRs3FieldMask;
}
inline int32_t ITypeBits() const { return InstructionBits() & kITypeMask; }
inline int32_t InstructionOpcodeType() const {
if (IsShortInstruction()) {
return InstructionBits() & kRvcOpcodeMask;
}
return InstructionBits() & kBaseOpcodeMask;
}
// Get the encoding type of the instruction.
Type InstructionType() const ;
OffsetSize GetOffsetSize() const ;
inline ImmBranchRangeType GetImmBranchRangeType() const {
return OffsetSizeToImmBranchRangeType(GetOffsetSize());
}
/// Getters
// Say if the instruction is a break or a trap.
inline bool IsTrap() const { return InstructionBits() == kBreakInstr; }
// Check if the instruction is a branch of some kind.
inline bool IsBranch() const { return BaseOpcode() == BRANCH; }
inline bool IsJal() const { return BaseOpcode() == JAL; }
inline bool IsJalr() const { return BaseOpcode() == JALR; }
inline bool IsLui() const { return BaseOpcode() == LUI; }
inline bool IsAuipc() const { return BaseOpcode() == AUIPC; }
inline bool IsAddi() const {
return (InstructionBits() & kITypeMask) == RO_ADDI;
}
inline bool IsOri() const {
return (InstructionBits() & kITypeMask) == RO_ORI;
}
inline bool IsSlli() const {
return (InstructionBits() & kITypeMask) == RO_SLLI;
}
inline bool IsLw() const { return (InstructionBits() & kITypeMask) == RO_LW; }
inline bool IsLd() const { return (InstructionBits() & kITypeMask) == RO_LD; }
inline bool IsAddiw() const {
return (InstructionBits() & kITypeMask) == RO_ADDIW;
}
inline bool IsNop() const { return InstructionBits() == kNopByte; }
inline int BaseOpcode() const { return InstructionBits() & kBaseOpcodeMask; }
inline int RvcOpcode() const {
MOZ_ASSERT(IsShortInstruction());
return InstructionBits() & kRvcOpcodeMask;
}
inline int Rs1Value() const {
MOZ_ASSERT(InstructionType() == InstructionBase::kRType ||
InstructionType() == InstructionBase::kR4Type ||
InstructionType() == InstructionBase::kIType ||
InstructionType() == InstructionBase::kSType ||
InstructionType() == InstructionBase::kBType ||
InstructionType() == InstructionBase::kVType);
return Bits(kRs1Shift + kRs1Bits - 1 , kRs1Shift);
}
inline int Rs2Value() const {
MOZ_ASSERT(InstructionType() == InstructionBase::kRType ||
InstructionType() == InstructionBase::kR4Type ||
InstructionType() == InstructionBase::kSType ||
InstructionType() == InstructionBase::kBType ||
InstructionType() == InstructionBase::kIType ||
InstructionType() == InstructionBase::kVType);
return Bits(kRs2Shift + kRs2Bits - 1 , kRs2Shift);
}
inline int Rs3Value() const {
MOZ_ASSERT(InstructionType() == InstructionBase::kR4Type);
return Bits(kRs3Shift + kRs3Bits - 1 , kRs3Shift);
}
inline int Vs1Value() const {
MOZ_ASSERT(InstructionType() == InstructionBase::kVType ||
InstructionType() == InstructionBase::kIType ||
InstructionType() == InstructionBase::kSType);
return Bits(kVs1Shift + kVs1Bits - 1 , kVs1Shift);
}
inline int Vs2Value() const {
MOZ_ASSERT(InstructionType() == InstructionBase::kVType ||
InstructionType() == InstructionBase::kIType ||
InstructionType() == InstructionBase::kSType);
return Bits(kVs2Shift + kVs2Bits - 1 , kVs2Shift);
}
inline int VdValue() const {
MOZ_ASSERT(InstructionType() == InstructionBase::kVType ||
InstructionType() == InstructionBase::kIType ||
InstructionType() == InstructionBase::kSType);
return Bits(kVdShift + kVdBits - 1 , kVdShift);
}
inline int RdValue() const {
MOZ_ASSERT(InstructionType() == InstructionBase::kRType ||
InstructionType() == InstructionBase::kR4Type ||
InstructionType() == InstructionBase::kIType ||
InstructionType() == InstructionBase::kSType ||
InstructionType() == InstructionBase::kUType ||
InstructionType() == InstructionBase::kJType ||
InstructionType() == InstructionBase::kVType);
return Bits(kRdShift + kRdBits - 1 , kRdShift);
}
inline int RvcRs1Value() const { return RvcRdValue(); }
inline int RvcRdValue() const {
MOZ_ASSERT(IsShortInstruction());
return Bits(kRvcRdShift + kRvcRdBits - 1 , kRvcRdShift);
}
inline int RvcRs2Value() const {
MOZ_ASSERT(IsShortInstruction());
return Bits(kRvcRs2Shift + kRvcRs2Bits - 1 , kRvcRs2Shift);
}
inline int RvcRs1sValue() const {
MOZ_ASSERT(IsShortInstruction());
return 0 b1000 + Bits(kRvcRs1sShift + kRvcRs1sBits - 1 , kRvcRs1sShift);
}
inline int RvcRs2sValue() const {
MOZ_ASSERT(IsShortInstruction());
return 0 b1000 + Bits(kRvcRs2sShift + kRvcRs2sBits - 1 , kRvcRs2sShift);
}
inline int Funct7Value() const {
MOZ_ASSERT(InstructionType() == InstructionBase::kRType);
return Bits(kFunct7Shift + kFunct7Bits - 1 , kFunct7Shift);
}
inline int Funct2Value() const {
MOZ_ASSERT(InstructionType() == InstructionBase::kR4Type);
return Bits(kFunct2Shift + kFunct2Bits - 1 , kFunct2Shift);
}
inline int Funct3Value() const {
MOZ_ASSERT(InstructionType() == InstructionBase::kRType ||
InstructionType() == InstructionBase::kR4Type ||
InstructionType() == InstructionBase::kIType ||
InstructionType() == InstructionBase::kSType ||
InstructionType() == InstructionBase::kBType);
return Bits(kFunct3Shift + kFunct3Bits - 1 , kFunct3Shift);
}
inline int Funct5Value() const {
MOZ_ASSERT(InstructionType() == InstructionBase::kRType &&
BaseOpcode() == OP_FP);
return Bits(kFunct5Shift + kFunct5Bits - 1 , kFunct5Shift);
}
inline int RvcFunct6Value() const {
MOZ_ASSERT(IsShortInstruction());
return Bits(kRvcFunct6Shift + kRvcFunct6Bits - 1 , kRvcFunct6Shift);
}
inline int RvcFunct4Value() const {
MOZ_ASSERT(IsShortInstruction());
return Bits(kRvcFunct4Shift + kRvcFunct4Bits - 1 , kRvcFunct4Shift);
}
inline int RvcFunct3Value() const {
MOZ_ASSERT(IsShortInstruction());
return Bits(kRvcFunct3Shift + kRvcFunct3Bits - 1 , kRvcFunct3Shift);
}
inline int RvcFunct2Value() const {
MOZ_ASSERT(IsShortInstruction());
return Bits(kRvcFunct2Shift + kRvcFunct2Bits - 1 , kRvcFunct2Shift);
}
inline int RvcFunct2BValue() const {
MOZ_ASSERT(IsShortInstruction());
return Bits(kRvcFunct2BShift + kRvcFunct2Bits - 1 , kRvcFunct2BShift);
}
inline int CsrValue() const {
MOZ_ASSERT(InstructionType() == InstructionBase::kIType &&
BaseOpcode() == SYSTEM);
return Bits(kCsrShift + kCsrBits - 1 , kCsrShift);
}
inline int RoundMode() const {
MOZ_ASSERT((InstructionType() == InstructionBase::kRType ||
InstructionType() == InstructionBase::kR4Type) &&
BaseOpcode() == OP_FP);
return Bits(kFunct3Shift + kFunct3Bits - 1 , kFunct3Shift);
}
inline int MemoryOrder(bool is_pred) const {
MOZ_ASSERT(InstructionType() == InstructionBase::kIType &&
BaseOpcode() == MISC_MEM);
if (is_pred) {
return Bits(kPredOrderShift + kMemOrderBits - 1 , kPredOrderShift);
}
return Bits(kSuccOrderShift + kMemOrderBits - 1 , kSuccOrderShift);
}
inline int Imm12Value() const {
MOZ_ASSERT(InstructionType() == InstructionBase::kIType);
int Value = Bits(kImm12Shift + kImm12Bits - 1 , kImm12Shift);
return sext(Value, kImm12Bits);
}
inline int BranchOffset() const {
MOZ_ASSERT(InstructionType() == InstructionBase::kBType);
// | imm[12|10:5] | rs2 | rs1 | funct3 | imm[4:1|11] | opcode |
// 31 25 11 7
uint32_t Bits = InstructionBits();
int16_t imm13 = ((Bits & 0 xf00) >> 7 ) | ((Bits & 0 x7e000000) >> 20 ) |
((Bits & 0 x80) << 4 ) | ((Bits & 0 x80000000) >> 19 );
return sext(imm13, 13 );
}
inline int StoreOffset() const {
MOZ_ASSERT(InstructionType() == InstructionBase::kSType);
// | imm[11:5] | rs2 | rs1 | funct3 | imm[4:0] | opcode |
// 31 25 11 7
uint32_t Bits = InstructionBits();
int16_t imm12 = ((Bits & 0 xf80) >> 7 ) | ((Bits & 0 xfe000000) >> 20 );
return sext(imm12, 12 );
}
inline int Imm20UValue() const {
MOZ_ASSERT(InstructionType() == InstructionBase::kUType);
// | imm[31:12] | rd | opcode |
// 31 12
int32_t Bits = InstructionBits();
return Bits >> 12 ;
}
inline int Imm20JValue() const {
MOZ_ASSERT(InstructionType() == InstructionBase::kJType);
// | imm[20|10:1|11|19:12] | rd | opcode |
// 31 12
uint32_t Bits = InstructionBits();
int32_t imm20 = ((Bits & 0 x7fe00000) >> 20 ) | ((Bits & 0 x100000) >> 9 ) |
(Bits & 0 xff000) | ((Bits & 0 x80000000) >> 11 );
return sext(imm20, 20 + 1 ); // +1 b/c J immediates are shifted by 1 bit.
}
inline bool IsArithShift() const {
// Valid only for right shift operations
MOZ_ASSERT((BaseOpcode() == OP || BaseOpcode() == OP_32 ||
BaseOpcode() == OP_IMM || BaseOpcode() == OP_IMM_32) &&
Funct3Value() == 0 b101);
return InstructionBits() & 0 x40000000;
}
inline int Shamt() const {
// Valid only for shift instructions (SLLI, SRLI, SRAI)
MOZ_ASSERT(((InstructionBits() & kBaseOpcodeMask) == OP_IMM ||
(InstructionBits() & kBaseOpcodeMask) == OP_IMM_32) &&
(Funct3Value() == 0 b001 || Funct3Value() == 0 b101));
// | 0A0000 | shamt | rs1 | funct3 | rd | opcode |
// 31 25 20
return Bits(kImm12Shift + 5 , kImm12Shift);
}
inline int Shamt32() const {
// Valid only for shift instructions (SLLIW, SRLIW, SRAIW)
MOZ_ASSERT((InstructionBits() & kBaseOpcodeMask) == OP_IMM_32 &&
(Funct3Value() == 0 b001 || Funct3Value() == 0 b101));
// | 0A00000 | shamt | rs1 | funct3 | rd | opcode |
// 31 24 20
return Bits(kImm12Shift + 4 , kImm12Shift);
}
inline int RvcImm6Value() const {
MOZ_ASSERT(IsShortInstruction());
// | funct3 | imm[5] | rs1/rd | imm[4:0] | opcode |
// 15 12 6 2
uint32_t Bits = InstructionBits();
int32_t imm6 = ((Bits & 0 x1000) >> 7 ) | ((Bits & 0 x7c) >> 2 );
return sext(imm6, 6 );
}
inline int RvcImm6Addi16spValue() const {
MOZ_ASSERT(IsShortInstruction());
// | funct3 | nzimm[9] | 2 | nzimm[4|6|8:7|5] | opcode |
// 15 12 6 2
uint32_t Bits = InstructionBits();
int32_t imm10 = ((Bits & 0 x1000) >> 3 ) | ((Bits & 0 x40) >> 2 ) |
((Bits & 0 x20) << 1 ) | ((Bits & 0 x18) << 4 ) |
((Bits & 0 x4) << 3 );
MOZ_ASSERT(imm10 != 0 );
return sext(imm10, 10 );
}
inline int RvcImm8Addi4spnValue() const {
MOZ_ASSERT(IsShortInstruction());
// | funct3 | nzimm[11] | rd' | opcode |
// 15 13 5 2
uint32_t Bits = InstructionBits();
int32_t uimm10 = ((Bits & 0 x20) >> 2 ) | ((Bits & 0 x40) >> 4 ) |
((Bits & 0 x780) >> 1 ) | ((Bits & 0 x1800) >> 7 );
MOZ_ASSERT(uimm10 != 0 );
return uimm10;
}
inline int RvcShamt6() const {
MOZ_ASSERT(IsShortInstruction());
// | funct3 | nzuimm[5] | rs1/rd | nzuimm[4:0] | opcode |
// 15 12 6 2
int32_t imm6 = RvcImm6Value();
return imm6 & 0 x3f;
}
inline int RvcImm6LwspValue() const {
MOZ_ASSERT(IsShortInstruction());
// | funct3 | uimm[5] | rs1 | uimm[4:2|7:6] | opcode |
// 15 12 6 2
uint32_t Bits = InstructionBits();
int32_t imm8 =
((Bits & 0 x1000) >> 7 ) | ((Bits & 0 x70) >> 2 ) | ((Bits & 0 xc) << 4 );
return imm8;
}
inline int RvcImm6LdspValue() const {
MOZ_ASSERT(IsShortInstruction());
// | funct3 | uimm[5] | rs1 | uimm[4:3|8:6] | opcode |
// 15 12 6 2
uint32_t Bits = InstructionBits();
int32_t imm9 =
((Bits & 0 x1000) >> 7 ) | ((Bits & 0 x60) >> 2 ) | ((Bits & 0 x1c) << 4 );
return imm9;
}
inline int RvcImm6SwspValue() const {
MOZ_ASSERT(IsShortInstruction());
// | funct3 | uimm[5:2|7:6] | rs2 | opcode |
// 15 12 7
uint32_t Bits = InstructionBits();
int32_t imm8 = ((Bits & 0 x1e00) >> 7 ) | ((Bits & 0 x180) >> 1 );
return imm8;
}
inline int RvcImm6SdspValue() const {
MOZ_ASSERT(IsShortInstruction());
// | funct3 | uimm[5:3|8:6] | rs2 | opcode |
// 15 12 7
uint32_t Bits = InstructionBits();
int32_t imm9 = ((Bits & 0 x1c00) >> 7 ) | ((Bits & 0 x380) >> 1 );
return imm9;
}
inline int RvcImm5WValue() const {
MOZ_ASSERT(IsShortInstruction());
// | funct3 | imm[5:3] | rs1 | imm[2|6] | rd | opcode |
// 15 12 10 6 4 2
uint32_t Bits = InstructionBits();
int32_t imm7 =
((Bits & 0 x1c00) >> 7 ) | ((Bits & 0 x40) >> 4 ) | ((Bits & 0 x20) << 1 );
return imm7;
}
inline int RvcImm5DValue() const {
MOZ_ASSERT(IsShortInstruction());
// | funct3 | imm[5:3] | rs1 | imm[7:6] | rd | opcode |
// 15 12 10 6 4 2
uint32_t Bits = InstructionBits();
int32_t imm8 = ((Bits & 0 x1c00) >> 7 ) | ((Bits & 0 x60) << 1 );
return imm8;
}
inline int RvcImm11CJValue() const {
MOZ_ASSERT(IsShortInstruction());
// | funct3 | [11|4|9:8|10|6|7|3:1|5] | opcode |
// 15 12 2
uint32_t Bits = InstructionBits();
int32_t imm12 = ((Bits & 0 x4) << 3 ) | ((Bits & 0 x38) >> 2 ) |
((Bits & 0 x40) << 1 ) | ((Bits & 0 x80) >> 1 ) |
((Bits & 0 x100) << 2 ) | ((Bits & 0 x600) >> 1 ) |
((Bits & 0 x800) >> 7 ) | ((Bits & 0 x1000) >> 1 );
return sext(imm12, 12 );
}
inline int RvcImm8BValue() const {
MOZ_ASSERT(IsShortInstruction());
// | funct3 | imm[8|4:3] | rs1` | imm[7:6|2:1|5] | opcode |
// 15 12 10 7 2
uint32_t Bits = InstructionBits();
int32_t imm9 = ((Bits & 0 x4) << 3 ) | ((Bits & 0 x18) >> 2 ) |
((Bits & 0 x60) << 1 ) | ((Bits & 0 xc00) >> 7 ) |
((Bits & 0 x1000) >> 4 );
return sext(imm9, 9 );
}
inline int vl_vs_width() {
int width = 0 ;
if ((InstructionBits() & kBaseOpcodeMask) != LOAD_FP &&
(InstructionBits() & kBaseOpcodeMask) != STORE_FP) {
return -1 ;
}
switch (InstructionBits() & (kRvvWidthMask | kRvvMewMask)) {
case 0 x0:
width = 8 ;
break ;
case 0 x00005000:
width = 16 ;
break ;
case 0 x00006000:
width = 32 ;
break ;
case 0 x00007000:
width = 64 ;
break ;
case 0 x10000000:
width = 128 ;
break ;
case 0 x10005000:
width = 256 ;
break ;
case 0 x10006000:
width = 512 ;
break ;
case 0 x10007000:
width = 1024 ;
break ;
default :
width = -1 ;
break ;
}
return width;
}
inline uint32_t Rvvzimm() const {
if ((InstructionBits() & (kBaseOpcodeMask | kFunct3Mask | 0 x80000000)) ==
RO_V_VSETVLI) {
uint32_t Bits = InstructionBits();
uint32_t zimm = Bits & kRvvZimmMask;
return zimm >> kRvvZimmShift;
} else {
MOZ_ASSERT((InstructionBits() & (kBaseOpcodeMask | kFunct3Mask |
0 xC0000000)) == RO_V_VSETIVLI);
uint32_t Bits = InstructionBits();
uint32_t zimm = Bits & kRvvZimmMask;
return (zimm >> kRvvZimmShift) & 0 x3FF;
}
}
inline uint32_t Rvvuimm() const {
MOZ_ASSERT((InstructionBits() &
(kBaseOpcodeMask | kFunct3Mask | 0 xC0000000)) == RO_V_VSETIVLI);
uint32_t Bits = InstructionBits();
uint32_t uimm = Bits & kRvvUimmMask;
return uimm >> kRvvUimmShift;
}
inline uint32_t RvvVsew() const {
uint32_t zimm = Rvvzimm();
uint32_t vsew = (zimm >> 3 ) & 0 x7;
return vsew;
}
inline uint32_t RvvVlmul() const {
uint32_t zimm = Rvvzimm();
uint32_t vlmul = zimm & 0 x7;
return vlmul;
}
inline uint8_t RvvVM() const {
MOZ_ASSERT(InstructionType() == InstructionBase::kVType ||
InstructionType() == InstructionBase::kIType ||
InstructionType() == InstructionBase::kSType);
return Bits(kRvvVmShift + kRvvVmBits - 1 , kRvvVmShift);
}
inline const char * RvvSEW() const {
uint32_t vsew = RvvVsew();
switch (vsew) {
#define CAST_VSEW(name) \
case name: \
return #name ;
RVV_SEW(CAST_VSEW)
default :
return "unknown" ;
#undef CAST_VSEW
}
}
inline const char * RvvLMUL() const {
uint32_t vlmul = RvvVlmul();
switch (vlmul) {
#define CAST_VLMUL(name) \
case name: \
return #name ;
RVV_LMUL(CAST_VLMUL)
default :
return "unknown" ;
#undef CAST_VLMUL
}
}
inline int32_t RvvSimm5() const {
MOZ_ASSERT(InstructionType() == InstructionBase::kVType);
return sext(Bits(kRvvImm5Shift + kRvvImm5Bits - 1 , kRvvImm5Shift),
kRvvImm5Bits);
}
inline uint32_t RvvUimm5() const {
MOZ_ASSERT(InstructionType() == InstructionBase::kVType);
uint32_t imm = Bits(kRvvImm5Shift + kRvvImm5Bits - 1 , kRvvImm5Shift);
return zext(imm, kRvvImm5Bits);
}
inline bool AqValue() const { return Bits(kAqShift, kAqShift); }
inline bool RlValue() const { return Bits(kRlShift, kRlShift); }
/// Setters
inline void SetRdValue(int rd) {
MOZ_ASSERT(InstructionType() == InstructionBase::kRType ||
InstructionType() == InstructionBase::kR4Type ||
InstructionType() == InstructionBase::kIType ||
InstructionType() == InstructionBase::kSType ||
InstructionType() == InstructionBase::kUType ||
InstructionType() == InstructionBase::kJType ||
InstructionType() == InstructionBase::kVType);
MOZ_ASSERT(is_uintn(rd, kRdBits));
Instr bits = InstructionBits() & ~kRdFieldMask;
SetInstructionBits((rd << kRdShift) | bits);
}
inline void SetRs1Value(int rs1) {
MOZ_ASSERT(InstructionType() == InstructionBase::kRType ||
InstructionType() == InstructionBase::kR4Type ||
InstructionType() == InstructionBase::kIType ||
InstructionType() == InstructionBase::kSType ||
InstructionType() == InstructionBase::kBType ||
InstructionType() == InstructionBase::kVType);
MOZ_ASSERT(is_uintn(rs1, kRs1Bits));
Instr bits = InstructionBits() & ~kRs1FieldMask;
SetInstructionBits((rs1 << kRs1Shift) | bits);
}
inline void SetImm12Value(int32_t imm12) {
MOZ_ASSERT(InstructionType() == InstructionBase::kIType);
MOZ_ASSERT(is_uint12(imm12) || is_int12(imm12));
// | imm[11:0] | rs1 | funct3 | rd | opcode |
// 31 20
Instr bits = InstructionBits() & ~kImm12Mask;
SetInstructionBits((imm12 << kImm12Shift) | bits);
}
inline void SetBranchOffset(int32_t imm13) {
MOZ_ASSERT(InstructionType() == InstructionBase::kBType);
MOZ_ASSERT((imm13 & 1 ) == 0 );
MOZ_ASSERT(is_intn(imm13, kBranchOffsetBits));
// | imm[12|10:5] | rs2 | rs1 | funct3 | imm[4:1|11] | opcode |
// 31 25 11 7
Instr bits = InstructionBits() & ~kBImm12Mask;
int32_t imm12 = ((imm13 & 0 x800) >> 4 ) | // bit 11
((imm13 & 0 x1e) << 7 ) | // bits 4-1
((imm13 & 0 x7e0) << 20 ) | // bits 10-5
((imm13 & 0 x1000) << 19 ); // bit 12
SetInstructionBits((imm12 & kBImm12Mask) | bits);
}
inline void SetImm20UValue(int32_t imm20) {
MOZ_ASSERT(InstructionType() == InstructionBase::kUType);
MOZ_ASSERT(is_int20(imm20) || is_uint20(imm20));
// | imm[31:12] | rd | opcode |
// 31 12
Instr bits = InstructionBits() & ~kImm20Mask;
SetInstructionBits((imm20 << kImm20Shift) | bits);
}
inline void SetImm20JValue(int32_t imm21) {
MOZ_ASSERT(InstructionType() == InstructionBase::kJType);
MOZ_ASSERT((imm21 & 1 ) == 0 );
MOZ_ASSERT(is_intn(imm21, kJumpOffsetBits));
// | imm[20|10:1|11|19:12] | rd | opcode |
// 31 12
Instr bits = InstructionBits() & ~kImm20Mask;
int32_t imm20 = (imm21 & 0 xff000) | // bits 19-12
((imm21 & 0 x800) << 9 ) | // bit 11
((imm21 & 0 x7fe) << 20 ) | // bits 10-1
((imm21 & 0 x100000) << 11 ); // bit 20
SetInstructionBits((imm20 & kImm20Mask) | bits);
}
inline void SetShamt(int32_t shamt) {
// Valid only for shift instructions (SLLI, SRLI, SRAI)
MOZ_ASSERT(((InstructionBits() & kBaseOpcodeMask) == OP_IMM ||
(InstructionBits() & kBaseOpcodeMask) == OP_IMM_32) &&
(Funct3Value() == 0 b001 || Funct3Value() == 0 b101));
MOZ_ASSERT_IF((InstructionBits() & kBaseOpcodeMask) == OP_IMM,
0 <= shamt && shamt <= 63 );
MOZ_ASSERT_IF((InstructionBits() & kBaseOpcodeMask) == OP_IMM_32,
0 <= shamt && shamt <= 31 );
// SLLI, SRLI, SRAI:
// | 0A0000 | shamt | rs1 | funct3 | rd | opcode |
// 31 25 20
//
// SLLIW, SRLIW, SRAIW:
// | 0A00000 | shamt | rs1 | funct3 | rd | opcode |
// 31 24 20
int32_t imm12 = ((InstructionBits() & 0 x40000000) >> kImm12Shift) | shamt;
SetImm12Value(imm12);
}
/// Compound setters
void SetIFormat(OpcodeRISCV32I opcode, int rd, int rs1, int32_t imm12) {
SetInstructionBits(opcode);
MOZ_ASSERT(InstructionType() == kIType);
SetRdValue(rd);
SetRs1Value(rs1);
SetImm12Value(imm12);
}
void SetJFormat(OpcodeRISCV32I opcode, int rd, int32_t imm21) {
SetInstructionBits(opcode);
MOZ_ASSERT(InstructionType() == kJType);
SetRdValue(rd);
SetImm20JValue(imm21);
}
void SetUFormat(OpcodeRISCV32I opcode, int rd, int32_t imm20) {
SetInstructionBits(opcode);
MOZ_ASSERT(InstructionType() == kUType);
SetRdValue(rd);
SetImm20UValue(imm20);
}
void SetNop() { SetInstructionBits(kNopByte); }
protected :
InstructionBase() {}
};
class Instruction : public InstructionBase {
public:
// Instructions are read of out a code stream. The only way to get a
// reference to an instruction is to convert a pointer. There is no way
// to allocate or create instances of class Instruction.
// Use the At(pc) function to create references to Instruction.
static Instruction* At(uint8_t* pc) {
return reinterpret_cast<Instruction*>(pc);
}
static const Instruction* At(const uint8_t* pc) {
return reinterpret_cast<const Instruction*>(pc);
}
// We need to prevent the creation of instances of class Instruction.
Instruction() = delete ;
Instruction(const Instruction&) = delete ;
Instruction& operator =(const Instruction&) = delete ;
};
} // namespace js::jit
#endif // jit_riscv64_base_Instruction_h
Messung V0.5 in Prozent C=87 H=100 G=93
¤ Dauer der Verarbeitung: 0.16 Sekunden
(vorverarbeitet am 2026-08-25)
¤
*© Formatika GbR, Deutschland