re PR target/54087 (__atomic_fetch_add does not use xadd instruction)
authorAndrew MacLeod <amacleod@redhat.com>
Mon, 1 Oct 2012 15:50:09 +0000 (15:50 +0000)
committerAndrew Macleod <amacleod@gcc.gnu.org>
Mon, 1 Oct 2012 15:50:09 +0000 (15:50 +0000)
2012-10-01  Andrew MacLeod  <amacleod@redhat.com>

PR target/54087
* optabs.c (expand_atomic_fetch_op_no_fallback): New.  Factored code
from expand_atomic_fetch_op.
(expand_atomic_fetch_op):  Try atomic_{add|sub} operations in terms of
the other one if direct opcode fails.
* testsuite/gcc.dg/pr54087.c:  New testcase for atomic_sub ->
atomic_add when atomic_sub fails.

From-SVN: r191929

gcc/ChangeLog
gcc/optabs.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/pr54087.c [new file with mode: 0644]

index f543b7b..9a20ab5 100644 (file)
@@ -1,3 +1,11 @@
+2012-10-01  Andrew MacLeod  <amacleod@redhat.com>
+
+       PR target/54087
+       * optabs.c (expand_atomic_fetch_op_no_fallback): New.  Factored code
+       from expand_atomic_fetch_op.
+       (expand_atomic_fetch_op):  Try atomic_{add|sub} operations in terms of
+       the other one if direct opcode fails.
+
 2012-10-01  Uros Bizjak  <ubizjak@gmail.com>
 
        PR rtl-optimization/54457
index cdd5d69..8a6c6a3 100644 (file)
@@ -7733,10 +7733,15 @@ maybe_emit_op (const struct atomic_op_functions *optab, rtx target, rtx mem,
    CODE is the operation being performed (OP)
    MEMMODEL is the memory model variant to use.
    AFTER is true to return the result of the operation (OP_fetch).
-   AFTER is false to return the value before the operation (fetch_OP).  */
-rtx
-expand_atomic_fetch_op (rtx target, rtx mem, rtx val, enum rtx_code code,
-                       enum memmodel model, bool after)
+   AFTER is false to return the value before the operation (fetch_OP).  
+
+   This function will *only* generate instructions if there is a direct
+   optab. No compare and swap loops or libcalls will be generated. */
+
+static rtx
+expand_atomic_fetch_op_no_fallback (rtx target, rtx mem, rtx val,
+                                   enum rtx_code code, enum memmodel model,
+                                   bool after)
 {
   enum machine_mode mode = GET_MODE (mem);
   struct atomic_op_functions optab;
@@ -7809,13 +7814,66 @@ expand_atomic_fetch_op (rtx target, rtx mem, rtx val, enum rtx_code code,
        }
     }
 
+  /* No direct opcode can be generated.  */
+  return NULL_RTX;
+}
+
+
+
+/* This function expands an atomic fetch_OP or OP_fetch operation:
+   TARGET is an option place to stick the return value.  const0_rtx indicates
+   the result is unused. 
+   atomically fetch MEM, perform the operation with VAL and return it to MEM.
+   CODE is the operation being performed (OP)
+   MEMMODEL is the memory model variant to use.
+   AFTER is true to return the result of the operation (OP_fetch).
+   AFTER is false to return the value before the operation (fetch_OP).  */
+rtx
+expand_atomic_fetch_op (rtx target, rtx mem, rtx val, enum rtx_code code,
+                       enum memmodel model, bool after)
+{
+  enum machine_mode mode = GET_MODE (mem);
+  rtx result;
+  bool unused_result = (target == const0_rtx);
+
+  result = expand_atomic_fetch_op_no_fallback (target, mem, val, code, model,
+                                              after);
+  
+  if (result)
+    return result;
+
+  /* Add/sub can be implemented by doing the reverse operation with -(val).  */
+  if (code == PLUS || code == MINUS)
+    {
+      rtx tmp;
+      enum rtx_code reverse = (code == PLUS ? MINUS : PLUS);
+
+      start_sequence ();
+      tmp = expand_simple_unop (mode, NEG, val, NULL_RTX, true);
+      result = expand_atomic_fetch_op_no_fallback (target, mem, tmp, reverse,
+                                                  model, after);
+      if (result)
+       {
+         /* PLUS worked so emit the insns and return.  */
+         tmp = get_insns ();
+         end_sequence ();
+         emit_insn (tmp);
+          return result;
+       }
+
+      /* PLUS did not work, so throw away the negation code and continue.  */
+      end_sequence ();
+    }
+
   /* Try the __sync libcalls only if we can't do compare-and-swap inline.  */
   if (!can_compare_and_swap_p (mode, false))
     {
       rtx libfunc;
       bool fixup = false;
       enum rtx_code orig_code = code;
+      struct atomic_op_functions optab;
 
+      get_atomic_op_for_code (&optab, code);
       libfunc = optab_libfunc (after ? optab.fetch_after
                               : optab.fetch_before, mode);
       if (libfunc == NULL
index 89d7eeb..dc6956a 100644 (file)
@@ -1,3 +1,9 @@
+2012-10-01  Andrew MacLeod  <amacleod@redhat.com>
+
+       PR target/54087
+       * gcc.dg/pr54087.c:  New testcase for atomic_sub -> atomic_add when
+       atomic_sub fails.
+
 2012-10-01  Uros Bizjak  <ubizjak@gmail.com>
 
        PR rtl-optimization/54457
diff --git a/gcc/testsuite/gcc.dg/pr54087.c b/gcc/testsuite/gcc.dg/pr54087.c
new file mode 100644 (file)
index 0000000..abb0af3
--- /dev/null
@@ -0,0 +1,18 @@
+/* PR54087.  Verify __atomic_sub (val) uses __atomic_add (-val) if there is no
+             atomic_aub.  */
+/* { dg-require-effective-target sync_int_long } */
+/* { dg-do compile { target { i?86-*-* x86_64-*-* } } } */
+/* { dg-final { scan-assembler-times "xadd" 2 } } */
+
+
+int a;
+
+int f1(int p)
+{
+  return __atomic_sub_fetch(&a, p, __ATOMIC_SEQ_CST) == 0;
+}
+
+int f2(int p)
+{
+  return __atomic_fetch_sub(&a, p, __ATOMIC_SEQ_CST) - p == 0;
+}