]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
bitint: Do not optimize away conversion to _BitInt before a VCE
authorYang Yujie <yangyujie@loongson.cn>
Wed, 6 Aug 2025 10:04:51 +0000 (12:04 +0200)
committerJakub Jelinek <jakub@gcc.gnu.org>
Wed, 6 Aug 2025 10:04:51 +0000 (12:04 +0200)
A _BitInt value may rely on a conversion to become properly extended.
So a conversion to _BitInt is not trivially removable even if the
types of the result and the operand have the same precision and size.

This patch fixes gcc.dg/torture/bitint-64.c at -O2 on LoongArch,
which fails because extension of the result is dropped in a
compare-and-swap loop generated for incrementing an _Atomic _BitInt,
causing an ABI violation.

* match.pd: Preserve conversion to _BitInt before a VCE
if the _BitInt is extended.

* gcc.dg/torture/bitint-84.c: New test.

gcc/match.pd
gcc/testsuite/gcc.dg/torture/bitint-84.c [new file with mode: 0644]

index 82e6e291ae19fd3907de254ff4fec118b61637b2..06a4a91579f6c978da2b6038b4de3e5c5ec78f35 100644 (file)
@@ -5508,16 +5508,31 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
    (convert @0)))
 
 /* Strip inner integral conversions that do not change precision or size, or
-   zero-extend while keeping the same size (for bool-to-char).  */
+   zero-extend while keeping the same size (for bool-to-char).
+   However, keep this conversion if the result is an extended _BitInt,
+   since it may rely on this conversion to extend properly.  */
+
 (simplify
   (view_convert (convert@0 @1))
+  (with {
+    bool extended_bitint = false;
+    if (BITINT_TYPE_P (TREE_TYPE (@0)))
+      {
+       struct bitint_info info;
+       extended_bitint
+         = targetm.c.bitint_type_info (TYPE_PRECISION (TREE_TYPE (@0)),
+                                                       &info);
+       extended_bitint = extended_bitint && info.extended;
+      }
+   }
   (if ((INTEGRAL_TYPE_P (TREE_TYPE (@0)) || POINTER_TYPE_P (TREE_TYPE (@0)))
        && (INTEGRAL_TYPE_P (TREE_TYPE (@1)) || POINTER_TYPE_P (TREE_TYPE (@1)))
+       && !extended_bitint
        && TYPE_SIZE (TREE_TYPE (@0)) == TYPE_SIZE (TREE_TYPE (@1))
        && (TYPE_PRECISION (TREE_TYPE (@0)) == TYPE_PRECISION (TREE_TYPE (@1))
           || (TYPE_PRECISION (TREE_TYPE (@0)) > TYPE_PRECISION (TREE_TYPE (@1))
               && TYPE_UNSIGNED (TREE_TYPE (@1)))))
-   (view_convert @1)))
+   (view_convert @1))))
 
 /* Simplify a view-converted empty or single-element constructor.  */
 (simplify
diff --git a/gcc/testsuite/gcc.dg/torture/bitint-84.c b/gcc/testsuite/gcc.dg/torture/bitint-84.c
new file mode 100644 (file)
index 0000000..b3ecbef
--- /dev/null
@@ -0,0 +1,18 @@
+/* A simple variant of gcc.dg/torture/bitint-64.c */
+/* { dg-do run { target bitint } } */
+/* { 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;
+}