simplify-rtx: Transform (xor (and (xor A B) C) B) with C const
authorSegher Boessenkool <segher@kernel.crashing.org>
Thu, 10 Nov 2016 00:32:43 +0000 (01:32 +0100)
committerSegher Boessenkool <segher@gcc.gnu.org>
Thu, 10 Nov 2016 00:32:43 +0000 (01:32 +0100)
match.pd transforms (A&C)|(B&~C) to ((A^B)&C)^B, which is fewer
operations if C is not const (and it is not on simple tests at least,
this transform is done very early already).

Various processors have "insert" instructions that can do this, but
combine cannot build those from the xor-and-xor, especially it has no
chance at all to do that if A or B or multiple instructions as well
(on PowerPC, the rl[wd]imi instructions can do this with together with
a rotate, or a simple shift with appropriate C; other ISAs have similar
insns).

This patch makes RTL simplify transform (xor (and (xor A B) C) B) back
to (ior (and A C) (and B ~C)) for constant C (and similar with A instead
of B for that last term).

* simplify-rtx.c (simplify_binary_operation_1): Simplify
(xor (and (xor A B) C) B) to (ior (and A C) (and B ~C)) and
(xor (and (xor A B) C) A) to (ior (and A ~C) (and B C)) if C
is a const_int.

From-SVN: r242031

gcc/ChangeLog
gcc/simplify-rtx.c

index edf734f..c9034e8 100644 (file)
@@ -1,3 +1,10 @@
+2016-11-09  Segher Boessenkool  <segher@kernel.crashing.org>
+
+       * simplify-rtx.c (simplify_binary_operation_1): Simplify
+       (xor (and (xor A B) C) B) to (ior (and A C) (and B ~C)) and
+       (xor (and (xor A B) C) A) to (ior (and A ~C) (and B C)) if C
+       is a const_int.
+
 2016-11-09  David Malcolm  <dmalcolm@redhat.com>
 
        * print-rtl-function.c: Include varasm.h.
index 5c3dea1..11a2e02 100644 (file)
@@ -2886,6 +2886,37 @@ simplify_binary_operation_1 (enum rtx_code code, machine_mode mode,
            }
        }
 
+      /* If we have (xor (and (xor A B) C) A) with C a constant we can instead
+        do (ior (and A ~C) (and B C)) which is a machine instruction on some
+        machines, and also has shorter instruction path length.  */
+      if (GET_CODE (op0) == AND
+         && GET_CODE (XEXP (op0, 0)) == XOR
+         && CONST_INT_P (XEXP (op0, 1))
+         && rtx_equal_p (XEXP (XEXP (op0, 0), 0), trueop1))
+       {
+         rtx a = trueop1;
+         rtx b = XEXP (XEXP (op0, 0), 1);
+         rtx c = XEXP (op0, 1);
+         rtx nc = simplify_gen_unary (NOT, mode, c, mode);
+         rtx a_nc = simplify_gen_binary (AND, mode, a, nc);
+         rtx bc = simplify_gen_binary (AND, mode, b, c);
+         return simplify_gen_binary (IOR, mode, a_nc, bc);
+       }
+      /* Similarly, (xor (and (xor A B) C) B) as (ior (and A C) (and B ~C))  */
+      else if (GET_CODE (op0) == AND
+         && GET_CODE (XEXP (op0, 0)) == XOR
+         && CONST_INT_P (XEXP (op0, 1))
+         && rtx_equal_p (XEXP (XEXP (op0, 0), 1), trueop1))
+       {
+         rtx a = XEXP (XEXP (op0, 0), 0);
+         rtx b = trueop1;
+         rtx c = XEXP (op0, 1);
+         rtx nc = simplify_gen_unary (NOT, mode, c, mode);
+         rtx b_nc = simplify_gen_binary (AND, mode, b, nc);
+         rtx ac = simplify_gen_binary (AND, mode, a, c);
+         return simplify_gen_binary (IOR, mode, ac, b_nc);
+       }
+
       /* (xor (comparison foo bar) (const_int 1)) can become the reversed
         comparison if STORE_FLAG_VALUE is 1.  */
       if (STORE_FLAG_VALUE == 1