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> 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. * lra-eliminations.c (lra_eliminate_regs_1): Check for clobber high.
(mark_not_eliminable): Likewise. (mark_not_eliminable): Likewise.
* lra-int.h (struct lra_insn_reg): Add clobber high marker. * 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, ...@@ -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, static struct table_elt *insert (rtx, struct table_elt *, unsigned,
machine_mode); machine_mode);
static void merge_equiv_classes (struct table_elt *, struct table_elt *); 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 invalidate (rtx, machine_mode);
static void remove_invalid_refs (unsigned int); static void remove_invalid_refs (unsigned int);
static void remove_invalid_subreg_refs (unsigned int, poly_uint64, 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) ...@@ -1818,7 +1819,85 @@ check_dependence (const_rtx x, rtx exp, machine_mode mode, rtx addr)
} }
return false; 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 /* 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 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 a memory reference with nonvarying address (because, when a memory
...@@ -1841,65 +1920,7 @@ invalidate (rtx x, machine_mode full_mode) ...@@ -1841,65 +1920,7 @@ invalidate (rtx x, machine_mode full_mode)
switch (GET_CODE (x)) switch (GET_CODE (x))
{ {
case REG: case REG:
{ invalidate_reg (x, false);
/* 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);
}
}
}
return; return;
case SUBREG: case SUBREG:
...@@ -4399,6 +4420,8 @@ canonicalize_insn (rtx_insn *insn, struct set **psets, int n_sets) ...@@ -4399,6 +4420,8 @@ canonicalize_insn (rtx_insn *insn, struct set **psets, int n_sets)
if (MEM_P (XEXP (x, 0))) if (MEM_P (XEXP (x, 0)))
canon_reg (XEXP (x, 0), insn); 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 else if (GET_CODE (x) == USE
&& ! (REG_P (XEXP (x, 0)) && ! (REG_P (XEXP (x, 0))
&& REGNO (XEXP (x, 0)) < FIRST_PSEUDO_REGISTER)) && REGNO (XEXP (x, 0)) < FIRST_PSEUDO_REGISTER))
...@@ -4430,6 +4453,8 @@ canonicalize_insn (rtx_insn *insn, struct set **psets, int n_sets) ...@@ -4430,6 +4453,8 @@ canonicalize_insn (rtx_insn *insn, struct set **psets, int n_sets)
if (MEM_P (XEXP (y, 0))) if (MEM_P (XEXP (y, 0)))
canon_reg (XEXP (y, 0), insn); 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 else if (GET_CODE (y) == USE
&& ! (REG_P (XEXP (y, 0)) && ! (REG_P (XEXP (y, 0))
&& REGNO (XEXP (y, 0)) < FIRST_PSEUDO_REGISTER)) && REGNO (XEXP (y, 0)) < FIRST_PSEUDO_REGISTER))
...@@ -6130,6 +6155,12 @@ invalidate_from_clobbers (rtx_insn *insn) ...@@ -6130,6 +6155,12 @@ invalidate_from_clobbers (rtx_insn *insn)
invalidate (XEXP (ref, 0), GET_MODE (ref)); 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) else if (GET_CODE (x) == PARALLEL)
{ {
int i; int i;
...@@ -6146,6 +6177,12 @@ invalidate_from_clobbers (rtx_insn *insn) ...@@ -6146,6 +6177,12 @@ invalidate_from_clobbers (rtx_insn *insn)
|| GET_CODE (ref) == ZERO_EXTRACT) || GET_CODE (ref) == ZERO_EXTRACT)
invalidate (XEXP (ref, 0), GET_MODE (ref)); 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) ...@@ -6163,8 +6200,17 @@ invalidate_from_sets_and_clobbers (rtx_insn *insn)
if (CALL_P (insn)) if (CALL_P (insn))
{ {
for (tem = CALL_INSN_FUNCTION_USAGE (insn); tem; tem = XEXP (tem, 1)) 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. /* Ensure we invalidate the destination register of a CALL insn.
...@@ -6191,6 +6237,12 @@ invalidate_from_sets_and_clobbers (rtx_insn *insn) ...@@ -6191,6 +6237,12 @@ invalidate_from_sets_and_clobbers (rtx_insn *insn)
|| GET_CODE (clobbered) == ZERO_EXTRACT) || GET_CODE (clobbered) == ZERO_EXTRACT)
invalidate (XEXP (clobbered, 0), GET_MODE (clobbered)); 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) else if (GET_CODE (y) == SET && GET_CODE (SET_SRC (y)) == CALL)
invalidate (SET_DEST (y), VOIDmode); invalidate (SET_DEST (y), VOIDmode);
} }
...@@ -6850,6 +6902,10 @@ count_reg_usage (rtx x, int *counts, rtx dest, int incr) ...@@ -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); count_reg_usage (XEXP (XEXP (x, 0), 0), counts, NULL_RTX, incr);
return; return;
case CLOBBER_HIGH:
gcc_assert (REG_P ((XEXP (x, 0))));
return;
case SET: case SET:
/* Unless we are setting a REG, count everything in SET_DEST. */ /* Unless we are setting a REG, count everything in SET_DEST. */
if (!REG_P (SET_DEST (x))) if (!REG_P (SET_DEST (x)))
...@@ -6902,7 +6958,8 @@ count_reg_usage (rtx x, int *counts, rtx dest, int incr) ...@@ -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) || (REG_NOTE_KIND (x) != REG_NONNEG && GET_CODE (XEXP (x,0)) == USE)
/* FUNCTION_USAGE expression lists may include (CLOBBER (mem /u)), /* FUNCTION_USAGE expression lists may include (CLOBBER (mem /u)),
involving registers in the address. */ 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, 0), counts, NULL_RTX, incr);
count_reg_usage (XEXP (x, 1), 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) ...@@ -6986,7 +7043,9 @@ insn_live_p (rtx_insn *insn, int *counts)
if (set_live_p (elt, insn, counts)) if (set_live_p (elt, insn, counts))
return true; 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 true;
} }
return false; return false;
......
...@@ -54,7 +54,8 @@ static unsigned int cselib_hash_rtx (rtx, int, machine_mode); ...@@ -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 cselib_val *new_cselib_val (unsigned int, machine_mode, rtx);
static void add_mem_for_addr (cselib_val *, cselib_val *, rtx); static void add_mem_for_addr (cselib_val *, cselib_val *, rtx);
static cselib_val *cselib_lookup_mem (rtx, int); 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_invalidate_mem (rtx);
static void cselib_record_set (rtx, cselib_val *, cselib_val *); static void cselib_record_set (rtx, cselib_val *, cselib_val *);
static void cselib_record_sets (rtx_insn *); static void cselib_record_sets (rtx_insn *);
...@@ -1661,6 +1662,7 @@ cselib_expand_value_rtx_1 (rtx orig, struct expand_value_data *evd, ...@@ -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. */ /* SCRATCH must be shared because they represent distinct values. */
return orig; return orig;
case CLOBBER: case CLOBBER:
case CLOBBER_HIGH:
if (REG_P (XEXP (orig, 0)) && HARD_REGISTER_NUM_P (REGNO (XEXP (orig, 0)))) if (REG_P (XEXP (orig, 0)) && HARD_REGISTER_NUM_P (REGNO (XEXP (orig, 0))))
return orig; return orig;
break; break;
...@@ -2163,7 +2165,8 @@ cselib_lookup (rtx x, machine_mode mode, ...@@ -2163,7 +2165,8 @@ cselib_lookup (rtx x, machine_mode mode,
invalidating call clobbered registers across a call. */ invalidating call clobbered registers across a call. */
static void 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 endregno;
unsigned int i; unsigned int i;
...@@ -2186,6 +2189,9 @@ cselib_invalidate_regno (unsigned int regno, machine_mode mode) ...@@ -2186,6 +2189,9 @@ cselib_invalidate_regno (unsigned int regno, machine_mode mode)
i = regno - max_value_regs; i = regno - max_value_regs;
endregno = end_hard_regno (mode, regno); endregno = end_hard_regno (mode, regno);
if (setter && GET_CODE (setter) == CLOBBER_HIGH)
gcc_assert (endregno == regno + 1);
} }
else else
{ {
...@@ -2218,6 +2224,19 @@ cselib_invalidate_regno (unsigned int regno, machine_mode mode) ...@@ -2218,6 +2224,19 @@ cselib_invalidate_regno (unsigned int regno, machine_mode mode)
continue; 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. */ /* We have an overlap. */
if (*l == REG_VALUES (i)) if (*l == REG_VALUES (i))
{ {
...@@ -2352,10 +2371,10 @@ cselib_invalidate_mem (rtx mem_rtx) ...@@ -2352,10 +2371,10 @@ cselib_invalidate_mem (rtx mem_rtx)
*vp = &dummy_val; *vp = &dummy_val;
} }
/* Invalidate DEST, which is being assigned to or clobbered. */ /* Invalidate DEST, which is being assigned to or clobbered by SETTER. */
void void
cselib_invalidate_rtx (rtx dest) cselib_invalidate_rtx (rtx dest, const_rtx setter)
{ {
while (GET_CODE (dest) == SUBREG while (GET_CODE (dest) == SUBREG
|| GET_CODE (dest) == ZERO_EXTRACT || GET_CODE (dest) == ZERO_EXTRACT
...@@ -2363,7 +2382,7 @@ cselib_invalidate_rtx (rtx dest) ...@@ -2363,7 +2382,7 @@ cselib_invalidate_rtx (rtx dest)
dest = XEXP (dest, 0); dest = XEXP (dest, 0);
if (REG_P (dest)) 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)) else if (MEM_P (dest))
cselib_invalidate_mem (dest); cselib_invalidate_mem (dest);
} }
...@@ -2371,10 +2390,10 @@ cselib_invalidate_rtx (rtx dest) ...@@ -2371,10 +2390,10 @@ cselib_invalidate_rtx (rtx dest)
/* A wrapper for cselib_invalidate_rtx to be called via note_stores. */ /* A wrapper for cselib_invalidate_rtx to be called via note_stores. */
static void 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) 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 /* Record the result of a SET instruction. DEST is being set; the source
...@@ -2775,9 +2794,12 @@ cselib_process_insn (rtx_insn *insn) ...@@ -2775,9 +2794,12 @@ cselib_process_insn (rtx_insn *insn)
if (CALL_P (insn)) if (CALL_P (insn))
{ {
for (x = CALL_INSN_FUNCTION_USAGE (insn); x; x = XEXP (x, 1)) 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)); gcc_assert (GET_CODE (XEXP (x, 0)) != CLOBBER_HIGH);
/* Flush evertything on setjmp. */ if (GET_CODE (XEXP (x, 0)) == CLOBBER)
cselib_invalidate_rtx (XEXP (XEXP (x, 0), 0));
}
/* Flush everything on setjmp. */
if (cselib_preserve_constants if (cselib_preserve_constants
&& find_reg_note (insn, REG_SETJMP, NULL)) && find_reg_note (insn, REG_SETJMP, NULL))
{ {
......
...@@ -92,7 +92,7 @@ extern bool cselib_dummy_expand_value_rtx_cb (rtx, bitmap, int, ...@@ -92,7 +92,7 @@ extern bool cselib_dummy_expand_value_rtx_cb (rtx, bitmap, int,
cselib_expand_callback, void *); cselib_expand_callback, void *);
extern rtx cselib_subst_to_values (rtx, machine_mode); extern rtx cselib_subst_to_values (rtx, machine_mode);
extern rtx cselib_subst_to_values_from_insn (rtx, machine_mode, rtx_insn *); 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 void cselib_reset_table (unsigned int);
extern unsigned int cselib_get_next_uid (void); 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