gcc:
authorjsm28 <jsm28@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 7 Nov 2013 21:15:25 +0000 (21:15 +0000)
committerjsm28 <jsm28@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 7 Nov 2013 21:15:25 +0000 (21:15 +0000)
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.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@204544 138bc75d-0d04-0410-961f-82ee72b054a4

50 files changed:
gcc/ChangeLog
gcc/c-family/ChangeLog
gcc/c-family/c-common.c
gcc/c-family/c-common.h
gcc/c-family/c-format.c
gcc/c-family/c-pretty-print.c
gcc/c/ChangeLog
gcc/c/c-aux-info.c
gcc/c/c-decl.c
gcc/c/c-parser.c
gcc/c/c-tree.h
gcc/c/c-typeck.c
gcc/config/i386/i386-builtin-types.def
gcc/config/i386/i386.c
gcc/config/i386/i386.md
gcc/doc/tm.texi
gcc/doc/tm.texi.in
gcc/objc/ChangeLog
gcc/objc/objc-act.c
gcc/print-tree.c
gcc/sync-builtins.def
gcc/target.def
gcc/targhooks.c
gcc/targhooks.h
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/atomic/atomic.exp [new file with mode: 0644]
gcc/testsuite/gcc.dg/atomic/c11-atomic-exec-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/atomic/c11-atomic-exec-2.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/atomic/c11-atomic-exec-3.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/atomic/c11-atomic-exec-4.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/atomic/c11-atomic-exec-5.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/c11-atomic-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/c11-atomic-2.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/c11-atomic-3.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/c90-atomic-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/c99-atomic-1.c [new file with mode: 0644]
gcc/testsuite/lib/atomic-dg.exp [new file with mode: 0644]
gcc/testsuite/lib/target-supports.exp
gcc/tree-core.h
gcc/tree-pretty-print.c
gcc/tree.c
gcc/tree.h
libatomic/ChangeLog
libatomic/Makefile.am
libatomic/Makefile.in
libatomic/auto-config.h.in
libatomic/configure
libatomic/configure.ac
libatomic/fenv.c [new file with mode: 0644]
libatomic/libatomic.map

index e59e37a..23cf4ec 100644 (file)
@@ -1,3 +1,48 @@
+2013-11-07  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.
+
 2013-11-07  Steve Ellcey  <sellcey@mips.com>
 
        * config/mips/mti-linux.h (SYSROOT_SUFFIX_SPEC): Add fp64 directory.
index 4a4e061..4ff4310 100644 (file)
@@ -1,3 +1,15 @@
+2013-11-07  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.
+
 2013-11-06  Tobias Burnus  <burnus@net-b.de>
 
        * c-common.c (reason_option_codes_t): Add CPP_W_DATE_TIME.
index 69a068e..e237926 100644 (file)
@@ -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 },
@@ -10172,6 +10173,7 @@ sync_resolve_params (location_t loc, tree orig_function, tree function,
      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.  */
@@ -11568,6 +11570,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 8dd40c8..74fd59f 100644 (file)
@@ -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 f0371d3..99cae17 100644 (file)
@@ -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 d0283e8..652c3a8 100644 (file)
@@ -179,8 +179,16 @@ pp_c_cv_qualifiers (c_pretty_printer *pp, int qualifiers, bool func_type)
   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 *pp, tree t)
        __restrict__                          -- GNU C
        address-space-qualifier              -- GNU C
        volatile
+       _Atomic                               -- C11
 
    address-space-qualifier:
        identifier                           -- GNU C  */
index cc335e4..e38bcb8 100644 (file)
@@ -1,3 +1,72 @@
+2013-11-07  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.
+
 2013-11-06  DJ Delorie  <dj@redhat.com>
 
        * c-decl.c (locate_old_decl): If a previous conflicting decl is
index dd9c768..823a3c4 100644 (file)
@@ -285,6 +285,8 @@ gen_type (const char *ret_val, tree t, formals_style style)
       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_style style)
          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 23f0516..9520e4d 100644 (file)
@@ -1584,8 +1584,14 @@ validate_proto_after_old_defn (tree newdecl, tree newtype, tree oldtype)
       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;
@@ -3715,6 +3721,7 @@ shadow_tag_warned (const struct c_declspecs *declspecs, int warned)
                    && declspecs->typespec_kind != ctsk_tagfirstref
                   && (declspecs->const_p
                       || declspecs->volatile_p
+                      || declspecs->atomic_p
                       || declspecs->restrict_p
                       || declspecs->address_space))
            {
@@ -3804,6 +3811,7 @@ shadow_tag_warned (const struct c_declspecs *declspecs, int warned)
 
   if (!warned && !in_system_header && (declspecs->const_p
                                       || declspecs->volatile_p
+                                      || declspecs->atomic_p
                                       || declspecs->restrict_p
                                       || declspecs->address_space))
     {
@@ -3835,6 +3843,7 @@ quals_from_declspecs (const struct c_declspecs *specs)
   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
@@ -4170,7 +4179,7 @@ start_decl (struct c_declarator *declarator, struct c_declspecs *declspecs,
              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);
            }
        }
     }
@@ -4943,6 +4952,7 @@ grokdeclarator (const struct c_declarator *declarator,
   int constp;
   int restrictp;
   int volatilep;
+  int atomicp;
   int type_quals = TYPE_UNQUALIFIED;
   tree name = NULL_TREE;
   bool funcdef_flag = false;
@@ -5097,6 +5107,7 @@ grokdeclarator (const struct c_declarator *declarator,
   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;
@@ -5109,6 +5120,9 @@ grokdeclarator (const struct c_declarator *declarator,
        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)
@@ -5122,8 +5136,16 @@ grokdeclarator (const struct c_declarator *declarator,
   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.).  */
 
@@ -5699,9 +5721,15 @@ grokdeclarator (const struct c_declarator *declarator,
          {
            /* 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)
@@ -5815,7 +5843,20 @@ grokdeclarator (const struct c_declarator *declarator,
 
   /* 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)
@@ -5878,8 +5919,15 @@ grokdeclarator (const struct c_declarator *declarator,
   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)
@@ -5924,8 +5972,15 @@ grokdeclarator (const struct c_declarator *declarator,
         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)
@@ -5991,7 +6046,13 @@ grokdeclarator (const struct c_declarator *declarator,
          }
        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)
@@ -6086,7 +6147,13 @@ grokdeclarator (const struct c_declarator *declarator,
                           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");
 
@@ -6459,8 +6526,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");
 
@@ -8213,11 +8279,15 @@ store_parm_decls_oldstyle (tree fndecl, const struct c_arg_info *arg_info)
             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
@@ -8230,7 +8300,8 @@ store_parm_decls_oldstyle (tree fndecl, const struct c_arg_info *arg_info)
                      && 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
@@ -8432,7 +8503,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);
        }
     }
 
@@ -8911,6 +8982,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;
@@ -8972,6 +9044,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 4ae30c3..09cce1c 100644 (file)
@@ -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_parser *parser)
      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_parser *parser)
      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_parser *parser)
   (_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_declspecs *specs,
          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, bool id_present,
       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, bool id_present,
       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, bool id_present,
            {
              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, bool id_present,
                                     "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 * braced_init_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 *after,
       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 ivdep)
        {
        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 ivdep)
              }
            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 ivdep)
            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_expr *after,
   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, struct c_expr *after,
   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, struct c_expr *after,
   {
     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, struct c_expr *after,
        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, struct c_expr *after,
        {
        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, struct c_expr *after,
          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 c_expr *after)
       {
        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_parser *parser,
        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_parser *parser,
 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_p, bool fold_p,
     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_p, bool fold_p,
        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 *parser)
   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 *parser)
        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 *parser, tree initial_index,
              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 *parser, tree initial_index,
          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 2565ccb..8dffa9c 100644 (file)
@@ -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_conversion (location_t,
                                                        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 8f1d3a4..5ef1f93 100644 (file)
@@ -265,18 +265,25 @@ c_incomplete_type_error (const_tree value, const_tree type)
 tree
 c_type_promotes_to (tree type)
 {
-  if (TYPE_MAIN_VARIANT (type) == float_type_node)
-    return double_type_node;
+  tree ret = NULL_TREE;
 
-  if (c_promoting_integer_type_p (type))
+  if (TYPE_MAIN_VARIANT (type) == float_type_node)
+    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, tree ttr)
   /* 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_tree args2,
       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_tree args2,
                  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_tree args2,
                  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 loc, struct c_expr exp)
   return default_function_array_conversion (loc, exp);
 }
 
+/* Return whether EXPR should be treated as an atomic lvalue for the
+   purposes of load and store handling.  */
+
+static bool
+really_atomic_lvalue (tree expr)
+{
+  if (expr == error_mark_node || TREE_TYPE (expr) == error_mark_node)
+    return false;
+  if (!TYPE_ATOMIC (TREE_TYPE (expr)))
+    return false;
+  if (!lvalue_p (expr))
+    return false;
+
+  /* Ignore _Atomic on register variables, since their addresses can't
+     be taken so (a) atomicity is irrelevant and (b) the normal atomic
+     sequences wouldn't work.  Ignore _Atomic on structures containing
+     bit-fields, since accessing elements of atomic structures or
+     unions is undefined behavior (C11 6.5.2.3#5), but it's unclear if
+     it's undefined at translation time or execution time, and the
+     normal atomic sequences again wouldn't work.  */
+  while (handled_component_p (expr))
+    {
+      if (TREE_CODE (expr) == COMPONENT_REF
+         && DECL_C_BIT_FIELD (TREE_OPERAND (expr, 1)))
+       return false;
+      expr = TREE_OPERAND (expr, 0);
+    }
+  if (DECL_P (expr) && C_DECL_REGISTER (expr))
+    return false;
+  return true;
+}
+
+/* Convert expression EXP (location LOC) from lvalue to rvalue,
+   including converting functions and arrays to pointers if CONVERT_P.
+   If READ_P, also mark the expression as having been read.  */
+
+struct c_expr
+convert_lvalue_to_rvalue (location_t loc, struct c_expr exp,
+                         bool convert_p, bool read_p)
+{
+  if (read_p)
+    mark_exp_read (exp.value);
+  if (convert_p)
+    exp = default_function_array_conversion (loc, exp);
+  if (really_atomic_lvalue (exp.value))
+    {
+      vec<tree, va_gc> *params;
+      tree nonatomic_type, tmp, tmp_addr, fndecl, func_call;
+      tree expr_type = TREE_TYPE (exp.value);
+      tree expr_addr = build_unary_op (loc, ADDR_EXPR, exp.value, 0);
+      tree seq_cst = build_int_cst (integer_type_node, MEMMODEL_SEQ_CST);
+
+      gcc_assert (TYPE_ATOMIC (expr_type));
+
+      /* Expansion of a generic atomic load may require an addition
+        element, so allocate enough to prevent a resize.  */
+      vec_alloc (params, 4);
+
+      /* Remove the qualifiers for the rest of the expressions and
+        create the VAL temp variable to hold the RHS.  */
+      nonatomic_type = build_qualified_type (expr_type, TYPE_UNQUALIFIED);
+      tmp = create_tmp_var (nonatomic_type, NULL);
+      tmp_addr = build_unary_op (loc, ADDR_EXPR, tmp, 0);
+      TREE_ADDRESSABLE (tmp) = 1;
+
+      /* Issue __atomic_load (&expr, &tmp, SEQ_CST);  */
+      fndecl = builtin_decl_explicit (BUILT_IN_ATOMIC_LOAD);
+      params->quick_push (expr_addr);
+      params->quick_push (tmp_addr);
+      params->quick_push (seq_cst);
+      func_call = build_function_call_vec (loc, fndecl, params, NULL);
+
+      /* Return tmp which contains the value loaded.  */
+      exp.value = build2 (COMPOUND_EXPR, nonatomic_type, func_call, tmp);
+    }
+  return exp;
+}
+
 /* EXP is an expression of integer type.  Apply the integer promotions
    to it and return the promoted value.  */
 
@@ -3435,6 +3536,215 @@ pointer_diff (location_t loc, tree op0, tree op1)
   return convert (restype, result);
 }
 \f
+/* Expand atomic compound assignments into an approriate sequence as
+   specified by the C11 standard section 6.5.16.2.   
+    given 
+       _Atomic T1 E1
+       T2 E2
+       E1 op= E2
+
+  This sequence is used for all types for which these operations are
+  supported.
+
+  In addition, built-in versions of the 'fe' prefixed routines may
+  need to be invoked for floating point (real, complex or vector) when
+  floating-point exceptions are supported.  See 6.5.16.2 footnote 113.
+
+  T1 newval;
+  T1 old;
+  T1 *addr
+  T2 val
+  fenv_t fenv
+
+  addr = &E1;
+  val = (E2);
+  __atomic_load (addr, &old, SEQ_CST);
+  feholdexcept (&fenv);
+loop:
+    newval = old op val;
+    if (__atomic_compare_exchange_strong (addr, &old, &newval, SEQ_CST,
+                                         SEQ_CST))
+      goto done;
+    feclearexcept (FE_ALL_EXCEPT);
+    goto loop:
+done:
+  feupdateenv (&fenv);
+
+  Also note that the compiler is simply issuing the generic form of
+  the atomic operations.  This requires temp(s) and has their address
+  taken.  The atomic processing is smart enough to figure out when the
+  size of an object can utilize a lock-free version, and convert the
+  built-in call to the appropriate lock-free routine.  The optimizers
+  will then dispose of any temps that are no longer required, and
+  lock-free implementations are utilized as long as there is target
+  support for the required size.
+
+  If the operator is NOP_EXPR, then this is a simple assignment, and
+  an __atomic_store is issued to perform the assignment rather than
+  the above loop.
+
+*/
+
+/* Build an atomic assignment at LOC, expanding into the proper
+   sequence to store LHS MODIFYCODE= RHS.  Return a value representing
+   the result of the operation, unless RETURN_OLD_P in which case
+   return the old value of LHS (this is only for postincrement and
+   postdecrement).  */
+static tree
+build_atomic_assign (location_t loc, tree lhs, enum tree_code modifycode,
+                    tree rhs, bool return_old_p)
+{
+  tree fndecl, func_call;
+  vec<tree, va_gc> *params;
+  tree val, nonatomic_lhs_type, nonatomic_rhs_type, newval, newval_addr;
+  tree old, old_addr;
+  tree compound_stmt;
+  tree stmt, goto_stmt;
+  tree loop_label, loop_decl, done_label, done_decl;
+
+  tree lhs_type = TREE_TYPE (lhs);
+  tree lhs_addr = build_unary_op (loc, ADDR_EXPR, lhs, 0);
+  tree seq_cst = build_int_cst (integer_type_node, MEMMODEL_SEQ_CST);
+  tree rhs_type = TREE_TYPE (rhs);
+
+  gcc_assert (TYPE_ATOMIC (lhs_type));
+
+  if (return_old_p)
+    gcc_assert (modifycode == PLUS_EXPR || modifycode == MINUS_EXPR);
+
+  /* Allocate enough vector items for a compare_exchange.  */
+  vec_alloc (params, 6);
+
+  /* Create a compound statement to hold the sequence of statements
+     with a loop.  */
+  compound_stmt = c_begin_compound_stmt (false);
+
+  /* Fold the RHS if it hasn't already been folded.  */
+  if (modifycode != NOP_EXPR)
+    rhs = c_fully_fold (rhs, false, NULL);
+
+  /* Remove the qualifiers for the rest of the expressions and create
+     the VAL temp variable to hold the RHS.  */
+  nonatomic_lhs_type = build_qualified_type (lhs_type, TYPE_UNQUALIFIED);
+  nonatomic_rhs_type = build_qualified_type (rhs_type, TYPE_UNQUALIFIED);
+  val = create_tmp_var (nonatomic_rhs_type, NULL);
+  TREE_ADDRESSABLE (val) = 1;
+  rhs = build2 (MODIFY_EXPR, nonatomic_rhs_type, val, rhs);
+  SET_EXPR_LOCATION (rhs, loc);
+  add_stmt (rhs);
+
+  /* NOP_EXPR indicates it's a straight store of the RHS. Simply issue
+     an atomic_store.  */
+  if (modifycode == NOP_EXPR)
+    {
+      /* Build __atomic_store (&lhs, &val, SEQ_CST)  */
+      rhs = build_unary_op (loc, ADDR_EXPR, val, 0);
+      fndecl = builtin_decl_explicit (BUILT_IN_ATOMIC_STORE);
+      params->quick_push (lhs_addr);
+      params->quick_push (rhs);
+      params->quick_push (seq_cst);
+      func_call = build_function_call_vec (loc, fndecl, params, NULL);
+      add_stmt (func_call);
+
+      /* Finish the compound statement.  */
+      compound_stmt = c_end_compound_stmt (loc, compound_stmt, false);
+
+      /* VAL is the value which was stored, return a COMPOUND_STMT of
+        the statement and that value.  */
+      return build2 (COMPOUND_EXPR, nonatomic_lhs_type, compound_stmt, val);
+    }
+
+  /* Create the variables and labels required for the op= form.  */
+  old = create_tmp_var (nonatomic_lhs_type, NULL);
+  old_addr = build_unary_op (loc, ADDR_EXPR, old, 0);
+  TREE_ADDRESSABLE (val) = 1;
+
+  newval = create_tmp_var (nonatomic_lhs_type, NULL);
+  newval_addr = build_unary_op (loc, ADDR_EXPR, newval, 0);
+  TREE_ADDRESSABLE (newval) = 1;
+
+  loop_decl = create_artificial_label (loc);
+  loop_label = build1 (LABEL_EXPR, void_type_node, loop_decl);
+
+  done_decl = create_artificial_label (loc);
+  done_label = build1 (LABEL_EXPR, void_type_node, done_decl);
+
+  /* __atomic_load (addr, &old, SEQ_CST).  */
+  fndecl = builtin_decl_explicit (BUILT_IN_ATOMIC_LOAD);
+  params->quick_push (lhs_addr);
+  params->quick_push (old_addr);
+  params->quick_push (seq_cst);
+  func_call = build_function_call_vec (loc, fndecl, params, NULL);
+  add_stmt (func_call);
+  params->truncate (0);
+
+  /* Create the expressions for floating-point environment
+     manipulation, if required.  */
+  bool need_fenv = (flag_trapping_math
+                   && (FLOAT_TYPE_P (lhs_type) || FLOAT_TYPE_P (rhs_type)));
+  tree hold_call = NULL_TREE, clear_call = NULL_TREE, update_call = NULL_TREE;
+  if (need_fenv)
+    targetm.atomic_assign_expand_fenv (&hold_call, &clear_call, &update_call);
+
+  if (hold_call)
+    add_stmt (hold_call);
+
+  /* loop:  */
+  add_stmt (loop_label);
+
+  /* newval = old + val;  */
+  rhs = build_binary_op (loc, modifycode, old, val, 1);
+  rhs = convert_for_assignment (loc, nonatomic_lhs_type, rhs, NULL_TREE,
+                               ic_assign, false, NULL_TREE,
+                               NULL_TREE, 0);
+  if (rhs != error_mark_node)
+    {
+      rhs = build2 (MODIFY_EXPR, nonatomic_lhs_type, newval, rhs);
+      SET_EXPR_LOCATION (rhs, loc);
+      add_stmt (rhs);
+    }
+
+  /* if (__atomic_compare_exchange (addr, &old, &new, false, SEQ_CST, SEQ_CST))
+       goto done;  */
+  fndecl = builtin_decl_explicit (BUILT_IN_ATOMIC_COMPARE_EXCHANGE);
+  params->quick_push (lhs_addr);
+  params->quick_push (old_addr);
+  params->quick_push (newval_addr);
+  params->quick_push (integer_zero_node);
+  params->quick_push (seq_cst);
+  params->quick_push (seq_cst);
+  func_call = build_function_call_vec (loc, fndecl, params, NULL);
+
+  goto_stmt = build1 (GOTO_EXPR, void_type_node, done_decl);
+  SET_EXPR_LOCATION (goto_stmt, loc);
+
+  stmt = build3 (COND_EXPR, void_type_node, func_call, goto_stmt, NULL_TREE);
+  SET_EXPR_LOCATION (stmt, loc);
+  add_stmt (stmt);
+  
+  if (clear_call)
+    add_stmt (clear_call);
+
+  /* goto loop;  */
+  goto_stmt  = build1 (GOTO_EXPR, void_type_node, loop_decl);
+  SET_EXPR_LOCATION (goto_stmt, loc);
+  add_stmt (goto_stmt);
+  /* done:  */
+  add_stmt (done_label);
+
+  if (update_call)
+    add_stmt (update_call);
+
+  /* Finish the compound statement.  */
+  compound_stmt = c_end_compound_stmt (loc, compound_stmt, false);
+
+  /* NEWVAL is the value that was successfully stored, return a
+     COMPOUND_EXPR of the statement and the appropriate value.  */
+  return build2 (COMPOUND_EXPR, nonatomic_lhs_type, compound_stmt,
+                return_old_p ? old : newval);
+}
+
 /* Construct and perhaps optimize a tree representation
    for a unary operation.  CODE, a tree_code, specifies the operation
    and XARG is the operand.
@@ -3635,6 +3945,9 @@ build_unary_op (location_t location,
       /* Ensure the argument is fully folded inside any SAVE_EXPR.  */
       arg = c_fully_fold (arg, false, NULL);
 
+      bool atomic_op;
+      atomic_op = really_atomic_lvalue (arg);
+
       /* Increment or decrement the real part of the value,
         and don't change the imaginary part.  */
       if (typecode == COMPLEX_TYPE)
@@ -3644,21 +3957,25 @@ build_unary_op (location_t location,
          pedwarn (location, OPT_Wpedantic,
                   "ISO C does not support %<++%> and %<--%> on complex types");
 
-         arg = stabilize_reference (arg);
-         real = build_unary_op (EXPR_LOCATION (arg), REALPART_EXPR, arg, 1);
-         imag = build_unary_op (EXPR_LOCATION (arg), IMAGPART_EXPR, arg, 1);
-         real = build_unary_op (EXPR_LOCATION (arg), code, real, 1);
-         if (real == error_mark_node || imag == error_mark_node)
-           return error_mark_node;
-         ret = build2 (COMPLEX_EXPR, TREE_TYPE (arg),
-                       real, imag);
-         goto return_build_unary_op;
+         if (!atomic_op)
+           {
+             arg = stabilize_reference (arg);
+             real = build_unary_op (EXPR_LOCATION (arg), REALPART_EXPR, arg, 1);
+             imag = build_unary_op (EXPR_LOCATION (arg), IMAGPART_EXPR, arg, 1);
+             real = build_unary_op (EXPR_LOCATION (arg), code, real, 1);
+             if (real == error_mark_node || imag == error_mark_node)
+               return error_mark_node;
+             ret = build2 (COMPLEX_EXPR, TREE_TYPE (arg),
+                           real, imag);
+             goto return_build_unary_op;
+           }
        }
 
       /* Report invalid types.  */
 
       if (typecode != POINTER_TYPE && typecode != FIXED_POINT_TYPE
-         && typecode != INTEGER_TYPE && typecode != REAL_TYPE)
+         && typecode != INTEGER_TYPE && typecode != REAL_TYPE
+         && typecode != COMPLEX_TYPE)
        {
          if (code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR)
            error_at (location, "wrong type argument to increment");
@@ -3749,6 +4066,24 @@ build_unary_op (location_t location,
                              || code == POSTINCREMENT_EXPR)
                             ? lv_increment : lv_decrement));
 
+       /* If the argument is atomic, use the special code sequences for
+          atomic compound assignment.  */
+       if (atomic_op)
+         {
+           arg = stabilize_reference (arg);
+           ret = build_atomic_assign (location, arg,
+                                      ((code == PREINCREMENT_EXPR
+                                        || code == POSTINCREMENT_EXPR)
+                                       ? PLUS_EXPR
+                                       : MINUS_EXPR),
+                                      (FRACT_MODE_P (TYPE_MODE (argtype))
+                                       ? inc
+                                       : integer_one_node),
+                                      (code == POSTINCREMENT_EXPR
+                                       || code == POSTDECREMENT_EXPR));
+           goto return_build_unary_op;
+         }
+
        if (TREE_CODE (TREE_TYPE (arg)) == BOOLEAN_TYPE)
          val = boolean_increment (code, arg);
        else
@@ -4259,7 +4594,8 @@ build_conditional_expr (location_t colon_loc, tree ifexp, bool ifexp_bcp,
                    "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 ifexp, bool ifexp_bcp,
          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 lhs_origtype,
   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, tree lhs_origtype,
   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, tree lhs_origtype,
     {
       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, tree lhs_origtype,
                        ? 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, tree lhs_origtype,
 
   /* 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, tree 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, tree type, tree rhs)
              || 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, tree type, tree rhs)
          || (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 type, tree rhs,
                 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 type, tree rhs,
       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 type, tree rhs,
       /* 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 type, tree rhs,
          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 init, tree origtype,
   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 outputs, tree inputs,
              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_code code,
                        "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 314f3e8..c866170 100644 (file)
@@ -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 2aa74b9..430d562 100644 (file)
@@ -26993,6 +26993,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,
@@ -27969,6 +27974,12 @@ static const struct builtin_description bdesc_special_args[] =
   { ~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 },
 
@@ -32930,6 +32941,10 @@ ix86_expand_builtin (tree exp, rtx target, rtx subtarget,
     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:
@@ -32944,6 +32959,16 @@ ix86_expand_builtin (tree exp, rtx target, rtx subtarget,
        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 ();
        }
@@ -32956,7 +32981,7 @@ ix86_expand_builtin (tree exp, rtx target, rtx subtarget,
          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)
@@ -43566,6 +43591,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
@@ -43677,6 +43799,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 a2c81e5..a37fa64 100644 (file)
   UNSPECV_XSAVEOPT
   UNSPECV_XSAVEOPT64
 
+  ;; For atomic compound assignments.
+  UNSPECV_FNSTENV
+  UNSPECV_FLDENV
+  UNSPECV_FNSTSW
+  UNSPECV_FNCLEX
+
   ;; For RDRAND support
   UNSPECV_RDRAND
 
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;
+;; 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 f5e8d2c..5e7910b 100644 (file)
@@ -11485,3 +11485,7 @@ It returns true if the target supports GNU indirect functions.
 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 1624f4f..4e60d48 100644 (file)
@@ -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 f3fa0e0..e3be5f8 100644 (file)
@@ -1,3 +1,7 @@
+2013-11-07  Andrew MacLeod  <amacleod@redhat.com>
+
+       * objc-act.c (objc_push_parm): Handle atomic qualifier.
+
 2013-09-25  Tom Tromey  <tromey@redhat.com>
 
        * Make-lang.in (START_HDRS, cc1obj-checksum.o, objc/objc-lang.o)
index 95ec4ec..3125398 100644 (file)
@@ -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 e5d6664..08af30d 100644 (file)
@@ -305,6 +305,8 @@ print_node (FILE *file, const char *prefix, tree node, int indent)
 
   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 3176f9b..26c8ba0 100644 (file)
@@ -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 e665c1c..caf1cb6 100644 (file)
@@ -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 7585c14..e262fcb 100644 (file)
@@ -1600,6 +1600,13 @@ default_canonicalize_comparison (int *, rtx *, rtx *, bool)
 {
 }
 
+/* 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 e3e613a..a939fdb 100644 (file)
@@ -203,6 +203,7 @@ extern void default_asm_output_ident_directive (const char*);
 
 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 6cb4b98..099c392 100644 (file)
@@ -1,3 +1,16 @@
+2013-11-07  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.
+
 2013-11-07  Cong Hou  <congh@google.com>
 
        * gcc.dg/vect/vect-alias-check.c: New.
diff --git a/gcc/testsuite/gcc.dg/atomic/atomic.exp b/gcc/testsuite/gcc.dg/atomic/atomic.exp
new file mode 100644 (file)
index 0000000..ac2ca72
--- /dev/null
@@ -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
diff --git a/gcc/testsuite/gcc.dg/atomic/c11-atomic-exec-1.c b/gcc/testsuite/gcc.dg/atomic/c11-atomic-exec-1.c
new file mode 100644 (file)
index 0000000..c0db93f
--- /dev/null
@@ -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);
+}
diff --git a/gcc/testsuite/gcc.dg/atomic/c11-atomic-exec-2.c b/gcc/testsuite/gcc.dg/atomic/c11-atomic-exec-2.c
new file mode 100644 (file)
index 0000000..9ee56b6
--- /dev/null
@@ -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);
+}
diff --git a/gcc/testsuite/gcc.dg/atomic/c11-atomic-exec-3.c b/gcc/testsuite/gcc.dg/atomic/c11-atomic-exec-3.c
new file mode 100644 (file)
index 0000000..7bfa8c0
--- /dev/null
@@ -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);
+}
diff --git a/gcc/testsuite/gcc.dg/atomic/c11-atomic-exec-4.c b/gcc/testsuite/gcc.dg/atomic/c11-atomic-exec-4.c
new file mode 100644 (file)
index 0000000..02bb3cb
--- /dev/null
@@ -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);
+}
diff --git a/gcc/testsuite/gcc.dg/atomic/c11-atomic-exec-5.c b/gcc/testsuite/gcc.dg/atomic/c11-atomic-exec-5.c
new file mode 100644 (file)
index 0000000..9e6977b
--- /dev/null
@@ -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);
+}
diff --git a/gcc/testsuite/gcc.dg/c11-atomic-1.c b/gcc/testsuite/gcc.dg/c11-atomic-1.c
new file mode 100644 (file)
index 0000000..c7f9a1e
--- /dev/null
@@ -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" } */
+}
diff --git a/gcc/testsuite/gcc.dg/c11-atomic-2.c b/gcc/testsuite/gcc.dg/c11-atomic-2.c
new file mode 100644 (file)
index 0000000..34ee081
--- /dev/null
@@ -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 (|=);
+}
diff --git a/gcc/testsuite/gcc.dg/c11-atomic-3.c b/gcc/testsuite/gcc.dg/c11-atomic-3.c
new file mode 100644 (file)
index 0000000..4b314e8
--- /dev/null
@@ -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" } */
diff --git a/gcc/testsuite/gcc.dg/c90-atomic-1.c b/gcc/testsuite/gcc.dg/c90-atomic-1.c
new file mode 100644 (file)
index 0000000..3506563
--- /dev/null
@@ -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" } */
diff --git a/gcc/testsuite/gcc.dg/c99-atomic-1.c b/gcc/testsuite/gcc.dg/c99-atomic-1.c
new file mode 100644 (file)
index 0000000..3a13f77
--- /dev/null
@@ -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" } */
diff --git a/gcc/testsuite/lib/atomic-dg.exp b/gcc/testsuite/lib/atomic-dg.exp
new file mode 100644 (file)
index 0000000..c1317e4
--- /dev/null
@@ -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 5ca0b76..c3d9712 100644 (file)
@@ -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"]
+}
index 638b3ab..351f906 100644 (file)
@@ -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 fe75633..7cd578c 100644 (file)
@@ -878,6 +878,8 @@ dump_generic_node (pretty_printer *buffer, tree node, int spc, int flags,
        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 node, int spc, int flags,
       {
        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 98896f8..21b790a 100644 (file)
@@ -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 base, unsigned int align)
                                   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 unsignedp, int satp)
   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 short_double)
   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 5f9d0ea..96948f1 100644 (file)
@@ -1598,6 +1598,9 @@ extern enum machine_mode vector_type_mode (const_tree);
 /* 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_tree);
 #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,6 +1638,14 @@ extern enum machine_mode vector_type_mode (const_tree);
 #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.  */
@@ -3176,6 +3188,12 @@ tree_operand_check_code (const_tree __t, enum tree_code __code, int __i,
 #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 425ab11..900a619 100644 (file)
@@ -1,3 +1,13 @@
+2013-11-07  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.
+
 2013-10-17  Michael Hudson-Doyle  <michael.hudson@linaro.org>
 
        * libatomic/configure.tgt (aarch64*): Remove code preventing
index a98ee64..537b24a 100644 (file)
@@ -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 46e60c9..22c384b 100644 (file)
@@ -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 ab080e7..83e54e2 100644 (file)
 /* 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 6a27ebd..d707b09 100755 (executable)
@@ -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,6 +12040,18 @@ 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
 
index 0dc4a98..fd2d35b 100644 (file)
@@ -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])
diff --git a/libatomic/fenv.c b/libatomic/fenv.c
new file mode 100644 (file)
index 0000000..752cf3b
--- /dev/null
@@ -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 bcf0773..8fd2baf 100644 (file)
@@ -95,3 +95,7 @@ LIBATOMIC_1.0 {
   local:
        *;
 };
+LIBATOMIC_1.1 {
+  global:
+       __atomic_feraiseexcept;
+} LIBATOMIC_1.0;