summaryrefslogtreecommitdiff
path: root/gcc/reload1.c
diff options
context:
space:
mode:
authorcrux <crux@138bc75d-0d04-0410-961f-82ee72b054a4>2000-03-14 18:36:18 +0000
committercrux <crux@138bc75d-0d04-0410-961f-82ee72b054a4>2000-03-14 18:36:18 +0000
commit1617c2760b30669bfd9368d928b5a082a99fb649 (patch)
tree096b43f896f53dc9a7da616fc0b4de3800ddcee1 /gcc/reload1.c
parent166163adcbf7469c56e662765fd24054e4ab1511 (diff)
downloadgcc-1617c2760b30669bfd9368d928b5a082a99fb649.tar.gz
Add cselib; use it in loop and reload_cse_regs
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@32538 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/reload1.c')
-rw-r--r--gcc/reload1.c884
1 files changed, 146 insertions, 738 deletions
diff --git a/gcc/reload1.c b/gcc/reload1.c
index a716b132d72..37670e8cc8a 100644
--- a/gcc/reload1.c
+++ b/gcc/reload1.c
@@ -39,6 +39,7 @@ Boston, MA 02111-1307, USA. */
#include "reload.h"
#include "recog.h"
#include "output.h"
+#include "cselib.h"
#include "real.h"
#include "toplev.h"
@@ -430,16 +431,9 @@ static void delete_address_reloads_1 PARAMS ((rtx, rtx, rtx));
static rtx inc_for_reload PARAMS ((rtx, rtx, rtx, int));
static int constraint_accepts_reg_p PARAMS ((const char *, rtx));
static void reload_cse_regs_1 PARAMS ((rtx));
-static void reload_cse_invalidate_regno PARAMS ((int, enum machine_mode, int));
-static int reload_cse_mem_conflict_p PARAMS ((rtx, rtx));
-static void reload_cse_invalidate_mem PARAMS ((rtx));
-static void reload_cse_invalidate_rtx PARAMS ((rtx, rtx, void *));
-static int reload_cse_regno_equal_p PARAMS ((int, rtx, enum machine_mode));
-static int reload_cse_noop_set_p PARAMS ((rtx, rtx));
+static int reload_cse_noop_set_p PARAMS ((rtx));
static int reload_cse_simplify_set PARAMS ((rtx, rtx));
static int reload_cse_simplify_operands PARAMS ((rtx));
-static void reload_cse_check_clobber PARAMS ((rtx, rtx, void *));
-static void reload_cse_record_set PARAMS ((rtx, rtx));
static void reload_combine PARAMS ((void));
static void reload_combine_note_use PARAMS ((rtx *, rtx));
static void reload_combine_note_store PARAMS ((rtx, rtx, void *));
@@ -7842,229 +7836,110 @@ count_occurrences (x, find)
return count;
}
-/* This array holds values which are equivalent to a hard register
- during reload_cse_regs. Each array element is an EXPR_LIST of
- values. Each time a hard register is set, we set the corresponding
- array element to the value. Each time a hard register is copied
- into memory, we add the memory location to the corresponding array
- element. We don't store values or memory addresses with side
- effects in this array.
-
- If the value is a CONST_INT, then the mode of the containing
- EXPR_LIST is the mode in which that CONST_INT was referenced.
-
- We sometimes clobber a specific entry in a list. In that case, we
- just set XEXP (list-entry, 0) to 0. */
-
-static rtx *reg_values;
-
-/* This is a preallocated REG rtx which we use as a temporary in
- reload_cse_invalidate_regno, so that we don't need to allocate a
- new one each time through a loop in that function. */
-
-static rtx invalidate_regno_rtx;
-
-/* Invalidate any entries in reg_values which depend on REGNO,
- including those for REGNO itself. This is called if REGNO is
- changing. If CLOBBER is true, then always forget anything we
- currently know about REGNO. MODE is the mode of the assignment to
- REGNO, which is used to determine how many hard registers are being
- changed. If MODE is VOIDmode, then only REGNO is being changed;
- this is used when invalidating call clobbered registers across a
- call. */
-
+/* INSN is a no-op; delete it.
+ If this sets the return value of the function, we must keep a USE around,
+ in case this is in a different basic block than the final USE. Otherwise,
+ we could loose important register lifeness information on
+ SMALL_REGISTER_CLASSES machines, where return registers might be used as
+ spills: subsequent passes assume that spill registers are dead at the end
+ of a basic block.
+ VALUE must be the return value in such a case, NULL otherwise. */
static void
-reload_cse_invalidate_regno (regno, mode, clobber)
- int regno;
- enum machine_mode mode;
- int clobber;
+reload_cse_delete_noop_set (insn, value)
+ rtx insn, value;
{
- int endregno;
- register int i;
-
- /* Our callers don't always go through true_regnum; we may see a
- pseudo-register here from a CLOBBER or the like. We probably
- won't ever see a pseudo-register that has a real register number,
- for we check anyhow for safety. */
- if (regno >= FIRST_PSEUDO_REGISTER)
- regno = reg_renumber[regno];
- if (regno < 0)
- return;
-
- if (mode == VOIDmode)
- endregno = regno + 1;
- else
- endregno = regno + HARD_REGNO_NREGS (regno, mode);
-
- if (clobber)
- for (i = regno; i < endregno; i++)
- reg_values[i] = 0;
-
- for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ if (value)
{
- rtx x;
-
- for (x = reg_values[i]; x; x = XEXP (x, 1))
- {
- if (XEXP (x, 0) != 0
- && refers_to_regno_p (regno, endregno, XEXP (x, 0), NULL_PTR))
- {
- /* If this is the only entry on the list, clear
- reg_values[i]. Otherwise, just clear this entry on
- the list. */
- if (XEXP (x, 1) == 0 && x == reg_values[i])
- {
- reg_values[i] = 0;
- break;
- }
- XEXP (x, 0) = 0;
- }
- }
+ PATTERN (insn) = gen_rtx_USE (VOIDmode, value);
+ INSN_CODE (insn) = -1;
+ REG_NOTES (insn) = NULL_RTX;
}
-
- /* We must look at earlier registers, in case REGNO is part of a
- multi word value but is not the first register. If an earlier
- register has a value in a mode which overlaps REGNO, then we must
- invalidate that earlier register. Note that we do not need to
- check REGNO or later registers (we must not check REGNO itself,
- because we would incorrectly conclude that there was a conflict). */
-
- for (i = 0; i < regno; i++)
+ else
{
- rtx x;
-
- for (x = reg_values[i]; x; x = XEXP (x, 1))
- {
- if (XEXP (x, 0) != 0)
- {
- PUT_MODE (invalidate_regno_rtx, GET_MODE (x));
- REGNO (invalidate_regno_rtx) = i;
- if (refers_to_regno_p (regno, endregno, invalidate_regno_rtx,
- NULL_PTR))
- {
- reload_cse_invalidate_regno (i, VOIDmode, 1);
- break;
- }
- }
- }
+ PUT_CODE (insn, NOTE);
+ NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
+ NOTE_SOURCE_FILE (insn) = 0;
}
}
-/* The memory at address MEM_BASE is being changed.
- Return whether this change will invalidate VAL. */
-
+/* See whether a single set SET is a noop. */
static int
-reload_cse_mem_conflict_p (mem_base, val)
- rtx mem_base;
- rtx val;
+reload_cse_noop_set_p (set)
+ rtx set;
{
- enum rtx_code code;
- const char *fmt;
- int i;
-
- code = GET_CODE (val);
- switch (code)
- {
- /* Get rid of a few simple cases quickly. */
- case REG:
- case PC:
- case CC0:
- case SCRATCH:
- case CONST:
- case CONST_INT:
- case CONST_DOUBLE:
- case SYMBOL_REF:
- case LABEL_REF:
- return 0;
-
- case MEM:
- if (GET_MODE (mem_base) == BLKmode
- || GET_MODE (val) == BLKmode)
- return 1;
- if (anti_dependence (val, mem_base))
- return 1;
- /* The address may contain nested MEMs. */
- break;
-
- default:
- break;
- }
+ return rtx_equal_for_cselib_p (SET_DEST (set), SET_SRC (set));
+}
- fmt = GET_RTX_FORMAT (code);
+/* Try to simplify INSN. */
+static void
+reload_cse_simplify (insn)
+ rtx insn;
+{
+ rtx body = PATTERN (insn);
- for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+ if (GET_CODE (body) == SET)
{
- if (fmt[i] == 'e')
+ int count = 0;
+ if (reload_cse_noop_set_p (body))
{
- if (reload_cse_mem_conflict_p (mem_base, XEXP (val, i)))
- return 1;
- }
- else if (fmt[i] == 'E')
- {
- int j;
-
- for (j = 0; j < XVECLEN (val, i); j++)
- if (reload_cse_mem_conflict_p (mem_base, XVECEXP (val, i, j)))
- return 1;
+ rtx value = SET_DEST (body);
+ if (! REG_FUNCTION_VALUE_P (SET_DEST (body)))
+ value = 0;
+ reload_cse_delete_noop_set (insn, value);
+ return;
}
- }
-
- return 0;
-}
-
-/* Invalidate any entries in reg_values which are changed because of a
- store to MEM_RTX. If this is called because of a non-const call
- instruction, MEM_RTX is (mem:BLK const0_rtx). */
-static void
-reload_cse_invalidate_mem (mem_rtx)
- rtx mem_rtx;
-{
- register int i;
+ /* It's not a no-op, but we can try to simplify it. */
+ count += reload_cse_simplify_set (body, insn);
- for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ if (count > 0)
+ apply_change_group ();
+ else
+ reload_cse_simplify_operands (insn);
+ }
+ else if (GET_CODE (body) == PARALLEL)
{
- rtx x;
+ int i;
+ int count = 0;
+ rtx value = NULL_RTX;
- for (x = reg_values[i]; x; x = XEXP (x, 1))
+ /* If every action in a PARALLEL is a noop, we can delete
+ the entire PARALLEL. */
+ for (i = XVECLEN (body, 0) - 1; i >= 0; --i)
{
- if (XEXP (x, 0) != 0
- && reload_cse_mem_conflict_p (mem_rtx, XEXP (x, 0)))
+ rtx part = XVECEXP (body, 0, i);
+ if (GET_CODE (part) == SET)
{
- /* If this is the only entry on the list, clear
- reg_values[i]. Otherwise, just clear this entry on
- the list. */
- if (XEXP (x, 1) == 0 && x == reg_values[i])
+ if (! reload_cse_noop_set_p (part))
+ break;
+ if (REG_FUNCTION_VALUE_P (SET_DEST (part)))
{
- reg_values[i] = 0;
- break;
+ if (value)
+ break;
+ value = SET_DEST (part);
}
- XEXP (x, 0) = 0;
}
+ else if (GET_CODE (part) != CLOBBER)
+ break;
}
- }
-}
-/* Invalidate DEST, which is being assigned to or clobbered. The
- second parameter exists so that this function can be passed to
- note_stores; it is ignored. */
+ if (i < 0)
+ {
+ reload_cse_delete_noop_set (insn, value);
+ /* We're done with this insn. */
+ return;
+ }
-static void
-reload_cse_invalidate_rtx (dest, ignore, data)
- rtx dest;
- rtx ignore ATTRIBUTE_UNUSED;
- void *data ATTRIBUTE_UNUSED;
-{
- while (GET_CODE (dest) == STRICT_LOW_PART
- || GET_CODE (dest) == SIGN_EXTRACT
- || GET_CODE (dest) == ZERO_EXTRACT
- || GET_CODE (dest) == SUBREG)
- dest = XEXP (dest, 0);
-
- if (GET_CODE (dest) == REG)
- reload_cse_invalidate_regno (REGNO (dest), GET_MODE (dest), 1);
- else if (GET_CODE (dest) == MEM)
- reload_cse_invalidate_mem (dest);
+ /* It's not a no-op, but we can try to simplify it. */
+ for (i = XVECLEN (body, 0) - 1; i >= 0; --i)
+ if (GET_CODE (XVECEXP (body, 0, i)) == SET)
+ count += reload_cse_simplify_set (XVECEXP (body, 0, i), insn);
+
+ if (count > 0)
+ apply_change_group ();
+ else
+ reload_cse_simplify_operands (insn);
+ }
}
/* Do a very simple CSE pass over the hard registers.
@@ -8088,223 +7963,22 @@ static void
reload_cse_regs_1 (first)
rtx first;
{
- char *firstobj;
- rtx callmem;
- register int i;
rtx insn;
+ cselib_init ();
init_alias_analysis ();
- reg_values = (rtx *) alloca (FIRST_PSEUDO_REGISTER * sizeof (rtx));
- bzero ((char *)reg_values, FIRST_PSEUDO_REGISTER * sizeof (rtx));
-
- /* Create our EXPR_LIST structures on reload_obstack, so that we can
- free them when we are done. */
- push_obstacks (&reload_obstack, &reload_obstack);
- firstobj = (char *) obstack_alloc (&reload_obstack, 0);
-
- /* We pass this to reload_cse_invalidate_mem to invalidate all of
- memory for a non-const call instruction. */
- callmem = gen_rtx_MEM (BLKmode, const0_rtx);
-
- /* This is used in reload_cse_invalidate_regno to avoid consing a
- new REG in a loop in that function. */
- invalidate_regno_rtx = gen_rtx_REG (VOIDmode, 0);
-
for (insn = first; insn; insn = NEXT_INSN (insn))
{
- rtx body;
-
- if (GET_CODE (insn) == CODE_LABEL)
- {
- /* Forget all the register values at a code label. We don't
- try to do anything clever around jumps. */
- for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- reg_values[i] = 0;
-
- continue;
- }
-
-#ifdef NON_SAVING_SETJMP
- if (NON_SAVING_SETJMP && GET_CODE (insn) == NOTE
- && NOTE_LINE_NUMBER (insn) == NOTE_INSN_SETJMP)
- {
- for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- reg_values[i] = 0;
-
- continue;
- }
-#endif
-
- if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
- continue;
-
- /* If this is a call instruction, forget anything stored in a
- call clobbered register, or, if this is not a const call, in
- memory. */
- if (GET_CODE (insn) == CALL_INSN)
- {
- for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- if (call_used_regs[i])
- reload_cse_invalidate_regno (i, VOIDmode, 1);
-
- if (! CONST_CALL_P (insn))
- reload_cse_invalidate_mem (callmem);
- }
-
-
- /* Forget all the register values at a volatile asm. */
- if (GET_CODE (insn) == INSN
- && GET_CODE (PATTERN (insn)) == ASM_OPERANDS
- && MEM_VOLATILE_P (PATTERN (insn)))
- for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- reg_values[i] = 0;
-
- body = PATTERN (insn);
- if (GET_CODE (body) == SET)
- {
- int count = 0;
- if (reload_cse_noop_set_p (body, insn))
- {
- /* If this sets the return value of the function, we must keep
- a USE around, in case this is in a different basic block
- than the final USE. Otherwise, we could loose important
- register lifeness information on SMALL_REGISTER_CLASSES
- machines, where return registers might be used as spills:
- subsequent passes assume that spill registers are dead at
- the end of a basic block. */
- if (REG_FUNCTION_VALUE_P (SET_DEST (body)))
- {
- pop_obstacks ();
- PATTERN (insn) = gen_rtx_USE (VOIDmode, SET_DEST (body));
- INSN_CODE (insn) = -1;
- REG_NOTES (insn) = NULL_RTX;
- push_obstacks (&reload_obstack, &reload_obstack);
- }
- else
- {
- PUT_CODE (insn, NOTE);
- NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
- NOTE_SOURCE_FILE (insn) = 0;
- }
-
- /* We're done with this insn. */
- continue;
- }
-
- /* It's not a no-op, but we can try to simplify it. */
- count += reload_cse_simplify_set (body, insn);
-
- if (count > 0)
- apply_change_group ();
- else
- reload_cse_simplify_operands (insn);
-
- reload_cse_record_set (body, body);
- }
- else if (GET_CODE (body) == PARALLEL)
- {
- int count = 0;
- rtx value = NULL_RTX;
-
- /* If every action in a PARALLEL is a noop, we can delete
- the entire PARALLEL. */
- for (i = XVECLEN (body, 0) - 1; i >= 0; --i)
- {
- rtx part = XVECEXP (body, 0, i);
- if (GET_CODE (part) == SET)
- {
- if (! reload_cse_noop_set_p (part, insn))
- break;
- if (REG_FUNCTION_VALUE_P (SET_DEST (part)))
- {
- if (value)
- break;
- value = SET_DEST (part);
- }
- }
- else if (GET_CODE (part) != CLOBBER)
- break;
- }
- if (i < 0)
- {
- if (value)
- {
- pop_obstacks ();
- PATTERN (insn) = gen_rtx_USE (VOIDmode, value);
- INSN_CODE (insn) = -1;
- REG_NOTES (insn) = NULL_RTX;
- push_obstacks (&reload_obstack, &reload_obstack);
- }
- else
- {
- PUT_CODE (insn, NOTE);
- NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
- NOTE_SOURCE_FILE (insn) = 0;
- }
-
- /* We're done with this insn. */
- continue;
- }
-
- /* It's not a no-op, but we can try to simplify it. */
- for (i = XVECLEN (body, 0) - 1; i >= 0; --i)
- if (GET_CODE (XVECEXP (body, 0, i)) == SET)
- count += reload_cse_simplify_set (XVECEXP (body, 0, i), insn);
-
- if (count > 0)
- apply_change_group ();
- else
- reload_cse_simplify_operands (insn);
-
- /* Look through the PARALLEL and record the values being
- set, if possible. Also handle any CLOBBERs. */
- for (i = XVECLEN (body, 0) - 1; i >= 0; --i)
- {
- rtx x = XVECEXP (body, 0, i);
-
- if (GET_CODE (x) == SET)
- reload_cse_record_set (x, body);
- else
- note_stores (x, reload_cse_invalidate_rtx, NULL);
- }
- }
- else
- note_stores (body, reload_cse_invalidate_rtx, NULL);
-
-#ifdef AUTO_INC_DEC
- /* Clobber any registers which appear in REG_INC notes. We
- could keep track of the changes to their values, but it is
- unlikely to help. */
- {
- rtx x;
-
- for (x = REG_NOTES (insn); x; x = XEXP (x, 1))
- if (REG_NOTE_KIND (x) == REG_INC)
- reload_cse_invalidate_rtx (XEXP (x, 0), NULL_RTX, NULL);
- }
-#endif
-
- /* Look for any CLOBBERs in CALL_INSN_FUNCTION_USAGE, but only
- after we have processed the insn. */
- if (GET_CODE (insn) == CALL_INSN)
- {
- rtx x;
+ if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
+ reload_cse_simplify (insn);
- for (x = CALL_INSN_FUNCTION_USAGE (insn); x; x = XEXP (x, 1))
- if (GET_CODE (XEXP (x, 0)) == CLOBBER)
- reload_cse_invalidate_rtx (XEXP (XEXP (x, 0), 0), NULL_RTX,
- NULL);
- }
+ cselib_process_insn (insn);
}
/* Clean up. */
end_alias_analysis ();
-
- /* Free all the temporary structures we created, and go back to the
- regular obstacks. */
- obstack_free (&reload_obstack, firstobj);
- pop_obstacks ();
+ cselib_finish ();
}
/* Call cse / combine like post-reload optimization phases.
@@ -8320,127 +7994,6 @@ reload_cse_regs (first)
reload_cse_regs_1 (first);
}
-/* Return whether the values known for REGNO are equal to VAL. MODE
- is the mode of the object that VAL is being copied to; this matters
- if VAL is a CONST_INT. */
-
-static int
-reload_cse_regno_equal_p (regno, val, mode)
- int regno;
- rtx val;
- enum machine_mode mode;
-{
- rtx x;
-
- if (val == 0)
- return 0;
-
- for (x = reg_values[regno]; x; x = XEXP (x, 1))
- if (XEXP (x, 0) != 0
- && rtx_equal_p (XEXP (x, 0), val)
- && (! flag_float_store || GET_CODE (XEXP (x, 0)) != MEM
- || GET_MODE_CLASS (GET_MODE (x)) != MODE_FLOAT)
- && (GET_CODE (val) != CONST_INT
- || mode == GET_MODE (x)
- || (GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (x))
- /* On a big endian machine if the value spans more than
- one register then this register holds the high part of
- it and we can't use it.
-
- ??? We should also compare with the high part of the
- value. */
- && !(WORDS_BIG_ENDIAN
- && HARD_REGNO_NREGS (regno, GET_MODE (x)) > 1)
- && TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode),
- GET_MODE_BITSIZE (GET_MODE (x))))))
- return 1;
-
- return 0;
-}
-
-/* See whether a single set is a noop. SET is the set instruction we
- are should check, and INSN is the instruction from which it came. */
-
-static int
-reload_cse_noop_set_p (set, insn)
- rtx set;
- rtx insn ATTRIBUTE_UNUSED;
-{
- rtx src, dest;
- enum machine_mode dest_mode;
- int dreg, sreg;
- int ret;
-
- src = SET_SRC (set);
- dest = SET_DEST (set);
- dest_mode = GET_MODE (dest);
-
- if (side_effects_p (src))
- return 0;
-
- dreg = true_regnum (dest);
- sreg = true_regnum (src);
-
- /* Check for setting a register to itself. In this case, we don't
- have to worry about REG_DEAD notes. */
- if (dreg >= 0 && dreg == sreg)
- return 1;
-
- ret = 0;
- if (dreg >= 0)
- {
- /* Check for setting a register to itself. */
- if (dreg == sreg)
- ret = 1;
-
- /* Check for setting a register to a value which we already know
- is in the register. */
- else if (reload_cse_regno_equal_p (dreg, src, dest_mode))
- ret = 1;
-
- /* Check for setting a register DREG to another register SREG
- where SREG is equal to a value which is already in DREG. */
- else if (sreg >= 0)
- {
- rtx x;
-
- for (x = reg_values[sreg]; x; x = XEXP (x, 1))
- {
- rtx tmp;
-
- if (XEXP (x, 0) == 0)
- continue;
-
- if (dest_mode == GET_MODE (x))
- tmp = XEXP (x, 0);
- else if (GET_MODE_BITSIZE (dest_mode)
- < GET_MODE_BITSIZE (GET_MODE (x)))
- tmp = gen_lowpart_common (dest_mode, XEXP (x, 0));
- else
- continue;
-
- if (tmp
- && reload_cse_regno_equal_p (dreg, tmp, dest_mode))
- {
- ret = 1;
- break;
- }
- }
- }
- }
- else if (GET_CODE (dest) == MEM)
- {
- /* Check for storing a register to memory when we know that the
- register is equivalent to the memory location. */
- if (sreg >= 0
- && reload_cse_regno_equal_p (sreg, dest, dest_mode)
- && ! side_effects_p (dest))
- ret = 1;
- }
-
- return ret;
-}
-
/* Try to simplify a single SET instruction. SET is the set pattern.
INSN is the instruction it came from.
This function only handles one case: if we set a register to a value
@@ -8452,11 +8005,13 @@ reload_cse_simplify_set (set, insn)
rtx set;
rtx insn;
{
+ int did_change = 0;
int dreg;
rtx src;
- enum machine_mode dest_mode;
enum reg_class dclass;
- register int i;
+ int old_cost;
+ cselib_val *val;
+ struct elt_loc_list *l;
dreg = true_regnum (SET_DEST (set));
if (dreg < 0)
@@ -8469,39 +8024,40 @@ reload_cse_simplify_set (set, insn)
dclass = REGNO_REG_CLASS (dreg);
/* If memory loads are cheaper than register copies, don't change them. */
- if (GET_CODE (src) == MEM
- && MEMORY_MOVE_COST (GET_MODE (src), dclass, 1) < 2)
- return 0;
+ if (GET_CODE (src) == MEM)
+ old_cost = MEMORY_MOVE_COST (GET_MODE (src), dclass, 1);
+ else if (CONSTANT_P (src))
+ old_cost = rtx_cost (src, SET);
+ else if (GET_CODE (src) == REG)
+ old_cost = REGISTER_MOVE_COST (REGNO_REG_CLASS (REGNO (src)), dclass);
+ else
+ /* ??? */
+ old_cost = rtx_cost (src, SET);
- /* If the constant is cheaper than a register, don't change it. */
- if (CONSTANT_P (src)
- && rtx_cost (src, SET) < 2)
+ val = cselib_lookup (src, VOIDmode, 0);
+ if (! val)
return 0;
-
- dest_mode = GET_MODE (SET_DEST (set));
- for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- {
- if (i != dreg
- && REGISTER_MOVE_COST (REGNO_REG_CLASS (i), dclass) == 2
- && reload_cse_regno_equal_p (i, src, dest_mode))
- {
- int validated;
-
- /* Pop back to the real obstacks while changing the insn. */
- pop_obstacks ();
-
- validated = validate_change (insn, &SET_SRC (set),
- gen_rtx_REG (dest_mode, i), 1);
-
- /* Go back to the obstack we are using for temporary
- storage. */
- push_obstacks (&reload_obstack, &reload_obstack);
-
- if (validated)
- return 1;
- }
+ for (l = val->locs; l; l = l->next)
+ {
+ int this_cost;
+ if (CONSTANT_P (l->loc) && ! references_value_p (l->loc, 0))
+ this_cost = rtx_cost (l->loc, SET);
+ else if (GET_CODE (l->loc) == REG)
+ this_cost = REGISTER_MOVE_COST (REGNO_REG_CLASS (REGNO (l->loc)),
+ dclass);
+ else
+ continue;
+ /* If equal costs, prefer registers over anything else. That tends to
+ lead to smaller instructions on some machines. */
+ if ((this_cost < old_cost
+ || (this_cost == old_cost
+ && GET_CODE (l->loc) == REG
+ && GET_CODE (SET_SRC (set)) != REG))
+ && validate_change (insn, &SET_SRC (set), copy_rtx (l->loc), 1))
+ old_cost = this_cost, did_change = 1;
}
- return 0;
+
+ return did_change;
}
/* Try to replace operands in INSN with equivalent values that are already
@@ -8521,6 +8077,9 @@ reload_cse_simplify_operands (insn)
{
int i,j;
+ /* For each operand, all registers that are equivalent to it. */
+ HARD_REG_SET equiv_regs[MAX_RECOG_OPERANDS];
+
const char *constraints[MAX_RECOG_OPERANDS];
/* Vector recording how bad an alternative is. */
@@ -8544,13 +8103,35 @@ reload_cse_simplify_operands (insn)
/* Figure out which alternative currently matches. */
if (! constrain_operands (1))
fatal_insn_not_found (insn);
-
+
alternative_reject = (int *) alloca (recog_data.n_alternatives * sizeof (int));
alternative_nregs = (int *) alloca (recog_data.n_alternatives * sizeof (int));
alternative_order = (int *) alloca (recog_data.n_alternatives * sizeof (int));
bzero ((char *)alternative_reject, recog_data.n_alternatives * sizeof (int));
bzero ((char *)alternative_nregs, recog_data.n_alternatives * sizeof (int));
+ /* For each operand, find out which regs are equivalent. */
+ for (i = 0; i < recog_data.n_operands; i++)
+ {
+ cselib_val *v;
+ struct elt_loc_list *l;
+
+ CLEAR_HARD_REG_SET (equiv_regs[i]);
+
+ /* cselib blows up on CODE_LABELs. Trying to fix that doesn't seem
+ right, so avoid the problem here. */
+ if (GET_CODE (recog_data.operand[i]) == CODE_LABEL)
+ continue;
+
+ v = cselib_lookup (recog_data.operand[i], recog_data.operand_mode[i], 0);
+ if (! v)
+ continue;
+
+ for (l = v->locs; l; l = l->next)
+ if (GET_CODE (l->loc) == REG)
+ SET_HARD_REG_BIT (equiv_regs[i], REGNO (l->loc));
+ }
+
for (i = 0; i < recog_data.n_operands; i++)
{
enum machine_mode mode;
@@ -8590,7 +8171,7 @@ reload_cse_simplify_operands (insn)
{
int class = (int) NO_REGS;
- if (! reload_cse_regno_equal_p (regno, recog_data.operand[i], mode))
+ if (! TEST_HARD_REG_BIT (equiv_regs[i], regno))
continue;
REGNO (reg) = regno;
@@ -8696,9 +8277,6 @@ reload_cse_simplify_operands (insn)
alternative. */
j = alternative_order[0];
- /* Pop back to the real obstacks while changing the insn. */
- pop_obstacks ();
-
for (i = 0; i < recog_data.n_operands; i++)
{
enum machine_mode mode = recog_data.operand_mode[i];
@@ -8721,178 +8299,8 @@ reload_cse_simplify_operands (insn)
gen_rtx_REG (mode, op_alt_regno[op][j]), 1);
}
- /* Go back to the obstack we are using for temporary
- storage. */
- push_obstacks (&reload_obstack, &reload_obstack);
-
return apply_change_group ();
}
-
-/* These two variables are used to pass information from
- reload_cse_record_set to reload_cse_check_clobber. */
-
-static int reload_cse_check_clobbered;
-static rtx reload_cse_check_src;
-
-/* See if DEST overlaps with RELOAD_CSE_CHECK_SRC. If it does, set
- RELOAD_CSE_CHECK_CLOBBERED. This is called via note_stores. The
- second argument, which is passed by note_stores, is ignored. */
-
-static void
-reload_cse_check_clobber (dest, ignore, data)
- rtx dest;
- rtx ignore ATTRIBUTE_UNUSED;
- void *data ATTRIBUTE_UNUSED;
-{
- if (reg_overlap_mentioned_p (dest, reload_cse_check_src))
- reload_cse_check_clobbered = 1;
-}
-
-/* Record the result of a SET instruction. SET is the set pattern.
- BODY is the pattern of the insn that it came from. */
-
-static void
-reload_cse_record_set (set, body)
- rtx set;
- rtx body;
-{
- rtx dest, src, x;
- int dreg, sreg;
- enum machine_mode dest_mode;
-
- dest = SET_DEST (set);
- src = SET_SRC (set);
- dreg = true_regnum (dest);
- sreg = true_regnum (src);
- dest_mode = GET_MODE (dest);
-
- /* Some machines don't define AUTO_INC_DEC, but they still use push
- instructions. We need to catch that case here in order to
- invalidate the stack pointer correctly. Note that invalidating
- the stack pointer is different from invalidating DEST. */
- x = dest;
- while (GET_CODE (x) == SUBREG
- || GET_CODE (x) == ZERO_EXTRACT
- || GET_CODE (x) == SIGN_EXTRACT
- || GET_CODE (x) == STRICT_LOW_PART)
- x = XEXP (x, 0);
- if (push_operand (x, GET_MODE (x)))
- {
- reload_cse_invalidate_rtx (stack_pointer_rtx, NULL_RTX, NULL);
- reload_cse_invalidate_rtx (dest, NULL_RTX, NULL);
- return;
- }
-
- /* We can only handle an assignment to a register, or a store of a
- register to a memory location. For other cases, we just clobber
- the destination. We also have to just clobber if there are side
- effects in SRC or DEST. */
- if ((dreg < 0 && GET_CODE (dest) != MEM)
- || side_effects_p (src)
- || side_effects_p (dest))
- {
- reload_cse_invalidate_rtx (dest, NULL_RTX, NULL);
- return;
- }
-
-#ifdef HAVE_cc0
- /* We don't try to handle values involving CC, because it's a pain
- to keep track of when they have to be invalidated. */
- if (reg_mentioned_p (cc0_rtx, src)
- || reg_mentioned_p (cc0_rtx, dest))
- {
- reload_cse_invalidate_rtx (dest, NULL_RTX, NULL);
- return;
- }
-#endif
-
- /* If BODY is a PARALLEL, then we need to see whether the source of
- SET is clobbered by some other instruction in the PARALLEL. */
- if (GET_CODE (body) == PARALLEL)
- {
- int i;
-
- for (i = XVECLEN (body, 0) - 1; i >= 0; --i)
- {
- rtx x;
-
- x = XVECEXP (body, 0, i);
- if (x == set)
- continue;
-
- reload_cse_check_clobbered = 0;
- reload_cse_check_src = src;
- note_stores (x, reload_cse_check_clobber, NULL);
- if (reload_cse_check_clobbered)
- {
- reload_cse_invalidate_rtx (dest, NULL_RTX, NULL);
- return;
- }
- }
- }
-
- if (dreg >= 0)
- {
- int i;
-
- /* This is an assignment to a register. Update the value we
- have stored for the register. */
- if (sreg >= 0)
- {
- rtx x;
-
- /* This is a copy from one register to another. Any values
- which were valid for SREG are now valid for DREG. If the
- mode changes, we use gen_lowpart_common to extract only
- the part of the value that is copied. */
- reg_values[dreg] = 0;
- for (x = reg_values[sreg]; x; x = XEXP (x, 1))
- {
- rtx tmp;
-
- if (XEXP (x, 0) == 0)
- continue;
- if (dest_mode == GET_MODE (XEXP (x, 0)))
- tmp = XEXP (x, 0);
- else if (GET_MODE_BITSIZE (dest_mode)
- > GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0))))
- continue;
- else
- tmp = gen_lowpart_common (dest_mode, XEXP (x, 0));
- if (tmp)
- reg_values[dreg] = gen_rtx_EXPR_LIST (dest_mode, tmp,
- reg_values[dreg]);
- }
- }
- else
- reg_values[dreg] = gen_rtx_EXPR_LIST (dest_mode, src, NULL_RTX);
-
- /* We've changed DREG, so invalidate any values held by other
- registers that depend upon it. */
- reload_cse_invalidate_regno (dreg, dest_mode, 0);
-
- /* If this assignment changes more than one hard register,
- forget anything we know about the others. */
- for (i = 1; i < HARD_REGNO_NREGS (dreg, dest_mode); i++)
- reg_values[dreg + i] = 0;
- }
- else if (GET_CODE (dest) == MEM)
- {
- /* Invalidate conflicting memory locations. */
- reload_cse_invalidate_mem (dest);
-
- /* If we're storing a register to memory, add DEST to the list
- in REG_VALUES. */
- if (sreg >= 0 && ! side_effects_p (dest))
- reg_values[sreg] = gen_rtx_EXPR_LIST (dest_mode, dest,
- reg_values[sreg]);
- }
- else
- {
- /* We should have bailed out earlier. */
- abort ();
- }
-}
/* If reload couldn't use reg+reg+offset addressing, try to use reg+reg
addressing now.