Allows crossjump over fallthru paths.
Thanks,
- Tom
diff -u gcc/cfgcleanup.c gcc/cfgcleanup.c
--- gcc/cfgcleanup.c (working copy)
+++ gcc/cfgcleanup.c (working copy)
@@ -1139,6 +1139,43 @@
}
}
+ /* Walks from I1 in BB1 backward till the next non-debug insn, and returns the
+resulting insn in I1, and the corresponding bb in BB1. At the head of a
+bb, if there is a predecessor bb that reaches this bb via fallthru, and
+FOLLOW_FALLTHRU, walks further in the predecessor bb and registers this in
+DID_FALLTHRU. Otherwise, stops at the head of the bb. */
+
+static void
+walk_to_nondebug_insn (rtx *i1, basic_block *bb1, bool follow_fallthru,
+ bool *did_fallthru)
+{
+ edge fallthru;
+
+ *did_fallthru = false;
+
+ /* Ignore notes. */
+ while (!NONDEBUG_INSN_P (*i1))
+{
+ if (*i1 != BB_HEAD (*bb1))
+{
+ *i1 = PREV_INSN (*i1);
+ continue;
+}
+
+ if (!follow_fallthru)
+return;
+
+ fallthru = find_fallthru_edge ((*bb1)-preds);
+ if (!fallthru || fallthru-src == ENTRY_BLOCK_PTR_FOR_FUNCTION (cfun)
+ || !single_succ_p (fallthru-src))
+return;
+
+ *bb1 = fallthru-src;
+ *i1 = BB_END (*bb1);
+ *did_fallthru = true;
+ }
+}
+
/* 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.
@@ -1153,6 +1190,7 @@
rtx i1, i2, last1, last2, afterlast1, afterlast2;
int ninsns = 0;
enum replace_direction dir, last_dir, afterlast_dir;
+ bool follow_fallthru, did_fallthru;
if (dir_p)
dir = *dir_p;
@@ -1187,11 +1225,30 @@
while (true)
{
- /* Ignore notes. */
- while (!NONDEBUG_INSN_P (i1) i1 != BB_HEAD (bb1))
- i1 = PREV_INSN (i1);
-
- while (!NONDEBUG_INSN_P (i2) i2 != BB_HEAD (bb2))
- i2 = PREV_INSN (i2);
+ /* In the following example, we can replace all jumps to C by jumps to A.
+
+ This removes 4 duplicate insns.
+ [bb A] insn1[bb C] insn1
+insn2 insn2
+ [bb B] insn3 insn3
+insn4 insn4
+jump_insn jump_insn
+
+ We could also replace all jumps to A by jumps to C, but that leaves B
+ alive, and removes only 2 duplicate insns. In a subsequent crossjump
+ step, all jumps to B would be replaced with jumps to the middle of C,
+ achieving the same result with more effort.
+ So we allow only the first possibility, which means that we don't allow
+ fallthru in the block that's being replaced. */
+
+ follow_fallthru = dir_p dir != dir_forward;
+ walk_to_nondebug_insn (i1, bb1, follow_fallthru, did_fallthru);
+ if (did_fallthru)
+dir = dir_backward;
+
+ follow_fallthru = dir_p dir != dir_backward;
+ walk_to_nondebug_insn (i2, bb2, follow_fallthru, did_fallthru);
+ if (did_fallthru)
+dir = dir_forward;
if (i1 == BB_HEAD (bb1) || i2 == BB_HEAD (bb2))
break;
@@ -1230,12 +1287,14 @@
Two, it keeps line number notes as matched as may be. */
if (ninsns)
{
+ bb1 = BLOCK_FOR_INSN (last1);
while (last1 != BB_HEAD (bb1) !NONDEBUG_INSN_P (PREV_INSN (last1)))
last1 = PREV_INSN (last1);
if (last1 != BB_HEAD (bb1) LABEL_P (PREV_INSN (last1)))
last1 = PREV_INSN (last1);
+ bb2 = BLOCK_FOR_INSN (last2);
while (last2 != BB_HEAD (bb2) !NONDEBUG_INSN_P (PREV_INSN (last2)))
last2 = PREV_INSN (last2);
@@ -1659,6 +1718,7 @@
int nmatch;
basic_block src1 = e1-src, src2 = e2-src;
basic_block redirect_to, redirect_from, to_remove;
+ basic_block osrc1, osrc2, redirect_edges_to, tmp;
enum replace_direction dir;
rtx newpos1, newpos2;
edge s;
@@ -1720,8 +1780,15 @@
return false;
/* ... and part the second. */
dir = dir_forward;
nmatch = flow_find_cross_jump (src1, src2, newpos1, newpos2, dir);
+
+ osrc1 = src1;
+ osrc2 = src2;
+ if (newpos1 != NULL_RTX)
+src1 = BLOCK_FOR_INSN (newpos1);
+ if (newpos2 != NULL_RTX)
+src2 = BLOCK_FOR_INSN (newpos2);
/* Don't proceed with the crossjump unless we found a sufficient number
of matching instructions or the 'from' block was totally matched
@@ -1745,8 +1812,8 @@
rtx label1, label2;
rtx table1, table2;
- if (tablejump_p (BB_END (src1), label1, table1)
- tablejump_p (BB_END (src2), label2, table2)
+ if (tablejump_p (BB_END (osrc1), label1, table1)
+ tablejump_p (BB_END (osrc2), label2, table2)
label1 != label2)
{
replace_label_data rr;
@@ -1761,7 +1828,7 @@
/* Do not replace the label in SRC1-END because when deleting
a block whose end is a tablejump, the tablejump referenced
from the instruction is deleted too. */
- if (insn != BB_END (src1))
+ if