diff options
author | Richard Henderson <richard.henderson@linaro.org> | 2023-05-27 07:19:07 -0700 |
---|---|---|
committer | Richard Henderson <richard.henderson@linaro.org> | 2023-07-01 08:26:54 +0200 |
commit | e2041f4d5de01cb03b52908d36e9602b8c4a2479 (patch) | |
tree | 400f8bcf2d1326b8099154fbc07c8dccfea360c6 /fpu/softfloat-parts.c.inc | |
parent | e665cf72fe6357945fdbecf747dac58c0c7c7c66 (diff) |
fpu: Add float64_to_int{32,64}_modulo
Add versions of float64_to_int* which do not saturate the result.
Reviewed-by: Christoph Muellner <christoph.muellner@vrull.eu>
Tested-by: Christoph Muellner <christoph.muellner@vrull.eu>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Message-Id: <20230527141910.1885950-2-richard.henderson@linaro.org>
Diffstat (limited to 'fpu/softfloat-parts.c.inc')
-rw-r--r-- | fpu/softfloat-parts.c.inc | 78 |
1 files changed, 78 insertions, 0 deletions
diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc index 247400031c..527e15e6ab 100644 --- a/fpu/softfloat-parts.c.inc +++ b/fpu/softfloat-parts.c.inc @@ -1182,6 +1182,84 @@ static uint64_t partsN(float_to_uint)(FloatPartsN *p, FloatRoundMode rmode, } /* + * Like partsN(float_to_sint), except do not saturate the result. + * Instead, return the rounded unbounded precision two's compliment result, + * modulo 2**(bitsm1 + 1). + */ +static int64_t partsN(float_to_sint_modulo)(FloatPartsN *p, + FloatRoundMode rmode, + int bitsm1, float_status *s) +{ + int flags = 0; + uint64_t r; + bool overflow = false; + + switch (p->cls) { + case float_class_snan: + flags |= float_flag_invalid_snan; + /* fall through */ + case float_class_qnan: + flags |= float_flag_invalid; + r = 0; + break; + + case float_class_inf: + overflow = true; + r = 0; + break; + + case float_class_zero: + return 0; + + case float_class_normal: + /* TODO: N - 2 is frac_size for rounding; could use input fmt. */ + if (parts_round_to_int_normal(p, rmode, 0, N - 2)) { + flags = float_flag_inexact; + } + + if (p->exp <= DECOMPOSED_BINARY_POINT) { + /* + * Because we rounded to integral, and exp < 64, + * we know frac_low is zero. + */ + r = p->frac_hi >> (DECOMPOSED_BINARY_POINT - p->exp); + if (p->exp < bitsm1) { + /* Result in range. */ + } else if (p->exp == bitsm1) { + /* The only in-range value is INT_MIN. */ + overflow = !p->sign || p->frac_hi != DECOMPOSED_IMPLICIT_BIT; + } else { + overflow = true; + } + } else { + /* Overflow, but there might still be bits to return. */ + int shl = p->exp - DECOMPOSED_BINARY_POINT; + if (shl < N) { + frac_shl(p, shl); + r = p->frac_hi; + } else { + r = 0; + } + overflow = true; + } + + if (p->sign) { + r = -r; + } + break; + + default: + g_assert_not_reached(); + } + + if (overflow) { + flags = float_flag_invalid | float_flag_invalid_cvti; + } + float_raise(flags, s); + return r; +} + +/* * Integer to float conversions * * Returns the result of converting the two's complement integer `a' |