On Wed, 30 Sep 2026, Richard Sandiford wrote: > 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.
Yeah, I think we probably should up the IV the vectorizer adds to either integer_type_node or an integer type corresponding to word_mode. (I see create_canonical_iv also simply uses the niter type) But I'll also note that there's code for determining the integer type to use for the .WHILE_ULT comparison and there we already widen the scalar iteration counter IIRC. So I wonder why it still breaks down. > 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", > -- Richard Biener <[email protected]> SUSE Software Solutions Germany GmbH, Frankenstrasse 146, 90461 Nuernberg, Germany; GF: Stefan Gaiser, Jochen Jaser, Abhinav Puri; (HRB 36809, AG Nuernberg)
