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:
Alan Hayward 2018-08-06 09:54:28 +00:00 committed by Alan Hayward
parent 30dc1902a7
commit 99788e0630
4 changed files with 172 additions and 75 deletions

View File

@ -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
View File

@ -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;

View File

@ -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))
{

View File

@ -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);