This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
expr.c / cse.c patches for member function constructor optimization applied
- To: egcs-patches at cygnus dot com, wilson at cygnus dot com
- Subject: expr.c / cse.c patches for member function constructor optimization applied
- From: Joern Rennecke <amylaar at cygnus dot co dot uk>
- Date: Thu, 24 Sep 1998 18:01:09 +0100 (BST)
Thu Sep 24 17:55:31 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
* 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.
Index: expr.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/expr.c,v
retrieving revision 1.96
diff -p -r1.96 expr.c
*** expr.c 1998/09/15 19:18:52 1.96
--- expr.c 1998/09/24 16:56:52
*************** store_constructor (exp, target, cleared)
*** 3819,3824 ****
--- 3819,3825 ----
int cleared;
{
tree type = TREE_TYPE (exp);
+ rtx exp_size = expr_size (exp);
/* We know our target cannot conflict, since safe_from_p has been called. */
#if 0
*************** store_constructor (exp, target, cleared)
*** 3880,3885 ****
--- 3881,3887 ----
for (elt = CONSTRUCTOR_ELTS (exp); elt; elt = TREE_CHAIN (elt))
{
register tree field = TREE_PURPOSE (elt);
+ tree value = TREE_VALUE (elt);
register enum machine_mode mode;
int bitsize;
int bitpos = 0;
*************** store_constructor (exp, target, cleared)
*** 3951,3958 ****
RTX_UNCHANGING_P (to_rtx) = 1;
}
store_constructor_field (to_rtx, bitsize, bitpos,
! mode, TREE_VALUE (elt), type, cleared);
}
}
else if (TREE_CODE (type) == ARRAY_TYPE)
--- 3953,3988 ----
RTX_UNCHANGING_P (to_rtx) = 1;
}
+ #ifdef WORD_REGISTER_OPERATIONS
+ /* If this initializes a field that is smaller than a word, at the
+ start of a word, try to widen it to a full word.
+ This special case allows us to output C++ member function
+ initializations in a form that the optimizers can understand. */
+ if (constant
+ && GET_CODE (target) == REG
+ && bitsize < BITS_PER_WORD
+ && bitpos % BITS_PER_WORD == 0
+ && GET_MODE_CLASS (mode) == MODE_INT
+ && TREE_CODE (value) == INTEGER_CST
+ && GET_CODE (exp_size) == CONST_INT
+ && bitpos + BITS_PER_WORD <= INTVAL (exp_size) * BITS_PER_UNIT)
+ {
+ tree type = TREE_TYPE (value);
+ if (TYPE_PRECISION (type) < BITS_PER_WORD)
+ {
+ type = type_for_size (BITS_PER_WORD, TREE_UNSIGNED (type));
+ value = convert (type, value);
+ }
+ if (BYTES_BIG_ENDIAN)
+ value
+ = fold (build (LSHIFT_EXPR, type, value,
+ build_int_2 (BITS_PER_WORD - bitsize, 0)));
+ bitsize = BITS_PER_WORD;
+ mode = word_mode;
+ }
+ #endif
store_constructor_field (to_rtx, bitsize, bitpos,
! mode, value, type, cleared);
}
}
else if (TREE_CODE (type) == ARRAY_TYPE)
Index: cse.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cse.c,v
retrieving revision 1.46
diff -p -r1.46 cse.c
*** cse.c 1998/08/14 16:28:29 1.46
--- cse.c 1998/09/24 16:56:55
*************** static void merge_equiv_classes PROTO((s
*** 626,631 ****
--- 626,632 ----
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));
*************** mention_regs (x)
*** 980,985 ****
--- 981,1010 ----
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
*************** insert_regs (x, classp, modified)
*** 1077,1084 ****
else if (GET_CODE (x) == SUBREG && GET_CODE (SUBREG_REG (x)) == REG
&& ! REGNO_QTY_VALID_P (REGNO (SUBREG_REG (x))))
{
insert_regs (SUBREG_REG (x), NULL_PTR, 0);
! mention_regs (SUBREG_REG (x));
return 1;
}
else
--- 1102,1120 ----
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 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
*************** lookup_as_function (x, code)
*** 1254,1259 ****
--- 1290,1306 ----
{
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;
*************** remove_invalid_refs (regno)
*** 1684,1689 ****
--- 1731,1767 ----
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.
*************** canon_hash (x, mode)
*** 1930,1935 ****
--- 2008,2027 ----
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);
*************** cse_insn (insn, libcall_insn)
*** 7409,7416 ****
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));
/* 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. */
--- 7501,7544 ----
we are going to hash the SET_DEST values unconditionally. */
for (i = 0; i < n_sets; i++)
! {
! 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. */