mirror of
https://gcc.gnu.org/git/gcc.git
synced 2025-01-15 08:13:57 +08:00
re PR tree-optimization/55964 (Segmentation fault with -O -ftree-loop-distribution -funswitch-loops)
2013-01-16 Richard Biener <rguenther@suse.de> 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. * gcc.dg/torture/pr55964.c: New testcase. From-SVN: r195239
This commit is contained in:
parent
c25a0c60a5
commit
2cfc56b9bd
@ -1,3 +1,20 @@
|
||||
2013-01-16 Richard Biener <rguenther@suse.de>
|
||||
|
||||
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 <rguenther@suse.de>
|
||||
|
||||
PR tree-optimization/54767
|
||||
|
@ -1,3 +1,8 @@
|
||||
2013-01-16 Richard Biener <rguenther@suse.de>
|
||||
|
||||
PR tree-optimization/55964
|
||||
* gcc.dg/torture/pr55964.c: New testcase.
|
||||
|
||||
2013-01-16 Richard Biener <rguenther@suse.de>
|
||||
|
||||
PR tree-optimization/54767
|
||||
|
24
gcc/testsuite/gcc.dg/torture/pr55964.c
Normal file
24
gcc/testsuite/gcc.dg/torture/pr55964.c
Normal file
@ -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;
|
||||
}
|
@ -654,8 +654,6 @@ bool gimple_duplicate_loop_to_header_edge (struct loop *, edge,
|
||||
edge, vec<edge> *,
|
||||
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 *);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user