https://gcc.gnu.org/g:6cf65539ea4e95ece988782885261476140a5c40

commit 6cf65539ea4e95ece988782885261476140a5c40
Author: Kito Cheng <[email protected]>
Date:   Mon Jan 12 21:31:11 2026 +0800

    RISC-V: Add support for _BitInt [PR117581]
    
    This patch implements _BitInt support for RISC-V target by defining the
    type layout and ABI requirements.  The limb mode selection is based on
    the bit width, using appropriate integer modes from QImode to TImode.
    The implementation also adds the necessary libgcc version symbols for
    _BitInt runtime support functions.
    
    Changes in v3:
    - Require sync_char_short effective target for bitint-64.c, bitint-82.c
      and bitint-84.c tests since they use atomic operations.
    - Add -fno-section-anchors to bitint-32-on-rv64.c and adjust expected
      assembly output patterns.
    
    Changes in v2:
    - limb_mode use up to XLEN when N > XLEN, which is different setting from
      the abi_limb_mode.
    - Adding missing floatbitinthf in libgcc.
    
    gcc/ChangeLog:
    
            PR target/117581
            * config/riscv/riscv.cc (riscv_bitint_type_info): New function.
            (TARGET_C_BITINT_TYPE_INFO): Define.
    
    gcc/testsuite/ChangeLog:
    
            PR target/117581
            * gcc.dg/torture/bitint-64.c: Add sync_char_short effective target
            requirement.
            * gcc.dg/torture/bitint-82.c: Likewise.
            * gcc.dg/torture/bitint-84.c: Likewise.
            * gcc.target/riscv/bitint-32-on-rv64.c: New test.
            * gcc.target/riscv/bitint-alignments.c: New test.
            * gcc.target/riscv/bitint-args.c: New test.
            * gcc.target/riscv/bitint-sizes.c: New test.
    
    libgcc/ChangeLog:
    
            PR target/117581
            * config/riscv/libgcc-riscv.ver: New file.
            * config/riscv/t-elf (SHLIB_MAPFILES): Add libgcc-riscv.ver.
            * config/riscv/t-softfp32 (softfp_extras): Add floatbitinttf and
            fixtfbitint.
    
    (cherry picked from commit 808b684172c7689a225f853e2d90a8687e528ea8)

Diff:
---
 gcc/config/riscv/riscv.cc                          | 35 ++++++++
 gcc/testsuite/gcc.dg/torture/bitint-64.c           |  1 +
 gcc/testsuite/gcc.dg/torture/bitint-82.c           | 95 ++++++++++++++++++++++
 gcc/testsuite/gcc.dg/torture/bitint-84.c           | 19 +++++
 gcc/testsuite/gcc.target/riscv/bitint-32-on-rv64.c | 47 +++++++++++
 gcc/testsuite/gcc.target/riscv/bitint-alignments.c | 60 ++++++++++++++
 gcc/testsuite/gcc.target/riscv/bitint-args.c       | 82 +++++++++++++++++++
 gcc/testsuite/gcc.target/riscv/bitint-sizes.c      | 65 +++++++++++++++
 libgcc/config/riscv/libgcc-riscv.ver               | 29 +++++++
 libgcc/config/riscv/t-elf                          |  2 +
 libgcc/config/riscv/t-softfp32                     |  5 +-
 11 files changed, 439 insertions(+), 1 deletion(-)

diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index 945d78d06265..a5bda2e43751 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -14770,8 +14770,40 @@ riscv_c_mode_for_floating_type (enum tree_index ti)
   return default_mode_for_floating_type (ti);
 }
 
+/* Implement TARGET_C_BITINT_TYPE_INFO.
+   Return true if _BitInt(N) is supported and fill its details into *INFO.  */
+bool
+riscv_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 && TARGET_64BIT)
+    info->limb_mode = TImode;
+  else
+    info->limb_mode = TARGET_64BIT ? DImode : SImode;
+
+  info->abi_limb_mode = info->limb_mode;
+
+  if (n > 64 && TARGET_64BIT)
+    info->abi_limb_mode = TImode;
+
+  if (n > 32 && !TARGET_64BIT)
+    info->abi_limb_mode = DImode;
+
+  info->big_endian = TARGET_BIG_ENDIAN;
+  info->extended = true;
+  return true;
+}
+
 /* Parse the attribute arguments to target_version in DECL and modify
    the feature mask and priority required to select those targets.
+
    If LOC is nonnull, report diagnostics against *LOC, otherwise
    remain silent.  */
 static void
@@ -16786,6 +16818,9 @@ riscv_prefetch_offset_address_p (rtx x, machine_mode 
mode)
 #undef TARGET_C_MODE_FOR_FLOATING_TYPE
 #define TARGET_C_MODE_FOR_FLOATING_TYPE riscv_c_mode_for_floating_type
 
+#undef TARGET_C_BITINT_TYPE_INFO
+#define TARGET_C_BITINT_TYPE_INFO riscv_bitint_type_info
+
 #undef TARGET_USE_BY_PIECES_INFRASTRUCTURE_P
 #define TARGET_USE_BY_PIECES_INFRASTRUCTURE_P 
riscv_use_by_pieces_infrastructure_p
 
diff --git a/gcc/testsuite/gcc.dg/torture/bitint-64.c 
b/gcc/testsuite/gcc.dg/torture/bitint-64.c
index 8f0f21cbee29..8a9a732b0341 100644
--- a/gcc/testsuite/gcc.dg/torture/bitint-64.c
+++ b/gcc/testsuite/gcc.dg/torture/bitint-64.c
@@ -1,5 +1,6 @@
 /* PR middle-end/114332 */
 /* { dg-do run { target bitint } } */
+/* { dg-require-effective-target sync_char_short } */
 /* { dg-options "-std=c23 -fwrapv" } */
 /* { dg-skip-if "" { ! run_expensive_tests }  { "*" } { "-O0" "-O2" } } */
 /* { dg-skip-if "" { ! run_expensive_tests } { "-flto" } { "" } } */
diff --git a/gcc/testsuite/gcc.dg/torture/bitint-82.c 
b/gcc/testsuite/gcc.dg/torture/bitint-82.c
new file mode 100644
index 000000000000..76a9cfa439cc
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/bitint-82.c
@@ -0,0 +1,95 @@
+/* { dg-do run { target bitint } } */
+/* { dg-require-effective-target sync_char_short } */
+/* { dg-options "-std=c23 -pedantic-errors" } */
+/* { dg-skip-if "" { ! run_expensive_tests }  { "*" } { "-O0" "-O2" } } */
+/* { dg-skip-if "" { ! run_expensive_tests } { "-flto" } { "" } } */
+
+#if __BITINT_MAXWIDTH__ >= 532
+_BitInt(5) a = 2, b = -2;
+_BitInt(38) c = 12345, d = -12345;
+_BitInt(129) e = 147090211948845388976606115811401318743wb, f = 
-147090211948845388976606115811401318743wb;
+_BitInt(532) g = 34476769918317100226195145251004381172591594205376273814wb, h 
= -102116935649428556311918486808926113041433456371844211259677321wb;
+unsigned _BitInt(1) i = 1;
+unsigned _BitInt(17) j = 49127uwb;
+unsigned _BitInt(60) k = 588141367522129848uwb;
+unsigned _BitInt(205) l = 
33991671979236490040668305838261113909013362173682935296620088uwb;
+unsigned _BitInt(475) z = 
14834685124553929878903720794923785539321715423294864257448721201977655202426343038777008759878862591302200019811097993772912691139803983786083uwb;
+#endif
+
+#include "../bitintext.h"
+
+#if __BITINT_MAXWIDTH__ >= 532
+[[gnu::noipa]] _BitInt(217)
+f1 (_BitInt(9) a, unsigned _BitInt(12) b, _BitInt(36) c, unsigned _BitInt(105) 
d,
+    _BitInt(135) e, unsigned _BitInt(168) f, _BitInt(207) g, _BitInt(207) h,
+    unsigned _BitInt(531) i, _BitInt(36) j)
+{
+  BEXTC (a); BEXTC (b); BEXTC (c); BEXTC (d);
+  BEXTC (e); BEXTC (f); BEXTC (g); BEXTC (h);
+  BEXTC (i); BEXTC (j);
+  _BitInt(9) k = a + 1;
+  unsigned _BitInt(12) l = b - a;
+  _BitInt(36) m = c * j;
+  unsigned _BitInt(105) n = d >> (-2 * j);
+  _BitInt(135) o = e | -j;
+  unsigned _BitInt(168) p = f & 101010101010101010101010uwb;
+  _BitInt(207) q = g * j;
+  _BitInt(207) r = g + h;
+  unsigned _BitInt(531) s = i / j;
+  BEXTC (k); BEXTC (l); BEXTC (m); BEXTC (n);
+  BEXTC (o); BEXTC (p); BEXTC (q); BEXTC (r);
+  BEXTC (s);
+  unsigned _BitInt(105) t = d << (38 - j);
+  BEXTC (t);
+  _Atomic _BitInt(5) u = 15;
+  u += 8U;
+  BEXTC (u);
+  _BitInt(135) v = e << 28;
+  BEXTC (v);
+  unsigned _BitInt(475) w = z << (29 + j);
+  BEXTC (w);
+  return a + 4;
+}
+#endif
+
+int
+main ()
+{
+#if __BITINT_MAXWIDTH__ >= 532
+  BEXTC (a); BEXTC (b);
+  BEXTC (c); BEXTC (d);
+  BEXTC (e); BEXTC (f);
+  BEXTC (g); BEXTC (h);
+  BEXTC (i);
+  BEXTC (j);
+  BEXTC (k);
+  BEXTC (l);
+  BEXTC (z);
+  {
+    _BitInt(5) a = 2, b = -2;
+    _BitInt(38) c = 12345, d = -12345;
+    _BitInt(129) e = 147090211948845388976606115811401318743wb, f = 
-147090211948845388976606115811401318743wb;
+    _BitInt(532) g = 
34476769918317100226195145251004381172591594205376273814wb, h = 
-102116935649428556311918486808926113041433456371844211259677321wb;
+    unsigned _BitInt(1) i = 1;
+    unsigned _BitInt(17) j = 49127uwb;
+    unsigned _BitInt(60) k = 588141367522129848uwb;
+    unsigned _BitInt(205) l = 
33991671979236490040668305838261113909013362173682935296620088uwb;
+    BEXTC (a); BEXTC (b);
+    BEXTC (c); BEXTC (d);
+    BEXTC (e); BEXTC (f);
+    BEXTC (g); BEXTC (h);
+    BEXTC (i);
+    BEXTC (j);
+    BEXTC (k);
+    BEXTC (l);
+  }
+  _BitInt(217) m = f1 (57wb, 3927uwb, 10625699364wb, 
23030359755638571619326514462579uwb,
+                      20797625176303404170317957140841712396356wb,
+                      111831871006433449872067089878311637796827405335256uwb,
+                      
64853652491049541618437564623858346454131583900201311683495230wb,
+                      
25108562626494976011700565632680191924545340440636663075662700wb,
+                      
6366583146545926097709747296452085257498446783797668089081516596003270602920229800152065594152964557479773813310423759077951305431130758723519892452009351743676uwb,
+                      -1);
+  BEXTC (m);
+#endif
+}
diff --git a/gcc/testsuite/gcc.dg/torture/bitint-84.c 
b/gcc/testsuite/gcc.dg/torture/bitint-84.c
new file mode 100644
index 000000000000..cb3f4cbd0728
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/bitint-84.c
@@ -0,0 +1,19 @@
+/* A simple variant of gcc.dg/torture/bitint-64.c */
+/* { dg-do run { target bitint } } */
+/* { dg-require-effective-target sync_char_short } */
+/* { dg-options "-std=c23" } */
+/* { dg-skip-if "" { ! run_expensive_tests }  { "*" } { "-O0" "-O2" } } */
+/* { dg-skip-if "" { ! run_expensive_tests } { "-flto" } { "" } } */
+
+#include "../bitintext.h"
+
+enum E : char { E22 = 22 } e = E22;
+
+int
+main ()
+{
+  _Atomic _BitInt (5) b = 0;
+  b += e;
+  BEXTC (b);
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/riscv/bitint-32-on-rv64.c 
b/gcc/testsuite/gcc.target/riscv/bitint-32-on-rv64.c
new file mode 100644
index 000000000000..bd9246d3c745
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/bitint-32-on-rv64.c
@@ -0,0 +1,47 @@
+/* { dg-do compile { target bitint } } */
+/* { dg-additional-options "-march=rv64gc -mabi=lp64d -std=c23 -O 
-fno-stack-clash-protection -g -fpie -mcmodel=medlow -fno-section-anchors" } */
+/* { dg-skip-if "" { *-*-* } { "-flto" "-O0"} } */
+/* { dg-final { check-function-bodies "**" "" } } */
+
+signed _BitInt(32) a;
+unsigned _BitInt(32) b;
+signed _BitInt(16) c;
+unsigned _BitInt(16) d;
+
+signed _BitInt(32) f1(void) {
+/*
+** f1:
+**     ...
+**     lw      a0,a
+**      ret
+*/
+  return a;
+}
+unsigned _BitInt(32) f2(void) {
+/*
+** f2:
+**     ...
+**     lw      a0,b
+**      ret
+*/
+  return b;
+}
+
+signed _BitInt(16) f3(void) {
+/*
+** f3:
+**     ...
+**     lh      a0,c
+**      ret
+*/
+  return c;
+}
+unsigned _BitInt(16) f4(void) {
+/*
+** f4:
+**     ...
+**     lhu     a0,d
+**      ret
+*/
+  return d;
+}
diff --git a/gcc/testsuite/gcc.target/riscv/bitint-alignments.c 
b/gcc/testsuite/gcc.target/riscv/bitint-alignments.c
new file mode 100644
index 000000000000..01cc41eb88d5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/bitint-alignments.c
@@ -0,0 +1,60 @@
+/* { dg-do run { target bitint } } */
+/* { dg-additional-options "-std=c23" } */
+
+static long unsigned int
+calc_alignof (int n)
+{
+#if __riscv_xlen == 64
+  if (n > 64)
+    return alignof(__int128_t);
+#endif
+  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/riscv/bitint-args.c 
b/gcc/testsuite/gcc.target/riscv/bitint-args.c
new file mode 100644
index 000000000000..eacddc40bd6b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/bitint-args.c
@@ -0,0 +1,82 @@
+/* { dg-do compile { target bitint } } */
+/* { dg-additional-options "-march=rv64gc -mabi=lp64d -std=c23 -O 
-fno-stack-clash-protection -g" } */
+/* { dg-skip-if "" { *-*-* } { "-flto" "-O0"} } */
+/* { dg-final { check-function-bodies "**" "" } } */
+
+#define CHECK_ARG(N)                           \
+void f##N(_BitInt(N) *ptr, _BitInt(N) y)       \
+{                                              \
+    *ptr = y;                                  \
+}
+
+
+CHECK_ARG(2)
+/*
+** f2:
+**     sb      a1,0\(a0\)
+**     ret
+*/
+CHECK_ARG(8)
+/*
+** f8:
+**     sb      a1,0\(a0\)
+**     ret
+*/
+CHECK_ARG(9)
+/*
+** f9:
+**     sh      a1,0\(a0\)
+**     ret
+*/
+CHECK_ARG(16)
+/*
+** f16:
+**     sh      a1,0\(a0\)
+**     ret
+*/
+CHECK_ARG(19)
+/*
+** f19:
+**     sw      a1,0\(a0\)
+**     ret
+*/
+CHECK_ARG(32)
+/*
+** f32:
+**     sw      a1,0\(a0\)
+**     ret
+*/
+CHECK_ARG(42)
+/*
+** f42:
+**     sd      a1,0\(a0\)
+**     ret
+*/
+CHECK_ARG(64)
+/*
+** f64:
+**     sd      a1,0\(a0\)
+**     ret
+*/
+CHECK_ARG(65)
+/*
+** f65:
+**     sd      a1,0\(a0\)
+**     sd      a2,8\(a0\)
+**     ret
+*/
+CHECK_ARG(127)
+/*
+** f127:
+**     sd      a1,0\(a0\)
+**     sd      a2,8\(a0\)
+**     ret
+*/
+
+CHECK_ARG(128)
+/*
+** f128:
+**     sd      a1,0\(a0\)
+**     sd      a2,8\(a0\)
+**     ret
+*/
diff --git a/gcc/testsuite/gcc.target/riscv/bitint-sizes.c 
b/gcc/testsuite/gcc.target/riscv/bitint-sizes.c
new file mode 100644
index 000000000000..6cdb746e3a22
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/bitint-sizes.c
@@ -0,0 +1,65 @@
+/* { dg-do run { target bitint } } */
+/* { dg-additional-options "-std=c23" } */
+
+static long unsigned int
+calc_size (int n)
+{
+#if __riscv_xlen == 64
+  if (n > 128)
+    return ((n - 1)/128 + 1)  * sizeof(__int128_t);
+  if (n > 64)
+    return sizeof(__int128_t);
+#elif __riscv_xlen == 32
+  if (n > 64)
+    return ((n - 1)/64 + 1)  * sizeof(long long);
+#endif
+  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/riscv/libgcc-riscv.ver 
b/libgcc/config/riscv/libgcc-riscv.ver
new file mode 100644
index 000000000000..a67a2b0e3b76
--- /dev/null
+++ b/libgcc/config/riscv/libgcc-riscv.ver
@@ -0,0 +1,29 @@
+# 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
+    __fixtfbitint
+    __floatbitinthf
+    __floatbitintsf
+    __floatbitintdf
+    __floatbitinttf
+}
diff --git a/libgcc/config/riscv/t-elf b/libgcc/config/riscv/t-elf
index acb5e2806764..c0c73dd57bcc 100644
--- a/libgcc/config/riscv/t-elf
+++ b/libgcc/config/riscv/t-elf
@@ -7,3 +7,5 @@ LIB2ADD += $(srcdir)/config/riscv/save-restore.S \
 
 # Avoid the full unwinder being pulled along with the division libcalls.
 LIB2_DIVMOD_EXCEPTION_FLAGS := -fasynchronous-unwind-tables
+
+SHLIB_MAPFILES += $(srcdir)/config/riscv/libgcc-riscv.ver
diff --git a/libgcc/config/riscv/t-softfp32 b/libgcc/config/riscv/t-softfp32
index da55eb348c18..41a6c92b8084 100644
--- a/libgcc/config/riscv/t-softfp32
+++ b/libgcc/config/riscv/t-softfp32
@@ -34,6 +34,8 @@ endif
 
 endif
 
+softfp_extras += floatbitinttf fixtfbitint
+
 else
 # ABI_QUAD
 
@@ -49,4 +51,5 @@ softfp_truncations += tfhf dfhf sfhf \
                      hfbf bfhf
 softfp_extras += fixhfsi fixhfdi fixunshfsi fixunshfdi \
                 floatsihf floatdihf floatunsihf floatundihf \
-                floatsibf floatdibf floatunsibf floatundibf
+                floatsibf floatdibf floatunsibf floatundibf \
+                floatbitinthf

Reply via email to