1 /* Copyright (C) 2007-2016 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 #include "bid_internal.h" 25 26 /***************************************************************************** 27 * BID64_round_integral_exact 28 ****************************************************************************/ 29 30 #if DECIMAL_CALL_BY_REFERENCE 31 void 32 bid64_from_int32 (UINT64 * pres, 33 int *px _EXC_MASKS_PARAM _EXC_INFO_PARAM) { 34 int x = *px; 35 #else 36 UINT64 37 bid64_from_int32 (int x _EXC_MASKS_PARAM _EXC_INFO_PARAM) { 38 #endif 39 UINT64 res; 40 41 // if integer is negative, put the absolute value 42 // in the lowest 32bits of the result 43 if ((x & SIGNMASK32) == SIGNMASK32) { 44 // negative int32 45 x = ~x + 1; // 2's complement of x 46 res = (unsigned int) x | 0xb1c0000000000000ull; 47 // (exp << 53)) = biased exp. is 0 48 } else { // positive int32 49 res = x | 0x31c0000000000000ull; // (exp << 53)) = biased exp. is 0 50 } 51 BID_RETURN (res); 52 } 53 54 #if DECIMAL_CALL_BY_REFERENCE 55 void 56 bid64_from_uint32 (UINT64 * pres, unsigned int *px 57 _EXC_MASKS_PARAM _EXC_INFO_PARAM) { 58 unsigned int x = *px; 59 #else 60 UINT64 61 bid64_from_uint32 (unsigned int x _EXC_MASKS_PARAM _EXC_INFO_PARAM) { 62 #endif 63 UINT64 res; 64 65 res = x | 0x31c0000000000000ull; // (exp << 53)) = biased exp. is 0 66 BID_RETURN (res); 67 } 68 69 #if DECIMAL_CALL_BY_REFERENCE 70 void 71 bid64_from_int64 (UINT64 * pres, SINT64 * px 72 _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM 73 _EXC_INFO_PARAM) { 74 SINT64 x = *px; 75 #if !DECIMAL_GLOBAL_ROUNDING 76 unsigned int rnd_mode = *prnd_mode; 77 #endif 78 #else 79 UINT64 80 bid64_from_int64 (SINT64 x 81 _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM 82 _EXC_INFO_PARAM) { 83 #endif 84 85 UINT64 res; 86 UINT64 x_sign, C; 87 unsigned int q, ind; 88 int incr_exp = 0; 89 int is_midpoint_lt_even = 0, is_midpoint_gt_even = 0; 90 int is_inexact_lt_midpoint = 0, is_inexact_gt_midpoint = 0; 91 92 x_sign = x & 0x8000000000000000ull; 93 // if the integer is negative, use the absolute value 94 if (x_sign) 95 C = ~((UINT64) x) + 1; 96 else 97 C = x; 98 if (C <= BID64_SIG_MAX) { // |C| <= 10^16-1 and the result is exact 99 if (C < 0x0020000000000000ull) { // C < 2^53 100 res = x_sign | 0x31c0000000000000ull | C; 101 } else { // C >= 2^53 102 res = 103 x_sign | 0x6c70000000000000ull | (C & 0x0007ffffffffffffull); 104 } 105 } else { // |C| >= 10^16 and the result may be inexact 106 // the smallest |C| is 10^16 which has 17 decimal digits 107 // the largest |C| is 0x8000000000000000 = 9223372036854775808 w/ 19 digits 108 if (C < 0x16345785d8a0000ull) { // x < 10^17 109 q = 17; 110 ind = 1; // number of digits to remove for q = 17 111 } else if (C < 0xde0b6b3a7640000ull) { // C < 10^18 112 q = 18; 113 ind = 2; // number of digits to remove for q = 18 114 } else { // C < 10^19 115 q = 19; 116 ind = 3; // number of digits to remove for q = 19 117 } 118 // overflow and underflow are not possible 119 // Note: performace can be improved by inlining this call 120 round64_2_18 ( // will work for 19 digits too if C fits in 64 bits 121 q, ind, C, &res, &incr_exp, 122 &is_midpoint_lt_even, &is_midpoint_gt_even, 123 &is_inexact_lt_midpoint, &is_inexact_gt_midpoint); 124 if (incr_exp) 125 ind++; 126 // set the inexact flag 127 if (is_inexact_lt_midpoint || is_inexact_gt_midpoint || 128 is_midpoint_lt_even || is_midpoint_gt_even) 129 *pfpsf |= INEXACT_EXCEPTION; 130 // general correction from RN to RA, RM, RP, RZ; result uses ind for exp 131 if (rnd_mode != ROUNDING_TO_NEAREST) { 132 if ((!x_sign 133 && ((rnd_mode == ROUNDING_UP && is_inexact_lt_midpoint) 134 || 135 ((rnd_mode == ROUNDING_TIES_AWAY 136 || rnd_mode == ROUNDING_UP) && is_midpoint_gt_even))) 137 || (x_sign 138 && ((rnd_mode == ROUNDING_DOWN && is_inexact_lt_midpoint) 139 || 140 ((rnd_mode == ROUNDING_TIES_AWAY 141 || rnd_mode == ROUNDING_DOWN) 142 && is_midpoint_gt_even)))) { 143 res = res + 1; 144 if (res == 0x002386f26fc10000ull) { // res = 10^16 => rounding overflow 145 res = 0x00038d7ea4c68000ull; // 10^15 146 ind = ind + 1; 147 } 148 } else if ((is_midpoint_lt_even || is_inexact_gt_midpoint) && 149 ((x_sign && (rnd_mode == ROUNDING_UP || 150 rnd_mode == ROUNDING_TO_ZERO)) || 151 (!x_sign && (rnd_mode == ROUNDING_DOWN || 152 rnd_mode == ROUNDING_TO_ZERO)))) { 153 res = res - 1; 154 // check if we crossed into the lower decade 155 if (res == 0x00038d7ea4c67fffull) { // 10^15 - 1 156 res = 0x002386f26fc0ffffull; // 10^16 - 1 157 ind = ind - 1; 158 } 159 } else { 160 ; // exact, the result is already correct 161 } 162 } 163 if (res < 0x0020000000000000ull) { // res < 2^53 164 res = x_sign | (((UINT64) ind + 398) << 53) | res; 165 } else { // res >= 2^53 166 res = 167 x_sign | 0x6000000000000000ull | (((UINT64) ind + 398) << 51) | 168 (res & 0x0007ffffffffffffull); 169 } 170 } 171 BID_RETURN (res); 172 } 173 174 #if DECIMAL_CALL_BY_REFERENCE 175 void 176 bid64_from_uint64 (UINT64 * pres, UINT64 * px 177 _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM 178 _EXC_INFO_PARAM) { 179 UINT64 x = *px; 180 #if !DECIMAL_GLOBAL_ROUNDING 181 unsigned int rnd_mode = *prnd_mode; 182 #endif 183 #else 184 UINT64 185 bid64_from_uint64 (UINT64 x 186 _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM 187 _EXC_INFO_PARAM) { 188 #endif 189 190 UINT64 res; 191 UINT128 x128, res128; 192 unsigned int q, ind; 193 int incr_exp = 0; 194 int is_midpoint_lt_even = 0, is_midpoint_gt_even = 0; 195 int is_inexact_lt_midpoint = 0, is_inexact_gt_midpoint = 0; 196 197 if (x <= BID64_SIG_MAX) { // x <= 10^16-1 and the result is exact 198 if (x < 0x0020000000000000ull) { // x < 2^53 199 res = 0x31c0000000000000ull | x; 200 } else { // x >= 2^53 201 res = 0x6c70000000000000ull | (x & 0x0007ffffffffffffull); 202 } 203 } else { // x >= 10^16 and the result may be inexact 204 // the smallest x is 10^16 which has 17 decimal digits 205 // the largest x is 0xffffffffffffffff = 18446744073709551615 w/ 20 digits 206 if (x < 0x16345785d8a0000ull) { // x < 10^17 207 q = 17; 208 ind = 1; // number of digits to remove for q = 17 209 } else if (x < 0xde0b6b3a7640000ull) { // x < 10^18 210 q = 18; 211 ind = 2; // number of digits to remove for q = 18 212 } else if (x < 0x8ac7230489e80000ull) { // x < 10^19 213 q = 19; 214 ind = 3; // number of digits to remove for q = 19 215 } else { // x < 10^20 216 q = 20; 217 ind = 4; // number of digits to remove for q = 20 218 } 219 // overflow and underflow are not possible 220 // Note: performace can be improved by inlining this call 221 if (q <= 19) { 222 round64_2_18 ( // will work for 20 digits too if x fits in 64 bits 223 q, ind, x, &res, &incr_exp, 224 &is_midpoint_lt_even, &is_midpoint_gt_even, 225 &is_inexact_lt_midpoint, &is_inexact_gt_midpoint); 226 } else { // q = 20 227 x128.w[1] = 0x0; 228 x128.w[0] = x; 229 round128_19_38 (q, ind, x128, &res128, &incr_exp, 230 &is_midpoint_lt_even, &is_midpoint_gt_even, 231 &is_inexact_lt_midpoint, &is_inexact_gt_midpoint); 232 res = res128.w[0]; // res.w[1] is 0 233 } 234 if (incr_exp) 235 ind++; 236 // set the inexact flag 237 if (is_inexact_lt_midpoint || is_inexact_gt_midpoint || 238 is_midpoint_lt_even || is_midpoint_gt_even) 239 *pfpsf |= INEXACT_EXCEPTION; 240 // general correction from RN to RA, RM, RP, RZ; result uses ind for exp 241 if (rnd_mode != ROUNDING_TO_NEAREST) { 242 if ((rnd_mode == ROUNDING_UP && is_inexact_lt_midpoint) || 243 ((rnd_mode == ROUNDING_TIES_AWAY || rnd_mode == ROUNDING_UP) 244 && is_midpoint_gt_even)) { 245 res = res + 1; 246 if (res == 0x002386f26fc10000ull) { // res = 10^16 => rounding overflow 247 res = 0x00038d7ea4c68000ull; // 10^15 248 ind = ind + 1; 249 } 250 } else if ((is_midpoint_lt_even || is_inexact_gt_midpoint) && 251 (rnd_mode == ROUNDING_DOWN || 252 rnd_mode == ROUNDING_TO_ZERO)) { 253 res = res - 1; 254 // check if we crossed into the lower decade 255 if (res == 0x00038d7ea4c67fffull) { // 10^15 - 1 256 res = 0x002386f26fc0ffffull; // 10^16 - 1 257 ind = ind - 1; 258 } 259 } else { 260 ; // exact, the result is already correct 261 } 262 } 263 if (res < 0x0020000000000000ull) { // res < 2^53 264 res = (((UINT64) ind + 398) << 53) | res; 265 } else { // res >= 2^53 266 res = 0x6000000000000000ull | (((UINT64) ind + 398) << 51) | 267 (res & 0x0007ffffffffffffull); 268 } 269 } 270 BID_RETURN (res); 271 } 272 273 #if DECIMAL_CALL_BY_REFERENCE 274 void 275 bid128_from_int32 (UINT128 * pres, 276 int *px _EXC_MASKS_PARAM _EXC_INFO_PARAM) { 277 int x = *px; 278 #else 279 UINT128 280 bid128_from_int32 (int x _EXC_MASKS_PARAM _EXC_INFO_PARAM) { 281 #endif 282 UINT128 res; 283 284 // if integer is negative, use the absolute value 285 if ((x & SIGNMASK32) == SIGNMASK32) { 286 res.w[HIGH_128W] = 0xb040000000000000ull; 287 res.w[LOW_128W] = ~((unsigned int) x) + 1; // 2's complement of x 288 } else { 289 res.w[HIGH_128W] = 0x3040000000000000ull; 290 res.w[LOW_128W] = (unsigned int) x; 291 } 292 BID_RETURN (res); 293 } 294 295 #if DECIMAL_CALL_BY_REFERENCE 296 void 297 bid128_from_uint32 (UINT128 * pres, unsigned int *px 298 _EXC_MASKS_PARAM _EXC_INFO_PARAM) { 299 unsigned int x = *px; 300 #else 301 UINT128 302 bid128_from_uint32 (unsigned int x _EXC_MASKS_PARAM _EXC_INFO_PARAM) { 303 #endif 304 UINT128 res; 305 306 res.w[HIGH_128W] = 0x3040000000000000ull; 307 res.w[LOW_128W] = x; 308 BID_RETURN (res); 309 } 310 311 #if DECIMAL_CALL_BY_REFERENCE 312 void 313 bid128_from_int64 (UINT128 * pres, SINT64 * px 314 _EXC_MASKS_PARAM _EXC_INFO_PARAM) { 315 SINT64 x = *px; 316 #else 317 UINT128 318 bid128_from_int64 (SINT64 x _EXC_MASKS_PARAM _EXC_INFO_PARAM) { 319 #endif 320 321 UINT128 res; 322 323 // if integer is negative, use the absolute value 324 if ((x & SIGNMASK64) == SIGNMASK64) { 325 res.w[HIGH_128W] = 0xb040000000000000ull; 326 res.w[LOW_128W] = ~x + 1; // 2's complement of x 327 } else { 328 res.w[HIGH_128W] = 0x3040000000000000ull; 329 res.w[LOW_128W] = x; 330 } 331 BID_RETURN (res); 332 } 333 334 #if DECIMAL_CALL_BY_REFERENCE 335 void 336 bid128_from_uint64 (UINT128 * pres, UINT64 * px 337 _EXC_MASKS_PARAM _EXC_INFO_PARAM) { 338 UINT64 x = *px; 339 #else 340 UINT128 341 bid128_from_uint64 (UINT64 x _EXC_MASKS_PARAM _EXC_INFO_PARAM) { 342 #endif 343 344 UINT128 res; 345 346 res.w[HIGH_128W] = 0x3040000000000000ull; 347 res.w[LOW_128W] = x; 348 BID_RETURN (res); 349 } 350