@samitouri / QOSamiQemu / commits / ea79f8bac1

fpu: Fix NaN encoding for E4M3 in parts64_uncanon

There is only one NaN fractional encoding for E4M3. Retain the incoming sign, but force the outgoing fraction to the unique value. Reported-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>

Richard Henderson committed May 19, 2026 at 09:15 UTC ea79f8bac125554ae791a9637a94033ecc730f13
2 files changed +26 -4
fpu/softfloat-parts.c.inc
+24 -4
@@ -278,11 +278,16 @@ static void partsN(uncanon_e4m3_overflow)(FloatPartsN *p, float_status *s,
278 const FloatFmt *fmt, bool saturate)
279 {
280 assert(N == 64);
281 + p->exp = fmt->exp_max;
282 if (saturate) {
282 - p->exp = fmt->exp_max;
283 p->frac_hi = E4M3_NORMAL_FRAC_MAX;
284 } else {
285 - *p = partsN(default_nan)(s);
285 + /*
286 + * The class isn't actually used after this point in uncanon,
287 + * but for clarity while debugging, don't leave it set to normal.
288 + */
289 + p->cls = float_class_qnan;
290 + p->frac_hi = E4M3_NAN_FRAC;
291 }
292 }
293
@@ -507,9 +512,24 @@ static void partsN(uncanon)(FloatPartsN *p, float_status *s,
512 return;
513 case float_class_qnan:
514 case float_class_snan:
510 - assert(fmt->exp_max_kind != float_expmax_normal);
515 p->exp = fmt->exp_max;
512 - fracN(shr)(p, fmt->frac_shift);
516 + switch (fmt->exp_max_kind) {
517 + case float_expmax_e4m3:
518 + /*
519 + * There is only one NaN encoding for E4M3, and with a
520 + * conversion from another format, the input NaN fraction
521 + * may not apply.
522 + */
523 + assert(N == 64);
524 + p->frac_hi = E4M3_NAN_FRAC;
525 + /* fall through */
526 + case float_expmax_ieee:
527 + fracN(shr)(p, fmt->frac_shift);
528 + break;
529 + case float_expmax_normal:
530 + default:
531 + g_assert_not_reached();
532 + }
533 return;
534 default:
535 break;
fpu/softfloat.c
+2
@@ -499,6 +499,8 @@ const FloatFmt float8_e4m3_params = {
499
500 /* 110 << frac_shift, with the implicit bit set */
501 #define E4M3_NORMAL_FRAC_MAX 0xe000000000000000ull
502 +/* 111 << frac_shift, no implicit bit */
503 +#define E4M3_NAN_FRAC 0x7000000000000000ull
504
505 const FloatFmt float8_e5m2_params = {
506 FLOAT_PARAMS(5, 2)