i386: Additional peephole2 to use flags from CMPXCHG more [PR96189]
authorUros Bizjak <ubizjak@gmail.com>
Thu, 16 Jul 2020 18:11:43 +0000 (20:11 +0200)
committerUros Bizjak <ubizjak@gmail.com>
Thu, 16 Jul 2020 18:13:06 +0000 (20:13 +0200)
CMPXCHG instruction sets ZF flag if the values in the destination operand
and EAX register are equal; otherwise the ZF flag is cleared and value
from destination operand is loaded to EAX. Following assembly:

        xorl    %eax, %eax
        lock cmpxchgl   %edx, (%rdi)
        testl   %eax, %eax
        sete    %al

can be optimized by removing the unneeded comparison, since set ZF flag
signals that no update to EAX happened.  This patch adds peephole2
pattern to also handle XOR zeroing and load of -1 by OR.

2020-07-16  Uroš Bizjak  <ubizjak@gmail.com>

gcc/ChangeLog:
PR target/96189
* config/i386/sync.md
(peephole2 to remove unneded compare after CMPXCHG):
New pattern, also handle XOR zeroing and load of -1 by OR.

gcc/testsuite/ChangeLog:
PR target/96189
* gcc.target/i386/pr96189-1.c: New test.

gcc/config/i386/sync.md
gcc/testsuite/gcc.target/i386/pr96189-1.c [new file with mode: 0644]

index d203e9d1ecba16af82c9c751a562aeccf8d41e99..e22109039c10459cc38ca657a9015d9537c687bb 100644 (file)
              (set (reg:CCZ FLAGS_REG)
                   (unspec_volatile:CCZ [(const_int 0)] UNSPECV_CMPXCHG))])])
 
+(define_peephole2
+  [(parallel [(set (match_operand:SWI48 0 "register_operand")
+                  (match_operand:SWI48 1 "const_int_operand"))
+             (clobber (reg:CC FLAGS_REG))])
+   (parallel [(set (match_operand:SWI 2 "register_operand")
+                  (unspec_volatile:SWI
+                    [(match_operand:SWI 3 "memory_operand")
+                     (match_dup 2)
+                     (match_operand:SWI 4 "register_operand")
+                     (match_operand:SI 5 "const_int_operand")]
+                    UNSPECV_CMPXCHG))
+             (set (match_dup 3)
+                  (unspec_volatile:SWI [(const_int 0)] UNSPECV_CMPXCHG))
+             (set (reg:CCZ FLAGS_REG)
+                  (unspec_volatile:CCZ [(const_int 0)] UNSPECV_CMPXCHG))])
+   (set (reg:CCZ FLAGS_REG)
+       (compare:CCZ (match_dup 2)
+                    (match_dup 1)))]
+  "REGNO (operands[0]) == REGNO (operands[2])"
+  [(parallel [(set (match_dup 0)
+                  (match_dup 1))
+             (clobber (reg:CC FLAGS_REG))])
+   (parallel [(set (match_dup 2)
+                  (unspec_volatile:SWI
+                    [(match_dup 3)
+                     (match_dup 2)
+                     (match_dup 4)
+                     (match_dup 5)]
+                    UNSPECV_CMPXCHG))
+             (set (match_dup 3)
+                  (unspec_volatile:SWI [(const_int 0)] UNSPECV_CMPXCHG))
+             (set (reg:CCZ FLAGS_REG)
+                  (unspec_volatile:CCZ [(const_int 0)] UNSPECV_CMPXCHG))])])
+
 ;; For operand 2 nonmemory_operand predicate is used instead of
 ;; register_operand to allow combiner to better optimize atomic
 ;; additions of constants.
diff --git a/gcc/testsuite/gcc.target/i386/pr96189-1.c b/gcc/testsuite/gcc.target/i386/pr96189-1.c
new file mode 100644 (file)
index 0000000..fd95cb2
--- /dev/null
@@ -0,0 +1,24 @@
+/* PR target/96176 */
+/* { dg-do compile { target lp64 } } */
+/* { dg-options "-Os" } */
+/* { dg-final { scan-assembler-not "\tcmpb\t" } } */
+
+_Bool
+foo (short *x, short z)
+{
+  short y = 0;
+  __atomic_compare_exchange_n (x, &y, z, 0, __ATOMIC_RELAXED, __ATOMIC_RELAXED);
+  return y == 0;
+}
+
+/* { dg-final { scan-assembler-not "\ttestw\t" } } */
+
+_Bool
+bar (short *x, short z)
+{
+  short y = -1;
+  __atomic_compare_exchange_n (x, &y, z, 0, __ATOMIC_RELAXED, __ATOMIC_RELAXED);
+  return y == -1;
+}
+
+/* { dg-final { scan-assembler-not "\tincw\t" } } */