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

Reply via email to