The issue that I'm trying to solve is that we will have at least two targets
whose test-and-set insn does not define "set" as 1, as a variable of type
"bool" would expect. In the case of Sparc we *could* make the test-and-set
implementation test for any non-zero value, but in the case of m68k the hw will
only test-and-set the msb of the byte.
This compiles on x86_64, and is still undergoing testing, but I wanted to get
this out before Ben quits for the day. ;-)
Notes:
* I try to leave _M_i as bool if at all possible,
as this gives the best information to the debugger.
* The suggestion on IRC to derive private from __atomic_flag_base
falls afoul of src/c++11/compatibility-atomic-c++0x.cc.
I'll leave any possible cleanup here to libstdc++ maintainers. ;-)
* The changes to the target files actually depend on outstanding patches
in my tree. But at least show where the problems would lie.
Did I miss anything?
r~
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/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/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/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
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;