mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-03-14 17:41:08 +08:00
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
This commit is contained in:
parent
284893341f
commit
14fa2cc057
@ -1,3 +1,19 @@
|
||||
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>
|
||||
|
||||
PR middle-end/30696
|
||||
|
@ -318,6 +318,48 @@ redirect_edge_and_branch (edge e, basic_block dest)
|
||||
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
|
||||
of a new basic block; then it returns the newly created basic block.
|
||||
Aborts when redirection is impossible. */
|
||||
|
@ -47,6 +47,10 @@ struct cfg_hooks
|
||||
not be abnormal. */
|
||||
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. */
|
||||
void (*delete_basic_block) (basic_block);
|
||||
|
||||
@ -138,6 +142,8 @@ extern void verify_flow_info (void);
|
||||
extern void dump_bb (basic_block, FILE *, int);
|
||||
extern edge redirect_edge_and_branch (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_after_labels (basic_block);
|
||||
extern bool move_block_after (basic_block, basic_block);
|
||||
|
@ -35,7 +35,6 @@ static void duplicate_subloops (struct loop *, struct loop *);
|
||||
static void copy_loops_to (struct loop **, int,
|
||||
struct loop *);
|
||||
static void loop_redirect_edge (edge, basic_block);
|
||||
static bool loop_delete_branch_edge (edge, int);
|
||||
static void remove_bbs (basic_block *, int);
|
||||
static bool rpe_enum_p (basic_block, void *);
|
||||
static int find_path (edge, basic_block **);
|
||||
@ -283,10 +282,10 @@ remove_path (edge e)
|
||||
basic_block *rem_bbs, *bord_bbs, *dom_bbs, from, bb;
|
||||
int i, nrem, n_bord_bbs, n_dom_bbs, nreml;
|
||||
sbitmap seen;
|
||||
bool deleted, irred_invalidated = false;
|
||||
bool irred_invalidated = false;
|
||||
struct loop **deleted_loop;
|
||||
|
||||
if (!loop_delete_branch_edge (e, 0))
|
||||
if (!can_remove_branch_p (e))
|
||||
return false;
|
||||
|
||||
/* Keep track of whether we need to update information about irreducible
|
||||
@ -341,8 +340,7 @@ remove_path (edge e)
|
||||
|
||||
/* Remove the path. */
|
||||
from = e->src;
|
||||
deleted = loop_delete_branch_edge (e, 1);
|
||||
gcc_assert (deleted);
|
||||
remove_branch (e);
|
||||
dom_bbs = XCNEWVEC (basic_block, n_basic_blocks);
|
||||
|
||||
/* Cancel loops contained in the path. */
|
||||
@ -698,45 +696,6 @@ loop_redirect_edge (edge e, basic_block 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. */
|
||||
bool
|
||||
can_duplicate_loop_p (struct loop *loop)
|
||||
|
34
gcc/cfgrtl.c
34
gcc/cfgrtl.c
@ -2977,6 +2977,38 @@ insert_insn_end_bb_new (rtx pat, basic_block bb)
|
||||
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. */
|
||||
struct cfg_hooks rtl_cfg_hooks = {
|
||||
"rtl",
|
||||
@ -2985,6 +3017,7 @@ struct cfg_hooks rtl_cfg_hooks = {
|
||||
rtl_create_basic_block,
|
||||
rtl_redirect_edge_and_branch,
|
||||
rtl_redirect_edge_and_branch_force,
|
||||
rtl_can_remove_branch_p,
|
||||
rtl_delete_block,
|
||||
rtl_split_block,
|
||||
rtl_move_block_after,
|
||||
@ -3028,6 +3061,7 @@ struct cfg_hooks cfg_layout_rtl_cfg_hooks = {
|
||||
cfg_layout_create_basic_block,
|
||||
cfg_layout_redirect_edge_and_branch,
|
||||
cfg_layout_redirect_edge_and_branch_force,
|
||||
rtl_can_remove_branch_p,
|
||||
cfg_layout_delete_block,
|
||||
cfg_layout_split_block,
|
||||
rtl_move_block_after,
|
||||
|
@ -4219,6 +4219,17 @@ tree_redirect_edge_and_branch (edge e, basic_block dest)
|
||||
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. */
|
||||
|
||||
@ -5614,6 +5625,7 @@ struct cfg_hooks tree_cfg_hooks = {
|
||||
create_bb, /* create_basic_block */
|
||||
tree_redirect_edge_and_branch,/* redirect_edge_and_branch */
|
||||
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 */
|
||||
tree_split_block, /* split_block */
|
||||
tree_move_block_after, /* move_block_after */
|
||||
|
@ -756,6 +756,29 @@ determine_exit_conditions (struct loop *loop, struct tree_niter_desc *desc,
|
||||
*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.
|
||||
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,
|
||||
transform_callback transform,
|
||||
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;
|
||||
enum tree_code exit_cmp;
|
||||
tree phi_old_loop, phi_new_loop, phi_rest, init, next, new_init, var;
|
||||
struct loop *new_loop;
|
||||
basic_block rest, exit_bb;
|
||||
edge old_entry, new_entry, old_latch, precond_edge, new_exit;
|
||||
edge new_nonexit;
|
||||
edge new_nonexit, e;
|
||||
block_stmt_iterator bsi;
|
||||
use_operand_p op;
|
||||
bool ok;
|
||||
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;
|
||||
sbitmap wont_exit;
|
||||
VEC (edge, heap) *to_remove = NULL;
|
||||
|
||||
est_niter = expected_loop_iterations (loop);
|
||||
determine_exit_conditions (loop, desc, factor,
|
||||
@ -882,14 +906,20 @@ tree_transform_and_unroll_loop (struct loop *loop, unsigned factor,
|
||||
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;
|
||||
precond_edge = single_pred_edge (rest);
|
||||
split_edge (loop_latch_edge (loop));
|
||||
exit_bb = single_pred (loop->latch);
|
||||
|
||||
/* For the moment, make it appear that the new exit edge cannot
|
||||
be taken. */
|
||||
/* Since the exit edge will be removed, the frequency of all the blocks
|
||||
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);
|
||||
exit_if = build_if_stmt (boolean_true_node,
|
||||
tree_block_label (loop->latch),
|
||||
@ -897,10 +927,20 @@ tree_transform_and_unroll_loop (struct loop *loop, unsigned factor,
|
||||
bsi_insert_after (&bsi, exit_if, BSI_NEW_STMT);
|
||||
new_exit = make_edge (exit_bb, rest, EDGE_FALSE_VALUE | irr);
|
||||
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->probability = REG_BR_PROB_BASE - exit->probability;
|
||||
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);
|
||||
new_entry = loop_preheader_edge (new_loop);
|
||||
@ -938,25 +978,30 @@ tree_transform_and_unroll_loop (struct loop *loop, unsigned factor,
|
||||
SET_USE (op, new_init);
|
||||
}
|
||||
|
||||
remove_path (exit);
|
||||
|
||||
/* Transform the loop. */
|
||||
if (transform)
|
||||
(*transform) (loop, data);
|
||||
|
||||
/* Unroll the loop and remove the old exits. */
|
||||
dont_exit = ((exit->flags & EDGE_TRUE_VALUE)
|
||||
? boolean_false_node
|
||||
: boolean_true_node);
|
||||
exit_if = last_stmt (exit->src);
|
||||
COND_EXPR_COND (exit_if) = dont_exit;
|
||||
update_stmt (exit_if);
|
||||
|
||||
/* Unroll the loop and remove the exits in all iterations except for the
|
||||
last one. */
|
||||
wont_exit = sbitmap_alloc (factor);
|
||||
sbitmap_ones (wont_exit);
|
||||
RESET_BIT (wont_exit, factor - 1);
|
||||
|
||||
ok = tree_duplicate_loop_to_header_edge
|
||||
(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);
|
||||
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);
|
||||
|
||||
/* 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,
|
||||
rest->frequency += EDGE_FREQUENCY (new_exit);
|
||||
|
||||
new_nonexit = single_pred_edge (loop->latch);
|
||||
prob = new_nonexit->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,
|
||||
REG_BR_PROB_BASE);
|
||||
prob);
|
||||
|
||||
/* Finally create the new counter for number of iterations and add the new
|
||||
exit instruction. */
|
||||
|
Loading…
x
Reference in New Issue
Block a user