Avoid exponent overflow as well as checking that we don't lose information with opposing scaling. Use it in partsN(scalbn) and partsN(round_to_int_normal).
Signed-off-by: Richard Henderson <[email protected]> --- fpu/softfloat.c | 29 +++++++++++++++++++++++++++++ fpu/softfloat-parts.c.inc | 5 ++--- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/fpu/softfloat.c b/fpu/softfloat.c index a762f4b43a..df94f299e1 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -461,6 +461,15 @@ typedef struct { uint64_t frac_lo; } FloatParts256; +/* + * Minimum and maximum exponent for scalbn. + * These are chosen to be much larger than the true exponent for any input format, + * but also not at the bounds of INT32_{MIN,MAX} so that we can perform other + * arithmetic on the exponent without overflowing, particularly during uncanon. + */ +#define SCALBN_EXP_MAX 0x0fffffff +#define SCALBN_EXP_MIN (-SCALBN_EXP_MAX) + /* These apply to the most significant word of each FloatPartsN. */ #define DECOMPOSED_BINARY_POINT 63 #define DECOMPOSED_IMPLICIT_BIT (1ull << DECOMPOSED_BINARY_POINT) @@ -601,6 +610,26 @@ static float128 QEMU_FLATTEN float128_pack_raw(const FloatParts128 *p) *----------------------------------------------------------------------------*/ #include "softfloat-specialize.c.inc" +static int32_t exp_scalbn(int32_t exp, int32_t scale) +{ + /* + * Catch chains of scaling which lose information. + * In particular, if the exponent has been saturated, + * do not allow it to become unsaturated. + */ + if (exp >= SCALBN_EXP_MAX) { + assert(scale >= 0); + } else if (exp <= SCALBN_EXP_MIN) { + assert(scale <= 0); + } + if (sadd32_overflow(exp, scale, &exp)) { + exp = scale < 0 ? SCALBN_EXP_MIN : SCALBN_EXP_MAX; + } else { + exp = MIN(MAX(exp, SCALBN_EXP_MIN), SCALBN_EXP_MAX); + } + return exp; +} + /* * Helper functions for softfloat-parts.c.inc, per-size operations. */ diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc index 45606f8402..4715187017 100644 --- a/fpu/softfloat-parts.c.inc +++ b/fpu/softfloat-parts.c.inc @@ -1098,8 +1098,7 @@ static bool partsN(round_to_int_normal)(FloatPartsN *a, FloatRoundMode rmode, uint64_t frac_lsb, frac_lsbm1, rnd_even_mask, rnd_mask, inc; int shift_adj; - scale = MIN(MAX(scale, -0x10000), 0x10000); - a->exp += scale; + a->exp = exp_scalbn(a->exp, scale); if (a->exp < 0) { bool one; @@ -1623,7 +1622,7 @@ FloatPartsN partsN(scalbn)(const FloatPartsN *a, int n, float_status *s) case float_class_normal: { FloatPartsN r = *a; - r.exp += MIN(MAX(n, -0x10000), 0x10000); + r.exp = exp_scalbn(r.exp, n); return r; } default: -- 2.43.0
