From cd8b6dc554e8ca488ec5d3f975250e29b316397c Mon Sep 17 00:00:00 2001 From: Andrew MacLeod Date: Mon, 1 Oct 2012 15:50:09 +0000 Subject: [PATCH] re PR target/54087 (__atomic_fetch_add does not use xadd instruction) 2012-10-01 Andrew MacLeod 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 | 8 +++++ gcc/optabs.c | 66 +++++++++++++++++++++++++++++++--- gcc/testsuite/ChangeLog | 6 ++++ gcc/testsuite/gcc.dg/pr54087.c | 18 ++++++++++ 4 files changed, 94 insertions(+), 4 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/pr54087.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index f543b7b8b62b..9a20ab5e0579 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,11 @@ +2012-10-01 Andrew MacLeod + + 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 PR rtl-optimization/54457 diff --git a/gcc/optabs.c b/gcc/optabs.c index cdd5d69760d4..8a6c6a330b49 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 89d7eeb341d9..dc6956a533b9 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2012-10-01 Andrew MacLeod + + PR target/54087 + * gcc.dg/pr54087.c: New testcase for atomic_sub -> atomic_add when + atomic_sub fails. + 2012-10-01 Uros Bizjak 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 000000000000..abb0af3d9bb3 --- /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; +}