Commit 99788e06 by Alan Hayward Committed by Alan Hayward

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
parent 30dc1902
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.
(mark_not_eliminable): Likewise.
* lra-int.h (struct lra_insn_reg): Add clobber high marker.
......
......@@ -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,
......@@ -1820,28 +1821,15 @@ check_dependence (const_rtx x, rtx exp, machine_mode mode, rtx addr)
}
/* 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
reference with a varying address is stored in, all memory references are
removed by invalidate_memory so specific invalidation is superfluous).
FULL_MODE, if not VOIDmode, indicates that this much should be
invalidated instead of just the amount indicated by the mode of X. This
is only used for bitfield stores into memory.
values could be altered by storing in register X.
A nonvarying address may be just a register or just a symbol reference,
or it may be either of those plus a numeric offset. */
CLOBBER_HIGH is set if X was part of a CLOBBER_HIGH expression. */
static void
invalidate (rtx x, machine_mode full_mode)
invalidate_reg (rtx x, bool clobber_high)
{
int i;
struct table_elt *p;
rtx addr;
gcc_assert (GET_CODE (x) == REG);
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,
......@@ -1863,13 +1851,15 @@ invalidate (rtx x, machine_mode full_mode)
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);
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;
unsigned int rn;
struct table_elt *p, *next;
CLEAR_HARD_REG_BIT (hard_regs_in_table, regno);
......@@ -1889,17 +1879,48 @@ invalidate (rtx x, machine_mode full_mode)
{
next = p->next_same_hash;
if (!REG_P (p->exp)
|| REGNO (p->exp) >= FIRST_PSEUDO_REGISTER)
if (!REG_P (p->exp) || REGNO (p->exp) >= FIRST_PSEUDO_REGISTER)
continue;
tregno = REGNO (p->exp);
tendregno = END_REGNO (p->exp);
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
reference with a varying address is stored in, all memory references are
removed by invalidate_memory so specific invalidation is superfluous).
FULL_MODE, if not VOIDmode, indicates that this much should be
invalidated instead of just the amount indicated by the mode of X. This
is only used for bitfield stores into memory.
A nonvarying address may be just a register or just a symbol reference,
or it may be either of those plus a numeric offset. */
static void
invalidate (rtx x, machine_mode full_mode)
{
int i;
struct table_elt *p;
rtx addr;
switch (GET_CODE (x))
{
case REG:
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;
......
......@@ -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))
{
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 evertything on setjmp. */
}
/* 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);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment