https://gcc.gnu.org/bugzilla/show_bug.cgi?id=121382

Richard Biener <rguenth at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
           Assignee|tnfchris at gcc dot gnu.org        |rguenth at gcc dot 
gnu.org

--- Comment #9 from Richard Biener <rguenth at gcc dot gnu.org> ---
So we have

(get_scalar_evolution
  (scalar = f_9)
  (scalar_evolution = {2147483647 - e_8(D), +, -e_8(D)}_1))

and

(set_scalar_evolution
  instantiated_below = 8
  (scalar = _6)
  (scalar_evolution = {(2147483647 - e_8(D)) * -9 + c.0_5, +, e_8(D) * 9}_1))

the latter (we check _6 against zero for the early exit to abort) invokes
UB once it iterates (e_8(D) * 9 is UB).  That isn't an issue originally
because that's only computed (virtually) in the latch which we do not reach
since we never iterate.  But IVOPTs inserts the e_8(D) * 9 expression
in the loop preheader, invoking UB there and it also performs the
IV increment before the c != 0 exit check (so that value computed with UB
is even actually used).  Ranger happily derives

  c.0_5 = c;
  # RANGE [irange] int [45, 45][+INF, +INF]
  _14 = e_8(D) * 9;
  # RANGE [irange] unsigned int [45, 45][2147483647, 2147483647] MASK
0x7fffffff VALUE 0x0
  _15 = (unsigned int) _14; 
  _17 = (unsigned int) e_8(D);
  _19 = (unsigned int) c.0_5;
  _7 = _19 + 2147483657;
  ivtmp.11_16 = _7 + _15;

and things go downhill from there.  So what needs to happen and what
does not, for some reason, is that the IV increment needs to be
computed in unsigned arithmetic.  You can see IVOPTs already rewrites
the initial value, but for some reason it fails to do the same to the
increment.

I'll note that one could argue SCEV is at fault here as well, given it
associates (((f_7 - e_8) * -9 + c) - e_8) * -9 + c ... without
regard for overflow when building the CHREC.  That's the long-standing
issue I mentioned.

tree-affine rewrites associated expressions to unsigned, so that should
be all fine.

But IVOPTs cannot rely on the SCEV IV increment being computable without
UB in the loop preheader at least.  IVOPTs emits the IV in create_new_iv
via

  create_iv (base, PLUS_EXPR, unshare_expr (cand->iv->step),
             cand->var_before, data->current_loop,
             &incr_pos, after, &cand->var_before, &cand->var_after);

The following fixes the issue:

diff --git a/gcc/tree-ssa-loop-ivopts.cc b/gcc/tree-ssa-loop-ivopts.cc
index 879668c518a..4797f4ca609 100644
--- a/gcc/tree-ssa-loop-ivopts.cc
+++ b/gcc/tree-ssa-loop-ivopts.cc
@@ -132,6 +132,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-vectorizer.h"
 #include "dbgcnt.h"
 #include "cfganal.h"
+#include "gimple-fold.h"

 /* For lang_hooks.types.type_for_mode.  */
 #include "langhooks.h"
@@ -7252,7 +7253,19 @@ create_new_iv (struct ivopts_data *data, struct iv_cand
*cand)

   base = unshare_expr (cand->iv->base);

-  create_iv (base, PLUS_EXPR, unshare_expr (cand->iv->step),
+  gimple_seq stmts = NULL;
+  tree step = force_gimple_operand (unshare_expr (cand->iv->step), &stmts,
+                                   true, NULL_TREE);
+  if (stmts)
+    {
+      for (auto gsi = gsi_start (stmts); !gsi_end_p (gsi); gsi_next (&gsi))
+       if (gimple_needing_rewrite_undefined (gsi_stmt (gsi)))
+         rewrite_to_defined_unconditional (&gsi);
+      gsi_insert_seq_on_edge_immediate (loop_preheader_edge
(data->current_loop),
+                                       stmts);
+    }
+
+  create_iv (base, PLUS_EXPR, step,
             cand->var_before, data->current_loop,
             &incr_pos, after, &cand->var_before, &cand->var_after);
 }

Reply via email to