On Wed, 20 May 2026 at 18:18, Richard Henderson <[email protected]> wrote: > > 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 <[email protected]> > Signed-off-by: Richard Henderson <[email protected]> > --- > fpu/softfloat.c | 2 ++ > fpu/softfloat-parts.c.inc | 29 ++++++++++++++++++++++++----- > 2 files changed, 26 insertions(+), 5 deletions(-) > > 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) > diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc > index 559e40d196..d6687df982 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,10 +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); > - return; > + 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); > + return; > + case float_expmax_normal:
We used to assert() that exp_max_kind wasn't "expmax_normal", but now we don't. What does it mean to have a FloatPartsN that says it's a NaN when the format says there isn't a NaN representation ? Either way, the "break" here means we won't treat it like we do NaNs and we won't treat it like we do normals either... > + break; > + } > + g_assert_not_reached(); > default: > break; > } thanks -- PMM
