This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

expr.c / cse.c patches for member function constructor optimization applied


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.  */


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]