From 18981635127c6701733dc052aa054e569271b733 Mon Sep 17 00:00:00 2001 From: Joseph Myers Date: Fri, 14 Oct 2022 02:18:45 +0000 Subject: c: C2x storage class specifiers in compound literals Implement the C2x feature of storage class specifiers in compound literals. Such storage class specifiers (static, register or thread_local; also constexpr, but we don't yet have C2x constexpr support implemented) can be used before the type name (not mixed with type specifiers, unlike in declarations) and have the same semantics and constraints as for declarations of named objects. Also allow GNU __thread to be used, given that thread_local can be. Bootstrapped with no regressions for x86_64-pc-linux-gnu. gcc/c/ * c-decl.cc (build_compound_literal): Add parameter scspecs. Handle storage class specifiers. * c-parser.cc (c_token_starts_compound_literal) (c_parser_compound_literal_scspecs): New. (c_parser_postfix_expression_after_paren_type): Add parameter scspecs. Call pedwarn_c11 for use of storage class specifiers. Update call to build_compound_literal. (c_parser_cast_expression, c_parser_sizeof_expression) (c_parser_alignof_expression): Handle storage class specifiers for compound literals. Update calls to c_parser_postfix_expression_after_paren_type. (c_parser_postfix_expression): Update syntax comment. * c-tree.h (build_compound_literal): Update prototype. * c-typeck.cc (c_mark_addressable): Diagnose taking address of register compound literal. gcc/testsuite/ * gcc.dg/c11-complit-1.c, gcc.dg/c11-complit-2.c, gcc.dg/c11-complit-3.c, gcc.dg/c2x-complit-2.c, gcc.dg/c2x-complit-3.c, gcc.dg/c2x-complit-4.c, gcc.dg/c2x-complit-5.c, gcc.dg/c2x-complit-6.c, gcc.dg/c2x-complit-7.c, gcc.dg/c90-complit-2.c, gcc.dg/gnu2x-complit-1.c, gcc.dg/gnu2x-complit-2.c: New tests. --- gcc/c/c-decl.cc | 33 ++++++++++++++++++-- gcc/c/c-parser.cc | 91 +++++++++++++++++++++++++++++++++++++++++++++++++------ gcc/c/c-tree.h | 2 +- gcc/c/c-typeck.cc | 5 +++ 4 files changed, 117 insertions(+), 14 deletions(-) (limited to 'gcc/c') diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc index 193e268..a7571cc 100644 --- a/gcc/c/c-decl.cc +++ b/gcc/c/c-decl.cc @@ -6048,11 +6048,13 @@ mark_forward_parm_decls (void) literal. NON_CONST is true if the initializers contain something that cannot occur in a constant expression. If ALIGNAS_ALIGN is nonzero, it is the (valid) alignment for this compound literal, as specified - with _Alignas. */ + with _Alignas. SCSPECS are the storage class specifiers (C2x) from the + compound literal. */ tree build_compound_literal (location_t loc, tree type, tree init, bool non_const, - unsigned int alignas_align) + unsigned int alignas_align, + struct c_declspecs *scspecs) { /* We do not use start_decl here because we have a type, not a declarator; and do not use finish_decl because the decl should be stored inside @@ -6060,15 +6062,33 @@ build_compound_literal (location_t loc, tree type, tree init, bool non_const, tree decl; tree complit; tree stmt; + bool threadp = scspecs ? scspecs->thread_p : false; + enum c_storage_class storage_class = (scspecs + ? scspecs->storage_class + : csc_none); if (type == error_mark_node || init == error_mark_node) return error_mark_node; + if (current_scope == file_scope && storage_class == csc_register) + { + error_at (loc, "file-scope compound literal specifies %"); + storage_class = csc_none; + } + + if (current_scope != file_scope && threadp && storage_class == csc_none) + { + error_at (loc, "compound literal implicitly auto and declared %qs", + scspecs->thread_gnu_p ? "__thread" : "_Thread_local"); + threadp = false; + } + decl = build_decl (loc, VAR_DECL, NULL_TREE, type); DECL_EXTERNAL (decl) = 0; TREE_PUBLIC (decl) = 0; - TREE_STATIC (decl) = (current_scope == file_scope); + TREE_STATIC (decl) = (current_scope == file_scope + || storage_class == csc_static); DECL_CONTEXT (decl) = current_function_decl; TREE_USED (decl) = 1; DECL_READ_P (decl) = 1; @@ -6076,6 +6096,13 @@ build_compound_literal (location_t loc, tree type, tree init, bool non_const, DECL_IGNORED_P (decl) = 1; C_DECL_COMPOUND_LITERAL_P (decl) = 1; TREE_TYPE (decl) = type; + if (threadp) + set_decl_tls_model (decl, decl_default_tls_model (decl)); + if (storage_class == csc_register) + { + C_DECL_REGISTER (decl) = 1; + DECL_REGISTER (decl) = 1; + } c_apply_type_quals_to_decl (TYPE_QUALS (strip_array_types (type)), decl); if (alignas_align) { diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc index 89e0587..602e023 100644 --- a/gcc/c/c-parser.cc +++ b/gcc/c/c-parser.cc @@ -666,6 +666,30 @@ c_parser_next_tokens_start_typename (c_parser *parser, enum c_lookahead_kind la) return false; } +/* Return true if TOKEN, after an open parenthesis, can start a + compound literal (either a storage class specifier allowed in that + context, or a type name), false otherwise. */ +static bool +c_token_starts_compound_literal (c_token *token) +{ + switch (token->type) + { + case CPP_KEYWORD: + switch (token->keyword) + { + case RID_REGISTER: + case RID_STATIC: + case RID_THREAD: + return true; + default: + break; + } + /* Fall through. */ + default: + return c_token_starts_typename (token); + } +} + /* Return true if TOKEN is a type qualifier, false otherwise. */ static bool c_token_is_qualifier (c_token *token) @@ -1563,6 +1587,7 @@ static struct c_expr c_parser_sizeof_expression (c_parser *); static struct c_expr c_parser_alignof_expression (c_parser *); static struct c_expr c_parser_postfix_expression (c_parser *); static struct c_expr c_parser_postfix_expression_after_paren_type (c_parser *, + struct c_declspecs *, struct c_type_name *, location_t); static struct c_expr c_parser_postfix_expression_after_primary (c_parser *, @@ -8237,6 +8262,34 @@ c_parser_binary_expression (c_parser *parser, struct c_expr *after, #undef POP } +/* Parse any storage class specifiers after an open parenthesis in a + context where a compound literal is permitted. */ + +static struct c_declspecs * +c_parser_compound_literal_scspecs (c_parser *parser) +{ + bool seen_scspec = false; + struct c_declspecs *specs = build_null_declspecs (); + while (c_parser_next_token_is (parser, CPP_KEYWORD)) + { + switch (c_parser_peek_token (parser)->keyword) + { + case RID_REGISTER: + case RID_STATIC: + case RID_THREAD: + seen_scspec = true; + declspecs_add_scspec (c_parser_peek_token (parser)->location, + specs, c_parser_peek_token (parser)->value); + c_parser_consume_token (parser); + break; + default: + goto out; + } + } + out: + return seen_scspec ? specs : NULL; +} + /* Parse a cast expression (C90 6.3.4, C99 6.5.4, C11 6.5.4). If AFTER is not NULL then it is an Objective-C message expression which is the primary-expression starting the expression as an initializer. @@ -8260,13 +8313,15 @@ c_parser_cast_expression (c_parser *parser, struct c_expr *after) an unary expression. Full detection of unknown typenames here would require a 3-token lookahead. */ if (c_parser_next_token_is (parser, CPP_OPEN_PAREN) - && c_token_starts_typename (c_parser_peek_2nd_token (parser))) + && c_token_starts_compound_literal (c_parser_peek_2nd_token (parser))) { + struct c_declspecs *scspecs; struct c_type_name *type_name; struct c_expr ret; struct c_expr expr; matching_parens parens; parens.consume_open (parser); + scspecs = c_parser_compound_literal_scspecs (parser); type_name = c_parser_type_name (parser, true); parens.skip_until_found_close (parser); if (type_name == NULL) @@ -8281,8 +8336,11 @@ c_parser_cast_expression (c_parser *parser, struct c_expr *after) used_types_insert (type_name->specs->type); if (c_parser_next_token_is (parser, CPP_OPEN_BRACE)) - return c_parser_postfix_expression_after_paren_type (parser, type_name, + return c_parser_postfix_expression_after_paren_type (parser, scspecs, + type_name, cast_loc); + if (scspecs) + error_at (cast_loc, "storage class specifier in cast"); if (type_name->specs->alignas_p) error_at (type_name->specs->locations[cdw_alignas], "alignment specified for type name in cast"); @@ -8485,14 +8543,16 @@ c_parser_sizeof_expression (c_parser *parser) c_inhibit_evaluation_warnings++; in_sizeof++; if (c_parser_next_token_is (parser, CPP_OPEN_PAREN) - && c_token_starts_typename (c_parser_peek_2nd_token (parser))) + && c_token_starts_compound_literal (c_parser_peek_2nd_token (parser))) { /* Either sizeof ( type-name ) or sizeof unary-expression starting with a compound literal. */ + struct c_declspecs *scspecs; struct c_type_name *type_name; matching_parens parens; parens.consume_open (parser); expr_loc = c_parser_peek_token (parser)->location; + scspecs = c_parser_compound_literal_scspecs (parser); type_name = c_parser_type_name (parser, true); parens.skip_until_found_close (parser); finish = parser->tokens_buf[0].location; @@ -8508,13 +8568,15 @@ c_parser_sizeof_expression (c_parser *parser) } if (c_parser_next_token_is (parser, CPP_OPEN_BRACE)) { - expr = c_parser_postfix_expression_after_paren_type (parser, + expr = c_parser_postfix_expression_after_paren_type (parser, scspecs, type_name, expr_loc); finish = expr.get_finish (); goto sizeof_expr; } /* sizeof ( type-name ). */ + if (scspecs) + error_at (expr_loc, "storage class specifier in %"); if (type_name->specs->alignas_p) error_at (type_name->specs->locations[cdw_alignas], "alignment specified for type name in %"); @@ -8572,16 +8634,18 @@ c_parser_alignof_expression (c_parser *parser) c_inhibit_evaluation_warnings++; in_alignof++; if (c_parser_next_token_is (parser, CPP_OPEN_PAREN) - && c_token_starts_typename (c_parser_peek_2nd_token (parser))) + && c_token_starts_compound_literal (c_parser_peek_2nd_token (parser))) { /* Either __alignof__ ( type-name ) or __alignof__ unary-expression starting with a compound literal. */ location_t loc; + struct c_declspecs *scspecs; struct c_type_name *type_name; struct c_expr ret; matching_parens parens; parens.consume_open (parser); loc = c_parser_peek_token (parser)->location; + scspecs = c_parser_compound_literal_scspecs (parser); type_name = c_parser_type_name (parser, true); end_loc = c_parser_peek_token (parser)->location; parens.skip_until_found_close (parser); @@ -8597,12 +8661,14 @@ c_parser_alignof_expression (c_parser *parser) } if (c_parser_next_token_is (parser, CPP_OPEN_BRACE)) { - expr = c_parser_postfix_expression_after_paren_type (parser, + expr = c_parser_postfix_expression_after_paren_type (parser, scspecs, type_name, loc); goto alignof_expr; } /* alignof ( type-name ). */ + if (scspecs) + error_at (loc, "storage class specifier in %qE", alignof_spelling); if (type_name->specs->alignas_p) error_at (type_name->specs->locations[cdw_alignas], "alignment specified for type name in %qE", @@ -9140,8 +9206,8 @@ c_parser_predefined_identifier (c_parser *parser) postfix-expression -> identifier postfix-expression ++ postfix-expression -- - ( type-name ) { initializer-list } - ( type-name ) { initializer-list , } + ( storage-class-specifiers[opt] type-name ) { initializer-list[opt] } + ( storage-class-specifiers[opt] type-name ) { initializer-list , } argument-expression-list: argument-expression @@ -10483,6 +10549,7 @@ c_parser_postfix_expression (c_parser *parser) static struct c_expr c_parser_postfix_expression_after_paren_type (c_parser *parser, + struct c_declspecs *scspecs, struct c_type_name *type_name, location_t type_loc) { @@ -10515,7 +10582,11 @@ c_parser_postfix_expression_after_paren_type (c_parser *parser, type = error_mark_node; } - pedwarn_c90 (start_loc, OPT_Wpedantic, "ISO C90 forbids compound literals"); + if (!pedwarn_c90 (start_loc, OPT_Wpedantic, + "ISO C90 forbids compound literals") && scspecs) + pedwarn_c11 (start_loc, OPT_Wpedantic, + "ISO C forbids storage class specifiers in compound literals " + "before C2X"); non_const = ((init.value && TREE_CODE (init.value) == CONSTRUCTOR) ? CONSTRUCTOR_NON_CONST (init.value) : init.original_code == C_MAYBE_CONST_EXPR); @@ -10534,7 +10605,7 @@ c_parser_postfix_expression_after_paren_type (c_parser *parser, } } expr.value = build_compound_literal (start_loc, type, init.value, non_const, - alignas_align); + alignas_align, scspecs); set_c_expr_source_range (&expr, init.src_range); expr.m_decimal = 0; expr.original_code = ERROR_MARK; diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h index 46a3e8e..e7cdd2f 100644 --- a/gcc/c/c-tree.h +++ b/gcc/c/c-tree.h @@ -734,7 +734,7 @@ extern void set_init_label (location_t, tree, location_t, struct obstack *); extern void process_init_element (location_t, struct c_expr, bool, struct obstack *); extern tree build_compound_literal (location_t, tree, tree, bool, - unsigned int); + unsigned int, struct c_declspecs *); extern void check_compound_literal_type (location_t, struct c_type_name *); extern tree c_start_switch (location_t, location_t, tree, bool); extern void c_finish_switch (tree, tree); diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index f919068..0176580 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -5114,6 +5114,11 @@ c_mark_addressable (tree exp, bool array_ref_p) break; case COMPOUND_LITERAL_EXPR: + if (C_DECL_REGISTER (COMPOUND_LITERAL_EXPR_DECL (x))) + { + error ("address of register compound literal requested"); + return false; + } TREE_ADDRESSABLE (x) = 1; TREE_ADDRESSABLE (COMPOUND_LITERAL_EXPR_DECL (x)) = 1; return true; -- cgit v1.1 From c2565a31c1622ab0926aeef4a6579413e121b9f9 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Fri, 14 Oct 2022 09:37:01 +0200 Subject: middle-end, c++, i386, libgcc: std::bfloat16_t and __bf16 arithmetic support Here is a complete patch to add std::bfloat16_t support on x86 (AArch64 and ARM left for later). Almost no BFmode optabs are added by the patch, so for binops/unops it extends to SFmode first and then truncates back to BFmode. For {HF,SF,DF,XF,TF}mode -> BFmode conversions libgcc has implementations of all those conversions so that we avoid double rounding, for BFmode -> {DF,XF,TF}mode conversions to avoid growing libgcc too much it emits BFmode -> SFmode conversion first and then converts to the even wider mode, neither step should be imprecise. For BFmode -> HFmode, it first emits a precise BFmode -> SFmode conversion and then SFmode -> HFmode, because neither format is subset or superset of the other, while SFmode is superset of both. expr.cc then contains a -ffast-math optimization of the BF -> SF and SF -> BF conversions if we don't optimize for space (and for the latter if -frounding-math isn't enabled either). For x86, perhaps truncsfbf2 optab could be defined for TARGET_AVX512BF16 but IMNSHO should FAIL if !flag_finite_math || flag_rounding_math || !flag_unsafe_math_optimizations, because I think the insn doesn't raise on sNaNs, hardcodes round to nearest and flushes denormals to zero. By default (unless x86 -fexcess-precision=16) we use float excess precision for BFmode, so truncate only on explicit casts and assignments. The patch introduces a single __bf16 builtin - __builtin_nansf16b, because (__bf16) __builtin_nansf ("") will drop the sNaN into qNaN, and uses f16b suffix instead of bf16 because there would be ambiguity on log vs. logb - __builtin_logbf16 could be either log with bf16 suffix or logb with f16 suffix. In other cases libstdc++ should mostly use __builtin_*f for std::bfloat16_t overloads (we have a problem with std::nextafter though but that one we have also for std::float16_t). 2022-10-14 Jakub Jelinek gcc/ * tree-core.h (enum tree_index): Add TI_BFLOAT16_TYPE. * tree.h (bfloat16_type_node): Define. * tree.cc (excess_precision_type): Promote bfloat16_type_mode like float16_type_mode. (build_common_tree_nodes): Initialize bfloat16_type_node if BFmode is supported. * expmed.h (maybe_expand_shift): Declare. * expmed.cc (maybe_expand_shift): No longer static. * expr.cc (convert_mode_scalar): Don't ICE on BF -> HF or HF -> BF conversions. If there is no optab, handle BF -> {DF,XF,TF,HF} conversions as separate BF -> SF -> {DF,XF,TF,HF} conversions, add -ffast-math generic implementation for BF -> SF and SF -> BF conversions. * builtin-types.def (BT_BFLOAT16, BT_FN_BFLOAT16_CONST_STRING): New. * builtins.def (BUILT_IN_NANSF16B): New builtin. * fold-const-call.cc (fold_const_call): Handle CFN_BUILT_IN_NANSF16B. * config/i386/i386.cc (classify_argument): Handle E_BCmode. (ix86_libgcc_floating_mode_supported_p): Also return true for BFmode for -msse2. (ix86_mangle_type): Mangle BFmode as DF16b. (ix86_invalid_conversion, ix86_invalid_unary_op, ix86_invalid_binary_op): Remove. (TARGET_INVALID_CONVERSION, TARGET_INVALID_UNARY_OP, TARGET_INVALID_BINARY_OP): Don't redefine. * config/i386/i386-builtins.cc (ix86_bf16_type_node): Remove. (ix86_register_bf16_builtin_type): Use bfloat16_type_node rather than ix86_bf16_type_node, only create it if still NULL. * config/i386/i386-builtin-types.def (BFLOAT16): Likewise. * config/i386/i386.md (cbranchbf4, cstorebf4): New expanders. gcc/c-family/ * c-cppbuiltin.cc (c_cpp_builtins): If bfloat16_type_node, predefine __BFLT16_*__ macros and for C++23 also __STDCPP_BFLOAT16_T__. Predefine bfloat16_type_node related macros for -fbuilding-libgcc. * c-lex.cc (interpret_float): Handle CPP_N_BFLOAT16. gcc/c/ * c-typeck.cc (convert_arguments): Don't promote __bf16 to double. gcc/cp/ * cp-tree.h (extended_float_type_p): Return true for bfloat16_type_node. * typeck.cc (cp_compare_floating_point_conversion_ranks): Set extended{1,2} if mv{1,2} is bfloat16_type_node. Adjust comment. gcc/testsuite/ * lib/target-supports.exp (check_effective_target_bfloat16, check_effective_target_bfloat16_runtime, add_options_for_bfloat16): New. * gcc.dg/torture/bfloat16-basic.c: New test. * gcc.dg/torture/bfloat16-builtin.c: New test. * gcc.dg/torture/bfloat16-builtin-issignaling-1.c: New test. * gcc.dg/torture/bfloat16-complex.c: New test. * gcc.dg/torture/builtin-issignaling-1.c: Allow to be includable from bfloat16-builtin-issignaling-1.c. * gcc.dg/torture/floatn-basic.h: Allow to be includable from bfloat16-basic.c. * gcc.target/i386/vect-bfloat16-typecheck_2.c: Adjust expected diagnostics. * gcc.target/i386/sse2-bfloat16-scalar-typecheck.c: Likewise. * gcc.target/i386/vect-bfloat16-typecheck_1.c: Likewise. * g++.target/i386/bfloat_cpp_typecheck.C: Likewise. libcpp/ * include/cpplib.h (CPP_N_BFLOAT16): Define. * expr.cc (interpret_float_suffix): Handle bf16 and BF16 suffixes for C++. libgcc/ * config/i386/t-softfp (softfp_extensions): Add bfsf. (softfp_truncations): Add tfbf xfbf dfbf sfbf hfbf. (CFLAGS-extendbfsf2.c, CFLAGS-truncsfbf2.c, CFLAGS-truncdfbf2.c, CFLAGS-truncxfbf2.c, CFLAGS-trunctfbf2.c, CFLAGS-trunchfbf2.c): Add -msse2. * config/i386/libgcc-glibc.ver (GCC_13.0.0): Export __extendbfsf2 and __trunc{s,d,x,t,h}fbf2. * config/i386/sfp-machine.h (_FP_NANSIGN_B): Define. * config/i386/64/sfp-machine.h (_FP_NANFRAC_B): Define. * config/i386/32/sfp-machine.h (_FP_NANFRAC_B): Define. * soft-fp/brain.h: New file. * soft-fp/truncsfbf2.c: New file. * soft-fp/truncdfbf2.c: New file. * soft-fp/truncxfbf2.c: New file. * soft-fp/trunctfbf2.c: New file. * soft-fp/trunchfbf2.c: New file. * soft-fp/truncbfhf2.c: New file. * soft-fp/extendbfsf2.c: New file. libiberty/ * cp-demangle.h (D_BUILTIN_TYPE_COUNT): Increment. * cp-demangle.c (cplus_demangle_builtin_types): Add std::bfloat16_t entry. (cplus_demangle_type): Demangle DF16b. * testsuite/demangle-expected (_Z3xxxDF16b): New test. --- gcc/c/c-typeck.cc | 3 +++ 1 file changed, 3 insertions(+) (limited to 'gcc/c') diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index 0176580..fdb96c2 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -3678,6 +3678,9 @@ convert_arguments (location_t loc, vec arg_loc, tree typelist, promote_float_arg = false; break; } + /* Don't promote __bf16 either. */ + if (TYPE_MAIN_VARIANT (valtype) == bfloat16_type_node) + promote_float_arg = false; } if (type != NULL_TREE) -- cgit v1.1 From baeec7cc83b19b46d1c73523f06efa7ea2b30390 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Sat, 15 Oct 2022 00:17:38 +0000 Subject: Daily bump. --- gcc/c/ChangeLog | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'gcc/c') diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index a25e1b4..d28585b 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,26 @@ +2022-10-14 Jakub Jelinek + + * c-typeck.cc (convert_arguments): Don't promote __bf16 to + double. + +2022-10-14 Joseph Myers + + * c-decl.cc (build_compound_literal): Add parameter scspecs. + Handle storage class specifiers. + * c-parser.cc (c_token_starts_compound_literal) + (c_parser_compound_literal_scspecs): New. + (c_parser_postfix_expression_after_paren_type): Add parameter + scspecs. Call pedwarn_c11 for use of storage class specifiers. + Update call to build_compound_literal. + (c_parser_cast_expression, c_parser_sizeof_expression) + (c_parser_alignof_expression): Handle storage class specifiers for + compound literals. Update calls to + c_parser_postfix_expression_after_paren_type. + (c_parser_postfix_expression): Update syntax comment. + * c-tree.h (build_compound_literal): Update prototype. + * c-typeck.cc (c_mark_addressable): Diagnose taking address of + register compound literal. + 2022-10-07 Qing Zhao * c-decl.cc (flexible_array_member_type_p): New function. -- cgit v1.1