aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog10
-rw-r--r--gcc/doc/extend.texi7
-rw-r--r--gcc/doc/md.texi13
-rw-r--r--gcc/optabs.c75
4 files changed, 79 insertions, 26 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index c06613e..9616c2b 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,15 @@
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.
2012-01-25 Richard Henderson <rth@redhat.com>
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 229e87c..e159736 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 bcfd420..afdc3e3 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 a532ba3..0f6d763 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;