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); }