At -O1, a complemented XOR whose result is masked to bit zero is
currently emitted as:

        eor     w0, w0, w1
        ubfx    x0, x0, 0, 1
        eor     w0, w0, 1

Recognize (and (not (xor ...)) 1) and split it into a complemented
XOR followed by an AND, allowing the complemented XOR to use EON:

        eon     w0, w0, w1
        and     w0, w0, 1

Tested on aarch64-unknown-linux-gnu with no regressions.

gcc/ChangeLog:

        * config/aarch64/aarch64.md (*aarch64_xor_not_and_one): New
        define_insn_and_split.

gcc/testsuite/ChangeLog:

        * gcc.target/aarch64/xor-not-and-one.c: New test.

Signed-off-by: Shivam Gupta <[email protected]>
---
 gcc/config/aarch64/aarch64.md                 | 14 +++++++++++
 .../gcc.target/aarch64/xor-not-and-one.c      | 23 +++++++++++++++++++
 2 files changed, 37 insertions(+)
 create mode 100644 gcc/testsuite/gcc.target/aarch64/xor-not-and-one.c

diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md
index b2185c63819..1a61d7f85ca 100644
--- a/gcc/config/aarch64/aarch64.md
+++ b/gcc/config/aarch64/aarch64.md
@@ -5263,6 +5263,20 @@
 ;; Logical operations
 ;; -------------------------------------------------------------------
 
+(define_insn_and_split "*aarch64_xor_not_and_one<mode>"
+  [(set (match_operand:GPI 0 "register_operand" "=r")
+       (and:GPI
+         (not:GPI
+           (xor:GPI (match_operand:GPI 1 "register_operand" "r")
+                    (match_operand:GPI 2 "register_operand" "r")))
+         (const_int 1)))]
+  ""
+  "#"
+  "true"
+  [(set (match_dup 0)
+       (not:GPI (xor:GPI (match_dup 1) (match_dup 2))))
+   (set (match_dup 0)
+       (and:GPI (match_dup 0) (const_int 1)))])
 
 (define_insn_and_split "*aarch64_and<mode>_imm2"
   [(set (match_operand:GPI 0 "register_operand" "=rk")
diff --git a/gcc/testsuite/gcc.target/aarch64/xor-not-and-one.c 
b/gcc/testsuite/gcc.target/aarch64/xor-not-and-one.c
new file mode 100644
index 00000000000..090c1f9e5de
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/xor-not-and-one.c
@@ -0,0 +1,23 @@
+/* { dg-do compile } */
+/* { dg-options "-O1" } */
+
+typedef unsigned int u32;
+typedef unsigned long long u64;
+
+_Bool
+xor_eq_ne (u32 a, u32 b)
+{
+  u32 t1 = a & 1;
+  u32 t2 = b & 1;
+  return (t1 == 0) ^ (t2 != 0);
+}
+
+u64
+foo_di (u64 a, u64 b)
+{
+  return (~(a ^ b)) & 1;
+}
+
+/* { dg-final { scan-assembler-times {\teon\t} 2 } } */
+/* { dg-final { scan-assembler-times {\tand\t} 2 } } */
+/* { dg-final { scan-assembler-not {\tubfx\t} } } */
-- 
2.43.0

Reply via email to