This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: crossjumping speedups
On Sun, Jul 22, 2001 at 07:53:22PM +0200, Jan Hubicka wrote:
> Unfortunately, this part is most important one.
> I am not assuming any particular order. All I assume that one of edges
> is the first edge.
>
> Imagine blocks A and B, every containing tablejump with 10 outgoing edges.
> These blocks are not equivalent, but 9 of edges are. What I do is checking
> these two block for equality in any of these 9 meeting blocks. With the test
> above I test only on two blocks.
>
> I don't need any particular order, as, if the blocks are crossjumpable, all
> the outgoing edges are equivalent. I just need to pick one of edges as the
> "good edge to try".
Ok, it took me a while, but I think I finally understand what you
were after here -- the duplicates come not within a single invocation
of try_crossjump_bb, but from the sum of all of them.
As such, the check you added _still_ doesn't really make sense.
How exactly does the IOR in (e->src->succ == e || e2->src->succ == e2)
apply to this situation?
I think what you were after is contained within
! /* Non-obvious work limiting check: Recognize that we're going
! to call try_crossjump_bb on every basic block. So if we have
! two blocks with lots of outgoing edges (a switch) and they
! share lots of common destinations, then we would do the
! cross-jump check once for each common destination.
!
! Now, if the blocks actually are cross-jump candidates, then
! all of their destinations will be shared. Which means that
! we only need check them for cross-jump candidacy once. We
! can eliminate redundant checks of crossjump(A,B) by arbitrarily
! choosing to do the check from the block for which the edge
! in question is the first successor of A. */
! if (e->src->succ != e)
! continue;
[...]
! /* The "first successor" check above only prevents multiple
! checks of crossjump(A,B). In order to prevent redundant
! checks of crossjump(B,A), require that A be the block
! with the lowest index. */
! /* ??? Perhaps better is lowest execution frequency. */
! if (e->src->index > e2->src->index)
! continue;
Correct me if I'm wrong. And if I am wrong, you're going to
need several paragraphs with pretty ascii diagrams to show me.
In the course of trying to figure out what was going on here, I
took the liberty of cleaning up the grammar in the comments, and
expanding on them in some instances, as well as tweaking the code
in various ways that seemed like a good idea at the time.
I added a couple of ??? comments that I think you need to either
address or answer:
! /* ??? Won't we have eliminated these by now? */
! /* ??? Non-jump? You mean GET_CODE (e1->src-end) != JUMP_INSN?
! This fails for computed-goto as well, which may in fact be joinable. */
On review, I'm somewhat concerned about how try_optimize_cfg
is evolving. I have a feeling we'd be much better off with
more smaller loops over n_basic_blocks. I also have some ideas
for eliminating the bulk of the forwarder_block_p checks, but
I'll discuss that under separate cover.
Bootstrapped on alphaev6-linux.
r~
* flow.c: Grammar check and clarify a lot of comments.
(try_simplify_condjump): Rename variables to be clearer.
(try_forward_edges): Skip complex and fallthru edges.
Rearrange tests to avoid duplicate checks.
(flow_find_cross_jump): Likewise.
(outgoing_edges_match): Allow match if neither branch has
probability data. Loosen probability match to 5%.
(try_crossjump_to_edge): Hoist repeated indirection into
local variables.
(try_crossjump_bb): Don't check complex edges. Eliminate
redundant crossjump tests.
(try_optimize_cfg): Fix use of bool. Reorganize cheaper
checks before more expensive checks.
Index: flow.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/flow.c,v
retrieving revision 1.433
diff -c -p -d -r1.433 flow.c
*** flow.c 2001/07/22 22:49:00 1.433
--- flow.c 2001/07/23 06:46:30
*************** merge_blocks (e, b, c, mode)
*** 2963,2989 ****
int c_has_outgoing_fallthru;
int b_has_incoming_fallthru;
! /* Avoid overactive code motion, as the forwarder blocks should eb
! eliminated by the edge redirection instead. Only exception is the
! case b is an forwarder block and c has no fallthru edge, but no
! optimizers should be confused by this extra jump and we are about
! to kill the jump in bb_reorder pass instead. */
if (forwarder_block_p (b) || forwarder_block_p (c))
return 0;
-
- /* We must make sure to not munge nesting of exception regions,
- lexical blocks, and loop notes.
-
- The first is taken care of by requiring that the active eh
- region at the end of one block always matches the active eh
- region at the beginning of the next block.
! The later two are taken care of by squeezing out all the notes. */
!
! /* ??? A throw/catch edge (or any abnormal edge) should be rarely
! executed and we may want to treat blocks which have two out
! edges, one normal, one abnormal as only having one edge for
! block merging purposes. */
for (tmp_edge = c->succ; tmp_edge; tmp_edge = tmp_edge->succ_next)
if (tmp_edge->flags & EDGE_FALLTHRU)
--- 2963,2978 ----
int c_has_outgoing_fallthru;
int b_has_incoming_fallthru;
! /* Avoid overactive code motion, as the forwarder blocks should be
! eliminated by edge redirection instead. One exception might have
! been if B is a forwarder block and C has no fallthru edge, but
! that should be cleaned up by bb-reorder instead. */
if (forwarder_block_p (b) || forwarder_block_p (c))
return 0;
! /* We must make sure to not munge nesting of lexical blocks,
! and loop notes. This is done by squeezing out all the notes
! and leaving them there to lie. Not ideal, but functional. */
for (tmp_edge = c->succ; tmp_edge; tmp_edge = tmp_edge->succ_next)
if (tmp_edge->flags & EDGE_FALLTHRU)
*************** merge_blocks (e, b, c, mode)
*** 3029,3036 ****
redirect_edge_succ (c_fallthru_edge, ENTRY_BLOCK_PTR);
new = redirect_edge_and_branch_force (c_fallthru_edge, target);
! /* We've just created barrier, but other barrier is already present
! in the stream. Avoid duplicate. */
barrier = next_nonnote_insn (new ? new->end : b->end);
if (GET_CODE (barrier) != BARRIER)
abort ();
--- 3018,3025 ----
redirect_edge_succ (c_fallthru_edge, ENTRY_BLOCK_PTR);
new = redirect_edge_and_branch_force (c_fallthru_edge, target);
! /* We've just created barrier, but another barrier is
! already present in the stream. Avoid the duplicate. */
barrier = next_nonnote_insn (new ? new->end : b->end);
if (GET_CODE (barrier) != BARRIER)
abort ();
*************** merge_blocks (e, b, c, mode)
*** 3042,3117 ****
return 0;
}
! /* Simplify conditional jump around an jump.
! Return nonzero in case optimization matched. */
static bool
! try_simplify_condjump (src)
! basic_block src;
{
! basic_block final_block, next_block;
! rtx insn = src->end;
! edge branch, fallthru;
/* Verify that there are exactly two successors. */
! if (!src->succ || !src->succ->succ_next || src->succ->succ_next->succ_next
! || !any_condjump_p (insn))
return false;
-
- fallthru = FALLTHRU_EDGE (src);
! /* Following block must be simple forwarder block with single
! entry and must not be last in the stream. */
! next_block = fallthru->dest;
! if (!forwarder_block_p (next_block)
! || next_block->pred->pred_next
! || next_block->index == n_basic_blocks - 1)
return false;
! /* The branch must target to block afterwards. */
! final_block = BASIC_BLOCK (next_block->index + 1);
! branch = BRANCH_EDGE (src);
! if (branch->dest != final_block)
return false;
! /* Avoid jump.c from being overactive on removin ureachable insns. */
! LABEL_NUSES (JUMP_LABEL (insn))++;
! if (!invert_jump (insn, block_label (next_block->succ->dest), 1))
{
! LABEL_NUSES (JUMP_LABEL (insn))--;
return false;
}
if (rtl_dump_file)
fprintf (rtl_dump_file, "Simplifying condjump %i around jump %i\n",
! INSN_UID (insn), INSN_UID (next_block->end));
!
! redirect_edge_succ (branch, final_block);
! redirect_edge_succ (fallthru, next_block->succ->dest);
! branch->flags |= EDGE_FALLTHRU;
! fallthru->flags &= ~EDGE_FALLTHRU;
! flow_delete_block (next_block);
return true;
}
/* Attempt to forward edges leaving basic block B.
! Return nonzero if sucessfull. */
static bool
try_forward_edges (b)
basic_block b;
{
! bool changed = 0;
! edge e;
! for (e = b->succ; e; e = e->succ_next)
{
! basic_block target = e->dest, first = e->dest;
! int counter = 0;
! /* Look for the real destination of jump.
Avoid inifinite loop in the infinite empty loop by counting
up to n_basic_blocks. */
while (forwarder_block_p (target)
--- 3031,3127 ----
return 0;
}
! /* Simplify a conditional jump around an unconditional jump.
! Return true if something changed. */
static bool
! try_simplify_condjump (cbranch_block)
! basic_block cbranch_block;
{
! basic_block jump_block, jump_dest_block, cbranch_dest_block;
! edge cbranch_jump_edge, cbranch_fallthru_edge;
! rtx cbranch_insn;
/* Verify that there are exactly two successors. */
! if (!cbranch_block->succ
! || !cbranch_block->succ->succ_next
! || cbranch_block->succ->succ_next->succ_next)
return false;
! /* Verify that we've got a normal conditional branch at the end
! of the block. */
! cbranch_insn = cbranch_block->end;
! if (!any_condjump_p (cbranch_insn))
return false;
! cbranch_fallthru_edge = FALLTHRU_EDGE (cbranch_block);
! cbranch_jump_edge = BRANCH_EDGE (cbranch_block);
! /* The next block must not have multiple predecessors, must not
! be the last block in the function, and must contain just the
! unconditional jump. */
! jump_block = cbranch_fallthru_edge->dest;
! if (jump_block->pred->pred_next
! || jump_block->index == n_basic_blocks - 1
! || !forwarder_block_p (jump_block))
! return false;
! jump_dest_block = jump_block->succ->dest;
! /* The conditional branch must target the block after the
! unconditional branch. */
! cbranch_dest_block = cbranch_jump_edge->dest;
! if (cbranch_dest_block->index != jump_block->index + 1)
return false;
! /* Invert the conditional branch. Prevent jump.c from deleting
! "unreachable" instructions. */
! LABEL_NUSES (JUMP_LABEL (cbranch_insn))++;
! if (!invert_jump (cbranch_insn, block_label (jump_dest_block), 1))
{
! LABEL_NUSES (JUMP_LABEL (cbranch_insn))--;
return false;
}
+
if (rtl_dump_file)
fprintf (rtl_dump_file, "Simplifying condjump %i around jump %i\n",
! INSN_UID (cbranch_insn), INSN_UID (jump_block->end));
! /* Success. Update the CFG to match. */
! redirect_edge_succ (cbranch_jump_edge, cbranch_dest_block);
! redirect_edge_succ (cbranch_fallthru_edge, jump_dest_block);
! cbranch_jump_edge->flags |= EDGE_FALLTHRU;
! cbranch_fallthru_edge->flags &= ~EDGE_FALLTHRU;
! flow_delete_block (jump_block);
return true;
}
/* Attempt to forward edges leaving basic block B.
! Return true if sucessful. */
static bool
try_forward_edges (b)
basic_block b;
{
! bool changed = false;
! edge e, next;
!
! for (e = b->succ; e ; e = next)
{
! basic_block target, first;
! int counter;
! next = e->succ_next;
!
! /* Skip complex edges because we don't know how to update them.
! Skip fallthru edges because there's no jump to update. */
! if (e->flags & (EDGE_COMPLEX | EDGE_FALLTHRU))
! continue;
!
! target = first = e->dest;
! counter = 0;
!
! /* Look for the real destination of the jump.
Avoid inifinite loop in the infinite empty loop by counting
up to n_basic_blocks. */
while (forwarder_block_p (target)
*************** try_forward_edges (b)
*** 3124,3133 ****
target = target->succ->dest, counter++;
}
! if (target != first && counter < n_basic_blocks
! && redirect_edge_and_branch (e, target))
{
! while (first != target)
{
first->count -= e->count;
first->succ->count -= e->count;
--- 3134,3153 ----
target = target->succ->dest, counter++;
}
! if (counter >= n_basic_blocks)
{
! if (rtl_dump_file)
! fprintf (rtl_dump_file, "Infinite loop in BB %i.\n",
! target->index);
! }
! else if (target == first)
! ; /* We didn't do anything. */
! else if (redirect_edge_and_branch (e, target))
! {
! /* We successfully forwarded the edge. Now update profile
! data: for each edge we traversed in the chain, remove
! the original edge's execution count. */
! do
{
first->count -= e->count;
first->succ->count -= e->count;
*************** try_forward_edges (b)
*** 3136,3194 ****
/ REG_BR_PROB_BASE);
first = first->succ->dest;
}
! /* We've possibly removed the edge. */
! changed = 1;
! e = b->succ;
}
! else if (rtl_dump_file && counter == n_basic_blocks)
! fprintf (rtl_dump_file, "Infinite loop in BB %i.\n", target->index);
! else if (rtl_dump_file && first != target)
! fprintf (rtl_dump_file,
! "Forwarding edge %i->%i to %i failed.\n", b->index,
! e->dest->index, target->index);
}
return changed;
}
! /* Compare the instructions before end of B1 and B2
! to find an opportunity for cross jumping.
! (This means detecting identical sequences of insns)
! Find the longest possible equivalent sequences
! and store the first insns of those sequences into *F1 and *F2
! and return length of that sequence.
! To simplify callers of this function, in the
! all instructions were matched, allways store bb->head. */
static int
flow_find_cross_jump (mode, bb1, bb2, f1, f2)
! int mode;
basic_block bb1, bb2;
rtx *f1, *f2;
{
! rtx i1 = onlyjump_p (bb1->end) ? PREV_INSN (bb1->end): bb1->end;
! rtx i2 = onlyjump_p (bb2->end) ? PREV_INSN (bb2->end): bb2->end;
! rtx p1, p2;
! int lose = 0;
int ninsns = 0;
- rtx last1 = bb1->end, last2 = bb2->end;
- rtx afterlast1 = bb1->end, afterlast2 = bb2->end;
! /* In case basic block ends by nontrivial jump instruction, count it as
! an instruction. Do not count an unconditional jump, as it will be
! removed by basic_block reordering pass in case it is on the common
! path. */
! if (bb1->succ->succ_next && bb1->end != i1)
! ninsns++;
! for (;i1 != bb1->head; i1 = PREV_INSN (i1))
{
/* Ignore notes. */
! if (GET_CODE (i1) == NOTE)
! continue;
while ((GET_CODE (i2) == NOTE && i2 != bb2->head))
i2 = PREV_INSN (i2);
if (GET_CODE (i1) != GET_CODE (i2))
break;
--- 3156,3216 ----
/ REG_BR_PROB_BASE);
first = first->succ->dest;
}
! while (first != target);
!
! changed = true;
}
! else
! {
! if (rtl_dump_file)
! fprintf (rtl_dump_file, "Forwarding edge %i->%i to %i failed.\n",
! b->index, e->dest->index, target->index);
! }
}
+
return changed;
}
! /* Look through the insns at the end of BB1 and BB2 and find the longest
! sequence that are equivalent. Store the first insns for that sequence
! in *F1 and *F2 and return the sequence length.
! To simplify callers of this function, if the blocks match exactly,
! store the head of the blocks in *F1 and *F2. */
static int
flow_find_cross_jump (mode, bb1, bb2, f1, f2)
! int mode ATTRIBUTE_UNUSED;
basic_block bb1, bb2;
rtx *f1, *f2;
{
! rtx i1, i2, p1, p2, last1, last2, afterlast1, afterlast2;
int ninsns = 0;
! /* Skip simple jumps at the end of the blocks. Complex jumps still
! need to be compared for equivalence, which we'll do below. */
! i1 = bb1->end;
! if (onlyjump_p (i1))
! i1 = PREV_INSN (i1);
! i2 = bb2->end;
! if (onlyjump_p (i2))
! i2 = PREV_INSN (i2);
!
! last1 = afterlast1 = last2 = afterlast2 = NULL_RTX;
! while (true)
{
/* Ignore notes. */
! while ((GET_CODE (i1) == NOTE && i1 != bb1->head))
! i1 = PREV_INSN (i1);
while ((GET_CODE (i2) == NOTE && i2 != bb2->head))
i2 = PREV_INSN (i2);
+ if (i1 == bb1->head || i2 == bb2->head)
+ break;
+
+ /* Verify that I1 and I2 are equivalent. */
+
if (GET_CODE (i1) != GET_CODE (i2))
break;
*************** flow_find_cross_jump (mode, bb1, bb2, f1
*** 3208,3221 ****
if (GET_CODE (i1) == CALL_INSN
&& ! rtx_equal_p (CALL_INSN_FUNCTION_USAGE (i1),
CALL_INSN_FUNCTION_USAGE (i2)))
! lose = 1;
#ifdef STACK_REGS
/* If cross_jump_death_matters is not 0, the insn's mode
indicates whether or not the insn contains any stack-like
regs. */
! if (!lose && (mode & CLEANUP_POST_REGSTACK ) && stack_regs_mentioned (i1))
{
/* If register stack conversion has already been done, then
death notes must also be compared before it is certain that
--- 3230,3243 ----
if (GET_CODE (i1) == CALL_INSN
&& ! rtx_equal_p (CALL_INSN_FUNCTION_USAGE (i1),
CALL_INSN_FUNCTION_USAGE (i2)))
! break;
#ifdef STACK_REGS
/* If cross_jump_death_matters is not 0, the insn's mode
indicates whether or not the insn contains any stack-like
regs. */
! if ((mode & CLEANUP_POST_REGSTACK) && stack_regs_mentioned (i1))
{
/* If register stack conversion has already been done, then
death notes must also be compared before it is certain that
*************** flow_find_cross_jump (mode, bb1, bb2, f1
*** 3239,3263 ****
GO_IF_HARD_REG_EQUAL (i1_regset, i2_regset, done);
! lose = 1;
done:
;
}
#endif
! if (lose || GET_CODE (p1) != GET_CODE (p2)
! || ! rtx_renumbered_equal_p (p1, p2))
{
/* The following code helps take care of G++ cleanups. */
! rtx equiv1;
! rtx equiv2;
! if (!lose && GET_CODE (p1) == GET_CODE (p2)
! && ((equiv1 = find_reg_note (i1, REG_EQUAL, NULL_RTX)) != 0
! || (equiv1 = find_reg_note (i1, REG_EQUIV, NULL_RTX)) != 0)
! && ((equiv2 = find_reg_note (i2, REG_EQUAL, NULL_RTX)) != 0
! || (equiv2 = find_reg_note (i2, REG_EQUIV, NULL_RTX)) != 0)
/* If the equivalences are not to a constant, they may
reference pseudos that no longer exist, so we can't
use them. */
--- 3261,3283 ----
GO_IF_HARD_REG_EQUAL (i1_regset, i2_regset, done);
! break;
done:
;
}
#endif
! if (GET_CODE (p1) != GET_CODE (p2))
! break;
!
! if (! rtx_renumbered_equal_p (p1, p2))
{
/* The following code helps take care of G++ cleanups. */
! rtx equiv1 = find_reg_equal_equiv_note (i1);
! rtx equiv2 = find_reg_equal_equiv_note (i2);
! if (equiv1 && equiv2
/* If the equivalences are not to a constant, they may
reference pseudos that no longer exist, so we can't
use them. */
*************** flow_find_cross_jump (mode, bb1, bb2, f1
*** 3277,3323 ****
goto win;
}
}
-
- /* Insns fail to match; cross jumping is limited to the following
- insns. */
-
- #ifdef HAVE_cc0
- /* Don't allow the insn after a compare to be shared by
- cross-jumping unless the compare is also shared.
- Here, if either of these non-matching insns is a compare,
- exclude the following insn from possible cross-jumping. */
- if (sets_cc0_p (p1) || sets_cc0_p (p2))
- last1 = afterlast1, last2 = afterlast2, ninsns--;
- #endif
break;
}
win:
if (GET_CODE (p1) != USE && GET_CODE (p1) != CLOBBER)
{
- /* Ok, this insn is potentially includable in a cross-jump here. */
afterlast1 = last1, afterlast2 = last2;
last1 = i1, last2 = i2;
ninsns++;
}
!
! if (i2 == bb2->end)
! break;
i2 = PREV_INSN (i2);
}
! /* Skip the notes to reach potential head of basic block. */
! while (last1 != bb1->head && GET_CODE (PREV_INSN (last1)) == NOTE)
! last1 = PREV_INSN (last1);
! if (last1 != bb1->head && GET_CODE (PREV_INSN (last1)) == CODE_LABEL)
! last1 = PREV_INSN (last1);
! while (last2 != bb2->head && GET_CODE (PREV_INSN (last2)) == NOTE)
! last2 = PREV_INSN (last2);
! if (last2 != bb2->head && GET_CODE (PREV_INSN (last2)) == CODE_LABEL)
! last2 = PREV_INSN (last2);
! *f1 = last1;
! *f2 = last2;
return ninsns;
}
--- 3297,3345 ----
goto win;
}
}
break;
}
win:
+ /* Don't begin a cross-jump with a USE or CLOBBER insn. */
if (GET_CODE (p1) != USE && GET_CODE (p1) != CLOBBER)
{
afterlast1 = last1, afterlast2 = last2;
last1 = i1, last2 = i2;
ninsns++;
}
! i1 = PREV_INSN (i1);
i2 = PREV_INSN (i2);
}
! #ifdef HAVE_cc0
! if (ninsns)
! {
! /* Don't allow the insn after a compare to be shared by
! cross-jumping unless the compare is also shared. */
! if (reg_mentioned_p (cc0_rtx, last1) && ! sets_cc0_p (last1))
! last1 = afterlast1, last2 = afterlast2, ninsns--;
! }
! #endif
! /* Include preceeding notes and labels in the cross-jump. One,
! this may bring us to the head of the blocks as requested above.
! Two, it keeps line number notes as matched as may be. */
! if (ninsns)
! {
! while (last1 != bb1->head && GET_CODE (PREV_INSN (last1)) == NOTE)
! last1 = PREV_INSN (last1);
! if (last1 != bb1->head && GET_CODE (PREV_INSN (last1)) == CODE_LABEL)
! last1 = PREV_INSN (last1);
! while (last2 != bb2->head && GET_CODE (PREV_INSN (last2)) == NOTE)
! last2 = PREV_INSN (last2);
! if (last2 != bb2->head && GET_CODE (PREV_INSN (last2)) == CODE_LABEL)
! last2 = PREV_INSN (last2);
!
! *f1 = last1;
! *f2 = last2;
! }
!
return ninsns;
}
*************** flow_find_cross_jump (mode, bb1, bb2, f1
*** 3325,3344 ****
the branch instruction. This means that if we commonize the control
flow before end of the basic block, the semantic remains unchanged.
! Assume that at least one outgoing edge is forwarded to the same
! location. */
static bool
outgoing_edges_match (bb1, bb2)
basic_block bb1;
basic_block bb2;
{
! /* bb1 has one succesor, so we are seeing unconditional jump. */
if (bb1->succ && !bb1->succ->succ_next)
return (bb2->succ && !bb2->succ->succ_next);
/* Match conditional jumps - this may get tricky when fallthru and branch
edges are crossed. */
! if (bb1->succ && bb1->succ->succ_next && !bb1->succ->succ_next->succ_next
&& any_condjump_p (bb1->end))
{
edge b1, f1, b2, f2;
--- 3347,3370 ----
the branch instruction. This means that if we commonize the control
flow before end of the basic block, the semantic remains unchanged.
! We may assume that there exists one edge with a common destination. */
!
static bool
outgoing_edges_match (bb1, bb2)
basic_block bb1;
basic_block bb2;
{
! /* If BB1 has only one successor, we must be looking at an unconditional
! jump. Which, by the assumption above, means that we only need to check
! that BB2 has one successor. */
if (bb1->succ && !bb1->succ->succ_next)
return (bb2->succ && !bb2->succ->succ_next);
/* Match conditional jumps - this may get tricky when fallthru and branch
edges are crossed. */
! if (bb1->succ
! && bb1->succ->succ_next
! && !bb1->succ->succ_next->succ_next
&& any_condjump_p (bb1->end))
{
edge b1, f1, b2, f2;
*************** outgoing_edges_match (bb1, bb2)
*** 3346,3354 ****
rtx set1, set2, cond1, cond2;
enum rtx_code code1, code2;
! if (!bb2->succ || !bb2->succ->succ_next
! || bb1->succ->succ_next->succ_next || !any_condjump_p (bb2->end))
return false;
b1 = BRANCH_EDGE (bb1);
b2 = BRANCH_EDGE (bb2);
f1 = FALLTHRU_EDGE (bb1);
--- 3372,3383 ----
rtx set1, set2, cond1, cond2;
enum rtx_code code1, code2;
! if (!bb2->succ
! || !bb2->succ->succ_next
! || bb1->succ->succ_next->succ_next
! || !any_condjump_p (bb2->end))
return false;
+
b1 = BRANCH_EDGE (bb1);
b2 = BRANCH_EDGE (bb2);
f1 = FALLTHRU_EDGE (bb1);
*************** outgoing_edges_match (bb1, bb2)
*** 3390,3400 ****
code2 = reversed_comparison_code (cond2, bb2->end);
else
code2 = GET_CODE (cond2);
-
if (code2 == UNKNOWN)
return false;
! /* See if we don have (cross) match in the codes and operands. */
match = ((code1 == code2
&& rtx_renumbered_equal_p (XEXP (cond1, 0), XEXP (cond2, 0))
&& rtx_renumbered_equal_p (XEXP (cond1, 1), XEXP (cond2, 1)))
--- 3419,3428 ----
code2 = reversed_comparison_code (cond2, bb2->end);
else
code2 = GET_CODE (cond2);
if (code2 == UNKNOWN)
return false;
! /* Verify codes and operands match. */
match = ((code1 == code2
&& rtx_renumbered_equal_p (XEXP (cond1, 0), XEXP (cond2, 0))
&& rtx_renumbered_equal_p (XEXP (cond1, 1), XEXP (cond2, 1)))
*************** outgoing_edges_match (bb1, bb2)
*** 3403,3473 ****
XEXP (cond2, 0))
&& rtx_renumbered_equal_p (XEXP (cond1, 0),
XEXP (cond2, 1))));
! /* In case of returning true, we will commonize the flow.
! This also means, that both branches will contain only single
! branch prediction algorithm. To match require resulting branch
! to be still well predictable. */
if (match && !optimize_size)
{
rtx note1, note2;
int prob1, prob2;
note1 = find_reg_note (bb1->end, REG_BR_PROB, 0);
note2 = find_reg_note (bb2->end, REG_BR_PROB, 0);
- if (!note1 || !note2)
- return false;
- prob1 = INTVAL (XEXP (note1, 0));
- prob2 = INTVAL (XEXP (note2, 0));
- if (reverse)
- prob2 = REG_BR_PROB_BASE - prob2;
! /* ??? Later we should use basic block frequency to allow merging
! in the infrequent blocks, but at the moment it is not
! available when cleanup_cfg is run. */
! if (abs (prob1 - prob2) > REG_BR_PROB_BASE / 90)
return false;
}
if (rtl_dump_file && match)
fprintf (rtl_dump_file, "Conditionals in bb %i and %i match.\n",
bb1->index, bb2->index);
return match;
}
/* ??? We can handle computed jumps too. This may be important for
inlined functions containing switch statements. Also jumps w/o
fallthru edges can be handled by simply matching whole insn. */
return false;
}
! /* Assume that e1 and e2 are the edges from the same basic block.
! Attempt to find common code on both paths and forward control flow
! from the first path to second if such exist. */
static bool
try_crossjump_to_edge (mode, e1, e2)
int mode;
edge e1, e2;
{
int nmatch;
basic_block redirect_to;
rtx newpos1, newpos2;
- rtx first, last;
edge s;
rtx label;
- rtx barrier;
! /* Skip forwarder blocks. This is needed to avoid forced forwarders
! after conditional jumps from making us to miss optimization.
!
! We don't need to worry about multiple entry or chained forwarders, as they
! will be optimized out. */
! if (e1->src->pred && !e1->src->pred->pred_next
! && forwarder_block_p (e1->src))
! e1 = e1->src->pred;
! if (e2->src->pred && !e2->src->pred->pred_next
! && forwarder_block_p (e2->src))
! e2 = e2->src->pred;
! if (e1->src == ENTRY_BLOCK_PTR || e2->src == ENTRY_BLOCK_PTR)
return false;
! if (e1->src == e2->src)
return false;
/* Seeing more than 1 forwarder blocks would confuse us later... */
--- 3431,3520 ----
XEXP (cond2, 0))
&& rtx_renumbered_equal_p (XEXP (cond1, 0),
XEXP (cond2, 1))));
!
! /* If we return true, we will join the blocks. Which means that
! we will only have one branch prediction bit to work with. Thus
! we require the existing branches to have probabilities that are
! roughly similar. */
! /* ??? We should use bb->frequency to allow merging in infrequently
! executed blocks, but at the moment it is not available when
! cleanup_cfg is run. */
if (match && !optimize_size)
{
rtx note1, note2;
int prob1, prob2;
note1 = find_reg_note (bb1->end, REG_BR_PROB, 0);
note2 = find_reg_note (bb2->end, REG_BR_PROB, 0);
! if (note1 && note2)
! {
! prob1 = INTVAL (XEXP (note1, 0));
! prob2 = INTVAL (XEXP (note2, 0));
! if (reverse)
! prob2 = REG_BR_PROB_BASE - prob2;
!
! /* Fail if the difference in probabilities is
! greater than 5%. */
! if (abs (prob1 - prob2) > REG_BR_PROB_BASE / 20)
! return false;
! }
! else if (note1 || note2)
return false;
}
+
if (rtl_dump_file && match)
fprintf (rtl_dump_file, "Conditionals in bb %i and %i match.\n",
bb1->index, bb2->index);
+
return match;
}
+
/* ??? We can handle computed jumps too. This may be important for
inlined functions containing switch statements. Also jumps w/o
fallthru edges can be handled by simply matching whole insn. */
return false;
}
! /* E1 and E2 are edges with the same destination block. Search their
! predecessors for common code. If found, redirect control flow from
! (maybe the middle of) E1->SRC to (maybe the middle of) E2->SRC. */
!
static bool
try_crossjump_to_edge (mode, e1, e2)
int mode;
edge e1, e2;
{
int nmatch;
+ basic_block src1 = e1->src, src2 = e2->src;
basic_block redirect_to;
rtx newpos1, newpos2;
edge s;
+ rtx last;
rtx label;
! /* Search backward through forwarder blocks. We don't need to worry
! about multiple entry or chained forwarders, as they will be optimized
! away. We do this to look past the unconditional jump following a
! conditional jump that is required due to the current CFG shape. */
! if (src1->pred
! && !src1->pred->pred_next
! && forwarder_block_p (src1))
! {
! e1 = src1->pred;
! src1 = e1->src;
! }
! if (src2->pred
! && !src2->pred->pred_next
! && forwarder_block_p (src2))
! {
! e2 = src2->pred;
! src2 = e2->src;
! }
! /* Nothing to do if we reach ENTRY, or a common source block. */
! if (src1 == ENTRY_BLOCK_PTR || src2 == ENTRY_BLOCK_PTR)
return false;
! if (src1 == src2)
return false;
/* Seeing more than 1 forwarder blocks would confuse us later... */
*************** try_crossjump_to_edge (mode, e1, e2)
*** 3477,3531 ****
if (forwarder_block_p (e2->dest)
&& forwarder_block_p (e2->dest->succ->dest))
return false;
! /* ... similary as seeing dead code... */
! if (!e1->src->pred || !e2->src->pred)
return false;
! /* ...similary non-jump edges. */
if (e1->flags & EDGE_COMPLEX)
return false;
! if (!outgoing_edges_match (e1->src, e2->src))
return false;
! nmatch = flow_find_cross_jump (mode, e1->src, e2->src, &newpos1, &newpos2);
if (!nmatch)
return false;
/* Avoid splitting if possible. */
! if (newpos2 == e2->src->head)
! redirect_to = e2->src;
else
{
if (rtl_dump_file)
fprintf (rtl_dump_file, "Splitting bb %i before %i insns\n",
! e2->src->index, nmatch);
! redirect_to = split_block (e2->src, PREV_INSN (newpos2))->dest;
}
if (rtl_dump_file)
fprintf (rtl_dump_file,
! "Cross jumping from bb %i to bb %i. %i insn commoized\n",
! e1->src->index, e2->src->index, nmatch);
! redirect_to->count += e1->src->count;
! redirect_to->frequency += e1->src->frequency;
/* Recompute the frequencies and counts of outgoing edges. */
for (s = redirect_to->succ; s; s = s->succ_next)
{
edge s2;
! basic_block d = (forwarder_block_p (s->dest) ? s->dest->succ->dest
! : s->dest);
! for (s2 = e1->src->succ;; s2 = s2->succ_next)
{
! basic_block d2 =
! (forwarder_block_p (s2->dest) ? s2->dest->succ->dest : s2->dest);
if (d == d2)
break;
}
s->count += s2->count;
! /* Take care to update possible forwarder blocks. We took care
! that there is no more than one in chain, so we can't run
into infinite loop. */
if (forwarder_block_p (s->dest))
{
--- 3524,3589 ----
if (forwarder_block_p (e2->dest)
&& forwarder_block_p (e2->dest->succ->dest))
return false;
!
! /* Likewise with dead code. */
! /* ??? Won't we have eliminated these by now? */
! if (!src1->pred || !src2->pred)
return false;
!
! /* Likewise with non-jump edges. */
! /* ??? Non-jump? You mean GET_CODE (e1->src-end) != JUMP_INSN?
! This fails for computed-goto as well, which may in fact be joinable. */
if (e1->flags & EDGE_COMPLEX)
return false;
! /* Look for the common insn sequence, part the first ... */
! if (!outgoing_edges_match (src1, src2))
return false;
!
! /* ... and part the second. */
! nmatch = flow_find_cross_jump (mode, src1, src2, &newpos1, &newpos2);
if (!nmatch)
return false;
/* Avoid splitting if possible. */
! if (newpos2 == src2->head)
! redirect_to = src2;
else
{
if (rtl_dump_file)
fprintf (rtl_dump_file, "Splitting bb %i before %i insns\n",
! src2->index, nmatch);
! redirect_to = split_block (src2, PREV_INSN (newpos2))->dest;
}
if (rtl_dump_file)
fprintf (rtl_dump_file,
! "Cross jumping from bb %i to bb %i; %i common insns\n",
! src1->index, src2->index, nmatch);
! redirect_to->count += src1->count;
! redirect_to->frequency += src1->frequency;
/* Recompute the frequencies and counts of outgoing edges. */
for (s = redirect_to->succ; s; s = s->succ_next)
{
edge s2;
! basic_block d = s->dest;
!
! if (forwarder_block_p (d))
! d = d->succ->dest;
! for (s2 = src1->succ; ; s2 = s2->succ_next)
{
! basic_block d2 = s2->dest;
! if (forwarder_block_p (d2))
! d2 = d2->succ->dest;
if (d == d2)
break;
}
s->count += s2->count;
! /* Take care to update possible forwarder blocks. We verified
! that there is no more than one in the chain, so we can't run
into infinite loop. */
if (forwarder_block_p (s->dest))
{
*************** try_crossjump_to_edge (mode, e1, e2)
*** 3541,3656 ****
s2->dest->frequency -= ((s->probability * s->src->frequency)
/ REG_BR_PROB_BASE);
}
! if (!redirect_to->frequency && !e1->src->frequency)
s->probability = (s->probability + s2->probability) / 2;
else
s->probability =
((s->probability * redirect_to->frequency +
! s2->probability * e1->src->frequency)
! / (redirect_to->frequency + e1->src->frequency));
}
! /* FIXME: enable once probabilities are fetched properly at
! CFG build. */
#if 0
note = find_reg_note (redirect_to->end, REG_BR_PROB, 0);
if (note)
XEXP (note, 0) = GEN_INT (BRANCH_EDGE (redirect_to)->probability);
#endif
! /* Skip possible basic block header. */
! first = newpos1;
! if (GET_CODE (first) == CODE_LABEL)
! first = NEXT_INSN (first);
! if (GET_CODE (first) == NOTE)
! first = NEXT_INSN (first);
! last = e1->src->end;
! /* Now emit the jump insn. */
label = block_label (redirect_to);
! e1->src->end = emit_jump_insn_after (gen_jump (label), e1->src->end);
! JUMP_LABEL (e1->src->end) = label;
LABEL_NUSES (label)++;
if (basic_block_for_insn)
! set_block_for_new_insns (e1->src->end, e1->src);
! flow_delete_insn_chain (first, last);
! barrier = next_nonnote_insn (e1->src->end);
! if (!barrier || GET_CODE (barrier) != BARRIER)
! emit_barrier_after (e1->src->end);
/* Update CFG. */
! while (e1->src->succ->succ_next)
! remove_edge (e1->src->succ);
! e1->src->succ->flags = 0;
! redirect_edge_succ (e1->src->succ, redirect_to);
return true;
}
! /* Attempt to implement cross jumping. This means moving one or more branches
! to BB earlier to BB predecesors commonizing some code. */
static bool
try_crossjump_bb (mode, bb)
int mode;
basic_block bb;
{
edge e, e2, nexte2, nexte, fallthru;
! bool changed = false;
! /* In case basic block has single predecesor, do nothing. */
if (!bb->pred || !bb->pred->pred_next)
return false;
! /* It is always cheapest to jump into fallthru edge. */
for (fallthru = bb->pred; fallthru; fallthru = fallthru->pred_next)
if (fallthru->flags & EDGE_FALLTHRU)
break;
for (e = bb->pred; e; e = nexte)
{
nexte = e->pred_next;
- /* First of all prioritize the fallthru edge, as the cheapest. */
- if (e != fallthru && fallthru
- && try_crossjump_to_edge (mode, e, fallthru))
- changed = true, nexte = bb->pred;
- else
- /* Try match in other incomming edges.
! Loop only over the earlier edges to avoid,as the later
! will be examined in the oposite direction. */
! for (e2 = bb->pred; e2 != e; e2 = nexte2)
! {
! nexte2 = e2->pred_next;
! if (e2 != fallthru && try_crossjump_to_edge (mode, e, e2))
! {
! changed = true;
! nexte = bb->pred;
! /* We may've removed the fallthru edge. */
! for (fallthru = bb->pred; fallthru;
! fallthru = fallthru->pred_next)
! if (fallthru->flags & EDGE_FALLTHRU)
! break;
! break;
! }
! }
}
return changed;
}
/* Do simple CFG optimizations - basic block merging, simplifying of jump
! instructions etc.
!
! Return nonzero in case some optimizations matched. */
static bool
try_optimize_cfg (mode)
int mode;
{
int i;
! bool changed_overall = 0;
bool changed;
int iterations = 0;
--- 3599,3762 ----
s2->dest->frequency -= ((s->probability * s->src->frequency)
/ REG_BR_PROB_BASE);
}
! if (!redirect_to->frequency && !src1->frequency)
s->probability = (s->probability + s2->probability) / 2;
else
s->probability =
((s->probability * redirect_to->frequency +
! s2->probability * src1->frequency)
! / (redirect_to->frequency + src1->frequency));
}
! /* FIXME: enable once probabilities are fetched properly at CFG build. */
#if 0
note = find_reg_note (redirect_to->end, REG_BR_PROB, 0);
if (note)
XEXP (note, 0) = GEN_INT (BRANCH_EDGE (redirect_to)->probability);
#endif
! /* Edit SRC1 to go to REDIRECT_TO at NEWPOS1. */
! /* Skip possible basic block header. */
! if (GET_CODE (newpos1) == CODE_LABEL)
! newpos1 = NEXT_INSN (newpos1);
! if (GET_CODE (newpos1) == NOTE)
! newpos1 = NEXT_INSN (newpos1);
! last = src1->end;
! /* Emit the jump insn. */
label = block_label (redirect_to);
! src1->end = emit_jump_insn_before (gen_jump (label), newpos1);
! JUMP_LABEL (src1->end) = label;
LABEL_NUSES (label)++;
if (basic_block_for_insn)
! set_block_for_new_insns (src1->end, src1);
! /* Delete the now unreachable instructions. */
! flow_delete_insn_chain (newpos1, last);
! /* Make sure there is a barrier after the new jump. */
! last = next_nonnote_insn (src1->end);
! if (!last || GET_CODE (last) != BARRIER)
! emit_barrier_after (src1->end);
/* Update CFG. */
! while (src1->succ)
! remove_edge (src1->succ);
! make_edge (NULL, src1, redirect_to, 0);
!
return true;
}
! /* Search the predecessors of BB for common insn sequences. When found,
! share code between them by redirecting control flow. Return true if
! any changes made. */
!
static bool
try_crossjump_bb (mode, bb)
int mode;
basic_block bb;
{
edge e, e2, nexte2, nexte, fallthru;
! bool changed;
! /* Nothing to do if there is not at least two incomming edges. */
if (!bb->pred || !bb->pred->pred_next)
return false;
! /* It is always cheapest to redirect a block that ends in a branch to
! a block that falls through into BB, as that adds no branches to the
! program. We'll try that combination first. */
for (fallthru = bb->pred; fallthru; fallthru = fallthru->pred_next)
if (fallthru->flags & EDGE_FALLTHRU)
break;
+ changed = false;
for (e = bb->pred; e; e = nexte)
{
nexte = e->pred_next;
! /* Elide complex edges now, as neither try_crossjump_to_edge
! nor outgoing_edges_match can handle them. */
! if (e->flags & EDGE_COMPLEX)
! continue;
! /* As noted above, first try with the fallthru predecessor. */
! if (fallthru)
! {
! /* Don't combine the fallthru edge into anything else.
! If there is a match, we'll do it the other way around. */
! if (e == fallthru)
! continue;
!
! if (try_crossjump_to_edge (mode, e, fallthru))
! {
! changed = true;
! nexte = bb->pred;
! continue;
! }
! }
!
! /* Non-obvious work limiting check: Recognize that we're going
! to call try_crossjump_bb on every basic block. So if we have
! two blocks with lots of outgoing edges (a switch) and they
! share lots of common destinations, then we would do the
! cross-jump check once for each common destination.
!
! Now, if the blocks actually are cross-jump candidates, then
! all of their destinations will be shared. Which means that
! we only need check them for cross-jump candidacy once. We
! can eliminate redundant checks of crossjump(A,B) by arbitrarily
! choosing to do the check from the block for which the edge
! in question is the first successor of A. */
! if (e->src->succ != e)
! continue;
!
! for (e2 = bb->pred; e2; e2 = nexte2)
! {
! nexte2 = e2->pred_next;
!
! if (e2 == e)
! continue;
!
! /* We've already checked the fallthru edge above. */
! if (e2 == fallthru)
! continue;
!
! /* Again, neither try_crossjump_to_edge nor outgoing_edges_match
! can handle complex edges. */
! if (e2->flags & EDGE_COMPLEX)
! continue;
!
! /* The "first successor" check above only prevents multiple
! checks of crossjump(A,B). In order to prevent redundant
! checks of crossjump(B,A), require that A be the block
! with the lowest index. */
! /* ??? Perhaps better is lowest execution frequency. */
! if (e->src->index > e2->src->index)
! continue;
!
! if (try_crossjump_to_edge (mode, e, e2))
! {
! changed = true;
! nexte = bb->pred;
! break;
! }
! }
}
+
return changed;
}
/* Do simple CFG optimizations - basic block merging, simplifying of jump
! instructions etc. Return nonzero if changes were made. */
static bool
try_optimize_cfg (mode)
int mode;
{
int i;
! bool changed_overall = false;
bool changed;
int iterations = 0;
*************** try_optimize_cfg (mode)
*** 3660,3675 ****
do
{
! changed = 0;
iterations++;
if (rtl_dump_file)
fprintf (rtl_dump_file, "\n\ntry_optimize_cfg iteration %i\n\n",
iterations);
for (i = 0; i < n_basic_blocks;)
{
basic_block c, b = BASIC_BLOCK (i);
edge s;
! int changed_here = 0;
/* Delete trivially dead basic blocks. */
while (b->pred == NULL)
--- 3766,3783 ----
do
{
! changed = false;
iterations++;
+
if (rtl_dump_file)
fprintf (rtl_dump_file, "\n\ntry_optimize_cfg iteration %i\n\n",
iterations);
+
for (i = 0; i < n_basic_blocks;)
{
basic_block c, b = BASIC_BLOCK (i);
edge s;
! bool changed_here = false;
/* Delete trivially dead basic blocks. */
while (b->pred == NULL)
*************** try_optimize_cfg (mode)
*** 3678,3696 ****
if (rtl_dump_file)
fprintf (rtl_dump_file, "Deleting block %i.\n", b->index);
flow_delete_block (b);
! changed = 1;
b = c;
}
! /* Remove code labels no longer used.
! Don't do the optimization before sibling calls are discovered,
! as some branches may be hidden inside CALL_PLACEHOLDERs. */
if (b->pred->pred_next == NULL
&& (b->pred->flags & EDGE_FALLTHRU)
&& !(b->pred->flags & EDGE_COMPLEX)
&& GET_CODE (b->head) == CODE_LABEL
&& (!(mode & CLEANUP_PRE_SIBCALL)
|| !tail_recursion_label_p (b->head))
! /* If previous block does end with condjump jumping to next BB,
we can't delete the label. */
&& (b->pred->src == ENTRY_BLOCK_PTR
|| !reg_mentioned_p (b->head, b->pred->src->end)))
--- 3786,3805 ----
if (rtl_dump_file)
fprintf (rtl_dump_file, "Deleting block %i.\n", b->index);
flow_delete_block (b);
! changed = true;
b = c;
}
!
! /* Remove code labels no longer used. Don't do this before
! CALL_PLACEHOLDER is removed, as some branches may be hidden
! within. */
if (b->pred->pred_next == NULL
&& (b->pred->flags & EDGE_FALLTHRU)
&& !(b->pred->flags & EDGE_COMPLEX)
&& GET_CODE (b->head) == CODE_LABEL
&& (!(mode & CLEANUP_PRE_SIBCALL)
|| !tail_recursion_label_p (b->head))
! /* If previous block ends with condjump jumping to next BB,
we can't delete the label. */
&& (b->pred->src == ENTRY_BLOCK_PTR
|| !reg_mentioned_p (b->head, b->pred->src->end)))
*************** try_optimize_cfg (mode)
*** 3702,3776 ****
fprintf (rtl_dump_file, "Deleted label in block %i.\n",
b->index);
}
! /* The fallthru forwarder block can be deleted. */
if (b->pred->pred_next == NULL
- && forwarder_block_p (b)
- && n_basic_blocks > 1
&& (b->pred->flags & EDGE_FALLTHRU)
&& (b->succ->flags & EDGE_FALLTHRU)
! && GET_CODE (b->head) != CODE_LABEL)
{
if (rtl_dump_file)
fprintf (rtl_dump_file, "Deleting fallthru block %i.\n",
b->index);
! c = BASIC_BLOCK (i ? i - 1 : i + 1);
redirect_edge_succ (b->pred, b->succ->dest);
flow_delete_block (b);
! changed = 1;
b = c;
}
-
! /* A loop because chains of blocks might be combineable. */
while ((s = b->succ) != NULL
&& s->succ_next == NULL
- && (s->flags & EDGE_EH) == 0
- && (c = s->dest) != EXIT_BLOCK_PTR
&& !(s->flags & EDGE_COMPLEX)
&& c->pred->pred_next == NULL
/* If the jump insn has side effects,
we can't kill the edge. */
&& (GET_CODE (b->end) != JUMP_INSN
! || onlyjump_p (b->end)) && merge_blocks (s, b, c, mode))
! changed_here = 1;
if ((mode & CLEANUP_EXPENSIVE) && try_simplify_condjump (b))
! changed_here = 1;
!
! /* In the case basic blocks has single outgoing edge, but over by the
! non-trivial jump instruction, we can replace it by unconditional
! jump, or delete the jump completely. Use logic of
! redirect_edge_and_branch to do the dirty job for us.
!
! We match cases as conditional jumps jumping to the next block or
! dispatch tables. */
if (b->succ
! && b->succ->succ_next == NULL
! && GET_CODE (b->end) == JUMP_INSN
&& b->succ->dest != EXIT_BLOCK_PTR
&& redirect_edge_and_branch (b->succ, b->succ->dest))
! changed_here = 1;
if (try_forward_edges (b))
! changed_here = 1;
! if ((mode & CLEANUP_CROSSJUMP) && try_crossjump_bb (mode, b))
! changed_here = 1;
/* Don't get confused by the index shift caused by deleting
blocks. */
if (!changed_here)
i = b->index + 1;
else
! changed = 1;
}
! if ((mode & CLEANUP_CROSSJUMP) && try_crossjump_bb (mode, EXIT_BLOCK_PTR))
! changed = 1;
#ifdef ENABLE_CHECKING
if (changed)
verify_flow_info ();
#endif
changed_overall |= changed;
}
while (changed);
--- 3811,3892 ----
fprintf (rtl_dump_file, "Deleted label in block %i.\n",
b->index);
}
!
! /* If we fall through an empty block, we can remove it. */
if (b->pred->pred_next == NULL
&& (b->pred->flags & EDGE_FALLTHRU)
+ && GET_CODE (b->head) != CODE_LABEL
+ && forwarder_block_p (b)
+ /* Note that forwarder_block_p true ensures that there
+ is a successor for this block. */
&& (b->succ->flags & EDGE_FALLTHRU)
! && n_basic_blocks > 1)
{
if (rtl_dump_file)
fprintf (rtl_dump_file, "Deleting fallthru block %i.\n",
b->index);
! c = BASIC_BLOCK (b->index ? b->index - 1 : 1);
redirect_edge_succ (b->pred, b->succ->dest);
flow_delete_block (b);
! changed = true;
b = c;
}
! /* Merge blocks. Loop because chains of blocks might be
! combineable. */
while ((s = b->succ) != NULL
&& s->succ_next == NULL
&& !(s->flags & EDGE_COMPLEX)
+ && (c = s->dest) != EXIT_BLOCK_PTR
&& c->pred->pred_next == NULL
/* If the jump insn has side effects,
we can't kill the edge. */
&& (GET_CODE (b->end) != JUMP_INSN
! || onlyjump_p (b->end))
! && merge_blocks (s, b, c, mode))
! changed_here = true;
+ /* Simplify branch over branch. */
if ((mode & CLEANUP_EXPENSIVE) && try_simplify_condjump (b))
! changed_here = true;
+ /* If B has a single outgoing edge, but uses a non-trivial jump
+ instruction without side-effects, we can either delete the
+ jump entirely, or replace it with a simple unconditional jump.
+ Use redirect_edge_and_branch to do the dirty work. */
if (b->succ
! && ! b->succ->succ_next
&& b->succ->dest != EXIT_BLOCK_PTR
+ && onlyjump_p (b->end)
&& redirect_edge_and_branch (b->succ, b->succ->dest))
! changed_here = true;
+ /* Simplify branch to branch. */
if (try_forward_edges (b))
! changed_here = true;
! /* Look for shared code between blocks. */
! if ((mode & CLEANUP_CROSSJUMP)
! && try_crossjump_bb (mode, b))
! changed_here = true;
/* Don't get confused by the index shift caused by deleting
blocks. */
if (!changed_here)
i = b->index + 1;
else
! changed = true;
}
!
! if ((mode & CLEANUP_CROSSJUMP)
! && try_crossjump_bb (mode, EXIT_BLOCK_PTR))
! changed = true;
!
#ifdef ENABLE_CHECKING
if (changed)
verify_flow_info ();
#endif
+
changed_overall |= changed;
}
while (changed);