The C atomic_init macro is implemented in terms of simple assignment
to the atomic variable pointed to by its first argument.  That's
inefficient since the variable under initialization must not be
accessed by other threads and assignment provides sequentially
consistent semantics.  The inefficiency is apparent in the generated
dumps (e.g. the gimple dump contains calls to __atomic_store (...,
memory_order_seq_cst), and the assembly dump contains the fence
instruction).

The attached patch changes the macro to use atomic_store with relaxed
consistency semantics and adds a test verifying that invocations of
the atomic_init macro emit __atomic_store_N with a zero last argument
(memory_order_relaxed).

This brings GCC on par with Clang.

Tested on powerpc64le and x86_64.

Martin
gcc/ChangeLog
2015-12-14  Martin Sebor  <mse...@redhat.com>

	PR c/68868
	* ginclude/stdatomic.h (atomic_init): Use atomic_store instead
	of plain assignment.

gcc/testsuite/ChangeLog
2015-12-14  Martin Sebor  <mse...@redhat.com>

	PR c/68868
	* testsuite/gcc.dg/atomic/stdatomic-init.c: New test.

Index: ginclude/stdatomic.h
===================================================================
--- ginclude/stdatomic.h	(revision 231532)
+++ ginclude/stdatomic.h	(working copy)
@@ -77,13 +77,11 @@
 
 
 #define ATOMIC_VAR_INIT(VALUE)	(VALUE)
-#define atomic_init(PTR, VAL)			\
-  do						\
-    {						\
-      *(PTR) = (VAL);				\
-    }						\
-  while (0)
 
+/* Initialize an atomic object pointed to by PTR with VAL.  */
+#define atomic_init(PTR, VAL)                                           \
+  atomic_store_explicit (PTR, VAL, __ATOMIC_RELAXED)
+
 #define kill_dependency(Y)			\
   __extension__					\
   ({						\
Index: testsuite/gcc.dg/atomic/stdatomic-init.c
===================================================================
--- testsuite/gcc.dg/atomic/stdatomic-init.c	(revision 0)
+++ testsuite/gcc.dg/atomic/stdatomic-init.c	(working copy)
@@ -0,0 +1,121 @@
+/* Test the atomic_init generic function.  Verify that __atomic_store_N
+   is called with the last argument of memory_order_relaxed (i.e., 0)
+   for each invocation of the atomic_init() macro in the test and that
+   there are no calls to __atomic_store_N with a non-zero last argument.  */
+/* { dg-do compile } */
+/* { dg-options "-fdump-tree-gimple -std=c11 -pedantic-errors" } */
+/* { dg-final { scan-tree-dump-times "__atomic_store_. \\(\[^\n\r]*, 0\\)" 54 "gimple" } } */
+/* { dg-final { scan-tree-dump-not "__atomic_store_. \\(\[^\n\r]*, \[1-5\]\\)" "gimple" } } */
+
+#include <stdatomic.h>
+
+struct Atomic {
+  /* Volatile to prevent re-initialization from being optimized away.  */
+  volatile atomic_bool   b;
+  volatile atomic_char   c;
+  volatile atomic_schar  sc;
+  volatile atomic_uchar  uc;
+  volatile atomic_short  ss;
+  volatile atomic_ushort us;
+  volatile atomic_int    si;
+  volatile atomic_uint   ui;
+  volatile atomic_long   sl;
+  volatile atomic_ulong  ul;
+  volatile atomic_llong  sll;
+  volatile atomic_ullong ull;
+  volatile atomic_size_t sz;
+};
+
+struct Value {
+  _Bool              b;
+  char               c;
+  signed char        sc;
+  unsigned char      uc;
+  short              ss;
+  unsigned short     us;
+  int                si;
+  unsigned int       ui;
+  long               sl;
+  unsigned long      ul;
+  long long          sll;
+  unsigned long long ull;
+  __SIZE_TYPE__      sz;
+};
+
+/* Exercise the atomic_init() macro with a literal argument.  */
+
+void atomic_init_lit (struct Atomic *pa)
+{
+  atomic_init (&pa->b, 0);
+  atomic_init (&pa->b, 1);
+
+  atomic_init (&pa->c, 'x');
+  atomic_init (&pa->c, 0);
+  atomic_init (&pa->c, 1);
+  atomic_init (&pa->c, 255);
+  
+  atomic_init (&pa->sc, (signed char)'x');
+  atomic_init (&pa->sc, (signed char)0);
+  atomic_init (&pa->sc, (signed char)1);
+  atomic_init (&pa->sc, (signed char)__SCHAR_MAX__);
+
+  atomic_init (&pa->uc, (unsigned char)'x');
+  atomic_init (&pa->uc, (unsigned char)0);
+  atomic_init (&pa->uc, (unsigned char)1);
+  atomic_init (&pa->sc, (unsigned char)__SCHAR_MAX__);
+
+  atomic_init (&pa->ss, (signed short)0);
+  atomic_init (&pa->ss, (signed short)1);
+  atomic_init (&pa->ss, (signed short)__SHRT_MAX__);
+
+  atomic_init (&pa->us, (unsigned short)0);
+  atomic_init (&pa->us, (unsigned short)1);
+  atomic_init (&pa->us, (unsigned short)__SHRT_MAX__);
+
+  atomic_init (&pa->si, (signed int)0);
+  atomic_init (&pa->si, (signed int)1);
+  atomic_init (&pa->si, (signed int)__INT_MAX__);
+
+  atomic_init (&pa->ui, (unsigned int)0);
+  atomic_init (&pa->ui, (unsigned int)1);
+  atomic_init (&pa->ui, (unsigned int)__INT_MAX__);
+  
+  atomic_init (&pa->sl, (signed long)0);
+  atomic_init (&pa->sl, (signed long)1);
+  atomic_init (&pa->sl, (signed long)__LONG_MAX__);
+
+  atomic_init (&pa->ul, (unsigned long)0);
+  atomic_init (&pa->ul, (unsigned long)1);
+  atomic_init (&pa->ul, (unsigned long)__LONG_MAX__);
+
+  atomic_init (&pa->sll, (signed long long)0);
+  atomic_init (&pa->sll, (signed long long)1);
+  atomic_init (&pa->sll, (signed long long)__LONG_LONG_MAX__);
+
+  atomic_init (&pa->ull, (unsigned long long)0);
+  atomic_init (&pa->ull, (unsigned long long)1);
+  atomic_init (&pa->ull, (unsigned long long)__LONG_LONG_MAX__); 
+
+  atomic_init (&pa->sz, 0);
+  atomic_init (&pa->sz, 1);
+  atomic_init (&pa->sz, __SIZE_MAX__); 
+}
+
+/* Exercise the atomic_init() macro with an lvalue argument.  */
+
+void atomic_init_lval (struct Atomic *pa, const struct Value *pv)
+{
+  atomic_init (&pa->b, pv->b);
+  atomic_init (&pa->c, pv->c);
+  atomic_init (&pa->sc, pv->sc);
+  atomic_init (&pa->uc, pv->uc);
+  atomic_init (&pa->ss, pv->ss);
+  atomic_init (&pa->us, pv->us);
+  atomic_init (&pa->si, pv->si);
+  atomic_init (&pa->ui, pv->ui); 
+  atomic_init (&pa->sl, pv->sl);
+  atomic_init (&pa->ul, pv->ul);
+  atomic_init (&pa->sll, pv->sll);
+  atomic_init (&pa->ull, pv->ull);
+  atomic_init (&pa->sz, pv->sz);
+}

Reply via email to