aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorAndrew MacLeod <amacleod@redhat.com>2012-10-01 15:50:09 +0000
committerAndrew Macleod <amacleod@gcc.gnu.org>2012-10-01 15:50:09 +0000
commitcd8b6dc554e8ca488ec5d3f975250e29b316397c (patch)
treea9e7aba800558d9f52393d40679b24f9f4b5aa3c /gcc
parent992103ad6991bfbd908d10b18b3fba28196ff7a8 (diff)
downloadgcc-cd8b6dc554e8ca488ec5d3f975250e29b316397c.zip
gcc-cd8b6dc554e8ca488ec5d3f975250e29b316397c.tar.gz
gcc-cd8b6dc554e8ca488ec5d3f975250e29b316397c.tar.bz2
re PR target/54087 (__atomic_fetch_add does not use xadd instruction)
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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog8
-rw-r--r--gcc/optabs.c66
-rw-r--r--gcc/testsuite/ChangeLog6
-rw-r--r--gcc/testsuite/gcc.dg/pr54087.c18
4 files changed, 94 insertions, 4 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index f543b7b..9a20ab5 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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
diff --git a/gcc/optabs.c b/gcc/optabs.c
index cdd5d69..8a6c6a3 100644
--- a/gcc/optabs.c
+++ b/gcc/optabs.c
@@ -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
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 89d7eeb..dc6956a 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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
index 0000000..abb0af3
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr54087.c
@@ -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;
+}