From a49b011c01557bfb9c21474331438ccc13e8e8ef Mon Sep 17 00:00:00 2001 From: wangyang Date: Sun, 6 Sep 2026 14:37:45 +0800 Subject: [PATCH] riscv: resolve frm for dynamic rounding of fcvt float-to-int --- src/cpu/riscv_fpu.c | 23 ++++++++++++----------- src/util/fpu_lib.c | 10 ++-------- 2 files changed, 14 insertions(+), 19 deletions(-) diff --git a/src/cpu/riscv_fpu.c b/src/cpu/riscv_fpu.c index aa2daa341..0e3729653 100644 --- a/src/cpu/riscv_fpu.c +++ b/src/cpu/riscv_fpu.c @@ -124,12 +124,13 @@ static slow_path void riscv_emulate_f_opc_op_impl(rvvm_hart_t* vm, const uint32_ { const size_t rds = bit_ext_u32(insn, 7, 5); const uint32_t rm = bit_ext_u32(insn, 12, 3); + const uint32_t eff_rm = (rm == RM_DYN) ? bit_cut(vm->csr.fcsr, 5, 3) : rm; const size_t rs1 = bit_ext_u32(insn, 15, 5); const size_t rs2 = bit_ext_u32(insn, 20, 5); if (likely(riscv_fpu_is_enabled(vm))) { - if (unlikely(((rm == 0x07) ? vm->csr.fcsr >> 5 : rm) == 0x04)) { + if (unlikely(eff_rm == RM_RMM)) { // Handle RMM rounding in the effective mode: a static rmm field // behaves exactly like frm == RMM riscv_prepare_rmm(vm, insn, rs1, rs2); @@ -185,7 +186,7 @@ static slow_path void riscv_emulate_f_opc_op_impl(rvvm_hart_t* vm, const uint32_ return; case 0x04: // fround.s (Zfa) case 0x05: // TODO: froundx.s (Zfa) - riscv_emit_s(vm, rds, fpu_fcvt_i64_to_f32(fpu_round_f32_to_i64(riscv_read_s(vm, rs1), rm))); + riscv_emit_s(vm, rds, fpu_fcvt_i64_to_f32(fpu_round_f32_to_i64(riscv_read_s(vm, rs1), eff_rm))); return; } break; @@ -196,27 +197,27 @@ static slow_path void riscv_emulate_f_opc_op_impl(rvvm_hart_t* vm, const uint32_ return; case 0x04: // fround.s (Zfa) case 0x05: // TODO: froundx.s (Zfa) - riscv_emit_d(vm, rds, fpu_fcvt_i64_to_f64(fpu_round_f64_to_i64(riscv_view_d(vm, rs1), rm))); + riscv_emit_d(vm, rds, fpu_fcvt_i64_to_f64(fpu_round_f64_to_i64(riscv_view_d(vm, rs1), eff_rm))); return; } break; case RISCV_FPU_GEN_RM_CASES(0xC0000000UL): switch (rs2) { case 0x00: // fcvt.w.s - riscv_write_reg(vm, rds, (int32_t)fpu_round_f32_to_i32(riscv_read_s(vm, rs1), rm)); + riscv_write_reg(vm, rds, (int32_t)fpu_round_f32_to_i32(riscv_read_s(vm, rs1), eff_rm)); return; case 0x01: // fcvt.wu.s - riscv_write_reg(vm, rds, (int32_t)fpu_round_f32_to_u32(riscv_read_s(vm, rs1), rm)); + riscv_write_reg(vm, rds, (int32_t)fpu_round_f32_to_u32(riscv_read_s(vm, rs1), eff_rm)); return; case 0x02: // fcvt.l.s if (likely(vm->rv64)) { - riscv_write_reg(vm, rds, (int64_t)fpu_round_f32_to_i64(riscv_read_s(vm, rs1), rm)); + riscv_write_reg(vm, rds, (int64_t)fpu_round_f32_to_i64(riscv_read_s(vm, rs1), eff_rm)); return; } break; case 0x03: // fcvt.lu.s if (likely(vm->rv64)) { - riscv_write_reg(vm, rds, (int64_t)fpu_round_f32_to_u64(riscv_read_s(vm, rs1), rm)); + riscv_write_reg(vm, rds, (int64_t)fpu_round_f32_to_u64(riscv_read_s(vm, rs1), eff_rm)); return; } break; @@ -225,20 +226,20 @@ static slow_path void riscv_emulate_f_opc_op_impl(rvvm_hart_t* vm, const uint32_ case RISCV_FPU_GEN_RM_CASES(0xC2000000UL): switch (rs2) { case 0x00: // fcvt.w.d - riscv_write_reg(vm, rds, (int32_t)fpu_round_f64_to_i32(riscv_view_d(vm, rs1), rm)); + riscv_write_reg(vm, rds, (int32_t)fpu_round_f64_to_i32(riscv_view_d(vm, rs1), eff_rm)); return; case 0x01: // fcvt.wu.d - riscv_write_reg(vm, rds, (int32_t)fpu_round_f64_to_u32(riscv_view_d(vm, rs1), rm)); + riscv_write_reg(vm, rds, (int32_t)fpu_round_f64_to_u32(riscv_view_d(vm, rs1), eff_rm)); return; case 0x02: // fcvt.l.d if (likely(vm->rv64)) { - riscv_write_reg(vm, rds, (int64_t)fpu_round_f64_to_i64(riscv_view_d(vm, rs1), rm)); + riscv_write_reg(vm, rds, (int64_t)fpu_round_f64_to_i64(riscv_view_d(vm, rs1), eff_rm)); return; } break; case 0x03: // fcvt.lu.d if (likely(vm->rv64)) { - riscv_write_reg(vm, rds, (int64_t)fpu_round_f64_to_u64(riscv_view_d(vm, rs1), rm)); + riscv_write_reg(vm, rds, (int64_t)fpu_round_f64_to_u64(riscv_view_d(vm, rs1), eff_rm)); return; } break; diff --git a/src/util/fpu_lib.c b/src/util/fpu_lib.c index 9d39191bf..b389a6da3 100644 --- a/src/util/fpu_lib.c +++ b/src/util/fpu_lib.c @@ -407,8 +407,8 @@ slow_path uint32_t fpu_fclass64(fpu_f64_t d) /* * Round to an integral value directly on the encoding: no host FP arithmetic, so - * no spurious exception flags and no double rounding. Only DYN falls back to the - * tracked mode; an explicit RMM request is honored as-is. + * no spurious exception flags and no double rounding. The caller resolves RM_DYN + * to the guest frm before calling, so mode is never RM_DYN and RMM is honored. */ slow_path fpu_f32_t fpu_round_f32_internal(fpu_f32_t f, uint32_t mode) { @@ -416,9 +416,6 @@ slow_path fpu_f32_t fpu_round_f32_internal(fpu_f32_t f, uint32_t mode) const uint32_t s = u & FPU_LIB_FP32_SIGNEDFP_MASK; const int32_t e = fpu_exponent32(f); bool away = false; - if (unlikely(mode > FPU_LIB_ROUND_MM)) { - mode = fpu_get_rounding_mode(); - } if (e >= 23 || !(u << 1)) { return f; // Already integral: |f| >= 2^23, +/-0, inf, NaN } @@ -476,9 +473,6 @@ slow_path fpu_f64_t fpu_round_f64_internal(fpu_f64_t d, uint32_t mode) const uint64_t s = u & FPU_LIB_FP64_SIGNEDFP_MASK; const int32_t e = fpu_exponent64(d); bool away = false; - if (unlikely(mode > FPU_LIB_ROUND_MM)) { - mode = fpu_get_rounding_mode(); - } if (e >= 52 || !(u << 1)) { return d; // Already integral: |d| >= 2^52, +/-0, inf, NaN }