aboutsummaryrefslogtreecommitdiff
path: root/gcc/cfgcleanup.c
diff options
context:
space:
mode:
authorJ"orn Rennecke <joern.rennecke@st.com>2005-12-13 13:04:18 +0000
committerJoern Rennecke <amylaar@gcc.gnu.org>2005-12-13 13:04:18 +0000
commit7d22e8989c52bd3b6ddbf85761204c7a759cf8c6 (patch)
treee701881426d487009dc1064a87c21abe61a14c8a /gcc/cfgcleanup.c
parent80e6edb051397f18aa328e0ddeb83f4bf380b3f9 (diff)
downloadgcc-7d22e8989c52bd3b6ddbf85761204c7a759cf8c6.zip
gcc-7d22e8989c52bd3b6ddbf85761204c7a759cf8c6.tar.gz
gcc-7d22e8989c52bd3b6ddbf85761204c7a759cf8c6.tar.bz2
PR rtl-optimization/20070 / part1
PR rtl-optimization/20070 / part1 * flow.c (update_life_info): If PROP_POST_REGSTACK is set, call count_or_remove_death_notes with kill == -1. (mark_set_1): Don't add REG_DEAD / REG_UNUSED notes for stack registers if PROP_POST_REGSTACK is set. (mark_used_reg): Likewise. (count_or_remove_death_notes): If kill is -1, don't remove REG_DEAD / REG_UNUSED notes for stack regs. * cfgcleanup.c (condjump_equiv_p): Change parameters and processing to match rtx_equiv_p machinery. Change caller. (outgoing_edges_match): Likewise. (try_crossjump_to_edge): Use struct_equiv_block_eq instead of flow_find_cross_jump. * basic-block.h (PROP_POST_REGSTACK, STRUCT_EQUIV_START): Define. (STRUCT_EQUIV_RERUN, STRUCT_EQUIV_FINAL): Likewise. (STRUCT_EQUIV_NEED_FULL_BLOCK, STRUCT_EQUIV_MATCH_JUMPS): Likewise. (STRUCT_EQUIV_MAX_LOCAL): Likewise. (struct struct_equiv_checkpoint, struct equiv_info): Likewise. (insns_match_p): Update prototype. (flow_find_cross_jump): Remove prototype. (struct_equiv_block_eq, struct_equiv_init): Declare. (rtx_equiv_p, condjump_equiv_p): Likewise. * struct-equiv.c: Include reload.h. (IMPOSSIBLE_MOVE_FACTOR): Define. (assign_reg_reg_set, struct_equiv_make_checkpoint): New functions. (struct_equiv_improve_checkpoint): Likewise. (struct_equiv_restore_checkpoint, rtx_equiv_p): Likewise. (set_dest_equiv_p, set_dest_addr_equiv_p, struct_equiv_init): Likewise. (struct_equiv_merge, find_dying_input): Likewise. (resolve_input_conflict, note_local_live): Likewise. (death_notes_match_p): Change parameters and processing to match rtx_equiv_p machinery. Change caller. (insns_match_p): Likewise. (flow_find_cross_jump): Replace with: (struct_equiv_block_eq). Back out this change: 2005-03-07 Kazu Hirata <kazu@cs.umass.edu> * recog.c (verify_changes): Make it static. * recog.h: Remove the corresponding prototype. From-SVN: r108480
Diffstat (limited to 'gcc/cfgcleanup.c')
-rw-r--r--gcc/cfgcleanup.c205
1 files changed, 137 insertions, 68 deletions
diff --git a/gcc/cfgcleanup.c b/gcc/cfgcleanup.c
index 80d68de..c4939d0 100644
--- a/gcc/cfgcleanup.c
+++ b/gcc/cfgcleanup.c
@@ -60,7 +60,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
static bool first_pass;
static bool try_crossjump_to_edge (int, edge, edge);
static bool try_crossjump_bb (int, basic_block);
-static bool outgoing_edges_match (int, basic_block, basic_block);
+static bool outgoing_edges_match (int *, struct equiv_info *);
static void merge_blocks_move_predecessor_nojumps (basic_block, basic_block);
static void merge_blocks_move_successor_nojumps (basic_block, basic_block);
@@ -879,20 +879,20 @@ merge_blocks_move (edge e, basic_block b, basic_block c, int mode)
}
/* Return true iff the condbranches at the end of BB1 and BB2 match. */
-static bool
-condjump_equiv_p (basic_block bb1, basic_block bb2)
+bool
+condjump_equiv_p (struct equiv_info *info, bool call_init)
{
- edge b1, f1, b2, f2;
+ basic_block bb1 = info->x_block;
+ basic_block bb2 = info->y_block;
+ edge b1 = BRANCH_EDGE (bb1);
+ edge b2 = BRANCH_EDGE (bb2);
+ edge f1 = FALLTHRU_EDGE (bb1);
+ edge f2 = FALLTHRU_EDGE (bb2);
bool reverse, match;
rtx set1, set2, cond1, cond2;
+ rtx src1, src2;
enum rtx_code code1, code2;
-
- b1 = BRANCH_EDGE (bb1);
- b2 = BRANCH_EDGE (bb2);
- f1 = FALLTHRU_EDGE (bb1);
- f2 = FALLTHRU_EDGE (bb2);
-
/* Get around possible forwarders on fallthru edges. Other cases
should be optimized out already. */
if (FORWARDER_BLOCK_P (f1->dest))
@@ -923,8 +923,10 @@ condjump_equiv_p (basic_block bb1, basic_block bb2)
!= (XEXP (SET_SRC (set2), 1) == pc_rtx))
reverse = !reverse;
- cond1 = XEXP (SET_SRC (set1), 0);
- cond2 = XEXP (SET_SRC (set2), 0);
+ src1 = SET_SRC (set1);
+ src2 = SET_SRC (set2);
+ cond1 = XEXP (src1, 0);
+ cond2 = XEXP (src2, 0);
code1 = GET_CODE (cond1);
if (reverse)
code2 = reversed_comparison_code (cond2, BB_END (bb2));
@@ -934,15 +936,35 @@ condjump_equiv_p (basic_block bb1, basic_block bb2)
if (code2 == UNKNOWN)
return false;
+ if (call_init && !struct_equiv_init (STRUCT_EQUIV_START | info->mode, info))
+ gcc_unreachable ();
+ /* Make the sources of the pc sets unreadable so that when we call
+ insns_match_p it won't process them.
+ The death_notes_match_p from insns_match_p won't see the local registers
+ used for the pc set, but that could only cause missed optimizations when
+ there are actually condjumps that use stack registers. */
+ SET_SRC (set1) = pc_rtx;
+ SET_SRC (set2) = pc_rtx;
/* 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)))
- || (code1 == swap_condition (code2)
- && rtx_renumbered_equal_p (XEXP (cond1, 1),
- XEXP (cond2, 0))
- && rtx_renumbered_equal_p (XEXP (cond1, 0),
- XEXP (cond2, 1))));
+ if (code1 == code2)
+ {
+ match = (insns_match_p (BB_END (bb1), BB_END (bb2), info)
+ && rtx_equiv_p (&XEXP (cond1, 0), XEXP (cond2, 0), 1, info)
+ && rtx_equiv_p (&XEXP (cond1, 1), XEXP (cond2, 1), 1, info));
+
+ }
+ else if (code1 == swap_condition (code2))
+ {
+ match = (insns_match_p (BB_END (bb1), BB_END (bb2), info)
+ && rtx_equiv_p (&XEXP (cond1, 1), XEXP (cond2, 0), 1, info)
+ && rtx_equiv_p (&XEXP (cond1, 0), XEXP (cond2, 1), 1, info));
+
+ }
+ else
+ match = false;
+ SET_SRC (set1) = src1;
+ SET_SRC (set2) = src2;
+ match &= verify_changes (0);
/* If we return true, we will join the blocks. Which means that
we will only have one branch prediction bit to work with. Thus
@@ -971,7 +993,7 @@ condjump_equiv_p (basic_block bb1, basic_block bb2)
"Outcomes of branch in bb %i and %i differ too much (%i %i)\n",
bb1->index, bb2->index, b1->probability, prob2);
- return false;
+ match = false;
}
}
@@ -979,17 +1001,25 @@ condjump_equiv_p (basic_block bb1, basic_block bb2)
fprintf (dump_file, "Conditionals in bb %i and %i match.\n",
bb1->index, bb2->index);
+ if (!match)
+ cancel_changes (0);
return match;
}
-/* Return true iff outgoing edges of BB1 and BB2 match, together with
- the branch instruction. This means that if we commonize the control
- flow before end of the basic block, the semantic remains unchanged.
+
+/* Return true iff outgoing edges of INFO->y_block and INFO->x_block match,
+ together with the branch instruction. This means that if we commonize the
+ control flow before end of the basic block, the semantic remains unchanged.
+ If we need to compare jumps, we set STRUCT_EQUIV_MATCH_JUMPS in *MODE,
+ and pass *MODE to struct_equiv_init or assign it to INFO->mode, as
+ appropriate.
We may assume that there exists one edge with a common destination. */
static bool
-outgoing_edges_match (int mode, basic_block bb1, basic_block bb2)
+outgoing_edges_match (int *mode, struct equiv_info *info)
{
+ basic_block bb1 = info->y_block;
+ basic_block bb2 = info->x_block;
int nehedges1 = 0, nehedges2 = 0;
edge fallthru1 = 0, fallthru2 = 0;
edge e1, e2;
@@ -1005,6 +1035,7 @@ outgoing_edges_match (int mode, basic_block bb1, basic_block bb2)
& (EDGE_COMPLEX | EDGE_FAKE)) == 0
&& (!JUMP_P (BB_END (bb2)) || simplejump_p (BB_END (bb2))));
+ *mode |= STRUCT_EQUIV_MATCH_JUMPS;
/* Match conditional jumps - this may get tricky when fallthru and branch
edges are crossed. */
if (EDGE_COUNT (bb1->succs) == 2
@@ -1015,7 +1046,8 @@ outgoing_edges_match (int mode, basic_block bb1, basic_block bb2)
|| !any_condjump_p (BB_END (bb2))
|| !onlyjump_p (BB_END (bb2)))
return false;
- return condjump_equiv_p (bb1, bb2);
+ info->mode = *mode;
+ return condjump_equiv_p (info, true);
}
/* Generic case - we are seeing a computed jump, table jump or trapping
@@ -1063,31 +1095,22 @@ outgoing_edges_match (int mode, basic_block bb1, basic_block bb2)
identical = false;
}
- if (identical)
+ if (identical
+ && struct_equiv_init (STRUCT_EQUIV_START | *mode, info))
{
- replace_label_data rr;
bool match;
- /* Temporarily replace references to LABEL1 with LABEL2
+ /* Indicate that LABEL1 is to be replaced with LABEL2
in BB1->END so that we could compare the instructions. */
- rr.r1 = label1;
- rr.r2 = label2;
- rr.update_label_nuses = false;
- for_each_rtx (&BB_END (bb1), replace_label, &rr);
+ info->y_label = label1;
+ info->x_label = label2;
- match = insns_match_p (mode, BB_END (bb1), BB_END (bb2));
+ match = insns_match_p (BB_END (bb1), BB_END (bb2), info);
if (dump_file && match)
fprintf (dump_file,
"Tablejumps in bb %i and %i match.\n",
bb1->index, bb2->index);
- /* Set the original label in BB1->END because when deleting
- a block whose end is a tablejump, the tablejump referenced
- from the instruction is deleted too. */
- rr.r1 = label2;
- rr.r2 = label1;
- for_each_rtx (&BB_END (bb1), replace_label, &rr);
-
return match;
}
}
@@ -1097,7 +1120,8 @@ outgoing_edges_match (int mode, basic_block bb1, basic_block bb2)
/* First ensure that the instructions match. There may be many outgoing
edges so this test is generally cheaper. */
- if (!insns_match_p (mode, BB_END (bb1), BB_END (bb2)))
+ if (!struct_equiv_init (STRUCT_EQUIV_START | *mode, info)
+ || !insns_match_p (BB_END (bb1), BB_END (bb2), info))
return false;
/* Search the outgoing edges, ensure that the counts do match, find possible
@@ -1163,14 +1187,13 @@ outgoing_edges_match (int mode, basic_block bb1, basic_block bb2)
static bool
try_crossjump_to_edge (int mode, edge e1, edge e2)
{
- int nmatch;
+ int nmatch, i;
basic_block src1 = e1->src, src2 = e2->src;
basic_block redirect_to, redirect_from, to_remove;
- rtx newpos1, newpos2;
edge s;
edge_iterator ei;
-
- newpos1 = newpos2 = NULL_RTX;
+ struct equiv_info info;
+ rtx x_active, y_active;
/* If we have partitioned hot/cold basic blocks, it is a bad idea
to try this optimization.
@@ -1217,19 +1240,66 @@ try_crossjump_to_edge (int mode, edge e1, edge e2)
return false;
/* Look for the common insn sequence, part the first ... */
- if (!outgoing_edges_match (mode, src1, src2))
+ info.x_block = src2;
+ info.y_block = src1;
+ if (!outgoing_edges_match (&mode, &info))
return false;
/* ... and part the second. */
- nmatch = flow_find_cross_jump (mode, src1, src2, &newpos1, &newpos2);
+ info.input_cost = optimize_size ? COSTS_N_INSNS (1) : -1;
+ nmatch = struct_equiv_block_eq (STRUCT_EQUIV_START | mode, &info);
/* Don't proceed with the crossjump unless we found a sufficient number
of matching instructions or the 'from' block was totally matched
(such that its predecessors will hopefully be redirected and the
block removed). */
- if ((nmatch < PARAM_VALUE (PARAM_MIN_CROSSJUMP_INSNS))
- && (newpos1 != BB_HEAD (src1)))
+ if (!nmatch)
return false;
+ if ((nmatch -info.cur.input_count < PARAM_VALUE (PARAM_MIN_CROSSJUMP_INSNS))
+ && (info.cur.y_start != BB_HEAD (src1)))
+ return false;
+ while (info.need_rerun)
+ {
+ nmatch = struct_equiv_block_eq (STRUCT_EQUIV_RERUN | mode, &info);
+ if (!nmatch)
+ return false;
+ if ((nmatch -info.cur.input_count < PARAM_VALUE (PARAM_MIN_CROSSJUMP_INSNS))
+ && (info.cur.y_start != BB_HEAD (src1)))
+ return false;
+ }
+ nmatch = struct_equiv_block_eq (STRUCT_EQUIV_FINAL | mode, &info);
+ if ((nmatch -info.cur.input_count < PARAM_VALUE (PARAM_MIN_CROSSJUMP_INSNS))
+ && (info.cur.y_start != BB_HEAD (src1)))
+ return false;
+
+ /* Skip possible basic block header. */
+ x_active = info.cur.x_start;
+ if (LABEL_P (x_active))
+ x_active = NEXT_INSN (x_active);
+ if (NOTE_P (x_active))
+ x_active = NEXT_INSN (x_active);
+
+ y_active = info.cur.y_start;
+ if (LABEL_P (y_active))
+ y_active = NEXT_INSN (y_active);
+ if (NOTE_P (y_active))
+ y_active = NEXT_INSN (y_active);
+
+ /* In order for this code to become active, either we have to be called
+ before reload, or struct_equiv_block_eq needs to add register scavenging
+ code to allocate input_reg after reload. */
+ if (info.input_reg)
+ {
+ emit_insn_before (gen_move_insn (info.input_reg, info.x_input),
+ x_active);
+ emit_insn_before (gen_move_insn (info.input_reg, info.y_input),
+ y_active);
+ }
+
+ for (i = 0; i < info.cur.local_count; i++)
+ if (info.local_rvalue[i])
+ emit_insn_before (gen_move_insn (info.x_local[i], info.y_local[i]),
+ y_active);
/* Here we know that the insns in the end of SRC1 which are common with SRC2
will be deleted.
@@ -1265,30 +1335,36 @@ try_crossjump_to_edge (int mode, edge e1, edge e2)
/* Avoid splitting if possible. We must always split when SRC2 has
EH predecessor edges, or we may end up with basic blocks with both
normal and EH predecessor edges. */
- if (newpos2 == BB_HEAD (src2)
+ if (info.cur.x_start == BB_HEAD (src2)
&& !(EDGE_PRED (src2, 0)->flags & EDGE_EH))
redirect_to = src2;
else
{
- if (newpos2 == BB_HEAD (src2))
+ if (info.cur.x_start == BB_HEAD (src2))
{
/* Skip possible basic block header. */
- if (LABEL_P (newpos2))
- newpos2 = NEXT_INSN (newpos2);
- if (NOTE_P (newpos2))
- newpos2 = NEXT_INSN (newpos2);
+ if (LABEL_P (info.cur.x_start))
+ info.cur.x_start = NEXT_INSN (info.cur.x_start);
+ if (NOTE_P (info.cur.x_start))
+ info.cur.x_start = NEXT_INSN (info.cur.x_start);
}
if (dump_file)
fprintf (dump_file, "Splitting bb %i before %i insns\n",
src2->index, nmatch);
- redirect_to = split_block (src2, PREV_INSN (newpos2))->dest;
+ redirect_to = split_block (src2, PREV_INSN (info.cur.x_start))->dest;
+ COPY_REG_SET (info.y_block->il.rtl->global_live_at_end,
+ info.x_block->il.rtl->global_live_at_end);
}
if (dump_file)
- fprintf (dump_file,
- "Cross jumping from bb %i to bb %i; %i common insns\n",
- src1->index, src2->index, nmatch);
+ {
+ fprintf (dump_file, "Cross jumping from bb %i to bb %i; %i common insns",
+ src1->index, src2->index, nmatch);
+ if (info.cur.local_count)
+ fprintf (dump_file, ", %i local registers", info.cur.local_count);
+ fprintf (dump_file, "\n");
+ }
redirect_to->count += src1->count;
redirect_to->frequency += src1->frequency;
@@ -1352,14 +1428,7 @@ try_crossjump_to_edge (int mode, edge e1, edge e2)
/* Edit SRC1 to go to REDIRECT_TO at NEWPOS1. */
- /* Skip possible basic block header. */
- if (LABEL_P (newpos1))
- newpos1 = NEXT_INSN (newpos1);
-
- if (NOTE_P (newpos1))
- newpos1 = NEXT_INSN (newpos1);
-
- redirect_from = split_block (src1, PREV_INSN (newpos1))->src;
+ redirect_from = split_block (src1, PREV_INSN (y_active))->src;
to_remove = single_succ (redirect_from);
redirect_edge_and_branch_force (single_succ_edge (redirect_from), redirect_to);