mirror of
https://gcc.gnu.org/git/gcc.git
synced 2024-11-24 03:14:08 +08:00
2ce182e258
This patch adds the library helpers for multiplication, division + modulo and casts from and to floating point (both binary and decimal). As described in the intro, the first step is try to reduce further the passed in precision by skipping over most significant limbs with just zeros or sign bit copies. For multiplication and division I've implemented a simple algorithm, using something smarter like Karatsuba or Toom N-Way might be faster for very large _BitInts (which we don't support right now anyway), but could mean more code in libgcc, which maybe isn't what people are willing to accept. For the to/from floating point conversions the patch uses soft-fp, because it already has tons of handy macros which can be used for that. In theory it could be implemented using {,unsigned} long long or {,unsigned} __int128 to/from floating point conversions with some frexp before/after, but at that point we already need to force it into integer registers and analyze it anyway. Plus, for 32-bit arches there is no __int128 that could be used for XF/TF mode stuff. I know that soft-fp is owned by glibc and I think the op-common.h change should be propagated there, but the bitint stuff is really GCC specific and IMHO doesn't belong into the glibc copy. 2023-09-06 Jakub Jelinek <jakub@redhat.com> PR c/102989 libgcc/ * config/aarch64/t-softfp (softfp_extras): Use += rather than :=. * config/i386/64/t-softfp (softfp_extras): Likewise. * config/i386/libgcc-glibc.ver (GCC_14.0.0): Export _BitInt support routines. * config/i386/t-softfp (softfp_extras): Add fixxfbitint and bf, hf and xf mode floatbitint. (CFLAGS-floatbitintbf.c, CFLAGS-floatbitinthf.c): Add -msse2. * config/riscv/t-softfp32 (softfp_extras): Use += rather than :=. * config/rs6000/t-e500v1-fp (softfp_extras): Likewise. * config/rs6000/t-e500v2-fp (softfp_extras): Likewise. * config/t-softfp (softfp_floatbitint_funcs): New. (softfp_bid_list): New. (softfp_func_list): Add sf and df mode from and to _BitInt libcalls. (softfp_bid_file_list): New. (LIB2ADD_ST): Add $(softfp_bid_file_list). * config/t-softfp-sfdftf (softfp_extras): Add fixtfbitint and floatbitinttf. * config/t-softfp-tf (softfp_extras): Likewise. * libgcc2.c (bitint_reduce_prec): New inline function. (BITINT_INC, BITINT_END): Define. (bitint_mul_1, bitint_addmul_1): New helper functions. (__mulbitint3): New function. (bitint_negate, bitint_submul_1): New helper functions. (__divmodbitint4): New function. * libgcc2.h (LIBGCC2_UNITS_PER_WORD): When building _BitInt support libcalls, redefine depending on __LIBGCC_BITINT_LIMB_WIDTH__. (__mulbitint3, __divmodbitint4): Declare. * libgcc-std.ver.in (GCC_14.0.0): Export _BitInt support routines. * Makefile.in (lib2funcs): Add _mulbitint3. (LIB2_DIVMOD_FUNCS): Add _divmodbitint4. * soft-fp/bitint.h: New file. * soft-fp/fixdfbitint.c: New file. * soft-fp/fixsfbitint.c: New file. * soft-fp/fixtfbitint.c: New file. * soft-fp/fixxfbitint.c: New file. * soft-fp/floatbitintbf.c: New file. * soft-fp/floatbitintdf.c: New file. * soft-fp/floatbitinthf.c: New file. * soft-fp/floatbitintsf.c: New file. * soft-fp/floatbitinttf.c: New file. * soft-fp/floatbitintxf.c: New file. * soft-fp/op-common.h (_FP_FROM_INT): Add support for rsize up to 4 * _FP_W_TYPE_SIZE rather than just 2 * _FP_W_TYPE_SIZE. * soft-fp/bitintpow10.c: New file. * soft-fp/fixsdbitint.c: New file. * soft-fp/fixddbitint.c: New file. * soft-fp/fixtdbitint.c: New file. * soft-fp/floatbitintsd.c: New file. * soft-fp/floatbitintdd.c: New file. * soft-fp/floatbitinttd.c: New file.
133 lines
5.1 KiB
C
133 lines
5.1 KiB
C
/* Software floating-point emulation.
|
|
Compute powers of 10 into _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__
|
|
# define BIL_VAL(x) ((UBILtype) (x))
|
|
# if BIL_TYPE_SIZE == 64
|
|
# define BIL_PAIR(x, y) ((BIL_VAL (x) << 32) | BIL_VAL (y))
|
|
# define BIL_OFF(x, y) (x)
|
|
# elif BIL_TYPE_SIZE == 32
|
|
# if __LIBGCC_BITINT_ORDER__ == __ORDER_BIG_ENDIAN__
|
|
# define BIL_PAIR(x, y) BIL_VAL (x), BIL_VAL (y)
|
|
# else
|
|
# define BIL_PAIR(x, y) BIL_VAL (y), BIL_VAL (x)
|
|
# endif
|
|
# define BIL_OFF(x, y) (y)
|
|
# else
|
|
# error Unsupported _BitInt limb size
|
|
# endif
|
|
#if __LIBGCC_BITINT_ORDER__ == __ORDER_BIG_ENDIAN__
|
|
# define BIL_SET2(a, b) a, b
|
|
# define BIL_SET3(a, b, c) a, b, c
|
|
# define BIL_SET4(a, b, c, d) a, b, c, d
|
|
# define BIL_SET5(a, b, c, d, e) a, b, c, d, e
|
|
# define BIL_SET6(a, b, c, d, e, f) a, b, c, d, e, f
|
|
# define BIL_SET7(a, b, c, d, e, f, g) a, b, c, d, e, f, g
|
|
# define BIL_SET8(a, b, c, d, e, f, g, h) a, b, c, d, e, f, g, h
|
|
# define BIL_SET9(a, b, c, d, e, f, g, h, i) a, b, c, d, e, f, g, h, i
|
|
# define BIL_SET10(a, b, c, d, e, f, g, h, i, j) a, b, c, d, e, f, g, h, i, j
|
|
# define BIL_SET11(a, b, c, d, e, f, g, h, i, j, k) \
|
|
a, b, c, d, e, f, g, h, i, j, k
|
|
# define BIL_SET12(a, b, c, d, e, f, g, h, i, j, k, l) \
|
|
a, b, c, d, e, f, g, h, i, j, k, l
|
|
# define BIL_SET13(a, b, c, d, e, f, g, h, i, j, k, l, m) \
|
|
a, b, c, d, e, f, g, h, i, j, k, l, m
|
|
# define BIL_SET14(a, b, c, d, e, f, g, h, i, j, k, l, m, n) \
|
|
a, b, c, d, e, f, g, h, i, j, k, l, m, n
|
|
# define BIL_SET15(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) \
|
|
a, b, c, d, e, f, g, h, i, j, k, l, m, n, o
|
|
#else
|
|
# define BIL_SET2(a, b) b, a
|
|
# define BIL_SET3(a, b, c) c, b, a
|
|
# define BIL_SET4(a, b, c, d) d, c, b, a
|
|
# define BIL_SET5(a, b, c, d, e) e, d, c, b, a
|
|
# define BIL_SET6(a, b, c, d, e, f) f, e, d, c, b, a
|
|
# define BIL_SET7(a, b, c, d, e, f, g) g, f, e, d, c, b, a
|
|
# define BIL_SET8(a, b, c, d, e, f, g, h) h, g, f, e, d, c, b, a
|
|
# define BIL_SET9(a, b, c, d, e, f, g, h, i) i, h, g, f, e, d, c, b, a
|
|
# define BIL_SET10(a, b, c, d, e, f, g, h, i, j) j, i, h, g, f, e, d, c, b, a
|
|
# define BIL_SET11(a, b, c, d, e, f, g, h, i, j, k) \
|
|
k, j, i, h, g, f, e, d, c, b, a
|
|
# define BIL_SET12(a, b, c, d, e, f, g, h, i, j, k, l) \
|
|
l, k, j, i, h, g, f, e, d, c, b, a
|
|
# define BIL_SET13(a, b, c, d, e, f, g, h, i, j, k, l, m) \
|
|
m, l, k, j, i, h, g, f, e, d, c, b, a
|
|
# define BIL_SET14(a, b, c, d, e, f, g, h, i, j, k, l, m, n) \
|
|
n, m, l, k, j, i, h, g, f, e, d, c, b, a
|
|
# define BIL_SET15(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) \
|
|
o, n, m, l, k, j, i, h, g, f, e, d, c, b, a
|
|
#endif
|
|
|
|
#include "bitintpow10.h"
|
|
|
|
/* Set r (_BitInt limbs with rprec bits) to pow10 (n),
|
|
where n is in [0, 6111]. Returns number of least significant
|
|
limbs with just 0s in it. */
|
|
|
|
USItype
|
|
__bid_pow10bitint (UBILtype *r, SItype rprec, USItype n)
|
|
{
|
|
USItype rn = ((USItype) rprec + BIL_TYPE_SIZE - 1) / BIL_TYPE_SIZE;
|
|
if (n <= 256)
|
|
{
|
|
/* No need to multiply anything, just copy it from pow10_limbs
|
|
array. */
|
|
USItype low_zeros = (n / 64) * (64 / BIL_TYPE_SIZE);
|
|
UBILtype *p = &pow10_limbs[pow10_offs[n]];
|
|
USItype cnt = pow10_offs[n + 1] - pow10_offs[n];
|
|
if (low_zeros)
|
|
__builtin_memset (r + BITINT_END (rn - low_zeros, 0), '\0',
|
|
low_zeros * sizeof (UBILtype));
|
|
__builtin_memcpy (r + BITINT_END (rn - low_zeros - cnt, low_zeros),
|
|
p, cnt * sizeof (UBILtype));
|
|
if (rn > low_zeros + cnt)
|
|
__builtin_memset (r + BITINT_END (0, low_zeros + cnt), '\0',
|
|
(rn - low_zeros - cnt) * sizeof (UBILtype));
|
|
return low_zeros;
|
|
}
|
|
else
|
|
{
|
|
USItype m = n / 256;
|
|
n &= 255;
|
|
USItype low_zeros = ((n / 64) + (m * 4)) * (64 / BIL_TYPE_SIZE);
|
|
UBILtype *pm = &pow10_limbs[pow10_offs[m + 255]];
|
|
USItype cntm = pow10_offs[m + 256] - pow10_offs[m + 255];
|
|
UBILtype *pn = &pow10_limbs[pow10_offs[n]];
|
|
USItype cntn = pow10_offs[n + 1] - pow10_offs[n];
|
|
if (low_zeros)
|
|
__builtin_memset (r + BITINT_END (rn - low_zeros, 0), '\0',
|
|
low_zeros * sizeof (UBILtype));
|
|
__mulbitint3 (r + BITINT_END (0, low_zeros),
|
|
rprec - low_zeros * BIL_TYPE_SIZE,
|
|
pm, cntm * BIL_TYPE_SIZE, pn, cntn * BIL_TYPE_SIZE);
|
|
return low_zeros;
|
|
}
|
|
}
|
|
#endif
|