dom3 now folds the limit of the second SVE control in a widening loop,
MAX (33, [2, 2]) - [2, 2], to the unsigned int POLY_INT_CST [31, 4294967294],
i.e. 31 - 2x.  fold_const_call read that as the poly_uint64
31 + 4294967294x, so .WHILE_ULT (0, 31 - 2x) became all-true and the first
vector iteration stored past the end of the array for VL >= 1152 bits.
Read the limit as poly_int64, which sign-extends POLY_INT_CST coefficients,
and fold only if it is known to be nonnegative.  The MAX fold appeared with
a3fb4bf350d (POLY_INT_CST bounds for SVE), which also lowered the whilelo
counts in slp_12.c; those folds were right only because x <= 15 there, so
restore the old counts.  GCC 16 is not affected.

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:

        * fold-const-call.cc (fold_const_call) <CFN_WHILE_ULT>: Read the
        limit as poly_int64 and require it to be known nonnegative.

gcc/testsuite/ChangeLog:

        * gcc.target/aarch64/sve/slp_12.c: Restore the whilelo counts.
        * gcc.target/aarch64/sve/while_ult_poly_1.c: New test.
        * gcc.target/aarch64/sve/while_ult_poly_1_run.c: New test.

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

 gcc/fold-const-call.cc                        |  6 +++--
 gcc/testsuite/gcc.target/aarch64/sve/slp_12.c |  6 ++---
 .../gcc.target/aarch64/sve/while_ult_poly_1.c | 18 +++++++++++++
 .../aarch64/sve/while_ult_poly_1_run.c        | 25 +++++++++++++++++++
 4 files changed, 50 insertions(+), 5 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/aarch64/sve/while_ult_poly_1.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/sve/while_ult_poly_1_run.c

diff --git a/gcc/fold-const-call.cc b/gcc/fold-const-call.cc
index 94841e8fb65..48efea3f689 100644
--- a/gcc/fold-const-call.cc
+++ b/gcc/fold-const-call.cc
@@ -2197,8 +2197,10 @@ fold_const_call (combined_fn fn, tree type, tree arg0, 
tree arg1, tree arg2)
 
     case CFN_WHILE_ULT:
       {
-       poly_uint64 parg0, parg1;
-       if (poly_int_tree_p (arg0, &parg0) && poly_int_tree_p (arg1, &parg1))
+       poly_uint64 parg0;
+       poly_int64 parg1;
+       if (poly_int_tree_p (arg0, &parg0) && poly_int_tree_p (arg1, &parg1)
+           && known_ge (parg1, 0))
          return fold_while_ult (type, parg0, parg1);
        return NULL_TREE;
       }
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/slp_12.c 
b/gcc/testsuite/gcc.target/aarch64/sve/slp_12.c
index c81845f2c87..5c48543e41c 100644
--- a/gcc/testsuite/gcc.target/aarch64/sve/slp_12.c
+++ b/gcc/testsuite/gcc.target/aarch64/sve/slp_12.c
@@ -47,9 +47,9 @@ TEST_ALL (VEC_PERM)
 
 /* We should use WHILEs for all accesses.  */
 /* { dg-final { scan-assembler-times {\twhilelo\tp[0-7]\.b} 20 } } */
-/* { dg-final { scan-assembler-times {\twhilelo\tp[0-7]\.h} 16 } } */
-/* { dg-final { scan-assembler-times {\twhilelo\tp[0-7]\.s} 21 } } */
-/* { dg-final { scan-assembler-times {\twhilelo\tp[0-7]\.d} 15 } } */
+/* { dg-final { scan-assembler-times {\twhilelo\tp[0-7]\.h} 18 } } */
+/* { dg-final { scan-assembler-times {\twhilelo\tp[0-7]\.s} 27 } } */
+/* { dg-final { scan-assembler-times {\twhilelo\tp[0-7]\.d} 24 } } */
 
 /* 6 for the 8-bit types and 2 for the 16-bit types.  */
 /* { dg-final { scan-assembler-times {\tuqdecb\t} 8 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/while_ult_poly_1.c 
b/gcc/testsuite/gcc.target/aarch64/sve/while_ult_poly_1.c
new file mode 100644
index 00000000000..dd0ee63a338
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/while_ult_poly_1.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -fno-vect-cost-model -fdump-tree-optimized" } */
+
+#include <stdint.h>
+
+int64_t d64[128];
+int32_t d32[128];
+int32_t s32[128];
+int16_t s16[128];
+int8_t s8[128];
+
+void __attribute__ ((noipa)) f1 (void) { for (int i = 0; i < 33; i++) d64[i] = 
i; }
+void __attribute__ ((noipa)) f2 (void) { for (int i = 0; i < 63; i++) d64[i] = 
s32[i]; }
+void __attribute__ ((noipa)) f3 (void) { for (int i = 0; i < 100; i++) d64[i] 
= s16[i]; }
+void __attribute__ ((noipa)) f4 (void) { for (int i = 0; i < 120; i++) d64[i] 
= s8[i]; }
+void __attribute__ ((noipa)) f5 (void) { for (int i = 0; i < 65; i++) d32[i] = 
s8[i]; }
+
+/* { dg-final { scan-tree-dump-not {PHI <[^>]*\{ -1, \.\.\. \}} "optimized" } 
} */
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/while_ult_poly_1_run.c 
b/gcc/testsuite/gcc.target/aarch64/sve/while_ult_poly_1_run.c
new file mode 100644
index 00000000000..764c514d297
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/while_ult_poly_1_run.c
@@ -0,0 +1,25 @@
+/* { dg-do run { target aarch64_sve_hw } } */
+/* { dg-options "-O3 -fno-vect-cost-model" } */
+
+#include "while_ult_poly_1.c"
+
+#define CHECK(F, D, N, V)                              \
+  for (int i = 0; i < 128; i++)                                \
+    D[i] = -1;                                         \
+  F ();                                                        \
+  for (int i = 0; i < 128; i++)                                \
+    if (D[i] != (i < N ? V : -1))                      \
+      __builtin_abort ();
+
+int __attribute__ ((optimize (1)))
+main (void)
+{
+  for (int i = 0; i < 128; i++)
+    s32[i] = s16[i] = s8[i] = i + 1;
+  CHECK (f1, d64, 33, i)
+  CHECK (f2, d64, 63, i + 1)
+  CHECK (f3, d64, 100, i + 1)
+  CHECK (f4, d64, 120, i + 1)
+  CHECK (f5, d32, 65, i + 1)
+  return 0;
+}
-- 
2.55.0

Reply via email to