When the divisor is the same in every element, the analysis in
expand_vector_divmod needs only one element of it, and the shifts,
additions and highpart multiplications that it emits work for any
vector length. Use it for variable-length vectors in that case, also
at -O0, where they have no piecewise fallback. The testcase from the
PR (svint16_t x / 4) becomes a shift sequence instead of a sorry.
Divisors that differ between elements, and those that
expand_vector_divmod also rejects for fixed-length vectors, still get
the sorry.
Bootstrapped and regression tested on x86_64-pc-linux-gnu. The SVE
and vect tests have no regressions on aarch64-linux-gnu (qemu, VL128
and VL2048).
Assisted-by: Claude Opus 5 (Anthropic)
PR target/118377
gcc/ChangeLog:
* tree-vect-generic.cc (add_shift): Handle variable-length vectors.
(expand_vector_divmod): Handle variable-length vectors when the
divisor is uniform.
(expand_vector_operation): Try expand_vector_divmod for
variable-length vectors at -O0 too.
gcc/testsuite/ChangeLog:
* gcc.target/aarch64/sve/acle/general-c/pr118377.c: Expect no
diagnostic for division and modulus by a uniform constant.
* g++.target/aarch64/sve/acle/general-c++/pr118377.C: Likewise.
* gcc.target/aarch64/sve/pr118377_run.c: New test.
* gcc.target/aarch64/sve/pr118377_run_2.c: New test.
Signed-off-by: Dominic P <gcc@gcc.dp11.uk>
---
OK for trunk?
When optimizing, release builds of GCC 16 already compile these cases
correctly, because to_constant () returns the minimum length and the
equal elements fold to a duplicate, so without this patch 1/2 would
turn them into a sorry. At -O0 they lower the first 128 bits only.
.../aarch64/sve/acle/general-c++/pr118377.C | 4 +-
.../aarch64/sve/acle/general-c/pr118377.c | 4 +-
.../gcc.target/aarch64/sve/pr118377_run.c | 39 +++++++++++++++++++
.../gcc.target/aarch64/sve/pr118377_run_2.c | 4 ++
gcc/tree-vect-generic.cc | 14 +++++--
5 files changed, 57 insertions(+), 8 deletions(-)
create mode 100644 gcc/testsuite/gcc.target/aarch64/sve/pr118377_run.c
create mode 100644 gcc/testsuite/gcc.target/aarch64/sve/pr118377_run_2.c
@@ -11,7 +11,7 @@ f1 (svint8_t x, svint8_t y)
svint16_t
f2 (svint16_t x)
{
- return x / 4; // { dg-message {unsupported operation on variable-length vectors} }
+ return x / 4;
}
svint32_t
@@ -23,7 +23,7 @@ f3 (svint32_t x, svint32_t y)
svuint8_t
f4 (svuint8_t x)
{
- return x % 3; // { dg-message {unsupported operation on variable-length vectors} }
+ return x % 3;
}
svbfloat16_t
@@ -11,7 +11,7 @@ f1 (svint8_t x, svint8_t y)
svint16_t
f2 (svint16_t x)
{
- return x / 4; /* { dg-message {unsupported operation on variable-length vectors} } */
+ return x / 4;
}
svint32_t
@@ -23,7 +23,7 @@ f3 (svint32_t x, svint32_t y)
svuint8_t
f4 (svuint8_t x)
{
- return x % 3; /* { dg-message {unsupported operation on variable-length vectors} } */
+ return x % 3;
}
svbfloat16_t
new file mode 100644
@@ -0,0 +1,39 @@
+/* { dg-do run { target aarch64_sve_hw } } */
+/* { dg-options "-O2" } */
+
+#include <arm_sve.h>
+
+#define TEST(NAME, VT, ST, PTRUE, OP, D) \
+ __attribute__((noipa)) VT NAME (VT x) { return x OP (D); } \
+ void check_##NAME (void) \
+ { \
+ ST a[256], r[256]; \
+ int n = svcntp_b8 (svptrue_b8 (), PTRUE ()); \
+ for (int i = 0; i < n; i++) \
+ a[i] = (ST) (i * 2654435761u + 12345u); \
+ svst1 (PTRUE (), r, NAME (svld1 (PTRUE (), a))); \
+ for (int i = 0; i < n; i++) \
+ if (r[i] != (ST) (a[i] OP (ST) (D))) \
+ __builtin_abort (); \
+ }
+
+TEST (s8_div_7, svint8_t, signed char, svptrue_b8, /, 7)
+TEST (u8_mod_3, svuint8_t, unsigned char, svptrue_b8, %, 3)
+TEST (s16_div_4, svint16_t, short, svptrue_b16, /, 4)
+TEST (s16_mod_m10, svint16_t, short, svptrue_b16, %, -10)
+TEST (u16_div_10, svuint16_t, unsigned short, svptrue_b16, /, 10)
+TEST (s32_mod_8, svint32_t, int, svptrue_b32, %, 8)
+TEST (u64_mod_10, svuint64_t, unsigned long, svptrue_b64, %, 10)
+
+int
+main (void)
+{
+ check_s8_div_7 ();
+ check_u8_mod_3 ();
+ check_s16_div_4 ();
+ check_s16_mod_m10 ();
+ check_u16_div_10 ();
+ check_s32_mod_8 ();
+ check_u64_mod_10 ();
+ return 0;
+}
new file mode 100644
@@ -0,0 +1,4 @@
+/* { dg-do run { target aarch64_sve_hw } } */
+/* { dg-options "-O0" } */
+
+#include "pr118377_run.c"
@@ -470,7 +470,9 @@ add_shift (gimple_stmt_iterator *gsi, tree type, tree op0, int *shiftcnts,
enum tree_code code)
{
optab op;
- unsigned int i, nunits = nunits_for_known_piecewise_op (type);
+ unsigned HOST_WIDE_INT i, nunits;
+ if (!TYPE_VECTOR_SUBPARTS (type).is_constant (&nunits))
+ nunits = 1;
bool scalar_shift = true;
for (i = 1; i < nunits; i++)
@@ -712,7 +714,11 @@ expand_vector_divmod (gimple_stmt_iterator *gsi, tree type, tree op0,
int pre_shift = -1, post_shift;
unsigned HOST_WIDE_INT nunits;
if (!TYPE_VECTOR_SUBPARTS (type).is_constant (&nunits))
- return NULL_TREE;
+ {
+ if (!uniform_vector_p (op1))
+ return NULL_TREE;
+ nunits = 1;
+ }
int *shifts = XALLOCAVEC (int, nunits * 4);
int *pre_shifts = shifts + nunits;
int *post_shifts = pre_shifts + nunits;
@@ -904,7 +910,7 @@ expand_vector_divmod (gimple_stmt_iterator *gsi, tree type, tree op0,
break;
uns_type
= build_vector_type (build_nonstandard_integer_type (prec, 1),
- nunits);
+ TYPE_VECTOR_SUBPARTS (type));
if (i == nunits && TYPE_MODE (uns_type) == TYPE_MODE (type))
{
for (i = 0; i < nunits; i++)
@@ -1340,7 +1346,7 @@ expand_vector_operation (gimple_stmt_iterator *gsi, tree type, tree compute_type
tree rhs2 = gimple_assign_rhs2 (assign);
tree ret;
- if (!optimize
+ if ((!optimize && TYPE_VECTOR_SUBPARTS (type).is_constant ())
|| !VECTOR_INTEGER_TYPE_P (type)
|| TREE_CODE (rhs2) != VECTOR_CST
|| !VECTOR_MODE_P (TYPE_MODE (type)))