// The `Riscv64Extension` enumeration is used for restricting the instructions that the assembler // can use. Some restrictions are checked only in debug mode (for example load and store // instructions check `kLoadStore`), other restrictions are checked at run time and affect the // emitted code (for example, the `SextW()` pseudo-instruction selects between an implementation // from "Zcb", "Zbb" and a two-instruction sequence from the basic instruction set. enumclass Riscv64Extension : uint32_t {
kLoadStore, // Pseudo-extension encompassing all loads and stores. Used to check that // we do not have loads and stores in the middle of a LR/SC sequence.
kZifencei,
kM,
kA,
kZicsr,
kF,
kD,
kZba,
kZbb,
kZbs,
kV,
kZca, // "C" extension instructions except floating point loads/stores.
kZcd, // "C" extension double loads/stores. // Note: RV64 cannot implement Zcf ("C" extension float loads/stores).
kZcb, // Simple 16-bit operations not present in the original "C" extension.
// Extensions allowed in a LR/SC sequence (between the LR and SC).
constexpr Riscv64ExtensionMask kRiscv64LrScSequenceExtensionsMask =
Riscv64ExtensionBit(Riscv64Extension::kZca);
enumclass FPRoundingMode : uint32_t {
kRNE = 0x0, // Round to Nearest, ties to Even
kRTZ = 0x1, // Round towards Zero
kRDN = 0x2, // Round Down (towards −Infinity)
kRUP = 0x3, // Round Up (towards +Infinity)
kRMM = 0x4, // Round to Nearest, ties to Max Magnitude
kDYN = 0x7, // Dynamic rounding mode
kDefault = kDYN, // Some instructions never need to round even though the spec includes the RM field. // To simplify testing, emit the RM as 0 by default for these instructions because that's what // `clang` does and because the `llvm-objdump` fails to disassemble the other rounding modes.
kIgnored = 0
};
// Jump table: table of labels emitted after the code and before the literals. Similar to literals. class JumpTable { public: explicit JumpTable(ArenaVector<Riscv64Label*>&& labels) : label_(), labels_(std::move(labels)) {}
// According to "The RISC-V Instruction Set Manual"
// LUI/AUIPC (RV32I, with sign-extension on RV64I), opcode = 0x17, 0x37 // Note: These take a 20-bit unsigned value to align with the clang assembler for testing, // but the value stored in the register shall actually be sign-extended to 64 bits. void Lui(XRegister rd, uint32_t imm20); void Auipc(XRegister rd, uint32_t imm20);
// Vector Strided Load/Store Instructions void VLse8(VRegister vd, XRegister rs1, XRegister rs2, VM vm = VM::kUnmasked); void VLse16(VRegister vd, XRegister rs1, XRegister rs2, VM vm = VM::kUnmasked); void VLse32(VRegister vd, XRegister rs1, XRegister rs2, VM vm = VM::kUnmasked); void VLse64(VRegister vd, XRegister rs1, XRegister rs2, VM vm = VM::kUnmasked);
void VSse8(VRegister vs3, XRegister rs1, XRegister rs2, VM vm = VM::kUnmasked); void VSse16(VRegister vs3, XRegister rs1, XRegister rs2, VM vm = VM::kUnmasked); void VSse32(VRegister vs3, XRegister rs1, XRegister rs2, VM vm = VM::kUnmasked); void VSse64(VRegister vs3, XRegister rs1, XRegister rs2, VM vm = VM::kUnmasked);
// Vector Indexed Load/Store Instructions void VLoxei8(VRegister vd, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VLoxei16(VRegister vd, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VLoxei32(VRegister vd, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VLoxei64(VRegister vd, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked);
void VLuxei8(VRegister vd, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VLuxei16(VRegister vd, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VLuxei32(VRegister vd, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VLuxei64(VRegister vd, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked);
void VSoxei8(VRegister vs3, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VSoxei16(VRegister vs3, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VSoxei32(VRegister vs3, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VSoxei64(VRegister vs3, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked);
void VSuxei8(VRegister vs3, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VSuxei16(VRegister vs3, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VSuxei32(VRegister vs3, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VSuxei64(VRegister vs3, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked);
// Vector Segment Load/Store
// Vector Unit-Stride Segment Loads/Stores
void VLseg2e8(VRegister vd, XRegister rs1, VM vm = VM::kUnmasked); void VLseg2e16(VRegister vd, XRegister rs1, VM vm = VM::kUnmasked); void VLseg2e32(VRegister vd, XRegister rs1, VM vm = VM::kUnmasked); void VLseg2e64(VRegister vd, XRegister rs1, VM vm = VM::kUnmasked); void VLseg3e8(VRegister vd, XRegister rs1, VM vm = VM::kUnmasked); void VLseg3e16(VRegister vd, XRegister rs1, VM vm = VM::kUnmasked); void VLseg3e32(VRegister vd, XRegister rs1, VM vm = VM::kUnmasked); void VLseg3e64(VRegister vd, XRegister rs1, VM vm = VM::kUnmasked); void VLseg4e8(VRegister vd, XRegister rs1, VM vm = VM::kUnmasked); void VLseg4e16(VRegister vd, XRegister rs1, VM vm = VM::kUnmasked); void VLseg4e32(VRegister vd, XRegister rs1, VM vm = VM::kUnmasked); void VLseg4e64(VRegister vd, XRegister rs1, VM vm = VM::kUnmasked); void VLseg5e8(VRegister vd, XRegister rs1, VM vm = VM::kUnmasked); void VLseg5e16(VRegister vd, XRegister rs1, VM vm = VM::kUnmasked); void VLseg5e32(VRegister vd, XRegister rs1, VM vm = VM::kUnmasked); void VLseg5e64(VRegister vd, XRegister rs1, VM vm = VM::kUnmasked); void VLseg6e8(VRegister vd, XRegister rs1, VM vm = VM::kUnmasked); void VLseg6e16(VRegister vd, XRegister rs1, VM vm = VM::kUnmasked); void VLseg6e32(VRegister vd, XRegister rs1, VM vm = VM::kUnmasked); void VLseg6e64(VRegister vd, XRegister rs1, VM vm = VM::kUnmasked); void VLseg7e8(VRegister vd, XRegister rs1, VM vm = VM::kUnmasked); void VLseg7e16(VRegister vd, XRegister rs1, VM vm = VM::kUnmasked); void VLseg7e32(VRegister vd, XRegister rs1, VM vm = VM::kUnmasked); void VLseg7e64(VRegister vd, XRegister rs1, VM vm = VM::kUnmasked); void VLseg8e8(VRegister vd, XRegister rs1, VM vm = VM::kUnmasked); void VLseg8e16(VRegister vd, XRegister rs1, VM vm = VM::kUnmasked); void VLseg8e32(VRegister vd, XRegister rs1, VM vm = VM::kUnmasked); void VLseg8e64(VRegister vd, XRegister rs1, VM vm = VM::kUnmasked);
void VSseg2e8(VRegister vs3, XRegister rs1, VM vm = VM::kUnmasked); void VSseg2e16(VRegister vs3, XRegister rs1, VM vm = VM::kUnmasked); void VSseg2e32(VRegister vs3, XRegister rs1, VM vm = VM::kUnmasked); void VSseg2e64(VRegister vs3, XRegister rs1, VM vm = VM::kUnmasked); void VSseg3e8(VRegister vs3, XRegister rs1, VM vm = VM::kUnmasked); void VSseg3e16(VRegister vs3, XRegister rs1, VM vm = VM::kUnmasked); void VSseg3e32(VRegister vs3, XRegister rs1, VM vm = VM::kUnmasked); void VSseg3e64(VRegister vs3, XRegister rs1, VM vm = VM::kUnmasked); void VSseg4e8(VRegister vs3, XRegister rs1, VM vm = VM::kUnmasked); void VSseg4e16(VRegister vs3, XRegister rs1, VM vm = VM::kUnmasked); void VSseg4e32(VRegister vs3, XRegister rs1, VM vm = VM::kUnmasked); void VSseg4e64(VRegister vs3, XRegister rs1, VM vm = VM::kUnmasked); void VSseg5e8(VRegister vs3, XRegister rs1, VM vm = VM::kUnmasked); void VSseg5e16(VRegister vs3, XRegister rs1, VM vm = VM::kUnmasked); void VSseg5e32(VRegister vs3, XRegister rs1, VM vm = VM::kUnmasked); void VSseg5e64(VRegister vs3, XRegister rs1, VM vm = VM::kUnmasked); void VSseg6e8(VRegister vs3, XRegister rs1, VM vm = VM::kUnmasked); void VSseg6e16(VRegister vs3, XRegister rs1, VM vm = VM::kUnmasked); void VSseg6e32(VRegister vs3, XRegister rs1, VM vm = VM::kUnmasked); void VSseg6e64(VRegister vs3, XRegister rs1, VM vm = VM::kUnmasked); void VSseg7e8(VRegister vs3, XRegister rs1, VM vm = VM::kUnmasked); void VSseg7e16(VRegister vs3, XRegister rs1, VM vm = VM::kUnmasked); void VSseg7e32(VRegister vs3, XRegister rs1, VM vm = VM::kUnmasked); void VSseg7e64(VRegister vs3, XRegister rs1, VM vm = VM::kUnmasked); void VSseg8e8(VRegister vs3, XRegister rs1, VM vm = VM::kUnmasked); void VSseg8e16(VRegister vs3, XRegister rs1, VM vm = VM::kUnmasked); void VSseg8e32(VRegister vs3, XRegister rs1, VM vm = VM::kUnmasked); void VSseg8e64(VRegister vs3, XRegister rs1, VM vm = VM::kUnmasked);
void VLseg2e8ff(VRegister vd, XRegister rs1, VM vm = VM::kUnmasked); void VLseg2e16ff(VRegister vd, XRegister rs1, VM vm = VM::kUnmasked); void VLseg2e32ff(VRegister vd, XRegister rs1, VM vm = VM::kUnmasked); void VLseg2e64ff(VRegister vd, XRegister rs1, VM vm = VM::kUnmasked); void VLseg3e8ff(VRegister vd, XRegister rs1, VM vm = VM::kUnmasked); void VLseg3e16ff(VRegister vd, XRegister rs1, VM vm = VM::kUnmasked); void VLseg3e32ff(VRegister vd, XRegister rs1, VM vm = VM::kUnmasked); void VLseg3e64ff(VRegister vd, XRegister rs1, VM vm = VM::kUnmasked); void VLseg4e8ff(VRegister vd, XRegister rs1, VM vm = VM::kUnmasked); void VLseg4e16ff(VRegister vd, XRegister rs1, VM vm = VM::kUnmasked); void VLseg4e32ff(VRegister vd, XRegister rs1, VM vm = VM::kUnmasked); void VLseg4e64ff(VRegister vd, XRegister rs1, VM vm = VM::kUnmasked); void VLseg5e8ff(VRegister vd, XRegister rs1, VM vm = VM::kUnmasked); void VLseg5e16ff(VRegister vd, XRegister rs1, VM vm = VM::kUnmasked); void VLseg5e32ff(VRegister vd, XRegister rs1, VM vm = VM::kUnmasked); void VLseg5e64ff(VRegister vd, XRegister rs1, VM vm = VM::kUnmasked); void VLseg6e8ff(VRegister vd, XRegister rs1, VM vm = VM::kUnmasked); void VLseg6e16ff(VRegister vd, XRegister rs1, VM vm = VM::kUnmasked); void VLseg6e32ff(VRegister vd, XRegister rs1, VM vm = VM::kUnmasked); void VLseg6e64ff(VRegister vd, XRegister rs1, VM vm = VM::kUnmasked); void VLseg7e8ff(VRegister vd, XRegister rs1, VM vm = VM::kUnmasked); void VLseg7e16ff(VRegister vd, XRegister rs1, VM vm = VM::kUnmasked); void VLseg7e32ff(VRegister vd, XRegister rs1, VM vm = VM::kUnmasked); void VLseg7e64ff(VRegister vd, XRegister rs1, VM vm = VM::kUnmasked); void VLseg8e8ff(VRegister vd, XRegister rs1, VM vm = VM::kUnmasked); void VLseg8e16ff(VRegister vd, XRegister rs1, VM vm = VM::kUnmasked); void VLseg8e32ff(VRegister vd, XRegister rs1, VM vm = VM::kUnmasked); void VLseg8e64ff(VRegister vd, XRegister rs1, VM vm = VM::kUnmasked);
// Vector Strided Segment Loads/Stores
void VLsseg2e8(VRegister vd, XRegister rs1, XRegister rs2, VM vm = VM::kUnmasked); void VLsseg2e16(VRegister vd, XRegister rs1, XRegister rs2, VM vm = VM::kUnmasked); void VLsseg2e32(VRegister vd, XRegister rs1, XRegister rs2, VM vm = VM::kUnmasked); void VLsseg2e64(VRegister vd, XRegister rs1, XRegister rs2, VM vm = VM::kUnmasked); void VLsseg3e8(VRegister vd, XRegister rs1, XRegister rs2, VM vm = VM::kUnmasked); void VLsseg3e16(VRegister vd, XRegister rs1, XRegister rs2, VM vm = VM::kUnmasked); void VLsseg3e32(VRegister vd, XRegister rs1, XRegister rs2, VM vm = VM::kUnmasked); void VLsseg3e64(VRegister vd, XRegister rs1, XRegister rs2, VM vm = VM::kUnmasked); void VLsseg4e8(VRegister vd, XRegister rs1, XRegister rs2, VM vm = VM::kUnmasked); void VLsseg4e16(VRegister vd, XRegister rs1, XRegister rs2, VM vm = VM::kUnmasked); void VLsseg4e32(VRegister vd, XRegister rs1, XRegister rs2, VM vm = VM::kUnmasked); void VLsseg4e64(VRegister vd, XRegister rs1, XRegister rs2, VM vm = VM::kUnmasked); void VLsseg5e8(VRegister vd, XRegister rs1, XRegister rs2, VM vm = VM::kUnmasked); void VLsseg5e16(VRegister vd, XRegister rs1, XRegister rs2, VM vm = VM::kUnmasked); void VLsseg5e32(VRegister vd, XRegister rs1, XRegister rs2, VM vm = VM::kUnmasked); void VLsseg5e64(VRegister vd, XRegister rs1, XRegister rs2, VM vm = VM::kUnmasked); void VLsseg6e8(VRegister vd, XRegister rs1, XRegister rs2, VM vm = VM::kUnmasked); void VLsseg6e16(VRegister vd, XRegister rs1, XRegister rs2, VM vm = VM::kUnmasked); void VLsseg6e32(VRegister vd, XRegister rs1, XRegister rs2, VM vm = VM::kUnmasked); void VLsseg6e64(VRegister vd, XRegister rs1, XRegister rs2, VM vm = VM::kUnmasked); void VLsseg7e8(VRegister vd, XRegister rs1, XRegister rs2, VM vm = VM::kUnmasked); void VLsseg7e16(VRegister vd, XRegister rs1, XRegister rs2, VM vm = VM::kUnmasked); void VLsseg7e32(VRegister vd, XRegister rs1, XRegister rs2, VM vm = VM::kUnmasked); void VLsseg7e64(VRegister vd, XRegister rs1, XRegister rs2, VM vm = VM::kUnmasked); void VLsseg8e8(VRegister vd, XRegister rs1, XRegister rs2, VM vm = VM::kUnmasked); void VLsseg8e16(VRegister vd, XRegister rs1, XRegister rs2, VM vm = VM::kUnmasked); void VLsseg8e32(VRegister vd, XRegister rs1, XRegister rs2, VM vm = VM::kUnmasked); void VLsseg8e64(VRegister vd, XRegister rs1, XRegister rs2, VM vm = VM::kUnmasked);
void VSsseg2e8(VRegister vs3, XRegister rs1, XRegister rs2, VM vm = VM::kUnmasked); void VSsseg2e16(VRegister vs3, XRegister rs1, XRegister rs2, VM vm = VM::kUnmasked); void VSsseg2e32(VRegister vs3, XRegister rs1, XRegister rs2, VM vm = VM::kUnmasked); void VSsseg2e64(VRegister vs3, XRegister rs1, XRegister rs2, VM vm = VM::kUnmasked); void VSsseg3e8(VRegister vs3, XRegister rs1, XRegister rs2, VM vm = VM::kUnmasked); void VSsseg3e16(VRegister vs3, XRegister rs1, XRegister rs2, VM vm = VM::kUnmasked); void VSsseg3e32(VRegister vs3, XRegister rs1, XRegister rs2, VM vm = VM::kUnmasked); void VSsseg3e64(VRegister vs3, XRegister rs1, XRegister rs2, VM vm = VM::kUnmasked); void VSsseg4e8(VRegister vs3, XRegister rs1, XRegister rs2, VM vm = VM::kUnmasked); void VSsseg4e16(VRegister vs3, XRegister rs1, XRegister rs2, VM vm = VM::kUnmasked); void VSsseg4e32(VRegister vs3, XRegister rs1, XRegister rs2, VM vm = VM::kUnmasked); void VSsseg4e64(VRegister vs3, XRegister rs1, XRegister rs2, VM vm = VM::kUnmasked); void VSsseg5e8(VRegister vs3, XRegister rs1, XRegister rs2, VM vm = VM::kUnmasked); void VSsseg5e16(VRegister vs3, XRegister rs1, XRegister rs2, VM vm = VM::kUnmasked); void VSsseg5e32(VRegister vs3, XRegister rs1, XRegister rs2, VM vm = VM::kUnmasked); void VSsseg5e64(VRegister vs3, XRegister rs1, XRegister rs2, VM vm = VM::kUnmasked); void VSsseg6e8(VRegister vs3, XRegister rs1, XRegister rs2, VM vm = VM::kUnmasked); void VSsseg6e16(VRegister vs3, XRegister rs1, XRegister rs2, VM vm = VM::kUnmasked); void VSsseg6e32(VRegister vs3, XRegister rs1, XRegister rs2, VM vm = VM::kUnmasked); void VSsseg6e64(VRegister vs3, XRegister rs1, XRegister rs2, VM vm = VM::kUnmasked); void VSsseg7e8(VRegister vs3, XRegister rs1, XRegister rs2, VM vm = VM::kUnmasked); void VSsseg7e16(VRegister vs3, XRegister rs1, XRegister rs2, VM vm = VM::kUnmasked); void VSsseg7e32(VRegister vs3, XRegister rs1, XRegister rs2, VM vm = VM::kUnmasked); void VSsseg7e64(VRegister vs3, XRegister rs1, XRegister rs2, VM vm = VM::kUnmasked); void VSsseg8e8(VRegister vs3, XRegister rs1, XRegister rs2, VM vm = VM::kUnmasked); void VSsseg8e16(VRegister vs3, XRegister rs1, XRegister rs2, VM vm = VM::kUnmasked); void VSsseg8e32(VRegister vs3, XRegister rs1, XRegister rs2, VM vm = VM::kUnmasked); void VSsseg8e64(VRegister vs3, XRegister rs1, XRegister rs2, VM vm = VM::kUnmasked);
// Vector Indexed-unordered Segment Loads/Stores
void VLuxseg2ei8(VRegister vd, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VLuxseg2ei16(VRegister vd, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VLuxseg2ei32(VRegister vd, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VLuxseg2ei64(VRegister vd, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VLuxseg3ei8(VRegister vd, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VLuxseg3ei16(VRegister vd, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VLuxseg3ei32(VRegister vd, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VLuxseg3ei64(VRegister vd, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VLuxseg4ei8(VRegister vd, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VLuxseg4ei16(VRegister vd, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VLuxseg4ei32(VRegister vd, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VLuxseg4ei64(VRegister vd, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VLuxseg5ei8(VRegister vd, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VLuxseg5ei16(VRegister vd, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VLuxseg5ei32(VRegister vd, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VLuxseg5ei64(VRegister vd, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VLuxseg6ei8(VRegister vd, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VLuxseg6ei16(VRegister vd, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VLuxseg6ei32(VRegister vd, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VLuxseg6ei64(VRegister vd, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VLuxseg7ei8(VRegister vd, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VLuxseg7ei16(VRegister vd, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VLuxseg7ei32(VRegister vd, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VLuxseg7ei64(VRegister vd, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VLuxseg8ei8(VRegister vd, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VLuxseg8ei16(VRegister vd, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VLuxseg8ei32(VRegister vd, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VLuxseg8ei64(VRegister vd, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked);
void VSuxseg2ei8(VRegister vs3, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VSuxseg2ei16(VRegister vs3, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VSuxseg2ei32(VRegister vs3, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VSuxseg2ei64(VRegister vs3, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VSuxseg3ei8(VRegister vs3, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VSuxseg3ei16(VRegister vs3, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VSuxseg3ei32(VRegister vs3, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VSuxseg3ei64(VRegister vs3, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VSuxseg4ei8(VRegister vs3, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VSuxseg4ei16(VRegister vs3, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VSuxseg4ei32(VRegister vs3, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VSuxseg4ei64(VRegister vs3, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VSuxseg5ei8(VRegister vs3, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VSuxseg5ei16(VRegister vs3, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VSuxseg5ei32(VRegister vs3, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VSuxseg5ei64(VRegister vs3, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VSuxseg6ei8(VRegister vs3, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VSuxseg6ei16(VRegister vs3, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VSuxseg6ei32(VRegister vs3, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VSuxseg6ei64(VRegister vs3, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VSuxseg7ei8(VRegister vs3, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VSuxseg7ei16(VRegister vs3, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VSuxseg7ei32(VRegister vs3, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VSuxseg7ei64(VRegister vs3, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VSuxseg8ei8(VRegister vs3, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VSuxseg8ei16(VRegister vs3, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VSuxseg8ei32(VRegister vs3, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VSuxseg8ei64(VRegister vs3, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked);
// Vector Indexed-ordered Segment Loads/Stores
void VLoxseg2ei8(VRegister vd, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VLoxseg2ei16(VRegister vd, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VLoxseg2ei32(VRegister vd, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VLoxseg2ei64(VRegister vd, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VLoxseg3ei8(VRegister vd, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VLoxseg3ei16(VRegister vd, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VLoxseg3ei32(VRegister vd, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VLoxseg3ei64(VRegister vd, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VLoxseg4ei8(VRegister vd, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VLoxseg4ei16(VRegister vd, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VLoxseg4ei32(VRegister vd, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VLoxseg4ei64(VRegister vd, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VLoxseg5ei8(VRegister vd, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VLoxseg5ei16(VRegister vd, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VLoxseg5ei32(VRegister vd, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VLoxseg5ei64(VRegister vd, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VLoxseg6ei8(VRegister vd, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VLoxseg6ei16(VRegister vd, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VLoxseg6ei32(VRegister vd, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VLoxseg6ei64(VRegister vd, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VLoxseg7ei8(VRegister vd, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VLoxseg7ei16(VRegister vd, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VLoxseg7ei32(VRegister vd, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VLoxseg7ei64(VRegister vd, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VLoxseg8ei8(VRegister vd, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VLoxseg8ei16(VRegister vd, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VLoxseg8ei32(VRegister vd, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VLoxseg8ei64(VRegister vd, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked);
void VSoxseg2ei8(VRegister vs3, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VSoxseg2ei16(VRegister vs3, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VSoxseg2ei32(VRegister vs3, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VSoxseg2ei64(VRegister vs3, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VSoxseg3ei8(VRegister vs3, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VSoxseg3ei16(VRegister vs3, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VSoxseg3ei32(VRegister vs3, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VSoxseg3ei64(VRegister vs3, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VSoxseg4ei8(VRegister vs3, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VSoxseg4ei16(VRegister vs3, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VSoxseg4ei32(VRegister vs3, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VSoxseg4ei64(VRegister vs3, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VSoxseg5ei8(VRegister vs3, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VSoxseg5ei16(VRegister vs3, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VSoxseg5ei32(VRegister vs3, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VSoxseg5ei64(VRegister vs3, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VSoxseg6ei8(VRegister vs3, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VSoxseg6ei16(VRegister vs3, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VSoxseg6ei32(VRegister vs3, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VSoxseg6ei64(VRegister vs3, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VSoxseg7ei8(VRegister vs3, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VSoxseg7ei16(VRegister vs3, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VSoxseg7ei32(VRegister vs3, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VSoxseg7ei64(VRegister vs3, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VSoxseg8ei8(VRegister vs3, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VSoxseg8ei16(VRegister vs3, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VSoxseg8ei32(VRegister vs3, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked); void VSoxseg8ei64(VRegister vs3, XRegister rs1, VRegister vs2, VM vm = VM::kUnmasked);
void VL1r(VRegister vd, XRegister rs1); // Pseudoinstruction equal to VL1re8 void VL2r(VRegister vd, XRegister rs1); // Pseudoinstruction equal to VL2re8 void VL4r(VRegister vd, XRegister rs1); // Pseudoinstruction equal to VL4re8 void VL8r(VRegister vd, XRegister rs1); // Pseudoinstruction equal to VL8re8
void VS1r(VRegister vs3, XRegister rs1); // Store {vs3} to address in a1 void VS2r(VRegister vs3, XRegister rs1); // Store {vs3}-{vs3 + 1} to address in a1 void VS4r(VRegister vs3, XRegister rs1); // Store {vs3}-{vs3 + 3} to address in a1 void VS8r(VRegister vs3, XRegister rs1); // Store {vs3}-{vs3 + 7} to address in a1
// Vector Arithmetic Instruction
// Vector vadd instructions, funct6 = 0b000000 void VAdd_vv(VRegister vd, VRegister vs2, VRegister vs1, VM vm = VM::kUnmasked); void VAdd_vx(VRegister vd, VRegister vs2, XRegister rs1, VM vm = VM::kUnmasked); void VAdd_vi(VRegister vd, VRegister vs2, int32_t imm5, VM vm = VM::kUnmasked);
// Vector vsub instructions, funct6 = 0b000010 void VSub_vv(VRegister vd, VRegister vs2, VRegister vs1, VM vm = VM::kUnmasked); void VSub_vx(VRegister vd, VRegister vs2, XRegister rs1, VM vm = VM::kUnmasked);
// Vector vrsub instructions, funct6 = 0b000011 void VRsub_vx(VRegister vd, VRegister vs2, XRegister rs1, VM vm = VM::kUnmasked); void VRsub_vi(VRegister vd, VRegister vs2, int32_t imm5, VM vm = VM::kUnmasked);
// Pseudo-instruction over VRsub_vi void VNeg_v(VRegister vd, VRegister vs2);
// Vector vminu instructions, funct6 = 0b000100 void VMinu_vv(VRegister vd, VRegister vs2, VRegister vs1, VM vm = VM::kUnmasked); void VMinu_vx(VRegister vd, VRegister vs2, XRegister rs1, VM vm = VM::kUnmasked);
// Vector vmin instructions, funct6 = 0b000101 void VMin_vv(VRegister vd, VRegister vs2, VRegister vs1, VM vm = VM::kUnmasked); void VMin_vx(VRegister vd, VRegister vs2, XRegister rs1, VM vm = VM::kUnmasked);
// Vector vmaxu instructions, funct6 = 0b000110 void VMaxu_vv(VRegister vd, VRegister vs2, VRegister vs1, VM vm = VM::kUnmasked); void VMaxu_vx(VRegister vd, VRegister vs2, XRegister rs1, VM vm = VM::kUnmasked);
// Vector vmax instructions, funct6 = 0b000111 void VMax_vv(VRegister vd, VRegister vs2, VRegister vs1, VM vm = VM::kUnmasked); void VMax_vx(VRegister vd, VRegister vs2, XRegister rs1, VM vm = VM::kUnmasked);
// Vector vand instructions, funct6 = 0b001001 void VAnd_vv(VRegister vd, VRegister vs2, VRegister vs1, VM vm = VM::kUnmasked); void VAnd_vx(VRegister vd, VRegister vs2, XRegister rs1, VM vm = VM::kUnmasked); void VAnd_vi(VRegister vd, VRegister vs2, int32_t imm5, VM vm = VM::kUnmasked);
// Vector vor instructions, funct6 = 0b001010 void VOr_vv(VRegister vd, VRegister vs2, VRegister vs1, VM vm = VM::kUnmasked); void VOr_vx(VRegister vd, VRegister vs2, XRegister rs1, VM vm = VM::kUnmasked); void VOr_vi(VRegister vd, VRegister vs2, int32_t imm5, VM vm = VM::kUnmasked);
// Vector vxor instructions, funct6 = 0b001011 void VXor_vv(VRegister vd, VRegister vs2, VRegister vs1, VM vm = VM::kUnmasked); void VXor_vx(VRegister vd, VRegister vs2, XRegister rs1, VM vm = VM::kUnmasked); void VXor_vi(VRegister vd, VRegister vs2, int32_t imm5, VM vm = VM::kUnmasked);
// Pseudo-instruction over VXor_vi void VNot_v(VRegister vd, VRegister vs2, VM vm = VM::kUnmasked);
// Vector vrgather instructions, funct6 = 0b001100 void VRgather_vv(VRegister vd, VRegister vs2, VRegister vs1, VM vm = VM::kUnmasked); void VRgather_vx(VRegister vd, VRegister vs2, XRegister rs1, VM vm = VM::kUnmasked); void VRgather_vi(VRegister vd, VRegister vs2, uint32_t uimm5, VM vm = VM::kUnmasked);
// Vector vslideup instructions, funct6 = 0b001110 void VSlideup_vx(VRegister vd, VRegister vs2, XRegister rs1, VM vm = VM::kUnmasked); void VSlideup_vi(VRegister vd, VRegister vs2, uint32_t uimm5, VM vm = VM::kUnmasked);
// Vector vrgatherei16 instructions, funct6 = 0b001110 void VRgatherei16_vv(VRegister vd, VRegister vs2, VRegister vs1, VM vm = VM::kUnmasked);
// Vector vslidedown instructions, funct6 = 0b001111 void VSlidedown_vx(VRegister vd, VRegister vs2, XRegister rs1, VM vm = VM::kUnmasked); void VSlidedown_vi(VRegister vd, VRegister vs2, uint32_t uimm5, VM vm = VM::kUnmasked);
// Vector VFUNARY0 kind instructions, funct6 = 0b010010 void VFcvt_xu_f_v(VRegister vd, VRegister vs2, VM vm = VM::kUnmasked); void VFcvt_x_f_v(VRegister vd, VRegister vs2, VM vm = VM::kUnmasked); void VFcvt_f_xu_v(VRegister vd, VRegister vs2, VM vm = VM::kUnmasked); void VFcvt_f_x_v(VRegister vd, VRegister vs2, VM vm = VM::kUnmasked); void VFcvt_rtz_xu_f_v(VRegister vd, VRegister vs2, VM vm = VM::kUnmasked); void VFcvt_rtz_x_f_v(VRegister vd, VRegister vs2, VM vm = VM::kUnmasked); void VFwcvt_xu_f_v(VRegister vd, VRegister vs2, VM vm = VM::kUnmasked); void VFwcvt_x_f_v(VRegister vd, VRegister vs2, VM vm = VM::kUnmasked); void VFwcvt_f_xu_v(VRegister vd, VRegister vs2, VM vm = VM::kUnmasked); void VFwcvt_f_x_v(VRegister vd, VRegister vs2, VM vm = VM::kUnmasked); void VFwcvt_f_f_v(VRegister vd, VRegister vs2, VM vm = VM::kUnmasked); void VFwcvt_rtz_xu_f_v(VRegister vd, VRegister vs2, VM vm = VM::kUnmasked); void VFwcvt_rtz_x_f_v(VRegister vd, VRegister vs2, VM vm = VM::kUnmasked); void VFncvt_xu_f_w(VRegister vd, VRegister vs2, VM vm = VM::kUnmasked); void VFncvt_x_f_w(VRegister vd, VRegister vs2, VM vm = VM::kUnmasked); void VFncvt_f_xu_w(VRegister vd, VRegister vs2, VM vm = VM::kUnmasked); void VFncvt_f_x_w(VRegister vd, VRegister vs2, VM vm = VM::kUnmasked); void VFncvt_f_f_w(VRegister vd, VRegister vs2, VM vm = VM::kUnmasked); void VFncvt_rod_f_f_w(VRegister vd, VRegister vs2, VM vm = VM::kUnmasked); void VFncvt_rtz_xu_f_w(VRegister vd, VRegister vs2, VM vm = VM::kUnmasked); void VFncvt_rtz_x_f_w(VRegister vd, VRegister vs2, VM vm = VM::kUnmasked);
// Vector VFUNARY1 kind instructions, funct6 = 0b010011 void VFsqrt_v(VRegister vd, VRegister vs2, VM vm = VM::kUnmasked); void VFrsqrt7_v(VRegister vd, VRegister vs2, VM vm = VM::kUnmasked); void VFrec7_v(VRegister vd, VRegister vs2, VM vm = VM::kUnmasked); void VFclass_v(VRegister vd, VRegister vs2, VM vm = VM::kUnmasked);
// Vector VMUNARY0 kind instructions, funct6 = 0b010100 void VMsbf_m(VRegister vd, VRegister vs2, VM vm = VM::kUnmasked); void VMsof_m(VRegister vd, VRegister vs2, VM vm = VM::kUnmasked); void VMsif_m(VRegister vd, VRegister vs2, VM vm = VM::kUnmasked); void VIota_m(VRegister vd, VRegister vs2, VM vm = VM::kUnmasked); void VId_v(VRegister vd, VM vm = VM::kUnmasked);
////////////////////////////// RISC-V Vector Instructions END //////////////////////////////
////////////////////////////// RV64 MACRO Instructions START /////////////////////////////// // These pseudo instructions are from "RISC-V Assembly Programmer's Manual".
// Create a new literal with a given value. // NOTE:Use `Identity<>` to force the template parameter to be explicitly specified. template <typename T>
Literal* NewLiteral(typename Identity<T>::type value) {
static_assert(std::is_integral<T>::value, "T must be an integral type."); return NewLiteral(sizeof(value), reinterpret_cast<const uint8_t*>(&value));
}
// Create a new literal with the given data.
Literal* NewLiteral(size_t size, const uint8_t* data);
// Create a jump table for the given labels that will be emitted when finalizing. // When the table is emitted, offsets will be relative to the location of the table. // The table location is determined by the location of its label (the label precedes // the table data) and should be loaded using LoadLabelAddress().
JumpTable* CreateJumpTable(ArenaVector<Riscv64Label*>&& labels);
public: // Emit slow paths queued during assembly, promote short branches to long if needed, // and emit branches. void FinalizeCode() override;
// Returns the current location of a label. // // This function must be used instead of `Riscv64Label::GetPosition()` // which returns assembler's internal data instead of an actual location. // // The location can change during branch fixup in `FinalizeCode()`. Before that, // the location is not final and therefore not very useful to external users, // so they should preferably retrieve the location only after `FinalizeCode()`.
uint32_t GetLabelLocation(const Riscv64Label* label) const;
// Get the final position of a label after local fixup based on the old position // recorded before FinalizeCode().
uint32_t GetAdjustedPosition(uint32_t old_position);
private: static uint32_t ConvertExtensions( const Riscv64InstructionSetFeatures* instruction_set_features) { // The `Riscv64InstructionSetFeatures` currently does not support "Zcb", // only the original "C" extension. For riscv64 that means "Zca" and "Zcd".
constexpr Riscv64ExtensionMask kCompressedExtensionsMask =
Riscv64ExtensionBit(Riscv64Extension::kZca) | Riscv64ExtensionBit(Riscv64Extension::kZcd); return
(Riscv64ExtensionBit(Riscv64Extension::kLoadStore)) |
(Riscv64ExtensionBit(Riscv64Extension::kZifencei)) |
(Riscv64ExtensionBit(Riscv64Extension::kM)) |
(Riscv64ExtensionBit(Riscv64Extension::kA)) |
(Riscv64ExtensionBit(Riscv64Extension::kZicsr)) |
(Riscv64ExtensionBit(Riscv64Extension::kF)) |
(Riscv64ExtensionBit(Riscv64Extension::kD)) |
(instruction_set_features->HasZba() ? Riscv64ExtensionBit(Riscv64Extension::kZba) : 0u) |
(instruction_set_features->HasZbb() ? Riscv64ExtensionBit(Riscv64Extension::kZbb) : 0u) |
(instruction_set_features->HasZbs() ? Riscv64ExtensionBit(Riscv64Extension::kZbs) : 0u) |
(instruction_set_features->HasVector() ? Riscv64ExtensionBit(Riscv64Extension::kV) : 0u) |
(instruction_set_features->HasCompressed() ? kCompressedExtensionsMask : 0u);
}
// Note that PC-relative literal loads are handled as pseudo branches because they need // to be emitted after branch relocation to use correct offsets. class Branch { public: enum Type : uint8_t { // Compressed branches (can be promoted to longer)
kCondCBranch,
kUncondCBranch, // Compressed branches (can't be promoted to longer)
kBareCondCBranch,
kBareUncondCBranch,
// Short branches (can be promoted to longer).
kCondBranch,
kUncondBranch,
kCall, // Short branches (can't be promoted to longer).
kBareCondBranch,
kBareUncondBranch,
kBareCall,
// Medium branches (can be promoted to long). // Compressed version
kCondCBranch21,
kCondBranch21,
// Long branches.
kLongCondCBranch,
kLongCondBranch,
kLongUncondBranch,
kLongCall,
struct BranchInfo { // Branch length in bytes.
uint32_t length; // The offset in bytes of the PC used in the (only) PC-relative instruction from // the start of the branch sequence. RISC-V always uses the address of the PC-relative // instruction as the PC, so this is essentially the offset of that instruction.
uint32_t pc_offset; // How large (in bits) a PC-relative offset can be for a given type of branch.
OffsetBits offset_size;
}; staticconst BranchInfo branch_info_[/* Type */];
// Checks if condition meets compression requirements bool IsCompressableCondition() const;
// Returns the bit size of the signed offset that the branch instruction can handle.
OffsetBits GetOffsetSize() const;
// Calculates the distance between two byte locations in the assembler buffer and // returns the number of bits needed to represent the distance as a signed integer. static OffsetBits GetOffsetSizeNeeded(uint32_t location, uint32_t target);
// Resolve a branch when the target is known. void Resolve(uint32_t target);
// Relocate a branch by a given delta if needed due to expansion of this or another // branch at a given location by this delta (just changes location_ and target_). void Relocate(uint32_t expand_location, uint32_t delta);
// If necessary, updates the type by promoting a short branch to a longer branch // based on the branch location and target. Returns the amount (in bytes) by // which the branch size has increased.
uint32_t PromoteIfNeeded();
// Returns the offset into assembler buffer that shall be used as the base PC for // offset calculation. RISC-V always uses the address of the PC-relative instruction // as the PC, so this is essentially the location of that instruction.
uint32_t GetOffsetLocation() const;
// Calculates and returns the offset ready for encoding in the branch instruction(s).
int32_t GetOffset() const;
// Link with the next branch void LinkToList(uint32_t next_branch_id);
private: // Completes branch construction by determining and recording its type. void InitializeType(Type initial_type); // Helper for the above. void InitShortOrLong(OffsetBits ofs_size, std::initializer_list<Type> types);
uint32_t old_location_; // Offset into assembler buffer in bytes.
uint32_t location_; // Offset into assembler buffer in bytes.
uint32_t target_; // Offset into assembler buffer in bytes.
XRegister lhs_reg_; // Left-hand side register in conditional branches or // destination register in calls or literals.
XRegister rhs_reg_; // Right-hand side register in conditional branches.
FRegister freg_; // Destination register in FP literals.
BranchCondition condition_; // Condition for conditional branches.
Type type_; // Current type of the branch.
Type old_type_; // Initial type of the branch.
bool compression_allowed_;
// Id of the next branch bound to the same label in singly-linked zero-terminated list // NOTE: encoded the same way as a position in a linked Label (id + sizeof(void*)) // Label itself is used to hold the 'head' of this list
uint32_t next_branch_id_;
};
// Emit data (e.g. encoded instruction or immediate) to the instruction stream. template <typename T> void Emit(T value) {
static_assert(std::is_same_v<T, uint32_t> || std::is_same_v<T, uint16_t>, "Only Integer types are allowed"); if (overwriting_) { // Branches to labels are emitted into their placeholders here.
buffer_.Store<T>(overwrite_location_, value);
overwrite_location_ += sizeof(T);
} else { // Other instructions are simply appended at the end here.
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
buffer_.Emit<T>(value);
}
}
// Adjust base register and offset if needed for load/store with a large offset. void AdjustBaseAndOffset(XRegister& base, int32_t& offset, ScratchRegisterScope& srs);
// Rearrange given offset in the way {offset[0] | offset[1]} static constexpr uint32_t EncodeOffset0_1(int32_t offset) {
uint32_t u_offset = static_cast<uint32_t>(offset);
DCHECK(IsUint<2>(u_offset));
return u_offset >> 1 | (u_offset & 1u) << 1;
}
// Rearrange given offset, scaled by 4, in the way {offset[5:2] | offset[7:6]} static constexpr uint32_t ExtractOffset52_76(int32_t offset) {
DCHECK(IsAligned<4>(offset)) << "Offset should be scalable by 4";
// Rearrange given offset, scaled by 8, in the way {offset[5:3] | offset[8:6]} static constexpr uint32_t ExtractOffset53_86(int32_t offset) {
DCHECK(IsAligned<8>(offset)) << "Offset should be scalable by 8";
// Rearrange given offset, scaled by 4, in the way {offset[5:2] | offset[6]} static constexpr uint32_t ExtractOffset52_6(int32_t offset) {
DCHECK(IsAligned<4>(offset)) << "Offset should be scalable by 4";
// Rearrange given offset, scaled by 8, in the way {offset[5:3], offset[7:6]} static constexpr uint32_t ExtractOffset53_76(int32_t offset) {
DCHECK(IsAligned<8>(offset)) << "Offset should be scalable by 4";
static constexpr bool IsImmCLuiEncodable(uint32_t uimm) { // Instruction c.lui is odd and its immediate value is a bit tricky // Its value is not a full 32 bits value, but its bits [31:12] // (where the bit 17 marks the sign bit) shifted towards the bottom i.e. bits [19:0] // are the meaningful ones. Since that we want a signed non-zero 6-bit immediate to // keep values in the range [0, 0x1f], and the range [0xfffe0, 0xfffff] for negative values // since the sign bit was bit 17 (which is now bit 5 and replicated in the higher bits too) // Also encoding with immediate = 0 is reserved // For more details please see 16.5 chapter is the specification
// For checking that we finalize the code only once. bool finalized_;
// Whether appending instructions at the end of the buffer or overwriting the existing ones. bool overwriting_; // The current overwrite location.
uint32_t overwrite_location_;
// Use `std::deque<>` for literal labels to allow insertions at the end // without invalidating pointers and references to existing elements.
ArenaDeque<Literal> literals_;
ArenaDeque<Literal> long_literals_; // 64-bit literals separated for alignment reasons.
// Data for `GetAdjustedPosition()`, see the description there.
uint32_t last_position_adjustment_;
uint32_t last_old_position_;
uint32_t last_branch_id_;
// Alocate a scratch `XRegister`. There must be an available register to allocate.
XRegister AllocateXRegister() {
CHECK_NE(assembler_->available_scratch_core_registers_, 0u); // Allocate the highest available scratch register (prefer TMP(T6) over TMP2(T5)).
uint32_t reg_num = (BitSizeOf(assembler_->available_scratch_core_registers_) - 1u) -
CLZ(assembler_->available_scratch_core_registers_);
assembler_->available_scratch_core_registers_ &= ~(1u << reg_num);
DCHECK_LT(reg_num, enum_cast<uint32_t>(kNumberOfXRegisters)); return enum_cast<XRegister>(reg_num);
}
// Free a previously unavailable core register for use as a scratch register. // This can be an arbitrary register, not necessarly the usual `TMP` or `TMP2`. void FreeXRegister(XRegister reg) {
uint32_t reg_num = enum_cast<uint32_t>(reg);
DCHECK_LT(reg_num, enum_cast<uint32_t>(kNumberOfXRegisters));
CHECK_EQ((1u << reg_num) & assembler_->available_scratch_core_registers_, 0u);
assembler_->available_scratch_core_registers_ |= 1u << reg_num;
}
// The number of available scratch core registers.
size_t AvailableXRegisters() { return POPCOUNT(assembler_->available_scratch_core_registers_);
}
// Make sure a core register is available for use as a scratch register. void IncludeXRegister(XRegister reg) {
uint32_t reg_num = enum_cast<uint32_t>(reg);
DCHECK_LT(reg_num, enum_cast<uint32_t>(kNumberOfXRegisters));
assembler_->available_scratch_core_registers_ |= 1u << reg_num;
}
// Make sure a core register is not available for use as a scratch register. void ExcludeXRegister(XRegister reg) {
uint32_t reg_num = enum_cast<uint32_t>(reg);
DCHECK_LT(reg_num, enum_cast<uint32_t>(kNumberOfXRegisters));
assembler_->available_scratch_core_registers_ &= ~(1u << reg_num);
}
// Alocate a scratch `FRegister`. There must be an available register to allocate.
FRegister AllocateFRegister() {
CHECK_NE(assembler_->available_scratch_fp_registers_, 0u); // Allocate the highest available scratch register (same as for core registers).
uint32_t reg_num = (BitSizeOf(assembler_->available_scratch_fp_registers_) - 1u) -
CLZ(assembler_->available_scratch_fp_registers_);
assembler_->available_scratch_fp_registers_ &= ~(1u << reg_num);
DCHECK_LT(reg_num, enum_cast<uint32_t>(kNumberOfFRegisters)); return enum_cast<FRegister>(reg_num);
}
// Free a previously unavailable FP register for use as a scratch register. // This can be an arbitrary register, not necessarly the usual `FTMP`. void FreeFRegister(FRegister reg) {
uint32_t reg_num = enum_cast<uint32_t>(reg);
DCHECK_LT(reg_num, enum_cast<uint32_t>(kNumberOfFRegisters));
CHECK_EQ((1u << reg_num) & assembler_->available_scratch_fp_registers_, 0u);
assembler_->available_scratch_fp_registers_ |= 1u << reg_num;
}
// The number of available scratch FP registers.
size_t AvailableFRegisters() { return POPCOUNT(assembler_->available_scratch_fp_registers_);
}
// Make sure an FP register is available for use as a scratch register. void IncludeFRegister(FRegister reg) {
uint32_t reg_num = enum_cast<uint32_t>(reg);
DCHECK_LT(reg_num, enum_cast<uint32_t>(kNumberOfFRegisters));
assembler_->available_scratch_fp_registers_ |= 1u << reg_num;
}
// Make sure an FP register is not available for use as a scratch register. void ExcludeFRegister(FRegister reg) {
uint32_t reg_num = enum_cast<uint32_t>(reg);
DCHECK_LT(reg_num, enum_cast<uint32_t>(kNumberOfFRegisters));
assembler_->available_scratch_fp_registers_ &= ~(1u << reg_num);
}
using ScopedNoCInstructions = ScopedExtensionsExclusion<kRiscv64CompressedExtensionsMask>; using ScopedUseCInstructions = ScopedExtensionsInclusion<kRiscv64CompressedExtensionsMask>;
¤ 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.0.55Bemerkung:
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-06-29)
¤