\f
#include "config.h"
#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
#include "tree.h"
#include "rtl.h"
#include "tm_p.h"
#include "obstack.h"
#include "splay-tree.h"
-#define obstack_chunk_alloc xmalloc
-#define obstack_chunk_free free
-
/* EXIT_IGNORE_STACK should be nonzero if, when returning from a function,
the stack pointer does not matter. The value is tested only in
functions that have frame pointers.
/* The length of mem_set_list. */
int mem_set_list_len;
- /* Non-zero if the value of CC0 is live. */
+ /* Nonzero if the value of CC0 is live. */
int cc0_live;
- /* Flags controling the set of information propagate_block collects. */
+ /* Flags controlling the set of information propagate_block collects. */
int flags;
};
is no longer in the chain. */
if (INSN_UID (cfun->x_clobber_return_insn) < max_uid)
{
- /* Recompute insn->block mapping, since the initial mapping is
- set before we delete unreachable blocks. */
- if (BLOCK_FOR_INSN (cfun->x_clobber_return_insn) != NULL)
- warning ("control reaches end of non-void function");
+ rtx insn;
+
+ for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+ if (insn == cfun->x_clobber_return_insn)
+ {
+ warning ("control reaches end of non-void function");
+ break;
+ }
}
}
}
SET_HARD_REG_BIT (elim_reg_set, FRAME_POINTER_REGNUM);
#endif
+
+#ifdef CANNOT_CHANGE_MODE_CLASS
+ if (flags & PROP_REG_INFO)
+ {
+ int j;
+ for (j=0; j < NUM_MACHINE_MODES; ++j)
+ INIT_REG_SET (&subregs_of_mode[j]);
+ }
+#endif
+
if (! optimize)
flags &= ~(PROP_LOG_LINKS | PROP_AUTOINC | PROP_ALLOW_CFG_CHANGES);
flags &= ~(PROP_REG_INFO | PROP_AUTOINC);
/* We want alias analysis information for local dead store elimination. */
- if (optimize && (flags & PROP_SCAN_DEAD_CODE))
+ if (optimize && (flags & PROP_SCAN_DEAD_STORES))
init_alias_analysis ();
/* Always remove no-op moves. Do this before other processing so
update_life_info (NULL, UPDATE_LIFE_GLOBAL, flags);
/* Clean up. */
- if (optimize && (flags & PROP_SCAN_DEAD_CODE))
+ if (optimize && (flags & PROP_SCAN_DEAD_STORES))
end_alias_analysis ();
if (file)
regset_head tmp_head;
int i;
int stabilized_prop_flags = prop_flags;
+ basic_block bb;
tmp = INITIALIZE_REG_SET (tmp_head);
ndead = 0;
calculate_global_regs_live (blocks, blocks,
prop_flags & (PROP_SCAN_DEAD_CODE
+ | PROP_SCAN_DEAD_STORES
| PROP_ALLOW_CFG_CHANGES));
if ((prop_flags & (PROP_KILL_DEAD_CODE | PROP_ALLOW_CFG_CHANGES))
/* Removing dead code may allow the CFG to be simplified which
in turn may allow for further dead code detection / removal. */
- for (i = n_basic_blocks - 1; i >= 0; --i)
+ FOR_EACH_BB_REVERSE (bb)
{
- basic_block bb = BASIC_BLOCK (i);
-
COPY_REG_SET (tmp, bb->global_live_at_end);
changed |= propagate_block (bb, tmp, NULL, NULL,
prop_flags & (PROP_SCAN_DEAD_CODE
+ | PROP_SCAN_DEAD_STORES
| PROP_KILL_DEAD_CODE));
}
removing dead code can affect global register liveness, which
is supposed to be finalized for this call after this loop. */
stabilized_prop_flags
- &= ~(PROP_SCAN_DEAD_CODE | PROP_KILL_DEAD_CODE);
+ &= ~(PROP_SCAN_DEAD_CODE | PROP_SCAN_DEAD_STORES
+ | PROP_KILL_DEAD_CODE);
if (! changed)
break;
partial improvement (see MAX_MEM_SET_LIST_LEN usage).
Further improvement may be possible. */
cleanup_cfg (CLEANUP_EXPENSIVE);
+
+ /* Zap the life information from the last round. If we don't
+ do this, we can wind up with registers that no longer appear
+ in the code being marked live at entry, which twiggs bogus
+ warnings from regno_uninitialized. */
+ FOR_EACH_BB (bb)
+ {
+ CLEAR_REG_SET (bb->global_live_at_start);
+ CLEAR_REG_SET (bb->global_live_at_end);
+ }
}
/* If asked, remove notes from the blocks we'll update. */
{
EXECUTE_IF_SET_IN_SBITMAP (blocks, 0, i,
{
- basic_block bb = BASIC_BLOCK (i);
+ bb = BASIC_BLOCK (i);
COPY_REG_SET (tmp, bb->global_live_at_end);
propagate_block (bb, tmp, NULL, NULL, stabilized_prop_flags);
}
else
{
- for (i = n_basic_blocks - 1; i >= 0; --i)
+ FOR_EACH_BB_REVERSE (bb)
{
- basic_block bb = BASIC_BLOCK (i);
-
COPY_REG_SET (tmp, bb->global_live_at_end);
propagate_block (bb, tmp, NULL, NULL, stabilized_prop_flags);
enum update_life_extent extent;
int prop_flags;
{
- sbitmap update_life_blocks = sbitmap_alloc (n_basic_blocks);
- int block_num;
+ sbitmap update_life_blocks = sbitmap_alloc (last_basic_block);
int n = 0;
+ basic_block bb;
int retval = 0;
sbitmap_zero (update_life_blocks);
- for (block_num = 0; block_num < n_basic_blocks; block_num++)
- if (BASIC_BLOCK (block_num)->flags & BB_DIRTY)
- {
- SET_BIT (update_life_blocks, block_num);
- n++;
- }
+ FOR_EACH_BB (bb)
+ {
+ if (extent == UPDATE_LIFE_LOCAL)
+ {
+ if (bb->flags & BB_DIRTY)
+ {
+ SET_BIT (update_life_blocks, bb->index);
+ n++;
+ }
+ }
+ else
+ {
+ /* ??? Bootstrap with -march=pentium4 fails to terminate
+ with only a partial life update. */
+ SET_BIT (update_life_blocks, bb->index);
+ if (bb->flags & BB_DIRTY)
+ n++;
+ }
+ }
if (n)
retval = update_life_info (update_life_blocks, extent, prop_flags);
/* Free the variables allocated by find_basic_blocks.
- KEEP_HEAD_END_P is non-zero if basic_block_info is not to be freed. */
+ KEEP_HEAD_END_P is nonzero if basic_block_info is not to be freed. */
void
free_basic_block_vars (keep_head_end_p)
VARRAY_FREE (basic_block_info);
}
n_basic_blocks = 0;
+ last_basic_block = 0;
ENTRY_BLOCK_PTR->aux = NULL;
ENTRY_BLOCK_PTR->global_live_at_end = NULL;
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++)
+ FOR_EACH_BB (bb)
{
- bb = BASIC_BLOCK (i);
for (insn = bb->head; insn != NEXT_INSN (bb->end); insn = next)
{
next = NEXT_INSN (insn);
/* Many architectures have a GP register even without flag_pic.
Assume the pic register is not in use, or will be handled by
other means, if it is not fixed. */
- if (PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM
+ if ((unsigned) PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM
&& fixed_regs[PIC_OFFSET_TABLE_REGNUM])
SET_REGNO_REG_SET (set, PIC_OFFSET_TABLE_REGNUM);
#endif
sbitmap blocks_in, blocks_out;
int flags;
{
- basic_block *queue, *qhead, *qtail, *qend;
- regset tmp, new_live_at_end, call_used;
- regset_head tmp_head, call_used_head;
+ basic_block *queue, *qhead, *qtail, *qend, bb;
+ regset tmp, new_live_at_end, invalidated_by_call;
+ regset_head tmp_head, invalidated_by_call_head;
regset_head new_live_at_end_head;
int i;
/* Some passes used to forget clear aux field of basic block causing
- sick behaviour here. */
+ sick behavior here. */
#ifdef ENABLE_CHECKING
- if (ENTRY_BLOCK_PTR->aux || EXIT_BLOCK_PTR->aux)
- abort ();
- for (i = 0; i < n_basic_blocks; i++)
- if (BASIC_BLOCK (i)->aux)
+ FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb)
+ if (bb->aux)
abort ();
#endif
tmp = INITIALIZE_REG_SET (tmp_head);
new_live_at_end = INITIALIZE_REG_SET (new_live_at_end_head);
- call_used = INITIALIZE_REG_SET (call_used_head);
+ invalidated_by_call = INITIALIZE_REG_SET (invalidated_by_call_head);
/* Inconveniently, this is only readily available in hard reg set form. */
for (i = 0; i < FIRST_PSEUDO_REGISTER; ++i)
- if (call_used_regs[i])
- SET_REGNO_REG_SET (call_used, i);
+ if (TEST_HARD_REG_BIT (regs_invalidated_by_call, i))
+ SET_REGNO_REG_SET (invalidated_by_call, i);
/* Create a worklist. Allocate an extra slot for ENTRY_BLOCK, and one
because the `head == tail' style test for an empty queue doesn't
useful work. We use AUX non-null to flag that the block is queued. */
if (blocks_in)
{
- /* Clear out the garbage that might be hanging out in bb->aux. */
- for (i = n_basic_blocks - 1; i >= 0; --i)
- BASIC_BLOCK (i)->aux = NULL;
-
- EXECUTE_IF_SET_IN_SBITMAP (blocks_in, 0, i,
- {
- basic_block bb = BASIC_BLOCK (i);
- *--qhead = bb;
- bb->aux = bb;
- });
+ FOR_EACH_BB (bb)
+ if (TEST_BIT (blocks_in, bb->index))
+ {
+ *--qhead = bb;
+ bb->aux = bb;
+ }
}
else
{
- for (i = 0; i < n_basic_blocks; ++i)
+ FOR_EACH_BB (bb)
{
- basic_block bb = BASIC_BLOCK (i);
*--qhead = bb;
bb->aux = bb;
}
if (e->flags & EDGE_EH)
{
bitmap_operation (tmp, sb->global_live_at_start,
- call_used, BITMAP_AND_COMPL);
+ invalidated_by_call, BITMAP_AND_COMPL);
IOR_REG_SET (new_live_at_end, tmp);
}
else
/* Any constant, or pseudo with constant equivalences, may
require reloading from memory using the pic register. */
- if (PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM
+ if ((unsigned) PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM
&& fixed_regs[PIC_OFFSET_TABLE_REGNUM])
SET_REGNO_REG_SET (new_live_at_end, PIC_OFFSET_TABLE_REGNUM);
}
FREE_REG_SET (tmp);
FREE_REG_SET (new_live_at_end);
- FREE_REG_SET (call_used);
+ FREE_REG_SET (invalidated_by_call);
if (blocks_out)
{
}
else
{
- for (i = n_basic_blocks - 1; i >= 0; --i)
+ FOR_EACH_BB (bb)
{
- basic_block bb = BASIC_BLOCK (i);
FREE_REG_SET (bb->local_set);
FREE_REG_SET (bb->cond_local_set);
}
}
\f
-/* This structure is used to pass parameters to an from the
+/* This structure is used to pass parameters to and from the
the function find_regno_partial(). It is used to pass in the
register number we are looking, as well as to return any rtx
we find. */
void
allocate_bb_life_data ()
{
- int i;
+ basic_block bb;
- for (i = 0; i < n_basic_blocks; i++)
+ FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb)
{
- basic_block bb = BASIC_BLOCK (i);
-
bb->global_live_at_start = OBSTACK_ALLOC_REG_SET (&flow_obstack);
bb->global_live_at_end = OBSTACK_ALLOC_REG_SET (&flow_obstack);
}
- ENTRY_BLOCK_PTR->global_live_at_end
- = OBSTACK_ALLOC_REG_SET (&flow_obstack);
- EXIT_BLOCK_PTR->global_live_at_start
- = OBSTACK_ALLOC_REG_SET (&flow_obstack);
-
regs_live_at_setjmp = OBSTACK_ALLOC_REG_SET (&flow_obstack);
}
REG_N_DEATHS (i) = 0;
REG_N_CALLS_CROSSED (i) = 0;
REG_LIVE_LENGTH (i) = 0;
+ REG_FREQ (i) = 0;
REG_BASIC_BLOCK (i) = REG_BLOCK_UNKNOWN;
}
}
if (libcall_is_dead)
prev = propagate_block_delete_libcall ( insn, note);
else
- propagate_block_delete_insn (insn);
+ {
+
+ /* If INSN contains a RETVAL note and is dead, but the libcall
+ as a whole is not dead, then we want to remove INSN, but
+ not the whole libcall sequence.
+
+ However, we need to also remove the dangling REG_LIBCALL
+ note so that we do not have mis-matched LIBCALL/RETVAL
+ notes. In theory we could find a new location for the
+ REG_RETVAL note, but it hardly seems worth the effort.
+
+ NOTE at this point will be the RETVAL note if it exists. */
+ if (note)
+ {
+ rtx libcall_note;
+
+ libcall_note
+ = find_reg_note (XEXP (note, 0), REG_LIBCALL, NULL_RTX);
+ remove_note (XEXP (note, 0), libcall_note);
+ }
+
+ /* Similarly if INSN contains a LIBCALL note, remove the
+ dangling REG_RETVAL note. */
+ note = find_reg_note (insn, REG_LIBCALL, NULL_RTX);
+ if (note)
+ {
+ rtx retval_note;
+
+ retval_note
+ = find_reg_note (XEXP (note, 0), REG_RETVAL, NULL_RTX);
+ remove_note (XEXP (note, 0), retval_note);
+ }
+
+ /* Now delete INSN. */
+ propagate_block_delete_insn (insn);
+ }
return prev;
}
if (TEST_HARD_REG_BIT (regs_invalidated_by_call, i))
{
/* We do not want REG_UNUSED notes for these registers. */
- mark_set_1 (pbi, CLOBBER, gen_rtx_REG (reg_raw_mode[i], i),
- cond, insn,
+ mark_set_1 (pbi, CLOBBER, regno_reg_rtx[i], cond, insn,
pbi->flags & ~(PROP_DEATH_NOTES | PROP_REG_INFO));
}
}
so they are made live. */
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
if (global_regs[i])
- mark_used_reg (pbi, gen_rtx_REG (reg_raw_mode[i], i),
- cond, insn);
+ mark_used_reg (pbi, regno_reg_rtx[i], cond, insn);
}
}
&& ! (TREE_CODE (TREE_TYPE (current_function_decl)) == FUNCTION_TYPE
&& (TYPE_RETURNS_STACK_DEPRESSED
(TREE_TYPE (current_function_decl))))
- && (flags & PROP_SCAN_DEAD_CODE)
+ && (flags & PROP_SCAN_DEAD_STORES)
&& (bb->succ == NULL
|| (bb->succ->succ_next == NULL
&& bb->succ->dest == EXIT_BLOCK_PTR
case, the resulting set will be equal to the union of the two sets that
would otherwise be computed.
- Return non-zero if an INSN is deleted (i.e. by dead code removal). */
+ Return nonzero if an INSN is deleted (i.e. by dead code removal). */
int
propagate_block (bb, live, local_set, cond_local_set, flags)
(SET expressions whose destinations are registers dead after the insn).
NEEDED is the regset that says which regs are alive after the insn.
- Unless CALL_OK is non-zero, an insn is needed if it contains a CALL.
+ Unless CALL_OK is nonzero, an insn is needed if it contains a CALL.
If X is the entire body of an insn, NOTES contains the reg notes
pertaining to the insn. */
{
enum rtx_code code = GET_CODE (x);
+ /* Don't eliminate insns that may trap. */
+ if (flag_non_call_exceptions && may_trap_p (x))
+ return 0;
+
#ifdef AUTO_INC_DEC
/* As flow is invoked after combine, we must take existing AUTO_INC
expressions into account. */
|| FUNCTION_ARG_REGNO_P (regno))))
return 0;
- return REGNO_REG_SET_P (ENTRY_BLOCK_PTR->next_bb->global_live_at_start, regno);
+ return REGNO_REG_SET_P (ENTRY_BLOCK_PTR->global_live_at_end, regno);
}
/* 1 if register REGNO was alive at a place where `setjmp' was called
return 0;
return ((REG_N_SETS (regno) > 1
- || REGNO_REG_SET_P (ENTRY_BLOCK_PTR->next_bb->global_live_at_start, regno))
+ || REGNO_REG_SET_P (ENTRY_BLOCK_PTR->global_live_at_end, regno))
&& REGNO_REG_SET_P (regs_live_at_setjmp, regno));
}
\f
/* If this set is a MEM, then it kills any aliased writes.
If this set is a REG, then it kills any MEMs which use the reg. */
- if (optimize && (flags & PROP_SCAN_DEAD_CODE))
+ if (optimize && (flags & PROP_SCAN_DEAD_STORES))
{
if (GET_CODE (reg) == REG)
invalidate_mems_from_set (pbi, reg);
if (! REGNO_REG_SET_P (pbi->reg_live, i))
REG_NOTES (insn)
= alloc_EXPR_LIST (REG_UNUSED,
- gen_rtx_REG (reg_raw_mode[i], i),
+ regno_reg_rtx[i],
REG_NOTES (insn));
}
}
/* We now know we'll be doing this change, so emit the
new insn(s) and do the updates. */
- emit_insns_before (insns, insn);
+ emit_insn_before (insns, insn);
if (pbi->bb->head == insn)
pbi->bb->head = insns;
addr,
inc_val)),
insn, x, incr, addr);
+ else if (HAVE_PRE_MODIFY_DISP && offset == INTVAL (inc_val))
+ attempt_auto_inc (pbi, gen_rtx_PRE_MODIFY (Pmode, addr,
+ gen_rtx_PLUS (Pmode,
+ addr,
+ inc_val)),
+ insn, x, incr, addr);
}
else if (GET_CODE (inc_val) == REG
&& ! reg_set_between_p (inc_val, PREV_INSN (insn),
&& ! dead_or_set_regno_p (insn, i))
REG_NOTES (insn)
= alloc_EXPR_LIST (REG_DEAD,
- gen_rtx_REG (reg_raw_mode[i], i),
+ regno_reg_rtx[i],
REG_NOTES (insn));
}
}
case MEM:
/* Don't bother watching stores to mems if this is not the
final pass. We'll not be deleting dead stores this round. */
- if (optimize && (flags & PROP_SCAN_DEAD_CODE))
+ if (optimize && (flags & PROP_SCAN_DEAD_STORES))
{
/* Invalidate the data for the last MEM stored, but only if MEM is
something that can be stored into. */
break;
case SUBREG:
-#ifdef CLASS_CANNOT_CHANGE_MODE
+#ifdef CANNOT_CHANGE_MODE_CLASS
if (GET_CODE (SUBREG_REG (x)) == REG
- && REGNO (SUBREG_REG (x)) >= FIRST_PSEUDO_REGISTER
- && CLASS_CANNOT_CHANGE_MODE_P (GET_MODE (x),
- GET_MODE (SUBREG_REG (x))))
- REG_CHANGES_MODE (REGNO (SUBREG_REG (x))) = 1;
+ && REGNO (SUBREG_REG (x)) >= FIRST_PSEUDO_REGISTER)
+ SET_REGNO_REG_SET (&subregs_of_mode[GET_MODE (x)],
+ REGNO (SUBREG_REG (x)));
#endif
/* While we're here, optimize this case. */
|| GET_CODE (testreg) == SIGN_EXTRACT
|| GET_CODE (testreg) == SUBREG)
{
-#ifdef CLASS_CANNOT_CHANGE_MODE
+#ifdef CANNOT_CHANGE_MODE_CLASS
if (GET_CODE (testreg) == SUBREG
&& GET_CODE (SUBREG_REG (testreg)) == REG
- && REGNO (SUBREG_REG (testreg)) >= FIRST_PSEUDO_REGISTER
- && CLASS_CANNOT_CHANGE_MODE_P (GET_MODE (SUBREG_REG (testreg)),
- GET_MODE (testreg)))
- REG_CHANGES_MODE (REGNO (SUBREG_REG (testreg))) = 1;
+ && REGNO (SUBREG_REG (testreg)) >= FIRST_PSEUDO_REGISTER)
+ SET_REGNO_REG_SET (&subregs_of_mode[GET_MODE (testreg)],
+ REGNO (SUBREG_REG (testreg)));
#endif
/* Modifying a single register in an alternate mode
});
}
-/* Print a human-reaable representation of R on the standard error
+/* Print a human-readable representation of R on the standard error
stream. This function is designed to be used from within the
debugger. */
sbitmap blocks;
int kill;
{
- int i, count = 0;
+ int count = 0;
+ basic_block bb;
- for (i = n_basic_blocks - 1; i >= 0; --i)
+ FOR_EACH_BB_REVERSE (bb)
{
- basic_block bb;
rtx insn;
- if (blocks && ! TEST_BIT (blocks, i))
+ if (blocks && ! TEST_BIT (blocks, bb->index))
continue;
- bb = BASIC_BLOCK (i);
-
for (insn = bb->head;; insn = NEXT_INSN (insn))
{
if (INSN_P (insn))