cfgrtl.c (delete_insn_and_edges, [...]): New.
* cfgrtl.c (delete_insn_and_edges, delete_insn_chain_and_edges): New. * rtl.h (delete_insn_and_edges, delete_insn_chain_and_edges): Declare * basic-block.h (update_life_info, update_life_info_in_dirty_blocks, delete_noop_moves): Return indeger. * flow.c (ndead): New variable. (propagate_block_delete_insn): Use delete_insn_and_edges; remove BB argument; update callers. (propagate_block_delete_libcall): Use delete_insn_chain_and_edges. (life_analysis): Do not call purge_all_dead_edges. (update_life_info): Return number of deleted insns; print statistics. (update_life_info_in_dirty_blocks): likewise. (delete_noop_moves): Use delete_insn_and_edges; print statistics; return number of insns deleted. * cse.c: Include timevar.h (delete_trivially_dead_insns): Kill preserve_basic_blocks argument; iterate until stabilizes; print statistics; return number of killed insns. * Makefile.in: (cse.o): Add timevar.h dependency * rtl.h (delete_trivially_dead_insns): New. * timever.def: Add TV_DELETE_TRIVIALLY_DEAD timer. * toplev.c (rest_of_compilation): Update callers. * cfgcleanup.c (try_optimize_cfg): Kill blocks. (try_optimize_cfg): Do not update liveness. (cleanup-cfg): Loop until try_optimize_cfg and dead code removal stabilizes; use delete_trivially_dead_insns. * cfgrtl.c (verify_flow_info): Sanity check outgoing edges. From-SVN: r50355
This commit is contained in:
parent
9533dec173
commit
3dec402428
14 changed files with 388 additions and 183 deletions
|
@ -1,3 +1,36 @@
|
|||
Wed Mar 6 10:59:39 CET 2002 Jan Hubicka <jh@suse.cz>
|
||||
|
||||
* cfgrtl.c (delete_insn_and_edges, delete_insn_chain_and_edges): New.
|
||||
* rtl.h (delete_insn_and_edges, delete_insn_chain_and_edges): Declare
|
||||
|
||||
* basic-block.h (update_life_info, update_life_info_in_dirty_blocks,
|
||||
delete_noop_moves): Return indeger.
|
||||
* flow.c (ndead): New variable.
|
||||
(propagate_block_delete_insn): Use delete_insn_and_edges; remove
|
||||
BB argument; update callers.
|
||||
(propagate_block_delete_libcall): Use delete_insn_chain_and_edges.
|
||||
(life_analysis): Do not call purge_all_dead_edges.
|
||||
(update_life_info): Return number of deleted insns; print statistics.
|
||||
(update_life_info_in_dirty_blocks): likewise.
|
||||
(delete_noop_moves): Use delete_insn_and_edges; print statistics;
|
||||
return number of insns deleted.
|
||||
|
||||
* cse.c: Include timevar.h
|
||||
(delete_trivially_dead_insns): Kill preserve_basic_blocks argument;
|
||||
iterate until stabilizes; print statistics; return number of killed
|
||||
insns.
|
||||
* Makefile.in: (cse.o): Add timevar.h dependency
|
||||
* rtl.h (delete_trivially_dead_insns): New.
|
||||
* timever.def: Add TV_DELETE_TRIVIALLY_DEAD timer.
|
||||
* toplev.c (rest_of_compilation): Update callers.
|
||||
|
||||
* cfgcleanup.c (try_optimize_cfg): Kill blocks.
|
||||
(try_optimize_cfg): Do not update liveness.
|
||||
(cleanup-cfg): Loop until try_optimize_cfg and dead code
|
||||
removal stabilizes; use delete_trivially_dead_insns.
|
||||
|
||||
* cfgrtl.c (verify_flow_info): Sanity check outgoing edges.
|
||||
|
||||
2002-03-05 Zack Weinberg <zack@codesourcery.com>
|
||||
|
||||
* cppmain.c (setup_callbacks): Disable #pragma and #ident
|
||||
|
|
|
@ -1445,7 +1445,7 @@ cselib.o : cselib.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(REGS_H) \
|
|||
output.h function.h cselib.h $(GGC_H) $(OBSTACK_H) $(TM_P_H)
|
||||
cse.o : cse.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(REGS_H) hard-reg-set.h flags.h \
|
||||
real.h insn-config.h $(RECOG_H) $(EXPR_H) toplev.h output.h function.h \
|
||||
$(BASIC_BLOCK_H) $(GGC_H) $(TM_P_H)
|
||||
$(BASIC_BLOCK_H) $(GGC_H) $(TM_P_H) $(TIMEVAR_H)
|
||||
gcse.o : gcse.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(REGS_H) hard-reg-set.h \
|
||||
flags.h real.h insn-config.h ggc.h $(RECOG_H) $(EXPR_H) $(BASIC_BLOCK_H) \
|
||||
function.h output.h toplev.h $(TM_P_H) $(PARAMS_H)
|
||||
|
|
|
@ -295,7 +295,10 @@ extern void free_basic_block_vars PARAMS ((int));
|
|||
extern edge split_block PARAMS ((basic_block, rtx));
|
||||
extern basic_block split_edge PARAMS ((edge));
|
||||
extern void insert_insn_on_edge PARAMS ((rtx, edge));
|
||||
|
||||
extern void commit_edge_insertions PARAMS ((void));
|
||||
extern void commit_edge_insertions_watch_calls PARAMS ((void));
|
||||
|
||||
extern void remove_fake_edges PARAMS ((void));
|
||||
extern void add_noreturn_fake_exit_edges PARAMS ((void));
|
||||
extern void connect_infinite_loops_to_exit PARAMS ((void));
|
||||
|
@ -588,9 +591,9 @@ enum update_life_extent
|
|||
#define LOOP_ALL 31 /* All of the above */
|
||||
|
||||
extern void life_analysis PARAMS ((rtx, FILE *, int));
|
||||
extern void update_life_info PARAMS ((sbitmap, enum update_life_extent,
|
||||
extern int update_life_info PARAMS ((sbitmap, enum update_life_extent,
|
||||
int));
|
||||
extern void update_life_info_in_dirty_blocks PARAMS ((enum update_life_extent,
|
||||
extern int update_life_info_in_dirty_blocks PARAMS ((enum update_life_extent,
|
||||
int));
|
||||
extern int count_or_remove_death_notes PARAMS ((sbitmap, int));
|
||||
extern int propagate_block PARAMS ((basic_block, regset, regset, regset,
|
||||
|
@ -636,7 +639,7 @@ extern void allocate_bb_life_data PARAMS ((void));
|
|||
extern void expunge_block PARAMS ((basic_block));
|
||||
extern basic_block alloc_block PARAMS ((void));
|
||||
extern void find_unreachable_blocks PARAMS ((void));
|
||||
extern void delete_noop_moves PARAMS ((rtx));
|
||||
extern int delete_noop_moves PARAMS ((rtx));
|
||||
extern basic_block redirect_edge_and_branch_force PARAMS ((edge, basic_block));
|
||||
extern basic_block force_nonfallthru PARAMS ((edge));
|
||||
extern bool redirect_edge_and_branch PARAMS ((edge, basic_block));
|
||||
|
|
|
@ -55,7 +55,6 @@ static void flow_dfs_compute_reverse_finish
|
|||
PARAMS ((depth_first_search_ds));
|
||||
static void remove_fake_successors PARAMS ((basic_block));
|
||||
static bool need_fake_edge_p PARAMS ((rtx));
|
||||
static bool keep_with_call_p PARAMS ((rtx));
|
||||
|
||||
/* Return true if the block has no effect and only forwards control flow to
|
||||
its single destination. */
|
||||
|
@ -212,32 +211,6 @@ need_fake_edge_p (insn)
|
|||
|| GET_CODE (PATTERN (insn)) == ASM_INPUT);
|
||||
}
|
||||
|
||||
/* Return true if INSN should be kept in the same block as a preceding call.
|
||||
This is done for a single-set whose destination is a fixed register or
|
||||
whose source is the function return value. This is a helper function for
|
||||
flow_call_edges_add. */
|
||||
|
||||
static bool
|
||||
keep_with_call_p (insn)
|
||||
rtx insn;
|
||||
{
|
||||
rtx set;
|
||||
|
||||
if (INSN_P (insn) && (set = single_set (insn)) != NULL)
|
||||
{
|
||||
if (GET_CODE (SET_DEST (set)) == REG
|
||||
&& fixed_regs[REGNO (SET_DEST (set))]
|
||||
&& general_operand (SET_SRC (set), VOIDmode))
|
||||
return true;
|
||||
if (GET_CODE (SET_SRC (set)) == REG
|
||||
&& FUNCTION_VALUE_REGNO_P (REGNO (SET_SRC (set)))
|
||||
&& GET_CODE (SET_DEST (set)) == REG
|
||||
&& REGNO (SET_DEST (set)) >= FIRST_PSEUDO_REGISTER)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Add fake edges to the function exit for any non constant and non noreturn
|
||||
calls, volatile inline assembly in the bitmap of blocks specified by
|
||||
BLOCKS or to the whole CFG if BLOCKS is zero. Return the number of blocks
|
||||
|
|
|
@ -1510,7 +1510,6 @@ try_optimize_cfg (mode)
|
|||
bool changed_overall = false;
|
||||
bool changed;
|
||||
int iterations = 0;
|
||||
sbitmap blocks;
|
||||
|
||||
if (mode & CLEANUP_CROSSJUMP)
|
||||
add_noreturn_fake_exit_edges ();
|
||||
|
@ -1673,11 +1672,6 @@ try_optimize_cfg (mode)
|
|||
if (mode & CLEANUP_CROSSJUMP)
|
||||
remove_fake_edges ();
|
||||
|
||||
if ((mode & CLEANUP_UPDATE_LIFE) && changed_overall)
|
||||
update_life_info_in_dirty_blocks (UPDATE_LIFE_GLOBAL,
|
||||
PROP_DEATH_NOTES | PROP_SCAN_DEAD_CODE
|
||||
| PROP_KILL_DEAD_CODE | PROP_LOG_LINKS);
|
||||
|
||||
for (i = 0; i < n_basic_blocks; i++)
|
||||
BASIC_BLOCK (i)->aux = NULL;
|
||||
|
||||
|
@ -1720,9 +1714,39 @@ cleanup_cfg (mode)
|
|||
bool changed = false;
|
||||
|
||||
timevar_push (TV_CLEANUP_CFG);
|
||||
changed = delete_unreachable_blocks ();
|
||||
if (try_optimize_cfg (mode))
|
||||
delete_unreachable_blocks (), changed = true;
|
||||
if (delete_unreachable_blocks ())
|
||||
{
|
||||
changed = true;
|
||||
/* We've possibly created trivially dead code. Cleanup it right
|
||||
now to introduce more oppurtunities for try_optimize_cfg. */
|
||||
if (!(mode & (CLEANUP_UPDATE_LIFE | CLEANUP_PRE_SIBCALL))
|
||||
&& !reload_completed)
|
||||
delete_trivially_dead_insns (get_insns(), max_reg_num ());
|
||||
}
|
||||
while (try_optimize_cfg (mode))
|
||||
{
|
||||
delete_unreachable_blocks (), changed = true;
|
||||
if (mode & CLEANUP_UPDATE_LIFE)
|
||||
{
|
||||
/* Cleaning up CFG introduces more oppurtunities for dead code
|
||||
removal that in turn may introduce more oppurtunities for
|
||||
cleaning up the CFG. */
|
||||
if (!update_life_info_in_dirty_blocks (UPDATE_LIFE_GLOBAL,
|
||||
PROP_DEATH_NOTES
|
||||
| PROP_SCAN_DEAD_CODE
|
||||
| PROP_KILL_DEAD_CODE
|
||||
| PROP_LOG_LINKS))
|
||||
break;
|
||||
}
|
||||
else if (!(mode & CLEANUP_PRE_SIBCALL) && !reload_completed)
|
||||
{
|
||||
if (!delete_trivially_dead_insns (get_insns(), max_reg_num ()))
|
||||
break;
|
||||
}
|
||||
else
|
||||
break;
|
||||
delete_dead_jumptables ();
|
||||
}
|
||||
|
||||
/* Kill the data we won't maintain. */
|
||||
free_EXPR_LIST_list (&label_value_list);
|
||||
|
|
256
gcc/cfgrtl.c
256
gcc/cfgrtl.c
|
@ -74,7 +74,7 @@ rtx tail_recursion_label_list;
|
|||
|
||||
static int can_delete_note_p PARAMS ((rtx));
|
||||
static int can_delete_label_p PARAMS ((rtx));
|
||||
static void commit_one_edge_insertion PARAMS ((edge));
|
||||
static void commit_one_edge_insertion PARAMS ((edge, int));
|
||||
static bool try_redirect_by_replacing_jump PARAMS ((edge, basic_block));
|
||||
static rtx last_loop_beg_note PARAMS ((rtx));
|
||||
static bool back_edge_of_syntactic_loop_p PARAMS ((basic_block, basic_block));
|
||||
|
@ -178,6 +178,26 @@ delete_insn (insn)
|
|||
return next;
|
||||
}
|
||||
|
||||
/* Like delete_insn but also purge dead edges from BB. */
|
||||
rtx
|
||||
delete_insn_and_edges (insn)
|
||||
rtx insn;
|
||||
{
|
||||
rtx x;
|
||||
bool purge = false;
|
||||
|
||||
if (basic_block_for_insn
|
||||
&& INSN_P (insn)
|
||||
&& (unsigned int)INSN_UID (insn) < basic_block_for_insn->num_elements
|
||||
&& BLOCK_FOR_INSN (insn)
|
||||
&& BLOCK_FOR_INSN (insn)->end == insn)
|
||||
purge = true;
|
||||
x = delete_insn (insn);
|
||||
if (purge)
|
||||
purge_dead_edges (BLOCK_FOR_INSN (insn));
|
||||
return x;
|
||||
}
|
||||
|
||||
/* Unlink a chain of insns between START and FINISH, leaving notes
|
||||
that must be paired. */
|
||||
|
||||
|
@ -203,6 +223,24 @@ delete_insn_chain (start, finish)
|
|||
start = next;
|
||||
}
|
||||
}
|
||||
|
||||
/* Like delete_insn but also purge dead edges from BB. */
|
||||
void
|
||||
delete_insn_chain_and_edges (first, last)
|
||||
rtx first, last;
|
||||
{
|
||||
bool purge = false;
|
||||
|
||||
if (basic_block_for_insn
|
||||
&& INSN_P (last)
|
||||
&& (unsigned int)INSN_UID (last) < basic_block_for_insn->num_elements
|
||||
&& BLOCK_FOR_INSN (last)
|
||||
&& BLOCK_FOR_INSN (last)->end == last)
|
||||
purge = true;
|
||||
delete_insn_chain (first, last);
|
||||
if (purge)
|
||||
purge_dead_edges (BLOCK_FOR_INSN (last));
|
||||
}
|
||||
|
||||
/* Create a new basic block consisting of the instructions between HEAD and END
|
||||
inclusive. This function is designed to allow fast BB construction - reuses
|
||||
|
@ -1271,8 +1309,9 @@ insert_insn_on_edge (pattern, e)
|
|||
/* Update the CFG for the instructions queued on edge E. */
|
||||
|
||||
static void
|
||||
commit_one_edge_insertion (e)
|
||||
commit_one_edge_insertion (e, watch_calls)
|
||||
edge e;
|
||||
int watch_calls;
|
||||
{
|
||||
rtx before = NULL_RTX, after = NULL_RTX, insns, tmp, last;
|
||||
basic_block bb;
|
||||
|
@ -1281,63 +1320,84 @@ commit_one_edge_insertion (e)
|
|||
insns = e->insns;
|
||||
e->insns = NULL_RTX;
|
||||
|
||||
/* Figure out where to put these things. If the destination has
|
||||
one predecessor, insert there. Except for the exit block. */
|
||||
if (e->dest->pred->pred_next == NULL
|
||||
&& e->dest != EXIT_BLOCK_PTR)
|
||||
/* Special case -- avoid inserting code between call and storing
|
||||
its return value. */
|
||||
if (watch_calls && (e->flags & EDGE_FALLTHRU) && !e->dest->pred->pred_next
|
||||
&& e->src != ENTRY_BLOCK_PTR
|
||||
&& GET_CODE (e->src->end) == CALL_INSN)
|
||||
{
|
||||
rtx next = next_nonnote_insn (e->src->end);
|
||||
|
||||
after = e->dest->head;
|
||||
/* The first insn after the call may be a stack pop, skip it. */
|
||||
while (next
|
||||
&& keep_with_call_p (next))
|
||||
{
|
||||
after = next;
|
||||
next = next_nonnote_insn (next);
|
||||
}
|
||||
bb = e->dest;
|
||||
|
||||
/* Get the location correct wrt a code label, and "nice" wrt
|
||||
a basic block note, and before everything else. */
|
||||
tmp = bb->head;
|
||||
if (GET_CODE (tmp) == CODE_LABEL)
|
||||
tmp = NEXT_INSN (tmp);
|
||||
if (NOTE_INSN_BASIC_BLOCK_P (tmp))
|
||||
tmp = NEXT_INSN (tmp);
|
||||
if (tmp == bb->head)
|
||||
before = tmp;
|
||||
else
|
||||
after = PREV_INSN (tmp);
|
||||
}
|
||||
|
||||
/* If the source has one successor and the edge is not abnormal,
|
||||
insert there. Except for the entry block. */
|
||||
else if ((e->flags & EDGE_ABNORMAL) == 0
|
||||
&& e->src->succ->succ_next == NULL
|
||||
&& e->src != ENTRY_BLOCK_PTR)
|
||||
if (!before && !after)
|
||||
{
|
||||
bb = e->src;
|
||||
/* Figure out where to put these things. If the destination has
|
||||
one predecessor, insert there. Except for the exit block. */
|
||||
if (e->dest->pred->pred_next == NULL && e->dest != EXIT_BLOCK_PTR)
|
||||
{
|
||||
bb = e->dest;
|
||||
|
||||
/* It is possible to have a non-simple jump here. Consider a target
|
||||
where some forms of unconditional jumps clobber a register. This
|
||||
happens on the fr30 for example.
|
||||
/* Get the location correct wrt a code label, and "nice" wrt
|
||||
a basic block note, and before everything else. */
|
||||
tmp = bb->head;
|
||||
if (GET_CODE (tmp) == CODE_LABEL)
|
||||
tmp = NEXT_INSN (tmp);
|
||||
if (NOTE_INSN_BASIC_BLOCK_P (tmp))
|
||||
tmp = NEXT_INSN (tmp);
|
||||
if (tmp == bb->head)
|
||||
before = tmp;
|
||||
else if (tmp)
|
||||
after = PREV_INSN (tmp);
|
||||
else
|
||||
after = get_last_insn ();
|
||||
}
|
||||
|
||||
We know this block has a single successor, so we can just emit
|
||||
the queued insns before the jump. */
|
||||
if (GET_CODE (bb->end) == JUMP_INSN)
|
||||
for (before = bb->end;
|
||||
GET_CODE (PREV_INSN (before)) == NOTE
|
||||
&& NOTE_LINE_NUMBER (PREV_INSN (before)) == NOTE_INSN_LOOP_BEG;
|
||||
before = PREV_INSN (before))
|
||||
;
|
||||
/* If the source has one successor and the edge is not abnormal,
|
||||
insert there. Except for the entry block. */
|
||||
else if ((e->flags & EDGE_ABNORMAL) == 0
|
||||
&& e->src->succ->succ_next == NULL
|
||||
&& e->src != ENTRY_BLOCK_PTR)
|
||||
{
|
||||
bb = e->src;
|
||||
|
||||
/* It is possible to have a non-simple jump here. Consider a target
|
||||
where some forms of unconditional jumps clobber a register. This
|
||||
happens on the fr30 for example.
|
||||
|
||||
We know this block has a single successor, so we can just emit
|
||||
the queued insns before the jump. */
|
||||
if (GET_CODE (bb->end) == JUMP_INSN)
|
||||
for (before = bb->end;
|
||||
GET_CODE (PREV_INSN (before)) == NOTE
|
||||
&& NOTE_LINE_NUMBER (PREV_INSN (before)) ==
|
||||
NOTE_INSN_LOOP_BEG; before = PREV_INSN (before))
|
||||
;
|
||||
else
|
||||
{
|
||||
/* We'd better be fallthru, or we've lost track of what's what. */
|
||||
if ((e->flags & EDGE_FALLTHRU) == 0)
|
||||
abort ();
|
||||
|
||||
after = bb->end;
|
||||
}
|
||||
}
|
||||
/* Otherwise we must split the edge. */
|
||||
else
|
||||
{
|
||||
/* We'd better be fallthru, or we've lost track of what's what. */
|
||||
if ((e->flags & EDGE_FALLTHRU) == 0)
|
||||
abort ();
|
||||
|
||||
bb = split_edge (e);
|
||||
after = bb->end;
|
||||
}
|
||||
}
|
||||
|
||||
/* Otherwise we must split the edge. */
|
||||
else
|
||||
{
|
||||
bb = split_edge (e);
|
||||
after = bb->end;
|
||||
}
|
||||
|
||||
/* Now that we've found the spot, do the insertion. */
|
||||
|
||||
if (before)
|
||||
|
@ -1352,13 +1412,12 @@ commit_one_edge_insertion (e)
|
|||
{
|
||||
/* ??? Remove all outgoing edges from BB and add one for EXIT.
|
||||
This is not currently a problem because this only happens
|
||||
for the (single) epilogue, which already has a fallthru edge
|
||||
to EXIT. */
|
||||
for the (single) epilogue, which already has a fallthru edge
|
||||
to EXIT. */
|
||||
|
||||
e = bb->succ;
|
||||
if (e->dest != EXIT_BLOCK_PTR
|
||||
|| e->succ_next != NULL
|
||||
|| (e->flags & EDGE_FALLTHRU) == 0)
|
||||
|| e->succ_next != NULL || (e->flags & EDGE_FALLTHRU) == 0)
|
||||
abort ();
|
||||
|
||||
e->flags &= ~EDGE_FALLTHRU;
|
||||
|
@ -1395,7 +1454,39 @@ commit_edge_insertions ()
|
|||
{
|
||||
next = e->succ_next;
|
||||
if (e->insns)
|
||||
commit_one_edge_insertion (e);
|
||||
commit_one_edge_insertion (e, false);
|
||||
}
|
||||
|
||||
if (++i >= n_basic_blocks)
|
||||
break;
|
||||
bb = BASIC_BLOCK (i);
|
||||
}
|
||||
}
|
||||
|
||||
/* Update the CFG for all queued instructions, taking special care of inserting
|
||||
code on edges between call and storing its return value. */
|
||||
|
||||
void
|
||||
commit_edge_insertions_watch_calls ()
|
||||
{
|
||||
int i;
|
||||
basic_block bb;
|
||||
|
||||
#ifdef ENABLE_CHECKING
|
||||
verify_flow_info ();
|
||||
#endif
|
||||
|
||||
i = -1;
|
||||
bb = ENTRY_BLOCK_PTR;
|
||||
while (1)
|
||||
{
|
||||
edge e, next;
|
||||
|
||||
for (e = bb->succ; e; e = next)
|
||||
{
|
||||
next = e->succ_next;
|
||||
if (e->insns)
|
||||
commit_one_edge_insertion (e, true);
|
||||
}
|
||||
|
||||
if (++i >= n_basic_blocks)
|
||||
|
@ -1649,7 +1740,7 @@ verify_flow_info ()
|
|||
for (i = n_basic_blocks - 1; i >= 0; i--)
|
||||
{
|
||||
basic_block bb = BASIC_BLOCK (i);
|
||||
int has_fallthru = 0;
|
||||
int n_fallthru = 0, n_eh = 0, n_call = 0, n_abnormal = 0, n_branch = 0;
|
||||
edge e;
|
||||
rtx note;
|
||||
|
||||
|
@ -1705,7 +1796,18 @@ verify_flow_info ()
|
|||
last_visited [e->dest->index + 2] = bb;
|
||||
|
||||
if (e->flags & EDGE_FALLTHRU)
|
||||
has_fallthru = 1;
|
||||
n_fallthru++;
|
||||
|
||||
if ((e->flags & ~EDGE_DFS_BACK) == 0)
|
||||
n_branch++;
|
||||
|
||||
if (e->flags & EDGE_ABNORMAL_CALL)
|
||||
n_call++;
|
||||
|
||||
if (e->flags & EDGE_EH)
|
||||
n_eh++;
|
||||
else if (e->flags & EDGE_ABNORMAL)
|
||||
n_abnormal++;
|
||||
|
||||
if ((e->flags & EDGE_FALLTHRU)
|
||||
&& e->src != ENTRY_BLOCK_PTR
|
||||
|
@ -1753,7 +1855,51 @@ verify_flow_info ()
|
|||
edge_checksum[e->dest->index + 2] += (size_t) e;
|
||||
}
|
||||
|
||||
if (!has_fallthru)
|
||||
if (n_eh && !find_reg_note (bb->end, REG_EH_REGION, NULL_RTX))
|
||||
{
|
||||
error ("Missing REG_EH_REGION note in the end of bb %i", bb->index);
|
||||
err = 1;
|
||||
}
|
||||
if (n_branch
|
||||
&& (GET_CODE (bb->end) != JUMP_INSN
|
||||
|| (n_branch > 1 && (any_uncondjump_p (bb->end)
|
||||
|| any_condjump_p (bb->end)))))
|
||||
{
|
||||
error ("Too many outgoing branch edges from bb %i", bb->index);
|
||||
err = 1;
|
||||
}
|
||||
if (n_fallthru && any_uncondjump_p (bb->end))
|
||||
{
|
||||
error ("Fallthru edge after unconditional jump %i", bb->index);
|
||||
err = 1;
|
||||
}
|
||||
if (n_branch != 1 && any_uncondjump_p (bb->end))
|
||||
{
|
||||
error ("Wrong amount of branch edges after unconditional jump %i", bb->index);
|
||||
err = 1;
|
||||
}
|
||||
if (n_branch != 1 && any_condjump_p (bb->end)
|
||||
&& JUMP_LABEL (bb->end) != BASIC_BLOCK (bb->index + 1)->head)
|
||||
{
|
||||
error ("Wrong amount of branch edges after conditional jump %i", bb->index);
|
||||
err = 1;
|
||||
}
|
||||
if (n_call && GET_CODE (bb->end) != CALL_INSN)
|
||||
{
|
||||
error ("Call edges for non-call insn in bb %i", bb->index);
|
||||
err = 1;
|
||||
}
|
||||
if (n_abnormal
|
||||
&& (GET_CODE (bb->end) != CALL_INSN && n_call != n_abnormal)
|
||||
&& (GET_CODE (bb->end) != JUMP_INSN
|
||||
|| any_condjump_p (bb->end)
|
||||
|| any_uncondjump_p (bb->end)))
|
||||
{
|
||||
error ("Abnormal edges for no purpose in bb %i", bb->index);
|
||||
err = 1;
|
||||
}
|
||||
|
||||
if (!n_fallthru)
|
||||
{
|
||||
rtx insn;
|
||||
|
||||
|
|
87
gcc/cse.c
87
gcc/cse.c
|
@ -37,6 +37,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
|||
#include "toplev.h"
|
||||
#include "output.h"
|
||||
#include "ggc.h"
|
||||
#include "timevar.h"
|
||||
|
||||
/* The basic idea of common subexpression elimination is to go
|
||||
through the code, keeping a record of expressions that would
|
||||
|
@ -7605,81 +7606,42 @@ dead_libcall_p (insn)
|
|||
move dead invariants out of loops or make givs for dead quantities. The
|
||||
remaining passes of the compilation are also sped up. */
|
||||
|
||||
void
|
||||
delete_trivially_dead_insns (insns, nreg, preserve_basic_blocks)
|
||||
int
|
||||
delete_trivially_dead_insns (insns, nreg)
|
||||
rtx insns;
|
||||
int nreg;
|
||||
int preserve_basic_blocks;
|
||||
{
|
||||
int *counts;
|
||||
rtx insn, prev;
|
||||
int i;
|
||||
int in_libcall = 0, dead_libcall = 0;
|
||||
basic_block bb;
|
||||
int ndead = 0, nlastdead, niterations = 0;
|
||||
|
||||
timevar_push (TV_DELETE_TRIVIALLY_DEAD);
|
||||
/* First count the number of times each register is used. */
|
||||
counts = (int *) xcalloc (nreg, sizeof (int));
|
||||
for (insn = next_real_insn (insns); insn; insn = next_real_insn (insn))
|
||||
count_reg_usage (insn, counts, NULL_RTX, 1);
|
||||
|
||||
/* Go from the last insn to the first and delete insns that only set unused
|
||||
registers or copy a register to itself. As we delete an insn, remove
|
||||
usage counts for registers it uses.
|
||||
do
|
||||
{
|
||||
nlastdead = ndead;
|
||||
niterations++;
|
||||
/* Go from the last insn to the first and delete insns that only set unused
|
||||
registers or copy a register to itself. As we delete an insn, remove
|
||||
usage counts for registers it uses.
|
||||
|
||||
The first jump optimization pass may leave a real insn as the last
|
||||
insn in the function. We must not skip that insn or we may end
|
||||
up deleting code that is not really dead. */
|
||||
insn = get_last_insn ();
|
||||
if (! INSN_P (insn))
|
||||
insn = prev_real_insn (insn);
|
||||
The first jump optimization pass may leave a real insn as the last
|
||||
insn in the function. We must not skip that insn or we may end
|
||||
up deleting code that is not really dead. */
|
||||
insn = get_last_insn ();
|
||||
if (! INSN_P (insn))
|
||||
insn = prev_real_insn (insn);
|
||||
|
||||
if (!preserve_basic_blocks)
|
||||
for (; insn; insn = prev)
|
||||
{
|
||||
int live_insn = 0;
|
||||
|
||||
prev = prev_real_insn (insn);
|
||||
|
||||
/* Don't delete any insns that are part of a libcall block unless
|
||||
we can delete the whole libcall block.
|
||||
|
||||
Flow or loop might get confused if we did that. Remember
|
||||
that we are scanning backwards. */
|
||||
if (find_reg_note (insn, REG_RETVAL, NULL_RTX))
|
||||
{
|
||||
in_libcall = 1;
|
||||
live_insn = 1;
|
||||
dead_libcall = dead_libcall_p (insn);
|
||||
}
|
||||
else if (in_libcall)
|
||||
live_insn = ! dead_libcall;
|
||||
else
|
||||
live_insn = insn_live_p (insn, counts);
|
||||
|
||||
/* If this is a dead insn, delete it and show registers in it aren't
|
||||
being used. */
|
||||
|
||||
if (! live_insn)
|
||||
{
|
||||
count_reg_usage (insn, counts, NULL_RTX, -1);
|
||||
delete_related_insns (insn);
|
||||
}
|
||||
|
||||
if (find_reg_note (insn, REG_LIBCALL, NULL_RTX))
|
||||
{
|
||||
in_libcall = 0;
|
||||
dead_libcall = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
for (i = 0; i < n_basic_blocks; i++)
|
||||
for (bb = BASIC_BLOCK (i), insn = bb->end; insn != bb->head; insn = prev)
|
||||
for (; insn; insn = prev)
|
||||
{
|
||||
int live_insn = 0;
|
||||
|
||||
prev = PREV_INSN (insn);
|
||||
if (!INSN_P (insn))
|
||||
continue;
|
||||
prev = prev_real_insn (insn);
|
||||
|
||||
/* Don't delete any insns that are part of a libcall block unless
|
||||
we can delete the whole libcall block.
|
||||
|
@ -7703,7 +7665,8 @@ delete_trivially_dead_insns (insns, nreg, preserve_basic_blocks)
|
|||
if (! live_insn)
|
||||
{
|
||||
count_reg_usage (insn, counts, NULL_RTX, -1);
|
||||
delete_insn (insn);
|
||||
delete_insn_and_edges (insn);
|
||||
ndead++;
|
||||
}
|
||||
|
||||
if (find_reg_note (insn, REG_LIBCALL, NULL_RTX))
|
||||
|
@ -7712,7 +7675,13 @@ delete_trivially_dead_insns (insns, nreg, preserve_basic_blocks)
|
|||
dead_libcall = 0;
|
||||
}
|
||||
}
|
||||
} while (ndead != nlastdead);
|
||||
|
||||
if (rtl_dump_file && ndead)
|
||||
fprintf (rtl_dump_file, "Deleted %i trivially dead insns; %i iterations\n",
|
||||
ndead, niterations);
|
||||
/* Clean up. */
|
||||
free (counts);
|
||||
timevar_pop (TV_DELETE_TRIVIALLY_DEAD);
|
||||
return ndead;
|
||||
}
|
||||
|
|
|
@ -2468,6 +2468,17 @@ get_insns ()
|
|||
return first_insn;
|
||||
}
|
||||
|
||||
/* Specify a new insn as the first in the chain. */
|
||||
|
||||
void
|
||||
set_first_insn (insn)
|
||||
rtx insn;
|
||||
{
|
||||
if (PREV_INSN (insn) != 0)
|
||||
abort ();
|
||||
first_insn = insn;
|
||||
}
|
||||
|
||||
/* Return the last insn emitted in current sequence or current function. */
|
||||
|
||||
rtx
|
||||
|
|
53
gcc/flow.c
53
gcc/flow.c
|
@ -276,6 +276,9 @@ struct propagate_block_info
|
|||
int flags;
|
||||
};
|
||||
|
||||
/* Number of dead insns removed. */
|
||||
static int ndead;
|
||||
|
||||
/* Maximum length of pbi->mem_set_list before we start dropping
|
||||
new elements on the floor. */
|
||||
#define MAX_MEM_SET_LIST_LEN 100
|
||||
|
@ -290,7 +293,7 @@ static void mark_reg PARAMS ((rtx, void *));
|
|||
static void mark_regs_live_at_end PARAMS ((regset));
|
||||
static int set_phi_alternative_reg PARAMS ((rtx, int, int, void *));
|
||||
static void calculate_global_regs_live PARAMS ((sbitmap, sbitmap, int));
|
||||
static void propagate_block_delete_insn PARAMS ((basic_block, rtx));
|
||||
static void propagate_block_delete_insn PARAMS ((rtx));
|
||||
static rtx propagate_block_delete_libcall PARAMS ((rtx, rtx));
|
||||
static int insn_dead_p PARAMS ((struct propagate_block_info *,
|
||||
rtx, int, rtx));
|
||||
|
@ -448,7 +451,6 @@ life_analysis (f, file, flags)
|
|||
/* Always remove no-op moves. Do this before other processing so
|
||||
that we don't have to keep re-scanning them. */
|
||||
delete_noop_moves (f);
|
||||
purge_all_dead_edges (false);
|
||||
|
||||
/* Some targets can emit simpler epilogues if they know that sp was
|
||||
not ever modified during the function. After reload, of course,
|
||||
|
@ -623,7 +625,7 @@ verify_local_live_at_start (new_live_at_start, bb)
|
|||
Including PROP_REG_INFO does not properly refresh regs_ever_live
|
||||
unless the caller resets it to zero. */
|
||||
|
||||
void
|
||||
int
|
||||
update_life_info (blocks, extent, prop_flags)
|
||||
sbitmap blocks;
|
||||
enum update_life_extent extent;
|
||||
|
@ -634,6 +636,7 @@ update_life_info (blocks, extent, prop_flags)
|
|||
int i;
|
||||
|
||||
tmp = INITIALIZE_REG_SET (tmp_head);
|
||||
ndead = 0;
|
||||
|
||||
timevar_push ((extent == UPDATE_LIFE_LOCAL || blocks)
|
||||
? TV_LIFE_UPDATE : TV_LIFE);
|
||||
|
@ -743,11 +746,14 @@ update_life_info (blocks, extent, prop_flags)
|
|||
}
|
||||
timevar_pop ((extent == UPDATE_LIFE_LOCAL || blocks)
|
||||
? TV_LIFE_UPDATE : TV_LIFE);
|
||||
if (ndead && rtl_dump_file)
|
||||
fprintf (rtl_dump_file, "deleted %i dead insns\n", ndead);
|
||||
return ndead;
|
||||
}
|
||||
|
||||
/* Update life information in all blocks where BB_DIRTY is set. */
|
||||
|
||||
void
|
||||
int
|
||||
update_life_info_in_dirty_blocks (extent, prop_flags)
|
||||
enum update_life_extent extent;
|
||||
int prop_flags;
|
||||
|
@ -755,6 +761,7 @@ update_life_info_in_dirty_blocks (extent, prop_flags)
|
|||
sbitmap update_life_blocks = sbitmap_alloc (n_basic_blocks);
|
||||
int block_num;
|
||||
int n = 0;
|
||||
int ndead;
|
||||
|
||||
sbitmap_zero (update_life_blocks);
|
||||
for (block_num = 0; block_num < n_basic_blocks; block_num++)
|
||||
|
@ -765,9 +772,10 @@ update_life_info_in_dirty_blocks (extent, prop_flags)
|
|||
}
|
||||
|
||||
if (n)
|
||||
update_life_info (update_life_blocks, extent, prop_flags);
|
||||
ndead = update_life_info (update_life_blocks, extent, prop_flags);
|
||||
|
||||
sbitmap_free (update_life_blocks);
|
||||
return ndead;
|
||||
}
|
||||
|
||||
/* Free the variables allocated by find_basic_blocks.
|
||||
|
@ -796,13 +804,14 @@ free_basic_block_vars (keep_head_end_p)
|
|||
|
||||
/* Delete any insns that copy a register to itself. */
|
||||
|
||||
void
|
||||
int
|
||||
delete_noop_moves (f)
|
||||
rtx f ATTRIBUTE_UNUSED;
|
||||
{
|
||||
int i;
|
||||
rtx insn, next;
|
||||
basic_block bb;
|
||||
int nnoops = 0;
|
||||
|
||||
for (i = 0; i < n_basic_blocks; i++)
|
||||
{
|
||||
|
@ -829,14 +838,14 @@ delete_noop_moves (f)
|
|||
XEXP (retval_note, 0) = new_libcall_insn;
|
||||
}
|
||||
|
||||
/* Do not call delete_insn here since that may change
|
||||
the basic block boundaries which upsets some callers. */
|
||||
PUT_CODE (insn, NOTE);
|
||||
NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
|
||||
NOTE_SOURCE_FILE (insn) = 0;
|
||||
delete_insn_and_edges (insn);
|
||||
nnoops++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (nnoops && rtl_dump_file)
|
||||
fprintf (rtl_dump_file, "deleted %i noop moves", nnoops);
|
||||
return nnoops;
|
||||
}
|
||||
|
||||
/* Delete any jump tables never referenced. We can't delete them at the
|
||||
|
@ -1483,12 +1492,11 @@ allocate_reg_life_data ()
|
|||
/* Delete dead instructions for propagate_block. */
|
||||
|
||||
static void
|
||||
propagate_block_delete_insn (bb, insn)
|
||||
basic_block bb;
|
||||
propagate_block_delete_insn (insn)
|
||||
rtx insn;
|
||||
{
|
||||
rtx inote = find_reg_note (insn, REG_LABEL, NULL_RTX);
|
||||
bool purge = false;
|
||||
basic_block bb = BLOCK_FOR_INSN (insn);
|
||||
|
||||
/* If the insn referred to a label, and that label was attached to
|
||||
an ADDR_VEC, it's safe to delete the ADDR_VEC. In fact, it's
|
||||
|
@ -1526,15 +1534,13 @@ propagate_block_delete_insn (bb, insn)
|
|||
for (i = 0; i < len; i++)
|
||||
LABEL_NUSES (XEXP (XVECEXP (pat, diff_vec_p, i), 0))--;
|
||||
|
||||
delete_insn (next);
|
||||
delete_insn_and_edges (next);
|
||||
ndead++;
|
||||
}
|
||||
}
|
||||
|
||||
if (bb->end == insn)
|
||||
purge = true;
|
||||
delete_insn (insn);
|
||||
if (purge)
|
||||
purge_dead_edges (bb);
|
||||
delete_insn_and_edges (insn);
|
||||
ndead++;
|
||||
}
|
||||
|
||||
/* Delete dead libcalls for propagate_block. Return the insn
|
||||
|
@ -1547,7 +1553,8 @@ propagate_block_delete_libcall ( insn, note)
|
|||
rtx first = XEXP (note, 0);
|
||||
rtx before = PREV_INSN (first);
|
||||
|
||||
delete_insn_chain (first, insn);
|
||||
delete_insn_chain_and_edges (first, insn);
|
||||
ndead++;
|
||||
return before;
|
||||
}
|
||||
|
||||
|
@ -1608,7 +1615,7 @@ propagate_one_insn (pbi, insn)
|
|||
if (libcall_is_dead)
|
||||
prev = propagate_block_delete_libcall ( insn, note);
|
||||
else
|
||||
propagate_block_delete_insn (pbi->bb, insn);
|
||||
propagate_block_delete_insn (insn);
|
||||
|
||||
return prev;
|
||||
}
|
||||
|
@ -3940,7 +3947,7 @@ try_pre_increment_1 (pbi, insn)
|
|||
{
|
||||
/* We have found a suitable auto-increment and already changed
|
||||
insn Y to do it. So flush this increment instruction. */
|
||||
propagate_block_delete_insn (pbi->bb, insn);
|
||||
propagate_block_delete_insn (insn);
|
||||
|
||||
/* Count a reference to this reg for the increment insn we are
|
||||
deleting. When a reg is incremented, spilling it is worse,
|
||||
|
|
|
@ -169,7 +169,7 @@ instrument_edges (el)
|
|||
if (rtl_dump_file)
|
||||
fprintf (rtl_dump_file, "%d edges instrumented\n", num_instr_edges);
|
||||
|
||||
commit_edge_insertions ();
|
||||
commit_edge_insertions_watch_calls ();
|
||||
}
|
||||
|
||||
/* Output STRING to bb_file, surrounded by DELIMITER. */
|
||||
|
|
|
@ -1518,6 +1518,7 @@ 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));
|
||||
extern rtx find_first_parameter_load PARAMS ((rtx, rtx));
|
||||
extern bool keep_with_call_p PARAMS ((rtx));
|
||||
|
||||
/* flow.c */
|
||||
|
||||
|
@ -1792,7 +1793,7 @@ struct cse_basic_block_data;
|
|||
|
||||
extern int rtx_cost PARAMS ((rtx, enum rtx_code));
|
||||
extern int address_cost PARAMS ((rtx, enum machine_mode));
|
||||
extern void delete_trivially_dead_insns PARAMS ((rtx, int, int));
|
||||
extern int delete_trivially_dead_insns PARAMS ((rtx, int));
|
||||
#ifdef BUFSIZ
|
||||
extern int cse_main PARAMS ((rtx, int, int, FILE *));
|
||||
#endif
|
||||
|
@ -1873,6 +1874,8 @@ extern void renumber_insns PARAMS ((FILE *));
|
|||
extern void remove_unnecessary_notes PARAMS ((void));
|
||||
extern rtx delete_insn PARAMS ((rtx));
|
||||
extern void delete_insn_chain PARAMS ((rtx, rtx));
|
||||
extern rtx delete_insn_and_edges PARAMS ((rtx));
|
||||
extern void delete_insn_chain_and_edges PARAMS ((rtx, rtx));
|
||||
|
||||
/* In combine.c */
|
||||
extern int combine_instructions PARAMS ((rtx, unsigned int));
|
||||
|
|
|
@ -3119,3 +3119,38 @@ find_first_parameter_load (call_insn, boundary)
|
|||
}
|
||||
return before;
|
||||
}
|
||||
|
||||
/* Return true if we should avoid inserting code between INSN and preceeding
|
||||
call instruction. */
|
||||
|
||||
bool
|
||||
keep_with_call_p (insn)
|
||||
rtx insn;
|
||||
{
|
||||
rtx set;
|
||||
|
||||
if (INSN_P (insn) && (set = single_set (insn)) != NULL)
|
||||
{
|
||||
if (GET_CODE (SET_DEST (set)) == REG
|
||||
&& fixed_regs[REGNO (SET_DEST (set))]
|
||||
&& general_operand (SET_SRC (set), VOIDmode))
|
||||
return true;
|
||||
if (GET_CODE (SET_SRC (set)) == REG
|
||||
&& FUNCTION_VALUE_REGNO_P (REGNO (SET_SRC (set)))
|
||||
&& GET_CODE (SET_DEST (set)) == REG
|
||||
&& REGNO (SET_DEST (set)) >= FIRST_PSEUDO_REGISTER)
|
||||
return true;
|
||||
/* There may be stack pop just after the call and
|
||||
before actual store of return register. Search
|
||||
for the actual store when deciding if we can break
|
||||
or not. */
|
||||
if (SET_DEST (set) == stack_pointer_rtx)
|
||||
{
|
||||
rtx i2 = next_nonnote_insn (insn);
|
||||
if (i2 && keep_with_call_p (insn))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -43,6 +43,7 @@ DEFTIMEVAR (TV_DUMP , "dump files")
|
|||
DEFTIMEVAR (TV_CFG , "cfg construction")
|
||||
/* Time spent by cleaning up CFG. */
|
||||
DEFTIMEVAR (TV_CLEANUP_CFG , "cfg cleanup")
|
||||
DEFTIMEVAR (TV_DELETE_TRIVIALLY_DEAD , "trivially dead code")
|
||||
/* Time spent by life analysis. */
|
||||
DEFTIMEVAR (TV_LIFE , "life analysis")
|
||||
DEFTIMEVAR (TV_LIFE_UPDATE , "life info update")
|
||||
|
|
|
@ -2778,7 +2778,7 @@ rest_of_compilation (decl)
|
|||
|
||||
/* Run this after jump optmizations remove all the unreachable code
|
||||
so that unreachable code will not keep values live. */
|
||||
delete_trivially_dead_insns (insns, max_reg_num (), 1);
|
||||
delete_trivially_dead_insns (insns, max_reg_num ());
|
||||
|
||||
/* Try to identify useless null pointer tests and delete them. */
|
||||
if (flag_delete_null_pointer_checks || flag_thread_jumps)
|
||||
|
@ -2851,7 +2851,7 @@ rest_of_compilation (decl)
|
|||
tem = tem2 = 0;
|
||||
timevar_push (TV_JUMP);
|
||||
rebuild_jump_labels (insns);
|
||||
delete_trivially_dead_insns (insns, max_reg_num (), 1);
|
||||
delete_trivially_dead_insns (insns, max_reg_num ());
|
||||
cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_PRE_LOOP);
|
||||
timevar_pop (TV_JUMP);
|
||||
|
||||
|
@ -2899,7 +2899,7 @@ rest_of_compilation (decl)
|
|||
trivially dead. We delete those instructions now in the
|
||||
hope that doing so will make the heuristics in loop work
|
||||
better and possibly speed up compilation. */
|
||||
delete_trivially_dead_insns (insns, max_reg_num (), 0);
|
||||
delete_trivially_dead_insns (insns, max_reg_num ());
|
||||
|
||||
/* The regscan pass is currently necessary as the alias
|
||||
analysis code depends on this information. */
|
||||
|
@ -2911,7 +2911,7 @@ rest_of_compilation (decl)
|
|||
| (flag_prefetch_loop_arrays ? LOOP_PREFETCH : 0));
|
||||
|
||||
/* Loop can create trivially dead instructions. */
|
||||
delete_trivially_dead_insns (insns, max_reg_num (), 0);
|
||||
delete_trivially_dead_insns (insns, max_reg_num ());
|
||||
close_dump_file (DFI_loop, print_rtl, insns);
|
||||
timevar_pop (TV_LOOP);
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue