https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69224
Richard Biener <rguenth at gcc dot gnu.org> changed: What |Removed |Added ---------------------------------------------------------------------------- Status|NEW |ASSIGNED Assignee|unassigned at gcc dot gnu.org |rguenth at gcc dot gnu.org --- Comment #4 from Richard Biener <rguenth at gcc dot gnu.org> --- Ok, so the issue is that discover_iteration_bound_by_body_walk adds one to the upper bound derived for s->x[j] (5) because /* Exit terminates loop at given iteration, while non-exits produce undefined effect on the next iteration. */ and after unrolling to 6 iterations we do Latch of last iteration was marked by __builtin_unreachable (). Forced statement unreachable: _25 = s_7(D)->x[_24]; Forced statement unreachable: _22 = s_7(D)->x[j_2]; so figure both reads have undefined behavior in iteration 6. But we never try to force stmts unreachable in earlier iterations - s->x[j + 1] is already undefined in iteration 5 which would end up removing that iteration completely. remove_exits_and_undefined_stmts only has links to stmts in the original loop body (which will become the last iteration), so marking stmts unreachable would need to be done during gimple_duplicate_loop_to_header_edge itself to catch this case. Or avoid the + 1 in discover_iteration_bound_by_body_walk for unconditionally executed "bounds". So the following untested patch fixes the issue by unrolling one iteration less. Index: gcc/tree-ssa-loop-niter.c =================================================================== --- gcc/tree-ssa-loop-niter.c (revision 233661) +++ gcc/tree-ssa-loop-niter.c (working copy) @@ -3171,9 +3171,12 @@ discover_iteration_bound_by_body_walk (s { widest_int bound = elt->bound; - /* Exit terminates loop at given iteration, while non-exits produce undefined - effect on the next iteration. */ - if (!elt->is_exit) + /* Exit terminates loop at given iteration, while non-exits produce + undefined effect on the next iteration. Unless they are always + executed. */ + if (!elt->is_exit + && ! dominated_by_p (CDI_DOMINATORS, loop->latch, + gimple_bb (elt->stmt))) { bound += 1; /* If an overflow occurred, ignore the result. */ @@ -3203,7 +3206,9 @@ discover_iteration_bound_by_body_walk (s for (elt = loop->bounds; elt; elt = elt->next) { widest_int bound = elt->bound; - if (!elt->is_exit) + if (!elt->is_exit + && ! dominated_by_p (CDI_DOMINATORS, loop->latch, + gimple_bb (elt->stmt))) { bound += 1; /* If an overflow occurred, ignore the result. */