8347794: RISC-V: Add Zfhmin - Float cleanup

Reviewed-by: fyang, mli
This commit is contained in:
Robbin Ehn 2025-01-22 10:25:36 +00:00
parent 9b98cc0ba7
commit fb43849227
8 changed files with 403 additions and 233 deletions

View File

@ -552,24 +552,6 @@ public:
#undef INSN
#define INSN(NAME, op, funct3) \
void NAME(FloatRegister Rd, Register Rs, const int32_t offset) { \
guarantee(is_simm12(offset), "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_simm13(offset) && ((offset % 2) == 0), "offset is invalid."); \
@ -813,26 +795,6 @@ enum operand_size { int8, int16, int32, uint32, int64 };
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_h, 0b1010011, 0b00010, 0b0100000);
INSN(fcvt_h_s, 0b1010011, 0b00000, 0b0100010);
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, int64_t imm) { \
@ -928,209 +890,408 @@ enum operand_size { int8, int16, int32, uint32, int64 };
#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); \
// ==========================
// Floating Point Instructions
// ==========================
static constexpr uint32_t OP_FP_MAJOR = 0b1010011;
enum FmtPrecision : uint8_t {
S_32_sp = 0b00,
D_64_dp = 0b01,
H_16_hp = 0b10,
Q_128_qp = 0b11
};
private:
template <FmtPrecision Fmt, uint8_t funct5>
void fp_base(uint8_t Rd, uint8_t Rs1, uint8_t Rs2, RoundingMode rm) {
assert(Fmt != H_16_hp || UseZfh || UseZfhmin, "No half precision enabled");
assert_cond(Fmt != Q_128_qp);
guarantee(is_uimm3(rm), "Rounding mode is out of validity");
guarantee(is_uimm2(Fmt), "FMT is out of validity");
guarantee(is_uimm5(funct5), "Funct5 is out of validity");
uint32_t insn = 0;
patch((address)&insn, 6, 0, OP_FP_MAJOR);
patch((address)&insn, 11, 7, Rd);
patch((address)&insn, 14, 12, rm);
patch((address)&insn, 19, 15, Rs1);
patch((address)&insn, 24, 20, Rs2);
patch((address)&insn, 26, 25, Fmt);
patch((address)&insn, 31, 27, funct5);
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); \
template <FmtPrecision Fmt, uint8_t funct5>
void fp_base(FloatRegister Rd, FloatRegister Rs1, FloatRegister Rs2, RoundingMode rm) {
fp_base<Fmt, funct5>(Rd->raw_encoding(), Rs1->raw_encoding(), Rs2->raw_encoding(), rm);
}
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); \
template <FmtPrecision Fmt, uint8_t funct5>
void fp_base(FloatRegister Rd, FloatRegister Rs1, FloatRegister Rs2, int8_t rm) {
fp_base<Fmt, funct5>(Rd->raw_encoding(), Rs1->raw_encoding(), Rs2->raw_encoding(), (RoundingMode)rm);
}
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); \
template <FmtPrecision Fmt, uint8_t funct5>
void fp_base(Register Rd, FloatRegister Rs1, FloatRegister Rs2, int8_t rm) {
fp_base<Fmt, funct5>(Rd->raw_encoding(), Rs1->raw_encoding(), Rs2->raw_encoding(), (RoundingMode)rm);
}
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); \
template <FmtPrecision Fmt, uint8_t funct5>
void fp_base(FloatRegister Rd, FloatRegister Rs1, int8_t Rs2, int8_t rm) {
guarantee(is_uimm5(Rs2), "Rs2 is out of validity");
fp_base<Fmt, funct5>(Rd->raw_encoding(), Rs1->raw_encoding(), Rs2, (RoundingMode)rm);
}
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); \
template <FmtPrecision Fmt, uint8_t funct5>
void fp_base(FloatRegister Rd, Register Rs1, FloatRegister Rs2, RoundingMode rm) {
fp_base<Fmt, funct5>(Rd->raw_encoding(), Rs1->raw_encoding(), Rs2->raw_encoding(), rm);
}
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); \
template <FmtPrecision Fmt, uint8_t funct5>
void fp_base(Register Rd, FloatRegister Rs1, uint8_t Rs2, RoundingMode rm) {
guarantee(is_uimm5(Rs2), "Rs2 is out of validity");
fp_base<Fmt, funct5>(Rd->raw_encoding(), Rs1->raw_encoding(), Rs2, rm);
}
INSN(fmv_h_x, 0b1010011, 0b000, 0b00000, 0b1111010);
INSN(fmv_w_x, 0b1010011, 0b000, 0b00000, 0b1111000);
INSN(fmv_d_x, 0b1010011, 0b000, 0b00000, 0b1111001);
#undef INSN
enum fclass_mask {
minf = 1 << 0, // negative infinite
mnorm = 1 << 1, // negative normal number
msubnorm = 1 << 2, // negative subnormal number
mzero = 1 << 3, // negative zero
pzero = 1 << 4, // positive zero
psubnorm = 1 << 5, // positive subnormal number
pnorm = 1 << 6, // positive normal number
pinf = 1 << 7, // positive infinite
snan = 1 << 8, // signaling NaN
qnan = 1 << 9, // quiet NaN
zero = mzero | pzero,
subnorm = msubnorm | psubnorm,
norm = mnorm | pnorm,
inf = minf | pinf,
nan = snan | qnan,
finite = zero | subnorm | norm,
};
// Float and Double Conversion/Classify 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); \
template <FmtPrecision Fmt, uint8_t funct5>
void fp_base(Register Rd, FloatRegister Rs1, uint8_t Rs2, uint8_t rm) {
guarantee(is_uimm5(Rs2), "Rs2 is out of validity");
fp_base<Fmt, funct5>(Rd->raw_encoding(), Rs1->raw_encoding(), Rs2, (RoundingMode)rm);
}
INSN(fclass_h, 0b1010011, 0b001, 0b00000, 0b1110010);
INSN(fclass_s, 0b1010011, 0b001, 0b00000, 0b1110000);
INSN(fclass_d, 0b1010011, 0b001, 0b00000, 0b1110001);
INSN(fmv_x_h, 0b1010011, 0b000, 0b00000, 0b1110010);
INSN(fmv_x_w, 0b1010011, 0b000, 0b00000, 0b1110000);
INSN(fmv_x_d, 0b1010011, 0b000, 0b00000, 0b1110001);
template <FmtPrecision Fmt, uint8_t funct5>
void fp_base(FloatRegister Rd, Register Rs1, uint8_t Rs2, RoundingMode rm) {
guarantee(is_uimm5(Rs2), "Rs2 is out of validity");
fp_base<Fmt, funct5>(Rd->raw_encoding(), Rs1->raw_encoding(), Rs2, rm);
}
#undef INSN
template <FmtPrecision Fmt, uint8_t funct5>
void fp_base(FloatRegister Rd, Register Rs1, uint8_t Rs2, int8_t rm) {
guarantee(is_uimm5(Rs2), "Rs2 is out of validity");
fp_base<Fmt, funct5>(Rd->raw_encoding(), Rs1->raw_encoding(), Rs2, (RoundingMode)rm);
}
public:
enum FClassBits {
minf = 1 << 0, // negative infinite
mnorm = 1 << 1, // negative normal number
msubnorm = 1 << 2, // negative subnormal number
mzero = 1 << 3, // negative zero
pzero = 1 << 4, // positive zero
psubnorm = 1 << 5, // positive subnormal number
pnorm = 1 << 6, // positive normal number
pinf = 1 << 7, // positive infinite
snan = 1 << 8, // signaling NaN
qnan = 1 << 9, // quiet NaN
zero = mzero | pzero,
subnorm = msubnorm | psubnorm,
norm = mnorm | pnorm,
inf = minf | pinf,
nan = snan | qnan,
finite = zero | subnorm | norm,
};
void fsqrt_s(FloatRegister Rd, FloatRegister Rs1, RoundingMode rm = rne) {
fp_base<S_32_sp, 0b01011>(Rd, Rs1, 0b00000, rm);
}
void fsqrt_d(FloatRegister Rd, FloatRegister Rs1, RoundingMode rm = rne) {
fp_base<D_64_dp, 0b01011>(Rd, Rs1, 0b00000, rm);
}
void fcvt_s_d(FloatRegister Rd, FloatRegister Rs1, RoundingMode rm = rne) {
fp_base<S_32_sp, 0b01000>(Rd, Rs1, 0b00001, rm);
}
void fcvt_d_s(FloatRegister Rd, FloatRegister Rs1, RoundingMode rm = rne) {
fp_base<D_64_dp, 0b01000>(Rd, Rs1, 0b00000, rm);
}
void fsgnj_s(FloatRegister Rd, FloatRegister Rs1, FloatRegister Rs2) {
fp_base<S_32_sp, 0b00100>(Rd, Rs1, Rs2, 0b000);
}
void fsgnjn_s(FloatRegister Rd, FloatRegister Rs1, FloatRegister Rs2) {
fp_base<S_32_sp, 0b00100>(Rd, Rs1, Rs2, 0b001);
}
void fsgnjx_s(FloatRegister Rd, FloatRegister Rs1, FloatRegister Rs2) {
fp_base<S_32_sp, 0b00100>(Rd, Rs1, Rs2, 0b010);
}
void fmin_s(FloatRegister Rd, FloatRegister Rs1, FloatRegister Rs2) {
fp_base<S_32_sp, 0b00101>(Rd, Rs1, Rs2, 0b000);
}
void fmax_s(FloatRegister Rd, FloatRegister Rs1, FloatRegister Rs2) {
fp_base<S_32_sp, 0b00101>(Rd, Rs1, Rs2, 0b001);
}
void fsgnj_d(FloatRegister Rd, FloatRegister Rs1, FloatRegister Rs2) {
fp_base<D_64_dp, 0b00100>(Rd, Rs1, Rs2, 0b000);
}
void fsgnjn_d(FloatRegister Rd, FloatRegister Rs1, FloatRegister Rs2) {
fp_base<D_64_dp, 0b00100>(Rd, Rs1, Rs2, 0b001);
}
void fsgnjx_d(FloatRegister Rd, FloatRegister Rs1, FloatRegister Rs2) {
fp_base<D_64_dp, 0b00100>(Rd, Rs1, Rs2, 0b010);
}
void fmin_d(FloatRegister Rd, FloatRegister Rs1, FloatRegister Rs2) {
fp_base<D_64_dp, 0b00101>(Rd, Rs1, Rs2, 0b000);
}
void fmax_d(FloatRegister Rd, FloatRegister Rs1, FloatRegister Rs2) {
fp_base<D_64_dp, 0b00101>(Rd, Rs1, Rs2, 0b001);
}
void feq_s(Register Rd, FloatRegister Rs1, FloatRegister Rs2) {
fp_base<S_32_sp, 0b10100>(Rd, Rs1, Rs2, 0b010);
}
void flt_s(Register Rd, FloatRegister Rs1, FloatRegister Rs2) {
fp_base<S_32_sp, 0b10100>(Rd, Rs1, Rs2, 0b001);
}
void fle_s(Register Rd, FloatRegister Rs1, FloatRegister Rs2) {
fp_base<S_32_sp, 0b10100>(Rd, Rs1, Rs2, 0b000);
}
void feq_d(Register Rd, FloatRegister Rs1, FloatRegister Rs2) {
fp_base<D_64_dp, 0b10100>(Rd, Rs1, Rs2, 0b010);
}
void fle_d(Register Rd, FloatRegister Rs1, FloatRegister Rs2) {
fp_base<D_64_dp, 0b10100>(Rd, Rs1, Rs2, 0b000);
}
void flt_d(Register Rd, FloatRegister Rs1, FloatRegister Rs2) {
fp_base<D_64_dp, 0b10100>(Rd, Rs1, Rs2, 0b001);
}
void fadd_s(FloatRegister Rd, FloatRegister Rs1, FloatRegister Rs2, RoundingMode rm = rne) {
fp_base<S_32_sp, 0b00000>(Rd, Rs1, Rs2, rm);
}
void fsub_s(FloatRegister Rd, FloatRegister Rs1, FloatRegister Rs2, RoundingMode rm = rne) {
fp_base<S_32_sp, 0b00001>(Rd, Rs1, Rs2, rm);
}
void fmul_s(FloatRegister Rd, FloatRegister Rs1, FloatRegister Rs2, RoundingMode rm = rne) {
fp_base<S_32_sp, 0b00010>(Rd, Rs1, Rs2, rm);
}
void fdiv_s(FloatRegister Rd, FloatRegister Rs1, FloatRegister Rs2, RoundingMode rm = rne) {
fp_base<S_32_sp, 0b00011>(Rd, Rs1, Rs2, rm);
}
void fadd_d(FloatRegister Rd, FloatRegister Rs1, FloatRegister Rs2, RoundingMode rm = rne) {
fp_base<D_64_dp, 0b00000>(Rd, Rs1, Rs2, rm);
}
void fsub_d(FloatRegister Rd, FloatRegister Rs1, FloatRegister Rs2, RoundingMode rm = rne) {
fp_base<D_64_dp, 0b00001>(Rd, Rs1, Rs2, rm);
}
void fmul_d(FloatRegister Rd, FloatRegister Rs1, FloatRegister Rs2, RoundingMode rm = rne) {
fp_base<D_64_dp, 0b00010>(Rd, Rs1, Rs2, rm);
}
void fdiv_d(FloatRegister Rd, FloatRegister Rs1, FloatRegister Rs2, RoundingMode rm = rne) {
fp_base<D_64_dp, 0b00011>(Rd, Rs1, Rs2, rm);
}
void fcvt_s_w(FloatRegister Rd, Register Rs1, RoundingMode rm = rne) {
fp_base<S_32_sp, 0b11010>(Rd, Rs1, 0b00000, rm);
}
void fcvt_s_wu(FloatRegister Rd, Register Rs1, RoundingMode rm = rne) {
fp_base<S_32_sp, 0b11010>(Rd, Rs1, 0b00001, rm);
}
void fcvt_s_l(FloatRegister Rd, Register Rs1, RoundingMode rm = rne) {
fp_base<S_32_sp, 0b11010>(Rd, Rs1, 0b00010, rm);
}
void fcvt_s_lu(FloatRegister Rd, Register Rs1, RoundingMode rm = rne) {
fp_base<S_32_sp, 0b11010>(Rd, Rs1, 0b00011, rm);
}
void fcvt_d_w(FloatRegister Rd, Register Rs1, RoundingMode rm = rne) {
fp_base<D_64_dp, 0b11010>(Rd, Rs1, 0b00000, rm);
}
void fcvt_d_wu(FloatRegister Rd, Register Rs1, RoundingMode rm = rne) {
fp_base<D_64_dp, 0b11010>(Rd, Rs1, 0b00001, rm);
}
void fcvt_d_l(FloatRegister Rd, Register Rs1, RoundingMode rm = rne) {
fp_base<D_64_dp, 0b11010>(Rd, Rs1, 0b00010, rm);
}
void fcvt_d_lu(FloatRegister Rd, Register Rs1, RoundingMode rm = rne) {
fp_base<D_64_dp, 0b11010>(Rd, Rs1, 0b00011, rm);
}
void fcvt_w_s(Register Rd, FloatRegister Rs1, RoundingMode rm = rtz) {
fp_base<S_32_sp, 0b11000>(Rd, Rs1, 0b00000, rm);
}
void fcvt_l_s(Register Rd, FloatRegister Rs1, RoundingMode rm = rtz) {
fp_base<S_32_sp, 0b11000>(Rd, Rs1, 0b00010, rm);
}
void fcvt_wu_s(Register Rd, FloatRegister Rs1, RoundingMode rm = rtz) {
fp_base<S_32_sp, 0b11000>(Rd, Rs1, 0b00001, rm);
}
void fcvt_lu_s(Register Rd, FloatRegister Rs1, RoundingMode rm = rtz) {
fp_base<S_32_sp, 0b11000>(Rd, Rs1, 0b00011, rm);
}
void fcvt_w_d(Register Rd, FloatRegister Rs1, RoundingMode rm = rtz) {
fp_base<D_64_dp, 0b11000>(Rd, Rs1, 0b00000, rm);
}
void fcvt_wu_d(Register Rd, FloatRegister Rs1, RoundingMode rm = rtz) {
fp_base<D_64_dp, 0b11000>(Rd, Rs1, 0b00001, rm);
}
void fcvt_l_d(Register Rd, FloatRegister Rs1, RoundingMode rm = rtz) {
fp_base<D_64_dp, 0b11000>(Rd, Rs1, 0b00010, rm);
}
void fcvt_lu_d(Register Rd, FloatRegister Rs1, RoundingMode rm = rtz) {
fp_base<D_64_dp, 0b11000>(Rd, Rs1, 0b00011, rm);
}
void fmv_w_x(FloatRegister Rd, Register Rs1) {
fp_base<S_32_sp, 0b11110>(Rd, Rs1, 0b00000, 0b000);
}
void fmv_d_x(FloatRegister Rd, Register Rs1) {
fp_base<D_64_dp, 0b11110>(Rd, Rs1, 0b00000, 0b000);
}
void fclass_s(Register Rd, FloatRegister Rs1) {
fp_base<S_32_sp, 0b11100>(Rd, Rs1, 0b00000, 0b001);
}
void fclass_d(Register Rd, FloatRegister Rs1) {
fp_base<D_64_dp, 0b11100>(Rd, Rs1, 0b00000, 0b001);
}
void fmv_x_w(Register Rd, FloatRegister Rs1) {
fp_base<S_32_sp, 0b11100>(Rd, Rs1, 0b00000, 0b000);
}
void fmv_x_d(Register Rd, FloatRegister Rs1) {
fp_base<D_64_dp, 0b11100>(Rd, Rs1, 0b00000, 0b000);
}
private:
static constexpr unsigned int OP_LOAD_FP = 0b0000111;
template <int8_t FpWidth>
void fp_load(FloatRegister Rd, Register Rs, const int32_t offset) {
guarantee(is_uimm3(FpWidth), "Rounding mode is out of validity");
guarantee(is_simm12(offset), "offset is invalid.");
unsigned insn = 0;
uint32_t val = offset & 0xfff;
patch((address)&insn, 6, 0, OP_LOAD_FP);
patch_reg((address)&insn, 7, Rd);
patch((address)&insn, 14, 12, FpWidth);
patch_reg((address)&insn, 15, Rs);
patch((address)&insn, 31, 20, val);
emit(insn);
}
public:
void flw(FloatRegister Rd, Register Rs, const int32_t offset) { fp_load<0b010>(Rd, Rs, offset); }
void _fld(FloatRegister Rd, Register Rs, const int32_t offset) { fp_load<0b011>(Rd, Rs, offset); }
private:
template <FmtPrecision Fmt, uint8_t OpVal>
void fp_fm(FloatRegister Rd, FloatRegister Rs1, FloatRegister Rs2, FloatRegister Rs3, RoundingMode rm) {
assert_cond(Fmt != Q_128_qp);
guarantee(is_uimm3(rm), "Rounding mode is out of validity");
guarantee(is_uimm2(Fmt), "FMT is out of validity");
unsigned insn = 0;
patch((address)&insn, 6, 0, OpVal);
patch_reg((address)&insn, 7, Rd);
patch((address)&insn, 14, 12, rm);
patch_reg((address)&insn, 15, Rs1);
patch_reg((address)&insn, 20, Rs2);
patch((address)&insn, 26, 25, Fmt);
patch_reg((address)&insn, 27, Rs3);
emit(insn);
}
public:
void fmadd_s(FloatRegister Rd, FloatRegister Rs1, FloatRegister Rs2, FloatRegister Rs3, RoundingMode rm = rne) {
fp_fm<S_32_sp, 0b1000011>(Rd, Rs1, Rs2, Rs3, rm);
}
void fmsub_s(FloatRegister Rd, FloatRegister Rs1, FloatRegister Rs2, FloatRegister Rs3, RoundingMode rm = rne) {
fp_fm<S_32_sp, 0b1000111>(Rd, Rs1, Rs2, Rs3, rm);
}
void fnmsub_s(FloatRegister Rd, FloatRegister Rs1, FloatRegister Rs2, FloatRegister Rs3, RoundingMode rm = rne) {
fp_fm<S_32_sp, 0b1001011>(Rd, Rs1, Rs2, Rs3, rm);
}
void fnmadd_s(FloatRegister Rd, FloatRegister Rs1, FloatRegister Rs2, FloatRegister Rs3, RoundingMode rm = rne) {
fp_fm<S_32_sp, 0b1001111>(Rd, Rs1, Rs2, Rs3, rm);
}
void fmadd_d(FloatRegister Rd, FloatRegister Rs1, FloatRegister Rs2, FloatRegister Rs3, RoundingMode rm = rne) {
fp_fm<D_64_dp, 0b1000011>(Rd, Rs1, Rs2, Rs3, rm);
}
void fmsub_d(FloatRegister Rd, FloatRegister Rs1, FloatRegister Rs2, FloatRegister Rs3, RoundingMode rm = rne) {
fp_fm<D_64_dp, 0b1000111>(Rd, Rs1, Rs2, Rs3, rm);
}
void fnmsub_d(FloatRegister Rd, FloatRegister Rs1, FloatRegister Rs2, FloatRegister Rs3, RoundingMode rm = rne) {
fp_fm<D_64_dp, 0b1001011>(Rd, Rs1, Rs2, Rs3, rm);
}
void fnmadd_d(FloatRegister Rd, FloatRegister Rs1, FloatRegister Rs2, FloatRegister Rs3, RoundingMode rm = rne) {
fp_fm<D_64_dp, 0b1001111>(Rd, Rs1, Rs2, Rs3, rm);
}
// -------------- ZFH Instruction Definitions --------------
// Zfh Standard Extensions for Half-Precision Floating-Point
void fclass_h(Register Rd, FloatRegister Rs1) {
assert_cond(UseZfh);
fp_base<H_16_hp, 0b11100>(Rd, Rs1, 0b00000, 0b001);
}
// Zfh and Zfhmin Half-Precision Floating-Point
void fcvt_s_h(FloatRegister Rd, FloatRegister Rs1, RoundingMode rm = rne) {
assert_cond(UseZfh || UseZfhmin);
fp_base<S_32_sp, 0b01000>(Rd, Rs1, 0b00010, rm);
}
void fcvt_h_s(FloatRegister Rd, FloatRegister Rs1, RoundingMode rm = rne) {
assert_cond(UseZfh || UseZfhmin);
fp_base<H_16_hp, 0b01000>(Rd, Rs1, 0b00000, rm);
}
void fmv_h_x(FloatRegister Rd, Register Rs1) {
assert_cond(UseZfh || UseZfhmin);
fp_base<H_16_hp, 0b11110>(Rd, Rs1, 0b00000, 0b000);
}
void fmv_x_h(Register Rd, FloatRegister Rs1) {
assert_cond(UseZfh || UseZfhmin);
fp_base<H_16_hp, 0b11100>(Rd, Rs1, 0b00000, 0b000);
}
// ==========================
// RISC-V Vector Extension
@ -3402,6 +3563,7 @@ public:
static bool is_simm18(int64_t x);
static bool is_simm21(int64_t x);
static bool is_uimm2(uint64_t x);
static bool is_uimm3(uint64_t x);
static bool is_uimm5(uint64_t x);
static bool is_uimm6(uint64_t x);

View File

@ -38,6 +38,7 @@ inline bool Assembler::is_simm13(int64_t x) { return is_simm(x, 13); }
inline bool Assembler::is_simm18(int64_t x) { return is_simm(x, 18); }
inline bool Assembler::is_simm21(int64_t x) { return is_simm(x, 21); }
inline bool Assembler::is_uimm2(uint64_t x) { return is_uimm(x, 2); }
inline bool Assembler::is_uimm3(uint64_t x) { return is_uimm(x, 3); }
inline bool Assembler::is_uimm5(uint64_t x) { return is_uimm(x, 5); }
inline bool Assembler::is_uimm6(uint64_t x) { return is_uimm(x, 6); }

View File

@ -2058,7 +2058,7 @@ void C2_MacroAssembler::minmax_fp(FloatRegister dst, FloatRegister src1, FloatRe
is_double ? fclass_d(t1, src2)
: fclass_s(t1, src2);
orr(t0, t0, t1);
andi(t0, t0, fclass_mask::nan); // if src1 or src2 is quiet or signaling NaN then return NaN
andi(t0, t0, FClassBits::nan); // if src1 or src2 is quiet or signaling NaN then return NaN
beqz(t0, Compare);
is_double ? fadd_d(dst, src1, src2)
: fadd_s(dst, src1, src2);
@ -2152,7 +2152,7 @@ void C2_MacroAssembler::signum_fp(FloatRegister dst, FloatRegister one, bool is_
: fclass_s(t0, dst);
// check if input is -0, +0, signaling NaN or quiet NaN
andi(t0, t0, fclass_mask::zero | fclass_mask::nan);
andi(t0, t0, FClassBits::zero | FClassBits::nan);
bnez(t0, done);
@ -2368,7 +2368,7 @@ void C2_MacroAssembler::signum_fp_v(VectorRegister dst, VectorRegister one, Basi
// check if input is -0, +0, signaling NaN or quiet NaN
vfclass_v(v0, dst);
mv(t0, fclass_mask::zero | fclass_mask::nan);
mv(t0, FClassBits::zero | FClassBits::nan);
vand_vx(v0, v0, t0);
vmseq_vi(v0, v0, 0);

View File

@ -104,6 +104,7 @@ define_pd_global(intx, InlineSmallCode, 1000);
product(bool, UseZbb, false, DIAGNOSTIC, "Use Zbb instructions") \
product(bool, UseZbs, false, DIAGNOSTIC, "Use Zbs instructions") \
product(bool, UseZfh, false, DIAGNOSTIC, "Use Zfh instructions") \
product(bool, UseZfhmin, false, DIAGNOSTIC, "Use Zfhmin instructions") \
product(bool, UseZacas, false, EXPERIMENTAL, "Use Zacas instructions") \
product(bool, UseZcb, false, EXPERIMENTAL, "Use Zcb instructions") \
product(bool, UseZic64b, false, EXPERIMENTAL, "Use Zic64b instructions") \

View File

@ -5886,7 +5886,7 @@ void MacroAssembler::FLOATCVT##_safe(Register dst, FloatRegister src, Register t
fclass_##FLOATSIG(tmp, src); \
mv(dst, zr); \
/* check if src is NaN */ \
andi(tmp, tmp, fclass_mask::nan); \
andi(tmp, tmp, FClassBits::nan); \
bnez(tmp, done); \
FLOATCVT(dst, src); \
bind(done); \

View File

@ -1918,7 +1918,7 @@ bool Matcher::match_rule_supported(int opcode) {
case Op_ConvHF2F:
case Op_ConvF2HF:
return UseZfh;
return UseZfh || UseZfhmin;
}
return true; // Per default match rules are supported.
@ -7348,7 +7348,7 @@ instruct isInfiniteF_reg_reg(iRegINoSp dst, fRegF src)
format %{ "isInfinite $dst, $src" %}
ins_encode %{
__ fclass_s(as_Register($dst$$reg), as_FloatRegister($src$$reg));
__ andi(as_Register($dst$$reg), as_Register($dst$$reg), Assembler::fclass_mask::inf);
__ andi(as_Register($dst$$reg), as_Register($dst$$reg), Assembler::FClassBits::inf);
__ slt(as_Register($dst$$reg), zr, as_Register($dst$$reg));
%}
@ -7363,7 +7363,7 @@ instruct isInfiniteD_reg_reg(iRegINoSp dst, fRegD src)
format %{ "isInfinite $dst, $src" %}
ins_encode %{
__ fclass_d(as_Register($dst$$reg), as_FloatRegister($src$$reg));
__ andi(as_Register($dst$$reg), as_Register($dst$$reg), Assembler::fclass_mask::inf);
__ andi(as_Register($dst$$reg), as_Register($dst$$reg), Assembler::FClassBits::inf);
__ slt(as_Register($dst$$reg), zr, as_Register($dst$$reg));
%}
@ -7378,7 +7378,7 @@ instruct isFiniteF_reg_reg(iRegINoSp dst, fRegF src)
format %{ "isFinite $dst, $src" %}
ins_encode %{
__ fclass_s(as_Register($dst$$reg), as_FloatRegister($src$$reg));
__ andi(as_Register($dst$$reg), as_Register($dst$$reg), Assembler::fclass_mask::finite);
__ andi(as_Register($dst$$reg), as_Register($dst$$reg), Assembler::FClassBits::finite);
__ slt(as_Register($dst$$reg), zr, as_Register($dst$$reg));
%}
@ -7393,7 +7393,7 @@ instruct isFiniteD_reg_reg(iRegINoSp dst, fRegD src)
format %{ "isFinite $dst, $src" %}
ins_encode %{
__ fclass_d(as_Register($dst$$reg), as_FloatRegister($src$$reg));
__ andi(as_Register($dst$$reg), as_Register($dst$$reg), Assembler::fclass_mask::finite);
__ andi(as_Register($dst$$reg), as_Register($dst$$reg), Assembler::FClassBits::finite);
__ slt(as_Register($dst$$reg), zr, as_Register($dst$$reg));
%}

View File

@ -115,6 +115,7 @@ class VM_Version : public Abstract_VM_Version {
// Zbs Single-bit instructions
//
// Zfh Half-Precision Floating-Point instructions
// Zfhmin Minimal Half-Precision Floating-Point instructions
//
// Zicond Conditional operations
//
@ -157,6 +158,7 @@ class VM_Version : public Abstract_VM_Version {
decl(ext_Zbs , "Zbs" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZbs)) \
decl(ext_Zcb , "Zcb" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZcb)) \
decl(ext_Zfh , "Zfh" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZfh)) \
decl(ext_Zfhmin , "Zfhmin" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZfhmin)) \
decl(ext_Zicsr , "Zicsr" , RV_NO_FLAG_BIT, true , NO_UPDATE_DEFAULT) \
decl(ext_Zicntr , "Zicntr" , RV_NO_FLAG_BIT, true , NO_UPDATE_DEFAULT) \
decl(ext_Zifencei , "Zifencei" , RV_NO_FLAG_BIT, true , NO_UPDATE_DEFAULT) \
@ -224,6 +226,7 @@ class VM_Version : public Abstract_VM_Version {
RV_ENABLE_EXTENSION(UseZbb) \
RV_ENABLE_EXTENSION(UseZbs) \
RV_ENABLE_EXTENSION(UseZcb) \
RV_ENABLE_EXTENSION(UseZfhmin) \
RV_ENABLE_EXTENSION(UseZic64b) \
RV_ENABLE_EXTENSION(UseZicbom) \
RV_ENABLE_EXTENSION(UseZicbop) \

View File

@ -177,6 +177,9 @@ void RiscvHwprobe::add_features_from_query_result() {
if (is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_EXT_ZFH)) {
VM_Version::ext_Zfh.enable_feature();
}
if (is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_EXT_ZFHMIN)) {
VM_Version::ext_Zfhmin.enable_feature();
}
if (is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_EXT_ZVBC)) {
VM_Version::ext_Zvbc.enable_feature();
}