https://gcc.gnu.org/bugzilla/show_bug.cgi?id=128615
Bug ID: 128615
Summary: [14/15/16/17 Regression] wrong code at -O3: predictive
commoning unrolling drops the exit test of a
256-iteration unsigned char loop (niter + 1 wraps in
determine_exit_conditions)
Product: gcc
Version: 17.0
Status: UNCONFIRMED
Keywords: wrong-code
Severity: normal
Priority: P3
Component: tree-optimization
Assignee: unassigned at gcc dot gnu.org
Reporter: lzy20000419 at outlook dot com
Target Milestone: ---
Fails with trunk (gcc 17.0.0 20261110, 33ed38d4ee09) and with 12.1.0 through
16.2.0; 9.5.0 through 11.5.0 work.
Target: x86_64-pc-linux-gnu (target-independent).
int b[1024], x[1024];
__attribute__((noipa)) void
f (int *__restrict q, const int *__restrict p)
{
unsigned char i = 0;
do
*q++ = p[0] + p[1] + p[2] + p[3];
while (p++, i++ != 255); /* 256 iterations */
}
int
main (void)
{
for (int k = 0; k < 1024; k++)
x[k] = -1;
f (x, b);
if (x[256] != -1)
__builtin_abort ();
return 0;
}
gcc -O3 t.c && ./a.out
Observed: abort. f stores 768 elements instead of 256. Expected: exit 0.
-O3 -fno-predictive-commoning works. -O2 -fpredictive-commoning fails the same
way. Loop unroll-and-jam and -fprefetch-loop-arrays reach the same code through
tree_unroll_loop when the unroll factor is not a power of two.
Godbolt (trunk): https://godbolt.org/z/1c1vMGx51
Cause: determine_exit_conditions (tree-ssa-loop-manip.cc) computes the
iteration count as desc->niter + 1 in the type of the control IV:
tree niter = fold_build2 (PLUS_EXPR, type, desc->niter,
build_one_cst (type));
if (multiple_of_p (type, niter, build_int_cst (type, factor)))
return;
Here type is unsigned char and niter is 255, so niter + 1 folds to 0. 0 is a
multiple of the unroll factor 3, so the function returns without an exit bound.
tree_transform_and_unroll_loop then removes the exit tests of all copies but
the last, and the loop runs 3 * 256 times.
Possible fix: test divisibility of niter + 1 in a wider type (widest_int for
constants), so that the + 1 cannot wrap.
Related: PR127405 is a different exit-bound path in the same function.
Disclaimer: This test case was found with LLM-assisted targeted testing, and
the report was written with LLM assistance.