can_min_p compares POLY_INT_CSTs as poly_widest_ints, which zero-extends
the coefficients of an unsigned type. 33 - svcntb () in uint64_t is
POLY_INT_CST [17, 18446744073709551600] (17 - 16x), which then looks
known to be >= svcntb (), so MIN (33 - svcntb (), svcntb ()) folds to
svcntb () although the result is 1 at VL 256. Punt when an unsigned
POLY_INT_CST operand may be negative once its coefficients are
sign-extended. GCC 16 is affected too. RISC-V V uses the same folding;
no rvv test changes. Values that wrap past the top of the type, such as
(uint8_t) svcntb () at VL 2048, are a separate issue.
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.cc (can_min_p): Punt on unsigned POLY_INT_CST operands
that may be negative when read as signed.
gcc/testsuite/ChangeLog:
* gcc.target/aarch64/sve/acle/general/min_poly_1.c: New test.
Signed-off-by: Dominic P <[email protected]>
---
OK for trunk?
gcc/fold-const.cc | 8 +++++
.../aarch64/sve/acle/general/min_poly_1.c | 33 +++++++++++++++++++
2 files changed, 41 insertions(+)
create mode 100644
gcc/testsuite/gcc.target/aarch64/sve/acle/general/min_poly_1.c
diff --git a/gcc/fold-const.cc b/gcc/fold-const.cc
index 113558973f6..c963a29b265 100644
--- a/gcc/fold-const.cc
+++ b/gcc/fold-const.cc
@@ -1149,6 +1149,14 @@ wide_int_binop (wide_int &res,
bool
can_min_p (const_tree arg1, const_tree arg2, poly_wide_int &res)
{
+ /* An unsigned POLY_INT_CST with a coefficient that is negative when
+ read as signed can wrap. */
+ for (const_tree arg : { arg1, arg2 })
+ if (POLY_INT_CST_P (arg)
+ && TYPE_UNSIGNED (TREE_TYPE (arg))
+ && maybe_lt (tree_to_poly_int64 (arg), 0))
+ return false;
+
if (known_le (wi::to_poly_widest (arg1), wi::to_poly_widest (arg2)))
{
res = wi::to_poly_wide (arg1);
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/min_poly_1.c
b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/min_poly_1.c
new file mode 100644
index 00000000000..99a7139e9f1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/min_poly_1.c
@@ -0,0 +1,33 @@
+/* { dg-do run { target aarch64_sve_hw } } */
+/* { dg-options "-O2" } */
+
+#include <arm_sve.h>
+
+#define TEST(NAME, T, K, CNT) \
+ T __attribute__ ((noipa)) \
+ NAME (void) \
+ { \
+ T n = (T) K - (T) CNT (); \
+ return n < (T) CNT () ? n : (T) CNT (); \
+ }
+
+TEST (f1, uint64_t, 33, svcntb)
+TEST (f2, uint32_t, 33, svcnth)
+TEST (f3, uint64_t, 130, svcntb)
+TEST (f4, uint64_t, 300, svcntb)
+
+int __attribute__ ((optimize (0)))
+main (void)
+{
+#define CHECK(NAME, T, K, CNT) \
+ { \
+ T c = CNT (), n = (T) K - c; \
+ if (NAME () != (n < c ? n : c)) \
+ __builtin_abort (); \
+ }
+ CHECK (f1, uint64_t, 33, svcntb)
+ CHECK (f2, uint32_t, 33, svcnth)
+ CHECK (f3, uint64_t, 130, svcntb)
+ CHECK (f4, uint64_t, 300, svcntb)
+ return 0;
+}
--
2.55.0