diff options
Diffstat (limited to 'fpu/softfloat.c')
-rw-r--r-- | fpu/softfloat.c | 183 |
1 files changed, 183 insertions, 0 deletions
diff --git a/fpu/softfloat.c b/fpu/softfloat.c index 7f524d4377..5e2cf20448 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -3154,6 +3154,60 @@ static int64_t float128_to_int64_scalbn(float128 a, FloatRoundMode rmode, return parts_float_to_sint(&p, rmode, scale, INT64_MIN, INT64_MAX, s); } +static Int128 float128_to_int128_scalbn(float128 a, FloatRoundMode rmode, + int scale, float_status *s) +{ + int flags = 0; + Int128 r; + FloatParts128 p; + + float128_unpack_canonical(&p, a, s); + + switch (p.cls) { + case float_class_snan: + flags |= float_flag_invalid_snan; + /* fall through */ + case float_class_qnan: + flags |= float_flag_invalid; + r = UINT128_MAX; + break; + + case float_class_inf: + flags = float_flag_invalid | float_flag_invalid_cvti; + r = p.sign ? INT128_MIN : INT128_MAX; + break; + + case float_class_zero: + return int128_zero(); + + case float_class_normal: + if (parts_round_to_int_normal(&p, rmode, scale, 128 - 2)) { + flags = float_flag_inexact; + } + + if (p.exp < 127) { + int shift = 127 - p.exp; + r = int128_urshift(int128_make128(p.frac_lo, p.frac_hi), shift); + if (p.sign) { + r = int128_neg(r); + } + } else if (p.exp == 127 && p.sign && p.frac_lo == 0 && + p.frac_hi == DECOMPOSED_IMPLICIT_BIT) { + r = INT128_MIN; + } else { + flags = float_flag_invalid | float_flag_invalid_cvti; + r = p.sign ? INT128_MIN : INT128_MAX; + } + break; + + default: + g_assert_not_reached(); + } + + float_raise(flags, s); + return r; +} + static int32_t floatx80_to_int32_scalbn(floatx80 a, FloatRoundMode rmode, int scale, float_status *s) { @@ -3236,6 +3290,11 @@ int64_t float128_to_int64(float128 a, float_status *s) return float128_to_int64_scalbn(a, s->float_rounding_mode, 0, s); } +Int128 float128_to_int128(float128 a, float_status *s) +{ + return float128_to_int128_scalbn(a, s->float_rounding_mode, 0, s); +} + int32_t floatx80_to_int32(floatx80 a, float_status *s) { return floatx80_to_int32_scalbn(a, s->float_rounding_mode, 0, s); @@ -3301,6 +3360,11 @@ int64_t float128_to_int64_round_to_zero(float128 a, float_status *s) return float128_to_int64_scalbn(a, float_round_to_zero, 0, s); } +Int128 float128_to_int128_round_to_zero(float128 a, float_status *s) +{ + return float128_to_int128_scalbn(a, float_round_to_zero, 0, s); +} + int32_t floatx80_to_int32_round_to_zero(floatx80 a, float_status *s) { return floatx80_to_int32_scalbn(a, float_round_to_zero, 0, s); @@ -3480,6 +3544,61 @@ static uint64_t float128_to_uint64_scalbn(float128 a, FloatRoundMode rmode, return parts_float_to_uint(&p, rmode, scale, UINT64_MAX, s); } +static Int128 float128_to_uint128_scalbn(float128 a, FloatRoundMode rmode, + int scale, float_status *s) +{ + int flags = 0; + Int128 r; + FloatParts128 p; + + float128_unpack_canonical(&p, a, s); + + switch (p.cls) { + case float_class_snan: + flags |= float_flag_invalid_snan; + /* fall through */ + case float_class_qnan: + flags |= float_flag_invalid; + r = UINT128_MAX; + break; + + case float_class_inf: + flags = float_flag_invalid | float_flag_invalid_cvti; + r = p.sign ? int128_zero() : UINT128_MAX; + break; + + case float_class_zero: + return int128_zero(); + + case float_class_normal: + if (parts_round_to_int_normal(&p, rmode, scale, 128 - 2)) { + flags = float_flag_inexact; + if (p.cls == float_class_zero) { + r = int128_zero(); + break; + } + } + + if (p.sign) { + flags = float_flag_invalid | float_flag_invalid_cvti; + r = int128_zero(); + } else if (p.exp <= 127) { + int shift = 127 - p.exp; + r = int128_urshift(int128_make128(p.frac_lo, p.frac_hi), shift); + } else { + flags = float_flag_invalid | float_flag_invalid_cvti; + r = UINT128_MAX; + } + break; + + default: + g_assert_not_reached(); + } + + float_raise(flags, s); + return r; +} + uint8_t float16_to_uint8(float16 a, float_status *s) { return float16_to_uint8_scalbn(a, s->float_rounding_mode, 0, s); @@ -3540,6 +3659,11 @@ uint64_t float128_to_uint64(float128 a, float_status *s) return float128_to_uint64_scalbn(a, s->float_rounding_mode, 0, s); } +Int128 float128_to_uint128(float128 a, float_status *s) +{ + return float128_to_uint128_scalbn(a, s->float_rounding_mode, 0, s); +} + uint16_t float16_to_uint16_round_to_zero(float16 a, float_status *s) { return float16_to_uint16_scalbn(a, float_round_to_zero, 0, s); @@ -3595,6 +3719,11 @@ uint64_t float128_to_uint64_round_to_zero(float128 a, float_status *s) return float128_to_uint64_scalbn(a, float_round_to_zero, 0, s); } +Int128 float128_to_uint128_round_to_zero(float128 a, float_status *s) +{ + return float128_to_uint128_scalbn(a, float_round_to_zero, 0, s); +} + uint16_t bfloat16_to_uint16(bfloat16 a, float_status *s) { return bfloat16_to_uint16_scalbn(a, s->float_rounding_mode, 0, s); @@ -3780,6 +3909,35 @@ bfloat16 int16_to_bfloat16(int16_t a, float_status *status) return int64_to_bfloat16_scalbn(a, 0, status); } +float128 int128_to_float128(Int128 a, float_status *status) +{ + FloatParts128 p = { }; + int shift; + + if (int128_nz(a)) { + p.cls = float_class_normal; + if (!int128_nonneg(a)) { + p.sign = true; + a = int128_neg(a); + } + + shift = clz64(int128_gethi(a)); + if (shift == 64) { + shift += clz64(int128_getlo(a)); + } + + p.exp = 127 - shift; + a = int128_lshift(a, shift); + + p.frac_hi = int128_gethi(a); + p.frac_lo = int128_getlo(a); + } else { + p.cls = float_class_zero; + } + + return float128_round_pack_canonical(&p, status); +} + float128 int64_to_float128(int64_t a, float_status *status) { FloatParts128 p; @@ -3969,6 +4127,31 @@ float128 uint64_to_float128(uint64_t a, float_status *status) return float128_round_pack_canonical(&p, status); } +float128 uint128_to_float128(Int128 a, float_status *status) +{ + FloatParts128 p = { }; + int shift; + + if (int128_nz(a)) { + p.cls = float_class_normal; + + shift = clz64(int128_gethi(a)); + if (shift == 64) { + shift += clz64(int128_getlo(a)); + } + + p.exp = 127 - shift; + a = int128_lshift(a, shift); + + p.frac_hi = int128_gethi(a); + p.frac_lo = int128_getlo(a); + } else { + p.cls = float_class_zero; + } + + return float128_round_pack_canonical(&p, status); +} + /* * Minimum and maximum */ |