diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 8a1868b5324..7d3878107ef 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,8 @@ +2011-03-21 Chung-Lin Tang + + * simplify-rtx.c (simplify_binary_operation_1): Handle + (xor (and A B) C) case when B and C are both constants. + 2011-03-21 Mingjie Xing * tree-dfa.c (add_referenced_var): Fix typo in comment. diff --git a/gcc/simplify-rtx.c b/gcc/simplify-rtx.c index ce4eab45b92..4a8e3c61667 100644 --- a/gcc/simplify-rtx.c +++ b/gcc/simplify-rtx.c @@ -2480,6 +2480,46 @@ simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode, 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 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 259bcc0bab2..dbf0e213e39 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2011-03-21 Chung-Lin Tang + + * gcc.target/arm/xor-and.c: New. + 2010-03-21 Thomas Koenig PR fortran/22572 diff --git a/gcc/testsuite/gcc.target/arm/xor-and.c b/gcc/testsuite/gcc.target/arm/xor-and.c new file mode 100644 index 00000000000..4b0f79013fc --- /dev/null +++ b/gcc/testsuite/gcc.target/arm/xor-and.c @@ -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" } } */