aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlan Hayward <alan.hayward@arm.com>2018-08-06 09:54:28 +0000
committerAlan Hayward <alahay01@gcc.gnu.org>2018-08-06 09:54:28 +0000
commit99788e063016c4f8d87dae3de71c646effac654f (patch)
tree073666483b43c7890a2cd761d82b0a76d323033a
parent30dc1902a777966dc1d1dad0fb5f19b7a960e5ca (diff)
downloadgcc-99788e063016c4f8d87dae3de71c646effac654f.zip
gcc-99788e063016c4f8d87dae3de71c646effac654f.tar.gz
gcc-99788e063016c4f8d87dae3de71c646effac654f.tar.bz2
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
-rw-r--r--gcc/ChangeLog16
-rw-r--r--gcc/cse.c187
-rw-r--r--gcc/cselib.c42
-rw-r--r--gcc/cselib.h2
4 files changed, 172 insertions, 75 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 8d9b158..883399f 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,21 @@
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.
diff --git a/gcc/cse.c b/gcc/cse.c
index 4e94152..3d7888b 100644
--- a/gcc/cse.c
+++ b/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;
diff --git a/gcc/cselib.c b/gcc/cselib.c
index 5a978c1..6d3a407 100644
--- a/gcc/cselib.c
+++ b/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))
{
diff --git a/gcc/cselib.h b/gcc/cselib.h
index be6feaf..0005ad3 100644
--- a/gcc/cselib.h
+++ b/gcc/cselib.h
@@ -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);