More bitop simplifications in match.pd
authorMarc Glisse <marc.glisse@inria.fr>
Tue, 7 Nov 2017 11:08:06 +0000 (12:08 +0100)
committerMarc Glisse <glisse@gcc.gnu.org>
Tue, 7 Nov 2017 11:08:06 +0000 (11:08 +0000)
2017-11-07  Marc Glisse  <marc.glisse@inria.fr>

gcc/
* match.pd ((a&~b)|(a^b),(a&~b)^~a,(a|b)&~(a^b),a|~(a^b),
(a|b)|(a&^b),(a&b)|~(a^b),~(~a&b),~X^Y): New transformations.

gcc/testsuite/
* gcc.dg/tree-ssa/bitops-1.c: New file.

From-SVN: r254495

gcc/ChangeLog
gcc/match.pd
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/tree-ssa/bitops-1.c [new file with mode: 0644]

index d06fcee..bbb51e3 100644 (file)
@@ -1,5 +1,10 @@
 2017-11-07  Marc Glisse  <marc.glisse@inria.fr>
 
+       * match.pd ((a&~b)|(a^b),(a&~b)^~a,(a|b)&~(a^b),a|~(a^b),
+       (a|b)|(a&^b),(a&b)|~(a^b),~(~a&b),~X^Y): New transformations.
+
+2017-11-07  Marc Glisse  <marc.glisse@inria.fr>
+
        * fold-const.c (negate_expr_p) [PLUS_EXPR, MINUS_EXPR]: Handle
        non-scalar integral types.
        * match.pd (negate_expr_p): Handle MINUS_EXPR.
index 9113fd1..40ac5da 100644 (file)
@@ -685,6 +685,42 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
   (bit_ior:c (bit_xor:c @0 @1) @0)
   (bit_ior @0 @1))
 
+/* (a & ~b) | (a ^ b)  -->  a ^ b  */
+(simplify
+ (bit_ior:c (bit_and:c @0 (bit_not @1)) (bit_xor:c@2 @0 @1))
+ @2)
+
+/* (a & ~b) ^ ~a  -->  ~(a & b)  */
+(simplify
+ (bit_xor:c (bit_and:cs @0 (bit_not @1)) (bit_not @0))
+ (bit_not (bit_and @0 @1)))
+
+/* (a | b) & ~(a ^ b)  -->  a & b  */
+(simplify
+ (bit_and:c (bit_ior @0 @1) (bit_not (bit_xor:c @0 @1)))
+ (bit_and @0 @1))
+
+/* a | ~(a ^ b)  -->  a | ~b  */
+(simplify
+ (bit_ior:c @0 (bit_not:s (bit_xor:c @0 @1)))
+ (bit_ior @0 (bit_not @1)))
+
+/* (a | b) | (a &^ b)  -->  a | b  */
+(for op (bit_and bit_xor)
+ (simplify
+  (bit_ior:c (bit_ior@2 @0 @1) (op:c @0 @1))
+  @2))
+
+/* (a & b) | ~(a ^ b)  -->  ~(a ^ b)  */
+(simplify
+ (bit_ior:c (bit_and:c @0 @1) (bit_not@2 (bit_xor @0 @1)))
+ @2)
+
+/* ~(~a & b)  -->  a | ~b  */
+(simplify
+ (bit_not (bit_and:cs (bit_not @0) @1))
+ (bit_ior @0 (bit_not @1)))
+
 /* Simplify (~X & Y) to X ^ Y if we know that (X & ~Y) is 0.  */
 #if GIMPLE
 (simplify
@@ -1124,6 +1160,12 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
  (if (tree_nop_conversion_p (type, TREE_TYPE (@0)))
   (convert (bit_xor @0 @1))))
 
+/* Otherwise prefer ~(X ^ Y) to ~X ^ Y as more canonical.  */
+(simplify
+ (bit_xor:c (nop_convert:s (bit_not:s @0)) @1)
+ (if (tree_nop_conversion_p (type, TREE_TYPE (@0)))
+  (bit_not (bit_xor (view_convert @0) @1))))
+
 /* (x & ~m) | (y & m) -> ((x ^ y) & m) ^ x */
 (simplify
  (bit_ior:c (bit_and:cs @0 (bit_not @2)) (bit_and:cs @1 @2))
index 7f33b7c..bb0eb9b 100644 (file)
@@ -1,5 +1,9 @@
 2017-11-07  Marc Glisse  <marc.glisse@inria.fr>
 
+       * gcc.dg/tree-ssa/bitops-1.c: New file.
+
+2017-11-07  Marc Glisse  <marc.glisse@inria.fr>
+
        * gcc.dg/tree-ssa/negminus.c: New test.
 
 2017-11-06  Jeff Law  <law@redhat.com>
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/bitops-1.c b/gcc/testsuite/gcc.dg/tree-ssa/bitops-1.c
new file mode 100644 (file)
index 0000000..cf2823d
--- /dev/null
@@ -0,0 +1,72 @@
+/* { dg-do run } */
+/* { dg-options "-O -fdump-tree-optimized-raw" } */
+
+#define DECLS(n,VOL)                   \
+__attribute__((noinline,noclone))      \
+int f##n(int A,int B){                 \
+    VOL int C = A & ~B;                        \
+    VOL int D = A ^ B;                 \
+    return C | D;                      \
+}                                      \
+__attribute__((noinline,noclone))      \
+int g##n(int A,int B){                 \
+    VOL int C = A & ~B;                        \
+    return C ^ ~A;                     \
+}                                      \
+__attribute__((noinline,noclone))      \
+int h##n(int A,int B){                 \
+    VOL int C = A | B;                 \
+    VOL int D = A ^ B;                 \
+    return C & ~D;                     \
+}                                      \
+__attribute__((noinline,noclone))      \
+int i##n(int A,int B){                 \
+    VOL int C = A ^ B;                 \
+    return A | ~C;                     \
+}                                      \
+__attribute__((noinline,noclone))      \
+int J##n(int A,int B){                 \
+    VOL int C = A | B;                 \
+    VOL int D = A & B;                 \
+    return C | D;                      \
+}                                      \
+__attribute__((noinline,noclone))      \
+int k##n(int A,int B){                 \
+    VOL int C = A & B;                 \
+    VOL int D = A ^ B;                 \
+    return C | ~D;                     \
+}                                      \
+__attribute__((noinline,noclone))      \
+int l##n(int A,int B){                 \
+    VOL int C = A & ~B;                        \
+    return ~C;                         \
+}                                      \
+__attribute__((noinline,noclone))      \
+int m##n(int A,int B){                 \
+    VOL int C = A & B;                 \
+    VOL int D = A ^ B;                 \
+    return C ^ D;                      \
+}
+
+DECLS(0,)
+DECLS(1,volatile)
+
+int main(){
+    for(int A = 0; A <= 1; ++A)
+      for(int B = 0; B <= 1; ++B)
+       {
+         if (f0 (A, B) != f1 (A, B)) __builtin_abort();
+         if (g0 (A, B) != g1 (A, B)) __builtin_abort();
+         if (h0 (A, B) != h1 (A, B)) __builtin_abort();
+         if (i0 (A, B) != i1 (A, B)) __builtin_abort();
+         if (J0 (A, B) != J1 (A, B)) __builtin_abort();
+         if (k0 (A, B) != k1 (A, B)) __builtin_abort();
+         if (l0 (A, B) != l1 (A, B)) __builtin_abort();
+         if (m0 (A, B) != m1 (A, B)) __builtin_abort();
+       }
+}
+
+/* { dg-final { scan-tree-dump-times "bit_not_expr" 12 "optimized"} } */
+/* { dg-final { scan-tree-dump-times "bit_and_expr"  9 "optimized"} } */
+/* { dg-final { scan-tree-dump-times "bit_ior_expr" 10 "optimized"} } */
+/* { dg-final { scan-tree-dump-times "bit_xor_expr"  9 "optimized"} } */