Index: gcc/tree-ssa-loop-ivopts.c =================================================================== --- gcc/tree-ssa-loop-ivopts.c (revision 159362) +++ gcc/tree-ssa-loop-ivopts.c (working copy) @@ -5293,6 +5293,192 @@ find_optimal_iv_set (struct ivopts_data return set; } + +/* Performs a peephole optimization to reorder the iv update statement with + a mem ref to enable instruction combining in later phases. The mem ref uses + the iv value before the update, so the reordering transformation requires + adjustment of the offset. CAND is the selected IV_CAND. + + Example: + + t = MEM_REF (base, iv1, 8, 16); // base, index, stride, offset + iv2 = iv1 + 1; + + if (t < val) (1) + goto L; + goto Head; + + + directly propagating t over to (1) will introduce overlapping live range + thus increase register pressure. This peephole transform it into: + + + iv2 = iv1 + 1; + t = MEM_REF (base, iv2, 8, 8); + if (t < val) + goto L; + goto Head; +*/ + +static void +adjust_iv_update_pos (struct ivopts_data *data ATTRIBUTE_UNUSED, + struct iv_cand *cand) +{ + tree var_after, step, stride, index, offset_adjust, offset, mem_ref_op; + gimple iv_update, stmt, cond, mem_ref, index_to_base, use_stmt; + basic_block bb; + gimple_stmt_iterator gsi, gsi_iv; + use_operand_p use_p; + enum tree_code incr_op; + imm_use_iterator iter; + bool found = false; + + var_after = cand->var_after; + iv_update = SSA_NAME_DEF_STMT (var_after); + + /* Do not handle complicated iv update case. */ + incr_op = gimple_assign_rhs_code (iv_update); + if (incr_op != PLUS_EXPR && incr_op != MINUS_EXPR) + return; + + step = gimple_assign_rhs2 (iv_update); + if (!CONSTANT_CLASS_P (step)) + return; + + bb = gimple_bb (iv_update); + gsi = gsi_last_nondebug_bb (bb); + stmt = gsi_stmt (gsi); + + /* Only handle conditional statement for now. */ + if (gimple_code (stmt) != GIMPLE_COND) + return; + + cond = stmt; + + gsi_prev_nondebug (&gsi); + stmt = gsi_stmt (gsi); + if (stmt != iv_update) + return; + + gsi_prev_nondebug (&gsi); + if (gsi_end_p (gsi)) + return; + + stmt = gsi_stmt (gsi); + if (gimple_code (stmt) != GIMPLE_ASSIGN) + return; + + if (gimple_assign_rhs_code (stmt) != TARGET_MEM_REF) + return; + + mem_ref = stmt; + mem_ref_op = gimple_assign_rhs1 (mem_ref); + + if (TREE_CODE (gimple_assign_lhs (mem_ref)) != SSA_NAME) + return; + + if (!single_imm_use (gimple_assign_lhs (mem_ref), &use_p, &use_stmt)) + return; + + if (use_stmt != cond) + return; + + /* Found code motion candidate -- the statement with mem_ref. */ + + index = TMR_INDEX (mem_ref_op); + index_to_base = NULL; + if (index) + { + if (index != cand->var_before) + return; + } + else + { + /* Index used as base. */ + tree base = TMR_BASE (mem_ref_op); + + if (TREE_CODE (base) != SSA_NAME) + return; + + if (!has_single_use (base)) + return; + + index_to_base = SSA_NAME_DEF_STMT (base); + if (gimple_code (index_to_base) != GIMPLE_ASSIGN) + return; + if (gimple_assign_rhs_code (index_to_base) != NOP_EXPR) + return; + if (gimple_assign_rhs1 (index_to_base) != cand->var_before) + return; + } + + stride = TMR_STEP (mem_ref_op); + offset = TMR_OFFSET (mem_ref_op); + if (stride && index) + offset_adjust = int_const_binop (MULT_EXPR, stride, step, 0); + else + offset_adjust = step; + + if (offset_adjust == NULL) + return; + + offset = int_const_binop ((incr_op == PLUS_EXPR + ? MINUS_EXPR : PLUS_EXPR), + (offset ? offset : size_zero_node), + offset_adjust, 0); + + if (offset == NULL) + return; + + if (index_to_base) + gsi = gsi_for_stmt (index_to_base); + else + gsi = gsi_for_stmt (mem_ref); + gsi_iv = gsi_for_stmt (iv_update); + gsi_move_before (&gsi_iv, &gsi); + + /* Now fix up the mem_ref. */ + FOR_EACH_IMM_USE_FAST (use_p, iter, cand->var_before) + { + if (USE_STMT (use_p) == mem_ref || USE_STMT (use_p) == index_to_base) + { + set_ssa_use_from_ptr (use_p, var_after); + if (index_to_base) + *gimple_assign_rhs1_ptr (index_to_base) = var_after; + else + TMR_INDEX (mem_ref_op) = var_after; + + found = true; + break; + } + } + gcc_assert (found); + TMR_OFFSET (mem_ref_op) = offset; + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "Reordering \n"); + print_gimple_stmt (dump_file, iv_update, 0, 0); + print_gimple_stmt (dump_file, mem_ref, 0, 0); + fprintf (dump_file, "\n"); + } +} + +/* Performs reordering peep hole optimization for all selected ivs in SET. */ + +static void +adjust_update_pos_for_ivs (struct ivopts_data *data, struct iv_ca *set) +{ + unsigned i; + struct iv_cand *cand; + bitmap_iterator bi; + + EXECUTE_IF_SET_IN_BITMAP (set->cands, 0, i, bi) + { + cand = iv_cand (data, i); + adjust_iv_update_pos (data, cand); + } +} + /* Creates a new induction variable corresponding to CAND. */ static void @@ -5830,7 +6016,6 @@ tree_ssa_iv_optimize_loop (struct ivopts /* Create the new induction variables (item 4, part 1). */ create_new_ivs (data, iv_ca); - iv_ca_free (&iv_ca); /* Rewrite the uses (item 4, part 2). */ rewrite_uses (data); @@ -5838,6 +6023,10 @@ tree_ssa_iv_optimize_loop (struct ivopts /* Remove the ivs that are unused after rewriting. */ remove_unused_ivs (data); + adjust_update_pos_for_ivs (data, iv_ca); + + iv_ca_free (&iv_ca); + /* We have changed the structure of induction variables; it might happen that definitions in the scev database refer to some of them that were eliminated. */