]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c-family: Fix ICE with __sync_*_and_* on _BitInt [PR117641]
authorJakub Jelinek <jakub@redhat.com>
Tue, 19 Nov 2024 19:36:00 +0000 (20:36 +0100)
committerJakub Jelinek <jakub@gcc.gnu.org>
Tue, 19 Nov 2024 19:36:00 +0000 (20:36 +0100)
Only __atomic_* builtins are meant to work on arbitrary _BitInt types
(if not supported in hw we emit a CAS loop which uses __atomic_load_*
in that case), the compatibility __sync_* builtins work only if there
is a corresponding normal integral type (for _BitInt on 32-bit ARM
we'll need to limit even that to no padding, because the padding bits
are well defined there and the hw or libatomic __sync_* APIs don't
guarantee that), IMHO people shouldn't mix very old APIs with very
new ones and I don't see a replacement for the __atomic_load_*.

For size > 16 that is how it already correctly behaves,
in the hunk shown in the patch it is immediately followed by

  if (fetch && !orig_format && TREE_CODE (type) == BITINT_TYPE)
    return -1;

which returns -1 for the __atomic_* builtins (i.e. !orig_format),
which causes caller to use atomic_bitint_fetch_using_cas_loop,
and otherwise does diagnostic and return 0 (which causes caller
to punt).  But for size == 16 if TImode isn't suipported (i.e.
mostly 32-bit arches), we return (correctly) -1 if !orig_format,
so again force atomic_bitint_fetch_using_cas_loop on those arches
for e.g. _BitInt(115), but for orig_format the function returns
16 as if it could do 16 byte __sync_*_and_* (which it can't
because TImode isn't supported; for 16 byte it can only do
(perhaps using libatomic) normal compare and swap).  So we need
to error and return 0, rather than return 16.

The following patch ensures that.

2024-11-19  Jakub Jelinek  <jakub@redhat.com>

PR c/117641
* c-common.cc (sync_resolve_size): For size == 16 fetch of
BITINT_TYPE if TImode isn't supported scalar mode diagnose
and return 0 if orig_format instead of returning 16.

* gcc.dg/bitint-115.c: New test.

gcc/c-family/c-common.cc
gcc/testsuite/gcc.dg/bitint-115.c [new file with mode: 0644]

index b7586312537bcd539d99337e0ddc8944b5787ad7..367a9b07c872386715d9d89bddaf0d4ed63922ad 100644 (file)
@@ -7458,10 +7458,13 @@ sync_resolve_size (tree function, vec<tree, va_gc> *params, bool fetch,
   size = tree_to_uhwi (TYPE_SIZE_UNIT (type));
   if (size == 16
       && fetch
-      && !orig_format
       && TREE_CODE (type) == BITINT_TYPE
       && !targetm.scalar_mode_supported_p (TImode))
-    return -1;
+    {
+      if (!orig_format)
+       return -1;
+      goto incompatible;
+    }
 
   if (size == 1 || size == 2 || size == 4 || size == 8 || size == 16)
     return size;
diff --git a/gcc/testsuite/gcc.dg/bitint-115.c b/gcc/testsuite/gcc.dg/bitint-115.c
new file mode 100644 (file)
index 0000000..700fd6c
--- /dev/null
@@ -0,0 +1,9 @@
+/* PR c/117641 */
+/* { dg-do compile { target bitint575 } } */
+/* { dg-options "-std=c23" } */
+
+void
+foo (_BitInt(128) *b)
+{
+  __sync_fetch_and_add (b, 1); /* { dg-error "incompatible" "" { target { ! int128 } } } */
+}