/* Control flow optimization code for GNU compiler.
Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
This file is part of GCC.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING. If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA. */
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA. */
/* This file contains optimizer of the control flow. The main entry point is
cleanup_cfg. Following optimizations are performed:
#include "tm.h"
#include "rtl.h"
#include "hard-reg-set.h"
-#include "basic-block.h"
+#include "regs.h"
#include "timevar.h"
#include "output.h"
#include "insn-config.h"
#include "params.h"
#include "tm_p.h"
#include "target.h"
-#include "regs.h"
#include "cfglayout.h"
#include "emit-rtl.h"
+#include "tree-pass.h"
+#include "cfgloop.h"
+#include "expr.h"
-/* cleanup_cfg maintains following flags for each basic block. */
-
-enum bb_flags
-{
- /* Set if BB is the forwarder block to avoid too many
- forwarder_block_p calls. */
- BB_FORWARDER_BLOCK = 1,
- BB_NONTHREADABLE_BLOCK = 2
-};
-
-#define BB_FLAGS(BB) (enum bb_flags) (BB)->aux
-#define BB_SET_FLAG(BB, FLAG) \
- (BB)->aux = (void *) (long) ((enum bb_flags) (BB)->aux | (FLAG))
-#define BB_CLEAR_FLAG(BB, FLAG) \
- (BB)->aux = (void *) (long) ((enum bb_flags) (BB)->aux & ~(FLAG))
-
-#define FORWARDER_BLOCK_P(BB) (BB_FLAGS (BB) & BB_FORWARDER_BLOCK)
-
+#define FORWARDER_BLOCK_P(BB) ((BB)->flags & BB_FORWARDER_BLOCK)
+
/* Set to true when we are running first pass of try_optimize_cfg loop. */
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 int flow_find_cross_jump (int, basic_block, basic_block, rtx *, rtx *);
-static bool insns_match_p (int, rtx, rtx);
+static bool old_insns_match_p (int, rtx, rtx);
static void merge_blocks_move_predecessor_nojumps (basic_block, basic_block);
static void merge_blocks_move_successor_nojumps (basic_block, basic_block);
return;
if (forwarder_block_p (bb))
- BB_SET_FLAG (bb, BB_FORWARDER_BLOCK);
+ bb->flags |= BB_FORWARDER_BLOCK;
}
/* Recompute forwarder flag after block has been modified. */
update_forwarder_flag (basic_block bb)
{
if (forwarder_block_p (bb))
- BB_SET_FLAG (bb, BB_FORWARDER_BLOCK);
+ bb->flags |= BB_FORWARDER_BLOCK;
else
- BB_CLEAR_FLAG (bb, BB_FORWARDER_BLOCK);
+ bb->flags &= ~BB_FORWARDER_BLOCK;
}
\f
/* Simplify a conditional jump around an unconditional jump.
be the last block in the function, and must contain just the
unconditional jump. */
jump_block = cbranch_fallthru_edge->dest;
- if (EDGE_COUNT (jump_block->preds) >= 2
+ if (!single_pred_p (jump_block)
|| jump_block->next_bb == EXIT_BLOCK_PTR
|| !FORWARDER_BLOCK_P (jump_block))
return false;
- jump_dest_block = EDGE_SUCC (jump_block, 0)->dest;
+ jump_dest_block = single_succ (jump_block);
/* If we are partitioning hot/cold basic blocks, we don't want to
mess up unconditional or indirect jumps that cross between hot
partition boundaries). See the comments at the top of
bb-reorder.c:partition_hot_cold_basic_blocks for complete details. */
- if (flag_reorder_blocks_and_partition
- && (BB_PARTITION (jump_block) != BB_PARTITION (jump_dest_block)
- || (cbranch_jump_edge->flags & EDGE_CROSSING)))
+ if (BB_PARTITION (jump_block) != BB_PARTITION (jump_dest_block)
+ || (cbranch_jump_edge->flags & EDGE_CROSSING))
return false;
/* The conditional branch must target the block after the
rtx set1, set2, cond1, cond2, insn;
enum rtx_code code1, code2, reversed_code2;
bool reverse1 = false;
- int i;
+ unsigned i;
regset nonequal;
bool failed = false;
reg_set_iterator rsi;
- if (BB_FLAGS (b) & BB_NONTHREADABLE_BLOCK)
+ if (b->flags & BB_NONTHREADABLE_BLOCK)
return NULL;
/* At the moment, we do handle only conditional jumps, but later we may
return NULL;
if (EDGE_COUNT (b->succs) != 2)
{
- BB_SET_FLAG (b, BB_NONTHREADABLE_BLOCK);
+ b->flags |= BB_NONTHREADABLE_BLOCK;
return NULL;
}
if (!any_condjump_p (BB_END (b)) || !onlyjump_p (BB_END (b)))
{
- BB_SET_FLAG (b, BB_NONTHREADABLE_BLOCK);
+ b->flags |= BB_NONTHREADABLE_BLOCK;
return NULL;
}
insn = NEXT_INSN (insn))
if (INSN_P (insn) && side_effects_p (PATTERN (insn)))
{
- BB_SET_FLAG (b, BB_NONTHREADABLE_BLOCK);
+ b->flags |= BB_NONTHREADABLE_BLOCK;
return NULL;
}
cselib_init (false);
/* First process all values computed in the source basic block. */
- for (insn = NEXT_INSN (BB_HEAD (e->src)); insn != NEXT_INSN (BB_END (e->src));
+ for (insn = NEXT_INSN (BB_HEAD (e->src));
+ insn != NEXT_INSN (BB_END (e->src));
insn = NEXT_INSN (insn))
if (INSN_P (insn))
cselib_process_insn (insn);
- nonequal = BITMAP_XMALLOC();
+ nonequal = BITMAP_ALLOC (NULL);
CLEAR_REG_SET (nonequal);
/* Now assume that we've continued by the edge E to B and continue
processing as if it were same basic block.
Our goal is to prove that whole block is an NOOP. */
- for (insn = NEXT_INSN (BB_HEAD (b)); insn != NEXT_INSN (BB_END (b)) && !failed;
+ for (insn = NEXT_INSN (BB_HEAD (b));
+ insn != NEXT_INSN (BB_END (b)) && !failed;
insn = NEXT_INSN (insn))
{
if (INSN_P (insn))
if (GET_CODE (pat) == PARALLEL)
{
- for (i = 0; i < XVECLEN (pat, 0); i++)
+ for (i = 0; i < (unsigned)XVECLEN (pat, 0); i++)
failed |= mark_effect (XVECEXP (pat, 0, i), nonequal);
}
else
have life information in cfg_cleanup. */
if (failed)
{
- BB_SET_FLAG (b, BB_NONTHREADABLE_BLOCK);
+ b->flags |= BB_NONTHREADABLE_BLOCK;
goto failed_exit;
}
/* In case liveness information is available, we need to prove equivalence
only of the live values. */
if (mode & CLEANUP_UPDATE_LIFE)
- AND_REG_SET (nonequal, b->global_live_at_end);
+ AND_REG_SET (nonequal, b->il.rtl->global_live_at_end);
EXECUTE_IF_SET_IN_REG_SET (nonequal, 0, i, rsi)
goto failed_exit;
- BITMAP_XFREE (nonequal);
+ BITMAP_FREE (nonequal);
cselib_finish ();
if ((comparison_dominates_p (code1, code2) != 0)
!= (XEXP (SET_SRC (set2), 1) == pc_rtx))
return FALLTHRU_EDGE (b);
failed_exit:
- BITMAP_XFREE (nonequal);
+ BITMAP_FREE (nonequal);
cselib_finish ();
return NULL;
}
partition boundaries). See the comments at the top of
bb-reorder.c:partition_hot_cold_basic_blocks for complete details. */
- if (flag_reorder_blocks_and_partition
- && find_reg_note (BB_END (b), REG_CROSSING_JUMP, NULL_RTX))
+ if (find_reg_note (BB_END (b), REG_CROSSING_JUMP, NULL_RTX))
return false;
for (ei = ei_start (b->succs); (e = ei_safe_edge (ei)); )
}
target = first = e->dest;
- counter = 0;
+ counter = NUM_FIXED_BLOCKS;
/* If we are partitioning hot/cold basic_blocks, we don't want to mess
up jumps that cross between hot/cold sections.
bb-reorder.c:partition_hot_cold_basic_blocks for complete
details. */
- if (flag_reorder_blocks_and_partition
- && first != EXIT_BLOCK_PTR
+ if (first != EXIT_BLOCK_PTR
&& find_reg_note (BB_END (first), REG_CROSSING_JUMP, NULL_RTX))
return false;
may_thread |= target->flags & BB_DIRTY;
if (FORWARDER_BLOCK_P (target)
- && !(EDGE_SUCC (target, 0)->flags & EDGE_CROSSING)
- && EDGE_SUCC (target, 0)->dest != EXIT_BLOCK_PTR)
+ && !(single_succ_edge (target)->flags & EDGE_CROSSING)
+ && single_succ (target) != EXIT_BLOCK_PTR)
{
/* Bypass trivial infinite loops. */
- if (target == EDGE_SUCC (target, 0)->dest)
+ new_target = single_succ (target);
+ if (target == new_target)
counter = n_basic_blocks;
- new_target = EDGE_SUCC (target, 0)->dest;
}
/* Allow to thread only over one edge at time to simplify updating
if (t)
{
if (!threaded_edges)
- threaded_edges = xmalloc (sizeof (*threaded_edges)
- * n_basic_blocks);
+ threaded_edges = XNEWVEC (edge, n_basic_blocks);
else
{
int i;
if (t->dest == b)
break;
- gcc_assert (nthreaded_edges < n_basic_blocks);
+ gcc_assert (nthreaded_edges < n_basic_blocks - NUM_FIXED_BLOCKS);
threaded_edges[nthreaded_edges++] = t;
new_target = t->dest;
if (!new_target)
break;
- /* Avoid killing of loop pre-headers, as it is the place loop
- optimizer wants to hoist code to.
-
- For fallthru forwarders, the LOOP_BEG note must appear between
- the header of block and CODE_LABEL of the loop, for non forwarders
- it must appear before the JUMP_INSN. */
- if ((mode & CLEANUP_PRE_LOOP) && optimize)
- {
- rtx insn = (EDGE_SUCC (target, 0)->flags & EDGE_FALLTHRU
- ? BB_HEAD (target) : prev_nonnote_insn (BB_END (target)));
-
- if (!NOTE_P (insn))
- insn = NEXT_INSN (insn);
-
- for (; insn && !LABEL_P (insn) && !INSN_P (insn);
- insn = NEXT_INSN (insn))
- if (NOTE_P (insn)
- && NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG)
- break;
-
- if (NOTE_P (insn))
- break;
-
- /* Do not clean up branches to just past the end of a loop
- at this time; it can mess up the loop optimizer's
- recognition of some patterns. */
-
- insn = PREV_INSN (BB_HEAD (target));
- if (insn && NOTE_P (insn)
- && NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END)
- break;
- }
-
counter++;
target = new_target;
threaded |= new_target_threaded;
/ REG_BR_PROB_BASE);
if (!FORWARDER_BLOCK_P (b) && forwarder_block_p (b))
- BB_SET_FLAG (b, BB_FORWARDER_BLOCK);
+ b->flags |= BB_FORWARDER_BLOCK;
do
{
edge t;
- if (EDGE_COUNT (first->succs) > 1)
+ if (!single_succ_p (first))
{
gcc_assert (n < nthreaded_edges);
t = threaded_edges [n++];
if (n < nthreaded_edges
&& first == threaded_edges [n]->src)
n++;
- t = EDGE_SUCC (first, 0);
+ t = single_succ_edge (first);
}
t->count -= edge_count;
partition boundaries). See the comments at the top of
bb-reorder.c:partition_hot_cold_basic_blocks for complete details. */
- if (flag_reorder_blocks_and_partition
- && (BB_PARTITION (a) != BB_PARTITION (b)
- || find_reg_note (BB_END (a), REG_CROSSING_JUMP, NULL_RTX)))
+ if (BB_PARTITION (a) != BB_PARTITION (b))
return;
barrier = next_nonnote_insn (BB_END (a));
partition boundaries). See the comments at the top of
bb-reorder.c:partition_hot_cold_basic_blocks for complete details. */
- if (flag_reorder_blocks_and_partition
- && (find_reg_note (BB_END (a), REG_CROSSING_JUMP, NULL_RTX)
- || BB_PARTITION (a) != BB_PARTITION (b)))
+ if (BB_PARTITION (a) != BB_PARTITION (b))
return;
real_b_end = BB_END (b);
partition boundaries). See the comments at the top of
bb-reorder.c:partition_hot_cold_basic_blocks for complete details. */
- if (flag_reorder_blocks_and_partition
- && (find_reg_note (BB_END (b), REG_CROSSING_JUMP, NULL_RTX)
- || find_reg_note (BB_END (c), REG_CROSSING_JUMP, NULL_RTX)
- || BB_PARTITION (b) != BB_PARTITION (c)))
+ if (BB_PARTITION (b) != BB_PARTITION (c))
return NULL;
/* Return true if I1 and I2 are equivalent and thus can be crossjumped. */
static bool
-insns_match_p (int mode ATTRIBUTE_UNUSED, rtx i1, rtx i2)
+old_insns_match_p (int mode ATTRIBUTE_UNUSED, rtx i1, rtx i2)
{
rtx p1, p2;
if (i1 == BB_HEAD (bb1) || i2 == BB_HEAD (bb2))
break;
- if (!insns_match_p (mode, i1, i2))
+ if (!old_insns_match_p (mode, i1, i2))
break;
merge_memattrs (i1, i2);
return ninsns;
}
+/* Return true iff the condbranches at the end of BB1 and BB2 match. */
+bool
+condjump_equiv_p (struct equiv_info *info, bool call_init)
+{
+ 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;
+
+ /* Get around possible forwarders on fallthru edges. Other cases
+ should be optimized out already. */
+ if (FORWARDER_BLOCK_P (f1->dest))
+ f1 = single_succ_edge (f1->dest);
+
+ if (FORWARDER_BLOCK_P (f2->dest))
+ f2 = single_succ_edge (f2->dest);
+
+ /* To simplify use of this function, return false if there are
+ unneeded forwarder blocks. These will get eliminated later
+ during cleanup_cfg. */
+ if (FORWARDER_BLOCK_P (f1->dest)
+ || FORWARDER_BLOCK_P (f2->dest)
+ || FORWARDER_BLOCK_P (b1->dest)
+ || FORWARDER_BLOCK_P (b2->dest))
+ return false;
+
+ if (f1->dest == f2->dest && b1->dest == b2->dest)
+ reverse = false;
+ else if (f1->dest == b2->dest && b1->dest == f2->dest)
+ reverse = true;
+ else
+ return false;
+
+ set1 = pc_set (BB_END (bb1));
+ set2 = pc_set (BB_END (bb2));
+ if ((XEXP (SET_SRC (set1), 1) == pc_rtx)
+ != (XEXP (SET_SRC (set2), 1) == pc_rtx))
+ reverse = !reverse;
+
+ 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));
+ else
+ code2 = GET_CODE (cond2);
+
+ 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. */
+ 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
+ we require the existing branches to have probabilities that are
+ roughly similar. */
+ if (match
+ && !optimize_size
+ && maybe_hot_bb_p (bb1)
+ && maybe_hot_bb_p (bb2))
+ {
+ int prob2;
+
+ if (b1->dest == b2->dest)
+ prob2 = b2->probability;
+ else
+ /* Do not use f2 probability as f2 may be forwarded. */
+ prob2 = REG_BR_PROB_BASE - b2->probability;
+
+ /* Fail if the difference in probabilities is greater than 50%.
+ This rules out two well-predicted branches with opposite
+ outcomes. */
+ if (abs (b1->probability - prob2) > REG_BR_PROB_BASE / 2)
+ {
+ if (dump_file)
+ fprintf (dump_file,
+ "Outcomes of branch in bb %i and %i differ too much (%i %i)\n",
+ bb1->index, bb2->index, b1->probability, prob2);
+
+ match = false;
+ }
+ }
+
+ if (dump_file && match)
+ 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.
/* If BB1 has only one successor, we may be looking at either an
unconditional jump, or a fake edge to exit. */
- if (EDGE_COUNT (bb1->succs) == 1
- && (EDGE_SUCC (bb1, 0)->flags & (EDGE_COMPLEX | EDGE_FAKE)) == 0
+ if (single_succ_p (bb1)
+ && (single_succ_edge (bb1)->flags & (EDGE_COMPLEX | EDGE_FAKE)) == 0
&& (!JUMP_P (BB_END (bb1)) || simplejump_p (BB_END (bb1))))
- return (EDGE_COUNT (bb2->succs) == 1
- && (EDGE_SUCC (bb2, 0)->flags & (EDGE_COMPLEX | EDGE_FAKE)) == 0
+ return (single_succ_p (bb2)
+ && (single_succ_edge (bb2)->flags
+ & (EDGE_COMPLEX | EDGE_FAKE)) == 0
&& (!JUMP_P (BB_END (bb2)) || simplejump_p (BB_END (bb2))));
/* Match conditional jumps - this may get tricky when fallthru and branch
/* Get around possible forwarders on fallthru edges. Other cases
should be optimized out already. */
if (FORWARDER_BLOCK_P (f1->dest))
- f1 = EDGE_SUCC (f1->dest, 0);
+ f1 = single_succ_edge (f1->dest);
if (FORWARDER_BLOCK_P (f2->dest))
- f2 = EDGE_SUCC (f2->dest, 0);
+ f2 = single_succ_edge (f2->dest);
/* To simplify use of this function, return false if there are
unneeded forwarder blocks. These will get eliminated later
{
if (dump_file)
fprintf (dump_file,
- "Outcomes of branch in bb %i and %i differs too much (%i %i)\n",
+ "Outcomes of branch in bb %i and %i differ too much (%i %i)\n",
bb1->index, bb2->index, b1->probability, prob2);
return false;
/* Generic case - we are seeing a computed jump, table jump or trapping
instruction. */
-#ifndef CASE_DROPS_THROUGH
/* Check whether there are tablejumps in the end of BB1 and BB2.
Return true if they are identical. */
{
rr.update_label_nuses = false;
for_each_rtx (&BB_END (bb1), replace_label, &rr);
- match = insns_match_p (mode, BB_END (bb1), BB_END (bb2));
+ match = old_insns_match_p (mode, BB_END (bb1), BB_END (bb2));
if (dump_file && match)
fprintf (dump_file,
"Tablejumps in bb %i and %i match.\n",
return false;
}
}
-#endif
/* 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 (!old_insns_match_p (mode, BB_END (bb1), BB_END (bb2)))
return false;
/* Search the outgoing edges, ensure that the counts do match, find possible
if (fallthru1)
{
basic_block d1 = (forwarder_block_p (fallthru1->dest)
- ? EDGE_SUCC (fallthru1->dest, 0)->dest: fallthru1->dest);
+ ? single_succ (fallthru1->dest): fallthru1->dest);
basic_block d2 = (forwarder_block_p (fallthru2->dest)
- ? EDGE_SUCC (fallthru2->dest, 0)->dest: fallthru2->dest);
+ ? single_succ (fallthru2->dest): fallthru2->dest);
if (d1 != d2)
return false;
return false;
}
- /* We don't need to match the rest of edges as above checks should be enough
- to ensure that they are equivalent. */
+ /* The same checks as in try_crossjump_to_edge. It is required for RTL
+ version of sequence abstraction. */
+ FOR_EACH_EDGE (e1, ei, bb2->succs)
+ {
+ edge e2;
+ edge_iterator ei;
+ basic_block d1 = e1->dest;
+
+ if (FORWARDER_BLOCK_P (d1))
+ d1 = EDGE_SUCC (d1, 0)->dest;
+
+ FOR_EACH_EDGE (e2, ei, bb1->succs)
+ {
+ basic_block d2 = e2->dest;
+ if (FORWARDER_BLOCK_P (d2))
+ d2 = EDGE_SUCC (d2, 0)->dest;
+ if (d1 == d2)
+ break;
+ }
+
+ if (!e2)
+ return false;
+ }
+
return true;
}
+/* Returns true if BB basic block has a preserve label. */
+
+static bool
+block_has_preserve_label (basic_block bb)
+{
+ return (bb
+ && block_label (bb)
+ && LABEL_PRESERVE_P (block_label (bb)));
+}
+
/* 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. */
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 (EDGE_COUNT (src1->preds) == 1
+ if (single_pred_p (src1)
&& FORWARDER_BLOCK_P (src1))
- e1 = EDGE_PRED (src1, 0), src1 = e1->src;
+ e1 = single_pred_edge (src1), src1 = e1->src;
- if (EDGE_COUNT (src2->preds) == 1
+ if (single_pred_p (src2)
&& FORWARDER_BLOCK_P (src2))
- e2 = EDGE_PRED (src2, 0), src2 = e2->src;
+ e2 = single_pred_edge (src2), src2 = e2->src;
/* Nothing to do if we reach ENTRY, or a common source block. */
if (src1 == ENTRY_BLOCK_PTR || src2 == ENTRY_BLOCK_PTR)
/* Seeing more than 1 forwarder blocks would confuse us later... */
if (FORWARDER_BLOCK_P (e1->dest)
- && FORWARDER_BLOCK_P (EDGE_SUCC (e1->dest, 0)->dest))
+ && FORWARDER_BLOCK_P (single_succ (e1->dest)))
return false;
if (FORWARDER_BLOCK_P (e2->dest)
- && FORWARDER_BLOCK_P (EDGE_SUCC (e2->dest, 0)->dest))
+ && FORWARDER_BLOCK_P (single_succ (e2->dest)))
return false;
/* Likewise with dead code (possibly newly created by the other optimizations
&& (newpos1 != BB_HEAD (src1)))
return false;
-#ifndef CASE_DROPS_THROUGH
+ /* Avoid deleting preserve label when redirecting ABNORMAL edeges. */
+ if (block_has_preserve_label (e1->dest)
+ && (e1->flags & EDGE_ABNORMAL))
+ return false;
+
/* Here we know that the insns in the end of SRC1 which are common with SRC2
will be deleted.
If we have tablejumps in the end of SRC1 and SRC2
}
}
}
-#endif
- /* Avoid splitting if possible. */
- if (newpos2 == BB_HEAD (src2))
+ /* 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)
+ && !(EDGE_PRED (src2, 0)->flags & EDGE_EH))
redirect_to = src2;
else
{
+ if (newpos2 == 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 (dump_file)
fprintf (dump_file, "Splitting bb %i before %i insns\n",
src2->index, nmatch);
basic_block d = s->dest;
if (FORWARDER_BLOCK_P (d))
- d = EDGE_SUCC (d, 0)->dest;
+ d = single_succ (d);
FOR_EACH_EDGE (s2, ei, src1->succs)
{
basic_block d2 = s2->dest;
if (FORWARDER_BLOCK_P (d2))
- d2 = EDGE_SUCC (d2, 0)->dest;
+ d2 = single_succ (d2);
if (d == d2)
break;
}
into infinite loop. */
if (FORWARDER_BLOCK_P (s->dest))
{
- EDGE_SUCC (s->dest, 0)->count += s2->count;
+ single_succ_edge (s->dest)->count += s2->count;
s->dest->count += s2->count;
s->dest->frequency += EDGE_FREQUENCY (s);
}
if (FORWARDER_BLOCK_P (s2->dest))
{
- EDGE_SUCC (s2->dest, 0)->count -= s2->count;
- if (EDGE_SUCC (s2->dest, 0)->count < 0)
- EDGE_SUCC (s2->dest, 0)->count = 0;
+ single_succ_edge (s2->dest)->count -= s2->count;
+ if (single_succ_edge (s2->dest)->count < 0)
+ single_succ_edge (s2->dest)->count = 0;
s2->dest->count -= s2->count;
s2->dest->frequency -= EDGE_FREQUENCY (s);
if (s2->dest->frequency < 0)
newpos1 = NEXT_INSN (newpos1);
redirect_from = split_block (src1, PREV_INSN (newpos1))->src;
- to_remove = EDGE_SUCC (redirect_from, 0)->dest;
+ to_remove = single_succ (redirect_from);
- redirect_edge_and_branch_force (EDGE_SUCC (redirect_from, 0), redirect_to);
+ redirect_edge_and_branch_force (single_succ_edge (redirect_from), redirect_to);
delete_basic_block (to_remove);
update_forwarder_flag (redirect_from);
+ if (redirect_to != src2)
+ update_forwarder_flag (src2);
return true;
}
if (EDGE_COUNT (bb->preds) < 2)
return false;
+ /* Don't crossjump if this block ends in a computed jump,
+ unless we are optimizing for size. */
+ if (!optimize_size
+ && bb != EXIT_BLOCK_PTR
+ && computed_jump_p (BB_END (bb)))
+ return false;
+
/* If we are partitioning hot/cold basic blocks, we don't want to
mess up unconditional or indirect jumps that cross between hot
and cold sections.
partition boundaries). See the comments at the top of
bb-reorder.c:partition_hot_cold_basic_blocks for complete details. */
- if (flag_reorder_blocks_and_partition
- && (BB_PARTITION (EDGE_PRED (bb, 0)->src) != BB_PARTITION (EDGE_PRED (bb, 1)->src)
- || (EDGE_PRED (bb, 0)->flags & EDGE_CROSSING)))
+ if (BB_PARTITION (EDGE_PRED (bb, 0)->src) !=
+ BB_PARTITION (EDGE_PRED (bb, 1)->src)
+ || (EDGE_PRED (bb, 0)->flags & EDGE_CROSSING))
return false;
/* It is always cheapest to redirect a block that ends in a branch to
if (mode & CLEANUP_CROSSJUMP)
add_noreturn_fake_exit_edges ();
- FOR_EACH_BB (bb)
- update_forwarder_flag (bb);
-
if (mode & (CLEANUP_UPDATE_LIFE | CLEANUP_CROSSJUMP | CLEANUP_THREADING))
clear_bb_flags ();
+ FOR_EACH_BB (bb)
+ update_forwarder_flag (bb);
+
if (! targetm.cannot_modify_jumps_p ())
{
first_pass = true;
}
/* Remove code labels no longer used. */
- if (EDGE_COUNT (b->preds) == 1
- && (EDGE_PRED (b, 0)->flags & EDGE_FALLTHRU)
- && !(EDGE_PRED (b, 0)->flags & EDGE_COMPLEX)
+ if (single_pred_p (b)
+ && (single_pred_edge (b)->flags & EDGE_FALLTHRU)
+ && !(single_pred_edge (b)->flags & EDGE_COMPLEX)
&& LABEL_P (BB_HEAD (b))
/* If the previous block ends with a branch to this
block, we can't delete the label. Normally this
if CASE_DROPS_THRU, this can be a tablejump with
some element going to the same place as the
default (fallthru). */
- && (EDGE_PRED (b, 0)->src == ENTRY_BLOCK_PTR
- || !JUMP_P (BB_END (EDGE_PRED (b, 0)->src))
+ && (single_pred (b) == ENTRY_BLOCK_PTR
+ || !JUMP_P (BB_END (single_pred (b)))
|| ! label_is_jump_target_p (BB_HEAD (b),
- BB_END (EDGE_PRED (b, 0)->src))))
+ BB_END (single_pred (b)))))
{
rtx label = BB_HEAD (b);
/* If we fall through an empty block, we can remove it. */
if (!(mode & CLEANUP_CFGLAYOUT)
- && EDGE_COUNT (b->preds) == 1
- && (EDGE_PRED (b, 0)->flags & EDGE_FALLTHRU)
+ && single_pred_p (b)
+ && (single_pred_edge (b)->flags & EDGE_FALLTHRU)
&& !LABEL_P (BB_HEAD (b))
&& FORWARDER_BLOCK_P (b)
/* Note that forwarder_block_p true ensures that
there is a successor for this block. */
- && (EDGE_SUCC (b, 0)->flags & EDGE_FALLTHRU)
- && n_basic_blocks > 1)
+ && (single_succ_edge (b)->flags & EDGE_FALLTHRU)
+ && n_basic_blocks > NUM_FIXED_BLOCKS + 1)
{
if (dump_file)
fprintf (dump_file,
b->index);
c = b->prev_bb == ENTRY_BLOCK_PTR ? b->next_bb : b->prev_bb;
- redirect_edge_succ_nodup (EDGE_PRED (b, 0), EDGE_SUCC (b, 0)->dest);
+ redirect_edge_succ_nodup (single_pred_edge (b),
+ single_succ (b));
delete_basic_block (b);
changed = true;
b = c;
}
- if (EDGE_COUNT (b->succs) == 1
- && (s = EDGE_SUCC (b, 0))
+ if (single_succ_p (b)
+ && (s = single_succ_edge (b))
&& !(s->flags & EDGE_COMPLEX)
&& (c = s->dest) != EXIT_BLOCK_PTR
- && EDGE_COUNT (c->preds) == 1
+ && single_pred_p (c)
&& b != c)
{
/* When not in cfg_layout mode use code aware of reordering
non-trivial jump instruction without side-effects, we
can either delete the jump entirely, or replace it
with a simple unconditional jump. */
- if (EDGE_COUNT (b->succs) == 1
- && EDGE_SUCC (b, 0)->dest != EXIT_BLOCK_PTR
+ if (single_succ_p (b)
+ && single_succ (b) != EXIT_BLOCK_PTR
&& onlyjump_p (BB_END (b))
&& !find_reg_note (BB_END (b), REG_CROSSING_JUMP, NULL_RTX)
- && try_redirect_by_replacing_jump (EDGE_SUCC (b, 0), EDGE_SUCC (b, 0)->dest,
+ && try_redirect_by_replacing_jump (single_succ_edge (b),
+ single_succ (b),
(mode & CLEANUP_CFGLAYOUT) != 0))
{
update_forwarder_flag (b);
if (mode & CLEANUP_CROSSJUMP)
remove_fake_exit_edges ();
- clear_aux_for_blocks ();
+ FOR_ALL_BB (b)
+ b->flags &= ~(BB_FORWARDER_BLOCK | BB_NONTHREADABLE_BLOCK);
return changed_overall;
}
for (bb = ENTRY_BLOCK_PTR->next_bb; bb != EXIT_BLOCK_PTR; )
{
- if (EDGE_COUNT (bb->succs) == 1
- && can_merge_blocks_p (bb, EDGE_SUCC (bb, 0)->dest))
+ if (single_succ_p (bb)
+ && can_merge_blocks_p (bb, single_succ (bb)))
{
/* Merge the blocks and retry. */
- merge_blocks (bb, EDGE_SUCC (bb, 0)->dest);
+ merge_blocks (bb, single_succ (bb));
changed = true;
continue;
}
delete_dead_jumptables ();
}
- /* Kill the data we won't maintain. */
- free_EXPR_LIST_list (&label_value_list);
timevar_pop (TV_CLEANUP_CFG);
return changed;
}
+\f
+static void
+rest_of_handle_jump (void)
+{
+ delete_unreachable_blocks ();
+
+ if (cfun->tail_call_emit)
+ fixup_tail_calls ();
+}
+
+struct tree_opt_pass pass_jump =
+{
+ "sibling", /* name */
+ NULL, /* gate */
+ rest_of_handle_jump, /* execute */
+ NULL, /* sub */
+ NULL, /* next */
+ 0, /* static_pass_number */
+ TV_JUMP, /* tv_id */
+ 0, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ TODO_ggc_collect, /* todo_flags_start */
+ TODO_dump_func |
+ TODO_verify_flow, /* todo_flags_finish */
+ 'i' /* letter */
+};
+
+
+static void
+rest_of_handle_jump2 (void)
+{
+ /* Turn NOTE_INSN_EXPECTED_VALUE into REG_BR_PROB. Do this
+ before jump optimization switches branch directions. */
+ if (flag_guess_branch_prob)
+ expected_value_to_br_prob ();
+
+ delete_trivially_dead_insns (get_insns (), max_reg_num ());
+ reg_scan (get_insns (), max_reg_num ());
+ if (dump_file)
+ dump_flow_info (dump_file, dump_flags);
+ cleanup_cfg ((optimize ? CLEANUP_EXPENSIVE : 0) | CLEANUP_PRE_LOOP
+ | (flag_thread_jumps ? CLEANUP_THREADING : 0));
+
+ create_loop_notes ();
+
+ purge_line_number_notes ();
+
+ if (optimize)
+ cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_PRE_LOOP);
+
+ /* Jump optimization, and the removal of NULL pointer checks, may
+ have reduced the number of instructions substantially. CSE, and
+ future passes, allocate arrays whose dimensions involve the
+ maximum instruction UID, so if we can reduce the maximum UID
+ we'll save big on memory. */
+ renumber_insns ();
+}
+
+
+struct tree_opt_pass pass_jump2 =
+{
+ "jump", /* name */
+ NULL, /* gate */
+ rest_of_handle_jump2, /* execute */
+ NULL, /* sub */
+ NULL, /* next */
+ 0, /* static_pass_number */
+ TV_JUMP, /* tv_id */
+ 0, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ TODO_ggc_collect, /* todo_flags_start */
+ TODO_dump_func, /* todo_flags_finish */
+ 'j' /* letter */
+};
+
+