On Fri, 2 Oct 2026, Tamar Christina wrote:

> > -----Original Message-----
> > From: Richard Biener <[email protected]>
> > Sent: 01 October 2026 11:43
> > To: Tamar Christina <[email protected]>
> > Cc: [email protected]; nd <[email protected]>; [email protected]
> > Subject: Re: [patch][vect]: Fix scalar iteration bounds when doing alignment
> > peeling with partial vectors [PR127677]
> > 
> > On Thu, 1 Oct 2026, Tamar Christina wrote:
> > 
> > > static unsigned int list[32] __attribute__((aligned(64)));
> > >
> > > __attribute__((noinline, noipa))
> > > static int
> > > contains (const unsigned int *p, unsigned int count, unsigned int start,
> > >           unsigned int key)
> > > {
> > >   for (unsigned int i = start; i < count; ++i)
> > >     if (p[i] == key)
> > >       return 1;
> > >   return 0;
> > > }
> > >
> > > int
> > > main (void)
> > > {
> > >   return contains (list, 2, 1, 1);
> > > }
> > >
> > > when compiled on RISC-V with
> > >
> > > -O3 -march=rv64gcv_zvl256b -mabi=lp64d -mrvv-vector-bits=zvl -mrvv-
> > max-lmul=m2 -g0
> > >
> > > shows
> > >
> > >   bnd.9_47 = niters.5_27 - prolog_loop_niters.7_31;
> > >   _63 = (unsigned long) bnd.9_47;
> > >
> > > ...
> > >
> > >
> > > and so if niters is lower than prolog iters we get an underflow.
> > > i.e.
> > >
> > >   niters        = count - start = 2 - 1 = 1
> > >   prolog_niters = 7
> > >
> > > so when it calculates the remainder
> > >
> > >   remaining = niters - prolog_niters;
> > >
> > > this underflows:
> > >
> > >    1 - 7 = 4294967290
> > >
> > > Normally we don't get here for AArch64 and x86_64 because of the different
> > > paths they take in vectorization.
> > >
> > > For SVE we perform the loop fully masked, including trailing elements.
> > > for Adv. SIMD and x86_64 we insert a peeling check.
> > >
> > >   _46 = niters - 1 = 0;
> > >   _48 = MAX(peel + 3, 5);   // at least 5
> > >
> > >   if (0 < _48)
> > >       goto bb26;
> > >
> > > which skips the alignment peeling prologue.  Prior to
> > > 8af2e8e49d6e5d33c01c2beaead4933bc286974c we would have generated
> > an epilog
> > > for the early break and alignment peeling.
> > >
> > > The change removed the requirement for an epilog for early break loops
> > which
> > > don't have side-effects, but still required alignment peeling.
> > >
> > > This exposed that the checks in vect_do_peeling generate the epilog and so
> > > the iteration check only when
> > >
> > >   poly_uint64 bound_epilog = 0;
> > >   if (!LOOP_VINFO_USING_PARTIAL_VECTORS_P (loop_vinfo)
> > >       && LOOP_VINFO_PEELING_FOR_NITER (loop_vinfo))
> > >     bound_epilog += vf - 1;
> > >   if (LOOP_VINFO_PEELING_FOR_GAPS (loop_vinfo))
> > >     bound_epilog += 1;
> > >
> > > so if LOOP_VINFO_USING_PARTUAL_VECTORS_P then no epilog or check is
> > generated.
> > > This means that vect_gen_prolog_loop_niters needs to in itself handle this
> > > assumption.
> > >
> > > This is easy to do by generating a MIN (niters, prolog_niters) check.
> > > If the guard is generated this will be optimized out, but if not,
> > > it makes the prolog peeling loop handle the "scalar" iterations itself 
> > > without
> > > needing a second scalar loop.
> > >
> > > Bootstrapped Regtested on aarch64-none-linux-gnu,
> > > arm-none-linux-gnueabihf, x86_64-pc-linux-gnu
> > > -m32, -m64 and no issues.
> > >
> > > Any comments?
> > 
> > So when not using partial vectors this is guaranteed by a niter check
> > which would skip the prologue and main loop if there's not enough
> > iterations to cover at least one full vector iteration?
> 
> Indeed.
> 
> > With
> > partial vectors we assume it's always profitable to enter the loop
> > (IIRC), right?
> 
> Yeah and its normally expected that the partial vector be able to handle
> any remaining operations.  You then have two approaches to handle the
> peeling, using masks, or using scalar iters.
> 
> SVE uses masks of course, and RISC-V seems to use scalar peeling.
> 
> > I wonder if it makes more sense to put this check
> > into the caller at the correct place ('remaining' isn't visible here)?
> 
> I originally did think of putting it in the caller, in the
> 
>       if (!uncounted_p)
>       {
>         /* Update niters for vector loop.  */
> 
> That generates the adjustment.  But in this case the value out of
> vect_gen_prolog_loop_niters, because essentially we know it's
> invalid to peel more iterations than we have niters.
> 
> So it seemed odd to me to allow vect_gen_prolog_loop_niters to
> return a known, invalid value.
> 
> But we then use this value in e.g. setting loop control, or moving the
> DRs in
> 
>       vect_update_inits_of_drs (loop_vinfo, niters_prolog, PLUS_EXPR);

Yeah, but that's only for non-mask peeling?

> and those DRs are now invalid.  But at least returning the capped number
> can make sense, for if e..g p was misaligned by 7 elements (in this example)
> since doing the single step does get you aligned.
> 
> So putting it in the callee seemed more correct, but indeed the comment
> needs updating.
>
> Do you still want me to pull it to the caller?

I'm fine with the explanation but please update the comment.

Thanks,
Richard.
 
> Thanks,
> Tamar
> 
> > The comment would also need to be updated to reflect this.
> > 
> 
> Yeah,
> 
> > Richard.
> > 
> > > Thanks,
> > > Tamar
> > >
> > > gcc/ChangeLog:
> > >
> > >   PR tree-optimization/127677
> > >   * tree-vect-loop-manip.cc (vect_gen_prolog_loop_niters): Generate
> > MIN
> > >   expression on niters.
> > >
> > > gcc/testsuite/ChangeLog:
> > >
> > >   PR tree-optimization/127677
> > >   * gcc.dg/vect/vect-early-break_146-pr127677.c: New test.
> > >
> > > ---
> > > diff --git a/gcc/testsuite/gcc.dg/vect/vect-early-break_146-pr127677.c
> > b/gcc/testsuite/gcc.dg/vect/vect-early-break_146-pr127677.c
> > > new file mode 100644
> > > index
> > 0000000000000000000000000000000000000000..f3bd8665c7fe39cff5e2
> > be88521650fae9bf4c90
> > > --- /dev/null
> > > +++ b/gcc/testsuite/gcc.dg/vect/vect-early-break_146-pr127677.c
> > > @@ -0,0 +1,45 @@
> > > +/* { dg-add-options vect_early_break } */
> > > +/* { dg-require-effective-target vect_early_break_hw } */
> > > +/* { dg-require-effective-target vect_partial_vectors } */
> > > +/* { dg-require-effective-target vect_int } */
> > > +
> > > +/* { dg-additional-options "-O3" } */
> > > +
> > > +#include "tree-vect.h"
> > > +
> > > +struct data
> > > +{
> > > +  unsigned int list[16];
> > > +  unsigned int sentinel;
> > > +};
> > > +
> > > +static struct data data __attribute__ ((aligned (64))) =
> > > +{
> > > +  { 0 },
> > > +  1
> > > +};
> > > +
> > > +__attribute__ ((noinline, noipa))
> > > +static int
> > > +contains (const unsigned int *p, unsigned int count, unsigned int start,
> > > +          unsigned int key)
> > > +{
> > > +  for (unsigned int i = start; i < count; ++i)
> > > +    if (p[i] == key)
> > > +      return 1;
> > > +
> > > +  return 0;
> > > +}
> > > +
> > > +int
> > > +main (void)
> > > +{
> > > +  check_vect ();
> > > +
> > > +  if (contains (data.list, 2, 1, 1) != 0)
> > > +    __builtin_abort ();
> > > +
> > > +  return 0;
> > > +}
> > > +
> > > +/* { dg-final { scan-tree-dump "LOOP VECTORIZED" "vect" } } */
> > > diff --git a/gcc/tree-vect-loop-manip.cc b/gcc/tree-vect-loop-manip.cc
> > > index
> > 9d22d87705baaa60b96d973486bf38398c9ac3f2..37b1b83703718a7d0bc
> > 091ec6f755485855141af 100644
> > > --- a/gcc/tree-vect-loop-manip.cc
> > > +++ b/gcc/tree-vect-loop-manip.cc
> > > @@ -2832,6 +2832,30 @@ vect_gen_prolog_loop_niters (loop_vec_info
> > loop_vinfo,
> > >        *bound = align_in_elems;
> > >      }
> > >
> > > +  /* Peeling for alignment if the amount to peel is larger than scalar 
> > > niters
> > > +     needs to cap the scalar niters to the MIN of niters and peeling.
> > Otherwise
> > > +     when we are calculating the number of iterations the peeled loop
> > performs
> > > +     we may cause an overflow.  i.e.
> > > +
> > > +     niters        = count - start = 2 - 1 = 1
> > > +     prolog_niters = 7
> > > +
> > > +     we then calculate the iteration count with
> > > +
> > > +     remaining = niters - prolog_niters;
> > > +
> > > +     which would overflow:
> > > +
> > > +     remaining = 1 - 7 = 4294967290 and then produce an incorrect value. 
> > >  */
> > > +  if (LOOP_VINFO_USING_PARTIAL_VECTORS_P (loop_vinfo)
> > > +      && !LOOP_VINFO_NITERS_UNCOUNTED_P (loop_vinfo))
> > > +    {
> > > +      tree niters = LOOP_VINFO_NITERS (loop_vinfo);
> > > +      if (!types_compatible_p (niters_type, TREE_TYPE (niters)))
> > > +       niters = fold_convert (niters_type, niters);
> > > +      iters = fold_build2 (MIN_EXPR, niters_type, iters, niters);
> > > +    }
> > > +
> > >    if (dump_enabled_p ())
> > >      dump_printf_loc (MSG_NOTE, vect_location,
> > >                "niters for prolog loop: %T\n", iters);
> > >
> > >
> > >
> > 
> > --
> > 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)
> 

-- 
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)

Reply via email to