Commit ea79f8bac1 for qemu.org
commit ea79f8bac125554ae791a9637a94033ecc730f13
Author: Richard Henderson <richard.henderson@linaro.org>
Date: Tue May 19 09:15:31 2026 -0700
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>
diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc
index 559e40d196..d0064f5d22 100644
--- a/fpu/softfloat-parts.c.inc
+++ b/fpu/softfloat-parts.c.inc
@@ -278,11 +278,16 @@ static void partsN(uncanon_e4m3_overflow)(FloatPartsN *p, float_status *s,
const FloatFmt *fmt, bool saturate)
{
assert(N == 64);
+ p->exp = fmt->exp_max;
if (saturate) {
- p->exp = fmt->exp_max;
p->frac_hi = E4M3_NORMAL_FRAC_MAX;
} else {
- *p = partsN(default_nan)(s);
+ /*
+ * The class isn't actually used after this point in uncanon,
+ * but for clarity while debugging, don't leave it set to normal.
+ */
+ p->cls = float_class_qnan;
+ p->frac_hi = E4M3_NAN_FRAC;
}
}
@@ -507,9 +512,24 @@ static void partsN(uncanon)(FloatPartsN *p, float_status *s,
return;
case float_class_qnan:
case float_class_snan:
- assert(fmt->exp_max_kind != float_expmax_normal);
p->exp = fmt->exp_max;
- fracN(shr)(p, fmt->frac_shift);
+ switch (fmt->exp_max_kind) {
+ case float_expmax_e4m3:
+ /*
+ * There is only one NaN encoding for E4M3, and with a
+ * conversion from another format, the input NaN fraction
+ * may not apply.
+ */
+ assert(N == 64);
+ p->frac_hi = E4M3_NAN_FRAC;
+ /* fall through */
+ case float_expmax_ieee:
+ fracN(shr)(p, fmt->frac_shift);
+ break;
+ case float_expmax_normal:
+ default:
+ g_assert_not_reached();
+ }
return;
default:
break;
diff --git a/fpu/softfloat.c b/fpu/softfloat.c
index be6b02d866..2c3bf01213 100644
--- a/fpu/softfloat.c
+++ b/fpu/softfloat.c
@@ -499,6 +499,8 @@ const FloatFmt float8_e4m3_params = {
/* 110 << frac_shift, with the implicit bit set */
#define E4M3_NORMAL_FRAC_MAX 0xe000000000000000ull
+/* 111 << frac_shift, no implicit bit */
+#define E4M3_NAN_FRAC 0x7000000000000000ull
const FloatFmt float8_e5m2_params = {
FLOAT_PARAMS(5, 2)