2011-06-02  Chung-Lin Tang  <cltang@codesourcery.com>

	Backport from mainline:

	2011-03-21  Chung-Lin Tang  <cltang@codesourcery.com>

	gcc/
	* simplify-rtx.c (simplify_binary_operation_1): Handle
	(xor (and A B) C) case when B and C are both constants.

	gcc/testsuite/
	* gcc.target/arm/xor-and.c: New.

	2011-03-18  Chung-Lin Tang  <cltang@codesourcery.com>

	gcc/
	* combine.c (try_combine): Do simplification only call of
	subst() on i2 even when i1 is present. Update comments.

	gcc/testsuite/
	* gcc.target/arm/unsigned-extend-1.c: New.

=== modified file 'gcc/combine.c'
--- old/gcc/combine.c	2011-05-06 11:28:27 +0000
+++ new/gcc/combine.c	2011-05-27 14:31:18 +0000
@@ -3089,7 +3089,7 @@
       /* It is possible that the source of I2 or I1 may be performing
 	 an unneeded operation, such as a ZERO_EXTEND of something
 	 that is known to have the high part zero.  Handle that case
-	 by letting subst look at the innermost one of them.
+	 by letting subst look at the inner insns.
 
 	 Another way to do this would be to have a function that tries
 	 to simplify a single insn instead of merging two or more
@@ -3114,11 +3114,9 @@
 	      subst_low_luid = DF_INSN_LUID (i1);
 	      i1src = subst (i1src, pc_rtx, pc_rtx, 0, 0, 0);
 	    }
-	  else
-	    {
-	      subst_low_luid = DF_INSN_LUID (i2);
-	      i2src = subst (i2src, pc_rtx, pc_rtx, 0, 0, 0);
-	    }
+
+	  subst_low_luid = DF_INSN_LUID (i2);
+	  i2src = subst (i2src, pc_rtx, pc_rtx, 0, 0, 0);
 	}
 
       n_occurrences = 0;		/* `subst' counts here */

=== modified file 'gcc/simplify-rtx.c'
--- old/gcc/simplify-rtx.c	2011-03-26 09:24:06 +0000
+++ new/gcc/simplify-rtx.c	2011-05-27 14:31:18 +0000
@@ -2484,6 +2484,46 @@
 							XEXP (op0, 1), mode),
 				    op1);
 
+      /* Given (xor (and A B) C), using P^Q == (~P&Q) | (~Q&P),
+	 we can transform like this:
+            (A&B)^C == ~(A&B)&C | ~C&(A&B)
+                    == (~A|~B)&C | ~C&(A&B)    * DeMorgan's Law
+                    == ~A&C | ~B&C | A&(~C&B)  * Distribute and re-order
+	 Attempt a few simplifications when B and C are both constants.  */
+      if (GET_CODE (op0) == AND
+	  && CONST_INT_P (op1)
+	  && CONST_INT_P (XEXP (op0, 1)))
+	{
+	  rtx a = XEXP (op0, 0);
+	  rtx b = XEXP (op0, 1);
+	  rtx c = op1;
+	  HOST_WIDE_INT bval = INTVAL (b);
+	  HOST_WIDE_INT cval = INTVAL (c);
+
+	  rtx na_c
+	    = simplify_binary_operation (AND, mode,
+					 simplify_gen_unary (NOT, mode, a, mode),
+					 c);
+	  if ((~cval & bval) == 0)
+	    {
+	      /* Try to simplify ~A&C | ~B&C.  */
+	      if (na_c != NULL_RTX)
+		return simplify_gen_binary (IOR, mode, na_c,
+					    GEN_INT (~bval & cval));
+	    }
+	  else
+	    {
+	      /* If ~A&C is zero, simplify A&(~C&B) | ~B&C.  */
+	      if (na_c == const0_rtx)
+		{
+		  rtx a_nc_b = simplify_gen_binary (AND, mode, a,
+						    GEN_INT (~cval & bval));
+		  return simplify_gen_binary (IOR, mode, a_nc_b,
+					      GEN_INT (~bval & cval));
+		}
+	    }
+	}
+
       /* (xor (comparison foo bar) (const_int 1)) can become the reversed
 	 comparison if STORE_FLAG_VALUE is 1.  */
       if (STORE_FLAG_VALUE == 1

=== added file 'gcc/testsuite/gcc.target/arm/unsigned-extend-1.c'
--- old/gcc/testsuite/gcc.target/arm/unsigned-extend-1.c	1970-01-01 00:00:00 +0000
+++ new/gcc/testsuite/gcc.target/arm/unsigned-extend-1.c	2011-05-27 14:31:18 +0000
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=armv6" } */
+
+unsigned char foo (unsigned char c)
+{
+  return (c >= '0') && (c <= '9');
+}
+
+/* { dg-final { scan-assembler-not "uxtb" } } */

=== added file 'gcc/testsuite/gcc.target/arm/xor-and.c'
--- old/gcc/testsuite/gcc.target/arm/xor-and.c	1970-01-01 00:00:00 +0000
+++ new/gcc/testsuite/gcc.target/arm/xor-and.c	2011-05-27 14:31:18 +0000
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-O -march=armv6" } */
+
+unsigned short foo (unsigned short x)
+{
+  x ^= 0x4002;
+  x >>= 1;
+  x |= 0x8000;
+  return x;
+}
+
+/* { dg-final { scan-assembler "orr" } } */
+/* { dg-final { scan-assembler-not "mvn" } } */
+/* { dg-final { scan-assembler-not "uxth" } } */

