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] Fix PR39715 (Thumb pessimization)


This patch fixes a bug in combine that originated PR39715.  While
the pessimization in the PR was introduced by the cond-optab merge,
the bug was latent.

In the PR test case, after the cond-optab merge, an unnecessary sign
extension is introduced.

As explained in the PR, the bug is in combine's attempt to widen
the operands of a comparison.  Combine incorrectly does this with a
paradoxical subreg; this however introduces undefined bits, so that
introducing the sign extension is actually correct.

With this patch, instead, a zero or sign extension is used.  With this
more precise information, simplify-rtx.c can be taught to strip the
extension.

Also, since in general an AND is (if it cannot be eliminated) cheaper
than a zero or sign extension, I moved the other optimization done in
this area of combine earlier.

Tested i686-pc-linux-gnu, plus on arm-elf I looked by hand at some
testcases to test the paths I modified, but building a combined
tree failed with an internal assembler error.

Paolo

2009-08-01  Paolo Bonzini  <bonzini@gnu.org>

	PR rtl-optimization/39715
	* combine.c (simplify_comparison): Use extensions to
	widen comparisons.  Try an ANDing first.
	* simplify-rtx.c (simplify_relational_operation_1):
	Look for useless extensions of a subreg, if the extension
	is from the same mode as the subreg.

2009-08-01  Paolo Bonzini  <bonzini@gnu.org>

	* gcc.target/arm/thumb-bitfld1.c: New.

Index: gcc/combine.c
===================================================================
--- gcc/combine.c	(branch cond-optab2)
+++ gcc/combine.c	(working copy)
@@ -11208,6 +11208,22 @@ simplify_comparison (enum rtx_code code,
 	{
 	  int zero_extended;
 
+	  /* If this is a test for negative, we can make an explicit
+	     test of the sign bit.  Test this first so we can use
+	     a paradoxical subreg to extend OP0.  */
+
+	  if (op1 == const0_rtx && (code == LT || code == GE)
+	      && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
+	    {
+	      op0 = simplify_gen_binary (AND, tmode,
+					 gen_lowpart (tmode, op0),
+					 GEN_INT ((HOST_WIDE_INT) 1
+						  << (GET_MODE_BITSIZE (mode)
+						      - 1)));
+	      code = (code == LT) ? NE : EQ;
+	      break;
+	    }
+
 	  /* If the only nonzero bits in OP0 and OP1 are those in the
 	     narrower mode and this is an equality or unsigned comparison,
 	     we can use the wider mode.  Similarly for sign-extended
@@ -11238,27 +11254,20 @@ simplify_comparison (enum rtx_code code,
 							XEXP (op0, 0)),
 					   gen_lowpart (tmode,
 							XEXP (op0, 1)));
-
-	      op0 = gen_lowpart (tmode, op0);
-	      if (zero_extended && CONST_INT_P (op1))
-		op1 = GEN_INT (INTVAL (op1) & GET_MODE_MASK (mode));
-	      op1 = gen_lowpart (tmode, op1);
-	      break;
-	    }
-
-	  /* If this is a test for negative, we can make an explicit
-	     test of the sign bit.  */
-
-	  if (op1 == const0_rtx && (code == LT || code == GE)
-	      && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
-	    {
-	      op0 = simplify_gen_binary (AND, tmode,
-					 gen_lowpart (tmode, op0),
-					 GEN_INT ((HOST_WIDE_INT) 1
-						  << (GET_MODE_BITSIZE (mode)
-						      - 1)));
-	      code = (code == LT) ? NE : EQ;
-	      break;
+	      else
+		{
+		  if (zero_extended)
+		    {
+		      op0 = simplify_gen_unary (ZERO_EXTEND, tmode, op0, mode);
+		      op1 = simplify_gen_unary (ZERO_EXTEND, tmode, op1, mode);
+		    }
+		  else
+		    {
+		      op0 = simplify_gen_unary (SIGN_EXTEND, tmode, op0, mode);
+		      op1 = simplify_gen_unary (SIGN_EXTEND, tmode, op1, mode);
+		    }
+		  break;
+		}
 	    }
 	}
Index: gcc/simplify-rtx.c
===================================================================
--- gcc/simplify-rtx.c	(branch cond-optab2)
+++ gcc/simplify-rtx.c	(working copy)
@@ -3990,6 +3990,49 @@ simplify_relational_operation_1 (enum rt
 				    simplify_gen_binary (XOR, cmp_mode,
 							 XEXP (op0, 1), op1));
 
+  /* Look for useless extensions of a subreg, if the extension
+     is from the same mode as the subreg.  */
+  if (op0code == SIGN_EXTEND
+      && GET_CODE (XEXP (op0, 0)) == SUBREG
+      && subreg_lowpart_p (XEXP (op0, 0))
+      && GET_MODE (op0) == GET_MODE (SUBREG_REG (XEXP (op0, 0)))
+      && num_sign_bit_copies (SUBREG_REG (XEXP (op0, 0)), GET_MODE (op0))
+         > (unsigned) (GET_MODE_BITSIZE (GET_MODE (op0))
+		       - GET_MODE_BITSIZE (GET_MODE (XEXP (op0, 0)))))
+    return simplify_gen_relational (code, mode, cmp_mode,
+				    SUBREG_REG (XEXP (op0, 0)), op1);
+    
+  if (GET_CODE (op1) == SIGN_EXTEND
+      && GET_CODE (XEXP (op1, 0)) == SUBREG
+      && subreg_lowpart_p (XEXP (op0, 0))
+      && GET_MODE (op1) == GET_MODE (SUBREG_REG (XEXP (op1, 0)))
+      && num_sign_bit_copies (SUBREG_REG (XEXP (op1, 0)), GET_MODE (op1))
+         > (unsigned) (GET_MODE_BITSIZE (GET_MODE (op1))
+		       - GET_MODE_BITSIZE (GET_MODE (XEXP (op1, 0)))))
+    return simplify_gen_relational (code, mode, cmp_mode,
+				    op0, SUBREG_REG (XEXP (op1, 0)));
+
+  if (code != LE && code != GE && code != LT && code != GT)
+    {
+      if (op0code == ZERO_EXTEND
+	  && GET_CODE (XEXP (op0, 0)) == SUBREG
+          && subreg_lowpart_p (XEXP (op0, 0))
+	  && GET_MODE (op0) == GET_MODE (SUBREG_REG (XEXP (op0, 0)))
+	  && (nonzero_bits (SUBREG_REG (XEXP (op0, 0)), GET_MODE (op0))
+	      & ~GET_MODE_MASK (GET_MODE (XEXP (op0, 0)))) == 0)
+	return simplify_gen_relational (code, mode, cmp_mode,
+					SUBREG_REG (XEXP (op0, 0)), op1);
+
+      if (GET_CODE (op1) == ZERO_EXTEND
+	  && GET_CODE (XEXP (op1, 0)) == SUBREG
+          && subreg_lowpart_p (XEXP (op0, 0))
+	  && GET_MODE (op1) == GET_MODE (SUBREG_REG (XEXP (op1, 0)))
+	  && (nonzero_bits (SUBREG_REG (XEXP (op1, 0)), GET_MODE (op1))
+	      & ~GET_MODE_MASK (GET_MODE (XEXP (op1, 0)))) == 0)
+	return simplify_gen_relational (code, mode, cmp_mode,
+					op0, SUBREG_REG (XEXP (op1, 0)));
+    }
+
   if (op0code == POPCOUNT && op1 == const0_rtx)
     switch (code)
       {


/* { dg-do compile } */
/* { dg-options "-O1 -mthumb -march=armv5t" }  */

struct foo
{
  unsigned b31 : 1;
  unsigned b30 : 1;
  unsigned b29 : 1;
  unsigned b28 : 1;
  unsigned rest : 28;
};
foo(a)
     struct foo a;
{
  return a.b30;
}

/* { dg-final { scan-assembler-times "lsl" 1 } } */
/* { dg-final { scan-assembler-times "lsr" 1 } } */


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