> -----Original Message----- > From: [email protected] <[email protected]> > Sent: 15 June 2026 15:27 > To: [email protected] > Cc: Tamar Christina <[email protected]>; Kyrylo Tkachov > <[email protected]> > Subject: [PATCH] aarch64: Fix early-ra wrong code with full-width FPR color > groups [PR125795] > > From: Kyrylo Tkachov <[email protected]> > > early_ra::allocate_colors marks the FPRs occupied by a color with > > m_allocated_fprs |= ((1U << color->group->size) - 1) << best; > > When a color group spans the whole register file (size == 32), as can > happen for a heavily unrolled, vectorized loop, "1U << 32" is undefined > and evaluates to 1 sometimes, so the expression sets no bits at all. > The 32 FPRs of the group are therefore not recorded as allocated. > Subsequent colors (and broaden_colors) then reuse those registers, which > breaks the invariant that distinct colors receive disjoint FPRs. > > In PR125795 this let the loop-invariant TBL permute index, which is live > across the whole loop, share v28 with the LD2 tuple destinations, so the > index was clobbered mid-loop and the loop produced wrong results. > > Fix this by building the mask with a loop, which is well-defined for any > group size in [1, 32] (the candidate search already guarantees > best + size <= 32, which the patch also asserts). When the full-width > group can no longer be hidden, allocate_colors correctly fails to find a > register for the other color and the region is left to the real register > allocator, matching -mearly-ra=none. > > Bootstrapped and tested on aarch64-none-linux-gnu. > > I'll push it to trunk tomorrow if no objections.
LGTM. Thanks, Tamar > Thanks, > Kyrill > > Signed-off-by: Kyrylo Tkachov <[email protected]> > > gcc/ChangeLog: > > PR target/125795 > * config/aarch64/aarch64-early-ra.cc (early_ra::allocate_colors): > Build the allocated-FPR mask with a loop instead of > "((1U << size) - 1) << best". > > gcc/testsuite/ChangeLog: > > PR target/125795 > * gcc.target/aarch64/pr125795.c: New test. > --- > gcc/config/aarch64/aarch64-early-ra.cc | 9 +++- > gcc/testsuite/gcc.target/aarch64/pr125795.c | 47 > +++++++++++++++++++++ > 2 files changed, 55 insertions(+), 1 deletion(-) > create mode 100644 gcc/testsuite/gcc.target/aarch64/pr125795.c > > diff --git a/gcc/config/aarch64/aarch64-early-ra.cc > b/gcc/config/aarch64/aarch64-early-ra.cc > index 24f0e1bdffb..243017e4ac1 100644 > --- a/gcc/config/aarch64/aarch64-early-ra.cc > +++ b/gcc/config/aarch64/aarch64-early-ra.cc > @@ -3038,7 +3038,14 @@ early_ra::allocate_colors () > if (dump_file && (dump_flags & TDF_DETAILS)) > fprintf (dump_file, " Allocating [v%d:v%d] to color %d\n", > best, best + color->group->size - 1, color->id); > - m_allocated_fprs |= ((1U << color->group->size) - 1) << best; > + // Mark the COLOR's FPRs as allocated. Build the mask with a loop > + // rather than ((1U << size) - 1), since a full-width color can have > + // size == 32 and "1U << 32" would be undefined. The candidate > + // search above guarantees best + size <= 32, so each shift is in > + // range. > + gcc_assert (best + color->group->size <= 32); > + for (unsigned int i = 0; i < color->group->size; ++i) > + m_allocated_fprs |= 1U << (best + i); > } > } > > diff --git a/gcc/testsuite/gcc.target/aarch64/pr125795.c > b/gcc/testsuite/gcc.target/aarch64/pr125795.c > new file mode 100644 > index 00000000000..9f5c6a32b5d > --- /dev/null > +++ b/gcc/testsuite/gcc.target/aarch64/pr125795.c > @@ -0,0 +1,47 @@ > +/* PR target/125795 */ > +/* { dg-do run } */ > +/* { dg-options "-O2 -funroll-loops" } */ > + > +/* This loop is vectorized with LD2 (deinterleave) and TBL (lane reversal), > + then unrolled. The unrolled body builds a full-width (32 FPR) early-ra > + color group, which used to trigger a "1U << 32" undefined shift in > + early_ra::allocate_colors. As a result the long-lived TBL permute index > + was wrongly allocated to the same FPR as an LD2 tuple destination and got > + clobbered, so the result was miscomputed. */ > + > +extern void abort (void); > + > +#define N 256 > + > +static int __attribute__ ((noipa)) > +foo (void) > +{ > + int k[N]; > + int k2[N]; > + int i; > + > + for (i = 0; i < N; i++) > + k2[i] = i; > + > + for (i = 0; i < 64; i++) > + { > + k[i] = k2[2 * i + 0]; > + k[255 - i] = k2[2 * i + 1]; > + k[64 + i] = k2[2 * i + 128]; > + k[191 - i] = k2[2 * i + 129]; > + } > + > + for (i = 0; i < N; i++) > + if (k[i] != ((i < 128) ? (2 * i) : (511 - 2 * i))) > + return 1; > + > + return 0; > +} > + > +int > +main (void) > +{ > + if (foo ()) > + abort (); > + return 0; > +} > -- > 2.50.1 (Apple Git-155)
