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