tree-core.h (enum cv_qualifier): Add TYPE_QUAL_ATOMIC.

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

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

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

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

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

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

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

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

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

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

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

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

From-SVN: r204544
This commit is contained in:
Joseph Myers 2013-11-07 21:15:25 +00:00
parent 07cb5010c8
commit 267bac1078
50 changed files with 3337 additions and 153 deletions

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

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

View 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;

View 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,

View 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)",

View 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 */

View 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

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

View 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 ();
}

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

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

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

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

View 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

View file

@ -222,6 +222,12 @@
UNSPECV_XSAVEOPT
UNSPECV_XSAVEOPT64
;; For atomic compound assignments.
UNSPECV_FNSTENV
UNSPECV_FLDENV
UNSPECV_FNSTSW
UNSPECV_FNCLEX
;; For RDRAND support
UNSPECV_RDRAND
@ -18012,6 +18018,71 @@
(set (attr "length")
(symbol_ref "ix86_attr_length_address_default (insn) + 4"))])
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; 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

View 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

View 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

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

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

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

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

View 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

View 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

View 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 *);

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

View file

@ -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

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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" } */
}

View file

@ -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 (|=);
}

View file

@ -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" } */

View file

@ -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" } */

View file

@ -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" } */

View file

@ -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
}
}

View 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"]
}

View 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;

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

View 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");

View 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,11 +1630,20 @@ 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)))))
/* The same as TYPE_QUALS without the address space qualifications. */
#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)))
@ -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]

View 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

View 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@

View 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@

View file

@ -105,6 +105,9 @@
/* Define to 1 if you have the <dlfcn.h> header file. */
#undef HAVE_DLFCN_H
/* Define to 1 if you have the <fenv.h> header file. */
#undef HAVE_FENV_H
/* Define to 1 if the target supports __attribute__((ifunc(...))). */
#undef HAVE_IFUNC

105
libatomic/configure vendored
View file

@ -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

View 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])

72
libatomic/fenv.c Normal file
View file

@ -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
}

View file

@ -95,3 +95,7 @@ LIBATOMIC_1.0 {
local:
*;
};
LIBATOMIC_1.1 {
global:
__atomic_feraiseexcept;
} LIBATOMIC_1.0;