> -----Original Message-----
> From: Pengfei Li <[email protected]>
> Sent: 02 July 2026 09:24
> To: Tamar Christina <[email protected]>; [email protected]
> Cc: [email protected]; [email protected]; Alex Coplan
> <[email protected]>; [email protected]
> Subject: Re: [PATCH] AArch64: Cap suggested unroll factor for small known-
> niters loops
> 
> Hi Tamar,
> 
> 
> On 02/07/2026 08:13, Tamar Christina wrote:
> >> -----Original Message-----
> >> From: Pengfei Li <[email protected]>
> >> Sent: 29 June 2026 09:31
> >> To: [email protected]
> >> Cc: [email protected]; Tamar Christina <[email protected]>;
> >> [email protected]; Alex Coplan <[email protected]>;
> >> [email protected]; Pengfei Li <[email protected]>
> >> Subject: [PATCH] AArch64: Cap suggested unroll factor for small known-
> niters
> >> loops
> >>
> >> The AArch64 backend can suggest an unroll factor to the vectorizer in
> >> order to expose more ILP. However, in some cases the suggested value is
> >> larger than needed. For the test cases added by this patch, the AArch64
> >> backend suggests an unroll factor of 4, but the loops only need 1 or 2
> >> SVE vector iterations respectively to cover their 10 or 20 scalar
> >> iterations.
> >>
> >> This patch caps the suggested unroll factor with CEIL (niters, VF) for
> >> small known-niters loops. CEIL is used rather than truncating division
> >> so that the completely unrolled vector loop still covers all scalar
> >> iterations. Reducing the unroll factor below the number of required
> >> vector iterations could require a separate epilogue loop and lead to
> >> worse code generation.
> >>
> >> Bootstrapped and tested on aarch64-linux-gnu.
> >>
> > OK.
> 
> Thanks for your review.
> 
> >
> > The testcase also shows an unrelated missed optimizations:
> >
> > When Adv. SIMD it's a case where V4QI would have helped, but aside from
> that
> > the scalar epilogue does
> >
> > .L2:
> >          ldrb    w2, [x0, x3]
> >          ldrb    w4, [x1, x3]
> >          add     x3, x3, 1
> >          subs    w2, w2, w4
> >          csneg   w2, w2, w2, pl
> >          fmov    s30, w2
> >          add     v31.2s, v31.2s, v30.2s
> >          cmp     x3, 20
> >          bne     .L2
> >          fmov    w0, s31
> >          ret
> 
> I haven't been able to reproduce the same AdvSIMD code sequence as you
> showed. Did you use the testcase you posted? Could you share the exact
> GCC options you are using?

https://godbolt.org/z/qq9s4nboq this also shows why I said V4QI would be useful 
here.

Tamar.
> 
> > so it's doing a register transfer to just do a scalar add, this slows down 
> > the
> > scalar code a lot. For some reason reload thinks it's cheaper to do the
> transfer
> > inside the loop rather than outside. This is likely because of the PHI that 
> > takes
> > the reduction value from the main loop into the epilog.
> >
> > We should check out RTX costs here.. but that's unrelated to the patch
> >
> > Thanks,
> > Tamar
> >
> >> gcc/ChangeLog:
> >>
> >>    * config/aarch64/aarch64.cc
> >>    (aarch64_vector_costs::determine_suggested_unroll_factor): Add a
> >>    loop_vec_info parameter.
> >>    (determine_suggested_unroll_factor): Cap the suggested unroll for
> >>    small-niters loops.
> >>    (aarch64_vector_costs::finish_cost): Pass loop_vinfo to
> >>    determine_suggested_unroll_factor.
> >>
> >> gcc/testsuite/ChangeLog:
> >>
> >>    * gcc.target/aarch64/sve/vect-unroll-1.c: New test.
> >>    * gcc.target/aarch64/sve/vect-unroll-2.c: New test.
> >> ---
> >>   gcc/config/aarch64/aarch64.cc                  | 18 +++++++++++++++---
> >>   .../gcc.target/aarch64/sve/vect-unroll-1.c     | 17 +++++++++++++++++
> >>   .../gcc.target/aarch64/sve/vect-unroll-2.c     | 17 +++++++++++++++++
> >>   3 files changed, 49 insertions(+), 3 deletions(-)
> >>   create mode 100644 gcc/testsuite/gcc.target/aarch64/sve/vect-unroll-1.c
> >>   create mode 100644 gcc/testsuite/gcc.target/aarch64/sve/vect-unroll-2.c
> >>
> >> diff --git a/gcc/config/aarch64/aarch64.cc
> b/gcc/config/aarch64/aarch64.cc
> >> index 124e6dc37cc..6246c8846f9 100644
> >> --- a/gcc/config/aarch64/aarch64.cc
> >> +++ b/gcc/config/aarch64/aarch64.cc
> >> @@ -17462,7 +17462,7 @@ private:
> >>     unsigned int adjust_body_cost (loop_vec_info, const
> aarch64_vector_costs
> >> *,
> >>                             unsigned int);
> >>     bool prefer_unrolled_loop () const;
> >> -  unsigned int determine_suggested_unroll_factor ();
> >> +  unsigned int determine_suggested_unroll_factor (loop_vec_info
> >> loop_vinfo);
> >>
> >>     /* True if we have performed one-time initialization based on the
> >>        vec_info.  */
> >> @@ -19024,7 +19024,8 @@ adjust_body_cost_sve (const
> >> aarch64_vec_op_count *ops,
> >>   }
> >>
> >>   unsigned int
> >> -aarch64_vector_costs::determine_suggested_unroll_factor ()
> >> +aarch64_vector_costs::
> >> +determine_suggested_unroll_factor (loop_vec_info loop_vinfo)
> >>   {
> >>     bool sve = m_vec_flags & VEC_ANY_SVE;
> >>     /* If we are trying to unroll an Advanced SIMD main loop that contains
> >> @@ -19081,6 +19082,16 @@
> >> aarch64_vector_costs::determine_suggested_unroll_factor ()
> >>         max_unroll_factor = MAX (max_unroll_factor, unroll_factor);
> >>       }
> >>
> >> +  /* For known iteration loops, cap suggested unroll factor to avoid
> >> redundant
> >> +     unrolled chunks.  Use CEIL rather than truncating division to make 
> >> sure
> >> +     the completely unrolled vector loop covers all scalar iterations.  */
> >> +  if (LOOP_VINFO_NITERS_KNOWN_P (loop_vinfo))
> >> +    {
> >> +      unsigned int niters = LOOP_VINFO_INT_NITERS (loop_vinfo);
> >> +      unsigned int estimated_vf = vect_vf_for_cost (loop_vinfo);
> >> +      max_unroll_factor = MIN (max_unroll_factor, CEIL (niters,
> estimated_vf));
> >> +    }
> >> +
> >>     /* Make sure unroll factor is power of 2.  */
> >>     return 1 << ceil_log2 (max_unroll_factor);
> >>   }
> >> @@ -19272,7 +19283,8 @@ aarch64_vector_costs::finish_cost (const
> >> vector_costs *uncast_scalar_costs)
> >>       {
> >>         m_costs[vect_body] = adjust_body_cost (loop_vinfo, scalar_costs,
> >>                                         m_costs[vect_body]);
> >> -      m_suggested_unroll_factor = determine_suggested_unroll_factor ();
> >> +      m_suggested_unroll_factor
> >> +  = determine_suggested_unroll_factor (loop_vinfo);
> >>
> >>         /* For gather and scatters there's an additional overhead for the 
> >> first
> >>     iteration.  For low count loops they're not beneficial so model the
> >> diff --git a/gcc/testsuite/gcc.target/aarch64/sve/vect-unroll-1.c
> >> b/gcc/testsuite/gcc.target/aarch64/sve/vect-unroll-1.c
> >> new file mode 100644
> >> index 00000000000..8548f504db0
> >> --- /dev/null
> >> +++ b/gcc/testsuite/gcc.target/aarch64/sve/vect-unroll-1.c
> >> @@ -0,0 +1,17 @@
> >> +/* Check that the loop is not unrolled.  */
> >> +/* { dg-do compile } */
> >> +/* { dg-options "-O2 -mtune=neoverse-v2 -mautovec-preference=sve-
> only" }
> >> */
> >> +
> >> +#include <stdint.h>
> >> +#include <stdlib.h>
> >> +
> >> +int
> >> +foo (uint8_t *p1, uint8_t *p2)
> >> +{
> >> +  int sum = 0;
> >> +  for (int i = 0; i < 10; i++)
> >> +    sum += abs (p1[i] - p2[i]);
> >> +  return sum;
> >> +}
> >> +
> >> +/* { dg-final { scan-assembler-not {\tld1b\t[^\n]*, mul vl} } } */
> >> diff --git a/gcc/testsuite/gcc.target/aarch64/sve/vect-unroll-2.c
> >> b/gcc/testsuite/gcc.target/aarch64/sve/vect-unroll-2.c
> >> new file mode 100644
> >> index 00000000000..e5f8c457d30
> >> --- /dev/null
> >> +++ b/gcc/testsuite/gcc.target/aarch64/sve/vect-unroll-2.c
> >> @@ -0,0 +1,17 @@
> >> +/* Check that the loop is unrolled by 2 rather than 4 for small niters.  
> >> */
> >> +/* { dg-do compile } */
> >> +/* { dg-options "-O2 -mtune=neoverse-v2 -mautovec-preference=sve-
> only" }
> >> */
> >> +
> >> +#include <stdint.h>
> >> +#include <stdlib.h>
> >> +
> >> +int
> >> +foo (uint8_t *p1, uint8_t *p2)
> >> +{
> >> +  int sum = 0;
> >> +  for (int i = 0; i < 20; i++)
> >> +    sum += abs (p1[i] - p2[i]);
> >> +  return sum;
> >> +}
> >> +
> >> +/* { dg-final { scan-assembler-times {\tld1b\t[^\n]*, mul vl} 2 } } */
> >> --
> >> 2.43.0

Reply via email to