Skip to content

Commit

Permalink
Fix rounding mode selection
Browse files Browse the repository at this point in the history
Some F extension instructions include an rm field, indicating the
rounding mode to be used. When an instruction has an rm field, the
rounding mode should be chosen based on the value of that field. If the
rm field is set to 0b111, it signifies dynamic selection of the
rounding mode based on the fcsr's frm field.

The current implementation always selected the rounding mode
dynamically based on fcsr's frm, regardless of the rm field in the
instruction. This patch corrects this error, ensuring that the rounding
mode is now chosen according to the rm field when present.
  • Loading branch information
visitorckw committed Jan 6, 2024
1 parent 664f90d commit 9239652
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 22 deletions.
11 changes: 6 additions & 5 deletions src/decode.c
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,7 @@ static inline void decode_r4type(rv_insn_t *ir, const uint32_t insn)
ir->rs1 = decode_rs1(insn);
ir->rs2 = decode_rs2(insn);
ir->rs3 = decode_r4type_rs3(insn);
ir->rm = decode_funct3(insn);
}
#endif

Expand Down Expand Up @@ -1044,7 +1045,7 @@ static inline bool op_op_fp(rv_insn_t *ir, const uint32_t insn)
*/

/* decode R-type */
uint8_t funct3 = decode_funct3(insn);
ir->rm = decode_funct3(insn);
decode_rtype(ir, insn);

/* dispatch from funct7 field */
Expand All @@ -1066,7 +1067,7 @@ static inline bool op_op_fp(rv_insn_t *ir, const uint32_t insn)
break;
case 0b0010000:
/* dispatch from rm region */
switch (funct3) {
switch (ir->rm) {
case 0b000: /* FSGNJ.S */
ir->opcode = rv_insn_fsgnjs;
break;
Expand All @@ -1093,7 +1094,7 @@ static inline bool op_op_fp(rv_insn_t *ir, const uint32_t insn)
break;
case 0b0010100:
/* dispatch from rm region */
switch (funct3) {
switch (ir->rm) {
case 0b000: /* FMIN.S */
ir->opcode = rv_insn_fmins;
break;
Expand All @@ -1106,7 +1107,7 @@ static inline bool op_op_fp(rv_insn_t *ir, const uint32_t insn)
break;
case 0b1110000:
/* dispatch from rm region */
switch (funct3) {
switch (ir->rm) {
case 0b000: /* FMV.X.W */
ir->opcode = rv_insn_fmvxw;
break;
Expand All @@ -1119,7 +1120,7 @@ static inline bool op_op_fp(rv_insn_t *ir, const uint32_t insn)
break;
case 0b1010000:
/* dispatch from rm region */
switch (funct3) {
switch (ir->rm) {
case 0b010: /* FEQ.S */
ir->opcode = rv_insn_feqs;
break;
Expand Down
5 changes: 5 additions & 0 deletions src/decode.h
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,11 @@ typedef struct rv_insn {
#if RV32_HAS(EXT_C)
uint8_t shamt;
#endif

#if RV32_HAS(EXT_F)
uint8_t rm;
#endif

/* fuse operation */
int32_t imm2;
opcode_fuse_t *fuse;
Expand Down
71 changes: 55 additions & 16 deletions src/rv32_template.c
Original file line number Diff line number Diff line change
Expand Up @@ -1413,7 +1413,10 @@ RVOP(
RVOP(
fmadds,
{
set_rounding_mode(rv);
if (likely(ir->rm == 0b111))
set_dynamic_rounding_mode(rv);
else
set_static_rounding_mode(ir->rm);
rv->F[ir->rd] =
f32_mulAdd(rv->F[ir->rs1], rv->F[ir->rs2], rv->F[ir->rs3]);
set_fflag(rv);
Expand All @@ -1426,7 +1429,10 @@ RVOP(
RVOP(
fmsubs,
{
set_rounding_mode(rv);
if (likely(ir->rm == 0b111))
set_dynamic_rounding_mode(rv);
else
set_static_rounding_mode(ir->rm);
riscv_float_t tmp = rv->F[ir->rs3];
tmp.v ^= FMASK_SIGN;
rv->F[ir->rd] = f32_mulAdd(rv->F[ir->rs1], rv->F[ir->rs2], tmp);
Expand All @@ -1440,7 +1446,10 @@ RVOP(
RVOP(
fnmsubs,
{
set_rounding_mode(rv);
if (likely(ir->rm == 0b111))
set_dynamic_rounding_mode(rv);
else
set_static_rounding_mode(ir->rm);
riscv_float_t tmp = rv->F[ir->rs1];
tmp.v ^= FMASK_SIGN;
rv->F[ir->rd] = f32_mulAdd(tmp, rv->F[ir->rs2], rv->F[ir->rs3]);
Expand All @@ -1454,7 +1463,10 @@ RVOP(
RVOP(
fnmadds,
{
set_rounding_mode(rv);
if (likely(ir->rm == 0b111))
set_dynamic_rounding_mode(rv);
else
set_static_rounding_mode(ir->rm);
riscv_float_t tmp1 = rv->F[ir->rs1];
riscv_float_t tmp2 = rv->F[ir->rs3];
tmp1.v ^= FMASK_SIGN;
Expand All @@ -1470,7 +1482,10 @@ RVOP(
RVOP(
fadds,
{
set_rounding_mode(rv);
if (likely(ir->rm == 0b111))
set_dynamic_rounding_mode(rv);
else
set_static_rounding_mode(ir->rm);
rv->F[ir->rd] = f32_add(rv->F[ir->rs1], rv->F[ir->rs2]);
set_fflag(rv);
},
Expand All @@ -1482,7 +1497,10 @@ RVOP(
RVOP(
fsubs,
{
set_rounding_mode(rv);
if (likely(ir->rm == 0b111))
set_dynamic_rounding_mode(rv);
else
set_static_rounding_mode(ir->rm);
rv->F[ir->rd] = f32_sub(rv->F[ir->rs1], rv->F[ir->rs2]);
set_fflag(rv);
},
Expand All @@ -1494,7 +1512,10 @@ RVOP(
RVOP(
fmuls,
{
set_rounding_mode(rv);
if (likely(ir->rm == 0b111))
set_dynamic_rounding_mode(rv);
else
set_static_rounding_mode(ir->rm);
rv->F[ir->rd] = f32_mul(rv->F[ir->rs1], rv->F[ir->rs2]);
set_fflag(rv);
},
Expand All @@ -1506,7 +1527,10 @@ RVOP(
RVOP(
fdivs,
{
set_rounding_mode(rv);
if (likely(ir->rm == 0b111))
set_dynamic_rounding_mode(rv);
else
set_static_rounding_mode(ir->rm);
rv->F[ir->rd] = f32_div(rv->F[ir->rs1], rv->F[ir->rs2]);
set_fflag(rv);
},
Expand All @@ -1518,7 +1542,10 @@ RVOP(
RVOP(
fsqrts,
{
set_rounding_mode(rv);
if (likely(ir->rm == 0b111))
set_dynamic_rounding_mode(rv);
else
set_static_rounding_mode(ir->rm);
rv->F[ir->rd] = f32_sqrt(rv->F[ir->rs1]);
set_fflag(rv);
},
Expand Down Expand Up @@ -1611,7 +1638,10 @@ RVOP(
RVOP(
fcvtws,
{
set_rounding_mode(rv);
if (likely(ir->rm == 0b111))
set_dynamic_rounding_mode(rv);
else
set_static_rounding_mode(ir->rm);
uint32_t ret = f32_to_i32(rv->F[ir->rs1], softfloat_roundingMode, true);
if (ir->rd)
rv->X[ir->rd] = ret;
Expand All @@ -1625,7 +1655,10 @@ RVOP(
RVOP(
fcvtwus,
{
set_rounding_mode(rv);
if (likely(ir->rm == 0b111))
set_dynamic_rounding_mode(rv);
else
set_static_rounding_mode(ir->rm);
uint32_t ret =
f32_to_ui32(rv->F[ir->rs1], softfloat_roundingMode, true);
if (ir->rd)
Expand Down Expand Up @@ -1653,7 +1686,7 @@ RVOP(
RVOP(
feqs,
{
set_rounding_mode(rv);
set_dynamic_rounding_mode(rv);
uint32_t ret = f32_eq(rv->F[ir->rs1], rv->F[ir->rs2]);
if (ir->rd)
rv->X[ir->rd] = ret;
Expand All @@ -1670,7 +1703,7 @@ RVOP(
RVOP(
flts,
{
set_rounding_mode(rv);
set_dynamic_rounding_mode(rv);
uint32_t ret = f32_lt(rv->F[ir->rs1], rv->F[ir->rs2]);
if (ir->rd)
rv->X[ir->rd] = ret;
Expand All @@ -1683,7 +1716,7 @@ RVOP(
RVOP(
fles,
{
set_rounding_mode(rv);
set_dynamic_rounding_mode(rv);
uint32_t ret = f32_le(rv->F[ir->rs1], rv->F[ir->rs2]);
if (ir->rd)
rv->X[ir->rd] = ret;
Expand All @@ -1708,7 +1741,10 @@ RVOP(
RVOP(
fcvtsw,
{
set_rounding_mode(rv);
if (likely(ir->rm == 0b111))
set_dynamic_rounding_mode(rv);
else
set_static_rounding_mode(ir->rm);
rv->F[ir->rd] = i32_to_f32(rv->X[ir->rs1]);
set_fflag(rv);
},
Expand All @@ -1720,7 +1756,10 @@ RVOP(
RVOP(
fcvtswu,
{
set_rounding_mode(rv);
if (likely(ir->rm == 0b111))
set_dynamic_rounding_mode(rv);
else
set_static_rounding_mode(ir->rm);
rv->F[ir->rd] = ui32_to_f32(rv->X[ir->rs1]);
set_fflag(rv);
},
Expand Down
16 changes: 15 additions & 1 deletion src/softfloat.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ static inline void set_fflag(riscv_t *rv)
softfloat_exceptionFlags = 0;
}

static inline void set_rounding_mode(riscv_t *rv)
static inline void set_dynamic_rounding_mode(riscv_t *rv)
{
uint32_t frm = (rv->csr_fcsr >> 5) & (~(1 << 3));
if (frm == 0b000)
Expand All @@ -115,3 +115,17 @@ static inline void set_rounding_mode(riscv_t *rv)
if (frm == 0b100)
softfloat_roundingMode = softfloat_round_near_maxMag;
}

static inline void set_static_rounding_mode(uint8_t rm)
{
if (rm == 0b000)
softfloat_roundingMode = softfloat_round_near_even;
if (rm == 0b001)
softfloat_roundingMode = softfloat_round_minMag;
if (rm == 0b010)
softfloat_roundingMode = softfloat_round_min;
if (rm == 0b011)
softfloat_roundingMode = softfloat_round_max;
if (rm == 0b100)
softfloat_roundingMode = softfloat_round_near_maxMag;
}

1 comment on commit 9239652

@jserv
Copy link
Contributor

@jserv jserv commented on 9239652 Jan 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Benchmarks

Benchmark suite Current: 9239652 Previous: 194846c Ratio
Dhrystone 1753.66 Average DMIPS over 10 runs 1621.3 Average DMIPS over 10 runs 0.92
Coremark 1472.295 Average iterations/sec over 10 runs 1484.53 Average iterations/sec over 10 runs 1.01

This comment was automatically generated by workflow using github-action-benchmark.

Please sign in to comment.