mirror of git://gcc.gnu.org/git/gcc.git
360 lines
11 KiB
C
360 lines
11 KiB
C
/* Software floating-point emulation.
|
|
Definitions for _BitInt implementation details.
|
|
|
|
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/>. */
|
|
|
|
#ifndef GCC_SOFT_FP_BITINT_H
|
|
#define GCC_SOFT_FP_BITINT_H
|
|
|
|
#ifdef __BITINT_MAXWIDTH__
|
|
#define BIL_UNITS_PER_WORD (__LIBGCC_BITINT_LIMB_WIDTH__ / __CHAR_BIT__)
|
|
|
|
#if BIL_UNITS_PER_WORD == 8
|
|
#define BIL_TYPE_SIZE (8 * __CHAR_BIT__)
|
|
#define BILtype DItype
|
|
typedef UDItype __attribute__ ((__may_alias__)) UBILtype;
|
|
#elif BIL_UNITS_PER_WORD == 4
|
|
#define BIL_TYPE_SIZE (4 * __CHAR_BIT__)
|
|
#define BILtype SItype
|
|
typedef USItype __attribute__ ((__may_alias__)) UBILtype;
|
|
#elif BIL_UNITS_PER_WORD == 2
|
|
#define BIL_TYPE_SIZE (2 * __CHAR_BIT__)
|
|
#define BILtype HItype
|
|
typedef UHItype __attribute__ ((__may_alias__)) UBILtype;
|
|
#else
|
|
#define BIL_TYPE_SIZE __CHAR_BIT__
|
|
#define BILtype QItype
|
|
typedef UQItype __attribute__ ((__may_alias__)) UBILtype;
|
|
#endif
|
|
|
|
/* If *P is zero or sign extended (the latter only for PREC < 0) from
|
|
some narrower _BitInt value, reduce precision. */
|
|
|
|
static inline __attribute__((__always_inline__)) SItype
|
|
bitint_reduce_prec (const UBILtype **p, SItype prec)
|
|
{
|
|
UBILtype mslimb;
|
|
SItype i;
|
|
if (prec < 0)
|
|
{
|
|
#if __LIBGCC_BITINT_ORDER__ == __ORDER_BIG_ENDIAN__
|
|
i = 0;
|
|
#else
|
|
i = ((USItype) -1 - prec) / BIL_TYPE_SIZE;
|
|
#endif
|
|
mslimb = (*p)[i];
|
|
if (mslimb & ((UBILtype) 1 << (((USItype) -1 - prec) % BIL_TYPE_SIZE)))
|
|
{
|
|
SItype n = ((USItype) -prec) % BIL_TYPE_SIZE;
|
|
if (n)
|
|
{
|
|
mslimb |= ((UBILtype) -1 << (((USItype) -1 - prec) % BIL_TYPE_SIZE));
|
|
if (mslimb == (UBILtype) -1)
|
|
{
|
|
prec += n;
|
|
if (prec >= -1)
|
|
return -2;
|
|
#if __LIBGCC_BITINT_ORDER__ == __ORDER_BIG_ENDIAN__
|
|
++p;
|
|
#else
|
|
--i;
|
|
#endif
|
|
mslimb = (*p)[i];
|
|
n = 0;
|
|
}
|
|
}
|
|
while (mslimb == (UBILtype) -1)
|
|
{
|
|
prec += BIL_TYPE_SIZE;
|
|
if (prec >= -1)
|
|
return -2;
|
|
#if __LIBGCC_BITINT_ORDER__ == __ORDER_BIG_ENDIAN__
|
|
++p;
|
|
#else
|
|
--i;
|
|
#endif
|
|
mslimb = (*p)[i];
|
|
}
|
|
if (n == 0)
|
|
{
|
|
if ((BILtype) mslimb >= 0)
|
|
{
|
|
#if __LIBGCC_BITINT_ORDER__ == __ORDER_BIG_ENDIAN__
|
|
--p;
|
|
#endif
|
|
return prec - 1;
|
|
}
|
|
}
|
|
return prec;
|
|
}
|
|
else
|
|
prec = -prec;
|
|
}
|
|
else
|
|
{
|
|
#if __LIBGCC_BITINT_ORDER__ == __ORDER_BIG_ENDIAN__
|
|
i = 0;
|
|
#else
|
|
i = ((USItype) prec - 1) / BIL_TYPE_SIZE;
|
|
#endif
|
|
mslimb = (*p)[i];
|
|
}
|
|
SItype n = ((USItype) prec) % BIL_TYPE_SIZE;
|
|
if (n)
|
|
{
|
|
mslimb &= ((UBILtype) 1 << (((USItype) prec) % BIL_TYPE_SIZE)) - 1;
|
|
if (mslimb == 0)
|
|
{
|
|
prec -= n;
|
|
if (prec == 0)
|
|
return 1;
|
|
#if __LIBGCC_BITINT_ORDER__ == __ORDER_BIG_ENDIAN__
|
|
++p;
|
|
#else
|
|
--i;
|
|
#endif
|
|
mslimb = (*p)[i];
|
|
}
|
|
}
|
|
while (mslimb == 0)
|
|
{
|
|
prec -= BIL_TYPE_SIZE;
|
|
if (prec == 0)
|
|
return 1;
|
|
#if __LIBGCC_BITINT_ORDER__ == __ORDER_BIG_ENDIAN__
|
|
++p;
|
|
#else
|
|
--i;
|
|
#endif
|
|
mslimb = (*p)[i];
|
|
}
|
|
return prec;
|
|
}
|
|
|
|
#if __LIBGCC_BITINT_ORDER__ == __ORDER_BIG_ENDIAN__
|
|
# define BITINT_INC -1
|
|
# define BITINT_END(be, le) (be)
|
|
#else
|
|
# define BITINT_INC 1
|
|
# define BITINT_END(be, le) (le)
|
|
#endif
|
|
|
|
/* Negate N limbs from S into D. D and S should point to
|
|
the least significant limb. */
|
|
|
|
static inline __attribute__((__always_inline__)) void
|
|
bitint_negate (UBILtype *d, const UBILtype *s, SItype n)
|
|
{
|
|
UBILtype c = 1;
|
|
do
|
|
{
|
|
UBILtype sv = *s, lo;
|
|
s += BITINT_INC;
|
|
c = __builtin_add_overflow (~sv, c, &lo);
|
|
*d = lo;
|
|
d += BITINT_INC;
|
|
}
|
|
while (--n);
|
|
}
|
|
|
|
/* Common final part of __fix?fbitint conversion functions.
|
|
The A floating point value should have been converted using
|
|
soft-fp macros into RV, U##DI##type DI##_BITS precise normal
|
|
integral type and SHIFT, how many bits should that value be
|
|
shifted to the left. R is pointer to limbs array passed to the
|
|
function, RN number of limbs in it, ARPREC absolute value of
|
|
RPREC argument passed to it, RSIZE number of significant bits in RV.
|
|
RSIGNED is non-zero if the result is signed bit-precise integer,
|
|
otherwise zero. If OVF is true, instead of storing RV shifted left
|
|
by SHIFT bits and zero or sign extended store minimum or maximum
|
|
of the signed or unsigned bit-precise integer type or zero depending on if
|
|
RV contains the minimum or maximum signed or unsigned value or zero. */
|
|
|
|
#define FP_TO_BITINT(r, rn, arprec, shift, rv, rsize, rsigned, ovf, DI) \
|
|
if (ovf) \
|
|
{ \
|
|
if ((rv & 1) != 0) \
|
|
__builtin_memset (r, -1, rn * sizeof (UBILtype)); \
|
|
else \
|
|
__builtin_memset (r, 0, rn * sizeof (UBILtype)); \
|
|
if (rv & (((U##DI##type) 1) << (rsize - 1))) \
|
|
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)); \
|
|
} \
|
|
else \
|
|
{ \
|
|
USItype shiftl = shift / BIL_TYPE_SIZE; \
|
|
rsize = DI##_BITS; \
|
|
if (rsigned && (DI##type) rv >= 0) \
|
|
rsigned = 0; \
|
|
if (shift + DI##_BITS > arprec) \
|
|
rsize = arprec - shift; \
|
|
USItype shiftr = shift % BIL_TYPE_SIZE; \
|
|
if (shiftl) \
|
|
__builtin_memset (r + BITINT_END (rn - shiftl, 0), 0, \
|
|
shiftl * sizeof (UBILtype)); \
|
|
USItype idx = BITINT_END (rn - shiftl - 1, shiftl); \
|
|
DI##type rvs = rv; \
|
|
if (shiftr) \
|
|
{ \
|
|
r[idx] = (rsigned ? (UBILtype) rvs : (UBILtype) rv) << shiftr;\
|
|
idx += BITINT_INC; \
|
|
if (rsize > BIL_TYPE_SIZE - shiftr) \
|
|
{ \
|
|
rv >>= BIL_TYPE_SIZE - shiftr; \
|
|
rvs >>= BIL_TYPE_SIZE - shiftr; \
|
|
rsize -= BIL_TYPE_SIZE - shiftr; \
|
|
} \
|
|
else \
|
|
rsize = 0; \
|
|
} \
|
|
while (rsize) \
|
|
{ \
|
|
r[idx] = rsigned ? (UBILtype) rvs : (UBILtype) rv; \
|
|
idx += BITINT_INC; \
|
|
if (rsize <= BIL_TYPE_SIZE) \
|
|
break; \
|
|
rv >>= (DI##_BITS > BIL_TYPE_SIZE ? BIL_TYPE_SIZE : 0); \
|
|
rvs >>= (DI##_BITS > BIL_TYPE_SIZE ? BIL_TYPE_SIZE : 0); \
|
|
rsize -= BIL_TYPE_SIZE; \
|
|
} \
|
|
if (idx < rn) \
|
|
__builtin_memset (r + BITINT_END (0, idx), rsigned ? -1 : 0, \
|
|
BITINT_END (idx + 1, rn - idx) \
|
|
* sizeof (UBILtype)); \
|
|
}
|
|
|
|
/* Common initial part of __floatbitint?f conversion functions.
|
|
I and IPREC are arguments passed to those functions, convert that
|
|
into a pair of DI##type IV integer and SHIFT, such that converting
|
|
IV to floating point and multiplicating that by pow (2, SHIFT)
|
|
gives the expected result. IV size needs to be chosen such that
|
|
it is larger than number of bits in floating-point mantissa and
|
|
contains there even at least a two bits below the mantissa for
|
|
rounding purposes. If any of the SHIFT bits shifted out is non-zero,
|
|
the least significant bit should be non-zero. */
|
|
|
|
#define FP_FROM_BITINT(i, iprec, iv, shift, DI) \
|
|
do \
|
|
{ \
|
|
iprec = bitint_reduce_prec (&i, iprec); \
|
|
USItype aiprec = iprec < 0 ? -iprec : iprec; \
|
|
USItype in = (aiprec + BIL_TYPE_SIZE - 1) / BIL_TYPE_SIZE; \
|
|
USItype idx = BITINT_END (0, in - 1); \
|
|
UBILtype msb = i[idx]; \
|
|
SItype n = 0; \
|
|
if (aiprec % BIL_TYPE_SIZE) \
|
|
{ \
|
|
if (iprec > 0) \
|
|
msb &= ((UBILtype) 1 << (aiprec % BIL_TYPE_SIZE)) - 1; \
|
|
else \
|
|
msb |= (UBILtype) -1 << (aiprec % BIL_TYPE_SIZE); \
|
|
} \
|
|
if (iprec < 0) \
|
|
{ \
|
|
if (msb == (UBILtype) -1) \
|
|
n = 1; \
|
|
else \
|
|
n = (sizeof (0ULL) * __CHAR_BIT__ + 1 \
|
|
- __builtin_clzll (~msb)); \
|
|
if (BIL_TYPE_SIZE > DI##_BITS && n > DI##_BITS) \
|
|
{ \
|
|
iv = msb >> (n - DI##_BITS); \
|
|
shift = n - DI##_BITS; \
|
|
n = 0; \
|
|
} \
|
|
else \
|
|
{ \
|
|
iv = (BILtype) msb; \
|
|
n = DI##_BITS - n; \
|
|
} \
|
|
} \
|
|
/* bitint_reduce_prec guarantees that if msb is 0, then whole \
|
|
i must be zero, otherwise it would have reduced the \
|
|
precision. */ \
|
|
else if (msb == 0) \
|
|
iv = 0; \
|
|
else \
|
|
{ \
|
|
n = sizeof (0ULL) * __CHAR_BIT__ - __builtin_clzll (msb); \
|
|
if (BIL_TYPE_SIZE >= DI##_BITS && n >= DI##_BITS) \
|
|
{ \
|
|
iv = msb >> (n - DI##_BITS + 1); \
|
|
shift = n - DI##_BITS + 1; \
|
|
n = 0; \
|
|
} \
|
|
else \
|
|
{ \
|
|
iv = msb; \
|
|
n = DI##_BITS - 1 - n; \
|
|
} \
|
|
} \
|
|
while (n && BITINT_END (idx < in - 1, idx)) \
|
|
{ \
|
|
idx -= BITINT_INC; \
|
|
msb = i[idx]; \
|
|
if (BIL_TYPE_SIZE < DI##_BITS && n >= BIL_TYPE_SIZE) \
|
|
{ \
|
|
iv = (U##DI##type) iv << (BIL_TYPE_SIZE < DI##_BITS \
|
|
? BIL_TYPE_SIZE : 0); \
|
|
iv |= msb; \
|
|
n -= BIL_TYPE_SIZE; \
|
|
} \
|
|
else \
|
|
{ \
|
|
iv = (U##DI##type) iv << n; \
|
|
iv |= msb >> (BIL_TYPE_SIZE - n); \
|
|
shift = BIL_TYPE_SIZE - n; \
|
|
break; \
|
|
} \
|
|
} \
|
|
\
|
|
UBILtype low_bits = 0; \
|
|
if (shift) \
|
|
low_bits = msb & (((UBILtype) 1 << shift) - 1); \
|
|
shift += BITINT_END (in - 1 - idx, idx) * BIL_TYPE_SIZE; \
|
|
while (!low_bits && BITINT_END (idx < in - 1, idx)) \
|
|
{ \
|
|
idx -= BITINT_INC; \
|
|
low_bits |= i[idx]; \
|
|
} \
|
|
iv |= (low_bits != 0); \
|
|
} \
|
|
while (0)
|
|
|
|
extern void __mulbitint3 (UBILtype *, SItype, const UBILtype *, SItype,
|
|
const UBILtype *, SItype);
|
|
extern void __divmodbitint4 (UBILtype *, SItype, UBILtype *, SItype,
|
|
const UBILtype *, SItype,
|
|
const UBILtype *, SItype);
|
|
|
|
extern USItype __bid_pow10bitint (UBILtype *, SItype, USItype);
|
|
|
|
#endif /* __BITINT_MAXWIDTH__ */
|
|
|
|
#endif /* GCC_SOFT_FP_BITINT_H */
|