diff options
Diffstat (limited to 'libgcc/config/libbid/bid32_to_bid128.c')
-rw-r--r-- | libgcc/config/libbid/bid32_to_bid128.c | 162 |
1 files changed, 102 insertions, 60 deletions
diff --git a/libgcc/config/libbid/bid32_to_bid128.c b/libgcc/config/libbid/bid32_to_bid128.c index 1d47a5f519c..ed8e7f9847c 100644 --- a/libgcc/config/libbid/bid32_to_bid128.c +++ b/libgcc/config/libbid/bid32_to_bid128.c @@ -29,31 +29,38 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA #define BID_128RES #include "bid_internal.h" -/* +/* * Takes a BID32 as input and converts it to a BID128 and returns it. */ -TYPE0_FUNCTION_ARGTYPE1_NORND(UINT128, __bid32_to_bid128, UINT32, x) - - UINT128 new_coeff, res; - UINT32 sign_x; - int exponent_x = 0; - UINT32 coefficient_x = 0; - - if (!unpack_BID32 (&sign_x, &exponent_x, &coefficient_x, x)) { - if (((x) & 0x78000000) == 0x78000000) { - res.w[0] = 0; - res.w[1] = ((UINT64) (x)) << 32; - BID_RETURN (res); - } - } +TYPE0_FUNCTION_ARGTYPE1_NORND (UINT128, bid32_to_bid128, UINT32, x) + + UINT128 new_coeff, res; + UINT32 sign_x; + int exponent_x; + UINT32 coefficient_x; + +if (!unpack_BID32 (&sign_x, &exponent_x, &coefficient_x, x)) { +if (((x) & 0x78000000) == 0x78000000) { +#ifdef SET_STATUS_FLAGS + if (((x) & 0x7e000000) == 0x7e000000) // sNaN + __set_status_flags (pfpsf, INVALID_EXCEPTION); +#endif + res.w[0] = (coefficient_x & 0x000fffff); + __mul_64x128_low (res, res.w[0], power10_table_128[27]); + res.w[1] |= + ((((UINT64) coefficient_x) << 32) & 0xfc00000000000000ull); - new_coeff.w[0] = coefficient_x; - new_coeff.w[1] = 0; - get_BID128_very_fast (&res, ((UINT64) sign_x) << 32, - exponent_x + DECIMAL_EXPONENT_BIAS_128 - - DECIMAL_EXPONENT_BIAS_32, new_coeff); BID_RETURN (res); -} // convert_bid32_to_bid128 +} +} + +new_coeff.w[0] = coefficient_x; +new_coeff.w[1] = 0; +get_BID128_very_fast (&res, ((UINT64) sign_x) << 32, + exponent_x + DECIMAL_EXPONENT_BIAS_128 - + DECIMAL_EXPONENT_BIAS_32, new_coeff); +BID_RETURN (res); +} // convert_bid32_to_bid128 /* @@ -62,7 +69,7 @@ TYPE0_FUNCTION_ARGTYPE1_NORND(UINT128, __bid32_to_bid128, UINT32, x) #if DECIMAL_CALL_BY_REFERENCE void -__bid128_to_bid32 (UINT32 * pres, +bid128_to_bid32 (UINT32 * pres, UINT128 * px _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM _EXC_INFO_PARAM) { @@ -70,15 +77,15 @@ __bid128_to_bid32 (UINT32 * pres, #else UINT32 -__bid128_to_bid32 (UINT128 x _RND_MODE_PARAM _EXC_FLAGS_PARAM +bid128_to_bid32 (UINT128 x _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM _EXC_INFO_PARAM) { #endif - UINT128 CX, T128, TP128, Qh, Ql, Qh1, Stemp, Tmp, Tmp1; + UINT128 CX, T128, TP128, Qh, Ql, Qh1, Stemp, Tmp, Tmp1, CX1; UINT64 sign_x, carry, cy; SINT64 D; UINT32 res; int_float f64, fx; - int exponent_x = 0, extra_digits, amount, bin_expon_cx; + int exponent_x, extra_digits, amount, bin_expon_cx, uf_check = 0; unsigned rmode, status; #if DECIMAL_CALL_BY_REFERENCE @@ -87,25 +94,32 @@ __bid128_to_bid32 (UINT128 x _RND_MODE_PARAM _EXC_FLAGS_PARAM #endif #endif - BID_SWAP128(x); + BID_SWAP128 (x); // unpack arguments, check for NaN or Infinity or 0 - if (!unpack_BID128 (&sign_x, &exponent_x, &CX, &x)) { + if (!unpack_BID128_value (&sign_x, &exponent_x, &CX, x)) { if (((x.w[1]) & 0x7800000000000000ull) == 0x7800000000000000ull) { - res = ((UINT32) (x.w[1] >> 32)) & 0xfc000000; + Tmp.w[1] = (CX.w[1] & 0x00003fffffffffffull); + Tmp.w[0] = CX.w[0]; + TP128 = reciprocals10_128[27]; + __mul_128x128_full (Qh, Ql, Tmp, TP128); + amount = recip_scale[27] - 64; + res = ((CX.w[1] >> 32) & 0xfc000000) | (Qh.w[1] >> amount); +#ifdef SET_STATUS_FLAGS + if ((x.w[1] & SNAN_MASK64) == SNAN_MASK64) // sNaN + __set_status_flags (pfpsf, INVALID_EXCEPTION); +#endif BID_RETURN_VAL (res); } // x is 0 - amount = + exponent_x = exponent_x - DECIMAL_EXPONENT_BIAS_128 + DECIMAL_EXPONENT_BIAS_32; - if (((unsigned) amount) > DECIMAL_MAX_EXPON_32) { - sign_x >>= 32; - if (amount < 0) - res = sign_x; - res = - get_BID32 ((UINT32) (sign_x >> 32), DECIMAL_MAX_EXPON_32, 0, - rnd_mode, pfpsf); - BID_RETURN_VAL (res); - } + if (exponent_x < 0) + exponent_x = 0; + if (exponent_x > DECIMAL_MAX_EXPON_32) + exponent_x = DECIMAL_MAX_EXPON_32; + res = (sign_x >> 32) | (exponent_x << 23); + BID_RETURN_VAL (res); + } if (CX.w[1] || (CX.w[0] >= 10000000)) { @@ -115,10 +129,12 @@ __bid128_to_bid32 (UINT128 x _RND_MODE_PARAM _EXC_FLAGS_PARAM // fx ~ CX fx.d = (float) CX.w[1] * f64.d + (float) CX.w[0]; bin_expon_cx = ((fx.i >> 23) & 0xff) - 0x7f; - extra_digits = __bid_estimate_decimal_digits[bin_expon_cx] - 7; - // scale = 38-__bid_estimate_decimal_digits[bin_expon_cx]; - D = CX.w[1] - __bid_power10_index_binexp_128[bin_expon_cx].w[1]; - if (D > 0 || (!D && CX.w[0] >= __bid_power10_index_binexp_128[bin_expon_cx].w[0])) + extra_digits = estimate_decimal_digits[bin_expon_cx] - 7; + // scale = 38-estimate_decimal_digits[bin_expon_cx]; + D = CX.w[1] - power10_index_binexp_128[bin_expon_cx].w[1]; + if (D > 0 + || (!D + && CX.w[0] >= power10_index_binexp_128[bin_expon_cx].w[0])) extra_digits++; exponent_x += extra_digits; @@ -134,13 +150,36 @@ __bid128_to_bid32 (UINT128 x _RND_MODE_PARAM _EXC_FLAGS_PARAM #else rmode = 0; #endif - T128 = __bid_round_const_table_128[rmode][extra_digits]; + if (exponent_x < + DECIMAL_EXPONENT_BIAS_128 - DECIMAL_EXPONENT_BIAS_32) { + uf_check = 1; + if (-extra_digits + exponent_x - DECIMAL_EXPONENT_BIAS_128 + + DECIMAL_EXPONENT_BIAS_32 + 35 >= 0) { + if (exponent_x == + DECIMAL_EXPONENT_BIAS_128 - DECIMAL_EXPONENT_BIAS_32 - 1) { + T128 = round_const_table_128[rmode][extra_digits]; + __add_carry_out (CX1.w[0], carry, T128.w[0], CX.w[0]); + CX1.w[1] = CX.w[1] + T128.w[1] + carry; + if (__unsigned_compare_ge_128 + (CX1, power10_table_128[extra_digits + 7])) + uf_check = 0; + } + extra_digits = + extra_digits + DECIMAL_EXPONENT_BIAS_128 - + DECIMAL_EXPONENT_BIAS_32 - exponent_x; + exponent_x = + DECIMAL_EXPONENT_BIAS_128 - DECIMAL_EXPONENT_BIAS_32; + } else + rmode = ROUNDING_TO_ZERO; + } + + T128 = round_const_table_128[rmode][extra_digits]; __add_carry_out (CX.w[0], carry, T128.w[0], CX.w[0]); CX.w[1] = CX.w[1] + T128.w[1] + carry; - TP128 = __bid_reciprocals10_128[extra_digits]; + TP128 = reciprocals10_128[extra_digits]; __mul_128x128_full (Qh, Ql, CX, TP128); - amount = __bid_recip_scale[extra_digits]; + amount = recip_scale[extra_digits]; if (amount >= 64) { CX.w[0] = Qh.w[1] >> (amount - 64); @@ -160,15 +199,14 @@ __bid128_to_bid32 (UINT128 x _RND_MODE_PARAM _EXC_FLAGS_PARAM __shl_128_long (Qh1, Qh, (128 - amount)); if (!Qh1.w[1] && !Qh1.w[0] - && (Ql.w[1] < __bid_reciprocals10_128[extra_digits].w[1] - || (Ql.w[1] == __bid_reciprocals10_128[extra_digits].w[1] - && Ql.w[0] < __bid_reciprocals10_128[extra_digits].w[0]))) { + && (Ql.w[1] < reciprocals10_128[extra_digits].w[1] + || (Ql.w[1] == reciprocals10_128[extra_digits].w[1] + && Ql.w[0] < reciprocals10_128[extra_digits].w[0]))) { CX.w[0]--; } } #endif -#ifdef SET_STATUS_FLAGS { status = INEXACT_EXCEPTION; @@ -180,25 +218,25 @@ __bid128_to_bid32 (UINT128 x _RND_MODE_PARAM _EXC_FLAGS_PARAM case ROUNDING_TIES_AWAY: // test whether fractional part is 0 if (Qh1.w[1] == 0x8000000000000000ull && (!Qh1.w[0]) - && (Ql.w[1] < __bid_reciprocals10_128[extra_digits].w[1] - || (Ql.w[1] == __bid_reciprocals10_128[extra_digits].w[1] - && Ql.w[0] < __bid_reciprocals10_128[extra_digits].w[0]))) + && (Ql.w[1] < reciprocals10_128[extra_digits].w[1] + || (Ql.w[1] == reciprocals10_128[extra_digits].w[1] + && Ql.w[0] < reciprocals10_128[extra_digits].w[0]))) status = EXACT_STATUS; break; case ROUNDING_DOWN: case ROUNDING_TO_ZERO: if ((!Qh1.w[1]) && (!Qh1.w[0]) - && (Ql.w[1] < __bid_reciprocals10_128[extra_digits].w[1] - || (Ql.w[1] == __bid_reciprocals10_128[extra_digits].w[1] - && Ql.w[0] < __bid_reciprocals10_128[extra_digits].w[0]))) + && (Ql.w[1] < reciprocals10_128[extra_digits].w[1] + || (Ql.w[1] == reciprocals10_128[extra_digits].w[1] + && Ql.w[0] < reciprocals10_128[extra_digits].w[0]))) status = EXACT_STATUS; break; default: // round up __add_carry_out (Stemp.w[0], cy, Ql.w[0], - __bid_reciprocals10_128[extra_digits].w[0]); + reciprocals10_128[extra_digits].w[0]); __add_carry_in_out (Stemp.w[1], carry, Ql.w[1], - __bid_reciprocals10_128[extra_digits].w[1], cy); + reciprocals10_128[extra_digits].w[1], cy); __shr_128_long (Qh, Qh1, (128 - amount)); Tmp.w[0] = 1; Tmp.w[1] = 0; @@ -210,11 +248,15 @@ __bid128_to_bid32 (UINT128 x _RND_MODE_PARAM _EXC_FLAGS_PARAM status = EXACT_STATUS; } - if (status != EXACT_STATUS) + if (status != EXACT_STATUS) { + if (uf_check) { + status |= UNDERFLOW_EXCEPTION; + } +#ifdef SET_STATUS_FLAGS __set_status_flags (pfpsf, status); - } - #endif + } + } } |