On Mon, Feb 23, 2026 at 07:21:49PM +1100, Richard Henderson wrote:
> Generalize arm_althp to indicate how exp==max should
> be handled for the format.  Reorganize canonicalize
> and uncanon_normal to use a switch statement, allowing
> more cases to be added trivially.
> 
> Signed-off-by: Richard Henderson <[email protected]>
> ---
>  fpu/softfloat.c           | 17 ++++++--
>  fpu/softfloat-parts.c.inc | 92 ++++++++++++++++++++++++---------------
>  2 files changed, 69 insertions(+), 40 deletions(-)
> 
> diff --git a/fpu/softfloat.c b/fpu/softfloat.c
> index 8740975348..8d8e576757 100644
> --- a/fpu/softfloat.c
> +++ b/fpu/softfloat.c
> @@ -522,7 +522,16 @@ typedef struct {
>  #define DECOMPOSED_BINARY_POINT    63
>  #define DECOMPOSED_IMPLICIT_BIT    (1ull << DECOMPOSED_BINARY_POINT)
>  
> -/* Structure holding all of the relevant parameters for a format.
> +/* Format-specific handling of exp == exp_max */
> +typedef enum __attribute__((__packed__)) {
> +    /* exp==max, frac==0 ? infinity : nan; this is ieee standard. */
> +    float_expmax_ieee,
> +    /* exp==max is a normal number; no infinity or nan representation. */
> +    float_expmax_normal,
> +} FloatFmtExpMaxKind;
> +
> +/*
> + * Structure holding all of the relevant parameters for a format.
>   *   exp_size: the size of the exponent field
>   *   exp_bias: the offset applied to the exponent field
>   *   exp_max: the maximum normalised exponent
> @@ -531,7 +540,7 @@ typedef struct {
>   * The following are computed based the size of fraction
>   *   round_mask: bits below lsb which must be rounded
>   * The following optional modifiers are available:
> - *   arm_althp: handle ARM Alternative Half Precision
> + *   exp_max_kind: affects how exp == exp_max is interpreted
>   *   has_explicit_bit: has an explicit integer bit; this affects whether
>   *   the float_status floatx80_behaviour handling applies
>   */
> @@ -542,7 +551,7 @@ typedef struct {
>      int exp_max;
>      int frac_size;
>      int frac_shift;
> -    bool arm_althp;
> +    FloatFmtExpMaxKind exp_max_kind;
>      bool has_explicit_bit;
>      uint64_t round_mask;
>  } FloatFmt;
> @@ -566,7 +575,7 @@ static const FloatFmt float16_params = {
>  
>  static const FloatFmt float16_params_ahp = {
>      FLOAT_PARAMS(5, 10),
> -    .arm_althp = true
> +    .exp_max_kind = float_expmax_normal,
>  };
>  
>  static const FloatFmt bfloat16_params = {
> diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc
> index 79b56014ab..455bbf281e 100644
> --- a/fpu/softfloat-parts.c.inc
> +++ b/fpu/softfloat-parts.c.inc
> @@ -227,18 +227,30 @@ static void partsN(canonicalize)(FloatPartsN *p, 
> float_status *status,
>              p->exp = fmt->frac_shift - fmt->exp_bias
>                     - shift + !has_pseudo_denormals;
>          }
> -    } else if (likely(p->exp < fmt->exp_max) || fmt->arm_althp) {
> -        p->cls = float_class_normal;
> -        p->exp -= fmt->exp_bias;
> -        frac_shl(p, fmt->frac_shift);
> -        p->frac_hi |= DECOMPOSED_IMPLICIT_BIT;
> -    } else if (likely(frac_eqz(p))) {
> -        p->cls = float_class_inf;
> -    } else {
> -        frac_shl(p, fmt->frac_shift);
> -        p->cls = (parts_is_snan_frac(p->frac_hi, status)
> -                  ? float_class_snan : float_class_qnan);
> +        return;
>      }
> +    if (unlikely(p->exp == fmt->exp_max)) {
> +        switch (fmt->exp_max_kind) {
> +        case float_expmax_ieee:
> +            if (likely(frac_eqz(p))) {
> +                p->cls = float_class_inf;
> +            } else {
> +                frac_shl(p, fmt->frac_shift);
> +                p->cls = (parts_is_snan_frac(p->frac_hi, status)
> +                          ? float_class_snan : float_class_qnan);
> +            }
> +            return;
> +        case float_expmax_normal:
> +            break;
> +        default:
> +            g_assert_not_reached();
> +        }
> +    }
> +
> +    p->cls = float_class_normal;
> +    p->exp -= fmt->exp_bias;
> +    frac_shl(p, fmt->frac_shift);
> +    p->frac_hi |= DECOMPOSED_IMPLICIT_BIT;
>  }
>  
>  /*
> @@ -314,29 +326,37 @@ static void partsN(uncanon_normal)(FloatPartsN *p, 
> float_status *s,
>              p->frac_lo &= ~round_mask;
>          }
>  
> -        if (fmt->arm_althp) {
> -            /* ARM Alt HP eschews Inf and NaN for a wider exponent.  */
> -            if (unlikely(exp > exp_max)) {
> -                /* Overflow.  Return the maximum normal.  */
> -                flags = float_flag_invalid;
> -                exp = exp_max;
> -                frac_allones(p);
> -                p->frac_lo &= ~round_mask;
> -            }
> -        } else if (unlikely(exp >= exp_max)) {
> -            flags |= float_flag_overflow;
> -            if (s->rebias_overflow) {
> -                exp -= fmt->exp_re_bias;
> -            } else if (overflow_norm) {
> -                flags |= float_flag_inexact;
> -                exp = exp_max - 1;
> -                frac_allones(p);
> -                p->frac_lo &= ~round_mask;
> -            } else {
> -                flags |= float_flag_inexact;
> -                p->cls = float_class_inf;
> -                exp = exp_max;
> -                frac_clear(p);
> +        if (unlikely(exp >= exp_max)) {
> +            switch (fmt->exp_max_kind) {
> +            case float_expmax_ieee:
> +                flags |= float_flag_overflow;
> +                if (s->rebias_overflow) {
> +                    exp -= fmt->exp_re_bias;
> +                } else if (overflow_norm) {
> +                    flags |= float_flag_inexact;
> +                    exp = exp_max - 1;
> +                    frac_allones(p);
> +                    p->frac_lo &= ~round_mask;
> +                } else {
> +                    flags |= float_flag_inexact;
> +                    p->cls = float_class_inf;
> +                    exp = exp_max;
> +                    frac_clear(p);
> +                }
> +                break;
> +
> +            case float_expmax_normal:
> +                if (unlikely(exp > exp_max)) {
> +                    /* Overflow.  Return the maximum normal.  */
> +                    flags = float_flag_invalid;
> +                    exp = exp_max;
> +                    frac_allones(p);
> +                    p->frac_lo &= ~round_mask;
> +                }
> +                break;
> +
> +            default:
> +                g_assert_not_reached();
>              }
>          }
>          frac_shr(p, frac_shift);
> @@ -434,13 +454,13 @@ static void partsN(uncanon)(FloatPartsN *p, 
> float_status *s,
>              frac_clear(p);
>              return;
>          case float_class_inf:
> -            g_assert(!fmt->arm_althp);
> +            assert(fmt->exp_max_kind == float_expmax_ieee);
>              p->exp = fmt->exp_max;
>              frac_clear(p);
>              return;
>          case float_class_qnan:
>          case float_class_snan:
> -            g_assert(!fmt->arm_althp);
> +            assert(fmt->exp_max_kind != float_expmax_normal);
>              p->exp = fmt->exp_max;
>              frac_shr(p, fmt->frac_shift);
>              return;
> -- 
> 2.43.0
> 

Reviewed-by: Chao Liu <[email protected]>

Thanks,
Chao

Reply via email to