From 39ca90d51f0c4282d89cbcaa9d1153e44d048133 Mon Sep 17 00:00:00 2001 From: rth Date: Tue, 24 Jan 2012 17:55:29 +0000 Subject: [PATCH] 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@183483 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 10 +++++++ gcc/doc/extend.texi | 7 ++--- gcc/doc/md.texi | 13 ++++++++++ gcc/optabs.c | 75 +++++++++++++++++++++++++++++++++++++---------------- 4 files changed, 79 insertions(+), 26 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index c06613e4930..9616c2bdfdb 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,15 @@ 2012-01-25 Richard Henderson + * 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 + * config/sparc/predicates.md (zero_or_v7_operand): Use match_code. 2012-01-25 Richard Henderson diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index 229e87c2493..e159736d420 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -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. diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi index bcfd4204cba..afdc3e3f3bb 100644 --- a/gcc/doc/md.texi +++ b/gcc/doc/md.texi @@ -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 diff --git a/gcc/optabs.c b/gcc/optabs.c index a532ba3d538..0f6d763e592 100644 --- a/gcc/optabs.c +++ b/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; -- 2.11.0