https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127677
Tamar Christina <tnfchris at gcc dot gnu.org> changed:
What |Removed |Added
----------------------------------------------------------------------------
Status|UNCONFIRMED |ASSIGNED
Blocks| |53947
Ever confirmed|0 |1
Component|middle-end |tree-optimization
Keywords| |wrong-code
Last reconfirmed| |2026-09-30
CC|tamar.christina at arm dot com |tnfchris at gcc dot
gnu.org
--- Comment #1 from Tamar Christina <tnfchris at gcc dot gnu.org> ---
Thanks for the report,
This is an alignment peeling bug which my patch exposed.
A reduced testcase:
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);
}
which when compiled shows
Global Exported: niters.8_45 = [irange] unsigned int [16, +INF]
This range is bogus because of alignment peeling. The code generates
niters = count - start = 2 - 1 = 1
prolog_niters = 7
so when it calculates the remainder
remaining = niters - prolog_niters;
this underflows:
1 - 7 = 4294967290
This only shows up for RISC-V because
1. SVE uses fully masked loops to handle the remainder
2. Adv. SIMD and x86_64 and other targets use a low iteration guard. i.e. if
peeling count > niters they branch to a scalar epilog.
Early break just happens to expose this, because normally it forces alignment
peeling, and in this case without an epilog.
previously the scalar epilog would restart the loop at the original IV start of
1, and so the underflow was hidden and ignored.
Mine.
Referenced Bugs:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53947
[Bug 53947] [meta-bug] vectorizer missed-optimizations