This patch adds support for C23's _BitInt for LoongArch.

Though there's not an official psABI definition, our plan
is to have 16-byte alignment for N > 64 and the padding bits
sign/zero-extended when passed between procedures.

One exception would be "unsigned _BitInt(32)". To match the
behavior of "unsigned int" in the current LP64 ABIs, it is
sign-extended when stored in a 64-bit GPR as a function
argument or return value.

        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.

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             | 31 ++++++-
 gcc/config/loongarch/loongarch.h              |  4 +-
 .../gcc.target/loongarch/bitint-alignments.c  | 58 ++++++++++++
 .../gcc.target/loongarch/bitint-args.c        | 93 +++++++++++++++++++
 .../gcc.target/loongarch/bitint-sizes.c       | 60 ++++++++++++
 libgcc/config/loongarch/t-softfp-tf           |  1 +
 6 files changed, 244 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

diff --git a/gcc/config/loongarch/loongarch.cc 
b/gcc/config/loongarch/loongarch.cc
index 7533e53839f..f713d904b55 100644
--- a/gcc/config/loongarch/loongarch.cc
+++ b/gcc/config/loongarch/loongarch.cc
@@ -10852,9 +10852,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)
 {
@@ -11216,6 +11216,30 @@ 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
+    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"
@@ -11490,6 +11514,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..c23f152a558
--- /dev/null
+++ b/gcc/testsuite/gcc.target/loongarch/bitint-args.c
@@ -0,0 +1,93 @@
+/* { 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
+*/
+
+CHECK_ARG(129)
+/*
+** f129:
+**     ldptr.d \$r12,\$r5,0
+**     stptr.d \$r12,\$r4,0
+**     ld.d    \$r12,\$r5,8
+**     st.d    \$r12,\$r4,8
+**     ld.d    \$r12,\$r5,16
+**     st.d    \$r12,\$r4,16
+**     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/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.34.1

Reply via email to