[backport from gcc-4.7/trunk, supposed to improve code on ARMv6+ ] Date: Fri, 11 Mar 2011 22:14:34 +0800 From: Chung-Lin Tang Subject: [patch][4.7] Enhance XOR handling in simplify-rtx.c List-Archive: Hi, this patch adds a bit more sophistication to the handled xor RTX cases in foo(). This may look a bit ad hoc, but I am seeing it useful for some cases where we combine zero_extend with (not (shift ...)). The supplied ARM testcase demonstrates when 3-insn combining comes up with: (set (reg:SI 145) (xor:SI (and:SI (not:SI (reg/v:SI 135 [ crc ])) (const_int 32767 [0x7fff])) (const_int 65535 [0xffff]))) when it is actually equivalent to: (set (reg:SI 145) (ior:SI (reg/v:SI 135 [ x ]) (const_int 32768 [0x8000]))) This happens on ARM architecture levels v6 and above, due to its possession of real zero_extend instructions. On ARMv5 and earlier, the use of two shifts for zero extending actually helped to work around this, due to staged combining effects of optimizing the shifts away one by one... Cross-tested using QEMU for ARM-Linux, currently undergoing x86 bootstrapping and testing. If results are clear, is this okay for trunk when stage1 opens again? Thanks, Chung-Lin gcc/ 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. gcc/testsuite/ 2011-03-21 Chung-Lin Tang * gcc.target/arm/xor-and.c: New. --- gcc-4.6-20110318/gcc/simplify-rtx.c.~1~ 2010-11-30 17:36:19.000000000 +0100 +++ gcc-4.6-20110318/gcc/simplify-rtx.c 2011-03-21 16:48:19.000000000 +0100 @@ -2480,6 +2480,46 @@ simplify_binary_operation_1 (enum rtx_co 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 --- gcc-4.6-20110318/gcc/testsuite/gcc.target/arm/xor-and.c.~1~ 1970-01-01 01:00:00.000000000 +0100 +++ gcc-4.6-20110318/gcc/testsuite/gcc.target/arm/xor-and.c 2011-03-21 16:48:19.000000000 +0100 @@ -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" } } */