aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Henderson <rth@redhat.com>2012-03-03 10:21:06 -0800
committerRichard Henderson <rth@gcc.gnu.org>2012-03-03 10:21:06 -0800
commita6de595f94a9a1956f19124195b0c852fd9fde73 (patch)
tree96b4628bf6a7a2b7e88c64b5788289627c0d35dd
parent6ecbd3a745b94e379458f0f67745379c969bc569 (diff)
downloadgcc-a6de595f94a9a1956f19124195b0c852fd9fde73.zip
gcc-a6de595f94a9a1956f19124195b0c852fd9fde73.tar.gz
gcc-a6de595f94a9a1956f19124195b0c852fd9fde73.tar.bz2
optabs.c (expand_atomic_test_and_set): Honor atomic_test_and_set_trueval even when atomic_test_and_set optab is not in use.
* optabs.c (expand_atomic_test_and_set): Honor atomic_test_and_set_trueval even when atomic_test_and_set optab is not in use. From-SVN: r184862
-rw-r--r--gcc/ChangeLog6
-rw-r--r--gcc/optabs.c61
2 files changed, 48 insertions, 19 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index e2c179d..a9edea9 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,9 @@
+2012-03-02 Richard Henderson <rth@redhat.com>
+
+ * optabs.c (expand_atomic_test_and_set): Honor
+ atomic_test_and_set_trueval even when atomic_test_and_set
+ optab is not in use.
+
2012-03-02 Kaz Kojima <kkojima@gcc.gnu.org>
PR target/48596
diff --git a/gcc/optabs.c b/gcc/optabs.c
index b0ecdf0..fd353d7 100644
--- a/gcc/optabs.c
+++ b/gcc/optabs.c
@@ -7384,34 +7384,57 @@ rtx
expand_atomic_test_and_set (rtx target, rtx mem, enum memmodel model)
{
enum machine_mode mode = GET_MODE (mem);
- rtx ret;
+ rtx ret, trueval, subtarget;
ret = maybe_emit_atomic_test_and_set (target, mem, model);
if (ret)
return ret;
- if (target == NULL_RTX)
- target = gen_reg_rtx (mode);
+ /* Be binary compatible with non-default settings of trueval, and different
+ cpu revisions. E.g. one revision may have atomic-test-and-set, but
+ another only has atomic-exchange. */
+ if (targetm.atomic_test_and_set_trueval == 1)
+ {
+ trueval = const1_rtx;
+ subtarget = target ? target : gen_reg_rtx (mode);
+ }
+ else
+ {
+ trueval = gen_int_mode (targetm.atomic_test_and_set_trueval, mode);
+ subtarget = gen_reg_rtx (mode);
+ }
- /* 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;
+ /* Try the atomic-exchange optab... */
+ ret = maybe_emit_atomic_exchange (subtarget, mem, trueval, model);
- ret = maybe_emit_compare_and_swap_exchange_loop (target, mem, const1_rtx);
- if (ret)
- return ret;
+ /* ... then an atomic-compare-and-swap loop ... */
+ if (!ret)
+ ret = maybe_emit_compare_and_swap_exchange_loop (subtarget, mem, trueval);
- ret = maybe_emit_sync_lock_test_and_set (target, mem, const1_rtx, model);
- if (ret)
- return ret;
+ /* ... before trying the vaguely defined legacy lock_test_and_set. */
+ if (!ret)
+ ret = maybe_emit_sync_lock_test_and_set (subtarget, mem, trueval, model);
- /* Failing all else, assume a single threaded environment and simply perform
- the operation. */
- emit_move_insn (target, mem);
- emit_move_insn (mem, const1_rtx);
- return target;
+ /* Recall that the legacy lock_test_and_set optab was allowed to do magic
+ things with the value 1. Thus we try again without trueval. */
+ if (!ret && targetm.atomic_test_and_set_trueval != 1)
+ ret = maybe_emit_sync_lock_test_and_set (subtarget, mem, const1_rtx, model);
+
+ /* Failing all else, assume a single threaded environment and simply
+ perform the operation. */
+ if (!ret)
+ {
+ emit_move_insn (subtarget, mem);
+ emit_move_insn (mem, trueval);
+ ret = subtarget;
+ }
+
+ /* Recall that have to return a boolean value; rectify if trueval
+ is not exactly one. */
+ if (targetm.atomic_test_and_set_trueval != 1)
+ ret = emit_store_flag_force (target, NE, ret, const0_rtx, mode, 0, 1);
+
+ return ret;
}
/* This function expands the atomic exchange operation: