tree-optimization/121382 - avoid UB in IVOPTs inserted step computation

IVOPTs, when replacing an IV, inserts the computation of the new IVs
step in the loop preheader without considering the case of the loop
not iterating.  This means we have to ensure the step computation
does not invoke UB.  There is also SCEV which does not care about
signed arithmetic UB when re-associating expressions to form CHRECs,
so even when we know the loop iterates this is required.

	PR tree-optimization/121382
	* tree-ssa-loop-ivopts.cc (create_new_iv): Rewrite the IV
	step to defined form.

	* gcc.dg/torture/pr121382.c: New testcase.
This commit is contained in:
Richard Biener
2025-08-05 10:38:03 +02:00
committed by Richard Biener
parent afafae0972
commit 5d55cd95e2
2 changed files with 42 additions and 1 deletions

View File

@@ -0,0 +1,23 @@
/* { dg-do run } */
/* { dg-require-effective-target int32plus } */
int a, b, c;
__attribute__((noipa))
static void d(int e, int f)
{
if (e != 5 && e != 2147483647)
__builtin_abort();
f = 2147483647;
do {
f = f - e;
if (c - 9 * f) {
__builtin_abort();
}
} while (c);
}
__attribute__((noipa))
int main(void)
{
d(2147483647, 2147483647);
return 0;
}

View File

@@ -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,24 @@ 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),
/* The step computation could invoke UB when the loop does not iterate.
Avoid inserting it on the preheader in its native form but rewrite
it to a well-defined form. This also helps masking SCEV issues
which freely re-associates the IV computations when building up
CHRECs without much regard for signed overflow invoking UB. */
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);
}