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:
parent
07cb5010c8
commit
267bac1078
50 changed files with 3337 additions and 153 deletions
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)",
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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))
|
||||
|
|
118
gcc/c/c-decl.c
118
gcc/c/c-decl.c
|
@ -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 ();
|
||||
}
|
||||
|
|
227
gcc/c/c-parser.c
227
gcc/c/c-parser.c
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
513
gcc/c/c-typeck.c
513
gcc/c/c-typeck.c
|
@ -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 "
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 *);
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
34
gcc/testsuite/gcc.dg/atomic/atomic.exp
Normal file
34
gcc/testsuite/gcc.dg/atomic/atomic.exp
Normal 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
|
88
gcc/testsuite/gcc.dg/atomic/c11-atomic-exec-1.c
Normal file
88
gcc/testsuite/gcc.dg/atomic/c11-atomic-exec-1.c
Normal 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, ©, sizeof init) != 0)
|
||||
abort ();
|
||||
copy = (s2 = s1);
|
||||
if (memcmp (&init, ©, sizeof init) != 0)
|
||||
abort ();
|
||||
copy = s1;
|
||||
if (memcmp (&init, ©, sizeof init) != 0)
|
||||
abort ();
|
||||
copy = s2;
|
||||
if (memcmp (&init, ©, sizeof init) != 0)
|
||||
abort ();
|
||||
}
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
test_simple_assign ();
|
||||
exit (0);
|
||||
}
|
171
gcc/testsuite/gcc.dg/atomic/c11-atomic-exec-2.c
Normal file
171
gcc/testsuite/gcc.dg/atomic/c11-atomic-exec-2.c
Normal 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);
|
||||
}
|
85
gcc/testsuite/gcc.dg/atomic/c11-atomic-exec-3.c
Normal file
85
gcc/testsuite/gcc.dg/atomic/c11-atomic-exec-3.c
Normal 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);
|
||||
}
|
208
gcc/testsuite/gcc.dg/atomic/c11-atomic-exec-4.c
Normal file
208
gcc/testsuite/gcc.dg/atomic/c11-atomic-exec-4.c
Normal 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);
|
||||
}
|
541
gcc/testsuite/gcc.dg/atomic/c11-atomic-exec-5.c
Normal file
541
gcc/testsuite/gcc.dg/atomic/c11-atomic-exec-5.c
Normal 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);
|
||||
}
|
267
gcc/testsuite/gcc.dg/c11-atomic-1.c
Normal file
267
gcc/testsuite/gcc.dg/c11-atomic-1.c
Normal 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" } */
|
||||
}
|
165
gcc/testsuite/gcc.dg/c11-atomic-2.c
Normal file
165
gcc/testsuite/gcc.dg/c11-atomic-2.c
Normal 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 (|=);
|
||||
}
|
174
gcc/testsuite/gcc.dg/c11-atomic-3.c
Normal file
174
gcc/testsuite/gcc.dg/c11-atomic-3.c
Normal 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" } */
|
7
gcc/testsuite/gcc.dg/c90-atomic-1.c
Normal file
7
gcc/testsuite/gcc.dg/c90-atomic-1.c
Normal 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" } */
|
8
gcc/testsuite/gcc.dg/c99-atomic-1.c
Normal file
8
gcc/testsuite/gcc.dg/c99-atomic-1.c
Normal 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" } */
|
104
gcc/testsuite/lib/atomic-dg.exp
Normal file
104
gcc/testsuite/lib/atomic-dg.exp
Normal 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
|
||||
}
|
||||
}
|
|
@ -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"]
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
88
gcc/tree.c
88
gcc/tree.c
|
@ -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");
|
||||
|
|
18
gcc/tree.h
18
gcc/tree.h
|
@ -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]
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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@
|
||||
|
|
|
@ -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@
|
||||
|
|
|
@ -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
105
libatomic/configure
vendored
|
@ -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
|
||||
|
||||
|
|
|
@ -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
72
libatomic/fenv.c
Normal 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
|
||||
}
|
|
@ -95,3 +95,7 @@ LIBATOMIC_1.0 {
|
|||
local:
|
||||
*;
|
||||
};
|
||||
LIBATOMIC_1.1 {
|
||||
global:
|
||||
__atomic_feraiseexcept;
|
||||
} LIBATOMIC_1.0;
|
||||
|
|
Loading…
Add table
Reference in a new issue