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

Reply via email to