public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
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

  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).