re PR middle-end/18041 (OR of two single-bit bitfields is inefficient)
authorRichard Biener <rguenther@suse.de>
Tue, 6 Nov 2018 08:09:03 +0000 (08:09 +0000)
committerRichard Biener <rguenth@gcc.gnu.org>
Tue, 6 Nov 2018 08:09:03 +0000 (08:09 +0000)
2018-11-06  Richard Biener  <rguenther@suse.de>

PR middle-end/18041
* simplify-rtx.c (simplify_binary_operation_1): Add pattern
matching bitfield insertion.

* gcc.target/i386/pr18041-1.c: New testcase.
* gcc.target/i386/pr18041-2.c: Likewise.

From-SVN: r265829

gcc/ChangeLog
gcc/simplify-rtx.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/i386/pr18041-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/pr18041-2.c [new file with mode: 0644]

index 2c5abd3..b4b36e0 100644 (file)
@@ -1,3 +1,9 @@
+2018-11-06  Richard Biener  <rguenther@suse.de>
+
+       PR middle-end/18041
+       * simplify-rtx.c (simplify_binary_operation_1): Add pattern
+       matching bitfield insertion.
+
 2018-11-06  Alexandre Oliva <aoliva@redhat.com>
 
        * auto-inc-dec.c: Include valtrack.h.  Improve comments.
index 2ff68ce..0d53135 100644 (file)
@@ -2857,6 +2857,38 @@ simplify_binary_operation_1 (enum rtx_code code, machine_mode mode,
                                        XEXP (op0, 1));
         }
 
+      /* The following happens with bitfield merging.
+         (X & C) | ((X | Y) & ~C) -> X | (Y & ~C) */
+      if (GET_CODE (op0) == AND
+         && GET_CODE (op1) == AND
+         && CONST_INT_P (XEXP (op0, 1))
+         && CONST_INT_P (XEXP (op1, 1))
+         && (INTVAL (XEXP (op0, 1))
+             == ~INTVAL (XEXP (op1, 1))))
+       {
+         /* The IOR may be on both sides.  */
+         rtx top0 = NULL_RTX, top1 = NULL_RTX;
+         if (GET_CODE (XEXP (op1, 0)) == IOR)
+           top0 = op0, top1 = op1;
+         else if (GET_CODE (XEXP (op0, 0)) == IOR)
+           top0 = op1, top1 = op0;
+         if (top0 && top1)
+           {
+             /* X may be on either side of the inner IOR.  */
+             rtx tem = NULL_RTX;
+             if (rtx_equal_p (XEXP (top0, 0),
+                              XEXP (XEXP (top1, 0), 0)))
+               tem = XEXP (XEXP (top1, 0), 1);
+             else if (rtx_equal_p (XEXP (top0, 0),
+                                   XEXP (XEXP (top1, 0), 1)))
+               tem = XEXP (XEXP (top1, 0), 0);
+             if (tem)
+               return simplify_gen_binary (IOR, mode, XEXP (top0, 0),
+                                           simplify_gen_binary
+                                             (AND, mode, tem, XEXP (top1, 1)));
+           }
+       }
+
       tem = simplify_byte_swapping_operation (code, mode, op0, op1);
       if (tem)
        return tem;
index 061fa46..0bfb80f 100644 (file)
@@ -1,3 +1,9 @@
+2018-11-06  Richard Biener  <rguenther@suse.de>
+
+       PR middle-end/18041
+       * gcc.target/i386/pr18041-1.c: New testcase.
+       * gcc.target/i386/pr18041-2.c: Likewise.
+
 2018-11-06 Wei Xiao <wei3.xiao@intel.com>
 
        * gcc.target/i386/avx-1.c: Update tests for VFIXUPIMM* intrinsics.
diff --git a/gcc/testsuite/gcc.target/i386/pr18041-1.c b/gcc/testsuite/gcc.target/i386/pr18041-1.c
new file mode 100644 (file)
index 0000000..24da41a
--- /dev/null
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+struct B { unsigned bit0 : 1; unsigned bit1 : 1; };
+
+void
+foo (struct B *b)
+{
+    b->bit0 = b->bit0 | b->bit1;
+}
+
+/* { dg-final { scan-assembler-times "and" 1 } } */
+/* { dg-final { scan-assembler-times "or" 1 } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr18041-2.c b/gcc/testsuite/gcc.target/i386/pr18041-2.c
new file mode 100644 (file)
index 0000000..00ebd2a
--- /dev/null
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+struct B { unsigned bit0 : 1; unsigned bit1 : 1; };
+
+void
+bar  (struct B *b, int x)
+{
+  b->bit0 |= x;
+}
+
+/* This fails to combine in 32bit mode but not for x32.  */
+/* { dg-final { scan-assembler-times "and" 1 { xfail { { ! x32 } && ilp32 } } } } */
+/* { dg-final { scan-assembler-times "or" 1 { xfail { { ! x32 } && ilp32 } } } } */