This patch from Zdenek removes special code handling the forced rewrite of the original BIV definition. The code was broken, so simply fallback to the general rewriting code which works fine.
Bootstrapped and tested on x86_64-unknown-linux-gnu, applied to trunk (the issue is latent on the branches). Thanks Zdenek for the fix, Richard. 2012-12-12 Zdenek Dvorak <o...@ucw.cz> PR tree-optimization/55481 * tree-ssa-loop-ivopts.c (rewrite_use_nonlinear_expr): Fall back to general rewriting if we cannot leave an original biv definition alone. * gcc.dg/torture/pr55481.c: New testcase. Index: gcc/tree-ssa-loop-ivopts.c =================================================================== *** gcc/tree-ssa-loop-ivopts.c (revision 194438) --- gcc/tree-ssa-loop-ivopts.c (working copy) *************** rewrite_use_nonlinear_expr (struct ivopt *** 6088,6122 **** if (cand->pos == IP_ORIGINAL && cand->incremented_at == use->stmt) { ! tree step, ctype, utype; ! enum tree_code incr_code = PLUS_EXPR, old_code; gcc_assert (is_gimple_assign (use->stmt)); gcc_assert (gimple_assign_lhs (use->stmt) == cand->var_after); - step = cand->iv->step; - ctype = TREE_TYPE (step); - utype = TREE_TYPE (cand->var_after); - if (TREE_CODE (step) == NEGATE_EXPR) - { - incr_code = MINUS_EXPR; - step = TREE_OPERAND (step, 0); - } - /* Check whether we may leave the computation unchanged. This is the case only if it does not rely on other computations in the loop -- otherwise, the computation we rely upon may be removed in remove_unused_ivs, thus leading to ICE. */ ! old_code = gimple_assign_rhs_code (use->stmt); ! if (old_code == PLUS_EXPR ! || old_code == MINUS_EXPR ! || old_code == POINTER_PLUS_EXPR) { if (gimple_assign_rhs1 (use->stmt) == cand->var_before) op = gimple_assign_rhs2 (use->stmt); ! else if (old_code != MINUS_EXPR ! && gimple_assign_rhs2 (use->stmt) == cand->var_before) op = gimple_assign_rhs1 (use->stmt); else op = NULL_TREE; --- 6088,6111 ---- if (cand->pos == IP_ORIGINAL && cand->incremented_at == use->stmt) { ! enum tree_code stmt_code; gcc_assert (is_gimple_assign (use->stmt)); gcc_assert (gimple_assign_lhs (use->stmt) == cand->var_after); /* Check whether we may leave the computation unchanged. This is the case only if it does not rely on other computations in the loop -- otherwise, the computation we rely upon may be removed in remove_unused_ivs, thus leading to ICE. */ ! stmt_code = gimple_assign_rhs_code (use->stmt); ! if (stmt_code == PLUS_EXPR ! || stmt_code == MINUS_EXPR ! || stmt_code == POINTER_PLUS_EXPR) { if (gimple_assign_rhs1 (use->stmt) == cand->var_before) op = gimple_assign_rhs2 (use->stmt); ! else if (gimple_assign_rhs2 (use->stmt) == cand->var_before) op = gimple_assign_rhs1 (use->stmt); else op = NULL_TREE; *************** rewrite_use_nonlinear_expr (struct ivopt *** 6124,6147 **** else op = NULL_TREE; ! if (op ! && (TREE_CODE (op) == INTEGER_CST ! || operand_equal_p (op, step, 0))) return; - - /* Otherwise, add the necessary computations to express - the iv. */ - op = fold_convert (ctype, cand->var_before); - comp = fold_convert (utype, - build2 (incr_code, ctype, op, - unshare_expr (step))); - } - else - { - comp = get_computation (data->current_loop, use, cand); - gcc_assert (comp != NULL_TREE); } switch (gimple_code (use->stmt)) { case GIMPLE_PHI: --- 6113,6125 ---- else op = NULL_TREE; ! if (op && expr_invariant_in_loop_p (data->current_loop, op)) return; } + comp = get_computation (data->current_loop, use, cand); + gcc_assert (comp != NULL_TREE); + switch (gimple_code (use->stmt)) { case GIMPLE_PHI: Index: gcc/testsuite/gcc.dg/torture/pr55481.c =================================================================== *** gcc/testsuite/gcc.dg/torture/pr55481.c (revision 0) --- gcc/testsuite/gcc.dg/torture/pr55481.c (revision 0) *************** *** 0 **** --- 1,16 ---- + /* { dg-do run } */ + + int main() + { + signed char result = 0; + int n; + for (n = 0; n < 13; ++n) + { + int tem = result; + tem = tem + 31; + result = tem; + } + if (result != -109) + __builtin_abort (); + return 0; + }