/* 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);
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.
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)
+ if (EDGE_COUNT (cbranch_block->succs) != 2)
return false;
/* Verify that we've got a normal conditional branch at the end
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
+ if (!single_pred_p (jump_block)
|| jump_block->next_bb == EXIT_BLOCK_PTR
|| !FORWARDER_BLOCK_P (jump_block))
return false;
- jump_dest_block = jump_block->succ->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
want to extend this code to tablejumps and others. */
- if (!e->src->succ->succ_next || e->src->succ->succ_next->succ_next)
+ if (EDGE_COUNT (e->src->succs) != 2)
return NULL;
- if (!b->succ || !b->succ->succ_next || b->succ->succ_next->succ_next)
+ 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, goto failed_exit;);
+ 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;
}
try_forward_edges (int mode, basic_block b)
{
bool changed = false;
- edge e, next, *threaded_edges = NULL;
+ edge_iterator ei;
+ edge e, *threaded_edges = NULL;
/* 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
- && 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 (e = b->succ; e; e = next)
+ for (ei = ei_start (b->succs); (e = ei_safe_edge (ei)); )
{
basic_block target, first;
int counter;
int nthreaded_edges = 0;
bool may_thread = first_pass | (b->flags & BB_DIRTY);
- next = e->succ_next;
-
/* Skip complex edges because we don't know how to update them.
Still handle fallthru edges, as we can succeed to forward fallthru
edge to the same place as the branch edge of conditional branch
and turn conditional branch to an unconditional branch. */
if (e->flags & EDGE_COMPLEX)
- continue;
+ {
+ ei_next (&ei);
+ continue;
+ }
target = first = e->dest;
counter = 0;
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)
- && !(target->succ->flags & EDGE_CROSSING)
- && target->succ->dest != EXIT_BLOCK_PTR)
+ && !(single_succ_edge (target)->flags & EDGE_CROSSING)
+ && single_succ (target) != EXIT_BLOCK_PTR)
{
/* Bypass trivial infinite loops. */
- if (target == target->succ->dest)
+ new_target = single_succ (target);
+ if (target == new_target)
counter = n_basic_blocks;
- new_target = target->succ->dest;
}
/* Allow to thread only over one edge at time to simplify updating
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)
+ if ((mode & CLEANUP_PRE_LOOP) && optimize && flag_loop_optimize)
{
- rtx insn = (target->succ->flags & EDGE_FALLTHRU
+ rtx insn = (EDGE_SUCC (target, 0)->flags & EDGE_FALLTHRU
? BB_HEAD (target) : prev_nonnote_insn (BB_END (target)));
if (!NOTE_P (insn))
fprintf (dump_file,
"Forwarding edge %i->%i to %i failed.\n",
b->index, e->dest->index, target->index);
+ ei_next (&ei);
continue;
}
/ 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 (first->succ->succ_next)
+ 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 = first->succ;
+ t = single_succ_edge (first);
}
t->count -= edge_count;
while (first != target);
changed = true;
+ continue;
}
+ ei_next (&ei);
}
if (threaded_edges)
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;
edge tmp_edge, b_fallthru_edge;
bool c_has_outgoing_fallthru;
bool b_has_incoming_fallthru;
+ edge_iterator ei;
/* Avoid overactive code motion, as the forwarder blocks should be
eliminated by edge redirection instead. One exception might have
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)
+ FOR_EACH_EDGE (tmp_edge, ei, c->succs)
if (tmp_edge->flags & EDGE_FALLTHRU)
break;
c_has_outgoing_fallthru = (tmp_edge != NULL);
- for (tmp_edge = b->pred; tmp_edge; tmp_edge = tmp_edge->pred_next)
+ FOR_EACH_EDGE (tmp_edge, ei, b->preds)
if (tmp_edge->flags & EDGE_FALLTHRU)
break;
MEM_ATTRS (x) = 0;
else
{
+ rtx mem_size;
+
if (MEM_ALIAS_SET (x) != MEM_ALIAS_SET (y))
{
set_mem_alias_set (x, 0);
set_mem_offset (x, 0);
set_mem_offset (y, 0);
}
-
- set_mem_size (x, GEN_INT (MAX (INTVAL (MEM_SIZE (x)),
- INTVAL (MEM_SIZE (y)))));
- set_mem_size (y, MEM_SIZE (x));
+
+ if (!MEM_SIZE (x))
+ mem_size = NULL_RTX;
+ else if (!MEM_SIZE (y))
+ mem_size = NULL_RTX;
+ else
+ mem_size = GEN_INT (MAX (INTVAL (MEM_SIZE (x)),
+ INTVAL (MEM_SIZE (y))));
+ set_mem_size (x, mem_size);
+ set_mem_size (y, mem_size);
set_mem_align (x, MIN (MEM_ALIGN (x), MEM_ALIGN (y)));
set_mem_align (y, MEM_ALIGN (x));
int nehedges1 = 0, nehedges2 = 0;
edge fallthru1 = 0, fallthru2 = 0;
edge e1, e2;
+ edge_iterator ei;
/* If BB1 has only one successor, we may be looking at either an
unconditional jump, or a fake edge to exit. */
- if (bb1->succ && !bb1->succ->succ_next
- && (bb1->succ->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 (bb2->succ && !bb2->succ->succ_next
- && (bb2->succ->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
edges are crossed. */
- if (bb1->succ
- && bb1->succ->succ_next
- && !bb1->succ->succ_next->succ_next
+ if (EDGE_COUNT (bb1->succs) == 2
&& any_condjump_p (BB_END (bb1))
&& onlyjump_p (BB_END (bb1)))
{
rtx set1, set2, cond1, cond2;
enum rtx_code code1, code2;
- if (!bb2->succ
- || !bb2->succ->succ_next
- || bb2->succ->succ_next->succ_next
+ if (EDGE_COUNT (bb2->succs) != 2
|| !any_condjump_p (BB_END (bb2))
|| !onlyjump_p (BB_END (bb2)))
return false;
/* Get around possible forwarders on fallthru edges. Other cases
should be optimized out already. */
if (FORWARDER_BLOCK_P (f1->dest))
- f1 = f1->dest->succ;
+ f1 = single_succ_edge (f1->dest);
if (FORWARDER_BLOCK_P (f2->dest))
- f2 = f2->dest->succ;
+ 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 to 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. */
{
return false;
}
}
-#endif
/* First ensure that the instructions match. There may be many outgoing
edges so this test is generally cheaper. */
/* Search the outgoing edges, ensure that the counts do match, find possible
fallthru and exception handling edges since these needs more
validation. */
- for (e1 = bb1->succ, e2 = bb2->succ; e1 && e2;
- e1 = e1->succ_next, e2 = e2->succ_next)
+ if (EDGE_COUNT (bb1->succs) != EDGE_COUNT (bb2->succs))
+ return false;
+
+ FOR_EACH_EDGE (e1, ei, bb1->succs)
{
+ e2 = EDGE_SUCC (bb2, ei.index);
+
if (e1->flags & EDGE_EH)
nehedges1++;
}
/* If number of edges of various types does not match, fail. */
- if (e1 || e2
- || nehedges1 != nehedges2
+ if (nehedges1 != nehedges2
|| (fallthru1 != 0) != (fallthru2 != 0))
return false;
if (fallthru1)
{
basic_block d1 = (forwarder_block_p (fallthru1->dest)
- ? fallthru1->dest->succ->dest: fallthru1->dest);
+ ? single_succ (fallthru1->dest): fallthru1->dest);
basic_block d2 = (forwarder_block_p (fallthru2->dest)
- ? fallthru2->dest->succ->dest: fallthru2->dest);
+ ? single_succ (fallthru2->dest): fallthru2->dest);
if (d1 != d2)
return false;
basic_block redirect_to, redirect_from, to_remove;
rtx newpos1, newpos2;
edge s;
+ edge_iterator ei;
newpos1 = newpos2 = NULL_RTX;
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
+ if (single_pred_p (src1)
&& FORWARDER_BLOCK_P (src1))
- e1 = src1->pred, src1 = e1->src;
+ e1 = single_pred_edge (src1), src1 = e1->src;
- if (src2->pred
- && !src2->pred->pred_next
+ if (single_pred_p (src2)
&& FORWARDER_BLOCK_P (src2))
- e2 = src2->pred, 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 (e1->dest->succ->dest))
+ && FORWARDER_BLOCK_P (single_succ (e1->dest)))
return false;
if (FORWARDER_BLOCK_P (e2->dest)
- && FORWARDER_BLOCK_P (e2->dest->succ->dest))
+ && FORWARDER_BLOCK_P (single_succ (e2->dest)))
return false;
/* Likewise with dead code (possibly newly created by the other optimizations
of cfg_cleanup). */
- if (!src1->pred || !src2->pred)
+ if (EDGE_COUNT (src1->preds) == 0 || EDGE_COUNT (src2->preds) == 0)
return false;
/* Look for the common insn sequence, part the first ... */
&& (newpos1 != BB_HEAD (src1)))
return false;
-#ifndef CASE_DROPS_THROUGH
/* 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))
redirect_to->flags |= BB_DIRTY;
/* Recompute the frequencies and counts of outgoing edges. */
- for (s = redirect_to->succ; s; s = s->succ_next)
+ FOR_EACH_EDGE (s, ei, redirect_to->succs)
{
edge s2;
+ edge_iterator ei;
basic_block d = s->dest;
if (FORWARDER_BLOCK_P (d))
- d = d->succ->dest;
+ d = single_succ (d);
- for (s2 = src1->succ; ; s2 = s2->succ_next)
+ FOR_EACH_EDGE (s2, ei, src1->succs)
{
basic_block d2 = s2->dest;
if (FORWARDER_BLOCK_P (d2))
- d2 = d2->succ->dest;
+ d2 = single_succ (d2);
if (d == d2)
break;
}
into infinite loop. */
if (FORWARDER_BLOCK_P (s->dest))
{
- s->dest->succ->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))
{
- s2->dest->succ->count -= s2->count;
- if (s2->dest->succ->count < 0)
- s2->dest->succ->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 = redirect_from->succ->dest;
+ to_remove = single_succ (redirect_from);
- redirect_edge_and_branch_force (redirect_from->succ, 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;
}
static bool
try_crossjump_bb (int mode, basic_block bb)
{
- edge e, e2, nexte2, nexte, fallthru;
+ edge e, e2, fallthru;
bool changed;
- int n = 0, max;
+ unsigned max, ix, ix2;
+ basic_block ev, ev2;
+ edge_iterator ei;
/* Nothing to do if there is not at least two incoming edges. */
- if (!bb->pred || !bb->pred->pred_next)
+ 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
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 (bb->pred->src) != BB_PARTITION (bb->pred->pred_next->src)
- || (bb->pred->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
program. We'll try that combination first. */
fallthru = NULL;
max = PARAM_VALUE (PARAM_MAX_CROSSJUMP_EDGES);
- for (e = bb->pred; e ; e = e->pred_next, n++)
+
+ if (EDGE_COUNT (bb->preds) > max)
+ return false;
+
+ FOR_EACH_EDGE (e, ei, bb->preds)
{
if (e->flags & EDGE_FALLTHRU)
- fallthru = e;
- if (n > max)
- return false;
+ fallthru = e;
}
changed = false;
- for (e = bb->pred; e; e = nexte)
+ for (ix = 0, ev = bb; ix < EDGE_COUNT (ev->preds); )
{
- nexte = e->pred_next;
+ e = EDGE_PRED (ev, ix);
+ ix++;
/* As noted above, first try with the fallthru predecessor. */
if (fallthru)
if (try_crossjump_to_edge (mode, e, fallthru))
{
changed = true;
- nexte = bb->pred;
+ ix = 0;
+ ev = bb;
continue;
}
}
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)
+ if (EDGE_SUCC (e->src, 0) != e)
continue;
- for (e2 = bb->pred; e2; e2 = nexte2)
+ for (ix2 = 0, ev2 = bb; ix2 < EDGE_COUNT (ev2->preds); )
{
- nexte2 = e2->pred_next;
+ e2 = EDGE_PRED (ev2, ix2);
+ ix2++;
if (e2 == e)
continue;
if (try_crossjump_to_edge (mode, e, e2))
{
changed = true;
- nexte = bb->pred;
+ ev2 = bb;
+ ix = 0;
break;
}
}
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;
bool changed_here = false;
/* Delete trivially dead basic blocks. */
- while (b->pred == NULL)
+ while (EDGE_COUNT (b->preds) == 0)
{
c = b->prev_bb;
if (dump_file)
}
/* Remove code labels no longer used. */
- if (b->pred->pred_next == NULL
- && (b->pred->flags & EDGE_FALLTHRU)
- && !(b->pred->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). */
- && (b->pred->src == ENTRY_BLOCK_PTR
- || !JUMP_P (BB_END (b->pred->src))
+ && (single_pred (b) == ENTRY_BLOCK_PTR
+ || !JUMP_P (BB_END (single_pred (b)))
|| ! label_is_jump_target_p (BB_HEAD (b),
- BB_END (b->pred->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)
- && b->pred->pred_next == NULL
- && (b->pred->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. */
- && (b->succ->flags & EDGE_FALLTHRU)
+ && (single_succ_edge (b)->flags & EDGE_FALLTHRU)
&& n_basic_blocks > 1)
{
if (dump_file)
b->index);
c = b->prev_bb == ENTRY_BLOCK_PTR ? b->next_bb : b->prev_bb;
- redirect_edge_succ_nodup (b->pred, b->succ->dest);
+ redirect_edge_succ_nodup (single_pred_edge (b),
+ single_succ (b));
delete_basic_block (b);
changed = true;
b = c;
}
- if ((s = b->succ) != NULL
- && s->succ_next == NULL
+ if (single_succ_p (b)
+ && (s = single_succ_edge (b))
&& !(s->flags & EDGE_COMPLEX)
&& (c = s->dest) != EXIT_BLOCK_PTR
- && c->pred->pred_next == NULL
+ && 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 (b->succ
- && ! b->succ->succ_next
- && b->succ->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 (b->succ, b->succ->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 (bb->succ
- && !bb->succ->succ_next
- && can_merge_blocks_p (bb, bb->succ->dest))
+ if (single_succ_p (bb)
+ && can_merge_blocks_p (bb, single_succ (bb)))
{
/* Merge the blocks and retry. */
- merge_blocks (bb, bb->succ->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);
+ 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 (dump_file);
+}
+
+
+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 */
+};
+
+