| /* Software floating-point emulation. | |
| Convert _Decimal64 to signed or unsigned _BitInt. | |
| Copyright (C) 2023-2025 Free Software Foundation, Inc. | |
| This file is part of GCC. | |
| GCC is free software; you can redistribute it and/or modify it under | |
| the terms of the GNU General Public License as published by the Free | |
| Software Foundation; either version 3, or (at your option) any later | |
| version. | |
| GCC is distributed in the hope that it will be useful, but WITHOUT ANY | |
| WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| for more details. | |
| Under Section 7 of GPL version 3, you are granted additional | |
| permissions described in the GCC Runtime Library Exception, version | |
| 3.1, as published by the Free Software Foundation. | |
| You should have received a copy of the GNU General Public License and | |
| a copy of the GCC Runtime Library Exception along with this program; | |
| see the files COPYING3 and COPYING.RUNTIME respectively. If not, see | |
| <http://www.gnu.org/licenses/>. */ | |
| #include "soft-fp.h" | |
| #include "bitint.h" | |
| #ifdef __BITINT_MAXWIDTH__ | |
| #ifndef ENABLE_DECIMAL_BID_FORMAT | |
| #define __bid_fixddbitint __dpd_fixddbitint | |
| #endif | |
| extern void __bid_fixddbitint (UBILtype *, SItype, _Decimal64); | |
| void | |
| __bid_fixddbitint (UBILtype *r, SItype rprec, _Decimal64 a) | |
| { | |
| FP_DECL_EX; | |
| USItype arprec = rprec < 0 ? -rprec : rprec; | |
| USItype rn = (arprec + BIL_TYPE_SIZE - 1) / BIL_TYPE_SIZE; | |
| union { _Decimal64 d; UDItype u; } u; | |
| UDItype mantissa, t; | |
| SItype sgn; | |
| SItype exponent; | |
| USItype exp_bits, mant_bits; | |
| UBILtype *pow10v, *resv; | |
| USItype pow10_limbs, res_limbs, min_limbs, mant_limbs, low_zeros; | |
| FP_INIT_EXCEPTIONS; | |
| u.d = a; | |
| t = u.u >> 51; | |
| sgn = (DItype) u.u < 0; | |
| #ifdef ENABLE_DECIMAL_BID_FORMAT | |
| if ((t & (3 << 10)) != (3 << 10)) | |
| { | |
| mantissa = u.u & ((((UDItype) 1) << 53) - 1); | |
| exponent = (t >> 2) & 0x3ff; | |
| } | |
| else if ((t & (3 << 8)) != (3 << 8)) | |
| { | |
| mantissa = u.u & ((((UDItype) 1) << 51) - 1); | |
| mantissa |= ((UDItype) 1) << 53; | |
| exponent = t & 0x3ff; | |
| if (mantissa > (UDItype) 9999999999999999) | |
| mantissa = 0; | |
| } | |
| #else | |
| if ((t & (15 << 8)) != (15 << 8)) | |
| { | |
| exponent = (u.u >> 50) & 255; | |
| if ((t & (3 << 10)) != (3 << 10)) | |
| { | |
| mantissa = ((t >> 7) & 7) * 1000; | |
| exponent += (t >> 2) & (3 << 8); | |
| } | |
| else | |
| { | |
| mantissa = ((t >> 7) & 1) ? 9000 : 8000; | |
| exponent += t & (3 << 8); | |
| } | |
| mantissa += __dpd_d2bbitint[(u.u >> 40) & 1023]; | |
| mantissa *= 1000; | |
| mantissa += __dpd_d2bbitint[(u.u >> 30) & 1023]; | |
| mantissa *= 1000; | |
| mantissa += __dpd_d2bbitint[(u.u >> 20) & 1023]; | |
| mantissa *= 1000; | |
| mantissa += __dpd_d2bbitint[(u.u >> 10) & 1023]; | |
| mantissa *= 1000; | |
| mantissa += __dpd_d2bbitint[u.u & 1023]; | |
| } | |
| #endif | |
| else | |
| { | |
| FP_SET_EXCEPTION (FP_EX_INVALID | |
| | FP_EX_INVALID_CVI | |
| | ((FP_EX_INVALID_SNAN | |
| && ((t & 0x80)) != 0) | |
| ? FP_EX_INVALID_SNAN : 0)); | |
| ovf: | |
| if (!sgn) | |
| __builtin_memset (r, -1, rn * sizeof (UBILtype)); | |
| else | |
| __builtin_memset (r, 0, rn * sizeof (UBILtype)); | |
| if (sgn ^ (rprec >= 0)) | |
| r[BITINT_END (0, rn - 1)] | |
| |= (UBILtype) -1 << ((arprec - 1) % BIL_TYPE_SIZE); | |
| else | |
| r[BITINT_END (0, rn - 1)] | |
| &= ~((UBILtype) -1 << ((arprec - 1) % BIL_TYPE_SIZE)); | |
| goto done; | |
| } | |
| exponent -= 398; | |
| if (mantissa == 0) | |
| { | |
| /* Zero (with any exponent). */ | |
| zero: | |
| __builtin_memset (r, 0, rn * sizeof (UBILtype)); | |
| goto done; | |
| } | |
| if (exponent <= -16) | |
| { | |
| FP_SET_EXCEPTION (FP_EX_INEXACT); | |
| goto zero; | |
| } | |
| else if (exponent < 0) | |
| { | |
| UBILtype limbs[64 / BIL_TYPE_SIZE]; | |
| UDItype d, rem; | |
| __bid_pow10bitint (limbs, 64, -exponent); | |
| #if BIL_TYPE_SIZE == 64 | |
| d = limbs[0]; | |
| #elif BIL_TYPE_SIZE == 32 | |
| d = (UDItype) limbs[BITINT_END (0, 1)] << 32 | limbs[BITINT_END (1, 0)]; | |
| #else | |
| # error Unsupported BIL_TYPE_SIZE | |
| #endif | |
| rem = mantissa % d; | |
| mantissa /= d; | |
| if (rem) | |
| FP_SET_EXCEPTION (FP_EX_INEXACT); | |
| if (mantissa == 0) | |
| goto zero; | |
| exponent = 0; | |
| } | |
| if (rprec >= 0 && sgn) | |
| { | |
| ovf_ex: | |
| FP_SET_EXCEPTION (FP_EX_INVALID | FP_EX_INVALID_CVI); | |
| goto ovf; | |
| } | |
| /* Lower estimate for number of bits needed for pow10 (exponent). */ | |
| exp_bits = exponent / 3; | |
| exp_bits = exp_bits * 10 - exp_bits / 29; | |
| mant_bits = sizeof (0ULL) * __CHAR_BIT__ - __builtin_clzll (mantissa); | |
| if (exp_bits + mant_bits > arprec + 1) | |
| goto ovf_ex; | |
| /* Upper estimate for number of bits needed for pow10 (exponent). */ | |
| exp_bits = (exponent + 2) / 3; | |
| exp_bits = exp_bits * 10 - exp_bits / 30; | |
| if (exp_bits == 0) | |
| exp_bits = 1; | |
| pow10_limbs = (exp_bits + BIL_TYPE_SIZE - 1) / BIL_TYPE_SIZE; | |
| pow10v = __builtin_alloca (pow10_limbs * sizeof (UBILtype)); | |
| low_zeros = __bid_pow10bitint (pow10v, exp_bits, exponent); | |
| res_limbs = ((exp_bits + mant_bits + BIL_TYPE_SIZE - 1) | |
| / BIL_TYPE_SIZE) - low_zeros; | |
| mant_limbs = (mant_bits + BIL_TYPE_SIZE - 1) / BIL_TYPE_SIZE; | |
| resv = __builtin_alloca ((res_limbs + mant_limbs) * sizeof (UBILtype)); | |
| #if BIL_TYPE_SIZE >= 64 | |
| resv[res_limbs] = mantissa; | |
| #else | |
| if (mant_limbs == 1) | |
| resv[res_limbs] = mantissa; | |
| else | |
| { | |
| resv[res_limbs + BITINT_END (1, 0)] = mantissa; | |
| resv[res_limbs + BITINT_END (0, 1)] = mantissa >> 32; | |
| } | |
| #endif | |
| __mulbitint3 (resv, exp_bits + mant_bits - low_zeros * BIL_TYPE_SIZE, | |
| resv + res_limbs, mant_bits, | |
| pow10v + BITINT_END (0, low_zeros), | |
| exp_bits - low_zeros * BIL_TYPE_SIZE); | |
| if (res_limbs + low_zeros >= rn) | |
| { | |
| if (res_limbs + low_zeros > rn && resv[BITINT_END (0, res_limbs - 1)]) | |
| goto ovf_ex; | |
| if ((arprec % BIL_TYPE_SIZE) != 0 | |
| && (resv[BITINT_END (res_limbs + low_zeros - rn, rn - 1 - low_zeros)] | |
| & ((UBILtype) -1 << (arprec % BIL_TYPE_SIZE))) != 0) | |
| goto ovf_ex; | |
| min_limbs = rn - low_zeros; | |
| } | |
| else | |
| min_limbs = res_limbs; | |
| if (low_zeros) | |
| __builtin_memset (r + BITINT_END (rn - low_zeros, 0), '\0', | |
| low_zeros * sizeof (UBILtype)); | |
| if (sgn) | |
| bitint_negate (r + BITINT_END (rn - low_zeros - 1, low_zeros), | |
| resv + BITINT_END (res_limbs - 1, 0), min_limbs); | |
| else | |
| __builtin_memcpy (r + BITINT_END (rn - low_zeros - min_limbs, low_zeros), | |
| resv + BITINT_END (res_limbs - min_limbs, 0), | |
| min_limbs * sizeof (UBILtype)); | |
| if (res_limbs + low_zeros < rn) | |
| { | |
| if (sgn) | |
| __builtin_memset (r + BITINT_END (0, res_limbs + low_zeros), -1, | |
| (rn - res_limbs - low_zeros) * sizeof (UBILtype)); | |
| else | |
| __builtin_memset (r + BITINT_END (0, res_limbs + low_zeros), '\0', | |
| (rn - res_limbs - low_zeros) * sizeof (UBILtype)); | |
| } | |
| else if (sgn) | |
| { | |
| if ((r[BITINT_END (0, rn - 1)] | |
| & ((UBILtype) 1 << ((arprec - 1) % BIL_TYPE_SIZE))) == 0) | |
| goto ovf_ex; | |
| } | |
| else if (rprec < 0 | |
| && (r[BITINT_END (0, rn - 1)] | |
| & ((UBILtype) 1 << ((arprec - 1) % BIL_TYPE_SIZE))) != 0) | |
| goto ovf_ex; | |
| done: | |
| FP_HANDLE_EXCEPTIONS; | |
| } | |
| #endif |