This is the mail archive of the gcc@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]

Re: CPROP and spec2000 slowdown in mid february


Hi,
just to clarify thinks, I've found my patch that rorganized the
validate_replace_rtx to do first the recursion and then simplification
to avoid the problems with nested simplifications.
The patch is outdated and would probably need to be redone for new review
if we conclude that this makes sense.

Hi
This patch fixes problem in validate_replace_rtx_1 constructing invalid
rtl.  The problem is that code taking care to avoid VOIDmodes where they
shouldn't be (in SUBREG, ZERO_EXTEND, SIGN_EXTEND and comparisons for instance)
misses chase, where chained simplification is performed (i.e the operand is
SUBREG with proper mode, but it gets simplified in the recursion).

This patch just reorganizes it to work in similar way as other do - recurse
first and simplify later.
I've also break out the subreg simplification bits - I need them elsewhere
and I don't want to cause too much trouble to SUBREG_BYTE merging by copying
the code again and again.

Honza

Tue Oct  3 09:35:47 MET DST 2000  Jan Hubicka  <jh@suse.cz>

	* simplify-rtx.c (simplify_subreg): Break out of ...
	* recog.c (validate_replace_rtx_1): ... here; Reorganize.
	* rtl.h (simplify_subreg): New.

Index: egcs/gcc//recog.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/recog.c,v
retrieving revision 1.78
diff -c -3 -p -r1.78 recog.c
*** recog.c	2000/09/29 11:40:24	1.78
--- recog.c	2000/10/03 07:33:46
*************** validate_replace_rtx_1 (loc, from, to, o
*** 429,477 ****
        return;
      }
  
    /* For commutative or comparison operations, try replacing each argument
       separately and seeing if we made any changes.  If so, put a constant
       argument last.*/
!   if (GET_RTX_CLASS (code) == '<' || GET_RTX_CLASS (code) == 'c')
      {
!       int prev_changes = num_changes;
! 
!       validate_replace_rtx_1 (&XEXP (x, 0), from, to, object);
!       validate_replace_rtx_1 (&XEXP (x, 1), from, to, object);
!       if (prev_changes != num_changes && CONSTANT_P (XEXP (x, 0)))
! 	{
! 	  validate_change (object, loc,
! 			   gen_rtx_fmt_ee (GET_RTX_CLASS (code) == 'c' ? code
! 					   : swap_condition (code),
! 					   GET_MODE (x), XEXP (x, 1),
! 					   XEXP (x, 0)),
! 			   1);
! 	  x = *loc;
! 	  code = GET_CODE (x);
! 	}
      }
! 
!   /* Note that if CODE's RTX_CLASS is "c" or "<" we will have already
!      done the substitution, otherwise we won't.  */
  
    switch (code)
      {
      case PLUS:
        /* If we have a PLUS whose second operand is now a CONST_INT, use
  	 plus_constant to try to simplify it.  */
!       if (GET_CODE (XEXP (x, 1)) == CONST_INT && XEXP (x, 1) == to)
! 	validate_change (object, loc, plus_constant (XEXP (x, 0), INTVAL (to)),
  			 1);
!       return;
  
      case MINUS:
!       if (GET_CODE (to) == CONST_INT && XEXP (x, 1) == from)
! 	{
! 	  validate_change (object, loc,
! 			   plus_constant (XEXP (x, 0), - INTVAL (to)),
! 			   1);
! 	  return;
! 	}
        break;
        
      case ZERO_EXTEND:
--- 429,486 ----
        return;
      }
  
+   /* For commutative or comparison operations we've already performed
+      replacements.  Don't try to perform them again.  */
+   fmt = GET_RTX_FORMAT (code);
+   if (fmt[0] == 'e')
+     op0_mode = GET_MODE (XEXP (x, 0));
+ 
+   for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+     {
+       if (fmt[i] == 'e')
+ 	validate_replace_rtx_1 (&XEXP (x, i), from, to, object);
+       else if (fmt[i] == 'E')
+ 	for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+ 	  validate_replace_rtx_1 (&XVECEXP (x, i, j), from, to, object);
+     }
+ 
    /* For commutative or comparison operations, try replacing each argument
       separately and seeing if we made any changes.  If so, put a constant
       argument last.*/
!   if ((GET_RTX_CLASS (code) == '<' || GET_RTX_CLASS (code) == 'c')
!       && prev_changes != num_changes && CONSTANT_P (XEXP (x, 0)))
      {
!       validate_change (object, loc,
! 		       gen_rtx_fmt_ee (GET_RTX_CLASS (code) == 'c' ? code
! 				       : swap_condition (code),
! 				       GET_MODE (x), XEXP (x, 1),
! 				       XEXP (x, 0)),
! 		       1);
!       x = *loc;
!       code = GET_CODE (x);
      }
!   /* When no changes was performed, we won't need to fix rtx.  */
!   if (prev_changes == num_changes)
!     return;
  
+   /* Otherwise do changes required to keep RTX proper, like canonicalization
+      simplifying SUBREGs of constants etc.  */
    switch (code)
      {
      case PLUS:
        /* If we have a PLUS whose second operand is now a CONST_INT, use
  	 plus_constant to try to simplify it.  */
!       if (GET_CODE (XEXP (x, 1)) == CONST_INT)
! 	validate_change (object, loc, plus_constant (XEXP (x, 0),
! 						     INTVAL (XEXP (x, 1))),
  			 1);
!       break;
  
      case MINUS:
!       if (GET_CODE (XEXP (x, 1)) == CONST_INT)
! 	validate_change (object, loc,
! 			 plus_constant (XEXP (x, 0), - INTVAL (XEXP (x, 1))),
! 			 1);
        break;
        
      case ZERO_EXTEND:
*************** validate_replace_rtx_1 (loc, from, to, o
*** 479,583 ****
        /* In these cases, the operation to be performed depends on the mode
  	 of the operand.  If we are replacing the operand with a VOIDmode
  	 constant, we lose the information.  So try to simplify the operation
! 	 in that case.  If it fails, substitute in something that we know
! 	 won't be recognized.  */
!       if (GET_MODE (to) == VOIDmode
! 	  && rtx_equal_p (XEXP (x, 0), from))
  	{
! 	  rtx new = simplify_unary_operation (code, GET_MODE (x), to,
! 					      GET_MODE (from));
  	  if (new == 0)
! 	    new = gen_rtx_CLOBBER (GET_MODE (x), const0_rtx);
  
  	  validate_change (object, loc, new, 1);
- 	  return;
  	}
        break;
  	
      case SUBREG:
!       /* In case we are replacing by constant, attempt to simplify it to non-SUBREG
!          expression.  We can't do this later, since the information about inner mode
!          may be lost.  */
!       if (CONSTANT_P (to) && rtx_equal_p (SUBREG_REG (x), from))
!         {
! 	  if (GET_MODE_SIZE (GET_MODE (x)) == UNITS_PER_WORD
! 	      && GET_MODE_SIZE (GET_MODE (from)) > UNITS_PER_WORD
! 	      && GET_MODE_CLASS (GET_MODE (x)) == MODE_INT)
! 	    {
! 	      rtx temp = operand_subword (to, SUBREG_WORD (x),
! 					  0, GET_MODE (from));
! 	      if (temp)
! 		{
! 		  validate_change (object, loc, temp, 1);
! 		  return;
! 		}
! 	    }
! 	  if (subreg_lowpart_p (x))
! 	    {
! 	      rtx new =  gen_lowpart_if_possible (GET_MODE (x), to);
! 	      if (new)
! 		{
! 		  validate_change (object, loc, new, 1);
! 		  return;
! 		}
! 	    }
! 
! 	  /* A paradoxical SUBREG of a VOIDmode constant is the same constant,
! 	     since we are saying that the high bits don't matter.  */
! 	  if (GET_MODE (to) == VOIDmode
! 	      && GET_MODE_SIZE (GET_MODE (x)) > GET_MODE_SIZE (GET_MODE (from)))
! 	    {
! 	      validate_change (object, loc, to, 1);
! 	      return;
! 	    }
!         }
! 
!       /* Changing mode twice with SUBREG => just change it once,
! 	 or not at all if changing back to starting mode.  */
!       if (GET_CODE (to) == SUBREG
! 	  && rtx_equal_p (SUBREG_REG (x), from))
! 	{
! 	  if (GET_MODE (x) == GET_MODE (SUBREG_REG (to))
! 	      && SUBREG_WORD (x) == 0 && SUBREG_WORD (to) == 0)
! 	    {
! 	      validate_change (object, loc, SUBREG_REG (to), 1);
! 	      return;
! 	    }
! 
! 	  validate_change (object, loc,
! 			   gen_rtx_SUBREG (GET_MODE (x), SUBREG_REG (to),
! 					   SUBREG_WORD (x) + SUBREG_WORD (to)), 1);
! 	  return;
! 	}
! 
!       /* If we have a SUBREG of a register that we are replacing and we are
! 	 replacing it with a MEM, make a new MEM and try replacing the
! 	 SUBREG with it.  Don't do this if the MEM has a mode-dependent address
! 	 or if we would be widening it.  */
! 
!       if (GET_CODE (from) == REG
! 	  && GET_CODE (to) == MEM
! 	  && rtx_equal_p (SUBREG_REG (x), from)
! 	  && ! mode_dependent_address_p (XEXP (to, 0))
! 	  && ! MEM_VOLATILE_P (to)
! 	  && GET_MODE_SIZE (GET_MODE (x)) <= GET_MODE_SIZE (GET_MODE (to)))
! 	{
! 	  int offset = SUBREG_WORD (x) * UNITS_PER_WORD;
! 	  enum machine_mode mode = GET_MODE (x);
! 	  rtx new;
! 
! 	  if (BYTES_BIG_ENDIAN)
! 	    offset += (MIN (UNITS_PER_WORD,
! 			    GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))
! 		       - MIN (UNITS_PER_WORD, GET_MODE_SIZE (mode)));
! 
! 	  new = gen_rtx_MEM (mode, plus_constant (XEXP (to, 0), offset));
! 	  MEM_COPY_ATTRIBUTES (new, to);
  	  validate_change (object, loc, new, 1);
! 	  return;
! 	}
        break;
- 
      case ZERO_EXTRACT:
      case SIGN_EXTRACT:
        /* If we are replacing a register with memory, try to change the memory
--- 488,522 ----
        /* In these cases, the operation to be performed depends on the mode
  	 of the operand.  If we are replacing the operand with a VOIDmode
  	 constant, we lose the information.  So try to simplify the operation
! 	 in that case.  */
!       if (GET_MODE (XEXP (x, 0)) == VOIDmode)
  	{
! 	  rtx new = simplify_unary_operation (code, GET_MODE (x),
! 					      XEXP (x, 0), op0_mode);
! 	  if (op0_mode == VOIDmode)
! 	    abort();
! 	  /* We used to replace the expression by CLOBBER and expect that it
! 	     will be refused.  In case this code is really needed, we will
! 	     need to develop new way to signalize that replace_rtx failed,
! 	     since the refusal won't happen on changes in REG_EQUAL notes
! 	     used by gcse.  */
  	  if (new == 0)
! 	    abort();
  
  	  validate_change (object, loc, new, 1);
  	}
        break;
  	
      case SUBREG:
!       {
! 	rtx new = simplify_subreg (GET_MODE (x), op0_mode,
! 				   SUBREG_WORD (x), SUBREG_REG (x));
! 	if (new)
  	  validate_change (object, loc, new, 1);
! 	else if (GET_MODE (SUBREG_REG (x)) == VOIDmode)
! 	  abort ();
!       }
        break;
      case ZERO_EXTRACT:
      case SIGN_EXTRACT:
        /* If we are replacing a register with memory, try to change the memory
*************** validate_replace_rtx_1 (loc, from, to, o
*** 585,596 ****
  	 likely to be an insertion operation; if it was, nothing bad will
  	 happen, we might just fail in some cases).  */
  
!       if (GET_CODE (from) == REG && GET_CODE (to) == MEM
  	  && rtx_equal_p (XEXP (x, 0), from)
  	  && GET_CODE (XEXP (x, 1)) == CONST_INT
  	  && GET_CODE (XEXP (x, 2)) == CONST_INT
! 	  && ! mode_dependent_address_p (XEXP (to, 0))
! 	  && ! MEM_VOLATILE_P (to))
  	{
  	  enum machine_mode wanted_mode = VOIDmode;
  	  enum machine_mode is_mode = GET_MODE (to);
--- 524,535 ----
  	 likely to be an insertion operation; if it was, nothing bad will
  	 happen, we might just fail in some cases).  */
  
!       if (GET_CODE (XEXP (x, 0)) == MEM
  	  && rtx_equal_p (XEXP (x, 0), from)
  	  && GET_CODE (XEXP (x, 1)) == CONST_INT
  	  && GET_CODE (XEXP (x, 2)) == CONST_INT
! 	  && ! mode_dependent_address_p (XEXP (XEXP (x, 0), 0))
! 	  && ! MEM_VOLATILE_P (XEXP (x, 0)))
  	{
  	  enum machine_mode wanted_mode = VOIDmode;
  	  enum machine_mode is_mode = GET_MODE (to);
*************** validate_replace_rtx_1 (loc, from, to, o
*** 629,635 ****
  	      pos %= GET_MODE_BITSIZE (wanted_mode);
  
  	      newmem = gen_rtx_MEM (wanted_mode,
! 				    plus_constant (XEXP (to, 0), offset));
  	      MEM_COPY_ATTRIBUTES (newmem, to);
  
  	      validate_change (object, &XEXP (x, 2), GEN_INT (pos), 1);
--- 568,574 ----
  	      pos %= GET_MODE_BITSIZE (wanted_mode);
  
  	      newmem = gen_rtx_MEM (wanted_mode,
! 				    plus_constant (XEXP (XEXP (x, 0), 0), offset));
  	      MEM_COPY_ATTRIBUTES (newmem, to);
  
  	      validate_change (object, &XEXP (x, 2), GEN_INT (pos), 1);
*************** validate_replace_rtx_1 (loc, from, to, o
*** 638,662 ****
  	}
  
        break;
!       
      default:
        break;
      }
        
-   /* For commutative or comparison operations we've already performed
-      replacements.  Don't try to perform them again.  */
-   if (GET_RTX_CLASS (code) != '<' && GET_RTX_CLASS (code) != 'c')
-     {
-       fmt = GET_RTX_FORMAT (code);
-       for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
-         {
-           if (fmt[i] == 'e')
-             validate_replace_rtx_1 (&XEXP (x, i), from, to, object);
-           else if (fmt[i] == 'E')
-             for (j = XVECLEN (x, i) - 1; j >= 0; j--)
-               validate_replace_rtx_1 (&XVECEXP (x, i, j), from, to, object);
-         }
-     }
  }
  
  /* Try replacing every occurrence of FROM in subexpression LOC of INSN
--- 577,601 ----
  	}
  
        break;
! 
      default:
+       /* We need to take care for simplifying the comparisons.  In case we replace
+          both operands by VOIDmode constants, the information about the rtx type is
+          lost.  */
+       if (GET_RTX_CLASS (code) == '<'
+ 	  && GET_MODE (XEXP (x, 0)) == VOIDmode
+ 	  && GET_MODE (XEXP (x, 1)) == VOIDmode)
+ 	{
+ 	  rtx y;
+ 	  y = simplify_relational_operation (code, op0_mode,  XEXP (x, 0), XEXP (x, 1));
+ 	  if (y)
+ 	    validate_change (object, loc, y, 1);
+ 	  else
+ 	    abort();
+ 	}
        break;
      }
        
  }
  
  /* Try replacing every occurrence of FROM in subexpression LOC of INSN
Index: egcs/gcc//reload.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/reload.c,v
retrieving revision 1.130
Index: egcs/gcc//rtl.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/rtl.h,v
retrieving revision 1.226
diff -c -3 -p -r1.226 rtl.h
*** rtl.h	2000/09/29 11:24:12	1.226
--- rtl.h	2000/10/03 07:33:48
*************** extern rtx simplify_relational_operation
*** 1301,1306 ****
--- 1301,1307 ----
  extern rtx simplify_gen_binary		PARAMS ((enum rtx_code, enum machine_mode,
  					       rtx, rtx));
  extern rtx simplify_rtx			PARAMS ((rtx));
+ extern rtx simplify_subreg 		PARAMS ((enum machine_mode, enum machine_mode, int, rtx));
  
  /* In optabs.c  */
  extern rtx gen_move_insn		PARAMS ((rtx, rtx));
Index: egcs/gcc//simplify-rtx.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/simplify-rtx.c,v
retrieving revision 1.28
diff -c -3 -p -r1.28 simplify-rtx.c
*** simplify-rtx.c	2000/09/18 18:24:32	1.28
--- simplify-rtx.c	2000/10/03 07:33:49
*************** simplify_ternary_operation (code, mode, 
*** 2040,2045 ****
--- 2061,2152 ----
  
    return 0;
  }
+ 
+ /* Simplify SUBREG of outer mode OUT_MODE, inner mode IN_MODE
+    and SUBREG_WORD WORD and SUBREG_REG EXP.  */
+ rtx
+ simplify_subreg (out_mode, in_mode, word, exp)
+    enum machine_mode out_mode;
+    enum machine_mode in_mode;
+    int word;
+    rtx exp;
+ {
+   if (out_mode == VOIDmode)
+     abort ();
+   if (in_mode == VOIDmode)
+     abort ();
+   if (GET_MODE (exp) != VOIDmode && GET_MODE (exp) != in_mode)
+     abort ();
+   if (GET_MODE_SIZE (out_mode) == UNITS_PER_WORD
+       && GET_MODE_SIZE (in_mode) > UNITS_PER_WORD
+       && GET_MODE_CLASS (out_mode) == MODE_INT)
+     {
+       rtx temp = operand_subword (exp, word,
+ 				  0, in_mode);
+       if (temp)
+ 	return temp;
+     }
+   /* Equivalent to subreg_lowpart_p.  */
+   if ((WORDS_BIG_ENDIAN
+        && GET_MODE_SIZE (in_mode) > UNITS_PER_WORD)
+       ? (word
+ 	 == ((GET_MODE_SIZE (in_mode)
+ 	      - MAX (GET_MODE_SIZE (in_mode), UNITS_PER_WORD))
+ 	     / UNITS_PER_WORD))
+       : word == 0)
+     {
+       rtx new = gen_lowpart_if_possible (out_mode, exp);
+       if (new)
+ 	return new;
+     }
+ 
+   /* A paradoxical SUBREG of a VOIDmode constant is the same constant,
+      since we are saying that the high bits don't matter.  */
+   if (GET_MODE (exp) == VOIDmode
+       && GET_MODE_SIZE (out_mode) > GET_MODE_SIZE (in_mode))
+     return exp;
+ 
+   /* Changing mode twice with SUBREG => just change it once,
+      or not at all if changing back to starting mode.  */
+   if (GET_CODE (exp) == SUBREG)
+     {
+       if (out_mode == GET_MODE (SUBREG_REG (exp))
+ 	  && word == 0 && SUBREG_WORD (exp) == 0)
+ 	{
+ 	  return (SUBREG_REG (exp));
+ 	}
+ 
+       return gen_rtx_SUBREG (out_mode, SUBREG_REG (exp),
+ 			     word + SUBREG_WORD (exp));
+     }
+ 
+   /* If we have a SUBREG of a register that we are replacing and we are
+      replacing it with a MEM, make a new MEM and try replacing the
+      SUBREG with it.  Don't do this if the MEM has a mode-dependent address
+      or if we would be widening it.  */
+ 
+   if (GET_CODE (exp) == MEM
+       && !mode_dependent_address_p (XEXP (exp, 0))
+       && !MEM_VOLATILE_P (exp)
+       && GET_MODE_SIZE (out_mode) <= GET_MODE_SIZE (in_mode))
+     {
+       int offset = word * UNITS_PER_WORD;
+       enum machine_mode mode = in_mode;
+       rtx new;
+ 
+       if (BYTES_BIG_ENDIAN)
+ 	offset += (MIN (UNITS_PER_WORD,
+ 			GET_MODE_SIZE (GET_MODE (exp)))
+ 		   - MIN (UNITS_PER_WORD, GET_MODE_SIZE (mode)));
+ 
+       new =
+ 	gen_rtx_MEM (mode, plus_constant (XEXP (exp, 0), offset));
+       MEM_COPY_ATTRIBUTES (new, exp);
+       return new;
+     }
+   return NULL;
+ }
+ 
  
  /* Simplify X, an rtx expression.
  


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