cse support for clobber_high
gcc/ * cse.c (invalidate_reg): New function extracted from... (invalidate): ...here. (canonicalize_insn): Check for clobber high. (invalidate_from_clobbers): invalidate clobber highs. (invalidate_from_sets_and_clobbers): Likewise. (count_reg_usage): Check for clobber high. (insn_live_p): Likewise. * cselib.c (cselib_expand_value_rtx_1):Likewise. (cselib_invalidate_regno): Check for clobber in setter. (cselib_invalidate_rtx): Pass through setter. (cselib_invalidate_rtx_note_stores): (cselib_process_insn): Check for clobber high. * cselib.h (cselib_invalidate_rtx): Add operand. From-SVN: r263330
This commit is contained in:
parent
30dc1902a7
commit
99788e0630
@ -1,3 +1,19 @@
|
||||
2018-08-06 Alan Hayward <alan.hayward@arm.com>
|
||||
|
||||
* cse.c (invalidate_reg): New function extracted from...
|
||||
(invalidate): ...here.
|
||||
(canonicalize_insn): Check for clobber high.
|
||||
(invalidate_from_clobbers): invalidate clobber highs.
|
||||
(invalidate_from_sets_and_clobbers): Likewise.
|
||||
(count_reg_usage): Check for clobber high.
|
||||
(insn_live_p): Likewise.
|
||||
* cselib.c (cselib_expand_value_rtx_1):Likewise.
|
||||
(cselib_invalidate_regno): Check for clobber in setter.
|
||||
(cselib_invalidate_rtx): Pass through setter.
|
||||
(cselib_invalidate_rtx_note_stores):
|
||||
(cselib_process_insn): Check for clobber high.
|
||||
* cselib.h (cselib_invalidate_rtx): Add operand.
|
||||
|
||||
2018-08-06 Alan Hayward <alan.hayward@arm.com>
|
||||
|
||||
* lra-eliminations.c (lra_eliminate_regs_1): Check for clobber high.
|
||||
|
187
gcc/cse.c
187
gcc/cse.c
@ -559,6 +559,7 @@ static struct table_elt *insert_with_costs (rtx, struct table_elt *, unsigned,
|
||||
static struct table_elt *insert (rtx, struct table_elt *, unsigned,
|
||||
machine_mode);
|
||||
static void merge_equiv_classes (struct table_elt *, struct table_elt *);
|
||||
static void invalidate_reg (rtx, bool);
|
||||
static void invalidate (rtx, machine_mode);
|
||||
static void remove_invalid_refs (unsigned int);
|
||||
static void remove_invalid_subreg_refs (unsigned int, poly_uint64,
|
||||
@ -1818,7 +1819,85 @@ check_dependence (const_rtx x, rtx exp, machine_mode mode, rtx addr)
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/* Remove from the hash table, or mark as invalid, all expressions whose
|
||||
values could be altered by storing in register X.
|
||||
|
||||
CLOBBER_HIGH is set if X was part of a CLOBBER_HIGH expression. */
|
||||
|
||||
static void
|
||||
invalidate_reg (rtx x, bool clobber_high)
|
||||
{
|
||||
gcc_assert (GET_CODE (x) == REG);
|
||||
|
||||
/* If X is a register, dependencies on its contents are recorded
|
||||
through the qty number mechanism. Just change the qty number of
|
||||
the register, mark it as invalid for expressions that refer to it,
|
||||
and remove it itself. */
|
||||
unsigned int regno = REGNO (x);
|
||||
unsigned int hash = HASH (x, GET_MODE (x));
|
||||
|
||||
/* Remove REGNO from any quantity list it might be on and indicate
|
||||
that its value might have changed. If it is a pseudo, remove its
|
||||
entry from the hash table.
|
||||
|
||||
For a hard register, we do the first two actions above for any
|
||||
additional hard registers corresponding to X. Then, if any of these
|
||||
registers are in the table, we must remove any REG entries that
|
||||
overlap these registers. */
|
||||
|
||||
delete_reg_equiv (regno);
|
||||
REG_TICK (regno)++;
|
||||
SUBREG_TICKED (regno) = -1;
|
||||
|
||||
if (regno >= FIRST_PSEUDO_REGISTER)
|
||||
{
|
||||
gcc_assert (!clobber_high);
|
||||
remove_pseudo_from_table (x, hash);
|
||||
}
|
||||
else
|
||||
{
|
||||
HOST_WIDE_INT in_table = TEST_HARD_REG_BIT (hard_regs_in_table, regno);
|
||||
unsigned int endregno = END_REGNO (x);
|
||||
unsigned int rn;
|
||||
struct table_elt *p, *next;
|
||||
|
||||
CLEAR_HARD_REG_BIT (hard_regs_in_table, regno);
|
||||
|
||||
for (rn = regno + 1; rn < endregno; rn++)
|
||||
{
|
||||
in_table |= TEST_HARD_REG_BIT (hard_regs_in_table, rn);
|
||||
CLEAR_HARD_REG_BIT (hard_regs_in_table, rn);
|
||||
delete_reg_equiv (rn);
|
||||
REG_TICK (rn)++;
|
||||
SUBREG_TICKED (rn) = -1;
|
||||
}
|
||||
|
||||
if (in_table)
|
||||
for (hash = 0; hash < HASH_SIZE; hash++)
|
||||
for (p = table[hash]; p; p = next)
|
||||
{
|
||||
next = p->next_same_hash;
|
||||
|
||||
if (!REG_P (p->exp) || REGNO (p->exp) >= FIRST_PSEUDO_REGISTER)
|
||||
continue;
|
||||
|
||||
if (clobber_high)
|
||||
{
|
||||
if (reg_is_clobbered_by_clobber_high (p->exp, x))
|
||||
remove_from_table (p, hash);
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned int tregno = REGNO (p->exp);
|
||||
unsigned int tendregno = END_REGNO (p->exp);
|
||||
if (tendregno > regno && tregno < endregno)
|
||||
remove_from_table (p, hash);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Remove from the hash table, or mark as invalid, all expressions whose
|
||||
values could be altered by storing in X. X is a register, a subreg, or
|
||||
a memory reference with nonvarying address (because, when a memory
|
||||
@ -1841,65 +1920,7 @@ invalidate (rtx x, machine_mode full_mode)
|
||||
switch (GET_CODE (x))
|
||||
{
|
||||
case REG:
|
||||
{
|
||||
/* If X is a register, dependencies on its contents are recorded
|
||||
through the qty number mechanism. Just change the qty number of
|
||||
the register, mark it as invalid for expressions that refer to it,
|
||||
and remove it itself. */
|
||||
unsigned int regno = REGNO (x);
|
||||
unsigned int hash = HASH (x, GET_MODE (x));
|
||||
|
||||
/* Remove REGNO from any quantity list it might be on and indicate
|
||||
that its value might have changed. If it is a pseudo, remove its
|
||||
entry from the hash table.
|
||||
|
||||
For a hard register, we do the first two actions above for any
|
||||
additional hard registers corresponding to X. Then, if any of these
|
||||
registers are in the table, we must remove any REG entries that
|
||||
overlap these registers. */
|
||||
|
||||
delete_reg_equiv (regno);
|
||||
REG_TICK (regno)++;
|
||||
SUBREG_TICKED (regno) = -1;
|
||||
|
||||
if (regno >= FIRST_PSEUDO_REGISTER)
|
||||
remove_pseudo_from_table (x, hash);
|
||||
else
|
||||
{
|
||||
HOST_WIDE_INT in_table
|
||||
= TEST_HARD_REG_BIT (hard_regs_in_table, regno);
|
||||
unsigned int endregno = END_REGNO (x);
|
||||
unsigned int tregno, tendregno, rn;
|
||||
struct table_elt *p, *next;
|
||||
|
||||
CLEAR_HARD_REG_BIT (hard_regs_in_table, regno);
|
||||
|
||||
for (rn = regno + 1; rn < endregno; rn++)
|
||||
{
|
||||
in_table |= TEST_HARD_REG_BIT (hard_regs_in_table, rn);
|
||||
CLEAR_HARD_REG_BIT (hard_regs_in_table, rn);
|
||||
delete_reg_equiv (rn);
|
||||
REG_TICK (rn)++;
|
||||
SUBREG_TICKED (rn) = -1;
|
||||
}
|
||||
|
||||
if (in_table)
|
||||
for (hash = 0; hash < HASH_SIZE; hash++)
|
||||
for (p = table[hash]; p; p = next)
|
||||
{
|
||||
next = p->next_same_hash;
|
||||
|
||||
if (!REG_P (p->exp)
|
||||
|| REGNO (p->exp) >= FIRST_PSEUDO_REGISTER)
|
||||
continue;
|
||||
|
||||
tregno = REGNO (p->exp);
|
||||
tendregno = END_REGNO (p->exp);
|
||||
if (tendregno > regno && tregno < endregno)
|
||||
remove_from_table (p, hash);
|
||||
}
|
||||
}
|
||||
}
|
||||
invalidate_reg (x, false);
|
||||
return;
|
||||
|
||||
case SUBREG:
|
||||
@ -4399,6 +4420,8 @@ canonicalize_insn (rtx_insn *insn, struct set **psets, int n_sets)
|
||||
if (MEM_P (XEXP (x, 0)))
|
||||
canon_reg (XEXP (x, 0), insn);
|
||||
}
|
||||
else if (GET_CODE (x) == CLOBBER_HIGH)
|
||||
gcc_assert (REG_P (XEXP (x, 0)));
|
||||
else if (GET_CODE (x) == USE
|
||||
&& ! (REG_P (XEXP (x, 0))
|
||||
&& REGNO (XEXP (x, 0)) < FIRST_PSEUDO_REGISTER))
|
||||
@ -4430,6 +4453,8 @@ canonicalize_insn (rtx_insn *insn, struct set **psets, int n_sets)
|
||||
if (MEM_P (XEXP (y, 0)))
|
||||
canon_reg (XEXP (y, 0), insn);
|
||||
}
|
||||
else if (GET_CODE (y) == CLOBBER_HIGH)
|
||||
gcc_assert (REG_P (XEXP (y, 0)));
|
||||
else if (GET_CODE (y) == USE
|
||||
&& ! (REG_P (XEXP (y, 0))
|
||||
&& REGNO (XEXP (y, 0)) < FIRST_PSEUDO_REGISTER))
|
||||
@ -6130,6 +6155,12 @@ invalidate_from_clobbers (rtx_insn *insn)
|
||||
invalidate (XEXP (ref, 0), GET_MODE (ref));
|
||||
}
|
||||
}
|
||||
if (GET_CODE (x) == CLOBBER_HIGH)
|
||||
{
|
||||
rtx ref = XEXP (x, 0);
|
||||
gcc_assert (REG_P (ref));
|
||||
invalidate_reg (ref, true);
|
||||
}
|
||||
else if (GET_CODE (x) == PARALLEL)
|
||||
{
|
||||
int i;
|
||||
@ -6146,6 +6177,12 @@ invalidate_from_clobbers (rtx_insn *insn)
|
||||
|| GET_CODE (ref) == ZERO_EXTRACT)
|
||||
invalidate (XEXP (ref, 0), GET_MODE (ref));
|
||||
}
|
||||
else if (GET_CODE (y) == CLOBBER_HIGH)
|
||||
{
|
||||
rtx ref = XEXP (y, 0);
|
||||
gcc_assert (REG_P (ref));
|
||||
invalidate_reg (ref, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -6163,8 +6200,17 @@ invalidate_from_sets_and_clobbers (rtx_insn *insn)
|
||||
if (CALL_P (insn))
|
||||
{
|
||||
for (tem = CALL_INSN_FUNCTION_USAGE (insn); tem; tem = XEXP (tem, 1))
|
||||
if (GET_CODE (XEXP (tem, 0)) == CLOBBER)
|
||||
invalidate (SET_DEST (XEXP (tem, 0)), VOIDmode);
|
||||
{
|
||||
rtx temx = XEXP (tem, 0);
|
||||
if (GET_CODE (temx) == CLOBBER)
|
||||
invalidate (SET_DEST (temx), VOIDmode);
|
||||
else if (GET_CODE (temx) == CLOBBER_HIGH)
|
||||
{
|
||||
rtx temref = XEXP (temx, 0);
|
||||
gcc_assert (REG_P (temref));
|
||||
invalidate_reg (temref, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Ensure we invalidate the destination register of a CALL insn.
|
||||
@ -6191,6 +6237,12 @@ invalidate_from_sets_and_clobbers (rtx_insn *insn)
|
||||
|| GET_CODE (clobbered) == ZERO_EXTRACT)
|
||||
invalidate (XEXP (clobbered, 0), GET_MODE (clobbered));
|
||||
}
|
||||
else if (GET_CODE (y) == CLOBBER_HIGH)
|
||||
{
|
||||
rtx ref = XEXP (y, 0);
|
||||
gcc_assert (REG_P (ref));
|
||||
invalidate_reg (ref, true);
|
||||
}
|
||||
else if (GET_CODE (y) == SET && GET_CODE (SET_SRC (y)) == CALL)
|
||||
invalidate (SET_DEST (y), VOIDmode);
|
||||
}
|
||||
@ -6850,6 +6902,10 @@ count_reg_usage (rtx x, int *counts, rtx dest, int incr)
|
||||
count_reg_usage (XEXP (XEXP (x, 0), 0), counts, NULL_RTX, incr);
|
||||
return;
|
||||
|
||||
case CLOBBER_HIGH:
|
||||
gcc_assert (REG_P ((XEXP (x, 0))));
|
||||
return;
|
||||
|
||||
case SET:
|
||||
/* Unless we are setting a REG, count everything in SET_DEST. */
|
||||
if (!REG_P (SET_DEST (x)))
|
||||
@ -6902,7 +6958,8 @@ count_reg_usage (rtx x, int *counts, rtx dest, int incr)
|
||||
|| (REG_NOTE_KIND (x) != REG_NONNEG && GET_CODE (XEXP (x,0)) == USE)
|
||||
/* FUNCTION_USAGE expression lists may include (CLOBBER (mem /u)),
|
||||
involving registers in the address. */
|
||||
|| GET_CODE (XEXP (x, 0)) == CLOBBER)
|
||||
|| GET_CODE (XEXP (x, 0)) == CLOBBER
|
||||
|| GET_CODE (XEXP (x, 0)) == CLOBBER_HIGH)
|
||||
count_reg_usage (XEXP (x, 0), counts, NULL_RTX, incr);
|
||||
|
||||
count_reg_usage (XEXP (x, 1), counts, NULL_RTX, incr);
|
||||
@ -6986,7 +7043,9 @@ insn_live_p (rtx_insn *insn, int *counts)
|
||||
if (set_live_p (elt, insn, counts))
|
||||
return true;
|
||||
}
|
||||
else if (GET_CODE (elt) != CLOBBER && GET_CODE (elt) != USE)
|
||||
else if (GET_CODE (elt) != CLOBBER
|
||||
&& GET_CODE (elt) != CLOBBER_HIGH
|
||||
&& GET_CODE (elt) != USE)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
42
gcc/cselib.c
42
gcc/cselib.c
@ -54,7 +54,8 @@ static unsigned int cselib_hash_rtx (rtx, int, machine_mode);
|
||||
static cselib_val *new_cselib_val (unsigned int, machine_mode, rtx);
|
||||
static void add_mem_for_addr (cselib_val *, cselib_val *, rtx);
|
||||
static cselib_val *cselib_lookup_mem (rtx, int);
|
||||
static void cselib_invalidate_regno (unsigned int, machine_mode);
|
||||
static void cselib_invalidate_regno (unsigned int, machine_mode,
|
||||
const_rtx = NULL);
|
||||
static void cselib_invalidate_mem (rtx);
|
||||
static void cselib_record_set (rtx, cselib_val *, cselib_val *);
|
||||
static void cselib_record_sets (rtx_insn *);
|
||||
@ -1661,6 +1662,7 @@ cselib_expand_value_rtx_1 (rtx orig, struct expand_value_data *evd,
|
||||
/* SCRATCH must be shared because they represent distinct values. */
|
||||
return orig;
|
||||
case CLOBBER:
|
||||
case CLOBBER_HIGH:
|
||||
if (REG_P (XEXP (orig, 0)) && HARD_REGISTER_NUM_P (REGNO (XEXP (orig, 0))))
|
||||
return orig;
|
||||
break;
|
||||
@ -2163,7 +2165,8 @@ cselib_lookup (rtx x, machine_mode mode,
|
||||
invalidating call clobbered registers across a call. */
|
||||
|
||||
static void
|
||||
cselib_invalidate_regno (unsigned int regno, machine_mode mode)
|
||||
cselib_invalidate_regno (unsigned int regno, machine_mode mode,
|
||||
const_rtx setter)
|
||||
{
|
||||
unsigned int endregno;
|
||||
unsigned int i;
|
||||
@ -2186,6 +2189,9 @@ cselib_invalidate_regno (unsigned int regno, machine_mode mode)
|
||||
i = regno - max_value_regs;
|
||||
|
||||
endregno = end_hard_regno (mode, regno);
|
||||
|
||||
if (setter && GET_CODE (setter) == CLOBBER_HIGH)
|
||||
gcc_assert (endregno == regno + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -2218,6 +2224,19 @@ cselib_invalidate_regno (unsigned int regno, machine_mode mode)
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Ignore if clobber high and the register isn't clobbered. */
|
||||
if (setter && GET_CODE (setter) == CLOBBER_HIGH)
|
||||
{
|
||||
gcc_assert (endregno == regno + 1);
|
||||
const_rtx x = XEXP (setter, 0);
|
||||
if (!reg_is_clobbered_by_clobber_high (i, GET_MODE (v->val_rtx),
|
||||
x))
|
||||
{
|
||||
l = &(*l)->next;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* We have an overlap. */
|
||||
if (*l == REG_VALUES (i))
|
||||
{
|
||||
@ -2352,10 +2371,10 @@ cselib_invalidate_mem (rtx mem_rtx)
|
||||
*vp = &dummy_val;
|
||||
}
|
||||
|
||||
/* Invalidate DEST, which is being assigned to or clobbered. */
|
||||
/* Invalidate DEST, which is being assigned to or clobbered by SETTER. */
|
||||
|
||||
void
|
||||
cselib_invalidate_rtx (rtx dest)
|
||||
cselib_invalidate_rtx (rtx dest, const_rtx setter)
|
||||
{
|
||||
while (GET_CODE (dest) == SUBREG
|
||||
|| GET_CODE (dest) == ZERO_EXTRACT
|
||||
@ -2363,7 +2382,7 @@ cselib_invalidate_rtx (rtx dest)
|
||||
dest = XEXP (dest, 0);
|
||||
|
||||
if (REG_P (dest))
|
||||
cselib_invalidate_regno (REGNO (dest), GET_MODE (dest));
|
||||
cselib_invalidate_regno (REGNO (dest), GET_MODE (dest), setter);
|
||||
else if (MEM_P (dest))
|
||||
cselib_invalidate_mem (dest);
|
||||
}
|
||||
@ -2371,10 +2390,10 @@ cselib_invalidate_rtx (rtx dest)
|
||||
/* A wrapper for cselib_invalidate_rtx to be called via note_stores. */
|
||||
|
||||
static void
|
||||
cselib_invalidate_rtx_note_stores (rtx dest, const_rtx ignore ATTRIBUTE_UNUSED,
|
||||
cselib_invalidate_rtx_note_stores (rtx dest, const_rtx setter,
|
||||
void *data ATTRIBUTE_UNUSED)
|
||||
{
|
||||
cselib_invalidate_rtx (dest);
|
||||
cselib_invalidate_rtx (dest, setter);
|
||||
}
|
||||
|
||||
/* Record the result of a SET instruction. DEST is being set; the source
|
||||
@ -2775,9 +2794,12 @@ cselib_process_insn (rtx_insn *insn)
|
||||
if (CALL_P (insn))
|
||||
{
|
||||
for (x = CALL_INSN_FUNCTION_USAGE (insn); x; x = XEXP (x, 1))
|
||||
if (GET_CODE (XEXP (x, 0)) == CLOBBER)
|
||||
cselib_invalidate_rtx (XEXP (XEXP (x, 0), 0));
|
||||
/* Flush evertything on setjmp. */
|
||||
{
|
||||
gcc_assert (GET_CODE (XEXP (x, 0)) != CLOBBER_HIGH);
|
||||
if (GET_CODE (XEXP (x, 0)) == CLOBBER)
|
||||
cselib_invalidate_rtx (XEXP (XEXP (x, 0), 0));
|
||||
}
|
||||
/* Flush everything on setjmp. */
|
||||
if (cselib_preserve_constants
|
||||
&& find_reg_note (insn, REG_SETJMP, NULL))
|
||||
{
|
||||
|
@ -92,7 +92,7 @@ extern bool cselib_dummy_expand_value_rtx_cb (rtx, bitmap, int,
|
||||
cselib_expand_callback, void *);
|
||||
extern rtx cselib_subst_to_values (rtx, machine_mode);
|
||||
extern rtx cselib_subst_to_values_from_insn (rtx, machine_mode, rtx_insn *);
|
||||
extern void cselib_invalidate_rtx (rtx);
|
||||
extern void cselib_invalidate_rtx (rtx, const_rtx = NULL);
|
||||
|
||||
extern void cselib_reset_table (unsigned int);
|
||||
extern unsigned int cselib_get_next_uid (void);
|
||||
|
Loading…
Reference in New Issue
Block a user