blob: 2ba550ff99fe96d7aeb16fa3f224a153d6343918 [file] [log] [blame]
/* Software floating-point emulation.
Convert _Decimal32 to signed or unsigned _BitInt.
Copyright (C) 2023 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__
extern void __bid_fixsdbitint (UBILtype *, SItype, _Decimal32);
void
__bid_fixsdbitint (UBILtype *r, SItype rprec, _Decimal32 a)
{
FP_DECL_EX;
USItype arprec = rprec < 0 ? -rprec : rprec;
USItype rn = (arprec + BIL_TYPE_SIZE - 1) / BIL_TYPE_SIZE;
union { _Decimal32 d; USItype u; } u;
USItype 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 >> 21;
sgn = (SItype) u.u < 0;
if ((t & (3 << 8)) != (3 << 8))
{
mantissa = u.u & ((((USItype) 1) << 23) - 1);
exponent = (t >> 2) & 0xff;
}
else if ((t & (3 << 6)) != (3 << 6))
{
mantissa = u.u & ((((USItype) 1) << 21) - 1);
mantissa |= ((USItype) 1) << 23;
exponent = t & 0xff;
if (mantissa > (USItype) 9999999)
mantissa = 0;
}
else
{
FP_SET_EXCEPTION (FP_EX_INVALID
| FP_EX_INVALID_CVI
| ((FP_EX_INVALID_SNAN
&& ((t & 0x20)) != 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 -= 101;
if (mantissa == 0)
{
/* Zero (with any exponent). */
zero:
__builtin_memset (r, 0, rn * sizeof (UBILtype));
goto done;
}
if (exponent <= -7)
{
FP_SET_EXCEPTION (FP_EX_INEXACT);
goto zero;
}
else if (exponent < 0)
{
UBILtype limbs[64 / BIL_TYPE_SIZE];
USItype rem;
UDItype d;
__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 % (USItype) d;
mantissa /= (USItype) 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 = 1;
resv = __builtin_alloca ((res_limbs + mant_limbs) * sizeof (UBILtype));
resv[res_limbs] = mantissa;
__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 (rn - res_limbs, 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