/* Data flow analysis for GNU compiler.
Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001 Free Software Foundation, Inc.
+ 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
This file is part of GCC.
\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.
#ifndef EPILOGUE_USES
#define EPILOGUE_USES(REGNO) 0
#endif
+#ifndef EH_USES
+#define EH_USES(REGNO) 0
+#endif
#ifdef HAVE_conditional_execution
#ifndef REVERSE_CONDEXEC_PREDICATES_P
/* 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;
};
+/* 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
-/* Have print_rtl_and_abort give the same information that fancy_abort
- does. */
-#define print_rtl_and_abort() \
- print_rtl_and_abort_fcn (__FILE__, __LINE__, __FUNCTION__)
-
/* Forward declarations */
static int verify_wide_reg_1 PARAMS ((rtx *, void *));
-static void verify_wide_reg PARAMS ((int, rtx, rtx));
+static void verify_wide_reg PARAMS ((int, basic_block));
static void verify_local_live_at_start PARAMS ((regset, basic_block));
static void notice_stack_pointer_modification_1 PARAMS ((rtx, rtx, void *));
static void notice_stack_pointer_modification PARAMS ((rtx));
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 rtx propagate_block_delete_libcall PARAMS ((basic_block, rtx, 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));
static int libcall_dead_p PARAMS ((struct propagate_block_info *,
static void mark_set_1 PARAMS ((struct propagate_block_info *,
enum rtx_code, rtx, rtx,
rtx, int));
+static int find_regno_partial PARAMS ((rtx *, void *));
+
#ifdef HAVE_conditional_execution
static int mark_regno_cond_dead PARAMS ((struct propagate_block_info *,
int, rtx));
rtx, rtx, rtx));
void dump_flow_info PARAMS ((FILE *));
void debug_flow_info PARAMS ((void));
-static void print_rtl_and_abort_fcn PARAMS ((const char *, int,
- const char *))
- ATTRIBUTE_NORETURN;
-
static void add_to_mem_set_list PARAMS ((struct propagate_block_info *,
rtx));
-static void invalidate_mems_from_autoinc PARAMS ((struct propagate_block_info *,
- rtx));
+static int invalidate_mems_from_autoinc PARAMS ((rtx *, void *));
static void invalidate_mems_from_set PARAMS ((struct propagate_block_info *,
rtx));
-static void delete_dead_jumptables PARAMS ((void));
+static void clear_log_links PARAMS ((sbitmap));
\f
void
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. */
- compute_bb_for_insn (max_uid);
+ rtx insn;
- if (BLOCK_FOR_INSN (cfun->x_clobber_return_insn) != NULL)
- warning ("control reaches end of non-void function");
+ 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;
+ }
}
}
}
int flags;
{
#ifdef ELIMINABLE_REGS
- register int i;
- static struct {int from, to; } eliminables[] = ELIMINABLE_REGS;
+ int i;
+ static const struct {const int from, to; } eliminables[] = ELIMINABLE_REGS;
#endif
/* Record which registers will be eliminated. We use this in
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)
free_basic_block_vars (1);
-#ifdef ENABLE_CHECKING
- {
- rtx insn;
-
- /* Search for any REG_LABEL notes which reference deleted labels. */
- for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
- {
- rtx inote = find_reg_note (insn, REG_LABEL, NULL_RTX);
-
- if (inote && GET_CODE (inote) == NOTE_INSN_DELETED_LABEL)
- abort ();
- }
- }
-#endif
/* Removing dead insns should've made jumptables really dead. */
delete_dead_jumptables ();
}
/* A subroutine of verify_wide_reg, called through for_each_rtx.
- Search for REGNO. If found, abort if it is not wider than word_mode. */
+ Search for REGNO. If found, return 2 if it is not wider than
+ word_mode. */
static int
verify_wide_reg_1 (px, pregno)
if (GET_CODE (x) == REG && REGNO (x) == regno)
{
if (GET_MODE_BITSIZE (GET_MODE (x)) <= BITS_PER_WORD)
- abort ();
+ return 2;
return 1;
}
return 0;
}
/* A subroutine of verify_local_live_at_start. Search through insns
- between HEAD and END looking for register REGNO. */
+ of BB looking for register REGNO. */
static void
-verify_wide_reg (regno, head, end)
+verify_wide_reg (regno, bb)
int regno;
- rtx head, end;
+ basic_block bb;
{
+ rtx head = bb->head, end = bb->end;
+
while (1)
{
- if (INSN_P (head)
- && for_each_rtx (&PATTERN (head), verify_wide_reg_1, ®no))
- return;
+ if (INSN_P (head))
+ {
+ int r = for_each_rtx (&PATTERN (head), verify_wide_reg_1, ®no);
+ if (r == 1)
+ return;
+ if (r == 2)
+ break;
+ }
if (head == end)
break;
head = NEXT_INSN (head);
}
- /* We didn't find the register at all. Something's way screwy. */
if (rtl_dump_file)
- fprintf (rtl_dump_file, "Aborting in verify_wide_reg; reg %d\n", regno);
- print_rtl_and_abort ();
+ {
+ fprintf (rtl_dump_file, "Register %d died unexpectedly.\n", regno);
+ dump_bb (bb, rtl_dump_file);
+ }
+ abort ();
}
/* A subroutine of update_life_info. Verify that there are no untoward
if (rtl_dump_file)
{
fprintf (rtl_dump_file,
- "live_at_start mismatch in bb %d, aborting\n",
+ "live_at_start mismatch in bb %d, aborting\nNew:\n",
bb->index);
- debug_bitmap_file (rtl_dump_file, bb->global_live_at_start);
debug_bitmap_file (rtl_dump_file, new_live_at_start);
+ fputs ("Old:\n", rtl_dump_file);
+ dump_bb (bb, rtl_dump_file);
}
- print_rtl_and_abort ();
+ abort ();
}
}
else
EXECUTE_IF_SET_IN_REG_SET (new_live_at_start, 0, i,
{
- /* No registers should die. */
+ /* No registers should die. */
if (REGNO_REG_SET_P (bb->global_live_at_start, i))
{
if (rtl_dump_file)
- fprintf (rtl_dump_file,
- "Register %d died unexpectedly in block %d\n", i,
- bb->index);
- print_rtl_and_abort ();
+ {
+ fprintf (rtl_dump_file,
+ "Register %d died unexpectedly.\n", i);
+ dump_bb (bb, rtl_dump_file);
+ }
+ abort ();
}
- /* Verify that the now-live register is wider than word_mode. */
- verify_wide_reg (i, bb->head, bb->end);
+ /* Verify that the now-live register is wider than word_mode. */
+ verify_wide_reg (i, 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;
regset tmp;
regset_head tmp_head;
int i;
+ int stabilized_prop_flags = prop_flags;
+ basic_block bb;
tmp = INITIALIZE_REG_SET (tmp_head);
+ ndead = 0;
+
+ timevar_push ((extent == UPDATE_LIFE_LOCAL || blocks)
+ ? TV_LIFE_UPDATE : TV_LIFE);
/* Changes to the CFG are only allowed when
doing a global update for the entire CFG. */
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));
}
- if (! changed || ! cleanup_cfg (CLEANUP_EXPENSIVE))
+ /* Don't pass PROP_SCAN_DEAD_CODE or PROP_KILL_DEAD_CODE to
+ subsequent propagate_block calls, since removing or acting as
+ 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_SCAN_DEAD_STORES
+ | PROP_KILL_DEAD_CODE);
+
+ if (! changed)
break;
+
+ /* We repeat regardless of what cleanup_cfg says. If there were
+ instructions deleted above, that might have been only a
+ 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. */
count_or_remove_death_notes (blocks, 1);
}
+ /* Clear log links in case we are asked to (re)compute them. */
+ if (prop_flags & PROP_LOG_LINKS)
+ clear_log_links (blocks);
+
if (blocks)
{
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, prop_flags);
+ propagate_block (bb, tmp, NULL, NULL, stabilized_prop_flags);
if (extent == UPDATE_LIFE_LOCAL)
verify_local_live_at_start (tmp, bb);
}
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, prop_flags);
+
+ propagate_block (bb, tmp, NULL, NULL, stabilized_prop_flags);
if (extent == UPDATE_LIFE_LOCAL)
verify_local_live_at_start (tmp, bb);
}
});
}
+ 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. */
+
+int
+update_life_info_in_dirty_blocks (extent, prop_flags)
+ enum update_life_extent extent;
+ int prop_flags;
+{
+ sbitmap update_life_blocks = sbitmap_alloc (last_basic_block);
+ int n = 0;
+ basic_block bb;
+ int retval = 0;
+
+ sbitmap_zero (update_life_blocks);
+ 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);
+
+ sbitmap_free (update_life_blocks);
+ return retval;
}
/* 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)
int keep_head_end_p;
{
- if (basic_block_for_insn)
- {
- VARRAY_FREE (basic_block_for_insn);
- basic_block_for_insn = NULL;
- }
-
if (! keep_head_end_p)
{
if (basic_block_info)
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 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++)
+ FOR_EACH_BB (bb)
{
- bb = BASIC_BLOCK (i);
for (insn = bb->head; insn != NEXT_INSN (bb->end); insn = next)
{
next = NEXT_INSN (insn);
if (INSN_P (insn) && noop_move_p (insn))
{
- /* Do not call flow_delete_insn here to not confuse backward
- pointers of LIBCALL block. */
- PUT_CODE (insn, NOTE);
- NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
- NOTE_SOURCE_FILE (insn) = 0;
- if (insn == bb->end)
- purge_dead_edges (bb);
+ rtx note;
+
+ /* If we're about to remove the first insn of a libcall
+ then move the libcall note to the next real insn and
+ update the retval note. */
+ if ((note = find_reg_note (insn, REG_LIBCALL, NULL_RTX))
+ && XEXP (note, 0) != insn)
+ {
+ rtx new_libcall_insn = next_real_insn (insn);
+ rtx retval_note = find_reg_note (XEXP (note, 0),
+ REG_RETVAL, NULL_RTX);
+ REG_NOTES (new_libcall_insn)
+ = gen_rtx_INSN_LIST (REG_LIBCALL, XEXP (note, 0),
+ REG_NOTES (new_libcall_insn));
+ XEXP (retval_note, 0) = new_libcall_insn;
+ }
+
+ 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
- time of removing tablejump insn as they are referenced by the preceeding
+ time of removing tablejump insn as they are referenced by the preceding
insns computing the destination, so we delay deleting and garbagecollect
them once life information is computed. */
-static void
+void
delete_dead_jumptables ()
{
rtx insn, next;
{
next = NEXT_INSN (insn);
if (GET_CODE (insn) == CODE_LABEL
- && LABEL_NUSES (insn) == 0
+ && LABEL_NUSES (insn) == LABEL_PRESERVE_P (insn)
&& GET_CODE (next) == JUMP_INSN
&& (GET_CODE (PATTERN (next)) == ADDR_VEC
|| GET_CODE (PATTERN (next)) == ADDR_DIFF_VEC))
{
if (rtl_dump_file)
fprintf (rtl_dump_file, "Dead jumptable %i removed\n", INSN_UID (insn));
- flow_delete_insn (NEXT_INSN (insn));
- flow_delete_insn (insn);
+ delete_insn (NEXT_INSN (insn));
+ delete_insn (insn);
next = NEXT_INSN (next);
}
}
#if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
/* If they are different, also mark the hard frame pointer as live. */
if (! LOCAL_REGNO (HARD_FRAME_POINTER_REGNUM))
- SET_REGNO_REG_SET (set, HARD_FRAME_POINTER_REGNUM);
+ SET_REGNO_REG_SET (set, HARD_FRAME_POINTER_REGNUM);
#endif
}
/* 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 behavior here. */
+#ifdef ENABLE_CHECKING
+ 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 redily available in hard reg set form. */
+ /* 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;
}
}
+ /* We clean aux when we remove the initially-enqueued bbs, but we
+ don't enqueue ENTRY and EXIT initially, so clean them upfront and
+ unconditionally. */
+ ENTRY_BLOCK_PTR->aux = EXIT_BLOCK_PTR->aux = NULL;
+
if (blocks_out)
sbitmap_zero (blocks_out);
/* Begin by propagating live_at_start from the successor blocks. */
CLEAR_REG_SET (new_live_at_end);
- for (e = bb->succ; e; e = e->succ_next)
- {
- basic_block sb = e->dest;
- /* Call-clobbered registers die across exception and call edges. */
- /* ??? Abnormal call edges ignored for the moment, as this gets
- confused by sibling call edges, which crashes reg-stack. */
- if (e->flags & EDGE_EH)
- {
- bitmap_operation (tmp, sb->global_live_at_start,
- call_used, BITMAP_AND_COMPL);
- IOR_REG_SET (new_live_at_end, tmp);
- }
- else
- IOR_REG_SET (new_live_at_end, sb->global_live_at_start);
+ if (bb->succ)
+ for (e = bb->succ; e; e = e->succ_next)
+ {
+ basic_block sb = e->dest;
+
+ /* Call-clobbered registers die across exception and
+ call edges. */
+ /* ??? Abnormal call edges ignored for the moment, as this gets
+ confused by sibling call edges, which crashes reg-stack. */
+ if (e->flags & EDGE_EH)
+ {
+ bitmap_operation (tmp, sb->global_live_at_start,
+ invalidated_by_call, BITMAP_AND_COMPL);
+ IOR_REG_SET (new_live_at_end, tmp);
+ }
+ else
+ IOR_REG_SET (new_live_at_end, sb->global_live_at_start);
+
+ /* If a target saves one register in another (instead of on
+ the stack) the save register will need to be live for EH. */
+ if (e->flags & EDGE_EH)
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ if (EH_USES (i))
+ SET_REGNO_REG_SET (new_live_at_end, i);
+ }
+ else
+ {
+ /* This might be a noreturn function that throws. And
+ even if it isn't, getting the unwind info right helps
+ debugging. */
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ if (EH_USES (i))
+ SET_REGNO_REG_SET (new_live_at_end, i);
}
/* The all-important stack pointer must always be live. */
/* 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);
}
free (queue);
}
+
+\f
+/* 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. */
+
+typedef struct {
+ unsigned regno_to_find;
+ rtx retval;
+} find_regno_partial_param;
+
+
+/* Find the rtx for the reg numbers specified in 'data' if it is
+ part of an expression which only uses part of the register. Return
+ it in the structure passed in. */
+static int
+find_regno_partial (ptr, data)
+ rtx *ptr;
+ void *data;
+{
+ find_regno_partial_param *param = (find_regno_partial_param *)data;
+ unsigned reg = param->regno_to_find;
+ param->retval = NULL_RTX;
+
+ if (*ptr == NULL_RTX)
+ return 0;
+
+ switch (GET_CODE (*ptr))
+ {
+ case ZERO_EXTRACT:
+ case SIGN_EXTRACT:
+ case STRICT_LOW_PART:
+ if (GET_CODE (XEXP (*ptr, 0)) == REG && REGNO (XEXP (*ptr, 0)) == reg)
+ {
+ param->retval = XEXP (*ptr, 0);
+ return 1;
+ }
+ break;
+
+ case SUBREG:
+ if (GET_CODE (SUBREG_REG (*ptr)) == REG
+ && REGNO (SUBREG_REG (*ptr)) == reg)
+ {
+ param->retval = SUBREG_REG (*ptr);
+ return 1;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+/* Process all immediate successors of the entry block looking for pseudo
+ registers which are live on entry. Find all of those whose first
+ instance is a partial register reference of some kind, and initialize
+ them to 0 after the entry block. This will prevent bit sets within
+ registers whose value is unknown, and may contain some kind of sticky
+ bits we don't want. */
+
+int
+initialize_uninitialized_subregs ()
+{
+ rtx insn;
+ edge e;
+ int reg, did_something = 0;
+ find_regno_partial_param param;
+
+ for (e = ENTRY_BLOCK_PTR->succ; e; e = e->succ_next)
+ {
+ basic_block bb = e->dest;
+ regset map = bb->global_live_at_start;
+ EXECUTE_IF_SET_IN_REG_SET (map,
+ FIRST_PSEUDO_REGISTER, reg,
+ {
+ int uid = REGNO_FIRST_UID (reg);
+ rtx i;
+
+ /* Find an insn which mentions the register we are looking for.
+ Its preferable to have an instance of the register's rtl since
+ there may be various flags set which we need to duplicate.
+ If we can't find it, its probably an automatic whose initial
+ value doesn't matter, or hopefully something we don't care about. */
+ for (i = get_insns (); i && INSN_UID (i) != uid; i = NEXT_INSN (i))
+ ;
+ if (i != NULL_RTX)
+ {
+ /* Found the insn, now get the REG rtx, if we can. */
+ param.regno_to_find = reg;
+ for_each_rtx (&i, find_regno_partial, ¶m);
+ if (param.retval != NULL_RTX)
+ {
+ insn = gen_move_insn (param.retval,
+ CONST0_RTX (GET_MODE (param.retval)));
+ insert_insn_on_edge (insn, e);
+ did_something = 1;
+ }
+ }
+ });
+ }
+
+ if (did_something)
+ commit_edge_insertions ();
+ return did_something;
+}
+
\f
/* Subroutines of life analysis. */
void
allocate_bb_life_data ()
{
- register 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;
}
}
/* 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);
INSN may reference a deleted label, particularly when a jump
table has been optimized into a direct jump. There's no
real good way to fix up the reference to the deleted label
- when the label is deleted, so we just allow it here.
-
- After dead code elimination is complete, we do search for
- any REG_LABEL notes which reference deleted labels as a
- sanity check. */
+ when the label is deleted, so we just allow it here. */
if (inote && GET_CODE (inote) == CODE_LABEL)
{
for (i = 0; i < len; i++)
LABEL_NUSES (XEXP (XVECEXP (pat, diff_vec_p, i), 0))--;
- flow_delete_insn (next);
+ delete_insn_and_edges (next);
+ ndead++;
}
}
- if (bb->end == insn)
- {
- bb->end = PREV_INSN (insn);
- purge_dead_edges (bb);
- }
- flow_delete_insn (insn);
+ delete_insn_and_edges (insn);
+ ndead++;
}
/* Delete dead libcalls for propagate_block. Return the insn
before the libcall. */
static rtx
-propagate_block_delete_libcall (bb, insn, note)
- basic_block bb;
+propagate_block_delete_libcall ( insn, note)
rtx insn, note;
{
rtx first = XEXP (note, 0);
rtx before = PREV_INSN (first);
- if (insn == bb->end)
- bb->end = before;
-
- flow_delete_insn_chain (first, insn);
+ delete_insn_chain_and_edges (first, insn);
+ ndead++;
return before;
}
|| (HAVE_sibcall_epilogue
&& sibcall_epilogue_contains (insn)))
&& find_reg_note (insn, REG_MAYBE_DEAD, NULL_RTX) == 0)
- abort ();
+ fatal_insn ("Attempt to delete prologue/epilogue insn:", insn);
/* Record sets. Do this even for dead instructions, since they
would have killed the values if they hadn't been deleted. */
pbi->cc0_live = 0;
if (libcall_is_dead)
- prev = propagate_block_delete_libcall (pbi->bb, insn, note);
+ prev = propagate_block_delete_libcall ( insn, note);
else
- propagate_block_delete_insn (pbi->bb, 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;
}
a following memory address. */
#ifdef AUTO_INC_DEC
{
- register rtx x = single_set (insn);
+ rtx x = single_set (insn);
/* Does this instruction increment or decrement a register? */
if ((flags & PROP_AUTOINC)
/* We have an insn to pop a constant amount off the stack.
(Such insns use PLUS regardless of the direction of the stack,
and any insn to adjust the stack by a constant is always a pop.)
- These insns, if not dead stores, have no effect on life. */
- ;
+ These insns, if not dead stores, have no effect on life, though
+ they do have an effect on the memory stores we are tracking. */
+ invalidate_mems_from_set (pbi, stack_pointer_rtx);
else
{
+ rtx note;
/* Any regs live at the time of a call instruction must not go
in a register clobbered by calls. Find all regs now live and
record this for them. */
if (GET_CODE (insn) == CALL_INSN)
{
- register int i;
+ int i;
rtx note, cond;
cond = NULL_RTX;
if (GET_CODE (PATTERN (insn)) == COND_EXEC)
cond = COND_EXEC_TEST (PATTERN (insn));
- /* Non-constant calls clobber memory. */
+ /* Non-constant calls clobber memory, constant calls do not
+ clobber memory, though they may clobber outgoing arguments
+ on the stack. */
if (! CONST_OR_PURE_CALL_P (insn))
{
free_EXPR_LIST_list (&pbi->mem_set_list);
pbi->mem_set_list_len = 0;
}
+ else
+ invalidate_mems_from_set (pbi, stack_pointer_rtx);
/* There may be extra registers to be clobbered. */
for (note = CALL_INSN_FUNCTION_USAGE (insn);
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));
}
}
/* Record uses. */
if (! insn_is_dead)
mark_used_regs (pbi, PATTERN (insn), NULL_RTX, insn);
+ if ((flags & PROP_EQUAL_NOTES)
+ && ((note = find_reg_note (insn, REG_EQUAL, NULL_RTX))
+ || (note = find_reg_note (insn, REG_EQUIV, NULL_RTX))))
+ mark_used_regs (pbi, XEXP (note, 0), NULL_RTX, insn);
/* Sometimes we may have inserted something before INSN (such as a move)
when we make an auto-inc. So ensure we will scan those insns. */
if (! insn_is_dead && GET_CODE (insn) == CALL_INSN)
{
- register int i;
+ int i;
rtx note, cond;
cond = NULL_RTX;
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)
if (flags & PROP_REG_INFO)
{
- register int i;
+ int i;
/* Process the regs live at the end of the block.
Mark them as not local to any one basic block. */
(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
- /* If flow is invoked after reload, we must take existing AUTO_INC
- expresions into account. */
- if (reload_completed)
+ /* As flow is invoked after combine, we must take existing AUTO_INC
+ expressions into account. */
+ for (; notes; notes = XEXP (notes, 1))
{
- for (; notes; notes = XEXP (notes, 1))
+ if (REG_NOTE_KIND (notes) == REG_INC)
{
- if (REG_NOTE_KIND (notes) == REG_INC)
- {
- int regno = REGNO (XEXP (notes, 0));
+ int regno = REGNO (XEXP (notes, 0));
- /* Don't delete insns to set global regs. */
- if ((regno < FIRST_PSEUDO_REGISTER && global_regs[regno])
- || REGNO_REG_SET_P (pbi->reg_live, regno))
- return 0;
- }
+ /* Don't delete insns to set global regs. */
+ if ((regno < FIRST_PSEUDO_REGISTER && global_regs[regno])
+ || REGNO_REG_SET_P (pbi->reg_live, regno))
+ return 0;
}
}
#endif
if (x)
{
- register rtx r = SET_SRC (x);
+ rtx r = SET_SRC (x);
if (GET_CODE (r) == REG)
{
rtx call = XEXP (note, 0);
rtx call_pat;
- register int i;
+ int i;
/* Find the call insn. */
while (call != insn && GET_CODE (call) != CALL_INSN)
int
regno_uninitialized (regno)
- int regno;
+ unsigned int regno;
{
if (n_basic_blocks == 0
|| (regno < FIRST_PSEUDO_REGISTER
|| FUNCTION_ARG_REGNO_P (regno))))
return 0;
- return REGNO_REG_SET_P (BASIC_BLOCK (0)->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 (BASIC_BLOCK (0)->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
Find any entries on the mem_set_list that need to be invalidated due
to an address change. */
-static void
-invalidate_mems_from_autoinc (pbi, insn)
- struct propagate_block_info *pbi;
- rtx insn;
+static int
+invalidate_mems_from_autoinc (px, data)
+ rtx *px;
+ void *data;
{
- rtx note = REG_NOTES (insn);
- for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
- if (REG_NOTE_KIND (note) == REG_INC)
- invalidate_mems_from_set (pbi, XEXP (note, 0));
+ rtx x = *px;
+ struct propagate_block_info *pbi = data;
+
+ if (GET_RTX_CLASS (GET_CODE (x)) == 'a')
+ {
+ invalidate_mems_from_set (pbi, XEXP (x, 0));
+ return -1;
+ }
+
+ return 0;
}
-/* EXP is a REG. Remove any dependant entries from pbi->mem_set_list. */
+/* EXP is a REG. Remove any dependent entries from pbi->mem_set_list. */
static void
invalidate_mems_from_set (pbi, exp)
case PARALLEL:
{
- register int i;
+ int i;
+
for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
{
rtx sub = XVECEXP (x, 0, i);
/* 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);
address modes. Then we may need to kill some entries on the
memory set list. */
if (insn && GET_CODE (reg) == MEM)
- invalidate_mems_from_autoinc (pbi, insn);
+ for_each_rtx (&PATTERN (insn), invalidate_mems_from_autoinc, pbi);
if (GET_CODE (reg) == MEM && ! side_effects_p (reg)
/* ??? With more effort we could track conditional memory life. */
- && ! cond
- /* There are no REG_INC notes for SP, so we can't assume we'll see
- everything that invalidates it. To be safe, don't eliminate any
- stores though SP; none of them should be redundant anyway. */
- && ! reg_mentioned_p (stack_pointer_rtx, reg))
- add_to_mem_set_list (pbi, canon_rtx (reg));
+ && ! cond)
+ add_to_mem_set_list (pbi, canon_rtx (reg));
}
if (GET_CODE (reg) == REG
if (flags & (PROP_LOG_LINKS | PROP_REG_INFO
| PROP_DEATH_NOTES | PROP_AUTOINC))
{
- register rtx y;
- register int blocknum = pbi->bb->index;
+ rtx y;
+ int blocknum = pbi->bb->index;
y = NULL_RTX;
if (flags & (PROP_LOG_LINKS | PROP_AUTOINC))
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));
}
}
SET_REGNO_REG_SET (pbi->reg_cond_reg, REGNO (XEXP (cond, 0)));
- /* Not unconditionaly dead. */
+ /* Not unconditionally dead. */
return 0;
}
else
SET_REGNO_REG_SET (pbi->reg_cond_reg, REGNO (XEXP (cond, 0)));
- /* Not unconditionaly dead. */
+ /* Not unconditionally dead. */
return 0;
}
}
For ior/and, the ADD flag determines whether we want to add the new
condition X to the old one unconditionally. If it is zero, we will
only return a new expression if X allows us to simplify part of
- OLD, otherwise we return OLD unchanged to the caller.
+ OLD, otherwise we return NULL to the caller.
If ADD is nonzero, we will return a new condition in all cases. The
toplevel caller of one of these functions should always pass 1 for
ADD. */
&& REGNO (XEXP (x, 0)) == REGNO (XEXP (old, 0)))
return old;
if (! add)
- return old;
+ return NULL;
return gen_rtx_IOR (0, old, x);
}
case IOR:
op0 = ior_reg_cond (XEXP (old, 0), x, 0);
op1 = ior_reg_cond (XEXP (old, 1), x, 0);
- if (op0 != XEXP (old, 0) || op1 != XEXP (old, 1))
+ if (op0 != NULL || op1 != NULL)
{
if (op0 == const0_rtx)
- return op1;
+ return op1 ? op1 : gen_rtx_IOR (0, XEXP (old, 1), x);
if (op1 == const0_rtx)
- return op0;
+ return op0 ? op0 : gen_rtx_IOR (0, XEXP (old, 0), x);
if (op0 == const1_rtx || op1 == const1_rtx)
return const1_rtx;
- if (op0 == XEXP (old, 0))
- op0 = gen_rtx_IOR (0, op0, x);
- else
- op1 = gen_rtx_IOR (0, op1, x);
+ if (op0 == NULL)
+ op0 = gen_rtx_IOR (0, XEXP (old, 0), x);
+ else if (rtx_equal_p (x, op0))
+ /* (x | A) | x ~ (x | A). */
+ return old;
+ if (op1 == NULL)
+ op1 = gen_rtx_IOR (0, XEXP (old, 1), x);
+ else if (rtx_equal_p (x, op1))
+ /* (A | x) | x ~ (A | x). */
+ return old;
return gen_rtx_IOR (0, op0, op1);
}
if (! add)
- return old;
+ return NULL;
return gen_rtx_IOR (0, old, x);
case AND:
op0 = ior_reg_cond (XEXP (old, 0), x, 0);
op1 = ior_reg_cond (XEXP (old, 1), x, 0);
- if (op0 != XEXP (old, 0) || op1 != XEXP (old, 1))
+ if (op0 != NULL || op1 != NULL)
{
if (op0 == const1_rtx)
- return op1;
+ return op1 ? op1 : gen_rtx_IOR (0, XEXP (old, 1), x);
if (op1 == const1_rtx)
- return op0;
+ return op0 ? op0 : gen_rtx_IOR (0, XEXP (old, 0), x);
if (op0 == const0_rtx || op1 == const0_rtx)
return const0_rtx;
- if (op0 == XEXP (old, 0))
- op0 = gen_rtx_IOR (0, op0, x);
- else
- op1 = gen_rtx_IOR (0, op1, x);
+ if (op0 == NULL)
+ op0 = gen_rtx_IOR (0, XEXP (old, 0), x);
+ else if (rtx_equal_p (x, op0))
+ /* (x & A) | x ~ x. */
+ return op0;
+ if (op1 == NULL)
+ op1 = gen_rtx_IOR (0, XEXP (old, 1), x);
+ else if (rtx_equal_p (x, op1))
+ /* (A & x) | x ~ x. */
+ return op1;
return gen_rtx_AND (0, op0, op1);
}
if (! add)
- return old;
+ return NULL;
return gen_rtx_IOR (0, old, x);
case NOT:
op0 = and_reg_cond (XEXP (old, 0), not_reg_cond (x), 0);
- if (op0 != XEXP (old, 0))
+ if (op0 != NULL)
return not_reg_cond (op0);
if (! add)
- return old;
+ return NULL;
return gen_rtx_IOR (0, old, x);
default:
&& REGNO (XEXP (x, 0)) == REGNO (XEXP (old, 0)))
return old;
if (! add)
- return old;
+ return NULL;
return gen_rtx_AND (0, old, x);
}
case IOR:
op0 = and_reg_cond (XEXP (old, 0), x, 0);
op1 = and_reg_cond (XEXP (old, 1), x, 0);
- if (op0 != XEXP (old, 0) || op1 != XEXP (old, 1))
+ if (op0 != NULL || op1 != NULL)
{
if (op0 == const0_rtx)
- return op1;
+ return op1 ? op1 : gen_rtx_AND (0, XEXP (old, 1), x);
if (op1 == const0_rtx)
- return op0;
+ return op0 ? op0 : gen_rtx_AND (0, XEXP (old, 0), x);
if (op0 == const1_rtx || op1 == const1_rtx)
return const1_rtx;
- if (op0 == XEXP (old, 0))
- op0 = gen_rtx_AND (0, op0, x);
- else
- op1 = gen_rtx_AND (0, op1, x);
+ if (op0 == NULL)
+ op0 = gen_rtx_AND (0, XEXP (old, 0), x);
+ else if (rtx_equal_p (x, op0))
+ /* (x | A) & x ~ x. */
+ return op0;
+ if (op1 == NULL)
+ op1 = gen_rtx_AND (0, XEXP (old, 1), x);
+ else if (rtx_equal_p (x, op1))
+ /* (A | x) & x ~ x. */
+ return op1;
return gen_rtx_IOR (0, op0, op1);
}
if (! add)
- return old;
+ return NULL;
return gen_rtx_AND (0, old, x);
case AND:
op0 = and_reg_cond (XEXP (old, 0), x, 0);
op1 = and_reg_cond (XEXP (old, 1), x, 0);
- if (op0 != XEXP (old, 0) || op1 != XEXP (old, 1))
+ if (op0 != NULL || op1 != NULL)
{
if (op0 == const1_rtx)
- return op1;
+ return op1 ? op1 : gen_rtx_AND (0, XEXP (old, 1), x);
if (op1 == const1_rtx)
- return op0;
+ return op0 ? op0 : gen_rtx_AND (0, XEXP (old, 0), x);
if (op0 == const0_rtx || op1 == const0_rtx)
return const0_rtx;
- if (op0 == XEXP (old, 0))
- op0 = gen_rtx_AND (0, op0, x);
- else
- op1 = gen_rtx_AND (0, op1, x);
+ if (op0 == NULL)
+ op0 = gen_rtx_AND (0, XEXP (old, 0), x);
+ else if (rtx_equal_p (x, op0))
+ /* (x & A) & x ~ (x & A). */
+ return old;
+ if (op1 == NULL)
+ op1 = gen_rtx_AND (0, XEXP (old, 1), x);
+ else if (rtx_equal_p (x, op1))
+ /* (A & x) & x ~ (A & x). */
+ return old;
return gen_rtx_AND (0, op0, op1);
}
if (! add)
- return old;
-
- /* If X is identical to one of the existing terms of the AND,
- then just return what we already have. */
- /* ??? There really should be some sort of recursive check here in
- case there are nested ANDs. */
- if ((GET_CODE (XEXP (old, 0)) == GET_CODE (x)
- && REGNO (XEXP (XEXP (old, 0), 0)) == REGNO (XEXP (x, 0)))
- || (GET_CODE (XEXP (old, 1)) == GET_CODE (x)
- && REGNO (XEXP (XEXP (old, 1), 0)) == REGNO (XEXP (x, 0))))
- return old;
-
+ return NULL;
return gen_rtx_AND (0, old, x);
case NOT:
op0 = ior_reg_cond (XEXP (old, 0), not_reg_cond (x), 0);
- if (op0 != XEXP (old, 0))
+ if (op0 != NULL)
return not_reg_cond (op0);
if (! add)
- return old;
+ return NULL;
return gen_rtx_AND (0, old, x);
default:
insns = get_insns ();
end_sequence ();
- if (basic_block_for_insn)
- for (temp = insns; temp; temp = NEXT_INSN (temp))
- set_block_for_insn (temp, pbi->bb);
-
/* If we can't make the auto-inc, or can't make the
replacement into Y, exit. There's no point in making
the change below if we can't do the auto-inc and doing
/* 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),
{
/* Keep track of which basic block each reg appears in. */
- register int blocknum = pbi->bb->index;
+ int blocknum = pbi->bb->index;
if (REG_BASIC_BLOCK (regno_first) == REG_BLOCK_UNKNOWN)
REG_BASIC_BLOCK (regno_first) = blocknum;
else if (REG_BASIC_BLOCK (regno_first) != blocknum)
&& ! 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));
}
}
/* Mark the register as being live. */
for (i = regno_first; i <= regno_last; ++i)
{
+#ifdef HAVE_conditional_execution
+ int this_was_live = REGNO_REG_SET_P (pbi->reg_live, i);
+#endif
+
SET_REGNO_REG_SET (pbi->reg_live, i);
#ifdef HAVE_conditional_execution
struct reg_cond_life_info *rcli;
rtx ncond;
- if (some_was_live)
+ if (this_was_live)
{
node = splay_tree_lookup (pbi->reg_cond_dead, i);
if (node == NULL)
SET_REGNO_REG_SET (pbi->reg_cond_reg, REGNO (XEXP (cond, 0)));
}
}
- else if (some_was_live)
+ else if (this_was_live)
{
/* The register may have been conditionally live previously, but
is now unconditionally live. Remove it from the conditionally
struct propagate_block_info *pbi;
rtx x, cond, insn;
{
- register RTX_CODE code;
- register int regno;
+ RTX_CODE code;
+ int regno;
int flags = pbi->flags;
retry:
+ if (!x)
+ return;
code = GET_CODE (x);
switch (code)
{
case CONST_INT:
case CONST:
case CONST_DOUBLE:
+ case CONST_VECTOR:
case PC:
case ADDR_VEC:
case ADDR_DIFF_VEC:
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. */
address modes. Then we may need to kill some entries on the
memory set list. */
if (insn)
- invalidate_mems_from_autoinc (pbi, insn);
+ for_each_rtx (&PATTERN (insn), invalidate_mems_from_autoinc, pbi);
}
#ifdef AUTO_INC_DEC
if (flags & PROP_AUTOINC)
- find_auto_inc (pbi, x, insn);
+ find_auto_inc (pbi, x, insn);
#endif
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. */
case SET:
{
- register rtx testreg = SET_DEST (x);
+ rtx testreg = SET_DEST (x);
int mark_dest = 0;
/* If storing into MEM, don't show it as being used. But do
|| 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
does not use any of the old value. But these other
ways of storing in a register do use the old value. */
if (GET_CODE (testreg) == SUBREG
- && !(REG_SIZE (SUBREG_REG (testreg)) > REG_SIZE (testreg)))
+ && !((REG_BYTES (SUBREG_REG (testreg))
+ + UNITS_PER_WORD - 1) / UNITS_PER_WORD
+ > (REG_BYTES (testreg)
+ + UNITS_PER_WORD - 1) / UNITS_PER_WORD))
;
else
mark_dest = 1;
/* Recursively scan the operands of this expression. */
{
- register const char * const fmt = GET_RTX_FORMAT (code);
- register int i;
+ const char * const fmt = GET_RTX_FORMAT (code);
+ int i;
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
}
else if (fmt[i] == 'E')
{
- register int j;
+ int j;
for (j = 0; j < XVECLEN (x, i); j++)
mark_used_regs (pbi, XVECEXP (x, i, j), cond, 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,
rtx insn, reg;
HOST_WIDE_INT amount;
{
- register rtx use;
+ rtx use;
/* Nonzero if we can try to make a pre-increment or pre-decrement.
For example, addl $4,r1; movl (r1),... can become movl +(r1),... */
use = 0;
if (pre_ok)
use = find_use_as_address (PATTERN (insn), reg, 0);
- if (post_ok && (use == 0 || use == (rtx) 1))
+ if (post_ok && (use == 0 || use == (rtx) (size_t) 1))
{
use = find_use_as_address (PATTERN (insn), reg, -amount);
do_post = 1;
}
- if (use == 0 || use == (rtx) 1)
+ if (use == 0 || use == (rtx) (size_t) 1)
return 0;
if (GET_MODE_SIZE (GET_MODE (use)) != (amount > 0 ? amount : - amount))
If such an address does not appear, return 0.
If REG appears more than once, or is used other than in such an address,
- return (rtx)1. */
+ return (rtx) 1. */
rtx
find_use_as_address (x, reg, plusconst)
- register rtx x;
+ rtx x;
rtx reg;
HOST_WIDE_INT plusconst;
{
enum rtx_code code = GET_CODE (x);
const char * const fmt = GET_RTX_FORMAT (code);
- register int i;
- register rtx value = 0;
- register rtx tem;
+ int i;
+ rtx value = 0;
+ rtx tem;
if (code == MEM && XEXP (x, 0) == reg && plusconst == 0)
return x;
/* If REG occurs inside a MEM used in a bit-field reference,
that is unacceptable. */
if (find_use_as_address (XEXP (x, 0), reg, 0) != 0)
- return (rtx) (HOST_WIDE_INT) 1;
+ return (rtx) (size_t) 1;
}
if (x == reg)
- return (rtx) (HOST_WIDE_INT) 1;
+ return (rtx) (size_t) 1;
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
if (value == 0)
value = tem;
else if (tem != 0)
- return (rtx) (HOST_WIDE_INT) 1;
+ return (rtx) (size_t) 1;
}
else if (fmt[i] == 'E')
{
- register int j;
+ int j;
for (j = XVECLEN (x, i) - 1; j >= 0; j--)
{
tem = find_use_as_address (XVECEXP (x, i, j), reg, plusconst);
if (value == 0)
value = tem;
else if (tem != 0)
- return (rtx) (HOST_WIDE_INT) 1;
+ return (rtx) (size_t) 1;
}
}
}
});
}
-/* 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. */
putc ('\n', stderr);
}
-/* Dump the rtl into the current debugging dump file, then abort. */
-
-static void
-print_rtl_and_abort_fcn (file, line, function)
- const char *file;
- int line;
- const char *function;
-{
- if (rtl_dump_file)
- {
- print_rtl_with_bb (rtl_dump_file, get_insns ());
- fclose (rtl_dump_file);
- }
-
- fancy_abort (file, line, function);
-}
-
/* Recompute register set/reference counts immediately prior to register
allocation.
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))
return count;
}
-/* Clear LOG_LINKS fields of insns in a chain.
- Also clear the global_live_at_{start,end} fields of the basic block
- structures. */
+/* Clear LOG_LINKS fields of insns in a selected blocks or whole chain
+ if blocks is NULL. */
-void
-clear_log_links (insns)
- rtx insns;
+static void
+clear_log_links (blocks)
+ sbitmap blocks;
{
- rtx i;
- int b;
-
- for (i = insns; i; i = NEXT_INSN (i))
- if (INSN_P (i))
- LOG_LINKS (i) = 0;
+ rtx insn;
+ int i;
- for (b = 0; b < n_basic_blocks; b++)
+ if (!blocks)
{
- basic_block bb = BASIC_BLOCK (b);
-
- bb->global_live_at_start = NULL;
- bb->global_live_at_end = NULL;
+ for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+ if (INSN_P (insn))
+ free_INSN_LIST_list (&LOG_LINKS (insn));
}
+ else
+ EXECUTE_IF_SET_IN_SBITMAP (blocks, 0, i,
+ {
+ basic_block bb = BASIC_BLOCK (i);
- ENTRY_BLOCK_PTR->global_live_at_end = NULL;
- EXIT_BLOCK_PTR->global_live_at_start = NULL;
+ for (insn = bb->head; insn != NEXT_INSN (bb->end);
+ insn = NEXT_INSN (insn))
+ if (INSN_P (insn))
+ free_INSN_LIST_list (&LOG_LINKS (insn));
+ });
}
/* Given a register bitmap, turn on the bits in a HARD_REG_SET that