svwhilelx_impl::fold reads unsigned operands as poly_uint64, so
33 - svcntb () in uint32_t, the POLY_INT_CST [17, 4294967280] (17 - 16x),
is taken as 17 + 4294967280x and svwhilelt_b8_u32 (0, 33 - svcntb ())
folds to an all-true predicate, although only one lane is active at VL 256.
A wrapped start operand likewise folds
svwhilelt_b64_u32 (40 - svcntd (), 20) to pfalse, wrong at VL 2048.
Punt when an unsigned POLY_INT_CST operand is not known to be nonnegative
with its coefficients sign-extended; INTEGER_CST operands still fold.
GCC 16 is affected too.

Bootstrapped and regression tested on x86_64-pc-linux-gnu; regression
tested on aarch64-linux-gnu (qemu, VL 128 and SVE VL 2048).

Assisted-by: Claude Opus 5 (Anthropic)

gcc/ChangeLog:

        * config/aarch64/aarch64-sve-builtins-base.cc (svwhilelx_impl::fold):
        Punt on unsigned POLY_INT_CST operands that may be negative when
        read as signed.

gcc/testsuite/ChangeLog:

        * gcc.target/aarch64/sve/acle/general/whilelt_7.c: New test.

Signed-off-by: Dominic P <[email protected]>
---
OK for trunk?

 .../aarch64/aarch64-sve-builtins-base.cc      | 11 ++++-
 .../aarch64/sve/acle/general/whilelt_7.c      | 40 +++++++++++++++++++
 2 files changed, 50 insertions(+), 1 deletion(-)
 create mode 100644 
gcc/testsuite/gcc.target/aarch64/sve/acle/general/whilelt_7.c

diff --git a/gcc/config/aarch64/aarch64-sve-builtins-base.cc 
b/gcc/config/aarch64/aarch64-sve-builtins-base.cc
index 96697319fdc..752f998dacc 100644
--- a/gcc/config/aarch64/aarch64-sve-builtins-base.cc
+++ b/gcc/config/aarch64/aarch64-sve-builtins-base.cc
@@ -3514,7 +3514,16 @@ public:
       return f.fold_to_ptrue ();
 
     if (f.type_suffix (1).unsigned_p)
-      return fold_type<poly_uint64> (f);
+      {
+       /* Punt on POLY_INT_CSTs that may be negative, such as 33 - svcntd ().  
*/
+       for (unsigned int i = 0; i < 2; ++i)
+         {
+           tree arg = gimple_call_arg (f.call, i);
+           if (POLY_INT_CST_P (arg) && maybe_lt (tree_to_poly_int64 (arg), 0))
+             return nullptr;
+         }
+       return fold_type<poly_uint64> (f);
+      }
     else
       return fold_type<poly_int64> (f);
   }
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/whilelt_7.c 
b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/whilelt_7.c
new file mode 100644
index 00000000000..a9d7d796344
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/whilelt_7.c
@@ -0,0 +1,40 @@
+/* { dg-do run { target aarch64_sve_hw } } */
+/* { dg-options "-O2" } */
+
+#include <arm_sve.h>
+
+#define TEST(NAME, CALL)                                       \
+  svbool_t __attribute__ ((noipa)) NAME (void) { return CALL; }
+
+TEST (lt8_1, svwhilelt_b8_u32 (0, 33u - (uint32_t) svcntb ()))
+TEST (lt32_1, svwhilelt_b64_u32 (0, 33u - (uint32_t) svcntd ()))
+TEST (lt64_1, svwhilelt_b64_u64 (0, 33u - svcntd ()))
+TEST (le32_1, svwhilele_b64_u32 (0, 32u - (uint32_t) svcntd ()))
+TEST (le64_1, svwhilele_b64_u64 (0, 32u - svcntd ()))
+TEST (lt32_0, svwhilelt_b64_u32 (40u - (uint32_t) svcntd (), 20))
+TEST (lt64_0, svwhilelt_b64_u64 (40u - svcntd (), 20))
+TEST (le32_0, svwhilele_b64_u32 (40u - (uint32_t) svcntd (), 19))
+TEST (le64_0, svwhilele_b64_u64 (40u - svcntd (), 19))
+
+#define CHECK(NAME, W, CNT, START, END)                        \
+  {                                                            \
+    uint64_t vl = CNT (), s = (START), e = (END);              \
+    uint64_t n = s < e ? e - s : 0;                            \
+    if (svcntp_##W (svptrue_##W (), NAME ()) != (n < vl ? n : vl))     \
+      __builtin_abort ();                                      \
+  }
+
+int __attribute__ ((optimize (1)))
+main (void)
+{
+  CHECK (lt8_1, b8, svcntb, 0, 33 - svcntb ())
+  CHECK (lt32_1, b64, svcntd, 0, 33 - svcntd ())
+  CHECK (lt64_1, b64, svcntd, 0, 33 - svcntd ())
+  CHECK (le32_1, b64, svcntd, 0, 33 - svcntd ())
+  CHECK (le64_1, b64, svcntd, 0, 33 - svcntd ())
+  CHECK (lt32_0, b64, svcntd, 40 - svcntd (), 20)
+  CHECK (lt64_0, b64, svcntd, 40 - svcntd (), 20)
+  CHECK (le32_0, b64, svcntd, 40 - svcntd (), 20)
+  CHECK (le64_0, b64, svcntd, 40 - svcntd (), 20)
+  return 0;
+}
-- 
2.55.0

Reply via email to