Dominic P <[email protected]> writes: > Without partial vectors, the vector IV step (VF) and the skip-vector bound > (VF - 1, plus 1 when peeling for gaps) are built as constants of the NITERS > type. With an 8-bit loop counter and a VF of [16, 16], a 2048-bit SVE > vector makes the VF 256 == 0: the guard NITERSM1 < VF never skips the > vector loop and the IV steps by 0, so the loop runs off the end of its > arrays. niters_vf_2.c fails this way at plain -O3 (VF [32, 32] from > #pragma GCC unroll); GCC 16 is affected too. Reject the loop_vinfo when > partial vectors are not used and the maximum VF does not fit the NITERS > type, bounding a variable VF with targetm.poly_int_indeterminate_bound > when the target has it. On SVE this only affects unmasked loops with an > 8-bit counter; they now use a smaller VF. Targets without the hook keep > vect_max_vf; on RISC-V this changes one rvv test, poly_licm-3.c, whose > 16-bit-counter loop now uses fixed-length vectors.
Sorry if this has already been suggested, but: rather than make this a reason to fail vectorisation, why not change the type to a pointer-sized integer type in cases where we cannot prove that the original type is small enough? Sub-32-bit counters aren't as efficient as 32-bit or 64-bit counters on AArch64 in any case. Thanks, Richard > 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: > > * tree-vect-loop.cc (vect_determine_partial_vectors_and_peeling): > Fail if the maximum VF does not fit the type of NITERS and partial > vectors are not used. > > gcc/testsuite/ChangeLog: > > * gcc.target/aarch64/sve/niters_vf_1.c: New test. > * gcc.target/aarch64/sve/niters_vf_1_run.c: New test. > * gcc.target/aarch64/sve/niters_vf_2.c: New test. > > Signed-off-by: Dominic P <[email protected]> > --- > OK for trunk? > > .../gcc.target/aarch64/sve/niters_vf_1.c | 25 +++++++++++++++ > .../gcc.target/aarch64/sve/niters_vf_1_run.c | 26 ++++++++++++++++ > .../gcc.target/aarch64/sve/niters_vf_2.c | 31 +++++++++++++++++++ > gcc/tree-vect-loop.cc | 22 +++++++++++++ > 4 files changed, 104 insertions(+) > create mode 100644 gcc/testsuite/gcc.target/aarch64/sve/niters_vf_1.c > create mode 100644 gcc/testsuite/gcc.target/aarch64/sve/niters_vf_1_run.c > create mode 100644 gcc/testsuite/gcc.target/aarch64/sve/niters_vf_2.c > > diff --git a/gcc/testsuite/gcc.target/aarch64/sve/niters_vf_1.c > b/gcc/testsuite/gcc.target/aarch64/sve/niters_vf_1.c > new file mode 100644 > index 00000000000..ff510ddf192 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/aarch64/sve/niters_vf_1.c > @@ -0,0 +1,25 @@ > +/* { dg-do compile } */ > +/* { dg-options "-O3 -fno-vect-cost-model --param > vect-partial-vector-usage=0 -fdump-tree-vect-details" } */ > + > +#include <stdint.h> > + > +uint8_t in[1024]; > +uint8_t out[256]; > + > +uint32_t __attribute__ ((noipa)) > +f1 (int n) > +{ > + uint32_t r = 7; > + for (uint8_t i = 0; i < (uint8_t) n; i++) > + r += in[i * 4 + 1]; > + return r; > +} > + > +void __attribute__ ((noipa)) > +f2 (int n) > +{ > + for (uint8_t i = 0; i < (uint8_t) n; i++) > + out[i] = in[i * 2] + 1; > +} > + > +/* { dg-final { scan-tree-dump "vectorization factor may not fit" "vect" } } > */ > diff --git a/gcc/testsuite/gcc.target/aarch64/sve/niters_vf_1_run.c > b/gcc/testsuite/gcc.target/aarch64/sve/niters_vf_1_run.c > new file mode 100644 > index 00000000000..144be94cf6c > --- /dev/null > +++ b/gcc/testsuite/gcc.target/aarch64/sve/niters_vf_1_run.c > @@ -0,0 +1,26 @@ > +/* { dg-do run { target aarch64_sve_hw } } */ > +/* { dg-options "-O3 -fno-vect-cost-model --param > vect-partial-vector-usage=0" } */ > + > +#include "niters_vf_1.c" > + > +int __attribute__ ((optimize (1))) > +main (void) > +{ > + for (int i = 0; i < 1024; i++) > + in[i] = i * 7; > + for (int n = 0; n < 256; n++) > + { > + uint32_t r = 7; > + for (int i = 0; i < n; i++) > + r += in[i * 4 + 1]; > + if (f1 (n) != r) > + __builtin_abort (); > + for (int i = 0; i < 256; i++) > + out[i] = 0; > + f2 (n); > + for (int i = 0; i < 256; i++) > + if (out[i] != (i < n ? (uint8_t) (in[i * 2] + 1) : 0)) > + __builtin_abort (); > + } > + return 0; > +} > diff --git a/gcc/testsuite/gcc.target/aarch64/sve/niters_vf_2.c > b/gcc/testsuite/gcc.target/aarch64/sve/niters_vf_2.c > new file mode 100644 > index 00000000000..f5c6dddc726 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/aarch64/sve/niters_vf_2.c > @@ -0,0 +1,31 @@ > +/* { dg-do run { target aarch64_sve_hw } } */ > +/* { dg-options "-O3" } */ > + > +#include <stdint.h> > + > +uint8_t c[512]; > + > +void __attribute__ ((noipa)) > +f (uint8_t n) > +{ > + uint8_t i = 0; > +#pragma GCC unroll 32 > + do > + c[i] += 1; > + while (i++ != n); > +} > + > +int __attribute__ ((optimize (1))) > +main (void) > +{ > + for (int n = 0; n < 256; n++) > + { > + for (int i = 0; i < 512; i++) > + c[i] = 0; > + f (n); > + for (int i = 0; i < 512; i++) > + if (c[i] != (i <= n)) > + __builtin_abort (); > + } > + return 0; > +} > diff --git a/gcc/tree-vect-loop.cc b/gcc/tree-vect-loop.cc > index 9b2afad6034..763c5800ef5 100644 > --- a/gcc/tree-vect-loop.cc > +++ b/gcc/tree-vect-loop.cc > @@ -2126,6 +2126,28 @@ vect_determine_partial_vectors_and_peeling > (loop_vec_info loop_vinfo, > "not vectorized: loop needs but cannot " > "use partial vectors\n"); > > + /* Without partial vectors the IV step and the epilogue bound are > + built in the type of NITERS, so they must be able to hold the VF. */ > + if (!LOOP_VINFO_USING_PARTIAL_VECTORS_P (loop_vinfo) > + && !LOOP_VINFO_NITERS_UNCOUNTED_P (loop_vinfo)) > + { > + poly_uint64 vf = LOOP_VINFO_VECT_FACTOR (loop_vinfo); > + widest_int max_vf = vect_max_vf (loop_vinfo); > + if (targetm.poly_int_indeterminate_bound) > + { > + poly_uint64 bound = targetm.poly_int_indeterminate_bound (); > + max_vf = vf.coeffs[0]; > + for (unsigned int i = 1; i < NUM_POLY_INT_COEFFS; ++i) > + max_vf += widest_int (vf.coeffs[i]) * bound.coeffs[i]; > + } > + if (wi::min_precision (max_vf, UNSIGNED) > + > TYPE_PRECISION (TREE_TYPE (LOOP_VINFO_NITERS (loop_vinfo)))) > + return opt_result::failure_at (vect_location, > + "not vectorized: vectorization factor " > + "may not fit the type of the iteration " > + "count\n"); > + } > + > if (dump_enabled_p ()) > dump_printf_loc (MSG_NOTE, vect_location, > "operating on %s vectors%s.\n",
