diff --git a/gcc/tree-outof-ssa.c b/gcc/tree-outof-ssa.c index 59bdcd6fadd..7efd835e2d1 100644 --- a/gcc/tree-outof-ssa.c +++ b/gcc/tree-outof-ssa.c @@ -43,6 +43,8 @@ along with GCC; see the file COPYING3. If not see #include "tree-ssa-coalesce.h" #include "tree-outof-ssa.h" #include "dojump.h" +#include "fold-const.h" +#include "tree-ssa-loop-niter.h" /* FIXME: A lot of code here deals with expanding to RTL. All that code should be in cfgexpand.c. */ @@ -1035,6 +1037,95 @@ trivially_conflicts_p (basic_block bb, tree result, tree arg) return false; } +/* Return TRUE if STMT is in the form: x_99 = SSA +p INT. */ +// FIXME: Generalize this a bit more. Perhaps handle PLUS/MINUS_EXPR too. +static bool +iv_plus_constant (gimple *stmt, tree ssa) +{ + return is_gimple_assign (stmt) + && gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR + && gimple_assign_rhs1 (stmt) == ssa + && TREE_CODE (gimple_assign_rhs2 (stmt)) == INTEGER_CST; +} + +/* If there is a use of a previous iteration of an IV outside of the + loop, see if we can rewrite the out-of-loop version in terms of IV. + + This undoes some of the damage done by forwprop creating + overlapping life-ranges for before and after values of an IV. + + We are looking for loops like this: + + LOOP: + # p_8 = PHI + ... + p_INC = p_8 - 1; + goto LOOP; + x_123 = p_8 - 2; + + The outside use of p_8 can be rewritten as: + x_123 = p_INC - 1; + which can yield better auto inc/dec addressing. + + IV is the induction variable (p_8 above). + IV_INCR is the increment variable (p_INC above). */ + +static void +uncoalesce_ivs_outside_loop (tree iv, tree iv_incr) +{ + gimple *incr_stmt = SSA_NAME_DEF_STMT (iv_incr); + if (!iv_plus_constant (incr_stmt, iv)) + return; + + gimple *use; + imm_use_iterator imm_iter; + tree curr_cst = gimple_assign_rhs2 (incr_stmt); + // FIXME: Generalize this. Perhaps handle any multiple of CURR_CST. + tree prev_cst = fold_build2 (PLUS_EXPR, TREE_TYPE (curr_cst), + curr_cst, curr_cst); + FOR_EACH_IMM_USE_STMT (use, imm_iter, iv) + { + if (is_gimple_debug (use) + || use == incr_stmt + || !iv_plus_constant (use, iv) + || prev_cst != gimple_assign_rhs2 (use) + || !stmt_dominates_stmt_p (incr_stmt, use)) + // FIXME: bail if USE is not outside loop ?? + continue; + + /* Rewrite: + iv_incr = iv + 1 + ... + x = iv + 2*CST + into + x = iv_incr + CST + */ + gimple_assign_set_rhs1 (use, iv_incr); + gimple_assign_set_rhs2 (use, curr_cst); + update_stmt (use); + + /* If possible, rewrite MEM[iv_incr + CST] into *x. */ + gimple *u; + tree x = gimple_assign_lhs (use); + imm_use_iterator imm_iter2; + FOR_EACH_IMM_USE_STMT (u, imm_iter2, iv_incr) + { + if (!is_gimple_assign (u) + || TREE_CODE (gimple_assign_lhs (u)) != MEM_REF) + continue; + tree lhs = gimple_assign_lhs (u); + if (TREE_OPERAND (lhs, 0) == iv_incr + && TREE_CODE (TREE_OPERAND (lhs, 1)) == INTEGER_CST + && tree_int_cst_equal (TREE_OPERAND (lhs, 1), curr_cst)) + { + TREE_OPERAND (lhs, 0) = x; + TREE_OPERAND (lhs, 1) + = build_int_cst (TREE_TYPE (TREE_OPERAND (lhs, 1)), 0); + update_stmt (u); + } + } + } +} /* Search every PHI node for arguments associated with backedges which we can trivially determine will need a copy (the argument is either @@ -1090,6 +1181,8 @@ insert_backedge_copies (void) if (!gsi_end_p (gsi2)) last = gsi_stmt (gsi2); + uncoalesce_ivs_outside_loop (result, arg); + /* In theory the only way we ought to get back to the start of a loop should be with a COND_EXPR or GOTO_EXPR. However, better safe than sorry.