On Mon, Feb 23, 2026 at 07:21:51PM +1100, Richard Henderson wrote:
> From: Max Chou <[email protected]>
> 
> The OCP FP8 conversion operations have a parameter to control
> saturate vs overflow.  Add a parameter, currently always false.
> 
> Signed-off-by: Max Chou <[email protected]>
> [rth: Split out of a larger patch]
> Signed-off-by: Richard Henderson <[email protected]>
> ---
>  fpu/softfloat.c           | 46 +++++++++++++++++++--------------------
>  fpu/softfloat-parts.c.inc | 15 ++++++++-----
>  2 files changed, 32 insertions(+), 29 deletions(-)
> 
> diff --git a/fpu/softfloat.c b/fpu/softfloat.c
> index 9d06a1bb59..b3c4104854 100644
> --- a/fpu/softfloat.c
> +++ b/fpu/softfloat.c
> @@ -771,20 +771,20 @@ static void parts128_canonicalize(FloatParts128 *p, 
> float_status *status,
>      PARTS_GENERIC_64_128(canonicalize, A)(A, S, F)
>  
>  static void parts64_uncanon_normal(FloatParts64 *p, float_status *status,
> -                                   const FloatFmt *fmt);
> +                                   const FloatFmt *fmt, bool saturate);
>  static void parts128_uncanon_normal(FloatParts128 *p, float_status *status,
> -                                    const FloatFmt *fmt);
> +                                    const FloatFmt *fmt, bool saturate);
>  
> -#define parts_uncanon_normal(A, S, F) \
> -    PARTS_GENERIC_64_128(uncanon_normal, A)(A, S, F)
> +#define parts_uncanon_normal(A, S, F, X) \
> +    PARTS_GENERIC_64_128(uncanon_normal, A)(A, S, F, X)
>  
>  static void parts64_uncanon(FloatParts64 *p, float_status *status,
> -                            const FloatFmt *fmt);
> +                            const FloatFmt *fmt, bool saturate);
>  static void parts128_uncanon(FloatParts128 *p, float_status *status,
> -                             const FloatFmt *fmt);
> +                             const FloatFmt *fmt, bool saturate);
>  
> -#define parts_uncanon(A, S, F) \
> -    PARTS_GENERIC_64_128(uncanon, A)(A, S, F)
> +#define parts_uncanon(A, S, F, X) \
> +    PARTS_GENERIC_64_128(uncanon, A)(A, S, F, X)
>  
>  static void parts64_add_normal(FloatParts64 *a, FloatParts64 *b);
>  static void parts128_add_normal(FloatParts128 *a, FloatParts128 *b);
> @@ -1699,7 +1699,7 @@ static float16 
> float16a_round_pack_canonical(FloatParts64 *p,
>                                               float_status *s,
>                                               const FloatFmt *params)
>  {
> -    parts_uncanon(p, s, params);
> +    parts_uncanon(p, s, params, false);
>      return float16_pack_raw(p);
>  }
>  
> @@ -1712,7 +1712,7 @@ static float16 
> float16_round_pack_canonical(FloatParts64 *p,
>  static bfloat16 bfloat16_round_pack_canonical(FloatParts64 *p,
>                                                float_status *s)
>  {
> -    parts_uncanon(p, s, &bfloat16_params);
> +    parts_uncanon(p, s, &bfloat16_params, false);
>      return bfloat16_pack_raw(p);
>  }
>  
> @@ -1726,7 +1726,7 @@ static void float32_unpack_canonical(FloatParts64 *p, 
> float32 f,
>  static float32 float32_round_pack_canonical(FloatParts64 *p,
>                                              float_status *s)
>  {
> -    parts_uncanon(p, s, &float32_params);
> +    parts_uncanon(p, s, &float32_params, false);
>      return float32_pack_raw(p);
>  }
>  
> @@ -1740,7 +1740,7 @@ static void float64_unpack_canonical(FloatParts64 *p, 
> float64 f,
>  static float64 float64_round_pack_canonical(FloatParts64 *p,
>                                              float_status *s)
>  {
> -    parts_uncanon(p, s, &float64_params);
> +    parts_uncanon(p, s, &float64_params, false);
>      return float64_pack_raw(p);
>  }
>  
> @@ -1789,7 +1789,7 @@ static float64 float64r32_pack_raw(FloatParts64 *p)
>  static float64 float64r32_round_pack_canonical(FloatParts64 *p,
>                                                 float_status *s)
>  {
> -    parts_uncanon(p, s, &float32_params);
> +    parts_uncanon(p, s, &float32_params, false);
>      return float64r32_pack_raw(p);
>  }
>  
> @@ -1803,7 +1803,7 @@ static void float128_unpack_canonical(FloatParts128 *p, 
> float128 f,
>  static float128 float128_round_pack_canonical(FloatParts128 *p,
>                                                float_status *s)
>  {
> -    parts_uncanon(p, s, &float128_params);
> +    parts_uncanon(p, s, &float128_params, false);
>      return float128_pack_raw(p);
>  }
>  
> @@ -1851,7 +1851,7 @@ static floatx80 
> floatx80_round_pack_canonical(FloatParts128 *p,
>      case float_class_normal:
>      case float_class_denormal:
>          if (s->floatx80_rounding_precision == floatx80_precision_x) {
> -            parts_uncanon_normal(p, s, fmt);
> +            parts_uncanon_normal(p, s, fmt, false);
>              frac = p->frac_hi;
>              exp = p->exp;
>          } else {
> @@ -1860,7 +1860,7 @@ static floatx80 
> floatx80_round_pack_canonical(FloatParts128 *p,
>              p64.sign = p->sign;
>              p64.exp = p->exp;
>              frac_truncjam(&p64, p);
> -            parts_uncanon_normal(&p64, s, fmt);
> +            parts_uncanon_normal(&p64, s, fmt, false);
>              frac = p64.frac;
>              exp = p64.exp;
>          }
> @@ -2258,7 +2258,7 @@ float16_muladd_scalbn(float16 a, float16 b, float16 c,
>      pr = parts_muladd_scalbn(&pa, &pb, &pc, scale, flags, status);
>  
>      /* Round before applying negate result. */
> -    parts_uncanon(pr, status, &float16_params);
> +    parts_uncanon(pr, status, &float16_params, false);
>      if ((flags & float_muladd_negate_result) && !is_nan(pr->cls)) {
>          pr->sign ^= 1;
>      }
> @@ -2283,7 +2283,7 @@ float32_muladd_scalbn(float32 a, float32 b, float32 c,
>      pr = parts_muladd_scalbn(&pa, &pb, &pc, scale, flags, status);
>  
>      /* Round before applying negate result. */
> -    parts_uncanon(pr, status, &float32_params);
> +    parts_uncanon(pr, status, &float32_params, false);
>      if ((flags & float_muladd_negate_result) && !is_nan(pr->cls)) {
>          pr->sign ^= 1;
>      }
> @@ -2302,7 +2302,7 @@ float64_muladd_scalbn(float64 a, float64 b, float64 c,
>      pr = parts_muladd_scalbn(&pa, &pb, &pc, scale, flags, status);
>  
>      /* Round before applying negate result. */
> -    parts_uncanon(pr, status, &float64_params);
> +    parts_uncanon(pr, status, &float64_params, false);
>      if ((flags & float_muladd_negate_result) && !is_nan(pr->cls)) {
>          pr->sign ^= 1;
>      }
> @@ -2461,7 +2461,7 @@ float64 float64r32_muladd(float64 a, float64 b, float64 
> c,
>      pr = parts_muladd_scalbn(&pa, &pb, &pc, 0, flags, status);
>  
>      /* Round before applying negate result. */
> -    parts_uncanon(pr, status, &float32_params);
> +    parts_uncanon(pr, status, &float32_params, false);
>      if ((flags & float_muladd_negate_result) && !is_nan(pr->cls)) {
>          pr->sign ^= 1;
>      }
> @@ -2479,7 +2479,7 @@ bfloat16 QEMU_FLATTEN bfloat16_muladd(bfloat16 a, 
> bfloat16 b, bfloat16 c,
>      pr = parts_muladd_scalbn(&pa, &pb, &pc, 0, flags, status);
>  
>      /* Round before applying negate result. */
> -    parts_uncanon(pr, status, &bfloat16_params);
> +    parts_uncanon(pr, status, &bfloat16_params, false);
>      if ((flags & float_muladd_negate_result) && !is_nan(pr->cls)) {
>          pr->sign ^= 1;
>      }
> @@ -2497,7 +2497,7 @@ float128 QEMU_FLATTEN float128_muladd(float128 a, 
> float128 b, float128 c,
>      pr = parts_muladd_scalbn(&pa, &pb, &pc, 0, flags, status);
>  
>      /* Round before applying negate result. */
> -    parts_uncanon(pr, status, &float128_params);
> +    parts_uncanon(pr, status, &float128_params, false);
>      if ((flags & float_muladd_negate_result) && !is_nan(pr->cls)) {
>          pr->sign ^= 1;
>      }
> @@ -5435,7 +5435,7 @@ static void parts_s390_divide_to_integer(FloatParts64 
> *a, FloatParts64 *b,
>          /* Round remainder to the target format */
>          *r = *r_precise;
>          status->float_exception_flags = 0;
> -        parts_uncanon(r, status, fmt);
> +        parts_uncanon(r, status, fmt, false);
>          r_flags = status->float_exception_flags;
>          r->frac &= (1ULL << fmt->frac_size) - 1;
>          parts_canonicalize(r, status, fmt);
> diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc
> index 4909ff7418..09be686645 100644
> --- a/fpu/softfloat-parts.c.inc
> +++ b/fpu/softfloat-parts.c.inc
> @@ -258,9 +258,12 @@ static void partsN(canonicalize)(FloatPartsN *p, 
> float_status *status,
>   * are FRAC_SHIFT bits that may require rounding at the bottom of the
>   * fraction; these bits will be removed. The exponent will be biased
>   * by EXP_BIAS and must be bounded by [EXP_MAX-1, 0].
> + *
> + * The saturate parameter controls saturation behavior for formats that
> + * support it -- when true, overflow produces max normal instead of infinity.
>   */
>  static void partsN(uncanon_normal)(FloatPartsN *p, float_status *s,
> -                                   const FloatFmt *fmt)
> +                                   const FloatFmt *fmt, bool saturate)
>  {
>      const int exp_max = fmt->exp_max;
>      const int frac_shift = fmt->frac_shift;
> @@ -269,7 +272,7 @@ static void partsN(uncanon_normal)(FloatPartsN *p, 
> float_status *s,
>      const uint64_t frac_lsbm1 = round_mask ^ (round_mask >> 1);
>      const uint64_t roundeven_mask = round_mask | frac_lsb;
>      uint64_t inc;
> -    bool overflow_norm = false;
> +    bool overflow_norm = saturate;
>      int exp, flags = 0;
>  
>      switch (s->float_rounding_mode) {
> @@ -294,11 +297,11 @@ static void partsN(uncanon_normal)(FloatPartsN *p, 
> float_status *s,
>          break;
>      case float_round_up:
>          inc = p->sign ? 0 : round_mask;
> -        overflow_norm = p->sign;
> +        overflow_norm |= p->sign;
>          break;
>      case float_round_down:
>          inc = p->sign ? round_mask : 0;
> -        overflow_norm = !p->sign;
> +        overflow_norm |= !p->sign;
>          break;
>      case float_round_to_odd:
>          overflow_norm = true;
> @@ -445,10 +448,10 @@ static void partsN(uncanon_normal)(FloatPartsN *p, 
> float_status *s,
>  }
>  
>  static void partsN(uncanon)(FloatPartsN *p, float_status *s,
> -                            const FloatFmt *fmt)
> +                            const FloatFmt *fmt, bool saturate)
>  {
>      if (likely(is_anynorm(p->cls))) {
> -        parts_uncanon_normal(p, s, fmt);
> +        parts_uncanon_normal(p, s, fmt, saturate);
>      } else {
>          switch (p->cls) {
>          case float_class_zero:
> -- 
> 2.43.0
> 

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

Thanks,
Chao

Reply via email to