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: + break; + } + g_assert_not_reached(); default: break; } -- 2.43.0
