diff options
author | J"orn Rennecke <amylaar@cygnus.co.uk> | 1998-09-24 09:59:41 +0000 |
---|---|---|
committer | Joern Rennecke <amylaar@gcc.gnu.org> | 1998-09-24 10:59:41 +0100 |
commit | 34c73909813a5b2225ceac86dc6402f86b64d451 (patch) | |
tree | 7abc19d3b6986f83e3eeb1c3ac8b63037020a7c2 /gcc/cse.c | |
parent | c5a951a851895f7184200911e63b12f884a01ded (diff) | |
download | gcc-34c73909813a5b2225ceac86dc6402f86b64d451.zip gcc-34c73909813a5b2225ceac86dc6402f86b64d451.tar.gz gcc-34c73909813a5b2225ceac86dc6402f86b64d451.tar.bz2 |
expr.c (store_constructor): When initializing a field that is smaller than a word...
* expr.c (store_constructor): When initializing a field that is smaller
than a word, at the start of a word, try to widen it to a full word.
* cse.c (cse_insn): When we are about to change a register,
remove any invalid references to it.
(remove_invalid_subreg_refs): New function.
(mention_regs): Special treatment for SUBREGs.
(insert_regs): Don't strip SUBREG for call to mention_regs.
Check if reg_tick needs to be bumped up before that call.
(lookup_as_function): Try to match known word_mode constants when
looking for a norrower constant.
(canon_hash): Special treatment for SUBREGs.
From-SVN: r22567
Diffstat (limited to 'gcc/cse.c')
-rw-r--r-- | gcc/cse.c | 134 |
1 files changed, 131 insertions, 3 deletions
@@ -626,6 +626,7 @@ static void merge_equiv_classes PROTO((struct table_elt *, static void invalidate PROTO((rtx, enum machine_mode)); static int cse_rtx_varies_p PROTO((rtx)); static void remove_invalid_refs PROTO((int)); +static void remove_invalid_subreg_refs PROTO((int, int, enum machine_mode)); static void rehash_using_reg PROTO((rtx)); static void invalidate_memory PROTO((void)); static void invalidate_for_call PROTO((void)); @@ -980,6 +981,30 @@ mention_regs (x) return 0; } + /* If this is a SUBREG, we don't want to discard other SUBREGs of the same + pseudo if they don't use overlapping words. We handle only pseudos + here for simplicity. */ + if (code == SUBREG && GET_CODE (SUBREG_REG (x)) == REG + && REGNO (SUBREG_REG (x)) >= FIRST_PSEUDO_REGISTER) + { + int i = REGNO (SUBREG_REG (x)); + + if (reg_in_table[i] >= 0 && reg_in_table[i] != reg_tick[i]) + { + /* If reg_tick has been incremented more than once since + reg_in_table was last set, that means that the entire + register has been set before, so discard anything memorized + for the entrire register, including all SUBREG expressions. */ + if (reg_in_table[i] != reg_tick[i] - 1) + remove_invalid_refs (i); + else + remove_invalid_subreg_refs (i, SUBREG_WORD (x), GET_MODE (x)); + } + + reg_in_table[i] = reg_tick[i]; + return 0; + } + /* If X is a comparison or a COMPARE and either operand is a register that does not have a quantity, give it one. This is so that a later call to record_jump_equiv won't cause X to be assigned a different @@ -1077,8 +1102,19 @@ insert_regs (x, classp, modified) else if (GET_CODE (x) == SUBREG && GET_CODE (SUBREG_REG (x)) == REG && ! REGNO_QTY_VALID_P (REGNO (SUBREG_REG (x)))) { + int regno = REGNO (SUBREG_REG (x)); + insert_regs (SUBREG_REG (x), NULL_PTR, 0); - mention_regs (SUBREG_REG (x)); + /* Mention_regs checks if REG_TICK is exactly one larger than + REG_IN_TABLE to find out if there was only a single preceding + invalidation - for the SUBREG - or another one, which would be + for the full register. Since we don't invalidate the SUBREG + here first, we might have to bump up REG_TICK so that mention_regs + will do the right thing. */ + if (reg_in_table[regno] >= 0 + && reg_tick[regno] == reg_in_table[regno] + 1) + reg_tick++; + mention_regs (x); return 1; } else @@ -1254,6 +1290,17 @@ lookup_as_function (x, code) { register struct table_elt *p = lookup (x, safe_hash (x, VOIDmode) % NBUCKETS, GET_MODE (x)); + /* If we are looking for a CONST_INT, the mode doesn't really matter, as + long as we are narrowing. So if we looked in vain for a mode narrower + than word_mode before, look for word_mode now. */ + if (p == 0 && code == CONST_INT + && GET_MODE_SIZE (GET_MODE (x)) < GET_MODE_SIZE (word_mode)) + { + x = copy_rtx (x); + PUT_MODE (x, word_mode); + p = lookup (x, safe_hash (x, VOIDmode) % NBUCKETS, word_mode); + } + if (p == 0) return 0; @@ -1684,6 +1731,37 @@ remove_invalid_refs (regno) remove_from_table (p, i); } } + +/* Likewise for a subreg with subreg_reg WORD and mode MODE. */ +static void +remove_invalid_subreg_refs (regno, word, mode) + int regno; + int word; + enum machine_mode mode; +{ + register int i; + register struct table_elt *p, *next; + int end = word + (GET_MODE_SIZE (mode) - 1) / UNITS_PER_WORD; + + for (i = 0; i < NBUCKETS; i++) + for (p = table[i]; p; p = next) + { + rtx exp; + next = p->next_same_hash; + + exp = p->exp; + if (GET_CODE (p->exp) != REG + && (GET_CODE (exp) != SUBREG + || GET_CODE (SUBREG_REG (exp)) != REG + || REGNO (SUBREG_REG (exp)) != regno + || (((SUBREG_WORD (exp) + + (GET_MODE_SIZE (GET_MODE (exp)) - 1) / UNITS_PER_WORD) + >= word) + && SUBREG_WORD (exp) <= end)) + && refers_to_regno_p (regno, regno + 1, p->exp, NULL_PTR)) + remove_from_table (p, i); + } +} /* Recompute the hash codes of any valid entries in the hash table that reference X, if X is a register, or SUBREG_REG (X) if X is a SUBREG. @@ -1930,6 +2008,20 @@ canon_hash (x, mode) return hash; } + /* We handle SUBREG of a REG specially because the underlying + reg changes its hash value with every value change; we don't + want to have to forget unrelated subregs when one subreg changes. */ + case SUBREG: + { + if (GET_CODE (SUBREG_REG (x)) == REG) + { + hash += (((unsigned) SUBREG << 7) + + REGNO (SUBREG_REG (x)) + SUBREG_WORD (x)); + return hash; + } + break; + } + case CONST_INT: { unsigned HOST_WIDE_INT tem = INTVAL (x); @@ -7409,8 +7501,44 @@ cse_insn (insn, libcall_insn) we are going to hash the SET_DEST values unconditionally. */ for (i = 0; i < n_sets; i++) - if (sets[i].rtl && GET_CODE (SET_DEST (sets[i].rtl)) != REG) - mention_regs (SET_DEST (sets[i].rtl)); + { + if (sets[i].rtl) + { + rtx x = SET_DEST (sets[i].rtl); + + if (GET_CODE (x) != REG) + mention_regs (x); + else + { + /* We used to rely on all references to a register becoming + inaccessible when a register changes to a new quantity, + since that changes the hash code. However, that is not + safe, since after NBUCKETS new quantities we get a + hash 'collision' of a register with its own invalid + entries. And since SUBREGs have been changed not to + change their hash code with the hash code of the register, + it wouldn't work any longer at all. So we have to check + for any invalid references lying around now. + This code is similar to the REG case in mention_regs, + but it knows that reg_tick has been incremented, and + it leaves reg_in_table as -1 . */ + register int regno = REGNO (x); + register int endregno + = regno + (regno >= FIRST_PSEUDO_REGISTER ? 1 + : HARD_REGNO_NREGS (regno, GET_MODE (x))); + int i; + + for (i = regno; i < endregno; i++) + { + if (reg_in_table[i] >= 0) + { + remove_invalid_refs (i); + reg_in_table[i] = -1; + } + } + } + } + } /* We may have just removed some of the src_elt's from the hash table. So replace each one with the current head of the same class. */ |