summaryrefslogtreecommitdiffstats
path: root/fpu/softfloat.c
diff options
context:
space:
mode:
Diffstat (limited to 'fpu/softfloat.c')
-rw-r--r--fpu/softfloat.c183
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
*/