mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-04-06 11:40:50 +08:00
atomic: Create and use maybe_emit_atomic_test_and_set.
* optabs.c (CODE_FOR_atomic_test_and_set): Provide default. (maybe_emit_atomic_test_and_set): New. (expand_sync_lock_test_and_set): Use it. (expand_atomic_test_and_set): Likewise. * doc/extend.texi (__atomic_test_and_set): Adjust the docs to match the implementation; clarify implementation defined details. * doc/md.texi (atomic_test_and_set): Document. From-SVN: r183483
This commit is contained in:
parent
3b547557aa
commit
f8a27aa631
@ -1,3 +1,13 @@
|
||||
2012-01-25 Richard Henderson <rth@redhat.com>
|
||||
|
||||
* optabs.c (CODE_FOR_atomic_test_and_set): Provide default.
|
||||
(maybe_emit_atomic_test_and_set): New.
|
||||
(expand_sync_lock_test_and_set): Use it.
|
||||
(expand_atomic_test_and_set): Likewise.
|
||||
* doc/extend.texi (__atomic_test_and_set): Adjust the docs to match
|
||||
the implementation; clarify implementation defined details.
|
||||
* doc/md.texi (atomic_test_and_set): Document.
|
||||
|
||||
2012-01-25 Richard Henderson <rth@redhat.com>
|
||||
|
||||
* config/sparc/predicates.md (zero_or_v7_operand): Use match_code.
|
||||
|
@ -7202,11 +7202,12 @@ All memory models are valid.
|
||||
|
||||
@end deftypefn
|
||||
|
||||
@deftypefn {Built-in Function} bool __atomic_test_and_set (bool *ptr, int memmodel)
|
||||
@deftypefn {Built-in Function} bool __atomic_test_and_set (void *ptr, int memmodel)
|
||||
|
||||
This built-in function performs an atomic test-and-set operation on
|
||||
@code{*@var{ptr}}. @code{*@var{ptr}} is set to the value 1 and
|
||||
the previous contents are returned.
|
||||
the byte at @code{*@var{ptr}}. The byte is set to some implementation
|
||||
defined non-zero "set" value and the return value is @code{true} if and only
|
||||
if the previous contents were "set".
|
||||
|
||||
All memory models are valid.
|
||||
|
||||
|
@ -5893,6 +5893,19 @@ the operation followed by the arithmetic operation required to produce the
|
||||
result. If none of these are available a compare-and-swap loop will be
|
||||
used.
|
||||
|
||||
@cindex @code{atomic_test_and_set} instruction pattern
|
||||
@item @samp{atomic_test_and_set}
|
||||
|
||||
This pattern emits code for @code{__builtin_atomic_test_and_set}.
|
||||
Operand 0 is an output operand which is set to true if the previous
|
||||
previous contents of the byte was "set", and false otherwise. Operand 1
|
||||
is the @code{QImode} memory to be modified. Operand 2 is the memory
|
||||
model to be used.
|
||||
|
||||
The specific value that defines "set" is implementation defined, and
|
||||
is normally based on what is performed by the native atomic test and set
|
||||
instruction.
|
||||
|
||||
@cindex @code{mem_thread_fence@var{mode}} instruction pattern
|
||||
@item @samp{mem_thread_fence@var{mode}}
|
||||
This pattern emits code required to implement a thread fence with
|
||||
|
75
gcc/optabs.c
75
gcc/optabs.c
@ -7304,11 +7304,41 @@ maybe_emit_compare_and_swap_exchange_loop (rtx target, rtx mem, rtx val)
|
||||
return NULL_RTX;
|
||||
}
|
||||
|
||||
/* This function tries to implement an atomic test-and-set operation
|
||||
using the atomic_test_and_set instruction pattern. A boolean value
|
||||
is returned from the operation, using TARGET if possible. */
|
||||
|
||||
#ifndef HAVE_atomic_test_and_set
|
||||
#define HAVE_atomic_test_and_set 0
|
||||
#define CODE_FOR_atomic_test_and_set CODE_FOR_nothing
|
||||
#define gen_atomic_test_and_set(x,y,z) (gcc_unreachable (), NULL_RTX)
|
||||
#endif
|
||||
|
||||
static rtx
|
||||
maybe_emit_atomic_test_and_set (rtx target, rtx mem, enum memmodel model)
|
||||
{
|
||||
enum machine_mode pat_bool_mode;
|
||||
const struct insn_data_d *id;
|
||||
|
||||
if (!HAVE_atomic_test_and_set)
|
||||
return NULL_RTX;
|
||||
|
||||
id = &insn_data[CODE_FOR_atomic_test_and_set];
|
||||
pat_bool_mode = id->operand[0].mode;
|
||||
|
||||
/* ??? We only support test-and-set on single bytes at the moment.
|
||||
We'd have to change the builtin to allow wider memories. */
|
||||
gcc_checking_assert (id->operand[1].mode == QImode);
|
||||
gcc_checking_assert (GET_MODE (mem) == QImode);
|
||||
|
||||
if (target == NULL || GET_MODE (target) != pat_bool_mode)
|
||||
target = gen_reg_rtx (pat_bool_mode);
|
||||
|
||||
emit_insn (gen_atomic_test_and_set (target, mem, GEN_INT (model)));
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
/* This function expands the legacy _sync_lock test_and_set operation which is
|
||||
generally an atomic exchange. Some limited targets only allow the
|
||||
constant 1 to be stored. This is an ACQUIRE operation.
|
||||
@ -7323,20 +7353,21 @@ expand_sync_lock_test_and_set (rtx target, rtx mem, rtx val)
|
||||
|
||||
/* Try an atomic_exchange first. */
|
||||
ret = maybe_emit_atomic_exchange (target, mem, val, MEMMODEL_ACQUIRE);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!ret)
|
||||
ret = maybe_emit_sync_lock_test_and_set (target, mem, val,
|
||||
MEMMODEL_ACQUIRE);
|
||||
if (!ret)
|
||||
ret = maybe_emit_compare_and_swap_exchange_loop (target, mem, val);
|
||||
ret = maybe_emit_sync_lock_test_and_set (target, mem, val, MEMMODEL_ACQUIRE);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = maybe_emit_compare_and_swap_exchange_loop (target, mem, val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* If there are no other options, try atomic_test_and_set if the value
|
||||
being stored is 1. */
|
||||
if (!ret && val == const1_rtx && HAVE_atomic_test_and_set)
|
||||
{
|
||||
ret = gen_atomic_test_and_set (target, mem, GEN_INT (MEMMODEL_ACQUIRE));
|
||||
emit_insn (ret);
|
||||
}
|
||||
if (val == const1_rtx)
|
||||
ret = maybe_emit_atomic_test_and_set (target, mem, MEMMODEL_ACQUIRE);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -7351,28 +7382,26 @@ rtx
|
||||
expand_atomic_test_and_set (rtx target, rtx mem, enum memmodel model)
|
||||
{
|
||||
enum machine_mode mode = GET_MODE (mem);
|
||||
rtx ret = NULL_RTX;
|
||||
rtx ret;
|
||||
|
||||
ret = maybe_emit_atomic_test_and_set (target, mem, model);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (target == NULL_RTX)
|
||||
target = gen_reg_rtx (mode);
|
||||
|
||||
if (HAVE_atomic_test_and_set)
|
||||
{
|
||||
ret = gen_atomic_test_and_set (target, mem, GEN_INT (MEMMODEL_ACQUIRE));
|
||||
emit_insn (ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* If there is no test and set, try exchange, then a compare_and_swap loop,
|
||||
then __sync_test_and_set. */
|
||||
ret = maybe_emit_atomic_exchange (target, mem, const1_rtx, model);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!ret)
|
||||
ret = maybe_emit_compare_and_swap_exchange_loop (target, mem, const1_rtx);
|
||||
|
||||
if (!ret)
|
||||
ret = maybe_emit_sync_lock_test_and_set (target, mem, const1_rtx, model);
|
||||
ret = maybe_emit_compare_and_swap_exchange_loop (target, mem, const1_rtx);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = maybe_emit_sync_lock_test_and_set (target, mem, const1_rtx, model);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user