diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 16a3abc7afa5..144175b6b46c 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,20 @@ +2013-01-16 Richard Biener + + PR tree-optimization/55964 + * tree-flow.h (rename_variables_in_loop): Remove. + (rename_variables_in_bb): Likewise. + * tree-loop-distribution.c (update_phis_for_loop_copy): Remove. + (copy_loop_before): Adjust and delete update-ssa status. + * tree-vect-loop-manip.c (rename_variables_in_bb): Make static. + (rename_variables_in_bb): Likewise. Properly walk over + predecessors. + (rename_variables_in_loop): Remove. + (slpeel_update_phis_for_duplicate_loop): Likewise. + (slpeel_tree_duplicate_loop_to_edge_cfg): Handle nested loops, + use available cfg machinery instead of duplicating it. + Update PHI nodes and perform poor-mans SSA update here. + (slpeel_tree_peel_loop_to_edge): Adjust. + 2013-01-16 Richard Biener PR tree-optimization/54767 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 05f76676eda7..fe566baee0eb 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2013-01-16 Richard Biener + + PR tree-optimization/55964 + * gcc.dg/torture/pr55964.c: New testcase. + 2013-01-16 Richard Biener PR tree-optimization/54767 diff --git a/gcc/testsuite/gcc.dg/torture/pr55964.c b/gcc/testsuite/gcc.dg/torture/pr55964.c new file mode 100644 index 000000000000..361151ccf0c7 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr55964.c @@ -0,0 +1,24 @@ +/* { dg-do compile } */ +/* { dg-options "-ftree-loop-distribution -funswitch-loops -w" } */ + +int a, b; + +void f(void) +{ +lbl1: + for(b = 0; b < 1; b++) + { + int u = 1; + + if((b %= 0) * (b ? 0 : a) - 1 && (u /= 0)) + { + int *q = &u, **k = q; + goto lbl1; +lbl2: +lbl3: + a = **k; + goto lbl2; + } + } + goto lbl3; +} diff --git a/gcc/tree-flow.h b/gcc/tree-flow.h index 1fddeef6d146..a87eeaef2632 100644 --- a/gcc/tree-flow.h +++ b/gcc/tree-flow.h @@ -654,8 +654,6 @@ bool gimple_duplicate_loop_to_header_edge (struct loop *, edge, edge, vec *, int); struct loop *slpeel_tree_duplicate_loop_to_edge_cfg (struct loop *, edge); -void rename_variables_in_loop (struct loop *); -void rename_variables_in_bb (basic_block bb); tree expand_simple_operations (tree); void substitute_in_loop_info (struct loop *, tree, tree); edge single_dom_exit (struct loop *); diff --git a/gcc/tree-loop-distribution.c b/gcc/tree-loop-distribution.c index 93e98eba991b..747b6ac6131d 100644 --- a/gcc/tree-loop-distribution.c +++ b/gcc/tree-loop-distribution.c @@ -151,58 +151,6 @@ stmt_has_scalar_dependences_outside_loop (loop_p loop, gimple stmt) return false; } -/* Update the PHI nodes of NEW_LOOP. NEW_LOOP is a duplicate of - ORIG_LOOP. */ - -static void -update_phis_for_loop_copy (struct loop *orig_loop, struct loop *new_loop) -{ - tree new_ssa_name; - gimple_stmt_iterator si_new, si_orig; - edge orig_loop_latch = loop_latch_edge (orig_loop); - edge orig_entry_e = loop_preheader_edge (orig_loop); - edge new_loop_entry_e = loop_preheader_edge (new_loop); - - /* Scan the phis in the headers of the old and new loops - (they are organized in exactly the same order). */ - for (si_new = gsi_start_phis (new_loop->header), - si_orig = gsi_start_phis (orig_loop->header); - !gsi_end_p (si_new) && !gsi_end_p (si_orig); - gsi_next (&si_new), gsi_next (&si_orig)) - { - tree def; - source_location locus; - gimple phi_new = gsi_stmt (si_new); - gimple phi_orig = gsi_stmt (si_orig); - - /* Add the first phi argument for the phi in NEW_LOOP (the one - associated with the entry of NEW_LOOP) */ - def = PHI_ARG_DEF_FROM_EDGE (phi_orig, orig_entry_e); - locus = gimple_phi_arg_location_from_edge (phi_orig, orig_entry_e); - add_phi_arg (phi_new, def, new_loop_entry_e, locus); - - /* Add the second phi argument for the phi in NEW_LOOP (the one - associated with the latch of NEW_LOOP) */ - def = PHI_ARG_DEF_FROM_EDGE (phi_orig, orig_loop_latch); - locus = gimple_phi_arg_location_from_edge (phi_orig, orig_loop_latch); - - if (TREE_CODE (def) == SSA_NAME) - { - new_ssa_name = get_current_def (def); - - if (!new_ssa_name) - /* This only happens if there are no definitions inside the - loop. Use the the invariant in the new loop as is. */ - new_ssa_name = def; - } - else - /* Could be an integer. */ - new_ssa_name = def; - - add_phi_arg (phi_new, new_ssa_name, loop_latch_edge (new_loop), locus); - } -} - /* Return a copy of LOOP placed before LOOP. */ static struct loop * @@ -215,9 +163,7 @@ copy_loop_before (struct loop *loop) res = slpeel_tree_duplicate_loop_to_edge_cfg (loop, preheader); gcc_assert (res != NULL); free_original_copy_tables (); - - update_phis_for_loop_copy (loop, res); - rename_variables_in_loop (res); + delete_update_ssa (); return res; } diff --git a/gcc/tree-vect-loop-manip.c b/gcc/tree-vect-loop-manip.c index 6b6e130159e7..8e589de6d1f1 100644 --- a/gcc/tree-vect-loop-manip.c +++ b/gcc/tree-vect-loop-manip.c @@ -67,7 +67,7 @@ rename_use_op (use_operand_p op_p) /* Renames the variables in basic block BB. */ -void +static void rename_variables_in_bb (basic_block bb) { gimple_stmt_iterator gsi; @@ -85,32 +85,16 @@ rename_variables_in_bb (basic_block bb) rename_use_op (use_p); } - FOR_EACH_EDGE (e, ei, bb->succs) + FOR_EACH_EDGE (e, ei, bb->preds) { - if (!flow_bb_inside_loop_p (loop, e->dest)) + if (!flow_bb_inside_loop_p (loop, e->src)) continue; - for (gsi = gsi_start_phis (e->dest); !gsi_end_p (gsi); gsi_next (&gsi)) + for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi)) rename_use_op (PHI_ARG_DEF_PTR_FROM_EDGE (gsi_stmt (gsi), e)); } } -/* Renames variables in new generated LOOP. */ - -void -rename_variables_in_loop (struct loop *loop) -{ - unsigned i; - basic_block *bbs; - - bbs = get_loop_body (loop); - - for (i = 0; i < loop->num_nodes; i++) - rename_variables_in_bb (bbs[i]); - - free (bbs); -} - typedef struct { tree from, to; @@ -234,101 +218,6 @@ adjust_phi_and_debug_stmts (gimple update_phi, edge e, tree new_def) } -/* Update the PHI nodes of NEW_LOOP. - - NEW_LOOP is a duplicate of ORIG_LOOP. - AFTER indicates whether NEW_LOOP executes before or after ORIG_LOOP: - AFTER is true if NEW_LOOP executes after ORIG_LOOP, and false if it - executes before it. */ - -static void -slpeel_update_phis_for_duplicate_loop (struct loop *orig_loop, - struct loop *new_loop, bool after) -{ - tree new_ssa_name; - gimple phi_new, phi_orig; - tree def; - edge orig_loop_latch = loop_latch_edge (orig_loop); - edge orig_entry_e = loop_preheader_edge (orig_loop); - edge new_loop_exit_e = single_exit (new_loop); - edge new_loop_entry_e = loop_preheader_edge (new_loop); - edge entry_arg_e = (after ? orig_loop_latch : orig_entry_e); - gimple_stmt_iterator gsi_new, gsi_orig; - - /* - step 1. For each loop-header-phi: - Add the first phi argument for the phi in NEW_LOOP - (the one associated with the entry of NEW_LOOP) - - step 2. For each loop-header-phi: - Add the second phi argument for the phi in NEW_LOOP - (the one associated with the latch of NEW_LOOP) - - step 3. Update the phis in the successor block of NEW_LOOP. - - case 1: NEW_LOOP was placed before ORIG_LOOP: - The successor block of NEW_LOOP is the header of ORIG_LOOP. - Updating the phis in the successor block can therefore be done - along with the scanning of the loop header phis, because the - header blocks of ORIG_LOOP and NEW_LOOP have exactly the same - phi nodes, organized in the same order. - - case 2: NEW_LOOP was placed after ORIG_LOOP: - The successor block of NEW_LOOP is the original exit block of - ORIG_LOOP - the phis to be updated are the loop-closed-ssa phis. - We postpone updating these phis to a later stage (when - loop guards are added). - */ - - - /* Scan the phis in the headers of the old and new loops - (they are organized in exactly the same order). */ - - for (gsi_new = gsi_start_phis (new_loop->header), - gsi_orig = gsi_start_phis (orig_loop->header); - !gsi_end_p (gsi_new) && !gsi_end_p (gsi_orig); - gsi_next (&gsi_new), gsi_next (&gsi_orig)) - { - source_location locus; - phi_new = gsi_stmt (gsi_new); - phi_orig = gsi_stmt (gsi_orig); - - /* step 1. */ - def = PHI_ARG_DEF_FROM_EDGE (phi_orig, entry_arg_e); - locus = gimple_phi_arg_location_from_edge (phi_orig, entry_arg_e); - add_phi_arg (phi_new, def, new_loop_entry_e, locus); - - /* step 2. */ - def = PHI_ARG_DEF_FROM_EDGE (phi_orig, orig_loop_latch); - locus = gimple_phi_arg_location_from_edge (phi_orig, orig_loop_latch); - if (TREE_CODE (def) != SSA_NAME) - continue; - - new_ssa_name = get_current_def (def); - if (!new_ssa_name) - { - /* This only happens if there are no definitions - inside the loop. use the phi_result in this case. */ - new_ssa_name = PHI_RESULT (phi_new); - } - - /* An ordinary ssa name defined in the loop. */ - add_phi_arg (phi_new, new_ssa_name, loop_latch_edge (new_loop), locus); - - /* Drop any debug references outside the loop, if they would - become ill-formed SSA. */ - adjust_debug_stmts (def, NULL, single_exit (orig_loop)->dest); - - /* step 3 (case 1). */ - if (!after) - { - gcc_assert (new_loop_exit_e == orig_entry_e); - adjust_phi_and_debug_stmts (phi_orig, new_loop_exit_e, new_ssa_name); - } - } -} - - /* Update PHI nodes for a guard of the LOOP. Input: @@ -809,16 +698,15 @@ slpeel_tree_duplicate_loop_to_edge_cfg (struct loop *loop, edge e) bool at_exit; bool was_imm_dom; basic_block exit_dest; - gimple phi; - tree phi_arg; edge exit, new_exit; - gimple_stmt_iterator gsi; - at_exit = (e == single_exit (loop)); + exit = single_exit (loop); + at_exit = (e == exit); if (!at_exit && e != loop_preheader_edge (loop)) return NULL; - bbs = get_loop_body (loop); + bbs = XNEWVEC (basic_block, loop->num_nodes + 1); + get_loop_body_with_size (loop, bbs, loop->num_nodes); /* Check whether duplication is possible. */ if (!can_copy_bbs_p (bbs, loop->num_nodes)) @@ -829,91 +717,71 @@ slpeel_tree_duplicate_loop_to_edge_cfg (struct loop *loop, edge e) /* Generate new loop structure. */ new_loop = duplicate_loop (loop, loop_outer (loop)); - if (!new_loop) - { - free (bbs); - return NULL; - } + duplicate_subloops (loop, new_loop); - exit_dest = single_exit (loop)->dest; + exit_dest = exit->dest; was_imm_dom = (get_immediate_dominator (CDI_DOMINATORS, exit_dest) == loop->header ? true : false); - new_bbs = XNEWVEC (basic_block, loop->num_nodes); + /* Also copy the pre-header, this avoids jumping through hoops to + duplicate the loop entry PHI arguments. Create an empty + pre-header unconditionally for this. */ + basic_block preheader = split_edge (loop_preheader_edge (loop)); + edge entry_e = single_pred_edge (preheader); + bbs[loop->num_nodes] = preheader; + new_bbs = XNEWVEC (basic_block, loop->num_nodes + 1); - exit = single_exit (loop); - copy_bbs (bbs, loop->num_nodes, new_bbs, + copy_bbs (bbs, loop->num_nodes + 1, new_bbs, &exit, 1, &new_exit, NULL, e->src); + basic_block new_preheader = new_bbs[loop->num_nodes]; - /* Duplicating phi args at exit bbs as coming - also from exit of duplicated loop. */ - for (gsi = gsi_start_phis (exit_dest); !gsi_end_p (gsi); gsi_next (&gsi)) - { - phi = gsi_stmt (gsi); - phi_arg = PHI_ARG_DEF_FROM_EDGE (phi, single_exit (loop)); - if (phi_arg) - { - edge new_loop_exit_edge; - source_location locus; - - locus = gimple_phi_arg_location_from_edge (phi, single_exit (loop)); - if (EDGE_SUCC (new_loop->header, 0)->dest == new_loop->latch) - new_loop_exit_edge = EDGE_SUCC (new_loop->header, 1); - else - new_loop_exit_edge = EDGE_SUCC (new_loop->header, 0); - - add_phi_arg (phi, phi_arg, new_loop_exit_edge, locus); - } - } + add_phi_args_after_copy (new_bbs, loop->num_nodes + 1, NULL); if (at_exit) /* Add the loop copy at exit. */ { - redirect_edge_and_branch_force (e, new_loop->header); - PENDING_STMT (e) = NULL; - set_immediate_dominator (CDI_DOMINATORS, new_loop->header, e->src); + redirect_edge_and_branch_force (e, new_preheader); + flush_pending_stmts (e); + set_immediate_dominator (CDI_DOMINATORS, new_preheader, e->src); if (was_imm_dom) set_immediate_dominator (CDI_DOMINATORS, exit_dest, new_loop->header); + + /* And remove the non-necessary forwarder again. Keep the other + one so we have a proper pre-header for the loop at the exit edge. */ + redirect_edge_pred (single_succ_edge (preheader), single_pred (preheader)); + delete_basic_block (preheader); + set_immediate_dominator (CDI_DOMINATORS, loop->header, + loop_preheader_edge (loop)->src); } else /* Add the copy at entry. */ { - edge new_exit_e; - edge entry_e = loop_preheader_edge (loop); - basic_block preheader = entry_e->src; + redirect_edge_and_branch_force (entry_e, new_preheader); + flush_pending_stmts (entry_e); + set_immediate_dominator (CDI_DOMINATORS, new_preheader, entry_e->src); - if (!flow_bb_inside_loop_p (new_loop, - EDGE_SUCC (new_loop->header, 0)->dest)) - new_exit_e = EDGE_SUCC (new_loop->header, 0); - else - new_exit_e = EDGE_SUCC (new_loop->header, 1); + redirect_edge_and_branch_force (new_exit, preheader); + flush_pending_stmts (new_exit); + set_immediate_dominator (CDI_DOMINATORS, preheader, new_exit->src); - redirect_edge_and_branch_force (new_exit_e, loop->header); - PENDING_STMT (new_exit_e) = NULL; - set_immediate_dominator (CDI_DOMINATORS, loop->header, - new_exit_e->src); - - /* We have to add phi args to the loop->header here as coming - from new_exit_e edge. */ - for (gsi = gsi_start_phis (loop->header); - !gsi_end_p (gsi); - gsi_next (&gsi)) - { - phi = gsi_stmt (gsi); - phi_arg = PHI_ARG_DEF_FROM_EDGE (phi, entry_e); - if (phi_arg) - add_phi_arg (phi, phi_arg, new_exit_e, - gimple_phi_arg_location_from_edge (phi, entry_e)); - } - - redirect_edge_and_branch_force (entry_e, new_loop->header); - PENDING_STMT (entry_e) = NULL; - set_immediate_dominator (CDI_DOMINATORS, new_loop->header, preheader); + /* And remove the non-necessary forwarder again. Keep the other + one so we have a proper pre-header for the loop at the exit edge. */ + redirect_edge_pred (single_succ_edge (new_preheader), single_pred (new_preheader)); + delete_basic_block (new_preheader); + set_immediate_dominator (CDI_DOMINATORS, new_loop->header, + loop_preheader_edge (new_loop)->src); } + for (unsigned i = 0; i < loop->num_nodes+1; i++) + rename_variables_in_bb (new_bbs[i]); + free (new_bbs); free (bbs); +#ifdef ENABLE_CHECKING + verify_dominators (CDI_DOMINATORS); +#endif + return new_loop; } @@ -1265,10 +1133,6 @@ slpeel_tree_peel_loop_to_edge (struct loop *loop, second_loop = loop; } - slpeel_update_phis_for_duplicate_loop (loop, new_loop, e == exit_e); - rename_variables_in_loop (new_loop); - - /* 2. Add the guard code in one of the following ways: 2.a Add the guard that controls whether the first loop is executed. @@ -1355,7 +1219,8 @@ slpeel_tree_peel_loop_to_edge (struct loop *loop, */ bb_before_first_loop = split_edge (loop_preheader_edge (first_loop)); - bb_before_second_loop = split_edge (single_exit (first_loop)); + /* Loop copying insterted a forwarder block for us here. */ + bb_before_second_loop = single_exit (first_loop)->dest; probability_of_second_loop = (inverse_probability (first_guard_probability) + combine_probabilities (second_guard_probability,