PR64817's testcase creates a long chain of XOR of AND of XOR of AND of
that our rtl simplifiers can't simplify, although they are simplifyable.

combine manages to simplify the generated insns that perform the
computation represented by such chains, but simplify-rtx doesn't.
That's because combine notices that, after the first and with a
constant, some bits are necessarily zero, and so it can simplify
subsequent redundant insns.

simplify-rtx doesn't do that, though.  I suppose it could try to compute
the nonzero bits of its operands, but doing so would likely lead to
exponential behavior on the depth of the expression.

We can still simplify the expressions to a great extent, though: for
each sequence of xor of and of xor of whatever, with constant second
operands for each of the 3 operations, we can get rid of the innermost
xor by tweaking the operands of the outermost one.  We can also do that
if the intervening operation is an ior rather than an and, though with a
slightly different adjustment for the second operand of the outermost
xor.

With this patch, the huge rtl debug location expressions in the
testcases for pr64817 simplify just as well as combine manages to
simplify them.

I'm a bit surprised the gimple layer does not even attempt to simplify
them, but I didn't try to tackle that, since I was not even sure this
was a useful optimization.  After all, how often do we see xor of and of
xor of and of xor of... in the wild, rather than in pathological
testcases? :-)  But hey, at least the rtl simplification is cheap, so
why not?

Regstrapped on x86_64-linux-gnu and i686-pc-linux-gnu.  Ok to install?

for  gcc/ChangeLog

        * simplify-rtx.c (simplify_binary_operation_1): Simplify one
        of two XORs that have an intervening AND or IOR.
---
 gcc/simplify-rtx.c |   33 +++++++++++++++++++++++++++++++++
 1 file changed, 33 insertions(+)

diff --git a/gcc/simplify-rtx.c b/gcc/simplify-rtx.c
index bea9ec3..04452c6 100644
--- a/gcc/simplify-rtx.c
+++ b/gcc/simplify-rtx.c
@@ -2708,6 +2708,39 @@ simplify_binary_operation_1 (enum rtx_code code, 
machine_mode mode,
                                                        XEXP (op0, 1), mode),
                                    op1);
 
+      /* Given (xor (ior (xor A B) C) D), where B, C and D are
+        constants, simplify to (xor (ior A C) (B&~C)^D), canceling
+        out bits inverted twice and not set by C.  Similarly, given
+        (xor (and (xor A B) C) D), simplify without inverting C in
+        the xor operand: (xor (and A C) (B&C)^D).
+      */
+      else if ((GET_CODE (op0) == IOR || GET_CODE (op0) == AND)
+              && GET_CODE (XEXP (op0, 0)) == XOR
+              && CONST_INT_P (op1)
+              && CONST_INT_P (XEXP (op0, 1))
+              && CONST_INT_P (XEXP (XEXP (op0, 0), 1)))
+       {
+         enum rtx_code op = GET_CODE (op0);
+         rtx a = XEXP (XEXP (op0, 0), 0);
+         rtx b = XEXP (XEXP (op0, 0), 1);
+         rtx c = XEXP (op0, 1);
+         rtx d = op1;
+         HOST_WIDE_INT bval = INTVAL (b);
+         HOST_WIDE_INT cval = INTVAL (c);
+         HOST_WIDE_INT dval = INTVAL (d);
+         HOST_WIDE_INT xcval;
+
+         if (op == IOR)
+           xcval = cval;
+         else
+           xcval = ~cval;
+
+         return simplify_gen_binary (XOR, mode,
+                                     simplify_gen_binary (op, mode, a, c),
+                                     gen_int_mode ((bval & xcval) ^ dval,
+                                                   mode));
+       }
+
       /* 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)


-- 
Alexandre Oliva, freedom fighter    http://FSFLA.org/~lxoliva/
You must be the change you wish to see in the world. -- Gandhi
Be Free! -- http://FSFLA.org/   FSF Latin America board member
Free Software Evangelist|Red Hat Brasil GNU Toolchain Engineer

Reply via email to