The bug observes that atomic and/or operations can occasionally be replaced with a exchange operation.

    fetch_and (&x, 0)   ->  exchange (&x, 0)

    fetch_or (&x, -1)    ->  exchange (&x, -1)

This is now trivial in the general expansion code. Others could easily be added later.

This patch works for both __atomic and __sync variations, but will only replace the operation if a native atomic_exchange pattern exists.

bootstrapped and no new regressions on x86_64-unknown-linux-gnu.

I created a testcase which will compile on x86 and verify in the assembly that an exchange operation is performed rather than a compare_swap loop... hopefully thats sufficient for testing.

Andrew
        PR target/50123
        * optabs.c (maybe_optimize_fetch_op): New.  Look for more optimal
        instructions for a FECTH_OP or OP_FECTH sequence.
        (expand_atomic_fetch_op): Call maybe_optimize_fetch_op.
        * testsuite/gcc.dg/atomic-op-optimize.c: New.  Test for optimizations.

Index: optabs.c
===================================================================
*** optabs.c    (revision 181702)
--- optabs.c    (working copy)
*************** get_atomic_op_for_code (struct atomic_op
*** 7943,7948 ****
--- 7943,7983 ----
      }
  }
  
+ /* See if there is a more optimal way to implement the operation "*MEM CODE 
VAL"
+    using memory order MODEL.  If AFTER is true the operation needs to return
+    the value of *MEM after the operation, otherwise the previous value.  
+    TARGET is an optional place to place the result.  The result is unused if
+    it is const0_rtx.
+    Return the result if there is a better sequence, otherwise NULL_RTX.  */
+ 
+ static rtx
+ maybe_optimize_fetch_op (rtx target, rtx mem, rtx val, enum rtx_code code,
+                        enum memmodel model, bool after)
+ {
+   /* If the value is prefetched, or not used, it may be possible to replace
+      the sequence with a native exchange operation.  */
+   if (!after || target == const0_rtx)
+     {
+       /* fetch_and (&x, 0, m) can be replaced with exchange (&x, 0, m).  */
+       if (code == AND && val == const0_rtx)
+         {
+         if (target == const0_rtx)
+           target = gen_reg_rtx (GET_MODE (mem));
+         return maybe_emit_atomic_exchange (target, mem, val, model);
+       }
+ 
+       /* fetch_or (&x, -1, m) can be replaced with exchange (&x, -1, m).  */
+       if (code == IOR && val == constm1_rtx)
+         {
+         if (target == const0_rtx)
+           target = gen_reg_rtx (GET_MODE (mem));
+         return maybe_emit_atomic_exchange (target, mem, val, model);
+       }
+     }
+ 
+   return NULL_RTX;
+ }
+ 
  /* Try to emit an instruction for a specific operation varaition. 
     OPTAB contains the OP functions.
     TARGET is an optional place to return the result. const0_rtx means unused.
*************** expand_atomic_fetch_op (rtx target, rtx 
*** 8028,8033 ****
--- 8063,8073 ----
  
    get_atomic_op_for_code (&optab, code);
  
+   /* Check to see if there are any better instructions.  */
+   result = maybe_optimize_fetch_op (target, mem, val, code, model, after);
+   if (result)
+     return result;
+ 
    /* Check for the case where the result isn't used and try those patterns.  
*/
    if (unused_result)
      {
Index: testsuite/gcc.dg/atomic-op-optimize.c
===================================================================
*** testsuite/gcc.dg/atomic-op-optimize.c       (revision 0)
--- testsuite/gcc.dg/atomic-op-optimize.c       (revision 0)
***************
*** 0 ****
--- 1,20 ----
+ /* Both these atomic operations should be optimized to an exchange operation.
+    Test that it at happens on x86 by making sure there are 2 xchg's and no
+    compare_exchange loop.  */
+ 
+ /* { dg-require-effective-target sync_int_long } */
+ /* { dg-do compile { target { i?86-*-* x86_64-*-* } } } */
+ /* { dg-final { scan-assembler-times "cmpxchg" 0 } } */
+ /* { dg-final { scan-assembler-times "xchg" 2 } } */
+ 
+ int x;
+ 
+ int f()
+ {
+   return __atomic_fetch_and (&x, 0, __ATOMIC_RELAXED);
+ }
+ 
+ int g()
+ {
+   return __atomic_fetch_or (&x, -1, __ATOMIC_RELAXED);
+ }

Reply via email to