[RFC] libstdc++ atomic_flag changes

2012-01-24 Thread Richard Henderson
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;

Re: [RFC] libstdc++ atomic_flag changes

2012-01-24 Thread Benjamin Kosnik

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

Looks fine to me.

-benjamin