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.  */

Reply via email to