1/* Copyright (C) 2007-2022 Free Software Foundation, Inc. 2 3This file is part of GCC. 4 5GCC is free software; you can redistribute it and/or modify it under 6the terms of the GNU General Public License as published by the Free 7Software Foundation; either version 3, or (at your option) any later 8version. 9 10GCC is distributed in the hope that it will be useful, but WITHOUT ANY 11WARRANTY; without even the implied warranty of MERCHANTABILITY or 12FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 13for more details. 14 15Under Section 7 of GPL version 3, you are granted additional 16permissions described in the GCC Runtime Library Exception, version 173.1, as published by the Free Software Foundation. 18 19You should have received a copy of the GNU General Public License and 20a copy of the GCC Runtime Library Exception along with this program; 21see 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 31void 32bid64_from_int32 (UINT64 * pres, 33 int *px _EXC_MASKS_PARAM _EXC_INFO_PARAM) { 34 int x = *px; 35#else 36UINT64 37bid64_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 55void 56bid64_from_uint32 (UINT64 * pres, unsigned int *px 57 _EXC_MASKS_PARAM _EXC_INFO_PARAM) { 58 unsigned int x = *px; 59#else 60UINT64 61bid64_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 70void 71bid64_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 79UINT64 80bid64_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 175void 176bid64_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 184UINT64 185bid64_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 274void 275bid128_from_int32 (UINT128 * pres, 276 int *px _EXC_MASKS_PARAM _EXC_INFO_PARAM) { 277 int x = *px; 278#else 279UINT128 280bid128_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 296void 297bid128_from_uint32 (UINT128 * pres, unsigned int *px 298 _EXC_MASKS_PARAM _EXC_INFO_PARAM) { 299 unsigned int x = *px; 300#else 301UINT128 302bid128_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 312void 313bid128_from_int64 (UINT128 * pres, SINT64 * px 314 _EXC_MASKS_PARAM _EXC_INFO_PARAM) { 315 SINT64 x = *px; 316#else 317UINT128 318bid128_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 335void 336bid128_from_uint64 (UINT128 * pres, UINT64 * px 337 _EXC_MASKS_PARAM _EXC_INFO_PARAM) { 338 UINT64 x = *px; 339#else 340UINT128 341bid128_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