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