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:
Jan Hubicka 2002-03-06 11:17:23 +01:00 committed by Jan Hubicka
parent 9533dec173
commit 3dec402428
14 changed files with 388 additions and 183 deletions

View File

@ -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

View File

@ -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)

View File

@ -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));

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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;
}

View File

@ -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

View File

@ -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,

View File

@ -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. */

View File

@ -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));

View File

@ -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;
}

View File

@ -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")

View File

@ -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);