From 99788e063016c4f8d87dae3de71c646effac654f Mon Sep 17 00:00:00 2001 From: Alan Hayward Date: Mon, 6 Aug 2018 09:54:28 +0000 Subject: [PATCH] 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 --- gcc/ChangeLog | 16 +++++ gcc/cse.c | 187 +++++++++++++++++++++++++++++++++----------------- gcc/cselib.c | 42 +++++++++--- gcc/cselib.h | 2 +- 4 files changed, 172 insertions(+), 75 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 8d9b158861d..883399fd2d1 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,19 @@ +2018-08-06 Alan Hayward + + * 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 * lra-eliminations.c (lra_eliminate_regs_1): Check for clobber high. 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; diff --git a/gcc/cselib.c b/gcc/cselib.c index 5a978c1f4b8..6d3a4078c68 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 be6feaf84de..0005ad3113c 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); -- 2.30.2