rtl.h (in_expr_list_p): New declaration.
* rtl.h (in_expr_list_p): New declaration. * rtlanal.c (in_expr_list_p): New function. * cfgcleanup.c: Reformatting and minor code rearrangement. * cfglayout.c, cfgloop.c, cfgrtl.c: Likewise. From-SVN: r48304
This commit is contained in:
parent
e88712b55b
commit
5f0d23589f
|
@ -1,3 +1,10 @@
|
|||
Mon Dec 24 10:24:59 2001 Richard Kenner <kenner@vlsi1.ultra.nyu.edu>
|
||||
|
||||
* rtl.h (in_expr_list_p): New declaration.
|
||||
* rtlanal.c (in_expr_list_p): New function.
|
||||
* cfgcleanup.c: Reformatting and minor code rearrangement.
|
||||
* cfglayout.c, cfgloop.c, cfgrtl.c: Likewise.
|
||||
|
||||
2001-12-23 Richard Henderson <rth@redhat.com>
|
||||
|
||||
PR c/5163:
|
||||
|
|
141
gcc/cfgcleanup.c
141
gcc/cfgcleanup.c
|
@ -47,21 +47,23 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
|||
#include "obstack.h"
|
||||
|
||||
/* cleanup_cfg maintains following flags for each basic block. */
|
||||
enum bb_flags {
|
||||
|
||||
enum bb_flags
|
||||
{
|
||||
/* Set if life info needs to be recomputed for given BB. */
|
||||
BB_UPDATE_LIFE = 1,
|
||||
/* Set if BB is the forwarder block to avoid too many
|
||||
forwarder_block_p calls. */
|
||||
BB_FORWARDER_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 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) & BB_FORWARDER_BLOCK)
|
||||
|
||||
static bool try_crossjump_to_edge PARAMS ((int, edge, edge));
|
||||
static bool try_crossjump_bb PARAMS ((int, basic_block));
|
||||
|
@ -96,6 +98,7 @@ notice_new_block (bb)
|
|||
{
|
||||
if (!bb)
|
||||
return;
|
||||
|
||||
BB_SET_FLAG (bb, BB_UPDATE_LIFE);
|
||||
if (forwarder_block_p (bb))
|
||||
BB_SET_FLAG (bb, BB_FORWARDER_BLOCK);
|
||||
|
@ -183,6 +186,7 @@ try_simplify_condjump (cbranch_block)
|
|||
|
||||
/* Attempt to prove that operation is NOOP using CSElib or mark the effect
|
||||
on register. Used by jump threading. */
|
||||
|
||||
static bool
|
||||
mark_effect (exp, nonequal)
|
||||
rtx exp;
|
||||
|
@ -196,6 +200,7 @@ mark_effect (exp, nonequal)
|
|||
if (REG_P (XEXP (exp, 0)))
|
||||
CLEAR_REGNO_REG_SET (nonequal, REGNO (XEXP (exp, 0)));
|
||||
return false;
|
||||
|
||||
case SET:
|
||||
if (rtx_equal_for_cselib_p (SET_DEST (exp), SET_SRC (exp)))
|
||||
return false;
|
||||
|
@ -203,6 +208,7 @@ mark_effect (exp, nonequal)
|
|||
return true;
|
||||
SET_REGNO_REG_SET (nonequal, REGNO (SET_SRC (exp)));
|
||||
return false;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
@ -281,10 +287,11 @@ thread_jump (mode, e, b)
|
|||
|
||||
nonequal = BITMAP_XMALLOC();
|
||||
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 (b->head); insn != b->end && !failed;
|
||||
insn = NEXT_INSN (insn))
|
||||
{
|
||||
|
@ -300,6 +307,7 @@ thread_jump (mode, e, b)
|
|||
else
|
||||
failed |= mark_effect (pat, nonequal);
|
||||
}
|
||||
|
||||
cselib_process_insn (insn);
|
||||
}
|
||||
|
||||
|
@ -340,7 +348,7 @@ try_forward_edges (mode, b)
|
|||
bool changed = false;
|
||||
edge e, next, threaded_edge;
|
||||
|
||||
for (e = b->succ; e ; e = next)
|
||||
for (e = b->succ; e; e = next)
|
||||
{
|
||||
basic_block target, first;
|
||||
int counter;
|
||||
|
@ -372,6 +380,7 @@ try_forward_edges (mode, b)
|
|||
counter = n_basic_blocks;
|
||||
new_target = target->succ->dest;
|
||||
}
|
||||
|
||||
/* Allow to thread only over one edge at time to simplify updating
|
||||
of probabilities. */
|
||||
else if ((mode & CLEANUP_THREADING) && !threaded)
|
||||
|
@ -383,6 +392,7 @@ try_forward_edges (mode, b)
|
|||
new_target_threaded = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!new_target)
|
||||
break;
|
||||
|
||||
|
@ -400,7 +410,7 @@ try_forward_edges (mode, b)
|
|||
if (GET_CODE (insn) != NOTE)
|
||||
insn = NEXT_INSN (insn);
|
||||
|
||||
for (;insn && GET_CODE (insn) != CODE_LABEL && !INSN_P (insn);
|
||||
for (; insn && GET_CODE (insn) != CODE_LABEL && !INSN_P (insn);
|
||||
insn = NEXT_INSN (insn))
|
||||
if (GET_CODE (insn) == NOTE
|
||||
&& NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG)
|
||||
|
@ -409,6 +419,7 @@ try_forward_edges (mode, b)
|
|||
if (GET_CODE (insn) == NOTE)
|
||||
break;
|
||||
}
|
||||
|
||||
counter++;
|
||||
target = new_target;
|
||||
threaded |= new_target_threaded;
|
||||
|
@ -438,10 +449,12 @@ try_forward_edges (mode, b)
|
|||
else if (!redirect_edge_and_branch (e, target))
|
||||
{
|
||||
if (rtl_dump_file)
|
||||
fprintf (rtl_dump_file, "Forwarding edge %i->%i to %i failed.\n",
|
||||
fprintf (rtl_dump_file,
|
||||
"Forwarding edge %i->%i to %i failed.\n",
|
||||
b->index, e->dest->index, target->index);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* We successfully forwarded the edge. Now update profile
|
||||
data: for each edge we traversed in the chain, remove
|
||||
the original edge's execution count. */
|
||||
|
@ -456,6 +469,7 @@ try_forward_edges (mode, b)
|
|||
do
|
||||
{
|
||||
edge t;
|
||||
|
||||
first->count -= edge_count;
|
||||
first->succ->count -= edge_count;
|
||||
first->frequency -= edge_frequency;
|
||||
|
@ -463,6 +477,7 @@ try_forward_edges (mode, b)
|
|||
t = threaded_edge;
|
||||
else
|
||||
t = first->succ;
|
||||
|
||||
first = t->dest;
|
||||
}
|
||||
while (first != target);
|
||||
|
@ -553,10 +568,8 @@ merge_blocks_move_predecessor_nojumps (a, b)
|
|||
BB_SET_FLAG (a, BB_UPDATE_LIFE);
|
||||
|
||||
if (rtl_dump_file)
|
||||
{
|
||||
fprintf (rtl_dump_file, "Moved block %d before %d and merged.\n",
|
||||
a->index, b->index);
|
||||
}
|
||||
fprintf (rtl_dump_file, "Moved block %d before %d and merged.\n",
|
||||
a->index, b->index);
|
||||
|
||||
/* Swap the records for the two blocks around. Although we are deleting B,
|
||||
A is now where B was and we want to compact the BB array from where
|
||||
|
@ -623,10 +636,8 @@ merge_blocks_move_successor_nojumps (a, b)
|
|||
BB_SET_FLAG (a, BB_UPDATE_LIFE);
|
||||
|
||||
if (rtl_dump_file)
|
||||
{
|
||||
fprintf (rtl_dump_file, "Moved block %d after %d and merged.\n",
|
||||
b->index, a->index);
|
||||
}
|
||||
fprintf (rtl_dump_file, "Moved block %d after %d and merged.\n",
|
||||
b->index, a->index);
|
||||
}
|
||||
|
||||
/* Attempt to merge basic blocks that are potentially non-adjacent.
|
||||
|
@ -660,13 +671,12 @@ merge_blocks (e, b, c, mode)
|
|||
update_forwarder_flag (b);
|
||||
|
||||
if (rtl_dump_file)
|
||||
{
|
||||
fprintf (rtl_dump_file, "Merged %d and %d without moving.\n",
|
||||
b->index, c->index);
|
||||
}
|
||||
fprintf (rtl_dump_file, "Merged %d and %d without moving.\n",
|
||||
b->index, c->index);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Otherwise we will need to move code around. Do that only if expensive
|
||||
transformations are allowed. */
|
||||
else if (mode & CLEANUP_EXPENSIVE)
|
||||
|
@ -689,11 +699,13 @@ merge_blocks (e, b, c, mode)
|
|||
for (tmp_edge = c->succ; tmp_edge; tmp_edge = tmp_edge->succ_next)
|
||||
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)
|
||||
if (tmp_edge->flags & EDGE_FALLTHRU)
|
||||
break;
|
||||
|
||||
b_has_incoming_fallthru = (tmp_edge != NULL);
|
||||
b_fallthru_edge = tmp_edge;
|
||||
|
||||
|
@ -714,6 +726,7 @@ merge_blocks (e, b, c, mode)
|
|||
if (b_has_incoming_fallthru)
|
||||
{
|
||||
basic_block bb;
|
||||
|
||||
if (b_fallthru_edge->src == ENTRY_BLOCK_PTR)
|
||||
return false;
|
||||
bb = force_nonfallthru (b_fallthru_edge);
|
||||
|
@ -722,9 +735,11 @@ merge_blocks (e, b, c, mode)
|
|||
else
|
||||
BB_SET_FLAG (b_fallthru_edge->src, BB_UPDATE_LIFE);
|
||||
}
|
||||
|
||||
merge_blocks_move_predecessor_nojumps (b, c);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -825,8 +840,10 @@ insns_match_p (mode, i1, i2)
|
|||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -857,6 +874,7 @@ flow_find_cross_jump (mode, bb1, bb2, f1, f2)
|
|||
last1 = i1;
|
||||
i1 = PREV_INSN (i1);
|
||||
}
|
||||
|
||||
i2 = bb2->end;
|
||||
if (onlyjump_p (i2)
|
||||
|| (returnjump_p (i2) && !side_effects_p (PATTERN (i2))))
|
||||
|
@ -873,6 +891,7 @@ flow_find_cross_jump (mode, bb1, bb2, f1, f2)
|
|||
/* Ignore notes. */
|
||||
while (!active_insn_p (i1) && i1 != bb1->head)
|
||||
i1 = PREV_INSN (i1);
|
||||
|
||||
while (!active_insn_p (i2) && i2 != bb2->head)
|
||||
i2 = PREV_INSN (i2);
|
||||
|
||||
|
@ -905,18 +924,16 @@ flow_find_cross_jump (mode, bb1, bb2, f1, f2)
|
|||
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--;
|
||||
}
|
||||
/* Don't allow the insn after a compare to be shared by
|
||||
cross-jumping unless the compare is also shared. */
|
||||
if (ninsns && reg_mentioned_p (cc0_rtx, last1) && ! sets_cc0_p (last1))
|
||||
last1 = afterlast1, last2 = afterlast2, ninsns--;
|
||||
#endif
|
||||
|
||||
/* Include preceding notes and labels in the cross-jump. One,
|
||||
|
@ -926,10 +943,13 @@ flow_find_cross_jump (mode, bb1, bb2, f1, f2)
|
|||
{
|
||||
while (last1 != bb1->head && !active_insn_p (PREV_INSN (last1)))
|
||||
last1 = PREV_INSN (last1);
|
||||
|
||||
if (last1 != bb1->head && GET_CODE (PREV_INSN (last1)) == CODE_LABEL)
|
||||
last1 = PREV_INSN (last1);
|
||||
|
||||
while (last2 != bb2->head && !active_insn_p (PREV_INSN (last2)))
|
||||
last2 = PREV_INSN (last2);
|
||||
|
||||
if (last2 != bb2->head && GET_CODE (PREV_INSN (last2)) == CODE_LABEL)
|
||||
last2 = PREV_INSN (last2);
|
||||
|
||||
|
@ -960,12 +980,8 @@ outgoing_edges_match (mode, bb1, bb2)
|
|||
unconditional jump, or a fake edge to exit. */
|
||||
if (bb1->succ && !bb1->succ->succ_next
|
||||
&& !(bb1->succ->flags & (EDGE_COMPLEX | EDGE_FAKE)))
|
||||
{
|
||||
if (! bb2->succ || bb2->succ->succ_next
|
||||
|| (bb2->succ->flags & (EDGE_COMPLEX | EDGE_FAKE)))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
return (bb2->succ && !bb2->succ->succ_next
|
||||
&& (bb2->succ->flags & (EDGE_COMPLEX | EDGE_FAKE)) == 0);
|
||||
|
||||
/* Match conditional jumps - this may get tricky when fallthru and branch
|
||||
edges are crossed. */
|
||||
|
@ -996,6 +1012,7 @@ outgoing_edges_match (mode, bb1, bb2)
|
|||
should be optimized out already. */
|
||||
if (FORWARDER_BLOCK_P (f1->dest))
|
||||
f1 = f1->dest->succ;
|
||||
|
||||
if (FORWARDER_BLOCK_P (f2->dest))
|
||||
f2 = f2->dest->succ;
|
||||
|
||||
|
@ -1028,6 +1045,7 @@ outgoing_edges_match (mode, bb1, bb2)
|
|||
code2 = reversed_comparison_code (cond2, bb2->end);
|
||||
else
|
||||
code2 = GET_CODE (cond2);
|
||||
|
||||
if (code2 == UNKNOWN)
|
||||
return false;
|
||||
|
||||
|
@ -1052,6 +1070,7 @@ outgoing_edges_match (mode, bb1, bb2)
|
|||
{
|
||||
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);
|
||||
|
||||
|
@ -1067,6 +1086,7 @@ outgoing_edges_match (mode, bb1, bb2)
|
|||
if (abs (prob1 - prob2) > REG_BR_PROB_BASE / 20)
|
||||
return false;
|
||||
}
|
||||
|
||||
else if (note1 || note2)
|
||||
return false;
|
||||
}
|
||||
|
@ -1096,19 +1116,20 @@ outgoing_edges_match (mode, bb1, bb2)
|
|||
{
|
||||
if (e1->flags & EDGE_EH)
|
||||
nehedges1++;
|
||||
|
||||
if (e2->flags & EDGE_EH)
|
||||
nehedges2++;
|
||||
|
||||
if (e1->flags & EDGE_FALLTHRU)
|
||||
fallthru1 = e1;
|
||||
if (e2->flags & EDGE_FALLTHRU)
|
||||
fallthru2 = e2;
|
||||
}
|
||||
|
||||
/* If number of edges of various types does not match, fail. */
|
||||
if (e1 || e2)
|
||||
return false;
|
||||
if (nehedges1 != nehedges2)
|
||||
return false;
|
||||
if ((fallthru1 != 0) != (fallthru2 != 0))
|
||||
if (e1 || e2
|
||||
|| nehedges1 != nehedges2
|
||||
|| (fallthru1 != 0) != (fallthru2 != 0))
|
||||
return false;
|
||||
|
||||
/* fallthru edges must be forwarded to the same destination. */
|
||||
|
@ -1118,17 +1139,21 @@ outgoing_edges_match (mode, bb1, bb2)
|
|||
? fallthru1->dest->succ->dest: fallthru1->dest);
|
||||
basic_block d2 = (forwarder_block_p (fallthru2->dest)
|
||||
? fallthru2->dest->succ->dest: fallthru2->dest);
|
||||
|
||||
if (d1 != d2)
|
||||
return false;
|
||||
}
|
||||
|
||||
/* In case we do have EH edges, ensure we are in the same region. */
|
||||
if (nehedges1)
|
||||
{
|
||||
rtx n1 = find_reg_note (bb1->end, REG_EH_REGION, 0);
|
||||
rtx n2 = find_reg_note (bb2->end, REG_EH_REGION, 0);
|
||||
|
||||
if (XEXP (n1, 0) != XEXP (n2, 0))
|
||||
return false;
|
||||
}
|
||||
|
||||
/* We don't need to match the rest of edges as above checks should be enought
|
||||
to ensure that they are equivalent. */
|
||||
return true;
|
||||
|
@ -1159,17 +1184,12 @@ try_crossjump_to_edge (mode, e1, e2)
|
|||
if (src1->pred
|
||||
&& !src1->pred->pred_next
|
||||
&& FORWARDER_BLOCK_P (src1))
|
||||
{
|
||||
e1 = src1->pred;
|
||||
src1 = e1->src;
|
||||
}
|
||||
e1 = src1->pred, src1 = e1->src;
|
||||
|
||||
if (src2->pred
|
||||
&& !src2->pred->pred_next
|
||||
&& FORWARDER_BLOCK_P (src2))
|
||||
{
|
||||
e2 = src2->pred;
|
||||
src2 = e2->src;
|
||||
}
|
||||
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)
|
||||
|
@ -1181,6 +1201,7 @@ try_crossjump_to_edge (mode, e1, e2)
|
|||
if (FORWARDER_BLOCK_P (e1->dest)
|
||||
&& FORWARDER_BLOCK_P (e1->dest->succ->dest))
|
||||
return false;
|
||||
|
||||
if (FORWARDER_BLOCK_P (e2->dest)
|
||||
&& FORWARDER_BLOCK_P (e2->dest->succ->dest))
|
||||
return false;
|
||||
|
@ -1226,6 +1247,7 @@ try_crossjump_to_edge (mode, e1, e2)
|
|||
|
||||
if (FORWARDER_BLOCK_P (d))
|
||||
d = d->succ->dest;
|
||||
|
||||
for (s2 = src1->succ; ; s2 = s2->succ_next)
|
||||
{
|
||||
basic_block d2 = s2->dest;
|
||||
|
@ -1234,6 +1256,7 @@ try_crossjump_to_edge (mode, e1, e2)
|
|||
if (d == d2)
|
||||
break;
|
||||
}
|
||||
|
||||
s->count += s2->count;
|
||||
|
||||
/* Take care to update possible forwarder blocks. We verified
|
||||
|
@ -1245,19 +1268,21 @@ try_crossjump_to_edge (mode, e1, e2)
|
|||
s->dest->count += s2->count;
|
||||
s->dest->frequency += EDGE_FREQUENCY (s);
|
||||
}
|
||||
|
||||
if (FORWARDER_BLOCK_P (s2->dest))
|
||||
{
|
||||
s2->dest->succ->count -= s2->count;
|
||||
s2->dest->count -= s2->count;
|
||||
s2->dest->frequency -= EDGE_FREQUENCY (s);
|
||||
}
|
||||
|
||||
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));
|
||||
s->probability
|
||||
= ((s->probability * redirect_to->frequency +
|
||||
s2->probability * src1->frequency)
|
||||
/ (redirect_to->frequency + src1->frequency));
|
||||
}
|
||||
|
||||
note = find_reg_note (redirect_to->end, REG_BR_PROB, 0);
|
||||
|
@ -1269,6 +1294,7 @@ try_crossjump_to_edge (mode, e1, e2)
|
|||
/* 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;
|
||||
|
@ -1409,7 +1435,6 @@ try_optimize_cfg (mode)
|
|||
/* Attempt to merge blocks as made possible by edge removal. If a block
|
||||
has only one successor, and the successor has only one predecessor,
|
||||
they may be combined. */
|
||||
|
||||
do
|
||||
{
|
||||
changed = false;
|
||||
|
@ -1431,6 +1456,7 @@ try_optimize_cfg (mode)
|
|||
c = BASIC_BLOCK (b->index - 1);
|
||||
if (rtl_dump_file)
|
||||
fprintf (rtl_dump_file, "Deleting block %i.\n", b->index);
|
||||
|
||||
flow_delete_block (b);
|
||||
changed = true;
|
||||
b = c;
|
||||
|
@ -1455,6 +1481,7 @@ try_optimize_cfg (mode)
|
|||
|| ! label_is_jump_target_p (b->head, b->pred->src->end)))
|
||||
{
|
||||
rtx label = b->head;
|
||||
|
||||
b->head = NEXT_INSN (b->head);
|
||||
delete_insn_chain (label, label);
|
||||
if (rtl_dump_file)
|
||||
|
@ -1475,6 +1502,7 @@ try_optimize_cfg (mode)
|
|||
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_nodup (b->pred, b->succ->dest);
|
||||
flow_delete_block (b);
|
||||
|
@ -1554,6 +1582,7 @@ try_optimize_cfg (mode)
|
|||
if ((mode & CLEANUP_UPDATE_LIFE) && changed_overall)
|
||||
{
|
||||
bool found = 0;
|
||||
|
||||
blocks = sbitmap_alloc (n_basic_blocks);
|
||||
sbitmap_zero (blocks);
|
||||
for (i = 0; i < n_basic_blocks; i++)
|
||||
|
@ -1562,12 +1591,14 @@ try_optimize_cfg (mode)
|
|||
found = 1;
|
||||
SET_BIT (blocks, i);
|
||||
}
|
||||
|
||||
if (found)
|
||||
update_life_info (blocks, UPDATE_LIFE_GLOBAL,
|
||||
PROP_DEATH_NOTES | PROP_SCAN_DEAD_CODE
|
||||
| PROP_KILL_DEAD_CODE);
|
||||
sbitmap_free (blocks);
|
||||
}
|
||||
|
||||
for (i = 0; i < n_basic_blocks; i++)
|
||||
BASIC_BLOCK (i)->aux = NULL;
|
||||
|
||||
|
|
269
gcc/cfglayout.c
269
gcc/cfglayout.c
|
@ -1,22 +1,22 @@
|
|||
/* Basic block reordering routines for the GNU compiler.
|
||||
Copyright (C) 2000, 2001 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GCC.
|
||||
This file is part of GCC.
|
||||
|
||||
GCC is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
GCC is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2, or (at your option) any later
|
||||
version.
|
||||
|
||||
GCC is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||
License for more details.
|
||||
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
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. */
|
||||
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. */
|
||||
|
||||
#include "config.h"
|
||||
#include "system.h"
|
||||
|
@ -30,9 +30,7 @@
|
|||
#include "cfglayout.h"
|
||||
|
||||
/* The contents of the current function definition are allocated
|
||||
in this obstack, and all are freed at the end of the function.
|
||||
For top-level functions, this is temporary_obstack.
|
||||
Separate obstacks are made for nested functions. */
|
||||
in this obstack, and all are freed at the end of the function. */
|
||||
|
||||
extern struct obstack flow_obstack;
|
||||
|
||||
|
@ -126,7 +124,7 @@ skip_insns_after_block (bb)
|
|||
if (bb->index + 1 != n_basic_blocks)
|
||||
next_head = BASIC_BLOCK (bb->index + 1)->head;
|
||||
|
||||
for (last_insn = insn = bb->end; (insn = NEXT_INSN (insn)); )
|
||||
for (last_insn = insn = bb->end; (insn = NEXT_INSN (insn)) != 0; )
|
||||
{
|
||||
if (insn == next_head)
|
||||
break;
|
||||
|
@ -172,30 +170,30 @@ skip_insns_after_block (bb)
|
|||
|
||||
break;
|
||||
}
|
||||
/* It is possible to hit contradicting sequence. For instance:
|
||||
|
||||
/* It is possible to hit contradictory sequence. For instance:
|
||||
|
||||
jump_insn
|
||||
NOTE_INSN_LOOP_BEG
|
||||
barrier
|
||||
|
||||
Where barrier belongs to jump_insn, but the note does not.
|
||||
This can be created by removing the basic block originally
|
||||
following NOTE_INSN_LOOP_BEG.
|
||||
Where barrier belongs to jump_insn, but the note does not. This can be
|
||||
created by removing the basic block originally following
|
||||
NOTE_INSN_LOOP_BEG. In such case reorder the notes. */
|
||||
|
||||
In such case reorder the notes. */
|
||||
for (insn = last_insn; insn != bb->end; insn = prev)
|
||||
{
|
||||
prev = PREV_INSN (insn);
|
||||
if (GET_CODE (insn) == NOTE)
|
||||
switch (NOTE_LINE_NUMBER (insn))
|
||||
{
|
||||
prev = PREV_INSN (insn);
|
||||
if (GET_CODE (insn) == NOTE)
|
||||
switch (NOTE_LINE_NUMBER (insn))
|
||||
{
|
||||
case NOTE_INSN_LOOP_END:
|
||||
case NOTE_INSN_BLOCK_END:
|
||||
case NOTE_INSN_DELETED:
|
||||
case NOTE_INSN_DELETED_LABEL:
|
||||
continue;
|
||||
continue;
|
||||
default:
|
||||
reorder_insns (insn, insn, last_insn);
|
||||
reorder_insns (insn, insn, last_insn);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -213,8 +211,7 @@ label_for_bb (bb)
|
|||
if (GET_CODE (label) != CODE_LABEL)
|
||||
{
|
||||
if (rtl_dump_file)
|
||||
fprintf (rtl_dump_file, "Emitting label for block %d\n",
|
||||
bb->index);
|
||||
fprintf (rtl_dump_file, "Emitting label for block %d\n", bb->index);
|
||||
|
||||
label = block_label (bb);
|
||||
if (bb->head == PREV_INSN (RBI (bb)->eff_head))
|
||||
|
@ -233,7 +230,7 @@ record_effective_endpoints ()
|
|||
rtx next_insn = get_insns ();
|
||||
int i;
|
||||
|
||||
for (i = 0; i < n_basic_blocks; ++i)
|
||||
for (i = 0; i < n_basic_blocks; i++)
|
||||
{
|
||||
basic_block bb = BASIC_BLOCK (i);
|
||||
rtx end;
|
||||
|
@ -243,32 +240,33 @@ record_effective_endpoints ()
|
|||
RBI (bb)->eff_end = end;
|
||||
next_insn = NEXT_INSN (end);
|
||||
}
|
||||
|
||||
function_tail_eff_head = next_insn;
|
||||
}
|
||||
|
||||
/* Return the next NOTE_INSN_BASIC_BLOCK after X. */
|
||||
|
||||
static rtx
|
||||
get_next_bb_note (x)
|
||||
rtx x;
|
||||
{
|
||||
while (x)
|
||||
{
|
||||
if (NOTE_INSN_BASIC_BLOCK_P (x))
|
||||
return x;
|
||||
x = NEXT_INSN (x);
|
||||
}
|
||||
for (; x; x = NEXT_INSN (x))
|
||||
if (NOTE_INSN_BASIC_BLOCK_P (x))
|
||||
return x;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Return the fist NOTE_INSN_BASIC_BLOCK before X. */
|
||||
|
||||
static rtx
|
||||
get_prev_bb_note (x)
|
||||
rtx x;
|
||||
{
|
||||
while (x)
|
||||
{
|
||||
if (NOTE_INSN_BASIC_BLOCK_P (x))
|
||||
return x;
|
||||
x = PREV_INSN (x);
|
||||
}
|
||||
for (; x; x = PREV_INSN (x))
|
||||
if (NOTE_INSN_BASIC_BLOCK_P (x))
|
||||
return x;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -313,6 +311,7 @@ relate_bbs_with_scopes (s)
|
|||
bbnote = get_next_bb_note (s->note_beg);
|
||||
if (! bbnote)
|
||||
abort ();
|
||||
|
||||
if (NOTE_BASIC_BLOCK (bbnote) == s->bb_end)
|
||||
{
|
||||
bbs_spanned = 0;
|
||||
|
@ -335,6 +334,7 @@ relate_bbs_with_scopes (s)
|
|||
bbnote = get_prev_bb_note (s->note_end);
|
||||
if (! bbnote)
|
||||
abort ();
|
||||
|
||||
if (NOTE_BASIC_BLOCK (bbnote) == s->bb_beg)
|
||||
{
|
||||
bbs_spanned = 0;
|
||||
|
@ -357,16 +357,15 @@ relate_bbs_with_scopes (s)
|
|||
bbs_spanned = 0;
|
||||
else
|
||||
{
|
||||
rtx x1, x2;
|
||||
/* Both notes are outside of any bbs. This implies that all the
|
||||
basic blocks spanned by the pair of notes are contained in
|
||||
this scope.
|
||||
There is a degenerate case to consider. If the notes do not
|
||||
span any basic blocks, then it is an empty scope that can
|
||||
safely be deleted or ignored. Mark these with level = -1. */
|
||||
rtx x1 = get_next_bb_note (s->note_beg);
|
||||
rtx x2 = get_prev_bb_note (s->note_end);
|
||||
|
||||
x1 = get_next_bb_note (s->note_beg);
|
||||
x2 = get_prev_bb_note (s->note_end);
|
||||
if (! (x1 && x2))
|
||||
{
|
||||
s->level = -1;
|
||||
|
@ -418,6 +417,7 @@ make_new_scope (level, note)
|
|||
rtx note;
|
||||
{
|
||||
scope new_scope = xcalloc (1, sizeof (struct scope_def));
|
||||
|
||||
new_scope->level = level;
|
||||
new_scope->note_beg = note;
|
||||
return new_scope;
|
||||
|
@ -442,6 +442,7 @@ build_scope_forest (forest)
|
|||
root = NULL;
|
||||
curr_bb = NULL;
|
||||
bbi = 0;
|
||||
|
||||
for (x = get_insns (); x; x = NEXT_INSN (x))
|
||||
{
|
||||
if (bbi < n_basic_blocks && x == BASIC_BLOCK (bbi)->head)
|
||||
|
@ -454,8 +455,10 @@ build_scope_forest (forest)
|
|||
if (root)
|
||||
{
|
||||
scope new_scope;
|
||||
|
||||
if (! curr_scope)
|
||||
abort();
|
||||
|
||||
level++;
|
||||
new_scope = make_new_scope (level, x);
|
||||
new_scope->outer = curr_scope;
|
||||
|
@ -471,10 +474,12 @@ build_scope_forest (forest)
|
|||
curr_scope->inner_last = new_scope;
|
||||
}
|
||||
curr_scope = curr_scope->inner_last;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
int ntrees = forest->num_trees;
|
||||
|
||||
level++;
|
||||
curr_scope = make_new_scope (level, x);
|
||||
root = curr_scope;
|
||||
|
@ -482,6 +487,7 @@ build_scope_forest (forest)
|
|||
sizeof (scope) * (ntrees + 1));
|
||||
forest->trees[forest->num_trees++] = root;
|
||||
}
|
||||
|
||||
curr_scope->bb_beg = curr_bb;
|
||||
}
|
||||
else if (NOTE_LINE_NUMBER (x) == NOTE_INSN_BLOCK_END)
|
||||
|
@ -493,22 +499,21 @@ build_scope_forest (forest)
|
|||
if (level == -1)
|
||||
root = NULL;
|
||||
}
|
||||
} /* if note */
|
||||
}
|
||||
|
||||
if (curr_bb && curr_bb->end == x)
|
||||
{
|
||||
curr_bb = NULL;
|
||||
bbi++;
|
||||
}
|
||||
|
||||
} /* for */
|
||||
}
|
||||
|
||||
for (i = 0; i < forest->num_trees; i++)
|
||||
relate_bbs_with_scopes (forest->trees[i]);
|
||||
}
|
||||
|
||||
/* Remove all the NOTE_INSN_BLOCK_BEG and NOTE_INSN_BLOCK_END notes from
|
||||
the insn chain. */
|
||||
/* Remove all NOTE_INSN_BLOCK_BEG and NOTE_INSN_BLOCK_END notes from the insn
|
||||
chain. */
|
||||
|
||||
static void
|
||||
remove_scope_notes ()
|
||||
|
@ -572,7 +577,6 @@ insert_intra_1 (s, ip, bb)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/* Insert NOTE_INSN_BLOCK_END notes and NOTE_INSN_BLOCK_BEG notes for
|
||||
scopes that are contained within BB. */
|
||||
|
||||
|
@ -598,7 +602,6 @@ insert_intra_bb_scope_notes (bb)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/* Given two consecutive basic blocks BB1 and BB2 with different scopes,
|
||||
insert NOTE_INSN_BLOCK_END notes after BB1 and NOTE_INSN_BLOCK_BEG
|
||||
notes before BB2 such that the notes are correctly balanced. If BB1 or
|
||||
|
@ -619,8 +622,10 @@ insert_inter_bb_scope_notes (bb1, bb2)
|
|||
{
|
||||
scope s1 = RBI (bb1)->scope;
|
||||
scope s2 = RBI (bb2)->scope;
|
||||
|
||||
if (! s1 && ! s2)
|
||||
return;
|
||||
|
||||
if (! s1)
|
||||
bb1 = NULL;
|
||||
else if (! s2)
|
||||
|
@ -632,10 +637,9 @@ insert_inter_bb_scope_notes (bb1, bb2)
|
|||
{
|
||||
scope s1 = RBI (bb1)->scope;
|
||||
scope s2 = RBI (bb2)->scope;
|
||||
|
||||
while (s1 != s2)
|
||||
{
|
||||
if (! (s1 && s2))
|
||||
abort ();
|
||||
if (s1->level > s2->level)
|
||||
s1 = s1->outer;
|
||||
else if (s2->level > s1->level)
|
||||
|
@ -646,6 +650,7 @@ insert_inter_bb_scope_notes (bb1, bb2)
|
|||
s2 = s2->outer;
|
||||
}
|
||||
}
|
||||
|
||||
com = s1;
|
||||
}
|
||||
else
|
||||
|
@ -655,18 +660,16 @@ insert_inter_bb_scope_notes (bb1, bb2)
|
|||
if (bb1)
|
||||
{
|
||||
rtx end = bb1->end;
|
||||
scope s;
|
||||
|
||||
scope s = RBI (bb1)->scope;
|
||||
ip = RBI (bb1)->eff_end;
|
||||
while (s != com)
|
||||
{
|
||||
if (NOTE_BLOCK (s->note_beg))
|
||||
{
|
||||
ip = emit_note_after (NOTE_INSN_BLOCK_END, ip);
|
||||
NOTE_BLOCK (ip) = NOTE_BLOCK (s->note_end);
|
||||
}
|
||||
s = s->outer;
|
||||
}
|
||||
for (s = RBI (bb1)->scope; s != com; s = s->outer)
|
||||
if (NOTE_BLOCK (s->note_beg))
|
||||
{
|
||||
ip = emit_note_after (NOTE_INSN_BLOCK_END, ip);
|
||||
NOTE_BLOCK (ip) = NOTE_BLOCK (s->note_end);
|
||||
}
|
||||
|
||||
/* Emitting note may move the end of basic block to unwanted place. */
|
||||
bb1->end = end;
|
||||
}
|
||||
|
@ -674,17 +677,15 @@ insert_inter_bb_scope_notes (bb1, bb2)
|
|||
/* Open scopes. */
|
||||
if (bb2)
|
||||
{
|
||||
scope s = RBI (bb2)->scope;
|
||||
scope s;
|
||||
|
||||
ip = bb2->head;
|
||||
while (s != com)
|
||||
{
|
||||
if (NOTE_BLOCK (s->note_beg))
|
||||
{
|
||||
ip = emit_note_before (NOTE_INSN_BLOCK_BEG, ip);
|
||||
NOTE_BLOCK (ip) = NOTE_BLOCK (s->note_beg);
|
||||
}
|
||||
s = s->outer;
|
||||
}
|
||||
for (s = RBI (bb2)->scope; s != com; s = s->outer)
|
||||
if (NOTE_BLOCK (s->note_beg))
|
||||
{
|
||||
ip = emit_note_before (NOTE_INSN_BLOCK_BEG, ip);
|
||||
NOTE_BLOCK (ip) = NOTE_BLOCK (s->note_beg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -709,6 +710,7 @@ rebuild_scope_notes (forest)
|
|||
{
|
||||
basic_block bb1 = BASIC_BLOCK (i);
|
||||
basic_block bb2 = BASIC_BLOCK (i + 1);
|
||||
|
||||
if (RBI (bb1)->scope != RBI (bb2)->scope)
|
||||
insert_inter_bb_scope_notes (bb1, bb2);
|
||||
insert_intra_bb_scope_notes (bb1);
|
||||
|
@ -745,6 +747,7 @@ free_scope_forest (forest)
|
|||
scope_forest_info *forest;
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < forest->num_trees; i++)
|
||||
free_scope_forest_1 (forest->trees[i]);
|
||||
}
|
||||
|
@ -755,15 +758,15 @@ void
|
|||
dump_scope_forest (forest)
|
||||
scope_forest_info *forest;
|
||||
{
|
||||
int i;
|
||||
|
||||
if (forest->num_trees == 0)
|
||||
fprintf (stderr, "\n< Empty scope forest >\n");
|
||||
else
|
||||
{
|
||||
int i;
|
||||
fprintf (stderr, "\n< Scope forest >\n");
|
||||
for (i = 0; i < forest->num_trees; i++)
|
||||
dump_scope_forest_1 (forest->trees[i], 0);
|
||||
}
|
||||
fprintf (stderr, "\n< Scope forest >\n");
|
||||
|
||||
for (i = 0; i < forest->num_trees; i++)
|
||||
dump_scope_forest_1 (forest->trees[i], 0);
|
||||
}
|
||||
|
||||
/* Recursive portion of dump_scope_forest. */
|
||||
|
@ -813,33 +816,28 @@ fixup_reorder_chain ()
|
|||
/* First do the bulk reordering -- rechain the blocks without regard to
|
||||
the needed changes to jumps and labels. */
|
||||
|
||||
last_bb = BASIC_BLOCK (0);
|
||||
bb = RBI (last_bb)->next;
|
||||
index = 1;
|
||||
while (bb)
|
||||
for (last_bb = BASIC_BLOCK (0), bb = RBI (last_bb)->next, index = 1;
|
||||
bb != 0;
|
||||
last_bb = bb, bb = RBI (bb)->next, index++)
|
||||
{
|
||||
rtx last_e = RBI (last_bb)->eff_end;
|
||||
rtx curr_h = RBI (bb)->eff_head;
|
||||
|
||||
NEXT_INSN (last_e) = curr_h;
|
||||
PREV_INSN (curr_h) = last_e;
|
||||
|
||||
last_bb = bb;
|
||||
bb = RBI (bb)->next;
|
||||
index++;
|
||||
}
|
||||
|
||||
if (index != n_basic_blocks)
|
||||
abort ();
|
||||
|
||||
insn = RBI (last_bb)->eff_end;
|
||||
|
||||
NEXT_INSN (insn) = function_tail_eff_head;
|
||||
if (function_tail_eff_head)
|
||||
PREV_INSN (function_tail_eff_head) = insn;
|
||||
|
||||
while (NEXT_INSN (insn))
|
||||
insn = NEXT_INSN (insn);
|
||||
|
||||
set_last_insn (insn);
|
||||
#ifdef ENABLE_CHECKING
|
||||
verify_insn_chain ();
|
||||
|
@ -884,6 +882,7 @@ fixup_reorder_chain ()
|
|||
if (RBI (bb)->next != e_taken->dest)
|
||||
{
|
||||
rtx note = find_reg_note (bb_end_insn, REG_BR_PROB, 0);
|
||||
|
||||
if (note
|
||||
&& INTVAL (XEXP (note, 0)) < REG_BR_PROB_BASE / 2
|
||||
&& invert_jump (bb_end_insn,
|
||||
|
@ -913,6 +912,7 @@ fixup_reorder_chain ()
|
|||
99% case, there should not have been a fallthru edge. */
|
||||
if (! e_fall)
|
||||
continue;
|
||||
|
||||
#ifdef CASE_DROPS_THROUGH
|
||||
/* Except for VAX. Since we didn't have predication for the
|
||||
tablejump, the fallthru block should not have moved. */
|
||||
|
@ -936,15 +936,13 @@ fixup_reorder_chain ()
|
|||
if (RBI (bb)->next == e_fall->dest)
|
||||
continue;
|
||||
|
||||
/* An fallthru to exit block. */
|
||||
/* A fallthru to exit block. */
|
||||
if (!RBI (bb)->next && e_fall->dest == EXIT_BLOCK_PTR)
|
||||
continue;
|
||||
}
|
||||
|
||||
/* We got here if we need to add a new jump insn. */
|
||||
|
||||
nb = force_nonfallthru (e_fall);
|
||||
|
||||
if (nb)
|
||||
{
|
||||
alloc_aux_for_block (nb, sizeof (struct reorder_block_def));
|
||||
|
@ -965,18 +963,17 @@ fixup_reorder_chain ()
|
|||
|
||||
if (rtl_dump_file)
|
||||
fprintf (rtl_dump_file, "Reordered sequence:\n");
|
||||
while (bb)
|
||||
|
||||
for (; bb; bb = RBI (bb)->next, index++)
|
||||
{
|
||||
if (rtl_dump_file)
|
||||
fprintf (rtl_dump_file, " %i %sbb %i freq %i\n", index,
|
||||
bb->index >= old_n_basic_blocks ? "compensation " : "",
|
||||
bb->index,
|
||||
bb->frequency);
|
||||
|
||||
bb->index = index;
|
||||
BASIC_BLOCK (index) = bb;
|
||||
|
||||
bb = RBI (bb)->next;
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -989,62 +986,31 @@ fixup_reorder_chain ()
|
|||
void
|
||||
verify_insn_chain ()
|
||||
{
|
||||
rtx x,
|
||||
prevx,
|
||||
nextx;
|
||||
int insn_cnt1,
|
||||
insn_cnt2;
|
||||
rtx x, prevx, nextx;
|
||||
int insn_cnt1, insn_cnt2;
|
||||
|
||||
prevx = NULL;
|
||||
insn_cnt1 = 1;
|
||||
for (x = get_insns (); x; x = NEXT_INSN (x))
|
||||
{
|
||||
if (PREV_INSN (x) != prevx)
|
||||
{
|
||||
fprintf (stderr, "Forward traversal: insn chain corrupt.\n");
|
||||
fprintf (stderr, "previous insn:\n");
|
||||
debug_rtx (prevx);
|
||||
fprintf (stderr, "current insn:\n");
|
||||
debug_rtx (x);
|
||||
abort ();
|
||||
}
|
||||
++insn_cnt1;
|
||||
prevx = x;
|
||||
}
|
||||
for (prevx = NULL, insn_cnt1 = 1, x = get_insns ();
|
||||
x != 0;
|
||||
prevx = x, insn_cnt1++, x = NEXT_INSN (x))
|
||||
if (PREV_INSN (x) != prevx)
|
||||
abort ();
|
||||
|
||||
if (prevx != get_last_insn ())
|
||||
{
|
||||
fprintf (stderr, "last_insn corrupt.\n");
|
||||
abort ();
|
||||
}
|
||||
abort ();
|
||||
|
||||
nextx = NULL;
|
||||
insn_cnt2 = 1;
|
||||
for (x = get_last_insn (); x; x = PREV_INSN (x))
|
||||
{
|
||||
if (NEXT_INSN (x) != nextx)
|
||||
{
|
||||
fprintf (stderr, "Reverse traversal: insn chain corrupt.\n");
|
||||
fprintf (stderr, "current insn:\n");
|
||||
debug_rtx (x);
|
||||
fprintf (stderr, "next insn:\n");
|
||||
debug_rtx (nextx);
|
||||
abort ();
|
||||
}
|
||||
++insn_cnt2;
|
||||
nextx = x;
|
||||
}
|
||||
for (nextx = NULL, insn_cnt2 = 1, x = get_last_insn ();
|
||||
x != 0;
|
||||
nextx = x, insn_cnt2++, x = PREV_INSN (x))
|
||||
if (NEXT_INSN (x) != nextx)
|
||||
abort ();
|
||||
|
||||
if (insn_cnt1 != insn_cnt2)
|
||||
{
|
||||
fprintf (stderr, "insn_cnt1 (%d) not equal to insn_cnt2 (%d).\n",
|
||||
insn_cnt1, insn_cnt2);
|
||||
abort ();
|
||||
}
|
||||
abort ();
|
||||
}
|
||||
|
||||
/* The block falling through to exit must be the last one in the
|
||||
reordered chain. Ensure that this condition is met. */
|
||||
/* The block falling through to exit must be the last one in the reordered
|
||||
chain. Ensure it is. */
|
||||
|
||||
static void
|
||||
fixup_fallthru_exit_predecessor ()
|
||||
{
|
||||
|
@ -1054,21 +1020,25 @@ fixup_fallthru_exit_predecessor ()
|
|||
for (e = EXIT_BLOCK_PTR->pred; e; e = e->pred_next)
|
||||
if (e->flags & EDGE_FALLTHRU)
|
||||
bb = e->src;
|
||||
|
||||
if (bb && RBI (bb)->next)
|
||||
{
|
||||
basic_block c = BASIC_BLOCK (0);
|
||||
|
||||
while (RBI (c)->next != bb)
|
||||
c = RBI (c)->next;
|
||||
|
||||
RBI (c)->next = RBI (bb)->next;
|
||||
while (RBI (c)->next)
|
||||
c = RBI (c)->next;
|
||||
|
||||
RBI (c)->next = bb;
|
||||
RBI (bb)->next = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Main entry point to this module - initialize the datastructures for
|
||||
CFG layout changes. */
|
||||
/* Main entry point to this module: initialize the datastructures for CFG
|
||||
layout changes. */
|
||||
|
||||
void
|
||||
cfg_layout_initialize ()
|
||||
|
@ -1081,14 +1051,15 @@ cfg_layout_initialize ()
|
|||
record_effective_endpoints ();
|
||||
}
|
||||
|
||||
/* Finalize the changes - reorder insn list according to the sequence,
|
||||
enter compensation code, rebuild scope forest. */
|
||||
/* Finalize the changes: reorder insn list according to the sequence, enter
|
||||
compensation code, rebuild scope forest. */
|
||||
|
||||
void
|
||||
cfg_layout_finalize ()
|
||||
{
|
||||
fixup_fallthru_exit_predecessor ();
|
||||
fixup_reorder_chain ();
|
||||
|
||||
#ifdef ENABLE_CHECKING
|
||||
verify_insn_chain ();
|
||||
#endif
|
||||
|
|
194
gcc/cfgloop.c
194
gcc/cfgloop.c
|
@ -31,11 +31,13 @@ static int flow_loop_nested_p PARAMS ((struct loop *,
|
|||
static int flow_loop_entry_edges_find PARAMS ((basic_block, const sbitmap,
|
||||
edge **));
|
||||
static int flow_loop_exit_edges_find PARAMS ((const sbitmap, edge **));
|
||||
static int flow_loop_nodes_find PARAMS ((basic_block, basic_block, sbitmap));
|
||||
static void flow_loop_pre_header_scan PARAMS ((struct loop *));
|
||||
static int flow_loop_nodes_find PARAMS ((basic_block, basic_block,
|
||||
sbitmap));
|
||||
static void flow_loop_pre_header_scan PARAMS ((struct loop *));
|
||||
static basic_block flow_loop_pre_header_find PARAMS ((basic_block,
|
||||
const sbitmap *));
|
||||
static void flow_loop_tree_node_add PARAMS ((struct loop *, struct loop *));
|
||||
static void flow_loop_tree_node_add PARAMS ((struct loop *,
|
||||
struct loop *));
|
||||
static void flow_loops_tree_build PARAMS ((struct loops *));
|
||||
static int flow_loop_level_compute PARAMS ((struct loop *, int));
|
||||
static int flow_loops_level_compute PARAMS ((struct loops *));
|
||||
|
@ -68,14 +70,17 @@ flow_loops_cfg_dump (loops, file)
|
|||
fputs (";; DFS order: ", file);
|
||||
for (i = 0; i < n_basic_blocks; i++)
|
||||
fprintf (file, "%d ", loops->cfg.dfs_order[i]);
|
||||
|
||||
fputs ("\n", file);
|
||||
}
|
||||
|
||||
/* Dump the reverse completion node order. */
|
||||
if (loops->cfg.rc_order)
|
||||
{
|
||||
fputs (";; RC order: ", file);
|
||||
for (i = 0; i < n_basic_blocks; i++)
|
||||
fprintf (file, "%d ", loops->cfg.rc_order[i]);
|
||||
|
||||
fputs ("\n", file);
|
||||
}
|
||||
}
|
||||
|
@ -107,12 +112,10 @@ flow_loop_dump (loop, file, loop_dump_aux, verbose)
|
|||
fprintf (file, ";;\n;; Loop %d (%d to %d):%s%s\n",
|
||||
loop->num, INSN_UID (loop->first->head),
|
||||
INSN_UID (loop->last->end),
|
||||
loop->shared ? " shared" : "",
|
||||
loop->invalid ? " invalid" : "");
|
||||
loop->shared ? " shared" : "", loop->invalid ? " invalid" : "");
|
||||
else
|
||||
fprintf (file, ";;\n;; Loop %d:%s%s\n", loop->num,
|
||||
loop->shared ? " shared" : "",
|
||||
loop->invalid ? " invalid" : "");
|
||||
loop->shared ? " shared" : "", loop->invalid ? " invalid" : "");
|
||||
|
||||
fprintf (file, ";; header %d, latch %d, pre-header %d, first %d, last %d\n",
|
||||
loop->header->index, loop->latch->index,
|
||||
|
@ -125,14 +128,17 @@ flow_loop_dump (loop, file, loop_dump_aux, verbose)
|
|||
if (loop->pre_header_edges)
|
||||
flow_edge_list_print (";; pre-header edges", loop->pre_header_edges,
|
||||
loop->num_pre_header_edges, file);
|
||||
|
||||
flow_edge_list_print (";; entry edges", loop->entry_edges,
|
||||
loop->num_entries, file);
|
||||
fprintf (file, ";; %d", loop->num_nodes);
|
||||
flow_nodes_print (" nodes", loop->nodes, file);
|
||||
flow_edge_list_print (";; exit edges", loop->exit_edges,
|
||||
loop->num_exits, file);
|
||||
|
||||
if (loop->exits_doms)
|
||||
flow_nodes_print (";; exit doms", loop->exits_doms, file);
|
||||
|
||||
if (loop_dump_aux)
|
||||
loop_dump_aux (loop, file, verbose);
|
||||
}
|
||||
|
@ -147,49 +153,42 @@ flow_loops_dump (loops, file, loop_dump_aux, verbose)
|
|||
void (*loop_dump_aux) PARAMS((const struct loop *, FILE *, int));
|
||||
int verbose;
|
||||
{
|
||||
int i;
|
||||
int i, j;
|
||||
int num_loops;
|
||||
|
||||
num_loops = loops->num;
|
||||
if (! num_loops || ! file)
|
||||
return;
|
||||
|
||||
fprintf (file, ";; %d loops found, %d levels\n",
|
||||
num_loops, loops->levels);
|
||||
|
||||
fprintf (file, ";; %d loops found, %d levels\n", num_loops, loops->levels);
|
||||
for (i = 0; i < num_loops; i++)
|
||||
{
|
||||
struct loop *loop = &loops->array[i];
|
||||
|
||||
flow_loop_dump (loop, file, loop_dump_aux, verbose);
|
||||
|
||||
if (loop->shared)
|
||||
{
|
||||
int j;
|
||||
for (j = 0; j < i; j++)
|
||||
{
|
||||
struct loop *oloop = &loops->array[j];
|
||||
|
||||
for (j = 0; j < i; j++)
|
||||
{
|
||||
struct loop *oloop = &loops->array[j];
|
||||
if (loop->header == oloop->header)
|
||||
{
|
||||
int disjoint;
|
||||
int smaller;
|
||||
|
||||
if (loop->header == oloop->header)
|
||||
{
|
||||
int disjoint;
|
||||
int smaller;
|
||||
smaller = loop->num_nodes < oloop->num_nodes;
|
||||
|
||||
smaller = loop->num_nodes < oloop->num_nodes;
|
||||
|
||||
/* If the union of LOOP and OLOOP is different than
|
||||
the larger of LOOP and OLOOP then LOOP and OLOOP
|
||||
must be disjoint. */
|
||||
disjoint = ! flow_loop_nested_p (smaller ? loop : oloop,
|
||||
smaller ? oloop : loop);
|
||||
fprintf (file,
|
||||
";; loop header %d shared by loops %d, %d %s\n",
|
||||
loop->header->index, i, j,
|
||||
disjoint ? "disjoint" : "nested");
|
||||
}
|
||||
}
|
||||
}
|
||||
/* If the union of LOOP and OLOOP is different than
|
||||
the larger of LOOP and OLOOP then LOOP and OLOOP
|
||||
must be disjoint. */
|
||||
disjoint = ! flow_loop_nested_p (smaller ? loop : oloop,
|
||||
smaller ? oloop : loop);
|
||||
fprintf (file,
|
||||
";; loop header %d shared by loops %d, %d %s\n",
|
||||
loop->header->index, i, j,
|
||||
disjoint ? "disjoint" : "nested");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (verbose)
|
||||
|
@ -225,11 +224,13 @@ flow_loops_free (loops)
|
|||
if (loop->exits_doms)
|
||||
sbitmap_free (loop->exits_doms);
|
||||
}
|
||||
|
||||
free (loops->array);
|
||||
loops->array = NULL;
|
||||
|
||||
if (loops->cfg.dom)
|
||||
sbitmap_vector_free (loops->cfg.dom);
|
||||
|
||||
if (loops->cfg.dfs_order)
|
||||
free (loops->cfg.dfs_order);
|
||||
|
||||
|
@ -394,42 +395,33 @@ static void
|
|||
flow_loop_pre_header_scan (loop)
|
||||
struct loop *loop;
|
||||
{
|
||||
int num = 0;
|
||||
int num;
|
||||
basic_block ebb;
|
||||
edge e;
|
||||
|
||||
loop->num_pre_header_edges = 0;
|
||||
|
||||
if (loop->num_entries != 1)
|
||||
return;
|
||||
return;
|
||||
|
||||
ebb = loop->entry_edges[0]->src;
|
||||
if (ebb == ENTRY_BLOCK_PTR)
|
||||
return;
|
||||
|
||||
if (ebb != ENTRY_BLOCK_PTR)
|
||||
{
|
||||
edge e;
|
||||
/* Count number of edges along trace from loop header to
|
||||
root of pre-header extended basic block. Usually this is
|
||||
only one or two edges. */
|
||||
for (num = 1; ebb->pred->src != ENTRY_BLOCK_PTR && ! ebb->pred->pred_next;
|
||||
num++)
|
||||
ebb = ebb->pred->src;
|
||||
|
||||
/* Count number of edges along trace from loop header to
|
||||
root of pre-header extended basic block. Usually this is
|
||||
only one or two edges. */
|
||||
num++;
|
||||
while (ebb->pred->src != ENTRY_BLOCK_PTR && ! ebb->pred->pred_next)
|
||||
{
|
||||
ebb = ebb->pred->src;
|
||||
num++;
|
||||
}
|
||||
loop->pre_header_edges = (edge *) xmalloc (num * sizeof (edge *));
|
||||
loop->num_pre_header_edges = num;
|
||||
|
||||
loop->pre_header_edges = (edge *) xmalloc (num * sizeof (edge *));
|
||||
loop->num_pre_header_edges = num;
|
||||
|
||||
/* Store edges in order that they are followed. The source
|
||||
of the first edge is the root node of the pre-header extended
|
||||
basic block and the destination of the last last edge is
|
||||
the loop header. */
|
||||
for (e = loop->entry_edges[0]; num; e = e->src->pred)
|
||||
{
|
||||
loop->pre_header_edges[--num] = e;
|
||||
}
|
||||
}
|
||||
/* Store edges in order that they are followed. The source of the first edge
|
||||
is the root node of the pre-header extended basic block and the
|
||||
destination of the last last edge is the loop header. */
|
||||
for (e = loop->entry_edges[0]; num; e = e->src->pred)
|
||||
loop->pre_header_edges[--num] = e;
|
||||
}
|
||||
|
||||
/* Return the block for the pre-header of the loop with header
|
||||
|
@ -465,6 +457,7 @@ flow_loop_pre_header_find (header, dom)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
return pre_header;
|
||||
}
|
||||
|
||||
|
@ -485,16 +478,13 @@ flow_loop_tree_node_add (prevloop, loop)
|
|||
return;
|
||||
}
|
||||
|
||||
while (prevloop->outer)
|
||||
{
|
||||
if (flow_loop_nested_p (prevloop->outer, loop))
|
||||
{
|
||||
prevloop->next = loop;
|
||||
loop->outer = prevloop->outer;
|
||||
return;
|
||||
}
|
||||
prevloop = prevloop->outer;
|
||||
}
|
||||
for (; prevloop->outer; prevloop = prevloop->outer)
|
||||
if (flow_loop_nested_p (prevloop->outer, loop))
|
||||
{
|
||||
prevloop->next = loop;
|
||||
loop->outer = prevloop->outer;
|
||||
return;
|
||||
}
|
||||
|
||||
prevloop->next = loop;
|
||||
loop->outer = NULL;
|
||||
|
@ -517,7 +507,8 @@ flow_loops_tree_build (loops)
|
|||
Since we used a depth first search this should be the
|
||||
outermost loop. */
|
||||
loops->tree_root = &loops->array[0];
|
||||
loops->tree_root->outer = loops->tree_root->inner = loops->tree_root->next = NULL;
|
||||
loops->tree_root->outer = loops->tree_root->inner
|
||||
= loops->tree_root->next = NULL;
|
||||
|
||||
/* Add the remaining loops to the tree. */
|
||||
for (i = 1; i < num_loops; i++)
|
||||
|
@ -546,13 +537,11 @@ flow_loop_level_compute (loop, depth)
|
|||
itself). */
|
||||
for (inner = loop->inner; inner; inner = inner->next)
|
||||
{
|
||||
int ilevel;
|
||||
int ilevel = flow_loop_level_compute (inner, depth + 1) + 1;
|
||||
|
||||
ilevel = flow_loop_level_compute (inner, depth + 1) + 1;
|
||||
|
||||
if (ilevel > level)
|
||||
level = ilevel;
|
||||
level = MAX (ilevel, level);
|
||||
}
|
||||
|
||||
loop->level = level;
|
||||
loop->depth = depth;
|
||||
return level;
|
||||
|
@ -566,17 +555,17 @@ static int
|
|||
flow_loops_level_compute (loops)
|
||||
struct loops *loops;
|
||||
{
|
||||
int levels = 0;
|
||||
struct loop *loop;
|
||||
int level;
|
||||
int levels = 0;
|
||||
|
||||
/* Traverse all the outer level loops. */
|
||||
for (loop = loops->tree_root; loop; loop = loop->next)
|
||||
{
|
||||
level = flow_loop_level_compute (loop, 1);
|
||||
if (level > levels)
|
||||
levels = level;
|
||||
levels = MAX (levels, level);
|
||||
}
|
||||
|
||||
return levels;
|
||||
}
|
||||
|
||||
|
@ -594,23 +583,15 @@ flow_loop_scan (loops, loop, flags)
|
|||
flags |= LOOP_EXIT_EDGES;
|
||||
|
||||
if (flags & LOOP_ENTRY_EDGES)
|
||||
{
|
||||
/* Find edges which enter the loop header.
|
||||
Note that the entry edges should only
|
||||
enter the header of a natural loop. */
|
||||
loop->num_entries
|
||||
= flow_loop_entry_edges_find (loop->header,
|
||||
loop->nodes,
|
||||
&loop->entry_edges);
|
||||
}
|
||||
/* Find edges which enter the loop header. Note that the entry edges
|
||||
should only enter the header of a natural loop. */
|
||||
loop->num_entries = flow_loop_entry_edges_find (loop->header, loop->nodes,
|
||||
&loop->entry_edges);
|
||||
|
||||
if (flags & LOOP_EXIT_EDGES)
|
||||
{
|
||||
/* Find edges which exit the loop. */
|
||||
loop->num_exits
|
||||
= flow_loop_exit_edges_find (loop->nodes,
|
||||
&loop->exit_edges);
|
||||
}
|
||||
/* Find edges which exit the loop. */
|
||||
loop->num_exits
|
||||
= flow_loop_exit_edges_find (loop->nodes, &loop->exit_edges);
|
||||
|
||||
if (flags & LOOP_EXITS_DOMS)
|
||||
{
|
||||
|
@ -640,13 +621,14 @@ flow_loop_scan (loops, loop, flags)
|
|||
the loop pre-header. */
|
||||
flow_loop_pre_header_scan (loop);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Find all the natural loops in the function and save in LOOPS structure
|
||||
and recalculate loop_depth information in basic block structures.
|
||||
FLAGS controls which loop information is collected.
|
||||
Return the number of natural loops found. */
|
||||
/* Find all the natural loops in the function and save in LOOPS structure and
|
||||
recalculate loop_depth information in basic block structures. FLAGS
|
||||
controls which loop information is collected. Return the number of natural
|
||||
loops found. */
|
||||
|
||||
int
|
||||
flow_loops_find (loops, flags)
|
||||
|
@ -668,7 +650,7 @@ flow_loops_find (loops, flags)
|
|||
if (! (flags & LOOP_TREE))
|
||||
abort ();
|
||||
|
||||
memset (loops, 0, sizeof (*loops));
|
||||
memset (loops, 0, sizeof *loops);
|
||||
|
||||
/* Taking care of this degenerate case makes the rest of
|
||||
this code simpler. */
|
||||
|
@ -684,7 +666,6 @@ flow_loops_find (loops, flags)
|
|||
|
||||
/* Count the number of loop edges (back edges). This should be the
|
||||
same as the number of natural loops. */
|
||||
|
||||
num_loops = 0;
|
||||
for (b = 0; b < n_basic_blocks; b++)
|
||||
{
|
||||
|
@ -810,9 +791,7 @@ flow_loops_find (loops, flags)
|
|||
sbitmap_free (headers);
|
||||
}
|
||||
else
|
||||
{
|
||||
sbitmap_vector_free (dom);
|
||||
}
|
||||
sbitmap_vector_free (dom);
|
||||
|
||||
loops->num = num_loops;
|
||||
|
||||
|
@ -828,6 +807,7 @@ flow_loops_find (loops, flags)
|
|||
|
||||
/* Update the information regarding the loops in the CFG
|
||||
specified by LOOPS. */
|
||||
|
||||
int
|
||||
flow_loops_update (loops, flags)
|
||||
struct loops *loops;
|
||||
|
@ -850,5 +830,7 @@ flow_loop_outside_edge_p (loop, e)
|
|||
{
|
||||
if (e->dest != loop->header)
|
||||
abort ();
|
||||
return (e->src == ENTRY_BLOCK_PTR) || ! TEST_BIT (loop->nodes, e->src->index);
|
||||
|
||||
return (e->src == ENTRY_BLOCK_PTR)
|
||||
|| ! TEST_BIT (loop->nodes, e->src->index);
|
||||
}
|
||||
|
|
458
gcc/cfgrtl.c
458
gcc/cfgrtl.c
File diff suppressed because it is too large
Load Diff
|
@ -1483,6 +1483,7 @@ typedef int (*rtx_function) PARAMS ((rtx *, void *));
|
|||
extern int for_each_rtx PARAMS ((rtx *, rtx_function, void *));
|
||||
extern rtx regno_use_in PARAMS ((unsigned int, rtx));
|
||||
extern int auto_inc_p PARAMS ((rtx));
|
||||
extern int in_expr_list_p PARAMS ((rtx, rtx));
|
||||
extern void remove_node_from_expr_list PARAMS ((rtx, rtx *));
|
||||
extern int insns_safe_to_move_p PARAMS ((rtx, rtx, rtx *));
|
||||
extern int loc_mentioned_in_p PARAMS ((rtx *, rtx));
|
||||
|
|
|
@ -1953,6 +1953,24 @@ remove_note (insn, note)
|
|||
abort ();
|
||||
}
|
||||
|
||||
/* Search LISTP (an EXPR_LIST) for an entry whose first operand is NODE and
|
||||
return 1 if it is found. A simple equality test is used to determine if
|
||||
NODE matches. */
|
||||
|
||||
int
|
||||
in_expr_list_p (listp, node)
|
||||
rtx listp;
|
||||
rtx node;
|
||||
{
|
||||
rtx x;
|
||||
|
||||
for (x = listp; x; x = XEXP (x, 1))
|
||||
if (node == XEXP (x, 0))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Search LISTP (an EXPR_LIST) for an entry whose first operand is NODE and
|
||||
remove that entry from the list if it is found.
|
||||
|
||||
|
|
Loading…
Reference in New Issue