@samitouri / QOSamiQemu / commits / 055b0d88ee

target/riscv: Set mstatus.FS dirty when scalar FP raises exceptions

According to the RISC-V privileged spec 3.1.6, any instruction that modifies FP extension state (FP CSRs including fflags, or f registers) must set mstatus.FS to Dirty. Raising fflags bits is modifying fcsr (an FP CSR). Scalar FP instructions that write integer registers (FP comparisons and FP-to-integer conversions) never call mark_fs_dirty at translation time to set mstatus.FS to dirty. However, they can raise FP exception flags via softfloat functions, which modifies fflags without any mechanism to dirty mstatus.FS. The affected helpers: - Comparisons: fle/fleq/flt/fltq/feq — raise NV on NaN operands - FP-to-integer: fcvt.[w|wu|l|lu]/fcvtmod.w.d — raise NX on inexact or NV on out-of-range Fix this issue by 1. Save float_exception_flags before the softfloat operation 2. Perform the operation 3. If any new exception bits are set, set fs to dirty Signed-off-by: Max Chou <max.chou@sifive.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-ID: <20260611105037.157773-2-max.chou@sifive.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>

Max Chou committed Jun 11, 2026 at 18:50 UTC 055b0d88eee38e823f10c60569d6a60ee7ccd68d
2 files changed +130 -28
target/riscv/cpu.h
+1
@@ -676,6 +676,7 @@ G_NORETURN void riscv_raise_exception(CPURISCVState *env,
676
677 uint8_t riscv_cpu_get_fflags(CPURISCVState *env);
678 void riscv_cpu_set_fflags(CPURISCVState *env, uint8_t);
679 +void riscv_cpu_check_fflags(CPURISCVState *env, FloatExceptionFlags);
680
681 #ifndef CONFIG_USER_ONLY
682 void cpu_set_exception_base(int vp_index, uint64_t address);
target/riscv/fpu_helper.c
+129 -28
@@ -50,6 +50,22 @@ void riscv_cpu_set_fflags(CPURISCVState *env, uint8_t hard)
50 set_float_exception_flags(soft, &env->fp_status);
51 }
52
53 +#ifndef CONFIG_USER_ONLY
54 +void riscv_cpu_check_fflags(CPURISCVState *env,
55 + FloatExceptionFlags pre_fflag)
56 +{
57 + if (get_float_exception_flags(&env->fp_status) & ~pre_fflag) {
58 + env->mstatus |= MSTATUS_FS;
59 + if (env->virt_enabled) {
60 + env->mstatus_hs |= MSTATUS_FS;
61 + }
62 + }
63 +}
64 +#else
65 +void riscv_cpu_check_fflags(CPURISCVState *env,
66 + FloatExceptionFlags pre_fflag) {}
67 +#endif
68 +
69 void helper_set_rounding_mode(CPURISCVState *env, uint32_t rm)
70 {
71 FloatRoundMode softrm;
@@ -286,59 +302,86 @@ target_ulong helper_fle_s(CPURISCVState *env, uint64_t rs1, uint64_t rs2)
302 {
303 float32 frs1 = check_nanbox_s(env, rs1);
304 float32 frs2 = check_nanbox_s(env, rs2);
289 - return float32_le(frs1, frs2, &env->fp_status);
305 + FloatExceptionFlags pre_fflag = get_float_exception_flags(&env->fp_status);
306 + target_ulong ret = float32_le(frs1, frs2, &env->fp_status);
307 + riscv_cpu_check_fflags(env, pre_fflag);
308 + return ret;
309 }
310
311 target_ulong helper_fleq_s(CPURISCVState *env, uint64_t rs1, uint64_t rs2)
312 {
313 float32 frs1 = check_nanbox_s(env, rs1);
314 float32 frs2 = check_nanbox_s(env, rs2);
296 - return float32_le_quiet(frs1, frs2, &env->fp_status);
315 + FloatExceptionFlags pre_fflag = get_float_exception_flags(&env->fp_status);
316 + target_ulong ret = float32_le_quiet(frs1, frs2, &env->fp_status);
317 + riscv_cpu_check_fflags(env, pre_fflag);
318 + return ret;
319 }
320
321 target_ulong helper_flt_s(CPURISCVState *env, uint64_t rs1, uint64_t rs2)
322 {
323 float32 frs1 = check_nanbox_s(env, rs1);
324 float32 frs2 = check_nanbox_s(env, rs2);
303 - return float32_lt(frs1, frs2, &env->fp_status);
325 + FloatExceptionFlags pre_fflag = get_float_exception_flags(&env->fp_status);
326 + target_ulong ret = float32_lt(frs1, frs2, &env->fp_status);
327 + riscv_cpu_check_fflags(env, pre_fflag);
328 + return ret;
329 }
330
331 target_ulong helper_fltq_s(CPURISCVState *env, uint64_t rs1, uint64_t rs2)
332 {
333 float32 frs1 = check_nanbox_s(env, rs1);
334 float32 frs2 = check_nanbox_s(env, rs2);
310 - return float32_lt_quiet(frs1, frs2, &env->fp_status);
335 + FloatExceptionFlags pre_fflag = get_float_exception_flags(&env->fp_status);
336 + target_ulong ret = float32_lt_quiet(frs1, frs2, &env->fp_status);
337 + riscv_cpu_check_fflags(env, pre_fflag);
338 + return ret;
339 }
340
341 target_ulong helper_feq_s(CPURISCVState *env, uint64_t rs1, uint64_t rs2)
342 {
343 float32 frs1 = check_nanbox_s(env, rs1);
344 float32 frs2 = check_nanbox_s(env, rs2);
317 - return float32_eq_quiet(frs1, frs2, &env->fp_status);
345 + FloatExceptionFlags pre_fflag = get_float_exception_flags(&env->fp_status);
346 + target_ulong ret = float32_eq_quiet(frs1, frs2, &env->fp_status);
347 + riscv_cpu_check_fflags(env, pre_fflag);
348 + return ret;
349 }
350
351 target_ulong helper_fcvt_w_s(CPURISCVState *env, uint64_t rs1)
352 {
353 float32 frs1 = check_nanbox_s(env, rs1);
323 - return float32_to_int32(frs1, &env->fp_status);
354 + FloatExceptionFlags pre_fflag = get_float_exception_flags(&env->fp_status);
355 + target_ulong ret = float32_to_int32(frs1, &env->fp_status);
356 + riscv_cpu_check_fflags(env, pre_fflag);
357 + return ret;
358 }
359
360 target_ulong helper_fcvt_wu_s(CPURISCVState *env, uint64_t rs1)
361 {
362 float32 frs1 = check_nanbox_s(env, rs1);
329 - return (int32_t)float32_to_uint32(frs1, &env->fp_status);
363 + FloatExceptionFlags pre_fflag = get_float_exception_flags(&env->fp_status);
364 + target_ulong ret = (int32_t)float32_to_uint32(frs1, &env->fp_status);
365 + riscv_cpu_check_fflags(env, pre_fflag);
366 + return ret;
367 }
368
369 target_ulong helper_fcvt_l_s(CPURISCVState *env, uint64_t rs1)
370 {
371 float32 frs1 = check_nanbox_s(env, rs1);
335 - return float32_to_int64(frs1, &env->fp_status);
372 + FloatExceptionFlags pre_fflag = get_float_exception_flags(&env->fp_status);
373 + target_ulong ret = float32_to_int64(frs1, &env->fp_status);
374 + riscv_cpu_check_fflags(env, pre_fflag);
375 + return ret;
376 }
377
378 target_ulong helper_fcvt_lu_s(CPURISCVState *env, uint64_t rs1)
379 {
380 float32 frs1 = check_nanbox_s(env, rs1);
341 - return float32_to_uint64(frs1, &env->fp_status);
381 + FloatExceptionFlags pre_fflag = get_float_exception_flags(&env->fp_status);
382 + target_ulong ret = float32_to_uint64(frs1, &env->fp_status);
383 + riscv_cpu_check_fflags(env, pre_fflag);
384 + return ret;
385 }
386
387 uint64_t helper_fcvt_s_w(CPURISCVState *env, target_ulong rs1)
@@ -453,52 +496,83 @@ uint64_t helper_fsqrt_d(CPURISCVState *env, uint64_t frs1)
496
497 target_ulong helper_fle_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
498 {
456 - return float64_le(frs1, frs2, &env->fp_status);
499 + FloatExceptionFlags pre_fflag = get_float_exception_flags(&env->fp_status);
500 + target_ulong ret = float64_le(frs1, frs2, &env->fp_status);
501 + riscv_cpu_check_fflags(env, pre_fflag);
502 + return ret;
503 }
504
505 target_ulong helper_fleq_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
506 {
461 - return float64_le_quiet(frs1, frs2, &env->fp_status);
507 + FloatExceptionFlags pre_fflag = get_float_exception_flags(&env->fp_status);
508 + target_ulong ret = float64_le_quiet(frs1, frs2, &env->fp_status);
509 + riscv_cpu_check_fflags(env, pre_fflag);
510 + return ret;
511 }
512
513 target_ulong helper_flt_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
514 {
466 - return float64_lt(frs1, frs2, &env->fp_status);
515 + FloatExceptionFlags pre_fflag = get_float_exception_flags(&env->fp_status);
516 + target_ulong ret = float64_lt(frs1, frs2, &env->fp_status);
517 + riscv_cpu_check_fflags(env, pre_fflag);
518 + return ret;
519 }
520
521 target_ulong helper_fltq_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
522 {
471 - return float64_lt_quiet(frs1, frs2, &env->fp_status);
523 + FloatExceptionFlags pre_fflag = get_float_exception_flags(&env->fp_status);
524 + target_ulong ret = float64_lt_quiet(frs1, frs2, &env->fp_status);
525 + riscv_cpu_check_fflags(env, pre_fflag);
526 + return ret;
527 }
528
529 target_ulong helper_feq_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
530 {
476 - return float64_eq_quiet(frs1, frs2, &env->fp_status);
531 + FloatExceptionFlags pre_fflag = get_float_exception_flags(&env->fp_status);
532 + target_ulong ret = float64_eq_quiet(frs1, frs2, &env->fp_status);
533 + riscv_cpu_check_fflags(env, pre_fflag);
534 + return ret;
535 }
536
537 target_ulong helper_fcvt_w_d(CPURISCVState *env, uint64_t frs1)
538 {
481 - return float64_to_int32(frs1, &env->fp_status);
539 + FloatExceptionFlags pre_fflag = get_float_exception_flags(&env->fp_status);
540 + target_ulong ret = float64_to_int32(frs1, &env->fp_status);
541 + riscv_cpu_check_fflags(env, pre_fflag);
542 + return ret;
543 }
544
545 uint64_t helper_fcvtmod_w_d(CPURISCVState *env, uint64_t value)
546 {
486 - return float64_to_int32_modulo(value, float_round_to_zero, &env->fp_status);
547 + FloatExceptionFlags pre_fflag = get_float_exception_flags(&env->fp_status);
548 + uint64_t ret = float64_to_int32_modulo(value, float_round_to_zero,
549 + &env->fp_status);
550 + riscv_cpu_check_fflags(env, pre_fflag);
551 + return ret;
552 }
553
554 target_ulong helper_fcvt_wu_d(CPURISCVState *env, uint64_t frs1)
555 {
491 - return (int32_t)float64_to_uint32(frs1, &env->fp_status);
556 + FloatExceptionFlags pre_fflag = get_float_exception_flags(&env->fp_status);
557 + target_ulong ret = (int32_t)float64_to_uint32(frs1, &env->fp_status);
558 + riscv_cpu_check_fflags(env, pre_fflag);
559 + return ret;
560 }
561
562 target_ulong helper_fcvt_l_d(CPURISCVState *env, uint64_t frs1)
563 {
496 - return float64_to_int64(frs1, &env->fp_status);
564 + FloatExceptionFlags pre_fflag = get_float_exception_flags(&env->fp_status);
565 + target_ulong ret = float64_to_int64(frs1, &env->fp_status);
566 + riscv_cpu_check_fflags(env, pre_fflag);
567 + return ret;
568 }
569
570 target_ulong helper_fcvt_lu_d(CPURISCVState *env, uint64_t frs1)
571 {
501 - return float64_to_uint64(frs1, &env->fp_status);
572 + FloatExceptionFlags pre_fflag = get_float_exception_flags(&env->fp_status);
573 + target_ulong ret = float64_to_uint64(frs1, &env->fp_status);
574 + riscv_cpu_check_fflags(env, pre_fflag);
575 + return ret;
576 }
577
578 uint64_t helper_fcvt_d_w(CPURISCVState *env, target_ulong rs1)
@@ -619,35 +693,50 @@ target_ulong helper_fle_h(CPURISCVState *env, uint64_t rs1, uint64_t rs2)
693 {
694 float16 frs1 = check_nanbox_h(env, rs1);
695 float16 frs2 = check_nanbox_h(env, rs2);
622 - return float16_le(frs1, frs2, &env->fp_status);
696 + FloatExceptionFlags pre_fflag = get_float_exception_flags(&env->fp_status);
697 + target_ulong ret = float16_le(frs1, frs2, &env->fp_status);
698 + riscv_cpu_check_fflags(env, pre_fflag);
699 + return ret;
700 }
701
702 target_ulong helper_fleq_h(CPURISCVState *env, uint64_t rs1, uint64_t rs2)
703 {
704 float16 frs1 = check_nanbox_h(env, rs1);
705 float16 frs2 = check_nanbox_h(env, rs2);
629 - return float16_le_quiet(frs1, frs2, &env->fp_status);
706 + FloatExceptionFlags pre_fflag = get_float_exception_flags(&env->fp_status);
707 + target_ulong ret = float16_le_quiet(frs1, frs2, &env->fp_status);
708 + riscv_cpu_check_fflags(env, pre_fflag);
709 + return ret;
710 }
711
712 target_ulong helper_flt_h(CPURISCVState *env, uint64_t rs1, uint64_t rs2)
713 {
714 float16 frs1 = check_nanbox_h(env, rs1);
715 float16 frs2 = check_nanbox_h(env, rs2);
636 - return float16_lt(frs1, frs2, &env->fp_status);
716 + FloatExceptionFlags pre_fflag = get_float_exception_flags(&env->fp_status);
717 + target_ulong ret = float16_lt(frs1, frs2, &env->fp_status);
718 + riscv_cpu_check_fflags(env, pre_fflag);
719 + return ret;
720 }
721
722 target_ulong helper_fltq_h(CPURISCVState *env, uint64_t rs1, uint64_t rs2)
723 {
724 float16 frs1 = check_nanbox_h(env, rs1);
725 float16 frs2 = check_nanbox_h(env, rs2);
643 - return float16_lt_quiet(frs1, frs2, &env->fp_status);
726 + FloatExceptionFlags pre_fflag = get_float_exception_flags(&env->fp_status);
727 + target_ulong ret = float16_lt_quiet(frs1, frs2, &env->fp_status);
728 + riscv_cpu_check_fflags(env, pre_fflag);
729 + return ret;
730 }
731
732 target_ulong helper_feq_h(CPURISCVState *env, uint64_t rs1, uint64_t rs2)
733 {
734 float16 frs1 = check_nanbox_h(env, rs1);
735 float16 frs2 = check_nanbox_h(env, rs2);
650 - return float16_eq_quiet(frs1, frs2, &env->fp_status);
736 + FloatExceptionFlags pre_fflag = get_float_exception_flags(&env->fp_status);
737 + target_ulong ret = float16_eq_quiet(frs1, frs2, &env->fp_status);
738 + riscv_cpu_check_fflags(env, pre_fflag);
739 + return ret;
740 }
741
742 target_ulong helper_fclass_h(CPURISCVState *env, uint64_t rs1)
@@ -683,25 +772,37 @@ uint64_t helper_froundnx_h(CPURISCVState *env, uint64_t rs1)
772 target_ulong helper_fcvt_w_h(CPURISCVState *env, uint64_t rs1)
773 {
774 float16 frs1 = check_nanbox_h(env, rs1);
686 - return float16_to_int32(frs1, &env->fp_status);
775 + FloatExceptionFlags pre_fflag = get_float_exception_flags(&env->fp_status);
776 + target_ulong ret = float16_to_int32(frs1, &env->fp_status);
777 + riscv_cpu_check_fflags(env, pre_fflag);
778 + return ret;
779 }
780
781 target_ulong helper_fcvt_wu_h(CPURISCVState *env, uint64_t rs1)
782 {
783 float16 frs1 = check_nanbox_h(env, rs1);
692 - return (int32_t)float16_to_uint32(frs1, &env->fp_status);
784 + FloatExceptionFlags pre_fflag = get_float_exception_flags(&env->fp_status);
785 + target_ulong ret = (int32_t)float16_to_uint32(frs1, &env->fp_status);
786 + riscv_cpu_check_fflags(env, pre_fflag);
787 + return ret;
788 }
789
790 target_ulong helper_fcvt_l_h(CPURISCVState *env, uint64_t rs1)
791 {
792 float16 frs1 = check_nanbox_h(env, rs1);
698 - return float16_to_int64(frs1, &env->fp_status);
793 + FloatExceptionFlags pre_fflag = get_float_exception_flags(&env->fp_status);
794 + target_ulong ret = float16_to_int64(frs1, &env->fp_status);
795 + riscv_cpu_check_fflags(env, pre_fflag);
796 + return ret;
797 }
798
799 target_ulong helper_fcvt_lu_h(CPURISCVState *env, uint64_t rs1)
800 {
801 float16 frs1 = check_nanbox_h(env, rs1);
704 - return float16_to_uint64(frs1, &env->fp_status);
802 + FloatExceptionFlags pre_fflag = get_float_exception_flags(&env->fp_status);
803 + target_ulong ret = float16_to_uint64(frs1, &env->fp_status);
804 + riscv_cpu_check_fflags(env, pre_fflag);
805 + return ret;
806 }
807
808 uint64_t helper_fcvt_h_w(CPURISCVState *env, target_ulong rs1)