summaryrefslogtreecommitdiff
path: root/gcc/cse.c
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 /gcc/cse.c
parent30dc1902a777966dc1d1dad0fb5f19b7a960e5ca (diff)
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
Diffstat (limited to 'gcc/cse.c')
-rw-r--r--gcc/cse.c187
1 files changed, 123 insertions, 64 deletions
diff --git a/gcc/cse.c b/gcc/cse.c
index 4e94152b380..3d7888b7093 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;