* 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
+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
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. */
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);
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);
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 **);
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
/* 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. */
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)
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",
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,
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,
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. */
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 */
*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.
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,
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),
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);
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
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. */