From: Andrew MacLeod <amacleod@redhat.com>
To: Hans-Peter Nilsson <hans-peter.nilsson@axis.com>
Cc: gcc-patches@gcc.gnu.org, libstdc++@gcc.gnu.org
Subject: Re: cxx-mem-model merge [6 of 9] - libstdc++-v3
Date: Mon, 07 Nov 2011 04:48:00 -0000 [thread overview]
Message-ID: <4EB75DAB.6020003@redhat.com> (raw)
In-Reply-To: <201111070038.pA70cqwC023528@ignucius.se.axis.com>
[-- Attachment #1: Type: text/plain, Size: 756 bytes --]
On 11/06/2011 07:38 PM, Hans-Peter Nilsson wrote:
>
> This (formally a change in the range 181027:181034) got me three
> libstdc++ regressions for cris-elf, which has no "atomic"
> support whatsoever (well, not the version represented in
> "cris-elf"), so something is amiss at the bottom of the default
> path:
yes, I have a final pending patch which didn't make it to the branch
before the merge. It changes the behaviour of atomic_flag on targets
with no compare_and_swap. I *think* it will resolve your problem.
I've attached the early version of the patch which you can try. Its
missing a documentation change I was going to add tomorrow before
submitting, but we can see if it resolves your problem. Give it a shot
and let me know.
Andrew
[-- Attachment #2: TAS.diff --]
[-- Type: text/plain, Size: 9642 bytes --]
gcc
* expr.h (expand_atomic_exchange): Add extra parameter.
* builtins.c (expand_builtin_sync_lock_test_and_set): Call
expand_atomic_exchange with true.
(expand_builtin_atomic_exchange): Call expand_atomic_exchange with
false.
* optabs.c (expand_atomic_exchange): Add use_test_and_set param and
only fall back to __sync_test_and_set when true.
(expand_atomic_store): Add false to expand_atomic_exchange call.
libstdc++-v3
* include/bits/atomic_base.h (test_and_set): Call __atomic_exchange
only if it is always lock free, otherwise __sync_lock_test_and_set.
Index: gcc/expr.h
===================================================================
*** gcc/expr.h (revision 180770)
--- gcc/expr.h (working copy)
*************** rtx emit_conditional_add (rtx, enum rtx_
*** 215,221 ****
rtx expand_sync_operation (rtx, rtx, enum rtx_code);
rtx expand_sync_fetch_operation (rtx, rtx, enum rtx_code, bool, rtx);
! rtx expand_atomic_exchange (rtx, rtx, rtx, enum memmodel);
rtx expand_atomic_load (rtx, rtx, enum memmodel);
rtx expand_atomic_store (rtx, rtx, enum memmodel);
rtx expand_atomic_fetch_op (rtx, rtx, rtx, enum rtx_code, enum memmodel,
--- 215,221 ----
rtx expand_sync_operation (rtx, rtx, enum rtx_code);
rtx expand_sync_fetch_operation (rtx, rtx, enum rtx_code, bool, rtx);
! rtx expand_atomic_exchange (rtx, rtx, rtx, enum memmodel, bool);
rtx expand_atomic_load (rtx, rtx, enum memmodel);
rtx expand_atomic_store (rtx, rtx, enum memmodel);
rtx expand_atomic_fetch_op (rtx, rtx, rtx, enum rtx_code, enum memmodel,
Index: gcc/builtins.c
===================================================================
*** gcc/builtins.c (revision 180789)
--- gcc/builtins.c (working copy)
*************** expand_builtin_sync_lock_test_and_set (e
*** 5221,5227 ****
mem = get_builtin_sync_mem (CALL_EXPR_ARG (exp, 0), mode);
val = expand_expr_force_mode (CALL_EXPR_ARG (exp, 1), mode);
! return expand_atomic_exchange (target, mem, val, MEMMODEL_ACQUIRE);
}
/* Expand the __sync_lock_release intrinsic. EXP is the CALL_EXPR. */
--- 5221,5227 ----
mem = get_builtin_sync_mem (CALL_EXPR_ARG (exp, 0), mode);
val = expand_expr_force_mode (CALL_EXPR_ARG (exp, 1), mode);
! return expand_atomic_exchange (target, mem, val, MEMMODEL_ACQUIRE, true);
}
/* Expand the __sync_lock_release intrinsic. EXP is the CALL_EXPR. */
*************** expand_builtin_atomic_exchange (enum mac
*** 5284,5290 ****
mem = get_builtin_sync_mem (CALL_EXPR_ARG (exp, 0), mode);
val = expand_expr_force_mode (CALL_EXPR_ARG (exp, 1), mode);
! return expand_atomic_exchange (target, mem, val, model);
}
/* Expand the __atomic_compare_exchange intrinsic:
--- 5284,5290 ----
mem = get_builtin_sync_mem (CALL_EXPR_ARG (exp, 0), mode);
val = expand_expr_force_mode (CALL_EXPR_ARG (exp, 1), mode);
! return expand_atomic_exchange (target, mem, val, model, false);
}
/* Expand the __atomic_compare_exchange intrinsic:
Index: gcc/optabs.c
===================================================================
*** gcc/optabs.c (revision 180770)
--- gcc/optabs.c (working copy)
*************** expand_compare_and_swap_loop (rtx mem, r
*** 6872,6881 ****
atomically store VAL in MEM and return the previous value in MEM.
MEMMODEL is the memory model variant to use.
! TARGET is an option place to stick the return value. */
rtx
! expand_atomic_exchange (rtx target, rtx mem, rtx val, enum memmodel model)
{
enum machine_mode mode = GET_MODE (mem);
enum insn_code icode;
--- 6872,6884 ----
atomically store VAL in MEM and return the previous value in MEM.
MEMMODEL is the memory model variant to use.
! TARGET is an optional place to stick the return value.
! USE_TEST_AND_SET indicates whether __sync_lock_test_and_set should be used
! as a fall back if the atomic_exchange pattern does not exist. */
rtx
! expand_atomic_exchange (rtx target, rtx mem, rtx val, enum memmodel model,
! bool use_test_and_set)
{
enum machine_mode mode = GET_MODE (mem);
enum insn_code icode;
*************** expand_atomic_exchange (rtx target, rtx
*** 6900,6930 ****
acquire barrier. If the pattern exists, and the memory model is stronger
than acquire, add a release barrier before the instruction.
The barrier is not needed if sync_lock_test_and_set doesn't exist since
! it will expand into a compare-and-swap loop. */
! icode = direct_optab_handler (sync_lock_test_and_set_optab, mode);
! last_insn = get_last_insn ();
! if ((icode != CODE_FOR_nothing) && (model == MEMMODEL_SEQ_CST ||
! model == MEMMODEL_RELEASE ||
! model == MEMMODEL_ACQ_REL))
! expand_builtin_mem_thread_fence (model);
! if (icode != CODE_FOR_nothing)
! {
! struct expand_operand ops[3];
! create_output_operand (&ops[0], target, mode);
! create_fixed_operand (&ops[1], mem);
! /* VAL may have been promoted to a wider mode. Shrink it if so. */
! create_convert_operand_to (&ops[2], val, mode, true);
! if (maybe_expand_insn (icode, 3, ops))
! return ops[0].value;
! }
! /* Remove any fence we may have inserted since a compare and swap loop is a
! full memory barrier. */
! if (last_insn != get_last_insn ())
! delete_insns_since (last_insn);
/* Otherwise, use a compare-and-swap loop for the exchange. */
if (can_compare_and_swap_p (mode))
--- 6903,6941 ----
acquire barrier. If the pattern exists, and the memory model is stronger
than acquire, add a release barrier before the instruction.
The barrier is not needed if sync_lock_test_and_set doesn't exist since
! it will expand into a compare-and-swap loop.
! Some targets have non-compliant test_and_sets, so it would be incorrect
! to emit a test_and_set in place of an __atomic_exchange. The test_and_set
! builtin shares this expander since exchange can always replace the
! test_and_set. */
!
! if (use_test_and_set)
! {
! icode = direct_optab_handler (sync_lock_test_and_set_optab, mode);
! last_insn = get_last_insn ();
! if ((icode != CODE_FOR_nothing) && (model == MEMMODEL_SEQ_CST ||
! model == MEMMODEL_RELEASE ||
! model == MEMMODEL_ACQ_REL))
! expand_builtin_mem_thread_fence (model);
! if (icode != CODE_FOR_nothing)
! {
! struct expand_operand ops[3];
! create_output_operand (&ops[0], target, mode);
! create_fixed_operand (&ops[1], mem);
! /* VAL may have been promoted to a wider mode. Shrink it if so. */
! create_convert_operand_to (&ops[2], val, mode, true);
! if (maybe_expand_insn (icode, 3, ops))
! return ops[0].value;
! }
! /* Remove any fence that was inserted since a compare and swap loop is
! already a full memory barrier. */
! if (last_insn != get_last_insn ())
! delete_insns_since (last_insn);
! }
/* Otherwise, use a compare-and-swap loop for the exchange. */
if (can_compare_and_swap_p (mode))
*************** expand_atomic_store (rtx mem, rtx val, e
*** 7130,7136 ****
the result. If that doesn't work, don't do anything. */
if (GET_MODE_PRECISION(mode) > BITS_PER_WORD)
{
! rtx target = expand_atomic_exchange (NULL_RTX, mem, val, model);
if (target)
return const0_rtx;
else
--- 7141,7147 ----
the result. If that doesn't work, don't do anything. */
if (GET_MODE_PRECISION(mode) > BITS_PER_WORD)
{
! rtx target = expand_atomic_exchange (NULL_RTX, mem, val, model, false);
if (target)
return const0_rtx;
else
Index: libstdc++-v3/include/bits/atomic_base.h
===================================================================
*** libstdc++-v3/include/bits/atomic_base.h (revision 180789)
--- libstdc++-v3/include/bits/atomic_base.h (working copy)
*************** _GLIBCXX_BEGIN_NAMESPACE_VERSION
*** 261,273 ****
bool
test_and_set(memory_order __m = memory_order_seq_cst) noexcept
{
! return __atomic_exchange_n(&_M_i, 1, __m);
}
bool
test_and_set(memory_order __m = memory_order_seq_cst) volatile noexcept
{
! return __atomic_exchange_n(&_M_i, 1, __m);
}
void
--- 261,295 ----
bool
test_and_set(memory_order __m = memory_order_seq_cst) noexcept
{
! /* The standard *requires* this to be lock free. If exchange is not
! always lock free, the resort to the old test_and_set. */
! if (__atomic_always_lock_free (sizeof (_M_i), 0))
! return __atomic_exchange_n(&_M_i, 1, __m);
! else
! {
! /* Sync test and set is only guaranteed to be acquire. */
! if (__m == memory_order_seq_cst || __m == memory_order_release
! || __m == memory_order_acq_rel)
! atomic_thread_fence (__m);
! return __sync_lock_test_and_set (&_M_i, 1);
! }
}
bool
test_and_set(memory_order __m = memory_order_seq_cst) volatile noexcept
{
! /* The standard *requires* this to be lock free. If exchange is not
! always lock free, the resort to the old test_and_set. */
! if (__atomic_always_lock_free (sizeof (_M_i), 0))
! return __atomic_exchange_n(&_M_i, 1, __m);
! else
! {
! /* Sync test and set is only guaranteed to be acquire. */
! if (__m == memory_order_seq_cst || __m == memory_order_release
! || __m == memory_order_acq_rel)
! atomic_thread_fence (__m);
! return __sync_lock_test_and_set (&_M_i, 1);
! }
}
void
next prev parent reply other threads:[~2011-11-07 4:25 UTC|newest]
Thread overview: 22+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-11-03 23:52 Andrew MacLeod
2011-11-04 18:17 ` Jeff Law
2011-11-04 18:53 ` Andrew MacLeod
2011-11-07 0:54 ` Hans-Peter Nilsson
2011-11-07 4:48 ` Andrew MacLeod [this message]
2011-11-07 11:36 ` Hans-Peter Nilsson
2011-11-07 14:41 ` Andrew MacLeod
2011-11-07 14:56 ` Andrew MacLeod
2011-11-07 15:38 ` Hans-Peter Nilsson
2011-11-07 16:28 ` Joseph S. Myers
2011-11-07 17:24 ` Andrew MacLeod
2011-11-07 17:43 ` Hans-Peter Nilsson
2011-11-07 18:27 ` Andrew MacLeod
2011-11-08 6:45 ` Hans-Peter Nilsson
2011-11-08 13:43 ` Andrew MacLeod
2011-11-11 17:49 ` Benjamin Kosnik
2011-11-11 17:56 ` Andrew MacLeod
2011-11-11 21:07 ` Hans-Peter Nilsson
2011-11-11 23:34 ` Torvald Riegel
2011-11-11 20:27 ` Hans-Peter Nilsson
2011-11-07 16:32 ` Richard Henderson
2011-11-08 20:22 ` Hans-Peter Nilsson
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4EB75DAB.6020003@redhat.com \
--to=amacleod@redhat.com \
--cc=gcc-patches@gcc.gnu.org \
--cc=hans-peter.nilsson@axis.com \
--cc=libstdc++@gcc.gnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).