/* Global common subexpression elimination/Partial redundancy elimination
and global constant/copy propagation for GNU compiler.
- Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
+ Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
Free Software Foundation, Inc.
This file is part of GCC.
the result of the expression is copied to a new register, and the redundant
expression is deleted by replacing it with this new register. Classic GCSE
doesn't have this problem as much as it computes the reaching defs of
- each register in each block and thus can try to use an existing register.
-
- **********************
-
- A fair bit of simplicity is created by creating small functions for simple
- tasks, even when the function is only called in one place. This may
- measurably slow things down [or may not] by creating more function call
- overhead than is necessary. The source is laid out so that it's trivial
- to make the affected functions inline so that one can measure what speed
- up, if any, can be achieved, and maybe later when things settle things can
- be rearranged.
-
- Help stamp out big monolithic functions! */
+ each register in each block and thus can try to use an existing
+ register. */
\f
/* GCSE global vars. */
{
/* The next setting of this register. */
struct reg_set *next;
- /* The insn where it was set. */
- rtx insn;
+ /* The index of the block where it was set. */
+ int bb_index;
} reg_set;
static reg_set **reg_set_table;
/* This array parallels modify_mem_list, but is kept canonicalized. */
static rtx * canon_modify_mem_list;
-static bitmap canon_modify_mem_list_set;
+
+/* Bitmap indexed by block numbers to record which blocks contain
+ function calls. */
+static bitmap blocks_with_calls;
/* Various variables for statistics gathering. */
\f
/* For available exprs */
static sbitmap *ae_kill, *ae_gen;
-
-/* Objects of this type are passed around by the null-pointer check
- removal routines. */
-struct null_pointer_info
-{
- /* The basic block being processed. */
- basic_block current_block;
- /* The first register to be handled in this pass. */
- unsigned int min_reg;
- /* One greater than the last register to be handled in this pass. */
- unsigned int max_reg;
- sbitmap *nonnull_local;
- sbitmap *nonnull_killed;
-};
\f
static void compute_can_copy (void);
static void *gmalloc (size_t) ATTRIBUTE_MALLOC;
static void *gcalloc (size_t, size_t) ATTRIBUTE_MALLOC;
static void *grealloc (void *, size_t);
static void *gcse_alloc (unsigned long);
-static void alloc_gcse_mem (rtx);
+static void alloc_gcse_mem (void);
static void free_gcse_mem (void);
static void alloc_reg_set_mem (int);
static void free_reg_set_mem (void);
static void record_one_set (int, rtx);
-static void replace_one_set (int, rtx, rtx);
static void record_set_info (rtx, rtx, void *);
-static void compute_sets (rtx);
+static void compute_sets (void);
static void hash_scan_insn (rtx, struct hash_table *, int);
static void hash_scan_set (rtx, rtx, struct hash_table *);
static void hash_scan_clobber (rtx, rtx, struct hash_table *);
static int cprop_insn (rtx, int);
static int cprop (int);
static void find_implicit_sets (void);
-static int one_cprop_pass (int, int, int);
-static bool constprop_register (rtx, rtx, rtx, int);
+static int one_cprop_pass (int, bool, bool);
+static bool constprop_register (rtx, rtx, rtx, bool);
static struct expr *find_bypass_set (int, int);
static bool reg_killed_on_edge (rtx, edge);
static int bypass_block (basic_block, rtx, rtx);
static void free_modify_mem_tables (void);
static rtx gcse_emit_move_after (rtx, rtx, rtx);
static void local_cprop_find_used_regs (rtx *, void *);
-static bool do_local_cprop (rtx, rtx, int, rtx*);
+static bool do_local_cprop (rtx, rtx, bool, rtx*);
static bool adjust_libcall_notes (rtx, rtx, rtx, rtx*);
-static void local_cprop_pass (int);
+static void local_cprop_pass (bool);
static bool is_too_expensive (const char *);
\f
/* Entry point for global common subexpression elimination.
- F is the first instruction in the function. */
+ F is the first instruction in the function. Return nonzero if a
+ change is mode. */
int
-gcse_main (rtx f, FILE *file)
+gcse_main (rtx f ATTRIBUTE_UNUSED, FILE *file)
{
int changed, pass;
/* Bytes used at start of pass. */
information about memory sets when we build the hash tables. */
alloc_reg_set_mem (max_gcse_regno);
- compute_sets (f);
+ compute_sets ();
pass = 0;
initial_bytes_used = bytes_used;
/* Each pass may create new registers, so recalculate each time. */
max_gcse_regno = max_reg_num ();
- alloc_gcse_mem (f);
+ alloc_gcse_mem ();
/* Don't allow constant propagation to modify jumps
during this pass. */
timevar_push (TV_CPROP1);
- changed = one_cprop_pass (pass + 1, 0, 0);
+ changed = one_cprop_pass (pass + 1, false, false);
timevar_pop (TV_CPROP1);
if (optimize_size)
}
free_reg_set_mem ();
alloc_reg_set_mem (max_reg_num ());
- compute_sets (f);
+ compute_sets ();
run_jump_opt_after_gcse = 1;
timevar_pop (TV_PRE);
}
{
timevar_push (TV_HOIST);
max_gcse_regno = max_reg_num ();
- alloc_gcse_mem (f);
+ alloc_gcse_mem ();
changed |= one_code_hoisting_pass ();
free_gcse_mem ();
conditional jumps. */
max_gcse_regno = max_reg_num ();
- alloc_gcse_mem (f);
+ alloc_gcse_mem ();
/* This time, go ahead and allow cprop to alter jumps. */
timevar_push (TV_CPROP2);
- one_cprop_pass (pass + 1, 1, 0);
+ one_cprop_pass (pass + 1, true, false);
timevar_pop (TV_CPROP2);
free_gcse_mem ();
This is called at the start of each pass. */
static void
-alloc_gcse_mem (rtx f)
+alloc_gcse_mem (void)
{
int i;
+ basic_block bb;
rtx insn;
/* Find the largest UID and create a mapping from UIDs to CUIDs.
CUIDs are like UIDs except they increase monotonically, have no gaps,
- and only apply to real insns. */
+ and only apply to real insns.
+ (Actually, there are gaps, for insn that are not inside a basic block.
+ but we should never see those anyway, so this is OK.) */
max_uid = get_max_uid ();
uid_cuid = gcalloc (max_uid + 1, sizeof (int));
- for (insn = f, i = 0; insn; insn = NEXT_INSN (insn))
- {
- if (INSN_P (insn))
- uid_cuid[INSN_UID (insn)] = i++;
- else
- uid_cuid[INSN_UID (insn)] = i;
- }
+ i = 0;
+ FOR_EACH_BB (bb)
+ FOR_BB_INSNS (bb, insn)
+ {
+ if (INSN_P (insn))
+ uid_cuid[INSN_UID (insn)] = i++;
+ else
+ uid_cuid[INSN_UID (insn)] = i;
+ }
/* Create a table mapping cuids to insns. */
max_cuid = i;
cuid_insn = gcalloc (max_cuid + 1, sizeof (rtx));
- for (insn = f, i = 0; insn; insn = NEXT_INSN (insn))
- if (INSN_P (insn))
- CUID_INSN (i++) = insn;
+ i = 0;
+ FOR_EACH_BB (bb)
+ FOR_BB_INSNS (bb, insn)
+ if (INSN_P (insn))
+ CUID_INSN (i++) = insn;
/* Allocate vars to track sets of regs. */
- reg_set_bitmap = BITMAP_XMALLOC ();
+ reg_set_bitmap = BITMAP_ALLOC (NULL);
/* Allocate vars to track sets of regs, memory per block. */
reg_set_in_block = sbitmap_vector_alloc (last_basic_block, max_gcse_regno);
basic block. */
modify_mem_list = gcalloc (last_basic_block, sizeof (rtx));
canon_modify_mem_list = gcalloc (last_basic_block, sizeof (rtx));
- modify_mem_list_set = BITMAP_XMALLOC ();
- canon_modify_mem_list_set = BITMAP_XMALLOC ();
+ modify_mem_list_set = BITMAP_ALLOC (NULL);
+ blocks_with_calls = BITMAP_ALLOC (NULL);
}
/* Free memory allocated by alloc_gcse_mem. */
free (uid_cuid);
free (cuid_insn);
- BITMAP_XFREE (reg_set_bitmap);
+ BITMAP_FREE (reg_set_bitmap);
sbitmap_vector_free (reg_set_in_block);
free_modify_mem_tables ();
- BITMAP_XFREE (modify_mem_list_set);
- BITMAP_XFREE (canon_modify_mem_list_set);
+ BITMAP_FREE (modify_mem_list_set);
+ BITMAP_FREE (blocks_with_calls);
}
\f
/* Compute the local properties of each recorded expression.
obstack_free (®_set_obstack, NULL);
}
-/* An OLD_INSN that used to set REGNO was replaced by NEW_INSN.
- Update the corresponding `reg_set_table' entry accordingly.
- We assume that NEW_INSN is not already recorded in reg_set_table[regno]. */
-
-static void
-replace_one_set (int regno, rtx old_insn, rtx new_insn)
-{
- struct reg_set *reg_info;
- if (regno >= reg_set_table_size)
- return;
- for (reg_info = reg_set_table[regno]; reg_info; reg_info = reg_info->next)
- if (reg_info->insn == old_insn)
- {
- reg_info->insn = new_insn;
- break;
- }
-}
-
/* Record REGNO in the reg_set table. */
static void
new_reg_info = obstack_alloc (®_set_obstack, sizeof (struct reg_set));
bytes_used += sizeof (struct reg_set);
- new_reg_info->insn = insn;
+ new_reg_info->bb_index = BLOCK_NUM (insn);
new_reg_info->next = reg_set_table[regno];
reg_set_table[regno] = new_reg_info;
}
`reg_set_table' for further documentation. */
static void
-compute_sets (rtx f)
+compute_sets (void)
{
+ basic_block bb;
rtx insn;
- for (insn = f; insn != 0; insn = NEXT_INSN (insn))
- if (INSN_P (insn))
- note_stores (PATTERN (insn), record_set_info, insn);
+ FOR_EACH_BB (bb)
+ FOR_BB_INSNS (bb, insn)
+ if (INSN_P (insn))
+ note_stores (PATTERN (insn), record_set_info, insn);
}
\f
/* Hash table support. */
{
while (GET_CODE (dest) == SUBREG
|| GET_CODE (dest) == ZERO_EXTRACT
- || GET_CODE (dest) == SIGN_EXTRACT
|| GET_CODE (dest) == STRICT_LOW_PART)
dest = XEXP (dest, 0);
unsigned int hash;
struct expr *cur_expr, *last_expr = NULL;
struct occr *antic_occr, *avail_occr;
- struct occr *last_occr = NULL;
hash = hash_expr (x, mode, &do_not_record_p, table->size);
{
antic_occr = cur_expr->antic_occr;
- /* Search for another occurrence in the same basic block. */
- while (antic_occr && BLOCK_NUM (antic_occr->insn) != BLOCK_NUM (insn))
- {
- /* If an occurrence isn't found, save a pointer to the end of
- the list. */
- last_occr = antic_occr;
- antic_occr = antic_occr->next;
- }
+ if (antic_occr && BLOCK_NUM (antic_occr->insn) != BLOCK_NUM (insn))
+ antic_occr = NULL;
if (antic_occr)
/* Found another instance of the expression in the same basic block.
/* First occurrence of this expression in this basic block. */
antic_occr = gcse_alloc (sizeof (struct occr));
bytes_used += sizeof (struct occr);
- /* First occurrence of this expression in any block? */
- if (cur_expr->antic_occr == NULL)
- cur_expr->antic_occr = antic_occr;
- else
- last_occr->next = antic_occr;
-
antic_occr->insn = insn;
- antic_occr->next = NULL;
+ antic_occr->next = cur_expr->antic_occr;
antic_occr->deleted_p = 0;
+ cur_expr->antic_occr = antic_occr;
}
}
{
avail_occr = cur_expr->avail_occr;
- /* Search for another occurrence in the same basic block. */
- while (avail_occr && BLOCK_NUM (avail_occr->insn) != BLOCK_NUM (insn))
+ if (avail_occr && BLOCK_NUM (avail_occr->insn) == BLOCK_NUM (insn))
{
- /* If an occurrence isn't found, save a pointer to the end of
- the list. */
- last_occr = avail_occr;
- avail_occr = avail_occr->next;
+ /* Found another instance of the expression in the same basic block.
+ Prefer this occurrence to the currently recorded one. We want
+ the last one in the block and the block is scanned from start
+ to end. */
+ avail_occr->insn = insn;
}
-
- if (avail_occr)
- /* Found another instance of the expression in the same basic block.
- Prefer this occurrence to the currently recorded one. We want
- the last one in the block and the block is scanned from start
- to end. */
- avail_occr->insn = insn;
else
{
/* First occurrence of this expression in this basic block. */
avail_occr = gcse_alloc (sizeof (struct occr));
bytes_used += sizeof (struct occr);
-
- /* First occurrence of this expression in any block? */
- if (cur_expr->avail_occr == NULL)
- cur_expr->avail_occr = avail_occr;
- else
- last_occr->next = avail_occr;
-
avail_occr->insn = insn;
- avail_occr->next = NULL;
+ avail_occr->next = cur_expr->avail_occr;
avail_occr->deleted_p = 0;
+ cur_expr->avail_occr = avail_occr;
}
}
}
int found;
unsigned int hash;
struct expr *cur_expr, *last_expr = NULL;
- struct occr *cur_occr, *last_occr = NULL;
+ struct occr *cur_occr;
gcc_assert (GET_CODE (x) == SET && REG_P (SET_DEST (x)));
/* Now record the occurrence. */
cur_occr = cur_expr->avail_occr;
- /* Search for another occurrence in the same basic block. */
- while (cur_occr && BLOCK_NUM (cur_occr->insn) != BLOCK_NUM (insn))
+ if (cur_occr && BLOCK_NUM (cur_occr->insn) == BLOCK_NUM (insn))
{
- /* If an occurrence isn't found, save a pointer to the end of
- the list. */
- last_occr = cur_occr;
- cur_occr = cur_occr->next;
+ /* Found another instance of the expression in the same basic block.
+ Prefer this occurrence to the currently recorded one. We want
+ the last one in the block and the block is scanned from start
+ to end. */
+ cur_occr->insn = insn;
}
-
- if (cur_occr)
- /* Found another instance of the expression in the same basic block.
- Prefer this occurrence to the currently recorded one. We want the
- last one in the block and the block is scanned from start to end. */
- cur_occr->insn = insn;
else
{
/* First occurrence of this expression in this basic block. */
cur_occr = gcse_alloc (sizeof (struct occr));
bytes_used += sizeof (struct occr);
- /* First occurrence of this expression in any block? */
- if (cur_expr->avail_occr == NULL)
- cur_expr->avail_occr = cur_occr;
- else
- last_occr->next = cur_occr;
-
- cur_occr->insn = insn;
- cur_occr->next = NULL;
- cur_occr->deleted_p = 0;
+ cur_occr->insn = insn;
+ cur_occr->next = cur_expr->avail_occr;
+ cur_occr->deleted_p = 0;
+ cur_expr->avail_occr = cur_occr;
}
}
while (GET_CODE (dest) == SUBREG
|| GET_CODE (dest) == ZERO_EXTRACT
- || GET_CODE (dest) == SIGN_EXTRACT
|| GET_CODE (dest) == STRICT_LOW_PART)
dest = XEXP (dest, 0);
alloc_EXPR_LIST (VOIDmode, dest_addr, canon_modify_mem_list[bb]);
canon_modify_mem_list[bb] =
alloc_EXPR_LIST (VOIDmode, dest, canon_modify_mem_list[bb]);
- bitmap_set_bit (canon_modify_mem_list_set, bb);
}
/* Record memory modification information for INSN. We do not actually care
need to insert a pair of items, as canon_list_insert does. */
canon_modify_mem_list[bb] =
alloc_INSN_LIST (insn, canon_modify_mem_list[bb]);
- bitmap_set_bit (canon_modify_mem_list_set, bb);
+ bitmap_set_bit (blocks_with_calls, bb);
}
else
note_stores (PATTERN (insn), canon_list_insert, (void*) insn);
??? hard-reg reg_set_in_block computation
could be moved to compute_sets since they currently don't change. */
- for (insn = BB_HEAD (current_bb);
- insn && insn != NEXT_INSN (BB_END (current_bb));
- insn = NEXT_INSN (insn))
+ FOR_BB_INSNS (current_bb, insn)
{
if (! INSN_P (insn))
continue;
if (CALL_P (insn))
{
- bool clobbers_all = false;
-#ifdef NON_SAVING_SETJMP
- if (NON_SAVING_SETJMP
- && find_reg_note (insn, REG_SETJMP, NULL_RTX))
- clobbers_all = true;
-#endif
-
for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
- if (clobbers_all
- || TEST_HARD_REG_BIT (regs_invalidated_by_call, regno))
+ if (TEST_HARD_REG_BIT (regs_invalidated_by_call, regno))
record_last_reg_set_info (insn, regno);
mark_call (insn);
BB_HEAD (current_bb), table);
/* The next pass builds the hash table. */
-
- for (insn = BB_HEAD (current_bb), in_libcall_block = 0;
- insn && insn != NEXT_INSN (BB_END (current_bb));
- insn = NEXT_INSN (insn))
+ in_libcall_block = 0;
+ FOR_BB_INSNS (current_bb, insn)
if (INSN_P (insn))
{
if (find_reg_note (insn, REG_LIBCALL, NULL_RTX))
static void
clear_modify_mem_tables (void)
{
- int i;
+ unsigned i;
bitmap_iterator bi;
EXECUTE_IF_SET_IN_BITMAP (modify_mem_list_set, 0, i, bi)
{
free_INSN_LIST_list (modify_mem_list + i);
- }
- bitmap_clear (modify_mem_list_set);
-
- EXECUTE_IF_SET_IN_BITMAP (canon_modify_mem_list_set, 0, i, bi)
- {
free_insn_expr_list_list (canon_modify_mem_list + i);
}
- bitmap_clear (canon_modify_mem_list_set);
+ bitmap_clear (modify_mem_list_set);
+ bitmap_clear (blocks_with_calls);
}
-/* Release memory used by modify_mem_list_set and canon_modify_mem_list_set. */
+/* Release memory used by modify_mem_list_set. */
static void
free_modify_mem_tables (void)
while (GET_CODE (dest) == SUBREG
|| GET_CODE (dest) == ZERO_EXTRACT
- || GET_CODE (dest) == SIGN_EXTRACT
|| GET_CODE (dest) == STRICT_LOW_PART)
dest = XEXP (dest, 0);
else
{
for (r = reg_set_table[REGNO (x)]; r != NULL; r = r->next)
- SET_BIT (bmap[BLOCK_NUM (r->insn)], indx);
+ SET_BIT (bmap[r->bb_index], indx);
}
}
else
else
{
for (r = reg_set_table[REGNO (x)]; r != NULL; r = r->next)
- RESET_BIT (bmap[BLOCK_NUM (r->insn)], indx);
+ RESET_BIT (bmap[r->bb_index], indx);
}
}
return;
case MEM:
- FOR_EACH_BB (bb)
- {
- rtx list_entry = canon_modify_mem_list[bb->index];
+ {
+ bitmap_iterator bi;
+ unsigned bb_index;
- while (list_entry)
- {
- rtx dest, dest_addr;
+ /* First handle all the blocks with calls. We don't need to
+ do any list walking for them. */
+ EXECUTE_IF_SET_IN_BITMAP (blocks_with_calls, 0, bb_index, bi)
+ {
+ if (set_p)
+ SET_BIT (bmap[bb_index], indx);
+ else
+ RESET_BIT (bmap[bb_index], indx);
+ }
- if (CALL_P (XEXP (list_entry, 0)))
- {
- if (set_p)
- SET_BIT (bmap[bb->index], indx);
- else
- RESET_BIT (bmap[bb->index], indx);
- break;
- }
- /* LIST_ENTRY must be an INSN of some kind that sets memory.
- Examine each hunk of memory that is modified. */
+ /* Now iterate over the blocks which have memory modifications
+ but which do not have any calls. */
+ EXECUTE_IF_AND_COMPL_IN_BITMAP (modify_mem_list_set, blocks_with_calls,
+ 0, bb_index, bi)
+ {
+ rtx list_entry = canon_modify_mem_list[bb_index];
- dest = XEXP (list_entry, 0);
- list_entry = XEXP (list_entry, 1);
- dest_addr = XEXP (list_entry, 0);
+ while (list_entry)
+ {
+ rtx dest, dest_addr;
- if (canon_true_dependence (dest, GET_MODE (dest), dest_addr,
- x, rtx_addr_varies_p))
- {
- if (set_p)
- SET_BIT (bmap[bb->index], indx);
- else
- RESET_BIT (bmap[bb->index], indx);
- break;
- }
- list_entry = XEXP (list_entry, 1);
- }
- }
+ /* LIST_ENTRY must be an INSN of some kind that sets memory.
+ Examine each hunk of memory that is modified. */
+
+ dest = XEXP (list_entry, 0);
+ list_entry = XEXP (list_entry, 1);
+ dest_addr = XEXP (list_entry, 0);
+
+ if (canon_true_dependence (dest, GET_MODE (dest), dest_addr,
+ x, rtx_addr_varies_p))
+ {
+ if (set_p)
+ SET_BIT (bmap[bb_index], indx);
+ else
+ RESET_BIT (bmap[bb_index], indx);
+ break;
+ }
+ list_entry = XEXP (list_entry, 1);
+ }
+ }
+ }
x = XEXP (x, 0);
goto repeat;
have a note, and have no special SET, add a REG_EQUAL note to not
lose information. */
if (!success && note == 0 && set != 0
- && GET_CODE (XEXP (set, 0)) != ZERO_EXTRACT
- && GET_CODE (XEXP (set, 0)) != SIGN_EXTRACT)
+ && GET_CODE (SET_DEST (set)) != ZERO_EXTRACT)
note = set_unique_reg_note (insn, REG_EQUAL, copy_rtx (src));
}
}
static bool
-constprop_register (rtx insn, rtx from, rtx to, int alter_jumps)
+constprop_register (rtx insn, rtx from, rtx to, bool alter_jumps)
{
rtx sset;
their REG_EQUAL notes need updating. */
static bool
-do_local_cprop (rtx x, rtx insn, int alter_jumps, rtx *libcall_sp)
+do_local_cprop (rtx x, rtx insn, bool alter_jumps, rtx *libcall_sp)
{
rtx newreg = NULL, newcnst = NULL;
rtx this_rtx = l->loc;
rtx note;
- if (l->in_libcall)
+ /* Don't CSE non-constant values out of libcall blocks. */
+ if (l->in_libcall && ! CONSTANT_P (this_rtx))
continue;
if (gcse_constant_p (this_rtx))
return true;
}
}
- XEXP (note, 0) = replace_rtx (XEXP (note, 0), oldreg, newval);
+ XEXP (note, 0) = simplify_replace_rtx (XEXP (note, 0), oldreg, newval);
insn = end;
}
return true;
#define MAX_NESTED_LIBCALLS 9
+/* Do local const/copy propagation (i.e. within each basic block).
+ If ALTER_JUMPS is true, allow propagating into jump insns, which
+ could modify the CFG. */
+
static void
-local_cprop_pass (int alter_jumps)
+local_cprop_pass (bool alter_jumps)
{
+ basic_block bb;
rtx insn;
struct reg_use *reg_used;
rtx libcall_stack[MAX_NESTED_LIBCALLS + 1], *libcall_sp;
cselib_init (false);
libcall_sp = &libcall_stack[MAX_NESTED_LIBCALLS];
*libcall_sp = 0;
- for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+ FOR_EACH_BB (bb)
{
- if (INSN_P (insn))
+ FOR_BB_INSNS (bb, insn)
{
- rtx note = find_reg_note (insn, REG_LIBCALL, NULL_RTX);
-
- if (note)
- {
- gcc_assert (libcall_sp != libcall_stack);
- *--libcall_sp = XEXP (note, 0);
- }
- note = find_reg_note (insn, REG_RETVAL, NULL_RTX);
- if (note)
- libcall_sp++;
- note = find_reg_equal_equiv_note (insn);
- do
+ if (INSN_P (insn))
{
- reg_use_count = 0;
- note_uses (&PATTERN (insn), local_cprop_find_used_regs, NULL);
- if (note)
- local_cprop_find_used_regs (&XEXP (note, 0), NULL);
+ rtx note = find_reg_note (insn, REG_LIBCALL, NULL_RTX);
- for (reg_used = ®_use_table[0]; reg_use_count > 0;
- reg_used++, reg_use_count--)
- if (do_local_cprop (reg_used->reg_rtx, insn, alter_jumps,
- libcall_sp))
- {
- changed = true;
+ if (note)
+ {
+ gcc_assert (libcall_sp != libcall_stack);
+ *--libcall_sp = XEXP (note, 0);
+ }
+ note = find_reg_note (insn, REG_RETVAL, NULL_RTX);
+ if (note)
+ libcall_sp++;
+ note = find_reg_equal_equiv_note (insn);
+ do
+ {
+ reg_use_count = 0;
+ note_uses (&PATTERN (insn), local_cprop_find_used_regs,
+ NULL);
+ if (note)
+ local_cprop_find_used_regs (&XEXP (note, 0), NULL);
+
+ for (reg_used = ®_use_table[0]; reg_use_count > 0;
+ reg_used++, reg_use_count--)
+ if (do_local_cprop (reg_used->reg_rtx, insn, alter_jumps,
+ libcall_sp))
+ {
+ changed = true;
+ break;
+ }
+ if (INSN_DELETED_P (insn))
break;
- }
- if (INSN_DELETED_P (insn))
- break;
+ }
+ while (reg_use_count);
}
- while (reg_use_count);
+ cselib_process_insn (insn);
}
- cselib_process_insn (insn);
+
+ /* Forget everything at the end of a basic block. Make sure we are
+ not inside a libcall, they should never cross basic blocks. */
+ cselib_clear_table ();
+ gcc_assert (libcall_sp == &libcall_stack[MAX_NESTED_LIBCALLS]);
}
+
cselib_finish ();
+
/* Global analysis may get into infinite loops for unreachable blocks. */
if (changed && alter_jumps)
{
delete_unreachable_blocks ();
free_reg_set_mem ();
alloc_reg_set_mem (max_reg_num ());
- compute_sets (get_insns ());
+ compute_sets ();
}
}
start of the block]. */
reset_opr_set_tables ();
- for (insn = BB_HEAD (bb);
- insn != NULL && insn != NEXT_INSN (BB_END (bb));
- insn = NEXT_INSN (insn))
+ FOR_BB_INSNS (bb, insn)
if (INSN_P (insn))
{
changed |= cprop_insn (insn, alter_jumps);
settle for the condition variable in the jump instruction being integral.
We prefer to be able to record the value of a user variable, rather than
the value of a temporary used in a condition. This could be solved by
- recording the value of *every* register scaned by canonicalize_condition,
+ recording the value of *every* register scanned by canonicalize_condition,
but this would require some code reorganization. */
rtx
dest = GET_CODE (cond) == EQ ? BRANCH_EDGE (bb)->dest
: FALLTHRU_EDGE (bb)->dest;
- if (dest && EDGE_COUNT (dest->preds) == 1
+ if (dest && single_pred_p (dest)
&& dest != EXIT_BLOCK_PTR)
{
new = gen_rtx_SET (VOIDmode, XEXP (cond, 0),
perform conditional jump bypassing optimizations. */
static int
-one_cprop_pass (int pass, int cprop_jumps, int bypass_jumps)
+one_cprop_pass (int pass, bool cprop_jumps, bool bypass_jumps)
{
int changed = 0;
}
else if (GET_CODE (new) == LABEL_REF)
{
- edge_iterator ei2;
-
dest = BLOCK_FOR_INSN (XEXP (new, 0));
/* Don't bypass edges containing instructions. */
- FOR_EACH_EDGE (edest, ei2, bb->succs)
- if (edest->dest == dest && edest->insns.r)
- {
- dest = NULL;
- break;
- }
+ edest = find_edge (bb, dest);
+ if (edest && edest->insns.r)
+ dest = NULL;
}
else
dest = NULL;
branch. We would end up emitting the instruction on "both"
edges. */
- if (dest && setcc && !CC0_P (SET_DEST (PATTERN (setcc))))
- {
- edge e2;
- edge_iterator ei2;
-
- FOR_EACH_EDGE (e2, ei2, e->src->succs)
- if (e2->dest == dest)
- {
- dest = NULL;
- break;
- }
- }
+ if (dest && setcc && !CC0_P (SET_DEST (PATTERN (setcc)))
+ && find_edge (e->src, dest))
+ dest = NULL;
old_dest = e->dest;
if (dest != NULL
EXIT_BLOCK_PTR, next_bb)
{
/* Check for more than one predecessor. */
- if (EDGE_COUNT (bb->preds) > 1)
+ if (!single_pred_p (bb))
{
setcc = NULL_RTX;
- for (insn = BB_HEAD (bb);
- insn != NULL && insn != NEXT_INSN (BB_END (bb));
- insn = NEXT_INSN (insn))
+ FOR_BB_INSNS (bb, insn)
if (NONJUMP_INSN_P (insn))
{
if (setcc)
if (JUMP_P (insn)
|| (NONJUMP_INSN_P (insn)
- && (EDGE_COUNT (bb->succs) > 1
- || EDGE_SUCC (bb, 0)->flags & EDGE_ABNORMAL)))
+ && (!single_succ_p (bb)
+ || single_succ_edge (bb)->flags & EDGE_ABNORMAL)))
{
#ifdef HAVE_cc0
rtx note;
/* Likewise if the last insn is a call, as will happen in the presence
of exception handling. */
else if (CALL_P (insn)
- && (EDGE_COUNT (bb->succs) > 1 || EDGE_SUCC (bb, 0)->flags & EDGE_ABNORMAL))
+ && (!single_succ_p (bb)
+ || single_succ_edge (bb)->flags & EDGE_ABNORMAL))
{
/* Keeping in mind SMALL_REGISTER_CLASSES and parameters in registers,
we search backward and place the instructions before the first
if (! occr->deleted_p)
continue;
- /* Insert this expression on this edge if if it would
+ /* Insert this expression on this edge if it would
reach the deleted occurrence in BB. */
if (!TEST_BIT (inserted[e], j))
{
handling this situation. This one is easiest for
now. */
- if ((eg->flags & EDGE_ABNORMAL) == EDGE_ABNORMAL)
+ if (eg->flags & EDGE_ABNORMAL)
insert_insn_end_bb (index_map[j], bb, 0);
else
{
new_insn = emit_insn_after (new_insn, insn);
/* Keep register set table up to date. */
- replace_one_set (REGNO (old_reg), insn, new_insn);
record_one_set (regno, insn);
}
else
FOR_EACH_BB (bb)
{
- for (insn = BB_HEAD (bb);
- insn && insn != NEXT_INSN (BB_END (bb));
- insn = NEXT_INSN (insn))
+ FOR_BB_INSNS (bb, insn)
{
if (INSN_P (insn))
{
/* First compute the registers set in this block. */
regvec = last_set_in;
- for (insn = BB_HEAD (bb);
- insn != NEXT_INSN (BB_END (bb));
- insn = NEXT_INSN (insn))
+ FOR_BB_INSNS (bb, insn)
{
if (! INSN_P (insn))
continue;
if (CALL_P (insn))
{
- bool clobbers_all = false;
-#ifdef NON_SAVING_SETJMP
- if (NON_SAVING_SETJMP
- && find_reg_note (insn, REG_SETJMP, NULL_RTX))
- clobbers_all = true;
-#endif
-
for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
- if (clobbers_all
- || TEST_HARD_REG_BIT (regs_invalidated_by_call, regno))
+ if (TEST_HARD_REG_BIT (regs_invalidated_by_call, regno))
{
last_set_in[regno] = INSN_UID (insn);
SET_BIT (reg_set_in_block[bb->index], regno);
/* Now find the stores. */
memset (already_set, 0, sizeof (int) * max_gcse_regno);
regvec = already_set;
- for (insn = BB_HEAD (bb);
- insn != NEXT_INSN (BB_END (bb));
- insn = NEXT_INSN (insn))
+ FOR_BB_INSNS (bb, insn)
{
if (! INSN_P (insn))
continue;
if (CALL_P (insn))
{
- bool clobbers_all = false;
-#ifdef NON_SAVING_SETJMP
- if (NON_SAVING_SETJMP
- && find_reg_note (insn, REG_SETJMP, NULL_RTX))
- clobbers_all = true;
-#endif
-
for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
- if (clobbers_all
- || TEST_HARD_REG_BIT (regs_invalidated_by_call, regno))
+ if (TEST_HARD_REG_BIT (regs_invalidated_by_call, regno))
already_set[regno] = 1;
}
note_stores (pat, reg_clear_last_set, last_set_in);
if (CALL_P (insn))
{
- bool clobbers_all = false;
-#ifdef NON_SAVING_SETJMP
- if (NON_SAVING_SETJMP
- && find_reg_note (insn, REG_SETJMP, NULL_RTX))
- clobbers_all = true;
-#endif
-
for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
- if ((clobbers_all
- || TEST_HARD_REG_BIT (regs_invalidated_by_call, regno))
+ if (TEST_HARD_REG_BIT (regs_invalidated_by_call, regno)
&& last_set_in[regno] == INSN_UID (insn))
last_set_in[regno] = 0;
}
/* Check if INSN kills the store pattern X (is aliased with it).
AFTER is true if we are checking the case when store X occurs
- after the insn. Return true if it it does. */
+ after the insn. Return true if it does. */
static bool
store_killed_in_insn (rtx x, rtx x_regs, rtx insn, int after)
rtx pat = PATTERN (insn);
rtx dest = SET_DEST (pat);
- if (GET_CODE (dest) == SIGN_EXTRACT
- || GET_CODE (dest) == ZERO_EXTRACT)
+ if (GET_CODE (dest) == ZERO_EXTRACT)
dest = XEXP (dest, 0);
/* Check for memory stores to aliased objects. */
return 0;
}
- /* We can't insert on this edge, so we'll insert at the head of the
- successors block. See Morgan, sec 10.5. */
- if ((e->flags & EDGE_ABNORMAL) == EDGE_ABNORMAL)
- {
- insert_insn_start_bb (insn, bb);
- return 0;
- }
+ /* We can't put stores in the front of blocks pointed to by abnormal
+ edges since that may put a store where one didn't used to be. */
+ gcc_assert (!(e->flags & EDGE_ABNORMAL));
insert_insn_on_edge (insn, e);
sbitmap_zero (visited);
- act = (EDGE_COUNT (ei.container) > 0 ? EDGE_I (ei.container, 0) : NULL);
+ act = (EDGE_COUNT (ei_container (ei)) > 0 ? EDGE_I (ei_container (ei), 0) : NULL);
while (1)
{
if (!act)
if (act)
stack[sp++] = ei;
ei = ei_start (bb->succs);
- act = (EDGE_COUNT (ei.container) > 0 ? EDGE_I (ei.container, 0) : NULL);
+ act = (EDGE_COUNT (ei_container (ei)) > 0 ? EDGE_I (ei_container (ei), 0) : NULL);
}
}
}
/* Now we want to insert the new stores which are going to be needed. */
for (ptr = first_ls_expr (); ptr != NULL; ptr = next_ls_expr (ptr))
{
+ /* If any of the edges we have above are abnormal, we can't move this
+ store. */
+ for (x = NUM_EDGES (edge_list) - 1; x >= 0; x--)
+ if (TEST_BIT (pre_insert_map[x], ptr->index)
+ && (INDEX_EDGE (edge_list, x)->flags & EDGE_ABNORMAL))
+ break;
+
+ if (x >= 0)
+ {
+ if (gcse_file != NULL)
+ fprintf (gcse_file,
+ "Can't replace store %d: abnormal edge from %d to %d\n",
+ ptr->index, INDEX_EDGE (edge_list, x)->src->index,
+ INDEX_EDGE (edge_list, x)->dest->index);
+ continue;
+ }
+
+ /* Now we want to insert the new stores which are going to be needed. */
+
FOR_EACH_BB (bb)
if (TEST_BIT (pre_delete_map[bb->index], ptr->index))
delete_store (ptr, bb);
information about memory sets when we build the hash tables. */
alloc_reg_set_mem (max_gcse_regno);
- compute_sets (get_insns ());
+ compute_sets ();
max_gcse_regno = max_reg_num ();
- alloc_gcse_mem (get_insns ());
- changed = one_cprop_pass (MAX_GCSE_PASSES + 2, 1, 1);
+ alloc_gcse_mem ();
+ changed = one_cprop_pass (MAX_GCSE_PASSES + 2, true, true);
free_gcse_mem ();
if (file)