flow.c (try_merge_block): Rename to try_optimize_cfg; do basic simplifications on the CFG.
* flow.c (try_merge_block): Rename to try_optimize_cfg; do basic simplifications on the CFG. (is_forwarder_block_p, can_fallthru, try_redirect_by_replacing_jump, try_simplify_condjump): New. (redirect_edge_and_branch): Try replace jump insn. (flow_delete_insn): Handle deleting of ADDR_VEC insns. * basic-block.h (FALLTHRU_EDGE, BRANCH_EDGE): New macros. From-SVN: r43642
This commit is contained in:
parent
d72c3ec3f6
commit
7a442791bb
3 changed files with 400 additions and 33 deletions
|
@ -1,3 +1,14 @@
|
|||
Thu Jun 28 20:13:11 CEST 2001 Jan Hubicka <jh@suse.cz>
|
||||
|
||||
* flow.c (try_merge_block): Rename to try_optimize_cfg;
|
||||
do basic simplifications on the CFG.
|
||||
(is_forwarder_block_p, can_fallthru, try_redirect_by_replacing_jump,
|
||||
try_simplify_condjump): New.
|
||||
(redirect_edge_and_branch): Try replace jump insn.
|
||||
(flow_delete_insn): Handle deleting of ADDR_VEC insns.
|
||||
|
||||
* basic-block.h (FALLTHRU_EDGE, BRANCH_EDGE): New macros.
|
||||
|
||||
Thu Jun 28 11:19:42 2001 Jeffrey A Law (law@cygnus.com)
|
||||
|
||||
* ssa-dce.c (eliminate_dead_code): Remove fake edges from the
|
||||
|
|
|
@ -488,6 +488,14 @@ struct edge_list
|
|||
/* Number of edges in the compressed edge list. */
|
||||
#define NUM_EDGES(el) ((el)->num_edges)
|
||||
|
||||
/* BB is assumed to contain conditional jump. Return the fallthru edge. */
|
||||
#define FALLTHRU_EDGE(bb) ((bb)->succ->flags & EDGE_FALLTHRU \
|
||||
? (bb)->succ : (bb)->succ->succ_next)
|
||||
|
||||
/* BB is assumed to contain conditional jump. Return the branch edge. */
|
||||
#define BRANCH_EDGE(bb) ((bb)->succ->flags & EDGE_FALLTHRU \
|
||||
? (bb)->succ->succ_next : (bb)->succ)
|
||||
|
||||
struct edge_list * create_edge_list PARAMS ((void));
|
||||
void free_edge_list PARAMS ((struct edge_list *));
|
||||
void print_edge_list PARAMS ((FILE *, struct edge_list *));
|
||||
|
|
414
gcc/flow.c
414
gcc/flow.c
|
@ -381,7 +381,12 @@ static int merge_blocks_move_predecessor_nojumps PARAMS ((basic_block,
|
|||
static int merge_blocks_move_successor_nojumps PARAMS ((basic_block,
|
||||
basic_block));
|
||||
static int merge_blocks PARAMS ((edge,basic_block,basic_block));
|
||||
static void try_merge_blocks PARAMS ((void));
|
||||
static bool try_optimize_cfg PARAMS ((void));
|
||||
static bool forwarder_block_p PARAMS ((basic_block));
|
||||
static bool can_fallthru PARAMS ((basic_block, basic_block));
|
||||
static bool try_redirect_by_replacing_jump PARAMS ((edge, basic_block));
|
||||
static bool try_simplify_condjump PARAMS ((basic_block));
|
||||
static bool try_forward_edges PARAMS ((basic_block));
|
||||
static void tidy_fallthru_edges PARAMS ((void));
|
||||
static int verify_wide_reg_1 PARAMS ((rtx *, void *));
|
||||
static void verify_wide_reg PARAMS ((int, rtx, rtx));
|
||||
|
@ -471,7 +476,7 @@ static int flow_loop_level_compute PARAMS ((struct loop *, int));
|
|||
static int flow_loops_level_compute PARAMS ((struct loops *));
|
||||
static void allocate_bb_life_data PARAMS ((void));
|
||||
static void find_sub_basic_blocks PARAMS ((basic_block));
|
||||
static int redirect_edge_and_branch PARAMS ((edge, basic_block));
|
||||
static bool redirect_edge_and_branch PARAMS ((edge, basic_block));
|
||||
static rtx block_label PARAMS ((basic_block));
|
||||
|
||||
/* Find basic blocks of the current function.
|
||||
|
@ -1010,7 +1015,8 @@ void
|
|||
cleanup_cfg ()
|
||||
{
|
||||
delete_unreachable_blocks ();
|
||||
try_merge_blocks ();
|
||||
if (try_optimize_cfg ())
|
||||
delete_unreachable_blocks ();
|
||||
mark_critical_edges ();
|
||||
|
||||
/* Kill the data we won't maintain. */
|
||||
|
@ -1586,22 +1592,161 @@ block_label (block)
|
|||
return block->head;
|
||||
}
|
||||
|
||||
/* Return true if the block has no effect and only forwards control flow to
|
||||
its single destination. */
|
||||
static bool
|
||||
forwarder_block_p (bb)
|
||||
basic_block bb;
|
||||
{
|
||||
rtx insn;
|
||||
if (bb == EXIT_BLOCK_PTR || bb == ENTRY_BLOCK_PTR
|
||||
|| !bb->succ || bb->succ->succ_next)
|
||||
return false;
|
||||
|
||||
insn = next_active_insn (bb->head);
|
||||
if (!insn)
|
||||
return false;
|
||||
if (GET_CODE (insn) == CODE_LABEL
|
||||
|| (GET_CODE (insn) == JUMP_INSN && onlyjump_p (insn)))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Return nonzero if we can reach target from src by falling trought. */
|
||||
static bool
|
||||
can_fallthru (src, target)
|
||||
basic_block src, target;
|
||||
{
|
||||
rtx insn = src->end;
|
||||
rtx insn2 = target->head;
|
||||
|
||||
if (!active_insn_p (insn2))
|
||||
insn2 = next_active_insn (insn2);
|
||||
/* ??? Later we may add code to move jump tables offline. */
|
||||
return next_active_insn (insn) == insn2;
|
||||
}
|
||||
|
||||
/* Attempt to perform edge redirection by replacing possibly complex jump
|
||||
instruction by unconditional jump or removing jump completely.
|
||||
This can apply only if all edges now point to the same block.
|
||||
|
||||
The parameters and return values are equivalent to redirect_edge_and_branch.
|
||||
*/
|
||||
static bool
|
||||
try_redirect_by_replacing_jump (e, target)
|
||||
edge e;
|
||||
basic_block target;
|
||||
{
|
||||
basic_block src = e->src;
|
||||
rtx insn = src->end;
|
||||
edge tmp;
|
||||
rtx set;
|
||||
int fallthru = 0;
|
||||
rtx barrier;
|
||||
|
||||
/* Verify that all targets will be TARGET. */
|
||||
for (tmp = src->succ; tmp; tmp = tmp->succ_next)
|
||||
if (tmp->dest != target && tmp != e)
|
||||
break;
|
||||
if (tmp || GET_CODE (insn) != JUMP_INSN)
|
||||
return false;
|
||||
|
||||
/* Avoid removing branch with side effects. */
|
||||
set = single_set (insn);
|
||||
if (!set || side_effects_p (set))
|
||||
return false;
|
||||
|
||||
/* See if we can create the fallthru edge. */
|
||||
if (can_fallthru (src, target))
|
||||
{
|
||||
src->end = PREV_INSN (insn);
|
||||
if (rtl_dump_file)
|
||||
fprintf (rtl_dump_file, "Removing jump %i.\n", INSN_UID (insn));
|
||||
flow_delete_insn (insn);
|
||||
fallthru = 1;
|
||||
insn = src->end;
|
||||
}
|
||||
/* If this already is simplejump, redirect it. */
|
||||
else if (simplejump_p (insn))
|
||||
{
|
||||
if (e->dest == target)
|
||||
return false;
|
||||
if (rtl_dump_file)
|
||||
fprintf (rtl_dump_file, "Redirecting jump %i from %i to %i.\n",
|
||||
INSN_UID (insn), e->dest->index, target->index);
|
||||
redirect_jump (insn, block_label (target), 0);
|
||||
}
|
||||
/* Or replace possibly complicated jump insn by simple jump insn. */
|
||||
else
|
||||
{
|
||||
rtx target_label = block_label (target);
|
||||
|
||||
src->end = PREV_INSN (insn);
|
||||
src->end = emit_jump_insn_after (gen_jump (target_label), src->end);
|
||||
JUMP_LABEL (src->end) = target_label;
|
||||
LABEL_NUSES (target_label)++;
|
||||
if (rtl_dump_file)
|
||||
fprintf (rtl_dump_file, "Replacing insn %i by jump %i\n",
|
||||
INSN_UID (insn), INSN_UID (src->end));
|
||||
flow_delete_insn (insn);
|
||||
insn = src->end;
|
||||
}
|
||||
|
||||
/* Keep only one edge out and set proper flags. */
|
||||
while (src->succ->succ_next)
|
||||
remove_edge (src->succ);
|
||||
e = src->succ;
|
||||
if (fallthru)
|
||||
e->flags = EDGE_FALLTHRU;
|
||||
else
|
||||
e->flags = 0;
|
||||
|
||||
/* Fixup barriers. */
|
||||
barrier = next_nonnote_insn (insn);
|
||||
if (fallthru && GET_CODE (barrier) == BARRIER)
|
||||
flow_delete_insn (barrier);
|
||||
else if (!fallthru && GET_CODE (barrier) != BARRIER)
|
||||
emit_barrier_after (insn);
|
||||
|
||||
if (e->dest != target)
|
||||
redirect_edge_succ (e, target);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Attempt to change code to redirect edge E to TARGET.
|
||||
Don't do that on expense of adding new instructions or reordering
|
||||
basic blocks. */
|
||||
static int
|
||||
basic blocks.
|
||||
|
||||
Function can be also called with edge destionation equivalent to the
|
||||
TARGET. Then it should try the simplifications and do nothing if
|
||||
none is possible.
|
||||
|
||||
Return true if transformation suceeded. We still return flase in case
|
||||
E already destinated TARGET and we didn't managed to simplify instruction
|
||||
stream. */
|
||||
static bool
|
||||
redirect_edge_and_branch (e, target)
|
||||
edge e;
|
||||
basic_block target;
|
||||
{
|
||||
rtx insn = e->src->end;
|
||||
rtx tmp;
|
||||
rtx old_label = e->dest->head;
|
||||
if (e->flags & EDGE_FALLTHRU)
|
||||
return 0;
|
||||
basic_block src = e->src;
|
||||
rtx insn = src->end;
|
||||
|
||||
if (try_redirect_by_replacing_jump (e, target))
|
||||
return true;
|
||||
/* Do this fast path late, as we want above code to simplify for cases
|
||||
where called on single edge leaving basic block containing nontrivial
|
||||
jump insn. */
|
||||
else if (e->dest == target)
|
||||
return false;
|
||||
|
||||
/* We can only redirect non-fallthru edges of jump insn. */
|
||||
if (e->flags & EDGE_FALLTHRU)
|
||||
return false;
|
||||
if (GET_CODE (insn) != JUMP_INSN)
|
||||
abort ();
|
||||
return false;
|
||||
|
||||
/* Recognize a tablejump and adjust all matching cases. */
|
||||
if ((tmp = JUMP_LABEL (insn)) != NULL_RTX
|
||||
|
@ -1646,11 +1791,11 @@ redirect_edge_and_branch (e, target)
|
|||
one basic block to the other in case only one computed_jump is
|
||||
available. */
|
||||
if (computed_jump_p (insn))
|
||||
return 0;
|
||||
return false;
|
||||
|
||||
/* A return instruction can't be redirected. */
|
||||
if (returnjump_p (insn))
|
||||
return 0;
|
||||
return false;
|
||||
|
||||
/* If the insn doesn't go where we think, we're confused. */
|
||||
if (JUMP_LABEL (insn) != old_label)
|
||||
|
@ -1658,11 +1803,27 @@ redirect_edge_and_branch (e, target)
|
|||
redirect_jump (insn, block_label (target), 0);
|
||||
}
|
||||
|
||||
redirect_edge_succ (e, target);
|
||||
return 1;
|
||||
if (rtl_dump_file)
|
||||
fprintf (rtl_dump_file, "Edge %i->%i redirected to %i\n",
|
||||
e->src->index, e->dest->index, target->index);
|
||||
if (e->dest != target)
|
||||
{
|
||||
edge s;
|
||||
/* Check whether the edge is already present. */
|
||||
for (s = src->succ; s; s=s->succ_next)
|
||||
if (s->dest == target)
|
||||
break;
|
||||
if (s)
|
||||
{
|
||||
s->flags |= e->flags;
|
||||
remove_edge (e);
|
||||
}
|
||||
else
|
||||
redirect_edge_succ (e, target);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/* Split a (typically critical) edge. Return the new block.
|
||||
Abort on abnormal edges.
|
||||
|
||||
|
@ -2331,6 +2492,19 @@ flow_delete_insn (insn)
|
|||
&& GET_CODE (XEXP (note, 0)) == CODE_LABEL)
|
||||
LABEL_NUSES (XEXP (note, 0))--;
|
||||
|
||||
if (GET_CODE (insn) == JUMP_INSN
|
||||
&& (GET_CODE (PATTERN (insn)) == ADDR_VEC
|
||||
|| GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC))
|
||||
{
|
||||
rtx pat = PATTERN (insn);
|
||||
int diff_vec_p = GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC;
|
||||
int len = XVECLEN (pat, diff_vec_p);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
LABEL_NUSES (XEXP (XVECEXP (pat, diff_vec_p, i), 0))--;
|
||||
}
|
||||
|
||||
return next;
|
||||
}
|
||||
|
||||
|
@ -2668,37 +2842,211 @@ merge_blocks (e, b, c)
|
|||
}
|
||||
}
|
||||
|
||||
/* Top level driver for merge_blocks. */
|
||||
/* Simplify conditional jump around an jump.
|
||||
Return nonzero in case optimization matched. */
|
||||
|
||||
static void
|
||||
try_merge_blocks ()
|
||||
static bool
|
||||
try_simplify_condjump (src)
|
||||
basic_block src;
|
||||
{
|
||||
basic_block final_block, next_block;
|
||||
rtx insn = src->end;
|
||||
edge branch, fallthru;
|
||||
|
||||
if (!any_condjump_p (insn))
|
||||
return false;
|
||||
|
||||
fallthru = FALLTHRU_EDGE (src);
|
||||
|
||||
/* Following block must be simple forwarder block with single
|
||||
entry and must not be last in the stream. */
|
||||
next_block = fallthru->dest;
|
||||
if (!forwarder_block_p (next_block)
|
||||
|| next_block->pred->pred_next
|
||||
|| next_block->index == n_basic_blocks - 1)
|
||||
return false;
|
||||
|
||||
/* The branch must target to block afterwards. */
|
||||
final_block = BASIC_BLOCK (next_block->index + 1);
|
||||
|
||||
branch = BRANCH_EDGE (src);
|
||||
|
||||
if (branch->dest != final_block)
|
||||
return false;
|
||||
|
||||
/* Avoid jump.c from being overactive on removin ureachable insns. */
|
||||
LABEL_NUSES (JUMP_LABEL (insn))++;
|
||||
if (!invert_jump (insn, block_label (next_block->succ->dest), 1))
|
||||
{
|
||||
LABEL_NUSES (JUMP_LABEL (insn))--;
|
||||
return false;
|
||||
}
|
||||
if (rtl_dump_file)
|
||||
fprintf (rtl_dump_file, "Simplifying condjump %i around jump %i\n",
|
||||
INSN_UID (insn), INSN_UID (next_block->end));
|
||||
|
||||
redirect_edge_succ (branch, final_block);
|
||||
redirect_edge_succ (fallthru, next_block->succ->dest);
|
||||
|
||||
branch->flags |= EDGE_FALLTHRU;
|
||||
fallthru->flags &= EDGE_FALLTHRU;
|
||||
|
||||
flow_delete_block (next_block);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Attempt to forward edges leaving basic block B.
|
||||
Return nonzero if sucessfull. */
|
||||
|
||||
static bool
|
||||
try_forward_edges (b)
|
||||
basic_block b;
|
||||
{
|
||||
bool changed = 0;
|
||||
edge e;
|
||||
for (e = b->succ; e; e = e->succ_next)
|
||||
{
|
||||
basic_block target = e->dest, first = e->dest;
|
||||
int counter = 0;
|
||||
|
||||
/* Look for the real destination of jump.
|
||||
Avoid inifinite loop in the infinite empty loop by counting
|
||||
up to n_basic_blocks. */
|
||||
while (forwarder_block_p (target)
|
||||
&& target->succ->dest != EXIT_BLOCK_PTR
|
||||
&& counter < n_basic_blocks)
|
||||
{
|
||||
/* Bypass trivial infinite loops. */
|
||||
if (target == target->succ->dest)
|
||||
counter = n_basic_blocks;
|
||||
target = target->succ->dest, counter++;
|
||||
}
|
||||
|
||||
if (target != first && counter < n_basic_blocks
|
||||
&& redirect_edge_and_branch (e, target))
|
||||
{
|
||||
while (first != target)
|
||||
{
|
||||
first->count -= e->count;
|
||||
first->succ->count -= e->count;
|
||||
first->frequency -= ((e->probability * b->frequency
|
||||
+ REG_BR_PROB_BASE / 2)
|
||||
/ REG_BR_PROB_BASE);
|
||||
first = first->succ->dest;
|
||||
}
|
||||
/* We've possibly removed the edge. */
|
||||
changed = 1;
|
||||
e = b->succ;
|
||||
}
|
||||
else if (rtl_dump_file && counter == n_basic_blocks)
|
||||
fprintf (rtl_dump_file, "Infinite loop in BB %i.\n", target->index);
|
||||
else if (rtl_dump_file && first != target)
|
||||
fprintf (rtl_dump_file,
|
||||
"Forwarding edge %i->%i to %i failed.\n", b->index,
|
||||
e->dest->index, target->index);
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
/* Do simple CFG optimizations - basic block merging, simplifying of jump
|
||||
instructions etc.
|
||||
|
||||
Return nonzero in case some optimizations matched. */
|
||||
|
||||
static bool
|
||||
try_optimize_cfg ()
|
||||
{
|
||||
int i;
|
||||
bool changed_overall = 0;
|
||||
bool changed;
|
||||
|
||||
/* 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. */
|
||||
|
||||
for (i = 0; i < n_basic_blocks;)
|
||||
do
|
||||
{
|
||||
basic_block c, b = BASIC_BLOCK (i);
|
||||
edge s;
|
||||
changed = 0;
|
||||
for (i = 0; i < n_basic_blocks;)
|
||||
{
|
||||
basic_block c, b = BASIC_BLOCK (i);
|
||||
edge s;
|
||||
int changed_here = 0;
|
||||
|
||||
/* A loop because chains of blocks might be combineable. */
|
||||
while ((s = b->succ) != NULL
|
||||
&& s->succ_next == NULL
|
||||
&& (s->flags & EDGE_EH) == 0
|
||||
&& (c = s->dest) != EXIT_BLOCK_PTR
|
||||
&& c->pred->pred_next == NULL
|
||||
/* If the jump insn has side effects, we can't kill the edge. */
|
||||
&& (GET_CODE (b->end) != JUMP_INSN
|
||||
|| onlyjump_p (b->end))
|
||||
&& merge_blocks (s, b, c))
|
||||
continue;
|
||||
/* Delete trivially dead basic block. */
|
||||
if (b->pred == NULL)
|
||||
{
|
||||
c = BASIC_BLOCK (i - 1);
|
||||
if (rtl_dump_file)
|
||||
fprintf (rtl_dump_file, "Deleting block %i.\n", b->index);
|
||||
flow_delete_block (b);
|
||||
changed = 1;
|
||||
b = c;
|
||||
}
|
||||
/* The fallthru forwarder block can be deleted. */
|
||||
if (b->pred->pred_next == NULL
|
||||
&& forwarder_block_p (b)
|
||||
&& (b->pred->flags & EDGE_FALLTHRU)
|
||||
&& (b->succ->flags & EDGE_FALLTHRU))
|
||||
{
|
||||
if (rtl_dump_file)
|
||||
fprintf (rtl_dump_file, "Deleting fallthru block %i.\n",
|
||||
b->index);
|
||||
c = BASIC_BLOCK (i ? i - 1 : i + 1);
|
||||
redirect_edge_succ (b->pred, b->succ->dest);
|
||||
flow_delete_block (b);
|
||||
changed = 1;
|
||||
b = c;
|
||||
}
|
||||
|
||||
/* Don't get confused by the index shift caused by deleting blocks. */
|
||||
i = b->index + 1;
|
||||
/* A loop because chains of blocks might be combineable. */
|
||||
while ((s = b->succ) != NULL
|
||||
&& s->succ_next == NULL
|
||||
&& (s->flags & EDGE_EH) == 0
|
||||
&& (c = s->dest) != EXIT_BLOCK_PTR
|
||||
&& c->pred->pred_next == NULL
|
||||
/* If the jump insn has side effects, we can't kill the edge. */
|
||||
&& (GET_CODE (b->end) != JUMP_INSN
|
||||
|| onlyjump_p (b->end)) && merge_blocks (s, b, c))
|
||||
changed_here = 1;
|
||||
|
||||
if (try_simplify_condjump (b))
|
||||
changed_here = 1;
|
||||
|
||||
/* In the case basic blocks has single outgoing edge, but over by the
|
||||
non-trivial jump instruction, we can replace it by unconditional
|
||||
jump, or delete the jump completely. Use logic of
|
||||
redirect_edge_and_branch to do the dirty job for us.
|
||||
|
||||
We match cases as conditional jumps jumping to the next block or
|
||||
dispatch tables. */
|
||||
|
||||
if (b->succ
|
||||
&& b->succ->succ_next == NULL
|
||||
&& GET_CODE (b->end) == JUMP_INSN
|
||||
&& b->succ->dest != EXIT_BLOCK_PTR
|
||||
&& redirect_edge_and_branch (b->succ, b->succ->dest))
|
||||
changed_here = 1;
|
||||
|
||||
if (try_forward_edges (b))
|
||||
changed_here = 1;
|
||||
|
||||
/* Don't get confused by the index shift caused by deleting
|
||||
blocks. */
|
||||
if (!changed_here)
|
||||
i = b->index + 1;
|
||||
else
|
||||
changed = 1;
|
||||
}
|
||||
changed_overall |= changed;
|
||||
changed = 0;
|
||||
}
|
||||
while (changed);
|
||||
#ifdef ENABLE_CHECKING
|
||||
if (changed)
|
||||
verify_flow_info ();
|
||||
#endif
|
||||
return changed_overall;
|
||||
}
|
||||
|
||||
/* The given edge should potentially be a fallthru edge. If that is in
|
||||
|
|
Loading…
Add table
Reference in a new issue