From 99788e063016c4f8d87dae3de71c646effac654f Mon Sep 17 00:00:00 2001 From: Alan Hayward Date: Mon, 6 Aug 2018 09:54:28 +0000 Subject: 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/cse.c | 187 +++++++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 123 insertions(+), 64 deletions(-) (limited to 'gcc/cse.c') 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; -- cgit v1.1