Commit 14fa2cc0 by Zdenek Dvorak Committed by Zdenek Dvorak

cfgloopmanip.c (loop_delete_branch_edge): Removed.

	* cfgloopmanip.c (loop_delete_branch_edge): Removed.
	(remove_path): Use can_remove_branch_p and remove_branch instead
	of loop_delete_branch_edge.
	* tree-ssa-loop-manip.c (scale_dominated_blocks_in_loop): New function.
	(tree_transform_and_unroll_loop): Remove dead branches immediately.
	Update profile using scale_dominated_blocks_in_loop.
	* cfghooks.c (can_remove_branch_p, remove_branch): New functions.
	* cfghooks.h (struct cfg_hooks): Add can_remove_branch_p.
	(can_remove_branch_p, remove_branch): Declare.
	* tree-cfg.c (tree_can_remove_branch_p): New function.
	(tree_cfg_hooks): Add tree_can_remove_branch_p.
	* cfgrtl.c (rtl_can_remove_branch_p): New function.
	(rtl_cfg_hooks, cfg_layout_rtl_cfg_hook): Add rtl_can_remove_branch_p.

From-SVN: r121583
parent 28489334
2007-02-04 Zdenek Dvorak <dvorakz@suse.cz>
* cfgloopmanip.c (loop_delete_branch_edge): Removed.
(remove_path): Use can_remove_branch_p and remove_branch instead
of loop_delete_branch_edge.
* tree-ssa-loop-manip.c (scale_dominated_blocks_in_loop): New function.
(tree_transform_and_unroll_loop): Remove dead branches immediately.
Update profile using scale_dominated_blocks_in_loop.
* cfghooks.c (can_remove_branch_p, remove_branch): New functions.
* cfghooks.h (struct cfg_hooks): Add can_remove_branch_p.
(can_remove_branch_p, remove_branch): Declare.
* tree-cfg.c (tree_can_remove_branch_p): New function.
(tree_cfg_hooks): Add tree_can_remove_branch_p.
* cfgrtl.c (rtl_can_remove_branch_p): New function.
(rtl_cfg_hooks, cfg_layout_rtl_cfg_hook): Add rtl_can_remove_branch_p.
2007-02-05 Jan Hubicka <jh@suse.cz> 2007-02-05 Jan Hubicka <jh@suse.cz>
PR middle-end/30696 PR middle-end/30696
......
...@@ -318,6 +318,48 @@ redirect_edge_and_branch (edge e, basic_block dest) ...@@ -318,6 +318,48 @@ redirect_edge_and_branch (edge e, basic_block dest)
return ret; return ret;
} }
/* Returns true if it is possible to remove the edge E by redirecting it
to the destination of the other edge going from its source. */
bool
can_remove_branch_p (edge e)
{
if (!cfg_hooks->can_remove_branch_p)
internal_error ("%s does not support can_remove_branch_p",
cfg_hooks->name);
if (EDGE_COUNT (e->src->succs) != 2)
return false;
return cfg_hooks->can_remove_branch_p (e);
}
/* Removes E, by redirecting it to the destination of the other edge going
from its source. Can_remove_branch_p must be true for E, hence this
operation cannot fail. */
void
remove_branch (edge e)
{
edge other;
basic_block src = e->src;
int irr;
gcc_assert (EDGE_COUNT (e->src->succs) == 2);
other = EDGE_SUCC (src, EDGE_SUCC (src, 0) == e);
irr = other->flags & EDGE_IRREDUCIBLE_LOOP;
if (current_loops != NULL)
rescan_loop_exit (e, false, true);
e = redirect_edge_and_branch (e, other->dest);
gcc_assert (e != NULL);
e->flags &= ~EDGE_IRREDUCIBLE_LOOP;
e->flags |= irr;
}
/* Redirect the edge E to basic block DEST even if it requires creating /* Redirect the edge E to basic block DEST even if it requires creating
of a new basic block; then it returns the newly created basic block. of a new basic block; then it returns the newly created basic block.
Aborts when redirection is impossible. */ Aborts when redirection is impossible. */
......
...@@ -47,6 +47,10 @@ struct cfg_hooks ...@@ -47,6 +47,10 @@ struct cfg_hooks
not be abnormal. */ not be abnormal. */
basic_block (*redirect_edge_and_branch_force) (edge, basic_block); basic_block (*redirect_edge_and_branch_force) (edge, basic_block);
/* Returns true if it is possible to remove the edge by redirecting it
to the destination of the other edge going from its source. */
bool (*can_remove_branch_p) (edge);
/* Remove statements corresponding to a given basic block. */ /* Remove statements corresponding to a given basic block. */
void (*delete_basic_block) (basic_block); void (*delete_basic_block) (basic_block);
...@@ -138,6 +142,8 @@ extern void verify_flow_info (void); ...@@ -138,6 +142,8 @@ extern void verify_flow_info (void);
extern void dump_bb (basic_block, FILE *, int); extern void dump_bb (basic_block, FILE *, int);
extern edge redirect_edge_and_branch (edge, basic_block); extern edge redirect_edge_and_branch (edge, basic_block);
extern basic_block redirect_edge_and_branch_force (edge, basic_block); extern basic_block redirect_edge_and_branch_force (edge, basic_block);
extern bool can_remove_branch_p (edge);
extern void remove_branch (edge);
extern edge split_block (basic_block, void *); extern edge split_block (basic_block, void *);
extern edge split_block_after_labels (basic_block); extern edge split_block_after_labels (basic_block);
extern bool move_block_after (basic_block, basic_block); extern bool move_block_after (basic_block, basic_block);
......
...@@ -35,7 +35,6 @@ static void duplicate_subloops (struct loop *, struct loop *); ...@@ -35,7 +35,6 @@ static void duplicate_subloops (struct loop *, struct loop *);
static void copy_loops_to (struct loop **, int, static void copy_loops_to (struct loop **, int,
struct loop *); struct loop *);
static void loop_redirect_edge (edge, basic_block); static void loop_redirect_edge (edge, basic_block);
static bool loop_delete_branch_edge (edge, int);
static void remove_bbs (basic_block *, int); static void remove_bbs (basic_block *, int);
static bool rpe_enum_p (basic_block, void *); static bool rpe_enum_p (basic_block, void *);
static int find_path (edge, basic_block **); static int find_path (edge, basic_block **);
...@@ -283,10 +282,10 @@ remove_path (edge e) ...@@ -283,10 +282,10 @@ remove_path (edge e)
basic_block *rem_bbs, *bord_bbs, *dom_bbs, from, bb; basic_block *rem_bbs, *bord_bbs, *dom_bbs, from, bb;
int i, nrem, n_bord_bbs, n_dom_bbs, nreml; int i, nrem, n_bord_bbs, n_dom_bbs, nreml;
sbitmap seen; sbitmap seen;
bool deleted, irred_invalidated = false; bool irred_invalidated = false;
struct loop **deleted_loop; struct loop **deleted_loop;
if (!loop_delete_branch_edge (e, 0)) if (!can_remove_branch_p (e))
return false; return false;
/* Keep track of whether we need to update information about irreducible /* Keep track of whether we need to update information about irreducible
...@@ -341,8 +340,7 @@ remove_path (edge e) ...@@ -341,8 +340,7 @@ remove_path (edge e)
/* Remove the path. */ /* Remove the path. */
from = e->src; from = e->src;
deleted = loop_delete_branch_edge (e, 1); remove_branch (e);
gcc_assert (deleted);
dom_bbs = XCNEWVEC (basic_block, n_basic_blocks); dom_bbs = XCNEWVEC (basic_block, n_basic_blocks);
/* Cancel loops contained in the path. */ /* Cancel loops contained in the path. */
...@@ -698,45 +696,6 @@ loop_redirect_edge (edge e, basic_block dest) ...@@ -698,45 +696,6 @@ loop_redirect_edge (edge e, basic_block dest)
redirect_edge_and_branch_force (e, dest); redirect_edge_and_branch_force (e, dest);
} }
/* Deletes edge E from a branch if possible. Unless REALLY_DELETE is set,
just test whether it is possible to remove the edge. */
static bool
loop_delete_branch_edge (edge e, int really_delete)
{
basic_block src = e->src;
basic_block newdest;
int irr;
edge snd;
gcc_assert (EDGE_COUNT (src->succs) > 1);
/* Cannot handle more than two exit edges. */
if (EDGE_COUNT (src->succs) > 2)
return false;
/* And it must be just a simple branch. */
if (!any_condjump_p (BB_END (src)))
return false;
snd = e == EDGE_SUCC (src, 0) ? EDGE_SUCC (src, 1) : EDGE_SUCC (src, 0);
newdest = snd->dest;
if (newdest == EXIT_BLOCK_PTR)
return false;
/* Hopefully the above conditions should suffice. */
if (!really_delete)
return true;
/* Redirecting behaves wrongly wrto this flag. */
irr = snd->flags & EDGE_IRREDUCIBLE_LOOP;
if (!redirect_edge_and_branch (e, newdest))
return false;
single_succ_edge (src)->flags &= ~EDGE_IRREDUCIBLE_LOOP;
single_succ_edge (src)->flags |= irr;
return true;
}
/* Check whether LOOP's body can be duplicated. */ /* Check whether LOOP's body can be duplicated. */
bool bool
can_duplicate_loop_p (struct loop *loop) can_duplicate_loop_p (struct loop *loop)
......
...@@ -2977,6 +2977,38 @@ insert_insn_end_bb_new (rtx pat, basic_block bb) ...@@ -2977,6 +2977,38 @@ insert_insn_end_bb_new (rtx pat, basic_block bb)
return new_insn; return new_insn;
} }
/* Returns true if it is possible to remove edge E by redirecting
it to the destination of the other edge from E->src. */
static bool
rtl_can_remove_branch_p (edge e)
{
basic_block src = e->src;
basic_block target = EDGE_SUCC (src, EDGE_SUCC (src, 0) == e)->dest;
rtx insn = BB_END (src), set;
/* The conditions are taken from try_redirect_by_replacing_jump. */
if (target == EXIT_BLOCK_PTR)
return false;
if (e->flags & (EDGE_ABNORMAL_CALL | EDGE_EH))
return false;
if (find_reg_note (insn, REG_CROSSING_JUMP, NULL_RTX)
|| BB_PARTITION (src) != BB_PARTITION (target))
return false;
if (!onlyjump_p (insn)
|| tablejump_p (insn, NULL, NULL))
return false;
set = single_set (insn);
if (!set || side_effects_p (set))
return false;
return true;
}
/* Implementation of CFG manipulation for linearized RTL. */ /* Implementation of CFG manipulation for linearized RTL. */
struct cfg_hooks rtl_cfg_hooks = { struct cfg_hooks rtl_cfg_hooks = {
"rtl", "rtl",
...@@ -2985,6 +3017,7 @@ struct cfg_hooks rtl_cfg_hooks = { ...@@ -2985,6 +3017,7 @@ struct cfg_hooks rtl_cfg_hooks = {
rtl_create_basic_block, rtl_create_basic_block,
rtl_redirect_edge_and_branch, rtl_redirect_edge_and_branch,
rtl_redirect_edge_and_branch_force, rtl_redirect_edge_and_branch_force,
rtl_can_remove_branch_p,
rtl_delete_block, rtl_delete_block,
rtl_split_block, rtl_split_block,
rtl_move_block_after, rtl_move_block_after,
...@@ -3028,6 +3061,7 @@ struct cfg_hooks cfg_layout_rtl_cfg_hooks = { ...@@ -3028,6 +3061,7 @@ struct cfg_hooks cfg_layout_rtl_cfg_hooks = {
cfg_layout_create_basic_block, cfg_layout_create_basic_block,
cfg_layout_redirect_edge_and_branch, cfg_layout_redirect_edge_and_branch,
cfg_layout_redirect_edge_and_branch_force, cfg_layout_redirect_edge_and_branch_force,
rtl_can_remove_branch_p,
cfg_layout_delete_block, cfg_layout_delete_block,
cfg_layout_split_block, cfg_layout_split_block,
rtl_move_block_after, rtl_move_block_after,
......
...@@ -4219,6 +4219,17 @@ tree_redirect_edge_and_branch (edge e, basic_block dest) ...@@ -4219,6 +4219,17 @@ tree_redirect_edge_and_branch (edge e, basic_block dest)
return e; return e;
} }
/* Returns true if it is possible to remove edge E by redirecting
it to the destination of the other edge from E->src. */
static bool
tree_can_remove_branch_p (edge e)
{
if (e->flags & EDGE_ABNORMAL)
return false;
return true;
}
/* Simple wrapper, as we can always redirect fallthru edges. */ /* Simple wrapper, as we can always redirect fallthru edges. */
...@@ -5614,6 +5625,7 @@ struct cfg_hooks tree_cfg_hooks = { ...@@ -5614,6 +5625,7 @@ struct cfg_hooks tree_cfg_hooks = {
create_bb, /* create_basic_block */ create_bb, /* create_basic_block */
tree_redirect_edge_and_branch,/* redirect_edge_and_branch */ tree_redirect_edge_and_branch,/* redirect_edge_and_branch */
tree_redirect_edge_and_branch_force,/* redirect_edge_and_branch_force */ tree_redirect_edge_and_branch_force,/* redirect_edge_and_branch_force */
tree_can_remove_branch_p, /* can_remove_branch_p */
remove_bb, /* delete_basic_block */ remove_bb, /* delete_basic_block */
tree_split_block, /* split_block */ tree_split_block, /* split_block */
tree_move_block_after, /* move_block_after */ tree_move_block_after, /* move_block_after */
......
...@@ -756,6 +756,29 @@ determine_exit_conditions (struct loop *loop, struct tree_niter_desc *desc, ...@@ -756,6 +756,29 @@ determine_exit_conditions (struct loop *loop, struct tree_niter_desc *desc,
*exit_bound = bound; *exit_bound = bound;
} }
/* Scales the frequencies of all basic blocks in LOOP that are strictly
dominated by BB by NUM/DEN. */
static void
scale_dominated_blocks_in_loop (struct loop *loop, basic_block bb,
int num, int den)
{
basic_block son;
if (den == 0)
return;
for (son = first_dom_son (CDI_DOMINATORS, bb);
son;
son = next_dom_son (CDI_DOMINATORS, son))
{
if (!flow_bb_inside_loop_p (loop, son))
continue;
scale_bbs_frequencies_int (&son, 1, num, den);
scale_dominated_blocks_in_loop (loop, son, num, den);
}
}
/* Unroll LOOP FACTOR times. DESC describes number of iterations of LOOP. /* Unroll LOOP FACTOR times. DESC describes number of iterations of LOOP.
EXIT is the exit of the loop to that DESC corresponds. EXIT is the exit of the loop to that DESC corresponds.
...@@ -819,21 +842,22 @@ tree_transform_and_unroll_loop (struct loop *loop, unsigned factor, ...@@ -819,21 +842,22 @@ tree_transform_and_unroll_loop (struct loop *loop, unsigned factor,
transform_callback transform, transform_callback transform,
void *data) void *data)
{ {
tree dont_exit, exit_if, ctr_before, ctr_after; tree exit_if, ctr_before, ctr_after;
tree enter_main_cond, exit_base, exit_step, exit_bound; tree enter_main_cond, exit_base, exit_step, exit_bound;
enum tree_code exit_cmp; enum tree_code exit_cmp;
tree phi_old_loop, phi_new_loop, phi_rest, init, next, new_init, var; tree phi_old_loop, phi_new_loop, phi_rest, init, next, new_init, var;
struct loop *new_loop; struct loop *new_loop;
basic_block rest, exit_bb; basic_block rest, exit_bb;
edge old_entry, new_entry, old_latch, precond_edge, new_exit; edge old_entry, new_entry, old_latch, precond_edge, new_exit;
edge new_nonexit; edge new_nonexit, e;
block_stmt_iterator bsi; block_stmt_iterator bsi;
use_operand_p op; use_operand_p op;
bool ok; bool ok;
unsigned est_niter, prob_entry, scale_unrolled, scale_rest, freq_e, freq_h; unsigned est_niter, prob_entry, scale_unrolled, scale_rest, freq_e, freq_h;
unsigned new_est_niter; unsigned new_est_niter, i, prob;
unsigned irr = loop_preheader_edge (loop)->flags & EDGE_IRREDUCIBLE_LOOP; unsigned irr = loop_preheader_edge (loop)->flags & EDGE_IRREDUCIBLE_LOOP;
sbitmap wont_exit; sbitmap wont_exit;
VEC (edge, heap) *to_remove = NULL;
est_niter = expected_loop_iterations (loop); est_niter = expected_loop_iterations (loop);
determine_exit_conditions (loop, desc, factor, determine_exit_conditions (loop, desc, factor,
...@@ -882,14 +906,20 @@ tree_transform_and_unroll_loop (struct loop *loop, unsigned factor, ...@@ -882,14 +906,20 @@ tree_transform_and_unroll_loop (struct loop *loop, unsigned factor,
new_est_niter = 5; new_est_niter = 5;
} }
/* Prepare the cfg and update the phi nodes. */ /* Prepare the cfg and update the phi nodes. Move the loop exit to the
loop latch (and make its condition dummy, for the moment). */
rest = loop_preheader_edge (new_loop)->src; rest = loop_preheader_edge (new_loop)->src;
precond_edge = single_pred_edge (rest); precond_edge = single_pred_edge (rest);
split_edge (loop_latch_edge (loop)); split_edge (loop_latch_edge (loop));
exit_bb = single_pred (loop->latch); exit_bb = single_pred (loop->latch);
/* For the moment, make it appear that the new exit edge cannot /* Since the exit edge will be removed, the frequency of all the blocks
be taken. */ in the loop that are dominated by it must be scaled by
1 / (1 - exit->probability). */
scale_dominated_blocks_in_loop (loop, exit->src,
REG_BR_PROB_BASE,
REG_BR_PROB_BASE - exit->probability);
bsi = bsi_last (exit_bb); bsi = bsi_last (exit_bb);
exit_if = build_if_stmt (boolean_true_node, exit_if = build_if_stmt (boolean_true_node,
tree_block_label (loop->latch), tree_block_label (loop->latch),
...@@ -897,10 +927,20 @@ tree_transform_and_unroll_loop (struct loop *loop, unsigned factor, ...@@ -897,10 +927,20 @@ tree_transform_and_unroll_loop (struct loop *loop, unsigned factor,
bsi_insert_after (&bsi, exit_if, BSI_NEW_STMT); bsi_insert_after (&bsi, exit_if, BSI_NEW_STMT);
new_exit = make_edge (exit_bb, rest, EDGE_FALSE_VALUE | irr); new_exit = make_edge (exit_bb, rest, EDGE_FALSE_VALUE | irr);
rescan_loop_exit (new_exit, true, false); rescan_loop_exit (new_exit, true, false);
new_exit->count = 0;
new_exit->probability = 0; /* Set the probability of new exit to the same of the old one. Fix
the frequency of the latch block, by scaling it back by
1 - exit->probability. */
new_exit->count = exit->count;
new_exit->probability = exit->probability;
new_nonexit = single_pred_edge (loop->latch); new_nonexit = single_pred_edge (loop->latch);
new_nonexit->probability = REG_BR_PROB_BASE - exit->probability;
new_nonexit->flags = EDGE_TRUE_VALUE; new_nonexit->flags = EDGE_TRUE_VALUE;
new_nonexit->count -= exit->count;
if (new_nonexit->count < 0)
new_nonexit->count = 0;
scale_bbs_frequencies_int (&loop->latch, 1, new_nonexit->probability,
REG_BR_PROB_BASE);
old_entry = loop_preheader_edge (loop); old_entry = loop_preheader_edge (loop);
new_entry = loop_preheader_edge (new_loop); new_entry = loop_preheader_edge (new_loop);
...@@ -938,25 +978,30 @@ tree_transform_and_unroll_loop (struct loop *loop, unsigned factor, ...@@ -938,25 +978,30 @@ tree_transform_and_unroll_loop (struct loop *loop, unsigned factor,
SET_USE (op, new_init); SET_USE (op, new_init);
} }
remove_path (exit);
/* Transform the loop. */ /* Transform the loop. */
if (transform) if (transform)
(*transform) (loop, data); (*transform) (loop, data);
/* Unroll the loop and remove the old exits. */ /* Unroll the loop and remove the exits in all iterations except for the
dont_exit = ((exit->flags & EDGE_TRUE_VALUE) last one. */
? boolean_false_node
: boolean_true_node);
exit_if = last_stmt (exit->src);
COND_EXPR_COND (exit_if) = dont_exit;
update_stmt (exit_if);
wont_exit = sbitmap_alloc (factor); wont_exit = sbitmap_alloc (factor);
sbitmap_ones (wont_exit); sbitmap_ones (wont_exit);
RESET_BIT (wont_exit, factor - 1);
ok = tree_duplicate_loop_to_header_edge ok = tree_duplicate_loop_to_header_edge
(loop, loop_latch_edge (loop), factor - 1, (loop, loop_latch_edge (loop), factor - 1,
wont_exit, exit, NULL, DLTHE_FLAG_UPDATE_FREQ); wont_exit, new_exit, &to_remove, DLTHE_FLAG_UPDATE_FREQ);
free (wont_exit); free (wont_exit);
gcc_assert (ok); gcc_assert (ok);
for (i = 0; VEC_iterate (edge, to_remove, i, e); i++)
{
ok = remove_path (e);
gcc_assert (ok);
}
VEC_free (edge, heap, to_remove);
update_ssa (TODO_update_ssa); update_ssa (TODO_update_ssa);
/* Ensure that the frequencies in the loop match the new estimated /* Ensure that the frequencies in the loop match the new estimated
...@@ -976,9 +1021,13 @@ tree_transform_and_unroll_loop (struct loop *loop, unsigned factor, ...@@ -976,9 +1021,13 @@ tree_transform_and_unroll_loop (struct loop *loop, unsigned factor,
rest->frequency += EDGE_FREQUENCY (new_exit); rest->frequency += EDGE_FREQUENCY (new_exit);
new_nonexit = single_pred_edge (loop->latch); new_nonexit = single_pred_edge (loop->latch);
prob = new_nonexit->probability;
new_nonexit->probability = REG_BR_PROB_BASE - new_exit->probability; new_nonexit->probability = REG_BR_PROB_BASE - new_exit->probability;
new_nonexit->count = exit_bb->count - new_exit->count;
if (new_nonexit->count < 0)
new_nonexit->count = 0;
scale_bbs_frequencies_int (&loop->latch, 1, new_nonexit->probability, scale_bbs_frequencies_int (&loop->latch, 1, new_nonexit->probability,
REG_BR_PROB_BASE); prob);
/* Finally create the new counter for number of iterations and add the new /* Finally create the new counter for number of iterations and add the new
exit instruction. */ exit instruction. */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment