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]
Other format: [Raw text]

[PATCH] Cleanup fold_rtx, 1/n


This patch removes an unnecessary optimization in fold_rtx_subreg, that
is (quoting a comment) "folding arithmetic in narrow modes when the
machine only supports word-sized arithmetic".  But the only relevant
arithmetic optimizations that CSE performs are on multi-word values,
and tree optimizers take care of the rest: indeed this part of the code
does not trigger anymore.  I tested this claim by building an i686->alpha
cross with 4.0 as the system compiler, and looking at code coverage traces
(attached to PR17921).

After doing so, the only simplifications that remain in fold_rtx_subreg
try to fold the SUBREG_REG and:

1) call simplify_subreg

2) find a SUBREG whose REG results from a zero extension and try to fold
it to zero (see PR13724).

fold_rtx already has code to look at the arguments, fold them and perform
further simplifications.  It is possible to move these two cases there,
which makes the code more readable.

This patch includes another cleanup.  The top switch statement in fold_rtx
can do two things: 1) simplify X, 2) simplify X and return it.  This patch
splits this into two switch statements: the first performs simplifications,
the second checks whether folding the arguments is useful.

BTW, the NOT and NEG transforms will never happen but I'm leaving them
in for now because they are cheap.  Would it be ok to remove them?

Bootstrapped i686-pc-linux-gnu (all languages except Ada which is broken
now), regtests in progress. I will bootstrap/regtest it on powerpc-apple-darwin
tomorrow. Ok for mainline?


Paolo

2005-04-13  Paolo Bonzini  <bonzini@gnu.org>

	* cse.c (fold_rtx_subreg): Remove parts that try to fold
	SUBREG_REG (x) and look at the result.  Remove insn parameter.
	(fold_rtx): Use a separate switch statement to perform
	CSE-specific simplifications.  Try calling simplify_subreg
	after folding a SUBREG, and also simplifying (subreg (reg))
	if (reg) is equivalent to a ZERO_EXTEND.

Index: cse.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cse.c,v
retrieving revision 1.353
diff -u -r1.353 cse.c
--- cse.c	6 Apr 2005 17:04:59 -0000	1.353
+++ cse.c	13 Apr 2005 14:17:03 -0000
@@ -3231,11 +3231,9 @@
 /* Fold SUBREG.  */
 
 static rtx
-fold_rtx_subreg (rtx x, rtx insn)
+fold_rtx_subreg (rtx x)
 {
   enum machine_mode mode = GET_MODE (x);
-  rtx folded_arg0;
-  rtx const_arg0;
   rtx new;
 
   /* See if we previously assigned a constant value to this SUBREG.  */
@@ -3271,157 +3269,6 @@
 		&& exp_equiv_p (elt->exp, elt->exp, 1, false))
 	      return copy_rtx (SUBREG_REG (elt->exp));
 	  }
-
-      return x;
-    }
-
-  /* Fold SUBREG_REG.  If it changed, see if we can simplify the
-     SUBREG.  We might be able to if the SUBREG is extracting a single
-     word in an integral mode or extracting the low part.  */
-
-  folded_arg0 = fold_rtx (SUBREG_REG (x), insn);
-  const_arg0 = equiv_constant (folded_arg0);
-  if (const_arg0)
-    folded_arg0 = const_arg0;
-
-  if (folded_arg0 != SUBREG_REG (x))
-    {
-      new = simplify_subreg (mode, folded_arg0,
-			     GET_MODE (SUBREG_REG (x)), SUBREG_BYTE (x));
-      if (new)
-	return new;
-    }
-
-  if (REG_P (folded_arg0)
-      && GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (folded_arg0)))
-    {
-      struct table_elt *elt;
-
-      elt = lookup (folded_arg0,
-		    HASH (folded_arg0, GET_MODE (folded_arg0)),
-		    GET_MODE (folded_arg0));
-
-      if (elt)
-	elt = elt->first_same_value;
-
-      if (subreg_lowpart_p (x))
-	/* If this is a narrowing SUBREG and our operand is a REG, see
-	   if we can find an equivalence for REG that is an arithmetic
-	   operation in a wider mode where both operands are
-	   paradoxical SUBREGs from objects of our result mode.  In
-	   that case, we couldn-t report an equivalent value for that
-	   operation, since we don't know what the extra bits will be.
-	   But we can find an equivalence for this SUBREG by folding
-	   that operation in the narrow mode.  This allows us to fold
-	   arithmetic in narrow modes when the machine only supports
-	   word-sized arithmetic.
-
-	   Also look for a case where we have a SUBREG whose operand
-	   is the same as our result.  If both modes are smaller than
-	   a word, we are simply interpreting a register in different
-	   modes and we can use the inner value.  */
-
-	for (; elt; elt = elt->next_same_value)
-	  {
-	    enum rtx_code eltcode = GET_CODE (elt->exp);
-
-	    /* Just check for unary and binary operations.  */
-	    if (UNARY_P (elt->exp)
-		&& eltcode != SIGN_EXTEND
-		&& eltcode != ZERO_EXTEND
-		&& GET_CODE (XEXP (elt->exp, 0)) == SUBREG
-		&& GET_MODE (SUBREG_REG (XEXP (elt->exp, 0))) == mode
-		&& (GET_MODE_CLASS (mode)
-		    == GET_MODE_CLASS (GET_MODE (XEXP (elt->exp, 0)))))
-	      {
-		rtx op0 = SUBREG_REG (XEXP (elt->exp, 0));
-
-		if (!REG_P (op0) && ! CONSTANT_P (op0))
-		  op0 = fold_rtx (op0, NULL_RTX);
-
-		op0 = equiv_constant (op0);
-		if (op0)
-		  new = simplify_unary_operation (GET_CODE (elt->exp), mode,
-						  op0, mode);
-	      }
-	    else if (ARITHMETIC_P (elt->exp)
-		     && eltcode != DIV && eltcode != MOD
-		     && eltcode != UDIV && eltcode != UMOD
-		     && eltcode != ASHIFTRT && eltcode != LSHIFTRT
-		     && eltcode != ROTATE && eltcode != ROTATERT
-		     && ((GET_CODE (XEXP (elt->exp, 0)) == SUBREG
-			  && (GET_MODE (SUBREG_REG (XEXP (elt->exp, 0)))
-			      == mode))
-			 || CONSTANT_P (XEXP (elt->exp, 0)))
-		     && ((GET_CODE (XEXP (elt->exp, 1)) == SUBREG
-			  && (GET_MODE (SUBREG_REG (XEXP (elt->exp, 1)))
-			      == mode))
-			 || CONSTANT_P (XEXP (elt->exp, 1))))
-	      {
-		rtx op0 = gen_lowpart_common (mode, XEXP (elt->exp, 0));
-		rtx op1 = gen_lowpart_common (mode, XEXP (elt->exp, 1));
-
-		if (op0 && !REG_P (op0) && ! CONSTANT_P (op0))
-		  op0 = fold_rtx (op0, NULL_RTX);
-
-		if (op0)
-		  op0 = equiv_constant (op0);
-
-		if (op1 && !REG_P (op1) && ! CONSTANT_P (op1))
-		  op1 = fold_rtx (op1, NULL_RTX);
-
-		if (op1)
-		  op1 = equiv_constant (op1);
-
-		/* If we are looking for the low SImode part of
-		   (ashift:DI c (const_int 32)), it doesn't work to
-		   compute that in SImode, because a 32-bit shift in
-		   SImode is unpredictable.  We know the value is
-		   0.  */
-		if (op0 && op1
-		    && GET_CODE (elt->exp) == ASHIFT
-		    && GET_CODE (op1) == CONST_INT
-		    && INTVAL (op1) >= GET_MODE_BITSIZE (mode))
-		  {
-		    if (INTVAL (op1)
-			< GET_MODE_BITSIZE (GET_MODE (elt->exp)))
-		      /* If the count fits in the inner mode's width,
-			 but exceeds the outer mode's width, the value
-			 will get truncated to 0 by the subreg.  */
-		      new = CONST0_RTX (mode);
-		    else
-		      /* If the count exceeds even the inner mode's width,
-			 don't fold this expression.  */
-		      new = 0;
-		  }
-		else if (op0 && op1)
-		  new = simplify_binary_operation (GET_CODE (elt->exp),
-						   mode, op0, op1);
-	      }
-
-	    else if (GET_CODE (elt->exp) == SUBREG
-		     && GET_MODE (SUBREG_REG (elt->exp)) == mode
-		     && (GET_MODE_SIZE (GET_MODE (folded_arg0))
-			 <= UNITS_PER_WORD)
-		     && exp_equiv_p (elt->exp, elt->exp, 1, false))
-	      new = copy_rtx (SUBREG_REG (elt->exp));
-
-	    if (new)
-	      return new;
-	  }
-      else
-	/* A SUBREG resulting from a zero extension may fold to zero
-	   if it extracts higher bits than the ZERO_EXTEND's source
-	   bits.  FIXME: if combine tried to, er, combine these
-	   instructions, this transformation may be moved to
-	   simplify_subreg.  */
-	for (; elt; elt = elt->next_same_value)
-	  {
-	    if (GET_CODE (elt->exp) == ZERO_EXTEND
-		&& subreg_lsb (x)
-		>= GET_MODE_BITSIZE (GET_MODE (XEXP (elt->exp, 0))))
-	      return CONST0_RTX (mode);
-	  }
     }
 
   return x;
@@ -3631,7 +3478,41 @@
   if (x == 0)
     return x;
 
-  mode = GET_MODE (x);
+  /* Try to perform some initial simplifications on X.  */
+  code = GET_CODE (x);
+  switch (code)
+    {
+    case SUBREG:
+      x = fold_rtx_subreg (x);
+      break;
+
+    case NOT:
+    case NEG:
+      /* If we have (NOT Y), see if Y is known to be (NOT Z).
+	 If so, (NOT Y) simplifies to Z.  Similarly for NEG.  */
+      new = lookup_as_function (XEXP (x, 0), code);
+      if (new)
+	x = copy_rtx (XEXP (new, 0));
+      break;
+
+    case MEM:
+      x = fold_rtx_mem (x, insn);
+      break;
+
+    case ASM_OPERANDS:
+      if (insn)
+	{
+	  for (i = ASM_OPERANDS_INPUT_LENGTH (x) - 1; i >= 0; i--)
+	    validate_change (insn, &ASM_OPERANDS_INPUT (x, i),
+			     fold_rtx (ASM_OPERANDS_INPUT (x, i), insn), 0);
+	}
+      break;
+
+    default:
+      break;
+    }
+  
+  /* See if x got simplified enough.  */
   code = GET_CODE (x);
   switch (code)
     {
@@ -3642,6 +3523,8 @@
     case SYMBOL_REF:
     case LABEL_REF:
     case REG:
+    case MEM:
+    case ASM_OPERANDS:
     case PC:
       /* No use simplifying an EXPR_LIST
 	 since they are used only for lists of args
@@ -3654,21 +3537,6 @@
       return prev_insn_cc0;
 #endif
 
-    case SUBREG:
-      return fold_rtx_subreg (x, insn);
-
-    case NOT:
-    case NEG:
-      /* If we have (NOT Y), see if Y is known to be (NOT Z).
-	 If so, (NOT Y) simplifies to Z.  Similarly for NEG.  */
-      new = lookup_as_function (XEXP (x, 0), code);
-      if (new)
-	return fold_rtx (copy_rtx (XEXP (new, 0)), insn);
-      break;
-
-    case MEM:
-      return fold_rtx_mem (x, insn);
-
 #ifdef NO_FUNCTION_CSE
     case CALL:
       if (CONSTANT_P (XEXP (XEXP (x, 0), 0)))
@@ -3676,19 +3544,11 @@
       break;
 #endif
 
-    case ASM_OPERANDS:
-      if (insn)
-	{
-	  for (i = ASM_OPERANDS_INPUT_LENGTH (x) - 1; i >= 0; i--)
-	    validate_change (insn, &ASM_OPERANDS_INPUT (x, i),
-			     fold_rtx (ASM_OPERANDS_INPUT (x, i), insn), 0);
-	}
-      break;
-
     default:
       break;
     }
 
+  mode = GET_MODE (x);
   const_arg0 = 0;
   const_arg1 = 0;
   const_arg2 = 0;
@@ -3847,14 +3717,6 @@
 	  }
       }
 
-    else
-      {
-	if (fmt[i] == 'E')
-	  /* Don't try to fold inside of a vector of expressions.
-	     Doing nothing is harmless.  */
-	  {;}
-      }
-
   /* If a commutative operation, place a constant integer as the second
      operand unless the first operand is also a constant integer.  Otherwise,
      place any constant second unless the first operand is also a constant.  */
@@ -4310,6 +4172,27 @@
 					const_arg2 ? const_arg2 : XEXP (x, 2));
       break;
 
+    case RTX_EXTRA:
+      if (GET_CODE (x) == SUBREG)
+	{
+	  rtx tem;
+          new = simplify_subreg (mode, const_arg0 ? const_arg0 : folded_arg0,
+			         mode_arg0, SUBREG_BYTE (x));
+
+          /* A SUBREG resulting from a zero extension may fold to zero
+             if it extracts higher bits than the ZERO_EXTEND's source
+	     bits.  */
+          if (!new
+	      && REG_P (folded_arg0)
+              && GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (folded_arg0))
+	      && !subreg_lowpart_p (x)
+	      && (tem = lookup_as_function (folded_arg0, ZERO_EXTEND))
+		 != NULL_RTX
+	      && subreg_lsb (x) >= GET_MODE_BITSIZE (GET_MODE (XEXP (tem, 0))))
+	    new = CONST0_RTX (mode);
+	}
+      break;
+
     default:
       break;
     }

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