This patch adds support for C23's _BitInt for LoongArch. >From the LoongArch psABI[1]:
> _BitInt(N) objects are stored in little-endian order in memory > and are signed by default. > > For N ≤ 64, a _BitInt(N) object have the same size and alignment > of the smallest fundamental integral type that can contain it. > The unused high-order bits within this containing type are filled > with sign or zero extension of the N-bit value, depending on whether > the _BitInt(N) object is signed or unsigned. The _BitInt(N) object > propagates its signedness to the containing type and is laid out > in a register or memory as an object of this type. > > For N > 64, _BitInt(N) objects are implemented as structs of 64-bit > integer chunks. The number of chunks is the smallest even integer M > so that M * 64 ≥ N. These objects are of the same size of the struct > containing the chunks, but always have 16-byte alignment. If there > are unused bits in the highest-ordered chunk that contains used > bits, they are defined as the sign- or zero- extension of the used > bits depending on whether the _BitInt(N) object is signed or > unsigned. If an entire chunk is unused, its bits are undefined. [1] https://github.com/loongson/la-abi-specs PR target/117599 gcc/ChangeLog: * config/loongarch/loongarch.h: Define a PROMOTE_MODE case for small _BitInts. * config/loongarch/loongarch.cc (loongarch_promote_function_mode): Same. (loongarch_bitint_type_info): New function. (TARGET_C_BITINT_TYPE_INFO): Declare. libgcc/ChangeLog: * config/loongarch/t-softfp-tf: Enable _BitInt helper functions. * config/loongarch/t-loongarch: Same. * config/loongarch/libgcc-loongarch.ver: New file. gcc/testsuite/ChangeLog: * gcc.target/loongarch/bitint-alignments.c: New test. * gcc.target/loongarch/bitint-args.c: New test. * gcc.target/loongarch/bitint-sizes.c: New test. --- gcc/config/loongarch/loongarch.cc | 35 +++++++- gcc/config/loongarch/loongarch.h | 4 +- .../gcc.target/loongarch/bitint-alignments.c | 58 +++++++++++++ .../gcc.target/loongarch/bitint-args.c | 81 +++++++++++++++++++ .../gcc.target/loongarch/bitint-sizes.c | 60 ++++++++++++++ libgcc/config/loongarch/libgcc-loongarch.ver | 26 ++++++ libgcc/config/loongarch/t-loongarch | 2 + libgcc/config/loongarch/t-softfp-tf | 1 + 8 files changed, 264 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/gcc.target/loongarch/bitint-alignments.c create mode 100644 gcc/testsuite/gcc.target/loongarch/bitint-args.c create mode 100644 gcc/testsuite/gcc.target/loongarch/bitint-sizes.c create mode 100644 libgcc/config/loongarch/libgcc-loongarch.ver diff --git a/gcc/config/loongarch/loongarch.cc b/gcc/config/loongarch/loongarch.cc index f62e4163c71..b1571f98378 100644 --- a/gcc/config/loongarch/loongarch.cc +++ b/gcc/config/loongarch/loongarch.cc @@ -10850,9 +10850,9 @@ loongarch_expand_vec_cmp (rtx operands[]) to a fixed type. */ static machine_mode -loongarch_promote_function_mode (const_tree type ATTRIBUTE_UNUSED, +loongarch_promote_function_mode (const_tree type, machine_mode mode, - int *punsignedp ATTRIBUTE_UNUSED, + int *punsignedp, const_tree fntype ATTRIBUTE_UNUSED, int for_return ATTRIBUTE_UNUSED) { @@ -11214,6 +11214,34 @@ loongarch_c_mode_for_suffix (char suffix) return VOIDmode; } +/* Implement TARGET_C_BITINT_TYPE_INFO. + Return true if _BitInt(N) is supported and fill its details into *INFO. */ +bool +loongarch_bitint_type_info (int n, struct bitint_info *info) +{ + if (n <= 8) + info->limb_mode = QImode; + else if (n <= 16) + info->limb_mode = HImode; + else if (n <= 32) + info->limb_mode = SImode; + else if (n <= 64) + info->limb_mode = DImode; + else if (n <= 128) + info->limb_mode = TImode; + else + info->limb_mode = DImode; + + info->abi_limb_mode = info->limb_mode; + + if (n > 64) + info->abi_limb_mode = TImode; + + info->big_endian = false; + info->extended = true; + return true; +} + /* Initialize the GCC target structure. */ #undef TARGET_ASM_ALIGNED_HI_OP #define TARGET_ASM_ALIGNED_HI_OP "\t.half\t" @@ -11488,6 +11516,9 @@ loongarch_c_mode_for_suffix (char suffix) #undef TARGET_C_MODE_FOR_SUFFIX #define TARGET_C_MODE_FOR_SUFFIX loongarch_c_mode_for_suffix +#undef TARGET_C_BITINT_TYPE_INFO +#define TARGET_C_BITINT_TYPE_INFO loongarch_bitint_type_info + struct gcc_target targetm = TARGET_INITIALIZER; #include "gt-loongarch.h" diff --git a/gcc/config/loongarch/loongarch.h b/gcc/config/loongarch/loongarch.h index d8977634b71..73372df838e 100644 --- a/gcc/config/loongarch/loongarch.h +++ b/gcc/config/loongarch/loongarch.h @@ -270,7 +270,9 @@ along with GCC; see the file COPYING3. If not see if (GET_MODE_CLASS (MODE) == MODE_INT \ && GET_MODE_SIZE (MODE) < UNITS_PER_WORD) \ { \ - if ((MODE) == SImode) \ + if ((MODE) == SImode \ + && !(TYPE && TREE_CODE (TYPE) == BITINT_TYPE \ + && TYPE_PRECISION (TYPE) < 32)) \ (UNSIGNEDP) = 0; \ (MODE) = Pmode; \ } diff --git a/gcc/testsuite/gcc.target/loongarch/bitint-alignments.c b/gcc/testsuite/gcc.target/loongarch/bitint-alignments.c new file mode 100644 index 00000000000..8592279b038 --- /dev/null +++ b/gcc/testsuite/gcc.target/loongarch/bitint-alignments.c @@ -0,0 +1,58 @@ +/* { dg-do run { target bitint } } */ +/* { dg-additional-options "-std=c23" } */ + +static long unsigned int +calc_alignof (int n) +{ + if (n > 64) + return alignof(__int128_t); + if (n > 32) + return alignof(long long); + if (n > 16) + return alignof(int); + if (n > 8) + return alignof(short); + else + return alignof(char); +} + +#define CHECK_ALIGNMENT(N) \ + if (alignof(_BitInt(N)) != calc_alignof(N)) \ + __builtin_abort (); + +int main (void) +{ + CHECK_ALIGNMENT(2); + CHECK_ALIGNMENT(3); + CHECK_ALIGNMENT(7); + CHECK_ALIGNMENT(8); + CHECK_ALIGNMENT(9); + CHECK_ALIGNMENT(13); + CHECK_ALIGNMENT(15); + CHECK_ALIGNMENT(16); + CHECK_ALIGNMENT(17); + CHECK_ALIGNMENT(24); + CHECK_ALIGNMENT(31); + CHECK_ALIGNMENT(32); + CHECK_ALIGNMENT(33); + CHECK_ALIGNMENT(42); + CHECK_ALIGNMENT(53); + CHECK_ALIGNMENT(63); + CHECK_ALIGNMENT(64); + CHECK_ALIGNMENT(65); + CHECK_ALIGNMENT(79); + CHECK_ALIGNMENT(96); + CHECK_ALIGNMENT(113); + CHECK_ALIGNMENT(127); + CHECK_ALIGNMENT(128); + CHECK_ALIGNMENT(129); + CHECK_ALIGNMENT(153); + CHECK_ALIGNMENT(255); + CHECK_ALIGNMENT(256); + CHECK_ALIGNMENT(257); + CHECK_ALIGNMENT(353); + CHECK_ALIGNMENT(512); + CHECK_ALIGNMENT(620); + CHECK_ALIGNMENT(1024); + CHECK_ALIGNMENT(30000); +} diff --git a/gcc/testsuite/gcc.target/loongarch/bitint-args.c b/gcc/testsuite/gcc.target/loongarch/bitint-args.c new file mode 100644 index 00000000000..ceba1fb6e3a --- /dev/null +++ b/gcc/testsuite/gcc.target/loongarch/bitint-args.c @@ -0,0 +1,81 @@ +/* { dg-do compile { target bitint } } */ +/* { dg-additional-options "-std=c23 -O -fno-stack-clash-protection -g" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +#define CHECK_ARG(N) \ +void f##N(_BitInt(N) *ptr, _BitInt(N) y) \ +{ \ + *ptr = y; \ +} + + +CHECK_ARG(2) +/* +** f2: +** st.b \$r5,\$r4,0 +** jr \$r1 +*/ +CHECK_ARG(8) +/* +** f8: +** st.b \$r5,\$r4,0 +** jr \$r1 +*/ +CHECK_ARG(9) +/* +** f9: +** st.h \$r5,\$r4,0 +** jr \$r1 +*/ +CHECK_ARG(16) +/* +** f16: +** st.h \$r5,\$r4,0 +** jr \$r1 +*/ +CHECK_ARG(19) +/* +** f19: +** stptr.w \$r5,\$r4,0 +** jr \$r1 +*/ +CHECK_ARG(32) +/* +** f32: +** stptr.w \$r5,\$r4,0 +** jr \$r1 +*/ +CHECK_ARG(42) +/* +** f42: +** stptr.d \$r5,\$r4,0 +** jr \$r1 +*/ +CHECK_ARG(64) +/* +** f64: +** stptr.d \$r5,\$r4,0 +** jr \$r1 +*/ +CHECK_ARG(65) +/* +** f65: +** stptr.d \$r5,\$r4,0 +** st.d \$r6,\$r4,8 +** jr \$r1 +*/ +CHECK_ARG(127) +/* +** f127: +** stptr.d \$r5,\$r4,0 +** st.d \$r6,\$r4,8 +** jr \$r1 +*/ + +CHECK_ARG(128) +/* +** f128: +** stptr.d \$r5,\$r4,0 +** st.d \$r6,\$r4,8 +** jr \$r1 +*/ diff --git a/gcc/testsuite/gcc.target/loongarch/bitint-sizes.c b/gcc/testsuite/gcc.target/loongarch/bitint-sizes.c new file mode 100644 index 00000000000..7272f98acbb --- /dev/null +++ b/gcc/testsuite/gcc.target/loongarch/bitint-sizes.c @@ -0,0 +1,60 @@ +/* { dg-do run { target bitint } } */ +/* { dg-additional-options "-std=c23" } */ + +static long unsigned int +calc_size (int n) +{ + if (n > 128) + return ((n - 1)/128 + 1) * sizeof(__int128_t); + if (n > 64) + return sizeof(__int128_t); + if (n > 32) + return sizeof(long long); + if (n > 16) + return sizeof(int); + if (n > 8) + return sizeof(short); + else + return sizeof(char); +} + +#define CHECK_SIZE(N) \ + if (sizeof(_BitInt(N)) != calc_size(N)) \ + __builtin_abort (); + +int main (void) +{ + CHECK_SIZE(2); + CHECK_SIZE(3); + CHECK_SIZE(7); + CHECK_SIZE(8); + CHECK_SIZE(9); + CHECK_SIZE(13); + CHECK_SIZE(15); + CHECK_SIZE(16); + CHECK_SIZE(17); + CHECK_SIZE(24); + CHECK_SIZE(31); + CHECK_SIZE(32); + CHECK_SIZE(33); + CHECK_SIZE(42); + CHECK_SIZE(53); + CHECK_SIZE(63); + CHECK_SIZE(64); + CHECK_SIZE(65); + CHECK_SIZE(79); + CHECK_SIZE(96); + CHECK_SIZE(113); + CHECK_SIZE(127); + CHECK_SIZE(128); + CHECK_SIZE(129); + CHECK_SIZE(153); + CHECK_SIZE(255); + CHECK_SIZE(256); + CHECK_SIZE(257); + CHECK_SIZE(353); + CHECK_SIZE(512); + CHECK_SIZE(620); + CHECK_SIZE(1024); + CHECK_SIZE(30000); +} diff --git a/libgcc/config/loongarch/libgcc-loongarch.ver b/libgcc/config/loongarch/libgcc-loongarch.ver new file mode 100644 index 00000000000..92fb511037e --- /dev/null +++ b/libgcc/config/loongarch/libgcc-loongarch.ver @@ -0,0 +1,26 @@ +# Copyright (C) 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. +# +# You should have received a copy of the GNU General Public License +# along with GCC; see the file COPYING3. If not see +# <http://www.gnu.org/licenses/>. + +GCC_16.0.0 { + __mulbitint3 + __divmodbitint4 + __fixsfbitint + __fixdfbitint + __floatbitintsf + __floatbitintdf +} diff --git a/libgcc/config/loongarch/t-loongarch b/libgcc/config/loongarch/t-loongarch index 2a7dbf6ca83..b9374fc7001 100644 --- a/libgcc/config/loongarch/t-loongarch +++ b/libgcc/config/loongarch/t-loongarch @@ -5,3 +5,5 @@ softfp_int_modes := si di softfp_extensions := softfp_truncations := softfp_exclude_libgcc2 := n + +SHLIB_MAPFILES += $(srcdir)/config/loongarch/libgcc-loongarch.ver diff --git a/libgcc/config/loongarch/t-softfp-tf b/libgcc/config/loongarch/t-softfp-tf index 306677b1255..be2b7302941 100644 --- a/libgcc/config/loongarch/t-softfp-tf +++ b/libgcc/config/loongarch/t-softfp-tf @@ -1,3 +1,4 @@ softfp_float_modes += tf softfp_extensions += sftf dftf softfp_truncations += tfsf tfdf +softfp_extras += floatbitinttf fixtfbitint -- 2.46.0