Two of the patches have been posted here before; the libstdc++
patch was approved by Benjamin.

All of the patches tested on sparc64-linux, and sanity checked
on x86_64-linux.  I've cross-compiled for m68k-linux, but I've
only been able to visually sanity check the code in libstdc++.

Committed.  Hopefully that wraps up the atomic patches...


r~
        * optabs.c (gen_atomic_test_and_set): Remove default.
        (maybe_emit_atomic_test_and_set): Use maybe_expand_insn.


diff --git a/gcc/optabs.c b/gcc/optabs.c
index fb01320..87cce8e 100644
--- a/gcc/optabs.c
+++ b/gcc/optabs.c
@@ -7311,39 +7311,34 @@ maybe_emit_compare_and_swap_exchange_loop (rtx target, 
rtx mem, rtx val)
 #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 (), (void) (0 && (x) && (y) && (z)), 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;
+  struct expand_operand ops[3];
 
   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);
-
   /* While we always get QImode from __atomic_test_and_set, we get
      other memory modes from __sync_lock_test_and_set.  Note that we
      use no endian adjustment here.  This matches the 4.6 behavior
      in the Sparc backend.  */
+  gcc_checking_assert
+    (insn_data[CODE_FOR_atomic_test_and_set].operand[1].mode == QImode);
   if (GET_MODE (mem) != QImode)
     mem = adjust_address_nv (mem, QImode, 0);
 
-  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)));
+  pat_bool_mode = insn_data[CODE_FOR_atomic_test_and_set].operand[0].mode;
+  create_output_operand (&ops[0], target, pat_bool_mode);
+  create_fixed_operand (&ops[1], mem);
+  create_integer_operand (&ops[2], model);
 
-  return target;
+  if (maybe_expand_insn (CODE_FOR_atomic_test_and_set, 3, ops))
+    return ops[0].value;
+  return NULL_RTX;
 }
 
 /* This function expands the legacy _sync_lock test_and_set operation which is
        * target.def (TARGET_ATOMIC_TEST_AND_SET_TRUEVAL): New.
        * c-cppbuiltin.c (cpp_atomic_builtins): Define
        __GCC_ATOMIC_TEST_AND_SET_TRUEVAL.
        * doc/tm.texi.in (TARGET_ATOMIC_TEST_AND_SET_TRUEVAL): Add doc hook.
        * doc/tm.texi: Rebuild.


diff --git a/gcc/c-family/c-cppbuiltin.c b/gcc/c-family/c-cppbuiltin.c
index 7e7b9c1..608dba6 100644
--- a/gcc/c-family/c-cppbuiltin.c
+++ b/gcc/c-family/c-cppbuiltin.c
@@ -670,6 +670,11 @@ cpp_atomic_builtins (cpp_reader *pfile)
   builtin_define_with_int_value ("__GCC_ATOMIC_LLONG_LOCK_FREE", 
                (have_swap[SWAP_INDEX (long_long_integer_type_node)]? 2 : 1));
 
+  /* If we're dealing with a "set" value that doesn't exactly correspond
+     to a boolean truth value, let the library work around that.  */
+  builtin_define_with_int_value ("__GCC_ATOMIC_TEST_AND_SET_TRUEVAL",
+                                targetm.atomic_test_and_set_trueval);
+
   /* ptr_type_node can't be used here since ptr_mode is only set when
      toplev calls backend_init which is not done with -E  or pch.  */
   psize = POINTER_SIZE / BITS_PER_UNIT;
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index ceb0d1e..91e4b04 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -11359,3 +11359,7 @@ value of @code{TARGET_CONST_ANCHOR} is a power of 2.  
For example, on
 MIPS, where add-immediate takes a 16-bit signed value,
 @code{TARGET_CONST_ANCHOR} is set to @samp{0x8000}.  The default value
 is zero, which disables this optimization.  @end deftypevr
+
+@deftypevr {Target Hook} {unsigned char} TARGET_ATOMIC_TEST_AND_SET_TRUEVAL
+This value should be set if the result written by @code{atomic_test_and_set} 
is not exactly 1, i.e. the @code{bool} @code{true}.
+@end deftypevr
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index 55c8432..0ebc15d 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -11237,3 +11237,5 @@ value of @code{TARGET_CONST_ANCHOR} is a power of 2.  
For example, on
 MIPS, where add-immediate takes a 16-bit signed value,
 @code{TARGET_CONST_ANCHOR} is set to @samp{0x8000}.  The default value
 is zero, which disables this optimization.  @end deftypevr
+
+@hook TARGET_ATOMIC_TEST_AND_SET_TRUEVAL
diff --git a/gcc/target.def b/gcc/target.def
index f86f782..6084b21 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -2667,6 +2667,13 @@ DEFHOOK
  enum unwind_info_type, (void),
  default_debug_unwind_info)
 
+DEFHOOKPOD
+(atomic_test_and_set_trueval,
+ "This value should be set if the result written by\
+ @code{atomic_test_and_set} is not exactly 1, i.e. the\
+ @code{bool} @code{true}.",
+ unsigned char, 1)
+ 
 /* Leave the boolean fields at the end.  */
 
 /* True if we can create zeroed data by switching to a BSS section
        * include/bits/atomic_base.h (__atomic_flag_base): Define _M_i
        based on the value of __GCC_ATOMIC_TEST_AND_SET_TRUEVAL.
        (ATOMIC_FLAG_INIT): Initialize with 0, not false.
        (atomic_flag::atomic_flag): Use __GCC_ATOMIC_TEST_AND_SET_TRUEVAL.


diff --git a/libstdc++-v3/include/bits/atomic_base.h 
b/libstdc++-v3/include/bits/atomic_base.h
index ef17b7e..aa43bcc 100644
--- a/libstdc++-v3/include/bits/atomic_base.h
+++ b/libstdc++-v3/include/bits/atomic_base.h
@@ -227,12 +227,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   struct __atomic_flag_base
   {
+    /* The target's "set" value for test-and-set may not be exactly 1.  */
+#if __GCC_ATOMIC_TEST_AND_SET_TRUEVAL == 1
     bool _M_i;
+#else
+    unsigned char _M_i;
+#endif
   };
 
   _GLIBCXX_END_EXTERN_C
 
-#define ATOMIC_FLAG_INIT { false }
+#define ATOMIC_FLAG_INIT { 0 }
 
   /// atomic_flag
   struct atomic_flag : public __atomic_flag_base
@@ -244,7 +249,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     atomic_flag& operator=(const atomic_flag&) volatile = delete;
 
     // Conversion to ATOMIC_FLAG_INIT.
-    atomic_flag(bool __i) noexcept : __atomic_flag_base({ __i }) { }
+    constexpr atomic_flag(bool __i) noexcept
+      : __atomic_flag_base({ __i ? __GCC_ATOMIC_TEST_AND_SET_TRUEVAL : 0 })
+    { }
 
     bool
     test_and_set(memory_order __m = memory_order_seq_cst) noexcept
        * gcc.dg/atomic-flag.c: Adjust for __GCC_ATOMIC_TEST_AND_SET_TRUEVAL.


diff --git a/gcc/testsuite/gcc.dg/atomic-flag.c 
b/gcc/testsuite/gcc.dg/atomic-flag.c
index 771df2c..1b76832 100644
--- a/gcc/testsuite/gcc.dg/atomic-flag.c
+++ b/gcc/testsuite/gcc.dg/atomic-flag.c
@@ -1,27 +1,25 @@
 /* Test __atomic routines for existence and execution.  */
 /* { dg-do run } */
 
-#include <stdbool.h>
-
 /* Test that __atomic_test_and_set and __atomic_clear builtins execute.  */
 
 extern void abort(void);
-bool a;
+unsigned char a;
 
 main ()
 {
-  bool b;
+  int b;
 
   __atomic_clear (&a, __ATOMIC_RELAXED);
   if (a != 0)
     abort ();
 
   b = __atomic_test_and_set (&a, __ATOMIC_SEQ_CST);
-  if (a != 1 || b != 0)
+  if (a != __GCC_ATOMIC_TEST_AND_SET_TRUEVAL || b != 0)
     abort ();
 
   b = __atomic_test_and_set (&a, __ATOMIC_ACQ_REL);
-  if (b != 1 || a != 1)
+  if (a != __GCC_ATOMIC_TEST_AND_SET_TRUEVAL || b != 1)
     abort ();
 
   __atomic_clear (&a, __ATOMIC_SEQ_CST);
        * config/sparc/sparc.c (TARGET_ATOMIC_TEST_AND_SET_TRUEVAL): New.
        * config/sparc/sync.md (atomic_test_and_set): Only handle QImode.
        (ldstub): Rename from ldstubqi.
        (ldstub<I24MODE>): Remove.


diff --git a/gcc/config/sparc/sparc.c b/gcc/config/sparc/sparc.c
index 19ab54a..1b3b4c8 100644
--- a/gcc/config/sparc/sparc.c
+++ b/gcc/config/sparc/sparc.c
@@ -779,6 +779,10 @@ char sparc_hard_reg_printed[8];
 #undef TARGET_PRINT_OPERAND_ADDRESS
 #define TARGET_PRINT_OPERAND_ADDRESS sparc_print_operand_address
 
+/* The value stored by LDSTUB.  */
+#undef TARGET_ATOMIC_TEST_AND_SET_TRUEVAL
+#define TARGET_ATOMIC_TEST_AND_SET_TRUEVAL 0xff
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 
 static void
diff --git a/gcc/config/sparc/sync.md b/gcc/config/sparc/sync.md
index be8c4c4..d07d572 100644
--- a/gcc/config/sparc/sync.md
+++ b/gcc/config/sparc/sync.md
@@ -242,25 +242,30 @@
   "swap\t%1, %0"
   [(set_attr "type" "multi")])
 
-(define_expand "atomic_test_and_set<mode>"
-  [(match_operand:I124MODE 0 "register_operand" "")
-   (match_operand:I124MODE 1 "memory_operand" "")
+(define_expand "atomic_test_and_set"
+  [(match_operand:QI 0 "register_operand" "")
+   (match_operand:QI 1 "memory_operand" "")
    (match_operand:SI 2 "const_int_operand" "")]
   ""
 {
   enum memmodel model = (enum memmodel) INTVAL (operands[2]);
+  rtx ret;
 
   sparc_emit_membar_for_model (model, 3, 1);
+  emit_insn (gen_ldstub (operands[0], operands[1]));
+  sparc_emit_membar_for_model (model, 3, 2);
 
-  if (<MODE>mode != QImode)
-    operands[1] = adjust_address (operands[1], QImode, 0);
-  emit_insn (gen_ldstub<mode> (operands[0], operands[1]));
+  /* Convert the 0/0xff result we would otherwise have to a boolean.
+     I.e. ignore all but bit 0.  */
+  ret = expand_simple_binop (QImode, AND, operands[0], const1_rtx,
+                            operands[0], true, OPTAB_LIB_WIDEN);
+  if (ret != operands[0])
+    emit_move_insn (operands[0], ret);
 
-  sparc_emit_membar_for_model (model, 3, 2);
   DONE;
 })
 
-(define_insn "ldstubqi"
+(define_insn "ldstub"
   [(set (match_operand:QI 0 "register_operand" "=r")
        (unspec_volatile:QI [(match_operand:QI 1 "memory_operand" "+m")]
                            UNSPECV_LDSTUB))
@@ -268,13 +273,3 @@
   ""
   "ldstub\t%1, %0"
   [(set_attr "type" "multi")])
-
-(define_insn "ldstub<mode>"
-  [(set (match_operand:I24MODE 0 "register_operand" "=r")
-       (zero_extend:I24MODE
-         (unspec_volatile:QI [(match_operand:QI 1 "memory_operand" "+m")]
-                             UNSPECV_LDSTUB)))
-   (set (match_dup 1) (const_int -1))]
-  ""
-  "ldstub\t%1, %0"
-  [(set_attr "type" "multi")])
        * config/m68k/m68k.c (TARGET_ATOMIC_TEST_AND_SET_TRUEVAL): New.
        * config/m68k/sync.md (atomic_test_and_set): Rename from
        sync_test_and_setqi and adjust the operands.
        (atomic_test_and_set_1): Rename from sync_test_and_setqi_1
        and unconditionally enable.


diff --git a/gcc/config/m68k/m68k.c b/gcc/config/m68k/m68k.c
index e0edd5b..d3ed82b 100644
--- a/gcc/config/m68k/m68k.c
+++ b/gcc/config/m68k/m68k.c
@@ -303,6 +303,10 @@ static void m68k_init_sync_libfuncs (void) 
ATTRIBUTE_UNUSED;
 #undef TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA
 #define TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA m68k_output_addr_const_extra
 
+/* The value stored by TAS.  */
+#undef TARGET_ATOMIC_TEST_AND_SET_TRUEVAL
+#define TARGET_ATOMIC_TEST_AND_SET_TRUEVAL 128
+
 static const struct attribute_spec m68k_attribute_table[] =
 {
   /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
diff --git a/gcc/config/m68k/sync.md b/gcc/config/m68k/sync.md
index a40a5bf..5d5002a 100644
--- a/gcc/config/m68k/sync.md
+++ b/gcc/config/m68k/sync.md
@@ -56,25 +56,23 @@
   ;; Elide the seq if operands[0] is dead.
   "cas<sz> %1,%4,%2\;seq %0")
 
-(define_expand "sync_test_and_setqi"
-  [(match_operand:QI 0 "register_operand" "")
-   (match_operand:QI 1 "memory_operand" "")
-   (match_operand:QI 2 "general_operand" "")]
-  "!TARGET_CAS"
+(define_expand "atomic_test_and_set"
+  [(match_operand:QI 0 "register_operand" "")          ;; bool success output
+   (match_operand:QI 1 "memory_operand" "")            ;; memory
+   (match_operand:SI 2 "const_int_operand" "")]                ;; model
+  ""
 {
-  if (operands[2] != const1_rtx)
-    FAIL;
-  emit_insn (gen_sync_test_and_setqi_1 (operands[0], operands[1]));
+  emit_insn (gen_atomic_test_and_set_1 (operands[0], operands[1]));
   emit_insn (gen_negqi2 (operands[0], operands[0]));
   DONE;
 })
 
-(define_insn "sync_test_and_setqi_1"
+(define_insn "atomic_test_and_set_1"
   [(set (match_operand:QI 0 "register_operand" "=d")
        (unspec_volatile:QI
          [(match_operand:QI 1 "memory_operand" "+m")]
          UNSPECV_TAS_1))
    (set (match_dup 1)
        (unspec_volatile:QI [(match_dup 1)] UNSPECV_TAS_2))]
-  "!TARGET_CAS"
+  ""
   "tas %1\;sne %0")

Reply via email to