summaryrefslogtreecommitdiff
path: root/gnu/usr.bin/gcc/cse.c
diff options
context:
space:
mode:
authorJason Downs <downsj@cvs.openbsd.org>1997-04-09 13:44:52 +0000
committerJason Downs <downsj@cvs.openbsd.org>1997-04-09 13:44:52 +0000
commit454abcd55d12d4ef15ec29c89b2ad4d47f3c82d1 (patch)
tree03ae5cb442348bb46932a1a62039a44962996f47 /gnu/usr.bin/gcc/cse.c
parentc1c4ca433ba86feadc773a80691f0e693d52ecd8 (diff)
Revert to older (working) version of gcc, plus recent changes.
Diffstat (limited to 'gnu/usr.bin/gcc/cse.c')
-rw-r--r--gnu/usr.bin/gcc/cse.c400
1 files changed, 281 insertions, 119 deletions
diff --git a/gnu/usr.bin/gcc/cse.c b/gnu/usr.bin/gcc/cse.c
index e6d2884245f..efd05dedaf9 100644
--- a/gnu/usr.bin/gcc/cse.c
+++ b/gnu/usr.bin/gcc/cse.c
@@ -519,6 +519,27 @@ static struct table_elt *last_jump_equiv_class;
static int constant_pool_entries_cost;
+/* Bits describing what kind of values in memory must be invalidated
+ for a particular instruction. If all three bits are zero,
+ no memory refs need to be invalidated. Each bit is more powerful
+ than the preceding ones, and if a bit is set then the preceding
+ bits are also set.
+
+ Here is how the bits are set:
+ Pushing onto the stack invalidates only the stack pointer,
+ writing at a fixed address invalidates only variable addresses,
+ writing in a structure element at variable address
+ invalidates all but scalar variables,
+ and writing in anything else at variable address invalidates everything. */
+
+struct write_data
+{
+ int sp : 1; /* Invalidate stack pointer. */
+ int var : 1; /* Invalidate variable addresses. */
+ int nonscalar : 1; /* Invalidate all but scalar variables. */
+ int all : 1; /* Invalidate all memory refs. */
+};
+
/* Define maximum length of a branch path. */
#define PATHLENGTH 10
@@ -604,10 +625,9 @@ static struct table_elt *insert PROTO((rtx, struct table_elt *, unsigned,
static void merge_equiv_classes PROTO((struct table_elt *,
struct table_elt *));
static void invalidate PROTO((rtx, enum machine_mode));
-static int cse_rtx_varies_p PROTO((rtx));
static void remove_invalid_refs PROTO((int));
static void rehash_using_reg PROTO((rtx));
-static void invalidate_memory PROTO((void));
+static void invalidate_memory PROTO((struct write_data *));
static void invalidate_for_call PROTO((void));
static rtx use_related_value PROTO((rtx, struct table_elt *));
static unsigned canon_hash PROTO((rtx, enum machine_mode));
@@ -617,6 +637,9 @@ static void set_nonvarying_address_components PROTO((rtx, int, rtx *,
HOST_WIDE_INT *,
HOST_WIDE_INT *));
static int refers_to_p PROTO((rtx, rtx));
+static int refers_to_mem_p PROTO((rtx, rtx, HOST_WIDE_INT,
+ HOST_WIDE_INT));
+static int cse_rtx_addr_varies_p PROTO((rtx));
static rtx canon_reg PROTO((rtx, rtx));
static void find_best_addr PROTO((rtx, rtx *));
static enum rtx_code find_comparison_args PROTO((enum rtx_code, rtx *, rtx *,
@@ -632,8 +655,8 @@ static void record_jump_equiv PROTO((rtx, int));
static void record_jump_cond PROTO((enum rtx_code, enum machine_mode,
rtx, rtx, int));
static void cse_insn PROTO((rtx, int));
-static int note_mem_written PROTO((rtx));
-static void invalidate_from_clobbers PROTO((rtx));
+static void note_mem_written PROTO((rtx, struct write_data *));
+static void invalidate_from_clobbers PROTO((struct write_data *, rtx));
static rtx cse_process_notes PROTO((rtx, rtx));
static void cse_around_loop PROTO((rtx));
static void invalidate_skipped_set PROTO((rtx, rtx));
@@ -1488,6 +1511,8 @@ invalidate (x, full_mode)
{
register int i;
register struct table_elt *p;
+ rtx base;
+ HOST_WIDE_INT start, end;
/* If X is a register, dependencies on its contents
are recorded through the qty number mechanism.
@@ -1579,17 +1604,16 @@ invalidate (x, full_mode)
if (full_mode == VOIDmode)
full_mode = GET_MODE (x);
+ set_nonvarying_address_components (XEXP (x, 0), GET_MODE_SIZE (full_mode),
+ &base, &start, &end);
+
for (i = 0; i < NBUCKETS; i++)
{
register struct table_elt *next;
for (p = table[i]; p; p = next)
{
next = p->next_same_hash;
- /* Invalidate ASM_OPERANDS which reference memory (this is easier
- than checking all the aliases). */
- if (p->in_memory
- && (GET_CODE (p->exp) != MEM
- || true_dependence (x, full_mode, p->exp, cse_rtx_varies_p)))
+ if (refers_to_mem_p (p->exp, base, start, end))
remove_from_table (p, i);
}
}
@@ -1670,6 +1694,30 @@ rehash_using_reg (x)
}
}
+/* Remove from the hash table all expressions that reference memory,
+ or some of them as specified by *WRITES. */
+
+static void
+invalidate_memory (writes)
+ struct write_data *writes;
+{
+ register int i;
+ register struct table_elt *p, *next;
+ int all = writes->all;
+ int nonscalar = writes->nonscalar;
+
+ for (i = 0; i < NBUCKETS; i++)
+ for (p = table[i]; p; p = next)
+ {
+ next = p->next_same_hash;
+ if (p->in_memory
+ && (all
+ || (nonscalar && p->in_struct)
+ || cse_rtx_addr_varies_p (p->exp)))
+ remove_from_table (p, i);
+ }
+}
+
/* Remove from the hash table any expression that is a call-clobbered
register. Also update their TICK values. */
@@ -1707,12 +1755,6 @@ invalidate_for_call ()
{
next = p->next_same_hash;
- if (p->in_memory)
- {
- remove_from_table (p, hash);
- continue;
- }
-
if (GET_CODE (p->exp) != REG
|| REGNO (p->exp) >= FIRST_PSEUDO_REGISTER)
continue;
@@ -2352,31 +2394,105 @@ set_nonvarying_address_components (addr, size, pbase, pstart, pend)
*pend = end;
}
-/* Nonzero if X, a memory address, refers to a varying address;
+/* Return 1 iff any subexpression of X refers to memory
+ at an address of BASE plus some offset
+ such that any of the bytes' offsets fall between START (inclusive)
+ and END (exclusive).
+
+ The value is undefined if X is a varying address (as determined by
+ cse_rtx_addr_varies_p). This function is not used in such cases.
+
+ When used in the cse pass, `qty_const' is nonzero, and it is used
+ to treat an address that is a register with a known constant value
+ as if it were that constant value.
+ In the loop pass, `qty_const' is zero, so this is not done. */
+
+static int
+refers_to_mem_p (x, base, start, end)
+ rtx x, base;
+ HOST_WIDE_INT start, end;
+{
+ register HOST_WIDE_INT i;
+ register enum rtx_code code;
+ register char *fmt;
+
+ repeat:
+ if (x == 0)
+ return 0;
+
+ code = GET_CODE (x);
+ if (code == MEM)
+ {
+ register rtx addr = XEXP (x, 0); /* Get the address. */
+ rtx mybase;
+ HOST_WIDE_INT mystart, myend;
+
+ set_nonvarying_address_components (addr, GET_MODE_SIZE (GET_MODE (x)),
+ &mybase, &mystart, &myend);
+
+
+ /* refers_to_mem_p is never called with varying addresses.
+ If the base addresses are not equal, there is no chance
+ of the memory addresses conflicting. */
+ if (! rtx_equal_p (mybase, base))
+ return 0;
+
+ return myend > start && mystart < end;
+ }
+
+ /* X does not match, so try its subexpressions. */
+
+ fmt = GET_RTX_FORMAT (code);
+ for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+ if (fmt[i] == 'e')
+ {
+ if (i == 0)
+ {
+ x = XEXP (x, 0);
+ goto repeat;
+ }
+ else
+ if (refers_to_mem_p (XEXP (x, i), base, start, end))
+ return 1;
+ }
+ else if (fmt[i] == 'E')
+ {
+ int j;
+ for (j = 0; j < XVECLEN (x, i); j++)
+ if (refers_to_mem_p (XVECEXP (x, i, j), base, start, end))
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Nonzero if X refers to memory at a varying address;
except that a register which has at the moment a known constant value
isn't considered variable. */
static int
-cse_rtx_varies_p (x)
- register rtx x;
+cse_rtx_addr_varies_p (x)
+ rtx x;
{
/* We need not check for X and the equivalence class being of the same
mode because if X is equivalent to a constant in some mode, it
doesn't vary in any mode. */
- if (GET_CODE (x) == REG
- && REGNO_QTY_VALID_P (REGNO (x))
- && GET_MODE (x) == qty_mode[reg_qty[REGNO (x)]]
- && qty_const[reg_qty[REGNO (x)]] != 0)
- return 0;
-
- if (GET_CODE (x) == PLUS
- && GET_CODE (XEXP (x, 1)) == CONST_INT
+ if (GET_CODE (x) == MEM
&& GET_CODE (XEXP (x, 0)) == REG
&& REGNO_QTY_VALID_P (REGNO (XEXP (x, 0)))
- && (GET_MODE (XEXP (x, 0))
- == qty_mode[reg_qty[REGNO (XEXP (x, 0))]])
- && qty_const[reg_qty[REGNO (XEXP (x, 0))]])
+ && GET_MODE (XEXP (x, 0)) == qty_mode[reg_qty[REGNO (XEXP (x, 0))]]
+ && qty_const[reg_qty[REGNO (XEXP (x, 0))]] != 0)
+ return 0;
+
+ if (GET_CODE (x) == MEM
+ && GET_CODE (XEXP (x, 0)) == PLUS
+ && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
+ && GET_CODE (XEXP (XEXP (x, 0), 0)) == REG
+ && REGNO_QTY_VALID_P (REGNO (XEXP (XEXP (x, 0), 0)))
+ && (GET_MODE (XEXP (XEXP (x, 0), 0))
+ == qty_mode[reg_qty[REGNO (XEXP (XEXP (x, 0), 0))]])
+ && qty_const[reg_qty[REGNO (XEXP (XEXP (x, 0), 0))]])
return 0;
/* This can happen as the result of virtual register instantiation, if
@@ -2384,20 +2500,21 @@ cse_rtx_varies_p (x)
us a three instruction sequence, load large offset into a register,
load fp minus a constant into a register, then a MEM which is the
sum of the two `constant' registers. */
- if (GET_CODE (x) == PLUS
- && GET_CODE (XEXP (x, 0)) == REG
- && GET_CODE (XEXP (x, 1)) == REG
- && REGNO_QTY_VALID_P (REGNO (XEXP (x, 0)))
- && (GET_MODE (XEXP (x, 0))
- == qty_mode[reg_qty[REGNO (XEXP (x, 0))]])
- && qty_const[reg_qty[REGNO (XEXP (x, 0))]]
- && REGNO_QTY_VALID_P (REGNO (XEXP (x, 1)))
- && (GET_MODE (XEXP (x, 1))
- == qty_mode[reg_qty[REGNO (XEXP (x, 1))]])
- && qty_const[reg_qty[REGNO (XEXP (x, 1))]])
+ if (GET_CODE (x) == MEM
+ && GET_CODE (XEXP (x, 0)) == PLUS
+ && GET_CODE (XEXP (XEXP (x, 0), 0)) == REG
+ && GET_CODE (XEXP (XEXP (x, 0), 1)) == REG
+ && REGNO_QTY_VALID_P (REGNO (XEXP (XEXP (x, 0), 0)))
+ && (GET_MODE (XEXP (XEXP (x, 0), 0))
+ == qty_mode[reg_qty[REGNO (XEXP (XEXP (x, 0), 0))]])
+ && qty_const[reg_qty[REGNO (XEXP (XEXP (x, 0), 0))]]
+ && REGNO_QTY_VALID_P (REGNO (XEXP (XEXP (x, 0), 1)))
+ && (GET_MODE (XEXP (XEXP (x, 0), 1))
+ == qty_mode[reg_qty[REGNO (XEXP (XEXP (x, 0), 1))]])
+ && qty_const[reg_qty[REGNO (XEXP (XEXP (x, 0), 1))]])
return 0;
- return rtx_varies_p (x);
+ return rtx_addr_varies_p (x);
}
/* Canonicalize an expression:
@@ -5987,6 +6104,8 @@ cse_insn (insn, in_libcall_block)
/* Records what this insn does to set CC0. */
rtx this_insn_cc0 = 0;
enum machine_mode this_insn_cc0_mode;
+ struct write_data writes_memory;
+ static struct write_data init = {0, 0, 0, 0};
rtx src_eqv = 0;
struct table_elt *src_eqv_elt = 0;
@@ -5998,6 +6117,7 @@ cse_insn (insn, in_libcall_block)
struct set *sets;
this_insn = insn;
+ writes_memory = init;
/* Find all the SETs and CLOBBERs in this instruction.
Record all the SETs in the array `set' and count them.
@@ -6099,13 +6219,14 @@ cse_insn (insn, in_libcall_block)
}
else if (GET_CODE (y) == CLOBBER)
{
- /* If we clobber memory, canon the address.
+ /* If we clobber memory, take note of that,
+ and canon the address.
This does nothing when a register is clobbered
because we have already invalidated the reg. */
if (GET_CODE (XEXP (y, 0)) == MEM)
{
canon_reg (XEXP (y, 0), NULL_RTX);
- note_mem_written (XEXP (y, 0));
+ note_mem_written (XEXP (y, 0), &writes_memory);
}
}
else if (GET_CODE (y) == USE
@@ -6127,7 +6248,7 @@ cse_insn (insn, in_libcall_block)
if (GET_CODE (XEXP (x, 0)) == MEM)
{
canon_reg (XEXP (x, 0), NULL_RTX);
- note_mem_written (XEXP (x, 0));
+ note_mem_written (XEXP (x, 0), &writes_memory);
}
}
@@ -6552,7 +6673,7 @@ cse_insn (insn, in_libcall_block)
}
}
#endif /* LOAD_EXTEND_OP */
-
+
if (src == src_folded)
src_folded = 0;
@@ -6738,8 +6859,7 @@ cse_insn (insn, in_libcall_block)
&& (src_folded == 0
|| (GET_CODE (src_folded) != MEM
&& ! src_folded_force_flag))
- && GET_MODE_CLASS (mode) != MODE_CC
- && mode != VOIDmode)
+ && GET_MODE_CLASS (mode) != MODE_CC)
{
src_folded_force_flag = 1;
src_folded = trial;
@@ -6863,7 +6983,12 @@ cse_insn (insn, in_libcall_block)
if (GET_CODE (dest) == MEM)
{
dest = fold_rtx (dest, insn);
- note_mem_written (dest);
+
+ /* Decide whether we invalidate everything in memory,
+ or just things at non-fixed places.
+ Writing a large aggregate must invalidate everything
+ because we don't know how long it is. */
+ note_mem_written (dest, &writes_memory);
}
/* Compute the hash code of the destination now,
@@ -7108,15 +7233,17 @@ cse_insn (insn, in_libcall_block)
so that the destination goes into that class. */
sets[i].src_elt = src_eqv_elt;
- invalidate_from_clobbers (x);
+ invalidate_from_clobbers (&writes_memory, x);
/* Some registers are invalidated by subroutine calls. Memory is
invalidated by non-constant calls. */
if (GET_CODE (insn) == CALL_INSN)
{
+ static struct write_data everything = {0, 1, 1, 1};
+
if (! CONST_CALL_P (insn))
- invalidate_memory ();
+ invalidate_memory (&everything);
invalidate_for_call ();
}
@@ -7137,7 +7264,8 @@ cse_insn (insn, in_libcall_block)
Needed for memory if this is a nonvarying address, unless
we have just done an invalidate_memory that covers even those. */
if (GET_CODE (dest) == REG || GET_CODE (dest) == SUBREG
- || GET_CODE (dest) == MEM)
+ || (GET_CODE (dest) == MEM && ! writes_memory.all
+ && ! cse_rtx_addr_varies_p (dest)))
invalidate (dest, VOIDmode);
else if (GET_CODE (dest) == STRICT_LOW_PART
|| GET_CODE (dest) == ZERO_EXTRACT)
@@ -7403,46 +7531,51 @@ cse_insn (insn, in_libcall_block)
prev_insn = insn;
}
+/* Store 1 in *WRITES_PTR for those categories of memory ref
+ that must be invalidated when the expression WRITTEN is stored in.
+ If WRITTEN is null, say everything must be invalidated. */
+
static void
-invalidate_memory ()
+note_mem_written (written, writes_ptr)
+ rtx written;
+ struct write_data *writes_ptr;
{
- register int i;
- register struct table_elt *p, *next;
-
- for (i = 0; i < NBUCKETS; i++)
- for (p = table[i]; p; p = next)
- {
- next = p->next_same_hash;
- if (p->in_memory)
- remove_from_table (p, i);
- }
-}
+ static struct write_data everything = {0, 1, 1, 1};
-static int
-note_mem_written (mem)
- register rtx mem;
-{
- if (mem == 0 || GET_CODE(mem) != MEM )
- return 0;
- else
- {
- register rtx addr = XEXP (mem, 0);
- /* Pushing or popping the stack invalidates just the stack pointer. */
- if ((GET_CODE (addr) == PRE_DEC || GET_CODE (addr) == PRE_INC
- || GET_CODE (addr) == POST_DEC || GET_CODE (addr) == POST_INC)
- && GET_CODE (XEXP (addr, 0)) == REG
- && REGNO (XEXP (addr, 0)) == STACK_POINTER_REGNUM)
+ if (written == 0)
+ *writes_ptr = everything;
+ else if (GET_CODE (written) == MEM)
{
- if (reg_tick[STACK_POINTER_REGNUM] >= 0)
- reg_tick[STACK_POINTER_REGNUM]++;
-
- /* This should be *very* rare. */
- if (TEST_HARD_REG_BIT (hard_regs_in_table, STACK_POINTER_REGNUM))
- invalidate (stack_pointer_rtx, VOIDmode);
- return 1;
+ /* Pushing or popping the stack invalidates just the stack pointer. */
+ rtx addr = XEXP (written, 0);
+ if ((GET_CODE (addr) == PRE_DEC || GET_CODE (addr) == PRE_INC
+ || GET_CODE (addr) == POST_DEC || GET_CODE (addr) == POST_INC)
+ && GET_CODE (XEXP (addr, 0)) == REG
+ && REGNO (XEXP (addr, 0)) == STACK_POINTER_REGNUM)
+ {
+ writes_ptr->sp = 1;
+ return;
+ }
+ else if (GET_MODE (written) == BLKmode)
+ *writes_ptr = everything;
+ /* (mem (scratch)) means clobber everything. */
+ else if (GET_CODE (addr) == SCRATCH)
+ *writes_ptr = everything;
+ else if (cse_rtx_addr_varies_p (written))
+ {
+ /* A varying address that is a sum indicates an array element,
+ and that's just as good as a structure element
+ in implying that we need not invalidate scalar variables.
+ However, we must allow QImode aliasing of scalars, because the
+ ANSI C standard allows character pointers to alias anything. */
+ if (! ((MEM_IN_STRUCT_P (written)
+ || GET_CODE (XEXP (written, 0)) == PLUS)
+ && GET_MODE (written) != QImode))
+ writes_ptr->all = 1;
+ writes_ptr->nonscalar = 1;
+ }
+ writes_ptr->var = 1;
}
- return 0;
- }
}
/* Perform invalidation on the basis of everything about an insn
@@ -7450,19 +7583,38 @@ note_mem_written (mem)
This includes the places CLOBBERed, and anything that might
alias with something that is SET or CLOBBERed.
+ W points to the writes_memory for this insn, a struct write_data
+ saying which kinds of memory references must be invalidated.
X is the pattern of the insn. */
static void
-invalidate_from_clobbers (x)
+invalidate_from_clobbers (w, x)
+ struct write_data *w;
rtx x;
{
+ /* If W->var is not set, W specifies no action.
+ If W->all is set, this step gets all memory refs
+ so they can be ignored in the rest of this function. */
+ if (w->var)
+ invalidate_memory (w);
+
+ if (w->sp)
+ {
+ if (reg_tick[STACK_POINTER_REGNUM] >= 0)
+ reg_tick[STACK_POINTER_REGNUM]++;
+
+ /* This should be *very* rare. */
+ if (TEST_HARD_REG_BIT (hard_regs_in_table, STACK_POINTER_REGNUM))
+ invalidate (stack_pointer_rtx, VOIDmode);
+ }
+
if (GET_CODE (x) == CLOBBER)
{
rtx ref = XEXP (x, 0);
if (ref)
{
if (GET_CODE (ref) == REG || GET_CODE (ref) == SUBREG
- || GET_CODE (ref) == MEM)
+ || (GET_CODE (ref) == MEM && ! w->all))
invalidate (ref, VOIDmode);
else if (GET_CODE (ref) == STRICT_LOW_PART
|| GET_CODE (ref) == ZERO_EXTRACT)
@@ -7481,7 +7633,7 @@ invalidate_from_clobbers (x)
if (ref)
{
if (GET_CODE (ref) == REG || GET_CODE (ref) == SUBREG
- || GET_CODE (ref) == MEM)
+ || (GET_CODE (ref) == MEM && !w->all))
invalidate (ref, VOIDmode);
else if (GET_CODE (ref) == STRICT_LOW_PART
|| GET_CODE (ref) == ZERO_EXTRACT)
@@ -7647,6 +7799,10 @@ cse_around_loop (loop_start)
}
}
+/* Variable used for communications between the next two routines. */
+
+static struct write_data skipped_writes_memory;
+
/* Process one SET of an insn that was skipped. We ignore CLOBBERs
since they are done elsewhere. This function is called via note_stores. */
@@ -7655,22 +7811,6 @@ invalidate_skipped_set (dest, set)
rtx set;
rtx dest;
{
- enum rtx_code code = GET_CODE (dest);
-
- if (code == MEM
- && ! note_mem_written (dest) /* If this is not a stack push ... */
- /* There are times when an address can appear varying and be a PLUS
- during this scan when it would be a fixed address were we to know
- the proper equivalences. So invalidate all memory if there is
- a BLKmode or nonscalar memory reference or a reference to a
- variable address. */
- && (MEM_IN_STRUCT_P (dest) || GET_MODE (dest) == BLKmode
- || cse_rtx_varies_p (XEXP (dest, 0))))
- {
- invalidate_memory ();
- return;
- }
-
if (GET_CODE (set) == CLOBBER
#ifdef HAVE_cc0
|| dest == cc0_rtx
@@ -7678,10 +7818,21 @@ invalidate_skipped_set (dest, set)
|| dest == pc_rtx)
return;
- if (code == STRICT_LOW_PART || code == ZERO_EXTRACT)
- invalidate (XEXP (dest, 0), GET_MODE (dest));
- else if (code == REG || code == SUBREG || code == MEM)
+ if (GET_CODE (dest) == MEM)
+ note_mem_written (dest, &skipped_writes_memory);
+
+ /* There are times when an address can appear varying and be a PLUS
+ during this scan when it would be a fixed address were we to know
+ the proper equivalences. So promote "nonscalar" to be "all". */
+ if (skipped_writes_memory.nonscalar)
+ skipped_writes_memory.all = 1;
+
+ if (GET_CODE (dest) == REG || GET_CODE (dest) == SUBREG
+ || (! skipped_writes_memory.all && ! cse_rtx_addr_varies_p (dest)))
invalidate (dest, VOIDmode);
+ else if (GET_CODE (dest) == STRICT_LOW_PART
+ || GET_CODE (dest) == ZERO_EXTRACT)
+ invalidate (XEXP (dest, 0), GET_MODE (dest));
}
/* Invalidate all insns from START up to the end of the function or the
@@ -7693,6 +7844,8 @@ invalidate_skipped_block (start)
rtx start;
{
rtx insn;
+ static struct write_data init = {0, 0, 0, 0};
+ static struct write_data everything = {0, 1, 1, 1};
for (insn = start; insn && GET_CODE (insn) != CODE_LABEL;
insn = NEXT_INSN (insn))
@@ -7700,14 +7853,16 @@ invalidate_skipped_block (start)
if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
continue;
+ skipped_writes_memory = init;
+
if (GET_CODE (insn) == CALL_INSN)
{
- if (! CONST_CALL_P (insn))
- invalidate_memory ();
invalidate_for_call ();
+ skipped_writes_memory = everything;
}
note_stores (PATTERN (insn), invalidate_skipped_set);
+ invalidate_from_clobbers (&skipped_writes_memory, PATTERN (insn));
}
}
@@ -7757,6 +7912,10 @@ cse_set_around_loop (x, insn, loop_start)
rtx loop_start;
{
struct table_elt *src_elt;
+ static struct write_data init = {0, 0, 0, 0};
+ struct write_data writes_memory;
+
+ writes_memory = init;
/* If this is a SET, see if we can replace SET_SRC, but ignore SETs that
are setting PC or CC0 or whose SET_SRC is already a register. */
@@ -7816,14 +7975,18 @@ cse_set_around_loop (x, insn, loop_start)
}
/* Now invalidate anything modified by X. */
- note_mem_written (SET_DEST (x));
-
- /* See comment on similar code in cse_insn for explanation of these tests. */
- if (GET_CODE (SET_DEST (x)) == REG || GET_CODE (SET_DEST (x)) == SUBREG
- || GET_CODE (SET_DEST (x)) == MEM)
- invalidate (SET_DEST (x), VOIDmode);
- else if (GET_CODE (SET_DEST (x)) == STRICT_LOW_PART
- || GET_CODE (SET_DEST (x)) == ZERO_EXTRACT)
+ note_mem_written (SET_DEST (x), &writes_memory);
+
+ if (writes_memory.var)
+ invalidate_memory (&writes_memory);
+
+ /* See comment on similar code in cse_insn for explanation of these tests. */
+ if (GET_CODE (SET_DEST (x)) == REG || GET_CODE (SET_DEST (x)) == SUBREG
+ || (GET_CODE (SET_DEST (x)) == MEM && ! writes_memory.all
+ && ! cse_rtx_addr_varies_p (SET_DEST (x))))
+ invalidate (SET_DEST (x), VOIDmode);
+ else if (GET_CODE (SET_DEST (x)) == STRICT_LOW_PART
+ || GET_CODE (SET_DEST (x)) == ZERO_EXTRACT)
invalidate (XEXP (SET_DEST (x), 0), GET_MODE (SET_DEST (x)));
}
@@ -8070,7 +8233,6 @@ cse_main (f, nregs, after_loop, file)
val.path_size = 0;
init_recog ();
- init_alias_analysis ();
max_reg = nregs;