1 /* Copyright (C) 2007, 2009 Free Software Foundation, Inc. 2 3 This file is part of GCC. 4 5 GCC is free software; you can redistribute it and/or modify it under 6 the terms of the GNU General Public License as published by the Free 7 Software Foundation; either version 3, or (at your option) any later 8 version. 9 10 GCC is distributed in the hope that it will be useful, but WITHOUT ANY 11 WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 13 for more details. 14 15 Under Section 7 of GPL version 3, you are granted additional 16 permissions described in the GCC Runtime Library Exception, version 17 3.1, as published by the Free Software Foundation. 18 19 You should have received a copy of the GNU General Public License and 20 a copy of the GCC Runtime Library Exception along with this program; 21 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 22 <http://www.gnu.org/licenses/>. */ 23 24 #define BID_128RES 25 #include "bid_internal.h" 26 27 /* 28 * Takes a BID32 as input and converts it to a BID128 and returns it. 29 */ 30 TYPE0_FUNCTION_ARGTYPE1_NORND (UINT128, bid32_to_bid128, UINT32, x) 31 32 UINT128 new_coeff, res; 33 UINT32 sign_x; 34 int exponent_x; 35 UINT32 coefficient_x; 36 37 if (!unpack_BID32 (&sign_x, &exponent_x, &coefficient_x, x)) { 38 if (((x) & 0x78000000) == 0x78000000) { 39 #ifdef SET_STATUS_FLAGS 40 if (((x) & 0x7e000000) == 0x7e000000) // sNaN 41 __set_status_flags (pfpsf, INVALID_EXCEPTION); 42 #endif 43 res.w[0] = (coefficient_x & 0x000fffff); 44 __mul_64x128_low (res, res.w[0], power10_table_128[27]); 45 res.w[1] |= 46 ((((UINT64) coefficient_x) << 32) & 0xfc00000000000000ull); 47 48 BID_RETURN (res); 49 } 50 } 51 52 new_coeff.w[0] = coefficient_x; 53 new_coeff.w[1] = 0; 54 get_BID128_very_fast (&res, ((UINT64) sign_x) << 32, 55 exponent_x + DECIMAL_EXPONENT_BIAS_128 - 56 DECIMAL_EXPONENT_BIAS_32, new_coeff); 57 BID_RETURN (res); 58 } // convert_bid32_to_bid128 59 60 61 /* 62 * Takes a BID128 as input and converts it to a BID32 and returns it. 63 */ 64 #if DECIMAL_CALL_BY_REFERENCE 65 66 void 67 bid128_to_bid32 (UINT32 * pres, 68 UINT128 * 69 px _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM 70 _EXC_INFO_PARAM) { 71 UINT128 x = *px; 72 #else 73 74 UINT32 75 bid128_to_bid32 (UINT128 x _RND_MODE_PARAM _EXC_FLAGS_PARAM 76 _EXC_MASKS_PARAM _EXC_INFO_PARAM) { 77 #endif 78 UINT128 CX, T128, TP128, Qh, Ql, Qh1, Stemp, Tmp, Tmp1, CX1; 79 UINT64 sign_x, carry, cy; 80 SINT64 D; 81 UINT32 res; 82 int_float f64, fx; 83 int exponent_x, extra_digits, amount, bin_expon_cx, uf_check = 0; 84 unsigned rmode, status; 85 86 #if DECIMAL_CALL_BY_REFERENCE 87 #if !DECIMAL_GLOBAL_ROUNDING 88 _IDEC_round rnd_mode = *prnd_mode; 89 #endif 90 #endif 91 92 BID_SWAP128 (x); 93 // unpack arguments, check for NaN or Infinity or 0 94 if (!unpack_BID128_value (&sign_x, &exponent_x, &CX, x)) { 95 if (((x.w[1]) & 0x7800000000000000ull) == 0x7800000000000000ull) { 96 Tmp.w[1] = (CX.w[1] & 0x00003fffffffffffull); 97 Tmp.w[0] = CX.w[0]; 98 TP128 = reciprocals10_128[27]; 99 __mul_128x128_full (Qh, Ql, Tmp, TP128); 100 amount = recip_scale[27] - 64; 101 res = ((CX.w[1] >> 32) & 0xfc000000) | (Qh.w[1] >> amount); 102 #ifdef SET_STATUS_FLAGS 103 if ((x.w[1] & SNAN_MASK64) == SNAN_MASK64) // sNaN 104 __set_status_flags (pfpsf, INVALID_EXCEPTION); 105 #endif 106 BID_RETURN_VAL (res); 107 } 108 // x is 0 109 exponent_x = 110 exponent_x - DECIMAL_EXPONENT_BIAS_128 + DECIMAL_EXPONENT_BIAS_32; 111 if (exponent_x < 0) 112 exponent_x = 0; 113 if (exponent_x > DECIMAL_MAX_EXPON_32) 114 exponent_x = DECIMAL_MAX_EXPON_32; 115 res = (sign_x >> 32) | (exponent_x << 23); 116 BID_RETURN_VAL (res); 117 118 } 119 120 if (CX.w[1] || (CX.w[0] >= 10000000)) { 121 // find number of digits in coefficient 122 // 2^64 123 f64.i = 0x5f800000; 124 // fx ~ CX 125 fx.d = (float) CX.w[1] * f64.d + (float) CX.w[0]; 126 bin_expon_cx = ((fx.i >> 23) & 0xff) - 0x7f; 127 extra_digits = estimate_decimal_digits[bin_expon_cx] - 7; 128 // scale = 38-estimate_decimal_digits[bin_expon_cx]; 129 D = CX.w[1] - power10_index_binexp_128[bin_expon_cx].w[1]; 130 if (D > 0 131 || (!D 132 && CX.w[0] >= power10_index_binexp_128[bin_expon_cx].w[0])) 133 extra_digits++; 134 135 exponent_x += extra_digits; 136 137 #ifndef IEEE_ROUND_NEAREST_TIES_AWAY 138 #ifndef IEEE_ROUND_NEAREST 139 rmode = rnd_mode; 140 if (sign_x && (unsigned) (rmode - 1) < 2) 141 rmode = 3 - rmode; 142 #else 143 rmode = 0; 144 #endif 145 #else 146 rmode = 0; 147 #endif 148 if (exponent_x < 149 DECIMAL_EXPONENT_BIAS_128 - DECIMAL_EXPONENT_BIAS_32) { 150 uf_check = 1; 151 if (-extra_digits + exponent_x - DECIMAL_EXPONENT_BIAS_128 + 152 DECIMAL_EXPONENT_BIAS_32 + 35 >= 0) { 153 if (exponent_x == 154 DECIMAL_EXPONENT_BIAS_128 - DECIMAL_EXPONENT_BIAS_32 - 1) { 155 T128 = round_const_table_128[rmode][extra_digits]; 156 __add_carry_out (CX1.w[0], carry, T128.w[0], CX.w[0]); 157 CX1.w[1] = CX.w[1] + T128.w[1] + carry; 158 if (__unsigned_compare_ge_128 159 (CX1, power10_table_128[extra_digits + 7])) 160 uf_check = 0; 161 } 162 extra_digits = 163 extra_digits + DECIMAL_EXPONENT_BIAS_128 - 164 DECIMAL_EXPONENT_BIAS_32 - exponent_x; 165 exponent_x = 166 DECIMAL_EXPONENT_BIAS_128 - DECIMAL_EXPONENT_BIAS_32; 167 } else 168 rmode = ROUNDING_TO_ZERO; 169 } 170 171 T128 = round_const_table_128[rmode][extra_digits]; 172 __add_carry_out (CX.w[0], carry, T128.w[0], CX.w[0]); 173 CX.w[1] = CX.w[1] + T128.w[1] + carry; 174 175 TP128 = reciprocals10_128[extra_digits]; 176 __mul_128x128_full (Qh, Ql, CX, TP128); 177 amount = recip_scale[extra_digits]; 178 179 if (amount >= 64) { 180 CX.w[0] = Qh.w[1] >> (amount - 64); 181 CX.w[1] = 0; 182 } else { 183 __shr_128 (CX, Qh, amount); 184 } 185 186 #ifndef IEEE_ROUND_NEAREST_TIES_AWAY 187 #ifndef IEEE_ROUND_NEAREST 188 if (!(rnd_mode)) 189 #endif 190 if (CX.w[0] & 1) { 191 // check whether fractional part of initial_P/10^ed1 is exactly .5 192 193 // get remainder 194 __shl_128_long (Qh1, Qh, (128 - amount)); 195 196 if (!Qh1.w[1] && !Qh1.w[0] 197 && (Ql.w[1] < reciprocals10_128[extra_digits].w[1] 198 || (Ql.w[1] == reciprocals10_128[extra_digits].w[1] 199 && Ql.w[0] < reciprocals10_128[extra_digits].w[0]))) { 200 CX.w[0]--; 201 } 202 } 203 #endif 204 205 206 { 207 status = INEXACT_EXCEPTION; 208 // get remainder 209 __shl_128_long (Qh1, Qh, (128 - amount)); 210 211 switch (rmode) { 212 case ROUNDING_TO_NEAREST: 213 case ROUNDING_TIES_AWAY: 214 // test whether fractional part is 0 215 if (Qh1.w[1] == 0x8000000000000000ull && (!Qh1.w[0]) 216 && (Ql.w[1] < reciprocals10_128[extra_digits].w[1] 217 || (Ql.w[1] == reciprocals10_128[extra_digits].w[1] 218 && Ql.w[0] < reciprocals10_128[extra_digits].w[0]))) 219 status = EXACT_STATUS; 220 break; 221 case ROUNDING_DOWN: 222 case ROUNDING_TO_ZERO: 223 if ((!Qh1.w[1]) && (!Qh1.w[0]) 224 && (Ql.w[1] < reciprocals10_128[extra_digits].w[1] 225 || (Ql.w[1] == reciprocals10_128[extra_digits].w[1] 226 && Ql.w[0] < reciprocals10_128[extra_digits].w[0]))) 227 status = EXACT_STATUS; 228 break; 229 default: 230 // round up 231 __add_carry_out (Stemp.w[0], cy, Ql.w[0], 232 reciprocals10_128[extra_digits].w[0]); 233 __add_carry_in_out (Stemp.w[1], carry, Ql.w[1], 234 reciprocals10_128[extra_digits].w[1], cy); 235 __shr_128_long (Qh, Qh1, (128 - amount)); 236 Tmp.w[0] = 1; 237 Tmp.w[1] = 0; 238 __shl_128_long (Tmp1, Tmp, amount); 239 Qh.w[0] += carry; 240 if (Qh.w[0] < carry) 241 Qh.w[1]++; 242 if (__unsigned_compare_ge_128 (Qh, Tmp1)) 243 status = EXACT_STATUS; 244 } 245 246 if (status != EXACT_STATUS) { 247 if (uf_check) { 248 status |= UNDERFLOW_EXCEPTION; 249 } 250 #ifdef SET_STATUS_FLAGS 251 __set_status_flags (pfpsf, status); 252 #endif 253 } 254 } 255 256 } 257 258 res = 259 get_BID32 ((UINT32) (sign_x >> 32), 260 exponent_x - DECIMAL_EXPONENT_BIAS_128 + 261 DECIMAL_EXPONENT_BIAS_32, CX.w[0], rnd_mode, pfpsf); 262 BID_RETURN_VAL (res); 263 264 } 265