ret = cfg_hooks->redirect_edge_and_branch (e, dest);
+ /* If RET != E, then the edge E was removed since RET already lead to the
+ same destination. */
+ if (ret != NULL && current_loops != NULL)
+ rescan_loop_exit (e, false, ret != e);
+
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. */
basic_block
redirect_edge_and_branch_force (edge e, basic_block dest)
{
- basic_block ret;
+ basic_block ret, src = e->src;
struct loop *loop;
if (!cfg_hooks->redirect_edge_and_branch_force)
internal_error ("%s does not support redirect_edge_and_branch_force",
cfg_hooks->name);
+ if (current_loops != NULL)
+ rescan_loop_exit (e, false, true);
+
ret = cfg_hooks->redirect_edge_and_branch_force (e, dest);
- if (current_loops != NULL && ret != NULL)
+ if (ret != NULL
+ && dom_info_available_p (CDI_DOMINATORS))
+ set_immediate_dominator (CDI_DOMINATORS, ret, src);
+
+ if (current_loops != NULL)
{
- loop = find_common_loop (single_pred (ret)->loop_father,
- single_succ (ret)->loop_father);
- add_bb_to_loop (ret, loop);
+ if (ret != NULL)
+ {
+ loop = find_common_loop (single_pred (ret)->loop_father,
+ single_succ (ret)->loop_father);
+ add_bb_to_loop (ret, loop);
+ }
+ else if (find_edge (src, dest) == e)
+ rescan_loop_exit (e, true, false);
}
return ret;
if (!cfg_hooks->split_edge)
internal_error ("%s does not support split_edge", cfg_hooks->name);
+ if (current_loops != NULL)
+ rescan_loop_exit (e, false, true);
+
ret = cfg_hooks->split_edge (e);
ret->count = count;
ret->frequency = freq;
whole lot of them and hope the caller knows what they're doing. */
while (EDGE_COUNT (a->succs) != 0)
- remove_edge (EDGE_SUCC (a, 0));
+ {
+ if (current_loops != NULL)
+ rescan_loop_exit (EDGE_SUCC (a, 0), false, true);
+ remove_edge (EDGE_SUCC (a, 0));
+ }
/* Adjust the edges out of B for the new owner. */
FOR_EACH_EDGE (e, ei, b->succs)
- e->src = a;
+ {
+ e->src = a;
+ if (current_loops != NULL)
+ rescan_loop_exit (e, true, false);
+ }
a->succs = b->succs;
a->flags |= b->flags;
fallthru->count = 0;
jump = redirect_edge_and_branch_force (e, bb);
- if (jump)
+ if (jump != NULL
+ && new_bb_cbk != NULL)
new_bb_cbk (jump);
}
/* If we do not split a loop header, then both blocks belong to the
same loop. In case we split loop header and do not redirect the
latch edge to DUMMY, then DUMMY belongs to the outer loop, and
- BB becomes the new header. */
+ BB becomes the new header. If latch is not recorded for the loop,
+ we leave this updating on the caller (this may only happen during
+ loop analysis). */
loop = dummy->loop_father;
if (loop->header == dummy
+ && loop->latch != NULL
&& find_edge (loop->latch, dummy) == NULL)
{
remove_bb_from_loops (dummy);
cfg_hook_duplicate_loop_to_header_edge (struct loop *loop, edge e,
unsigned int ndupl,
sbitmap wont_exit, edge orig,
- edge *to_remove,
- unsigned int *n_to_remove, int flags)
+ VEC (edge, heap) **to_remove,
+ int flags)
{
gcc_assert (cfg_hooks->cfg_hook_duplicate_loop_to_header_edge);
return cfg_hooks->cfg_hook_duplicate_loop_to_header_edge (loop, e,
ndupl, wont_exit,
orig, to_remove,
- n_to_remove, flags);
+ flags);
}
/* Conditional jumps are represented differently in trees and RTL,