public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* Implement C11 _Atomic
@ 2013-11-06  0:44 Joseph S. Myers
  2013-11-06 22:42 ` Andrew MacLeod
                   ` (3 more replies)
  0 siblings, 4 replies; 30+ messages in thread
From: Joseph S. Myers @ 2013-11-06  0:44 UTC (permalink / raw)
  To: gcc-patches
  Cc: amacleod, mikestump, stanshebs, jason, rth, jh, ubizjak, jakub

[-- Attachment #1: Type: text/plain, Size: 189034 bytes --]

This patch, relative to trunk and based on work done on the C11-atomic
branch, adds support for C11 _Atomic.  It is intended to include all
the required language support.

It does not include the <stdatomic.h> header; there's a version on the
branch, but it needs further review against the standard and test
coverage adding to the testsuite before I can propose it for mainline.

Support for atomic types having bigger alignment than the
corresponding non-atomic types is limited: it includes the code to
increase the alignment of types whose size is exactly 1, 2, 4, 8 or 16
to that of the corresponding integer type [*], but not anything for
target-specific alignment increases.  There's code for target-specific
alignment on the branch (and I intend to merge trunk back to the
branch once this patch is on trunk, so it's easy to tell what the
changes still left on the branch are), should any target maintainers
wish to have such alignment.  Note however that ideally libstdc++
atomics would be ABI-compatible with C atomics, requiring them to get
the same alignment; the branch has an "atomic" attribute for that
purpose, but I think further work on the C++ front-end changes would
be needed for them to be ready for mainline.

[*] The c-common.c code to resolve size-generic atomic built-in
functions to size-specific ones assumes that types are naturally
aligned (and so resolves to calls to the size-specific functions that
require natural alignment) without checking it.  If users should be
able to use the size-generic functions on types with lesser alignment,
e.g. _Complex double (8-byte rather than 16-byte aligned), rather than
just on their _Atomic variants, this is of course a bug in the code
resolving those built-in functions.  (The libatomic functions properly
check for alignment at runtime.)  But it seems reasonable enough
anyway to make _Atomic _Complex double 16-byte aligned.

Full use of _Atomic requires linking with libatomic, if you're doing
any atomic operations that aren't fully expanded inline; arguably
libatomic should be linked in by default with --as-needed (given that
previously ordinary C code didn't require the user to link any
libraries explicitly unless they directly called library functions),
but that's independent of this patch.  Correct handling of atomic
compound assignment for floating-point types also requires built-in
support for floating-point environment manipulation operations roughly
equivalent to feholdexcept, feclearexcept and feupdateenv (built-ins
are used to avoid introducing libm dependencies, which generic C code
not actually calling libm library functions shouldn't require); this
patch includes such support for x86 [*], and I expect other
architectures to be simpler.  If you don't have a libatomic port, the
execution tests for _Atomic simply won't be run; if you have libatomic
but not the floating-point support, the tests will be run but
c11-atomic-exec-5.c will fail (assuming the library features are
present for that test to run at all - it also requires pthreads).

[*] This could be optimized if desired by passing the types in
question to the target hook so it can generate code for only one of
x87 and SSE in most cases, much like an optimization present in glibc
when it internally does feholdexcept / fesetenv / feupdateenv
sequences.

_Atomic support is currently disabled for Objective-C and OpenMP.  For
both (but mainly OpenMP), the relevant parser code needs checking to
determine where convert_lvalue_to_rvalue calls need inserting to
ensure that accesses to atomic variables involve atomic loads.  For
Objective-C, there are also various special cases of compound
assignment that need special handling for atomics just as standard C
compound assignment is handled differently for atomics, as well as
some TYPE_MAIN_VARIANT calls to check for correctness for atomics; see
the comment on the relevant sorry () call for details.  OpenMP should
also have TYPE_MAIN_VARIANT uses checked as well as a use of
TYPE_QUALS_NO_ADDR_SPACE for a diagnostic in
c_parser_omp_declare_reduction (where the diagnostic refers to a
particular list of qualifiers).

Bootstrapped with no regressions on x86_64-unknown-linux-gnu.  OK to
commit (the various non-front-end pieces)?

gcc:
2013-11-05  Andrew MacLeod  <amacleod@redhat.com>
	    Joseph Myers  <joseph@codesourcery.com>

	* tree-core.h (enum cv_qualifier): Add TYPE_QUAL_ATOMIC.
	(enum tree_index): Add TI_ATOMICQI_TYPE, TI_ATOMICHI_TYPE,
	TI_ATOMICSI_TYPE, TI_ATOMICDI_TYPE and TI_ATOMICTI_TYPE.
	(struct tree_base): Add atomic_flag field.
	* tree.h (TYPE_ATOMIC): New accessor macro.
	(TYPE_QUALS, TYPE_QUALS_NO_ADDR_SPACE): Add TYPE_QUAL_ATOMIC.
	(TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC): New macro.
	(atomicQI_type_node, atomicHI_type_node, atomicSI_type_node)
	(atomicDI_type_node, atomicTI_type_node): New macros for type
	nodes.
	* tree.c (set_type_quals): Set TYPE_ATOMIC.
	(find_atomic_core_type): New function.
	(build_qualified_type): Adjust alignment for qualified types.
	(build_atomic_base): New function
	(build_common_tree_nodes): Build atomicQI_type_node,
	atomicHI_type_node, atomicSI_type_node, atomicDI_type_node and
	atomicTI_type_node.
	* print-tree.c (print_node): Print atomic qualifier.
	* tree-pretty-print.c (dump_generic_node): Print atomic type
	attribute.
	* target.def (atomic_assign_expand_fenv): New hook.
	* doc/tm.texi.in (TARGET_ATOMIC_ASSIGN_EXPAND_FENV): New @hook.
	* doc/tm.texi: Regenerate.
	* targhooks.c (default_atomic_assign_expand_fenv): New function.
	* targhooks.h (default_atomic_assign_expand_fenv): Declare.
	* sync-builtins.def (__atomic_feraiseexcept): New built-in
	function.
	* config/i386/i386-builtin-types.def (VOID_FTYPE_PUSHORT): New
	function type.
	* config/i386/i386.c (enum ix86_builtins): Add
	IX86_BUILTIN_FNSTENV, IX86_BUILTIN_FLDENV, IX86_BUILTIN_FNSTSW and
	IX86_BUILTIN_FNCLEX.
	(bdesc_special_args): Add __builtin_ia32_fnstenv,
	__builtin_ia32_fldenv, __builtin_ia32_fnstsw and
	__builtin_ia32_fnclex.
	(ix86_expand_builtin): Handle the new built-in functions.
	(ix86_atomic_assign_expand_fenv): New function.
	(TARGET_ATOMIC_ASSIGN_EXPAND_FENV): New macro.
	* config/i386/i386.md (UNSPECV_FNSTENV, UNSPECV_FLDENV)
	(UNSPECV_FNSTSW, UNSPECV_FNCLEX): New unspecs.
	(fnstenv, fldenv, fnstsw, fnclex): New insns.

gcc/c-family:
2013-11-05  Andrew MacLeod  <amacleod@redhat.com>
	    Joseph Myers  <joseph@codesourcery.com>

	* c-common.h (enum rid): Add RID_ATOMIC.
	* c-common.c (c_common_reswords): Add _Atomic.
	(sync_resolve_params): Use TYPE_MAIN_VARIANT on pointer argument.
	(keyword_is_type_qualifier): Accept RID_ATOMIC.
	* c-format.c (check_format_types): Check for extra _Atomic
	qualifiers in format argument.
	* c-pretty-print.c (pp_c_cv_qualifiers): Handle atomic qualifier.
	(pp_c_type_qualifier_list): Mention _Atomic in comment.

gcc/c:
2013-11-05  Joseph Myers  <joseph@codesourcery.com>
	    Andrew MacLeod  <amacleod@redhat.com>

	* c-aux-info.c (gen_type): Handle atomic qualifier.
	* c-decl.c (validate_proto_after_old_defn): Do not remove atomic
	qualifiers when compating types.
	(shadow_tag_warned): Handle atomic_p in declspecs.
	(quals_from_declspecs): Likewise.
	(start_decl): Use c_type_promotes_to when promoting argument
	types.
	(grokdeclarator): Handle _Atomic.
	(get_parm_info): Diagnose any qualifier on "void" as only
	parameter.
	(store_parm_decls_oldstyle): Do not remove atomic qualifiers when
	comparing types.  Use c_type_promotes_to when promoting argument
	types.
	(finish_function): Use c_type_promotes_to when promoting argument
	types.
	(build_null_declspecs): Handle atomic_p in declspecs.
	(declspecs_add_qual): Handle RID_ATOMIC.
	* c-parser.c (c_token_starts_typename, c_token_is_qualifier)
	(c_token_starts_declspecs): Handle RID_ATOMIC.
	(c_parser_declspecs): Handle atomic type specifiers and
	qualifiers.
	(c_parser_typeof_specifier): Remove const and _Atomic qualifiers
	from types of expressions with atomic type.
	(c_parser_direct_declarator_inner): Use convert_lvalue_to_rvalue.
	(c_parser_attribute_any_word): Handle RID_ATOMIC.
	(c_parser_initializer, c_parser_initelt, c_parser_initval)
	(c_parser_statement_after_labels, c_parser_switch_statement)
	(c_parser_for_statement, c_parser_expr_no_commas)
	(c_parser_conditional_expression, c_parser_binary_expression)
	(c_parser_cast_expression, c_parser_unary_expression)
	(c_parser_postfix_expression)
	(c_parser_postfix_expression_after_primary, c_parser_expression):
	Use convert_lvalue_to_rvalue.
	(c_parser_expression_conv, c_parser_expr_list): Document
	conversion of lvalues to rvalues.  Use convert_lvalue_to_rvalue.
	(c_parser_objc_synchronized_statement): Use
	convert_lvalue_to_rvalue.
	(c_parser_objc_selector): Handle RID_ATOMIC.
	(c_parser_objc_receiver, c_parser_array_notation): Use
	convert_lvalue_to_rvalue.
	* c-tree.h (ctsk_typeof): Adjust comment to mention use for
	_Atomic (type-name).
	(struct c_declspecs): Add atomic_p field.
	(convert_lvalue_to_rvalue): Declare.
	* c-typeck.c (c_type_promotes_to): Promote atomic types to
	corresponding atomic types.
	(qualify_type): Don't add _Atomic qualifiers from second argument.
	(comp_target_types): Do not allow _Atomic mismatches.
	(type_lists_compatible_p): Do not remove atomic qualifiers when
	comparing types.
	(really_atomic_lvalue, convert_lvalue_to_rvalue)
	(build_atomic_assign): New functions.
	(build_unary_op): Use build_atomic_assign for atomic increment and
	decrement.
	(build_conditional_expr): Do not treat _Atomic void as a qualified
	version of void.
	(build_modify_expr): Use build_atomic_assign for atomic LHS.
	(find_anonymous_field_with_type, convert_to_anonymous_field)
	(convert_for_assignment): Do not remove atomic qualifiers when
	comparing types.
	(digest_init): Do not accept initialization of arrays of atomic
	elements by string constants.
	(build_asm_expr): Use convert_lvalue_to_rvalue.
	(build_binary_op): Do not treat _Atomic void as a qualified
	version of void.

gcc/objc:
2013-11-05  Andrew MacLeod  <amacleod@redhat.com>

	* objc-act.c (objc_push_parm): Handle atomic qualifier.

gcc/testsuite:
2013-11-05  Joseph Myers  <joseph@codesourcery.com>

	* lib/target-supports.exp
	(check_effective_target_fenv_exceptions): New function.
	* lib/atomic-dg.exp, gcc.dg/atomic/atomic.exp: New files.
	* gcc.dg/atomic/c11-atomic-exec-1.c,
	gcc.dg/atomic/c11-atomic-exec-2.c,
	gcc.dg/atomic/c11-atomic-exec-3.c,
	gcc.dg/atomic/c11-atomic-exec-4.c,
	gcc.dg/atomic/c11-atomic-exec-5.c, gcc.dg/c11-atomic-1.c,
	gcc.dg/c11-atomic-2.c, gcc.dg/c11-atomic-3.c,
	gcc.dg/c90-atomic-1.c, gcc.dg/c99-atomic-1.c: New tests.

libatomic:
2013-11-05  Joseph Myers  <joseph@codesourcery.com>

	* fenv.c: New file.
	* libatomic.map (LIBATOMIC_1.1): New symbol version.  Include
	__atomic_feraiseexcept.
	* configure.ac (libtool_VERSION): Change to 2:0:1.
	(fenv.h): Test for header.
	* Makefile.am (libatomic_la_SOURCES): Add fenv.c.
	* Makefile.in, auto-config.h.in, configure: Regenerate.

Index: libatomic/fenv.c
===================================================================
--- libatomic/fenv.c	(revision 0)
+++ libatomic/fenv.c	(revision 0)
@@ -0,0 +1,72 @@
+/* Copyright (C) 2012-2013 Free Software Foundation, Inc.
+
+   This file is part of the GNU Atomic Library (libatomic).
+
+   Libatomic is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   Libatomic is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+   FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+   more details.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include "libatomic_i.h"
+
+#ifdef HAVE_FENV_H
+# include <fenv.h>
+#endif
+
+/* Raise the supported floating-point exceptions from EXCEPTS.  Other
+   bits in EXCEPTS are ignored.  */
+
+void
+__atomic_feraiseexcept (int excepts __attribute__ ((unused)))
+{
+  volatile float r __attribute__ ((unused));
+#ifdef FE_INVALID
+  if (excepts & FE_INVALID)
+  {
+    volatile float zero = 0.0f;
+    r = zero / zero;
+  }
+#endif
+#ifdef FE_DIVBYZERO
+  if (excepts & FE_DIVBYZERO)
+    {
+      volatile float zero = 0.0f;
+      r = 1.0f / zero;
+    }
+#endif
+#ifdef FE_OVERFLOW
+  if (excepts & FE_OVERFLOW)
+    {
+      volatile float max = __FLT_MAX__;
+      r = max * max;
+    }
+#endif
+#ifdef FE_UNDERFLOW
+  if (excepts & FE_UNDERFLOW)
+    {
+      volatile float min = __FLT_MIN__;
+      r = min * min;
+    }
+#endif
+#ifdef FE_INEXACT
+  if (excepts & FE_INEXACT)
+    {
+      volatile float three = 3.0f;
+      r = 1.0f / three;
+    }
+#endif
+}
Index: libatomic/configure.ac
===================================================================
--- libatomic/configure.ac	(revision 204390)
+++ libatomic/configure.ac	(working copy)
@@ -148,7 +148,7 @@ AC_SUBST(enable_static)
 AM_MAINTAINER_MODE
 
 # For libtool versioning info, format is CURRENT:REVISION:AGE
-libtool_VERSION=1:0:0
+libtool_VERSION=2:0:1
 AC_SUBST(libtool_VERSION)
 
 # Get target configury.
@@ -165,6 +165,7 @@ CFLAGS="$save_CFLAGS -fno-sync-libcalls $XCFLAGS"
 AC_STDC_HEADERS
 ACX_HEADER_STRING
 GCC_HEADER_STDINT(gstdint.h)
+AC_CHECK_HEADERS([fenv.h])
 
 # Check for common type sizes
 LIBAT_FORALL_MODES([LIBAT_HAVE_INT_MODE])
Index: libatomic/auto-config.h.in
===================================================================
--- libatomic/auto-config.h.in	(revision 204390)
+++ libatomic/auto-config.h.in	(working copy)
@@ -105,6 +105,9 @@
 /* Define to 1 if you have the <dlfcn.h> header file. */
 #undef HAVE_DLFCN_H
 
+/* Define to 1 if you have the <fenv.h> header file. */
+#undef HAVE_FENV_H
+
 /* Define to 1 if the target supports __attribute__((ifunc(...))). */
 #undef HAVE_IFUNC
 
Index: libatomic/Makefile.am
===================================================================
--- libatomic/Makefile.am	(revision 204390)
+++ libatomic/Makefile.am	(working copy)
@@ -67,7 +67,8 @@ endif
 libatomic_version_info = -version-info $(libtool_VERSION)
 
 libatomic_la_LDFLAGS = $(libatomic_version_info) $(libatomic_version_script)
-libatomic_la_SOURCES = gload.c gstore.c gcas.c gexch.c glfree.c lock.c init.c
+libatomic_la_SOURCES = gload.c gstore.c gcas.c gexch.c glfree.c lock.c init.c \
+	fenv.c
 
 SIZEOBJS = load store cas exch fadd fsub fand fior fxor fnand tas
 SIZES = @SIZES@
Index: libatomic/libatomic.map
===================================================================
--- libatomic/libatomic.map	(revision 204390)
+++ libatomic/libatomic.map	(working copy)
@@ -95,3 +95,7 @@ LIBATOMIC_1.0 {
   local:
 	*;
 };
+LIBATOMIC_1.1 {
+  global:
+	__atomic_feraiseexcept;
+} LIBATOMIC_1.0;
Index: libatomic/configure
===================================================================
--- libatomic/configure	(revision 204390)
+++ libatomic/configure	(working copy)
@@ -2000,6 +2000,93 @@ rm -f conftest.val
   return $ac_retval
 
 } # ac_fn_c_compute_int
+
+# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists, giving a warning if it cannot be compiled using
+# the include files in INCLUDES and setting the cache variable VAR
+# accordingly.
+ac_fn_c_check_header_mongrel ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then :
+  $as_echo_n "(cached) " >&6
+fi
+eval ac_res=\$$3
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+else
+  # Is the header compilable?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5
+$as_echo_n "checking $2 usability... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_header_compiler=yes
+else
+  ac_header_compiler=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5
+$as_echo "$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5
+$as_echo_n "checking $2 presence... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <$2>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+  ac_header_preproc=yes
+else
+  ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5
+$as_echo "$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #((
+  yes:no: )
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5
+$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+    ;;
+  no:yes:* )
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5
+$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2:     check for missing prerequisite headers?" >&5
+$as_echo "$as_me: WARNING: $2:     check for missing prerequisite headers?" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5
+$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2:     section \"Present But Cannot Be Compiled\"" >&5
+$as_echo "$as_me: WARNING: $2:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+    ;;
+esac
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then :
+  $as_echo_n "(cached) " >&6
+else
+  eval "$3=\$ac_header_compiler"
+fi
+eval ac_res=\$$3
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+fi
+  eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+
+} # ac_fn_c_check_header_mongrel
 cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
@@ -11019,7 +11106,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11022 "configure"
+#line 11109 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -11125,7 +11212,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11128 "configure"
+#line 11215 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -11389,7 +11476,7 @@ fi
 
 
 # For libtool versioning info, format is CURRENT:REVISION:AGE
-libtool_VERSION=1:0:0
+libtool_VERSION=2:0:1
 
 
 # Get target configury.
@@ -11953,7 +12040,19 @@ ac_config_commands="$ac_config_commands gstdint.h"
 
 
 
+for ac_header in fenv.h
+do :
+  ac_fn_c_check_header_mongrel "$LINENO" "fenv.h" "ac_cv_header_fenv_h" "$ac_includes_default"
+if test "x$ac_cv_header_fenv_h" = x""yes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_FENV_H 1
+_ACEOF
 
+fi
+
+done
+
+
 # Check for common type sizes
 
   { $as_echo "$as_me:${as_lineno-$LINENO}: checking for 1 byte integer" >&5
Index: libatomic/Makefile.in
===================================================================
--- libatomic/Makefile.in	(revision 204390)
+++ libatomic/Makefile.in	(working copy)
@@ -90,14 +90,14 @@ am__base_list = \
 am__installdirs = "$(DESTDIR)$(toolexeclibdir)"
 LTLIBRARIES = $(noinst_LTLIBRARIES) $(toolexeclib_LTLIBRARIES)
 am_libatomic_la_OBJECTS = gload.lo gstore.lo gcas.lo gexch.lo \
-	glfree.lo lock.lo init.lo
+	glfree.lo lock.lo init.lo fenv.lo
 libatomic_la_OBJECTS = $(am_libatomic_la_OBJECTS)
 libatomic_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
 	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
 	$(libatomic_la_LDFLAGS) $(LDFLAGS) -o $@
 libatomic_convenience_la_DEPENDENCIES = $(libatomic_la_LIBADD)
 am__objects_1 = gload.lo gstore.lo gcas.lo gexch.lo glfree.lo lock.lo \
-	init.lo
+	init.lo fenv.lo
 am_libatomic_convenience_la_OBJECTS = $(am__objects_1)
 libatomic_convenience_la_OBJECTS =  \
 	$(am_libatomic_convenience_la_OBJECTS)
@@ -286,7 +286,9 @@ noinst_LTLIBRARIES = libatomic_convenience.la
 @LIBAT_BUILD_VERSIONED_SHLIB_SUN_TRUE@@LIBAT_BUILD_VERSIONED_SHLIB_TRUE@libatomic_version_dep = libatomic.map-sun
 libatomic_version_info = -version-info $(libtool_VERSION)
 libatomic_la_LDFLAGS = $(libatomic_version_info) $(libatomic_version_script)
-libatomic_la_SOURCES = gload.c gstore.c gcas.c gexch.c glfree.c lock.c init.c
+libatomic_la_SOURCES = gload.c gstore.c gcas.c gexch.c glfree.c lock.c init.c \
+	fenv.c
+
 SIZEOBJS = load store cas exch fadd fsub fand fior fxor fnand tas
 EXTRA_libatomic_la_SOURCES = $(addsuffix _n.c,$(SIZEOBJS))
 libatomic_la_DEPENDENCIES = $(libatomic_la_LIBADD) $(libatomic_version_dep)
@@ -425,6 +427,7 @@ mostlyclean-compile:
 distclean-compile:
 	-rm -f *.tab.c
 
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fenv.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gcas.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gexch.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glfree.Plo@am__quote@
Index: gcc/sync-builtins.def
===================================================================
--- gcc/sync-builtins.def	(revision 204390)
+++ gcc/sync-builtins.def	(working copy)
@@ -606,3 +606,9 @@ DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_SIGNAL_FENCE,
 		  "__atomic_signal_fence",
 		  BT_FN_VOID_INT, ATTR_NOTHROW_LEAF_LIST)
 
+/* This one is actually a function in libatomic and not expected to be
+   inlined, declared here for convenience of targets generating calls
+   to it.  */
+DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FERAISEEXCEPT,
+		  "__atomic_feraiseexcept",
+		  BT_FN_VOID_INT, ATTR_LEAF_LIST)
Index: gcc/target.def
===================================================================
--- gcc/target.def	(revision 204390)
+++ gcc/target.def	(working copy)
@@ -5279,7 +5279,27 @@ DEFHOOKPOD
  @code{atomic_test_and_set} is not exactly 1, i.e. the\
  @code{bool} @code{true}.",
  unsigned char, 1)
- 
+
+DEFHOOK
+(atomic_assign_expand_fenv,
+"ISO C11 requires atomic compound assignments that may raise floating-point\
+ exceptions to raise exceptions corresponding to the arithmetic operation\
+ whose result was successfully stored in a compare-and-exchange sequence. \
+ This requires code equivalent to calls to @code{feholdexcept},\
+ @code{feclearexcept} and @code{feupdateenv} to be generated at\
+ appropriate points in the compare-and-exchange sequence.  This hook should\
+ set @code{*@var{hold}} to an expression equivalent to the call to\
+ @code{feholdexcept}, @code{*@var{clear}} to an expression equivalent to\
+ the call to @code{feclearexcept} and @code{*@var{update}} to an expression\
+ equivalent to the call to @code{feupdateenv}.  The three expressions are\
+ @code{NULL_TREE} on entry to the hook and may be left as @code{NULL_TREE}\
+ if no code is required in a particular place.  The default implementation\
+ leaves all three expressions as @code{NULL_TREE}.  The\
+ @code{__atomic_feraiseexcept} function from @code{libatomic} may be of use\
+ as part of the code generated in @code{*@var{update}}.",
+ void, (tree *hold, tree *clear, tree *update),
+ default_atomic_assign_expand_fenv)
+
 /* Leave the boolean fields at the end.  */
 
 /* True if we can create zeroed data by switching to a BSS section
Index: gcc/doc/tm.texi
===================================================================
--- gcc/doc/tm.texi	(revision 204390)
+++ gcc/doc/tm.texi	(working copy)
@@ -11485,3 +11485,7 @@ It returns true if the target supports GNU indirec
 The support includes the assembler, linker and dynamic linker.
 The default value of this hook is based on target's libc.
 @end deftypefn
+
+@deftypefn {Target Hook} void TARGET_ATOMIC_ASSIGN_EXPAND_FENV (tree *@var{hold}, tree *@var{clear}, tree *@var{update})
+ISO C11 requires atomic compound assignments that may raise floating-point exceptions to raise exceptions corresponding to the arithmetic operation whose result was successfully stored in a compare-and-exchange sequence.  This requires code equivalent to calls to @code{feholdexcept}, @code{feclearexcept} and @code{feupdateenv} to be generated at appropriate points in the compare-and-exchange sequence.  This hook should set @code{*@var{hold}} to an expression equivalent to the call to @code{feholdexcept}, @code{*@var{clear}} to an expression equivalent to the call to @code{feclearexcept} and @code{*@var{update}} to an expression equivalent to the call to @code{feupdateenv}.  The three expressions are @code{NULL_TREE} on entry to the hook and may be left as @code{NULL_TREE} if no code is required in a particular place.  The default implementation leaves all three expressions as @code{NULL_TREE}.  The @code{__atomic_feraiseexcept} function from @code{libatomic} may be of use as part of the code generated in @code{*@var{update}}.
+@end deftypefn
Index: gcc/doc/tm.texi.in
===================================================================
--- gcc/doc/tm.texi.in	(revision 204390)
+++ gcc/doc/tm.texi.in	(working copy)
@@ -8404,3 +8404,5 @@ and the associated definitions of those functions.
 @hook TARGET_ATOMIC_TEST_AND_SET_TRUEVAL
 
 @hook TARGET_HAS_IFUNC_P
+
+@hook TARGET_ATOMIC_ASSIGN_EXPAND_FENV
Index: gcc/c-family/c-pretty-print.c
===================================================================
--- gcc/c-family/c-pretty-print.c	(revision 204390)
+++ gcc/c-family/c-pretty-print.c	(working copy)
@@ -179,8 +179,16 @@ pp_c_cv_qualifiers (c_pretty_printer *pp, int qual
   if (p != NULL && (*p == '*' || *p == '&'))
     pp_c_whitespace (pp);
 
+  if (qualifiers & TYPE_QUAL_ATOMIC)
+    {
+      pp_c_ws_string (pp, "_Atomic");
+      previous = true;
+    }
+
   if (qualifiers & TYPE_QUAL_CONST)
     {
+      if (previous)
+        pp_c_whitespace (pp);
       pp_c_ws_string (pp, func_type ? "__attribute__((const))" : "const");
       previous = true;
     }
@@ -244,6 +252,7 @@ pp_c_space_for_pointer_operator (c_pretty_printer
        __restrict__                          -- GNU C
        address-space-qualifier		     -- GNU C
        volatile
+       _Atomic                               -- C11
 
    address-space-qualifier:
        identifier			     -- GNU C  */
Index: gcc/c-family/c-common.c
===================================================================
--- gcc/c-family/c-common.c	(revision 204390)
+++ gcc/c-family/c-common.c	(working copy)
@@ -409,6 +409,7 @@ const struct c_common_resword c_common_reswords[]
 {
   { "_Alignas",		RID_ALIGNAS,   D_CONLY },
   { "_Alignof",		RID_ALIGNOF,   D_CONLY },
+  { "_Atomic",		RID_ATOMIC,    D_CONLY },
   { "_Bool",		RID_BOOL,      D_CONLY },
   { "_Complex",		RID_COMPLEX,	0 },
   { "_Cilk_spawn",      RID_CILK_SPAWN, 0 },
@@ -10171,6 +10172,7 @@ sync_resolve_params (location_t loc, tree orig_fun
      call to check_function_arguments what ever type the user used.  */
   function_args_iter_next (&iter);
   ptype = TREE_TYPE (TREE_TYPE ((*params)[0]));
+  ptype = TYPE_MAIN_VARIANT (ptype);
 
   /* For the rest of the values, we need to cast these to FTYPE, so that we
      don't get warnings for passing pointer types, etc.  */
@@ -11567,6 +11569,7 @@ keyword_is_type_qualifier (enum rid keyword)
     case RID_CONST:
     case RID_VOLATILE:
     case RID_RESTRICT:
+    case RID_ATOMIC:
       return true;
     default:
       return false;
Index: gcc/c-family/c-format.c
===================================================================
--- gcc/c-family/c-format.c	(revision 204390)
+++ gcc/c-family/c-format.c	(working copy)
@@ -2374,6 +2374,7 @@ check_format_types (format_wanted_type *types)
 		  && pedantic
 		  && (TYPE_READONLY (cur_type)
 		      || TYPE_VOLATILE (cur_type)
+		      || TYPE_ATOMIC (cur_type)
 		      || TYPE_RESTRICT (cur_type)))
 		warning (OPT_Wformat_, "extra type qualifiers in format "
 			 "argument (argument %d)",
Index: gcc/c-family/c-common.h
===================================================================
--- gcc/c-family/c-common.h	(revision 204390)
+++ gcc/c-family/c-common.h	(working copy)
@@ -66,7 +66,7 @@ enum rid
   RID_UNSIGNED, RID_LONG,    RID_CONST, RID_EXTERN,
   RID_REGISTER, RID_TYPEDEF, RID_SHORT, RID_INLINE,
   RID_VOLATILE, RID_SIGNED,  RID_AUTO,  RID_RESTRICT,
-  RID_NORETURN,
+  RID_NORETURN, RID_ATOMIC,
 
   /* C extensions */
   RID_COMPLEX, RID_THREAD, RID_SAT,
Index: gcc/config/i386/i386.md
===================================================================
--- gcc/config/i386/i386.md	(revision 204390)
+++ gcc/config/i386/i386.md	(working copy)
@@ -222,6 +222,12 @@
   UNSPECV_XSAVEOPT
   UNSPECV_XSAVEOPT64
 
+  ;; For atomic compound assignments.
+  UNSPECV_FNSTENV
+  UNSPECV_FLDENV
+  UNSPECV_FNSTSW
+  UNSPECV_FNCLEX
+
   ;; For RDRAND support
   UNSPECV_RDRAND
 
@@ -18014,6 +18020,71 @@
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;
+;; Floating-point instructions for atomic compound assignments
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; Clobber all floating-point registers on environment save and restore
+; to ensure that the TOS value saved at fnstenv is valid after fldenv.
+(define_insn "fnstenv"
+  [(set (match_operand:BLK 0 "memory_operand" "=m")
+	(unspec_volatile:BLK [(const_int 0)] UNSPECV_FNSTENV))
+   (clobber (reg:HI FPCR_REG))
+   (clobber (reg:XF ST0_REG))
+   (clobber (reg:XF ST1_REG))
+   (clobber (reg:XF ST2_REG))
+   (clobber (reg:XF ST3_REG))
+   (clobber (reg:XF ST4_REG))
+   (clobber (reg:XF ST5_REG))
+   (clobber (reg:XF ST6_REG))
+   (clobber (reg:XF ST7_REG))]
+  "TARGET_80387"
+  "fnstenv\t%0"
+  [(set_attr "type" "other")
+   (set_attr "memory" "store")
+   (set (attr "length")
+        (symbol_ref "ix86_attr_length_address_default (insn) + 2"))])
+
+(define_insn "fldenv"
+  [(unspec_volatile [(match_operand:BLK 0 "memory_operand" "m")]
+		    UNSPECV_FLDENV)
+   (clobber (reg:CCFP FPSR_REG))
+   (clobber (reg:HI FPCR_REG))
+   (clobber (reg:XF ST0_REG))
+   (clobber (reg:XF ST1_REG))
+   (clobber (reg:XF ST2_REG))
+   (clobber (reg:XF ST3_REG))
+   (clobber (reg:XF ST4_REG))
+   (clobber (reg:XF ST5_REG))
+   (clobber (reg:XF ST6_REG))
+   (clobber (reg:XF ST7_REG))]
+  "TARGET_80387"
+  "fldenv\t%0"
+  [(set_attr "type" "other")
+   (set_attr "memory" "load")
+   (set (attr "length")
+        (symbol_ref "ix86_attr_length_address_default (insn) + 2"))])
+
+(define_insn "fnstsw"
+  [(set (match_operand:HI 0 "memory_operand" "=m")
+	(unspec_volatile:HI [(const_int 0)] UNSPECV_FNSTSW))]
+  "TARGET_80387"
+  "fnstsw\t%0"
+  [(set_attr "type" "other")
+   (set_attr "memory" "store")
+   (set (attr "length")
+        (symbol_ref "ix86_attr_length_address_default (insn) + 2"))])
+
+(define_insn "fnclex"
+  [(unspec_volatile [(const_int 0)] UNSPECV_FNCLEX)]
+  "TARGET_80387"
+  "fnclex"
+  [(set_attr "type" "other")
+   (set_attr "memory" "none")
+   (set_attr "length" "2")])
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
 ;; LWP instructions
 ;;
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Index: gcc/config/i386/i386-builtin-types.def
===================================================================
--- gcc/config/i386/i386-builtin-types.def	(revision 204390)
+++ gcc/config/i386/i386-builtin-types.def	(working copy)
@@ -227,6 +227,7 @@ DEF_FUNCTION_TYPE (VOID, PCVOID)
 DEF_FUNCTION_TYPE (VOID, PVOID)
 DEF_FUNCTION_TYPE (VOID, UINT64)
 DEF_FUNCTION_TYPE (VOID, UNSIGNED)
+DEF_FUNCTION_TYPE (VOID, PUSHORT)
 DEF_FUNCTION_TYPE (INT, PUSHORT)
 DEF_FUNCTION_TYPE (INT, PUNSIGNED)
 DEF_FUNCTION_TYPE (INT, PULONGLONG)
Index: gcc/config/i386/i386.c
===================================================================
--- gcc/config/i386/i386.c	(revision 204390)
+++ gcc/config/i386/i386.c	(working copy)
@@ -26958,6 +26958,11 @@ enum ix86_builtins
   IX86_BUILTIN_LFENCE,
   IX86_BUILTIN_PAUSE,
 
+  IX86_BUILTIN_FNSTENV,
+  IX86_BUILTIN_FLDENV,
+  IX86_BUILTIN_FNSTSW,
+  IX86_BUILTIN_FNCLEX,
+
   IX86_BUILTIN_BSRSI,
   IX86_BUILTIN_BSRDI,
   IX86_BUILTIN_RDPMC,
@@ -27934,6 +27939,12 @@ static const struct builtin_description bdesc_spec
   { ~OPTION_MASK_ISA_64BIT, CODE_FOR_nothing, "__builtin_ia32_rdtscp", IX86_BUILTIN_RDTSCP, UNKNOWN, (int) UINT64_FTYPE_PUNSIGNED },
   { ~OPTION_MASK_ISA_64BIT, CODE_FOR_pause, "__builtin_ia32_pause", IX86_BUILTIN_PAUSE, UNKNOWN, (int) VOID_FTYPE_VOID },
 
+  /* 80387 (for use internally for atomic compound assignment).  */
+  { 0, CODE_FOR_fnstenv, "__builtin_ia32_fnstenv", IX86_BUILTIN_FNSTENV, UNKNOWN, (int) VOID_FTYPE_PVOID },
+  { 0, CODE_FOR_fldenv, "__builtin_ia32_fldenv", IX86_BUILTIN_FLDENV, UNKNOWN, (int) VOID_FTYPE_PCVOID },
+  { 0, CODE_FOR_fnstsw, "__builtin_ia32_fnstsw", IX86_BUILTIN_FNSTSW, UNKNOWN, (int) VOID_FTYPE_PUSHORT },
+  { 0, CODE_FOR_fnclex, "__builtin_ia32_fnclex", IX86_BUILTIN_FNCLEX, UNKNOWN, (int) VOID_FTYPE_VOID },
+
   /* MMX */
   { OPTION_MASK_ISA_MMX, CODE_FOR_mmx_emms, "__builtin_ia32_emms", IX86_BUILTIN_EMMS, UNKNOWN, (int) VOID_FTYPE_VOID },
 
@@ -32895,6 +32906,10 @@ ix86_expand_builtin (tree exp, rtx target, rtx sub
     case IX86_BUILTIN_FXRSTOR:
     case IX86_BUILTIN_FXSAVE64:
     case IX86_BUILTIN_FXRSTOR64:
+    case IX86_BUILTIN_FNSTENV:
+    case IX86_BUILTIN_FLDENV:
+    case IX86_BUILTIN_FNSTSW:
+      mode0 = BLKmode;
       switch (fcode)
 	{
 	case IX86_BUILTIN_FXSAVE:
@@ -32909,6 +32924,16 @@ ix86_expand_builtin (tree exp, rtx target, rtx sub
 	case IX86_BUILTIN_FXRSTOR64:
 	  icode = CODE_FOR_fxrstor64;
 	  break;
+	case IX86_BUILTIN_FNSTENV:
+	  icode = CODE_FOR_fnstenv;
+	  break;
+	case IX86_BUILTIN_FLDENV:
+	  icode = CODE_FOR_fldenv;
+	  break;
+	case IX86_BUILTIN_FNSTSW:
+	  icode = CODE_FOR_fnstsw;
+	  mode0 = HImode;
+	  break;
 	default:
 	  gcc_unreachable ();
 	}
@@ -32921,7 +32946,7 @@ ix86_expand_builtin (tree exp, rtx target, rtx sub
 	  op0 = convert_memory_address (Pmode, op0);
 	  op0 = copy_addr_to_reg (op0);
 	}
-      op0 = gen_rtx_MEM (BLKmode, op0);
+      op0 = gen_rtx_MEM (mode0, op0);
 
       pat = GEN_FCN (icode) (op0);
       if (pat)
@@ -43531,6 +43556,103 @@ ix86_float_exceptions_rounding_supported_p (void)
   return TARGET_80387 || TARGET_SSE_MATH;
 }
 
+/* Implement TARGET_ATOMIC_ASSIGN_EXPAND_FENV.  */
+
+static void
+ix86_atomic_assign_expand_fenv (tree *hold, tree *clear, tree *update)
+{
+  if (!TARGET_80387 && !TARGET_SSE_MATH)
+    return;
+  tree exceptions_var = create_tmp_var (integer_type_node, NULL);
+  if (TARGET_80387)
+    {
+      tree fenv_index_type = build_index_type (size_int (6));
+      tree fenv_type = build_array_type (unsigned_type_node, fenv_index_type);
+      tree fenv_var = create_tmp_var (fenv_type, NULL);
+      mark_addressable (fenv_var);
+      tree fenv_ptr = build_pointer_type (fenv_type);
+      tree fenv_addr = build1 (ADDR_EXPR, fenv_ptr, fenv_var);
+      fenv_addr = fold_convert (ptr_type_node, fenv_addr);
+      tree fnstenv = ix86_builtins[IX86_BUILTIN_FNSTENV];
+      tree fldenv = ix86_builtins[IX86_BUILTIN_FLDENV];
+      tree fnstsw = ix86_builtins[IX86_BUILTIN_FNSTSW];
+      tree fnclex = ix86_builtins[IX86_BUILTIN_FNCLEX];
+      tree hold_fnstenv = build_call_expr (fnstenv, 1, fenv_addr);
+      tree hold_fnclex = build_call_expr (fnclex, 0);
+      *hold = build2 (COMPOUND_EXPR, void_type_node, hold_fnstenv,
+		      hold_fnclex);
+      *clear = build_call_expr (fnclex, 0);
+      tree sw_var = create_tmp_var (short_unsigned_type_node, NULL);
+      mark_addressable (sw_var);
+      tree su_ptr = build_pointer_type (short_unsigned_type_node);
+      tree sw_addr = build1 (ADDR_EXPR, su_ptr, sw_var);
+      tree fnstsw_call = build_call_expr (fnstsw, 1, sw_addr);
+      tree exceptions_x87 = fold_convert (integer_type_node, sw_var);
+      tree update_mod = build2 (MODIFY_EXPR, integer_type_node,
+				exceptions_var, exceptions_x87);
+      *update = build2 (COMPOUND_EXPR, integer_type_node,
+			fnstsw_call, update_mod);
+      tree update_fldenv = build_call_expr (fldenv, 1, fenv_addr);
+      *update = build2 (COMPOUND_EXPR, void_type_node, *update, update_fldenv);
+    }
+  if (TARGET_SSE_MATH)
+    {
+      tree mxcsr_orig_var = create_tmp_var (unsigned_type_node, NULL);
+      tree mxcsr_mod_var = create_tmp_var (unsigned_type_node, NULL);
+      tree stmxcsr = ix86_builtins[IX86_BUILTIN_STMXCSR];
+      tree ldmxcsr = ix86_builtins[IX86_BUILTIN_LDMXCSR];
+      tree stmxcsr_hold_call = build_call_expr (stmxcsr, 0);
+      tree hold_assign_orig = build2 (MODIFY_EXPR, unsigned_type_node,
+				      mxcsr_orig_var, stmxcsr_hold_call);
+      tree hold_mod_val = build2 (BIT_IOR_EXPR, unsigned_type_node,
+				  mxcsr_orig_var,
+				  build_int_cst (unsigned_type_node, 0x1f80));
+      hold_mod_val = build2 (BIT_AND_EXPR, unsigned_type_node, hold_mod_val,
+			     build_int_cst (unsigned_type_node, 0xffffffc0));
+      tree hold_assign_mod = build2 (MODIFY_EXPR, unsigned_type_node,
+				     mxcsr_mod_var, hold_mod_val);
+      tree ldmxcsr_hold_call = build_call_expr (ldmxcsr, 1, mxcsr_mod_var);
+      tree hold_all = build2 (COMPOUND_EXPR, unsigned_type_node,
+			      hold_assign_orig, hold_assign_mod);
+      hold_all = build2 (COMPOUND_EXPR, void_type_node, hold_all,
+			 ldmxcsr_hold_call);
+      if (*hold)
+	*hold = build2 (COMPOUND_EXPR, void_type_node, *hold, hold_all);
+      else
+	*hold = hold_all;
+      tree ldmxcsr_clear_call = build_call_expr (ldmxcsr, 1, mxcsr_mod_var);
+      if (*clear)
+	*clear = build2 (COMPOUND_EXPR, void_type_node, *clear,
+			 ldmxcsr_clear_call);
+      else
+	*clear = ldmxcsr_clear_call;
+      tree stxmcsr_update_call = build_call_expr (stmxcsr, 0);
+      tree exceptions_sse = fold_convert (integer_type_node,
+					  stxmcsr_update_call);
+      if (*update)
+	{
+	  tree exceptions_mod = build2 (BIT_IOR_EXPR, integer_type_node,
+					exceptions_var, exceptions_sse);
+	  tree exceptions_assign = build2 (MODIFY_EXPR, integer_type_node,
+					   exceptions_var, exceptions_mod);
+	  *update = build2 (COMPOUND_EXPR, integer_type_node, *update,
+			    exceptions_assign);
+	}
+      else
+	*update = build2 (MODIFY_EXPR, integer_type_node,
+			  exceptions_var, exceptions_sse);
+      tree ldmxcsr_update_call = build_call_expr (ldmxcsr, 1, mxcsr_orig_var);
+      *update = build2 (COMPOUND_EXPR, void_type_node, *update,
+			ldmxcsr_update_call);
+    }
+  tree atomic_feraiseexcept
+    = builtin_decl_implicit (BUILT_IN_ATOMIC_FERAISEEXCEPT);
+  tree atomic_feraiseexcept_call = build_call_expr (atomic_feraiseexcept,
+						    1, exceptions_var);
+  *update = build2 (COMPOUND_EXPR, void_type_node, *update,
+		    atomic_feraiseexcept_call);
+}
+
 /* Initialize the GCC target structure.  */
 #undef TARGET_RETURN_IN_MEMORY
 #define TARGET_RETURN_IN_MEMORY ix86_return_in_memory
@@ -43642,6 +43764,9 @@ ix86_float_exceptions_rounding_supported_p (void)
 #undef TARGET_MEMMODEL_CHECK
 #define TARGET_MEMMODEL_CHECK ix86_memmodel_check
 
+#undef TARGET_ATOMIC_ASSIGN_EXPAND_FENV
+#define TARGET_ATOMIC_ASSIGN_EXPAND_FENV ix86_atomic_assign_expand_fenv
+
 #ifdef HAVE_AS_TLS
 #undef TARGET_HAVE_TLS
 #define TARGET_HAVE_TLS true
Index: gcc/tree-core.h
===================================================================
--- gcc/tree-core.h	(revision 204390)
+++ gcc/tree-core.h	(working copy)
@@ -368,7 +368,8 @@ enum cv_qualifier {
   TYPE_UNQUALIFIED   = 0x0,
   TYPE_QUAL_CONST    = 0x1,
   TYPE_QUAL_VOLATILE = 0x2,
-  TYPE_QUAL_RESTRICT = 0x4
+  TYPE_QUAL_RESTRICT = 0x4,
+  TYPE_QUAL_ATOMIC   = 0x8
 };
 
 /* Enumerate visibility settings.  */
@@ -397,6 +398,12 @@ enum tree_index {
   TI_UINTDI_TYPE,
   TI_UINTTI_TYPE,
 
+  TI_ATOMICQI_TYPE,
+  TI_ATOMICHI_TYPE,
+  TI_ATOMICSI_TYPE,
+  TI_ATOMICDI_TYPE,
+  TI_ATOMICTI_TYPE,
+
   TI_UINT16_TYPE,
   TI_UINT32_TYPE,
   TI_UINT64_TYPE,
@@ -738,7 +745,8 @@ struct GTY(()) tree_base {
       unsigned packed_flag : 1;
       unsigned user_align : 1;
       unsigned nameless_flag : 1;
-      unsigned spare0 : 4;
+      unsigned atomic_flag : 1;
+      unsigned spare0 : 3;
 
       unsigned spare1 : 8;
 
Index: gcc/c/c-aux-info.c
===================================================================
--- gcc/c/c-aux-info.c	(revision 204390)
+++ gcc/c/c-aux-info.c	(working copy)
@@ -285,6 +285,8 @@ gen_type (const char *ret_val, tree t, formals_sty
       switch (TREE_CODE (t))
 	{
 	case POINTER_TYPE:
+	  if (TYPE_ATOMIC (t))
+	    ret_val = concat ("_Atomic ", ret_val, NULL);
 	  if (TYPE_READONLY (t))
 	    ret_val = concat ("const ", ret_val, NULL);
 	  if (TYPE_VOLATILE (t))
@@ -425,6 +427,8 @@ gen_type (const char *ret_val, tree t, formals_sty
 	  gcc_unreachable ();
 	}
     }
+  if (TYPE_ATOMIC (t))
+    ret_val = concat ("_Atomic ", ret_val, NULL);
   if (TYPE_READONLY (t))
     ret_val = concat ("const ", ret_val, NULL);
   if (TYPE_VOLATILE (t))
Index: gcc/c/c-parser.c
===================================================================
--- gcc/c/c-parser.c	(revision 204390)
+++ gcc/c/c-parser.c	(working copy)
@@ -494,6 +494,7 @@ c_token_starts_typename (c_token *token)
 	case RID_UNION:
 	case RID_TYPEOF:
 	case RID_CONST:
+	case RID_ATOMIC:
 	case RID_VOLATILE:
 	case RID_RESTRICT:
 	case RID_ATTRIBUTE:
@@ -576,6 +577,7 @@ c_token_is_qualifier (c_token *token)
 	case RID_VOLATILE:
 	case RID_RESTRICT:
 	case RID_ATTRIBUTE:
+	case RID_ATOMIC:
 	  return true;
 	default:
 	  return false;
@@ -656,6 +658,7 @@ c_token_starts_declspecs (c_token *token)
 	case RID_ACCUM:
 	case RID_SAT:
 	case RID_ALIGNAS:
+	case RID_ATOMIC:
 	  return true;
 	default:
 	  return false;
@@ -1991,8 +1994,10 @@ c_parser_static_assert_declaration_no_semi (c_pars
      struct-or-union-specifier
      enum-specifier
      typedef-name
+     atomic-type-specifier
 
    (_Bool and _Complex are new in C99.)
+   (atomic-type-specifier is new in C11.)
 
    C90 6.5.3, C99 6.7.3:
 
@@ -2001,8 +2006,10 @@ c_parser_static_assert_declaration_no_semi (c_pars
      restrict
      volatile
      address-space-qualifier
+     _Atomic
 
    (restrict is new in C99.)
+   (_Atomic is new in C11.)
 
    GNU extensions:
 
@@ -2031,6 +2038,9 @@ c_parser_static_assert_declaration_no_semi (c_pars
   (_Fract, _Accum, and _Sat are new from ISO/IEC DTR 18037:
    http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1169.pdf)
 
+   atomic-type-specifier
+    _Atomic ( type-name )
+
    Objective-C:
 
    type-specifier:
@@ -2224,6 +2234,64 @@ c_parser_declspecs (c_parser *parser, struct c_dec
 	  t = c_parser_typeof_specifier (parser);
 	  declspecs_add_type (loc, specs, t);
 	  break;
+	case RID_ATOMIC:
+	  /* C parser handling of Objective-C constructs needs
+	     checking for correct lvalue-to-rvalue conversions, and
+	     the code in build_modify_expr handling various
+	     Objective-C cases, and that in build_unary_op handling
+	     Objective-C cases for increment / decrement, also needs
+	     updating; uses of TYPE_MAIN_VARIANT in objc_compare_types
+	     and objc_types_are_equivalent may also need updates.  */
+	  if (c_dialect_objc ())
+	    sorry ("%<_Atomic%> in Objective-C");
+	  /* C parser handling of OpenMP constructs needs checking for
+	     correct lvalue-to-rvalue conversions.  */
+	  if (flag_openmp)
+	    sorry ("%<_Atomic%> with OpenMP");
+	  if (!flag_isoc11)
+	    {
+	      if (flag_isoc99)
+		pedwarn (loc, OPT_Wpedantic,
+			 "ISO C99 does not support the %<_Atomic%> qualifier");
+	      else
+		pedwarn (loc, OPT_Wpedantic,
+			 "ISO C90 does not support the %<_Atomic%> qualifier");
+	    }
+	  attrs_ok = true;
+	  tree value;
+	  value = c_parser_peek_token (parser)->value;
+	  c_parser_consume_token (parser);
+	  if (typespec_ok && c_parser_next_token_is (parser, CPP_OPEN_PAREN))
+	    {
+	      /* _Atomic ( type-name ).  */
+	      seen_type = true;
+	      c_parser_consume_token (parser);
+	      struct c_type_name *type = c_parser_type_name (parser);
+	      t.kind = ctsk_typeof;
+	      t.spec = error_mark_node;
+	      t.expr = NULL_TREE;
+	      t.expr_const_operands = true;
+	      if (type != NULL)
+		t.spec = groktypename (type, &t.expr,
+				       &t.expr_const_operands);
+	      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+					 "expected %<)%>");
+	      if (t.spec != error_mark_node)
+		{
+		  if (TREE_CODE (t.spec) == ARRAY_TYPE)
+		    error_at (loc, "%<_Atomic%>-qualified array type");
+		  else if (TREE_CODE (t.spec) == FUNCTION_TYPE)
+		    error_at (loc, "%<_Atomic%>-qualified function type");
+		  else if (TYPE_QUALS (t.spec) != TYPE_UNQUALIFIED)
+		    error_at (loc, "%<_Atomic%> applied to a qualified type");
+		  else
+		    t.spec = c_build_qualified_type (t.spec, TYPE_QUAL_ATOMIC);
+		}
+	      declspecs_add_type (loc, specs, t);
+	    }
+	  else
+	    declspecs_add_qual (loc, specs, value);
+	  break;
 	case RID_CONST:
 	case RID_VOLATILE:
 	case RID_RESTRICT:
@@ -2826,6 +2894,16 @@ c_parser_typeof_specifier (c_parser *parser)
       if (was_vm)
 	ret.expr = c_fully_fold (expr.value, false, &ret.expr_const_operands);
       pop_maybe_used (was_vm);
+      /* For use in macros such as those in <stdatomic.h>, remove
+	 _Atomic and const qualifiers from atomic types.  (Possibly
+	 all qualifiers should be removed; const can be an issue for
+	 more macros using typeof than just the <stdatomic.h>
+	 ones.)  */
+      if (ret.spec != error_mark_node && TYPE_ATOMIC (ret.spec))
+	ret.spec = c_build_qualified_type (ret.spec,
+					   (TYPE_QUALS (ret.spec)
+					    & ~(TYPE_QUAL_ATOMIC
+						| TYPE_QUAL_CONST)));
     }
   c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
   return ret;
@@ -3114,7 +3192,10 @@ c_parser_direct_declarator_inner (c_parser *parser
       struct c_declspecs *quals_attrs = build_null_declspecs ();
       bool static_seen;
       bool star_seen;
-      tree dimen;
+      struct c_expr dimen;
+      dimen.value = NULL_TREE;
+      dimen.original_code = ERROR_MARK;
+      dimen.original_type = NULL_TREE;
       c_parser_consume_token (parser);
       c_parser_declspecs (parser, quals_attrs, false, false, true,
 			  false, cla_prefer_id);
@@ -3132,19 +3213,19 @@ c_parser_direct_declarator_inner (c_parser *parser
       if (static_seen)
 	{
 	  star_seen = false;
-	  dimen = c_parser_expr_no_commas (parser, NULL).value;
+	  dimen = c_parser_expr_no_commas (parser, NULL);
 	}
       else
 	{
 	  if (c_parser_next_token_is (parser, CPP_CLOSE_SQUARE))
 	    {
-	      dimen = NULL_TREE;
+	      dimen.value = NULL_TREE;
 	      star_seen = false;
 	    }
 	  else if (flag_enable_cilkplus
 		   && c_parser_next_token_is (parser, CPP_COLON))
 	    {
-	      dimen = error_mark_node;
+	      dimen.value = error_mark_node;
 	      star_seen = false;
 	      error_at (c_parser_peek_token (parser)->location,
 			"array notations cannot be used in declaration");
@@ -3154,20 +3235,20 @@ c_parser_direct_declarator_inner (c_parser *parser
 	    {
 	      if (c_parser_peek_2nd_token (parser)->type == CPP_CLOSE_SQUARE)
 		{
-		  dimen = NULL_TREE;
+		  dimen.value = NULL_TREE;
 		  star_seen = true;
 		  c_parser_consume_token (parser);
 		}
 	      else
 		{
 		  star_seen = false;
-		  dimen = c_parser_expr_no_commas (parser, NULL).value;
+		  dimen = c_parser_expr_no_commas (parser, NULL);
 		}
 	    }
 	  else
 	    {
 	      star_seen = false;
-	      dimen = c_parser_expr_no_commas (parser, NULL).value;
+	      dimen = c_parser_expr_no_commas (parser, NULL);
 	    }
 	}
       if (c_parser_next_token_is (parser, CPP_CLOSE_SQUARE))
@@ -3186,9 +3267,9 @@ c_parser_direct_declarator_inner (c_parser *parser
 				     "expected %<]%>");
 	  return NULL;
 	}
-      if (dimen)
-	mark_exp_read (dimen);
-      declarator = build_array_declarator (brace_loc, dimen, quals_attrs,
+      if (dimen.value)
+	dimen = convert_lvalue_to_rvalue (brace_loc, dimen, true, true);
+      declarator = build_array_declarator (brace_loc, dimen.value, quals_attrs,
 					   static_seen, star_seen);
       if (declarator == NULL)
 	return NULL;
@@ -3558,6 +3639,7 @@ c_parser_attribute_any_word (c_parser *parser)
 	case RID_SAT:
 	case RID_TRANSACTION_ATOMIC:
 	case RID_TRANSACTION_CANCEL:
+	case RID_ATOMIC:
 	  ok = true;
 	  break;
 	default:
@@ -3814,7 +3896,7 @@ c_parser_initializer (c_parser *parser)
       ret = c_parser_expr_no_commas (parser, NULL);
       if (TREE_CODE (ret.value) != STRING_CST
 	  && TREE_CODE (ret.value) != COMPOUND_LITERAL_EXPR)
-	ret = default_function_array_read_conversion (loc, ret);
+	ret = convert_lvalue_to_rvalue (loc, ret, true, true);
       return ret;
     }
 }
@@ -3993,8 +4075,8 @@ c_parser_initelt (c_parser *parser, struct obstack
 		      c_parser_consume_token (parser);
 		      exp_loc = c_parser_peek_token (parser)->location;
 		      next = c_parser_expr_no_commas (parser, NULL);
-		      next = default_function_array_read_conversion (exp_loc,
-								     next);
+		      next = convert_lvalue_to_rvalue (exp_loc, next,
+						       true, true);
 		      rec = build_compound_expr (comma_loc, rec, next.value);
 		    }
 		parse_message_args:
@@ -4090,7 +4172,7 @@ c_parser_initval (c_parser *parser, struct c_expr
       if (init.value != NULL_TREE
 	  && TREE_CODE (init.value) != STRING_CST
 	  && TREE_CODE (init.value) != COMPOUND_LITERAL_EXPR)
-	init = default_function_array_read_conversion (loc, init);
+	init = convert_lvalue_to_rvalue (loc, init, true, true);
     }
   process_init_element (init, false, braced_init_obstack);
 }
@@ -4605,12 +4687,12 @@ c_parser_statement_after_labels (c_parser *parser)
 	    }
 	  else if (c_parser_next_token_is (parser, CPP_MULT))
 	    {
-	      tree val;
+	      struct c_expr val;
 
 	      c_parser_consume_token (parser);
-	      val = c_parser_expression (parser).value;
-	      mark_exp_read (val);
-	      stmt = c_finish_goto_ptr (loc, val);
+	      val = c_parser_expression (parser);
+	      val = convert_lvalue_to_rvalue (loc, val, false, true);
+	      stmt = c_finish_goto_ptr (loc, val.value);
 	    }
 	  else
 	    c_parser_error (parser, "expected identifier or %<*%>");
@@ -4659,9 +4741,10 @@ c_parser_statement_after_labels (c_parser *parser)
 	    }
 	  else
 	    {
-	      tree expr = c_parser_expression (parser).value;
-	      expr = c_fully_fold (expr, false, NULL);
-	      stmt = objc_build_throw_stmt (loc, expr);
+	      struct c_expr expr = c_parser_expression (parser);
+	      expr = convert_lvalue_to_rvalue (loc, expr, false, false);
+	      expr.value = c_fully_fold (expr.value, false, NULL);
+	      stmt = objc_build_throw_stmt (loc, expr.value);
 	      goto expect_semicolon;
 	    }
 	  break;
@@ -4873,6 +4956,7 @@ c_parser_if_statement (c_parser *parser)
 static void
 c_parser_switch_statement (c_parser *parser)
 {
+  struct c_expr ce;
   tree block, expr, body, save_break;
   location_t switch_loc = c_parser_peek_token (parser)->location;
   location_t switch_cond_loc;
@@ -4882,7 +4966,9 @@ c_parser_switch_statement (c_parser *parser)
   if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
     {
       switch_cond_loc = c_parser_peek_token (parser)->location;
-      expr = c_parser_expression (parser).value;
+      ce = c_parser_expression (parser);
+      ce = convert_lvalue_to_rvalue (switch_cond_loc, ce, true, false);
+      expr = ce.value;
       if (flag_enable_cilkplus && contains_array_notation_expr (expr))
 	{
 	  error_at (switch_cond_loc,
@@ -5135,8 +5221,10 @@ c_parser_for_statement (c_parser *parser, bool ivd
 	{
 	init_expr:
 	  {
+	    struct c_expr ce;
 	    tree init_expression;
-	    init_expression = c_parser_expression (parser).value;
+	    ce = c_parser_expression (parser);
+	    init_expression = ce.value;
 	    parser->objc_could_be_foreach_context = false;
 	    if (c_parser_next_token_is_keyword (parser, RID_IN))
 	      {
@@ -5148,6 +5236,8 @@ c_parser_for_statement (c_parser *parser, bool ivd
 	      }
 	    else
 	      {
+		ce = convert_lvalue_to_rvalue (loc, ce, true, false);
+		init_expression = ce.value;
 		c_finish_expr_stmt (loc, init_expression);
 		c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
 	      }
@@ -5208,7 +5298,11 @@ c_parser_for_statement (c_parser *parser, bool ivd
 	    collection_expression = c_fully_fold (c_parser_expression (parser).value,
 						  false, NULL);
 	  else
-	    incr = c_process_expr_stmt (loc, c_parser_expression (parser).value);
+	    {
+	      struct c_expr ce = c_parser_expression (parser);
+	      ce = convert_lvalue_to_rvalue (loc, ce, true, false);
+	      incr = c_process_expr_stmt (loc, ce.value);
+	    }
 	}
       c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
     }
@@ -5565,7 +5659,7 @@ c_parser_expr_no_commas (c_parser *parser, struct
   c_parser_consume_token (parser);
   exp_location = c_parser_peek_token (parser)->location;
   rhs = c_parser_expr_no_commas (parser, NULL);
-  rhs = default_function_array_read_conversion (exp_location, rhs);
+  rhs = convert_lvalue_to_rvalue (exp_location, rhs, true, true);
   
   ret.value = build_modify_expr (op_location, lhs.value, lhs.original_type,
 				 code, exp_location, rhs.value,
@@ -5609,7 +5703,7 @@ c_parser_conditional_expression (c_parser *parser,
   if (c_parser_next_token_is_not (parser, CPP_QUERY))
     return cond;
   cond_loc = c_parser_peek_token (parser)->location;
-  cond = default_function_array_read_conversion (cond_loc, cond);
+  cond = convert_lvalue_to_rvalue (cond_loc, cond, true, true);
   c_parser_consume_token (parser);
   if (c_parser_next_token_is (parser, CPP_COLON))
     {
@@ -5657,7 +5751,7 @@ c_parser_conditional_expression (c_parser *parser,
   {
     location_t exp2_loc = c_parser_peek_token (parser)->location;
     exp2 = c_parser_conditional_expression (parser, NULL, NULL_TREE);
-    exp2 = default_function_array_read_conversion (exp2_loc, exp2);
+    exp2 = convert_lvalue_to_rvalue (exp2_loc, exp2, true, true);
   }
   c_inhibit_evaluation_warnings -= cond.value == truthvalue_true_node;
   ret.value = build_conditional_expr (colon_loc, cond.value,
@@ -5801,11 +5895,11 @@ c_parser_binary_expression (c_parser *parser, stru
 	break;								      \
       }									      \
     stack[sp - 1].expr							      \
-      = default_function_array_read_conversion (stack[sp - 1].loc,	      \
-						stack[sp - 1].expr);	      \
+      = convert_lvalue_to_rvalue (stack[sp - 1].loc,			      \
+				  stack[sp - 1].expr, true, true);	      \
     stack[sp].expr							      \
-      = default_function_array_read_conversion (stack[sp].loc,		      \
-						stack[sp].expr);	      \
+      = convert_lvalue_to_rvalue (stack[sp].loc,			      \
+				  stack[sp].expr, true, true);		      \
     if (__builtin_expect (omp_atomic_lhs != NULL_TREE, 0) && sp == 1	      \
 	&& c_parser_peek_token (parser)->type == CPP_SEMICOLON		      \
 	&& ((1 << stack[sp].prec)					      \
@@ -5924,8 +6018,8 @@ c_parser_binary_expression (c_parser *parser, stru
 	{
 	case TRUTH_ANDIF_EXPR:
 	  stack[sp].expr
-	    = default_function_array_read_conversion (stack[sp].loc,
-						      stack[sp].expr);
+	    = convert_lvalue_to_rvalue (stack[sp].loc,
+					stack[sp].expr, true, true);
 	  stack[sp].expr.value = c_objc_common_truthvalue_conversion
 	    (stack[sp].loc, default_conversion (stack[sp].expr.value));
 	  c_inhibit_evaluation_warnings += (stack[sp].expr.value
@@ -5933,8 +6027,8 @@ c_parser_binary_expression (c_parser *parser, stru
 	  break;
 	case TRUTH_ORIF_EXPR:
 	  stack[sp].expr
-	    = default_function_array_read_conversion (stack[sp].loc,
-						      stack[sp].expr);
+	    = convert_lvalue_to_rvalue (stack[sp].loc,
+					stack[sp].expr, true, true);
 	  stack[sp].expr.value = c_objc_common_truthvalue_conversion
 	    (stack[sp].loc, default_conversion (stack[sp].expr.value));
 	  c_inhibit_evaluation_warnings += (stack[sp].expr.value
@@ -6005,7 +6099,7 @@ c_parser_cast_expression (c_parser *parser, struct
       {
 	location_t expr_loc = c_parser_peek_token (parser)->location;
 	expr = c_parser_cast_expression (parser, NULL);
-	expr = default_function_array_read_conversion (expr_loc, expr);
+	expr = convert_lvalue_to_rvalue (expr_loc, expr, true, true);
       }
       ret.value = c_cast_expr (cast_loc, type_name, expr.value);
       ret.original_code = ERROR_MARK;
@@ -6096,7 +6190,7 @@ c_parser_unary_expression (c_parser *parser)
       c_parser_consume_token (parser);
       exp_loc = c_parser_peek_token (parser)->location;
       op = c_parser_cast_expression (parser, NULL);
-      op = default_function_array_read_conversion (exp_loc, op);
+      op = convert_lvalue_to_rvalue (exp_loc, op, true, true);
       ret.value = build_indirect_ref (op_loc, op.value, RO_UNARY_STAR);
       return ret;
     case CPP_PLUS:
@@ -6107,25 +6201,25 @@ c_parser_unary_expression (c_parser *parser)
       c_parser_consume_token (parser);
       exp_loc = c_parser_peek_token (parser)->location;
       op = c_parser_cast_expression (parser, NULL);
-      op = default_function_array_read_conversion (exp_loc, op);
+      op = convert_lvalue_to_rvalue (exp_loc, op, true, true);
       return parser_build_unary_op (op_loc, CONVERT_EXPR, op);
     case CPP_MINUS:
       c_parser_consume_token (parser);
       exp_loc = c_parser_peek_token (parser)->location;
       op = c_parser_cast_expression (parser, NULL);
-      op = default_function_array_read_conversion (exp_loc, op);
+      op = convert_lvalue_to_rvalue (exp_loc, op, true, true);
       return parser_build_unary_op (op_loc, NEGATE_EXPR, op);
     case CPP_COMPL:
       c_parser_consume_token (parser);
       exp_loc = c_parser_peek_token (parser)->location;
       op = c_parser_cast_expression (parser, NULL);
-      op = default_function_array_read_conversion (exp_loc, op);
+      op = convert_lvalue_to_rvalue (exp_loc, op, true, true);
       return parser_build_unary_op (op_loc, BIT_NOT_EXPR, op);
     case CPP_NOT:
       c_parser_consume_token (parser);
       exp_loc = c_parser_peek_token (parser)->location;
       op = c_parser_cast_expression (parser, NULL);
-      op = default_function_array_read_conversion (exp_loc, op);
+      op = convert_lvalue_to_rvalue (exp_loc, op, true, true);
       return parser_build_unary_op (op_loc, TRUTH_NOT_EXPR, op);
     case CPP_AND_AND:
       /* Refer to the address of a label as a pointer.  */
@@ -6918,10 +7012,13 @@ c_parser_postfix_expression (c_parser *parser)
 		      }
 		    else
 		      {
+			struct c_expr ce;
 			tree idx;
 			loc = c_parser_peek_token (parser)->location;
 			c_parser_consume_token (parser);
-			idx = c_parser_expression (parser).value;
+			ce = c_parser_expression (parser);
+			ce = convert_lvalue_to_rvalue (loc, ce, false, false);
+			idx = ce.value;
 			idx = c_fully_fold (idx, false, NULL);
 			c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE,
 						   "expected %<]%>");
@@ -7044,11 +7141,11 @@ c_parser_postfix_expression (c_parser *parser)
 	    e1_p = &(*cexpr_list)[0];
 	    e2_p = &(*cexpr_list)[1];
 
-	    mark_exp_read (e1_p->value);
+	    *e1_p = convert_lvalue_to_rvalue (loc, *e1_p, true, true);
 	    if (TREE_CODE (e1_p->value) == EXCESS_PRECISION_EXPR)
 	      e1_p->value = convert (TREE_TYPE (e1_p->value),
 				     TREE_OPERAND (e1_p->value, 0));
-	    mark_exp_read (e2_p->value);
+	    *e2_p = convert_lvalue_to_rvalue (loc, *e2_p, true, true);
 	    if (TREE_CODE (e2_p->value) == EXCESS_PRECISION_EXPR)
 	      e2_p->value = convert (TREE_TYPE (e2_p->value),
 				     TREE_OPERAND (e2_p->value, 0));
@@ -7096,7 +7193,7 @@ c_parser_postfix_expression (c_parser *parser)
 	      }
 
 	    FOR_EACH_VEC_SAFE_ELT (cexpr_list, i, p)
-	      mark_exp_read (p->value);
+	      *p = convert_lvalue_to_rvalue (loc, *p, true, true);
 
 	    if (vec_safe_length (cexpr_list) == 2)
 	      expr.value =
@@ -7440,7 +7537,7 @@ c_parser_postfix_expression_after_primary (c_parse
 	case CPP_DEREF:
 	  /* Structure element reference.  */
 	  c_parser_consume_token (parser);
-	  expr = default_function_array_conversion (expr_loc, expr);
+	  expr = convert_lvalue_to_rvalue (expr_loc, expr, true, false);
 	  if (c_parser_next_token_is (parser, CPP_NAME))
 	    ident = c_parser_peek_token (parser)->value;
 	  else
@@ -7518,8 +7615,11 @@ c_parser_postfix_expression_after_primary (c_parse
 static struct c_expr
 c_parser_expression (c_parser *parser)
 {
+  location_t tloc = c_parser_peek_token (parser)->location;
   struct c_expr expr;
   expr = c_parser_expr_no_commas (parser, NULL);
+  if (c_parser_next_token_is (parser, CPP_COMMA))
+    expr = convert_lvalue_to_rvalue (tloc, expr, true, false);
   while (c_parser_next_token_is (parser, CPP_COMMA))
     {
       struct c_expr next;
@@ -7534,7 +7634,7 @@ c_parser_expression (c_parser *parser)
       if (DECL_P (lhsval) || handled_component_p (lhsval))
 	mark_exp_read (lhsval);
       next = c_parser_expr_no_commas (parser, NULL);
-      next = default_function_array_conversion (expr_loc, next);
+      next = convert_lvalue_to_rvalue (expr_loc, next, true, false);
       expr.value = build_compound_expr (loc, expr.value, next.value);
       expr.original_code = COMPOUND_EXPR;
       expr.original_type = next.original_type;
@@ -7542,8 +7642,8 @@ c_parser_expression (c_parser *parser)
   return expr;
 }
 
-/* Parse an expression and convert functions or arrays to
-   pointers.  */
+/* Parse an expression and convert functions or arrays to pointers and
+   lvalues to rvalues.  */
 
 static struct c_expr
 c_parser_expression_conv (c_parser *parser)
@@ -7551,12 +7651,13 @@ c_parser_expression_conv (c_parser *parser)
   struct c_expr expr;
   location_t loc = c_parser_peek_token (parser)->location;
   expr = c_parser_expression (parser);
-  expr = default_function_array_conversion (loc, expr);
+  expr = convert_lvalue_to_rvalue (loc, expr, true, false);
   return expr;
 }
 
 /* Parse a non-empty list of expressions.  If CONVERT_P, convert
-   functions and arrays to pointers.  If FOLD_P, fold the expressions.
+   functions and arrays to pointers and lvalues to rvalues.  If
+   FOLD_P, fold the expressions.
 
    nonempty-expr-list:
      assignment-expression
@@ -7586,7 +7687,7 @@ c_parser_expr_list (c_parser *parser, bool convert
     cur_sizeof_arg_loc = c_parser_peek_2nd_token (parser)->location;
   expr = c_parser_expr_no_commas (parser, NULL);
   if (convert_p)
-    expr = default_function_array_read_conversion (loc, expr);
+    expr = convert_lvalue_to_rvalue (loc, expr, true, true);
   if (fold_p)
     expr.value = c_fully_fold (expr.value, false, NULL);
   ret->quick_push (expr.value);
@@ -7610,7 +7711,7 @@ c_parser_expr_list (c_parser *parser, bool convert
 	cur_sizeof_arg_loc = UNKNOWN_LOCATION;
       expr = c_parser_expr_no_commas (parser, NULL);
       if (convert_p)
-	expr = default_function_array_read_conversion (loc, expr);
+	expr = convert_lvalue_to_rvalue (loc, expr, true, true);
       if (fold_p)
 	expr.value = c_fully_fold (expr.value, false, NULL);
       vec_safe_push (ret, expr.value);
@@ -8516,7 +8617,9 @@ c_parser_objc_synchronized_statement (c_parser *pa
   objc_maybe_warn_exceptions (loc);
   if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
     {
-      expr = c_parser_expression (parser).value;
+      struct c_expr ce = c_parser_expression (parser);
+      ce = convert_lvalue_to_rvalue (loc, ce, false, false);
+      expr = ce.value;
       expr = c_fully_fold (expr, false, NULL);
       c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
     }
@@ -8536,6 +8639,7 @@ c_parser_objc_synchronized_statement (c_parser *pa
        break continue return goto asm sizeof typeof __alignof
        unsigned long const short volatile signed restrict _Complex
        in out inout bycopy byref oneway int char float double void _Bool
+       _Atomic
 
    ??? Why this selection of keywords but not, for example, storage
    class specifiers?  */
@@ -8594,6 +8698,7 @@ c_parser_objc_selector (c_parser *parser)
     case RID_DOUBLE:
     case RID_VOID:
     case RID_BOOL:
+    case RID_ATOMIC:
       c_parser_consume_token (parser);
       return value;
     default:
@@ -8646,6 +8751,8 @@ c_parser_objc_selector_arg (c_parser *parser)
 static tree
 c_parser_objc_receiver (c_parser *parser)
 {
+  location_t loc = c_parser_peek_token (parser)->location;
+
   if (c_parser_peek_token (parser)->type == CPP_NAME
       && (c_parser_peek_token (parser)->id_kind == C_ID_TYPENAME
 	  || c_parser_peek_token (parser)->id_kind == C_ID_CLASSNAME))
@@ -8654,7 +8761,9 @@ c_parser_objc_receiver (c_parser *parser)
       c_parser_consume_token (parser);
       return objc_get_class_reference (id);
     }
-  return c_fully_fold (c_parser_expression (parser).value, false, NULL);
+  struct c_expr ce = c_parser_expression (parser);
+  ce = convert_lvalue_to_rvalue (loc, ce, false, false);
+  return c_fully_fold (ce.value, false, NULL);
 }
 
 /* Parse objc-message-args.
@@ -13441,7 +13550,9 @@ c_parser_array_notation (location_t loc, c_parser
 	      return error_mark_node;
 	    }
 	  c_parser_consume_token (parser); /* consume the ':' */
-	  end_index = c_parser_expression (parser).value;
+	  struct c_expr ce = c_parser_expression (parser);
+	  ce = convert_lvalue_to_rvalue (loc, ce, false, false);
+	  end_index = ce.value;
 	  if (!end_index || end_index == error_mark_node)
 	    {
 	      c_parser_skip_to_end_of_block_or_statement (parser);
@@ -13450,7 +13561,9 @@ c_parser_array_notation (location_t loc, c_parser
 	  if (c_parser_peek_token (parser)->type == CPP_COLON)
 	    {
 	      c_parser_consume_token (parser);
-	      stride = c_parser_expression (parser).value;
+	      ce = c_parser_expression (parser);
+	      ce = convert_lvalue_to_rvalue (loc, ce, false, false);
+	      stride = ce.value;
 	      if (!stride || stride == error_mark_node)
 		{
 		  c_parser_skip_to_end_of_block_or_statement (parser);
Index: gcc/c/c-typeck.c
===================================================================
--- gcc/c/c-typeck.c	(revision 204390)
+++ gcc/c/c-typeck.c	(working copy)
@@ -265,18 +265,25 @@ c_incomplete_type_error (const_tree value, const_t
 tree
 c_type_promotes_to (tree type)
 {
+  tree ret = NULL_TREE;
+
   if (TYPE_MAIN_VARIANT (type) == float_type_node)
-    return double_type_node;
-
-  if (c_promoting_integer_type_p (type))
+    ret = double_type_node;
+  else if (c_promoting_integer_type_p (type))
     {
       /* Preserve unsignedness if not really getting any wider.  */
       if (TYPE_UNSIGNED (type)
 	  && (TYPE_PRECISION (type) == TYPE_PRECISION (integer_type_node)))
-	return unsigned_type_node;
-      return integer_type_node;
+	ret = unsigned_type_node;
+      else
+	ret = integer_type_node;
     }
 
+  if (ret != NULL_TREE)
+    return (TYPE_ATOMIC (type)
+	    ? c_build_qualified_type (ret, TYPE_QUAL_ATOMIC)
+	    : ret);
+
   return type;
 }
 
@@ -327,7 +334,7 @@ qualify_type (tree type, tree like)
 
   return c_build_qualified_type (type,
 				 TYPE_QUALS_NO_ADDR_SPACE (type)
-				 | TYPE_QUALS_NO_ADDR_SPACE (like)
+				 | TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC (like)
 				 | ENCODE_QUAL_ADDR_SPACE (as_common));
 }
 
@@ -1214,9 +1221,13 @@ comp_target_types (location_t location, tree ttl,
   /* Do not lose qualifiers on element types of array types that are
      pointer targets by taking their TYPE_MAIN_VARIANT.  */
   if (TREE_CODE (mvl) != ARRAY_TYPE)
-    mvl = TYPE_MAIN_VARIANT (mvl);
+    mvl = (TYPE_ATOMIC (mvl)
+	   ? c_build_qualified_type (TYPE_MAIN_VARIANT (mvl), TYPE_QUAL_ATOMIC)
+	   : TYPE_MAIN_VARIANT (mvl));
   if (TREE_CODE (mvr) != ARRAY_TYPE)
-    mvr = TYPE_MAIN_VARIANT (mvr);
+    mvr = (TYPE_ATOMIC (mvr)
+	   ? c_build_qualified_type (TYPE_MAIN_VARIANT (mvr), TYPE_QUAL_ATOMIC)
+	   : TYPE_MAIN_VARIANT (mvr));
   enum_and_int_p = false;
   val = comptypes_check_enum_int (mvl, mvr, &enum_and_int_p);
 
@@ -1633,9 +1644,15 @@ type_lists_compatible_p (const_tree args1, const_t
       mv1 = a1 = TREE_VALUE (args1);
       mv2 = a2 = TREE_VALUE (args2);
       if (mv1 && mv1 != error_mark_node && TREE_CODE (mv1) != ARRAY_TYPE)
-	mv1 = TYPE_MAIN_VARIANT (mv1);
+	mv1 = (TYPE_ATOMIC (mv1)
+	       ? c_build_qualified_type (TYPE_MAIN_VARIANT (mv1),
+					 TYPE_QUAL_ATOMIC)
+	       : TYPE_MAIN_VARIANT (mv1));
       if (mv2 && mv2 != error_mark_node && TREE_CODE (mv2) != ARRAY_TYPE)
-	mv2 = TYPE_MAIN_VARIANT (mv2);
+	mv2 = (TYPE_ATOMIC (mv2)
+	       ? c_build_qualified_type (TYPE_MAIN_VARIANT (mv2),
+					 TYPE_QUAL_ATOMIC)
+	       : TYPE_MAIN_VARIANT (mv2));
       /* A null pointer instead of a type
 	 means there is supposed to be an argument
 	 but nothing is specified about what type it has.
@@ -1678,7 +1695,10 @@ type_lists_compatible_p (const_tree args1, const_t
 		  tree mv3 = TREE_TYPE (memb);
 		  if (mv3 && mv3 != error_mark_node
 		      && TREE_CODE (mv3) != ARRAY_TYPE)
-		    mv3 = TYPE_MAIN_VARIANT (mv3);
+		    mv3 = (TYPE_ATOMIC (mv3)
+			   ? c_build_qualified_type (TYPE_MAIN_VARIANT (mv3),
+						     TYPE_QUAL_ATOMIC)
+			   : TYPE_MAIN_VARIANT (mv3));
 		  if (comptypes_internal (mv3, mv2, enum_and_int_p,
 					  different_types_p))
 		    break;
@@ -1700,7 +1720,10 @@ type_lists_compatible_p (const_tree args1, const_t
 		  tree mv3 = TREE_TYPE (memb);
 		  if (mv3 && mv3 != error_mark_node
 		      && TREE_CODE (mv3) != ARRAY_TYPE)
-		    mv3 = TYPE_MAIN_VARIANT (mv3);
+		    mv3 = (TYPE_ATOMIC (mv3)
+			   ? c_build_qualified_type (TYPE_MAIN_VARIANT (mv3),
+						     TYPE_QUAL_ATOMIC)
+			   : TYPE_MAIN_VARIANT (mv3));
 		  if (comptypes_internal (mv3, mv1, enum_and_int_p,
 					  different_types_p))
 		    break;
@@ -1913,6 +1936,84 @@ default_function_array_read_conversion (location_t
   return default_function_array_conversion (loc, exp);
 }
 
+/* Return whether EXPR should be treated as an atomic lvalue for the
+   purposes of load and store handling.  */
+
+static bool
+really_atomic_lvalue (tree expr)
+{
+  if (expr == error_mark_node || TREE_TYPE (expr) == error_mark_node)
+    return false;
+  if (!TYPE_ATOMIC (TREE_TYPE (expr)))
+    return false;
+  if (!lvalue_p (expr))
+    return false;
+
+  /* Ignore _Atomic on register variables, since their addresses can't
+     be taken so (a) atomicity is irrelevant and (b) the normal atomic
+     sequences wouldn't work.  Ignore _Atomic on structures containing
+     bit-fields, since accessing elements of atomic structures or
+     unions is undefined behavior (C11 6.5.2.3#5), but it's unclear if
+     it's undefined at translation time or execution time, and the
+     normal atomic sequences again wouldn't work.  */
+  while (handled_component_p (expr))
+    {
+      if (TREE_CODE (expr) == COMPONENT_REF
+	  && DECL_C_BIT_FIELD (TREE_OPERAND (expr, 1)))
+	return false;
+      expr = TREE_OPERAND (expr, 0);
+    }
+  if (DECL_P (expr) && C_DECL_REGISTER (expr))
+    return false;
+  return true;
+}
+
+/* Convert expression EXP (location LOC) from lvalue to rvalue,
+   including converting functions and arrays to pointers if CONVERT_P.
+   If READ_P, also mark the expression as having been read.  */
+
+struct c_expr
+convert_lvalue_to_rvalue (location_t loc, struct c_expr exp,
+			  bool convert_p, bool read_p)
+{
+  if (read_p)
+    mark_exp_read (exp.value);
+  if (convert_p)
+    exp = default_function_array_conversion (loc, exp);
+  if (really_atomic_lvalue (exp.value))
+    {
+      vec<tree, va_gc> *params;
+      tree nonatomic_type, tmp, tmp_addr, fndecl, func_call;
+      tree expr_type = TREE_TYPE (exp.value);
+      tree expr_addr = build_unary_op (loc, ADDR_EXPR, exp.value, 0);
+      tree seq_cst = build_int_cst (integer_type_node, MEMMODEL_SEQ_CST);
+
+      gcc_assert (TYPE_ATOMIC (expr_type));
+
+      /* Expansion of a generic atomic load may require an addition
+	 element, so allocate enough to prevent a resize.  */
+      vec_alloc (params, 4);
+
+      /* Remove the qualifiers for the rest of the expressions and
+	 create the VAL temp variable to hold the RHS.  */
+      nonatomic_type = build_qualified_type (expr_type, TYPE_UNQUALIFIED);
+      tmp = create_tmp_var (nonatomic_type, NULL);
+      tmp_addr = build_unary_op (loc, ADDR_EXPR, tmp, 0);
+      TREE_ADDRESSABLE (tmp) = 1;
+
+      /* Issue __atomic_load (&expr, &tmp, SEQ_CST);  */
+      fndecl = builtin_decl_explicit (BUILT_IN_ATOMIC_LOAD);
+      params->quick_push (expr_addr);
+      params->quick_push (tmp_addr);
+      params->quick_push (seq_cst);
+      func_call = build_function_call_vec (loc, fndecl, params, NULL);
+
+      /* Return tmp which contains the value loaded.  */
+      exp.value = build2 (COMPOUND_EXPR, nonatomic_type, func_call, tmp);
+    }
+  return exp;
+}
+
 /* EXP is an expression of integer type.  Apply the integer promotions
    to it and return the promoted value.  */
 
@@ -3435,6 +3536,215 @@ pointer_diff (location_t loc, tree op0, tree op1)
   return convert (restype, result);
 }
 \f
+/* Expand atomic compound assignments into an approriate sequence as
+   specified by the C11 standard section 6.5.16.2.   
+    given 
+       _Atomic T1 E1
+       T2 E2
+       E1 op= E2
+
+  This sequence is used for all types for which these operations are
+  supported.
+
+  In addition, built-in versions of the 'fe' prefixed routines may
+  need to be invoked for floating point (real, complex or vector) when
+  floating-point exceptions are supported.  See 6.5.16.2 footnote 113.
+
+  T1 newval;
+  T1 old;
+  T1 *addr
+  T2 val
+  fenv_t fenv
+
+  addr = &E1;
+  val = (E2);
+  __atomic_load (addr, &old, SEQ_CST);
+  feholdexcept (&fenv);
+loop:
+    newval = old op val;
+    if (__atomic_compare_exchange_strong (addr, &old, &newval, SEQ_CST,
+					  SEQ_CST))
+      goto done;
+    feclearexcept (FE_ALL_EXCEPT);
+    goto loop:
+done:
+  feupdateenv (&fenv);
+
+  Also note that the compiler is simply issuing the generic form of
+  the atomic operations.  This requires temp(s) and has their address
+  taken.  The atomic processing is smart enough to figure out when the
+  size of an object can utilize a lock-free version, and convert the
+  built-in call to the appropriate lock-free routine.  The optimizers
+  will then dispose of any temps that are no longer required, and
+  lock-free implementations are utilized as long as there is target
+  support for the required size.
+
+  If the operator is NOP_EXPR, then this is a simple assignment, and
+  an __atomic_store is issued to perform the assignment rather than
+  the above loop.
+
+*/
+
+/* Build an atomic assignment at LOC, expanding into the proper
+   sequence to store LHS MODIFYCODE= RHS.  Return a value representing
+   the result of the operation, unless RETURN_OLD_P in which case
+   return the old value of LHS (this is only for postincrement and
+   postdecrement).  */
+static tree
+build_atomic_assign (location_t loc, tree lhs, enum tree_code modifycode,
+		     tree rhs, bool return_old_p)
+{
+  tree fndecl, func_call;
+  vec<tree, va_gc> *params;
+  tree val, nonatomic_lhs_type, nonatomic_rhs_type, newval, newval_addr;
+  tree old, old_addr;
+  tree compound_stmt;
+  tree stmt, goto_stmt;
+  tree loop_label, loop_decl, done_label, done_decl;
+
+  tree lhs_type = TREE_TYPE (lhs);
+  tree lhs_addr = build_unary_op (loc, ADDR_EXPR, lhs, 0);
+  tree seq_cst = build_int_cst (integer_type_node, MEMMODEL_SEQ_CST);
+  tree rhs_type = TREE_TYPE (rhs);
+
+  gcc_assert (TYPE_ATOMIC (lhs_type));
+
+  if (return_old_p)
+    gcc_assert (modifycode == PLUS_EXPR || modifycode == MINUS_EXPR);
+
+  /* Allocate enough vector items for a compare_exchange.  */
+  vec_alloc (params, 6);
+
+  /* Create a compound statement to hold the sequence of statements
+     with a loop.  */
+  compound_stmt = c_begin_compound_stmt (false);
+
+  /* Fold the RHS if it hasn't already been folded.  */
+  if (modifycode != NOP_EXPR)
+    rhs = c_fully_fold (rhs, false, NULL);
+
+  /* Remove the qualifiers for the rest of the expressions and create
+     the VAL temp variable to hold the RHS.  */
+  nonatomic_lhs_type = build_qualified_type (lhs_type, TYPE_UNQUALIFIED);
+  nonatomic_rhs_type = build_qualified_type (rhs_type, TYPE_UNQUALIFIED);
+  val = create_tmp_var (nonatomic_rhs_type, NULL);
+  TREE_ADDRESSABLE (val) = 1;
+  rhs = build2 (MODIFY_EXPR, nonatomic_rhs_type, val, rhs);
+  SET_EXPR_LOCATION (rhs, loc);
+  add_stmt (rhs);
+
+  /* NOP_EXPR indicates it's a straight store of the RHS. Simply issue
+     an atomic_store.  */
+  if (modifycode == NOP_EXPR)
+    {
+      /* Build __atomic_store (&lhs, &val, SEQ_CST)  */
+      rhs = build_unary_op (loc, ADDR_EXPR, val, 0);
+      fndecl = builtin_decl_explicit (BUILT_IN_ATOMIC_STORE);
+      params->quick_push (lhs_addr);
+      params->quick_push (rhs);
+      params->quick_push (seq_cst);
+      func_call = build_function_call_vec (loc, fndecl, params, NULL);
+      add_stmt (func_call);
+
+      /* Finish the compound statement.  */
+      compound_stmt = c_end_compound_stmt (loc, compound_stmt, false);
+
+      /* VAL is the value which was stored, return a COMPOUND_STMT of
+	 the statement and that value.  */
+      return build2 (COMPOUND_EXPR, nonatomic_lhs_type, compound_stmt, val);
+    }
+
+  /* Create the variables and labels required for the op= form.  */
+  old = create_tmp_var (nonatomic_lhs_type, NULL);
+  old_addr = build_unary_op (loc, ADDR_EXPR, old, 0);
+  TREE_ADDRESSABLE (val) = 1;
+
+  newval = create_tmp_var (nonatomic_lhs_type, NULL);
+  newval_addr = build_unary_op (loc, ADDR_EXPR, newval, 0);
+  TREE_ADDRESSABLE (newval) = 1;
+
+  loop_decl = create_artificial_label (loc);
+  loop_label = build1 (LABEL_EXPR, void_type_node, loop_decl);
+
+  done_decl = create_artificial_label (loc);
+  done_label = build1 (LABEL_EXPR, void_type_node, done_decl);
+
+  /* __atomic_load (addr, &old, SEQ_CST).  */
+  fndecl = builtin_decl_explicit (BUILT_IN_ATOMIC_LOAD);
+  params->quick_push (lhs_addr);
+  params->quick_push (old_addr);
+  params->quick_push (seq_cst);
+  func_call = build_function_call_vec (loc, fndecl, params, NULL);
+  add_stmt (func_call);
+  params->truncate (0);
+
+  /* Create the expressions for floating-point environment
+     manipulation, if required.  */
+  bool need_fenv = (flag_trapping_math
+		    && (FLOAT_TYPE_P (lhs_type) || FLOAT_TYPE_P (rhs_type)));
+  tree hold_call = NULL_TREE, clear_call = NULL_TREE, update_call = NULL_TREE;
+  if (need_fenv)
+    targetm.atomic_assign_expand_fenv (&hold_call, &clear_call, &update_call);
+
+  if (hold_call)
+    add_stmt (hold_call);
+
+  /* loop:  */
+  add_stmt (loop_label);
+
+  /* newval = old + val;  */
+  rhs = build_binary_op (loc, modifycode, old, val, 1);
+  rhs = convert_for_assignment (loc, nonatomic_lhs_type, rhs, NULL_TREE,
+				ic_assign, false, NULL_TREE,
+				NULL_TREE, 0);
+  if (rhs != error_mark_node)
+    {
+      rhs = build2 (MODIFY_EXPR, nonatomic_lhs_type, newval, rhs);
+      SET_EXPR_LOCATION (rhs, loc);
+      add_stmt (rhs);
+    }
+
+  /* if (__atomic_compare_exchange (addr, &old, &new, false, SEQ_CST, SEQ_CST))
+       goto done;  */
+  fndecl = builtin_decl_explicit (BUILT_IN_ATOMIC_COMPARE_EXCHANGE);
+  params->quick_push (lhs_addr);
+  params->quick_push (old_addr);
+  params->quick_push (newval_addr);
+  params->quick_push (integer_zero_node);
+  params->quick_push (seq_cst);
+  params->quick_push (seq_cst);
+  func_call = build_function_call_vec (loc, fndecl, params, NULL);
+
+  goto_stmt = build1 (GOTO_EXPR, void_type_node, done_decl);
+  SET_EXPR_LOCATION (goto_stmt, loc);
+
+  stmt = build3 (COND_EXPR, void_type_node, func_call, goto_stmt, NULL_TREE);
+  SET_EXPR_LOCATION (stmt, loc);
+  add_stmt (stmt);
+  
+  if (clear_call)
+    add_stmt (clear_call);
+
+  /* goto loop;  */
+  goto_stmt  = build1 (GOTO_EXPR, void_type_node, loop_decl);
+  SET_EXPR_LOCATION (goto_stmt, loc);
+  add_stmt (goto_stmt);
+ 
+  /* done:  */
+  add_stmt (done_label);
+
+  if (update_call)
+    add_stmt (update_call);
+
+  /* Finish the compound statement.  */
+  compound_stmt = c_end_compound_stmt (loc, compound_stmt, false);
+
+  /* NEWVAL is the value that was successfully stored, return a
+     COMPOUND_EXPR of the statement and the appropriate value.  */
+  return build2 (COMPOUND_EXPR, nonatomic_lhs_type, compound_stmt,
+		 return_old_p ? old : newval);
+}
+
 /* Construct and perhaps optimize a tree representation
    for a unary operation.  CODE, a tree_code, specifies the operation
    and XARG is the operand.
@@ -3635,6 +3945,9 @@ build_unary_op (location_t location,
       /* Ensure the argument is fully folded inside any SAVE_EXPR.  */
       arg = c_fully_fold (arg, false, NULL);
 
+      bool atomic_op;
+      atomic_op = really_atomic_lvalue (arg);
+
       /* Increment or decrement the real part of the value,
 	 and don't change the imaginary part.  */
       if (typecode == COMPLEX_TYPE)
@@ -3644,21 +3957,25 @@ build_unary_op (location_t location,
 	  pedwarn (location, OPT_Wpedantic,
 		   "ISO C does not support %<++%> and %<--%> on complex types");
 
-	  arg = stabilize_reference (arg);
-	  real = build_unary_op (EXPR_LOCATION (arg), REALPART_EXPR, arg, 1);
-	  imag = build_unary_op (EXPR_LOCATION (arg), IMAGPART_EXPR, arg, 1);
-	  real = build_unary_op (EXPR_LOCATION (arg), code, real, 1);
-	  if (real == error_mark_node || imag == error_mark_node)
-	    return error_mark_node;
-	  ret = build2 (COMPLEX_EXPR, TREE_TYPE (arg),
-			real, imag);
-	  goto return_build_unary_op;
+	  if (!atomic_op)
+	    {
+	      arg = stabilize_reference (arg);
+	      real = build_unary_op (EXPR_LOCATION (arg), REALPART_EXPR, arg, 1);
+	      imag = build_unary_op (EXPR_LOCATION (arg), IMAGPART_EXPR, arg, 1);
+	      real = build_unary_op (EXPR_LOCATION (arg), code, real, 1);
+	      if (real == error_mark_node || imag == error_mark_node)
+		return error_mark_node;
+	      ret = build2 (COMPLEX_EXPR, TREE_TYPE (arg),
+			    real, imag);
+	      goto return_build_unary_op;
+	    }
 	}
 
       /* Report invalid types.  */
 
       if (typecode != POINTER_TYPE && typecode != FIXED_POINT_TYPE
-	  && typecode != INTEGER_TYPE && typecode != REAL_TYPE)
+	  && typecode != INTEGER_TYPE && typecode != REAL_TYPE
+	  && typecode != COMPLEX_TYPE)
 	{
 	  if (code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR)
 	    error_at (location, "wrong type argument to increment");
@@ -3749,6 +4066,24 @@ build_unary_op (location_t location,
 			      || code == POSTINCREMENT_EXPR)
 			     ? lv_increment : lv_decrement));
 
+	/* If the argument is atomic, use the special code sequences for
+	   atomic compound assignment.  */
+	if (atomic_op)
+	  {
+	    arg = stabilize_reference (arg);
+	    ret = build_atomic_assign (location, arg,
+				       ((code == PREINCREMENT_EXPR
+					 || code == POSTINCREMENT_EXPR)
+					? PLUS_EXPR
+					: MINUS_EXPR),
+				       (FRACT_MODE_P (TYPE_MODE (argtype))
+					? inc
+					: integer_one_node),
+				       (code == POSTINCREMENT_EXPR
+					|| code == POSTDECREMENT_EXPR));
+	    goto return_build_unary_op;
+	  }
+
 	if (TREE_CODE (TREE_TYPE (arg)) == BOOLEAN_TYPE)
 	  val = boolean_increment (code, arg);
 	else
@@ -4259,7 +4594,8 @@ build_conditional_expr (location_t colon_loc, tree
 		    "used in conditional expression");
 	  return error_mark_node;
 	}
-      else if (VOID_TYPE_P (TREE_TYPE (type1)))
+      else if (VOID_TYPE_P (TREE_TYPE (type1))
+	       && !TYPE_ATOMIC (TREE_TYPE (type1)))
 	{
 	  if (TREE_CODE (TREE_TYPE (type2)) == FUNCTION_TYPE)
 	    pedwarn (colon_loc, OPT_Wpedantic,
@@ -4268,7 +4604,8 @@ build_conditional_expr (location_t colon_loc, tree
 	  result_type = build_pointer_type (qualify_type (TREE_TYPE (type1),
 							  TREE_TYPE (type2)));
 	}
-      else if (VOID_TYPE_P (TREE_TYPE (type2)))
+      else if (VOID_TYPE_P (TREE_TYPE (type2))
+	       && !TYPE_ATOMIC (TREE_TYPE (type2)))
 	{
 	  if (TREE_CODE (TREE_TYPE (type1)) == FUNCTION_TYPE)
 	    pedwarn (colon_loc, OPT_Wpedantic,
@@ -4850,6 +5187,7 @@ build_modify_expr (location_t location, tree lhs,
   tree lhstype = TREE_TYPE (lhs);
   tree olhstype = lhstype;
   bool npc;
+  bool is_atomic_op;
 
   /* Types that aren't fully specified cannot be used in assignments.  */
   lhs = require_complete_type (lhs);
@@ -4862,6 +5200,8 @@ build_modify_expr (location_t location, tree lhs,
   if (!objc_is_property_ref (lhs) && !lvalue_or_else (location, lhs, lv_assign))
     return error_mark_node;
 
+  is_atomic_op = really_atomic_lvalue (lhs);
+
   if (TREE_CODE (rhs) == EXCESS_PRECISION_EXPR)
     {
       rhs_semantic_type = TREE_TYPE (rhs);
@@ -4892,12 +5232,17 @@ build_modify_expr (location_t location, tree lhs,
     {
       lhs = c_fully_fold (lhs, false, NULL);
       lhs = stabilize_reference (lhs);
-      newrhs = build_binary_op (location,
-				modifycode, lhs, rhs, 1);
 
-      /* The original type of the right hand side is no longer
-	 meaningful.  */
-      rhs_origtype = NULL_TREE;
+      /* Construct the RHS for any non-atomic compound assignemnt. */
+      if (!is_atomic_op)
+        {
+	  newrhs = build_binary_op (location,
+				    modifycode, lhs, rhs, 1);
+
+	  /* The original type of the right hand side is no longer
+	     meaningful.  */
+	  rhs_origtype = NULL_TREE;
+	}
     }
 
   if (c_dialect_objc ())
@@ -4959,23 +5304,39 @@ build_modify_expr (location_t location, tree lhs,
 			? rhs_origtype
 			: TREE_TYPE (rhs));
       if (checktype != error_mark_node
-	  && TYPE_MAIN_VARIANT (checktype) != TYPE_MAIN_VARIANT (lhs_origtype))
+	  && (TYPE_MAIN_VARIANT (checktype) != TYPE_MAIN_VARIANT (lhs_origtype)
+	      || (is_atomic_op && modifycode != NOP_EXPR)))
 	warning_at (location, OPT_Wc___compat,
 		    "enum conversion in assignment is invalid in C++");
     }
 
+  /* If the lhs is atomic, remove that qualifier.  */
+  if (is_atomic_op)
+    {
+      lhstype = build_qualified_type (lhstype, 
+				      (TYPE_QUALS (lhstype)
+				       & ~TYPE_QUAL_ATOMIC));
+      olhstype = build_qualified_type (olhstype, 
+				       (TYPE_QUALS (lhstype)
+					& ~TYPE_QUAL_ATOMIC));
+    }
+
   /* Convert new value to destination type.  Fold it first, then
      restore any excess precision information, for the sake of
      conversion warnings.  */
 
-  npc = null_pointer_constant_p (newrhs);
-  newrhs = c_fully_fold (newrhs, false, NULL);
-  if (rhs_semantic_type)
-    newrhs = build1 (EXCESS_PRECISION_EXPR, rhs_semantic_type, newrhs);
-  newrhs = convert_for_assignment (location, lhstype, newrhs, rhs_origtype,
-				   ic_assign, npc, NULL_TREE, NULL_TREE, 0);
-  if (TREE_CODE (newrhs) == ERROR_MARK)
-    return error_mark_node;
+  if (!(is_atomic_op && modifycode != NOP_EXPR))
+    {
+      npc = null_pointer_constant_p (newrhs);
+      newrhs = c_fully_fold (newrhs, false, NULL);
+      if (rhs_semantic_type)
+	newrhs = build1 (EXCESS_PRECISION_EXPR, rhs_semantic_type, newrhs);
+      newrhs = convert_for_assignment (location, lhstype, newrhs, rhs_origtype,
+				       ic_assign, npc, NULL_TREE,
+				       NULL_TREE, 0);
+      if (TREE_CODE (newrhs) == ERROR_MARK)
+	return error_mark_node;
+    }
 
   /* Emit ObjC write barrier, if necessary.  */
   if (c_dialect_objc () && flag_objc_gc)
@@ -4990,9 +5351,14 @@ build_modify_expr (location_t location, tree lhs,
 
   /* Scan operands.  */
 
-  result = build2 (MODIFY_EXPR, lhstype, lhs, newrhs);
-  TREE_SIDE_EFFECTS (result) = 1;
-  protected_set_expr_location (result, location);
+  if (is_atomic_op)
+    result = build_atomic_assign (location, lhs, modifycode, newrhs, false);
+  else
+    {
+      result = build2 (MODIFY_EXPR, lhstype, lhs, newrhs);
+      TREE_SIDE_EFFECTS (result) = 1;
+      protected_set_expr_location (result, location);
+    }
 
   /* If we got the LHS in a different type for storing in,
      convert the result back to the nominal type of LHS
@@ -5024,8 +5390,12 @@ find_anonymous_field_with_type (tree struct_type,
        field != NULL_TREE;
        field = TREE_CHAIN (field))
     {
+      tree fieldtype = (TYPE_ATOMIC (TREE_TYPE (field))
+			? c_build_qualified_type (TREE_TYPE (field),
+						  TYPE_QUAL_ATOMIC)
+			: TYPE_MAIN_VARIANT (TREE_TYPE (field)));
       if (DECL_NAME (field) == NULL
-	  && comptypes (type, TYPE_MAIN_VARIANT (TREE_TYPE (field))))
+	  && comptypes (type, fieldtype))
 	{
 	  if (found)
 	    return false;
@@ -5063,7 +5433,10 @@ convert_to_anonymous_field (location_t location, t
 	      || TREE_CODE (rhs_struct_type) == UNION_TYPE);
 
   gcc_assert (POINTER_TYPE_P (type));
-  lhs_main_type = TYPE_MAIN_VARIANT (TREE_TYPE (type));
+  lhs_main_type = (TYPE_ATOMIC (TREE_TYPE (type))
+		   ? c_build_qualified_type (TREE_TYPE (type),
+					     TYPE_QUAL_ATOMIC)
+		   : TYPE_MAIN_VARIANT (TREE_TYPE (type)));
 
   found_field = NULL_TREE;
   found_sub_field = false;
@@ -5075,7 +5448,11 @@ convert_to_anonymous_field (location_t location, t
 	  || (TREE_CODE (TREE_TYPE (field)) != RECORD_TYPE
 	      && TREE_CODE (TREE_TYPE (field)) != UNION_TYPE))
 	continue;
-      if (comptypes (lhs_main_type, TYPE_MAIN_VARIANT (TREE_TYPE (field))))
+      tree fieldtype = (TYPE_ATOMIC (TREE_TYPE (field))
+			? c_build_qualified_type (TREE_TYPE (field),
+						  TYPE_QUAL_ATOMIC)
+			: TYPE_MAIN_VARIANT (TREE_TYPE (field)));
+      if (comptypes (lhs_main_type, fieldtype))
 	{
 	  if (found_field != NULL_TREE)
 	    return NULL_TREE;
@@ -5365,17 +5742,18 @@ convert_for_assignment (location_t location, tree
 		 and vice versa; otherwise, targets must be the same.
 		 Meanwhile, the lhs target must have all the qualifiers of
 		 the rhs.  */
-	      if (VOID_TYPE_P (ttl) || VOID_TYPE_P (ttr)
+	      if ((VOID_TYPE_P (ttl) && !TYPE_ATOMIC (ttl))
+		  || (VOID_TYPE_P (ttr) && !TYPE_ATOMIC (ttr))
 		  || comp_target_types (location, memb_type, rhstype))
 		{
+		  int lquals = TYPE_QUALS (ttl) & ~TYPE_QUAL_ATOMIC;
+		  int rquals = TYPE_QUALS (ttr) & ~TYPE_QUAL_ATOMIC;
 		  /* If this type won't generate any warnings, use it.  */
-		  if (TYPE_QUALS (ttl) == TYPE_QUALS (ttr)
+		  if (lquals == rquals
 		      || ((TREE_CODE (ttr) == FUNCTION_TYPE
 			   && TREE_CODE (ttl) == FUNCTION_TYPE)
-			  ? ((TYPE_QUALS (ttl) | TYPE_QUALS (ttr))
-			     == TYPE_QUALS (ttr))
-			  : ((TYPE_QUALS (ttl) | TYPE_QUALS (ttr))
-			     == TYPE_QUALS (ttl))))
+			  ? ((lquals | rquals) == rquals)
+			  : ((lquals | rquals) == lquals)))
 		    break;
 
 		  /* Keep looking for a better type, but remember this one.  */
@@ -5466,9 +5844,15 @@ convert_for_assignment (location_t location, tree
       addr_space_t asr;
 
       if (TREE_CODE (mvl) != ARRAY_TYPE)
-	mvl = TYPE_MAIN_VARIANT (mvl);
+	mvl = (TYPE_ATOMIC (mvl)
+	       ? c_build_qualified_type (TYPE_MAIN_VARIANT (mvl),
+					 TYPE_QUAL_ATOMIC)
+	       : TYPE_MAIN_VARIANT (mvl));
       if (TREE_CODE (mvr) != ARRAY_TYPE)
-	mvr = TYPE_MAIN_VARIANT (mvr);
+	mvr = (TYPE_ATOMIC (mvr)
+	       ? c_build_qualified_type (TYPE_MAIN_VARIANT (mvr),
+					 TYPE_QUAL_ATOMIC)
+	       : TYPE_MAIN_VARIANT (mvr));
       /* Opaque pointers are treated like void pointers.  */
       is_opaque_pointer = vector_targets_convertible_p (ttl, ttr);
 
@@ -5569,13 +5953,15 @@ convert_for_assignment (location_t location, tree
       /* Any non-function converts to a [const][volatile] void *
 	 and vice versa; otherwise, targets must be the same.
 	 Meanwhile, the lhs target must have all the qualifiers of the rhs.  */
-      if (VOID_TYPE_P (ttl) || VOID_TYPE_P (ttr)
+      if ((VOID_TYPE_P (ttl) && !TYPE_ATOMIC (ttl))
+	  || (VOID_TYPE_P (ttr) && !TYPE_ATOMIC (ttr))
 	  || (target_cmp = comp_target_types (location, type, rhstype))
 	  || is_opaque_pointer
 	  || ((c_common_unsigned_type (mvl)
 	       == c_common_unsigned_type (mvr))
-	      && c_common_signed_type (mvl)
-		 == c_common_signed_type (mvr)))
+	      && (c_common_signed_type (mvl)
+		  == c_common_signed_type (mvr))
+	      && TYPE_ATOMIC (mvl) == TYPE_ATOMIC (mvr)))
 	{
 	  if (pedantic
 	      && ((VOID_TYPE_P (ttl) && TREE_CODE (ttr) == FUNCTION_TYPE)
@@ -5598,8 +5984,9 @@ convert_for_assignment (location_t location, tree
 	  else if (TREE_CODE (ttr) != FUNCTION_TYPE
 		   && TREE_CODE (ttl) != FUNCTION_TYPE)
 	    {
-	      if (TYPE_QUALS_NO_ADDR_SPACE (ttr)
-		  & ~TYPE_QUALS_NO_ADDR_SPACE (ttl))
+	      /* Assignments between atomic and non-atomic objects are OK.  */
+	      if (TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC (ttr)
+		  & ~TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC (ttl))
 		{
 		  WARN_FOR_QUALIFIERS (location, 0,
 				       G_("passing argument %d of %qE discards "
@@ -6072,7 +6459,11 @@ digest_init (location_t init_loc, tree type, tree
   if (code == ARRAY_TYPE && inside_init
       && TREE_CODE (inside_init) == STRING_CST)
     {
-      tree typ1 = TYPE_MAIN_VARIANT (TREE_TYPE (type));
+      tree typ1
+	= (TYPE_ATOMIC (TREE_TYPE (type))
+	   ? c_build_qualified_type (TYPE_MAIN_VARIANT (TREE_TYPE (type)),
+				     TYPE_QUAL_ATOMIC)
+	   : TYPE_MAIN_VARIANT (TREE_TYPE (type)));
       /* Note that an array could be both an array of character type
 	 and an array of wchar_t if wchar_t is signed char or unsigned
 	 char.  */
@@ -8610,7 +9001,7 @@ build_asm_expr (location_t loc, tree string, tree
 	      struct c_expr expr;
 	      memset (&expr, 0, sizeof (expr));
 	      expr.value = input;
-	      expr = default_function_array_conversion (loc, expr);
+	      expr = convert_lvalue_to_rvalue (loc, expr, true, false);
 	      input = c_fully_fold (expr.value, false, NULL);
 
 	      if (input != error_mark_node && VOID_TYPE_P (TREE_TYPE (input)))
@@ -10096,13 +10487,13 @@ build_binary_op (location_t location, enum tree_co
 			"disjoint address spaces");
 	      return error_mark_node;
 	    }
-	  else if (VOID_TYPE_P (tt0))
+	  else if (VOID_TYPE_P (tt0) && !TYPE_ATOMIC (tt0))
 	    {
 	      if (pedantic && TREE_CODE (tt1) == FUNCTION_TYPE)
 		pedwarn (location, OPT_Wpedantic, "ISO C forbids "
 			 "comparison of %<void *%> with function pointer");
 	    }
-	  else if (VOID_TYPE_P (tt1))
+	  else if (VOID_TYPE_P (tt1) && !TYPE_ATOMIC (tt1))
 	    {
 	      if (pedantic && TREE_CODE (tt0) == FUNCTION_TYPE)
 		pedwarn (location, OPT_Wpedantic, "ISO C forbids "
Index: gcc/c/c-tree.h
===================================================================
--- gcc/c/c-tree.h	(revision 204390)
+++ gcc/c/c-tree.h	(working copy)
@@ -163,7 +163,7 @@ enum c_typespec_kind {
   ctsk_typedef,
   /* An ObjC-specific kind of type specifier.  */
   ctsk_objc,
-  /* A typeof specifier.  */
+  /* A typeof specifier, or _Atomic ( type-name ).  */
   ctsk_typeof
 };
 
@@ -328,6 +328,8 @@ struct c_declspecs {
   BOOL_BITFIELD volatile_p : 1;
   /* Whether "restrict" was specified.  */
   BOOL_BITFIELD restrict_p : 1;
+  /* Whether "_Atomic" was specified.  */
+  BOOL_BITFIELD atomic_p : 1;
   /* Whether "_Sat" was specified.  */
   BOOL_BITFIELD saturating_p : 1;
   /* Whether any alignment specifier (even with zero alignment) was
@@ -585,6 +587,8 @@ extern struct c_expr default_function_array_conver
 							struct c_expr);
 extern struct c_expr default_function_array_read_conversion (location_t,
 							     struct c_expr);
+extern struct c_expr convert_lvalue_to_rvalue (location_t, struct c_expr,
+					       bool, bool);
 extern void mark_exp_read (tree);
 extern tree composite_type (tree, tree);
 extern tree build_component_ref (location_t, tree, tree);
Index: gcc/c/c-decl.c
===================================================================
--- gcc/c/c-decl.c	(revision 204390)
+++ gcc/c/c-decl.c	(working copy)
@@ -1584,8 +1584,14 @@ validate_proto_after_old_defn (tree newdecl, tree
       if (oldargtype == error_mark_node || newargtype == error_mark_node)
 	return false;
 
-      oldargtype = TYPE_MAIN_VARIANT (oldargtype);
-      newargtype = TYPE_MAIN_VARIANT (newargtype);
+      oldargtype = (TYPE_ATOMIC (oldargtype)
+		    ? c_build_qualified_type (TYPE_MAIN_VARIANT (oldargtype),
+					      TYPE_QUAL_ATOMIC)
+		    : TYPE_MAIN_VARIANT (oldargtype));
+      newargtype = (TYPE_ATOMIC (newargtype)
+		    ? c_build_qualified_type (TYPE_MAIN_VARIANT (newargtype),
+					      TYPE_QUAL_ATOMIC)
+		    : TYPE_MAIN_VARIANT (newargtype));
 
       if (END_OF_ARGLIST (oldargtype) && END_OF_ARGLIST (newargtype))
 	break;
@@ -3714,6 +3720,7 @@ shadow_tag_warned (const struct c_declspecs *decls
                    && declspecs->typespec_kind != ctsk_tagfirstref
 		   && (declspecs->const_p
 		       || declspecs->volatile_p
+		       || declspecs->atomic_p
 		       || declspecs->restrict_p
 		       || declspecs->address_space))
 	    {
@@ -3803,6 +3810,7 @@ shadow_tag_warned (const struct c_declspecs *decls
 
   if (!warned && !in_system_header && (declspecs->const_p
 				       || declspecs->volatile_p
+				       || declspecs->atomic_p
 				       || declspecs->restrict_p
 				       || declspecs->address_space))
     {
@@ -3834,6 +3842,7 @@ quals_from_declspecs (const struct c_declspecs *sp
   int quals = ((specs->const_p ? TYPE_QUAL_CONST : 0)
 	       | (specs->volatile_p ? TYPE_QUAL_VOLATILE : 0)
 	       | (specs->restrict_p ? TYPE_QUAL_RESTRICT : 0)
+	       | (specs->atomic_p ? TYPE_QUAL_ATOMIC : 0)
 	       | (ENCODE_QUAL_ADDR_SPACE (specs->address_space)));
   gcc_assert (!specs->type
 	      && !specs->decl_attr
@@ -4169,7 +4178,7 @@ start_decl (struct c_declarator *declarator, struc
 	      tree type = TREE_TYPE (args);
 	      if (type && INTEGRAL_TYPE_P (type)
 		  && TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node))
-		DECL_ARG_TYPE (args) = integer_type_node;
+		DECL_ARG_TYPE (args) = c_type_promotes_to (type);
 	    }
 	}
     }
@@ -4942,6 +4951,7 @@ grokdeclarator (const struct c_declarator *declara
   int constp;
   int restrictp;
   int volatilep;
+  int atomicp;
   int type_quals = TYPE_UNQUALIFIED;
   tree name = NULL_TREE;
   bool funcdef_flag = false;
@@ -5096,6 +5106,7 @@ grokdeclarator (const struct c_declarator *declara
   constp = declspecs->const_p + TYPE_READONLY (element_type);
   restrictp = declspecs->restrict_p + TYPE_RESTRICT (element_type);
   volatilep = declspecs->volatile_p + TYPE_VOLATILE (element_type);
+  atomicp = declspecs->atomic_p + TYPE_ATOMIC (element_type);
   as1 = declspecs->address_space;
   as2 = TYPE_ADDR_SPACE (element_type);
   address_space = ADDR_SPACE_GENERIC_P (as1)? as2 : as1;
@@ -5108,6 +5119,9 @@ grokdeclarator (const struct c_declarator *declara
 	pedwarn (loc, OPT_Wpedantic, "duplicate %<restrict%>");
       if (volatilep > 1)
 	pedwarn (loc, OPT_Wpedantic, "duplicate %<volatile%>");
+      if (atomicp > 1)
+	pedwarn (loc, OPT_Wpedantic, "duplicate %<_Atomic%>");
+
     }
 
   if (!ADDR_SPACE_GENERIC_P (as1) && !ADDR_SPACE_GENERIC_P (as2) && as1 != as2)
@@ -5121,8 +5135,16 @@ grokdeclarator (const struct c_declarator *declara
   type_quals = ((constp ? TYPE_QUAL_CONST : 0)
 		| (restrictp ? TYPE_QUAL_RESTRICT : 0)
 		| (volatilep ? TYPE_QUAL_VOLATILE : 0)
+		| (atomicp ? TYPE_QUAL_ATOMIC : 0)
 		| ENCODE_QUAL_ADDR_SPACE (address_space));
 
+  /* Applying the _Atomic qualifier to an array type (through the use
+     of typedefs or typeof) must be detected here.  If the qualifier
+     is introduced later, any appearance of applying it to an array is
+     actually applying it to an element of that array.  */
+  if (atomicp && TREE_CODE (type) == ARRAY_TYPE)
+    error_at (loc, "%<_Atomic%>-qualified array type");
+
   /* Warn about storage classes that are invalid for certain
      kinds of declarations (parameters, typenames, etc.).  */
 
@@ -5698,9 +5720,15 @@ grokdeclarator (const struct c_declarator *declara
 	  {
 	    /* Merge any constancy or volatility into the target type
 	       for the pointer.  */
-
-	    if (pedantic && TREE_CODE (type) == FUNCTION_TYPE
-		&& type_quals)
+	    if ((type_quals & TYPE_QUAL_ATOMIC)
+		&& TREE_CODE (type) == FUNCTION_TYPE)
+	      {
+		error_at (loc,
+			  "%<_Atomic%>-qualified function type");
+		type_quals &= ~TYPE_QUAL_ATOMIC;
+	      }
+	    else if (pedantic && TREE_CODE (type) == FUNCTION_TYPE
+		     && type_quals)
 	      pedwarn (loc, OPT_Wpedantic,
 		       "ISO C forbids qualified function types");
 	    if (type_quals)
@@ -5814,7 +5842,20 @@ grokdeclarator (const struct c_declarator *declara
 
   /* Check the type and width of a bit-field.  */
   if (bitfield)
-    check_bitfield_type_and_width (&type, width, name);
+    {
+      check_bitfield_type_and_width (&type, width, name);
+      /* C11 makes it implementation-defined (6.7.2.1#5) whether
+	 atomic types are permitted for bit-fields; we have no code to
+	 make bit-field accesses atomic, so disallow them.  */
+      if (type_quals & TYPE_QUAL_ATOMIC)
+	{
+	  if (name)
+	    error ("bit-field %qE has atomic type", name);
+	  else
+	    error ("bit-field has atomic type");
+	  type_quals &= ~TYPE_QUAL_ATOMIC;
+	}
+    }
 
   /* Reject invalid uses of _Alignas.  */
   if (declspecs->alignas_p)
@@ -5877,8 +5918,15 @@ grokdeclarator (const struct c_declarator *declara
   if (storage_class == csc_typedef)
     {
       tree decl;
-      if (pedantic && TREE_CODE (type) == FUNCTION_TYPE
-	  && type_quals)
+      if ((type_quals & TYPE_QUAL_ATOMIC)
+	  && TREE_CODE (type) == FUNCTION_TYPE)
+	{
+	  error_at (loc,
+		    "%<_Atomic%>-qualified function type");
+	  type_quals &= ~TYPE_QUAL_ATOMIC;
+	}
+      else if (pedantic && TREE_CODE (type) == FUNCTION_TYPE
+	       && type_quals)
 	pedwarn (loc, OPT_Wpedantic,
 		 "ISO C forbids qualified function types");
       if (type_quals)
@@ -5923,8 +5971,15 @@ grokdeclarator (const struct c_declarator *declara
 	 and fields.  */
       gcc_assert (storage_class == csc_none && !threadp
 		  && !declspecs->inline_p && !declspecs->noreturn_p);
-      if (pedantic && TREE_CODE (type) == FUNCTION_TYPE
-	  && type_quals)
+      if ((type_quals & TYPE_QUAL_ATOMIC)
+	  && TREE_CODE (type) == FUNCTION_TYPE)
+	{
+	  error_at (loc,
+		    "%<_Atomic%>-qualified function type");
+	  type_quals &= ~TYPE_QUAL_ATOMIC;
+	}
+      else if (pedantic && TREE_CODE (type) == FUNCTION_TYPE
+	       && type_quals)
 	pedwarn (loc, OPT_Wpedantic,
 		 "ISO C forbids const or volatile function types");
       if (type_quals)
@@ -5990,7 +6045,13 @@ grokdeclarator (const struct c_declarator *declara
 	  }
 	else if (TREE_CODE (type) == FUNCTION_TYPE)
 	  {
-	    if (type_quals)
+	    if (type_quals & TYPE_QUAL_ATOMIC)
+	      {
+		error_at (loc,
+			  "%<_Atomic%>-qualified function type");
+		type_quals &= ~TYPE_QUAL_ATOMIC;
+	      }
+	    else if (type_quals)
 	      pedwarn (loc, OPT_Wpedantic,
 		       "ISO C forbids qualified function types");
 	    if (type_quals)
@@ -6085,7 +6146,13 @@ grokdeclarator (const struct c_declarator *declara
 			   FUNCTION_DECL, declarator->u.id, type);
 	decl = build_decl_attribute_variant (decl, decl_attr);
 
-	if (pedantic && type_quals && !DECL_IN_SYSTEM_HEADER (decl))
+	if (type_quals & TYPE_QUAL_ATOMIC)
+	  {
+	    error_at (loc,
+		      "%<_Atomic%>-qualified function type");
+	    type_quals &= ~TYPE_QUAL_ATOMIC;
+	  }
+	else if (pedantic && type_quals && !DECL_IN_SYSTEM_HEADER (decl))
 	  pedwarn (loc, OPT_Wpedantic,
 		   "ISO C forbids qualified function types");
 
@@ -6458,8 +6525,7 @@ get_parm_info (bool ellipsis, tree expr)
       && !DECL_NAME (b->decl)               /* anonymous */
       && VOID_TYPE_P (TREE_TYPE (b->decl))) /* of void type */
     {
-      if (TREE_THIS_VOLATILE (b->decl)
-	  || TREE_READONLY (b->decl)
+      if (TYPE_QUALS (TREE_TYPE (b->decl)) != TYPE_UNQUALIFIED
 	  || C_DECL_REGISTER (b->decl))
 	error ("%<void%> as only parameter may not be qualified");
 
@@ -8212,11 +8278,15 @@ store_parm_decls_oldstyle (tree fndecl, const stru
 	     type for parameters declared with qualified type.  */
 	  if (TREE_TYPE (parm) != error_mark_node
 	      && TREE_TYPE (type) != error_mark_node
-	      && !comptypes (TYPE_MAIN_VARIANT (DECL_ARG_TYPE (parm)),
-			     TYPE_MAIN_VARIANT (TREE_VALUE (type))))
+	      && ((TYPE_ATOMIC (DECL_ARG_TYPE (parm))
+		   != TYPE_ATOMIC (TREE_VALUE (type)))
+		  || !comptypes (TYPE_MAIN_VARIANT (DECL_ARG_TYPE (parm)),
+				 TYPE_MAIN_VARIANT (TREE_VALUE (type)))))
 	    {
-	      if (TYPE_MAIN_VARIANT (TREE_TYPE (parm))
-		  == TYPE_MAIN_VARIANT (TREE_VALUE (type)))
+	      if ((TYPE_ATOMIC (DECL_ARG_TYPE (parm))
+		   == TYPE_ATOMIC (TREE_VALUE (type)))
+		  && (TYPE_MAIN_VARIANT (TREE_TYPE (parm))
+		      == TYPE_MAIN_VARIANT (TREE_VALUE (type))))
 		{
 		  /* Adjust argument to match prototype.  E.g. a previous
 		     `int foo(float);' prototype causes
@@ -8229,7 +8299,8 @@ store_parm_decls_oldstyle (tree fndecl, const stru
 		      && INTEGRAL_TYPE_P (TREE_TYPE (parm))
 		      && TYPE_PRECISION (TREE_TYPE (parm))
 		      < TYPE_PRECISION (integer_type_node))
-		    DECL_ARG_TYPE (parm) = integer_type_node;
+		    DECL_ARG_TYPE (parm)
+		      = c_type_promotes_to (TREE_TYPE (parm));
 
 		  /* ??? Is it possible to get here with a
 		     built-in prototype or will it always have
@@ -8431,7 +8502,7 @@ finish_function (void)
 	  tree type = TREE_TYPE (args);
 	  if (INTEGRAL_TYPE_P (type)
 	      && TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node))
-	    DECL_ARG_TYPE (args) = integer_type_node;
+	    DECL_ARG_TYPE (args) = c_type_promotes_to (type);
 	}
     }
 
@@ -8910,6 +8981,7 @@ build_null_declspecs (void)
   ret->thread_p = false;
   ret->const_p = false;
   ret->volatile_p = false;
+  ret->atomic_p = false;
   ret->restrict_p = false;
   ret->saturating_p = false;
   ret->alignas_p = false;
@@ -8971,6 +9043,10 @@ declspecs_add_qual (source_location loc,
       specs->restrict_p = true;
       specs->locations[cdw_restrict] = loc;
       break;
+    case RID_ATOMIC:
+      dupe = specs->atomic_p;
+      specs->atomic_p = true;
+      break;
     default:
       gcc_unreachable ();
     }
Index: gcc/targhooks.c
===================================================================
--- gcc/targhooks.c	(revision 204390)
+++ gcc/targhooks.c	(working copy)
@@ -1600,6 +1600,13 @@ default_canonicalize_comparison (int *, rtx *, rtx
 {
 }
 
+/* Default implementation of TARGET_ATOMIC_ASSIGN_EXPAND_FENV.  */
+
+void
+default_atomic_assign_expand_fenv (tree *, tree *, tree *)
+{
+}
+
 #ifndef PAD_VARARGS_DOWN
 #define PAD_VARARGS_DOWN BYTES_BIG_ENDIAN
 #endif
Index: gcc/targhooks.h
===================================================================
--- gcc/targhooks.h	(revision 204390)
+++ gcc/targhooks.h	(working copy)
@@ -203,6 +203,7 @@ extern void default_asm_output_ident_directive (co
 
 extern enum machine_mode default_cstore_mode (enum insn_code);
 extern bool default_member_type_forces_blk (const_tree, enum machine_mode);
+extern void default_atomic_assign_expand_fenv (tree *, tree *, tree *);
 extern tree build_va_arg_indirect_ref (tree);
 extern tree std_gimplify_va_arg_expr (tree, tree, gimple_seq *, gimple_seq *);
 
Index: gcc/print-tree.c
===================================================================
--- gcc/print-tree.c	(revision 204390)
+++ gcc/print-tree.c	(working copy)
@@ -305,6 +305,8 @@ print_node (FILE *file, const char *prefix, tree n
 
   if (TYPE_P (node) ? TYPE_READONLY (node) : TREE_READONLY (node))
     fputs (" readonly", file);
+  if (TYPE_P (node) && TYPE_ATOMIC (node))
+    fputs (" atomic", file);
   if (!TYPE_P (node) && TREE_CONSTANT (node))
     fputs (" constant", file);
   else if (TYPE_P (node) && TYPE_SIZES_GIMPLIFIED (node))
Index: gcc/tree.c
===================================================================
--- gcc/tree.c	(revision 204390)
+++ gcc/tree.c	(working copy)
@@ -6202,6 +6202,7 @@ set_type_quals (tree type, int type_quals)
   TYPE_READONLY (type) = (type_quals & TYPE_QUAL_CONST) != 0;
   TYPE_VOLATILE (type) = (type_quals & TYPE_QUAL_VOLATILE) != 0;
   TYPE_RESTRICT (type) = (type_quals & TYPE_QUAL_RESTRICT) != 0;
+  TYPE_ATOMIC (type) = (type_quals & TYPE_QUAL_ATOMIC) != 0;
   TYPE_ADDR_SPACE (type) = DECODE_QUAL_ADDR_SPACE (type_quals);
 }
 
@@ -6235,6 +6236,48 @@ check_aligned_type (const_tree cand, const_tree ba
 				   TYPE_ATTRIBUTES (base)));
 }
 
+/* This function checks to see if TYPE matches the size one of the built-in 
+   atomic types, and returns that core atomic type.  */
+
+static tree
+find_atomic_core_type (tree type)
+{
+  tree base_atomic_type;
+
+  /* Only handle complete types.  */
+  if (TYPE_SIZE (type) == NULL_TREE)
+    return NULL_TREE;
+
+  HOST_WIDE_INT type_size = tree_low_cst (TYPE_SIZE (type), 1);
+  switch (type_size)
+    {
+    case 8:
+      base_atomic_type = atomicQI_type_node;
+      break;
+
+    case 16:
+      base_atomic_type = atomicHI_type_node;
+      break;
+
+    case 32:
+      base_atomic_type = atomicSI_type_node;
+      break;
+
+    case 64:
+      base_atomic_type = atomicDI_type_node;
+      break;
+
+    case 128:
+      base_atomic_type = atomicTI_type_node;
+      break;
+
+    default:
+      base_atomic_type = NULL_TREE;
+    }
+
+  return base_atomic_type;
+}
+
 /* Return a version of the TYPE, qualified as indicated by the
    TYPE_QUALS, if one exists.  If no qualified version exists yet,
    return NULL_TREE.  */
@@ -6274,6 +6317,19 @@ build_qualified_type (tree type, int type_quals)
       t = build_variant_type_copy (type);
       set_type_quals (t, type_quals);
 
+      if (((type_quals & TYPE_QUAL_ATOMIC) == TYPE_QUAL_ATOMIC))
+	{
+	  /* See if this object can map to a basic atomic type.  */
+	  tree atomic_type = find_atomic_core_type (type);
+	  if (atomic_type)
+	    {
+	      /* Ensure the alignment of this type is compatible with
+		 the required alignment of the atomic type.  */
+	      if (TYPE_ALIGN (atomic_type) > TYPE_ALIGN (t))
+		TYPE_ALIGN (t) = TYPE_ALIGN (atomic_type);
+	    }
+	}
+
       if (TYPE_STRUCTURAL_EQUALITY_P (type))
 	/* Propagate structural equality. */
 	SET_TYPE_STRUCTURAL_EQUALITY (t);
@@ -9774,6 +9830,28 @@ make_or_reuse_accum_type (unsigned size, int unsig
   return make_accum_type (size, unsignedp, satp);
 }
 
+
+/* Create an atomic variant node for TYPE.  This routine is called
+   during initialization of data types to create the 5 basic atomic
+   types. The generic build_variant_type function requires these to
+   already be set up in order to function properly, so cannot be
+   called from there.  */
+
+static tree
+build_atomic_base (tree type)
+{
+  tree t;
+
+  /* Make sure its not already registered.  */
+  if ((t = get_qualified_type (type, TYPE_QUAL_ATOMIC)))
+    return t;
+  
+  t = build_variant_type_copy (type);
+  set_type_quals (t, TYPE_QUAL_ATOMIC);
+
+  return t;
+}
+
 /* Create nodes for all integer types (and error_mark_node) using the sizes
    of C datatypes.  SIGNED_CHAR specifies whether char is signed,
    SHORT_DOUBLE specifies whether double should be of the same precision
@@ -9856,6 +9934,16 @@ build_common_tree_nodes (bool signed_char, bool sh
   unsigned_intDI_type_node = make_or_reuse_type (GET_MODE_BITSIZE (DImode), 1);
   unsigned_intTI_type_node = make_or_reuse_type (GET_MODE_BITSIZE (TImode), 1);
 
+  /* Don't call build_qualified type for atomics.  That routine does
+     special processing for atomics, and until they are initialized
+     it's better not to make that call.  */
+
+  atomicQI_type_node = build_atomic_base (unsigned_intQI_type_node);
+  atomicHI_type_node = build_atomic_base (unsigned_intHI_type_node);
+  atomicSI_type_node = build_atomic_base (unsigned_intSI_type_node);
+  atomicDI_type_node = build_atomic_base (unsigned_intDI_type_node);
+  atomicTI_type_node = build_atomic_base (unsigned_intTI_type_node);
+
   access_public_node = get_identifier ("public");
   access_protected_node = get_identifier ("protected");
   access_private_node = get_identifier ("private");
Index: gcc/tree.h
===================================================================
--- gcc/tree.h	(revision 204390)
+++ gcc/tree.h	(working copy)
@@ -1598,6 +1598,9 @@ extern enum machine_mode vector_type_mode (const_t
 /* Nonzero in a type considered volatile as a whole.  */
 #define TYPE_VOLATILE(NODE) (TYPE_CHECK (NODE)->base.volatile_flag)
 
+/* Nonzero in a type considered atomic as a whole.  */
+#define TYPE_ATOMIC(NODE) (TYPE_CHECK (NODE)->base.u.bits.atomic_flag)
+
 /* Means this type is const-qualified.  */
 #define TYPE_READONLY(NODE) (TYPE_CHECK (NODE)->base.readonly_flag)
 
@@ -1627,6 +1630,7 @@ extern enum machine_mode vector_type_mode (const_t
 #define TYPE_QUALS(NODE)					\
   ((int) ((TYPE_READONLY (NODE) * TYPE_QUAL_CONST)		\
 	  | (TYPE_VOLATILE (NODE) * TYPE_QUAL_VOLATILE)		\
+	  | (TYPE_ATOMIC (NODE) * TYPE_QUAL_ATOMIC)		\
 	  | (TYPE_RESTRICT (NODE) * TYPE_QUAL_RESTRICT)		\
 	  | (ENCODE_QUAL_ADDR_SPACE (TYPE_ADDR_SPACE (NODE)))))
 
@@ -1634,8 +1638,16 @@ extern enum machine_mode vector_type_mode (const_t
 #define TYPE_QUALS_NO_ADDR_SPACE(NODE)				\
   ((int) ((TYPE_READONLY (NODE) * TYPE_QUAL_CONST)		\
 	  | (TYPE_VOLATILE (NODE) * TYPE_QUAL_VOLATILE)		\
+	  | (TYPE_ATOMIC (NODE) * TYPE_QUAL_ATOMIC)		\
 	  | (TYPE_RESTRICT (NODE) * TYPE_QUAL_RESTRICT)))
 
+/* The same as TYPE_QUALS without the address space and atomic 
+   qualifications.  */
+#define TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC(NODE)		\
+  ((int) ((TYPE_READONLY (NODE) * TYPE_QUAL_CONST)		\
+	  | (TYPE_VOLATILE (NODE) * TYPE_QUAL_VOLATILE)		\
+	  | (TYPE_RESTRICT (NODE) * TYPE_QUAL_RESTRICT)))
+
 /* These flags are available for each language front end to use internally.  */
 #define TYPE_LANG_FLAG_0(NODE) (TYPE_CHECK (NODE)->type_common.lang_flag_0)
 #define TYPE_LANG_FLAG_1(NODE) (TYPE_CHECK (NODE)->type_common.lang_flag_1)
@@ -3176,6 +3188,12 @@ tree_operand_check_code (const_tree __t, enum tree
 #define unsigned_intDI_type_node	global_trees[TI_UINTDI_TYPE]
 #define unsigned_intTI_type_node	global_trees[TI_UINTTI_TYPE]
 
+#define atomicQI_type_node	global_trees[TI_ATOMICQI_TYPE]
+#define atomicHI_type_node	global_trees[TI_ATOMICHI_TYPE]
+#define atomicSI_type_node	global_trees[TI_ATOMICSI_TYPE]
+#define atomicDI_type_node	global_trees[TI_ATOMICDI_TYPE]
+#define atomicTI_type_node	global_trees[TI_ATOMICTI_TYPE]
+
 #define uint16_type_node		global_trees[TI_UINT16_TYPE]
 #define uint32_type_node		global_trees[TI_UINT32_TYPE]
 #define uint64_type_node		global_trees[TI_UINT64_TYPE]
Index: gcc/tree-pretty-print.c
===================================================================
--- gcc/tree-pretty-print.c	(revision 204390)
+++ gcc/tree-pretty-print.c	(working copy)
@@ -878,6 +878,8 @@ dump_generic_node (pretty_printer *buffer, tree no
 	unsigned int quals = TYPE_QUALS (node);
 	enum tree_code_class tclass;
 
+	if (quals & TYPE_QUAL_ATOMIC)
+	  pp_string (buffer, "atomic ");
 	if (quals & TYPE_QUAL_CONST)
 	  pp_string (buffer, "const ");
 	else if (quals & TYPE_QUAL_VOLATILE)
@@ -1179,6 +1181,8 @@ dump_generic_node (pretty_printer *buffer, tree no
       {
 	unsigned int quals = TYPE_QUALS (node);
 
+	if (quals & TYPE_QUAL_ATOMIC)
+	  pp_string (buffer, "atomic ");
 	if (quals & TYPE_QUAL_CONST)
 	  pp_string (buffer, "const ");
 	if (quals & TYPE_QUAL_VOLATILE)
Index: gcc/objc/objc-act.c
===================================================================
--- gcc/objc/objc-act.c	(revision 204390)
+++ gcc/objc/objc-act.c	(working copy)
@@ -8244,6 +8244,7 @@ objc_push_parm (tree parm)
   c_apply_type_quals_to_decl
   ((TYPE_READONLY (TREE_TYPE (parm)) ? TYPE_QUAL_CONST : 0)
    | (TYPE_RESTRICT (TREE_TYPE (parm)) ? TYPE_QUAL_RESTRICT : 0)
+   | (TYPE_ATOMIC (TREE_TYPE (parm)) ? TYPE_QUAL_ATOMIC : 0)
    | (TYPE_VOLATILE (TREE_TYPE (parm)) ? TYPE_QUAL_VOLATILE : 0), parm);
 
   objc_parmlist = chainon (objc_parmlist, parm);
Index: gcc/testsuite/gcc.dg/c11-atomic-3.c
===================================================================
--- gcc/testsuite/gcc.dg/c11-atomic-3.c	(revision 0)
+++ gcc/testsuite/gcc.dg/c11-atomic-3.c	(revision 0)
@@ -0,0 +1,174 @@
+/* Test for _Atomic in C11.  Test of invalid code.  */
+/* { dg-do compile } */
+/* { dg-options "-std=c11 -pedantic-errors" } */
+
+/* Increment and decrement are invalid for atomic complex types and
+   atomic pointers to incomplete types, just as for the corresponding
+   non-atomic types.  Likewise for types on which arithmetic is
+   invalid.  */
+_Atomic _Complex float acf;
+void *_Atomic apv;
+struct s *_Atomic aps;
+_Atomic struct t { char c; } as;
+
+void
+func (void)
+{
+  acf++; /* { dg-error "complex types" } */
+  acf--; /* { dg-error "complex types" } */
+  ++acf; /* { dg-error "complex types" } */
+  --acf; /* { dg-error "complex types" } */
+  apv++; /* { dg-error "wrong type|pointer of type" } */
+  apv--; /* { dg-error "wrong type|pointer of type" } */
+  ++apv; /* { dg-error "wrong type|pointer of type" } */
+  --apv; /* { dg-error "wrong type|pointer of type" } */
+  aps++; /* { dg-error "pointer to|invalid use of undefined type" } */
+  aps--; /* { dg-error "pointer to|invalid use of undefined type" } */
+  ++aps; /* { dg-error "pointer to|invalid use of undefined type" } */
+  --aps; /* { dg-error "pointer to|invalid use of undefined type" } */
+  as++; /* { dg-error "wrong type" } */
+  as--; /* { dg-error "wrong type" } */
+  ++as; /* { dg-error "wrong type" } */
+  --as; /* { dg-error "wrong type" } */
+}
+
+/* Pointer subtraction and comparisons differing in _Atomic are
+   invalid where such subtraction and comparisons differing in
+   qualifiers are valid.  There is no special allowance for equality
+   comparisons of pointers to atomic void to pointers to object
+   types.  Likewise for conditional expressions.  */
+int *pi;
+_Atomic int *pai;
+_Atomic void *pav;
+int r;
+
+void
+func2 (void)
+{
+  r = pai - pi; /* { dg-error "invalid operands" } */
+  r = pi - pai; /* { dg-error "invalid operands" } */
+  r = pi < pai; /* { dg-error "distinct pointer types" } */
+  r = pi > pai; /* { dg-error "distinct pointer types" } */
+  r = pi <= pai; /* { dg-error "distinct pointer types" } */
+  r = pi >= pai; /* { dg-error "distinct pointer types" } */
+  r = pai < pi; /* { dg-error "distinct pointer types" } */
+  r = pai > pi; /* { dg-error "distinct pointer types" } */
+  r = pai <= pi; /* { dg-error "distinct pointer types" } */
+  r = pai >= pi; /* { dg-error "distinct pointer types" } */
+  r = pav == pi; /* { dg-error "distinct pointer types" } */
+  r = pav != pi; /* { dg-error "distinct pointer types" } */
+  r = pi == pav; /* { dg-error "distinct pointer types" } */
+  r = pi != pav; /* { dg-error "distinct pointer types" } */
+  (void) (r ? pai : pi); /* { dg-error "pointer type mismatch" } */
+  (void) (r ? pi : pai); /* { dg-error "pointer type mismatch" } */
+  (void) (r ? pai : pav); /* { dg-error "pointer type mismatch" } */
+  (void) (r ? pav : pai); /* { dg-error "pointer type mismatch" } */
+}
+
+/* Likewise for pointer assignment.  */
+void
+func3 (void)
+{
+  pai = pi; /* { dg-error "incompatible pointer type" } */
+  pi = pai; /* { dg-error "incompatible pointer type" } */
+  pav = pai; /* { dg-error "incompatible pointer type" } */
+  pai = pav; /* { dg-error "incompatible pointer type" } */
+}
+
+/* Cases that are invalid for normal assignments are just as invalid
+   (and should not ICE) when the LHS is atomic.  */
+void
+func4 (void)
+{
+  as = acf; /* { dg-error "incompatible types" } */
+  apv = as; /* { dg-error "incompatible types" } */
+  as += 1; /* { dg-error "invalid operands" } */
+  apv -= 1; /* { dg-error "pointer of type" } */
+  apv *= 1; /* { dg-error "invalid operands" } */
+  apv /= 1; /* { dg-error "invalid operands" } */
+  apv %= 1; /* { dg-error "invalid operands" } */
+  apv <<= 1; /* { dg-error "invalid operands" } */
+  apv >>= 1; /* { dg-error "invalid operands" } */
+  apv &= 1; /* { dg-error "invalid operands" } */
+  apv ^= 1; /* { dg-error "invalid operands" } */
+  apv |= 1; /* { dg-error "invalid operands" } */
+}
+
+/* We don't allow atomic bit-fields in GCC (implementation-defined
+   whether they are permitted).  */
+struct abf
+{
+  _Atomic int i : 1; /* { dg-error "atomic type" } */
+  _Atomic int : 0; /* { dg-error "atomic type" } */
+};
+
+/* _Atomic (type-name) may not use a name for an array, function,
+   qualified or atomic type.  */
+_Atomic (int [2]) v0; /* { dg-error "array type" } */
+_Atomic (void (void)) v1; /* { dg-error "function type" } */
+_Atomic (_Atomic int) v2; /* { dg-error "applied to a qualified type" } */
+_Atomic (const int) v3; /* { dg-error "applied to a qualified type" } */
+_Atomic (volatile int) v4; /* { dg-error "applied to a qualified type" } */
+_Atomic (int *restrict) v5; /* { dg-error "applied to a qualified type" } */
+
+/* _Atomic, used as a qualifier, may not be applied to a function or
+   array type.  */
+typedef int arraytype[2];
+typedef void functiontype (void);
+_Atomic arraytype v6; /* { dg-error "array type" } */
+_Atomic arraytype *v7; /* { dg-error "array type" } */
+typedef _Atomic arraytype v8; /* { dg-error "array type" } */
+int v9 = sizeof (_Atomic arraytype); /* { dg-error "array type" } */
+void v10 (_Atomic arraytype parm); /* { dg-error "array type" } */
+struct v11 { _Atomic arraytype f; }; /* { dg-error "array type" } */
+_Atomic functiontype v12; /* { dg-error "function type" } */
+_Atomic functiontype *v13; /* { dg-error "function type" } */
+typedef _Atomic functiontype *v14; /* { dg-error "function type" } */
+void v15 (_Atomic functiontype parm); /* { dg-error "function type" } */
+
+/* Function parameters, when function types are required to be
+   compatible, may not differ in the presence of _Atomic.  See
+   c11-atomic-1.c for corresponding tests where _Atomic matches.  */
+void fc0 (int _Atomic); /* { dg-message "previous declaration" } */
+void fc0 (int); /* { dg-error "conflicting types" } */
+void fc1 (int); /* { dg-message "prototype declaration" } */
+void
+fc1 (x)
+     _Atomic int x; /* { dg-error "match prototype" } */
+{
+}
+void
+fc2 (x) /* { dg-message "previous definition" } */
+     _Atomic int x;
+{
+}
+void fc2 (int); /* { dg-error "incompatible type" } */
+void fc3 (int); /* { dg-message "prototype declaration" } */
+void
+fc3 (x)
+     _Atomic short x; /* { dg-error "match prototype" } */
+{
+}
+void
+fc4 (x) /* { dg-message "previous definition" } */
+     _Atomic short x;
+{
+}
+void fc4 (int); /* { dg-error "incompatible type" } */
+
+/* Arrays of atomic elements cannot be initialized with string
+   literals.  */
+_Atomic char si0[] = ""; /* { dg-error "inappropriate type" } */
+_Atomic char si1[] = u8""; /* { dg-error "inappropriate type" } */
+_Atomic signed char si2[] = ""; /* { dg-error "inappropriate type" } */
+_Atomic signed char si3[] = u8""; /* { dg-error "inappropriate type" } */
+_Atomic unsigned char si4[] = ""; /* { dg-error "inappropriate type" } */
+_Atomic unsigned char si5[] = u8""; /* { dg-error "inappropriate type" } */
+_Atomic __WCHAR_TYPE__ si6[] = L""; /* { dg-error "inappropriate type" } */
+_Atomic __CHAR16_TYPE__ si7[] = u""; /* { dg-error "inappropriate type" } */
+_Atomic __CHAR32_TYPE__ si8[] = U""; /* { dg-error "inappropriate type" } */
+
+/* Anything that is syntactically a qualifier applied to the (void)
+   parameter list results in undefined behavior, which we
+   diagnose.  */
+void fv (_Atomic void); /* { dg-error "may not be qualified" } */
Index: gcc/testsuite/gcc.dg/c90-atomic-1.c
===================================================================
--- gcc/testsuite/gcc.dg/c90-atomic-1.c	(revision 0)
+++ gcc/testsuite/gcc.dg/c90-atomic-1.c	(revision 0)
@@ -0,0 +1,7 @@
+/* Test for _Atomic: not in C90.  */
+/* { dg-do compile } */
+/* { dg-options "-std=c90 -pedantic-errors" } */
+
+_Atomic int i; /* { dg-error "_Atomic" } */
+_Atomic (int) j; /* { dg-error "_Atomic" } */
+int *_Atomic p; /* { dg-error "_Atomic" } */
Index: gcc/testsuite/gcc.dg/c11-atomic-1.c
===================================================================
--- gcc/testsuite/gcc.dg/c11-atomic-1.c	(revision 0)
+++ gcc/testsuite/gcc.dg/c11-atomic-1.c	(revision 0)
@@ -0,0 +1,267 @@
+/* Test for _Atomic in C11.  Test of valid code.  See c11-atomic-2.c
+   for more exhaustive tests of assignment cases.  */
+/* { dg-do compile } */
+/* { dg-options "-std=c11 -pedantic-errors" } */
+
+/* The use of _Atomic as a qualifier, and of _Atomic (type-name), give
+   the same type.  */
+extern _Atomic int a;
+extern _Atomic (int) a;
+extern int *_Atomic b;
+extern _Atomic (int *) b;
+extern void f (int [_Atomic]);
+extern void f (int *_Atomic);
+
+/* _Atomic may be applied to arbitrary types, with or without other
+   qualifiers, and assignments may be made as with non-atomic
+   types.  Structure and union elements may be atomic.  */
+_Atomic int ai1, ai2;
+int i1;
+volatile _Atomic long double ald1;
+const _Atomic long double ald2;
+long double ld1;
+_Atomic _Complex double acd1, acd2;
+_Complex double d1;
+_Atomic volatile _Bool ab1;
+int *p;
+int *_Atomic restrict ap;
+struct s { char c[1000]; };
+_Atomic struct s as1;
+struct s s1;
+struct t { _Atomic int i; };
+_Atomic struct t at1;
+_Atomic struct t *atp1;
+struct t t1;
+union u { char c[1000]; };
+_Atomic union u au1;
+union u u1;
+union v { _Atomic int i; };
+_Atomic union v av1;
+union v v1;
+
+void
+func (_Atomic volatile long al1)
+{
+  ai1 = ai2;
+  ai1 = i1;
+  i1 = ai2;
+  ai1 = ald2;
+  ald1 = d1;
+  ld1 = acd2;
+  acd1 += ab1;
+  acd2 /= ai1;
+  p = ap;
+  ap = p;
+  ab1 = p;
+  as1 = s1;
+  s1 = as1;
+  at1 = t1;
+  t1 = at1;
+  /* It's unclear whether the undefined behavior (6.5.2.3#5) for
+     accessing elements of atomic structures and unions is at
+     translation or execution time; presume here that it's at
+     execution time.  */
+  t1.i = at1.i;
+  at1.i = t1.i;
+  atp1->i = t1.i;
+  au1 = u1;
+  u1 = au1;
+  av1 = v1;
+  v1 = av1;
+  v1.i = av1.i;
+  av1.i = v1.i;
+  /* _Atomic is valid on register variables, even if not particularly
+     useful.  */
+  register _Atomic volatile int ra1 = 1, ra2 = 2;
+  ra1 = ra2;
+  ra2 = ra1;
+  /* And on parameters.  */
+  al1 = ra1;
+  ra2 = al1;
+}
+
+/* A function may return an atomic type.  */
+_Atomic int
+func2 (int i)
+{
+  return i;
+}
+
+/* Casts may specify atomic type.  */
+int
+func3 (int i)
+{
+  return func2 ((_Atomic long) i);
+}
+
+/* The _Atomic void type is valid.  */
+_Atomic void *avp;
+
+/* An array of atomic elements is valid (the elements being atomic,
+   not the array).  */
+_Atomic int aa[10];
+int
+func4 (void)
+{
+  return aa[2];
+}
+
+/* Increment and decrement are valid for atomic types when they are
+   valid for non-atomic types.  */
+void
+func5 (void)
+{
+  ald1++;
+  ald1--;
+  ++ald1;
+  --ald1;
+  ai1++;
+  ai1--;
+  ++ai1;
+  --ai1;
+  ab1++;
+  ab1--;
+  ++ab1;
+  --ab1;
+  ap++;
+  ap--;
+  ++ap;
+  --ap;
+}
+
+/* Compound literals may have atomic type.  */
+_Atomic int *aiclp = &(_Atomic int) { 1 };
+
+/* Test unary & and *.  */
+void
+func6 (void)
+{
+  int i = *aiclp;
+  _Atomic int *p = &ai2;
+}
+
+/* Casts to atomic type are valid (although the _Atomic has little
+   effect because the result is an rvalue).  */
+int i2 = (_Atomic int) 1.0;
+
+/* For pointer subtraction and comparisons, _Atomic does not count as
+   a qualifier.  Likewise for conditional expressions.  */
+_Atomic int *xaip1;
+volatile _Atomic int *xaip2;
+void *xvp1;
+
+void
+func7 (void)
+{
+  int r;
+  r = xaip1 - xaip2;
+  r = xaip1 < xaip2;
+  r = xaip1 > xaip2;
+  r = xaip1 <= xaip2;
+  r = xaip1 >= xaip2;
+  r = xaip1 == xaip2;
+  r = xaip1 != xaip2;
+  r = xaip1 == xvp1;
+  r = xaip1 != xvp1;
+  r = xvp1 == xaip1;
+  r = xvp1 != xaip1;
+  r = xaip1 == 0;
+  r = ((void *) 0) == xaip2;
+  (void) (r ? xaip1 : xaip2);
+  (void) (r ? xvp1 : xaip2);
+  (void) (r ? xaip2 : xvp1);
+  (void) (r ? xaip1 : 0);
+  (void) (r ? 0 : xaip1);
+  /* The result of a conditional expression between a pointer to
+     qualified or unqualified (but not atomic) void, and a pointer to
+     an atomic type, is a pointer to appropriately qualified, not
+     atomic, void.  As such, it is valid to use further in conditional
+     expressions with other pointer types.  */
+  (void) (r ? xaip1 : (r ? xaip1 : xvp1));
+}
+
+/* Pointer += and -= integer is valid.  */
+void
+func8 (void)
+{
+  b += 1;
+  b -= 2ULL;
+  ap += 3;
+}
+
+/* Various other cases of simple assignment are valid (some already
+   tested above).  */
+void
+func9 (void)
+{
+  ap = 0;
+  ap = (void *) 0;
+  xvp1 = atp1;
+  atp1 = xvp1;
+}
+
+/* Test compatibility of function types in cases where _Atomic matches
+   (see c11-atomic-3.c for corresponding cases where it doesn't
+   match).  */
+void fc0a (int const);
+void fc0a (int);
+void fc0b (int _Atomic);
+void fc0b (int _Atomic);
+void fc1a (int);
+void
+fc1a (x)
+     volatile int x;
+{
+}
+void fc1b (_Atomic int);
+void
+fc1b (x)
+     volatile _Atomic int x;
+{
+}
+void
+fc2a (x)
+     const int x;
+{
+}
+void fc2a (int); /* { dg-warning "follows non-prototype" } */
+void
+fc2b (x)
+     _Atomic int x;
+{
+}
+void fc2b (_Atomic int); /* { dg-warning "follows non-prototype" } */
+void fc3a (int);
+void
+fc3a (x)
+     volatile short x;
+{
+}
+void fc3b (_Atomic int);
+void
+fc3b (x)
+     _Atomic short x;
+{
+}
+void
+fc4a (x)
+     const short x;
+{
+}
+void fc4a (int); /* { dg-warning "follows non-prototype" } */
+void
+fc4b (x)
+     _Atomic short x;
+{
+}
+void fc4b (_Atomic int); /* { dg-warning "follows non-prototype" } */
+
+/* Test cases involving C_MAYBE_CONST_EXPR work.  */
+void
+func10 (_Atomic int *p)
+{
+  p[0 / 0] = 1; /* { dg-warning "division by zero" } */
+  p[0 / 0] += 1; /* { dg-warning "division by zero" } */
+  *p = 0 / 0; /* { dg-warning "division by zero" } */
+  *p += 0 / 0; /* { dg-warning "division by zero" } */
+}
Index: gcc/testsuite/gcc.dg/atomic/atomic.exp
===================================================================
--- gcc/testsuite/gcc.dg/atomic/atomic.exp	(revision 0)
+++ gcc/testsuite/gcc.dg/atomic/atomic.exp	(revision 0)
@@ -0,0 +1,34 @@
+# Copyright (C) 2012-2013 Free Software Foundation, Inc.
+#
+# This file is part of GCC.
+#
+# GCC is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GCC is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+# GCC testsuite that uses the `dg.exp' driver.
+
+# Load support procs.
+load_lib gcc-dg.exp
+load_lib atomic-dg.exp
+
+# Initialize `dg'.
+dg-init
+if [atomic_init] {
+    # Main loop.
+    gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.c]] ""
+}
+
+# All done.
+atomic_finish
+dg-finish
Index: gcc/testsuite/gcc.dg/atomic/c11-atomic-exec-1.c
===================================================================
--- gcc/testsuite/gcc.dg/atomic/c11-atomic-exec-1.c	(revision 0)
+++ gcc/testsuite/gcc.dg/atomic/c11-atomic-exec-1.c	(revision 0)
@@ -0,0 +1,88 @@
+/* Test for _Atomic in C11.  Basic execution tests for atomic loads
+   and stores.  */
+/* { dg-do run } */
+/* { dg-options "-std=c11 -pedantic-errors" } */
+
+extern void abort (void);
+extern void exit (int);
+extern int memcmp (const void *, const void *, __SIZE_TYPE__);
+
+#define CMPLX(X, Y) __builtin_complex ((X), (Y))
+
+#define TEST_SIMPLE_ASSIGN(TYPE, VALUE)				\
+  do								\
+    {								\
+      static volatile _Atomic (TYPE) a, b = (TYPE) (VALUE);	\
+      if (a != 0)						\
+	abort ();						\
+      if (b != ((TYPE) (VALUE)))				\
+	abort ();						\
+      if ((a = b) != ((TYPE) (VALUE)))				\
+	abort ();						\
+      if (a != ((TYPE) (VALUE)))				\
+	abort ();						\
+    }								\
+  while (0)
+
+#define TEST_SIMPLE_ASSIGN_ARITH(VALUE)				\
+  do								\
+    {								\
+      TEST_SIMPLE_ASSIGN (_Bool, (VALUE));			\
+      TEST_SIMPLE_ASSIGN (char, (VALUE));			\
+      TEST_SIMPLE_ASSIGN (signed char, (VALUE));		\
+      TEST_SIMPLE_ASSIGN (unsigned char, (VALUE));		\
+      TEST_SIMPLE_ASSIGN (signed short, (VALUE));		\
+      TEST_SIMPLE_ASSIGN (unsigned short, (VALUE));		\
+      TEST_SIMPLE_ASSIGN (signed int, (VALUE));			\
+      TEST_SIMPLE_ASSIGN (unsigned int, (VALUE));		\
+      TEST_SIMPLE_ASSIGN (signed long, (VALUE));		\
+      TEST_SIMPLE_ASSIGN (unsigned long, (VALUE));		\
+      TEST_SIMPLE_ASSIGN (signed long long, (VALUE));		\
+      TEST_SIMPLE_ASSIGN (unsigned long long, (VALUE));		\
+      TEST_SIMPLE_ASSIGN (float, (VALUE));			\
+      TEST_SIMPLE_ASSIGN (double, (VALUE));			\
+      TEST_SIMPLE_ASSIGN (long double, (VALUE));		\
+      TEST_SIMPLE_ASSIGN (_Complex float, (VALUE));		\
+      TEST_SIMPLE_ASSIGN (_Complex double, (VALUE));		\
+      TEST_SIMPLE_ASSIGN (_Complex long double, (VALUE));	\
+    }								\
+  while (0)
+
+static void
+test_simple_assign (void)
+{
+  TEST_SIMPLE_ASSIGN_ARITH (0);
+  TEST_SIMPLE_ASSIGN_ARITH (1);
+  TEST_SIMPLE_ASSIGN_ARITH (2);
+  TEST_SIMPLE_ASSIGN_ARITH (-1);
+  TEST_SIMPLE_ASSIGN_ARITH (1ULL << 63);
+  TEST_SIMPLE_ASSIGN_ARITH (1.5);
+  TEST_SIMPLE_ASSIGN_ARITH (CMPLX (2.5, 3.5));
+  static int i;
+  TEST_SIMPLE_ASSIGN (int *, 0);
+  TEST_SIMPLE_ASSIGN (int *, &i);
+  struct s { short a[1024]; };
+  struct s init, copy;
+  _Atomic struct s s1, s2;
+  for (int j = 0; j < 1024; j++)
+    init.a[j] = j;
+  copy = (s1 = init);
+  if (memcmp (&init, &copy, sizeof init) != 0)
+    abort ();
+  copy = (s2 = s1);
+  if (memcmp (&init, &copy, sizeof init) != 0)
+    abort ();
+  copy = s1;
+  if (memcmp (&init, &copy, sizeof init) != 0)
+    abort ();
+  copy = s2;
+  if (memcmp (&init, &copy, sizeof init) != 0)
+    abort ();
+}
+
+int
+main (void)
+{
+  test_simple_assign ();
+  exit (0);
+}
Index: gcc/testsuite/gcc.dg/atomic/c11-atomic-exec-2.c
===================================================================
--- gcc/testsuite/gcc.dg/atomic/c11-atomic-exec-2.c	(revision 0)
+++ gcc/testsuite/gcc.dg/atomic/c11-atomic-exec-2.c	(revision 0)
@@ -0,0 +1,171 @@
+/* Test for _Atomic in C11.  Basic execution tests for atomic compound
+   assignment.  */
+/* { dg-do run } */
+/* { dg-options "-std=c11 -pedantic-errors" } */
+
+extern void abort (void);
+extern void exit (int);
+
+#define CMPLX(X, Y) __builtin_complex ((X), (Y))
+
+#define TEST_COMPOUND(TYPE, LHSVAL, RHSVAL, OP)				\
+  do									\
+    {									\
+      static volatile _Atomic (TYPE) a = (TYPE) (LHSVAL);		\
+      if ((a OP##= (RHSVAL)) != (TYPE) ((TYPE) (LHSVAL) OP (RHSVAL)))	\
+	abort ();							\
+      if (a != (TYPE) ((TYPE) (LHSVAL) OP (RHSVAL)))			\
+	abort ();							\
+    }									\
+  while (0)
+
+#define TEST_COMPOUND_ARITH(LHSVAL, RHSVAL, OP)				\
+  do									\
+    {									\
+      TEST_COMPOUND (_Bool, (LHSVAL), (RHSVAL), OP);			\
+      TEST_COMPOUND (char, (LHSVAL), (RHSVAL), OP);			\
+      TEST_COMPOUND (signed char, (LHSVAL), (RHSVAL), OP);		\
+      TEST_COMPOUND (unsigned char, (LHSVAL), (RHSVAL), OP);		\
+      TEST_COMPOUND (signed short, (LHSVAL), (RHSVAL), OP);		\
+      TEST_COMPOUND (unsigned short, (LHSVAL), (RHSVAL), OP);		\
+      TEST_COMPOUND (signed int, (LHSVAL), (RHSVAL), OP);		\
+      TEST_COMPOUND (unsigned int, (LHSVAL), (RHSVAL), OP);		\
+      TEST_COMPOUND (signed long, (LHSVAL), (RHSVAL), OP);		\
+      TEST_COMPOUND (unsigned long, (LHSVAL), (RHSVAL), OP);		\
+      TEST_COMPOUND (signed long long, (LHSVAL), (RHSVAL), OP);		\
+      TEST_COMPOUND (unsigned long long, (LHSVAL), (RHSVAL), OP);	\
+      TEST_COMPOUND (float, (LHSVAL), (RHSVAL), OP);			\
+      TEST_COMPOUND (double, (LHSVAL), (RHSVAL), OP);			\
+      TEST_COMPOUND (long double, (LHSVAL), (RHSVAL), OP);		\
+      TEST_COMPOUND (_Complex float, (LHSVAL), (RHSVAL), OP);		\
+      TEST_COMPOUND (_Complex double, (LHSVAL), (RHSVAL), OP);		\
+      TEST_COMPOUND (_Complex long double, (LHSVAL), (RHSVAL), OP);	\
+    }									\
+  while (0)
+
+#define TEST_COMPOUND_INT(LHSVAL, RHSVAL, OP)				\
+  do									\
+    {									\
+      TEST_COMPOUND (_Bool, (LHSVAL), (RHSVAL), OP);			\
+      TEST_COMPOUND (char, (LHSVAL), (RHSVAL), OP);			\
+      TEST_COMPOUND (signed char, (LHSVAL), (RHSVAL), OP);		\
+      TEST_COMPOUND (unsigned char, (LHSVAL), (RHSVAL), OP);		\
+      TEST_COMPOUND (signed short, (LHSVAL), (RHSVAL), OP);		\
+      TEST_COMPOUND (unsigned short, (LHSVAL), (RHSVAL), OP);		\
+      TEST_COMPOUND (signed int, (LHSVAL), (RHSVAL), OP);		\
+      TEST_COMPOUND (unsigned int, (LHSVAL), (RHSVAL), OP);		\
+      TEST_COMPOUND (signed long, (LHSVAL), (RHSVAL), OP);		\
+      TEST_COMPOUND (unsigned long, (LHSVAL), (RHSVAL), OP);		\
+      TEST_COMPOUND (signed long long, (LHSVAL), (RHSVAL), OP);		\
+      TEST_COMPOUND (unsigned long long, (LHSVAL), (RHSVAL), OP);	\
+    }									\
+  while (0)
+
+static void
+test_mult (void)
+{
+  TEST_COMPOUND_ARITH (1, 2, *);
+  TEST_COMPOUND_ARITH (-3, 5, *);
+  TEST_COMPOUND_ARITH (-7, -20, *);
+  TEST_COMPOUND_ARITH (1.25, 3.5, *);
+  TEST_COMPOUND_ARITH (CMPLX (1.5, 2.5), CMPLX (3.5, 4.5), *);
+  TEST_COMPOUND_ARITH (CMPLX (1.5, 2.5), 2, *);
+}
+
+static void
+test_div (void)
+{
+  TEST_COMPOUND_ARITH (1, 2, /);
+  TEST_COMPOUND_ARITH (-6, 3, /);
+  TEST_COMPOUND_ARITH (-70, -10, /);
+  TEST_COMPOUND_ARITH (1.25, 2.5, /);
+  TEST_COMPOUND_ARITH (CMPLX (1.0, 1.0), CMPLX (0.5, 0.5), /);
+  TEST_COMPOUND_ARITH (CMPLX (1.5, 2.5), 2, /);
+}
+
+static void
+test_mod (void)
+{
+  TEST_COMPOUND_INT (1, 2, %);
+  TEST_COMPOUND_INT (-3, 5, %);
+  TEST_COMPOUND_INT (-7, -2, %);
+}
+
+static void
+test_plus (void)
+{
+  TEST_COMPOUND_ARITH (1, 2, +);
+  TEST_COMPOUND_ARITH (-3, 5, +);
+  TEST_COMPOUND_ARITH (-7, -20, +);
+  TEST_COMPOUND_ARITH (1.25, 3.5, +);
+  TEST_COMPOUND_ARITH (CMPLX (1.5, 2.5), CMPLX (3.5, 4.5), +);
+  TEST_COMPOUND_ARITH (CMPLX (1.5, 2.5), 2, +);
+  static int ia[2];
+  TEST_COMPOUND (int *, &ia[1], 1, +);
+  TEST_COMPOUND (int *, &ia[1], -1, +);
+}
+
+static void
+test_minus (void)
+{
+  TEST_COMPOUND_ARITH (1, 2, -);
+  TEST_COMPOUND_ARITH (-3, 5, -);
+  TEST_COMPOUND_ARITH (-7, -20, -);
+  TEST_COMPOUND_ARITH (3.5, 1.25, -);
+  TEST_COMPOUND_ARITH (CMPLX (3.5, 4.5), CMPLX (1.5, 2.5), -);
+  TEST_COMPOUND_ARITH (CMPLX (3.5, 2.5), 2, -);
+  static int ia[2];
+  TEST_COMPOUND (int *, &ia[1], 1, -);
+  TEST_COMPOUND (int *, &ia[1], -1, -);
+}
+
+static void
+test_lshift (void)
+{
+  TEST_COMPOUND_INT (1, 7, <<);
+  TEST_COMPOUND_INT (15, 3, <<);
+}
+
+static void
+test_rshift (void)
+{
+  TEST_COMPOUND_INT (1, 1, >>);
+  TEST_COMPOUND_INT (127, 4, >>);
+}
+
+static void
+test_and (void)
+{
+  TEST_COMPOUND_INT (0x1234, 0x7856, &);
+  TEST_COMPOUND_INT (-1, 0x12345678, &);
+}
+
+static void
+test_xor (void)
+{
+  TEST_COMPOUND_INT (0x1234, 0x7856, ^);
+  TEST_COMPOUND_INT (-1, 0x12345678, ^);
+}
+
+static void
+test_or (void)
+{
+  TEST_COMPOUND_INT (0x1234, 0x7856, |);
+  TEST_COMPOUND_INT (-12345, 0x12345678, |);
+}
+
+int
+main (void)
+{
+  test_mult ();
+  test_div ();
+  test_mod ();
+  test_plus ();
+  test_minus ();
+  test_lshift ();
+  test_rshift ();
+  test_and ();
+  test_xor ();
+  test_or ();
+  exit (0);
+}
Index: gcc/testsuite/gcc.dg/atomic/c11-atomic-exec-3.c
===================================================================
--- gcc/testsuite/gcc.dg/atomic/c11-atomic-exec-3.c	(revision 0)
+++ gcc/testsuite/gcc.dg/atomic/c11-atomic-exec-3.c	(revision 0)
@@ -0,0 +1,85 @@
+/* Test for _Atomic in C11.  Basic execution tests for atomic
+   increment and decrement.  */
+/* { dg-do run } */
+/* { dg-options "-std=c11 -pedantic-errors" } */
+
+extern void abort (void);
+extern void exit (int);
+
+#define TEST_INCDEC(TYPE, VALUE, PREOP, POSTOP, PRE_P, CHANGE)		\
+  do									\
+    {									\
+      static volatile _Atomic (TYPE) a = (TYPE) (VALUE);		\
+      if (PREOP a POSTOP != (PRE_P					\
+			     ? (TYPE) ((TYPE) (VALUE) + (CHANGE))	\
+			     : (TYPE) (VALUE)))				\
+	abort ();							\
+      if (a != (TYPE) ((TYPE) (VALUE) + (CHANGE)))			\
+	abort ();							\
+    }									\
+  while (0)
+
+#define TEST_INCDEC_ARITH(VALUE, PREOP, POSTOP, PRE_P, CHANGE)		\
+  do									\
+    {									\
+      TEST_INCDEC (_Bool, (VALUE), PREOP, POSTOP, (PRE_P), (CHANGE));	\
+      TEST_INCDEC (char, (VALUE), PREOP, POSTOP, (PRE_P), (CHANGE));	\
+      TEST_INCDEC (signed char, (VALUE), PREOP, POSTOP, (PRE_P),	\
+		   (CHANGE));						\
+      TEST_INCDEC (unsigned char, (VALUE), PREOP, POSTOP, (PRE_P),	\
+		   (CHANGE));						\
+      TEST_INCDEC (signed short, (VALUE), PREOP, POSTOP, (PRE_P),	\
+		   (CHANGE));						\
+      TEST_INCDEC (unsigned short, (VALUE), PREOP, POSTOP, (PRE_P),	\
+		   (CHANGE));						\
+      TEST_INCDEC (signed int, (VALUE), PREOP, POSTOP, (PRE_P),		\
+		   (CHANGE));						\
+      TEST_INCDEC (unsigned int, (VALUE), PREOP, POSTOP, (PRE_P),	\
+		   (CHANGE));						\
+      TEST_INCDEC (signed long, (VALUE), PREOP, POSTOP, (PRE_P),	\
+		   (CHANGE));						\
+      TEST_INCDEC (unsigned long, (VALUE), PREOP, POSTOP, (PRE_P),	\
+		   (CHANGE));						\
+      TEST_INCDEC (signed long long, (VALUE), PREOP, POSTOP, (PRE_P),	\
+		   (CHANGE));						\
+      TEST_INCDEC (unsigned long long, (VALUE), PREOP, POSTOP, (PRE_P), \
+		   (CHANGE));						\
+      TEST_INCDEC (float, (VALUE), PREOP, POSTOP, (PRE_P), (CHANGE));	\
+      TEST_INCDEC (double, (VALUE), PREOP, POSTOP, (PRE_P), (CHANGE));	\
+      TEST_INCDEC (long double, (VALUE), PREOP, POSTOP, (PRE_P),	\
+		   (CHANGE));						\
+    }									\
+  while (0)
+
+#define TEST_ALL_INCDEC_ARITH(VALUE)		\
+  do						\
+    {						\
+      TEST_INCDEC_ARITH ((VALUE), ++, , 1, 1);	\
+      TEST_INCDEC_ARITH ((VALUE), --, , 1, -1);	\
+      TEST_INCDEC_ARITH ((VALUE), , ++, 0, 1);	\
+      TEST_INCDEC_ARITH ((VALUE), , --, 0, -1);	\
+    }						\
+  while (0)
+
+static void
+test_incdec (void)
+{
+  TEST_ALL_INCDEC_ARITH (0);
+  TEST_ALL_INCDEC_ARITH (1);
+  TEST_ALL_INCDEC_ARITH (2);
+  TEST_ALL_INCDEC_ARITH (-1);
+  TEST_ALL_INCDEC_ARITH (1ULL << 60);
+  TEST_ALL_INCDEC_ARITH (1.5);
+  static int ia[2];
+  TEST_INCDEC (int *, &ia[1], ++, , 1, 1);
+  TEST_INCDEC (int *, &ia[1], --, , 1, -1);
+  TEST_INCDEC (int *, &ia[1], , ++, 0, 1);
+  TEST_INCDEC (int *, &ia[1], , --, 0, -1);
+}
+
+int
+main (void)
+{
+  test_incdec ();
+  exit (0);
+}
Index: gcc/testsuite/gcc.dg/atomic/c11-atomic-exec-4.c
===================================================================
--- gcc/testsuite/gcc.dg/atomic/c11-atomic-exec-4.c	(revision 0)
+++ gcc/testsuite/gcc.dg/atomic/c11-atomic-exec-4.c	(revision 0)
@@ -0,0 +1,208 @@
+/* Test for _Atomic in C11.  Test that compare-and-exchange is
+   operating properly when operations on the same variable are carried
+   out in two threads.  */
+/* { dg-do run } */
+/* { dg-options "-std=c11 -pedantic-errors -pthread -D_POSIX_C_SOURCE=200809L" } */
+/* { dg-require-effective-target pthread } */
+
+#include <stdint.h>
+#include <pthread.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define ITER_COUNT 10000
+
+static volatile _Atomic bool thread_ready;
+
+/* Generate test code (with NAME used to name functions and variables)
+   for atomic compound assignments to a variable of type LHSTYPE.  The
+   variable is initialized to INIT, then PRE var POST is executed
+   ITER_COUNT times in each of two threads, and the final result
+   should be FINAL.  A function test_main_##NAME is generated that
+   returns nonzero on failure, zero on success.  */
+
+#define TEST_FUNCS(NAME, LHSTYPE, PRE, POST, INIT, FINAL)		\
+									\
+static volatile _Atomic LHSTYPE var_##NAME = (INIT);			\
+									\
+static void *								\
+test_thread_##NAME (void *arg)						\
+{									\
+  thread_ready = true;							\
+  for (int i = 0; i < ITER_COUNT; i++)					\
+    PRE var_##NAME POST;						\
+  return NULL;								\
+}									\
+									\
+static int								\
+test_main_##NAME (void)							\
+{									\
+  thread_ready = false;							\
+  pthread_t thread_id;							\
+  int pret = pthread_create (&thread_id, NULL, test_thread_##NAME,	\
+			     NULL);					\
+  if (pret != 0)							\
+    {									\
+      printf ("pthread_create failed: %d\n", pret);			\
+      return 1;								\
+    }									\
+  while (!thread_ready)							\
+    ;									\
+  for (int i = 0; i < ITER_COUNT; i++)					\
+    PRE var_##NAME POST;						\
+  pthread_join (thread_id, NULL);					\
+  if (var_##NAME != (FINAL))						\
+    {									\
+      printf (#NAME " failed\n");					\
+      return 1;								\
+    }									\
+  else									\
+    {									\
+      printf (#NAME " passed\n");					\
+      return 0;								\
+    }									\
+}
+
+TEST_FUNCS (uint8_add, uint8_t, , += 1, 0, (uint8_t) 20000)
+TEST_FUNCS (uint8_add_3, uint8_t, , += 3, 0, (uint8_t) 60000)
+TEST_FUNCS (uint16_add, uint16_t, , += 1, 0, (uint16_t) 20000)
+TEST_FUNCS (uint16_add_3, uint16_t, , += 3, 0, (uint16_t) 60000)
+TEST_FUNCS (uint32_add, uint32_t, , += 1, 0, (uint32_t) 20000)
+TEST_FUNCS (uint32_add_3, uint32_t, , += 3, 0, (uint32_t) 60000)
+TEST_FUNCS (uint64_add, uint64_t, , += 1, 0, (uint64_t) 20000)
+TEST_FUNCS (uint64_add_3, uint64_t, , += 3, 0, (uint64_t) 60000)
+TEST_FUNCS (uint64_add_neg, uint64_t, , += 1, -10000, (uint64_t) 10000)
+TEST_FUNCS (float_add, float, , += 1, 0, 20000)
+TEST_FUNCS (double_add, double, , += 1, 0, 20000)
+TEST_FUNCS (long_double_add, long double, , += 1, 0, 20000)
+TEST_FUNCS (complex_float_add, _Complex float, , += 1, 0, 20000)
+TEST_FUNCS (complex_double_add, _Complex double, , += 1, 0, 20000)
+TEST_FUNCS (complex_long_double_add, _Complex long double, , += 1, 0, 20000)
+TEST_FUNCS (uint8_postinc, uint8_t, , ++, 0, (uint8_t) 20000)
+TEST_FUNCS (uint16_postinc, uint16_t, , ++, 0, (uint16_t) 20000)
+TEST_FUNCS (uint32_postinc, uint32_t, , ++, 0, (uint32_t) 20000)
+TEST_FUNCS (uint64_postinc, uint64_t, , ++, 0, (uint64_t) 20000)
+TEST_FUNCS (uint64_postinc_neg, uint64_t, , ++, -10000, (uint64_t) 10000)
+TEST_FUNCS (float_postinc, float, , ++, 0, 20000)
+TEST_FUNCS (double_postinc, double, , ++, 0, 20000)
+TEST_FUNCS (long_double_postinc, long double, , ++, 0, 20000)
+TEST_FUNCS (uint8_preinc, uint8_t, ++, , 0, (uint8_t) 20000)
+TEST_FUNCS (uint16_preinc, uint16_t, ++, , 0, (uint16_t) 20000)
+TEST_FUNCS (uint32_preinc, uint32_t, ++, , 0, (uint32_t) 20000)
+TEST_FUNCS (uint64_preinc, uint64_t, ++, , 0, (uint64_t) 20000)
+TEST_FUNCS (uint64_preinc_neg, uint64_t, ++, , -10000, (uint64_t) 10000)
+TEST_FUNCS (float_preinc, float, ++, , 0, 20000)
+TEST_FUNCS (double_preinc, double, ++, , 0, 20000)
+TEST_FUNCS (long_double_preinc, long double, ++, , 0, 20000)
+TEST_FUNCS (uint8_sub, uint8_t, , -= 1, 0, (uint8_t) -20000)
+TEST_FUNCS (uint8_sub_3, uint8_t, , -= 3, 0, (uint8_t) -60000)
+TEST_FUNCS (uint16_sub, uint16_t, , -= 1, 0, (uint16_t) -20000)
+TEST_FUNCS (uint16_sub_3, uint16_t, , -= 3, 0, (uint16_t) -60000)
+TEST_FUNCS (uint32_sub, uint32_t, , -= 1, 0, (uint32_t) -20000)
+TEST_FUNCS (uint32_sub_3, uint32_t, , -= 3, 0, (uint32_t) -60000)
+TEST_FUNCS (uint64_sub, uint64_t, , -= 1, 0, (uint64_t) -20000)
+TEST_FUNCS (uint64_sub_3, uint64_t, , -= 3, 0, (uint64_t) -60000)
+TEST_FUNCS (uint64_sub_neg, uint64_t, , -= 1, 10000, (uint64_t) -10000)
+TEST_FUNCS (float_sub, float, , -= 1, 0, -20000)
+TEST_FUNCS (double_sub, double, , -= 1, 0, -20000)
+TEST_FUNCS (long_double_sub, long double, , -= 1, 0, -20000)
+TEST_FUNCS (complex_float_sub, _Complex float, , -= 1, 0, -20000)
+TEST_FUNCS (complex_double_sub, _Complex double, , -= 1, 0, -20000)
+TEST_FUNCS (complex_long_double_sub, _Complex long double, , -= 1, 0, -20000)
+TEST_FUNCS (uint8_postdec, uint8_t, , --, 0, (uint8_t) -20000)
+TEST_FUNCS (uint16_postdec, uint16_t, , --, 0, (uint16_t) -20000)
+TEST_FUNCS (uint32_postdec, uint32_t, , --, 0, (uint32_t) -20000)
+TEST_FUNCS (uint64_postdec, uint64_t, , --, 0, (uint64_t) -20000)
+TEST_FUNCS (uint64_postdec_neg, uint64_t, , --, 10000, (uint64_t) -10000)
+TEST_FUNCS (float_postdec, float, , --, 0, -20000)
+TEST_FUNCS (double_postdec, double, , --, 0, -20000)
+TEST_FUNCS (long_double_postdec, long double, , --, 0, -20000)
+TEST_FUNCS (uint8_predec, uint8_t, --, , 0, (uint8_t) -20000)
+TEST_FUNCS (uint16_predec, uint16_t, --, , 0, (uint16_t) -20000)
+TEST_FUNCS (uint32_predec, uint32_t, --, , 0, (uint32_t) -20000)
+TEST_FUNCS (uint64_predec, uint64_t, --, , 0, (uint64_t) -20000)
+TEST_FUNCS (uint64_predec_neg, uint64_t, --, , 10000, (uint64_t) -10000)
+TEST_FUNCS (float_predec, float, --, , 0, -20000)
+TEST_FUNCS (double_predec, double, --, , 0, -20000)
+TEST_FUNCS (long_double_predec, long double, --, , 0, -20000)
+TEST_FUNCS (uint8_mul, uint8_t, , *= 3, 1, (uint8_t) 0x81)
+TEST_FUNCS (uint16_mul, uint16_t, , *= 3, 1, (uint16_t) 0x9681)
+TEST_FUNCS (uint32_mul, uint32_t, , *= 3, 1, (uint32_t) 0x62b49681U)
+TEST_FUNCS (uint64_mul, uint64_t, , *= 3, 1, (uint64_t) 0xcd926beb62b49681ULL)
+
+int
+main (void)
+{
+  int ret = 0;
+  ret |= test_main_uint8_add ();
+  ret |= test_main_uint8_add_3 ();
+  ret |= test_main_uint16_add ();
+  ret |= test_main_uint16_add_3 ();
+  ret |= test_main_uint32_add ();
+  ret |= test_main_uint32_add_3 ();
+  ret |= test_main_uint64_add ();
+  ret |= test_main_uint64_add_3 ();
+  ret |= test_main_uint64_add_neg ();
+  ret |= test_main_float_add ();
+  ret |= test_main_double_add ();
+  ret |= test_main_long_double_add ();
+  ret |= test_main_complex_float_add ();
+  ret |= test_main_complex_double_add ();
+  ret |= test_main_complex_long_double_add ();
+  ret |= test_main_uint8_postinc ();
+  ret |= test_main_uint16_postinc ();
+  ret |= test_main_uint32_postinc ();
+  ret |= test_main_uint64_postinc ();
+  ret |= test_main_uint64_postinc_neg ();
+  ret |= test_main_float_postinc ();
+  ret |= test_main_double_postinc ();
+  ret |= test_main_long_double_postinc ();
+  ret |= test_main_uint8_preinc ();
+  ret |= test_main_uint16_preinc ();
+  ret |= test_main_uint32_preinc ();
+  ret |= test_main_uint64_preinc ();
+  ret |= test_main_uint64_preinc_neg ();
+  ret |= test_main_float_preinc ();
+  ret |= test_main_double_preinc ();
+  ret |= test_main_long_double_preinc ();
+  ret |= test_main_uint8_sub ();
+  ret |= test_main_uint8_sub_3 ();
+  ret |= test_main_uint16_sub ();
+  ret |= test_main_uint16_sub_3 ();
+  ret |= test_main_uint32_sub ();
+  ret |= test_main_uint32_sub_3 ();
+  ret |= test_main_uint64_sub ();
+  ret |= test_main_uint64_sub_3 ();
+  ret |= test_main_uint64_sub_neg ();
+  ret |= test_main_float_sub ();
+  ret |= test_main_double_sub ();
+  ret |= test_main_long_double_sub ();
+  ret |= test_main_complex_float_sub ();
+  ret |= test_main_complex_double_sub ();
+  ret |= test_main_complex_long_double_sub ();
+  ret |= test_main_uint8_postdec ();
+  ret |= test_main_uint16_postdec ();
+  ret |= test_main_uint32_postdec ();
+  ret |= test_main_uint64_postdec ();
+  ret |= test_main_uint64_postdec_neg ();
+  ret |= test_main_float_postdec ();
+  ret |= test_main_double_postdec ();
+  ret |= test_main_long_double_postdec ();
+  ret |= test_main_uint8_predec ();
+  ret |= test_main_uint16_predec ();
+  ret |= test_main_uint32_predec ();
+  ret |= test_main_uint64_predec ();
+  ret |= test_main_uint64_predec_neg ();
+  ret |= test_main_float_predec ();
+  ret |= test_main_double_predec ();
+  ret |= test_main_long_double_predec ();
+  ret |= test_main_uint8_mul ();
+  ret |= test_main_uint16_mul ();
+  ret |= test_main_uint32_mul ();
+  ret |= test_main_uint64_mul ();
+  if (ret)
+    abort ();
+  else
+    exit (0);
+}
Index: gcc/testsuite/gcc.dg/atomic/c11-atomic-exec-5.c
===================================================================
--- gcc/testsuite/gcc.dg/atomic/c11-atomic-exec-5.c	(revision 0)
+++ gcc/testsuite/gcc.dg/atomic/c11-atomic-exec-5.c	(revision 0)
@@ -0,0 +1,541 @@
+/* Test for _Atomic in C11.  Test floating-point exceptions for
+   compound assignment are consistent with result (so that if multiple
+   iterations of the compare-and-exchange loop are needed, exceptions
+   get properly cleared).  */
+/* { dg-do run } */
+/* { dg-options "-std=c11 -pedantic-errors -pthread -D_POSIX_C_SOURCE=200809L" } */
+/* { dg-require-effective-target fenv_exceptions } */
+/* { dg-require-effective-target pthread } */
+
+#include <fenv.h>
+#include <float.h>
+#include <pthread.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define TEST_ALL_EXCEPT (FE_DIVBYZERO		\
+			 | FE_INEXACT		\
+			 | FE_INVALID		\
+			 | FE_OVERFLOW		\
+			 | FE_UNDERFLOW)
+
+#define ITER_COUNT 10000
+
+static volatile _Atomic bool thread_ready, thread_stop;
+
+/* Generate test code (with NAME used to name functions and variables)
+   for atomic compound assignments to a variable of type LHSTYPE.  One
+   thread repeatedly stores the values INIT1 and INIT2 in a variable,
+   while the other repeatedly executes PRE var POST having set
+   floating-point exceptions to BEXC.  If the value of the assignment
+   operation satisfies VALTEST1 (var), the floating-point exceptions
+   should be BEXC | EXC1; otherwise, they should be BEXC | EXC2.  A
+   function test_main_##NAME is generated that returns nonzero on
+   failure, zero on success.  */
+
+#define TEST_FUNCS(NAME, LHSTYPE, PRE, POST, BEXC,			\
+		   INIT1, VALTEST1, EXC1, INIT2, EXC2)			\
+									\
+static volatile _Atomic LHSTYPE var_##NAME;				\
+									\
+static void *								\
+test_thread_##NAME (void *arg)						\
+{									\
+  thread_ready = true;							\
+  while (!thread_stop)							\
+    {									\
+      var_##NAME = (INIT1);						\
+      var_##NAME = (INIT2);						\
+    }									\
+  return NULL;								\
+}									\
+									\
+static int								\
+test_main_##NAME (void)							\
+{									\
+  thread_stop = false;							\
+  thread_ready = false;							\
+  var_##NAME = (INIT1);							\
+  pthread_t thread_id;							\
+  int pret = pthread_create (&thread_id, NULL, test_thread_##NAME,	\
+			     NULL);					\
+  if (pret != 0)							\
+    {									\
+      printf ("pthread_create failed: %d\n", pret);			\
+      return 1;								\
+    }									\
+  int num_1_pass = 0, num_1_fail = 0, num_2_pass = 0, num_2_fail = 0;	\
+  while (!thread_ready)							\
+    ;									\
+  for (int i = 0; i < ITER_COUNT; i++)					\
+    {									\
+      feclearexcept (FE_ALL_EXCEPT);					\
+      feraiseexcept (BEXC);						\
+      LHSTYPE r = (PRE var_##NAME POST);				\
+      int rexc = fetestexcept (TEST_ALL_EXCEPT);			\
+      if (VALTEST1 (r))							\
+	{								\
+	  if (rexc == ((BEXC) | (EXC1)))				\
+	    num_1_pass++;						\
+	  else								\
+	    num_1_fail++;						\
+	  var_##NAME = (INIT2);						\
+	}								\
+      else								\
+	{								\
+	  if (rexc == ((BEXC) | (EXC2)))				\
+	    num_2_pass++;						\
+	  else								\
+	    num_2_fail++;						\
+	  var_##NAME = (INIT1);						\
+	}								\
+    }									\
+  thread_stop = true;							\
+  pthread_join (thread_id, NULL);					\
+  printf (#NAME " (a) %d pass, %d fail; (b) %d pass, %d fail\n",	\
+	  num_1_pass, num_1_fail, num_2_pass, num_2_fail);		\
+  return num_1_fail || num_2_fail;					\
+}
+
+TEST_FUNCS (float_add_invalid, float, , += __builtin_inff (), 0,
+	    0, __builtin_isinf, 0,
+	    -__builtin_inff (), FE_INVALID)
+TEST_FUNCS (float_add_invalid_prev, float, , += __builtin_inff (),
+	    FE_DIVBYZERO | FE_INEXACT | FE_OVERFLOW | FE_UNDERFLOW,
+	    0, __builtin_isinf, 0,
+	    -__builtin_inff (), FE_INVALID)
+TEST_FUNCS (float_add_overflow, float, , += FLT_MAX, 0,
+	    FLT_MAX, __builtin_isinf, FE_OVERFLOW | FE_INEXACT,
+	    0, 0)
+TEST_FUNCS (float_add_overflow_prev, float, , += FLT_MAX, FE_INVALID,
+	    FLT_MAX, __builtin_isinf, FE_OVERFLOW | FE_INEXACT,
+	    0, 0)
+TEST_FUNCS (float_add_overflow_double, float, , += (double) FLT_MAX, 0,
+	    FLT_MAX, __builtin_isinf, FE_OVERFLOW | FE_INEXACT,
+	    0, 0)
+TEST_FUNCS (float_add_overflow_long_double, float, , += (long double) FLT_MAX, 0,
+	    FLT_MAX, __builtin_isinf, FE_OVERFLOW | FE_INEXACT,
+	    0, 0)
+#define NOT_FLT_EPSILON_2(X) ((X) != FLT_EPSILON / 2)
+TEST_FUNCS (float_add_inexact, float, , += FLT_EPSILON / 2, 0,
+	    1.0f, NOT_FLT_EPSILON_2, FE_INEXACT,
+	    0, 0)
+#define NOT_0(X) ((X) != 0)
+TEST_FUNCS (float_add_inexact_int, float, , += 1, 0,
+	    FLT_EPSILON / 2, NOT_0, FE_INEXACT,
+	    -1, 0)
+TEST_FUNCS (float_preinc_inexact, float, ++, , 0,
+	    FLT_EPSILON / 2, NOT_0, FE_INEXACT,
+	    -1, 0)
+#define NOT_MINUS_1(X) ((X) != -1)
+TEST_FUNCS (float_postinc_inexact, float, , ++, 0,
+	    FLT_EPSILON / 2, NOT_MINUS_1, FE_INEXACT,
+	    -1, 0)
+#if FLT_EVAL_METHOD == 0
+TEST_FUNCS (long_add_float_inexact, long, , += 2 / FLT_EPSILON, 0,
+	    1, NOT_0, FE_INEXACT,
+	    -2 / FLT_EPSILON, 0)
+#endif
+#define REAL_ISINF(X) (__builtin_isinf (__real__ (X)))
+TEST_FUNCS (complex_float_add_overflow, _Complex float, , += FLT_MAX, 0,
+	    FLT_MAX, REAL_ISINF, FE_OVERFLOW | FE_INEXACT,
+	    0, 0)
+TEST_FUNCS (float_sub_invalid, float, , -= __builtin_inff (), 0,
+	    0, __builtin_isinf, 0,
+	    __builtin_inff (), FE_INVALID)
+TEST_FUNCS (float_sub_overflow, float, , -= FLT_MAX, 0,
+	    -FLT_MAX, __builtin_isinf, FE_OVERFLOW | FE_INEXACT,
+	    0, 0)
+#define NOT_MINUS_FLT_EPSILON_2(X) ((X) != -FLT_EPSILON / 2)
+TEST_FUNCS (float_sub_inexact, float, , -= FLT_EPSILON / 2, 0,
+	    -1.0f, NOT_MINUS_FLT_EPSILON_2, FE_INEXACT,
+	    0, 0)
+#define NOT_0(X) ((X) != 0)
+TEST_FUNCS (float_sub_inexact_int, float, , -= 1, 0,
+	    -FLT_EPSILON / 2, NOT_0, FE_INEXACT,
+	    1, 0)
+TEST_FUNCS (float_predec_inexact, float, --, , 0,
+	    -FLT_EPSILON / 2, NOT_0, FE_INEXACT,
+	    1, 0)
+#define NOT_1(X) ((X) != 1)
+TEST_FUNCS (float_postdec_inexact, float, , --, 0,
+	    -FLT_EPSILON / 2, NOT_1, FE_INEXACT,
+	    1, 0)
+#if FLT_EVAL_METHOD == 0
+TEST_FUNCS (long_sub_float_inexact, long, , -= 2 / FLT_EPSILON, 0,
+	    -1, NOT_0, FE_INEXACT,
+	    2 / FLT_EPSILON, 0)
+#endif
+TEST_FUNCS (complex_float_sub_overflow, _Complex float, , -= FLT_MAX, 0,
+	    -FLT_MAX, REAL_ISINF, FE_OVERFLOW | FE_INEXACT,
+	    0, 0)
+TEST_FUNCS (float_mul_invalid, float, , *= __builtin_inff (), 0,
+	    __builtin_inff (), __builtin_isinf, 0,
+	    0, FE_INVALID)
+TEST_FUNCS (float_mul_overflow, float, , *= FLT_MAX, 0,
+	    FLT_MAX, __builtin_isinf, FE_OVERFLOW | FE_INEXACT,
+	    0, 0)
+#define IS_0(X) ((X) == 0)
+TEST_FUNCS (float_mul_underflow, float, , *= FLT_MIN, 0,
+	    FLT_MIN, IS_0, FE_UNDERFLOW | FE_INEXACT,
+	    1, 0)
+TEST_FUNCS (float_mul_inexact, float, , *= 1 + FLT_EPSILON, 0,
+	    1 + FLT_EPSILON, NOT_0, FE_INEXACT,
+	    0, 0)
+TEST_FUNCS (float_mul_inexact_int, float, , *= 3, 0,
+	    1 + FLT_EPSILON, NOT_0, FE_INEXACT,
+	    0, 0)
+#if FLT_EVAL_METHOD == 0
+TEST_FUNCS(long_mul_float_inexact, long, , *= 3.0f, 0,
+	   1 + 1 / FLT_EPSILON, NOT_0, FE_INEXACT,
+	   0, 0)
+#endif
+TEST_FUNCS (complex_float_mul_overflow, _Complex float, , *= FLT_MAX, 0,
+	    FLT_MAX, REAL_ISINF, FE_OVERFLOW | FE_INEXACT,
+	    0, 0)
+TEST_FUNCS (float_div_invalid_divbyzero, float, , /= 0.0f, 0,
+	    1, __builtin_isinf, FE_DIVBYZERO,
+	    0, FE_INVALID)
+TEST_FUNCS (float_div_overflow, float, , /= FLT_MIN, 0,
+	    FLT_MAX, __builtin_isinf, FE_OVERFLOW | FE_INEXACT,
+	    0, 0)
+TEST_FUNCS (float_div_underflow, float, , /= FLT_MAX, 0,
+	    FLT_MIN, IS_0, FE_UNDERFLOW | FE_INEXACT,
+	    FLT_MAX, 0)
+TEST_FUNCS (float_div_inexact, float, , /= 3.0f, 0,
+	    1, NOT_0, FE_INEXACT,
+	    0, 0)
+TEST_FUNCS (float_div_inexact_int, float, , /= 3, 0,
+	    1, NOT_0, FE_INEXACT,
+	    0, 0)
+TEST_FUNCS (int_div_float_inexact, int, , /= 3.0f, 0,
+	    4, NOT_0, FE_INEXACT,
+	    0, 0)
+TEST_FUNCS (complex_float_div_overflow, _Complex float, , /= FLT_MIN, 0,
+	    FLT_MAX, REAL_ISINF, FE_OVERFLOW | FE_INEXACT,
+	    0, 0)
+
+TEST_FUNCS (double_add_invalid, double, , += __builtin_inf (), 0,
+	    0, __builtin_isinf, 0,
+	    -__builtin_inf (), FE_INVALID)
+TEST_FUNCS (double_add_overflow, double, , += DBL_MAX, 0,
+	    DBL_MAX, __builtin_isinf, FE_OVERFLOW | FE_INEXACT,
+	    0, 0)
+TEST_FUNCS (double_add_overflow_long_double, double, , += (long double) DBL_MAX, 0,
+	    DBL_MAX, __builtin_isinf, FE_OVERFLOW | FE_INEXACT,
+	    0, 0)
+#define NOT_DBL_EPSILON_2(X) ((X) != DBL_EPSILON / 2)
+TEST_FUNCS (double_add_inexact, double, , += DBL_EPSILON / 2, 0,
+	    1.0, NOT_DBL_EPSILON_2, FE_INEXACT,
+	    0, 0)
+TEST_FUNCS (double_add_inexact_int, double, , += 1, 0,
+	    DBL_EPSILON / 2, NOT_0, FE_INEXACT,
+	    -1, 0)
+TEST_FUNCS (double_preinc_inexact, double, ++, , 0,
+	    DBL_EPSILON / 2, NOT_0, FE_INEXACT,
+	    -1, 0)
+TEST_FUNCS (double_postinc_inexact, double, , ++, 0,
+	    DBL_EPSILON / 2, NOT_MINUS_1, FE_INEXACT,
+	    -1, 0)
+#if FLT_EVAL_METHOD == 0
+TEST_FUNCS (long_long_add_double_inexact, long long, , += 2 / DBL_EPSILON, 0,
+	    1, NOT_0, FE_INEXACT,
+	    -2 / DBL_EPSILON, 0)
+#endif
+TEST_FUNCS (complex_double_add_overflow, _Complex double, , += DBL_MAX, 0,
+	    DBL_MAX, REAL_ISINF, FE_OVERFLOW | FE_INEXACT,
+	    0, 0)
+TEST_FUNCS (double_sub_invalid, double, , -= __builtin_inf (), 0,
+	    0, __builtin_isinf, 0,
+	    __builtin_inf (), FE_INVALID)
+TEST_FUNCS (double_sub_overflow, double, , -= DBL_MAX, 0,
+	    -DBL_MAX, __builtin_isinf, FE_OVERFLOW | FE_INEXACT,
+	    0, 0)
+#define NOT_MINUS_DBL_EPSILON_2(X) ((X) != -DBL_EPSILON / 2)
+TEST_FUNCS (double_sub_inexact, double, , -= DBL_EPSILON / 2, 0,
+	    -1.0, NOT_MINUS_DBL_EPSILON_2, FE_INEXACT,
+	    0, 0)
+TEST_FUNCS (double_sub_inexact_int, double, , -= 1, 0,
+	    -DBL_EPSILON / 2, NOT_0, FE_INEXACT,
+	    1, 0)
+TEST_FUNCS (double_predec_inexact, double, --, , 0,
+	    -DBL_EPSILON / 2, NOT_0, FE_INEXACT,
+	    1, 0)
+TEST_FUNCS (double_postdec_inexact, double, , --, 0,
+	    -DBL_EPSILON / 2, NOT_1, FE_INEXACT,
+	    1, 0)
+#if FLT_EVAL_METHOD == 0
+TEST_FUNCS (long_long_sub_double_inexact, long long, , -= 2 / DBL_EPSILON, 0,
+	    -1, NOT_0, FE_INEXACT,
+	    2 / DBL_EPSILON, 0)
+#endif
+TEST_FUNCS (complex_double_sub_overflow, _Complex double, , -= DBL_MAX, 0,
+	    -DBL_MAX, REAL_ISINF, FE_OVERFLOW | FE_INEXACT,
+	    0, 0)
+TEST_FUNCS (double_mul_invalid, double, , *= __builtin_inf (), 0,
+	    __builtin_inf (), __builtin_isinf, 0,
+	    0, FE_INVALID)
+TEST_FUNCS (double_mul_overflow, double, , *= DBL_MAX, 0,
+	    DBL_MAX, __builtin_isinf, FE_OVERFLOW | FE_INEXACT,
+	    0, 0)
+TEST_FUNCS (double_mul_overflow_float, double, , *= FLT_MAX, 0,
+	    DBL_MAX, __builtin_isinf, FE_OVERFLOW | FE_INEXACT,
+	    0, 0)
+TEST_FUNCS (double_mul_underflow, double, , *= DBL_MIN, 0,
+	    DBL_MIN, IS_0, FE_UNDERFLOW | FE_INEXACT,
+	    1, 0)
+TEST_FUNCS (double_mul_inexact, double, , *= 1 + DBL_EPSILON, 0,
+	    1 + DBL_EPSILON, NOT_0, FE_INEXACT,
+	    0, 0)
+TEST_FUNCS (double_mul_inexact_int, double, , *= 3, 0,
+	    1 + DBL_EPSILON, NOT_0, FE_INEXACT,
+	    0, 0)
+#if FLT_EVAL_METHOD == 0
+TEST_FUNCS(long_long_mul_double_inexact, long long, , *= 3.0, 0,
+	   1 + 1 / DBL_EPSILON, NOT_0, FE_INEXACT,
+	   0, 0)
+#endif
+TEST_FUNCS (complex_double_mul_overflow, _Complex double, , *= DBL_MAX, 0,
+	    DBL_MAX, REAL_ISINF, FE_OVERFLOW | FE_INEXACT,
+	    0, 0)
+TEST_FUNCS (double_div_invalid_divbyzero, double, , /= 0.0, 0,
+	    1, __builtin_isinf, FE_DIVBYZERO,
+	    0, FE_INVALID)
+TEST_FUNCS (double_div_overflow, double, , /= DBL_MIN, 0,
+	    DBL_MAX, __builtin_isinf, FE_OVERFLOW | FE_INEXACT,
+	    0, 0)
+TEST_FUNCS (double_div_underflow, double, , /= DBL_MAX, 0,
+	    DBL_MIN, IS_0, FE_UNDERFLOW | FE_INEXACT,
+	    DBL_MAX, 0)
+TEST_FUNCS (double_div_inexact, double, , /= 3.0, 0,
+	    1, NOT_0, FE_INEXACT,
+	    0, 0)
+TEST_FUNCS (double_div_inexact_int, double, , /= 3, 0,
+	    1, NOT_0, FE_INEXACT,
+	    0, 0)
+TEST_FUNCS (int_div_double_inexact, int, , /= 3.0, 0,
+	    4, NOT_0, FE_INEXACT,
+	    0, 0)
+TEST_FUNCS (complex_double_div_overflow, _Complex double, , /= DBL_MIN, 0,
+	    DBL_MAX, REAL_ISINF, FE_OVERFLOW | FE_INEXACT,
+	    0, 0)
+
+TEST_FUNCS (long_double_add_invalid, long double, , += __builtin_infl (), 0,
+	    0, __builtin_isinf, 0,
+	    -__builtin_infl (), FE_INVALID)
+TEST_FUNCS (long_double_add_overflow, long double, , += LDBL_MAX, 0,
+	    LDBL_MAX, __builtin_isinf, FE_OVERFLOW | FE_INEXACT,
+	    0, 0)
+#define NOT_LDBL_EPSILON_2(X) ((X) != LDBL_EPSILON / 2)
+#if LDBL_MANT_DIG != 106
+TEST_FUNCS (long_double_add_inexact, long double, , += LDBL_EPSILON / 2, 0,
+	    1.0L, NOT_LDBL_EPSILON_2, FE_INEXACT,
+	    0, 0)
+TEST_FUNCS (long_double_add_inexact_int, long double, , += 1, 0,
+	    LDBL_EPSILON / 2, NOT_0, FE_INEXACT,
+	    -1, 0)
+TEST_FUNCS (long_double_preinc_inexact, long double, ++, , 0,
+	    LDBL_EPSILON / 2, NOT_0, FE_INEXACT,
+	    -1, 0)
+TEST_FUNCS (long_double_postinc_inexact, long double, , ++, 0,
+	    LDBL_EPSILON / 2, NOT_MINUS_1, FE_INEXACT,
+	    -1, 0)
+#endif
+TEST_FUNCS (complex_long_double_add_overflow, _Complex long double, , += LDBL_MAX, 0,
+	    LDBL_MAX, REAL_ISINF, FE_OVERFLOW | FE_INEXACT,
+	    0, 0)
+TEST_FUNCS (long_double_sub_invalid, long double, , -= __builtin_infl (), 0,
+	    0, __builtin_isinf, 0,
+	    __builtin_infl (), FE_INVALID)
+TEST_FUNCS (long_double_sub_overflow, long double, , -= LDBL_MAX, 0,
+	    -LDBL_MAX, __builtin_isinf, FE_OVERFLOW | FE_INEXACT,
+	    0, 0)
+#define NOT_MINUS_LDBL_EPSILON_2(X) ((X) != -LDBL_EPSILON / 2)
+#if LDBL_MANT_DIG != 106
+TEST_FUNCS (long_double_sub_inexact, long double, , -= LDBL_EPSILON / 2, 0,
+	    -1.0L, NOT_MINUS_LDBL_EPSILON_2, FE_INEXACT,
+	    0, 0)
+TEST_FUNCS (long_double_sub_inexact_int, long double, , -= 1, 0,
+	    -LDBL_EPSILON / 2, NOT_0, FE_INEXACT,
+	    1, 0)
+TEST_FUNCS (long_double_predec_inexact, long double, --, , 0,
+	    -LDBL_EPSILON / 2, NOT_0, FE_INEXACT,
+	    1, 0)
+TEST_FUNCS (long_double_postdec_inexact, long double, , --, 0,
+	    -LDBL_EPSILON / 2, NOT_1, FE_INEXACT,
+	    1, 0)
+#endif
+TEST_FUNCS (complex_long_double_sub_overflow, _Complex long double, , -= LDBL_MAX, 0,
+	    -LDBL_MAX, REAL_ISINF, FE_OVERFLOW | FE_INEXACT,
+	    0, 0)
+TEST_FUNCS (long_double_mul_invalid, long double, , *= __builtin_infl (), 0,
+	    __builtin_infl (), __builtin_isinf, 0,
+	    0, FE_INVALID)
+TEST_FUNCS (long_double_mul_overflow, long double, , *= LDBL_MAX, 0,
+	    LDBL_MAX, __builtin_isinf, FE_OVERFLOW | FE_INEXACT,
+	    0, 0)
+TEST_FUNCS (long_double_mul_overflow_float, long double, , *= FLT_MAX, 0,
+	    LDBL_MAX, __builtin_isinf, FE_OVERFLOW | FE_INEXACT,
+	    0, 0)
+TEST_FUNCS (long_double_mul_overflow_double, long double, , *= DBL_MAX, 0,
+	    LDBL_MAX, __builtin_isinf, FE_OVERFLOW | FE_INEXACT,
+	    0, 0)
+TEST_FUNCS (long_double_mul_underflow, long double, , *= LDBL_MIN, 0,
+	    LDBL_MIN, IS_0, FE_UNDERFLOW | FE_INEXACT,
+	    1, 0)
+#if LDBL_MANT_DIG != 106
+TEST_FUNCS (long_double_mul_inexact, long double, , *= 1 + LDBL_EPSILON, 0,
+	    1 + LDBL_EPSILON, NOT_0, FE_INEXACT,
+	    0, 0)
+TEST_FUNCS (long_double_mul_inexact_int, long double, , *= 3, 0,
+	    1 + LDBL_EPSILON, NOT_0, FE_INEXACT,
+	    0, 0)
+#endif
+TEST_FUNCS (complex_long_double_mul_overflow, _Complex long double, , *= LDBL_MAX, 0,
+	    LDBL_MAX, REAL_ISINF, FE_OVERFLOW | FE_INEXACT,
+	    0, 0)
+TEST_FUNCS (long_double_div_invalid_divbyzero, long double, , /= 0.0L, 0,
+	    1, __builtin_isinf, FE_DIVBYZERO,
+	    0, FE_INVALID)
+TEST_FUNCS (long_double_div_overflow, long double, , /= LDBL_MIN, 0,
+	    LDBL_MAX, __builtin_isinf, FE_OVERFLOW | FE_INEXACT,
+	    0, 0)
+TEST_FUNCS (long_double_div_underflow, long double, , /= LDBL_MAX, 0,
+	    LDBL_MIN, IS_0, FE_UNDERFLOW | FE_INEXACT,
+	    LDBL_MAX, 0)
+TEST_FUNCS (long_double_div_inexact, long double, , /= 3.0L, 0,
+	    1, NOT_0, FE_INEXACT,
+	    0, 0)
+TEST_FUNCS (long_double_div_inexact_int, long double, , /= 3, 0,
+	    1, NOT_0, FE_INEXACT,
+	    0, 0)
+TEST_FUNCS (int_div_long_double_inexact, int, , /= 3.0L, 0,
+	    4, NOT_0, FE_INEXACT,
+	    0, 0)
+TEST_FUNCS (complex_long_double_div_overflow, _Complex long double, , /= LDBL_MIN, 0,
+	    LDBL_MAX, REAL_ISINF, FE_OVERFLOW | FE_INEXACT,
+	    0, 0)
+
+int
+main (void)
+{
+  int ret = 0;
+  ret |= test_main_float_add_invalid ();
+  ret |= test_main_float_add_invalid_prev ();
+  ret |= test_main_float_add_overflow ();
+  ret |= test_main_float_add_overflow_prev ();
+  ret |= test_main_float_add_overflow_double ();
+  ret |= test_main_float_add_overflow_long_double ();
+  ret |= test_main_float_add_inexact ();
+  ret |= test_main_float_add_inexact_int ();
+  ret |= test_main_float_preinc_inexact ();
+  ret |= test_main_float_postinc_inexact ();
+#if FLT_EVAL_METHOD == 0
+  ret |= test_main_long_add_float_inexact ();
+#endif
+  ret |= test_main_complex_float_add_overflow ();
+  ret |= test_main_float_sub_invalid ();
+  ret |= test_main_float_sub_overflow ();
+  ret |= test_main_float_sub_inexact ();
+  ret |= test_main_float_sub_inexact_int ();
+  ret |= test_main_float_predec_inexact ();
+  ret |= test_main_float_postdec_inexact ();
+#if FLT_EVAL_METHOD == 0
+  ret |= test_main_long_sub_float_inexact ();
+#endif
+  ret |= test_main_complex_float_sub_overflow ();
+  ret |= test_main_float_mul_invalid ();
+  ret |= test_main_float_mul_overflow ();
+  ret |= test_main_float_mul_underflow ();
+  ret |= test_main_float_mul_inexact ();
+  ret |= test_main_float_mul_inexact_int ();
+#if FLT_EVAL_METHOD == 0
+  ret |= test_main_long_mul_float_inexact ();
+#endif
+  ret |= test_main_complex_float_mul_overflow ();
+  ret |= test_main_float_div_invalid_divbyzero ();
+  ret |= test_main_float_div_overflow ();
+  ret |= test_main_float_div_underflow ();
+  ret |= test_main_float_div_inexact ();
+  ret |= test_main_float_div_inexact_int ();
+  ret |= test_main_int_div_float_inexact ();
+  ret |= test_main_complex_float_div_overflow ();
+  ret |= test_main_double_add_invalid ();
+  ret |= test_main_double_add_overflow ();
+  ret |= test_main_double_add_overflow_long_double ();
+  ret |= test_main_double_add_inexact ();
+  ret |= test_main_double_add_inexact_int ();
+  ret |= test_main_double_preinc_inexact ();
+  ret |= test_main_double_postinc_inexact ();
+#if FLT_EVAL_METHOD == 0
+  ret |= test_main_long_long_add_double_inexact ();
+#endif
+  ret |= test_main_complex_double_add_overflow ();
+  ret |= test_main_double_sub_invalid ();
+  ret |= test_main_double_sub_overflow ();
+  ret |= test_main_double_sub_inexact ();
+  ret |= test_main_double_sub_inexact_int ();
+  ret |= test_main_double_predec_inexact ();
+  ret |= test_main_double_postdec_inexact ();
+#if FLT_EVAL_METHOD == 0
+  ret |= test_main_long_long_sub_double_inexact ();
+#endif
+  ret |= test_main_complex_double_sub_overflow ();
+  ret |= test_main_double_mul_invalid ();
+  ret |= test_main_double_mul_overflow ();
+  ret |= test_main_double_mul_overflow_float ();
+  ret |= test_main_double_mul_underflow ();
+  ret |= test_main_double_mul_inexact ();
+  ret |= test_main_double_mul_inexact_int ();
+#if FLT_EVAL_METHOD == 0
+  ret |= test_main_long_long_mul_double_inexact ();
+#endif
+  ret |= test_main_complex_double_mul_overflow ();
+  ret |= test_main_double_div_invalid_divbyzero ();
+  ret |= test_main_double_div_overflow ();
+  ret |= test_main_double_div_underflow ();
+  ret |= test_main_double_div_inexact ();
+  ret |= test_main_double_div_inexact_int ();
+  ret |= test_main_int_div_double_inexact ();
+  ret |= test_main_complex_double_div_overflow ();
+  ret |= test_main_long_double_add_invalid ();
+  ret |= test_main_long_double_add_overflow ();
+#if LDBL_MANT_DIG != 106
+  ret |= test_main_long_double_add_inexact ();
+  ret |= test_main_long_double_add_inexact_int ();
+  ret |= test_main_long_double_preinc_inexact ();
+  ret |= test_main_long_double_postinc_inexact ();
+#endif
+  ret |= test_main_complex_long_double_add_overflow ();
+  ret |= test_main_long_double_sub_invalid ();
+  ret |= test_main_long_double_sub_overflow ();
+#if LDBL_MANT_DIG != 106
+  ret |= test_main_long_double_sub_inexact ();
+  ret |= test_main_long_double_sub_inexact_int ();
+  ret |= test_main_long_double_predec_inexact ();
+  ret |= test_main_long_double_postdec_inexact ();
+#endif
+  ret |= test_main_complex_long_double_sub_overflow ();
+  ret |= test_main_long_double_mul_invalid ();
+  ret |= test_main_long_double_mul_overflow ();
+  ret |= test_main_long_double_mul_overflow_float ();
+  ret |= test_main_long_double_mul_overflow_double ();
+  ret |= test_main_long_double_mul_underflow ();
+#if LDBL_MANT_DIG != 106
+  ret |= test_main_long_double_mul_inexact ();
+  ret |= test_main_long_double_mul_inexact_int ();
+#endif
+  ret |= test_main_complex_long_double_mul_overflow ();
+  ret |= test_main_long_double_div_invalid_divbyzero ();
+  ret |= test_main_long_double_div_overflow ();
+  ret |= test_main_long_double_div_underflow ();
+  ret |= test_main_long_double_div_inexact ();
+  ret |= test_main_long_double_div_inexact_int ();
+  ret |= test_main_int_div_long_double_inexact ();
+  ret |= test_main_complex_long_double_div_overflow ();
+  if (ret != 0)
+    abort ();
+  else
+    exit (0);
+}
Index: gcc/testsuite/gcc.dg/c11-atomic-2.c
===================================================================
--- gcc/testsuite/gcc.dg/c11-atomic-2.c	(revision 0)
+++ gcc/testsuite/gcc.dg/c11-atomic-2.c	(revision 0)
@@ -0,0 +1,165 @@
+/* Test for _Atomic in C11.  Test of valid assignment cases for
+   arithmetic types.  */
+/* { dg-do compile } */
+/* { dg-options "-std=c11 -pedantic-errors" } */
+
+#define TEST_ASSIGN(TYPE1, OP, TYPE2)		\
+  do						\
+    {						\
+      _Atomic TYPE1 a = 0;			\
+      TYPE2 b = 0;				\
+      _Atomic TYPE2 c = 0;			\
+      a OP b;					\
+      a OP c;					\
+    }						\
+  while (0)
+
+#define TEST_ASSIGN_ARITHR(TYPE1, OP)			\
+  do							\
+    {							\
+      TEST_ASSIGN (TYPE1, OP, _Bool);			\
+      TEST_ASSIGN (TYPE1, OP, char);			\
+      TEST_ASSIGN (TYPE1, OP, signed char);		\
+      TEST_ASSIGN (TYPE1, OP, unsigned char);		\
+      TEST_ASSIGN (TYPE1, OP, signed short);		\
+      TEST_ASSIGN (TYPE1, OP, unsigned short);		\
+      TEST_ASSIGN (TYPE1, OP, signed int);		\
+      TEST_ASSIGN (TYPE1, OP, unsigned int);		\
+      TEST_ASSIGN (TYPE1, OP, signed long);		\
+      TEST_ASSIGN (TYPE1, OP, unsigned long);		\
+      TEST_ASSIGN (TYPE1, OP, signed long long);	\
+      TEST_ASSIGN (TYPE1, OP, unsigned long long);	\
+      TEST_ASSIGN (TYPE1, OP, float);			\
+      TEST_ASSIGN (TYPE1, OP, double);			\
+      TEST_ASSIGN (TYPE1, OP, long double);		\
+      TEST_ASSIGN (TYPE1, OP, _Complex float);		\
+      TEST_ASSIGN (TYPE1, OP, _Complex double);		\
+      TEST_ASSIGN (TYPE1, OP, _Complex long double);	\
+    }							\
+  while (0)
+
+#define TEST_ASSIGN_ARITHBOTH(OP)			\
+  do							\
+    {							\
+      TEST_ASSIGN_ARITHR (_Bool, OP);			\
+      TEST_ASSIGN_ARITHR (char, OP);			\
+      TEST_ASSIGN_ARITHR (signed char, OP);		\
+      TEST_ASSIGN_ARITHR (unsigned char, OP);		\
+      TEST_ASSIGN_ARITHR (signed short, OP);		\
+      TEST_ASSIGN_ARITHR (unsigned short, OP);		\
+      TEST_ASSIGN_ARITHR (signed int, OP);		\
+      TEST_ASSIGN_ARITHR (unsigned int, OP);		\
+      TEST_ASSIGN_ARITHR (signed long, OP);		\
+      TEST_ASSIGN_ARITHR (unsigned long, OP);		\
+      TEST_ASSIGN_ARITHR (signed long long, OP);	\
+      TEST_ASSIGN_ARITHR (unsigned long long, OP);	\
+      TEST_ASSIGN_ARITHR (float, OP);			\
+      TEST_ASSIGN_ARITHR (double, OP);			\
+      TEST_ASSIGN_ARITHR (long double, OP);		\
+      TEST_ASSIGN_ARITHR (_Complex float, OP);		\
+      TEST_ASSIGN_ARITHR (_Complex double, OP);		\
+      TEST_ASSIGN_ARITHR (_Complex long double, OP);	\
+    }							\
+  while (0)
+
+#define TEST_ASSIGN_INTR(TYPE1, OP)			\
+  do							\
+    {							\
+      TEST_ASSIGN (TYPE1, OP, _Bool);			\
+      TEST_ASSIGN (TYPE1, OP, char);			\
+      TEST_ASSIGN (TYPE1, OP, signed char);		\
+      TEST_ASSIGN (TYPE1, OP, unsigned char);		\
+      TEST_ASSIGN (TYPE1, OP, signed short);		\
+      TEST_ASSIGN (TYPE1, OP, unsigned short);		\
+      TEST_ASSIGN (TYPE1, OP, signed int);		\
+      TEST_ASSIGN (TYPE1, OP, unsigned int);		\
+      TEST_ASSIGN (TYPE1, OP, signed long);		\
+      TEST_ASSIGN (TYPE1, OP, unsigned long);		\
+      TEST_ASSIGN (TYPE1, OP, signed long long);	\
+      TEST_ASSIGN (TYPE1, OP, unsigned long long);	\
+    }							\
+  while (0)
+
+#define TEST_ASSIGN_INTBOTH(OP)				\
+  do							\
+    {							\
+      TEST_ASSIGN_INTR (_Bool, OP);			\
+      TEST_ASSIGN_INTR (char, OP);			\
+      TEST_ASSIGN_INTR (signed char, OP);		\
+      TEST_ASSIGN_INTR (unsigned char, OP);		\
+      TEST_ASSIGN_INTR (signed short, OP);		\
+      TEST_ASSIGN_INTR (unsigned short, OP);		\
+      TEST_ASSIGN_INTR (signed int, OP);		\
+      TEST_ASSIGN_INTR (unsigned int, OP);		\
+      TEST_ASSIGN_INTR (signed long, OP);		\
+      TEST_ASSIGN_INTR (unsigned long, OP);		\
+      TEST_ASSIGN_INTR (signed long long, OP);		\
+      TEST_ASSIGN_INTR (unsigned long long, OP);	\
+    }							\
+  while (0)
+
+void
+test_simple (void)
+{
+  TEST_ASSIGN_ARITHBOTH (=);
+}
+
+void
+test_mult (void)
+{
+  TEST_ASSIGN_ARITHBOTH (*=);
+}
+
+void
+test_div (void)
+{
+  TEST_ASSIGN_ARITHBOTH (/=);
+}
+
+void
+test_mod (void)
+{
+  TEST_ASSIGN_INTBOTH (%=);
+}
+
+void
+test_plus (void)
+{
+  TEST_ASSIGN_ARITHBOTH (+=);
+}
+
+void
+test_minus (void)
+{
+  TEST_ASSIGN_ARITHBOTH (-=);
+}
+
+void
+test_lshift (void)
+{
+  TEST_ASSIGN_INTBOTH (<<=);
+}
+
+void
+test_rshift (void)
+{
+  TEST_ASSIGN_INTBOTH (>>=);
+}
+
+void
+test_and (void)
+{
+  TEST_ASSIGN_INTBOTH (&=);
+}
+
+void
+test_xor (void)
+{
+  TEST_ASSIGN_INTBOTH (^=);
+}
+
+void
+test_or (void)
+{
+  TEST_ASSIGN_INTBOTH (|=);
+}
Index: gcc/testsuite/gcc.dg/c99-atomic-1.c
===================================================================
--- gcc/testsuite/gcc.dg/c99-atomic-1.c	(revision 0)
+++ gcc/testsuite/gcc.dg/c99-atomic-1.c	(revision 0)
@@ -0,0 +1,8 @@
+/* Test for _Atomic: not in C99.  */
+/* { dg-do compile } */
+/* { dg-options "-std=c99 -pedantic-errors" } */
+
+_Atomic int i; /* { dg-error "_Atomic" } */
+_Atomic (int) j; /* { dg-error "_Atomic" } */
+int *_Atomic p; /* { dg-error "_Atomic" } */
+void f (int a[_Atomic]); /* { dg-error "_Atomic" } */
Index: gcc/testsuite/lib/atomic-dg.exp
===================================================================
--- gcc/testsuite/lib/atomic-dg.exp	(revision 0)
+++ gcc/testsuite/lib/atomic-dg.exp	(revision 0)
@@ -0,0 +1,104 @@
+# Copyright (C) 2013 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+#
+# atomic_link_flags -- compute library path and flags to find libatomic.
+# (originally from g++.exp)
+#
+
+proc atomic_link_flags { paths } {
+    global srcdir
+    global ld_library_path
+    global shlib_ext
+
+    set gccpath ${paths}
+    set flags ""
+
+    set shlib_ext [get_shlib_extension]
+
+    if { $gccpath != "" } {
+      if { [file exists "${gccpath}/libatomic/.libs/libatomic.a"]
+	   || [file exists "${gccpath}/libatomic/.libs/libatomic.${shlib_ext}"] } {
+	  append flags " -B${gccpath}/libatomic/ "
+	  append flags " -L${gccpath}/libatomic/.libs"
+	  append ld_library_path ":${gccpath}/libatomic/.libs"
+      }
+    } else {
+      global tool_root_dir
+
+      set libatomic [lookfor_file ${tool_root_dir} libatomic]
+      if { $libatomic != "" } {
+	  append flags "-L${libatomic} "
+	  append ld_library_path ":${libatomic}"
+      }
+    }
+
+    set_ld_library_path_env_vars
+
+    append flags " -latomic "
+    return "$flags"
+}
+
+#
+# atomic_init -- called at the start of each subdir of tests
+#
+
+proc atomic_init { args } {
+    global TEST_ALWAYS_FLAGS
+    global ALWAYS_CXXFLAGS
+    global TOOL_OPTIONS
+    global atomic_saved_TEST_ALWAYS_FLAGS
+
+    set link_flags ""
+    if ![is_remote host] {
+	if [info exists TOOL_OPTIONS] {
+	    set link_flags "[atomic_link_flags [get_multilibs ${TOOL_OPTIONS}]]"
+	} else {
+	    set link_flags "[atomic_link_flags [get_multilibs]]"
+	}
+    }
+
+    if [info exists TEST_ALWAYS_FLAGS] {
+	set atomic_saved_TEST_ALWAYS_FLAGS $TEST_ALWAYS_FLAGS
+    }
+    if [info exists ALWAYS_CXXFLAGS] {
+	set ALWAYS_CXXFLAGS [concat "{ldflags=$link_flags}" $ALWAYS_CXXFLAGS]
+    } else {
+	if [info exists TEST_ALWAYS_FLAGS] {
+	    set TEST_ALWAYS_FLAGS "$link_flags $TEST_ALWAYS_FLAGS"
+	} else {
+	    set TEST_ALWAYS_FLAGS "$link_flags"
+	}
+    }
+    return [check_no_compiler_messages_nocache libatomic_available executable {
+	int main (void) { return 0; }
+    }]
+}
+
+#
+# atomic_finish -- called at the end of each subdir of tests
+#
+
+proc atomic_finish { args } {
+    global TEST_ALWAYS_FLAGS
+    global atomic_saved_TEST_ALWAYS_FLAGS
+
+    if [info exists atomic_saved_TEST_ALWAYS_FLAGS] {
+	set TEST_ALWAYS_FLAGS $atomic_saved_TEST_ALWAYS_FLAGS
+    } else {
+	unset TEST_ALWAYS_FLAGS
+    }
+}
Index: gcc/testsuite/lib/target-supports.exp
===================================================================
--- gcc/testsuite/lib/target-supports.exp	(revision 204390)
+++ gcc/testsuite/lib/target-supports.exp	(working copy)
@@ -5477,3 +5477,40 @@ proc check_effective_target_aarch64_large { } {
 	return 0
     }
 }
+
+# Return 1 if <fenv.h> is available with all the standard IEEE
+# exceptions and floating-point exceptions are raised by arithmetic
+# operations.  (If the target requires special options for "inexact"
+# exceptions, those need to be specified in the testcases.)
+
+proc check_effective_target_fenv_exceptions {} {
+    return [check_runtime fenv_exceptions {
+	#include <fenv.h>
+	#include <stdlib.h>
+	#ifndef FE_DIVBYZERO
+	# error Missing FE_DIVBYZERO
+	#endif
+	#ifndef FE_INEXACT
+	# error Missing FE_INEXACT
+	#endif
+	#ifndef FE_INVALID
+	# error Missing FE_INVALID
+	#endif
+	#ifndef FE_OVERFLOW
+	# error Missing FE_OVERFLOW
+	#endif
+	#ifndef FE_UNDERFLOW
+	# error Missing FE_UNDERFLOW
+	#endif
+	volatile float a = 0.0f, r;
+	int
+	main (void)
+	{
+	  r = a / a;
+	  if (fetestexcept (FE_INVALID))
+	    exit (0);
+	  else
+	    abort ();
+	}
+    } "-std=gnu99"]
+}

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Implement C11 _Atomic
  2013-11-06  0:44 Implement C11 _Atomic Joseph S. Myers
@ 2013-11-06 22:42 ` Andrew MacLeod
  2013-11-07 17:16 ` Uros Bizjak
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 30+ messages in thread
From: Andrew MacLeod @ 2013-11-06 22:42 UTC (permalink / raw)
  To: Joseph S. Myers
  Cc: gcc-patches, mikestump, stanshebs, jason, rth, jh, ubizjak, jakub

On 11/05/2013 06:21 PM, Joseph S. Myers wrote:
> This patch, relative to trunk and based on work done on the C11-atomic
> branch, adds support for C11 _Atomic.  It is intended to include all
> the required language support.
>
>
Thanks for picking this up Joseph... It would have taken me months to do 
the same thing, and been a lot more painful for everyone :-).

It is really excellent work.

Andrew

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Implement C11 _Atomic
  2013-11-06  0:44 Implement C11 _Atomic Joseph S. Myers
  2013-11-06 22:42 ` Andrew MacLeod
@ 2013-11-07 17:16 ` Uros Bizjak
  2013-11-07 17:24 ` Jakub Jelinek
  2013-11-21 13:19 ` Hans-Peter Nilsson
  3 siblings, 0 replies; 30+ messages in thread
From: Uros Bizjak @ 2013-11-07 17:16 UTC (permalink / raw)
  To: Joseph S. Myers
  Cc: gcc-patches, Andrew MacLeod, Mike Stump, stanshebs,
	Jason Merrill, Richard Henderson, jh, Jakub Jelinek

On Wed, Nov 6, 2013 at 12:21 AM, Joseph S. Myers
<joseph@codesourcery.com> wrote:
> This patch, relative to trunk and based on work done on the C11-atomic
> branch, adds support for C11 _Atomic.  It is intended to include all
> the required language support.
>
> It does not include the <stdatomic.h> header; there's a version on the
> branch, but it needs further review against the standard and test
> coverage adding to the testsuite before I can propose it for mainline.
>
> Support for atomic types having bigger alignment than the
> corresponding non-atomic types is limited: it includes the code to
> increase the alignment of types whose size is exactly 1, 2, 4, 8 or 16
> to that of the corresponding integer type [*], but not anything for
> target-specific alignment increases.  There's code for target-specific
> alignment on the branch (and I intend to merge trunk back to the
> branch once this patch is on trunk, so it's easy to tell what the
> changes still left on the branch are), should any target maintainers
> wish to have such alignment.  Note however that ideally libstdc++
> atomics would be ABI-compatible with C atomics, requiring them to get
> the same alignment; the branch has an "atomic" attribute for that
> purpose, but I think further work on the C++ front-end changes would
> be needed for them to be ready for mainline.
>
> [*] The c-common.c code to resolve size-generic atomic built-in
> functions to size-specific ones assumes that types are naturally
> aligned (and so resolves to calls to the size-specific functions that
> require natural alignment) without checking it.  If users should be
> able to use the size-generic functions on types with lesser alignment,
> e.g. _Complex double (8-byte rather than 16-byte aligned), rather than
> just on their _Atomic variants, this is of course a bug in the code
> resolving those built-in functions.  (The libatomic functions properly
> check for alignment at runtime.)  But it seems reasonable enough
> anyway to make _Atomic _Complex double 16-byte aligned.
>
> Full use of _Atomic requires linking with libatomic, if you're doing
> any atomic operations that aren't fully expanded inline; arguably
> libatomic should be linked in by default with --as-needed (given that
> previously ordinary C code didn't require the user to link any
> libraries explicitly unless they directly called library functions),
> but that's independent of this patch.  Correct handling of atomic
> compound assignment for floating-point types also requires built-in
> support for floating-point environment manipulation operations roughly
> equivalent to feholdexcept, feclearexcept and feupdateenv (built-ins
> are used to avoid introducing libm dependencies, which generic C code
> not actually calling libm library functions shouldn't require); this
> patch includes such support for x86 [*], and I expect other
> architectures to be simpler.  If you don't have a libatomic port, the
> execution tests for _Atomic simply won't be run; if you have libatomic
> but not the floating-point support, the tests will be run but
> c11-atomic-exec-5.c will fail (assuming the library features are
> present for that test to run at all - it also requires pthreads).
>
> [*] This could be optimized if desired by passing the types in
> question to the target hook so it can generate code for only one of
> x87 and SSE in most cases, much like an optimization present in glibc
> when it internally does feholdexcept / fesetenv / feupdateenv
> sequences.
>
> _Atomic support is currently disabled for Objective-C and OpenMP.  For
> both (but mainly OpenMP), the relevant parser code needs checking to
> determine where convert_lvalue_to_rvalue calls need inserting to
> ensure that accesses to atomic variables involve atomic loads.  For
> Objective-C, there are also various special cases of compound
> assignment that need special handling for atomics just as standard C
> compound assignment is handled differently for atomics, as well as
> some TYPE_MAIN_VARIANT calls to check for correctness for atomics; see
> the comment on the relevant sorry () call for details.  OpenMP should
> also have TYPE_MAIN_VARIANT uses checked as well as a use of
> TYPE_QUALS_NO_ADDR_SPACE for a diagnostic in
> c_parser_omp_declare_reduction (where the diagnostic refers to a
> particular list of qualifiers).
>
> Bootstrapped with no regressions on x86_64-unknown-linux-gnu.  OK to
> commit (the various non-front-end pieces)?
>
> gcc:
> 2013-11-05  Andrew MacLeod  <amacleod@redhat.com>
>             Joseph Myers  <joseph@codesourcery.com>
>
>         * tree-core.h (enum cv_qualifier): Add TYPE_QUAL_ATOMIC.
>         (enum tree_index): Add TI_ATOMICQI_TYPE, TI_ATOMICHI_TYPE,
>         TI_ATOMICSI_TYPE, TI_ATOMICDI_TYPE and TI_ATOMICTI_TYPE.
>         (struct tree_base): Add atomic_flag field.
>         * tree.h (TYPE_ATOMIC): New accessor macro.
>         (TYPE_QUALS, TYPE_QUALS_NO_ADDR_SPACE): Add TYPE_QUAL_ATOMIC.
>         (TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC): New macro.
>         (atomicQI_type_node, atomicHI_type_node, atomicSI_type_node)
>         (atomicDI_type_node, atomicTI_type_node): New macros for type
>         nodes.
>         * tree.c (set_type_quals): Set TYPE_ATOMIC.
>         (find_atomic_core_type): New function.
>         (build_qualified_type): Adjust alignment for qualified types.
>         (build_atomic_base): New function
>         (build_common_tree_nodes): Build atomicQI_type_node,
>         atomicHI_type_node, atomicSI_type_node, atomicDI_type_node and
>         atomicTI_type_node.
>         * print-tree.c (print_node): Print atomic qualifier.
>         * tree-pretty-print.c (dump_generic_node): Print atomic type
>         attribute.
>         * target.def (atomic_assign_expand_fenv): New hook.
>         * doc/tm.texi.in (TARGET_ATOMIC_ASSIGN_EXPAND_FENV): New @hook.
>         * doc/tm.texi: Regenerate.
>         * targhooks.c (default_atomic_assign_expand_fenv): New function.
>         * targhooks.h (default_atomic_assign_expand_fenv): Declare.
>         * sync-builtins.def (__atomic_feraiseexcept): New built-in
>         function.
>         * config/i386/i386-builtin-types.def (VOID_FTYPE_PUSHORT): New
>         function type.
>         * config/i386/i386.c (enum ix86_builtins): Add
>         IX86_BUILTIN_FNSTENV, IX86_BUILTIN_FLDENV, IX86_BUILTIN_FNSTSW and
>         IX86_BUILTIN_FNCLEX.
>         (bdesc_special_args): Add __builtin_ia32_fnstenv,
>         __builtin_ia32_fldenv, __builtin_ia32_fnstsw and
>         __builtin_ia32_fnclex.
>         (ix86_expand_builtin): Handle the new built-in functions.
>         (ix86_atomic_assign_expand_fenv): New function.
>         (TARGET_ATOMIC_ASSIGN_EXPAND_FENV): New macro.
>         * config/i386/i386.md (UNSPECV_FNSTENV, UNSPECV_FLDENV)
>         (UNSPECV_FNSTSW, UNSPECV_FNCLEX): New unspecs.
>         (fnstenv, fldenv, fnstsw, fnclex): New insns.

The x86 part of the patch is OK.

Uros.

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Implement C11 _Atomic
  2013-11-06  0:44 Implement C11 _Atomic Joseph S. Myers
  2013-11-06 22:42 ` Andrew MacLeod
  2013-11-07 17:16 ` Uros Bizjak
@ 2013-11-07 17:24 ` Jakub Jelinek
  2013-11-07 18:10   ` Uros Bizjak
  2013-11-21 13:19 ` Hans-Peter Nilsson
  3 siblings, 1 reply; 30+ messages in thread
From: Jakub Jelinek @ 2013-11-07 17:24 UTC (permalink / raw)
  To: Joseph S. Myers
  Cc: gcc-patches, amacleod, mikestump, stanshebs, jason, rth, jh, ubizjak

On Tue, Nov 05, 2013 at 11:21:56PM +0000, Joseph S. Myers wrote:
> 2013-11-05  Andrew MacLeod  <amacleod@redhat.com>
> 	    Joseph Myers  <joseph@codesourcery.com>
> 
> 	* tree-core.h (enum cv_qualifier): Add TYPE_QUAL_ATOMIC.
> 	(enum tree_index): Add TI_ATOMICQI_TYPE, TI_ATOMICHI_TYPE,
> 	TI_ATOMICSI_TYPE, TI_ATOMICDI_TYPE and TI_ATOMICTI_TYPE.
> 	(struct tree_base): Add atomic_flag field.
> 	* tree.h (TYPE_ATOMIC): New accessor macro.
> 	(TYPE_QUALS, TYPE_QUALS_NO_ADDR_SPACE): Add TYPE_QUAL_ATOMIC.
> 	(TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC): New macro.
> 	(atomicQI_type_node, atomicHI_type_node, atomicSI_type_node)
> 	(atomicDI_type_node, atomicTI_type_node): New macros for type
> 	nodes.
> 	* tree.c (set_type_quals): Set TYPE_ATOMIC.
> 	(find_atomic_core_type): New function.
> 	(build_qualified_type): Adjust alignment for qualified types.
> 	(build_atomic_base): New function
> 	(build_common_tree_nodes): Build atomicQI_type_node,
> 	atomicHI_type_node, atomicSI_type_node, atomicDI_type_node and
> 	atomicTI_type_node.
> 	* print-tree.c (print_node): Print atomic qualifier.
> 	* tree-pretty-print.c (dump_generic_node): Print atomic type
> 	attribute.
> 	* target.def (atomic_assign_expand_fenv): New hook.
> 	* doc/tm.texi.in (TARGET_ATOMIC_ASSIGN_EXPAND_FENV): New @hook.
> 	* doc/tm.texi: Regenerate.
> 	* targhooks.c (default_atomic_assign_expand_fenv): New function.
> 	* targhooks.h (default_atomic_assign_expand_fenv): Declare.
> 	* sync-builtins.def (__atomic_feraiseexcept): New built-in
> 	function.

> 2013-11-05  Joseph Myers  <joseph@codesourcery.com>
> 
> 	* lib/target-supports.exp
> 	(check_effective_target_fenv_exceptions): New function.
> 	* lib/atomic-dg.exp, gcc.dg/atomic/atomic.exp: New files.
> 	* gcc.dg/atomic/c11-atomic-exec-1.c,
> 	gcc.dg/atomic/c11-atomic-exec-2.c,
> 	gcc.dg/atomic/c11-atomic-exec-3.c,
> 	gcc.dg/atomic/c11-atomic-exec-4.c,
> 	gcc.dg/atomic/c11-atomic-exec-5.c, gcc.dg/c11-atomic-1.c,
> 	gcc.dg/c11-atomic-2.c, gcc.dg/c11-atomic-3.c,
> 	gcc.dg/c90-atomic-1.c, gcc.dg/c99-atomic-1.c: New tests.
> 
> libatomic:
> 2013-11-05  Joseph Myers  <joseph@codesourcery.com>
> 
> 	* fenv.c: New file.
> 	* libatomic.map (LIBATOMIC_1.1): New symbol version.  Include
> 	__atomic_feraiseexcept.
> 	* configure.ac (libtool_VERSION): Change to 2:0:1.
> 	(fenv.h): Test for header.
> 	* Makefile.am (libatomic_la_SOURCES): Add fenv.c.
> 	* Makefile.in, auto-config.h.in, configure: Regenerate.

The middle-end, libatomic and testsuite changes are ok.

	Jakub

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Implement C11 _Atomic
  2013-11-07 17:24 ` Jakub Jelinek
@ 2013-11-07 18:10   ` Uros Bizjak
  2013-11-07 18:44     ` Joseph S. Myers
  0 siblings, 1 reply; 30+ messages in thread
From: Uros Bizjak @ 2013-11-07 18:10 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: Joseph S. Myers, gcc-patches, Andrew MacLeod, Mike Stump,
	stanshebs, Jason Merrill, Richard Henderson, jh

On Thu, Nov 7, 2013 at 5:45 PM, Jakub Jelinek <jakub@redhat.com> wrote:
> On Tue, Nov 05, 2013 at 11:21:56PM +0000, Joseph S. Myers wrote:
>> 2013-11-05  Andrew MacLeod  <amacleod@redhat.com>
>>           Joseph Myers  <joseph@codesourcery.com>
>>
>>       * tree-core.h (enum cv_qualifier): Add TYPE_QUAL_ATOMIC.
>>       (enum tree_index): Add TI_ATOMICQI_TYPE, TI_ATOMICHI_TYPE,
>>       TI_ATOMICSI_TYPE, TI_ATOMICDI_TYPE and TI_ATOMICTI_TYPE.
>>       (struct tree_base): Add atomic_flag field.
>>       * tree.h (TYPE_ATOMIC): New accessor macro.
>>       (TYPE_QUALS, TYPE_QUALS_NO_ADDR_SPACE): Add TYPE_QUAL_ATOMIC.
>>       (TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC): New macro.
>>       (atomicQI_type_node, atomicHI_type_node, atomicSI_type_node)
>>       (atomicDI_type_node, atomicTI_type_node): New macros for type
>>       nodes.
>>       * tree.c (set_type_quals): Set TYPE_ATOMIC.
>>       (find_atomic_core_type): New function.
>>       (build_qualified_type): Adjust alignment for qualified types.
>>       (build_atomic_base): New function
>>       (build_common_tree_nodes): Build atomicQI_type_node,
>>       atomicHI_type_node, atomicSI_type_node, atomicDI_type_node and
>>       atomicTI_type_node.
>>       * print-tree.c (print_node): Print atomic qualifier.
>>       * tree-pretty-print.c (dump_generic_node): Print atomic type
>>       attribute.
>>       * target.def (atomic_assign_expand_fenv): New hook.
>>       * doc/tm.texi.in (TARGET_ATOMIC_ASSIGN_EXPAND_FENV): New @hook.
>>       * doc/tm.texi: Regenerate.
>>       * targhooks.c (default_atomic_assign_expand_fenv): New function.
>>       * targhooks.h (default_atomic_assign_expand_fenv): Declare.
>>       * sync-builtins.def (__atomic_feraiseexcept): New built-in
>>       function.
>
>> 2013-11-05  Joseph Myers  <joseph@codesourcery.com>
>>
>>       * lib/target-supports.exp
>>       (check_effective_target_fenv_exceptions): New function.
>>       * lib/atomic-dg.exp, gcc.dg/atomic/atomic.exp: New files.
>>       * gcc.dg/atomic/c11-atomic-exec-1.c,
>>       gcc.dg/atomic/c11-atomic-exec-2.c,
>>       gcc.dg/atomic/c11-atomic-exec-3.c,
>>       gcc.dg/atomic/c11-atomic-exec-4.c,
>>       gcc.dg/atomic/c11-atomic-exec-5.c, gcc.dg/c11-atomic-1.c,
>>       gcc.dg/c11-atomic-2.c, gcc.dg/c11-atomic-3.c,
>>       gcc.dg/c90-atomic-1.c, gcc.dg/c99-atomic-1.c: New tests.
>>
>> libatomic:
>> 2013-11-05  Joseph Myers  <joseph@codesourcery.com>
>>
>>       * fenv.c: New file.
>>       * libatomic.map (LIBATOMIC_1.1): New symbol version.  Include
>>       __atomic_feraiseexcept.
>>       * configure.ac (libtool_VERSION): Change to 2:0:1.
>>       (fenv.h): Test for header.
>>       * Makefile.am (libatomic_la_SOURCES): Add fenv.c.
>>       * Makefile.in, auto-config.h.in, configure: Regenerate.
>
> The middle-end, libatomic and testsuite changes are ok.

Please note that following code form fenv.c won't generate overflow
exception on x87:

  if (excepts & FP_EX_OVERFLOW)
    {
      volatile float max = __FLT_MAX__;
      r = max * max;
    }

Uros.

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Implement C11 _Atomic
  2013-11-07 18:10   ` Uros Bizjak
@ 2013-11-07 18:44     ` Joseph S. Myers
  2013-11-07 18:47       ` Uros Bizjak
  2013-11-08 10:09       ` Uros Bizjak
  0 siblings, 2 replies; 30+ messages in thread
From: Joseph S. Myers @ 2013-11-07 18:44 UTC (permalink / raw)
  To: Uros Bizjak
  Cc: Jakub Jelinek, gcc-patches, Andrew MacLeod, Mike Stump,
	stanshebs, Jason Merrill, Richard Henderson, jh

On Thu, 7 Nov 2013, Uros Bizjak wrote:

> Please note that following code form fenv.c won't generate overflow
> exception on x87:
> 
>   if (excepts & FP_EX_OVERFLOW)
>     {
>       volatile float max = __FLT_MAX__;
>       r = max * max;
>     }

r being volatile is intended to ensure that the result does get stored 
back to memory, and so in particular that a result computed with excess 
precision gets converted back to float and the exception is raised.

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Implement C11 _Atomic
  2013-11-07 18:44     ` Joseph S. Myers
@ 2013-11-07 18:47       ` Uros Bizjak
  2013-11-07 18:55         ` Joseph S. Myers
  2013-11-08 10:09       ` Uros Bizjak
  1 sibling, 1 reply; 30+ messages in thread
From: Uros Bizjak @ 2013-11-07 18:47 UTC (permalink / raw)
  To: Joseph S. Myers
  Cc: Jakub Jelinek, gcc-patches, Andrew MacLeod, Mike Stump,
	stanshebs, Jason Merrill, Richard Henderson, jh

On Thu, Nov 7, 2013 at 7:26 PM, Joseph S. Myers <joseph@codesourcery.com> wrote:
> On Thu, 7 Nov 2013, Uros Bizjak wrote:
>
>> Please note that following code form fenv.c won't generate overflow
>> exception on x87:
>>
>>   if (excepts & FP_EX_OVERFLOW)
>>     {
>>       volatile float max = __FLT_MAX__;
>>       r = max * max;
>>     }
>
> r being volatile is intended to ensure that the result does get stored
> back to memory, and so in particular that a result computed with excess
> precision gets converted back to float and the exception is raised.

--cut here--
#define _GNU_SOURCE
#include <fenv.h>

int main(void) {
    feenableexcept(FE_INVALID   |
                   FE_DIVBYZERO |
                   FE_OVERFLOW  |
                   FE_UNDERFLOW);

    volatile float a = __FLT_MAX__, b = __FLT_MAX__;
    volatile float c = a*b;

    return 0;
}
--cut here--

[uros@localhost test]$ gcc -lm -g fpex.c
[uros@localhost test]$ ./a.out
Floating point exception (core dumped)
[uros@localhost test]$ gcc -lm -g -m32 fpex.c
[uros@localhost test]$ ./a.out
[uros@localhost test]$

Uros.

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Implement C11 _Atomic
  2013-11-07 18:47       ` Uros Bizjak
@ 2013-11-07 18:55         ` Joseph S. Myers
       [not found]           ` <CAFULd4ZrAEECG+pptH8cRaWznioaM9VXS4TetpEvkWj--n7H1w@mail.gmail.com>
  0 siblings, 1 reply; 30+ messages in thread
From: Joseph S. Myers @ 2013-11-07 18:55 UTC (permalink / raw)
  To: Uros Bizjak
  Cc: Jakub Jelinek, gcc-patches, Andrew MacLeod, Mike Stump,
	stanshebs, Jason Merrill, Richard Henderson, jh

On Thu, 7 Nov 2013, Uros Bizjak wrote:

> [uros@localhost test]$ gcc -lm -g fpex.c
> [uros@localhost test]$ ./a.out
> Floating point exception (core dumped)
> [uros@localhost test]$ gcc -lm -g -m32 fpex.c
> [uros@localhost test]$ ./a.out
> [uros@localhost test]$

I see code of the form (testing compilation rather than execution):

        flds    4(%esp)
        flds    8(%esp)
        fmulp   %st, %st(1)
        fstps   12(%esp)

where the fstps should result in the exception, and glibc uses volatile in 
several places, conditional on __FLT_EVAL_METHOD__ != 0, to force a 
conversion to the semantic type (whether for correct results, or to ensure 
exceptions).

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Implement C11 _Atomic
       [not found]           ` <CAFULd4ZrAEECG+pptH8cRaWznioaM9VXS4TetpEvkWj--n7H1w@mail.gmail.com>
@ 2013-11-07 21:02             ` Joseph S. Myers
  2013-11-07 21:08               ` Uros Bizjak
  0 siblings, 1 reply; 30+ messages in thread
From: Joseph S. Myers @ 2013-11-07 21:02 UTC (permalink / raw)
  To: Uros Bizjak; +Cc: gcc-patches

On Thu, 7 Nov 2013, Uros Bizjak wrote:

> > I see code of the form (testing compilation rather than execution):
> >
> >         flds    4(%esp)
> >         flds    8(%esp)
> >         fmulp   %st, %st(1)
> >         fstps   12(%esp)
> >
> > where the fstps should result in the exception, and glibc uses volatile in
> > several places, conditional on __FLT_EVAL_METHOD__ != 0, to force a
> > conversion to the semantic type (whether for correct results, or to ensure
> > exceptions).
> 
> Yes, this is the exact sequence my example compiles to:
> 
>  8048405:       d9 44 24 14             flds   0x14(%esp)
>  8048409:       d9 44 24 18             flds   0x18(%esp)
>  804840d:       de c9                   fmulp  %st,%st(1)
>  804840f:       d9 5c 24 1c             fstps  0x1c(%esp)
> 
> unfortunately, it won't generate exception.

Are you sure?  It's documented as generating an exception.  That may mean, 
as usual on x87, setting the exception bit (as can be tested by 
fetestexcept) and only calling a trap handler on the *next* x87 
instruction.  So if fstps is the last floating-point instruction executed 
by the program, a trap handler may not be called - but that's no different 
from an ordinary floating-point compound assignment having the 
exception-raising operation as the last floating-point instruction.

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Implement C11 _Atomic
  2013-11-07 21:02             ` Joseph S. Myers
@ 2013-11-07 21:08               ` Uros Bizjak
  2013-11-07 22:25                 ` Uros Bizjak
  0 siblings, 1 reply; 30+ messages in thread
From: Uros Bizjak @ 2013-11-07 21:08 UTC (permalink / raw)
  To: Joseph S. Myers; +Cc: gcc-patches

On Thu, Nov 7, 2013 at 9:33 PM, Joseph S. Myers <joseph@codesourcery.com> wrote:


>> > I see code of the form (testing compilation rather than execution):
>> >
>> >         flds    4(%esp)
>> >         flds    8(%esp)
>> >         fmulp   %st, %st(1)
>> >         fstps   12(%esp)
>> >
>> > where the fstps should result in the exception, and glibc uses volatile in
>> > several places, conditional on __FLT_EVAL_METHOD__ != 0, to force a
>> > conversion to the semantic type (whether for correct results, or to ensure
>> > exceptions).
>>
>> Yes, this is the exact sequence my example compiles to:
>>
>>  8048405:       d9 44 24 14             flds   0x14(%esp)
>>  8048409:       d9 44 24 18             flds   0x18(%esp)
>>  804840d:       de c9                   fmulp  %st,%st(1)
>>  804840f:       d9 5c 24 1c             fstps  0x1c(%esp)
>>
>> unfortunately, it won't generate exception.
>
> Are you sure?  It's documented as generating an exception.  That may mean,
> as usual on x87, setting the exception bit (as can be tested by
> fetestexcept) and only calling a trap handler on the *next* x87
> instruction.  So if fstps is the last floating-point instruction executed
> by the program, a trap handler may not be called - but that's no different
> from an ordinary floating-point compound assignment having the
> exception-raising operation as the last floating-point instruction.

Aha, here is the problem.

The exception is not generated by fmulp, but by the fstps that follows
fmulp. The fstps will close exception window from fmulp, but fstps
needs another fwait to generate exception. I have added fwait after
fstps manually:

   0x080483fd <+29>:    fstps  0x18(%esp)
   0x08048401 <+33>:    flds   0x18(%esp)
   0x08048405 <+37>:    flds   0x18(%esp)
   0x08048409 <+41>:    fmulp  %st,%st(1)
   0x0804840b <+43>:    fstps  0x1c(%esp)
=> 0x0804840f <+47>:    fwait
   0x08048410 <+48>:    leave

And in this case, exception was generated, as marked by "=>" in gdb.

Uros.

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Implement C11 _Atomic
  2013-11-07 21:08               ` Uros Bizjak
@ 2013-11-07 22:25                 ` Uros Bizjak
  2013-11-07 22:43                   ` Joseph S. Myers
  0 siblings, 1 reply; 30+ messages in thread
From: Uros Bizjak @ 2013-11-07 22:25 UTC (permalink / raw)
  To: Joseph S. Myers; +Cc: gcc-patches

On Thu, Nov 7, 2013 at 9:55 PM, Uros Bizjak <ubizjak@gmail.com> wrote:

>>> > I see code of the form (testing compilation rather than execution):
>>> >
>>> >         flds    4(%esp)
>>> >         flds    8(%esp)
>>> >         fmulp   %st, %st(1)
>>> >         fstps   12(%esp)
>>> >
>>> > where the fstps should result in the exception, and glibc uses volatile in
>>> > several places, conditional on __FLT_EVAL_METHOD__ != 0, to force a
>>> > conversion to the semantic type (whether for correct results, or to ensure
>>> > exceptions).
>>>
>>> Yes, this is the exact sequence my example compiles to:
>>>
>>>  8048405:       d9 44 24 14             flds   0x14(%esp)
>>>  8048409:       d9 44 24 18             flds   0x18(%esp)
>>>  804840d:       de c9                   fmulp  %st,%st(1)
>>>  804840f:       d9 5c 24 1c             fstps  0x1c(%esp)
>>>
>>> unfortunately, it won't generate exception.
>>
>> Are you sure?  It's documented as generating an exception.  That may mean,
>> as usual on x87, setting the exception bit (as can be tested by
>> fetestexcept) and only calling a trap handler on the *next* x87
>> instruction.  So if fstps is the last floating-point instruction executed
>> by the program, a trap handler may not be called - but that's no different
>> from an ordinary floating-point compound assignment having the
>> exception-raising operation as the last floating-point instruction.
>
> Aha, here is the problem.
>
> The exception is not generated by fmulp, but by the fstps that follows
> fmulp. The fstps will close exception window from fmulp, but fstps
> needs another fwait to generate exception. I have added fwait after
> fstps manually:
>
>    0x080483fd <+29>:    fstps  0x18(%esp)
>    0x08048401 <+33>:    flds   0x18(%esp)
>    0x08048405 <+37>:    flds   0x18(%esp)
>    0x08048409 <+41>:    fmulp  %st,%st(1)
>    0x0804840b <+43>:    fstps  0x1c(%esp)
> => 0x0804840f <+47>:    fwait
>    0x08048410 <+48>:    leave
>
> And in this case, exception was generated, as marked by "=>" in gdb.

However, this insn also raised FE_INEXACT flag (also on x86_64),
probably not what you wanted. Your code that generates FE_UNDERFLOW
will also raise FE_INEXACT. (and FE_DENORMAL).

Uros.

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Implement C11 _Atomic
  2013-11-07 22:25                 ` Uros Bizjak
@ 2013-11-07 22:43                   ` Joseph S. Myers
  0 siblings, 0 replies; 30+ messages in thread
From: Joseph S. Myers @ 2013-11-07 22:43 UTC (permalink / raw)
  To: Uros Bizjak; +Cc: gcc-patches

On Thu, 7 Nov 2013, Uros Bizjak wrote:

> However, this insn also raised FE_INEXACT flag (also on x86_64),
> probably not what you wanted. Your code that generates FE_UNDERFLOW
> will also raise FE_INEXACT. (and FE_DENORMAL).

If the compound assignment raised overflow or underflow, it will also have 
raised inexact, so it's not a problem that this code raises inexact along 
with overflow/underflow (and then raises it again - ISO C expressly "does 
not require support for trap handlers that maintain information about the 
order or count of floating-point exceptions").  I raised the case of exact 
underflow in <http://www.open-std.org/jtc1/sc22/wg14/13103>, but it's a 
matter to be dealt with when standard C gets bindings for non-default 
exception handling (probably in TS 18661-5, not yet written) rather than 
now.

If GCC were to implement such bindings, the issues with delayed x87 
exceptions might also need addressing for them - but given the lack of 
support for exceptions and rounding modes following C99/C11 Annex F, I 
don't really expect support for new bindings for exceptions and rounding 
modes any time soon.

(Separately, C99/C11 also leave it implementation-defined whether 
feraiseexcept raises inexact along with overflow and underflow - but here 
we're dealing with exceptions we know came from floating-point arithmetic, 
rather than an arbitrary user-specified argument to feraiseexcept.)

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Implement C11 _Atomic
  2013-11-07 18:44     ` Joseph S. Myers
  2013-11-07 18:47       ` Uros Bizjak
@ 2013-11-08 10:09       ` Uros Bizjak
  2013-11-08 13:33         ` Joseph S. Myers
  1 sibling, 1 reply; 30+ messages in thread
From: Uros Bizjak @ 2013-11-08 10:09 UTC (permalink / raw)
  To: Joseph S. Myers
  Cc: Jakub Jelinek, gcc-patches, Andrew MacLeod, Mike Stump,
	stanshebs, Jason Merrill, Richard Henderson, jh

On Thu, Nov 7, 2013 at 7:26 PM, Joseph S. Myers <joseph@codesourcery.com> wrote:

>> Please note that following code form fenv.c won't generate overflow
>> exception on x87:
>>
>>   if (excepts & FP_EX_OVERFLOW)
>>     {
>>       volatile float max = __FLT_MAX__;
>>       r = max * max;
>>     }
>
> r being volatile is intended to ensure that the result does get stored
> back to memory, and so in particular that a result computed with excess
> precision gets converted back to float and the exception is raised.

Can we introduce a target-dependant source here, in the same way as
gfortran has different config/fpu-*.c files? I would like to propose
the code from (recently improved) libgcc/config/i386/sfp-exceptions.c
to generate exceptions on x86 targets. The main benefits of this code
are:
- precision: it generates exactly the exception it is supposed to
generate at the exact spot (x87 and SSE)
- the code doesn't do arithemtics with denormal results
- can also generate non-standard denormal exception

Your proposed code can be considered a generic fallback code then. I'm
sure other targets have their own, perhaps better ways to generate FP
exceptions.

Uros.

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Implement C11 _Atomic
  2013-11-08 10:09       ` Uros Bizjak
@ 2013-11-08 13:33         ` Joseph S. Myers
  0 siblings, 0 replies; 30+ messages in thread
From: Joseph S. Myers @ 2013-11-08 13:33 UTC (permalink / raw)
  To: Uros Bizjak
  Cc: Jakub Jelinek, gcc-patches, Andrew MacLeod, Mike Stump,
	stanshebs, Jason Merrill, Richard Henderson, jh

On Fri, 8 Nov 2013, Uros Bizjak wrote:

> Can we introduce a target-dependant source here, in the same way as

Sure, that seems a reasonable thing to do.  I think putting a file fenv.c 
in an appropriate subdirectory of libatomic/config will result in it being 
found automatically by the existing search path logic, but you'll need to 
test that.

The present code essentially follows what glibc's feraiseexcept does for 
lots of architectures, but with generic C code where the glibc code tends 
to use asms to control the exact instructions used (and thereby avoid the 
need for volatile, I suppose).

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Implement C11 _Atomic
  2013-11-06  0:44 Implement C11 _Atomic Joseph S. Myers
                   ` (2 preceding siblings ...)
  2013-11-07 17:24 ` Jakub Jelinek
@ 2013-11-21 13:19 ` Hans-Peter Nilsson
  2013-11-21 18:03   ` Andrew MacLeod
  3 siblings, 1 reply; 30+ messages in thread
From: Hans-Peter Nilsson @ 2013-11-21 13:19 UTC (permalink / raw)
  To: Joseph S. Myers; +Cc: gcc-patches, amacleod

On Tue, 5 Nov 2013, Joseph S. Myers wrote:

Thanks for doing this!  However, without examples I have trouble
reading out the bits I need as a target maintainer, and I can't
read out the answers from the patch, so pardon a few questions.

> This patch, relative to trunk and based on work done on the C11-atomic
> branch, adds support for C11 _Atomic.  It is intended to include all
> the required language support.
>
> It does not include the <stdatomic.h> header; there's a version on the
> branch, but it needs further review against the standard and test
> coverage adding to the testsuite before I can propose it for mainline.
>
> Support for atomic types having bigger alignment than the
> corresponding non-atomic types is limited: it includes the code to
> increase the alignment of types whose size is exactly 1, 2, 4, 8 or 16
> to that of the corresponding integer type [*], but not anything for
> target-specific alignment increases.

Target-maintainer perspective here: do I read that correctly,
that by default adding _Atomic raises the alignment of that type
to the "natural" one, for all targets?

To wit,

> There's code for target-specific
> alignment on the branch (and I intend to merge trunk back to the
> branch once this patch is on trunk, so it's easy to tell what the
> changes still left on the branch are), should any target maintainers
> wish to have such alignment.

...is that part needed for alignment that is only
target-specific and other-than-natural?  For example, 8-byte
aligment where required for atomic 4-byte types?

Or is that part also required for
anything-other-than-ordinary-C-type alignment for the target;
say, natural 4-byte alignment of 4-byte-types for targets where
alignment is otherwise "packed"; where only 1-byte alignment of
the basic type is ABI-mandated?

brgds, H-P

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Implement C11 _Atomic
  2013-11-21 13:19 ` Hans-Peter Nilsson
@ 2013-11-21 18:03   ` Andrew MacLeod
  2013-11-21 18:20     ` Hans-Peter Nilsson
  0 siblings, 1 reply; 30+ messages in thread
From: Andrew MacLeod @ 2013-11-21 18:03 UTC (permalink / raw)
  To: Hans-Peter Nilsson, Joseph S. Myers; +Cc: gcc-patches

On 11/21/2013 06:05 AM, Hans-Peter Nilsson wrote:
> On Tue, 5 Nov 2013, Joseph S. Myers wrote:
>
> Thanks for doing this!  However, without examples I have trouble
> reading out the bits I need as a target maintainer, and I can't
> read out the answers from the patch, so pardon a few questions.
>
>>
>> Support for atomic types having bigger alignment than the
>> corresponding non-atomic types is limited: it includes the code to
>> increase the alignment of types whose size is exactly 1, 2, 4, 8 or 16
>> to that of the corresponding integer type [*], but not anything for
>> target-specific alignment increases.
> Target-maintainer perspective here: do I read that correctly,
> that by default adding _Atomic raises the alignment of that type
> to the "natural" one, for all targets?
>
> To wit,

It sets up the default alignment for all atomic integral types to be 
that of the natural alignment of their integer counterpart. ie 
alignof(_Atomic short) = alignof (short)

   For non-integral types, if sizeof (type) == sizeof (integral-type), 
then it makes sure that  alignof (type) is at least as large as alignof 
(_Atomic integral-type), and overrides it if necessary, allowing the 
lock-free routines to work the same for non-integral types.


>
>> There's code for target-specific
>> alignment on the branch (and I intend to merge trunk back to the
>> branch once this patch is on trunk, so it's easy to tell what the
>> changes still left on the branch are), should any target maintainers
>> wish to have such alignment.
> ...is that part needed for alignment that is only
> target-specific and other-than-natural?  For example, 8-byte
> aligment where required for atomic 4-byte types?
Yes, I believe the override code is still on the branch. There is a 
target hook which allows the alignment for an atomic type to be changed.

So, the cris port would be able to override the alignment of the 
atomicHI_type_node and make it 4 bytes aligned,  which would then cause 
any variable declared as _Atomic short to automatically be 4 byte aligned.



> Or is that part also required for
> anything-other-than-ordinary-C-type alignment for the target;
> say, natural 4-byte alignment of 4-byte-types for targets where
> alignment is otherwise "packed"; where only 1-byte alignment of
> the basic type is ABI-mandated?
>
If I understand correctly, yes, it would be needed there as well.... if 
the compiler thinks alignof (int) is 1, then I believe it will set 
alignof(_Atomic int) to 1 as well, and that's probably not good.

Basically, atomic_types are given their own type nodes in tree.c:
   atomicQI_type_node = build_atomic_base (unsigned_intQI_type_node);
   atomicHI_type_node = build_atomic_base (unsigned_intHI_type_node);
   atomicSI_type_node = build_atomic_base (unsigned_intSI_type_node);
   atomicDI_type_node = build_atomic_base (unsigned_intDI_type_node);
   atomicTI_type_node = build_atomic_base (unsigned_intTI_type_node);

and on the branch that code instead looks something like:

#define SET_ATOMIC_TYPE_NODE(TYPE, MODE, DEFAULT)               \
  (TYPE) = build_atomic_base (DEFAULT, targetm.atomic_align_for_mode 
(MODE));

   SET_ATOMIC_TYPE_NODE (atomicQI_type_node, QImode, 
unsigned_intQI_type_node);
<...>

which provides a target hook to override the default values and a target 
can set them to whatever it deems necessary.

There was insufficient time to test and fully flush this out, so it 
hasn't made it into mainline.  Its only thanks to Josephs heroic efforts 
we have C11 :-)

I don't think its a lot of code if you wanted to fool with it for your port.

Andrew





^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Implement C11 _Atomic
  2013-11-21 18:03   ` Andrew MacLeod
@ 2013-11-21 18:20     ` Hans-Peter Nilsson
  2013-11-21 18:30       ` Andrew MacLeod
  0 siblings, 1 reply; 30+ messages in thread
From: Hans-Peter Nilsson @ 2013-11-21 18:20 UTC (permalink / raw)
  To: Andrew MacLeod; +Cc: Joseph S. Myers, gcc-patches

On Thu, 21 Nov 2013, Andrew MacLeod wrote:
> > Or is that part also required for
> > anything-other-than-ordinary-C-type alignment for the target;
> > say, natural 4-byte alignment of 4-byte-types for targets where
> > alignment is otherwise "packed"; where only 1-byte alignment of
> > the basic type is ABI-mandated?
> >
> If I understand correctly, yes, it would be needed there as well.... if the
> compiler thinks alignof (int) is 1, then I believe it will set alignof(_Atomic
> int) to 1 as well, and that's probably not good.

Right.

> Basically, atomic_types are given their own type nodes in tree.c:
>   atomicQI_type_node = build_atomic_base (unsigned_intQI_type_node);
>   atomicHI_type_node = build_atomic_base (unsigned_intHI_type_node);
>   atomicSI_type_node = build_atomic_base (unsigned_intSI_type_node);
>   atomicDI_type_node = build_atomic_base (unsigned_intDI_type_node);
>   atomicTI_type_node = build_atomic_base (unsigned_intTI_type_node);

It sounds like I should be able to hack that from the port in
some other tree initializer hook?

I'm trying to avoid ABI breakage of course.  I'd rather not have
to ask people not to use _Atomic with 4.9 for CRIS ports using
official releases or have ABI breakage with the next release.
Maybe there's one other port in the same situation...

> and on the branch that code instead looks something like:
>
> #define SET_ATOMIC_TYPE_NODE(TYPE, MODE, DEFAULT)               \
>  (TYPE) = build_atomic_base (DEFAULT, targetm.atomic_align_for_mode (MODE));
>
>   SET_ATOMIC_TYPE_NODE (atomicQI_type_node, QImode, unsigned_intQI_type_node);
> <...>
>
> which provides a target hook to override the default values and a target can
> set them to whatever it deems necessary.

Yah, that'd be nice.  Doesn't sound like more than the target
hook and the patched lines above left for that to happen,
though?  Or perhaps that's a too-naive assumption. I guess I
should have a look.

> There was insufficient time to test and fully flush this out, so it hasn't
> made it into mainline.  Its only thanks to Josephs heroic efforts we have C11
> :-)
>
> I don't think its a lot of code if you wanted to fool with it for your port.

So, what would be needed in terms of testing and coding to get
that part into 4.9?

brgds, H-P

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Implement C11 _Atomic
  2013-11-21 18:20     ` Hans-Peter Nilsson
@ 2013-11-21 18:30       ` Andrew MacLeod
  2013-11-21 18:49         ` Joseph S. Myers
                           ` (2 more replies)
  0 siblings, 3 replies; 30+ messages in thread
From: Andrew MacLeod @ 2013-11-21 18:30 UTC (permalink / raw)
  To: Hans-Peter Nilsson; +Cc: Joseph S. Myers, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 3254 bytes --]

On 11/21/2013 10:20 AM, Hans-Peter Nilsson wrote:
> On Thu, 21 Nov 2013, Andrew MacLeod wrote:
>>> Or is that part also required for
>>> anything-other-than-ordinary-C-type alignment for the target;
>>> say, natural 4-byte alignment of 4-byte-types for targets where
>>> alignment is otherwise "packed"; where only 1-byte alignment of
>>> the basic type is ABI-mandated?
>>>
>> If I understand correctly, yes, it would be needed there as well.... if the
>> compiler thinks alignof (int) is 1, then I believe it will set alignof(_Atomic
>> int) to 1 as well, and that's probably not good.
> Right.
>
>> Basically, atomic_types are given their own type nodes in tree.c:
>>    atomicQI_type_node = build_atomic_base (unsigned_intQI_type_node);
>>    atomicHI_type_node = build_atomic_base (unsigned_intHI_type_node);
>>    atomicSI_type_node = build_atomic_base (unsigned_intSI_type_node);
>>    atomicDI_type_node = build_atomic_base (unsigned_intDI_type_node);
>>    atomicTI_type_node = build_atomic_base (unsigned_intTI_type_node);
> It sounds like I should be able to hack that from the port in
> some other tree initializer hook?
>
> I'm trying to avoid ABI breakage of course.  I'd rather not have
> to ask people not to use _Atomic with 4.9 for CRIS ports using
> official releases or have ABI breakage with the next release.
> Maybe there's one other port in the same situation...

None I am aware of, but that doesn't mean much :-)
>> and on the branch that code instead looks something like:
>>
>> #define SET_ATOMIC_TYPE_NODE(TYPE, MODE, DEFAULT)               \
>>   (TYPE) = build_atomic_base (DEFAULT, targetm.atomic_align_for_mode (MODE));
>>
>>    SET_ATOMIC_TYPE_NODE (atomicQI_type_node, QImode, unsigned_intQI_type_node);
>> <...>
>>
>> which provides a target hook to override the default values and a target can
>> set them to whatever it deems necessary.
> Yah, that'd be nice.  Doesn't sound like more than the target
> hook and the patched lines above left for that to happen,
> though?  Or perhaps that's a too-naive assumption. I guess I
> should have a look.
>
That's all that is in theory needed, but it hasnt been tested very well.

>> There was insufficient time to test and fully flush this out, so it hasn't
>> made it into mainline.  Its only thanks to Josephs heroic efforts we have C11
>> :-)
>>
>> I don't think its a lot of code if you wanted to fool with it for your port.
> So, what would be needed in terms of testing and coding to get
> that part into 4.9?
>
>

If we add the hook for atomic_align_for_mode, and change the initalizers 
in tree.c, any target which doesnt need/use the hook should be 
unaffected. So everything remains as it is today.

So Putting the hook in shouldn't be an issue.  Then you can experiment 
with it on your port and see if you get the desired effect...

I've attached what I think the remaining bits are regarding the 
alignment.    All untested since I wrote it of course :-)  In any case,  
you should just need to provide a function to override the alignment for 
whatever mode(s)  you need with this...

I can bootstrap and check this on x86 to make sure it doesnt affect 
anything, and you can fool with it and see if you can get your desired 
results with your port.

Andrew



[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: align.patch --]
[-- Type: text/x-patch; name="align.patch", Size: 7205 bytes --]

Index: doc/tm.texi
===================================================================
*** doc/tm.texi	(revision 205220)
--- doc/tm.texi	(working copy)
*************** The support includes the assembler, link
*** 11500,11505 ****
--- 11500,11509 ----
  The default value of this hook is based on target's libc.
  @end deftypefn
  
+ @deftypefn {Target Hook} {unsigned int} TARGET_ATOMIC_ALIGN_FOR_MODE (enum machine_mode @var{mode})
+ If defined, this function returns an appropriate alignment in bits for an atomic object of machine_mode @var{mode}.  If 0 is returned then the default alignment for the specified mode is used. 
+ @end deftypefn
+ 
  @deftypefn {Target Hook} void TARGET_ATOMIC_ASSIGN_EXPAND_FENV (tree *@var{hold}, tree *@var{clear}, tree *@var{update})
  ISO C11 requires atomic compound assignments that may raise floating-point exceptions to raise exceptions corresponding to the arithmetic operation whose result was successfully stored in a compare-and-exchange sequence.  This requires code equivalent to calls to @code{feholdexcept}, @code{feclearexcept} and @code{feupdateenv} to be generated at appropriate points in the compare-and-exchange sequence.  This hook should set @code{*@var{hold}} to an expression equivalent to the call to @code{feholdexcept}, @code{*@var{clear}} to an expression equivalent to the call to @code{feclearexcept} and @code{*@var{update}} to an expression equivalent to the call to @code{feupdateenv}.  The three expressions are @code{NULL_TREE} on entry to the hook and may be left as @code{NULL_TREE} if no code is required in a particular place.  The default implementation leaves all three expressions as @code{NULL_TREE}.  The @code{__atomic_feraiseexcept} function from @code{libatomic} may be of use as part of the code generated in @code{*@var{update}}.
  @end deftypefn
Index: doc/tm.texi.in
===================================================================
*** doc/tm.texi.in	(revision 205220)
--- doc/tm.texi.in	(working copy)
*************** and the associated definitions of those
*** 8407,8410 ****
--- 8407,8412 ----
  
  @hook TARGET_HAS_IFUNC_P
  
+ @hook TARGET_ATOMIC_ALIGN_FOR_MODE
+ 
  @hook TARGET_ATOMIC_ASSIGN_EXPAND_FENV
Index: hooks.c
===================================================================
*** hooks.c	(revision 205220)
--- hooks.c	(working copy)
*************** hook_rtx_tree_int_null (tree a ATTRIBUTE
*** 358,363 ****
--- 358,370 ----
    return NULL;
  }
  
+ /* Generic hook that takes a machine mode and returns an unsigned int 0.  */
+ unsigned int
+ hook_uint_mode_0 (enum machine_mode m ATTRIBUTE_UNUSED)
+ {
+   return 0;
+ }
+ 
  /* Generic hook that takes three trees and returns the last one as is.  */
  tree
  hook_tree_tree_tree_tree_3rd_identity (tree a ATTRIBUTE_UNUSED,
Index: hooks.h
===================================================================
*** hooks.h	(revision 205220)
--- hooks.h	(working copy)
*************** extern tree hook_tree_tree_tree_tree_3rd
*** 92,97 ****
--- 92,98 ----
  extern tree hook_tree_tree_int_treep_bool_null (tree, int, tree *, bool);
  
  extern unsigned hook_uint_void_0 (void);
+ extern unsigned int hook_uint_mode_0 (enum machine_mode);
  
  extern bool default_can_output_mi_thunk_no_vcall (const_tree, HOST_WIDE_INT,
  						  HOST_WIDE_INT, const_tree);
Index: target.def
===================================================================
*** target.def	(revision 205220)
--- target.def	(working copy)
*************** DEFHOOKPOD
*** 5297,5302 ****
--- 5297,5313 ----
   @code{bool} @code{true}.",
   unsigned char, 1)
  
+ /* Return an unsigned int representing the alignment (in bits) of the atomic
+    type which maps to machine MODE.  This allows alignment to be overridden
+    as needed.  */
+ DEFHOOK
+ (atomic_align_for_mode,
+ "If defined, this function returns an appropriate alignment in bits for an\
+  atomic object of machine_mode @var{mode}.  If 0 is returned then the\
+  default alignment for the specified mode is used. ",
+  unsigned int, (enum machine_mode mode),
+  hook_uint_mode_0)
+ 
  DEFHOOK
  (atomic_assign_expand_fenv,
  "ISO C11 requires atomic compound assignments that may raise floating-point\
Index: tree.c
===================================================================
*** tree.c	(revision 205220)
--- tree.c	(working copy)
*************** make_or_reuse_accum_type (unsigned size,
*** 9547,9556 ****
     during initialization of data types to create the 5 basic atomic
     types. The generic build_variant_type function requires these to
     already be set up in order to function properly, so cannot be
!    called from there.  */
  
  static tree
! build_atomic_base (tree type)
  {
    tree t;
  
--- 9547,9557 ----
     during initialization of data types to create the 5 basic atomic
     types. The generic build_variant_type function requires these to
     already be set up in order to function properly, so cannot be
!    called from there.  If ALIGN is non-zero, then ensure alignment is
!    overridden to this value.  */
  
  static tree
! build_atomic_base (tree type, unsigned int align)
  {
    tree t;
  
*************** build_atomic_base (tree type)
*** 9561,9566 ****
--- 9562,9570 ----
    t = build_variant_type_copy (type);
    set_type_quals (t, TYPE_QUAL_ATOMIC);
  
+   if (align)
+     TYPE_ALIGN (t) = align;
+ 
    return t;
  }
  
*************** build_common_tree_nodes (bool signed_cha
*** 9648,9660 ****
  
    /* Don't call build_qualified type for atomics.  That routine does
       special processing for atomics, and until they are initialized
!      it's better not to make that call.  */
! 
!   atomicQI_type_node = build_atomic_base (unsigned_intQI_type_node);
!   atomicHI_type_node = build_atomic_base (unsigned_intHI_type_node);
!   atomicSI_type_node = build_atomic_base (unsigned_intSI_type_node);
!   atomicDI_type_node = build_atomic_base (unsigned_intDI_type_node);
!   atomicTI_type_node = build_atomic_base (unsigned_intTI_type_node);
  
    access_public_node = get_identifier ("public");
    access_protected_node = get_identifier ("protected");
--- 9652,9669 ----
  
    /* Don't call build_qualified type for atomics.  That routine does
       special processing for atomics, and until they are initialized
!      it's better not to make that call.
!      
!      Check to see if there is a target override for atomic types.  */
! 
! #define SET_ATOMIC_TYPE_NODE(TYPE, MODE, DEFAULT) 		\
!  (TYPE) = build_atomic_base (DEFAULT, targetm.atomic_align_for_mode (MODE));
! 
!   SET_ATOMIC_TYPE_NODE (atomicQI_type_node, QImode, unsigned_intQI_type_node);
!   SET_ATOMIC_TYPE_NODE (atomicHI_type_node, HImode, unsigned_intHI_type_node);
!   SET_ATOMIC_TYPE_NODE (atomicSI_type_node, SImode, unsigned_intSI_type_node);
!   SET_ATOMIC_TYPE_NODE (atomicDI_type_node, DImode, unsigned_intDI_type_node);
!   SET_ATOMIC_TYPE_NODE (atomicTI_type_node, TImode, unsigned_intTI_type_node);
  
    access_public_node = get_identifier ("public");
    access_protected_node = get_identifier ("protected");

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Implement C11 _Atomic
  2013-11-21 18:30       ` Andrew MacLeod
@ 2013-11-21 18:49         ` Joseph S. Myers
  2013-11-21 18:58           ` Andrew MacLeod
  2013-11-21 19:24         ` Hans-Peter Nilsson
  2013-11-22  2:57         ` Hans-Peter Nilsson
  2 siblings, 1 reply; 30+ messages in thread
From: Joseph S. Myers @ 2013-11-21 18:49 UTC (permalink / raw)
  To: Andrew MacLeod; +Cc: Hans-Peter Nilsson, gcc-patches

On Thu, 21 Nov 2013, Andrew MacLeod wrote:

> > I'm trying to avoid ABI breakage of course.  I'd rather not have
> > to ask people not to use _Atomic with 4.9 for CRIS ports using
> > official releases or have ABI breakage with the next release.
> > Maybe there's one other port in the same situation...
> 
> None I am aware of, but that doesn't mean much :-)

It has been suggested that hppa may have interesting issues for atomics - 
but I'd think atomics support for it in GCC would mainly be for GNU/Linux, 
where you have kernel helpers that may avoid the issues with the 
underlying architecture.

Note that if you want libstdc++ atomics to be ABI compatible with C 
atomics then there may be more work to do on that side (again, there are 
pieces on the branch).

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Implement C11 _Atomic
  2013-11-21 18:49         ` Joseph S. Myers
@ 2013-11-21 18:58           ` Andrew MacLeod
  0 siblings, 0 replies; 30+ messages in thread
From: Andrew MacLeod @ 2013-11-21 18:58 UTC (permalink / raw)
  To: Joseph S. Myers; +Cc: Hans-Peter Nilsson, gcc-patches

On 11/21/2013 11:32 AM, Joseph S. Myers wrote:
> On Thu, 21 Nov 2013, Andrew MacLeod wrote:
>
>>> I'm trying to avoid ABI breakage of course.  I'd rather not have
>>> to ask people not to use _Atomic with 4.9 for CRIS ports using
>>> official releases or have ABI breakage with the next release.
>>> Maybe there's one other port in the same situation...
>> None I am aware of, but that doesn't mean much :-)
> It has been suggested that hppa may have interesting issues for atomics -
> but I'd think atomics support for it in GCC would mainly be for GNU/Linux,
> where you have kernel helpers that may avoid the issues with the
> underlying architecture.
>
> Note that if you want libstdc++ atomics to be ABI compatible with C
> atomics then there may be more work to do on that side (again, there are
> pieces on the branch).
>
I was just about to point out that  :-)    that would be a 
shortcoming... 4.9 C++11 atomics do not use the same mechanism yet, so 
they would still behave the same as 4.8 C++ atomics, even with the 
override present.... C11 _Atomic variables would be the only beneficiary 
at this point of the override.

Andrew

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Implement C11 _Atomic
  2013-11-21 18:30       ` Andrew MacLeod
  2013-11-21 18:49         ` Joseph S. Myers
@ 2013-11-21 19:24         ` Hans-Peter Nilsson
  2013-11-22  2:57         ` Hans-Peter Nilsson
  2 siblings, 0 replies; 30+ messages in thread
From: Hans-Peter Nilsson @ 2013-11-21 19:24 UTC (permalink / raw)
  To: Andrew MacLeod; +Cc: Joseph S. Myers, gcc-patches

On Thu, 21 Nov 2013, Andrew MacLeod wrote:
> If we add the hook for atomic_align_for_mode, and change the initalizers in
> tree.c, any target which doesnt need/use the hook should be unaffected. So
> everything remains as it is today.
>
> So Putting the hook in shouldn't be an issue.  Then you can experiment with it
> on your port and see if you get the desired effect...
>
> I've attached what I think the remaining bits are regarding the alignment.

Right, that's about what I expected.  Nice.

Of course, I'd argue that a better default for the atomic
alignment is the max of the default alignment and the natural
alignment, since *you can't have atomic support without extra
machinery for misaligned data* - straddling a page or cache
boundary has dire consequences.

But then the patch would not have the nice property of
"obviously" being a NOP elsewhere.  Then again, where it isn't a
NOP, you have breakage anyway.  Bah.

> All untested since I wrote it of course :-)  In any case,  you should just
> need to provide a function to override the alignment for whatever mode(s)  you
> need with this...
>
> I can bootstrap and check this on x86 to make sure it doesnt affect anything,
> and you can fool with it and see if you can get your desired results with your
> port.

Thanks!  I'll play with it and get back.

brgds, H-P

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Implement C11 _Atomic
  2013-11-21 18:30       ` Andrew MacLeod
  2013-11-21 18:49         ` Joseph S. Myers
  2013-11-21 19:24         ` Hans-Peter Nilsson
@ 2013-11-22  2:57         ` Hans-Peter Nilsson
  2013-11-22  3:03           ` Andrew MacLeod
  2013-11-22  3:32           ` Hans-Peter Nilsson
  2 siblings, 2 replies; 30+ messages in thread
From: Hans-Peter Nilsson @ 2013-11-22  2:57 UTC (permalink / raw)
  To: Andrew MacLeod; +Cc: Joseph S. Myers, gcc-patches

[-- Attachment #1: Type: TEXT/PLAIN, Size: 737 bytes --]

On Thu, 21 Nov 2013, Andrew MacLeod wrote:
> I can bootstrap and check this on x86 to make sure it doesnt affect anything,
> and you can fool with it and see if you can get your desired results with your
> port.

Success!

For the record, tested together with the attached patch for the
CRIS ports, both regularly (not finished, but done with the C
testsuite part and no regressions there), as well as manually
for the attached test-programs, compiling and inspecting output
for different sub-targets and checking that data layout,
alignment and size is as intended.

Too bad about the libstdc++ atomics, but with this/these patches
at least I'll be able to tell people that _Atomic for C11 works.

Thanks to the both of you!

brgds, H-P

[-- Attachment #2: Type: TEXT/PLAIN, Size: 1377 bytes --]

Index: config/cris/cris.c
===================================================================
--- config/cris/cris.c	(revision 205225)
+++ config/cris/cris.c	(working copy)
@@ -93,6 +93,8 @@ static int cris_reg_overlap_mentioned_p 
 static enum machine_mode cris_promote_function_mode (const_tree, enum machine_mode,
 						     int *, const_tree, int);
 
+static unsigned int cris_atomic_align_for_mode (enum machine_mode);
+
 static void cris_print_base (rtx, FILE *);
 
 static void cris_print_index (rtx, FILE *);
@@ -227,6 +229,9 @@ int cris_cpu_version = CRIS_DEFAULT_CPU_
 #undef TARGET_PROMOTE_FUNCTION_MODE
 #define TARGET_PROMOTE_FUNCTION_MODE cris_promote_function_mode
 
+#undef TARGET_ATOMIC_ALIGN_FOR_MODE
+#define TARGET_ATOMIC_ALIGN_FOR_MODE cris_atomic_align_for_mode
+
 #undef TARGET_STRUCT_VALUE_RTX
 #define TARGET_STRUCT_VALUE_RTX cris_struct_value_rtx
 #undef TARGET_SETUP_INCOMING_VARARGS
@@ -4018,6 +4023,14 @@ cris_promote_function_mode (const_tree t
     return mode;
   return CRIS_PROMOTED_MODE (mode, *punsignedp, type);
 } 
+
+/* Atomic types require alignment to be at least the "natural" size. */
+
+static unsigned int
+cris_atomic_align_for_mode (enum machine_mode mode)
+{
+  return GET_MODE_BITSIZE (mode);
+}
 
 /* Let's assume all functions return in r[CRIS_FIRST_ARG_REG] for the
    time being.  */

[-- Attachment #3: Type: TEXT/PLAIN, Size: 1731 bytes --]

struct r0 {
  char a;
  int b;
};

struct l0 {
  char a;
  int b __attribute__((__aligned__(4)));
};

struct a0 {
  char a;
  _Atomic int b;
};

#define test(name, cond) typedef int test_ ## name [-!(cond)]

struct a0 ag;
struct l0 lg;
struct r0 rg;

struct a0 ai = {0, 1};
struct l0 li = {1, 2};
struct r0 ri = {2, 3};

extern struct a0 ae;
extern struct l0 le;
extern struct r0 re;

void foo(void)
{
  struct a0 al;
  struct l0 ll;
  struct r0 rl;
  test(a_al_ge_4, __alignof__(al) >= 4);
  test(a_al_ge_ll, __alignof__(al) >= __alignof__(ll));
  test(a_al_ge_rl, __alignof__(al) >= __alignof__(rl));
  test(a_ag_ge_4, __alignof__(ag) >= 4);
  test(a_ag_ge_lg, __alignof__(ag) >= __alignof__(lg));
  test(a_ag_ge_rg, __alignof__(ag) >= __alignof__(rg));
  test(a_ai_ge_4, __alignof__(ai) >= 4);
  test(a_ai_ge_li, __alignof__(ai) >= __alignof__(li));
  test(a_ai_ge_ri, __alignof__(ai) >= __alignof__(ri));
  test(a_ae_ge_4, __alignof__(ae) >= 4);
  test(a_ae_ge_le, __alignof__(ae) >= __alignof__(le));
  test(a_ae_ge_re, __alignof__(ae) >= __alignof__(re));

  test(s_al_ge_4, sizeof(al) >= 8);
  test(s_al_ge_ll, sizeof(al) >= sizeof(ll));
  test(s_al_ge_rl, sizeof(al) >= sizeof(rl));
  test(s_ag_ge_4, sizeof(ag) >= 8);
  test(s_ag_ge_lg, sizeof(ag) >= sizeof(lg));
  test(s_ag_ge_rg, sizeof(ag) >= sizeof(rg));
  test(s_ai_ge_4, sizeof(ai) >= 8);
  test(s_ai_ge_lg, sizeof(ai) >= sizeof(li));
  test(s_ai_ge_rg, sizeof(ai) >= sizeof(ri));
  test(s_ae_ge_4, sizeof(ae) >= 8);
  test(s_ae_ge_le, sizeof(ae) >= sizeof(le));
  test(s_ae_ge_re, sizeof(ae) >= sizeof(re));

  test(ab_eq_4, __builtin_offsetof(struct a0, b) == 4);
  al = ai;
  al.b++;
  ae = al;
}

[-- Attachment #4: Type: TEXT/PLAIN, Size: 311 bytes --]

_Atomic int foo;
int bar;
void baz(void)
{
  foo++;
}
void foobar(void)
{
  bar++;
}

void xyzzy(int *x)
{
  (*x)++;
}

void plugh(_Atomic int *x)
{
  (*x)++;
}

void xyzzy1(int *x)
{
  int y = *x;
  *x = y+1;
}

void plugh2(_Atomic int *x)
{
  _Atomic int y = *x;
  *x = y+1;
}

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Implement C11 _Atomic
  2013-11-22  2:57         ` Hans-Peter Nilsson
@ 2013-11-22  3:03           ` Andrew MacLeod
  2013-11-22  3:32           ` Hans-Peter Nilsson
  1 sibling, 0 replies; 30+ messages in thread
From: Andrew MacLeod @ 2013-11-22  3:03 UTC (permalink / raw)
  To: Hans-Peter Nilsson; +Cc: Joseph S. Myers, gcc-patches

On 11/21/2013 06:23 PM, Hans-Peter Nilsson wrote:
> On Thu, 21 Nov 2013, Andrew MacLeod wrote:
>> I can bootstrap and check this on x86 to make sure it doesnt affect anything,
>> and you can fool with it and see if you can get your desired results with your
>> port.
> Success!
>
> For the record, tested together with the attached patch for the
> CRIS ports, both regularly (not finished, but done with the C
> testsuite part and no regressions there), as well as manually
> for the attached test-programs, compiling and inspecting output
> for different sub-targets and checking that data layout,
> alignment and size is as intended.
>
> Too bad about the libstdc++ atomics, but with this/these patches
> at least I'll be able to tell people that _Atomic for C11 works.
>
> Thanks to the both of you!
>
>
All we need is a way to communicate the atomic property to the type 
within the libstdc++ template...  We cant use _Atomic there :-P

  I originally had created an __attribute__ ((atomic)) whch you could 
apply to the atomic template type and get the same behaviour  as 
_Atomic, Im not sure if there is another way or not.  The atomic 
template is generic, so I couldn't think of any special macro wizardry 
we could define...

Andrew

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Implement C11 _Atomic
  2013-11-22  2:57         ` Hans-Peter Nilsson
  2013-11-22  3:03           ` Andrew MacLeod
@ 2013-11-22  3:32           ` Hans-Peter Nilsson
  2013-11-22  3:32             ` Joseph S. Myers
  2013-11-22 19:12             ` Andrew MacLeod
  1 sibling, 2 replies; 30+ messages in thread
From: Hans-Peter Nilsson @ 2013-11-22  3:32 UTC (permalink / raw)
  To: Andrew MacLeod; +Cc: Joseph S. Myers, gcc-patches

On Thu, 21 Nov 2013, Hans-Peter Nilsson wrote:
> with this/these patches
> at least I'll be able to tell people that _Atomic for C11 works.

Oh right, gcc still doesn't remove target-introduced "manual"
alignment checks (when expanding atomic intrinsics), but at
least gcc makes sure it's aligned on stack, when options doesn't
say it's aligned.  And a.c:plugh2 doesn't seem to perform an
atomic assignment, but just assignment through an
_Atomic-aligned stack temporary.  Might be my C11-ignorance
showing.

(Without the patches layout and alignment is all broken.)

brgds, H-P

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Implement C11 _Atomic
  2013-11-22  3:32           ` Hans-Peter Nilsson
@ 2013-11-22  3:32             ` Joseph S. Myers
  2013-11-22 19:12             ` Andrew MacLeod
  1 sibling, 0 replies; 30+ messages in thread
From: Joseph S. Myers @ 2013-11-22  3:32 UTC (permalink / raw)
  To: Hans-Peter Nilsson; +Cc: Andrew MacLeod, gcc-patches

On Thu, 21 Nov 2013, Hans-Peter Nilsson wrote:

> Oh right, gcc still doesn't remove target-introduced "manual"
> alignment checks (when expanding atomic intrinsics), but at
> least gcc makes sure it's aligned on stack, when options doesn't
> say it's aligned.  And a.c:plugh2 doesn't seem to perform an
> atomic assignment, but just assignment through an
> _Atomic-aligned stack temporary.  Might be my C11-ignorance
> showing.

It appears to me on x86_64 to produce an __atomic_store_4 to *x (in the 
GIMPLE dumps, what happens after that is a matter for the back end).

Note that atomic variable initialization is *not* atomic (see 7.17.2.1 - 
in general ATOMIC_VAR_INIT needs using with the initializer, or the 
initialization needs to be carried out with atomic_init, though GCC 
doesn't require that).  (In C11, the effect of a plain initialization 
without ATOMIC_VAR_INIT is I think that the initializer is evaluated for 
its side effects, but if the variable gets used as either rvalue or lvalue 
without one of the special forms of initialization being used first then 
the behavior is undefined.  The idea is to support implementations with 
extra bits in atomic objects used for locking purposes.)  So no atomic 
store to y is expected - although there are atomic loads from y.

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Implement C11 _Atomic
  2013-11-22  3:32           ` Hans-Peter Nilsson
  2013-11-22  3:32             ` Joseph S. Myers
@ 2013-11-22 19:12             ` Andrew MacLeod
  2013-11-22 20:01               ` Hans-Peter Nilsson
  1 sibling, 1 reply; 30+ messages in thread
From: Andrew MacLeod @ 2013-11-22 19:12 UTC (permalink / raw)
  To: Hans-Peter Nilsson; +Cc: Joseph S. Myers, gcc-patches

On 11/21/2013 06:40 PM, Hans-Peter Nilsson wrote:
> On Thu, 21 Nov 2013, Hans-Peter Nilsson wrote:
>> with this/these patches
>> at least I'll be able to tell people that _Atomic for C11 works.
> Oh right, gcc still doesn't remove target-introduced "manual"
> alignment checks (when expanding atomic intrinsics), but at
> least gcc makes sure it's aligned on stack, when options doesn't
> say it's aligned.  And a.c:plugh2 doesn't seem to perform an
> atomic assignment, but just assignment through an
> _Atomic-aligned stack temporary.  Might be my C11-ignorance
> showing.
>
> (Without the patches layout and alignment is all broken.)
>
> brgds, H-P
The target hook patch is checked into mainline, revision 205273.

Andrew

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Implement C11 _Atomic
  2013-11-22 19:12             ` Andrew MacLeod
@ 2013-11-22 20:01               ` Hans-Peter Nilsson
  0 siblings, 0 replies; 30+ messages in thread
From: Hans-Peter Nilsson @ 2013-11-22 20:01 UTC (permalink / raw)
  To: gcc-patches

On Fri, 22 Nov 2013, Andrew MacLeod wrote:
> The target hook patch is checked into mainline, revision 205273.

Thanks!

The target patch is there too now; tested with the previous
version of the hook-patch.  I'm confident my autotester will
yell at me if I goofed.

gcc:
	* config/cris/cris.c (cris_atomic_align_for_mode): New function.
	(TARGET_ATOMIC_ALIGN_FOR_MODE): Define.

Index: config/cris/cris.c
===================================================================
--- config/cris/cris.c	(revision 205225)
+++ config/cris/cris.c	(working copy)
@@ -93,6 +93,8 @@ static int cris_reg_overlap_mentioned_p
 static enum machine_mode cris_promote_function_mode (const_tree, enum machine_mode,
 						     int *, const_tree, int);

+static unsigned int cris_atomic_align_for_mode (enum machine_mode);
+
 static void cris_print_base (rtx, FILE *);

 static void cris_print_index (rtx, FILE *);
@@ -227,6 +229,9 @@ int cris_cpu_version = CRIS_DEFAULT_CPU_
 #undef TARGET_PROMOTE_FUNCTION_MODE
 #define TARGET_PROMOTE_FUNCTION_MODE cris_promote_function_mode

+#undef TARGET_ATOMIC_ALIGN_FOR_MODE
+#define TARGET_ATOMIC_ALIGN_FOR_MODE cris_atomic_align_for_mode
+
 #undef TARGET_STRUCT_VALUE_RTX
 #define TARGET_STRUCT_VALUE_RTX cris_struct_value_rtx
 #undef TARGET_SETUP_INCOMING_VARARGS
@@ -4018,6 +4023,14 @@ cris_promote_function_mode (const_tree t
     return mode;
   return CRIS_PROMOTED_MODE (mode, *punsignedp, type);
 }
+
+/* Atomic types require alignment to be at least their "natural" size.  */
+
+static unsigned int
+cris_atomic_align_for_mode (enum machine_mode mode)
+{
+  return GET_MODE_BITSIZE (mode);
+}

 /* Let's assume all functions return in r[CRIS_FIRST_ARG_REG] for the
    time being.  */

brgds, H-P

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Implement C11 _Atomic
  2013-11-08 13:34 ` Joseph S. Myers
@ 2013-11-08 13:43   ` Dominique Dhumieres
  0 siblings, 0 replies; 30+ messages in thread
From: Dominique Dhumieres @ 2013-11-08 13:43 UTC (permalink / raw)
  To: joseph, dominiq; +Cc: rth, gcc-patches, amacleod

> I doubt the patch affects Fortran (there are language-independent changes,
> but they are fairly small and shouldn't affect code not using _Atomic 
> qualifiers).

The Fortran failures seem related to revision 204538.

Dominique

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Implement C11 _Atomic
  2013-11-08 13:28 Dominique Dhumieres
@ 2013-11-08 13:34 ` Joseph S. Myers
  2013-11-08 13:43   ` Dominique Dhumieres
  0 siblings, 1 reply; 30+ messages in thread
From: Joseph S. Myers @ 2013-11-08 13:34 UTC (permalink / raw)
  To: Dominique Dhumieres; +Cc: gcc-patches, rth, amacleod

On Fri, 8 Nov 2013, Dominique Dhumieres wrote:

> This revision may also causes the failures of
> gfortran.dg/typebound_operator_9.f03 and 
> FAIL: gfortran.fortran-torture/execute/forall_1.f90.

I doubt the patch affects Fortran (there are language-independent changes, 
but they are fairly small and shouldn't affect code not using _Atomic 
qualifiers).

> Undefined symbols for architecture i386:
>   "___atomic_compare_exchange_16", referenced from:

>   "___atomic_load_16", referenced from:

Either those functions should be in libatomic (using locking where 
necessary), or the built-in functions should be expanding to use the 
size-generic libatomic function rather than the _16 one.  Richard or 
Andrew should be able to advise on which the design was for systems that 
don't have lock-free atomics for all of the standard sizes (1, 2, 4, 8, 
16).

My guess is that it would be hard to provide the _16 functions in 
libatomic when TImode types aren't supported, and so the bug is that _16 
function calls are generated when not supported.  That is, c-common.c 
functions resolve_overloaded_atomic_exchange, 
resolve_overloaded_atomic_compare_exchange, 
resolve_overloaded_atomic_load, resolve_overloaded_atomic_store, where 
they check n != 16, should do something like (n != 16 || 
!targetm.scalar_mode_supported_p (TImode)).  (Better, refactor the (n != 1 
&& n != 2 && n != 4 && n != 8 && n != 16) into an atomic_size_supported_p 
or similar function.)

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Implement C11 _Atomic
@ 2013-11-08 13:28 Dominique Dhumieres
  2013-11-08 13:34 ` Joseph S. Myers
  0 siblings, 1 reply; 30+ messages in thread
From: Dominique Dhumieres @ 2013-11-08 13:28 UTC (permalink / raw)
  To: gcc-patches; +Cc: joseph

The tests introduced in revision 204544 fail with -m32
(see http://gcc.gnu.org/ml/gcc-regression/2013-11/msg00213.html
or http://gcc.gnu.org/ml/gcc-testresults/2013-11/msg00526.html ).
This revision may also causes the failures of
gfortran.dg/typebound_operator_9.f03 and 
FAIL: gfortran.fortran-torture/execute/forall_1.f90.

On x86_64-apple-darwin* typebound_operator_9.f03 gives the following ICE with -O3

/opt/gcc/work/gcc/testsuite/gfortran.dg/typebound_operator_9.f03: In function 'nabla2_cart2d':
/opt/gcc/work/gcc/testsuite/gfortran.dg/typebound_operator_9.f03:272:0: internal compiler error: tree check: expected integer_cst, have plus_expr in tree_int_cst_lt, at tree.c:7083
   function nabla2_cart2d (obj)

and the failures of c11-atomic-exec-*.exe are of the kind

Executing on host: /opt/gcc/build_w/gcc/xgcc -B/opt/gcc/build_w/gcc/ /opt/gcc/work/gcc/testsuite/gcc.dg/atomic/c11-atomic-exec-4.c   -B/opt/gcc/build_w/x86_64-apple-darwin13.0.0/i386/libatomic/  -L/opt/gcc/build_w/x86_64-apple-darwin13.0.0/i386/libatomic/.libs -latomic  -fno-diagnostics-show-caret -fdiagnostics-color=never   -Os  -std=c11 -pedantic-errors -pthread -D_POSIX_C_SOURCE=200809L  -lm   -m32 -o ./c11-atomic-exec-4.exe    (timeout = 300)
spawn /opt/gcc/build_w/gcc/xgcc -B/opt/gcc/build_w/gcc/ /opt/gcc/work/gcc/testsuite/gcc.dg/atomic/c11-atomic-exec-4.c -B/opt/gcc/build_w/x86_64-apple-darwin13.0.0/i386/libatomic/ -L/opt/gcc/build_w/x86_64-apple-darwin13.0.0/i386/libatomic/.libs -latomic -fno-diagnostics-show-caret -fdiagnostics-color=never -Os -std=c11 -pedantic-errors -pthread -D_POSIX_C_SOURCE=200809L -lm -m32 -o ./c11-atomic-exec-4.exe
Undefined symbols for architecture i386:
  "___atomic_compare_exchange_16", referenced from:
      _test_main_long_double_add in ccBbKO9A.o
      _test_thread_long_double_add in ccBbKO9A.o
      _test_main_complex_double_add in ccBbKO9A.o
      _test_thread_complex_double_add in ccBbKO9A.o
      _test_main_long_double_postinc in ccBbKO9A.o
      _test_thread_long_double_postinc in ccBbKO9A.o
      _test_main_long_double_preinc in ccBbKO9A.o
      ...^M
  "___atomic_load_16", referenced from:
      _test_main_long_double_add in ccBbKO9A.o
      _test_thread_long_double_add in ccBbKO9A.o
      _test_main_complex_double_add in ccBbKO9A.o
      _test_thread_complex_double_add in ccBbKO9A.o
      _test_main_long_double_postinc in ccBbKO9A.o
      _test_thread_long_double_postinc in ccBbKO9A.o
      _test_main_long_double_preinc in ccBbKO9A.o
      ...^M
ld: symbol(s) not found for architecture i386

Dominique

^ permalink raw reply	[flat|nested] 30+ messages in thread

end of thread, other threads:[~2013-11-22 16:47 UTC | newest]

Thread overview: 30+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-11-06  0:44 Implement C11 _Atomic Joseph S. Myers
2013-11-06 22:42 ` Andrew MacLeod
2013-11-07 17:16 ` Uros Bizjak
2013-11-07 17:24 ` Jakub Jelinek
2013-11-07 18:10   ` Uros Bizjak
2013-11-07 18:44     ` Joseph S. Myers
2013-11-07 18:47       ` Uros Bizjak
2013-11-07 18:55         ` Joseph S. Myers
     [not found]           ` <CAFULd4ZrAEECG+pptH8cRaWznioaM9VXS4TetpEvkWj--n7H1w@mail.gmail.com>
2013-11-07 21:02             ` Joseph S. Myers
2013-11-07 21:08               ` Uros Bizjak
2013-11-07 22:25                 ` Uros Bizjak
2013-11-07 22:43                   ` Joseph S. Myers
2013-11-08 10:09       ` Uros Bizjak
2013-11-08 13:33         ` Joseph S. Myers
2013-11-21 13:19 ` Hans-Peter Nilsson
2013-11-21 18:03   ` Andrew MacLeod
2013-11-21 18:20     ` Hans-Peter Nilsson
2013-11-21 18:30       ` Andrew MacLeod
2013-11-21 18:49         ` Joseph S. Myers
2013-11-21 18:58           ` Andrew MacLeod
2013-11-21 19:24         ` Hans-Peter Nilsson
2013-11-22  2:57         ` Hans-Peter Nilsson
2013-11-22  3:03           ` Andrew MacLeod
2013-11-22  3:32           ` Hans-Peter Nilsson
2013-11-22  3:32             ` Joseph S. Myers
2013-11-22 19:12             ` Andrew MacLeod
2013-11-22 20:01               ` Hans-Peter Nilsson
2013-11-08 13:28 Dominique Dhumieres
2013-11-08 13:34 ` Joseph S. Myers
2013-11-08 13:43   ` Dominique Dhumieres

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