diff mbox

Implement C11 _Atomic

Message ID Pine.LNX.4.64.1311052316480.30260@digraph.polyomino.org.uk
State New
Headers show

Commit Message

Joseph Myers Nov. 5, 2013, 11:21 p.m. UTC
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.

Comments

Andrew MacLeod Nov. 6, 2013, 10:32 p.m. UTC | #1
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
Uros Bizjak Nov. 7, 2013, 4:40 p.m. UTC | #2
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.
Jakub Jelinek Nov. 7, 2013, 4:45 p.m. UTC | #3
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
Uros Bizjak Nov. 7, 2013, 6:05 p.m. UTC | #4
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.
Joseph Myers Nov. 7, 2013, 6:26 p.m. UTC | #5
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.
Uros Bizjak Nov. 7, 2013, 6:36 p.m. UTC | #6
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.
Joseph Myers Nov. 7, 2013, 6:44 p.m. UTC | #7
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 Myers Nov. 7, 2013, 8:33 p.m. UTC | #8
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.
Uros Bizjak Nov. 7, 2013, 8:55 p.m. UTC | #9
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.
Uros Bizjak Nov. 7, 2013, 9:26 p.m. UTC | #10
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.
Joseph Myers Nov. 7, 2013, 9:40 p.m. UTC | #11
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.)
Uros Bizjak Nov. 8, 2013, 9:44 a.m. UTC | #12
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.
Joseph Myers Nov. 8, 2013, 1:13 p.m. UTC | #13
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).
Hans-Peter Nilsson Nov. 21, 2013, 11:05 a.m. UTC | #14
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
Andrew MacLeod Nov. 21, 2013, 2:43 p.m. UTC | #15
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
Hans-Peter Nilsson Nov. 21, 2013, 3:20 p.m. UTC | #16
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
diff mbox

Patch

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);
 }
 
+/* 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"]
+}