From bb169406cdc9e044eaec500dd742c2fed40f5488 Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Mon, 9 Aug 2021 10:19:10 +0200 Subject: middle-end/101824 - properly handle volatiles in nested fn lowering When we build the COMPONENT_REF of a formerly volatile local off the FRAME decl we have to make sure to mark the COMPONENT_REF as TREE_THIS_VOLATILE. While the GIMPLE operand scanner looks at the FIELD_DECL this is not how volatile GENERIC refs work. 2021-08-09 Richard Biener PR middle-end/101824 * tree-nested.c (get_frame_field): Mark the COMPONENT_REF as volatile in case the variable was. * gcc.dg/tree-ssa/pr101824.c: New testcase. --- gcc/testsuite/gcc.dg/tree-ssa/pr101824.c | 19 +++++++++++++++++++ gcc/tree-nested.c | 1 + 2 files changed, 20 insertions(+) create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr101824.c (limited to 'gcc') diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr101824.c b/gcc/testsuite/gcc.dg/tree-ssa/pr101824.c new file mode 100644 index 0000000..d5987e1 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr101824.c @@ -0,0 +1,19 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -fdump-tree-pcom-details -fdump-tree-optimized" } */ + +int main() +{ + volatile int y; + void bar() + { + __builtin_printf ("%d", y); + } + while (y) + ; + return 0; +} + +/* Make sure the load from y is correctly interpreted as volatile, even + when going through FRAME. */ +/* { dg-final { scan-tree-dump-not "Executing predictive commoning" "pcom" } } */ +/* { dg-final { scan-tree-dump " ={v} FRAME" "optimized" } } */ diff --git a/gcc/tree-nested.c b/gcc/tree-nested.c index 0c3fb02..cc59526 100644 --- a/gcc/tree-nested.c +++ b/gcc/tree-nested.c @@ -1033,6 +1033,7 @@ get_frame_field (struct nesting_info *info, tree target_context, } x = build3 (COMPONENT_REF, TREE_TYPE (field), x, field, NULL_TREE); + TREE_THIS_VOLATILE (x) = TREE_THIS_VOLATILE (field); return x; } -- cgit v1.1 From 19d1a529fa9f78e7ec7be38d423c90e00cec8f8c Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Mon, 9 Aug 2021 11:42:47 +0200 Subject: tree-optimization/101801 - rework generic vector vectorization more This builds ontop of the vect_worthwhile_without_simd_p refactoring done earlier. It was wrong in dropping the appearant double checks for operation support since the optab check can happen with an integer vector emulation mode and thus succeed but vector lowering might not actually support the operation on word_mode. The following patch adds a vect_emulated_vector_p helper and re-instantiates the check where it was previously. It also adds appropriate costing of the scalar stmts emitted by vector lowering to vectorizable_operation which should be the only place such operations are synthesized. I've also cared for the case where the vector mode is supported but the operation is not (though I think this will be unlikely given we're talking about plus, minus and negate). This fixes the observed FAIL of gcc.dg/tree-ssa/gen-vect-11b.c with -m32 where we end up vectorizing a multiplication that ends up being teared down to scalars again by vector lowering. I'm not super happy about all the other places where we're now and previously feeding scalar modes to optab checks where we want to know whether we can vectorize sth but well. 2021-09-08 Richard Biener PR tree-optimization/101801 PR tree-optimization/101819 * tree-vectorizer.h (vect_emulated_vector_p): Declare. * tree-vect-loop.c (vect_emulated_vector_p): New function. (vectorizable_reduction): Re-instantiate a check for emulated operations. * tree-vect-stmts.c (vectorizable_shift): Likewise. (vectorizable_operation): Likewise. Cost emulated vector operations according to the scalar sequence synthesized by vector lowering. --- gcc/tree-vect-loop.c | 18 ++++++++++++++++++ gcc/tree-vect-stmts.c | 45 +++++++++++++++++++++++++++++++++++++-------- gcc/tree-vectorizer.h | 1 + 3 files changed, 56 insertions(+), 8 deletions(-) (limited to 'gcc') diff --git a/gcc/tree-vect-loop.c b/gcc/tree-vect-loop.c index 37c7daa..995d143 100644 --- a/gcc/tree-vect-loop.c +++ b/gcc/tree-vect-loop.c @@ -7234,6 +7234,14 @@ vectorizable_reduction (loop_vec_info loop_vinfo, dump_printf (MSG_NOTE, "proceeding using word mode.\n"); } + if (vect_emulated_vector_p (vectype_in) + && !vect_can_vectorize_without_simd_p (code)) + { + if (dump_enabled_p ()) + dump_printf (MSG_NOTE, "using word mode not possible.\n"); + return false; + } + /* lane-reducing operations have to go through vect_transform_reduction. For the other cases try without the single cycle optimization. */ if (!ok) @@ -7936,6 +7944,16 @@ vectorizable_phi (vec_info *, return true; } +/* Return true if VECTYPE represents a vector that requires lowering + by the vector lowering pass. */ + +bool +vect_emulated_vector_p (tree vectype) +{ + return (!VECTOR_MODE_P (TYPE_MODE (vectype)) + && (!VECTOR_BOOLEAN_TYPE_P (vectype) + || TYPE_PRECISION (TREE_TYPE (vectype)) != 1)); +} /* Return true if we can emulate CODE on an integer mode representation of a vector. */ diff --git a/gcc/tree-vect-stmts.c b/gcc/tree-vect-stmts.c index 5b94d41..5a5a4da 100644 --- a/gcc/tree-vect-stmts.c +++ b/gcc/tree-vect-stmts.c @@ -5682,15 +5682,11 @@ vectorizable_shift (vec_info *vinfo, if (dump_enabled_p ()) dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, "op not supported by target.\n"); - /* Check only during analysis. */ - if (maybe_ne (GET_MODE_SIZE (vec_mode), UNITS_PER_WORD) - || (!vec_stmt - && !vect_can_vectorize_without_simd_p (code))) - return false; - if (dump_enabled_p ()) - dump_printf_loc (MSG_NOTE, vect_location, - "proceeding using word mode.\n"); + return false; } + /* vector lowering cannot optimize vector shifts using word arithmetic. */ + if (vect_emulated_vector_p (vectype)) + return false; if (!vec_stmt) /* transformation not required. */ { @@ -6076,6 +6072,7 @@ vectorizable_operation (vec_info *vinfo, != CODE_FOR_nothing); } + bool using_emulated_vectors_p = vect_emulated_vector_p (vectype); if (!target_support_p) { if (dump_enabled_p ()) @@ -6088,6 +6085,15 @@ vectorizable_operation (vec_info *vinfo, if (dump_enabled_p ()) dump_printf_loc (MSG_NOTE, vect_location, "proceeding using word mode.\n"); + using_emulated_vectors_p = true; + } + + if (using_emulated_vectors_p + && !vect_can_vectorize_without_simd_p (code)) + { + if (dump_enabled_p ()) + dump_printf (MSG_NOTE, "using word mode not possible.\n"); + return false; } int reduc_idx = STMT_VINFO_REDUC_IDX (stmt_info); @@ -6134,6 +6140,29 @@ vectorizable_operation (vec_info *vinfo, DUMP_VECT_SCOPE ("vectorizable_operation"); vect_model_simple_cost (vinfo, stmt_info, ncopies, dt, ndts, slp_node, cost_vec); + if (using_emulated_vectors_p) + { + /* The above vect_model_simple_cost call handles constants + in the prologue and (mis-)costs one of the stmts as + vector stmt. See tree-vect-generic.c:do_plus_minus/do_negate + for the actual lowering that will be applied. */ + unsigned n + = slp_node ? SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node) : ncopies; + switch (code) + { + case PLUS_EXPR: + n *= 5; + break; + case MINUS_EXPR: + n *= 6; + break; + case NEGATE_EXPR: + n *= 4; + break; + default:; + } + record_stmt_cost (cost_vec, n, scalar_stmt, stmt_info, 0, vect_body); + } return true; } diff --git a/gcc/tree-vectorizer.h b/gcc/tree-vectorizer.h index de0ecf8..9c2c29d 100644 --- a/gcc/tree-vectorizer.h +++ b/gcc/tree-vectorizer.h @@ -2061,6 +2061,7 @@ extern bool vectorizable_lc_phi (loop_vec_info, stmt_vec_info, gimple **, slp_tree); extern bool vectorizable_phi (vec_info *, stmt_vec_info, gimple **, slp_tree, stmt_vector_for_cost *); +extern bool vect_emulated_vector_p (tree); extern bool vect_can_vectorize_without_simd_p (tree_code); extern int vect_get_known_peeling_cost (loop_vec_info, int, int *, stmt_vector_for_cost *, -- cgit v1.1 From c318f8e42b3f90bed5a0648e42c0182a497566b7 Mon Sep 17 00:00:00 2001 From: Hongyu Wang Date: Tue, 10 Aug 2021 15:13:25 +0800 Subject: i386: Fix typos in amxbf16 runtime test. gcc/testsuite/ChangeLog: * gcc.target/i386/amxbf16-dpbf16ps-2.c: Fix typos. --- gcc/testsuite/gcc.target/i386/amxbf16-dpbf16ps-2.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'gcc') diff --git a/gcc/testsuite/gcc.target/i386/amxbf16-dpbf16ps-2.c b/gcc/testsuite/gcc.target/i386/amxbf16-dpbf16ps-2.c index 349ec58..f7002ca 100644 --- a/gcc/testsuite/gcc.target/i386/amxbf16-dpbf16ps-2.c +++ b/gcc/testsuite/gcc.target/i386/amxbf16-dpbf16ps-2.c @@ -57,7 +57,7 @@ void calc_matrix_dpbf16ps (__tile *dst, __tile *src1, __tile *src2) (make_f32(src1_buf[i * 4 * N + 4 * j + t]) * make_f32(src2_buf[j * 4 * K + 4 * k + t])) + (make_f32(src1_buf[i * 4 * N + 4 * j + t + 1]) * - make_f32(src1_buf[i * 4 * N + 4 * j + t + 1])); + make_f32(src2_buf[j * 4 * K + 4 * k + t + 1])); } } @@ -72,8 +72,8 @@ void test_amx_bf16_dpbf16ps () init_tile_config (&cfg); init_tile_reg_and_src_with_buffer (1, dst, tmp_dst_buf); - init_tile_reg_and_src_with_buffer (2, dst, tmp_dst_buf); - init_tile_reg_and_src_with_buffer (3, dst, tmp_dst_buf); + init_tile_reg_and_src_with_buffer (2, src1, tmp_dst_buf); + init_tile_reg_and_src_with_buffer (3, src2, tmp_dst_buf); calc_matrix_dpbf16ps (&dst, &src1, &src2); -- cgit v1.1 From c40c6a50fd4da342c87a715ae83927a37797e094 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Tue, 10 Aug 2021 11:22:33 +0200 Subject: openmp: Add support for declare simd and declare variant in a attribute syntax This patch adds support for declare simd and declare variant in attribute syntax. Either in attribute-specifier-seq at the start of declaration, in that case it has similar restriction to pragma-syntax, that there is a single function declaration/definition in the declaration, rather than variable declaration or more than one function declarations or mix of function and variable declarations. Or after the declarator id, in that case it applies just to the single function declaration and the same declaration can have multiple such attributes. Or both. Furthermore, cp_parser_statement has been adjusted so that it doesn't accept [[omp::directive (parallel)]] etc. before statements that don't take attributes at all, or where those attributes don't appertain to the statement but something else (e.g. to label, using directive, declaration, etc.). 2021-08-10 Jakub Jelinek gcc/cp/ * parser.h (struct cp_omp_declare_simd_data): Remove in_omp_attribute_pragma and clauses members, add loc and attribs. (struct cp_oacc_routine_data): Remove loc member, add clauses member. * parser.c (cp_finalize_omp_declare_simd): New function. (cp_parser_handle_statement_omp_attributes): Mention in function comment the function is used also for attribute-declaration. (cp_parser_handle_directive_omp_attributes): New function. (cp_parser_statement): Don't call cp_parser_handle_statement_omp_attributes if statement doesn't have attribute-specifier-seq at the beginning at all or if if those attributes don't appertain to the statement. (cp_parser_simple_declaration): Call cp_parser_handle_directive_omp_attributes and cp_finalize_omp_declare_simd. (cp_parser_explicit_instantiation): Likewise. (cp_parser_init_declarator): Initialize prefix_attributes only after parsing declarators. (cp_parser_direct_declarator): Call cp_parser_handle_directive_omp_attributes and cp_finalize_omp_declare_simd. (cp_parser_member_declaration): Likewise. (cp_parser_single_declaration): Likewise. (cp_parser_omp_declare_simd): Don't initialize data.in_omp_attribute_pragma, instead initialize data.attribs[0] and data.attribs[1]. (cp_finish_omp_declare_variant): Remove in_omp_attribute_pragma argument, instead use parser->lexer->in_omp_attribute_pragma. (cp_parser_late_parsing_omp_declare_simd): Adjust cp_finish_omp_declare_variant caller. Handle attribute-syntax declare simd/variant. gcc/testsuite/ * g++.dg/gomp/attrs-1.C (bar): Add missing semicolon after [[omp::directive (threadprivate (t2))]]. Add tests with if/while/switch after parallel in attribute syntax. (corge): Add missing omp:: before directive. * g++.dg/gomp/attrs-2.C (bar): Add missing semicolon after [[omp::directive (threadprivate (t2))]]. * g++.dg/gomp/attrs-10.C: New test. * g++.dg/gomp/attrs-11.C: New test. --- gcc/cp/parser.c | 419 +++++++++++++++++++++++++++++++++-- gcc/cp/parser.h | 7 +- gcc/testsuite/g++.dg/gomp/attrs-1.C | 12 +- gcc/testsuite/g++.dg/gomp/attrs-10.C | 240 ++++++++++++++++++++ gcc/testsuite/g++.dg/gomp/attrs-11.C | 74 +++++++ gcc/testsuite/g++.dg/gomp/attrs-2.C | 2 +- 6 files changed, 726 insertions(+), 28 deletions(-) create mode 100644 gcc/testsuite/g++.dg/gomp/attrs-10.C create mode 100644 gcc/testsuite/g++.dg/gomp/attrs-11.C (limited to 'gcc') diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 02ce954..34be15e 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -1440,6 +1440,24 @@ cp_finalize_omp_declare_simd (cp_parser *parser, tree fndecl) } } +/* Similarly, but for use in declaration parsing functions + which call cp_parser_handle_directive_omp_attributes. */ + +static inline void +cp_finalize_omp_declare_simd (cp_parser *parser, cp_omp_declare_simd_data *data) +{ + if (parser->omp_declare_simd != data) + return; + + if (!parser->omp_declare_simd->error_seen + && !parser->omp_declare_simd->fndecl_seen) + error_at (parser->omp_declare_simd->loc, + "% directive not immediately followed by " + "function declaration or definition", + parser->omp_declare_simd->variant_p ? "variant" : "simd"); + parser->omp_declare_simd = NULL; +} + /* Diagnose if #pragma acc routine isn't followed immediately by function declaration or definition. */ @@ -11661,7 +11679,7 @@ struct cp_omp_attribute_data }; /* Handle omp::directive and omp::sequence attributes in ATTRS - (if any) at the start of a statement. */ + (if any) at the start of a statement or in attribute-declaration. */ static tree cp_parser_handle_statement_omp_attributes (cp_parser *parser, tree attrs) @@ -11858,6 +11876,98 @@ cp_parser_handle_statement_omp_attributes (cp_parser *parser, tree attrs) return attrs; } +/* Handle omp::directive and omp::sequence attributes in *PATTRS + (if any) at the start or after declaration-id of a declaration. */ + +static void +cp_parser_handle_directive_omp_attributes (cp_parser *parser, tree *pattrs, + cp_omp_declare_simd_data *data, + bool start) +{ + if (!flag_openmp && !flag_openmp_simd) + return; + + int cnt = 0; + bool bad = false; + bool variant_p = false; + location_t loc = UNKNOWN_LOCATION; + for (tree pa = *pattrs; pa; pa = TREE_CHAIN (pa)) + if (get_attribute_namespace (pa) == omp_identifier + && is_attribute_p ("directive", get_attribute_name (pa))) + { + for (tree a = TREE_VALUE (pa); a; a = TREE_CHAIN (a)) + { + tree d = TREE_VALUE (a); + gcc_assert (TREE_CODE (d) == DEFERRED_PARSE); + cp_token *first = DEFPARSE_TOKENS (d)->first; + cp_token *last = DEFPARSE_TOKENS (d)->last; + const char *directive[3] = {}; + for (int i = 0; i < 3; i++) + { + tree id = NULL_TREE; + if (first + i == last) + break; + if (first[i].type == CPP_NAME) + id = first[i].u.value; + else if (first[i].type == CPP_KEYWORD) + id = ridpointers[(int) first[i].keyword]; + else + break; + directive[i] = IDENTIFIER_POINTER (id); + } + const c_omp_directive *dir = NULL; + if (directive[0]) + dir = c_omp_categorize_directive (directive[0], directive[1], + directive[2]); + if (dir == NULL) + continue; + if (dir->id == PRAGMA_OMP_DECLARE + && (strcmp (directive[1], "simd") == 0 + || strcmp (directive[1], "variant") == 0)) + { + if (cnt++ == 0) + { + variant_p = strcmp (directive[1], "variant") == 0; + loc = first->location; + } + if (start && parser->omp_declare_simd && !bad) + { + error_at (first->location, + "mixing OpenMP directives with attribute and " + "pragma syntax on the same declaration"); + bad = true; + } + } + } + } + + if (bad) + { + for (tree *pa = pattrs; *pa; ) + if (get_attribute_namespace (*pa) == omp_identifier + && is_attribute_p ("directive", get_attribute_name (*pa))) + *pa = TREE_CHAIN (*pa); + else + pa = &TREE_CHAIN (*pa); + return; + } + if (cnt == 0) + return; + + if (parser->omp_declare_simd == NULL) + { + data->error_seen = false; + data->fndecl_seen = false; + data->variant_p = variant_p; + data->loc = loc; + data->tokens = vNULL; + data->attribs[0] = NULL; + data->attribs[1] = NULL; + parser->omp_declare_simd = data; + } + parser->omp_declare_simd->attribs[!start] = pattrs; +} + /* Parse a statement. statement: @@ -11935,12 +12045,57 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, } has_std_attrs = cp_lexer_peek_token (parser->lexer) != token; + /* Peek at the next token. */ + token = cp_lexer_peek_token (parser->lexer); + bool omp_attrs_forbidden_p; + omp_attrs_forbidden_p = parser->omp_attrs_forbidden_p; + if (std_attrs && (flag_openmp || flag_openmp_simd)) - std_attrs = cp_parser_handle_statement_omp_attributes (parser, std_attrs); + { + bool handle_omp_attribs = false; + if (token->type == CPP_KEYWORD) + switch (token->keyword) + { + case RID_IF: + case RID_SWITCH: + case RID_WHILE: + case RID_DO: + case RID_FOR: + case RID_BREAK: + case RID_CONTINUE: + case RID_RETURN: + case RID_CO_RETURN: + case RID_GOTO: + case RID_AT_TRY: + case RID_AT_CATCH: + case RID_AT_FINALLY: + case RID_AT_SYNCHRONIZED: + case RID_AT_THROW: + case RID_TRY: + case RID_TRANSACTION_ATOMIC: + case RID_TRANSACTION_RELAXED: + case RID_SYNCHRONIZED: + case RID_ATOMIC_NOEXCEPT: + case RID_ATOMIC_CANCEL: + case RID_TRANSACTION_CANCEL: + handle_omp_attribs = true; + break; + default: + break; + } + else if (token->type == CPP_SEMICOLON + || token->type == CPP_OPEN_BRACE + || token->type == CPP_PRAGMA) + handle_omp_attribs = true; + if (handle_omp_attribs) + { + std_attrs = cp_parser_handle_statement_omp_attributes (parser, + std_attrs); + token = cp_lexer_peek_token (parser->lexer); + } + } parser->omp_attrs_forbidden_p = false; - /* Peek at the next token. */ - token = cp_lexer_peek_token (parser->lexer); /* Remember the location of the first token in the statement. */ cp_token *statement_token = token; statement_location = token->location; @@ -12058,6 +12213,7 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, a statement all its own. */ else if (token->type == CPP_PRAGMA) { + do_pragma:; cp_lexer *lexer = parser->lexer; bool do_restart = false; /* Only certain OpenMP pragmas are attached to statements, and thus @@ -12120,7 +12276,46 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, return; /* It didn't work, restore the post-attribute position. */ if (has_std_attrs) - cp_lexer_set_token_position (parser->lexer, statement_token); + { + cp_lexer_set_token_position (parser->lexer, statement_token); + if (flag_openmp || flag_openmp_simd) + { + size_t i = 1; + bool handle_omp_attribs = true; + while (cp_lexer_peek_nth_token (parser->lexer, i)->keyword + == RID_EXTENSION) + i++; + switch (cp_lexer_peek_nth_token (parser->lexer, i)->keyword) + { + case RID_ASM: + case RID_NAMESPACE: + case RID_USING: + case RID_LABEL: + case RID_STATIC_ASSERT: + /* Don't handle OpenMP attribs on keywords that + always start a declaration statement but don't + accept attribute before it and therefore + the tentative cp_parser_declaration_statement + fails to parse because of that. */ + handle_omp_attribs = false; + break; + default: + break; + } + + if (handle_omp_attribs) + { + parser->omp_attrs_forbidden_p = omp_attrs_forbidden_p; + std_attrs + = cp_parser_handle_statement_omp_attributes + (parser, std_attrs); + parser->omp_attrs_forbidden_p = false; + token = cp_lexer_peek_token (parser->lexer); + if (token->type == CPP_PRAGMA) + goto do_pragma; + } + } + } } /* All preceding labels have been parsed at this point. */ if (loc_after_labels != NULL) @@ -14770,6 +14965,12 @@ cp_parser_simple_declaration (cp_parser* parser, /* We no longer need to defer access checks. */ stop_deferring_access_checks (); + cp_omp_declare_simd_data odsd; + if (decl_specifiers.attributes && (flag_openmp || flag_openmp_simd)) + cp_parser_handle_directive_omp_attributes (parser, + &decl_specifiers.attributes, + &odsd, true); + /* In a block scope, a valid declaration must always have a decl-specifier-seq. By not trying to parse declarators, we can resolve the declaration/expression ambiguity more quickly. */ @@ -14962,6 +15163,7 @@ cp_parser_simple_declaration (cp_parser* parser, else { pop_deferring_access_checks (); + cp_finalize_omp_declare_simd (parser, &odsd); return; } } @@ -15042,6 +15244,7 @@ cp_parser_simple_declaration (cp_parser* parser, done: pop_deferring_access_checks (); + cp_finalize_omp_declare_simd (parser, &odsd); } /* Helper of cp_parser_simple_declaration, parse a decomposition declaration. @@ -18659,6 +18862,13 @@ cp_parser_explicit_instantiation (cp_parser* parser) CP_PARSER_FLAGS_OPTIONAL, &decl_specifiers, &declares_class_or_enum); + + cp_omp_declare_simd_data odsd; + if (decl_specifiers.attributes && (flag_openmp || flag_openmp_simd)) + cp_parser_handle_directive_omp_attributes (parser, + &decl_specifiers.attributes, + &odsd, true); + /* If there was exactly one decl-specifier, and it declared a class, and there's no declarator, then we have an explicit type instantiation. */ @@ -18727,6 +18937,8 @@ cp_parser_explicit_instantiation (cp_parser* parser) cp_parser_consume_semicolon_at_end_of_statement (parser); timevar_pop (TV_TEMPLATE_INST); + + cp_finalize_omp_declare_simd (parser, &odsd); } /* Parse an explicit-specialization. @@ -21964,10 +22176,6 @@ cp_parser_init_declarator (cp_parser* parser, if (decl_spec_seq_has_spec_p (decl_specifiers, ds_consteval)) flags |= CP_PARSER_FLAGS_CONSTEVAL; - /* Gather the attributes that were provided with the - decl-specifiers. */ - prefix_attributes = decl_specifiers->attributes; - /* Assume that this is not the declarator for a function definition. */ if (function_definition_p) @@ -22031,6 +22239,10 @@ cp_parser_init_declarator (cp_parser* parser, else asm_specification = NULL_TREE; + /* Gather the attributes that were provided with the + decl-specifiers. */ + prefix_attributes = decl_specifiers->attributes; + /* Look for attributes. */ attributes_start_token = cp_lexer_peek_token (parser->lexer); attributes = cp_parser_attributes_opt (parser); @@ -22679,13 +22891,27 @@ cp_parser_direct_declarator (cp_parser* parser, attrs = cp_parser_std_attribute_spec_seq (parser); + cp_omp_declare_simd_data odsd; + if ((flag_openmp || flag_openmp_simd) + && declarator + && declarator->std_attributes + && declarator->kind == cdk_id) + { + tree *pa = &declarator->std_attributes; + cp_parser_handle_directive_omp_attributes (parser, pa, + &odsd, false); + } + /* In here, we handle cases where attribute is used after the function declaration. For example: void func (int x) __attribute__((vector(..))); */ tree gnu_attrs = NULL_TREE; tree requires_clause = NULL_TREE; - late_return = (cp_parser_late_return_type_opt - (parser, declarator, requires_clause)); + late_return + = cp_parser_late_return_type_opt (parser, declarator, + requires_clause); + + cp_finalize_omp_declare_simd (parser, &odsd); /* Parse the virt-specifier-seq. */ virt_specifiers = cp_parser_virt_specifier_seq_opt (parser); @@ -26435,6 +26661,13 @@ cp_parser_member_declaration (cp_parser* parser) | CP_PARSER_FLAGS_TYPENAME_OPTIONAL), &decl_specifiers, &declares_class_or_enum); + + cp_omp_declare_simd_data odsd; + if (decl_specifiers.attributes && (flag_openmp || flag_openmp_simd)) + cp_parser_handle_directive_omp_attributes (parser, + &decl_specifiers.attributes, + &odsd, true); + /* Check for an invalid type-name. */ if (!decl_specifiers.any_type_specifiers_p && cp_parser_parse_and_diagnose_invalid_type_name (parser)) @@ -26554,6 +26787,10 @@ cp_parser_member_declaration (cp_parser* parser) being declared. */ prefix_attributes = decl_specifiers.attributes; decl_specifiers.attributes = NULL_TREE; + if (parser->omp_declare_simd + && (parser->omp_declare_simd->attribs[0] + == &decl_specifiers.attributes)) + parser->omp_declare_simd->attribs[0] = &prefix_attributes; /* See if these declarations will be friends. */ friend_p = cp_parser_friend_p (&decl_specifiers); @@ -26942,6 +27179,7 @@ cp_parser_member_declaration (cp_parser* parser) cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON); out: parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p; + cp_finalize_omp_declare_simd (parser, &odsd); } /* Parse a pure-specifier. @@ -31067,6 +31305,13 @@ cp_parser_single_declaration (cp_parser* parser, | CP_PARSER_FLAGS_TYPENAME_OPTIONAL), &decl_specifiers, &declares_class_or_enum); + + cp_omp_declare_simd_data odsd; + if (decl_specifiers.attributes && (flag_openmp || flag_openmp_simd)) + cp_parser_handle_directive_omp_attributes (parser, + &decl_specifiers.attributes, + &odsd, true); + if (friend_p) *friend_p = cp_parser_friend_p (&decl_specifiers); @@ -31195,6 +31440,8 @@ cp_parser_single_declaration (cp_parser* parser, parser->qualifying_scope = NULL_TREE; parser->object_scope = NULL_TREE; + cp_finalize_omp_declare_simd (parser, &odsd); + return decl; } @@ -43546,9 +43793,10 @@ cp_parser_omp_declare_simd (cp_parser *parser, cp_token *pragma_tok, data.error_seen = false; data.fndecl_seen = false; data.variant_p = variant_p; - data.in_omp_attribute_pragma = parser->lexer->in_omp_attribute_pragma; data.tokens = vNULL; - data.clauses = NULL_TREE; + data.attribs[0] = NULL; + data.attribs[1] = NULL; + data.loc = UNKNOWN_LOCATION; /* It is safe to take the address of a local variable; it will only be used while this scope is live. */ parser->omp_declare_simd = &data; @@ -43985,7 +44233,7 @@ cp_parser_omp_context_selector_specification (cp_parser *parser, static tree cp_finish_omp_declare_variant (cp_parser *parser, cp_token *pragma_tok, - tree attrs, bool in_omp_attribute_pragma) + tree attrs) { matching_parens parens; if (!parens.require_open (parser)) @@ -44044,7 +44292,7 @@ cp_finish_omp_declare_variant (cp_parser *parser, cp_token *pragma_tok, location_t varid_loc = make_location (caret_loc, start_loc, finish_loc); /* For now only in C++ attributes, do it always for OpenMP 5.1. */ - if (in_omp_attribute_pragma + if (parser->lexer->in_omp_attribute_pragma && cp_lexer_next_token_is (parser->lexer, CPP_COMMA) && cp_lexer_nth_token_is (parser->lexer, 2, CPP_NAME)) cp_lexer_consume_token (parser->lexer); @@ -44121,11 +44369,10 @@ cp_parser_late_parsing_omp_declare_simd (cp_parser *parser, tree attrs) cp_lexer_consume_token (parser->lexer); if (strcmp (kind, "simd") == 0) { - /* For now only in C++ attributes, do it always for OpenMP 5.1. */ - if (data->in_omp_attribute_pragma - && cp_lexer_next_token_is (parser->lexer, CPP_COMMA) + /* For now only in C++ attributes, do it always for OpenMP 5.1. + if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA) && cp_lexer_nth_token_is (parser->lexer, 2, CPP_NAME)) - cp_lexer_consume_token (parser->lexer); + cp_lexer_consume_token (parser->lexer); */ cl = cp_parser_omp_all_clauses (parser, OMP_DECLARE_SIMD_CLAUSE_MASK, "#pragma omp declare simd", @@ -44142,12 +44389,142 @@ cp_parser_late_parsing_omp_declare_simd (cp_parser *parser, tree attrs) { gcc_assert (strcmp (kind, "variant") == 0); attrs - = cp_finish_omp_declare_variant (parser, pragma_tok, attrs, - data->in_omp_attribute_pragma); + = cp_finish_omp_declare_variant (parser, pragma_tok, attrs); } cp_parser_pop_lexer (parser); } + cp_lexer *lexer = NULL; + for (int i = 0; i < 2; i++) + { + if (data->attribs[i] == NULL) + continue; + for (tree *pa = data->attribs[i]; *pa; ) + if (get_attribute_namespace (*pa) == omp_identifier + && is_attribute_p ("directive", get_attribute_name (*pa))) + { + for (tree a = TREE_VALUE (*pa); a; a = TREE_CHAIN (a)) + { + tree d = TREE_VALUE (a); + gcc_assert (TREE_CODE (d) == DEFERRED_PARSE); + cp_token *first = DEFPARSE_TOKENS (d)->first; + cp_token *last = DEFPARSE_TOKENS (d)->last; + const char *directive[3] = {}; + for (int j = 0; j < 3; j++) + { + tree id = NULL_TREE; + if (first + j == last) + break; + if (first[j].type == CPP_NAME) + id = first[j].u.value; + else if (first[j].type == CPP_KEYWORD) + id = ridpointers[(int) first[j].keyword]; + else + break; + directive[j] = IDENTIFIER_POINTER (id); + } + const c_omp_directive *dir = NULL; + if (directive[0]) + dir = c_omp_categorize_directive (directive[0], directive[1], + directive[2]); + if (dir == NULL) + { + error_at (first->location, + "unknown OpenMP directive name in " + "% attribute argument"); + continue; + } + if (dir->id != PRAGMA_OMP_DECLARE + || (strcmp (directive[1], "simd") != 0 + && strcmp (directive[1], "variant") != 0)) + { + error_at (first->location, + "OpenMP directive other than % " + "or % appertains to a " + "declaration"); + continue; + } + + if (!flag_openmp && strcmp (directive[1], "simd") != 0) + continue; + if (lexer == NULL) + { + lexer = cp_lexer_alloc (); + lexer->debugging_p = parser->lexer->debugging_p; + } + vec_safe_reserve (lexer->buffer, (last - first) + 2); + cp_token tok = {}; + tok.type = CPP_PRAGMA; + tok.keyword = RID_MAX; + tok.u.value = build_int_cst (NULL, PRAGMA_OMP_DECLARE); + tok.location = first->location; + lexer->buffer->quick_push (tok); + while (++first < last) + lexer->buffer->quick_push (*first); + tok = {}; + tok.type = CPP_PRAGMA_EOL; + tok.keyword = RID_MAX; + tok.location = last->location; + lexer->buffer->quick_push (tok); + tok = {}; + tok.type = CPP_EOF; + tok.keyword = RID_MAX; + tok.location = last->location; + lexer->buffer->quick_push (tok); + lexer->next = parser->lexer; + lexer->next_token = lexer->buffer->address (); + lexer->last_token = lexer->next_token + + lexer->buffer->length () + - 1; + lexer->in_omp_attribute_pragma = true; + parser->lexer = lexer; + /* Move the current source position to that of the first token + in the new lexer. */ + cp_lexer_set_source_position_from_token (lexer->next_token); + + cp_token *pragma_tok = cp_lexer_consume_token (parser->lexer); + tree id = cp_lexer_peek_token (parser->lexer)->u.value; + const char *kind = IDENTIFIER_POINTER (id); + cp_lexer_consume_token (parser->lexer); + + tree c, cl; + if (strcmp (kind, "simd") == 0) + { + if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA) + && cp_lexer_nth_token_is (parser->lexer, 2, CPP_NAME)) + cp_lexer_consume_token (parser->lexer); + + omp_clause_mask mask = OMP_DECLARE_SIMD_CLAUSE_MASK; + cl = cp_parser_omp_all_clauses (parser, mask, + "#pragma omp declare simd", + pragma_tok); + if (cl) + cl = tree_cons (NULL_TREE, cl, NULL_TREE); + c = build_tree_list (get_identifier ("omp declare simd"), + cl); + TREE_CHAIN (c) = attrs; + if (processing_template_decl) + ATTR_IS_DEPENDENT (c) = 1; + attrs = c; + } + else + { + gcc_assert (strcmp (kind, "variant") == 0); + attrs + = cp_finish_omp_declare_variant (parser, pragma_tok, + attrs); + } + gcc_assert (parser->lexer != lexer); + vec_safe_truncate (lexer->buffer, 0); + } + *pa = TREE_CHAIN (*pa); + } + else + pa = &TREE_CHAIN (*pa); + } + if (lexer) + cp_lexer_destroy (lexer); + data->fndecl_seen = true; return attrs; } diff --git a/gcc/cp/parser.h b/gcc/cp/parser.h index e62742d..3669587 100644 --- a/gcc/cp/parser.h +++ b/gcc/cp/parser.h @@ -216,15 +216,14 @@ struct cp_omp_declare_simd_data { bool error_seen; /* Set if error has been reported. */ bool fndecl_seen; /* Set if one fn decl/definition has been seen already. */ bool variant_p; /* Set for #pragma omp declare variant. */ - bool in_omp_attribute_pragma; /* True if declare simd/variant comes from - C++11 attribute rather than pragma. */ + location_t loc; vec tokens; - tree clauses; + tree *attribs[2]; }; /* Helper data structure for parsing #pragma acc routine. */ struct cp_oacc_routine_data : cp_omp_declare_simd_data { - location_t loc; + tree clauses; }; /* The cp_parser structure represents the C++ parser. */ diff --git a/gcc/testsuite/g++.dg/gomp/attrs-1.C b/gcc/testsuite/g++.dg/gomp/attrs-1.C index 6bbdcac..5c7007b 100644 --- a/gcc/testsuite/g++.dg/gomp/attrs-1.C +++ b/gcc/testsuite/g++.dg/gomp/attrs-1.C @@ -501,10 +501,18 @@ bar (int d, int m, int i1, int i2, int i3, int p, int *idp, int s, } } extern int t2; - [[omp::directive (threadprivate (t2))]] + [[omp::directive (threadprivate (t2))]]; extern int t2; [[omp::directive (declare reduction (dr: int: omp_out += omp_in) initializer (omp_priv = 0))]] ; + [[omp::directive (parallel)]] + if (0) + ; + [[omp::directive (parallel)]] + while (0) + ; + [[omp::directive (parallel)]] + switch (0) { case 1: break; default: break; } } void corge1 (); @@ -521,7 +529,7 @@ corge () omp::directive (declare simd simdlen(8) notinbranch)]] extern int corge3 (int l, int *p); [[omp::directive (declare simd simdlen(4) linear(l) aligned(p:4) uniform(p) inbranch), - directive (declare simd simdlen(8) notinbranch)]] + omp::directive (declare simd simdlen(8) notinbranch)]] extern int corge4 (int l, int *p); [[omp::sequence (directive (declare simd simdlen(4) linear(l) aligned(p:4) uniform(p) inbranch), omp::directive (declare simd simdlen(8) notinbranch))]] diff --git a/gcc/testsuite/g++.dg/gomp/attrs-10.C b/gcc/testsuite/g++.dg/gomp/attrs-10.C new file mode 100644 index 0000000..a78f892 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/attrs-10.C @@ -0,0 +1,240 @@ +// { dg-do compile { target c++11 } } +// { dg-options "-fopenmp -ffat-lto-objects -fdump-tree-gimple" } + +extern "C" void abort (); + +[[omp::directive (declare simd, linear (l))]] extern int f1 (int l); +extern int f2 (int), f3 [[omp::directive (declare simd, uniform (m))]] (int m), f4 (int), z; +[[omp::directive (declare simd, linear (l), simdlen(4))]] extern int f5 [[omp::directive (declare simd uniform (l) simdlen (8) notinbranch)]] (int l); + +int +f1 (int l) +{ + return l; +} + +// { dg-final { scan-assembler-times "_ZGVbM4l__Z2f1i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVbN4l__Z2f1i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcM4l__Z2f1i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcN4l__Z2f1i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdM8l__Z2f1i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdN8l__Z2f1i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeM16l__Z2f1i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeN16l__Z2f1i:" 1 { target { i?86-*-* x86_64-*-* } } } } + +int +f2 (int l) +{ + return l + 1; +} + +// { dg-final { scan-assembler-not "_ZGV\[a-zA-Z0-9]__Z2f2i:" { target { i?86-*-* x86_64-*-* } } } } + +int +f3 (int l) +{ + return l + 2; +} + +// { dg-final { scan-assembler-times "_ZGVbM4u__Z2f3i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVbN4u__Z2f3i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcM4u__Z2f3i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcN4u__Z2f3i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdM8u__Z2f3i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdN8u__Z2f3i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeM16u__Z2f3i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeN16u__Z2f3i:" 1 { target { i?86-*-* x86_64-*-* } } } } + +int +f4 (int l) +{ + return l + 3; +} + +// { dg-final { scan-assembler-not "_ZGV\[a-zA-Z0-9]__Z2f4i:" { target { i?86-*-* x86_64-*-* } } } } + +int +f5 (int l) +{ // { dg-warning "GCC does not currently support mixed size types for 'simd' functions" "" { target aarch64*-*-* } .-1 } + return l + 4; +} + +// { dg-final { scan-assembler-times "_ZGVbM4l__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVbN4l__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcM4l__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcN4l__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdM4l__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdN4l__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeM4l__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeN4l__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVbN8u__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcN8u__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdN8u__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeN8u__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-not "_ZGV\[bcde]M8u__Z2f5i:" { target { i?86-*-* x86_64-*-* } } } } + +[[omp::directive (declare simd, linear (l), simdlen(4), notinbranch), + omp::directive (declare simd, uniform (l), simdlen(4), inbranch)]] +int +f6 [[omp::sequence (directive (declare simd uniform (l) simdlen (8), notinbranch), + omp::directive (declare simd linear (l) simdlen (8) inbranch))]] (int l) +{ // { dg-warning "GCC does not currently support mixed size types for 'simd' functions" "" { target aarch64*-*-* } .-2 } + return l + 5; +} + +// { dg-final { scan-assembler-times "_ZGVbM4u__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVbN4l__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVbM8l__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVbN8u__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcM4u__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcN4l__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcM8l__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcN8u__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdM4u__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdN4l__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdM8l__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdN8u__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeM4u__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeN4l__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeM8l__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeN8u__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-not "_ZGV\[bcde]M4l__Z2f6i:" { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-not "_ZGV\[bcde]N4u__Z2f6i:" { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-not "_ZGV\[bcde]M8u__Z2f6i:" { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-not "_ZGV\[bcde]N8l__Z2f6i:" { target { i?86-*-* x86_64-*-* } } } } + +int +f7 (int l) +{ + return l + 6; +} + +// { dg-final { scan-assembler-not "_ZGV\[a-zA-Z0-9]__Z2f7i:" { target { i?86-*-* x86_64-*-* } } } } + +int +f8 (int l) +{ + return l + 7; +} + +// { dg-final { scan-assembler-not "_ZGV\[a-zA-Z0-9]__Z2f8i:" { target { i?86-*-* x86_64-*-* } } } } + +[[omp::sequence (omp::directive (declare variant (f7), match (construct={parallel})), + directive (declare simd uniform (l), simdlen(4)))]] +int +f9 [[omp::directive (declare simd uniform (l) simdlen (8)), + omp::directive (declare variant (f8) match (construct={parallel,for}))]] (int l) +{ // { dg-warning "GCC does not currently support mixed size types for 'simd' functions" "" { target aarch64*-*-* } .-2 } + return l + 8; +} + +// { dg-final { scan-assembler-times "_ZGVbM4u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVbN4u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcM4u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcN4u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdM4u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdN4u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeM4u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeN4u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVbM8u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVbN8u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcM8u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcN8u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdM8u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdN8u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeM8u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeN8u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } } + +int z; + +void +test () +{ + [[omp::directive (parallel)]] + if (f9 (3) != 9) + abort (); + [[omp::directive (parallel for)]] + for (int i = 0; i < 1; i++) + if (f9 (4) != 11) + abort (); + if (f9 (5) != 13) + abort (); +} + +// { dg-final { scan-tree-dump-times " = f7 \\\(3\\\);" 1 "gimple" } } +// { dg-final { scan-tree-dump-times " = f8 \\\(4\\\);" 1 "gimple" } } +// { dg-final { scan-tree-dump-times " = f9 \\\(5\\\);" 1 "gimple" } } + +template +int +f10 (int x) +{ + return x + N; +} + +template [[omp::directive (declare simd, notinbranch)]] int f10<0> (int); + +// { dg-final { scan-assembler-times "_ZGVbN4v__Z3f10ILi0EEii:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcN4v__Z3f10ILi0EEii:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdN8v__Z3f10ILi0EEii:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeN16v__Z3f10ILi0EEii:" 1 { target { i?86-*-* x86_64-*-* } } } } + +template int f10<1> [[omp::directive (declare simd inbranch linear(x))]] (int x); + +// { dg-final { scan-assembler-times "_ZGVbM4l__Z3f10ILi1EEii:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcM4l__Z3f10ILi1EEii:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdM8l__Z3f10ILi1EEii:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeM16l__Z3f10ILi1EEii:" 1 { target { i?86-*-* x86_64-*-* } } } } + +template +int f11 (int); + +template <> [[omp::directive (declare simd, inbranch)]] int +f11<0> (int x) +{ + return x; +} + +// { dg-final { scan-assembler-times "_ZGVbM4v__Z3f11ILi0EEii:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcM4v__Z3f11ILi0EEii:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdM8v__Z3f11ILi0EEii:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeM16v__Z3f11ILi0EEii:" 1 { target { i?86-*-* x86_64-*-* } } } } + +template <> int +f11<1> [[omp::directive (declare simd, notinbranch, linear (y))]] (int y) +{ + return y; +} + +// { dg-final { scan-assembler-times "_ZGVbN4l__Z3f11ILi1EEii:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcN4l__Z3f11ILi1EEii:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdN8l__Z3f11ILi1EEii:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeN16l__Z3f11ILi1EEii:" 1 { target { i?86-*-* x86_64-*-* } } } } + +struct S +{ + [[omp::sequence (directive (declare simd, inbranch, uniform (this)))]] int f12 (int x); + int f13 [[gnu::noinline, omp::directive (declare simd notinbranch uniform (this) linear (y))]] (int y) { return y; } +}; + +int +S::f12 (int x) +{ + return x; +} + +// { dg-final { scan-assembler-times "_ZGVbM4uv__ZN1S3f12Ei:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcM4uv__ZN1S3f12Ei:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdM8uv__ZN1S3f12Ei:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeM16uv__ZN1S3f12Ei:" 1 { target { i?86-*-* x86_64-*-* } } } } + +// { dg-final { scan-assembler-times "_ZGVbN4ul__ZN1S3f13Ei:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcN4ul__ZN1S3f13Ei:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdN8ul__ZN1S3f13Ei:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeN16ul__ZN1S3f13Ei:" 1 { target { i?86-*-* x86_64-*-* } } } } + +int +f14 (S &p, int x) +{ + return p.f13 (x); +} diff --git a/gcc/testsuite/g++.dg/gomp/attrs-11.C b/gcc/testsuite/g++.dg/gomp/attrs-11.C new file mode 100644 index 0000000..a8e27b7 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/attrs-11.C @@ -0,0 +1,74 @@ +// { dg-do compile { target c++11 } } +// { dg-options "-fopenmp -Wno-attributes" } + +namespace N {} +namespace O { typedef int T; }; + +void +foo () +{ + [[omp::directive (parallel)]] asm (""); // { dg-error "expected" } + [[omp::directive (parallel)]] __extension__ asm (""); // { dg-error "expected" } + __extension__ [[omp::directive (parallel)]] asm (""); // { dg-error "expected" } + [[omp::directive (parallel)]] namespace M = ::N; // { dg-error "expected" } + [[omp::directive (parallel)]] using namespace N; // { dg-bogus "expected" "" { xfail *-*-* } } + [[omp::directive (parallel)]] using O::T; // { dg-error "expected" } + [[omp::directive (parallel)]] __label__ foo; // { dg-error "expected" } + [[omp::directive (parallel)]] static_assert (true, ""); // { dg-error "expected" } + [[omp::directive (parallel)]] int a = 5; // { dg-error "not allowed to be specified in this context" } + int b = 0; + [[omp::directive (parallel)]] l: b++; // { dg-error "not allowed to be specified in this context" } + switch (0) + { + [[omp::directive (parallel)]] case 6: break; // { dg-error "not allowed to be specified in this context" } + [[omp::directive (parallel)]] default: break; // { dg-error "not allowed to be specified in this context" } + } +} + +void +bar () +{ + [[omp::directive (declare simd)]] int a; // { dg-error "not allowed to be specified in this context|not immediately followed by function declaration or definition" } + [[omp::directive (declare simd)]] int b, f1 (int); // { dg-error "not allowed to be specified in this context|not immediately followed by function declaration or definition" } + [[omp::directive (declare simd)]] int f2 (int), c; // { dg-error "not immediately followed by function declaration or definition" } + int d [[omp::directive (declare simd)]]; // { dg-error "not allowed to be specified in this context" } + int f3 [[omp::directive (declare simd)]] (int), f4 [[omp::directive (declare simd)]] (int); + __extension__ [[omp::directive (declare simd)]] int f5 (int); + __extension__ int f6 [[omp::directive (declare simd, notinbranch)]] (int); + #pragma omp declare simd notinbranch + [[omp::directive (declare simd inbranch)]] int f7 (int); // { dg-error "mixing OpenMP directives with attribute and pragma syntax on the same declaration" } + [[omp::directive (declare simd notinbranch)]] + #pragma omp declare simd inbranch // { dg-error "mixing OpenMP directives with attribute and pragma syntax on the same statement" } + int f8 (int); + static int t1, t2, t3, t4; + [[omp::directive (declare simd), omp::directive (foobar)]] int f9 (int); // { dg-error "unknown OpenMP directive name" } + [[omp::directive (foobar), omp::directive (declare simd)]] int f10 (int); // { dg-error "unknown OpenMP directive name" } + [[omp::directive (threadprivate (t1)), omp::directive (declare simd)]] int f10 (int); // { dg-error "OpenMP directive other than 'declare simd' or 'declare variant' appertains to a declaration" } + [[omp::directive (declare simd), omp::directive (threadprivate (t2))]] int f11 (int); // { dg-error "OpenMP directive other than 'declare simd' or 'declare variant' appertains to a declaration" } + int f12 [[omp::directive (declare simd), omp::directive (foobar)]] (int); // { dg-error "unknown OpenMP directive name" } + int f13 [[omp::directive (foobar), omp::directive (declare simd)]] (int); // { dg-error "unknown OpenMP directive name" } + int f14 [[omp::directive (threadprivate (t3)), omp::directive (declare simd)]] (int); // { dg-error "OpenMP directive other than 'declare simd' or 'declare variant' appertains to a declaration" } + int f15 [[omp::directive (declare simd), omp::directive (threadprivate (t4))]] (int); // { dg-error "OpenMP directive other than 'declare simd' or 'declare variant' appertains to a declaration" } +} + +[[omp::directive (declare simd)]] int a; // { dg-error "not allowed to be specified in this context|not immediately followed by function declaration or definition" } +[[omp::directive (declare simd)]] int b, f16 (int); // { dg-error "not allowed to be specified in this context|not immediately followed by function declaration or definition" } +[[omp::directive (declare simd)]] int f17 (int), c; // { dg-error "not immediately followed by function declaration or definition" } +int d [[omp::directive (declare simd)]]; // { dg-error "not allowed to be specified in this context" } +int f18 [[omp::directive (declare simd)]] (int), f19 [[omp::directive (declare simd)]] (int); +__extension__ [[omp::directive (declare simd)]] int f20 (int); +__extension__ int f21 [[omp::directive (declare simd, notinbranch)]] (int); +#pragma omp declare simd notinbranch +[[omp::directive (declare simd inbranch)]] int f22 (int); // { dg-error "mixing OpenMP directives with attribute and pragma syntax on the same declaration" } +[[omp::directive (declare simd notinbranch)]] // { dg-error "'declare simd' directive not immediately followed by function declaration or definition" } +#pragma omp declare simd inbranch // { dg-error "'#pragma' is not allowed here" } +int f23 (int); +int t5, t6, t7, t8; +[[omp::directive (declare simd), omp::directive (foobar)]] int f24 (int); // { dg-error "unknown OpenMP directive name" } +[[omp::directive (foobar), omp::directive (declare simd)]] int f25 (int); // { dg-error "unknown OpenMP directive name" } +[[omp::directive (threadprivate (t5)), omp::directive (declare simd)]] int f26 (int); // { dg-error "OpenMP directive other than 'declare simd' or 'declare variant' appertains to a declaration" } +[[omp::directive (declare simd), omp::directive (threadprivate (t6))]] int f27 (int); // { dg-error "OpenMP directive other than 'declare simd' or 'declare variant' appertains to a declaration" } +int f28 [[omp::directive (declare simd), omp::directive (foobar)]] (int); // { dg-error "unknown OpenMP directive name" } +int f29 [[omp::directive (foobar), omp::directive (declare simd)]] (int); // { dg-error "unknown OpenMP directive name" } +int f30 [[omp::directive (threadprivate (t7)), omp::directive (declare simd)]] (int); // { dg-error "OpenMP directive other than 'declare simd' or 'declare variant' appertains to a declaration" } +int f31 [[omp::directive (declare simd), omp::directive (threadprivate (t8))]] (int); // { dg-error "OpenMP directive other than 'declare simd' or 'declare variant' appertains to a declaration" } diff --git a/gcc/testsuite/g++.dg/gomp/attrs-2.C b/gcc/testsuite/g++.dg/gomp/attrs-2.C index 189dc6b..1b59abd 100644 --- a/gcc/testsuite/g++.dg/gomp/attrs-2.C +++ b/gcc/testsuite/g++.dg/gomp/attrs-2.C @@ -501,7 +501,7 @@ bar (int d, int m, int i1, int i2, int i3, int p, int *idp, int s, } } extern int t2; - [[omp::directive (threadprivate (t2))]] + [[omp::directive (threadprivate (t2))]]; extern int t2; [[omp::directive (declare reduction (dr: int: omp_out += omp_in),initializer (omp_priv = 0))]] ; -- cgit v1.1 From 7665af0b1a964b1baae3a59b22fcc420369c63cf Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Tue, 10 Aug 2021 11:34:53 +0200 Subject: i386: Improve single operand AVX512F permutations [PR80355] On the following testcase we emit vmovdqa32 .LC0(%rip), %zmm1 vpermd %zmm0, %zmm1, %zmm0 and vmovdqa64 .LC1(%rip), %zmm1 vpermq %zmm0, %zmm1, %zmm0 instead of vshufi32x4 $78, %zmm0, %zmm0, %zmm0 and vshufi64x2 $78, %zmm0, %zmm0, %zmm0 we can emit with the patch. We have patterns that match two argument permutations for vshuf[if]*, but for one argument it doesn't trigger. Either we can add two patterns for that, or we would need to add another routine to i386-expand.c that would transform under certain condition these cases to the two argument vshuf*, doing it in sse.md looked simpler. We don't need this for 32-byte vectors, we already emit single insn permutation that doesn't need memory op there. 2021-08-10 Jakub Jelinek PR target/80355 * config/i386/sse.md (*avx512f_shuf_64x2_1_1, *avx512f_shuf_32x4_1_1): New define_insn patterns. * gcc.target/i386/avx512f-pr80355-1.c: New test. --- gcc/config/i386/sse.md | 88 +++++++++++++++++++++++ gcc/testsuite/gcc.target/i386/avx512f-pr80355-1.c | 19 +++++ 2 files changed, 107 insertions(+) create mode 100644 gcc/testsuite/gcc.target/i386/avx512f-pr80355-1.c (limited to 'gcc') diff --git a/gcc/config/i386/sse.md b/gcc/config/i386/sse.md index 2b0d10e..3957c86 100644 --- a/gcc/config/i386/sse.md +++ b/gcc/config/i386/sse.md @@ -15336,6 +15336,42 @@ (set_attr "prefix" "evex") (set_attr "mode" "")]) +(define_insn "*avx512f_shuf_64x2_1_1" + [(set (match_operand:V8FI 0 "register_operand" "=v") + (vec_select:V8FI + (match_operand:V8FI 1 "register_operand" "v") + (parallel [(match_operand 2 "const_0_to_7_operand") + (match_operand 3 "const_0_to_7_operand") + (match_operand 4 "const_0_to_7_operand") + (match_operand 5 "const_0_to_7_operand") + (match_operand 6 "const_0_to_7_operand") + (match_operand 7 "const_0_to_7_operand") + (match_operand 8 "const_0_to_7_operand") + (match_operand 9 "const_0_to_7_operand")])))] + "TARGET_AVX512F + && (INTVAL (operands[2]) & 1) == 0 + && INTVAL (operands[2]) == INTVAL (operands[3]) - 1 + && (INTVAL (operands[4]) & 1) == 0 + && INTVAL (operands[4]) == INTVAL (operands[5]) - 1 + && (INTVAL (operands[6]) & 1) == 0 + && INTVAL (operands[6]) == INTVAL (operands[7]) - 1 + && (INTVAL (operands[8]) & 1) == 0 + && INTVAL (operands[8]) == INTVAL (operands[9]) - 1" +{ + int mask; + mask = INTVAL (operands[2]) / 2; + mask |= INTVAL (operands[4]) / 2 << 2; + mask |= INTVAL (operands[6]) / 2 << 4; + mask |= INTVAL (operands[8]) / 2 << 6; + operands[2] = GEN_INT (mask); + + return "vshuf64x2\t{%2, %1, %1, %0|%0, %1, %1, %2}"; +} + [(set_attr "type" "sselog") + (set_attr "length_immediate" "1") + (set_attr "prefix" "evex") + (set_attr "mode" "")]) + (define_expand "avx512vl_shuf_32x4_mask" [(match_operand:VI4F_256 0 "register_operand") (match_operand:VI4F_256 1 "register_operand") @@ -15482,6 +15518,58 @@ (set_attr "prefix" "evex") (set_attr "mode" "")]) +(define_insn "*avx512f_shuf_32x4_1_1" + [(set (match_operand:V16FI 0 "register_operand" "=v") + (vec_select:V16FI + (match_operand:V16FI 1 "register_operand" "v") + (parallel [(match_operand 2 "const_0_to_15_operand") + (match_operand 3 "const_0_to_15_operand") + (match_operand 4 "const_0_to_15_operand") + (match_operand 5 "const_0_to_15_operand") + (match_operand 6 "const_0_to_15_operand") + (match_operand 7 "const_0_to_15_operand") + (match_operand 8 "const_0_to_15_operand") + (match_operand 9 "const_0_to_15_operand") + (match_operand 10 "const_0_to_15_operand") + (match_operand 11 "const_0_to_15_operand") + (match_operand 12 "const_0_to_15_operand") + (match_operand 13 "const_0_to_15_operand") + (match_operand 14 "const_0_to_15_operand") + (match_operand 15 "const_0_to_15_operand") + (match_operand 16 "const_0_to_15_operand") + (match_operand 17 "const_0_to_15_operand")])))] + "TARGET_AVX512F + && (INTVAL (operands[2]) & 3) == 0 + && INTVAL (operands[2]) == INTVAL (operands[3]) - 1 + && INTVAL (operands[2]) == INTVAL (operands[4]) - 2 + && INTVAL (operands[2]) == INTVAL (operands[5]) - 3 + && (INTVAL (operands[6]) & 3) == 0 + && INTVAL (operands[6]) == INTVAL (operands[7]) - 1 + && INTVAL (operands[6]) == INTVAL (operands[8]) - 2 + && INTVAL (operands[6]) == INTVAL (operands[9]) - 3 + && (INTVAL (operands[10]) & 3) == 0 + && INTVAL (operands[10]) == INTVAL (operands[11]) - 1 + && INTVAL (operands[10]) == INTVAL (operands[12]) - 2 + && INTVAL (operands[10]) == INTVAL (operands[13]) - 3 + && (INTVAL (operands[14]) & 3) == 0 + && INTVAL (operands[14]) == INTVAL (operands[15]) - 1 + && INTVAL (operands[14]) == INTVAL (operands[16]) - 2 + && INTVAL (operands[14]) == INTVAL (operands[17]) - 3" +{ + int mask; + mask = INTVAL (operands[2]) / 4; + mask |= INTVAL (operands[6]) / 4 << 2; + mask |= INTVAL (operands[10]) / 4 << 4; + mask |= INTVAL (operands[14]) / 4 << 6; + operands[2] = GEN_INT (mask); + + return "vshuf32x4\t{%2, %1, %1, %0|%0, %1, %1, %2}"; +} + [(set_attr "type" "sselog") + (set_attr "length_immediate" "1") + (set_attr "prefix" "evex") + (set_attr "mode" "")]) + (define_expand "avx512f_pshufdv3_mask" [(match_operand:V16SI 0 "register_operand") (match_operand:V16SI 1 "nonimmediate_operand") diff --git a/gcc/testsuite/gcc.target/i386/avx512f-pr80355-1.c b/gcc/testsuite/gcc.target/i386/avx512f-pr80355-1.c new file mode 100644 index 0000000..b1ff010 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/avx512f-pr80355-1.c @@ -0,0 +1,19 @@ +/* PR target/80355 */ +/* { dg-do compile } */ +/* { dg-options "-O2 -mavx512f -mno-avx512vl -mno-avx512dq" } */ +/* { dg-final { scan-assembler "\tvshufi32x4\t" } } */ +/* { dg-final { scan-assembler "\tvshufi64x2\t" } } */ + +typedef long long V __attribute__((vector_size (64))); +typedef int W __attribute__((vector_size (64))); + +W +f0 (W x) +{ + return __builtin_shuffle (x, (W) { 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7 }); +} +V +f1 (V x) +{ + return __builtin_shuffle (x, (V) { 4, 5, 6, 7, 0, 1, 2, 3 }); +} -- cgit v1.1 From 08aa0e3d4f781fd6a6e293bb06d280365a0bdc1d Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Tue, 10 Aug 2021 10:54:58 +0200 Subject: tree-optimization/101809 - support emulated gather for double[int] This adds emulated gather support for index vectors with more elements than the data vector. The internal function gather vectorization code doesn't currently handle this (but the builtin decl code does). This allows vectorization of double data gather with int indexes on 32bit platforms where there isn't an implicit widening to 64bit present. 2021-08-10 Richard Biener PR tree-optimization/101809 * tree-vect-stmts.c (get_load_store_type): Allow emulated gathers with offset vector nunits being a constant multiple of the data vector nunits. (vect_get_gather_scatter_ops): Use the appropriate nunits for the offset vector defs. (vectorizable_store): Adjust call to vect_get_gather_scatter_ops. (vectorizable_load): Likewise. Handle the case of less offset vectors than data vectors. --- gcc/tree-vect-stmts.c | 47 ++++++++++++++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 17 deletions(-) (limited to 'gcc') diff --git a/gcc/tree-vect-stmts.c b/gcc/tree-vect-stmts.c index 5a5a4da..ab402b5 100644 --- a/gcc/tree-vect-stmts.c +++ b/gcc/tree-vect-stmts.c @@ -2377,9 +2377,11 @@ get_load_store_type (vec_info *vinfo, stmt_vec_info stmt_info, return false; } else if (!TYPE_VECTOR_SUBPARTS (vectype).is_constant () - || !known_eq (TYPE_VECTOR_SUBPARTS (vectype), - TYPE_VECTOR_SUBPARTS - (gs_info->offset_vectype))) + || !TYPE_VECTOR_SUBPARTS + (gs_info->offset_vectype).is_constant () + || !constant_multiple_p (TYPE_VECTOR_SUBPARTS + (gs_info->offset_vectype), + TYPE_VECTOR_SUBPARTS (vectype))) { if (dump_enabled_p ()) dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, @@ -2928,11 +2930,10 @@ vect_build_gather_load_calls (vec_info *vinfo, stmt_vec_info stmt_info, containing loop. */ static void -vect_get_gather_scatter_ops (vec_info *vinfo, +vect_get_gather_scatter_ops (loop_vec_info loop_vinfo, class loop *loop, stmt_vec_info stmt_info, gather_scatter_info *gs_info, - tree *dataref_ptr, vec *vec_offset, - unsigned ncopies) + tree *dataref_ptr, vec *vec_offset) { gimple_seq stmts = NULL; *dataref_ptr = force_gimple_operand (gs_info->base, &stmts, true, NULL_TREE); @@ -2943,8 +2944,10 @@ vect_get_gather_scatter_ops (vec_info *vinfo, new_bb = gsi_insert_seq_on_edge_immediate (pe, stmts); gcc_assert (!new_bb); } - vect_get_vec_defs_for_operand (vinfo, stmt_info, ncopies, gs_info->offset, - vec_offset, gs_info->offset_vectype); + unsigned ncopies = vect_get_num_copies (loop_vinfo, gs_info->offset_vectype); + vect_get_vec_defs_for_operand (loop_vinfo, stmt_info, ncopies, + gs_info->offset, vec_offset, + gs_info->offset_vectype); } /* Prepare to implement a grouped or strided load or store using @@ -8072,8 +8075,9 @@ vectorizable_store (vec_info *vinfo, } else if (STMT_VINFO_GATHER_SCATTER_P (stmt_info)) { - vect_get_gather_scatter_ops (vinfo, loop, stmt_info, &gs_info, - &dataref_ptr, &vec_offsets, ncopies); + vect_get_gather_scatter_ops (loop_vinfo, loop, stmt_info, + &gs_info, &dataref_ptr, + &vec_offsets); vec_offset = vec_offsets[0]; } else @@ -9376,9 +9380,9 @@ vectorizable_load (vec_info *vinfo, } else if (STMT_VINFO_GATHER_SCATTER_P (stmt_info)) { - vect_get_gather_scatter_ops (vinfo, loop, stmt_info, &gs_info, - &dataref_ptr, &vec_offsets, ncopies); - vec_offset = vec_offsets[0]; + vect_get_gather_scatter_ops (loop_vinfo, loop, stmt_info, + &gs_info, &dataref_ptr, + &vec_offsets); } else dataref_ptr @@ -9395,9 +9399,7 @@ vectorizable_load (vec_info *vinfo, if (dataref_offset) dataref_offset = int_const_binop (PLUS_EXPR, dataref_offset, bump); - else if (STMT_VINFO_GATHER_SCATTER_P (stmt_info)) - vec_offset = vec_offsets[j]; - else + else if (!STMT_VINFO_GATHER_SCATTER_P (stmt_info)) dataref_ptr = bump_vector_ptr (vinfo, dataref_ptr, ptr_incr, gsi, stmt_info, bump); if (mask) @@ -9490,6 +9492,7 @@ vectorizable_load (vec_info *vinfo, if (memory_access_type == VMAT_GATHER_SCATTER && gs_info.ifn != IFN_LAST) { + vec_offset = vec_offsets[j]; tree zero = build_zero_cst (vectype); tree scale = size_int (gs_info.scale); gcall *call; @@ -9512,9 +9515,18 @@ vectorizable_load (vec_info *vinfo, gcc_assert (!final_mask); unsigned HOST_WIDE_INT const_nunits = nunits.to_constant (); + unsigned HOST_WIDE_INT const_offset_nunits + = TYPE_VECTOR_SUBPARTS (gs_info.offset_vectype) + .to_constant (); vec *ctor_elts; vec_alloc (ctor_elts, const_nunits); gimple_seq stmts = NULL; + /* We support offset vectors with more elements + than the data vector for now. */ + unsigned HOST_WIDE_INT factor + = const_offset_nunits / const_nunits; + vec_offset = vec_offsets[j / factor]; + unsigned elt_offset = (j % factor) * const_nunits; tree idx_type = TREE_TYPE (TREE_TYPE (vec_offset)); tree scale = size_int (gs_info.scale); align @@ -9525,7 +9537,8 @@ vectorizable_load (vec_info *vinfo, { tree boff = size_binop (MULT_EXPR, TYPE_SIZE (idx_type), - bitsize_int (k)); + bitsize_int + (k + elt_offset)); tree idx = gimple_build (&stmts, BIT_FIELD_REF, idx_type, vec_offset, TYPE_SIZE (idx_type), -- cgit v1.1 From 50b5877925ef5ae8e9f913d6d2b5ce0204ebc588 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Tue, 10 Aug 2021 12:38:00 +0200 Subject: i386: Allow some V32HImode and V64QImode permutations even without AVX512BW [PR80355] When working on the PR, I've noticed we generate terrible code for V32HImode or V64QImode permutations for -mavx512f -mno-avx512bw. Generally we can't do much with such permutations, but since PR68655 we can handle at least some, those expressible using V16SImode or V8DImode permutations, but that wasn't reachable, because ix86_vectorize_vec_perm_const didn't even try, it said without TARGET_AVX512BW it can't do anything, and with it can do everything, no d.testing_p attempts. This patch makes it try it for TARGET_AVX512F && !TARGET_AVX512BW. The first hunk is to avoid ICE, expand_vec_perm_even_odd_1 asserts d->vmode isn't V32HImode because expand_vec_perm_1 for AVX512BW handles already all permutations, but when we let it through without !TARGET_AVX512BW, expand_vec_perm_1 doesn't handle it. If we want, that hunk can be dropped if we implement in expand_vec_perm_even_odd_1 and its helper the even permutation as vpmovdw + vpmovdw + vinserti64x4 and odd permutation as vpsrld $16 + vpsrld $16 + vpmovdw + vpmovdw + vinserti64x4. 2021-08-10 Jakub Jelinek PR target/80355 * config/i386/i386-expand.c (expand_vec_perm_even_odd): Return false for V32HImode if !TARGET_AVX512BW. (ix86_vectorize_vec_perm_const) : If !TARGET_AVX512BW and TARGET_AVX512F and d.testing_p, don't fail early, but actually check the permutation. * gcc.target/i386/avx512f-pr80355-2.c: New test. --- gcc/config/i386/i386-expand.c | 13 +++++++++---- gcc/testsuite/gcc.target/i386/avx512f-pr80355-2.c | 23 +++++++++++++++++++++++ 2 files changed, 32 insertions(+), 4 deletions(-) create mode 100644 gcc/testsuite/gcc.target/i386/avx512f-pr80355-2.c (limited to 'gcc') diff --git a/gcc/config/i386/i386-expand.c b/gcc/config/i386/i386-expand.c index bd21efa..c708b33 100644 --- a/gcc/config/i386/i386-expand.c +++ b/gcc/config/i386/i386-expand.c @@ -20337,6 +20337,11 @@ expand_vec_perm_even_odd (struct expand_vec_perm_d *d) if (d->perm[i] != 2 * i + odd) return false; + if (d->vmode == E_V32HImode + && d->testing_p + && !TARGET_AVX512BW) + return false; + return expand_vec_perm_even_odd_1 (d, odd); } @@ -20877,16 +20882,16 @@ ix86_vectorize_vec_perm_const (machine_mode vmode, rtx target, rtx op0, return true; break; case E_V32HImode: - if (!TARGET_AVX512BW) + if (!TARGET_AVX512F) return false; - if (d.testing_p) + if (d.testing_p && TARGET_AVX512BW) /* All implementable with a single vperm[it]2 insn. */ return true; break; case E_V64QImode: - if (!TARGET_AVX512BW) + if (!TARGET_AVX512F) return false; - if (d.testing_p) + if (d.testing_p && TARGET_AVX512BW) /* Implementable with 2 vperm[it]2, 2 vpshufb and 1 or insn. */ return true; break; diff --git a/gcc/testsuite/gcc.target/i386/avx512f-pr80355-2.c b/gcc/testsuite/gcc.target/i386/avx512f-pr80355-2.c new file mode 100644 index 0000000..c510b2f --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/avx512f-pr80355-2.c @@ -0,0 +1,23 @@ +/* PR target/80355 */ +/* { dg-do compile } */ +/* { dg-options "-O2 -mavx512f -mno-avx512vl -mno-avx512dq -mno-avx512bw" } */ +/* { dg-final { scan-assembler-times "\tvshufi(?:32x4|64x2)\t" 2 } } */ + +typedef short V __attribute__((vector_size (64))); +typedef char W __attribute__((vector_size (64))); + +W +f0 (W x) +{ + return __builtin_shuffle (x, (W) { 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 }); +} + +V +f1 (V x) +{ + return __builtin_shuffle (x, (V) { 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }); +} -- cgit v1.1 From 557d06f8b3ddb54bca134695e117c40c6e2267ab Mon Sep 17 00:00:00 2001 From: "H.J. Lu" Date: Tue, 10 Aug 2021 05:30:44 -0700 Subject: Enable gcc.target/i386/pr88531-1a.c for all targets PR tree-optimization/101809 * gcc.target/i386/pr88531-1a.c: Enable for all targets. --- gcc/testsuite/gcc.target/i386/pr88531-1a.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/testsuite/gcc.target/i386/pr88531-1a.c b/gcc/testsuite/gcc.target/i386/pr88531-1a.c index d1c29b2..5e4f28e 100644 --- a/gcc/testsuite/gcc.target/i386/pr88531-1a.c +++ b/gcc/testsuite/gcc.target/i386/pr88531-1a.c @@ -1,4 +1,4 @@ -/* { dg-do compile { target lp64 } } */ +/* { dg-do compile } */ /* { dg-options "-O3 -march=x86-64 -mfpmath=sse" } */ #include -- cgit v1.1 From 2ba0376ac40447ce7ee09fcef00511c18db25dfa Mon Sep 17 00:00:00 2001 From: Tobias Burnus Date: Tue, 10 Aug 2021 17:26:32 +0200 Subject: gfortran: Fix in-build-tree testing [PR101305, PR101660] ISO_Fortran_binding.h is written in the build dir - hence, a previous commit added it as include directory for in-build-tree testing. However, it turned out that -I$specdir/libgfortran interferes with reading .mod files as they are then no longer regareded as intrinsic modules. Solution: Create an extra include/ directory in the libgfortran build dir and copy ISO_Fortran_binding.h to that directory. As -B$specdir/libgfortran already causes gfortran to read that include subdirectory, the -I flag is no longer needed. PR libfortran/101305 PR fortran/101660 PR testsuite/101847 libgfortran/ChangeLog: * Makefile.am (ISO_Fortran_binding.h): Create include/ in the build dir and copy the include file to it. (clean-local): Add for removing the 'include' directory. * Makefile.in: Regenerate. gcc/testsuite/ChangeLog: * lib/gfortran.exp (gfortran_init): Remove -I$specpath/libgfortran from the string used to set GFORTRAN_UNDER_TEST. --- gcc/testsuite/lib/gfortran.exp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/testsuite/lib/gfortran.exp b/gcc/testsuite/lib/gfortran.exp index cae6738..43f4d4e 100644 --- a/gcc/testsuite/lib/gfortran.exp +++ b/gcc/testsuite/lib/gfortran.exp @@ -184,7 +184,7 @@ proc gfortran_init { args } { set specpath [get_multilibs] } set gfortran_init_set_GFORTRAN_UNDER_TEST 1 - set GFORTRAN_UNDER_TEST [findfile $base_dir/../../gfortran "$base_dir/../../gfortran -B$base_dir/../../ -B$specpath/libgfortran/ -I$specpath/libgfortran" [findfile $base_dir/gfortran "$base_dir/gfortran -B$base_dir/" [transform gfortran]]] + set GFORTRAN_UNDER_TEST [findfile $base_dir/../../gfortran "$base_dir/../../gfortran -B$base_dir/../../ -B$specpath/libgfortran/" [findfile $base_dir/gfortran "$base_dir/gfortran -B$base_dir/" [transform gfortran]]] } } } -- cgit v1.1 From d796cc7a3e719cc36f1851ca322e2877b974691b Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Tue, 10 Aug 2021 18:01:23 +0200 Subject: openmp: Fix up cp/parser.c build with GCC 4.8 to 6 Christophe Lyon reported that cp/parser.c no longer compiles with GCC 4.8.5 after my recent OpenMP changes. A goto out; there crosses odsd variable declaration, and odsd has a vec<...> member where vec has = default; default constructor and gcc before r7-2822-gd0b0fbd9fce2f30a82558bf2308b3a7b56c2f364 treated that as error. Fixed by moving the declaration earlier before the goto. Tested on x86_64-linux with GCC 4.8.5 system gcc, committed to trunk as obvious. 2021-08-10 Jakub Jelinek * parser.c (cp_parser_member_declaration): Move odsd declaration before cp_parser_using_declaration call to avoid errors with GCC 4.8 to 6. --- gcc/cp/parser.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'gcc') diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 34be15e..1be42a1 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -26651,8 +26651,9 @@ cp_parser_member_declaration (cp_parser* parser) parser->colon_corrects_to_scope_p = false; + cp_omp_declare_simd_data odsd; if (cp_parser_using_declaration (parser, /*access_declaration=*/true)) - goto out; + goto out; /* Parse the decl-specifier-seq. */ decl_spec_token_start = cp_lexer_peek_token (parser->lexer); @@ -26662,7 +26663,6 @@ cp_parser_member_declaration (cp_parser* parser) &decl_specifiers, &declares_class_or_enum); - cp_omp_declare_simd_data odsd; if (decl_specifiers.attributes && (flag_openmp || flag_openmp_simd)) cp_parser_handle_directive_omp_attributes (parser, &decl_specifiers.attributes, -- cgit v1.1 From 3ae564ea7410e99e533bc87f999a04b2647c831d Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Wed, 11 Aug 2021 00:16:27 +0000 Subject: Daily bump. --- gcc/ChangeLog | 67 +++++++++++++++++++++++++++++++++++++++++++++++ gcc/DATESTAMP | 2 +- gcc/c/ChangeLog | 6 +++++ gcc/cp/ChangeLog | 42 ++++++++++++++++++++++++++++++ gcc/testsuite/ChangeLog | 69 +++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 185 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index e2ffd84..3eea63b 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,70 @@ +2021-08-10 Jakub Jelinek + + PR target/80355 + * config/i386/i386-expand.c (expand_vec_perm_even_odd): Return false + for V32HImode if !TARGET_AVX512BW. + (ix86_vectorize_vec_perm_const) : + If !TARGET_AVX512BW and TARGET_AVX512F and d.testing_p, don't fail + early, but actually check the permutation. + +2021-08-10 Richard Biener + + PR tree-optimization/101809 + * tree-vect-stmts.c (get_load_store_type): Allow emulated + gathers with offset vector nunits being a constant multiple + of the data vector nunits. + (vect_get_gather_scatter_ops): Use the appropriate nunits + for the offset vector defs. + (vectorizable_store): Adjust call to + vect_get_gather_scatter_ops. + (vectorizable_load): Likewise. Handle the case of less + offset vectors than data vectors. + +2021-08-10 Jakub Jelinek + + PR target/80355 + * config/i386/sse.md (*avx512f_shuf_64x2_1_1, + *avx512f_shuf_32x4_1_1): New define_insn + patterns. + +2021-08-10 Richard Biener + + PR tree-optimization/101801 + PR tree-optimization/101819 + * tree-vectorizer.h (vect_emulated_vector_p): Declare. + * tree-vect-loop.c (vect_emulated_vector_p): New function. + (vectorizable_reduction): Re-instantiate a check for emulated + operations. + * tree-vect-stmts.c (vectorizable_shift): Likewise. + (vectorizable_operation): Likewise. Cost emulated vector + operations according to the scalar sequence synthesized by + vector lowering. + +2021-08-10 Richard Biener + + PR middle-end/101824 + * tree-nested.c (get_frame_field): Mark the COMPONENT_REF as + volatile in case the variable was. + +2021-08-10 H.J. Lu + + PR target/101804 + * config/i386/constraints.md (BC): Document for integer SSE + constant all bits set operand. + (BF): New constraint for const floating-point all bits set + vectors. + * config/i386/i386.c (standard_sse_constant_p): Likewise. + (standard_sse_constant_opcode): Likewise. + * config/i386/sse.md (sseconstm1): New mode attribute. + (mov_internal): Replace BC with . + +2021-08-10 liuhongt + + * config/i386/sse.md (cond_): New expander. + (VI248_AVX512VLBW): New mode iterator. + * config/i386/predicates.md + (nonimmediate_or_const_vec_dup_operand): New predicate. + 2021-08-09 Andrew MacLeod PR tree-optimization/101741 diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index 7eb9baf..4cf952c 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20210810 +20210811 diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index 6f15b0f..74ab186 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,9 @@ +2021-08-10 Martin Uecker + + PR c/29970 + * c-typeck.c (c_expr_sizeof_expr): Evaluate + size expressions for structs of variable size. + 2021-08-06 Tamar Christina * c-decl.c (c_simulate_enum_decl): Pass vec<> by pointer. diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index a8f70b0..fbd4af2e 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,45 @@ +2021-08-10 Jakub Jelinek + + * parser.c (cp_parser_member_declaration): Move odsd declaration + before cp_parser_using_declaration call to avoid errors with + GCC 4.8 to 6. + +2021-08-10 Jakub Jelinek + + * parser.h (struct cp_omp_declare_simd_data): Remove + in_omp_attribute_pragma and clauses members, add loc and attribs. + (struct cp_oacc_routine_data): Remove loc member, add clauses + member. + * parser.c (cp_finalize_omp_declare_simd): New function. + (cp_parser_handle_statement_omp_attributes): Mention in + function comment the function is used also for + attribute-declaration. + (cp_parser_handle_directive_omp_attributes): New function. + (cp_parser_statement): Don't call + cp_parser_handle_statement_omp_attributes if statement doesn't + have attribute-specifier-seq at the beginning at all or if + if those attributes don't appertain to the statement. + (cp_parser_simple_declaration): Call + cp_parser_handle_directive_omp_attributes and + cp_finalize_omp_declare_simd. + (cp_parser_explicit_instantiation): Likewise. + (cp_parser_init_declarator): Initialize prefix_attributes + only after parsing declarators. + (cp_parser_direct_declarator): Call + cp_parser_handle_directive_omp_attributes and + cp_finalize_omp_declare_simd. + (cp_parser_member_declaration): Likewise. + (cp_parser_single_declaration): Likewise. + (cp_parser_omp_declare_simd): Don't initialize + data.in_omp_attribute_pragma, instead initialize + data.attribs[0] and data.attribs[1]. + (cp_finish_omp_declare_variant): Remove + in_omp_attribute_pragma argument, instead use + parser->lexer->in_omp_attribute_pragma. + (cp_parser_late_parsing_omp_declare_simd): Adjust + cp_finish_omp_declare_variant caller. Handle attribute-syntax + declare simd/variant. + 2021-08-06 Tamar Christina * cp-objcp-common.h (cxx_simulate_enum_decl): Pass vec<> by pointer. diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index d0d2584..07d98f7 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,72 @@ +2021-08-10 Tobias Burnus + + PR libfortran/101305 + PR fortran/101660 + PR testsuite/101847 + * lib/gfortran.exp (gfortran_init): Remove -I$specpath/libgfortran + from the string used to set GFORTRAN_UNDER_TEST. + +2021-08-10 H.J. Lu + + PR tree-optimization/101809 + * gcc.target/i386/pr88531-1a.c: Enable for all targets. + +2021-08-10 Jakub Jelinek + + PR target/80355 + * gcc.target/i386/avx512f-pr80355-2.c: New test. + +2021-08-10 Jakub Jelinek + + PR target/80355 + * gcc.target/i386/avx512f-pr80355-1.c: New test. + +2021-08-10 Jakub Jelinek + + * g++.dg/gomp/attrs-1.C (bar): Add missing semicolon after + [[omp::directive (threadprivate (t2))]]. Add tests with + if/while/switch after parallel in attribute syntax. + (corge): Add missing omp:: before directive. + * g++.dg/gomp/attrs-2.C (bar): Add missing semicolon after + [[omp::directive (threadprivate (t2))]]. + * g++.dg/gomp/attrs-10.C: New test. + * g++.dg/gomp/attrs-11.C: New test. + +2021-08-10 Hongyu Wang + + * gcc.target/i386/amxbf16-dpbf16ps-2.c: Fix typos. + +2021-08-10 Richard Biener + + PR middle-end/101824 + * gcc.dg/tree-ssa/pr101824.c: New testcase. + +2021-08-10 Martin Uecker + + PR c/29970 + * gcc.dg/vla-stexp-1.c: New test. + +2021-08-10 H.J. Lu + + PR target/101804 + * gcc.target/i386/avx2-gather-2.c: Pass -march=skylake instead + of "-mavx2 -mtune=skylake". Scan vpcmpeqd. + +2021-08-10 liuhongt + + * gcc.target/i386/cond_op_shift_d-1.c: New test. + * gcc.target/i386/cond_op_shift_d-2.c: New test. + * gcc.target/i386/cond_op_shift_q-1.c: New test. + * gcc.target/i386/cond_op_shift_q-2.c: New test. + * gcc.target/i386/cond_op_shift_ud-1.c: New test. + * gcc.target/i386/cond_op_shift_ud-2.c: New test. + * gcc.target/i386/cond_op_shift_uq-1.c: New test. + * gcc.target/i386/cond_op_shift_uq-2.c: New test. + * gcc.target/i386/cond_op_shift_uw-1.c: New test. + * gcc.target/i386/cond_op_shift_uw-2.c: New test. + * gcc.target/i386/cond_op_shift_w-1.c: New test. + * gcc.target/i386/cond_op_shift_w-2.c: New test. + 2021-08-09 Andrew MacLeod * gcc.dg/pr101741.c: New. -- cgit v1.1 From 92f7016940e5a7281e3fd7628fbf1360d900b581 Mon Sep 17 00:00:00 2001 From: Hans-Peter Nilsson Date: Wed, 11 Aug 2021 01:40:12 +0200 Subject: gcc.dg/uninit-pred-9_b.c: Xfail for CRIS too Adding to the growing list, for autotester accounting purposes. FWIW I see this fails for m68k too: https://gcc.gnu.org/pipermail/gcc-testresults/2021-August/712395.html and moxie: https://gcc.gnu.org/pipermail/gcc-testresults/2021-August/712389.html and pru: https://gcc.gnu.org/pipermail/gcc-testresults/2021-August/712366.html testsuite: PR middle-end/101674 * gcc.dg/uninit-pred-9_b.c: Xfail for cris-*-* too. --- gcc/testsuite/gcc.dg/uninit-pred-9_b.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/testsuite/gcc.dg/uninit-pred-9_b.c b/gcc/testsuite/gcc.dg/uninit-pred-9_b.c index 9383c55..8c2d28c 100644 --- a/gcc/testsuite/gcc.dg/uninit-pred-9_b.c +++ b/gcc/testsuite/gcc.dg/uninit-pred-9_b.c @@ -20,7 +20,7 @@ int foo (int n, int l, int m, int r) blah(v); /* { dg-bogus "uninitialized" "bogus warning" } */ if ( (n <= 8) && (m < 99) && (r < 19) ) - blah(v); /* { dg-bogus "uninitialized" "pr101674" { xfail powerpc64*-*-* mmix-*-* } } */ + blah(v); /* { dg-bogus "uninitialized" "pr101674" { xfail powerpc64*-*-* mmix-*-* cris-*-* } } */ return 0; } -- cgit v1.1 From 05a03f3986db25cb5076b409f4048e9dbb5dbfdf Mon Sep 17 00:00:00 2001 From: liuhongt Date: Tue, 10 Aug 2021 19:00:18 +0800 Subject: Extend ldexp{s,d}f3 to vscalefs{s,d} when TARGET_AVX512F and TARGET_SSE_MATH. gcc/ChangeLog: PR target/98309 * config/i386/i386.md (ldexp3): Extend to vscalefs[sd] when TARGET_AVX512F and TARGET_SSE_MATH. gcc/testsuite/ChangeLog: PR target/98309 * gcc.target/i386/pr98309-1.c: New test. * gcc.target/i386/pr98309-2.c: New test. --- gcc/config/i386/i386.md | 34 ++++++++++++++++++++------- gcc/testsuite/gcc.target/i386/pr98309-1.c | 18 ++++++++++++++ gcc/testsuite/gcc.target/i386/pr98309-2.c | 39 +++++++++++++++++++++++++++++++ 3 files changed, 83 insertions(+), 8 deletions(-) create mode 100644 gcc/testsuite/gcc.target/i386/pr98309-1.c create mode 100644 gcc/testsuite/gcc.target/i386/pr98309-2.c (limited to 'gcc') diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index bc1c30b..56b09c5 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -17914,17 +17914,35 @@ [(use (match_operand:MODEF 0 "register_operand")) (use (match_operand:MODEF 1 "general_operand")) (use (match_operand:SI 2 "register_operand"))] - "TARGET_USE_FANCY_MATH_387 - && (!(SSE_FLOAT_MODE_P (mode) && TARGET_SSE_MATH) - || TARGET_MIX_SSE_I387) + "((TARGET_USE_FANCY_MATH_387 + && (!(SSE_FLOAT_MODE_P (mode) && TARGET_SSE_MATH) + || TARGET_MIX_SSE_I387)) + || (TARGET_AVX512F && TARGET_SSE_MATH)) && flag_unsafe_math_optimizations" { - rtx op0 = gen_reg_rtx (XFmode); - rtx op1 = gen_reg_rtx (XFmode); + /* Prefer avx512f version. */ + if (TARGET_AVX512F && TARGET_SSE_MATH) + { + rtx op2 = gen_reg_rtx (mode); + emit_insn (gen_floatsi2 (op2, operands[2])); + operands[0] = lowpart_subreg (mode, operands[0], mode); + if (MEM_P (operands[1])) + operands[1] = force_reg (mode, operands[1]); + operands[1] = lowpart_subreg (mode, operands[1], mode); + op2 = lowpart_subreg (mode, op2, mode); + emit_insn (gen_avx512f_vmscalef (operands[0], + operands[1], + op2)); + } + else + { + rtx op0 = gen_reg_rtx (XFmode); + rtx op1 = gen_reg_rtx (XFmode); - emit_insn (gen_extendxf2 (op1, operands[1])); - emit_insn (gen_ldexpxf3 (op0, op1, operands[2])); - emit_insn (gen_truncxf2 (operands[0], op0)); + emit_insn (gen_extendxf2 (op1, operands[1])); + emit_insn (gen_ldexpxf3 (op0, op1, operands[2])); + emit_insn (gen_truncxf2 (operands[0], op0)); + } DONE; }) diff --git a/gcc/testsuite/gcc.target/i386/pr98309-1.c b/gcc/testsuite/gcc.target/i386/pr98309-1.c new file mode 100644 index 0000000..3a7afb5 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr98309-1.c @@ -0,0 +1,18 @@ +/* { dg-do compile } */ +/* { dg-options "-mavx512f -O2 -mfpmath=sse -ffast-math" } */ +/* { dg-final { scan-assembler-times "vcvtsi2s\[sd\]" "2" } } */ +/* { dg-final { scan-assembler-times "vscalefs\[sd\]" "2" } } */ + +double +__attribute__((noipa)) +foo (double a, int b) +{ + return __builtin_ldexp (a, b); +} + +float +__attribute__((noipa)) +foo2 (float a, int b) +{ + return __builtin_ldexpf (a, b); +} diff --git a/gcc/testsuite/gcc.target/i386/pr98309-2.c b/gcc/testsuite/gcc.target/i386/pr98309-2.c new file mode 100644 index 0000000..ecfb916 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr98309-2.c @@ -0,0 +1,39 @@ +/* { dg-do run } */ +/* { dg-options "-mavx512f -O2 -mfpmath=sse -ffast-math" } */ +/* { dg-require-effective-target avx512f } */ + +#define AVX512F +#ifndef CHECK +#define CHECK "avx512f-helper.h" +#endif + +#include CHECK + +#include "pr98309-1.c" + +double +__attribute__((noipa, target("fpmath=387"))) +foo_i387 (double a, int b) +{ + return __builtin_ldexp (a, b); +} + +float +__attribute__((noipa, target("fpmath=387"))) +foo2_i387 (float a, int b) +{ + return __builtin_ldexpf (a, b); +} + +static void +test_512 (void) +{ + float fa = 14.5; + double da = 44.5; + int fb = 12; + int db = 8; + if (foo_i387 (da, db) != foo (da, db)) + abort (); + if (foo2_i387 (fa, fb) != foo2 (fa, fb)) + abort (); +} -- cgit v1.1 From fed7c1634e8e50600e20cb97dbfbd74ecbd5ba22 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Tue, 10 Aug 2021 16:13:01 -0700 Subject: compiler: don't crash on a, b := int(0) Fixes PR go/101851 Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/341330 --- gcc/go/gofrontend/MERGE | 2 +- gcc/go/gofrontend/expressions.cc | 15 +++++++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) (limited to 'gcc') diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index b983fda..be092de 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -d5d51242efc432fa62d4e9b141b01c280af32d19 +7e092d2cc5af7648036496485b639f2c9db2f2d8 The first line of this file holds the git revision number of the last merge done from the gofrontend repository. diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index f462b0e..67917da 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -11202,12 +11202,23 @@ Call_expression::do_lower(Gogo* gogo, Named_object* function, { Location loc = this->location(); + if (this->is_error_expression()) + return Expression::make_error(loc); + // A type cast can look like a function call. if (this->fn_->is_type_expression() && this->args_ != NULL && this->args_->size() == 1) - return Expression::make_cast(this->fn_->type(), this->args_->front(), - loc); + { + if (this->expected_result_count_ != 0 + && this->expected_result_count_ != 1) + { + this->report_error(_("type conversion result count mismatch")); + return Expression::make_error(loc); + } + return Expression::make_cast(this->fn_->type(), this->args_->front(), + loc); + } // Because do_type will return an error type and thus prevent future // errors, check for that case now to ensure that the error gets -- cgit v1.1 From a45918f8a7444a40eb397a037683ba5900a2db74 Mon Sep 17 00:00:00 2001 From: Bernd Edlinger Date: Sat, 24 Jul 2021 12:53:39 +0200 Subject: Ada: Remove debug line number for DECL_IGNORED_P functions It was pointed out in PR101598 to be inappropriate, that ignored Ada decls receive the source line number which was recorded in the function decl's DECL_SOURCE_LOCATION. Therefore set all front-end-generated Ada decls with DECL_IGNORED_P to UNKNOWN_LOCATION. 2021-08-11 Bernd Edlinger PR debug/101598 * gcc-interface/trans.c (Subprogram_Body_to_gnu): Set the DECL_SOURCE_LOCATION of DECL_IGNORED_P gnu_subprog_decl to UNKNOWN_LOCATION. --- gcc/ada/gcc-interface/trans.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ada/gcc-interface/trans.c b/gcc/ada/gcc-interface/trans.c index f61183d..3df56aa 100644 --- a/gcc/ada/gcc-interface/trans.c +++ b/gcc/ada/gcc-interface/trans.c @@ -3885,7 +3885,9 @@ Subprogram_Body_to_gnu (Node_Id gnat_node) } /* Set the line number in the decl to correspond to that of the body. */ - if (!Sloc_to_locus (Sloc (gnat_node), &locus, false, gnu_subprog_decl)) + if (DECL_IGNORED_P (gnu_subprog_decl)) + locus = UNKNOWN_LOCATION; + else if (!Sloc_to_locus (Sloc (gnat_node), &locus, false, gnu_subprog_decl)) locus = input_location; DECL_SOURCE_LOCATION (gnu_subprog_decl) = locus; -- cgit v1.1 From b8f604da25bfe0fd4dadbc338293885819fe8018 Mon Sep 17 00:00:00 2001 From: "prathamesh.kulkarni" Date: Wed, 11 Aug 2021 15:30:14 +0530 Subject: arm/66791: Replace builtins for vdup_n and vmov_n intrinsics. gcc/ChangeLog: PR target/66791 * config/arm/arm_neon.h (vdup_n_s8): Replace call to builtin with constructor. (vdup_n_s16): Likewise. (vdup_n_s32): Likewise. (vdup_n_s64): Likewise. (vdup_n_u8): Likewise. (vdup_n_u16): Likewise. (vdup_n_u32): Likewise. (vdup_n_u64): Likewise. (vdup_n_p8): Likewise. (vdup_n_p16): Likewise. (vdup_n_p64): Likewise. (vdup_n_f16): Likewise. (vdup_n_f32): Likewise. (vdupq_n_s8): Likewise. (vdupq_n_s16): Likewise. (vdupq_n_s32): Likewise. (vdupq_n_s64): Likewise. (vdupq_n_u8): Likewise. (vdupq_n_u16): Likewise. (vdupq_n_u32): Likewise. (vdupq_n_u64): Likewise. (vdupq_n_p8): Likewise. (vdupq_n_p16): Likewise. (vdupq_n_p64): Likewise. (vdupq_n_f16): Likewise. (vdupq_n_f32): Likewise. (vmov_n_s8): Replace call to builtin with call to corresponding vdup_n intrinsic. (vmov_n_s16): Likewise. (vmov_n_s32): Likewise. (vmov_n_s64): Likewise. (vmov_n_u8): Likewise. (vmov_n_u16): Likewise. (vmov_n_u32): Likewise. (vmov_n_u64): Likewise. (vmov_n_p8): Likewise. (vmov_n_p16): Likewise. (vmov_n_f16): Likewise. (vmov_n_f32): Likewise. (vmovq_n_s8): Likewise. (vmovq_n_s16): Likewise. (vmovq_n_s32): Likewise. (vmovq_n_s64): Likewise. (vmovq_n_u8): Likewise. (vmovq_n_u16): Likewise. (vmovq_n_u32): Likewise. (vmovq_n_u64): Likewise. (vmovq_n_p8): Likewise. (vmovq_n_p16): Likewise. (vmovq_n_f16): Likewise. (vmovq_n_f32): Likewise. * config/arm/arm_neon_builtins.def: Remove entries for vdup_n. gcc/testsuite/ChangeLog: PR target/66791 * gcc.target/arm/pr51534.c: Adjust test. --- gcc/config/arm/arm_neon.h | 107 +++++++++++++++++---------------- gcc/config/arm/arm_neon_builtins.def | 3 - gcc/testsuite/gcc.target/arm/pr51534.c | 26 +++----- 3 files changed, 63 insertions(+), 73 deletions(-) (limited to 'gcc') diff --git a/gcc/config/arm/arm_neon.h b/gcc/config/arm/arm_neon.h index 5a91d15..3364b37 100644 --- a/gcc/config/arm/arm_neon.h +++ b/gcc/config/arm/arm_neon.h @@ -6664,63 +6664,63 @@ __extension__ extern __inline int8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vdup_n_s8 (int8_t __a) { - return (int8x8_t)__builtin_neon_vdup_nv8qi ((__builtin_neon_qi) __a); + return (int8x8_t) {__a, __a, __a, __a, __a, __a, __a, __a}; } __extension__ extern __inline int16x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vdup_n_s16 (int16_t __a) { - return (int16x4_t)__builtin_neon_vdup_nv4hi ((__builtin_neon_hi) __a); + return (int16x4_t) {__a, __a, __a, __a}; } __extension__ extern __inline int32x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vdup_n_s32 (int32_t __a) { - return (int32x2_t)__builtin_neon_vdup_nv2si ((__builtin_neon_si) __a); + return (int32x2_t) {__a, __a}; } __extension__ extern __inline float32x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vdup_n_f32 (float32_t __a) { - return (float32x2_t)__builtin_neon_vdup_nv2sf ((__builtin_neon_sf) __a); + return (float32x2_t) {__a, __a}; } __extension__ extern __inline uint8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vdup_n_u8 (uint8_t __a) { - return (uint8x8_t)__builtin_neon_vdup_nv8qi ((__builtin_neon_qi) __a); + return (uint8x8_t) {__a, __a, __a, __a, __a, __a, __a, __a}; } __extension__ extern __inline uint16x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vdup_n_u16 (uint16_t __a) { - return (uint16x4_t)__builtin_neon_vdup_nv4hi ((__builtin_neon_hi) __a); + return (uint16x4_t) {__a, __a, __a, __a}; } __extension__ extern __inline uint32x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vdup_n_u32 (uint32_t __a) { - return (uint32x2_t)__builtin_neon_vdup_nv2si ((__builtin_neon_si) __a); + return (uint32x2_t) {__a, __a}; } __extension__ extern __inline poly8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vdup_n_p8 (poly8_t __a) { - return (poly8x8_t)__builtin_neon_vdup_nv8qi ((__builtin_neon_qi) __a); + return (poly8x8_t) {__a, __a, __a, __a, __a, __a, __a, __a}; } __extension__ extern __inline poly16x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vdup_n_p16 (poly16_t __a) { - return (poly16x4_t)__builtin_neon_vdup_nv4hi ((__builtin_neon_hi) __a); + return (poly16x4_t) {__a, __a, __a, __a}; } #pragma GCC push_options @@ -6729,7 +6729,7 @@ __extension__ extern __inline poly64x1_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vdup_n_p64 (poly64_t __a) { - return (poly64x1_t)__builtin_neon_vdup_ndi ((__builtin_neon_di) __a); + return (poly64x1_t) {__a}; } #pragma GCC pop_options @@ -6737,14 +6737,14 @@ __extension__ extern __inline int64x1_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vdup_n_s64 (int64_t __a) { - return (int64x1_t)__builtin_neon_vdup_ndi ((__builtin_neon_di) __a); + return (int64x1_t) {__a}; } __extension__ extern __inline uint64x1_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vdup_n_u64 (uint64_t __a) { - return (uint64x1_t)__builtin_neon_vdup_ndi ((__builtin_neon_di) __a); + return (uint64x1_t) {__a}; } #pragma GCC push_options @@ -6753,7 +6753,7 @@ __extension__ extern __inline poly64x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vdupq_n_p64 (poly64_t __a) { - return (poly64x2_t)__builtin_neon_vdup_nv2di ((__builtin_neon_di) __a); + return (poly64x2_t) {__a, __a}; } #pragma GCC pop_options @@ -6761,231 +6761,234 @@ __extension__ extern __inline int8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vdupq_n_s8 (int8_t __a) { - return (int8x16_t)__builtin_neon_vdup_nv16qi ((__builtin_neon_qi) __a); + return (int8x16_t) {__a, __a, __a, __a, __a, __a, __a, __a, + __a, __a, __a, __a, __a, __a, __a, __a}; } __extension__ extern __inline int16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vdupq_n_s16 (int16_t __a) { - return (int16x8_t)__builtin_neon_vdup_nv8hi ((__builtin_neon_hi) __a); + return (int16x8_t) {__a, __a, __a, __a, __a, __a, __a, __a}; } __extension__ extern __inline int32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vdupq_n_s32 (int32_t __a) { - return (int32x4_t)__builtin_neon_vdup_nv4si ((__builtin_neon_si) __a); + return (int32x4_t) {__a, __a, __a, __a}; } __extension__ extern __inline float32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vdupq_n_f32 (float32_t __a) { - return (float32x4_t)__builtin_neon_vdup_nv4sf ((__builtin_neon_sf) __a); + return (float32x4_t) {__a, __a, __a, __a}; } __extension__ extern __inline uint8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vdupq_n_u8 (uint8_t __a) { - return (uint8x16_t)__builtin_neon_vdup_nv16qi ((__builtin_neon_qi) __a); + return (uint8x16_t) {__a, __a, __a, __a, __a, __a, __a, __a, + __a, __a, __a, __a, __a, __a, __a, __a}; } __extension__ extern __inline uint16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vdupq_n_u16 (uint16_t __a) { - return (uint16x8_t)__builtin_neon_vdup_nv8hi ((__builtin_neon_hi) __a); + return (uint16x8_t) {__a, __a, __a, __a, __a, __a, __a, __a}; } __extension__ extern __inline uint32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vdupq_n_u32 (uint32_t __a) { - return (uint32x4_t)__builtin_neon_vdup_nv4si ((__builtin_neon_si) __a); + return (uint32x4_t) {__a, __a, __a, __a}; } __extension__ extern __inline poly8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vdupq_n_p8 (poly8_t __a) { - return (poly8x16_t)__builtin_neon_vdup_nv16qi ((__builtin_neon_qi) __a); + return (poly8x16_t) {__a, __a, __a, __a, __a, __a, __a, __a, + __a, __a, __a, __a, __a, __a, __a, __a}; } __extension__ extern __inline poly16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vdupq_n_p16 (poly16_t __a) { - return (poly16x8_t)__builtin_neon_vdup_nv8hi ((__builtin_neon_hi) __a); + return (poly16x8_t) {__a, __a, __a, __a, __a, __a, __a, __a}; } __extension__ extern __inline int64x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vdupq_n_s64 (int64_t __a) { - return (int64x2_t)__builtin_neon_vdup_nv2di ((__builtin_neon_di) __a); + return (int64x2_t) {__a, __a}; } __extension__ extern __inline uint64x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vdupq_n_u64 (uint64_t __a) { - return (uint64x2_t)__builtin_neon_vdup_nv2di ((__builtin_neon_di) __a); + return (uint64x2_t) {__a, __a}; } __extension__ extern __inline int8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vmov_n_s8 (int8_t __a) { - return (int8x8_t)__builtin_neon_vdup_nv8qi ((__builtin_neon_qi) __a); + return vdup_n_s8 (__a); } __extension__ extern __inline int16x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vmov_n_s16 (int16_t __a) { - return (int16x4_t)__builtin_neon_vdup_nv4hi ((__builtin_neon_hi) __a); + return vdup_n_s16 (__a); } __extension__ extern __inline int32x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vmov_n_s32 (int32_t __a) { - return (int32x2_t)__builtin_neon_vdup_nv2si ((__builtin_neon_si) __a); + return vdup_n_s32 (__a); } __extension__ extern __inline float32x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vmov_n_f32 (float32_t __a) { - return (float32x2_t)__builtin_neon_vdup_nv2sf ((__builtin_neon_sf) __a); + return vdup_n_f32 (__a); } __extension__ extern __inline uint8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vmov_n_u8 (uint8_t __a) { - return (uint8x8_t)__builtin_neon_vdup_nv8qi ((__builtin_neon_qi) __a); + return vdup_n_u8 (__a); } __extension__ extern __inline uint16x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vmov_n_u16 (uint16_t __a) { - return (uint16x4_t)__builtin_neon_vdup_nv4hi ((__builtin_neon_hi) __a); + return vdup_n_u16 (__a); } __extension__ extern __inline uint32x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vmov_n_u32 (uint32_t __a) { - return (uint32x2_t)__builtin_neon_vdup_nv2si ((__builtin_neon_si) __a); + return vdup_n_u32 (__a); } __extension__ extern __inline poly8x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vmov_n_p8 (poly8_t __a) { - return (poly8x8_t)__builtin_neon_vdup_nv8qi ((__builtin_neon_qi) __a); + return vdup_n_p8 (__a); } __extension__ extern __inline poly16x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vmov_n_p16 (poly16_t __a) { - return (poly16x4_t)__builtin_neon_vdup_nv4hi ((__builtin_neon_hi) __a); + return vdup_n_p16 (__a); } __extension__ extern __inline int64x1_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vmov_n_s64 (int64_t __a) { - return (int64x1_t)__builtin_neon_vdup_ndi ((__builtin_neon_di) __a); + return vdup_n_s64 (__a); } __extension__ extern __inline uint64x1_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vmov_n_u64 (uint64_t __a) { - return (uint64x1_t)__builtin_neon_vdup_ndi ((__builtin_neon_di) __a); + return vdup_n_u64 (__a); } __extension__ extern __inline int8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vmovq_n_s8 (int8_t __a) { - return (int8x16_t)__builtin_neon_vdup_nv16qi ((__builtin_neon_qi) __a); + return vdupq_n_s8 (__a); } __extension__ extern __inline int16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vmovq_n_s16 (int16_t __a) { - return (int16x8_t)__builtin_neon_vdup_nv8hi ((__builtin_neon_hi) __a); + return vdupq_n_s16 (__a); } __extension__ extern __inline int32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vmovq_n_s32 (int32_t __a) { - return (int32x4_t)__builtin_neon_vdup_nv4si ((__builtin_neon_si) __a); + return vdupq_n_s32 (__a); } __extension__ extern __inline float32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vmovq_n_f32 (float32_t __a) { - return (float32x4_t)__builtin_neon_vdup_nv4sf ((__builtin_neon_sf) __a); + return vdupq_n_f32 (__a); } __extension__ extern __inline uint8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vmovq_n_u8 (uint8_t __a) { - return (uint8x16_t)__builtin_neon_vdup_nv16qi ((__builtin_neon_qi) __a); + return vdupq_n_u8 (__a); } __extension__ extern __inline uint16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vmovq_n_u16 (uint16_t __a) { - return (uint16x8_t)__builtin_neon_vdup_nv8hi ((__builtin_neon_hi) __a); + return vdupq_n_u16 (__a); } __extension__ extern __inline uint32x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vmovq_n_u32 (uint32_t __a) { - return (uint32x4_t)__builtin_neon_vdup_nv4si ((__builtin_neon_si) __a); + return vdupq_n_u32 (__a); } __extension__ extern __inline poly8x16_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vmovq_n_p8 (poly8_t __a) { - return (poly8x16_t)__builtin_neon_vdup_nv16qi ((__builtin_neon_qi) __a); + return vdupq_n_p8 (__a); } __extension__ extern __inline poly16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vmovq_n_p16 (poly16_t __a) { - return (poly16x8_t)__builtin_neon_vdup_nv8hi ((__builtin_neon_hi) __a); + return vdupq_n_p16 (__a); } __extension__ extern __inline int64x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vmovq_n_s64 (int64_t __a) { - return (int64x2_t)__builtin_neon_vdup_nv2di ((__builtin_neon_di) __a); + return vdupq_n_s64 (__a); } __extension__ extern __inline uint64x2_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vmovq_n_u64 (uint64_t __a) { - return (uint64x2_t)__builtin_neon_vdup_nv2di ((__builtin_neon_di) __a); + return vdupq_n_u64 (__a); } __extension__ extern __inline int8x8_t @@ -18005,14 +18008,14 @@ __extension__ extern __inline float16x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vdup_n_f16 (float16_t __a) { - return __builtin_neon_vdup_nv4hf (__a); + return (float16x4_t) {__a, __a, __a, __a}; } __extension__ extern __inline float16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vdupq_n_f16 (float16_t __a) { - return __builtin_neon_vdup_nv8hf (__a); + return (float16x8_t) {__a, __a, __a, __a, __a, __a, __a, __a}; } __extension__ extern __inline float16x4_t @@ -18047,14 +18050,14 @@ __extension__ extern __inline float16x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vmov_n_f16 (float16_t __a) { - return __builtin_neon_vdup_nv4hf (__a); + return vdup_n_f16 (__a); } __extension__ extern __inline float16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vmovq_n_f16 (float16_t __a) { - return __builtin_neon_vdup_nv8hf (__a); + return vdupq_n_f16 (__a); } __extension__ extern __inline float16x4_t @@ -18978,14 +18981,14 @@ __extension__ extern __inline bfloat16x4_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vdup_n_bf16 (bfloat16_t __a) { - return __builtin_neon_vdup_nv4bf (__a); + return (bfloat16x4_t) {__a, __a, __a, __a}; } __extension__ extern __inline bfloat16x8_t __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) vdupq_n_bf16 (bfloat16_t __a) { - return __builtin_neon_vdup_nv8bf (__a); + return (bfloat16x8_t) {__a, __a, __a, __a, __a, __a, __a, __a}; } __extension__ extern __inline bfloat16x4_t diff --git a/gcc/config/arm/arm_neon_builtins.def b/gcc/config/arm/arm_neon_builtins.def index fb6d66e..fafb5c6 100644 --- a/gcc/config/arm/arm_neon_builtins.def +++ b/gcc/config/arm/arm_neon_builtins.def @@ -211,9 +211,6 @@ VAR10 (GETLANE, vget_lane, VAR6 (GETLANE, vget_laneu, v8qi, v4hi, v2si, v16qi, v8hi, v4si) VAR10 (SETLANE, vset_lane, v8qi, v4hi, v2si, v2sf, di, v16qi, v8hi, v4si, v4sf, v2di) -VAR10 (UNOP, vdup_n, - v8qi, v4hi, v2si, v2sf, di, v16qi, v8hi, v4si, v4sf, v2di) -VAR4 (UNOP, vdup_n, v8hf, v4hf, v8bf, v4bf) VAR10 (GETLANE, vdup_lane, v8qi, v4hi, v2si, v2sf, di, v16qi, v8hi, v4si, v4sf, v2di) VAR4 (GETLANE, vdup_lane, v8hf, v4hf, v8bf, v4bf) diff --git a/gcc/testsuite/gcc.target/arm/pr51534.c b/gcc/testsuite/gcc.target/arm/pr51534.c index 3711b45..ac7f1ea 100644 --- a/gcc/testsuite/gcc.target/arm/pr51534.c +++ b/gcc/testsuite/gcc.target/arm/pr51534.c @@ -35,29 +35,17 @@ GEN_COND_TESTS(vceq) /* Scan for expected outputs. */ /* { dg-final { scan-assembler "vcgt\.s8\[ \]+\[dD\]\[0-9\]+, \[dD\]\[0-9\]+, #0" } } */ -/* { dg-final { scan-assembler-times "vcgt\.u8\[ \]+\[dD\]\[0-9\]+, \[dD\]\[0-9\]+, \[dD\]\[0-9\]+" 2 } } */ /* { dg-final { scan-assembler "vcgt\.s16\[ \]+\[dD\]\[0-9\]+, \[dD\]\[0-9\]+, #0" } } */ -/* { dg-final { scan-assembler-times "vcgt\.u16\[ \]+\[dD\]\[0-9\]+, \[dD\]\[0-9\]+, \[dD\]\[0-9\]+" 2 } } */ /* { dg-final { scan-assembler "vcgt\.s32\[ \]+\[dD\]\[0-9\]+, \[dD\]\[0-9\]+, #0" } } */ -/* { dg-final { scan-assembler-times "vcgt\.u32\[ \]+\[dD\]\[0-9\]+, \[dD\]\[0-9\]+, \[dD\]\[0-9\]+" 2 } } */ /* { dg-final { scan-assembler "vcgt\.s8\[ \]+\[qQ\]\[0-9\]+, \[qQ\]\[0-9\]+, #0" } } */ -/* { dg-final { scan-assembler-times "vcgt\.u8\[ \]+\[qQ\]\[0-9\]+, \[qQ\]\[0-9\]+, \[qQ\]\[0-9\]+" 2 } } */ /* { dg-final { scan-assembler "vcgt\.s16\[ \]+\[qQ\]\[0-9\]+, \[qQ\]\[0-9\]+, #0" } } */ -/* { dg-final { scan-assembler-times "vcgt\.u16\[ \]+\[qQ\]\[0-9\]+, \[qQ\]\[0-9\]+, \[qQ\]\[0-9\]+" 2 } } */ /* { dg-final { scan-assembler "vcgt\.s32\[ \]+\[qQ\]\[0-9\]+, \[qQ\]\[0-9\]+, #0" } } */ -/* { dg-final { scan-assembler-times "vcgt\.u32\[ \]+\[qQ\]\[0-9\]+, \[qQ\]\[0-9\]+, \[qQ\]\[0-9\]+" 2 } } */ /* { dg-final { scan-assembler "vcge\.s8\[ \]+\[dD\]\[0-9\]+, \[dD\]\[0-9\]+, #0" } } */ -/* { dg-final { scan-assembler-times "vcge\.u8\[ \]+\[dD\]\[0-9\]+, \[dD\]\[0-9\]+, \[dD\]\[0-9\]+" 2 } } */ /* { dg-final { scan-assembler "vcge\.s16\[ \]+\[dD\]\[0-9\]+, \[dD\]\[0-9\]+, #0" } } */ -/* { dg-final { scan-assembler-times "vcge\.u16\[ \]+\[dD\]\[0-9\]+, \[dD\]\[0-9\]+, \[dD\]\[0-9\]+" 2 } } */ /* { dg-final { scan-assembler "vcge\.s32\[ \]+\[dD\]\[0-9\]+, \[dD\]\[0-9\]+, #0" } } */ -/* { dg-final { scan-assembler-times "vcge\.u32\[ \]+\[dD\]\[0-9\]+, \[dD\]\[0-9\]+, \[dD\]\[0-9\]+" 2 } } */ /* { dg-final { scan-assembler "vcge\.s8\[ \]+\[qQ\]\[0-9\]+, \[qQ\]\[0-9\]+, #0" } } */ -/* { dg-final { scan-assembler-times "vcge\.u8\[ \]+\[qQ\]\[0-9\]+, \[qQ\]\[0-9\]+, \[qQ\]\[0-9\]+" 2 } } */ /* { dg-final { scan-assembler "vcge\.s16\[ \]+\[qQ\]\[0-9\]+, \[qQ\]\[0-9\]+, #0" } } */ -/* { dg-final { scan-assembler-times "vcge\.u16\[ \]+\[qQ\]\[0-9\]+, \[qQ\]\[0-9\]+, \[qQ\]\[0-9\]+" 2 } } */ /* { dg-final { scan-assembler "vcge\.s32\[ \]+\[qQ\]\[0-9\]+, \[qQ\]\[0-9\]+, #0" } } */ -/* { dg-final { scan-assembler-times "vcge\.u32\[ \]+\[qQ\]\[0-9\]+, \[qQ\]\[0-9\]+, \[qQ\]\[0-9\]+" 2 } } */ /* { dg-final { scan-assembler "vclt\.s8\[ \]+\[dD\]\[0-9\]+, \[dD\]\[0-9\]+, #0" } } */ /* { dg-final { scan-assembler "vclt\.s16\[ \]+\[dD\]\[0-9\]+, \[dD\]\[0-9\]+, #0" } } */ /* { dg-final { scan-assembler "vclt\.s32\[ \]+\[dD\]\[0-9\]+, \[dD\]\[0-9\]+, #0" } } */ @@ -70,12 +58,14 @@ GEN_COND_TESTS(vceq) /* { dg-final { scan-assembler "vcle\.s8\[ \]+\[qQ\]\[0-9\]+, \[qQ\]\[0-9\]+, #0" } } */ /* { dg-final { scan-assembler "vcle\.s16\[ \]+\[qQ\]\[0-9\]+, \[qQ\]\[0-9\]+, #0" } } */ /* { dg-final { scan-assembler "vcle\.s32\[ \]+\[qQ\]\[0-9\]+, \[qQ\]\[0-9\]+, #0" } } */ -/* { dg-final { scan-assembler-times "vceq\.i8\[ \]+\[dD\]\[0-9\]+, \[dD\]\[0-9\]+, #0" 2 } } */ -/* { dg-final { scan-assembler-times "vceq\.i16\[ \]+\[dD\]\[0-9\]+, \[dD\]\[0-9\]+, #0" 2 } } */ -/* { dg-final { scan-assembler-times "vceq\.i32\[ \]+\[dD\]\[0-9\]+, \[dD\]\[0-9\]+, #0" 2 } } */ -/* { dg-final { scan-assembler-times "vceq\.i8\[ \]+\[qQ\]\[0-9\]+, \[qQ\]\[0-9\]+, #0" 2 } } */ -/* { dg-final { scan-assembler-times "vceq\.i16\[ \]+\[qQ\]\[0-9\]+, \[qQ\]\[0-9\]+, #0" 2 } } */ -/* { dg-final { scan-assembler-times "vceq\.i32\[ \]+\[qQ\]\[0-9\]+, \[qQ\]\[0-9\]+, #0" 2 } } */ +/* { dg-final { scan-assembler-times "vceq\.i8\[ \]+\[dD\]\[0-9\]+, \[dD\]\[0-9\]+, #0" 4 } } */ +/* { dg-final { scan-assembler-times "vceq\.i16\[ \]+\[dD\]\[0-9\]+, \[dD\]\[0-9\]+, #0" 4 } } */ +/* { dg-final { scan-assembler-times "vceq\.i32\[ \]+\[dD\]\[0-9\]+, \[dD\]\[0-9\]+, #0" 4 } } */ +/* { dg-final { scan-assembler-times "vceq\.i8\[ \]+\[qQ\]\[0-9\]+, \[qQ\]\[0-9\]+, #0" 4 } } */ +/* { dg-final { scan-assembler-times "vceq\.i16\[ \]+\[qQ\]\[0-9\]+, \[qQ\]\[0-9\]+, #0" 4 } } */ +/* { dg-final { scan-assembler-times "vceq\.i32\[ \]+\[qQ\]\[0-9\]+, \[qQ\]\[0-9\]+, #0" 4 } } */ +/* { dg-final { scan-assembler-times "vmov\.i32\[ \]+\[dD\]\[0-9\]+, #0xffffffff" 3 } } */ +/* { dg-final { scan-assembler-times "vmov\.i32\[ \]+\[qQ\]\[0-9\]+, #4294967295" 3 } } */ /* And ensure we don't have unexpected output too. */ /* { dg-final { scan-assembler-not "vc\[gl\]\[te\]\.u\[0-9\]+\[ \]+\[qQdD\]\[0-9\]+, \[qQdD\]\[0-9\]+, #0" } } */ -- cgit v1.1 From f19c70afa4aa2416c581484a6eb51c0ac46acd08 Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Wed, 11 Aug 2021 11:49:10 +0200 Subject: tree-optimization/101861 - fix gather use for non-gather refs My previous change broke the usage of gather for strided loads. The following fixes it. 2021-08-11 Richard Biener PR tree-optimization/101861 * tree-vect-stmts.c (vectorizable_load): Fix error in previous change with regard to gather vectorization. --- gcc/tree-vect-stmts.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/tree-vect-stmts.c b/gcc/tree-vect-stmts.c index ab402b5..cc6c091 100644 --- a/gcc/tree-vect-stmts.c +++ b/gcc/tree-vect-stmts.c @@ -9492,7 +9492,8 @@ vectorizable_load (vec_info *vinfo, if (memory_access_type == VMAT_GATHER_SCATTER && gs_info.ifn != IFN_LAST) { - vec_offset = vec_offsets[j]; + if (STMT_VINFO_GATHER_SCATTER_P (stmt_info)) + vec_offset = vec_offsets[j]; tree zero = build_zero_cst (vectype); tree scale = size_int (gs_info.scale); gcall *call; -- cgit v1.1 From d7e91f4894f6a1a2daeec5cbe1e912bb896b9f7a Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Wed, 11 Aug 2021 10:26:18 +0200 Subject: middle-end/101858 - avoid shift of pointer in folding This makes sure to not generate a shift of pointer types in simplification of X < (cast) (1 << Y). 2021-08-11 Richard Biener PR middle-end/101858 * fold-const.c (fold_binary_loc): Guard simplification of X < (cast) (1 << Y) to integer types. * gcc.dg/pr101858.c: New testcase. --- gcc/fold-const.c | 2 ++ gcc/testsuite/gcc.dg/pr101858.c | 9 +++++++++ 2 files changed, 11 insertions(+) create mode 100644 gcc/testsuite/gcc.dg/pr101858.c (limited to 'gcc') diff --git a/gcc/fold-const.c b/gcc/fold-const.c index 7dcecc9..ff23f12 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -12497,6 +12497,8 @@ fold_binary_loc (location_t loc, enum tree_code code, tree type, we can't optimize this. E.g. (unsigned long long) (1 << Y) for Y 31 might be 0xffffffff80000000. */ if ((code == LT_EXPR || code == GE_EXPR) + && (INTEGRAL_TYPE_P (TREE_TYPE (arg0)) + || VECTOR_INTEGER_TYPE_P (TREE_TYPE (arg0))) && TYPE_UNSIGNED (TREE_TYPE (arg0)) && CONVERT_EXPR_P (arg1) && TREE_CODE (TREE_OPERAND (arg1, 0)) == LSHIFT_EXPR diff --git a/gcc/testsuite/gcc.dg/pr101858.c b/gcc/testsuite/gcc.dg/pr101858.c new file mode 100644 index 0000000..61fcca6 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr101858.c @@ -0,0 +1,9 @@ +/* { dg-do compile } */ +/* { dg-options "-w" } */ + +int foo(int a) +{ + if (a < (int*)((__INTPTR_TYPE__)1 << a)) + a = 0; + return a; +} -- cgit v1.1 From 9851a1631f2915fafdc733539b6c8b5fb81e7ae5 Mon Sep 17 00:00:00 2001 From: Jan Hubicka Date: Wed, 11 Aug 2021 15:01:39 +0200 Subject: Fix min_flags handling in mod-ref gcc/ChangeLog: 2021-08-11 Jan Hubicka Alexandre Oliva * ipa-modref.c (modref_lattice::dump): Fix escape_point's min_flags dumping. (modref_lattice::merge_deref): Fix handling of indirect scape points. (update_escape_summary_1): Likewise. (update_escape_summary): Likewise. (ipa_merge_modref_summary_after_inlining): Likewise. gcc/testsuite/ChangeLog: * c-c++-common/modref-dse.c: New test. --- gcc/ipa-modref.c | 35 ++++++++++++++++++++---------- gcc/testsuite/c-c++-common/modref-dse.c | 38 +++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 11 deletions(-) create mode 100644 gcc/testsuite/c-c++-common/modref-dse.c (limited to 'gcc') diff --git a/gcc/ipa-modref.c b/gcc/ipa-modref.c index 7b849c1..c65b2f6 100644 --- a/gcc/ipa-modref.c +++ b/gcc/ipa-modref.c @@ -1406,7 +1406,7 @@ modref_lattice::dump (FILE *out, int indent) const fprintf (out, "%*s Arg %i (%s) min flags", indent, "", escape_points[i].arg, escape_points[i].direct ? "direct" : "indirect"); - dump_eaf_flags (out, flags, false); + dump_eaf_flags (out, escape_points[i].min_flags, false); fprintf (out, " in call "); print_gimple_stmt (out, escape_points[i].call, 0); } @@ -1503,10 +1503,18 @@ modref_lattice::merge_deref (const modref_lattice &with, bool ignore_stores) if (!flags) return changed; for (unsigned int i = 0; i < with.escape_points.length (); i++) - changed |= add_escape_point (with.escape_points[i].call, - with.escape_points[i].arg, - with.escape_points[i].min_flags, - false); + { + int min_flags = with.escape_points[i].min_flags; + + if (with.escape_points[i].direct) + min_flags = deref_flags (min_flags, ignore_stores); + else if (ignore_stores) + min_flags |= EAF_NOCLOBBER | EAF_NOESCAPE | EAF_NODIRECTESCAPE; + changed |= add_escape_point (with.escape_points[i].call, + with.escape_points[i].arg, + min_flags, + false); + } return changed; } @@ -3019,7 +3027,8 @@ struct escape_map static void update_escape_summary_1 (cgraph_edge *e, - vec > &map) + vec > &map, + bool ignore_stores) { escape_summary *sum = escape_summaries->get (e); if (!sum) @@ -3037,6 +3046,9 @@ update_escape_summary_1 (cgraph_edge *e, continue; FOR_EACH_VEC_ELT (map[ee->parm_index], j, em) { + int min_flags = ee->min_flags; + if (ee->direct && !em->direct) + min_flags = deref_flags (min_flags, ignore_stores); struct escape_entry entry = {em->parm_index, ee->arg, ee->min_flags, ee->direct & em->direct}; @@ -3051,18 +3063,19 @@ update_escape_summary_1 (cgraph_edge *e, static void update_escape_summary (cgraph_node *node, - vec > &map) + vec > &map, + bool ignore_stores) { if (!escape_summaries) return; for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee) - update_escape_summary_1 (e, map); + update_escape_summary_1 (e, map, ignore_stores); for (cgraph_edge *e = node->callees; e; e = e->next_callee) { if (!e->inline_failed) - update_escape_summary (e->callee, map); + update_escape_summary (e->callee, map, ignore_stores); else - update_escape_summary_1 (e, map); + update_escape_summary_1 (e, map, ignore_stores); } } @@ -3187,7 +3200,7 @@ ipa_merge_modref_summary_after_inlining (cgraph_edge *edge) if (needed) emap[ee->arg].safe_push (entry); } - update_escape_summary (edge->callee, emap); + update_escape_summary (edge->callee, emap, ignore_stores); for (i = 0; (int)i < max_escape + 1; i++) emap[i].release (); if (sum) diff --git a/gcc/testsuite/c-c++-common/modref-dse.c b/gcc/testsuite/c-c++-common/modref-dse.c new file mode 100644 index 0000000..5f64e8f --- /dev/null +++ b/gcc/testsuite/c-c++-common/modref-dse.c @@ -0,0 +1,38 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-dse2-details" } */ +/* { dg-final { scan-tree-dump-not "Deleted dead store" "dse2" } } */ + +struct foo { unsigned long bar; }; + +unsigned y; + +static int __attribute__ ((__noinline__, __noclone__)) +wrapped (struct foo *p, int i); + +static int wrapper (struct foo *p); + +static int __attribute__ ((__noclone__)) +wrapper (struct foo *p) { + return wrapped (p, 1); +} + +static int __attribute__ ((__noinline__, __noclone__)) +dind (struct foo **pp); + +int __attribute__ ((__noclone__, __no_reorder__)) +xfn () { + struct foo x = { 0xBADC0FFE }; + struct foo *p = &x; + return dind (&p); +} + +static int __attribute__ ((__noinline__, __no_reorder__)) +wrapped (struct foo *p, int i) { + return p->bar + i == y++; +} + +static int __attribute__ ((__noinline__, __noclone__, __no_reorder__)) +dind (struct foo **pp) { + wrapper (*pp); + return 0; +} -- cgit v1.1 From cecdff844ac3a4a1790794ce4aa17d7fa50ee3eb Mon Sep 17 00:00:00 2001 From: Eric Botcazou Date: Wed, 11 Aug 2021 15:31:32 +0200 Subject: Small tweak to expand_used_vars This completes the replacement of DECL_ATTRIBUTES (current_function_decl) with the attribs local variable. gcc/ * cfgexpand.c (expand_used_vars): Reuse attribs local variable. --- gcc/cfgexpand.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'gcc') diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c index 8183280..03260b0 100644 --- a/gcc/cfgexpand.c +++ b/gcc/cfgexpand.c @@ -2294,22 +2294,19 @@ expand_used_vars (bitmap forced_stack_vars) if (gen_stack_protect_signal || cfun->calls_alloca || has_protected_decls - || lookup_attribute ("stack_protect", - DECL_ATTRIBUTES (current_function_decl))) + || lookup_attribute ("stack_protect", attribs)) create_stack_guard (); break; case SPCT_FLAG_DEFAULT: if (cfun->calls_alloca || has_protected_decls - || lookup_attribute ("stack_protect", - DECL_ATTRIBUTES (current_function_decl))) + || lookup_attribute ("stack_protect", attribs)) create_stack_guard (); break; case SPCT_FLAG_EXPLICIT: - if (lookup_attribute ("stack_protect", - DECL_ATTRIBUTES (current_function_decl))) + if (lookup_attribute ("stack_protect", attribs)) create_stack_guard (); break; -- cgit v1.1 From e8426554e1375fec2d119ba9cc5feb263db84559 Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Mon, 9 Aug 2021 13:12:08 +0200 Subject: Adjust volatile handling of the operand scanner The GIMPLE SSA operand scanner handles COMPONENT_REFs that are not marked TREE_THIS_VOLATILE but have a TREE_THIS_VOLATILE FIELD_DECL as volatile. That's inconsistent in how TREE_THIS_VOLATILE testing on GENERIC refs works which requires operand zero of component references to mirror TREE_THIS_VOLATILE to the ref so that testing TREE_THIS_VOLATILE on the outermost reference is enough to determine the volatileness. The following patch thus removes FIELD_DECL scanning from the GIMPLE SSA operand scanner, possibly leaving fewer stmts marked as gimple_has_volatile_ops. It shows we miss at least one case in the fortran frontend, though there's a suspicious amount of COMPONENT_REF creation compared to little setting of TREE_THIS_VOLATILE. This fixes the FAIL of gfortran.dg/volatile11.f90 that would otherwise occur. Visually inspecting fortran/ reveals a bunch of likely to fix cases but I don't know the constraints of 'volatile' uses in the fortran language to assess whether some of these are not necessary. 2021-08-09 Richard Biener gcc/ * tree-ssa-operands.c (operands_scanner::get_expr_operands): Do not look at COMPONENT_REF FIELD_DECLs TREE_THIS_VOLATILE to determine has_volatile_ops. gcc/fortran/ * trans-common.c (create_common): Set TREE_THIS_VOLATILE on the COMPONENT_REF if the field is volatile. --- gcc/fortran/trans-common.c | 9 +++++---- gcc/tree-ssa-operands.c | 7 +------ 2 files changed, 6 insertions(+), 10 deletions(-) (limited to 'gcc') diff --git a/gcc/fortran/trans-common.c b/gcc/fortran/trans-common.c index a11cf4c..7bcf18d 100644 --- a/gcc/fortran/trans-common.c +++ b/gcc/fortran/trans-common.c @@ -759,10 +759,11 @@ create_common (gfc_common_head *com, segment_info *head, bool saw_equiv) else gfc_add_decl_to_function (var_decl); - SET_DECL_VALUE_EXPR (var_decl, - fold_build3_loc (input_location, COMPONENT_REF, - TREE_TYPE (s->field), - decl, s->field, NULL_TREE)); + tree comp = build3_loc (input_location, COMPONENT_REF, + TREE_TYPE (s->field), decl, s->field, NULL_TREE); + if (TREE_THIS_VOLATILE (s->field)) + TREE_THIS_VOLATILE (comp) = 1; + SET_DECL_VALUE_EXPR (var_decl, comp); DECL_HAS_VALUE_EXPR_P (var_decl) = 1; GFC_DECL_COMMON_OR_EQUIV (var_decl) = 1; diff --git a/gcc/tree-ssa-operands.c b/gcc/tree-ssa-operands.c index c155754..ebf7eea 100644 --- a/gcc/tree-ssa-operands.c +++ b/gcc/tree-ssa-operands.c @@ -834,12 +834,7 @@ operands_scanner::get_expr_operands (tree *expr_p, int flags) get_expr_operands (&TREE_OPERAND (expr, 0), flags); if (code == COMPONENT_REF) - { - if (!(flags & opf_no_vops) - && TREE_THIS_VOLATILE (TREE_OPERAND (expr, 1))) - gimple_set_has_volatile_ops (stmt, true); - get_expr_operands (&TREE_OPERAND (expr, 2), uflags); - } + get_expr_operands (&TREE_OPERAND (expr, 2), uflags); else if (code == ARRAY_REF || code == ARRAY_RANGE_REF) { get_expr_operands (&TREE_OPERAND (expr, 1), uflags); -- cgit v1.1 From 2cb02e065ff015a69db918eb545a00cd6edf0194 Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Wed, 11 Aug 2021 14:10:52 +0200 Subject: target/101788 - avoid decomposing hard-register "loads" This avoids decomposing hard-register accesses that masquerade as loads. 2021-08-11 Richard Biener PR target/101877 * tree-ssa-forwprop.c (pass_forwprop::execute): Do not decompose hard-register accesses. --- gcc/tree-ssa-forwprop.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/tree-ssa-forwprop.c b/gcc/tree-ssa-forwprop.c index bd64b8e..5b30d4c 100644 --- a/gcc/tree-ssa-forwprop.c +++ b/gcc/tree-ssa-forwprop.c @@ -3190,7 +3190,8 @@ pass_forwprop::execute (function *fun) || (fun->curr_properties & PROP_gimple_lvec)) && gimple_assign_load_p (stmt) && !gimple_has_volatile_ops (stmt) - && !stmt_can_throw_internal (cfun, stmt)) + && !stmt_can_throw_internal (cfun, stmt) + && (!VAR_P (rhs) || !DECL_HARD_REGISTER (rhs))) optimize_vector_load (&gsi); else if (code == COMPLEX_EXPR) -- cgit v1.1 From cba64d855df581cc26fa487162027138aef4dbe5 Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Wed, 11 Aug 2021 16:28:33 +0200 Subject: Fix gcc.dg/lto/pr48622_0.c testcase This fixes the testcase to not rely on the reference to ashift_qi_1 being optimized out by RTL optimization via help of the initregs pass that changes comparisons of uninitialized data with a comparison that is always false. 2021-08-11 Richard Biener * gcc.dg/lto/pr48622_1.c: Provide non-LTO definition of ashift_qi_1. --- gcc/testsuite/gcc.dg/lto/pr48622_1.c | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 gcc/testsuite/gcc.dg/lto/pr48622_1.c (limited to 'gcc') diff --git a/gcc/testsuite/gcc.dg/lto/pr48622_1.c b/gcc/testsuite/gcc.dg/lto/pr48622_1.c new file mode 100644 index 0000000..4d05bae --- /dev/null +++ b/gcc/testsuite/gcc.dg/lto/pr48622_1.c @@ -0,0 +1,6 @@ +/* { dg-options "-fno-lto" } */ + +typedef unsigned int u8 __attribute__ ((mode (QI))); +u8 ashift_qi_1 (u8) +{ +} -- cgit v1.1 From 58340a7cd3670024bafdbbc6ca63a9af841df98a Mon Sep 17 00:00:00 2001 From: Sandra Loosemore Date: Tue, 3 Aug 2021 16:21:16 -0700 Subject: Fortran: Fix c_float128 and c_float128_complex definitions. gfc_float128_type_node is only non-NULL on targets that support a 128-bit type that is not long double. Use float128_type_node instead when computing the value of the kind constants c_float128 and c_float128_complex from the ISO_C_BINDING intrinsic module; this also ensures it actually corresponds to __float128 (the IEEE encoding) and not some other 128-bit floating-point type. 2021-08-11 Sandra Loosemore gcc/fortran/ * iso-c-binding.def (c_float128, c_float128_complex): Check float128_type_node instead of gfc_float128_type_node. * trans-types.c (gfc_init_kinds, gfc_build_real_type): Update comments re supported 128-bit floating-point types. --- gcc/fortran/iso-c-binding.def | 15 +++++++++++---- gcc/fortran/trans-types.c | 12 ++++++++++-- 2 files changed, 21 insertions(+), 6 deletions(-) (limited to 'gcc') diff --git a/gcc/fortran/iso-c-binding.def b/gcc/fortran/iso-c-binding.def index 8bf69ef..e65c750 100644 --- a/gcc/fortran/iso-c-binding.def +++ b/gcc/fortran/iso-c-binding.def @@ -114,9 +114,14 @@ NAMED_REALCST (ISOCBINDING_DOUBLE, "c_double", \ get_real_kind_from_node (double_type_node), GFC_STD_F2003) NAMED_REALCST (ISOCBINDING_LONG_DOUBLE, "c_long_double", \ get_real_kind_from_node (long_double_type_node), GFC_STD_F2003) + +/* GNU Extension. Note that the equivalence here is specifically to + the IEEE 128-bit type __float128; if that does not map onto a type + otherwise supported by the Fortran front end, get_real_kind_from_node + will reject it as unsupported. */ NAMED_REALCST (ISOCBINDING_FLOAT128, "c_float128", \ - gfc_float128_type_node == NULL_TREE \ - ? -4 : get_real_kind_from_node (gfc_float128_type_node), \ + (float128_type_node == NULL_TREE \ + ? -4 : get_real_kind_from_node (float128_type_node)), \ GFC_STD_GNU) NAMED_CMPXCST (ISOCBINDING_FLOAT_COMPLEX, "c_float_complex", \ get_real_kind_from_node (float_type_node), GFC_STD_F2003) @@ -124,9 +129,11 @@ NAMED_CMPXCST (ISOCBINDING_DOUBLE_COMPLEX, "c_double_complex", \ get_real_kind_from_node (double_type_node), GFC_STD_F2003) NAMED_CMPXCST (ISOCBINDING_LONG_DOUBLE_COMPLEX, "c_long_double_complex", \ get_real_kind_from_node (long_double_type_node), GFC_STD_F2003) + +/* GNU Extension. Similar issues to c_float128 above. */ NAMED_CMPXCST (ISOCBINDING_FLOAT128_COMPLEX, "c_float128_complex", \ - gfc_float128_type_node == NULL_TREE \ - ? -4 : get_real_kind_from_node (gfc_float128_type_node), \ + (float128_type_node == NULL_TREE \ + ? -4 : get_real_kind_from_node (float128_type_node)), \ GFC_STD_GNU) NAMED_LOGCST (ISOCBINDING_BOOL, "c_bool", \ diff --git a/gcc/fortran/trans-types.c b/gcc/fortran/trans-types.c index 50fda43..1c78a90 100644 --- a/gcc/fortran/trans-types.c +++ b/gcc/fortran/trans-types.c @@ -446,7 +446,7 @@ gfc_init_kinds (void) if (!targetm.scalar_mode_supported_p (mode)) continue; - /* Only let float, double, long double and __float128 go through. + /* Only let float, double, long double and TFmode go through. Runtime support for others is not provided, so they would be useless. */ if (!targetm.libgcc_floating_mode_supported_p (mode)) @@ -471,7 +471,14 @@ gfc_init_kinds (void) We round up so as to handle IA-64 __floatreg (RFmode), which is an 82 bit type. Not to be confused with __float80 (XFmode), which is an 80 bit type also supported by IA-64. So XFmode should come out - to be kind=10, and RFmode should come out to be kind=11. Egads. */ + to be kind=10, and RFmode should come out to be kind=11. Egads. + + TODO: The kind calculation has to be modified to support all + three 128-bit floating-point modes on PowerPC as IFmode, KFmode, + and TFmode since the following line would all map to kind=16. + However, currently only float, double, long double, and TFmode + reach this code. + */ kind = (GET_MODE_PRECISION (mode) + 7) / 8; @@ -851,6 +858,7 @@ gfc_build_real_type (gfc_real_info *info) info->c_long_double = 1; if (mode_precision != LONG_DOUBLE_TYPE_SIZE && mode_precision == 128) { + /* TODO: see PR101835. */ info->c_float128 = 1; gfc_real16_is_float128 = true; } -- cgit v1.1 From 6186708312780bb2139da01946abdde39667e985 Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Wed, 11 Aug 2021 15:58:30 -0400 Subject: c++: most vexing parse and braced CTAD [PR89062] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Here grokdeclarator is emitting the error error: class template placeholder ‘Foo’ not permitted in this context during the tentative (and ultimately futile) parse of 'x' as a function declaration. This happens because when parsing 'Foo{1}', cp_parser_parameter_declaration yields a parameter declaration with no declarator and whose type is a CTAD placeholder, and stops short of consuming the '{'. The caller cp_parser_parameter_declaration_list then calls grokdeclarator on this declarator, hence the error, and soon thereafter we abort this tentative parse since the next token '{' doesn't make sense in the context of a parameter list. Note that we don't have this issue with parenthesized CTAD Foo x(Foo(1)); because in this case cp_parser_direct_declarator (called indirectly from c_p_p_d) consumes the '(' and returns cp_error_declarator instead of a NULL declarator (and also simulates a parse error), and grokdeclarator exits early for this declarator without emitting any error. Since grokdeclarator doesn't take a 'complain' parameter, to fix this we need to avoid calling grokdeclarator in this situation. To that end this patch makes c_p_p_d simulate an error when a construct is a CTAD expression and definitely not a parameter declaration, so that c_p_p_d_l can avoid calling grokdeclarator by checking for this simulated error. Alternatively we could keep all this logic inside c_p_p_d_l and not touch c_p_p_d at all, but this approach seems slightly less adhoc. PR c++/89062 gcc/cp/ChangeLog: * parser.c (cp_parser_parameter_declaration_list): Don't call grokdeclarator if cp_parser_error_occurred. (cp_parser_parameter_declaration): Simulate an error if we see the beginning of a CTAD form, i.e. if we see an opening brace after the decl-specifier-seq and the type is a CTAD placeholder. gcc/testsuite/ChangeLog: * g++.dg/cpp1z/class-deduction97.C: New test. --- gcc/cp/parser.c | 17 +++++++++++++---- gcc/testsuite/g++.dg/cpp1z/class-deduction97.C | 6 ++++++ 2 files changed, 19 insertions(+), 4 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp1z/class-deduction97.C (limited to 'gcc') diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 1be42a1..87e8d37 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -24284,7 +24284,7 @@ cp_parser_parameter_declaration_list (cp_parser* parser, cp_parser_flags flags) and warn in grokparms if appropriate. */ deprecated_state = DEPRECATED_SUPPRESS; - if (parameter) + if (parameter && !cp_parser_error_occurred (parser)) { decl = grokdeclarator (parameter->declarator, ¶meter->decl_specifiers, @@ -24499,7 +24499,7 @@ cp_parser_parameter_declaration (cp_parser *parser, parser->default_arg_ok_p = false; /* After seeing a decl-specifier-seq, if the next token is not a - "(", there is no possibility that the code is a valid + "(" or "{", there is no possibility that the code is a valid expression. Therefore, if parsing tentatively, we commit at this point. */ if (!parser->in_template_argument_list_p @@ -24512,9 +24512,18 @@ cp_parser_parameter_declaration (cp_parser *parser, of some object of type "char" to "int". */ && !parser->in_type_id_in_expr_p && cp_parser_uncommitted_to_tentative_parse_p (parser) - && cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_BRACE) && cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_PAREN)) - cp_parser_commit_to_tentative_parse (parser); + { + if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE)) + { + if (decl_specifiers.type + && template_placeholder_p (decl_specifiers.type)) + /* This is a CTAD expression, not a parameter declaration. */ + cp_parser_simulate_error (parser); + } + else + cp_parser_commit_to_tentative_parse (parser); + } /* Parse the declarator. */ declarator_token_start = token; declarator = cp_parser_declarator (parser, diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction97.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction97.C new file mode 100644 index 0000000..3281868 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction97.C @@ -0,0 +1,6 @@ +// PR c++/89062 +// { dg-do compile { target c++17 } } + +template struct Foo { Foo(T); }; + +Foo x(Foo{1}); -- cgit v1.1 From 7e39d1a15f5276f72ee478a692445569bb646e65 Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Wed, 11 Aug 2021 15:59:22 -0400 Subject: c++: recognize class-scope non-template dguides [PR79501] It looks like we still don't recognize class-scope non-template deduction guides even after r12-2260. This is because deduction guides are tagged as such in cp_parser_init_declarator after calling cp_parser_declarator, but in cp_parser_member_declaration we call cp_parser_declarator directly. So let's tag them in cp_parser_member_declaration as well. PR c++/79501 gcc/cp/ChangeLog: * parser.c (maybe_adjust_declarator_for_dguide): New, split out from ... (cp_parser_init_declarator): ... here. (cp_parser_member_declaration): Use it. gcc/testsuite/ChangeLog: * g++.dg/cpp1z/class-deduction98.C: New test. --- gcc/cp/parser.c | 63 ++++++++++++++++++-------- gcc/testsuite/g++.dg/cpp1z/class-deduction98.C | 10 ++++ 2 files changed, 54 insertions(+), 19 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp1z/class-deduction98.C (limited to 'gcc') diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 87e8d37..b5e117d 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -22078,6 +22078,37 @@ warn_about_ambiguous_parse (const cp_decl_specifier_seq *decl_specifiers, } } +/* If DECLARATOR with DECL_SPECS is a function declarator that has + the form of a deduction guide, tag it as such. CTOR_DTOR_OR_CONV_P + has the same meaning as in cp_parser_declarator. */ + +static void +cp_parser_maybe_adjust_declarator_for_dguide (cp_parser *parser, + cp_decl_specifier_seq *decl_specs, + cp_declarator *declarator, + int *ctor_dtor_or_conv_p) +{ + if (cxx_dialect >= cxx17 + && *ctor_dtor_or_conv_p <= 0 + && !decl_specs->type + && !decl_specs->any_type_specifiers_p + && function_declarator_p (declarator)) + { + cp_declarator *id = get_id_declarator (declarator); + tree name = id->u.id.unqualified_name; + parser->scope = id->u.id.qualifying_scope; + tree tmpl = cp_parser_lookup_name_simple (parser, name, id->id_loc); + if (tmpl + && (DECL_CLASS_TEMPLATE_P (tmpl) + || DECL_TEMPLATE_TEMPLATE_PARM_P (tmpl))) + { + id->u.id.unqualified_name = dguide_name (tmpl); + id->u.id.sfk = sfk_deduction_guide; + *ctor_dtor_or_conv_p = 1; + } + } +} + /* Declarators [gram.dcl.decl] */ /* Parse an init-declarator. @@ -22254,25 +22285,13 @@ cp_parser_init_declarator (cp_parser* parser, if (function_declarator_p (declarator)) { - /* Handle C++17 deduction guides. */ - if (!decl_specifiers->type - && !decl_specifiers->any_type_specifiers_p - && ctor_dtor_or_conv_p <= 0 - && cxx_dialect >= cxx17) - { - cp_declarator *id = get_id_declarator (declarator); - tree name = id->u.id.unqualified_name; - parser->scope = id->u.id.qualifying_scope; - tree tmpl = cp_parser_lookup_name_simple (parser, name, id->id_loc); - if (tmpl - && (DECL_CLASS_TEMPLATE_P (tmpl) - || DECL_TEMPLATE_TEMPLATE_PARM_P (tmpl))) - { - id->u.id.unqualified_name = dguide_name (tmpl); - id->u.id.sfk = sfk_deduction_guide; - ctor_dtor_or_conv_p = 1; - } - } + /* Handle C++17 deduction guides. Note that class-scope + non-template deduction guides are instead handled in + cp_parser_member_declaration. */ + cp_parser_maybe_adjust_declarator_for_dguide (parser, + decl_specifiers, + declarator, + &ctor_dtor_or_conv_p); if (!member_p && !cp_parser_error_occurred (parser)) warn_about_ambiguous_parse (decl_specifiers, declarator); @@ -26956,6 +26975,12 @@ cp_parser_member_declaration (cp_parser* parser) goto out; } + /* Handle class-scope non-template C++17 deduction guides. */ + cp_parser_maybe_adjust_declarator_for_dguide (parser, + &decl_specifiers, + declarator, + &ctor_dtor_or_conv_p); + if (declares_class_or_enum & 2) cp_parser_check_for_definition_in_return_type (declarator, decl_specifiers.type, diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction98.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction98.C new file mode 100644 index 0000000..bee0ce4 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction98.C @@ -0,0 +1,10 @@ +// PR c++/79501 +// { dg-do compile { target c++17 } } + +template +struct A { + template struct B { template B(V); }; + B(T) -> B; +}; + +A::B b(0); -- cgit v1.1 From ee8f9ff00d79998274c967ad0c23692be9dd3ada Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Wed, 11 Aug 2021 22:00:29 +0200 Subject: c++: Optimize constinit thread_local vars [PR101786] The paper that introduced constinit mentioned in rationale that constinit can be used on externs as well and that it can be used to avoid the thread_local initialization wrappers, because the standard requires that if constinit is present on any declaration, it is also present on the initialization declaration, even if it is in some other TU etc. There is a small problem though, we use the tls wrappers not just if the thread_local variable needs dynamic initialization, but also when it has static initialization, but non-trivial destructor, as the "dynamic initialization" in that case needs to register the destructor. So, the following patch optimizes constinit thread_local vars only if we can prove they will not have non-trivial destructors. That includes the case where we have incomplete type where we don't know and need to conservatively assume the type will have non-trivial destructor at the initializing declaration side. 2021-08-11 Jakub Jelinek PR c++/101786 * decl2.c (var_defined_without_dynamic_init): Return true for DECL_DECLARED_CONSTINIT_P with complete type and trivial destructor. * g++.dg/cpp2a/constinit16.C: New test. --- gcc/cp/decl2.c | 6 ++++++ gcc/testsuite/g++.dg/cpp2a/constinit16.C | 21 +++++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 gcc/testsuite/g++.dg/cpp2a/constinit16.C (limited to 'gcc') diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 9564b0d..ba27388 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -3447,6 +3447,12 @@ set_guard (tree guard) static bool var_defined_without_dynamic_init (tree var) { + /* constinit vars are guaranteed to not have dynamic initializer, + but still registering the destructor counts as dynamic initialization. */ + if (DECL_DECLARED_CONSTINIT_P (var) + && COMPLETE_TYPE_P (TREE_TYPE (var)) + && !TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (var))) + return true; /* If it's defined in another TU, we can't tell. */ if (DECL_EXTERNAL (var)) return false; diff --git a/gcc/testsuite/g++.dg/cpp2a/constinit16.C b/gcc/testsuite/g++.dg/cpp2a/constinit16.C new file mode 100644 index 0000000..dda81d5 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/constinit16.C @@ -0,0 +1,21 @@ +// PR c++/101786 +// { dg-do compile { target c++20 } } +// { dg-add-options tls } +// { dg-require-alias "" } +// { dg-require-effective-target tls_runtime } +// { dg-final { scan-assembler-not "_ZTH17mythreadlocalvar1" } } +// { dg-final { scan-assembler "_ZTH17mythreadlocalvar2" } } +// { dg-final { scan-assembler-not "_ZTH17mythreadlocalvar3" } } +// { dg-final { scan-assembler "_ZTH17mythreadlocalvar4" } } + +extern thread_local constinit int mythreadlocalvar1; +struct S; +extern thread_local constinit S mythreadlocalvar2; +struct T { int t; }; +extern thread_local constinit T mythreadlocalvar3; +struct U { int u; ~U (); }; +extern thread_local constinit U mythreadlocalvar4; +int foo () { return mythreadlocalvar1; } +S *bar () { return &mythreadlocalvar2; } +T *baz () { return &mythreadlocalvar3; } +U *qux () { return &mythreadlocalvar4; } -- cgit v1.1 From 9707d2e5dbb92d2bc990c922461a5a16ae652319 Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Wed, 11 Aug 2021 16:53:53 -0400 Subject: c++: parameterized requires-expr as default argument [PR101725] Here we're rejecting the default template argument requires (T t) { x(t); } because we consider the 't' in the requirement to be a local variable (according to local_variable_p), and we generally forbid local variables from appearing inside default arguments. We can perhaps fix this by giving special treatment to parameters introduced by requires-expressions, but DR 2082 relaxed the restriction about local variables appearing within default arguments to permit them inside unevaluated operands thereof. So this patch just implements DR 2082 which also fixes this PR since a requires-expression is an unevaluated context. PR c++/101725 DR 2082 gcc/cp/ChangeLog: * cp-tree.h (unevaluated_p): Return true for REQUIRES_EXPR. * decl.c (local_variable_p_walkfn): Don't walk into unevaluated operands. * parser.c (cp_parser_primary_expression) : Never reject uses of local variables in unevaluated contexts. * tree.c (cp_walk_subtrees) : Increment cp_unevaluated_operand. Use cp_walk_tree directly instead of WALK_SUBTREE to avoid the goto. Use REQUIRES_EXPR_REQS instead of TREE_OPERAND directly. gcc/testsuite/ChangeLog: * g++.dg/DRs/dr2082.C: New test. * g++.dg/cpp2a/concepts-uneval4.C: New test. --- gcc/cp/cp-tree.h | 3 ++- gcc/cp/decl.c | 8 ++++++++ gcc/cp/parser.c | 5 ++++- gcc/cp/tree.c | 4 +++- gcc/testsuite/g++.dg/DRs/dr2082.C | 12 ++++++++++++ gcc/testsuite/g++.dg/cpp2a/concepts-uneval4.C | 12 ++++++++++++ 6 files changed, 41 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/g++.dg/DRs/dr2082.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-uneval4.C (limited to 'gcc') diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 9a47a87..6a8264b 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -8494,7 +8494,8 @@ unevaluated_p (tree_code code) return (code == DECLTYPE_TYPE || code == ALIGNOF_EXPR || code == SIZEOF_EXPR - || code == NOEXCEPT_EXPR); + || code == NOEXCEPT_EXPR + || code == REQUIRES_EXPR); } /* RAII class to push/pop the access scope for T. */ diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index f626f1e..b3671ee 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -14270,6 +14270,14 @@ static tree local_variable_p_walkfn (tree *tp, int *walk_subtrees, void * /*data*/) { + if (unevaluated_p (TREE_CODE (*tp))) + { + /* DR 2082 permits local variables in unevaluated contexts + within a default argument. */ + *walk_subtrees = 0; + return NULL_TREE; + } + if (local_variable_p (*tp) && (!DECL_ARTIFICIAL (*tp) || DECL_NAME (*tp) == this_identifier)) return *tp; diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index b5e117d..d564e3b 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -5989,7 +5989,10 @@ cp_parser_primary_expression (cp_parser *parser, /* Check to see if DECL is a local variable in a context where that is forbidden. */ if ((parser->local_variables_forbidden_p & LOCAL_VARS_FORBIDDEN) - && local_variable_p (decl)) + && local_variable_p (decl) + /* DR 2082 permits local variables in unevaluated contexts + within a default argument. */ + && !cp_unevaluated_operand) { const char *msg = (TREE_CODE (decl) == PARM_DECL diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 8345396..e8831b2 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -5386,7 +5386,9 @@ cp_walk_subtrees (tree *tp, int *walk_subtrees_p, walk_tree_fn func, // walk the parameter list. Doing so causes false // positives in the pack expansion checker since the // requires parameters are introduced as pack expansions. - WALK_SUBTREE (TREE_OPERAND (*tp, 1)); + ++cp_unevaluated_operand; + result = cp_walk_tree (&REQUIRES_EXPR_REQS (*tp), func, data, pset); + --cp_unevaluated_operand; *walk_subtrees_p = 0; break; diff --git a/gcc/testsuite/g++.dg/DRs/dr2082.C b/gcc/testsuite/g++.dg/DRs/dr2082.C new file mode 100644 index 0000000..84bb23f --- /dev/null +++ b/gcc/testsuite/g++.dg/DRs/dr2082.C @@ -0,0 +1,12 @@ +// DR 2082 + +void f() { + int i; + extern void h(int x = sizeof(i)); +} + +class A { + void f(A* p = this) { } // { dg-error "this" } +}; + +int h(int a, int b = sizeof(a)); diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-uneval4.C b/gcc/testsuite/g++.dg/cpp2a/concepts-uneval4.C new file mode 100644 index 0000000..1be27d1 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-uneval4.C @@ -0,0 +1,12 @@ +// PR c++/101725 +// { dg-do compile { target c++20 } } + +template void f(); + +struct A { + int m; + void f(int a, int b = requires (int t) { a + m + t; }); +}; + +void g(); +static_assert(noexcept(requires { g(); })); -- cgit v1.1 From 6cc92e946edab03b26f8aaca23064adf664433f9 Mon Sep 17 00:00:00 2001 From: Bill Schmidt Date: Thu, 10 Jun 2021 11:14:51 -0500 Subject: rs6000: Add the rest of the [altivec] stanza to the builtins file 2021-06-10 Bill Schmidt gcc/ * config/rs6000/rs6000-builtin-new.def: Finish altivec stanza. * config/rs6000/rs6000-call.c (rs6000_init_builtins): Move initialization of pcvoid_type_node here... (altivec_init_builtins): ...from here. * config/rs6000/rs6000.h (rs6000_builtin_type_index): Add RS6000_BTI_const_ptr_void. (pcvoid_type_node): New macro. --- gcc/config/rs6000/rs6000-builtin-new.def | 831 +++++++++++++++++++++++++++++++ gcc/config/rs6000/rs6000-call.c | 7 +- gcc/config/rs6000/rs6000.h | 2 + 3 files changed, 836 insertions(+), 4 deletions(-) (limited to 'gcc') diff --git a/gcc/config/rs6000/rs6000-builtin-new.def b/gcc/config/rs6000/rs6000-builtin-new.def index a84a3de..f1aa552 100644 --- a/gcc/config/rs6000/rs6000-builtin-new.def +++ b/gcc/config/rs6000/rs6000-builtin-new.def @@ -197,3 +197,834 @@ const vss __builtin_altivec_abs_v8hi (vss); ABS_V8HI absv8hi2 {} + + const vsc __builtin_altivec_abss_v16qi (vsc); + ABSS_V16QI altivec_abss_v16qi {} + + const vsi __builtin_altivec_abss_v4si (vsi); + ABSS_V4SI altivec_abss_v4si {} + + const vss __builtin_altivec_abss_v8hi (vss); + ABSS_V8HI altivec_abss_v8hi {} + + const vf __builtin_altivec_copysignfp (vf, vf); + COPYSIGN_V4SF vector_copysignv4sf3 {} + + void __builtin_altivec_dss (const int<2>); + DSS altivec_dss {} + + void __builtin_altivec_dssall (); + DSSALL altivec_dssall {} + + void __builtin_altivec_dst (void *, const int, const int<2>); + DST altivec_dst {} + + void __builtin_altivec_dstst (void *, const int, const int<2>); + DSTST altivec_dstst {} + + void __builtin_altivec_dststt (void *, const int, const int<2>); + DSTSTT altivec_dststt {} + + void __builtin_altivec_dstt (void *, const int, const int<2>); + DSTT altivec_dstt {} + + fpmath vsi __builtin_altivec_fix_sfsi (vf); + FIX_V4SF_V4SI fix_truncv4sfv4si2 {} + + fpmath vui __builtin_altivec_fixuns_sfsi (vf); + FIXUNS_V4SF_V4SI fixuns_truncv4sfv4si2 {} + + fpmath vf __builtin_altivec_float_sisf (vsi); + FLOAT_V4SI_V4SF floatv4siv4sf2 {} + + pure vsc __builtin_altivec_lvebx (signed long, const void *); + LVEBX altivec_lvebx {ldvec} + + pure vss __builtin_altivec_lvehx (signed long, const void *); + LVEHX altivec_lvehx {ldvec} + + pure vsi __builtin_altivec_lvewx (signed long, const void *); + LVEWX altivec_lvewx {ldvec} + + pure vuc __builtin_altivec_lvsl (signed long, const void *); + LVSL altivec_lvsl {ldvec} + + pure vuc __builtin_altivec_lvsr (signed long, const void *); + LVSR altivec_lvsr {ldvec} + + pure vsi __builtin_altivec_lvx (signed long, const void *); + LVX altivec_lvx_v4si {ldvec} + + pure vsq __builtin_altivec_lvx_v1ti (signed long, const void *); + LVX_V1TI altivec_lvx_v1ti {ldvec} + + pure vsc __builtin_altivec_lvx_v16qi (signed long, const void *); + LVX_V16QI altivec_lvx_v16qi {ldvec} + + pure vf __builtin_altivec_lvx_v4sf (signed long, const void *); + LVX_V4SF altivec_lvx_v4sf {ldvec} + + pure vsi __builtin_altivec_lvx_v4si (signed long, const void *); + LVX_V4SI altivec_lvx_v4si {ldvec} + + pure vss __builtin_altivec_lvx_v8hi (signed long, const void *); + LVX_V8HI altivec_lvx_v8hi {ldvec} + + pure vsi __builtin_altivec_lvxl (signed long, const void *); + LVXL altivec_lvxl_v4si {ldvec} + + pure vsc __builtin_altivec_lvxl_v16qi (signed long, const void *); + LVXL_V16QI altivec_lvxl_v16qi {ldvec} + + pure vf __builtin_altivec_lvxl_v4sf (signed long, const void *); + LVXL_V4SF altivec_lvxl_v4sf {ldvec} + + pure vsi __builtin_altivec_lvxl_v4si (signed long, const void *); + LVXL_V4SI altivec_lvxl_v4si {ldvec} + + pure vss __builtin_altivec_lvxl_v8hi (signed long, const void *); + LVXL_V8HI altivec_lvxl_v8hi {ldvec} + + const vsc __builtin_altivec_mask_for_load (const void *); + MASK_FOR_LOAD altivec_lvsr_direct {ldstmask} + + vss __builtin_altivec_mfvscr (); + MFVSCR altivec_mfvscr {} + + void __builtin_altivec_mtvscr (vsi); + MTVSCR altivec_mtvscr {} + + const vsll __builtin_altivec_vmulesw (vsi, vsi); + VMULESW vec_widen_smult_even_v4si {} + + const vull __builtin_altivec_vmuleuw (vui, vui); + VMULEUW vec_widen_umult_even_v4si {} + + const vsll __builtin_altivec_vmulosw (vsi, vsi); + VMULOSW vec_widen_smult_odd_v4si {} + + const vull __builtin_altivec_vmulouw (vui, vui); + VMULOUW vec_widen_umult_odd_v4si {} + + const vsc __builtin_altivec_nabs_v16qi (vsc); + NABS_V16QI nabsv16qi2 {} + + const vf __builtin_altivec_nabs_v4sf (vf); + NABS_V4SF vsx_nabsv4sf2 {} + + const vsi __builtin_altivec_nabs_v4si (vsi); + NABS_V4SI nabsv4si2 {} + + const vss __builtin_altivec_nabs_v8hi (vss); + NABS_V8HI nabsv8hi2 {} + + void __builtin_altivec_stvebx (vsc, signed long, void *); + STVEBX altivec_stvebx {stvec} + + void __builtin_altivec_stvehx (vss, signed long, void *); + STVEHX altivec_stvehx {stvec} + + void __builtin_altivec_stvewx (vsi, signed long, void *); + STVEWX altivec_stvewx {stvec} + + void __builtin_altivec_stvx (vsi, signed long, void *); + STVX altivec_stvx_v4si {stvec} + + void __builtin_altivec_stvx_v16qi (vsc, signed long, void *); + STVX_V16QI altivec_stvx_v16qi {stvec} + + void __builtin_altivec_stvx_v4sf (vf, signed long, void *); + STVX_V4SF altivec_stvx_v4sf {stvec} + + void __builtin_altivec_stvx_v4si (vsi, signed long, void *); + STVX_V4SI altivec_stvx_v4si {stvec} + + void __builtin_altivec_stvx_v8hi (vss, signed long, void *); + STVX_V8HI altivec_stvx_v8hi {stvec} + + void __builtin_altivec_stvxl (vsi, signed long, void *); + STVXL altivec_stvxl_v4si {stvec} + + void __builtin_altivec_stvxl_v16qi (vsc, signed long, void *); + STVXL_V16QI altivec_stvxl_v16qi {stvec} + + void __builtin_altivec_stvxl_v4sf (vf, signed long, void *); + STVXL_V4SF altivec_stvxl_v4sf {stvec} + + void __builtin_altivec_stvxl_v4si (vsi, signed long, void *); + STVXL_V4SI altivec_stvxl_v4si {stvec} + + void __builtin_altivec_stvxl_v8hi (vss, signed long, void *); + STVXL_V8HI altivec_stvxl_v8hi {stvec} + + fpmath vf __builtin_altivec_uns_float_sisf (vui); + UNSFLOAT_V4SI_V4SF floatunsv4siv4sf2 {} + + const vui __builtin_altivec_vaddcuw (vui, vui); + VADDCUW altivec_vaddcuw {} + + const vf __builtin_altivec_vaddfp (vf, vf); + VADDFP addv4sf3 {} + + const vsc __builtin_altivec_vaddsbs (vsc, vsc); + VADDSBS altivec_vaddsbs {} + + const vss __builtin_altivec_vaddshs (vss, vss); + VADDSHS altivec_vaddshs {} + + const vsi __builtin_altivec_vaddsws (vsi, vsi); + VADDSWS altivec_vaddsws {} + + const vuc __builtin_altivec_vaddubm (vuc, vuc); + VADDUBM addv16qi3 {} + + const vuc __builtin_altivec_vaddubs (vuc, vuc); + VADDUBS altivec_vaddubs {} + + const vus __builtin_altivec_vadduhm (vus, vus); + VADDUHM addv8hi3 {} + + const vus __builtin_altivec_vadduhs (vus, vus); + VADDUHS altivec_vadduhs {} + + const vsi __builtin_altivec_vadduwm (vsi, vsi); + VADDUWM addv4si3 {} + + const vui __builtin_altivec_vadduws (vui, vui); + VADDUWS altivec_vadduws {} + + const vsc __builtin_altivec_vand_v16qi (vsc, vsc); + VAND_V16QI andv16qi3 {} + + const vuc __builtin_altivec_vand_v16qi_uns (vuc, vuc); + VAND_V16QI_UNS andv16qi3 {} + + const vf __builtin_altivec_vand_v4sf (vf, vf); + VAND_V4SF andv4sf3 {} + + const vsi __builtin_altivec_vand_v4si (vsi, vsi); + VAND_V4SI andv4si3 {} + + const vui __builtin_altivec_vand_v4si_uns (vui, vui); + VAND_V4SI_UNS andv4si3 {} + + const vss __builtin_altivec_vand_v8hi (vss, vss); + VAND_V8HI andv8hi3 {} + + const vus __builtin_altivec_vand_v8hi_uns (vus, vus); + VAND_V8HI_UNS andv8hi3 {} + + const vsc __builtin_altivec_vandc_v16qi (vsc, vsc); + VANDC_V16QI andcv16qi3 {} + + const vuc __builtin_altivec_vandc_v16qi_uns (vuc, vuc); + VANDC_V16QI_UNS andcv16qi3 {} + + const vf __builtin_altivec_vandc_v4sf (vf, vf); + VANDC_V4SF andcv4sf3 {} + + const vsi __builtin_altivec_vandc_v4si (vsi, vsi); + VANDC_V4SI andcv4si3 {} + + const vui __builtin_altivec_vandc_v4si_uns (vui, vui); + VANDC_V4SI_UNS andcv4si3 {} + + const vss __builtin_altivec_vandc_v8hi (vss, vss); + VANDC_V8HI andcv8hi3 {} + + const vus __builtin_altivec_vandc_v8hi_uns (vus, vus); + VANDC_V8HI_UNS andcv8hi3 {} + + const vsc __builtin_altivec_vavgsb (vsc, vsc); + VAVGSB avgv16qi3_ceil {} + + const vss __builtin_altivec_vavgsh (vss, vss); + VAVGSH avgv8hi3_ceil {} + + const vsi __builtin_altivec_vavgsw (vsi, vsi); + VAVGSW avgv4si3_ceil {} + + const vuc __builtin_altivec_vavgub (vuc, vuc); + VAVGUB uavgv16qi3_ceil {} + + const vus __builtin_altivec_vavguh (vus, vus); + VAVGUH uavgv8hi3_ceil {} + + const vui __builtin_altivec_vavguw (vui, vui); + VAVGUW uavgv4si3_ceil {} + + const vf __builtin_altivec_vcfsx (vsi, const int<5>); + VCFSX altivec_vcfsx {} + + const vf __builtin_altivec_vcfux (vui, const int<5>); + VCFUX altivec_vcfux {} + + const vsi __builtin_altivec_vcmpbfp (vf, vf); + VCMPBFP altivec_vcmpbfp {} + + const int __builtin_altivec_vcmpbfp_p (int, vf, vf); + VCMPBFP_P altivec_vcmpbfp_p {pred} + + const vf __builtin_altivec_vcmpeqfp (vf, vf); + VCMPEQFP vector_eqv4sf {} + + const int __builtin_altivec_vcmpeqfp_p (int, vf, vf); + VCMPEQFP_P vector_eq_v4sf_p {pred} + + const vsc __builtin_altivec_vcmpequb (vuc, vuc); + VCMPEQUB vector_eqv16qi {} + + const int __builtin_altivec_vcmpequb_p (int, vsc, vsc); + VCMPEQUB_P vector_eq_v16qi_p {pred} + + const vss __builtin_altivec_vcmpequh (vus, vus); + VCMPEQUH vector_eqv8hi {} + + const int __builtin_altivec_vcmpequh_p (int, vss, vss); + VCMPEQUH_P vector_eq_v8hi_p {pred} + + const vsi __builtin_altivec_vcmpequw (vui, vui); + VCMPEQUW vector_eqv4si {} + + const int __builtin_altivec_vcmpequw_p (int, vsi, vsi); + VCMPEQUW_P vector_eq_v4si_p {pred} + + const vf __builtin_altivec_vcmpgefp (vf, vf); + VCMPGEFP vector_gev4sf {} + + const int __builtin_altivec_vcmpgefp_p (int, vf, vf); + VCMPGEFP_P vector_ge_v4sf_p {pred} + + const vf __builtin_altivec_vcmpgtfp (vf, vf); + VCMPGTFP vector_gtv4sf {} + + const int __builtin_altivec_vcmpgtfp_p (int, vf, vf); + VCMPGTFP_P vector_gt_v4sf_p {pred} + + const vsc __builtin_altivec_vcmpgtsb (vsc, vsc); + VCMPGTSB vector_gtv16qi {} + + const int __builtin_altivec_vcmpgtsb_p (int, vsc, vsc); + VCMPGTSB_P vector_gt_v16qi_p {pred} + + const vss __builtin_altivec_vcmpgtsh (vss, vss); + VCMPGTSH vector_gtv8hi {} + + const int __builtin_altivec_vcmpgtsh_p (int, vss, vss); + VCMPGTSH_P vector_gt_v8hi_p {pred} + + const vsi __builtin_altivec_vcmpgtsw (vsi, vsi); + VCMPGTSW vector_gtv4si {} + + const int __builtin_altivec_vcmpgtsw_p (int, vsi, vsi); + VCMPGTSW_P vector_gt_v4si_p {pred} + + const vsc __builtin_altivec_vcmpgtub (vuc, vuc); + VCMPGTUB vector_gtuv16qi {} + + const int __builtin_altivec_vcmpgtub_p (int, vsc, vsc); + VCMPGTUB_P vector_gtu_v16qi_p {pred} + + const vss __builtin_altivec_vcmpgtuh (vus, vus); + VCMPGTUH vector_gtuv8hi {} + + const int __builtin_altivec_vcmpgtuh_p (int, vss, vss); + VCMPGTUH_P vector_gtu_v8hi_p {pred} + + const vsi __builtin_altivec_vcmpgtuw (vui, vui); + VCMPGTUW vector_gtuv4si {} + + const int __builtin_altivec_vcmpgtuw_p (int, vsi, vsi); + VCMPGTUW_P vector_gtu_v4si_p {pred} + + const vsi __builtin_altivec_vctsxs (vf, const int<5>); + VCTSXS altivec_vctsxs {} + + const vui __builtin_altivec_vctuxs (vf, const int<5>); + VCTUXS altivec_vctuxs {} + + fpmath vf __builtin_altivec_vexptefp (vf); + VEXPTEFP altivec_vexptefp {} + + fpmath vf __builtin_altivec_vlogefp (vf); + VLOGEFP altivec_vlogefp {} + + fpmath vf __builtin_altivec_vmaddfp (vf, vf, vf); + VMADDFP fmav4sf4 {} + + const vf __builtin_altivec_vmaxfp (vf, vf); + VMAXFP smaxv4sf3 {} + + const vsc __builtin_altivec_vmaxsb (vsc, vsc); + VMAXSB smaxv16qi3 {} + + const vuc __builtin_altivec_vmaxub (vuc, vuc); + VMAXUB umaxv16qi3 {} + + const vss __builtin_altivec_vmaxsh (vss, vss); + VMAXSH smaxv8hi3 {} + + const vsi __builtin_altivec_vmaxsw (vsi, vsi); + VMAXSW smaxv4si3 {} + + const vus __builtin_altivec_vmaxuh (vus, vus); + VMAXUH umaxv8hi3 {} + + const vui __builtin_altivec_vmaxuw (vui, vui); + VMAXUW umaxv4si3 {} + + vss __builtin_altivec_vmhaddshs (vss, vss, vss); + VMHADDSHS altivec_vmhaddshs {} + + vss __builtin_altivec_vmhraddshs (vss, vss, vss); + VMHRADDSHS altivec_vmhraddshs {} + + const vf __builtin_altivec_vminfp (vf, vf); + VMINFP sminv4sf3 {} + + const vsc __builtin_altivec_vminsb (vsc, vsc); + VMINSB sminv16qi3 {} + + const vss __builtin_altivec_vminsh (vss, vss); + VMINSH sminv8hi3 {} + + const vsi __builtin_altivec_vminsw (vsi, vsi); + VMINSW sminv4si3 {} + + const vuc __builtin_altivec_vminub (vuc, vuc); + VMINUB uminv16qi3 {} + + const vus __builtin_altivec_vminuh (vus, vus); + VMINUH uminv8hi3 {} + + const vui __builtin_altivec_vminuw (vui, vui); + VMINUW uminv4si3 {} + + const vss __builtin_altivec_vmladduhm (vss, vss, vss); + VMLADDUHM fmav8hi4 {} + + const vsc __builtin_altivec_vmrghb (vsc, vsc); + VMRGHB altivec_vmrghb {} + + const vss __builtin_altivec_vmrghh (vss, vss); + VMRGHH altivec_vmrghh {} + + const vsi __builtin_altivec_vmrghw (vsi, vsi); + VMRGHW altivec_vmrghw {} + + const vsc __builtin_altivec_vmrglb (vsc, vsc); + VMRGLB altivec_vmrglb {} + + const vss __builtin_altivec_vmrglh (vss, vss); + VMRGLH altivec_vmrglh {} + + const vsi __builtin_altivec_vmrglw (vsi, vsi); + VMRGLW altivec_vmrglw {} + + const vsi __builtin_altivec_vmsummbm (vsc, vuc, vsi); + VMSUMMBM altivec_vmsummbm {} + + const vsi __builtin_altivec_vmsumshm (vss, vss, vsi); + VMSUMSHM altivec_vmsumshm {} + + vsi __builtin_altivec_vmsumshs (vss, vss, vsi); + VMSUMSHS altivec_vmsumshs {} + + const vui __builtin_altivec_vmsumubm (vuc, vuc, vui); + VMSUMUBM altivec_vmsumubm {} + + const vui __builtin_altivec_vmsumuhm (vus, vus, vui); + VMSUMUHM altivec_vmsumuhm {} + + vui __builtin_altivec_vmsumuhs (vus, vus, vui); + VMSUMUHS altivec_vmsumuhs {} + + const vss __builtin_altivec_vmulesb (vsc, vsc); + VMULESB vec_widen_smult_even_v16qi {} + + const vsi __builtin_altivec_vmulesh (vss, vss); + VMULESH vec_widen_smult_even_v8hi {} + + const vus __builtin_altivec_vmuleub (vuc, vuc); + VMULEUB vec_widen_umult_even_v16qi {} + + const vui __builtin_altivec_vmuleuh (vus, vus); + VMULEUH vec_widen_umult_even_v8hi {} + + const vss __builtin_altivec_vmulosb (vsc, vsc); + VMULOSB vec_widen_smult_odd_v16qi {} + + const vus __builtin_altivec_vmuloub (vuc, vuc); + VMULOUB vec_widen_umult_odd_v16qi {} + + const vsi __builtin_altivec_vmulosh (vss, vss); + VMULOSH vec_widen_smult_odd_v8hi {} + + const vui __builtin_altivec_vmulouh (vus, vus); + VMULOUH vec_widen_umult_odd_v8hi {} + + fpmath vf __builtin_altivec_vnmsubfp (vf, vf, vf); + VNMSUBFP nfmsv4sf4 {} + + const vsc __builtin_altivec_vnor_v16qi (vsc, vsc); + VNOR_V16QI norv16qi3 {} + + const vuc __builtin_altivec_vnor_v16qi_uns (vuc, vuc); + VNOR_V16QI_UNS norv16qi3 {} + + const vf __builtin_altivec_vnor_v4sf (vf, vf); + VNOR_V4SF norv4sf3 {} + + const vsi __builtin_altivec_vnor_v4si (vsi, vsi); + VNOR_V4SI norv4si3 {} + + const vui __builtin_altivec_vnor_v4si_uns (vui, vui); + VNOR_V4SI_UNS norv4si3 {} + + const vss __builtin_altivec_vnor_v8hi (vss, vss); + VNOR_V8HI norv8hi3 {} + + const vus __builtin_altivec_vnor_v8hi_uns (vus, vus); + VNOR_V8HI_UNS norv8hi3 {} + + const vsc __builtin_altivec_vor_v16qi (vsc, vsc); + VOR_V16QI iorv16qi3 {} + + const vuc __builtin_altivec_vor_v16qi_uns (vuc, vuc); + VOR_V16QI_UNS iorv16qi3 {} + + const vf __builtin_altivec_vor_v4sf (vf, vf); + VOR_V4SF iorv4sf3 {} + + const vsi __builtin_altivec_vor_v4si (vsi, vsi); + VOR_V4SI iorv4si3 {} + + const vui __builtin_altivec_vor_v4si_uns (vui, vui); + VOR_V4SI_UNS iorv4si3 {} + + const vss __builtin_altivec_vor_v8hi (vss, vss); + VOR_V8HI iorv8hi3 {} + + const vus __builtin_altivec_vor_v8hi_uns (vus, vus); + VOR_V8HI_UNS iorv8hi3 {} + + const vsc __builtin_altivec_vperm_16qi (vsc, vsc, vuc); + VPERM_16QI altivec_vperm_v16qi {} + + const vuc __builtin_altivec_vperm_16qi_uns (vuc, vuc, vuc); + VPERM_16QI_UNS altivec_vperm_v16qi_uns {} + + const vsq __builtin_altivec_vperm_1ti (vsq, vsq, vuc); + VPERM_1TI altivec_vperm_v1ti {} + + const vuq __builtin_altivec_vperm_1ti_uns (vuq, vuq, vuc); + VPERM_1TI_UNS altivec_vperm_v1ti_uns {} + + const vf __builtin_altivec_vperm_4sf (vf, vf, vuc); + VPERM_4SF altivec_vperm_v4sf {} + + const vsi __builtin_altivec_vperm_4si (vsi, vsi, vuc); + VPERM_4SI altivec_vperm_v4si {} + + const vui __builtin_altivec_vperm_4si_uns (vui, vui, vuc); + VPERM_4SI_UNS altivec_vperm_v4si_uns {} + + const vss __builtin_altivec_vperm_8hi (vss, vss, vuc); + VPERM_8HI altivec_vperm_v8hi {} + + const vus __builtin_altivec_vperm_8hi_uns (vus, vus, vuc); + VPERM_8HI_UNS altivec_vperm_v8hi_uns {} + + const vp __builtin_altivec_vpkpx (vui, vui); + VPKPX altivec_vpkpx {} + + const vsc __builtin_altivec_vpkshss (vss, vss); + VPKSHSS altivec_vpkshss {} + + const vuc __builtin_altivec_vpkshus (vss, vss); + VPKSHUS altivec_vpkshus {} + + const vss __builtin_altivec_vpkswss (vsi, vsi); + VPKSWSS altivec_vpkswss {} + + const vus __builtin_altivec_vpkswus (vsi, vsi); + VPKSWUS altivec_vpkswus {} + + const vsc __builtin_altivec_vpkuhum (vss, vss); + VPKUHUM altivec_vpkuhum {} + + const vuc __builtin_altivec_vpkuhus (vus, vus); + VPKUHUS altivec_vpkuhus {} + + const vss __builtin_altivec_vpkuwum (vsi, vsi); + VPKUWUM altivec_vpkuwum {} + + const vus __builtin_altivec_vpkuwus (vui, vui); + VPKUWUS altivec_vpkuwus {} + + const vf __builtin_altivec_vrecipdivfp (vf, vf); + VRECIPFP recipv4sf3 {} + + fpmath vf __builtin_altivec_vrefp (vf); + VREFP rev4sf2 {} + + const vsc __builtin_altivec_vreve_v16qi (vsc); + VREVE_V16QI altivec_vrevev16qi2 {} + + const vf __builtin_altivec_vreve_v4sf (vf); + VREVE_V4SF altivec_vrevev4sf2 {} + + const vsi __builtin_altivec_vreve_v4si (vsi); + VREVE_V4SI altivec_vrevev4si2 {} + + const vss __builtin_altivec_vreve_v8hi (vss); + VREVE_V8HI altivec_vrevev8hi2 {} + + fpmath vf __builtin_altivec_vrfim (vf); + VRFIM vector_floorv4sf2 {} + + fpmath vf __builtin_altivec_vrfin (vf); + VRFIN altivec_vrfin {} + + fpmath vf __builtin_altivec_vrfip (vf); + VRFIP vector_ceilv4sf2 {} + + fpmath vf __builtin_altivec_vrfiz (vf); + VRFIZ vector_btruncv4sf2 {} + + const vsc __builtin_altivec_vrlb (vsc, vsc); + VRLB vrotlv16qi3 {} + + const vss __builtin_altivec_vrlh (vss, vss); + VRLH vrotlv8hi3 {} + + const vsi __builtin_altivec_vrlw (vsi, vsi); + VRLW vrotlv4si3 {} + + fpmath vf __builtin_altivec_vrsqrtefp (vf); + VRSQRTEFP rsqrtev4sf2 {} + + fpmath vf __builtin_altivec_vrsqrtfp (vf); + VRSQRTFP rsqrtv4sf2 {} + + const vsc __builtin_altivec_vsel_16qi (vsc, vsc, vuc); + VSEL_16QI vector_select_v16qi {} + + const vuc __builtin_altivec_vsel_16qi_uns (vuc, vuc, vuc); + VSEL_16QI_UNS vector_select_v16qi_uns {} + + const vsq __builtin_altivec_vsel_1ti (vsq, vsq, vuq); + VSEL_1TI vector_select_v1ti {} + + const vuq __builtin_altivec_vsel_1ti_uns (vuq, vuq, vuq); + VSEL_1TI_UNS vector_select_v1ti_uns {} + + const vf __builtin_altivec_vsel_4sf (vf, vf, vf); + VSEL_4SF vector_select_v4sf {} + + const vsi __builtin_altivec_vsel_4si (vsi, vsi, vui); + VSEL_4SI vector_select_v4si {} + + const vui __builtin_altivec_vsel_4si_uns (vui, vui, vui); + VSEL_4SI_UNS vector_select_v4si_uns {} + + const vss __builtin_altivec_vsel_8hi (vss, vss, vus); + VSEL_8HI vector_select_v8hi {} + + const vus __builtin_altivec_vsel_8hi_uns (vus, vus, vus); + VSEL_8HI_UNS vector_select_v8hi_uns {} + + const vsi __builtin_altivec_vsl (vsi, vsi); + VSL altivec_vsl {} + + const vsc __builtin_altivec_vslb (vsc, vuc); + VSLB vashlv16qi3 {} + + const vsc __builtin_altivec_vsldoi_16qi (vsc, vsc, const int<4>); + VSLDOI_16QI altivec_vsldoi_v16qi {} + + const vf __builtin_altivec_vsldoi_4sf (vf, vf, const int<4>); + VSLDOI_4SF altivec_vsldoi_v4sf {} + + const vsi __builtin_altivec_vsldoi_4si (vsi, vsi, const int<4>); + VSLDOI_4SI altivec_vsldoi_v4si {} + + const vss __builtin_altivec_vsldoi_8hi (vss, vss, const int<4>); + VSLDOI_8HI altivec_vsldoi_v8hi {} + + const vss __builtin_altivec_vslh (vss, vus); + VSLH vashlv8hi3 {} + + const vsi __builtin_altivec_vslo (vsi, vsi); + VSLO altivec_vslo {} + + const vsi __builtin_altivec_vslw (vsi, vui); + VSLW vashlv4si3 {} + + const vsc __builtin_altivec_vspltb (vsc, const int<4>); + VSPLTB altivec_vspltb {} + + const vss __builtin_altivec_vsplth (vss, const int<3>); + VSPLTH altivec_vsplth {} + + const vsc __builtin_altivec_vspltisb (const int<-16,15>); + VSPLTISB altivec_vspltisb {} + + const vss __builtin_altivec_vspltish (const int<-16,15>); + VSPLTISH altivec_vspltish {} + + const vsi __builtin_altivec_vspltisw (const int<-16,15>); + VSPLTISW altivec_vspltisw {} + + const vsi __builtin_altivec_vspltw (vsi, const int<2>); + VSPLTW altivec_vspltw {} + + const vsi __builtin_altivec_vsr (vsi, vsi); + VSR altivec_vsr {} + + const vsc __builtin_altivec_vsrab (vsc, vuc); + VSRAB vashrv16qi3 {} + + const vss __builtin_altivec_vsrah (vss, vus); + VSRAH vashrv8hi3 {} + + const vsi __builtin_altivec_vsraw (vsi, vui); + VSRAW vashrv4si3 {} + + const vsc __builtin_altivec_vsrb (vsc, vuc); + VSRB vlshrv16qi3 {} + + const vss __builtin_altivec_vsrh (vss, vus); + VSRH vlshrv8hi3 {} + + const vsi __builtin_altivec_vsro (vsi, vsi); + VSRO altivec_vsro {} + + const vsi __builtin_altivec_vsrw (vsi, vui); + VSRW vlshrv4si3 {} + + const vsi __builtin_altivec_vsubcuw (vsi, vsi); + VSUBCUW altivec_vsubcuw {} + + const vf __builtin_altivec_vsubfp (vf, vf); + VSUBFP subv4sf3 {} + + const vsc __builtin_altivec_vsubsbs (vsc, vsc); + VSUBSBS altivec_vsubsbs {} + + const vss __builtin_altivec_vsubshs (vss, vss); + VSUBSHS altivec_vsubshs {} + + const vsi __builtin_altivec_vsubsws (vsi, vsi); + VSUBSWS altivec_vsubsws {} + + const vuc __builtin_altivec_vsububm (vuc, vuc); + VSUBUBM subv16qi3 {} + + const vuc __builtin_altivec_vsububs (vuc, vuc); + VSUBUBS altivec_vsububs {} + + const vus __builtin_altivec_vsubuhm (vus, vus); + VSUBUHM subv8hi3 {} + + const vus __builtin_altivec_vsubuhs (vus, vus); + VSUBUHS altivec_vsubuhs {} + + const vui __builtin_altivec_vsubuwm (vui, vui); + VSUBUWM subv4si3 {} + + const vui __builtin_altivec_vsubuws (vui, vui); + VSUBUWS altivec_vsubuws {} + + const vsi __builtin_altivec_vsum2sws (vsi, vsi); + VSUM2SWS altivec_vsum2sws {} + + const vsi __builtin_altivec_vsum4sbs (vsc, vsi); + VSUM4SBS altivec_vsum4sbs {} + + const vsi __builtin_altivec_vsum4shs (vss, vsi); + VSUM4SHS altivec_vsum4shs {} + + const vui __builtin_altivec_vsum4ubs (vuc, vui); + VSUM4UBS altivec_vsum4ubs {} + + const vsi __builtin_altivec_vsumsws (vsi, vsi); + VSUMSWS altivec_vsumsws {} + + const vsi __builtin_altivec_vsumsws_be (vsi, vsi); + VSUMSWS_BE altivec_vsumsws_direct {} + + const vui __builtin_altivec_vupkhpx (vp); + VUPKHPX altivec_vupkhpx {} + + const vss __builtin_altivec_vupkhsb (vsc); + VUPKHSB altivec_vupkhsb {} + + const vsi __builtin_altivec_vupkhsh (vss); + VUPKHSH altivec_vupkhsh {} + + const vui __builtin_altivec_vupklpx (vp); + VUPKLPX altivec_vupklpx {} + + const vss __builtin_altivec_vupklsb (vsc); + VUPKLSB altivec_vupklsb {} + + const vsi __builtin_altivec_vupklsh (vss); + VUPKLSH altivec_vupklsh {} + + const vsc __builtin_altivec_vxor_v16qi (vsc, vsc); + VXOR_V16QI xorv16qi3 {} + + const vuc __builtin_altivec_vxor_v16qi_uns (vuc, vuc); + VXOR_V16QI_UNS xorv16qi3 {} + + const vf __builtin_altivec_vxor_v4sf (vf, vf); + VXOR_V4SF xorv4sf3 {} + + const vsi __builtin_altivec_vxor_v4si (vsi, vsi); + VXOR_V4SI xorv4si3 {} + + const vui __builtin_altivec_vxor_v4si_uns (vui, vui); + VXOR_V4SI_UNS xorv4si3 {} + + const vss __builtin_altivec_vxor_v8hi (vss, vss); + VXOR_V8HI xorv8hi3 {} + + const vus __builtin_altivec_vxor_v8hi_uns (vus, vus); + VXOR_V8HI_UNS xorv8hi3 {} + + const signed char __builtin_vec_ext_v16qi (vsc, signed int); + VEC_EXT_V16QI nothing {extract} + + const float __builtin_vec_ext_v4sf (vf, signed int); + VEC_EXT_V4SF nothing {extract} + + const signed int __builtin_vec_ext_v4si (vsi, signed int); + VEC_EXT_V4SI nothing {extract} + + const signed short __builtin_vec_ext_v8hi (vss, signed int); + VEC_EXT_V8HI nothing {extract} + + const vsc __builtin_vec_init_v16qi (signed char, signed char, signed char, signed char, signed char, signed char, signed char, signed char, signed char, signed char, signed char, signed char, signed char, signed char, signed char, signed char); + VEC_INIT_V16QI nothing {init} + + const vf __builtin_vec_init_v4sf (float, float, float, float); + VEC_INIT_V4SF nothing {init} + + const vsi __builtin_vec_init_v4si (signed int, signed int, signed int, signed int); + VEC_INIT_V4SI nothing {init} + + const vss __builtin_vec_init_v8hi (signed short, signed short, signed short, signed short, signed short, signed short, signed short, signed short); + VEC_INIT_V8HI nothing {init} + + const vsc __builtin_vec_set_v16qi (vsc, signed char, const int<4>); + VEC_SET_V16QI nothing {set} + + const vf __builtin_vec_set_v4sf (vf, float, const int<2>); + VEC_SET_V4SF nothing {set} + + const vsi __builtin_vec_set_v4si (vsi, signed int, const int<2>); + VEC_SET_V4SI nothing {set} + + const vss __builtin_vec_set_v8hi (vss, signed short, const int<3>); + VEC_SET_V8HI nothing {set} diff --git a/gcc/config/rs6000/rs6000-call.c b/gcc/config/rs6000/rs6000-call.c index 904e104..8b16d65 100644 --- a/gcc/config/rs6000/rs6000-call.c +++ b/gcc/config/rs6000/rs6000-call.c @@ -13493,6 +13493,9 @@ rs6000_init_builtins (void) intTI_type_node, 1); pixel_V8HI_type_node = rs6000_vector_type ("__vector __pixel", pixel_type_node, 8); + pcvoid_type_node + = build_pointer_type (build_qualified_type (void_type_node, + TYPE_QUAL_CONST)); /* Create Altivec, VSX and MMA builtins on machines with at least the general purpose extensions (970 and newer) to allow the use of @@ -13652,10 +13655,6 @@ altivec_init_builtins (void) tree pvoid_type_node = build_pointer_type (void_type_node); - tree pcvoid_type_node - = build_pointer_type (build_qualified_type (void_type_node, - TYPE_QUAL_CONST)); - tree int_ftype_opaque = build_function_type_list (integer_type_node, opaque_V4SI_type_node, NULL_TREE); diff --git a/gcc/config/rs6000/rs6000.h b/gcc/config/rs6000/rs6000.h index 4ca6372..c5d20d2 100644 --- a/gcc/config/rs6000/rs6000.h +++ b/gcc/config/rs6000/rs6000.h @@ -2460,6 +2460,7 @@ enum rs6000_builtin_type_index RS6000_BTI_const_str, /* pointer to const char * */ RS6000_BTI_vector_pair, /* unsigned 256-bit types (vector pair). */ RS6000_BTI_vector_quad, /* unsigned 512-bit types (vector quad). */ + RS6000_BTI_const_ptr_void, /* const pointer to void */ RS6000_BTI_MAX }; @@ -2515,6 +2516,7 @@ enum rs6000_builtin_type_index #define const_str_type_node (rs6000_builtin_types[RS6000_BTI_const_str]) #define vector_pair_type_node (rs6000_builtin_types[RS6000_BTI_vector_pair]) #define vector_quad_type_node (rs6000_builtin_types[RS6000_BTI_vector_quad]) +#define pcvoid_type_node (rs6000_builtin_types[RS6000_BTI_const_ptr_void]) extern GTY(()) tree rs6000_builtin_types[RS6000_BTI_MAX]; extern GTY(()) tree rs6000_builtin_decls[RS6000_BUILTIN_COUNT]; -- cgit v1.1 From ba6aa47470550065d1ff8a8acb40654cdc85fbd9 Mon Sep 17 00:00:00 2001 From: Bill Schmidt Date: Wed, 11 Aug 2021 14:56:26 -0500 Subject: rs6000: Add VSX builtins 2021-08-11 Bill Schmidt gcc/ * config/rs6000/rs6000-builtin-new.def: Add vsx stanza. --- gcc/config/rs6000/rs6000-builtin-new.def | 857 +++++++++++++++++++++++++++++++ 1 file changed, 857 insertions(+) (limited to 'gcc') diff --git a/gcc/config/rs6000/rs6000-builtin-new.def b/gcc/config/rs6000/rs6000-builtin-new.def index f1aa552..b5d3570 100644 --- a/gcc/config/rs6000/rs6000-builtin-new.def +++ b/gcc/config/rs6000/rs6000-builtin-new.def @@ -1028,3 +1028,860 @@ const vss __builtin_vec_set_v8hi (vss, signed short, const int<3>); VEC_SET_V8HI nothing {set} + + +; VSX builtins. +[vsx] + pure vd __builtin_altivec_lvx_v2df (signed long, const void *); + LVX_V2DF altivec_lvx_v2df {ldvec} + + pure vsll __builtin_altivec_lvx_v2di (signed long, const void *); + LVX_V2DI altivec_lvx_v2di {ldvec} + + pure vd __builtin_altivec_lvxl_v2df (signed long, const void *); + LVXL_V2DF altivec_lvxl_v2df {ldvec} + + pure vsll __builtin_altivec_lvxl_v2di (signed long, const void *); + LVXL_V2DI altivec_lvxl_v2di {ldvec} + + const vd __builtin_altivec_nabs_v2df (vd); + NABS_V2DF vsx_nabsv2df2 {} + + const vsll __builtin_altivec_nabs_v2di (vsll); + NABS_V2DI nabsv2di2 {} + + void __builtin_altivec_stvx_v2df (vd, signed long, void *); + STVX_V2DF altivec_stvx_v2df {stvec} + + void __builtin_altivec_stvx_v2di (vsll, signed long, void *); + STVX_V2DI altivec_stvx_v2di {stvec} + + void __builtin_altivec_stvxl_v2df (vd, signed long, void *); + STVXL_V2DF altivec_stvxl_v2df {stvec} + + void __builtin_altivec_stvxl_v2di (vsll, signed long, void *); + STVXL_V2DI altivec_stvxl_v2di {stvec} + + const vd __builtin_altivec_vand_v2df (vd, vd); + VAND_V2DF andv2df3 {} + + const vsll __builtin_altivec_vand_v2di (vsll, vsll); + VAND_V2DI andv2di3 {} + + const vull __builtin_altivec_vand_v2di_uns (vull, vull); + VAND_V2DI_UNS andv2di3 {} + + const vd __builtin_altivec_vandc_v2df (vd, vd); + VANDC_V2DF andcv2df3 {} + + const vsll __builtin_altivec_vandc_v2di (vsll, vsll); + VANDC_V2DI andcv2di3 {} + + const vull __builtin_altivec_vandc_v2di_uns (vull, vull); + VANDC_V2DI_UNS andcv2di3 {} + + const vsll __builtin_altivec_vcmpequd (vull, vull); + VCMPEQUD vector_eqv2di {} + + const int __builtin_altivec_vcmpequd_p (int, vsll, vsll); + VCMPEQUD_P vector_eq_v2di_p {pred} + + const vsll __builtin_altivec_vcmpgtsd (vsll, vsll); + VCMPGTSD vector_gtv2di {} + + const int __builtin_altivec_vcmpgtsd_p (int, vsll, vsll); + VCMPGTSD_P vector_gt_v2di_p {pred} + + const vsll __builtin_altivec_vcmpgtud (vull, vull); + VCMPGTUD vector_gtuv2di {} + + const int __builtin_altivec_vcmpgtud_p (int, vsll, vsll); + VCMPGTUD_P vector_gtu_v2di_p {pred} + + const vd __builtin_altivec_vnor_v2df (vd, vd); + VNOR_V2DF norv2df3 {} + + const vsll __builtin_altivec_vnor_v2di (vsll, vsll); + VNOR_V2DI norv2di3 {} + + const vull __builtin_altivec_vnor_v2di_uns (vull, vull); + VNOR_V2DI_UNS norv2di3 {} + + const vd __builtin_altivec_vor_v2df (vd, vd); + VOR_V2DF iorv2df3 {} + + const vsll __builtin_altivec_vor_v2di (vsll, vsll); + VOR_V2DI iorv2di3 {} + + const vull __builtin_altivec_vor_v2di_uns (vull, vull); + VOR_V2DI_UNS iorv2di3 {} + + const vd __builtin_altivec_vperm_2df (vd, vd, vuc); + VPERM_2DF altivec_vperm_v2df {} + + const vsll __builtin_altivec_vperm_2di (vsll, vsll, vuc); + VPERM_2DI altivec_vperm_v2di {} + + const vull __builtin_altivec_vperm_2di_uns (vull, vull, vuc); + VPERM_2DI_UNS altivec_vperm_v2di_uns {} + + const vd __builtin_altivec_vreve_v2df (vd); + VREVE_V2DF altivec_vrevev2df2 {} + + const vsll __builtin_altivec_vreve_v2di (vsll); + VREVE_V2DI altivec_vrevev2di2 {} + + const vd __builtin_altivec_vsel_2df (vd, vd, vd); + VSEL_2DF vector_select_v2df {} + + const vsll __builtin_altivec_vsel_2di (vsll, vsll, vsll); + VSEL_2DI_B vector_select_v2di {} + + const vull __builtin_altivec_vsel_2di_uns (vull, vull, vull); + VSEL_2DI_UNS vector_select_v2di_uns {} + + const vd __builtin_altivec_vsldoi_2df (vd, vd, const int<4>); + VSLDOI_2DF altivec_vsldoi_v2df {} + + const vsll __builtin_altivec_vsldoi_2di (vsll, vsll, const int<4>); + VSLDOI_2DI altivec_vsldoi_v2di {} + + const vd __builtin_altivec_vxor_v2df (vd, vd); + VXOR_V2DF xorv2df3 {} + + const vsll __builtin_altivec_vxor_v2di (vsll, vsll); + VXOR_V2DI xorv2di3 {} + + const vull __builtin_altivec_vxor_v2di_uns (vull, vull); + VXOR_V2DI_UNS xorv2di3 {} + + const signed __int128 __builtin_vec_ext_v1ti (vsq, signed int); + VEC_EXT_V1TI nothing {extract} + + const double __builtin_vec_ext_v2df (vd, signed int); + VEC_EXT_V2DF nothing {extract} + + const signed long long __builtin_vec_ext_v2di (vsll, signed int); + VEC_EXT_V2DI nothing {extract} + + const vsq __builtin_vec_init_v1ti (signed __int128); + VEC_INIT_V1TI nothing {init} + + const vd __builtin_vec_init_v2df (double, double); + VEC_INIT_V2DF nothing {init} + + const vsll __builtin_vec_init_v2di (signed long long, signed long long); + VEC_INIT_V2DI nothing {init} + + const vsq __builtin_vec_set_v1ti (vsq, signed __int128, const int<0,0>); + VEC_SET_V1TI nothing {set} + + const vd __builtin_vec_set_v2df (vd, double, const int<1>); + VEC_SET_V2DF nothing {set} + + const vsll __builtin_vec_set_v2di (vsll, signed long long, const int<1>); + VEC_SET_V2DI nothing {set} + + const vsc __builtin_vsx_cmpge_16qi (vsc, vsc); + CMPGE_16QI vector_nltv16qi {} + + const vsll __builtin_vsx_cmpge_2di (vsll, vsll); + CMPGE_2DI vector_nltv2di {} + + const vsi __builtin_vsx_cmpge_4si (vsi, vsi); + CMPGE_4SI vector_nltv4si {} + + const vss __builtin_vsx_cmpge_8hi (vss, vss); + CMPGE_8HI vector_nltv8hi {} + + const vsc __builtin_vsx_cmpge_u16qi (vuc, vuc); + CMPGE_U16QI vector_nltuv16qi {} + + const vsll __builtin_vsx_cmpge_u2di (vull, vull); + CMPGE_U2DI vector_nltuv2di {} + + const vsi __builtin_vsx_cmpge_u4si (vui, vui); + CMPGE_U4SI vector_nltuv4si {} + + const vss __builtin_vsx_cmpge_u8hi (vus, vus); + CMPGE_U8HI vector_nltuv8hi {} + + const vsc __builtin_vsx_cmple_16qi (vsc, vsc); + CMPLE_16QI vector_ngtv16qi {} + + const vsll __builtin_vsx_cmple_2di (vsll, vsll); + CMPLE_2DI vector_ngtv2di {} + + const vsi __builtin_vsx_cmple_4si (vsi, vsi); + CMPLE_4SI vector_ngtv4si {} + + const vss __builtin_vsx_cmple_8hi (vss, vss); + CMPLE_8HI vector_ngtv8hi {} + + const vsc __builtin_vsx_cmple_u16qi (vsc, vsc); + CMPLE_U16QI vector_ngtuv16qi {} + + const vsll __builtin_vsx_cmple_u2di (vsll, vsll); + CMPLE_U2DI vector_ngtuv2di {} + + const vsi __builtin_vsx_cmple_u4si (vsi, vsi); + CMPLE_U4SI vector_ngtuv4si {} + + const vss __builtin_vsx_cmple_u8hi (vss, vss); + CMPLE_U8HI vector_ngtuv8hi {} + + const vd __builtin_vsx_concat_2df (double, double); + CONCAT_2DF vsx_concat_v2df {} + + const vsll __builtin_vsx_concat_2di (signed long long, signed long long); + CONCAT_2DI vsx_concat_v2di {} + + const vd __builtin_vsx_cpsgndp (vd, vd); + CPSGNDP vector_copysignv2df3 {} + + const vf __builtin_vsx_cpsgnsp (vf, vf); + CPSGNSP vector_copysignv4sf3 {} + + const vsll __builtin_vsx_div_2di (vsll, vsll); + DIV_V2DI vsx_div_v2di {} + + const vd __builtin_vsx_doublee_v4sf (vf); + DOUBLEE_V4SF doubleev4sf2 {} + + const vd __builtin_vsx_doublee_v4si (vsi); + DOUBLEE_V4SI doubleev4si2 {} + + const vd __builtin_vsx_doubleh_v4sf (vf); + DOUBLEH_V4SF doublehv4sf2 {} + + const vd __builtin_vsx_doubleh_v4si (vsi); + DOUBLEH_V4SI doublehv4si2 {} + + const vd __builtin_vsx_doublel_v4sf (vf); + DOUBLEL_V4SF doublelv4sf2 {} + + const vd __builtin_vsx_doublel_v4si (vsi); + DOUBLEL_V4SI doublelv4si2 {} + + const vd __builtin_vsx_doubleo_v4sf (vf); + DOUBLEO_V4SF doubleov4sf2 {} + + const vd __builtin_vsx_doubleo_v4si (vsi); + DOUBLEO_V4SI doubleov4si2 {} + + const vf __builtin_vsx_floate_v2df (vd); + FLOATE_V2DF floatev2df {} + + const vf __builtin_vsx_floate_v2di (vsll); + FLOATE_V2DI floatev2di {} + + const vf __builtin_vsx_floato_v2df (vd); + FLOATO_V2DF floatov2df {} + + const vf __builtin_vsx_floato_v2di (vsll); + FLOATO_V2DI floatov2di {} + + pure vsq __builtin_vsx_ld_elemrev_v1ti (signed long, const void *); + LD_ELEMREV_V1TI vsx_ld_elemrev_v1ti {ldvec,endian} + + pure vd __builtin_vsx_ld_elemrev_v2df (signed long, const void *); + LD_ELEMREV_V2DF vsx_ld_elemrev_v2df {ldvec,endian} + + pure vsll __builtin_vsx_ld_elemrev_v2di (signed long, const void *); + LD_ELEMREV_V2DI vsx_ld_elemrev_v2di {ldvec,endian} + + pure vf __builtin_vsx_ld_elemrev_v4sf (signed long, const void *); + LD_ELEMREV_V4SF vsx_ld_elemrev_v4sf {ldvec,endian} + + pure vsi __builtin_vsx_ld_elemrev_v4si (signed long, const void *); + LD_ELEMREV_V4SI vsx_ld_elemrev_v4si {ldvec,endian} + + pure vss __builtin_vsx_ld_elemrev_v8hi (signed long, const void *); + LD_ELEMREV_V8HI vsx_ld_elemrev_v8hi {ldvec,endian} + + pure vsc __builtin_vsx_ld_elemrev_v16qi (signed long, const void *); + LD_ELEMREV_V16QI vsx_ld_elemrev_v16qi {ldvec,endian} + +; TODO: There is apparent intent in rs6000-builtin.def to have +; RS6000_BTC_SPECIAL processing for LXSDX, LXVDSX, and STXSDX, but there are +; no def_builtin calls for any of them. At some point, we may want to add a +; set of built-ins for whichever vector types make sense for these. + + pure vsq __builtin_vsx_lxvd2x_v1ti (signed long, const void *); + LXVD2X_V1TI vsx_load_v1ti {ldvec} + + pure vd __builtin_vsx_lxvd2x_v2df (signed long, const void *); + LXVD2X_V2DF vsx_load_v2df {ldvec} + + pure vsll __builtin_vsx_lxvd2x_v2di (signed long, const void *); + LXVD2X_V2DI vsx_load_v2di {ldvec} + + pure vsc __builtin_vsx_lxvw4x_v16qi (signed long, const void *); + LXVW4X_V16QI vsx_load_v16qi {ldvec} + + pure vf __builtin_vsx_lxvw4x_v4sf (signed long, const void *); + LXVW4X_V4SF vsx_load_v4sf {ldvec} + + pure vsi __builtin_vsx_lxvw4x_v4si (signed long, const void *); + LXVW4X_V4SI vsx_load_v4si {ldvec} + + pure vss __builtin_vsx_lxvw4x_v8hi (signed long, const void *); + LXVW4X_V8HI vsx_load_v8hi {ldvec} + + const vd __builtin_vsx_mergeh_2df (vd, vd); + VEC_MERGEH_V2DF vsx_mergeh_v2df {} + + const vsll __builtin_vsx_mergeh_2di (vsll, vsll); + VEC_MERGEH_V2DI vsx_mergeh_v2di {} + + const vd __builtin_vsx_mergel_2df (vd, vd); + VEC_MERGEL_V2DF vsx_mergel_v2df {} + + const vsll __builtin_vsx_mergel_2di (vsll, vsll); + VEC_MERGEL_V2DI vsx_mergel_v2di {} + + const vsll __builtin_vsx_mul_2di (vsll, vsll); + MUL_V2DI vsx_mul_v2di {} + + const vsq __builtin_vsx_set_1ti (vsq, signed __int128, const int<0,0>); + SET_1TI vsx_set_v1ti {set} + + const vd __builtin_vsx_set_2df (vd, double, const int<0,1>); + SET_2DF vsx_set_v2df {set} + + const vsll __builtin_vsx_set_2di (vsll, signed long long, const int<0,1>); + SET_2DI vsx_set_v2di {set} + + const vd __builtin_vsx_splat_2df (double); + SPLAT_2DF vsx_splat_v2df {} + + const vsll __builtin_vsx_splat_2di (signed long long); + SPLAT_2DI vsx_splat_v2di {} + + void __builtin_vsx_st_elemrev_v1ti (vsq, signed long, void *); + ST_ELEMREV_V1TI vsx_st_elemrev_v1ti {stvec,endian} + + void __builtin_vsx_st_elemrev_v2df (vd, signed long, void *); + ST_ELEMREV_V2DF vsx_st_elemrev_v2df {stvec,endian} + + void __builtin_vsx_st_elemrev_v2di (vsll, signed long, void *); + ST_ELEMREV_V2DI vsx_st_elemrev_v2di {stvec,endian} + + void __builtin_vsx_st_elemrev_v4sf (vf, signed long, void *); + ST_ELEMREV_V4SF vsx_st_elemrev_v4sf {stvec,endian} + + void __builtin_vsx_st_elemrev_v4si (vsi, signed long, void *); + ST_ELEMREV_V4SI vsx_st_elemrev_v4si {stvec,endian} + + void __builtin_vsx_st_elemrev_v8hi (vss, signed long, void *); + ST_ELEMREV_V8HI vsx_st_elemrev_v8hi {stvec,endian} + + void __builtin_vsx_st_elemrev_v16qi (vsc, signed long, void *); + ST_ELEMREV_V16QI vsx_st_elemrev_v16qi {stvec,endian} + + void __builtin_vsx_stxvd2x_v1ti (vsq, signed long, void *); + STXVD2X_V1TI vsx_store_v1ti {stvec} + + void __builtin_vsx_stxvd2x_v2df (vd, signed long, void *); + STXVD2X_V2DF vsx_store_v2df {stvec} + + void __builtin_vsx_stxvd2x_v2di (vsll, signed long, void *); + STXVD2X_V2DI vsx_store_v2di {stvec} + + void __builtin_vsx_stxvw4x_v4sf (vf, signed long, void *); + STXVW4X_V4SF vsx_store_v4sf {stvec} + + void __builtin_vsx_stxvw4x_v4si (vsi, signed long, void *); + STXVW4X_V4SI vsx_store_v4si {stvec} + + void __builtin_vsx_stxvw4x_v8hi (vss, signed long, void *); + STXVW4X_V8HI vsx_store_v8hi {stvec} + + void __builtin_vsx_stxvw4x_v16qi (vsc, signed long, void *); + STXVW4X_V16QI vsx_store_v16qi {stvec} + + const vull __builtin_vsx_udiv_2di (vull, vull); + UDIV_V2DI vsx_udiv_v2di {} + + const vd __builtin_vsx_uns_doublee_v4si (vsi); + UNS_DOUBLEE_V4SI unsdoubleev4si2 {} + + const vd __builtin_vsx_uns_doubleh_v4si (vsi); + UNS_DOUBLEH_V4SI unsdoublehv4si2 {} + + const vd __builtin_vsx_uns_doublel_v4si (vsi); + UNS_DOUBLEL_V4SI unsdoublelv4si2 {} + + const vd __builtin_vsx_uns_doubleo_v4si (vsi); + UNS_DOUBLEO_V4SI unsdoubleov4si2 {} + + const vf __builtin_vsx_uns_floate_v2di (vsll); + UNS_FLOATE_V2DI unsfloatev2di {} + + const vf __builtin_vsx_uns_floato_v2di (vsll); + UNS_FLOATO_V2DI unsfloatov2di {} + +; These are duplicates of __builtin_altivec_* counterparts, and are being +; kept for backwards compatibility. The reason for their existence is +; unclear. TODO: Consider deprecation/removal at some point. + const vsc __builtin_vsx_vperm_16qi (vsc, vsc, vuc); + VPERM_16QI_X altivec_vperm_v16qi {} + + const vuc __builtin_vsx_vperm_16qi_uns (vuc, vuc, vuc); + VPERM_16QI_UNS_X altivec_vperm_v16qi_uns {} + + const vsq __builtin_vsx_vperm_1ti (vsq, vsq, vsc); + VPERM_1TI_X altivec_vperm_v1ti {} + + const vsq __builtin_vsx_vperm_1ti_uns (vsq, vsq, vsc); + VPERM_1TI_UNS_X altivec_vperm_v1ti_uns {} + + const vd __builtin_vsx_vperm_2df (vd, vd, vuc); + VPERM_2DF_X altivec_vperm_v2df {} + + const vsll __builtin_vsx_vperm_2di (vsll, vsll, vuc); + VPERM_2DI_X altivec_vperm_v2di {} + + const vull __builtin_vsx_vperm_2di_uns (vull, vull, vuc); + VPERM_2DI_UNS_X altivec_vperm_v2di_uns {} + + const vf __builtin_vsx_vperm_4sf (vf, vf, vuc); + VPERM_4SF_X altivec_vperm_v4sf {} + + const vsi __builtin_vsx_vperm_4si (vsi, vsi, vuc); + VPERM_4SI_X altivec_vperm_v4si {} + + const vui __builtin_vsx_vperm_4si_uns (vui, vui, vuc); + VPERM_4SI_UNS_X altivec_vperm_v4si_uns {} + + const vss __builtin_vsx_vperm_8hi (vss, vss, vuc); + VPERM_8HI_X altivec_vperm_v8hi {} + + const vus __builtin_vsx_vperm_8hi_uns (vus, vus, vuc); + VPERM_8HI_UNS_X altivec_vperm_v8hi_uns {} + + const vsll __builtin_vsx_vsigned_v2df (vd); + VEC_VSIGNED_V2DF vsx_xvcvdpsxds {} + + const vsi __builtin_vsx_vsigned_v4sf (vf); + VEC_VSIGNED_V4SF vsx_xvcvspsxws {} + + const vsi __builtin_vsx_vsignede_v2df (vd); + VEC_VSIGNEDE_V2DF vsignede_v2df {} + + const vsi __builtin_vsx_vsignedo_v2df (vd); + VEC_VSIGNEDO_V2DF vsignedo_v2df {} + + const vsll __builtin_vsx_vunsigned_v2df (vd); + VEC_VUNSIGNED_V2DF vsx_xvcvdpsxds {} + + const vsi __builtin_vsx_vunsigned_v4sf (vf); + VEC_VUNSIGNED_V4SF vsx_xvcvspsxws {} + + const vsi __builtin_vsx_vunsignede_v2df (vd); + VEC_VUNSIGNEDE_V2DF vunsignede_v2df {} + + const vsi __builtin_vsx_vunsignedo_v2df (vd); + VEC_VUNSIGNEDO_V2DF vunsignedo_v2df {} + + const vf __builtin_vsx_xscvdpsp (double); + XSCVDPSP vsx_xscvdpsp {} + + const double __builtin_vsx_xscvspdp (vf); + XSCVSPDP vsx_xscvspdp {} + + const double __builtin_vsx_xsmaxdp (double, double); + XSMAXDP smaxdf3 {} + + const double __builtin_vsx_xsmindp (double, double); + XSMINDP smindf3 {} + + const double __builtin_vsx_xsrdpi (double); + XSRDPI vsx_xsrdpi {} + + const double __builtin_vsx_xsrdpic (double); + XSRDPIC vsx_xsrdpic {} + + const double __builtin_vsx_xsrdpim (double); + XSRDPIM floordf2 {} + + const double __builtin_vsx_xsrdpip (double); + XSRDPIP ceildf2 {} + + const double __builtin_vsx_xsrdpiz (double); + XSRDPIZ btruncdf2 {} + + const signed int __builtin_vsx_xstdivdp_fe (double, double); + XSTDIVDP_FE vsx_tdivdf3_fe {} + + const signed int __builtin_vsx_xstdivdp_fg (double, double); + XSTDIVDP_FG vsx_tdivdf3_fg {} + + const signed int __builtin_vsx_xstsqrtdp_fe (double); + XSTSQRTDP_FE vsx_tsqrtdf2_fe {} + + const signed int __builtin_vsx_xstsqrtdp_fg (double); + XSTSQRTDP_FG vsx_tsqrtdf2_fg {} + + const vd __builtin_vsx_xvabsdp (vd); + XVABSDP absv2df2 {} + + const vf __builtin_vsx_xvabssp (vf); + XVABSSP absv4sf2 {} + + fpmath vd __builtin_vsx_xvadddp (vd, vd); + XVADDDP addv2df3 {} + + fpmath vf __builtin_vsx_xvaddsp (vf, vf); + XVADDSP addv4sf3 {} + + const vd __builtin_vsx_xvcmpeqdp (vd, vd); + XVCMPEQDP vector_eqv2df {} + + const signed int __builtin_vsx_xvcmpeqdp_p (signed int, vd, vd); + XVCMPEQDP_P vector_eq_v2df_p {pred} + + const vf __builtin_vsx_xvcmpeqsp (vf, vf); + XVCMPEQSP vector_eqv4sf {} + + const signed int __builtin_vsx_xvcmpeqsp_p (signed int, vf, vf); + XVCMPEQSP_P vector_eq_v4sf_p {pred} + + const vd __builtin_vsx_xvcmpgedp (vd, vd); + XVCMPGEDP vector_gev2df {} + + const signed int __builtin_vsx_xvcmpgedp_p (signed int, vd, vd); + XVCMPGEDP_P vector_ge_v2df_p {pred} + + const vf __builtin_vsx_xvcmpgesp (vf, vf); + XVCMPGESP vector_gev4sf {} + + const signed int __builtin_vsx_xvcmpgesp_p (signed int, vf, vf); + XVCMPGESP_P vector_ge_v4sf_p {pred} + + const vd __builtin_vsx_xvcmpgtdp (vd, vd); + XVCMPGTDP vector_gtv2df {} + + const signed int __builtin_vsx_xvcmpgtdp_p (signed int, vd, vd); + XVCMPGTDP_P vector_gt_v2df_p {pred} + + const vf __builtin_vsx_xvcmpgtsp (vf, vf); + XVCMPGTSP vector_gtv4sf {} + + const signed int __builtin_vsx_xvcmpgtsp_p (signed int, vf, vf); + XVCMPGTSP_P vector_gt_v4sf_p {pred} + + const vf __builtin_vsx_xvcvdpsp (vd); + XVCVDPSP vsx_xvcvdpsp {} + + const vsll __builtin_vsx_xvcvdpsxds (vd); + XVCVDPSXDS vsx_fix_truncv2dfv2di2 {} + + const vsll __builtin_vsx_xvcvdpsxds_scale (vd, const int); + XVCVDPSXDS_SCALE vsx_xvcvdpsxds_scale {} + + const vsi __builtin_vsx_xvcvdpsxws (vd); + XVCVDPSXWS vsx_xvcvdpsxws {} + + const vsll __builtin_vsx_xvcvdpuxds (vd); + XVCVDPUXDS vsx_fixuns_truncv2dfv2di2 {} + + const vsll __builtin_vsx_xvcvdpuxds_scale (vd, const int); + XVCVDPUXDS_SCALE vsx_xvcvdpuxds_scale {} + + const vull __builtin_vsx_xvcvdpuxds_uns (vd); + XVCVDPUXDS_UNS vsx_fixuns_truncv2dfv2di2 {} + + const vsi __builtin_vsx_xvcvdpuxws (vd); + XVCVDPUXWS vsx_xvcvdpuxws {} + + const vd __builtin_vsx_xvcvspdp (vf); + XVCVSPDP vsx_xvcvspdp {} + + const vsll __builtin_vsx_xvcvspsxds (vf); + XVCVSPSXDS vsx_xvcvspsxds {} + + const vsi __builtin_vsx_xvcvspsxws (vf); + XVCVSPSXWS vsx_fix_truncv4sfv4si2 {} + + const vsll __builtin_vsx_xvcvspuxds (vf); + XVCVSPUXDS vsx_xvcvspuxds {} + + const vsi __builtin_vsx_xvcvspuxws (vf); + XVCVSPUXWS vsx_fixuns_truncv4sfv4si2 {} + + const vd __builtin_vsx_xvcvsxddp (vsll); + XVCVSXDDP vsx_floatv2div2df2 {} + + const vd __builtin_vsx_xvcvsxddp_scale (vsll, const int<5>); + XVCVSXDDP_SCALE vsx_xvcvsxddp_scale {} + + const vf __builtin_vsx_xvcvsxdsp (vsll); + XVCVSXDSP vsx_xvcvsxdsp {} + + const vd __builtin_vsx_xvcvsxwdp (vsi); + XVCVSXWDP vsx_xvcvsxwdp {} + + const vf __builtin_vsx_xvcvsxwsp (vsi); + XVCVSXWSP vsx_floatv4siv4sf2 {} + + const vd __builtin_vsx_xvcvuxddp (vsll); + XVCVUXDDP vsx_floatunsv2div2df2 {} + + const vd __builtin_vsx_xvcvuxddp_scale (vsll, const int<5>); + XVCVUXDDP_SCALE vsx_xvcvuxddp_scale {} + + const vd __builtin_vsx_xvcvuxddp_uns (vull); + XVCVUXDDP_UNS vsx_floatunsv2div2df2 {} + + const vf __builtin_vsx_xvcvuxdsp (vull); + XVCVUXDSP vsx_xvcvuxdsp {} + + const vd __builtin_vsx_xvcvuxwdp (vsi); + XVCVUXWDP vsx_xvcvuxwdp {} + + const vf __builtin_vsx_xvcvuxwsp (vsi); + XVCVUXWSP vsx_floatunsv4siv4sf2 {} + + fpmath vd __builtin_vsx_xvdivdp (vd, vd); + XVDIVDP divv2df3 {} + + fpmath vf __builtin_vsx_xvdivsp (vf, vf); + XVDIVSP divv4sf3 {} + + const vd __builtin_vsx_xvmadddp (vd, vd, vd); + XVMADDDP fmav2df4 {} + + const vf __builtin_vsx_xvmaddsp (vf, vf, vf); + XVMADDSP fmav4sf4 {} + + const vd __builtin_vsx_xvmaxdp (vd, vd); + XVMAXDP smaxv2df3 {} + + const vf __builtin_vsx_xvmaxsp (vf, vf); + XVMAXSP smaxv4sf3 {} + + const vd __builtin_vsx_xvmindp (vd, vd); + XVMINDP sminv2df3 {} + + const vf __builtin_vsx_xvminsp (vf, vf); + XVMINSP sminv4sf3 {} + + const vd __builtin_vsx_xvmsubdp (vd, vd, vd); + XVMSUBDP fmsv2df4 {} + + const vf __builtin_vsx_xvmsubsp (vf, vf, vf); + XVMSUBSP fmsv4sf4 {} + + fpmath vd __builtin_vsx_xvmuldp (vd, vd); + XVMULDP mulv2df3 {} + + fpmath vf __builtin_vsx_xvmulsp (vf, vf); + XVMULSP mulv4sf3 {} + + const vd __builtin_vsx_xvnabsdp (vd); + XVNABSDP vsx_nabsv2df2 {} + + const vf __builtin_vsx_xvnabssp (vf); + XVNABSSP vsx_nabsv4sf2 {} + + const vd __builtin_vsx_xvnegdp (vd); + XVNEGDP negv2df2 {} + + const vf __builtin_vsx_xvnegsp (vf); + XVNEGSP negv4sf2 {} + + const vd __builtin_vsx_xvnmadddp (vd, vd, vd); + XVNMADDDP nfmav2df4 {} + + const vf __builtin_vsx_xvnmaddsp (vf, vf, vf); + XVNMADDSP nfmav4sf4 {} + + const vd __builtin_vsx_xvnmsubdp (vd, vd, vd); + XVNMSUBDP nfmsv2df4 {} + + const vf __builtin_vsx_xvnmsubsp (vf, vf, vf); + XVNMSUBSP nfmsv4sf4 {} + + const vd __builtin_vsx_xvrdpi (vd); + XVRDPI vsx_xvrdpi {} + + const vd __builtin_vsx_xvrdpic (vd); + XVRDPIC vsx_xvrdpic {} + + const vd __builtin_vsx_xvrdpim (vd); + XVRDPIM vsx_floorv2df2 {} + + const vd __builtin_vsx_xvrdpip (vd); + XVRDPIP vsx_ceilv2df2 {} + + const vd __builtin_vsx_xvrdpiz (vd); + XVRDPIZ vsx_btruncv2df2 {} + + fpmath vd __builtin_vsx_xvrecipdivdp (vd, vd); + RECIP_V2DF recipv2df3 {} + + fpmath vf __builtin_vsx_xvrecipdivsp (vf, vf); + RECIP_V4SF recipv4sf3 {} + + const vd __builtin_vsx_xvredp (vd); + XVREDP vsx_frev2df2 {} + + const vf __builtin_vsx_xvresp (vf); + XVRESP vsx_frev4sf2 {} + + const vf __builtin_vsx_xvrspi (vf); + XVRSPI vsx_xvrspi {} + + const vf __builtin_vsx_xvrspic (vf); + XVRSPIC vsx_xvrspic {} + + const vf __builtin_vsx_xvrspim (vf); + XVRSPIM vsx_floorv4sf2 {} + + const vf __builtin_vsx_xvrspip (vf); + XVRSPIP vsx_ceilv4sf2 {} + + const vf __builtin_vsx_xvrspiz (vf); + XVRSPIZ vsx_btruncv4sf2 {} + + const vd __builtin_vsx_xvrsqrtdp (vd); + RSQRT_2DF rsqrtv2df2 {} + + const vf __builtin_vsx_xvrsqrtsp (vf); + RSQRT_4SF rsqrtv4sf2 {} + + const vd __builtin_vsx_xvrsqrtedp (vd); + XVRSQRTEDP rsqrtev2df2 {} + + const vf __builtin_vsx_xvrsqrtesp (vf); + XVRSQRTESP rsqrtev4sf2 {} + + const vd __builtin_vsx_xvsqrtdp (vd); + XVSQRTDP sqrtv2df2 {} + + const vf __builtin_vsx_xvsqrtsp (vf); + XVSQRTSP sqrtv4sf2 {} + + fpmath vd __builtin_vsx_xvsubdp (vd, vd); + XVSUBDP subv2df3 {} + + fpmath vf __builtin_vsx_xvsubsp (vf, vf); + XVSUBSP subv4sf3 {} + + const signed int __builtin_vsx_xvtdivdp_fe (vd, vd); + XVTDIVDP_FE vsx_tdivv2df3_fe {} + + const signed int __builtin_vsx_xvtdivdp_fg (vd, vd); + XVTDIVDP_FG vsx_tdivv2df3_fg {} + + const signed int __builtin_vsx_xvtdivsp_fe (vf, vf); + XVTDIVSP_FE vsx_tdivv4sf3_fe {} + + const signed int __builtin_vsx_xvtdivsp_fg (vf, vf); + XVTDIVSP_FG vsx_tdivv4sf3_fg {} + + const signed int __builtin_vsx_xvtsqrtdp_fe (vd); + XVTSQRTDP_FE vsx_tsqrtv2df2_fe {} + + const signed int __builtin_vsx_xvtsqrtdp_fg (vd); + XVTSQRTDP_FG vsx_tsqrtv2df2_fg {} + + const signed int __builtin_vsx_xvtsqrtsp_fe (vf); + XVTSQRTSP_FE vsx_tsqrtv4sf2_fe {} + + const signed int __builtin_vsx_xvtsqrtsp_fg (vf); + XVTSQRTSP_FG vsx_tsqrtv4sf2_fg {} + + const vf __builtin_vsx_xxmrghw (vf, vf); + XXMRGHW_4SF vsx_xxmrghw_v4sf {} + + const vsi __builtin_vsx_xxmrghw_4si (vsi, vsi); + XXMRGHW_4SI vsx_xxmrghw_v4si {} + + const vf __builtin_vsx_xxmrglw (vf, vf); + XXMRGLW_4SF vsx_xxmrglw_v4sf {} + + const vsi __builtin_vsx_xxmrglw_4si (vsi, vsi); + XXMRGLW_4SI vsx_xxmrglw_v4si {} + + const vsc __builtin_vsx_xxpermdi_16qi (vsc, vsc, const int<2>); + XXPERMDI_16QI vsx_xxpermdi_v16qi {} + + const vsq __builtin_vsx_xxpermdi_1ti (vsq, vsq, const int<2>); + XXPERMDI_1TI vsx_xxpermdi_v1ti {} + + const vd __builtin_vsx_xxpermdi_2df (vd, vd, const int<2>); + XXPERMDI_2DF vsx_xxpermdi_v2df {} + + const vsll __builtin_vsx_xxpermdi_2di (vsll, vsll, const int<2>); + XXPERMDI_2DI vsx_xxpermdi_v2di {} + + const vf __builtin_vsx_xxpermdi_4sf (vf, vf, const int<2>); + XXPERMDI_4SF vsx_xxpermdi_v4sf {} + + const vsi __builtin_vsx_xxpermdi_4si (vsi, vsi, const int<2>); + XXPERMDI_4SI vsx_xxpermdi_v4si {} + + const vss __builtin_vsx_xxpermdi_8hi (vss, vss, const int<2>); + XXPERMDI_8HI vsx_xxpermdi_v8hi {} + + const vsc __builtin_vsx_xxsel_16qi (vsc, vsc, vsc); + XXSEL_16QI vector_select_v16qi {} + + const vuc __builtin_vsx_xxsel_16qi_uns (vuc, vuc, vuc); + XXSEL_16QI_UNS vector_select_v16qi_uns {} + + const vsq __builtin_vsx_xxsel_1ti (vsq, vsq, vsq); + XXSEL_1TI vector_select_v1ti {} + + const vsq __builtin_vsx_xxsel_1ti_uns (vsq, vsq, vsq); + XXSEL_1TI_UNS vector_select_v1ti_uns {} + + const vd __builtin_vsx_xxsel_2df (vd, vd, vd); + XXSEL_2DF vector_select_v2df {} + + const vsll __builtin_vsx_xxsel_2di (vsll, vsll, vsll); + XXSEL_2DI vector_select_v2di {} + + const vull __builtin_vsx_xxsel_2di_uns (vull, vull, vull); + XXSEL_2DI_UNS vector_select_v2di_uns {} + + const vf __builtin_vsx_xxsel_4sf (vf, vf, vf); + XXSEL_4SF vector_select_v4sf {} + + const vsi __builtin_vsx_xxsel_4si (vsi, vsi, vsi); + XXSEL_4SI vector_select_v4si {} + + const vui __builtin_vsx_xxsel_4si_uns (vui, vui, vui); + XXSEL_4SI_UNS vector_select_v4si_uns {} + + const vss __builtin_vsx_xxsel_8hi (vss, vss, vss); + XXSEL_8HI vector_select_v8hi {} + + const vus __builtin_vsx_xxsel_8hi_uns (vus, vus, vus); + XXSEL_8HI_UNS vector_select_v8hi_uns {} + + const vsc __builtin_vsx_xxsldwi_16qi (vsc, vsc, const int<2>); + XXSLDWI_16QI vsx_xxsldwi_v16qi {} + + const vd __builtin_vsx_xxsldwi_2df (vd, vd, const int<2>); + XXSLDWI_2DF vsx_xxsldwi_v2df {} + + const vsll __builtin_vsx_xxsldwi_2di (vsll, vsll, const int<2>); + XXSLDWI_2DI vsx_xxsldwi_v2di {} + + const vf __builtin_vsx_xxsldwi_4sf (vf, vf, const int<2>); + XXSLDWI_4SF vsx_xxsldwi_v4sf {} + + const vsi __builtin_vsx_xxsldwi_4si (vsi, vsi, const int<2>); + XXSLDWI_4SI vsx_xxsldwi_v4si {} + + const vss __builtin_vsx_xxsldwi_8hi (vss, vss, const int<2>); + XXSLDWI_8HI vsx_xxsldwi_v8hi {} + + const vd __builtin_vsx_xxspltd_2df (vd, const int<1>); + XXSPLTD_V2DF vsx_xxspltd_v2df {} + + const vsll __builtin_vsx_xxspltd_2di (vsll, const int<1>); + XXSPLTD_V2DI vsx_xxspltd_v2di {} -- cgit v1.1 From 873273449a944d7796d08ce6fae06eabcab7bf65 Mon Sep 17 00:00:00 2001 From: Bill Schmidt Date: Wed, 11 Aug 2021 14:59:17 -0500 Subject: rs6000: Add available-everywhere and ancient builtins 2021-08-11 Bill Schmidt gcc/ * config/rs6000/rs6000-builtin-new.def: Add always, power5, and power6 stanzas. --- gcc/config/rs6000/rs6000-builtin-new.def | 76 ++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) (limited to 'gcc') diff --git a/gcc/config/rs6000/rs6000-builtin-new.def b/gcc/config/rs6000/rs6000-builtin-new.def index b5d3570..61f5b94 100644 --- a/gcc/config/rs6000/rs6000-builtin-new.def +++ b/gcc/config/rs6000/rs6000-builtin-new.def @@ -184,6 +184,82 @@ +; Builtins that have been around since time immemorial or are just +; considered available everywhere. +[always] + void __builtin_cpu_init (); + CPU_INIT nothing {cpu} + + bool __builtin_cpu_is (string); + CPU_IS nothing {cpu} + + bool __builtin_cpu_supports (string); + CPU_SUPPORTS nothing {cpu} + + unsigned long long __builtin_ppc_get_timebase (); + GET_TB rs6000_get_timebase {} + + double __builtin_mffs (); + MFFS rs6000_mffs {} + +; This thing really assumes long double == __ibm128, and I'm told it has +; been used as such within libgcc. Given that __builtin_pack_ibm128 +; exists for the same purpose, this should really not be used at all. +; TODO: Consider adding special handling for this to warn whenever +; long double is not __ibm128. + const long double __builtin_pack_longdouble (double, double); + PACK_TF packtf {} + + unsigned long __builtin_ppc_mftb (); + MFTB rs6000_mftb_di {32bit} + + void __builtin_mtfsb0 (const int<5>); + MTFSB0 rs6000_mtfsb0 {} + + void __builtin_mtfsb1 (const int<5>); + MTFSB1 rs6000_mtfsb1 {} + + void __builtin_mtfsf (const int<8>, double); + MTFSF rs6000_mtfsf {} + + const __ibm128 __builtin_pack_ibm128 (double, double); + PACK_IF packif {} + + void __builtin_set_fpscr_rn (const int[0,3]); + SET_FPSCR_RN rs6000_set_fpscr_rn {} + + const double __builtin_unpack_ibm128 (__ibm128, const int<1>); + UNPACK_IF unpackif {} + +; See above comments for __builtin_pack_longdouble. + const double __builtin_unpack_longdouble (long double, const int<1>); + UNPACK_TF unpacktf {} + + +; Builtins that have been around just about forever, but not quite. +[power5] + fpmath double __builtin_recipdiv (double, double); + RECIP recipdf3 {} + + fpmath float __builtin_recipdivf (float, float); + RECIPF recipsf3 {} + + fpmath double __builtin_rsqrt (double); + RSQRT rsqrtdf2 {} + + fpmath float __builtin_rsqrtf (float); + RSQRTF rsqrtsf2 {} + + +; Power6 builtins (ISA 2.05). +[power6] + const signed long __builtin_p6_cmpb (signed long, signed long); + CMPB cmpbdi3 {} + + const signed int __builtin_p6_cmpb_32 (signed int, signed int); + CMPB_32 cmpbsi3 {} + + ; AltiVec builtins. [altivec] const vsc __builtin_altivec_abs_v16qi (vsc); -- cgit v1.1 From 58f87503427e27bb069bd1841100f3c53440d51a Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Thu, 12 Aug 2021 00:16:28 +0000 Subject: Daily bump. --- gcc/ChangeLog | 120 ++++++++++++++++++++++++++++++++++++++++++++++++ gcc/DATESTAMP | 2 +- gcc/ada/ChangeLog | 7 +++ gcc/cp/ChangeLog | 37 +++++++++++++++ gcc/fortran/ChangeLog | 12 +++++ gcc/testsuite/ChangeLog | 52 +++++++++++++++++++++ 6 files changed, 229 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 3eea63b..31f7659 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,123 @@ +2021-08-11 Bill Schmidt + + * config/rs6000/rs6000-builtin-new.def: Add always, power5, and + power6 stanzas. + +2021-08-11 Bill Schmidt + + * config/rs6000/rs6000-builtin-new.def: Add vsx stanza. + +2021-08-11 Bill Schmidt + + * config/rs6000/rs6000-builtin-new.def: Finish altivec stanza. + * config/rs6000/rs6000-call.c (rs6000_init_builtins): Move + initialization of pcvoid_type_node here... + (altivec_init_builtins): ...from here. + * config/rs6000/rs6000.h (rs6000_builtin_type_index): Add + RS6000_BTI_const_ptr_void. + (pcvoid_type_node): New macro. + +2021-08-11 Richard Biener + + PR target/101877 + * tree-ssa-forwprop.c (pass_forwprop::execute): Do not decompose + hard-register accesses. + +2021-08-11 Richard Biener + + * tree-ssa-operands.c (operands_scanner::get_expr_operands): + Do not look at COMPONENT_REF FIELD_DECLs TREE_THIS_VOLATILE + to determine has_volatile_ops. + +2021-08-11 Eric Botcazou + + * cfgexpand.c (expand_used_vars): Reuse attribs local variable. + +2021-08-11 Jan Hubicka + Alexandre Oliva + + * ipa-modref.c (modref_lattice::dump): Fix escape_point's min_flags + dumping. + (modref_lattice::merge_deref): Fix handling of indirect scape points. + (update_escape_summary_1): Likewise. + (update_escape_summary): Likewise. + (ipa_merge_modref_summary_after_inlining): Likewise. + +2021-08-11 Richard Biener + + PR middle-end/101858 + * fold-const.c (fold_binary_loc): Guard simplification + of X < (cast) (1 << Y) to integer types. + +2021-08-11 Richard Biener + + PR tree-optimization/101861 + * tree-vect-stmts.c (vectorizable_load): Fix error in + previous change with regard to gather vectorization. + +2021-08-11 prathamesh.kulkarni + + PR target/66791 + * config/arm/arm_neon.h (vdup_n_s8): Replace call to builtin + with constructor. + (vdup_n_s16): Likewise. + (vdup_n_s32): Likewise. + (vdup_n_s64): Likewise. + (vdup_n_u8): Likewise. + (vdup_n_u16): Likewise. + (vdup_n_u32): Likewise. + (vdup_n_u64): Likewise. + (vdup_n_p8): Likewise. + (vdup_n_p16): Likewise. + (vdup_n_p64): Likewise. + (vdup_n_f16): Likewise. + (vdup_n_f32): Likewise. + (vdupq_n_s8): Likewise. + (vdupq_n_s16): Likewise. + (vdupq_n_s32): Likewise. + (vdupq_n_s64): Likewise. + (vdupq_n_u8): Likewise. + (vdupq_n_u16): Likewise. + (vdupq_n_u32): Likewise. + (vdupq_n_u64): Likewise. + (vdupq_n_p8): Likewise. + (vdupq_n_p16): Likewise. + (vdupq_n_p64): Likewise. + (vdupq_n_f16): Likewise. + (vdupq_n_f32): Likewise. + (vmov_n_s8): Replace call to builtin with call to corresponding + vdup_n intrinsic. + (vmov_n_s16): Likewise. + (vmov_n_s32): Likewise. + (vmov_n_s64): Likewise. + (vmov_n_u8): Likewise. + (vmov_n_u16): Likewise. + (vmov_n_u32): Likewise. + (vmov_n_u64): Likewise. + (vmov_n_p8): Likewise. + (vmov_n_p16): Likewise. + (vmov_n_f16): Likewise. + (vmov_n_f32): Likewise. + (vmovq_n_s8): Likewise. + (vmovq_n_s16): Likewise. + (vmovq_n_s32): Likewise. + (vmovq_n_s64): Likewise. + (vmovq_n_u8): Likewise. + (vmovq_n_u16): Likewise. + (vmovq_n_u32): Likewise. + (vmovq_n_u64): Likewise. + (vmovq_n_p8): Likewise. + (vmovq_n_p16): Likewise. + (vmovq_n_f16): Likewise. + (vmovq_n_f32): Likewise. + * config/arm/arm_neon_builtins.def: Remove entries for vdup_n. + +2021-08-11 liuhongt + + PR target/98309 + * config/i386/i386.md (ldexp3): Extend to vscalefs[sd] + when TARGET_AVX512F and TARGET_SSE_MATH. + 2021-08-10 Jakub Jelinek PR target/80355 diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index 4cf952c..cffca64 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20210811 +20210812 diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index 254b562..8e19ca4 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,3 +1,10 @@ +2021-08-11 Bernd Edlinger + + PR debug/101598 + * gcc-interface/trans.c (Subprogram_Body_to_gnu): Set the + DECL_SOURCE_LOCATION of DECL_IGNORED_P gnu_subprog_decl to + UNKNOWN_LOCATION. + 2021-07-25 Arnaud Charlet * libgnat/s-osprim__x32.adb: Add missing with clause. diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index fbd4af2e..fd4aa6e 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,40 @@ +2021-08-11 Patrick Palka + + PR c++/101725 + DR 2082 + * cp-tree.h (unevaluated_p): Return true for REQUIRES_EXPR. + * decl.c (local_variable_p_walkfn): Don't walk into unevaluated + operands. + * parser.c (cp_parser_primary_expression) : Never + reject uses of local variables in unevaluated contexts. + * tree.c (cp_walk_subtrees) : Increment + cp_unevaluated_operand. Use cp_walk_tree directly instead of + WALK_SUBTREE to avoid the goto. Use REQUIRES_EXPR_REQS instead + of TREE_OPERAND directly. + +2021-08-11 Jakub Jelinek + + PR c++/101786 + * decl2.c (var_defined_without_dynamic_init): Return true for + DECL_DECLARED_CONSTINIT_P with complete type and trivial destructor. + +2021-08-11 Patrick Palka + + PR c++/79501 + * parser.c (maybe_adjust_declarator_for_dguide): New, split + out from ... + (cp_parser_init_declarator): ... here. + (cp_parser_member_declaration): Use it. + +2021-08-11 Patrick Palka + + PR c++/89062 + * parser.c (cp_parser_parameter_declaration_list): Don't call + grokdeclarator if cp_parser_error_occurred. + (cp_parser_parameter_declaration): Simulate an error if we see + the beginning of a CTAD form, i.e. if we see an opening brace + after the decl-specifier-seq and the type is a CTAD placeholder. + 2021-08-10 Jakub Jelinek * parser.c (cp_parser_member_declaration): Move odsd declaration diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index 2e7a9ad..5f9623b 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,15 @@ +2021-08-11 Sandra Loosemore + + * iso-c-binding.def (c_float128, c_float128_complex): Check + float128_type_node instead of gfc_float128_type_node. + * trans-types.c (gfc_init_kinds, gfc_build_real_type): + Update comments re supported 128-bit floating-point types. + +2021-08-11 Richard Biener + + * trans-common.c (create_common): Set TREE_THIS_VOLATILE on the + COMPONENT_REF if the field is volatile. + 2021-08-07 Harald Anlauf PR fortran/68568 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 07d98f7..eaae083 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,55 @@ +2021-08-11 Patrick Palka + + PR c++/101725 + DR 2082 + * g++.dg/DRs/dr2082.C: New test. + * g++.dg/cpp2a/concepts-uneval4.C: New test. + +2021-08-11 Jakub Jelinek + + PR c++/101786 + * g++.dg/cpp2a/constinit16.C: New test. + +2021-08-11 Patrick Palka + + PR c++/79501 + * g++.dg/cpp1z/class-deduction98.C: New test. + +2021-08-11 Patrick Palka + + PR c++/89062 + * g++.dg/cpp1z/class-deduction97.C: New test. + +2021-08-11 Richard Biener + + * gcc.dg/lto/pr48622_1.c: Provide non-LTO definition + of ashift_qi_1. + +2021-08-11 Jan Hubicka + + * c-c++-common/modref-dse.c: New test. + +2021-08-11 Richard Biener + + PR middle-end/101858 + * gcc.dg/pr101858.c: New testcase. + +2021-08-11 prathamesh.kulkarni + + PR target/66791 + * gcc.target/arm/pr51534.c: Adjust test. + +2021-08-11 liuhongt + + PR target/98309 + * gcc.target/i386/pr98309-1.c: New test. + * gcc.target/i386/pr98309-2.c: New test. + +2021-08-11 Hans-Peter Nilsson + + PR middle-end/101674 + * gcc.dg/uninit-pred-9_b.c: Xfail for cris-*-* too. + 2021-08-10 Tobias Burnus PR libfortran/101305 -- cgit v1.1 From 21fd62e5ca9967bba8f97fd6244a8c6a564c2146 Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Wed, 11 Aug 2021 20:59:53 -0400 Subject: c++: constexpr std::construct_at on empty field [PR101663] Here during constexpr evaluation of std::construct_at(&a._M_value) we find ourselves in cxx_eval_store_expression where the target object is 'a._M_value' and the initializer is {}. Since _M_value is an empty [[no_unique_address]] member we don't create a sub-CONSTRUCTOR for it, so we end up in the early exit code path for empty stores with mismatched types and trip over the assert therein gcc_assert (is_empty_class (TREE_TYPE (init)) && !lval); because lval is true. The reason it's true is because the INIT_EXPR in question is the LHS of a COMPOUND_EXPR, and evaluation of the LHS is always performed with lval=true (to indicate there's no lvalue-to-rvalue conversion). This patch makes the code path in question handle the lval=true case appropriately rather than asserting. In passing, it also consolidates the duplicate implementations of std::construct_at/destroy_at in some of the C++20 constexpr tests into a common header file. PR c++/101663 gcc/cp/ChangeLog: * constexpr.c (cxx_eval_store_expression): Handle the lval=true case in the early exit code path for empty stores with mismatched types. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/construct_at.h: New convenience header file that defines minimal implementations of std::construct_at/destroy_at, split out from ... * g++.dg/cpp2a/constexpr-new5.C: ... here. * g++.dg/cpp2a/constexpr-new6.C: Use the header. * g++.dg/cpp2a/constexpr-new14.C: Likewise. * g++.dg/cpp2a/constexpr-new20.C: New test. --- gcc/cp/constexpr.c | 4 +- gcc/testsuite/g++.dg/cpp2a/constexpr-new14.C | 60 +------------------------- gcc/testsuite/g++.dg/cpp2a/constexpr-new20.C | 18 ++++++++ gcc/testsuite/g++.dg/cpp2a/constexpr-new5.C | 60 +------------------------- gcc/testsuite/g++.dg/cpp2a/constexpr-new6.C | 64 +--------------------------- gcc/testsuite/g++.dg/cpp2a/construct_at.h | 62 +++++++++++++++++++++++++++ 6 files changed, 85 insertions(+), 183 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp2a/constexpr-new20.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/construct_at.h (limited to 'gcc') diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 1af365d..25d84a3 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -5588,8 +5588,8 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, argument, which has the derived type rather than the base type. In this situation, just evaluate the initializer and return, since there's no actual data to store. */ - gcc_assert (is_empty_class (TREE_TYPE (init)) && !lval); - return init; + gcc_assert (is_empty_class (TREE_TYPE (init))); + return lval ? target : init; } CONSTRUCTOR_ELTS (*valp) = CONSTRUCTOR_ELTS (init); TREE_CONSTANT (*valp) = TREE_CONSTANT (init); diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-new14.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-new14.C index fd6f607..2603739 100644 --- a/gcc/testsuite/g++.dg/cpp2a/constexpr-new14.C +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-new14.C @@ -1,65 +1,7 @@ // PR c++/97195 // { dg-do compile { target c++20 } } -namespace std -{ - typedef __SIZE_TYPE__ size_t; - - template - struct allocator - { - constexpr allocator () noexcept {} - - constexpr T *allocate (size_t n) - { return static_cast (::operator new (n * sizeof(T))); } - - constexpr void - deallocate (T *p, size_t n) - { ::operator delete (p); } - }; - - template - U __declval (int); - template - T __declval (long); - template - auto declval () noexcept -> decltype (__declval (0)); - - template - struct remove_reference - { typedef T type; }; - template - struct remove_reference - { typedef T type; }; - template - struct remove_reference - { typedef T type; }; - - template - constexpr T && - forward (typename std::remove_reference::type &t) noexcept - { return static_cast (t); } - - template - constexpr T && - forward (typename std::remove_reference::type &&t) noexcept - { return static_cast (t); } - - template - constexpr auto - construct_at (T *l, A &&... a) - noexcept (noexcept (::new ((void *) 0) T (std::declval ()...))) - -> decltype (::new ((void *) 0) T (std::declval ()...)) - { return ::new ((void *) l) T (std::forward (a)...); } - - template - constexpr inline void - destroy_at (T *l) - { l->~T (); } -} - -inline void *operator new (std::size_t, void *p) noexcept -{ return p; } +#include "construct_at.h" constexpr bool foo () diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-new20.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-new20.C new file mode 100644 index 0000000..88bc442 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-new20.C @@ -0,0 +1,18 @@ +// PR c++/101663 +// { dg-do compile { target c++20 } } + +#include "construct_at.h" + +template struct __box { + [[no_unique_address]] _Tp _M_value; +}; + +struct Empty {}; + +constexpr bool test() { + __box a; + std::construct_at(&a._M_value); + return true; +} + +static_assert(test()); diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-new5.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-new5.C index 2bb407a..eeaee96 100644 --- a/gcc/testsuite/g++.dg/cpp2a/constexpr-new5.C +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-new5.C @@ -1,65 +1,7 @@ // P0784R7 // { dg-do compile { target c++20 } } -namespace std -{ - typedef __SIZE_TYPE__ size_t; - - template - struct allocator - { - constexpr allocator () noexcept {} - - constexpr T *allocate (size_t n) - { return static_cast (::operator new (n * sizeof(T))); } - - constexpr void - deallocate (T *p, size_t n) - { ::operator delete (p); } - }; - - template - U __declval (int); - template - T __declval (long); - template - auto declval () noexcept -> decltype (__declval (0)); - - template - struct remove_reference - { typedef T type; }; - template - struct remove_reference - { typedef T type; }; - template - struct remove_reference - { typedef T type; }; - - template - constexpr T && - forward (typename std::remove_reference::type &t) noexcept - { return static_cast (t); } - - template - constexpr T && - forward (typename std::remove_reference::type &&t) noexcept - { return static_cast (t); } - - template - constexpr auto - construct_at (T *l, A &&... a) - noexcept (noexcept (::new ((void *) 0) T (std::declval ()...))) - -> decltype (::new ((void *) 0) T (std::declval ()...)) - { return ::new ((void *) l) T (std::forward (a)...); } - - template - constexpr inline void - destroy_at (T *l) - { l->~T (); } -} - -inline void *operator new (std::size_t, void *p) noexcept -{ return p; } +#include "construct_at.h" constexpr bool foo () diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-new6.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-new6.C index d51bdbb..eeaee96 100644 --- a/gcc/testsuite/g++.dg/cpp2a/constexpr-new6.C +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-new6.C @@ -1,69 +1,7 @@ // P0784R7 // { dg-do compile { target c++20 } } -namespace std -{ - inline namespace _8 { } - namespace _8 { - - typedef __SIZE_TYPE__ size_t; - - template - struct allocator - { - constexpr allocator () noexcept {} - - constexpr T *allocate (size_t n) - { return static_cast (::operator new (n * sizeof(T))); } - - constexpr void - deallocate (T *p, size_t n) - { ::operator delete (p); } - }; - - template - U __declval (int); - template - T __declval (long); - template - auto declval () noexcept -> decltype (__declval (0)); - - template - struct remove_reference - { typedef T type; }; - template - struct remove_reference - { typedef T type; }; - template - struct remove_reference - { typedef T type; }; - - template - constexpr T && - forward (typename std::remove_reference::type &t) noexcept - { return static_cast (t); } - - template - constexpr T && - forward (typename std::remove_reference::type &&t) noexcept - { return static_cast (t); } - - template - constexpr auto - construct_at (T *l, A &&... a) - noexcept (noexcept (::new ((void *) 0) T (std::declval ()...))) - -> decltype (::new ((void *) 0) T (std::declval ()...)) - { return ::new ((void *) l) T (std::forward (a)...); } - - template - constexpr inline void - destroy_at (T *l) - { l->~T (); } - } -} - -inline void *operator new (std::size_t, void *p) noexcept -{ return p; } +#include "construct_at.h" constexpr bool foo () diff --git a/gcc/testsuite/g++.dg/cpp2a/construct_at.h b/gcc/testsuite/g++.dg/cpp2a/construct_at.h new file mode 100644 index 0000000..27e92cb --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/construct_at.h @@ -0,0 +1,62 @@ +// A minimal conforming implementation of std::construct_at/destroy_at, +// used by some C++20 constexpr tests to avoid including all of . + +namespace std +{ + typedef __SIZE_TYPE__ size_t; + + template + struct allocator + { + constexpr allocator () noexcept {} + + constexpr T *allocate (size_t n) + { return static_cast (::operator new (n * sizeof(T))); } + + constexpr void + deallocate (T *p, size_t n) + { ::operator delete (p); } + }; + + template + U __declval (int); + template + T __declval (long); + template + auto declval () noexcept -> decltype (__declval (0)); + + template + struct remove_reference + { typedef T type; }; + template + struct remove_reference + { typedef T type; }; + template + struct remove_reference + { typedef T type; }; + + template + constexpr T && + forward (typename std::remove_reference::type &t) noexcept + { return static_cast (t); } + + template + constexpr T && + forward (typename std::remove_reference::type &&t) noexcept + { return static_cast (t); } + + template + constexpr auto + construct_at (T *l, A &&... a) + noexcept (noexcept (::new ((void *) 0) T (std::declval ()...))) + -> decltype (::new ((void *) 0) T (std::declval ()...)) + { return ::new ((void *) l) T (std::forward (a)...); } + + template + constexpr inline void + destroy_at (T *l) + { l->~T (); } +} + +inline void *operator new (std::size_t, void *p) noexcept +{ return p; } -- cgit v1.1 From 95e1eca43d106d821720744ac6ff1f5df41a1e78 Mon Sep 17 00:00:00 2001 From: liuhongt Date: Wed, 11 Aug 2021 14:00:00 +0800 Subject: Combine avx_vec_concatv16si and avx512f_zero_extendv16hiv16si2_1 to avx512f_zero_extendv16hiv16si2_2. Add define_insn_and_split to combine avx_vec_concatv16si/2 and avx512f_zero_extendv16hiv16si2_1 since the latter already zero_extend the upper bits, similar for other patterns which are related to pmovzx{bw,wd,dq}. It will do optimization like - vmovdqa %ymm0, %ymm0 # 7 [c=4 l=6] avx_vec_concatv16si/2 vpmovzxwd %ymm0, %zmm0 # 22 [c=4 l=6] avx512f_zero_extendv16hiv16si2 ret # 25 [c=0 l=1] simple_return_internal gcc/ChangeLog: PR target/101846 * config/i386/sse.md (*avx2_zero_extendv16qiv16hi2_2): New post_reload define_insn_and_split. (*avx512bw_zero_extendv32qiv32hi2_2): Ditto. (*sse4_1_zero_extendv8qiv8hi2_4): Ditto. (*avx512f_zero_extendv16hiv16si2_2): Ditto. (*avx2_zero_extendv8hiv8si2_2): Ditto. (*sse4_1_zero_extendv4hiv4si2_4): Ditto. (*avx512f_zero_extendv8siv8di2_2): Ditto. (*avx2_zero_extendv4siv4di2_2): Ditto. (*sse4_1_zero_extendv2siv2di2_4): Ditto. (VI248_256, VI248_512, VI148_512, VI148_256, VI148_128): New mode iterator. gcc/testsuite/ChangeLog: PR target/101846 * gcc.target/i386/pr101846-1.c: New test. --- gcc/config/i386/sse.md | 219 +++++++++++++++++++++++++++++ gcc/testsuite/gcc.target/i386/pr101846-1.c | 95 +++++++++++++ 2 files changed, 314 insertions(+) create mode 100644 gcc/testsuite/gcc.target/i386/pr101846-1.c (limited to 'gcc') diff --git a/gcc/config/i386/sse.md b/gcc/config/i386/sse.md index 3957c86..3a7bbae 100644 --- a/gcc/config/i386/sse.md +++ b/gcc/config/i386/sse.md @@ -681,7 +681,12 @@ (define_mode_iterator VI124_128 [V16QI V8HI V4SI]) (define_mode_iterator VI24_128 [V8HI V4SI]) (define_mode_iterator VI248_128 [V8HI V4SI V2DI]) +(define_mode_iterator VI248_256 [V16HI V8SI V4DI]) +(define_mode_iterator VI248_512 [V32HI V16SI V8DI]) (define_mode_iterator VI48_128 [V4SI V2DI]) +(define_mode_iterator VI148_512 [V64QI V16SI V8DI]) +(define_mode_iterator VI148_256 [V32QI V8SI V4DI]) +(define_mode_iterator VI148_128 [V16QI V4SI V2DI]) ;; Various 256bit and 512 vector integer mode combinations (define_mode_iterator VI124_256 [V32QI V16HI V8SI]) @@ -18603,6 +18608,26 @@ operands[1] = lowpart_subreg (V16QImode, operands[1], V32QImode); }) +(define_insn_and_split "*avx2_zero_extendv16qiv16hi2_2" + [(set (match_operand:V32QI 0 "register_operand" "=v") + (vec_select:V32QI + (vec_concat:V64QI + (subreg:V32QI + (vec_concat:VI248_256 + (match_operand: 1 "nonimmediate_operand" "vm") + (match_operand: 2 "const0_operand" "C")) 0) + (match_operand:V32QI 3 "const0_operand" "C")) + (match_parallel 4 "pmovzx_parallel" + [(match_operand 5 "const_int_operand" "n")])))] + "TARGET_AVX2" + "#" + "&& reload_completed" + [(set (match_dup 0) (zero_extend:V16HI (match_dup 1)))] +{ + operands[0] = lowpart_subreg (V16HImode, operands[0], V32QImode); + operands[1] = lowpart_subreg (V16QImode, operands[1], mode); +}) + (define_expand "v16qiv16hi2" [(set (match_operand:V16HI 0 "register_operand") (any_extend:V16HI @@ -18637,6 +18662,26 @@ operands[1] = lowpart_subreg (V32QImode, operands[1], V64QImode); }) +(define_insn_and_split "*avx512bw_zero_extendv32qiv32hi2_2" + [(set (match_operand:V64QI 0 "register_operand" "=v") + (vec_select:V64QI + (vec_concat:V128QI + (subreg:V64QI + (vec_concat:VI248_512 + (match_operand: 1 "nonimmediate_operand" "vm") + (match_operand: 2 "const0_operand" "C")) 0) + (match_operand:V64QI 3 "const0_operand" "C")) + (match_parallel 4 "pmovzx_parallel" + [(match_operand 5 "const_int_operand" "n")])))] + "TARGET_AVX512BW" + "#" + "&& reload_completed" + [(set (match_dup 0) (zero_extend:V32HI (match_dup 1)))] +{ + operands[0] = lowpart_subreg (V32HImode, operands[0], V64QImode); + operands[1] = lowpart_subreg (V32QImode, operands[1], mode); +}) + (define_expand "v32qiv32hi2" [(set (match_operand:V32HI 0 "register_operand") (any_extend:V32HI @@ -18723,6 +18768,41 @@ } [(set_attr "isa" "noavx,noavx,avx")]) +(define_insn_and_split "*sse4_1_zero_extendv8qiv8hi2_4" + [(set (match_operand:V16QI 0 "register_operand" "=Yr,*x,Yw") + (vec_select:V16QI + (vec_concat:V32QI + (subreg:V16QI + (vec_concat:VI248_128 + (match_operand: 1 "vector_operand" "YrBm,*xBm,Ywm") + (match_operand: 2 "const0_operand" "C,C,C")) 0) + (match_operand:V16QI 3 "const0_operand" "C,C,C")) + (match_parallel 4 "pmovzx_parallel" + [(match_operand 5 "const_int_operand" "n,n,n")])))] + "TARGET_SSE4_1" + "#" + "&& reload_completed" + [(set (match_dup 0) + (zero_extend:V8HI + (vec_select:V8QI + (match_dup 1) + (parallel [(const_int 0) (const_int 1) + (const_int 2) (const_int 3) + (const_int 4) (const_int 5) + (const_int 6) (const_int 7)]))))] +{ + operands[0] = lowpart_subreg (V8HImode, operands[0], V16QImode); + if (MEM_P (operands[1])) + { + operands[1] = lowpart_subreg (V8QImode, operands[1], mode); + operands[1] = gen_rtx_ZERO_EXTEND (V8HImode, operands[1]); + emit_insn (gen_rtx_SET (operands[0], operands[1])); + DONE; + } + operands[1] = lowpart_subreg (V16QImode, operands[1], mode); +} + [(set_attr "isa" "noavx,noavx,avx")]) + (define_expand "v8qiv8hi2" [(set (match_operand:V8HI 0 "register_operand") (any_extend:V8HI @@ -18913,6 +18993,26 @@ operands[1] = lowpart_subreg (V16HImode, operands[1], V32HImode); }) +(define_insn_and_split "*avx512f_zero_extendv16hiv16si2_2" + [(set (match_operand:V32HI 0 "register_operand" "=v") + (vec_select:V32HI + (vec_concat:V64HI + (subreg:V32HI + (vec_concat:VI148_512 + (match_operand: 1 "nonimmediate_operand" "vm") + (match_operand: 2 "const0_operand" "C")) 0) + (match_operand:V32HI 3 "const0_operand" "C")) + (match_parallel 4 "pmovzx_parallel" + [(match_operand 5 "const_int_operand" "n")])))] + "TARGET_AVX512F" + "#" + "&& reload_completed" + [(set (match_dup 0) (zero_extend:V16SI (match_dup 1)))] +{ + operands[0] = lowpart_subreg (V16SImode, operands[0], V32HImode); + operands[1] = lowpart_subreg (V16HImode, operands[1], mode); +}) + (define_insn "avx2_v8hiv8si2" [(set (match_operand:V8SI 0 "register_operand" "=v") (any_extend:V8SI @@ -18947,6 +19047,27 @@ operands[1] = lowpart_subreg (V8HImode, operands[1], V16HImode); }) +(define_insn_and_split "*avx2_zero_extendv8hiv8si2_2" + [(set (match_operand:V16HI 0 "register_operand" "=v") + (vec_select:V16HI + (vec_concat:V32HI + (subreg:V16HI + (vec_concat:VI148_256 + (match_operand: 1 "nonimmediate_operand" "vm") + (match_operand: 2 "const0_operand" "C")) 0) + (match_operand:V16HI 3 "const0_operand" "C")) + (match_parallel 4 "pmovzx_parallel" + [(match_operand 5 "const_int_operand" "n")])))] + "TARGET_AVX2" + "#" + "&& reload_completed" + [(set (match_dup 0) (zero_extend:V8SI (match_dup 1)))] +{ + operands[0] = lowpart_subreg (V8SImode, operands[0], V16HImode); + operands[1] = lowpart_subreg (V8HImode, operands[1], mode); +}) + + (define_insn "sse4_1_v4hiv4si2" [(set (match_operand:V4SI 0 "register_operand" "=Yr,*x,v") (any_extend:V4SI @@ -19036,6 +19157,39 @@ } [(set_attr "isa" "noavx,noavx,avx")]) +(define_insn_and_split "*sse4_1_zero_extendv4hiv4si2_4" + [(set (match_operand:V8HI 0 "register_operand" "=Yr,*x,v") + (vec_select:V8HI + (vec_concat:V16HI + (subreg:V8HI + (vec_concat:VI148_128 + (match_operand: 1 "vector_operand" "YrBm,*xBm,vm") + (match_operand: 2 "const0_operand" "C,C,C")) 0) + (match_operand:V8HI 3 "const0_operand" "C,C,C")) + (match_parallel 4 "pmovzx_parallel" + [(match_operand 5 "const_int_operand" "n,n,n")])))] + "TARGET_SSE4_1" + "#" + "&& reload_completed" + [(set (match_dup 0) + (zero_extend:V4SI + (vec_select:V4HI + (match_dup 1) + (parallel [(const_int 0) (const_int 1) + (const_int 2) (const_int 3)]))))] +{ + operands[0] = lowpart_subreg (V4SImode, operands[0], V8HImode); + if (MEM_P (operands[1])) + { + operands[1] = lowpart_subreg (V4HImode, operands[1], mode); + operands[1] = gen_rtx_ZERO_EXTEND (V4SImode, operands[1]); + emit_insn (gen_rtx_SET (operands[0], operands[1])); + DONE; + } + operands[1] = lowpart_subreg (V8HImode, operands[1], mode); +} + [(set_attr "isa" "noavx,noavx,avx")]) + (define_insn "avx512f_v8qiv8di2" [(set (match_operand:V8DI 0 "register_operand" "=v") (any_extend:V8DI @@ -19346,6 +19500,24 @@ operands[1] = lowpart_subreg (V8SImode, operands[1], V16SImode); }) +(define_insn_and_split "*avx512f_zero_extendv8siv8di2_2" + [(set (match_operand:V16SI 0 "register_operand" "=v") + (vec_select:V16SI + (vec_concat:V32SI + (vec_concat:V16SI + (match_operand:V8SI 1 "nonimmediate_operand" "vm") + (match_operand:V8SI 2 "const0_operand" "C")) + (match_operand:V16SI 3 "const0_operand" "C")) + (match_parallel 4 "pmovzx_parallel" + [(match_operand 5 "const_int_operand" "n")])))] + "TARGET_AVX512F" + "#" + "&& reload_completed" + [(set (match_dup 0) (zero_extend:V8DI (match_dup 1)))] +{ + operands[0] = lowpart_subreg (V8DImode, operands[0], V16SImode); +}) + (define_expand "v8siv8di2" [(set (match_operand:V8DI 0 "register_operand" "=v") (any_extend:V8DI @@ -19380,6 +19552,24 @@ operands[1] = lowpart_subreg (V4SImode, operands[1], V8SImode); }) +(define_insn_and_split "*avx2_zero_extendv4siv4di2_2" + [(set (match_operand:V8SI 0 "register_operand" "=v") + (vec_select:V8SI + (vec_concat:V16SI + (vec_concat:V8SI + (match_operand:V4SI 1 "nonimmediate_operand" "vm") + (match_operand:V4SI 2 "const0_operand" "C")) + (match_operand:V8SI 3 "const0_operand" "C")) + (match_parallel 4 "pmovzx_parallel" + [(match_operand 5 "const_int_operand" "n")])))] + "TARGET_AVX2" + "#" + "&& reload_completed" + [(set (match_dup 0) (zero_extend:V4DI (match_dup 1)))] +{ + operands[0] = lowpart_subreg (V4DImode, operands[0], V8SImode); +}) + (define_expand "v4siv4di2" [(set (match_operand:V4DI 0 "register_operand") (any_extend:V4DI @@ -19456,6 +19646,35 @@ } [(set_attr "isa" "noavx,noavx,avx")]) +(define_insn_and_split "*sse4_1_zero_extendv2siv2di2_4" + [(set (match_operand:V4SI 0 "register_operand" "=Yr,*x,v") + (vec_select:V4SI + (vec_concat:V8SI + (vec_concat:V4SI + (match_operand:V2SI 1 "vector_operand" "YrBm, *xBm, vm") + (match_operand:V2SI 2 "const0_operand" "C,C,C")) + (match_operand:V4SI 3 "const0_operand" "C,C,C")) + (match_parallel 4 "pmovzx_parallel" + [(match_operand 5 "const_int_operand" "n,n,n")])))] + "TARGET_SSE4_1" + "#" + "&& reload_completed" + [(set (match_dup 0) + (zero_extend:V2DI + (vec_select:V2SI (match_dup 1) + (parallel [(const_int 0) (const_int 1)]))))] +{ + operands[0] = lowpart_subreg (V2DImode, operands[0], V4SImode); + if (MEM_P (operands[1])) + { + operands[1] = gen_rtx_ZERO_EXTEND (V2DImode, operands[1]); + emit_insn (gen_rtx_SET (operands[0], operands[1])); + DONE; + } + operands[1] = lowpart_subreg (V4SImode, operands[1], V2SImode); +} + [(set_attr "isa" "noavx,noavx,avx")]) + (define_expand "v2siv2di2" [(set (match_operand:V2DI 0 "register_operand") (any_extend:V2DI diff --git a/gcc/testsuite/gcc.target/i386/pr101846-1.c b/gcc/testsuite/gcc.target/i386/pr101846-1.c new file mode 100644 index 0000000..40d95bd --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr101846-1.c @@ -0,0 +1,95 @@ +/* { dg-do compile } */ +/* { dg-options "-mavx512bw -mavx512vl -mavx512dq -O2" } */ +/* { dg-final { scan-assembler-not "vmov" } } */ +/* { dg-final { scan-assembler-times "vpmovzxbw" "3" } } */ +/* { dg-final { scan-assembler-times "vpmovzxwd" "3" } } */ +/* { dg-final { scan-assembler-times "vpmovzxdq" "3" } } */ + +typedef short v4hi __attribute__((vector_size (8))); +typedef short v8hi __attribute__((vector_size (16))); +typedef short v16hi __attribute__((vector_size (32))); +typedef short v32hi __attribute__((vector_size (64))); +typedef char v8qi __attribute__((vector_size (8))); +typedef char v16qi __attribute__((vector_size (16))); +typedef char v32qi __attribute__((vector_size (32))); +typedef char v64qi __attribute__((vector_size (64))); +typedef int v2si __attribute__((vector_size (8))); +typedef int v4si __attribute__((vector_size (16))); +typedef int v8si __attribute__((vector_size (32))); +typedef int v16si __attribute__((vector_size (64))); + +v32hi +foo_zxwd_512 (v16hi x) +{ + return __builtin_shufflevector (x, (v16hi) {}, + 0, 16, 1, 17, 2, 18, 3, 19, + 4, 20, 5, 21, 6, 22, 7, 23, + 8, 24, 9, 25, 10, 26, 11, 27, + 12, 28, 13, 29, 14, 30, 15, 31); +} + +v16hi +foo_zxwd_256 (v8hi x) +{ + return __builtin_shufflevector (x, (v8hi) {}, + 0, 8, 1, 9, 2, 10, 3, 11, + 4, 12, 5, 13, 6, 14, 7, 15); +} + +v8hi +foo_zxwd_128 (v4hi x) +{ + return __builtin_shufflevector (x, (v4hi) {}, 0, 4, 1, 5, 2, 6, 3, 7); +} + +v16si +foo_zxdq_512 (v8si x) +{ + return __builtin_shufflevector (x, (v8si) {}, + 0, 8, 1, 9, 2, 10, 3, 11, + 4, 12, 5, 13, 6, 14, 7, 15); +} + +v8si +foo_zxdq_256 (v4si x) +{ + return __builtin_shufflevector (x, (v4si) {}, 0, 4, 1, 5, 2, 6, 3, 7); +} + +v4si +foo_zxdq_128 (v2si x) +{ + return __builtin_shufflevector (x, (v2si) {}, 0, 2, 1, 3); +} + +v64qi +foo_zxbw_512 (v32qi x) +{ + return __builtin_shufflevector (x, (v32qi) {}, + 0, 32, 1, 33, 2, 34, 3, 35, + 4, 36, 5, 37, 6, 38, 7, 39, + 8, 40, 9, 41, 10, 42, 11, 43, + 12, 44, 13, 45, 14, 46, 15, 47, + 16, 48, 17, 49, 18, 50, 19, 51, + 20, 52, 21, 53, 22, 54, 23, 55, + 24, 56, 25, 57, 26, 58, 27, 59, + 28, 60, 29, 61, 30, 62, 31, 63); +} + +v32qi +foo_zxbw_256 (v16qi x) +{ + return __builtin_shufflevector (x, (v16qi) {}, + 0, 16, 1, 17, 2, 18, 3, 19, + 4, 20, 5, 21, 6, 22, 7, 23, + 8, 24, 9, 25, 10, 26, 11, 27, + 12, 28, 13, 29, 14, 30, 15, 31); +} + +v16qi +foo_zxbw_128 (v8qi x) +{ + return __builtin_shufflevector (x, (v8qi) {}, + 0, 8, 1, 9, 2, 10, 3, 11, + 4, 12, 5, 13, 6, 14, 7, 15); +} -- cgit v1.1 From 2bdf17de1d0ad7a75d3474e672a3a2110919862f Mon Sep 17 00:00:00 2001 From: Eric Botcazou Date: Thu, 12 Aug 2021 09:30:31 +0200 Subject: Make -no-pie option work for native Windows Binutils 2.36/2.37 generate PIE executables by default on native Windows (because --dynamicbase is the default) so it makes sense to have a simple way to counter that and -no-pie seems appropriate, all the more so that it is automatically passed when building the compiler itself. gcc/ * configure.ac (PE linker --disable-dynamicbase support): New check. * configure: Regenerate. * config.in: Likewise. * config/i386/mingw32.h (LINK_SPEC_DISABLE_DYNAMICBASE): New define. (LINK_SPEC): Use it. * config/i386/mingw-w64.h (LINK_SPEC_DISABLE_DYNAMICBASE): Likewise. (LINK_SPEC): Likewise. --- gcc/config.in | 6 ++++++ gcc/config/i386/mingw-w64.h | 9 +++++++++ gcc/config/i386/mingw32.h | 8 ++++++++ gcc/configure | 20 ++++++++++++++++++++ gcc/configure.ac | 17 +++++++++++++++++ 5 files changed, 60 insertions(+) (limited to 'gcc') diff --git a/gcc/config.in b/gcc/config.in index affaff2..7f5b01f 100644 --- a/gcc/config.in +++ b/gcc/config.in @@ -1695,6 +1695,12 @@ #endif +/* Define if the PE linker supports --disable-dynamicbase option. */ +#ifndef USED_FOR_TARGET +#undef HAVE_LD_PE_DISABLE_DYNAMICBASE +#endif + + /* Define if your linker supports PIE option. */ #ifndef USED_FOR_TARGET #undef HAVE_LD_PIE diff --git a/gcc/config/i386/mingw-w64.h b/gcc/config/i386/mingw-w64.h index 0cec6b0..6cc7ac5 100644 --- a/gcc/config/i386/mingw-w64.h +++ b/gcc/config/i386/mingw-w64.h @@ -89,6 +89,14 @@ along with GCC; see the file COPYING3. If not see # define LINK_SPEC_LARGE_ADDR_AWARE "" #endif +#undef LINK_SPEC_DISABLE_DYNAMICBASE +#if HAVE_LD_PE_DISABLE_DYNAMICBASE +# define LINK_SPEC_DISABLE_DYNAMICBASE \ + "%{!shared:%{!mdll:%{no-pie:--disable-dynamicbase}}}" +#else +# define LINK_SPEC_DISABLE_DYNAMICBASE "" +#endif + #undef LINK_SPEC #define LINK_SPEC SUB_LINK_SPEC " %{mwindows:--subsystem windows} \ %{mconsole:--subsystem console} \ @@ -97,6 +105,7 @@ along with GCC; see the file COPYING3. If not see %{static:-Bstatic} %{!static:-Bdynamic} \ %{shared|mdll: " SUB_LINK_ENTRY " --enable-auto-image-base} \ " LINK_SPEC_LARGE_ADDR_AWARE "\ + " LINK_SPEC_DISABLE_DYNAMICBASE "\ %(shared_libgcc_undefs)" /* Enable sincos optimization, overriding cygming.h. sincos, sincosf diff --git a/gcc/config/i386/mingw32.h b/gcc/config/i386/mingw32.h index 36e7bae..779c933 100644 --- a/gcc/config/i386/mingw32.h +++ b/gcc/config/i386/mingw32.h @@ -148,6 +148,13 @@ along with GCC; see the file COPYING3. If not see "%{!shared:%{!mdll:%{!m64:--large-address-aware}}}" #endif +#if HAVE_LD_PE_DISABLE_DYNAMICBASE +# define LINK_SPEC_DISABLE_DYNAMICBASE \ + "%{!shared:%{!mdll:%{no-pie:--disable-dynamicbase}}}" +#else +# define LINK_SPEC_DISABLE_DYNAMICBASE "" +#endif + #define LINK_SPEC "%{mwindows:--subsystem windows} \ %{mconsole:--subsystem console} \ %{shared: %{mdll: %eshared and mdll are not compatible}} \ @@ -155,6 +162,7 @@ along with GCC; see the file COPYING3. If not see %{static:-Bstatic} %{!static:-Bdynamic} \ %{shared|mdll: " SUB_LINK_ENTRY " --enable-auto-image-base} \ " LINK_SPEC_LARGE_ADDR_AWARE "\ + " LINK_SPEC_DISABLE_DYNAMICBASE "\ %(shared_libgcc_undefs)" /* Include in the mingw32 libraries with libgcc */ diff --git a/gcc/configure b/gcc/configure index 8b5acd7..08c2867 100755 --- a/gcc/configure +++ b/gcc/configure @@ -30613,6 +30613,26 @@ $as_echo "#define HAVE_LD_BROKEN_PE_DWARF5 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_ld_broken_pe_dwarf5" >&5 $as_echo "$gcc_cv_ld_broken_pe_dwarf5" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking PE linker --disable-dynamicbase support" >&5 +$as_echo_n "checking PE linker --disable-dynamicbase support... " >&6; } + gcc_cv_ld_disable_dynamicbase=no + if test $in_tree_ld = yes; then + if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 36 -o "$gcc_cv_gld_major_version" -gt 2; then \ + gcc_cv_ld_disable_dynamicbase=yes + fi + else + if $gcc_cv_ld --help 2>&1 | grep -q 'disable\-]dynamicbase' > /dev/null; then + gcc_cv_ld_disable_dynamicbase=yes + fi + fi + if test x"$gcc_cv_ld_disable_dynamicbase" = xyes; then + +$as_echo "#define HAVE_LD_PE_DISABLE_DYNAMICBASE 1" >>confdefs.h + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_ld_disable_dynamicbase" >&5 +$as_echo "$gcc_cv_ld_disable_dynamicbase" >&6; } ;; esac diff --git a/gcc/configure.ac b/gcc/configure.ac index c8e0d63..653a1cc 100644 --- a/gcc/configure.ac +++ b/gcc/configure.ac @@ -6383,6 +6383,23 @@ case $target_os in [Define if the PE linker has broken DWARF 5 support.]) fi AC_MSG_RESULT($gcc_cv_ld_broken_pe_dwarf5) + + AC_MSG_CHECKING(PE linker --disable-dynamicbase support) + gcc_cv_ld_disable_dynamicbase=no + if test $in_tree_ld = yes; then + if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 36 -o "$gcc_cv_gld_major_version" -gt 2; then \ + gcc_cv_ld_disable_dynamicbase=yes + fi + else + if $gcc_cv_ld --help 2>&1 | grep -q 'disable\-]dynamicbase' > /dev/null; then + gcc_cv_ld_disable_dynamicbase=yes + fi + fi + if test x"$gcc_cv_ld_disable_dynamicbase" = xyes; then + AC_DEFINE(HAVE_LD_PE_DISABLE_DYNAMICBASE, 1, + [Define if the PE linker supports --disable-dynamicbase option.]) + fi + AC_MSG_RESULT($gcc_cv_ld_disable_dynamicbase) ;; esac -- cgit v1.1 From 3890c28ac5bd03ba334a20fbf9518a37dcdbfe5d Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Thu, 12 Aug 2021 09:09:39 +0200 Subject: c++: Fix up parsing of attributes for using-directive As I've said earlier and added xfails in gen-attrs-76.C test, https://eel.is/c++draft/namespace.udir#nt:using-directive has attribute-specifier-seq[opt] at the start, not at the end before ; as gcc is expecting. IMHO we should continue parsing at the end the GNU attributes because using namespace N __attribute__((strong));, while not supported anymore, used to be supported in the past, but my code searches for using namespace N [[gnu::strong]]; didn't reveal anything at all. 2021-08-12 Jakub Jelinek * parser.c (cp_parser_block_declaration): Call cp_parser_using_directive for C++11 attributes followed by using namespace tokens. (cp_parser_using_directive): Parse C++11 attributes at the start of the directive rather than at the end, only parse GNU attributes at the end. * g++.dg/lookup/strong-using.C: Add test using [[gnu::strong]] as well. * g++.dg/lookup/strong-using2.C: Likewise. * g++.dg/cpp0x/gen-attrs-58.C: Move alignas(int) before using namespace. * g++.dg/cpp0x/gen-attrs-59.C: Move alignas(X) before using namespace, add tests for alignas before semicolon. * g++.dg/cpp0x/gen-attrs-76.C: Remove xfails. Add test for C++11 attributes on using directive before semicolon. --- gcc/cp/parser.c | 31 ++++++++++++++++++++++++----- gcc/testsuite/g++.dg/cpp0x/gen-attrs-58.C | 2 +- gcc/testsuite/g++.dg/cpp0x/gen-attrs-59.C | 9 ++++++++- gcc/testsuite/g++.dg/cpp0x/gen-attrs-76.C | 7 +++++-- gcc/testsuite/g++.dg/lookup/strong-using.C | 9 +++++++++ gcc/testsuite/g++.dg/lookup/strong-using2.C | 9 +++++++++ 6 files changed, 58 insertions(+), 9 deletions(-) (limited to 'gcc') diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index d564e3b..ec885d7 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -14853,6 +14853,7 @@ cp_parser_block_declaration (cp_parser *parser, /* Peek at the next token to figure out which kind of declaration is present. */ cp_token *token1 = cp_lexer_peek_token (parser->lexer); + size_t attr_idx; /* If the next keyword is `asm', we have an asm-definition. */ if (token1->keyword == RID_ASM) @@ -14906,6 +14907,18 @@ cp_parser_block_declaration (cp_parser *parser, /* If the next token is `static_assert' we have a static assertion. */ else if (token1->keyword == RID_STATIC_ASSERT) cp_parser_static_assert (parser, /*member_p=*/false); + /* If the next tokens after attributes is `using namespace', then we have + a using-directive. */ + else if ((attr_idx = cp_parser_skip_std_attribute_spec_seq (parser, 1)) != 1 + && cp_lexer_nth_token_is_keyword (parser->lexer, attr_idx, + RID_USING) + && cp_lexer_nth_token_is_keyword (parser->lexer, attr_idx + 1, + RID_NAMESPACE)) + { + if (statement_p) + cp_parser_commit_to_tentative_parse (parser); + cp_parser_using_directive (parser); + } /* Anything else must be a simple-declaration. */ else cp_parser_simple_declaration (parser, !statement_p, @@ -21609,14 +21622,21 @@ cp_parser_alias_declaration (cp_parser* parser) /* Parse a using-directive. using-directive: - using namespace :: [opt] nested-name-specifier [opt] - namespace-name ; */ + attribute-specifier-seq [opt] using namespace :: [opt] + nested-name-specifier [opt] namespace-name ; */ static void cp_parser_using_directive (cp_parser* parser) { tree namespace_decl; - tree attribs; + tree attribs = cp_parser_std_attribute_spec_seq (parser); + if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON)) + { + /* Error during attribute parsing that resulted in skipping + to next semicolon. */ + cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON); + return; + } /* Look for the `using' keyword. */ cp_parser_require_keyword (parser, RID_USING, RT_USING); @@ -21633,8 +21653,9 @@ cp_parser_using_directive (cp_parser* parser) /* Get the namespace being used. */ namespace_decl = cp_parser_namespace_name (parser); cp_warn_deprecated_use_scopes (namespace_decl); - /* And any specified attributes. */ - attribs = cp_parser_attributes_opt (parser); + /* And any specified GNU attributes. */ + if (cp_next_tokens_can_be_gnu_attribute_p (parser)) + attribs = chainon (attribs, cp_parser_gnu_attributes_opt (parser)); /* Update the symbol table. */ finish_using_directive (namespace_decl, attribs); diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-58.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-58.C index f760f56..dc01722 100644 --- a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-58.C +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-58.C @@ -2,4 +2,4 @@ // { dg-do compile { target c++11 } } namespace N { int i; } -using namespace N alignas(int); // { dg-warning "ignored" } +alignas(int) using namespace N; // { dg-warning "ignored" } diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-59.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-59.C index c7839fe..9776dc3 100644 --- a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-59.C +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-59.C @@ -2,4 +2,11 @@ // { dg-do compile { target c++11 } } namespace N {} -using namespace N alignas(X); // { dg-error "declared" } +alignas(X) using namespace N; // { dg-error "declared" } +namespace O {} +using namespace O alignas(X); // { dg-error "expected" } +// { dg-error "declared" "" { target *-*-* } .-1 } +// { dg-warning "attribute ignored" "" { target *-*-* } .-2 } +namespace P {} +using namespace P alignas(int); // { dg-error "expected" } +// { dg-warning "attribute ignored" "" { target *-*-* } .-1 } diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-76.C b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-76.C index cbda8de..72cd4b3 100644 --- a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-76.C +++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-76.C @@ -3,6 +3,7 @@ namespace N {} namespace O { typedef int T; }; +namespace P {} void foo () @@ -11,7 +12,8 @@ foo () [[]] __extension__ asm (""); // { dg-error "expected" } __extension__ [[]] asm (""); // { dg-error "expected" } [[]] namespace M = ::N; // { dg-error "expected" } - [[]] using namespace N; // { dg-bogus "expected" "" { xfail *-*-* } } + [[]] using namespace N; // { dg-bogus "expected" } + using namespace P [[]]; // { dg-error "expected" } [[]] using O::T; // { dg-error "expected" } [[]] __label__ foo; // { dg-error "expected" } [[]] static_assert (true, ""); // { dg-error "expected" } @@ -24,7 +26,8 @@ bar () [[gnu::unused]] __extension__ asm (""); // { dg-error "expected" } __extension__ [[gnu::unused]] asm (""); // { dg-error "expected" } [[gnu::unused]] namespace M = ::N; // { dg-error "expected" } - [[gnu::unused]] using namespace N; // { dg-bogus "expected" "" { xfail *-*-* } } + [[gnu::unused]] using namespace N; // { dg-bogus "expected" } + using namespace P [[gnu::unused]]; // { dg-error "expected" } [[gnu::unused]] using O::T; // { dg-error "expected" } [[gnu::unused]] __label__ foo; // { dg-error "expected" } [[gnu::unused]] static_assert (true, ""); // { dg-error "expected" } diff --git a/gcc/testsuite/g++.dg/lookup/strong-using.C b/gcc/testsuite/g++.dg/lookup/strong-using.C index 9d58fdd..2bd821e 100644 --- a/gcc/testsuite/g++.dg/lookup/strong-using.C +++ b/gcc/testsuite/g++.dg/lookup/strong-using.C @@ -8,3 +8,12 @@ namespace A using namespace B __attribute__ ((strong)); // { dg-warning "no longer supported" "" } } + +namespace C +{ + namespace D // { dg-message "inline namespace" } + { + } + + [[gnu::strong]] using namespace D; // { dg-warning "no longer supported" "" } +} diff --git a/gcc/testsuite/g++.dg/lookup/strong-using2.C b/gcc/testsuite/g++.dg/lookup/strong-using2.C index 1728494..989827c 100644 --- a/gcc/testsuite/g++.dg/lookup/strong-using2.C +++ b/gcc/testsuite/g++.dg/lookup/strong-using2.C @@ -9,3 +9,12 @@ namespace A using namespace B __attribute__ ((strong)); // { dg-bogus "no longer supported" } } + +namespace C +{ + namespace D // { dg-bogus "inline namespace" } + { + } + + [[gnu::strong]] using namespace D; // { dg-bogus "no longer supported" } +} -- cgit v1.1 From c84f79e9e3f63e9ae447fd15dbd0a768cab3f643 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Thu, 12 Aug 2021 09:10:46 +0200 Subject: openmp: Diagnose omp::directive/sequence on using-directive With the using-directive parsing changes, we now emit only a warning for [[omp::directive (...)]] on using-directive. While that is right without -fopenmp/-fopenmp-simd, when OpenMP is enabled, that should be an error as OpenMP (is going to) disallow such attributes there as they do not appertain to a statement. 2021-08-12 Jakub Jelinek * name-lookup.c (finish_using_directive): Diagnose omp::directive or omp::sequence attributes on using-directive. * g++.dg/gomp/attrs-11.C: Adjust expected diagnostics. --- gcc/cp/name-lookup.c | 11 +++++++++++ gcc/testsuite/g++.dg/gomp/attrs-11.C | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index 1be5f3d..8e9c61e 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -8560,6 +8560,7 @@ finish_using_directive (tree target, tree attribs) add_using_namespace (current_binding_level->using_directives, ORIGINAL_NAMESPACE (target)); + bool diagnosed = false; if (attribs != error_mark_node) for (tree a = attribs; a; a = TREE_CHAIN (a)) { @@ -8572,6 +8573,16 @@ finish_using_directive (tree target, tree attribs) inform (DECL_SOURCE_LOCATION (target), "you can use an inline namespace instead"); } + else if ((flag_openmp || flag_openmp_simd) + && get_attribute_namespace (a) == omp_identifier + && (is_attribute_p ("directive", name) + || is_attribute_p ("sequence", name))) + { + if (!diagnosed) + error ("% not allowed to be specified in this " + "context", name); + diagnosed = true; + } else warning (OPT_Wattributes, "%qD attribute directive ignored", name); } diff --git a/gcc/testsuite/g++.dg/gomp/attrs-11.C b/gcc/testsuite/g++.dg/gomp/attrs-11.C index a8e27b7..009bcb2 100644 --- a/gcc/testsuite/g++.dg/gomp/attrs-11.C +++ b/gcc/testsuite/g++.dg/gomp/attrs-11.C @@ -11,7 +11,7 @@ foo () [[omp::directive (parallel)]] __extension__ asm (""); // { dg-error "expected" } __extension__ [[omp::directive (parallel)]] asm (""); // { dg-error "expected" } [[omp::directive (parallel)]] namespace M = ::N; // { dg-error "expected" } - [[omp::directive (parallel)]] using namespace N; // { dg-bogus "expected" "" { xfail *-*-* } } + [[omp::directive (parallel)]] using namespace N; // { dg-error "not allowed to be specified in this context" } [[omp::directive (parallel)]] using O::T; // { dg-error "expected" } [[omp::directive (parallel)]] __label__ foo; // { dg-error "expected" } [[omp::directive (parallel)]] static_assert (true, ""); // { dg-error "expected" } -- cgit v1.1 From 9b7ab853bf33106fd0539e36d6ce7730269026e1 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Thu, 12 Aug 2021 09:16:13 +0200 Subject: c++: Fix ICE on defaulted spaceship with pointer return type [PR94162] The spaceship-synth-neg6.C testcase ICEs because we call cat_tag_for on the explicit return type, but pointer types don't have TYPE_LINKAGE_IDENTIFIER. The patch fixes that by checking for CLASS_TYPE_P only and also adds verification that it is in std namespace, so we don't return non-cc_last for my_namespace::partial_ordering. The g++.dg/cpp2a/spaceship-synth11.C testcase is from a PR that has been fixed with r12-619-gfc178519771db508c03611cff4a1466cf67fce1d (but not backported to 11). 2021-08-12 Jakub Jelinek gcc/cp/ PR c++/94162 * method.c (cat_tag_for): Return cc_last for !CLASS_TYPE_P or for classes not in std namespace. gcc/testsuite/ PR c++/99429 * g++.dg/cpp2a/spaceship-synth11.C: New test. PR c++/94162 * g++.dg/cpp2a/spaceship-synth-neg6.C: New test. --- gcc/cp/method.c | 2 ++ gcc/testsuite/g++.dg/cpp2a/spaceship-synth-neg6.C | 11 +++++++++ gcc/testsuite/g++.dg/cpp2a/spaceship-synth11.C | 29 +++++++++++++++++++++++ 3 files changed, 42 insertions(+) create mode 100644 gcc/testsuite/g++.dg/cpp2a/spaceship-synth-neg6.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/spaceship-synth11.C (limited to 'gcc') diff --git a/gcc/cp/method.c b/gcc/cp/method.c index f268aab..353046d 100644 --- a/gcc/cp/method.c +++ b/gcc/cp/method.c @@ -1029,6 +1029,8 @@ is_cat (tree type, comp_cat_tag tag) static comp_cat_tag cat_tag_for (tree type) { + if (!CLASS_TYPE_P (type) || !decl_in_std_namespace_p (TYPE_MAIN_DECL (type))) + return cc_last; for (int i = 0; i < cc_last; ++i) { comp_cat_tag tag = (comp_cat_tag)i; diff --git a/gcc/testsuite/g++.dg/cpp2a/spaceship-synth-neg6.C b/gcc/testsuite/g++.dg/cpp2a/spaceship-synth-neg6.C new file mode 100644 index 0000000..d3f95e1 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/spaceship-synth-neg6.C @@ -0,0 +1,11 @@ +// PR c++/94162 +// { dg-do compile { target c++20 } } + +#include + +struct S { + int a; // { dg-error "three-way comparison of 'S::a' has type 'std::strong_ordering', which does not convert to 'int\\*'" } + int *operator<=>(const S&) const = default; +}; + +bool b = S{} < S{}; // { dg-error "use of deleted function 'constexpr int\\* S::operator<=>\\\(const S&\\\) const'" } diff --git a/gcc/testsuite/g++.dg/cpp2a/spaceship-synth11.C b/gcc/testsuite/g++.dg/cpp2a/spaceship-synth11.C new file mode 100644 index 0000000..37c8157 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/spaceship-synth11.C @@ -0,0 +1,29 @@ +// PR c++/99429 +// { dg-do compile { target c++20 } } + +namespace std { +struct strong_ordering { + int _v; + constexpr strong_ordering (int v) :_v(v) {} + constexpr operator int (void) const { return _v; } + static const strong_ordering less; + static const strong_ordering equal; + static const strong_ordering greater; +}; +constexpr strong_ordering strong_ordering::less = -1; +constexpr strong_ordering strong_ordering::equal = 0; +constexpr strong_ordering strong_ordering::greater = 1; +} + +template +struct duration { + static constexpr const long period = N; + constexpr duration (void) = default; + constexpr duration (const duration& d) = default; + constexpr bool operator== (const duration& d) const = default; + constexpr bool operator<=> (const duration& d) const = default; + long _d; +}; + +using nanoseconds = duration<1>; +using microseconds = duration; -- cgit v1.1 From ef07b918a7ad4f64e0e1e3db21d861f2e79de92a Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Thu, 12 Aug 2021 09:18:23 +0200 Subject: openmp: Diagnose another case of mixing parameter and attribute syntax This patch diagnoses cases like: #pragma omp parallel [[omp::directive (declare simd)]] int foo (); or #pragma omp taskgroup int bar [[omp::directive (declare simd)]] (int); where the pragma is on the same declaration statement as the declare simd attribute. 2021-08-12 Jakub Jelinek * parser.c (cp_parser_lambda_body): Add temp overrides for parser->{omp_declare_simd,oacc_routine,omp_attrs_forbidden_p}. (cp_parser_statement): Restore parser->omp_attrs_forbidden_p for cp_parser_declaration_statement. (cp_parser_default_argument): Add temp override for parser->omp_attrs_forbidden_p. (cp_parser_late_parsing_omp_declare_simd): Diagnose declare simd or declare variant in attribute syntax on a declaration immediately following an OpenMP construct in pragma syntax. * g++.dg/gomp/attrs-11.C: Add new tests. --- gcc/cp/parser.c | 15 +++++++++++++++ gcc/testsuite/g++.dg/gomp/attrs-11.C | 12 ++++++++++++ 2 files changed, 27 insertions(+) (limited to 'gcc') diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index ec885d7..fbb8130 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -11628,6 +11628,9 @@ cp_parser_lambda_body (cp_parser* parser, tree lambda_expr) middle of an expression. */ ++function_depth; + auto odsd = make_temp_override (parser->omp_declare_simd, NULL); + auto ord = make_temp_override (parser->oacc_routine, NULL); + auto oafp = make_temp_override (parser->omp_attrs_forbidden_p, false); vec omp_privatization_save; save_omp_privatization_clauses (omp_privatization_save); /* Clear this in case we're in the middle of a default argument. */ @@ -12271,9 +12274,11 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, so let's un-parse them. */ saved_tokens.rollback(); + parser->omp_attrs_forbidden_p = omp_attrs_forbidden_p; cp_parser_parse_tentatively (parser); /* Try to parse the declaration-statement. */ cp_parser_declaration_statement (parser); + parser->omp_attrs_forbidden_p = false; /* If that worked, we're done. */ if (cp_parser_parse_definitely (parser)) return; @@ -24768,6 +24773,8 @@ cp_parser_default_argument (cp_parser *parser, bool template_parm_p) parser->greater_than_is_operator_p = !template_parm_p; auto odsd = make_temp_override (parser->omp_declare_simd, NULL); auto ord = make_temp_override (parser->oacc_routine, NULL); + auto oafp = make_temp_override (parser->omp_attrs_forbidden_p, false); + /* Local variable names (and the `this' keyword) may not appear in a default argument. */ saved_local_variables_forbidden_p = parser->local_variables_forbidden_p; @@ -44503,6 +44510,14 @@ cp_parser_late_parsing_omp_declare_simd (cp_parser *parser, tree attrs) continue; } + if (parser->omp_attrs_forbidden_p) + { + error_at (first->location, + "mixing OpenMP directives with attribute and " + "pragma syntax on the same statement"); + parser->omp_attrs_forbidden_p = false; + } + if (!flag_openmp && strcmp (directive[1], "simd") != 0) continue; if (lexer == NULL) diff --git a/gcc/testsuite/g++.dg/gomp/attrs-11.C b/gcc/testsuite/g++.dg/gomp/attrs-11.C index 009bcb2..44e025e 100644 --- a/gcc/testsuite/g++.dg/gomp/attrs-11.C +++ b/gcc/testsuite/g++.dg/gomp/attrs-11.C @@ -72,3 +72,15 @@ int f28 [[omp::directive (declare simd), omp::directive (foobar)]] (int); // { d int f29 [[omp::directive (foobar), omp::directive (declare simd)]] (int); // { dg-error "unknown OpenMP directive name" } int f30 [[omp::directive (threadprivate (t7)), omp::directive (declare simd)]] (int); // { dg-error "OpenMP directive other than 'declare simd' or 'declare variant' appertains to a declaration" } int f31 [[omp::directive (declare simd), omp::directive (threadprivate (t8))]] (int); // { dg-error "OpenMP directive other than 'declare simd' or 'declare variant' appertains to a declaration" } + +void +baz () +{ + #pragma omp parallel + [[omp::directive (declare simd)]] extern int f32 (int); // { dg-error "mixing OpenMP directives with attribute and pragma syntax on the same statement" } + #pragma omp parallel + extern int f33 [[omp::directive (declare simd)]] (int); // { dg-error "mixing OpenMP directives with attribute and pragma syntax on the same statement" } + [[omp::directive (parallel)]] + #pragma omp declare simd // { dg-error "mixing OpenMP directives with attribute and pragma syntax on the same statement" } + extern int f34 (int); +} -- cgit v1.1 From 01f8a8b48e50cbaa68b878d9f8a330b8c0736bed Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Thu, 12 Aug 2021 09:26:27 +0200 Subject: openmp: Diagnose syntax mismatches between declare target and end declare target OpenMP 5.1 says: For any directive that has a paired end directive, including those with a begin and end pair, both directives must use either the attribute syntax or the pragma syntax. The following patch enforces it with the only pair so far recognized in C++ (Fortran has many, but on the other side doesn't have attribute syntax). While I initially wanted to use vec *member; in there, that unfortunately doesn't work, one gets linker errors and I guess it is fixable, but for begin declare target we'll need a struct anyway to store device_type etc. 2021-08-12 Jakub Jelinek * cp-tree.h (omp_declare_target_attr): New type. (struct saved_scope): Change type of omp_declare_target_attribute from int to vec * and move it. * parser.c (cp_parser_omp_declare_target): Instead of incrementing scope_chain->omp_declare_target_attribute, push a struct containing parser->lexer->in_omp_attribute_pragma to the vector. (cp_parser_omp_end_declare_target): Instead of decrementing scope_chain->omp_declare_target_attribute, pop a structure from it. Diagnose mismatching declare target vs. end declare target syntax. * semantics.c (finish_translation_unit): Use vec_safe_length and vec_safe_truncate on scope_chain->omp_declare_target_attributes. * decl2.c (cplus_decl_attributes): Use vec_safe_length on scope_chain->omp_declare_target_attributes. * g++.dg/gomp/attrs-12.C: New test. --- gcc/cp/cp-tree.h | 8 ++++--- gcc/cp/decl2.c | 2 +- gcc/cp/parser.c | 23 +++++++++++++++++--- gcc/cp/semantics.c | 4 ++-- gcc/testsuite/g++.dg/gomp/attrs-12.C | 41 ++++++++++++++++++++++++++++++++++++ 5 files changed, 69 insertions(+), 9 deletions(-) create mode 100644 gcc/testsuite/g++.dg/gomp/attrs-12.C (limited to 'gcc') diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 6a8264b..bd3f12a 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -1789,6 +1789,10 @@ union GTY((desc ("cp_tree_node_structure (&%h)"), }; +struct GTY(()) omp_declare_target_attr { + bool attr_syntax; +}; + /* Global state. */ struct GTY(()) saved_scope { @@ -1826,9 +1830,6 @@ struct GTY(()) saved_scope { int unevaluated_operand; int inhibit_evaluation_warnings; int noexcept_operand; - /* If non-zero, implicit "omp declare target" attribute is added into the - attribute lists. */ - int omp_declare_target_attribute; int ref_temp_count; struct stmt_tree_s x_stmt_tree; @@ -1837,6 +1838,7 @@ struct GTY(()) saved_scope { cp_binding_level *bindings; hash_map *GTY((skip)) x_local_specializations; + vec *omp_declare_target_attribute; struct saved_scope *prev; }; diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index ba27388..0c9d2f4 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -1551,7 +1551,7 @@ cplus_decl_attributes (tree *decl, tree attributes, int flags) return; /* Add implicit "omp declare target" attribute if requested. */ - if (scope_chain->omp_declare_target_attribute + if (vec_safe_length (scope_chain->omp_declare_target_attribute) && ((VAR_P (*decl) && (TREE_STATIC (*decl) || DECL_EXTERNAL (*decl))) || TREE_CODE (*decl) == FUNCTION_DECL)) diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index fbb8130..74de529 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -44641,8 +44641,10 @@ cp_parser_omp_declare_target (cp_parser *parser, cp_token *pragma_tok) } else { + struct omp_declare_target_attr a + = { parser->lexer->in_omp_attribute_pragma }; + vec_safe_push (scope_chain->omp_declare_target_attribute, a); cp_parser_require_pragma_eol (parser, pragma_tok); - scope_chain->omp_declare_target_attribute++; return; } for (tree c = clauses; c; c = OMP_CLAUSE_CHAIN (c)) @@ -44723,6 +44725,7 @@ static void cp_parser_omp_end_declare_target (cp_parser *parser, cp_token *pragma_tok) { const char *p = ""; + bool in_omp_attribute_pragma = parser->lexer->in_omp_attribute_pragma; if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) { tree id = cp_lexer_peek_token (parser->lexer)->u.value; @@ -44753,12 +44756,26 @@ cp_parser_omp_end_declare_target (cp_parser *parser, cp_token *pragma_tok) return; } cp_parser_require_pragma_eol (parser, pragma_tok); - if (!scope_chain->omp_declare_target_attribute) + if (!vec_safe_length (scope_chain->omp_declare_target_attribute)) error_at (pragma_tok->location, "%<#pragma omp end declare target%> without corresponding " "%<#pragma omp declare target%>"); else - scope_chain->omp_declare_target_attribute--; + { + omp_declare_target_attr + a = scope_chain->omp_declare_target_attribute->pop (); + if (a.attr_syntax != in_omp_attribute_pragma) + { + if (a.attr_syntax) + error_at (pragma_tok->location, + "% in attribute syntax terminated " + "with % in pragma syntax"); + else + error_at (pragma_tok->location, + "% in pragma syntax terminated " + "with % in attribute syntax"); + } + } } /* Helper function of cp_parser_omp_declare_reduction. Parse the combiner diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 34e5d76..2e23818 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -3271,12 +3271,12 @@ finish_translation_unit (void) /* Do file scope __FUNCTION__ et al. */ finish_fname_decls (); - if (scope_chain->omp_declare_target_attribute) + if (vec_safe_length (scope_chain->omp_declare_target_attribute)) { if (!errorcount) error ("%<#pragma omp declare target%> without corresponding " "%<#pragma omp end declare target%>"); - scope_chain->omp_declare_target_attribute = 0; + vec_safe_truncate (scope_chain->omp_declare_target_attribute, 0); } } diff --git a/gcc/testsuite/g++.dg/gomp/attrs-12.C b/gcc/testsuite/g++.dg/gomp/attrs-12.C new file mode 100644 index 0000000..b613872 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/attrs-12.C @@ -0,0 +1,41 @@ +// { dg-do compile { target c++11 } } + +#pragma omp declare target +#pragma omp declare target +[[omp::directive (declare target)]]; +int a; +[[omp::directive (end declare target)]]; +#pragma omp end declare target +#pragma omp end declare target +[[omp::directive (declare target)]]; +int b; +#pragma omp end declare target // { dg-error "'declare target' in attribute syntax terminated with 'end declare target' in pragma syntax" } +#pragma omp declare target +int c; +[[omp::directive (end declare target)]];// { dg-error "'declare target' in pragma syntax terminated with 'end declare target' in attribute syntax" } +#pragma omp declare target +[[omp::directive (declare target)]]; +int d; +#pragma omp end declare target // { dg-error "'declare target' in attribute syntax terminated with 'end declare target' in pragma syntax" } +#pragma omp declare target +int e; +[[omp::directive (end declare target)]];// { dg-error "'declare target' in pragma syntax terminated with 'end declare target' in attribute syntax" } +#pragma omp end declare target +[[omp::directive (declare target)]]; +[[omp::directive (declare target)]]; +int f; +#pragma omp end declare target // { dg-error "'declare target' in attribute syntax terminated with 'end declare target' in pragma syntax" } +#pragma omp declare target +int g; +[[omp::directive (end declare target)]];// { dg-error "'declare target' in pragma syntax terminated with 'end declare target' in attribute syntax" } +[[omp::directive (end declare target)]]; +[[omp::directive (declare target)]]; +#pragma omp declare target +int h; +#pragma omp end declare target +#pragma omp end declare target // { dg-error "'declare target' in attribute syntax terminated with 'end declare target' in pragma syntax" } +#pragma omp declare target +[[omp::directive (declare target)]]; +int i; +[[omp::directive (end declare target)]]; +[[omp::directive (end declare target)]];// { dg-error "'declare target' in pragma syntax terminated with 'end declare target' in attribute syntax" } -- cgit v1.1 From 04b4f3152593f85b05974528d1607619dd77d702 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Thu, 12 Aug 2021 11:26:57 +0200 Subject: i386: Fix up V32HImode permutations with -mno-avx512bw [PR101860] My patch from yesterday apparently broke some V32HImode permutations as the testcase shows. The first function assumed it would never be called in d->testing_p mode and so went right away into emitting the code. And the second one assumed V32HImode would never reach it, which now can for the !TARGET_AVX512BW case. We don't have a instruction in that case though. 2021-08-12 Jakub Jelinek PR target/101860 * config/i386/i386-expand.c (ix86_expand_vec_one_operand_perm_avx512): If d->testing_p, return true after performing checks instead of actually expanding the insn. (expand_vec_perm_broadcast_1): Handle V32HImode - assert !TARGET_AVX512BW and return false. * gcc.target/i386/avx512f-pr101860.c: New test. --- gcc/config/i386/i386-expand.c | 7 +++++++ gcc/testsuite/gcc.target/i386/avx512f-pr101860.c | 5 +++++ 2 files changed, 12 insertions(+) create mode 100644 gcc/testsuite/gcc.target/i386/avx512f-pr101860.c (limited to 'gcc') diff --git a/gcc/config/i386/i386-expand.c b/gcc/config/i386/i386-expand.c index c708b33..a652b25 100644 --- a/gcc/config/i386/i386-expand.c +++ b/gcc/config/i386/i386-expand.c @@ -18116,6 +18116,9 @@ ix86_expand_vec_one_operand_perm_avx512 (struct expand_vec_perm_d *d) return false; } + if (d->testing_p) + return true; + target = d->target; op0 = d->op0; for (int i = 0; i < d->nelt; ++i) @@ -20481,6 +20484,10 @@ expand_vec_perm_broadcast_1 (struct expand_vec_perm_d *d) gcc_assert (!TARGET_AVX2 || d->perm[0]); return false; + case E_V32HImode: + gcc_assert (!TARGET_AVX512BW); + return false; + default: gcc_unreachable (); } diff --git a/gcc/testsuite/gcc.target/i386/avx512f-pr101860.c b/gcc/testsuite/gcc.target/i386/avx512f-pr101860.c new file mode 100644 index 0000000..1aadfa2 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/avx512f-pr101860.c @@ -0,0 +1,5 @@ +/* PR target/101860 */ +/* { dg-do compile } */ +/* { dg-options "-O2 -mavx512f -mno-avx512bw" } */ + +#include "../../gcc.dg/torture/vshuf-v32hi.c" -- cgit v1.1 From fb0cd8f11167600f11034031ce190151a54a5a95 Mon Sep 17 00:00:00 2001 From: Hans-Peter Nilsson Date: Wed, 11 Aug 2021 23:33:40 +0200 Subject: gfortran.dg/PR82376.f90: Avoid matching a file-path I had a file-path to sources with the substring "new" in it, and (only) this test regressed compared to results from another build without "new" in the name. The test does ! { dg-final { scan-tree-dump-times "new" 4 "original" } } i.e. the contents of the tree-dump-file .original needs to match the undelimited string "new" exactly four times. Very brittle. In the dump-file, there are three lines with calls to new: D.908 = new ((integer(kind=4) *) data); integer(kind=4) * new (integer(kind=4) & data) static integer(kind=4) * new (integer(kind=4) &); But, there's also a line, which for me and cris-elf looked like: _gfortran_runtime_error_at (&"At line 46 of file /X/xyzzynewfrob/gcc/testsuite/gfortran.dg/PR82376.f90"[1]{lb: 1 sz: 1}, &"Pointer actual argument \'new\' is not associated"[1]{lb: 1 sz: 1}); The fourth match is obviously intended to match this line, but only with *one* match, whereas the path can as above yield another hit. With Tcl, the regexp for matching the " " *and* the "'" *and* the "\" gets a bit unsightly, so I suggest just matching the "new" calls, which according to the comment in the test is the key point. You can't have a file-path with spaces and parentheses in a gcc build. I'm also making use of {} rather than "" needing one level of quoting; the "\(" is needed because the matched string is a regexp. testsuite: * gfortran.dg/PR82376.f90: Robustify match. --- gcc/testsuite/gfortran.dg/PR82376.f90 | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'gcc') diff --git a/gcc/testsuite/gfortran.dg/PR82376.f90 b/gcc/testsuite/gfortran.dg/PR82376.f90 index 07143ab..b99779c 100644 --- a/gcc/testsuite/gfortran.dg/PR82376.f90 +++ b/gcc/testsuite/gfortran.dg/PR82376.f90 @@ -2,7 +2,8 @@ ! { dg-options "-fdump-tree-original -fcheck=pointer" } ! ! Test the fix for PR82376. The pointer check was doubling up the call -! to new. The fix reduces the count of 'new' from 5 to 4. +! to new. The fix reduces the count of 'new' from 5 to 4, or to 3, when +! counting only calls. ! ! Contributed by José Rui Faustino de Sousa ! @@ -56,4 +57,4 @@ contains end subroutine set end program main_p -! { dg-final { scan-tree-dump-times "new" 4 "original" } } +! { dg-final { scan-tree-dump-times { new \(} 3 "original" } } -- cgit v1.1 From 2d7967a10c2f3b4652f77a1a2119ba03b3472266 Mon Sep 17 00:00:00 2001 From: Claudiu Zissulescu Date: Thu, 12 Aug 2021 14:21:22 +0300 Subject: arc: Small data doesn't need fcommon option ARC backend is defaulting to -fcommon. This is not anylonger needed, remove it. gcc/ 2021-08-12 Claudiu Zissulescu * common/config/arc/arc-common.c (arc_option_init_struct): Remove fno-common reference. * config/arc/arc.c (arc_override_options): Remove overriding of flag_no_common. Signed-off-by: Claudiu Zissulescu --- gcc/common/config/arc/arc-common.c | 4 +--- gcc/config/arc/arc.c | 3 --- 2 files changed, 1 insertion(+), 6 deletions(-) (limited to 'gcc') diff --git a/gcc/common/config/arc/arc-common.c b/gcc/common/config/arc/arc-common.c index 6a11902..3b36d09 100644 --- a/gcc/common/config/arc/arc-common.c +++ b/gcc/common/config/arc/arc-common.c @@ -30,10 +30,8 @@ along with GCC; see the file COPYING3. If not see #include "flags.h" static void -arc_option_init_struct (struct gcc_options *opts) +arc_option_init_struct (struct gcc_options *opts ATTRIBUTE_UNUSED) { - opts->x_flag_no_common = 255; /* Mark as not user-initialized. */ - /* Which cpu we're compiling for (ARC600, ARC601, ARC700, ARCv2). */ arc_cpu = PROCESSOR_NONE; } diff --git a/gcc/config/arc/arc.c b/gcc/config/arc/arc.c index 69f6ae4..92797db 100644 --- a/gcc/config/arc/arc.c +++ b/gcc/config/arc/arc.c @@ -1440,9 +1440,6 @@ arc_override_options (void) if (flag_pic) target_flags |= MASK_NO_SDATA_SET; - if (flag_no_common == 255) - flag_no_common = !TARGET_NO_SDATA_SET; - /* Check for small data option */ if (!global_options_set.x_g_switch_value && !TARGET_NO_SDATA_SET) g_switch_value = TARGET_LL64 ? 8 : 4; -- cgit v1.1 From 432de08498142d2266c0fb05f2c555a7f1e10ddd Mon Sep 17 00:00:00 2001 From: Tobias Burnus Date: Thu, 12 Aug 2021 15:48:28 +0200 Subject: OpenMP 5.1: Add proc-bind 'primary' support In OpenMP 5.1 "master thread" was changed to "primary thread" and the proc_bind clause and the OMP_PROC_BIND environment variable now take 'primary' as argument as alias for 'master', while the latter is deprecated. This commit accepts 'primary' and adds the named constant omp_proc_bind_primary and changes 'master thread' in the documentation; however, given that not even OpenMP 5.0 is fully supported, omp_display_env and the dumps currently still output 'master' and there is no deprecation warning when using the 'master' in the proc_bind clause. gcc/c/ChangeLog: * c-parser.c (c_parser_omp_clause_proc_bind): Accept 'primary' as alias for 'master'. gcc/cp/ChangeLog: * parser.c (cp_parser_omp_clause_proc_bind): Accept 'primary' as alias for 'master'. gcc/fortran/ChangeLog: * gfortran.h (gfc_omp_proc_bind_kind): Add OMP_PROC_BIND_PRIMARY. * dump-parse-tree.c (show_omp_clauses): Add TODO comment to change 'master' to 'primary' in proc_bind for OpenMP 5.1. * intrinsic.texi (OMP_LIB): Mention OpenMP 5.1; add omp_proc_bind_primary. * openmp.c (gfc_match_omp_clauses): Accept 'primary' as alias for 'master'. * trans-openmp.c (gfc_trans_omp_clauses): Handle OMP_PROC_BIND_PRIMARY. gcc/ChangeLog: * tree-core.h (omp_clause_proc_bind_kind): Add OMP_CLAUSE_PROC_BIND_PRIMARY. * tree-pretty-print.c (dump_omp_clause): Add TODO comment to change 'master' to 'primary' in proc_bind for OpenMP 5.1. libgomp/ChangeLog: * env.c (parse_bind_var): Accept 'primary' as alias for 'master'. (omp_display_env): Add TODO comment to change 'master' to 'primary' in proc_bind for OpenMP 5.1. * libgomp.texi: Change 'master thread' to 'primary thread' in line with OpenMP 5.1. (omp_get_proc_bind): Add omp_proc_bind_primary and note that omp_proc_bind_master is an alias of it. (OMP_PROC_BIND): Mention 'PRIMARY'. * omp.h.in (__GOMP_DEPRECATED_5_1): Define. (omp_proc_bind_primary): Add. (omp_proc_bind_master): Deprecate for OpenMP 5.1. * omp_lib.f90.in (omp_proc_bind_primary): Add. (omp_proc_bind_master): Deprecate for OpenMP 5.1. * omp_lib.h.in (omp_proc_bind_primary): Add. * testsuite/libgomp.c/affinity-1.c: Check that 'primary' works and is identical to 'master'. gcc/testsuite/ChangeLog: * c-c++-common/gomp/pr61486-2.c: Duplicate one proc_bind(master) testcase and test proc_bind(primary) instead. * gfortran.dg/gomp/affinity-1.f90: Likewise. --- gcc/c/c-parser.c | 7 +++++-- gcc/cp/parser.c | 7 +++++-- gcc/fortran/dump-parse-tree.c | 1 + gcc/fortran/gfortran.h | 1 + gcc/fortran/intrinsic.texi | 6 ++++-- gcc/fortran/openmp.c | 5 ++++- gcc/fortran/trans-openmp.c | 3 +++ gcc/testsuite/c-c++-common/gomp/pr61486-2.c | 13 +++++++++++++ gcc/testsuite/gfortran.dg/gomp/affinity-1.f90 | 9 +++++++++ gcc/tree-core.h | 1 + gcc/tree-pretty-print.c | 2 ++ 11 files changed, 48 insertions(+), 7 deletions(-) (limited to 'gcc') diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index d24bfdb..195c137 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -15959,7 +15959,8 @@ c_parser_omp_clause_dist_schedule (c_parser *parser, tree list) proc_bind ( proc-bind-kind ) proc-bind-kind: - master | close | spread */ + primary | master | close | spread + where OpenMP 5.1 added 'primary' and deprecated the alias 'master'. */ static tree c_parser_omp_clause_proc_bind (c_parser *parser, tree list) @@ -15975,7 +15976,9 @@ c_parser_omp_clause_proc_bind (c_parser *parser, tree list) if (c_parser_next_token_is (parser, CPP_NAME)) { const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); - if (strcmp ("master", p) == 0) + if (strcmp ("primary", p) == 0) + kind = OMP_CLAUSE_PROC_BIND_PRIMARY; + else if (strcmp ("master", p) == 0) kind = OMP_CLAUSE_PROC_BIND_MASTER; else if (strcmp ("close", p) == 0) kind = OMP_CLAUSE_PROC_BIND_CLOSE; diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 74de529..b7fe4b4 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -39020,7 +39020,8 @@ cp_parser_omp_clause_dist_schedule (cp_parser *parser, tree list, proc_bind ( proc-bind-kind ) proc-bind-kind: - master | close | spread */ + primary | master | close | spread + where OpenMP 5.1 added 'primary' and deprecated the alias 'master'. */ static tree cp_parser_omp_clause_proc_bind (cp_parser *parser, tree list, @@ -39037,7 +39038,9 @@ cp_parser_omp_clause_proc_bind (cp_parser *parser, tree list, tree id = cp_lexer_peek_token (parser->lexer)->u.value; const char *p = IDENTIFIER_POINTER (id); - if (strcmp ("master", p) == 0) + if (strcmp ("primary", p) == 0) + kind = OMP_CLAUSE_PROC_BIND_PRIMARY; + else if (strcmp ("master", p) == 0) kind = OMP_CLAUSE_PROC_BIND_MASTER; else if (strcmp ("close", p) == 0) kind = OMP_CLAUSE_PROC_BIND_CLOSE; diff --git a/gcc/fortran/dump-parse-tree.c b/gcc/fortran/dump-parse-tree.c index 8e4a101..360abf1 100644 --- a/gcc/fortran/dump-parse-tree.c +++ b/gcc/fortran/dump-parse-tree.c @@ -1712,6 +1712,7 @@ show_omp_clauses (gfc_omp_clauses *omp_clauses) const char *type; switch (omp_clauses->proc_bind) { + case OMP_PROC_BIND_PRIMARY: type = "PRIMARY"; break; case OMP_PROC_BIND_MASTER: type = "MASTER"; break; case OMP_PROC_BIND_SPREAD: type = "SPREAD"; break; case OMP_PROC_BIND_CLOSE: type = "CLOSE"; break; diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h index 921aed9..8f75dd9 100644 --- a/gcc/fortran/gfortran.h +++ b/gcc/fortran/gfortran.h @@ -1362,6 +1362,7 @@ enum gfc_omp_default_sharing enum gfc_omp_proc_bind_kind { OMP_PROC_BIND_UNKNOWN, + OMP_PROC_BIND_PRIMARY, OMP_PROC_BIND_MASTER, OMP_PROC_BIND_SPREAD, OMP_PROC_BIND_CLOSE diff --git a/gcc/fortran/intrinsic.texi b/gcc/fortran/intrinsic.texi index 8a92b86..1aacd33 100644 --- a/gcc/fortran/intrinsic.texi +++ b/gcc/fortran/intrinsic.texi @@ -15293,8 +15293,9 @@ with the following options: @code{-fno-unsafe-math-optimizations @section OpenMP Modules @code{OMP_LIB} and @code{OMP_LIB_KINDS} @table @asis @item @emph{Standard}: -OpenMP Application Program Interface v4.5 and -OpenMP Application Program Interface v5.0 (partially supported). +OpenMP Application Program Interface v4.5, +OpenMP Application Program Interface v5.0 (partially supported) and +OpenMP Application Program Interface v5.1 (partially supported). @end table The OpenMP Fortran runtime library routines are provided both in @@ -15357,6 +15358,7 @@ kind @code{omp_proc_bind_kind}: @table @asis @item @code{omp_proc_bind_false} @item @code{omp_proc_bind_true} +@item @code{omp_proc_bind_primary} @item @code{omp_proc_bind_master} @item @code{omp_proc_bind_close} @item @code{omp_proc_bind_spread} diff --git a/gcc/fortran/openmp.c b/gcc/fortran/openmp.c index 520a435..ec55865 100644 --- a/gcc/fortran/openmp.c +++ b/gcc/fortran/openmp.c @@ -2231,7 +2231,10 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask, if ((mask & OMP_CLAUSE_PROC_BIND) && c->proc_bind == OMP_PROC_BIND_UNKNOWN) { - if (gfc_match ("proc_bind ( master )") == MATCH_YES) + /* Primary is new and master is deprecated in OpenMP 5.1. */ + if (gfc_match ("proc_bind ( primary )") == MATCH_YES) + c->proc_bind = OMP_PROC_BIND_MASTER; + else if (gfc_match ("proc_bind ( master )") == MATCH_YES) c->proc_bind = OMP_PROC_BIND_MASTER; else if (gfc_match ("proc_bind ( spread )") == MATCH_YES) c->proc_bind = OMP_PROC_BIND_SPREAD; diff --git a/gcc/fortran/trans-openmp.c b/gcc/fortran/trans-openmp.c index ac3f5f3..3d3b35e 100644 --- a/gcc/fortran/trans-openmp.c +++ b/gcc/fortran/trans-openmp.c @@ -3865,6 +3865,9 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses, c = build_omp_clause (gfc_get_location (&where), OMP_CLAUSE_PROC_BIND); switch (clauses->proc_bind) { + case OMP_PROC_BIND_PRIMARY: + OMP_CLAUSE_PROC_BIND_KIND (c) = OMP_CLAUSE_PROC_BIND_PRIMARY; + break; case OMP_PROC_BIND_MASTER: OMP_CLAUSE_PROC_BIND_KIND (c) = OMP_CLAUSE_PROC_BIND_MASTER; break; diff --git a/gcc/testsuite/c-c++-common/gomp/pr61486-2.c b/gcc/testsuite/c-c++-common/gomp/pr61486-2.c index 4a68023..c86fd91 100644 --- a/gcc/testsuite/c-c++-common/gomp/pr61486-2.c +++ b/gcc/testsuite/c-c++-common/gomp/pr61486-2.c @@ -216,6 +216,19 @@ test (int n, int o, int p, int q, int r, int s, int *pp) s = i * 10; } #pragma omp target device (n + 1) if (n != 6)map(from:n) map(alloc:a[2:o-2]) + #pragma omp teams distribute parallel for simd if (n != 6)default(shared) \ + private (p) firstprivate (q) shared (n) reduction (+: r) \ + thread_limit (n * 2) dist_schedule (static, 4) num_threads (n + 4) \ + proc_bind (primary) lastprivate (s) schedule (static, 8) \ + num_teams (n + 4) safelen(16) linear(i:1) aligned (pp:4) + for (i = 0; i < 10; i++) + { + r = r + 1; + p = q; + a[2+i] = p + q; + s = i * 10; + } + #pragma omp target device (n + 1) if (n != 6)map(from:n) map(alloc:a[2:o-2]) #pragma omp teams distribute simd default(shared) \ private (p) firstprivate (q) shared (n) reduction (+: r) \ thread_limit (n * 2) dist_schedule (static, 4) collapse (2) \ diff --git a/gcc/testsuite/gfortran.dg/gomp/affinity-1.f90 b/gcc/testsuite/gfortran.dg/gomp/affinity-1.f90 index b6e20b9..cb1543b 100644 --- a/gcc/testsuite/gfortran.dg/gomp/affinity-1.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/affinity-1.f90 @@ -9,6 +9,15 @@ j = 8 end do !$omp end parallel do +!$omp parallel do default(none)proc_bind(primary)shared(a) + do i = 1, 10 + j = 4 + do j = 1, 10 + a(i, j) = i + j + end do + j = 8 + end do +!$omp end parallel do !$omp parallel proc_bind (close) !$omp parallel default(none) proc_bind (spread) firstprivate(a) private (i) do i = 1, 10 diff --git a/gcc/tree-core.h b/gcc/tree-core.h index bfab988..9a1aa9a 100644 --- a/gcc/tree-core.h +++ b/gcc/tree-core.h @@ -1498,6 +1498,7 @@ enum omp_clause_proc_bind_kind /* Numbers should match omp_proc_bind_t enum in omp.h. */ OMP_CLAUSE_PROC_BIND_FALSE = 0, OMP_CLAUSE_PROC_BIND_TRUE = 1, + OMP_CLAUSE_PROC_BIND_PRIMARY = 2, OMP_CLAUSE_PROC_BIND_MASTER = 2, OMP_CLAUSE_PROC_BIND_CLOSE = 3, OMP_CLAUSE_PROC_BIND_SPREAD = 4, diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c index 7201bd7..31f886f 100644 --- a/gcc/tree-pretty-print.c +++ b/gcc/tree-pretty-print.c @@ -1008,6 +1008,8 @@ dump_omp_clause (pretty_printer *pp, tree clause, int spc, dump_flags_t flags) switch (OMP_CLAUSE_PROC_BIND_KIND (clause)) { case OMP_CLAUSE_PROC_BIND_MASTER: + /* Same enum value: case OMP_CLAUSE_PROC_BIND_PRIMARY: */ + /* TODO: Change to 'primary' for OpenMP 5.1. */ pp_string (pp, "master"); break; case OMP_CLAUSE_PROC_BIND_CLOSE: -- cgit v1.1 From 34cd97ff94bdb43e8c9de150f1d89527fc42138e Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Thu, 5 Aug 2021 08:01:47 +0200 Subject: Remove legacy back threader. At this point I don't see any use for the legacy mode, which I had originally left in place during the transition. This patch removes the legacy back threader, and cleans up the code a bit. There are no functional changes to the non-legacy code. Tested on x86-64 Linux. gcc/ChangeLog: * doc/invoke.texi: Remove docs for threader-mode param. * flag-types.h (enum threader_mode): Remove. * params.opt: Remove threader-mode param. * tree-ssa-threadbackward.c (class back_threader): Remove path_is_unreachable_p. Make find_paths private. Add maybe_thread and thread_through_all_blocks. Remove reference marker for m_registry. Remove reference marker for m_profit. (back_threader::back_threader): Adjust for registry and profit not being references. (dump_path): Move down. (debug): Move down. (class thread_jumps): Remove. (class back_threader_registry): Remove m_all_paths. Remove destructor. (thread_jumps::thread_through_all_blocks): Move to back_threader class. (fsm_find_thread_path): Remove (back_threader::maybe_thread): New. (back_threader::thread_through_all_blocks): Move from thread_jumps. (back_threader_registry::back_threader_registry): Remove m_all_paths. (back_threader_registry::~back_threader_registry): Remove. (thread_jumps::find_taken_edge): Remove. (thread_jumps::check_subpath_and_update_thread_path): Remove. (thread_jumps::maybe_register_path): Remove. (thread_jumps::handle_phi): Remove. (handle_assignment_p): Remove. (thread_jumps::handle_assignment): Remove. (thread_jumps::fsm_find_control_statement_thread_paths): Remove. (thread_jumps::find_jump_threads_backwards): Remove. (thread_jumps::find_jump_threads_backwards_with_ranger): Remove. (try_thread_blocks): Rename find_jump_threads_backwards to maybe_thread. (pass_early_thread_jumps::execute): Same. gcc/testsuite/ChangeLog: * gcc.dg/tree-ssa/ssa-dom-thread-7.c: Remove call into the legacy code and adjust for ranger threader. --- gcc/doc/invoke.texi | 3 - gcc/flag-types.h | 7 - gcc/params.opt | 13 - gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-7.c | 3 +- gcc/tree-ssa-threadbackward.c | 543 +++-------------------- 5 files changed, 61 insertions(+), 508 deletions(-) (limited to 'gcc') diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index a64cec5..57b97a0 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -13421,9 +13421,6 @@ Setting to 0 disables the analysis completely. @item modref-max-escape-points Specifies the maximum number of escape points tracked by modref per SSA-name. -@item threader-mode -Specifies the mode the backwards threader should run in. - @item profile-func-internal-id A parameter to control whether to use function internal id in profile database lookup. If the value is 0, the compiler uses an id that diff --git a/gcc/flag-types.h b/gcc/flag-types.h index e39673f..e43d1de 100644 --- a/gcc/flag-types.h +++ b/gcc/flag-types.h @@ -454,13 +454,6 @@ enum evrp_mode EVRP_MODE_RVRP_DEBUG = EVRP_MODE_RVRP_ONLY | EVRP_MODE_DEBUG }; -/* Backwards threader mode. */ -enum threader_mode -{ - THREADER_MODE_LEGACY = 0, - THREADER_MODE_RANGER = 1 -}; - /* Modes of OpenACC 'kernels' constructs handling. */ enum openacc_kernels { diff --git a/gcc/params.opt b/gcc/params.opt index aa2fb40..92b003e 100644 --- a/gcc/params.opt +++ b/gcc/params.opt @@ -1010,19 +1010,6 @@ Maximum depth of DFS walk used by modref escape analysis. Common Joined UInteger Var(param_modref_max_escape_points) Init(256) Param Optimization Maximum number of escape points tracked by modref per SSA-name. --param=threader-mode= -Common Joined Var(param_threader_mode) Enum(threader_mode) Init(THREADER_MODE_RANGER) Param Optimization ---param=threader-mode=[legacy|ranger] Specifies the mode the backwards threader should run in. - -Enum -Name(threader_mode) Type(enum threader_mode) UnknownError(unknown threader mode %qs) - -EnumValue -Enum(threader_mode) String(legacy) Value(THREADER_MODE_LEGACY) - -EnumValue -Enum(threader_mode) String(ranger) Value(THREADER_MODE_RANGER) - -param=tm-max-aggregate-size= Common Joined UInteger Var(param_tm_max_aggregate_size) Init(9) Param Optimization Size in bytes after which thread-local aggregates should be instrumented with the logging functions instead of save/restore pairs. diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-7.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-7.c index 1c2d12a..5fc2145 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-7.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-7.c @@ -1,6 +1,5 @@ /* { dg-do compile } */ /* { dg-options "-O2 -fdump-tree-thread1-stats -fdump-tree-thread2-stats -fdump-tree-dom2-stats -fdump-tree-thread3-stats -fdump-tree-dom3-stats -fdump-tree-vrp2-stats -fno-guess-branch-probability" } */ -/* { dg-additional-options "--param=threader-mode=legacy" } */ /* Here we have the same issue as was commented in ssa-dom-thread-6.c. The PHI coming into the threader has a lot more constants, so the @@ -17,7 +16,7 @@ $ diff clean/a.c.105t.mergephi2 a.c.105t.mergephi2 basically tracking the switch index better through multiple paths. */ -/* { dg-final { scan-tree-dump "Jumps threaded: 19" "thread1" } } */ +/* { dg-final { scan-tree-dump "Jumps threaded: 18" "thread1" } } */ /* { dg-final { scan-tree-dump "Jumps threaded: 8" "thread2" } } */ /* { dg-final { scan-tree-dump-not "Jumps threaded" "dom2" } } */ diff --git a/gcc/tree-ssa-threadbackward.c b/gcc/tree-ssa-threadbackward.c index e237eb4..3aad1493 100644 --- a/gcc/tree-ssa-threadbackward.c +++ b/gcc/tree-ssa-threadbackward.c @@ -51,12 +51,9 @@ class back_threader_registry { public: back_threader_registry (int max_allowable_paths); - ~back_threader_registry (); bool register_path (const vec &, edge taken); bool thread_through_all_blocks (); - private: - vec> m_all_paths; jump_thread_path_registry m_lowlevel_registry; const int m_max_allowable_paths; int m_threaded_paths; @@ -72,24 +69,19 @@ public: { } bool profitable_path_p (const vec &, tree name, edge taken, bool *irreducible_loop = NULL); - private: const bool m_speed_p; }; -// Ranger based backwards threader. - class back_threader { - // Temporary until we remove old code. - friend bool path_is_unreachable_p (const vec &); - public: - back_threader (back_threader_profitability &, back_threader_registry &); + back_threader (bool speed_p); ~back_threader (); - void find_paths (basic_block bb, tree name); - + void maybe_thread_block (basic_block bb); + bool thread_through_all_blocks (); private: + void find_paths (basic_block bb, tree name); void maybe_register_path (edge taken_edge); bool find_paths_to_names (basic_block bb, bitmap imports); bool resolve_def (tree name, bitmap interesting, vec &worklist); @@ -98,8 +90,8 @@ private: edge find_taken_edge_cond (const vec &path, gcond *); edge find_taken_edge_switch (const vec &path, gswitch *); - back_threader_registry &m_registry; - back_threader_profitability &m_profit; + back_threader_registry m_registry; + back_threader_profitability m_profit; gimple_ranger m_ranger; path_range_query m_solver; @@ -123,10 +115,9 @@ private: // in a the given direction. const edge back_threader::UNREACHABLE_EDGE = (edge) -1; -back_threader::back_threader (back_threader_profitability &profit, - back_threader_registry ®istry) - : m_registry (registry), - m_profit (profit), +back_threader::back_threader (bool speed_p) + : m_registry (param_max_fsm_thread_paths), + m_profit (speed_p), m_solver (m_ranger) { m_last_stmt = NULL; @@ -456,74 +447,9 @@ back_threader::find_paths (basic_block bb, tree name) } } -// Dump a sequence of BBs through the CFG. - -DEBUG_FUNCTION void -dump_path (FILE *dump_file, const vec &path) -{ - for (size_t i = 0; i < path.length (); ++i) - { - fprintf (dump_file, "BB%d", path[i]->index); - if (i + 1 < path.length ()) - fprintf (dump_file, " <- "); - } - fprintf (dump_file, "\n"); -} - -DEBUG_FUNCTION void -debug (const vec &path) -{ - dump_path (stderr, path); -} - -class thread_jumps -{ -public: - thread_jumps (bool speed_p = true) - : m_profit (speed_p), - m_registry (param_max_fsm_thread_paths), - m_back_threader (m_profit, m_registry) - { } - void find_jump_threads_backwards (basic_block bb); - void find_jump_threads_backwards_with_ranger (basic_block bb); - bool thread_through_all_blocks (); - -private: - void maybe_register_path (const vec &m_path, - tree name, - edge taken_edge); - edge find_taken_edge (const vec &path, tree arg); - void handle_assignment (gimple *stmt, basic_block def_bb); - void handle_phi (gphi *phi, basic_block def_bb); - void fsm_find_control_statement_thread_paths (tree name); - bool check_subpath_and_update_thread_path (basic_block last_bb, - basic_block new_bb, - int *next_path_length); - - /* Hash to keep track of seen bbs. */ - hash_set m_visited_bbs; - /* Current path we're analyzing. */ - auto_vec m_path; - /* Tracks if we have recursed through a loop PHI node. */ - bool m_seen_loop_phi; - - tree m_name; - back_threader_profitability m_profit; - back_threader_registry m_registry; - back_threader m_back_threader; -}; - -// Perform the actual jump threading for the all queued paths. - -bool -thread_jumps::thread_through_all_blocks () -{ - return m_registry.thread_through_all_blocks (); -} - -/* Simple helper to get the last statement from BB, which is assumed - to be a control statement. Return NULL if the last statement is - not a control statement. */ +// Simple helper to get the last statement from BB, which is assumed +// to be a control statement. Return NULL if the last statement is +// not a control statement. static gimple * get_gimple_control_stmt (basic_block bb) @@ -540,55 +466,65 @@ get_gimple_control_stmt (basic_block bb) return NULL; } -/* Return true if the CFG contains at least one path from START_BB to - END_BB. When a path is found, record in PATH the blocks from - END_BB to START_BB. LOCAL_VISITED_BBS is used to make sure we - don't fall into an infinite loop. Bound the recursion to basic - blocks belonging to LOOP. */ +// Search backwards from BB looking for paths where the final +// conditional maybe threaded to a successor block. Record such paths +// for jump threading. -static bool -fsm_find_thread_path (basic_block start_bb, basic_block end_bb, - vec &path, - hash_set &local_visited_bbs, - loop_p loop) +void +back_threader::maybe_thread_block (basic_block bb) { - if (loop != start_bb->loop_father) - return false; + gimple *stmt = get_gimple_control_stmt (bb); + if (!stmt) + return; - if (start_bb == end_bb) - { - path.safe_push (start_bb); - return true; - } + enum gimple_code code = gimple_code (stmt); + tree name; + if (code == GIMPLE_SWITCH) + name = gimple_switch_index (as_a (stmt)); + else if (code == GIMPLE_COND) + name = gimple_cond_lhs (stmt); + else if (code == GIMPLE_GOTO) + name = gimple_goto_dest (stmt); + else + name = NULL; + + find_paths (bb, name); +} + +// Perform the actual jump threading for the all queued paths. + +bool +back_threader::thread_through_all_blocks () +{ + return m_registry.thread_through_all_blocks (); +} + +// Dump a sequence of BBs through the CFG. - if (!local_visited_bbs.add (start_bb)) +DEBUG_FUNCTION void +dump_path (FILE *dump_file, const vec &path) +{ + for (size_t i = 0; i < path.length (); ++i) { - edge e; - edge_iterator ei; - FOR_EACH_EDGE (e, ei, start_bb->succs) - if (fsm_find_thread_path (e->dest, end_bb, path, local_visited_bbs, - loop)) - { - path.safe_push (start_bb); - return true; - } + fprintf (dump_file, "BB%d", path[i]->index); + if (i + 1 < path.length ()) + fprintf (dump_file, " <- "); } + fprintf (dump_file, "\n"); +} - return false; +DEBUG_FUNCTION void +debug (const vec &path) +{ + dump_path (stderr, path); } back_threader_registry::back_threader_registry (int max_allowable_paths) : m_max_allowable_paths (max_allowable_paths) { - m_all_paths.create (5); m_threaded_paths = 0; } -back_threader_registry::~back_threader_registry () -{ - m_all_paths.release (); -} - bool back_threader_registry::thread_through_all_blocks () { @@ -881,39 +817,6 @@ back_threader_profitability::profitable_path_p (const vec &m_path, return true; } -/* Return the taken edge out of a path, assuming that the underlying assignment - or PHI SSA resolves to ARG. */ - -edge -thread_jumps::find_taken_edge (const vec &path, tree arg) -{ - if (TREE_CODE_CLASS (TREE_CODE (arg)) != tcc_constant) - return NULL; - - gcc_checking_assert (!path.is_empty ()); - gimple *stmt = get_gimple_control_stmt (m_path[0]); - - /* We have found a constant value for ARG. For GIMPLE_SWITCH - and GIMPLE_GOTO, we use it as-is. However, for a GIMPLE_COND - we need to substitute, fold and simplify so we can determine - the edge taken out of the last block. */ - if (gimple_code (stmt) == GIMPLE_COND) - { - enum tree_code cond_code = gimple_cond_code (stmt); - - /* We know the underyling format of the condition. */ - arg = fold_binary (cond_code, boolean_type_node, - arg, gimple_cond_rhs (stmt)); - } - - /* If this path threaded through the loop latch back into the - same loop and the destination does not dominate the loop - latch, then this thread would create an irreducible loop. - - We have to know the outgoing edge to figure this out. */ - return ::find_taken_edge (m_path[0], arg); -} - /* The current path PATH is a vector of blocks forming a jump threading path in reverse order. TAKEN_EDGE is the edge taken from path[0]. @@ -962,331 +865,6 @@ back_threader_registry::register_path (const vec &m_path, return true; } -/* While following a chain of SSA_NAME definitions, we jumped from a - definition in LAST_BB to a definition in NEW_BB (walking - backwards). - - Verify there is a single path between the blocks and none of the - blocks in the path is already in VISITED_BBS. If so, then update - VISISTED_BBS, add the new blocks to PATH and return TRUE. - Otherwise return FALSE. - - Store the length of the subpath in NEXT_PATH_LENGTH. */ - -bool -thread_jumps::check_subpath_and_update_thread_path (basic_block last_bb, - basic_block new_bb, - int *next_path_length) -{ - edge e; - int e_count = 0; - edge_iterator ei; - auto_vec next_path; - - FOR_EACH_EDGE (e, ei, last_bb->preds) - { - hash_set local_visited_bbs; - - if (fsm_find_thread_path (new_bb, e->src, next_path, - local_visited_bbs, e->src->loop_father)) - ++e_count; - - /* If there is more than one path, stop. */ - if (e_count > 1) - return false; - } - - /* Stop if we have not found a path: this could occur when the recursion - is stopped by one of the bounds. */ - if (e_count == 0) - return false; - - /* Make sure we haven't already visited any of the nodes in - NEXT_PATH. Don't add them here to avoid pollution. */ - for (unsigned int i = 0; i + 1 < next_path.length (); i++) - { - if (m_visited_bbs.contains (next_path[i])) - return false; - } - - /* Now add the nodes to VISISTED_BBS. */ - for (unsigned int i = 0; i + 1 < next_path.length (); i++) - m_visited_bbs.add (next_path[i]); - - /* Append all the nodes from NEXT_PATH to PATH. */ - m_path.safe_splice (next_path); - *next_path_length = next_path.length (); - - return true; -} - -/* If this is a profitable jump thread path, register it. - - NAME is an SSA NAME with a possible constant value of ARG on PATH. - - DEF_BB is the basic block that ultimately defines the constant. */ - -void -thread_jumps::maybe_register_path (const vec &m_path, - tree name, - edge taken_edge) -{ - bool irreducible = false; - bool profitable = m_profit.profitable_path_p (m_path, name, taken_edge, - &irreducible); - if (profitable) - { - if (!m_registry.register_path (m_path, taken_edge)) - return; - - if (irreducible) - vect_free_loop_info_assumptions (m_path[0]->loop_father); - } -} - -/* Given PHI which defines NAME in block DEF_BB, recurse through the - PHI's arguments searching for paths where NAME will ultimately have - a constant value. - - PATH contains the series of blocks to traverse that will result in - NAME having a constant value. */ - -void -thread_jumps::handle_phi (gphi *phi, basic_block def_bb) -{ - /* Iterate over the arguments of PHI. */ - for (unsigned int i = 0; i < gimple_phi_num_args (phi); i++) - { - tree arg = gimple_phi_arg_def (phi, i); - basic_block bbi = gimple_phi_arg_edge (phi, i)->src; - - /* Skip edges pointing outside the current loop. */ - if (!arg || def_bb->loop_father != bbi->loop_father) - continue; - - if (TREE_CODE (arg) == SSA_NAME) - { - m_path.safe_push (bbi); - /* Recursively follow SSA_NAMEs looking for a constant - definition. */ - fsm_find_control_statement_thread_paths (arg); - - m_path.pop (); - continue; - } - - m_path.safe_push (bbi); - edge taken_edge = find_taken_edge (m_path, arg); - if (taken_edge) - maybe_register_path (m_path, m_name, taken_edge); - m_path.pop (); - } -} - -/* Return TRUE if STMT is a gimple assignment we want to either directly - handle or recurse through. Return FALSE otherwise. - - Note that adding more cases here requires adding cases to handle_assignment - below. */ - -static bool -handle_assignment_p (gimple *stmt) -{ - if (is_gimple_assign (stmt)) - { - enum tree_code def_code = gimple_assign_rhs_code (stmt); - - /* If the RHS is an SSA_NAME, then we will recurse through it. - Go ahead and filter out cases where the SSA_NAME is a default - definition. There's little to be gained by trying to handle that. */ - if (def_code == SSA_NAME - && !SSA_NAME_IS_DEFAULT_DEF (gimple_assign_rhs1 (stmt))) - return true; - - /* If the RHS is a constant, then it's a terminal that we'll want - to handle as well. */ - if (TREE_CODE_CLASS (def_code) == tcc_constant) - return true; - } - - /* Anything not explicitly allowed is not handled. */ - return false; -} - -/* Given STMT which defines NAME in block DEF_BB, recurse through the - PHI's arguments searching for paths where NAME will ultimately have - a constant value. - - PATH contains the series of blocks to traverse that will result in - NAME having a constant value. */ - -void -thread_jumps::handle_assignment (gimple *stmt, basic_block def_bb) -{ - tree arg = gimple_assign_rhs1 (stmt); - - if (TREE_CODE (arg) == SSA_NAME) - fsm_find_control_statement_thread_paths (arg); - else - { - if (CHECKING_P) - { - gcc_assert (!m_path.is_empty ()); - basic_block top = m_path[m_path.length () - 1]; - gcc_assert (top == def_bb); - } - edge taken_edge = find_taken_edge (m_path, arg); - if (taken_edge) - maybe_register_path (m_path, m_name, taken_edge); - } -} - -/* We trace the value of the SSA_NAME NAME back through any phi nodes - looking for places where it gets a constant value and save the - path. */ - -void -thread_jumps::fsm_find_control_statement_thread_paths (tree name) -{ - /* If NAME appears in an abnormal PHI, then don't try to trace its - value back through PHI nodes. */ - if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (name)) - return; - - gimple *def_stmt = SSA_NAME_DEF_STMT (name); - basic_block def_bb = gimple_bb (def_stmt); - - if (def_bb == NULL) - return; - - /* We allow the SSA chain to contains PHIs and simple copies and constant - initializations. */ - if (gimple_code (def_stmt) != GIMPLE_PHI - && gimple_code (def_stmt) != GIMPLE_ASSIGN) - return; - - if (gimple_code (def_stmt) == GIMPLE_PHI - && (gimple_phi_num_args (def_stmt) - >= (unsigned) param_fsm_maximum_phi_arguments)) - return; - - if (is_gimple_assign (def_stmt) - && ! handle_assignment_p (def_stmt)) - return; - - /* Avoid infinite recursion. */ - if (m_visited_bbs.add (def_bb)) - return; - - int next_path_length = 0; - basic_block last_bb_in_path = m_path.last (); - - if (loop_containing_stmt (def_stmt)->header == gimple_bb (def_stmt)) - { - /* Do not walk through more than one loop PHI node. */ - if (m_seen_loop_phi) - return; - m_seen_loop_phi = true; - } - - /* Following the chain of SSA_NAME definitions, we jumped from a definition in - LAST_BB_IN_PATH to a definition in DEF_BB. When these basic blocks are - different, append to PATH the blocks from LAST_BB_IN_PATH to DEF_BB. */ - if (def_bb != last_bb_in_path) - { - /* When DEF_BB == LAST_BB_IN_PATH, then the first block in the path - will already be in VISITED_BBS. When they are not equal, then we - must ensure that first block is accounted for to ensure we do not - create bogus jump threading paths. */ - m_visited_bbs.add (m_path[0]); - if (!check_subpath_and_update_thread_path (last_bb_in_path, def_bb, - &next_path_length)) - return; - } - - gcc_assert (m_path.last () == def_bb); - - if (gimple_code (def_stmt) == GIMPLE_PHI) - handle_phi (as_a (def_stmt), def_bb); - else if (gimple_code (def_stmt) == GIMPLE_ASSIGN) - handle_assignment (def_stmt, def_bb); - - /* Remove all the nodes that we added from NEXT_PATH. */ - if (next_path_length) - m_path.truncate (m_path.length () - next_path_length); -} - -/* Search backwards from BB looking for paths where NAME (an SSA_NAME) - is a constant. Record such paths for jump threading. - - It is assumed that BB ends with a control statement and that by - finding a path where NAME is a constant, we can thread the path. - SPEED_P indicates that we could increase code size to improve the - code path. */ - -void -thread_jumps::find_jump_threads_backwards (basic_block bb) -{ - if (param_threader_mode & THREADER_MODE_RANGER) - { - find_jump_threads_backwards_with_ranger (bb); - return; - } - - gimple *stmt = get_gimple_control_stmt (bb); - if (!stmt) - return; - - enum gimple_code code = gimple_code (stmt); - tree name = NULL; - if (code == GIMPLE_SWITCH) - name = gimple_switch_index (as_a (stmt)); - else if (code == GIMPLE_GOTO) - name = gimple_goto_dest (stmt); - else if (code == GIMPLE_COND) - { - if (TREE_CODE (gimple_cond_lhs (stmt)) == SSA_NAME - && TREE_CODE_CLASS (TREE_CODE (gimple_cond_rhs (stmt))) == tcc_constant - && (INTEGRAL_TYPE_P (TREE_TYPE (gimple_cond_lhs (stmt))) - || POINTER_TYPE_P (TREE_TYPE (gimple_cond_lhs (stmt))))) - name = gimple_cond_lhs (stmt); - } - - if (!name || TREE_CODE (name) != SSA_NAME) - return; - - /* Initialize pass local data that's different for each BB. */ - m_path.truncate (0); - m_path.safe_push (bb); - m_visited_bbs.empty (); - m_seen_loop_phi = false; - m_name = name; - - fsm_find_control_statement_thread_paths (name); -} - -// Like find_jump_threads_backwards(), but using ranger. - -void -thread_jumps::find_jump_threads_backwards_with_ranger (basic_block bb) -{ - gimple *stmt = get_gimple_control_stmt (bb); - if (!stmt) - return; - - enum gimple_code code = gimple_code (stmt); - tree name = NULL; - if (code == GIMPLE_SWITCH) - name = gimple_switch_index (as_a (stmt)); - else if (code == GIMPLE_GOTO) - name = gimple_goto_dest (stmt); - else if (code == GIMPLE_COND) - name = gimple_cond_lhs (stmt); - - m_name = name; - m_back_threader.find_paths (bb, name); -} - namespace { const pass_data pass_data_thread_jumps = @@ -1327,12 +905,12 @@ static bool try_thread_blocks (function *fun) { /* Try to thread each block with more than one successor. */ - thread_jumps threader; + back_threader threader (/*speed_p=*/true); basic_block bb; FOR_EACH_BB_FN (bb, fun) { if (EDGE_COUNT (bb->succs) > 1) - threader.find_jump_threads_backwards (bb); + threader.maybe_thread_block (bb); } return threader.thread_through_all_blocks (); } @@ -1390,19 +968,18 @@ pass_early_thread_jumps::gate (function *fun ATTRIBUTE_UNUSED) return true; } - unsigned int pass_early_thread_jumps::execute (function *fun) { loop_optimizer_init (AVOID_CFG_MODIFICATIONS); /* Try to thread each block with more than one successor. */ - thread_jumps threader (/*speed_p=*/false); + back_threader threader (/*speed_p=*/false); basic_block bb; FOR_EACH_BB_FN (bb, fun) { if (EDGE_COUNT (bb->succs) > 1) - threader.find_jump_threads_backwards (bb); + threader.maybe_thread_block (bb); } threader.thread_through_all_blocks (); -- cgit v1.1 From d2ba65ab6010f0d507bf5512a0223692e6653b23 Mon Sep 17 00:00:00 2001 From: Martin Uecker Date: Thu, 12 Aug 2021 20:32:16 +0200 Subject: Evaluate type arguments of sizeof that are structs of variable size [PR101838] Evaluate type arguments of sizeof for all types of variable size and not just for VLAs. This fixes PR101838 and some issues related to PR29970 where statement expressions need to be evaluated so that the size is well defined. 2021-08-12 Martin Uecker gcc/c/ PR c/101838 PR c/29970 * c-typeck.c (c_expr_sizeof_type): Evaluate size expressions for structs of variable size. gcc/testsuite/ PR c/101838 * gcc.dg/vla-stexp-2.c: New test. --- gcc/c/c-typeck.c | 8 +++++++- gcc/testsuite/gcc.dg/vla-stexp-2.c | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/gcc.dg/vla-stexp-2.c (limited to 'gcc') diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c index c5bf337..eb5c87d 100644 --- a/gcc/c/c-typeck.c +++ b/gcc/c/c-typeck.c @@ -3022,8 +3022,14 @@ c_expr_sizeof_type (location_t loc, struct c_type_name *t) c_last_sizeof_loc = loc; ret.original_code = SIZEOF_EXPR; ret.original_type = NULL; + if (type == error_mark_node) + { + ret.value = error_mark_node; + ret.original_code = ERROR_MARK; + } + else if ((type_expr || TREE_CODE (ret.value) == INTEGER_CST) - && c_vla_type_p (type)) + && C_TYPE_VARIABLE_SIZE (type)) { /* If the type is a [*] array, it is a VLA but is represented as having a size of zero. In such a case we must ensure that diff --git a/gcc/testsuite/gcc.dg/vla-stexp-2.c b/gcc/testsuite/gcc.dg/vla-stexp-2.c new file mode 100644 index 0000000..176f400 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-stexp-2.c @@ -0,0 +1,33 @@ +/* PR101838 */ +/* { dg-do run } */ +/* { dg-options "-Wpedantic -O0" } */ + + +int bar0( + int (*a)[*], + int (*b)[sizeof(*a)] +); + + +int bar( + struct f { /* { dg-warning "will not be visible outside of this definition" } */ + int a[*]; } v, /* { dg-warning "variably modified type" } */ + int (*b)[sizeof(struct f)] // should not warn about zero size +); + +int foo(void) +{ + int n = 0; + return sizeof(typeof(*({ n = 10; struct foo { /* { dg-warning "braced-groups" } */ + int x[n]; /* { dg-warning "variably modified type" } */ + } x; &x; }))); +} + + +int main() +{ + if (sizeof(struct foo { int x[10]; }) != foo()) + __builtin_abort(); + + return 0; +} -- cgit v1.1 From 27a1fb385b7fe706f05608e53f3e91d7d3442b8b Mon Sep 17 00:00:00 2001 From: Sergei Trofimovich Date: Fri, 6 Aug 2021 16:14:16 +0100 Subject: c++: fix ptrmemfunc template instantiation [PR101219] r12-1804 ("cp: add support for per-location warning groups.") among other things removed warning suppression from a few places including ptrmemfuncs. This exposed a bug in warning detection code as a reference to missing BINFO (it's intentionally missing for ptrmemfunc types): crash_signal gcc/toplev.c:328 perform_or_defer_access_check(tree_node*, tree_node*, tree_node*, int, access_failure_info*) gcc/cp/semantics.c:490 finish_non_static_data_member(tree_node*, tree_node*, tree_node*) gcc/cp/semantics.c:2208 ... The change special cases ptrmemfuncs in templace substitution by using build_ptrmemfunc_access_expr() instead of finish_non_static_data_member(). gcc/cp/ChangeLog: PR c++/101219 * pt.c (tsubst_copy_and_build): Use build_ptrmemfunc_access_expr to construct ptrmemfunc expression instantiation. gcc/testsuite/ChangeLog: PR c++/101219 * g++.dg/warn/pr101219.C: New test. --- gcc/cp/pt.c | 8 +++++++- gcc/testsuite/g++.dg/warn/pr101219.C | 11 +++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/g++.dg/warn/pr101219.C (limited to 'gcc') diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index b396ddd..42ea51c 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -20530,7 +20530,13 @@ tsubst_copy_and_build (tree t, if (member == error_mark_node) RETURN (error_mark_node); - if (TREE_CODE (member) == FIELD_DECL) + if (object_type && TYPE_PTRMEMFUNC_P (object_type) + && TREE_CODE (member) == FIELD_DECL) + { + r = build_ptrmemfunc_access_expr (object, DECL_NAME (member)); + RETURN (r); + } + else if (TREE_CODE (member) == FIELD_DECL) { r = finish_non_static_data_member (member, object, NULL_TREE); if (TREE_CODE (r) == COMPONENT_REF) diff --git a/gcc/testsuite/g++.dg/warn/pr101219.C b/gcc/testsuite/g++.dg/warn/pr101219.C new file mode 100644 index 0000000..0d23d73 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/pr101219.C @@ -0,0 +1,11 @@ +/* PR c++/101219 - ICE on use of uninitialized memfun pointer + { dg-do compile } + { dg-options "-Wall" } */ + +struct S { void m(); }; + +template bool f() { + void (S::*mp)(); + + return &S::m == mp; // no warning emitted here (no instantiation) +} -- cgit v1.1 From a6da2cddcf0e959de6666d4d74411af23507f9f9 Mon Sep 17 00:00:00 2001 From: Jan Hubicka Date: Thu, 12 Aug 2021 20:52:54 +0200 Subject: Fix condition testing void functions in ipa-split. gcc/ChangeLog: 2021-08-12 Jan Hubicka * ipa-split.c (consider_split): Fix condition testing void functions. --- gcc/ipa-split.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'gcc') diff --git a/gcc/ipa-split.c b/gcc/ipa-split.c index 5e918ee..c68577d 100644 --- a/gcc/ipa-split.c +++ b/gcc/ipa-split.c @@ -546,8 +546,9 @@ consider_split (class split_point *current, bitmap non_ssa_vars, } } } - if (!VOID_TYPE_P (TREE_TYPE (current_function_decl))) - call_overhead += estimate_move_cost (TREE_TYPE (current_function_decl), + if (!VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl)))) + call_overhead += estimate_move_cost (TREE_TYPE (TREE_TYPE + (current_function_decl)), false); if (current->split_size <= call_overhead) -- cgit v1.1 From 8c8df06e46493f6cb55333db72fa1802279b48b4 Mon Sep 17 00:00:00 2001 From: Uros Bizjak Date: Thu, 12 Aug 2021 21:18:46 +0200 Subject: [i386] Introduce scalar version of avx512f_vmscalef. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 2021-08-12 UroÅ¡ Bizjak gcc/ PR target/98309 * config/i386/i386.md (avx512f_scalef2): New insn pattern. (ldexp3): Use avx512f_scalef2. (UNSPEC_SCALEF): Move from ... * config/i386/sse.md (UNSPEC_SCALEF): ... here. --- gcc/config/i386/i386.md | 27 +++++++++++++++++++-------- gcc/config/i386/sse.md | 1 - 2 files changed, 19 insertions(+), 9 deletions(-) (limited to 'gcc') diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index 56b09c5..4a8e8fe 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -125,6 +125,9 @@ UNSPEC_RSQRT UNSPEC_PSADBW + ;; For AVX512F support + UNSPEC_SCALEF + ;; Generic math support UNSPEC_COPYSIGN UNSPEC_XORSIGN @@ -17894,6 +17897,17 @@ DONE; }) +(define_insn "avx512f_scalef2" + [(set (match_operand:MODEF 0 "register_operand" "=v") + (unspec:MODEF + [(match_operand:MODEF 1 "register_operand" "v") + (match_operand:MODEF 2 "nonimmediate_operand" "vm")] + UNSPEC_SCALEF))] + "TARGET_AVX512F" + "vscalef\t{%2, %1, %0|%0, %1, %2}" + [(set_attr "prefix" "evex") + (set_attr "mode" "")]) + (define_expand "ldexpxf3" [(match_operand:XF 0 "register_operand") (match_operand:XF 1 "register_operand") @@ -17924,15 +17938,12 @@ if (TARGET_AVX512F && TARGET_SSE_MATH) { rtx op2 = gen_reg_rtx (mode); - emit_insn (gen_floatsi2 (op2, operands[2])); - operands[0] = lowpart_subreg (mode, operands[0], mode); - if (MEM_P (operands[1])) + + if (!nonimmediate_operand (operands[1], mode)) operands[1] = force_reg (mode, operands[1]); - operands[1] = lowpart_subreg (mode, operands[1], mode); - op2 = lowpart_subreg (mode, op2, mode); - emit_insn (gen_avx512f_vmscalef (operands[0], - operands[1], - op2)); + + emit_insn (gen_floatsi2 (op2, operands[2])); + emit_insn (gen_avx512f_scalef2 (operands[0], operands[1], op2)); } else { diff --git a/gcc/config/i386/sse.md b/gcc/config/i386/sse.md index 3a7bbae..60e69a4 100644 --- a/gcc/config/i386/sse.md +++ b/gcc/config/i386/sse.md @@ -92,7 +92,6 @@ UNSPEC_RCP14 UNSPEC_RSQRT14 UNSPEC_FIXUPIMM - UNSPEC_SCALEF UNSPEC_VTERNLOG UNSPEC_GETEXP UNSPEC_GETMANT -- cgit v1.1 From 8464894c86b03e4407dee83868bbaf29a3d43523 Mon Sep 17 00:00:00 2001 From: Michael Meissner Date: Thu, 12 Aug 2021 16:36:49 -0400 Subject: Fix typo in fold-vec-load-builtin_vec_xl-* tests. When I checked in the fix for running tests on power10 systems with power10 code generation, I had a typo in the fold-vec-load-builtin_vec_xl-* tests, swapping 'x' and 'v' in the p?lxv pattern. gcc/testsuite/ 2021-08-12 Michael Meissner * gcc.target/powerpc/fold-vec-load-builtin_vec_xl-char.c: Fix typo in regular expression. * gcc.target/powerpc/fold-vec-load-builtin_vec_xl-double.c: Likewise. * gcc.target/powerpc/fold-vec-load-builtin_vec_xl-float.c: Likewise. * gcc.target/powerpc/fold-vec-load-builtin_vec_xl-int.c: Likewise. * gcc.target/powerpc/fold-vec-load-builtin_vec_xl-longlong.c: Likewise. * gcc.target/powerpc/fold-vec-load-builtin_vec_xl-short.c: Likewise. --- gcc/testsuite/gcc.target/powerpc/fold-vec-load-builtin_vec_xl-char.c | 2 +- gcc/testsuite/gcc.target/powerpc/fold-vec-load-builtin_vec_xl-double.c | 2 +- gcc/testsuite/gcc.target/powerpc/fold-vec-load-builtin_vec_xl-float.c | 2 +- gcc/testsuite/gcc.target/powerpc/fold-vec-load-builtin_vec_xl-int.c | 2 +- .../gcc.target/powerpc/fold-vec-load-builtin_vec_xl-longlong.c | 2 +- gcc/testsuite/gcc.target/powerpc/fold-vec-load-builtin_vec_xl-short.c | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) (limited to 'gcc') diff --git a/gcc/testsuite/gcc.target/powerpc/fold-vec-load-builtin_vec_xl-char.c b/gcc/testsuite/gcc.target/powerpc/fold-vec-load-builtin_vec_xl-char.c index f6eb88f..9fc24f9 100644 --- a/gcc/testsuite/gcc.target/powerpc/fold-vec-load-builtin_vec_xl-char.c +++ b/gcc/testsuite/gcc.target/powerpc/fold-vec-load-builtin_vec_xl-char.c @@ -36,4 +36,4 @@ BUILD_VAR_TEST( test10, vector unsigned char, signed long long, vector unsigned BUILD_VAR_TEST( test11, vector unsigned char, signed int, vector unsigned char); BUILD_CST_TEST( test12, vector unsigned char, 8, vector unsigned char); -/* { dg-final { scan-assembler-times {\mlxvw4x\M|\mlxvd2x\M|\mlxvx\M|\mp?lvx\M} 12 } } */ +/* { dg-final { scan-assembler-times {\mlxvw4x\M|\mlxvd2x\M|\mlxvx\M|\mp?lxv\M|\mlvx\M} 12 } } */ diff --git a/gcc/testsuite/gcc.target/powerpc/fold-vec-load-builtin_vec_xl-double.c b/gcc/testsuite/gcc.target/powerpc/fold-vec-load-builtin_vec_xl-double.c index 66d5445..770bf36 100644 --- a/gcc/testsuite/gcc.target/powerpc/fold-vec-load-builtin_vec_xl-double.c +++ b/gcc/testsuite/gcc.target/powerpc/fold-vec-load-builtin_vec_xl-double.c @@ -28,4 +28,4 @@ BUILD_VAR_TEST( test4, vector double, signed long long, vector double); BUILD_VAR_TEST( test5, vector double, signed int, vector double); BUILD_CST_TEST( test6, vector double, 12, vector double); -/* { dg-final { scan-assembler-times {\mlxvd2x\M|\mlxvx\M|\mp?lvx\M} 6 } } */ +/* { dg-final { scan-assembler-times {\mlxvd2x\M|\mlxvx\M|\mp?lxv\M|\mlvx\M} 6 } } */ diff --git a/gcc/testsuite/gcc.target/powerpc/fold-vec-load-builtin_vec_xl-float.c b/gcc/testsuite/gcc.target/powerpc/fold-vec-load-builtin_vec_xl-float.c index 7d84c20..9b35a44 100644 --- a/gcc/testsuite/gcc.target/powerpc/fold-vec-load-builtin_vec_xl-float.c +++ b/gcc/testsuite/gcc.target/powerpc/fold-vec-load-builtin_vec_xl-float.c @@ -28,4 +28,4 @@ BUILD_VAR_TEST( test4, vector float, signed long long, vector float); BUILD_VAR_TEST( test5, vector float, signed int, vector float); BUILD_CST_TEST( test6, vector float, 12, vector float); -/* { dg-final { scan-assembler-times {\mlxvw4x\M|\mlxvd2x\M|\mlxvx\M|\mp?lvx\M} 6 } } */ +/* { dg-final { scan-assembler-times {\mlxvw4x\M|\mlxvd2x\M|\mlxvx\M|\mp?lxv\M|\mlvx\M} 6 } } */ diff --git a/gcc/testsuite/gcc.target/powerpc/fold-vec-load-builtin_vec_xl-int.c b/gcc/testsuite/gcc.target/powerpc/fold-vec-load-builtin_vec_xl-int.c index c6a8226..75903a9 100644 --- a/gcc/testsuite/gcc.target/powerpc/fold-vec-load-builtin_vec_xl-int.c +++ b/gcc/testsuite/gcc.target/powerpc/fold-vec-load-builtin_vec_xl-int.c @@ -36,4 +36,4 @@ BUILD_VAR_TEST( test10, vector unsigned int, signed long long, vector unsigned i BUILD_VAR_TEST( test11, vector unsigned int, signed int, vector unsigned int); BUILD_CST_TEST( test12, vector unsigned int, 12, vector unsigned int); -/* { dg-final { scan-assembler-times {\mlxvw4x\M|\mlxvd2x\M|\mlxvx\M|\mp?lvx\M} 12 } } */ +/* { dg-final { scan-assembler-times {\mlxvw4x\M|\mlxvd2x\M|\mlxvx\M|\mp?lxv\M|\mlvx\M} 12 } } */ diff --git a/gcc/testsuite/gcc.target/powerpc/fold-vec-load-builtin_vec_xl-longlong.c b/gcc/testsuite/gcc.target/powerpc/fold-vec-load-builtin_vec_xl-longlong.c index 6f0cd73..204f738 100644 --- a/gcc/testsuite/gcc.target/powerpc/fold-vec-load-builtin_vec_xl-longlong.c +++ b/gcc/testsuite/gcc.target/powerpc/fold-vec-load-builtin_vec_xl-longlong.c @@ -36,4 +36,4 @@ BUILD_VAR_TEST( test10, vector unsigned long long, signed long long, vector uns BUILD_VAR_TEST( test11, vector unsigned long long, signed int, vector unsigned long long); BUILD_CST_TEST( test12, vector unsigned long long, 12, vector unsigned long long); -/* { dg-final { scan-assembler-times {\mlxvd2x\M|\mlxvx\M|\mp?lvx\M} 12 } } */ +/* { dg-final { scan-assembler-times {\mlxvd2x\M|\mlxvx\M|\mp?lxv\M|\mlvx\M} 12 } } */ diff --git a/gcc/testsuite/gcc.target/powerpc/fold-vec-load-builtin_vec_xl-short.c b/gcc/testsuite/gcc.target/powerpc/fold-vec-load-builtin_vec_xl-short.c index 6c270a9..1be7765 100644 --- a/gcc/testsuite/gcc.target/powerpc/fold-vec-load-builtin_vec_xl-short.c +++ b/gcc/testsuite/gcc.target/powerpc/fold-vec-load-builtin_vec_xl-short.c @@ -36,4 +36,4 @@ BUILD_VAR_TEST( test10, vector unsigned short, signed long long, vector unsigne BUILD_VAR_TEST( test11, vector unsigned short, signed int, vector unsigned short); BUILD_CST_TEST( test12, vector unsigned short, 12, vector unsigned short); -/* { dg-final { scan-assembler-times {\mlxvw4x\M|\mlxvd2x\M|\mlxvx\M|\mp?lvx\M} 12 } } */ +/* { dg-final { scan-assembler-times {\mlxvw4x\M|\mlxvd2x\M|\mlxvx\M|\mp?lxv\M|\mlvx\M} 12 } } */ -- cgit v1.1 From 408d88af60e3268f7fad59fa393ec7e28922c435 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Thu, 12 Aug 2021 22:38:18 +0200 Subject: libcpp: Fix ICE with -Wtraditional preprocessing [PR101638] The following testcase ICEs in cpp_sys_macro_p, because cpp_sys_macro_p is called for a builtin macro which doesn't use node->value.macro union member but a different one and so dereferencing it ICEs. As the testcase is distilled from contemporary glibc headers, it means basically -Wtraditional now ICEs on almost everything. The fix can be either the patch below, return true for builtin macros, or we could instead return false for builtin macros, or the fix could be also (untested): --- libcpp/expr.c 2021-05-07 10:34:46.345122608 +0200 +++ libcpp/expr.c 2021-08-12 09:54:01.837556365 +0200 @@ -783,13 +783,13 @@ cpp_classify_number (cpp_reader *pfile, /* Traditional C only accepted the 'L' suffix. Suppress warning about 'LL' with -Wno-long-long. */ - if (CPP_WTRADITIONAL (pfile) && ! cpp_sys_macro_p (pfile)) + if (CPP_WTRADITIONAL (pfile)) { int u_or_i = (result & (CPP_N_UNSIGNED|CPP_N_IMAGINARY)); int large = (result & CPP_N_WIDTH) == CPP_N_LARGE && CPP_OPTION (pfile, cpp_warn_long_long); - if (u_or_i || large) + if ((u_or_i || large) && ! cpp_sys_macro_p (pfile)) cpp_warning_with_line (pfile, large ? CPP_W_LONG_LONG : CPP_W_TRADITIONAL, virtual_location, 0, "traditional C rejects the \"%.*s\" suffix", The builtin macros at least currently don't add any suffixes or numbers -Wtraditional would like to warn about. For floating point suffixes, -Wtraditional calls cpp_sys_macro_p only right away before emitting the warning, but in the above case the ICE is because cpp_sys_macro_p is called even if the number doesn't have any suffixes (that is I think always for builtin macros right now). 2021-08-12 Jakub Jelinek PR preprocessor/101638 * macro.c (cpp_sys_macro_p): Return true instead of crashing on builtin macros. * gcc.dg/cpp/pr101638.c: New test. --- gcc/testsuite/gcc.dg/cpp/pr101638.c | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 gcc/testsuite/gcc.dg/cpp/pr101638.c (limited to 'gcc') diff --git a/gcc/testsuite/gcc.dg/cpp/pr101638.c b/gcc/testsuite/gcc.dg/cpp/pr101638.c new file mode 100644 index 0000000..1030473 --- /dev/null +++ b/gcc/testsuite/gcc.dg/cpp/pr101638.c @@ -0,0 +1,7 @@ +/* PR preprocessor/101638 */ +/* { dg-do preprocess } */ +/* { dg-options "-Wtraditional" } */ + +#define foo(attr) __has_attribute(attr) +#if foo(__deprecated__) +#endif -- cgit v1.1 From d0befed793b94f3f407be44e6f69f81a02f5f073 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Thu, 12 Aug 2021 22:41:17 +0200 Subject: openmp: Add support for OpenMP 5.1 masked construct This construct has been introduced as a replacement for master construct, but unlike that construct is slightly more general, has an optional clause which allows to choose which thread will be the one running the region, it can be some other thread than the master (primary) thread with number 0, or it could be no threads or multiple threads (then of course one needs to be careful about data races). It is way too early to deprecate the master construct though, we don't even have OpenMP 5.0 fully implemented, it has been deprecated in 5.1, will be also in 5.2 and removed in 6.0. But even then it will likely be a good idea to just -Wdeprecated warn about it and still accept it. The patch also contains something I should have done much earlier, for clauses that accept some integral expression where we only care about the value, forces during gimplification that value into either a min invariant (as before), SSA_NAME or a fresh temporary, but never e.g. a user VAR_DECL, so that for those clauses we don't need to worry about adjusting it. 2021-08-12 Jakub Jelinek gcc/ * tree.def (OMP_MASKED): New tree code. * tree-core.h (enum omp_clause_code): Add OMP_CLAUSE_FILTER. * tree.h (OMP_MASKED_BODY, OMP_MASKED_CLAUSES, OMP_MASKED_COMBINED, OMP_CLAUSE_FILTER_EXPR): Define. * tree.c (omp_clause_num_ops): Add OMP_CLAUSE_FILTER entry. (omp_clause_code_name): Likewise. (walk_tree_1): Handle OMP_CLAUSE_FILTER. * tree-nested.c (convert_nonlocal_omp_clauses, convert_local_omp_clauses): Handle OMP_CLAUSE_FILTER. (convert_nonlocal_reference_stmt, convert_local_reference_stmt, convert_gimple_call): Handle GIMPLE_OMP_MASTER. * tree-pretty-print.c (dump_omp_clause): Handle OMP_CLAUSE_FILTER. (dump_generic_node): Handle OMP_MASTER. * gimple.def (GIMPLE_OMP_MASKED): New gimple code. * gimple.c (gimple_build_omp_masked): New function. (gimple_copy): Handle GIMPLE_OMP_MASKED. * gimple.h (gimple_build_omp_masked): Declare. (gimple_has_substatements): Handle GIMPLE_OMP_MASKED. (gimple_omp_masked_clauses, gimple_omp_masked_clauses_ptr, gimple_omp_masked_set_clauses): New inline functions. (CASE_GIMPLE_OMP): Add GIMPLE_OMP_MASKED. * gimple-pretty-print.c (dump_gimple_omp_masked): New function. (pp_gimple_stmt_1): Handle GIMPLE_OMP_MASKED. * gimple-walk.c (walk_gimple_stmt): Likewise. * gimple-low.c (lower_stmt): Likewise. * gimplify.c (is_gimple_stmt): Handle OMP_MASTER. (gimplify_scan_omp_clauses): Handle OMP_CLAUSE_FILTER. For clauses that take one expression rather than decl or constant, force gimplification of that into a SSA_NAME or temporary unless min invariant. (gimplify_adjust_omp_clauses): Handle OMP_CLAUSE_FILTER. (gimplify_expr): Handle OMP_MASKED. * tree-inline.c (remap_gimple_stmt): Handle GIMPLE_OMP_MASKED. (estimate_num_insns): Likewise. * omp-low.c (scan_sharing_clauses): Handle OMP_CLAUSE_FILTER. (check_omp_nesting_restrictions): Handle GIMPLE_OMP_MASKED. Adjust diagnostics for existence of masked construct. (scan_omp_1_stmt, lower_omp_master, lower_omp_1, diagnose_sb_1, diagnose_sb_2): Handle GIMPLE_OMP_MASKED. * omp-expand.c (expand_omp_synch, expand_omp, omp_make_gimple_edges): Likewise. gcc/c-family/ * c-pragma.h (enum pragma_kind): Add PRAGMA_OMP_MASKED. (enum pragma_omp_clause): Add PRAGMA_OMP_CLAUSE_FILTER. * c-pragma.c (omp_pragmas_simd): Add masked construct. * c-common.h (enum c_omp_clause_split): Add C_OMP_CLAUSE_SPLIT_MASKED enumerator. (c_finish_omp_masked): Declare. * c-omp.c (c_finish_omp_masked): New function. (c_omp_split_clauses): Handle combined masked constructs. gcc/c/ * c-parser.c (c_parser_omp_clause_name): Parse filter clause name. (c_parser_omp_clause_filter): New function. (c_parser_omp_all_clauses): Handle PRAGMA_OMP_CLAUSE_FILTER. (OMP_MASKED_CLAUSE_MASK): Define. (c_parser_omp_masked): New function. (c_parser_omp_parallel): Handle parallel masked. (c_parser_omp_construct): Handle PRAGMA_OMP_MASKED. * c-typeck.c (c_finish_omp_clauses): Handle OMP_CLAUSE_FILTER. gcc/cp/ * parser.c (cp_parser_omp_clause_name): Parse filter clause name. (cp_parser_omp_clause_filter): New function. (cp_parser_omp_all_clauses): Handle PRAGMA_OMP_CLAUSE_FILTER. (OMP_MASKED_CLAUSE_MASK): Define. (cp_parser_omp_masked): New function. (cp_parser_omp_parallel): Handle parallel masked. (cp_parser_omp_construct, cp_parser_pragma): Handle PRAGMA_OMP_MASKED. * semantics.c (finish_omp_clauses): Handle OMP_CLAUSE_FILTER. * pt.c (tsubst_omp_clauses): Likewise. (tsubst_expr): Handle OMP_MASKED. gcc/testsuite/ * c-c++-common/gomp/clauses-1.c (bar): Add tests for combined masked constructs with clauses. * c-c++-common/gomp/clauses-5.c (foo): Add testcase for filter clause. * c-c++-common/gomp/clause-dups-1.c (f1): Likewise. * c-c++-common/gomp/masked-1.c: New test. * c-c++-common/gomp/masked-2.c: New test. * c-c++-common/gomp/masked-combined-1.c: New test. * c-c++-common/gomp/masked-combined-2.c: New test. * c-c++-common/goacc/uninit-if-clause.c: Remove xfails. * g++.dg/gomp/block-11.C: New test. * g++.dg/gomp/tpl-masked-1.C: New test. * g++.dg/gomp/attrs-1.C (bar): Add tests for masked construct and combined masked constructs with clauses in attribute syntax. * g++.dg/gomp/attrs-2.C (bar): Likewise. * gcc.dg/gomp/nesting-1.c (f1, f2): Add tests for masked construct nesting. * gfortran.dg/goacc/host_data-tree.f95: Allow also SSA_NAMEs in if clause. * gfortran.dg/goacc/kernels-tree.f95: Likewise. libgomp/ * testsuite/libgomp.c-c++-common/masked-1.c: New test. --- gcc/c-family/c-common.h | 4 +- gcc/c-family/c-omp.c | 52 ++++++-- gcc/c-family/c-pragma.c | 1 + gcc/c-family/c-pragma.h | 2 + gcc/c/c-parser.c | 139 +++++++++++++++++++- gcc/c/c-typeck.c | 1 + gcc/cp/parser.c | 142 ++++++++++++++++++++- gcc/cp/pt.c | 2 + gcc/cp/semantics.c | 23 ++++ gcc/gimple-low.c | 1 + gcc/gimple-pretty-print.c | 33 +++++ gcc/gimple-walk.c | 1 + gcc/gimple.c | 20 +++ gcc/gimple.def | 4 + gcc/gimple.h | 37 ++++++ gcc/gimplify.c | 31 ++++- gcc/omp-expand.c | 3 + gcc/omp-low.c | 41 +++++- .../c-c++-common/goacc/uninit-if-clause.c | 9 +- gcc/testsuite/c-c++-common/gomp/clause-dups-1.c | 3 +- gcc/testsuite/c-c++-common/gomp/clauses-1.c | 52 ++++++++ gcc/testsuite/c-c++-common/gomp/clauses-5.c | 2 + gcc/testsuite/c-c++-common/gomp/masked-1.c | 23 ++++ gcc/testsuite/c-c++-common/gomp/masked-2.c | 11 ++ .../c-c++-common/gomp/masked-combined-1.c | 37 ++++++ .../c-c++-common/gomp/masked-combined-2.c | 13 ++ gcc/testsuite/g++.dg/gomp/attrs-1.C | 54 ++++++++ gcc/testsuite/g++.dg/gomp/attrs-2.C | 54 ++++++++ gcc/testsuite/g++.dg/gomp/block-11.C | 18 +++ gcc/testsuite/g++.dg/gomp/tpl-masked-1.C | 21 +++ gcc/testsuite/gcc.dg/gomp/nesting-1.c | 39 +++++- gcc/testsuite/gfortran.dg/goacc/host_data-tree.f95 | 4 +- gcc/testsuite/gfortran.dg/goacc/kernels-tree.f95 | 4 +- gcc/tree-core.h | 3 + gcc/tree-inline.c | 7 + gcc/tree-nested.c | 5 + gcc/tree-pretty-print.c | 12 ++ gcc/tree.c | 3 + gcc/tree.def | 5 + gcc/tree.h | 10 ++ 40 files changed, 886 insertions(+), 40 deletions(-) create mode 100644 gcc/testsuite/c-c++-common/gomp/masked-1.c create mode 100644 gcc/testsuite/c-c++-common/gomp/masked-2.c create mode 100644 gcc/testsuite/c-c++-common/gomp/masked-combined-1.c create mode 100644 gcc/testsuite/c-c++-common/gomp/masked-combined-2.c create mode 100644 gcc/testsuite/g++.dg/gomp/tpl-masked-1.C (limited to 'gcc') diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index 65d8c1c..025123a 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -1201,7 +1201,8 @@ enum c_omp_clause_split C_OMP_CLAUSE_SPLIT_COUNT, C_OMP_CLAUSE_SPLIT_SECTIONS = C_OMP_CLAUSE_SPLIT_FOR, C_OMP_CLAUSE_SPLIT_TASKLOOP = C_OMP_CLAUSE_SPLIT_FOR, - C_OMP_CLAUSE_SPLIT_LOOP = C_OMP_CLAUSE_SPLIT_FOR + C_OMP_CLAUSE_SPLIT_LOOP = C_OMP_CLAUSE_SPLIT_FOR, + C_OMP_CLAUSE_SPLIT_MASKED = C_OMP_CLAUSE_SPLIT_DISTRIBUTE }; enum c_omp_region_type @@ -1215,6 +1216,7 @@ enum c_omp_region_type }; extern tree c_finish_omp_master (location_t, tree); +extern tree c_finish_omp_masked (location_t, tree, tree); extern tree c_finish_omp_taskgroup (location_t, tree, tree); extern tree c_finish_omp_critical (location_t, tree, tree, tree); extern tree c_finish_omp_ordered (location_t, tree, tree); diff --git a/gcc/c-family/c-omp.c b/gcc/c-family/c-omp.c index e70974d..54eba61 100644 --- a/gcc/c-family/c-omp.c +++ b/gcc/c-family/c-omp.c @@ -86,6 +86,20 @@ c_finish_omp_master (location_t loc, tree stmt) return t; } +/* Complete a #pragma omp masked construct. BODY is the structured-block + that follows the pragma. LOC is the location of the #pragma. */ + +tree +c_finish_omp_masked (location_t loc, tree body, tree clauses) +{ + tree stmt = make_node (OMP_MASKED); + TREE_TYPE (stmt) = void_type_node; + OMP_MASKED_BODY (stmt) = body; + OMP_MASKED_CLAUSES (stmt) = clauses; + SET_EXPR_LOCATION (stmt, loc); + return add_stmt (stmt); +} + /* Complete a #pragma omp taskgroup construct. BODY is the structured-block that follows the pragma. LOC is the location of the #pragma. */ @@ -1542,11 +1556,16 @@ c_oacc_split_loop_clauses (tree clauses, tree *not_loop_clauses, #pragma omp distribute parallel for simd #pragma omp distribute simd #pragma omp for simd + #pragma omp masked taskloop + #pragma omp masked taskloop simd #pragma omp master taskloop #pragma omp master taskloop simd #pragma omp parallel for #pragma omp parallel for simd #pragma omp parallel loop + #pragma omp parallel masked + #pragma omp parallel masked taskloop + #pragma omp parallel masked taskloop simd #pragma omp parallel master #pragma omp parallel master taskloop #pragma omp parallel master taskloop simd @@ -1651,6 +1670,9 @@ c_omp_split_clauses (location_t loc, enum tree_code code, case OMP_CLAUSE_BIND: s = C_OMP_CLAUSE_SPLIT_LOOP; break; + case OMP_CLAUSE_FILTER: + s = C_OMP_CLAUSE_SPLIT_MASKED; + break; /* Duplicate this to all of taskloop, distribute, for, simd and loop. */ case OMP_CLAUSE_COLLAPSE: @@ -1700,10 +1722,10 @@ c_omp_split_clauses (location_t loc, enum tree_code code, else s = C_OMP_CLAUSE_SPLIT_DISTRIBUTE; break; - /* Private clause is supported on all constructs but master, - it is enough to put it on the innermost one other than master. For - #pragma omp {for,sections} put it on parallel though, - as that's what we did for OpenMP 3.1. */ + /* Private clause is supported on all constructs but master/masked, + it is enough to put it on the innermost one other than + master/masked. For #pragma omp {for,sections} put it on parallel + though, as that's what we did for OpenMP 3.1. */ case OMP_CLAUSE_PRIVATE: switch (code) { @@ -1713,14 +1735,15 @@ c_omp_split_clauses (location_t loc, enum tree_code code, case OMP_DISTRIBUTE: s = C_OMP_CLAUSE_SPLIT_DISTRIBUTE; break; case OMP_TEAMS: s = C_OMP_CLAUSE_SPLIT_TEAMS; break; case OMP_MASTER: s = C_OMP_CLAUSE_SPLIT_PARALLEL; break; + case OMP_MASKED: s = C_OMP_CLAUSE_SPLIT_PARALLEL; break; case OMP_TASKLOOP: s = C_OMP_CLAUSE_SPLIT_TASKLOOP; break; case OMP_LOOP: s = C_OMP_CLAUSE_SPLIT_LOOP; break; default: gcc_unreachable (); } break; /* Firstprivate clause is supported on all constructs but - simd, master and loop. Put it on the outermost of those and - duplicate on teams and parallel. */ + simd, master, masked and loop. Put it on the outermost of those + and duplicate on teams and parallel. */ case OMP_CLAUSE_FIRSTPRIVATE: if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP)) != 0) @@ -1773,7 +1796,7 @@ c_omp_split_clauses (location_t loc, enum tree_code code, else if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOGROUP)) != 0) /* This must be - #pragma omp parallel master taskloop{, simd}. */ + #pragma omp parallel mas{ked,ter} taskloop{, simd}. */ s = C_OMP_CLAUSE_SPLIT_TASKLOOP; else /* This must be @@ -1805,9 +1828,10 @@ c_omp_split_clauses (location_t loc, enum tree_code code, else if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOGROUP)) != 0) { - /* This must be #pragma omp {,{,parallel }master }taskloop simd + /* This must be + #pragma omp {,{,parallel }mas{ked,ter} }taskloop simd or - #pragma omp {,parallel }master taskloop. */ + #pragma omp {,parallel }mas{ked,ter} taskloop. */ gcc_assert (code == OMP_SIMD || code == OMP_TASKLOOP); s = C_OMP_CLAUSE_SPLIT_TASKLOOP; } @@ -2044,7 +2068,8 @@ c_omp_split_clauses (location_t loc, enum tree_code code, } else if (code == OMP_SECTIONS || code == OMP_PARALLEL - || code == OMP_MASTER) + || code == OMP_MASTER + || code == OMP_MASKED) s = C_OMP_CLAUSE_SPLIT_PARALLEL; else if (code == OMP_TASKLOOP) s = C_OMP_CLAUSE_SPLIT_TASKLOOP; @@ -2455,7 +2480,8 @@ c_omp_split_clauses (location_t loc, enum tree_code code, gcc_assert (cclauses[C_OMP_CLAUSE_SPLIT_TARGET] == NULL_TREE); if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_TEAMS)) == 0) gcc_assert (cclauses[C_OMP_CLAUSE_SPLIT_TEAMS] == NULL_TREE); - if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DIST_SCHEDULE)) == 0) + if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DIST_SCHEDULE)) == 0 + && (mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FILTER)) == 0) gcc_assert (cclauses[C_OMP_CLAUSE_SPLIT_DISTRIBUTE] == NULL_TREE); if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_THREADS)) == 0) gcc_assert (cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL] == NULL_TREE); @@ -2975,8 +3001,8 @@ static const struct c_omp_directive omp_directives[] = { C_OMP_DIR_STANDALONE, false }, */ { "loop", nullptr, nullptr, PRAGMA_OMP_LOOP, C_OMP_DIR_CONSTRUCT, true }, - /* { "masked", nullptr, nullptr, PRAGMA_OMP_MASKED, - C_OMP_DIR_CONSTRUCT, true }, */ + { "masked", nullptr, nullptr, PRAGMA_OMP_MASKED, + C_OMP_DIR_CONSTRUCT, true }, { "master", nullptr, nullptr, PRAGMA_OMP_MASTER, C_OMP_DIR_CONSTRUCT, true }, /* { "metadirective", nullptr, nullptr, PRAGMA_OMP_METADIRECTIVE, diff --git a/gcc/c-family/c-pragma.c b/gcc/c-family/c-pragma.c index f46b5b9..b466a27 100644 --- a/gcc/c-family/c-pragma.c +++ b/gcc/c-family/c-pragma.c @@ -1343,6 +1343,7 @@ static const struct omp_pragma_def omp_pragmas_simd[] = { { "distribute", PRAGMA_OMP_DISTRIBUTE }, { "for", PRAGMA_OMP_FOR }, { "loop", PRAGMA_OMP_LOOP }, + { "masked", PRAGMA_OMP_MASKED }, { "master", PRAGMA_OMP_MASTER }, { "ordered", PRAGMA_OMP_ORDERED }, { "parallel", PRAGMA_OMP_PARALLEL }, diff --git a/gcc/c-family/c-pragma.h b/gcc/c-family/c-pragma.h index abd6667..b7ec6e5 100644 --- a/gcc/c-family/c-pragma.h +++ b/gcc/c-family/c-pragma.h @@ -57,6 +57,7 @@ enum pragma_kind { PRAGMA_OMP_FLUSH, PRAGMA_OMP_FOR, PRAGMA_OMP_LOOP, + PRAGMA_OMP_MASKED, PRAGMA_OMP_MASTER, PRAGMA_OMP_ORDERED, PRAGMA_OMP_PARALLEL, @@ -104,6 +105,7 @@ enum pragma_omp_clause { PRAGMA_OMP_CLAUSE_DEVICE, PRAGMA_OMP_CLAUSE_DEVICE_TYPE, PRAGMA_OMP_CLAUSE_DIST_SCHEDULE, + PRAGMA_OMP_CLAUSE_FILTER, PRAGMA_OMP_CLAUSE_FINAL, PRAGMA_OMP_CLAUSE_FIRSTPRIVATE, PRAGMA_OMP_CLAUSE_FOR, diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index 195c137..ca6e56a 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -12696,7 +12696,9 @@ c_parser_omp_clause_name (c_parser *parser) result = PRAGMA_OMP_CLAUSE_DIST_SCHEDULE; break; case 'f': - if (!strcmp ("final", p)) + if (!strcmp ("filter", p)) + result = PRAGMA_OMP_CLAUSE_FILTER; + else if (!strcmp ("final", p)) result = PRAGMA_OMP_CLAUSE_FINAL; else if (!strcmp ("finalize", p)) result = PRAGMA_OACC_CLAUSE_FINALIZE; @@ -13948,6 +13950,38 @@ c_parser_omp_clause_hint (c_parser *parser, tree list) return list; } +/* OpenMP 5.1: + filter ( integer-expression ) */ + +static tree +c_parser_omp_clause_filter (c_parser *parser, tree list) +{ + location_t hint_loc = c_parser_peek_token (parser)->location; + matching_parens parens; + if (parens.require_open (parser)) + { + location_t expr_loc = c_parser_peek_token (parser)->location; + c_expr expr = c_parser_expr_no_commas (parser, NULL); + expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); + tree c, t = expr.value; + t = c_fully_fold (t, false, NULL); + if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + c_parser_error (parser, "expected integer expression"); + return list; + } + parens.skip_until_found_close (parser); + check_no_duplicate_clause (list, OMP_CLAUSE_FILTER, "filter"); + + c = build_omp_clause (hint_loc, OMP_CLAUSE_FILTER); + OMP_CLAUSE_FILTER_EXPR (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + list = c; + } + + return list; +} + /* OpenMP 4.5: defaultmap ( tofrom : scalar ) @@ -16410,6 +16444,10 @@ c_parser_omp_all_clauses (c_parser *parser, omp_clause_mask mask, clauses = c_parser_omp_clause_detach (parser, clauses); c_name = "detach"; break; + case PRAGMA_OMP_CLAUSE_FILTER: + clauses = c_parser_omp_clause_filter (parser, clauses); + c_name = "filter"; + break; case PRAGMA_OMP_CLAUSE_FIRSTPRIVATE: clauses = c_parser_omp_clause_firstprivate (parser, clauses); c_name = "firstprivate"; @@ -18975,6 +19013,70 @@ c_parser_omp_master (location_t loc, c_parser *parser, if_p)); } +/* OpenMP 5.1: + # pragma omp masked masked-clauses new-line + structured-block + + LOC is the location of the #pragma token. +*/ + +#define OMP_MASKED_CLAUSE_MASK \ + (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FILTER) + +static tree +c_parser_omp_masked (location_t loc, c_parser *parser, + char *p_name, omp_clause_mask mask, tree *cclauses, + bool *if_p) +{ + tree block, clauses, ret; + + strcat (p_name, " masked"); + mask |= OMP_MASKED_CLAUSE_MASK; + + if (c_parser_next_token_is (parser, CPP_NAME)) + { + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + + if (strcmp (p, "taskloop") == 0) + { + tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; + if (cclauses == NULL) + cclauses = cclauses_buf; + + c_parser_consume_token (parser); + if (!flag_openmp) /* flag_openmp_simd */ + return c_parser_omp_taskloop (loc, parser, p_name, mask, cclauses, + if_p); + block = c_begin_compound_stmt (true); + ret = c_parser_omp_taskloop (loc, parser, p_name, mask, cclauses, + if_p); + block = c_end_compound_stmt (loc, block, true); + if (ret == NULL_TREE) + return ret; + ret = c_finish_omp_masked (loc, block, + cclauses[C_OMP_CLAUSE_SPLIT_MASKED]); + OMP_MASKED_COMBINED (ret) = 1; + return ret; + } + } + if (!flag_openmp) /* flag_openmp_simd */ + { + c_parser_skip_to_pragma_eol (parser, false); + return NULL_TREE; + } + + clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL); + if (cclauses) + { + omp_split_clauses (loc, OMP_MASKED, mask, clauses, cclauses); + clauses = cclauses[C_OMP_CLAUSE_SPLIT_MASKED]; + } + + return c_finish_omp_masked (loc, c_parser_omp_structured_block (parser, + if_p), + clauses); +} + /* OpenMP 2.5: # pragma omp ordered new-line structured-block @@ -19237,7 +19339,36 @@ c_parser_omp_parallel (location_t loc, c_parser *parser, else if (c_parser_next_token_is (parser, CPP_NAME)) { const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); - if (cclauses == NULL && strcmp (p, "master") == 0) + if (cclauses == NULL && strcmp (p, "masked") == 0) + { + tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; + cclauses = cclauses_buf; + + c_parser_consume_token (parser); + if (!flag_openmp) /* flag_openmp_simd */ + return c_parser_omp_masked (loc, parser, p_name, mask, cclauses, + if_p); + block = c_begin_omp_parallel (); + tree ret = c_parser_omp_masked (loc, parser, p_name, mask, cclauses, + if_p); + stmt = c_finish_omp_parallel (loc, + cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL], + block); + if (ret == NULL) + return ret; + /* masked does have just filter clause, but during gimplification + isn't represented by a gimplification omp context, so for + #pragma omp parallel masked don't set OMP_PARALLEL_COMBINED, + so that + #pragma omp parallel masked + #pragma omp taskloop simd lastprivate (x) + isn't confused with + #pragma omp parallel masked taskloop simd lastprivate (x) */ + if (OMP_MASKED_COMBINED (ret)) + OMP_PARALLEL_COMBINED (stmt) = 1; + return stmt; + } + else if (cclauses == NULL && strcmp (p, "master") == 0) { tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; cclauses = cclauses_buf; @@ -21815,6 +21946,10 @@ c_parser_omp_construct (c_parser *parser, bool *if_p) strcpy (p_name, "#pragma omp"); stmt = c_parser_omp_loop (loc, parser, p_name, mask, NULL, if_p); break; + case PRAGMA_OMP_MASKED: + strcpy (p_name, "#pragma omp"); + stmt = c_parser_omp_masked (loc, parser, p_name, mask, NULL, if_p); + break; case PRAGMA_OMP_MASTER: strcpy (p_name, "#pragma omp"); stmt = c_parser_omp_master (loc, parser, p_name, mask, NULL, if_p); diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c index eb5c87d..0c07af61 100644 --- a/gcc/c/c-typeck.c +++ b/gcc/c/c-typeck.c @@ -15158,6 +15158,7 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) case OMP_CLAUSE_THREADS: case OMP_CLAUSE_SIMD: case OMP_CLAUSE_HINT: + case OMP_CLAUSE_FILTER: case OMP_CLAUSE_DEFAULTMAP: case OMP_CLAUSE_BIND: case OMP_CLAUSE_NUM_GANGS: diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index b7fe4b4..edb69ae 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -36004,7 +36004,9 @@ cp_parser_omp_clause_name (cp_parser *parser) result = PRAGMA_OMP_CLAUSE_DIST_SCHEDULE; break; case 'f': - if (!strcmp ("final", p)) + if (!strcmp ("filter", p)) + result = PRAGMA_OMP_CLAUSE_FILTER; + else if (!strcmp ("final", p)) result = PRAGMA_OMP_CLAUSE_FINAL; else if (!strcmp ("finalize", p)) result = PRAGMA_OACC_CLAUSE_FINALIZE; @@ -37340,6 +37342,34 @@ cp_parser_omp_clause_hint (cp_parser *parser, tree list, location_t location) return c; } +/* OpenMP 5.1: + filter ( integer-expression ) */ + +static tree +cp_parser_omp_clause_filter (cp_parser *parser, tree list, location_t location) +{ + tree t, c; + + matching_parens parens; + if (!parens.require_open (parser)) + return list; + + t = cp_parser_assignment_expression (parser); + + if (t == error_mark_node + || !parens.require_close (parser)) + cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + check_no_duplicate_clause (list, OMP_CLAUSE_FILTER, "filter", location); + + c = build_omp_clause (location, OMP_CLAUSE_FILTER); + OMP_CLAUSE_FILTER_EXPR (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + + return c; +} + /* OpenMP 4.5: defaultmap ( tofrom : scalar ) @@ -39449,6 +39479,11 @@ cp_parser_omp_all_clauses (cp_parser *parser, omp_clause_mask mask, token->location, false); c_name = "default"; break; + case PRAGMA_OMP_CLAUSE_FILTER: + clauses = cp_parser_omp_clause_filter (parser, clauses, + token->location); + c_name = "filter"; + break; case PRAGMA_OMP_CLAUSE_FINAL: clauses = cp_parser_omp_clause_final (parser, clauses, token->location); c_name = "final"; @@ -41985,6 +42020,73 @@ cp_parser_omp_master (cp_parser *parser, cp_token *pragma_tok, cp_parser_omp_structured_block (parser, if_p)); } +/* OpenMP 5.1: + # pragma omp masked masked-clauses new-line + structured-block */ + +#define OMP_MASKED_CLAUSE_MASK \ + (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FILTER) + +static tree +cp_parser_omp_masked (cp_parser *parser, cp_token *pragma_tok, + char *p_name, omp_clause_mask mask, tree *cclauses, + bool *if_p) +{ + tree clauses, sb, ret; + unsigned int save; + location_t loc = cp_lexer_peek_token (parser->lexer)->location; + + strcat (p_name, " masked"); + mask |= OMP_MASKED_CLAUSE_MASK; + + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) + { + tree id = cp_lexer_peek_token (parser->lexer)->u.value; + const char *p = IDENTIFIER_POINTER (id); + + if (strcmp (p, "taskloop") == 0) + { + tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; + if (cclauses == NULL) + cclauses = cclauses_buf; + + cp_lexer_consume_token (parser->lexer); + if (!flag_openmp) /* flag_openmp_simd */ + return cp_parser_omp_taskloop (parser, pragma_tok, p_name, mask, + cclauses, if_p); + sb = begin_omp_structured_block (); + save = cp_parser_begin_omp_structured_block (parser); + ret = cp_parser_omp_taskloop (parser, pragma_tok, p_name, mask, + cclauses, if_p); + cp_parser_end_omp_structured_block (parser, save); + tree body = finish_omp_structured_block (sb); + if (ret == NULL) + return ret; + ret = c_finish_omp_masked (loc, body, + cclauses[C_OMP_CLAUSE_SPLIT_MASKED]); + OMP_MASKED_COMBINED (ret) = 1; + return ret; + } + } + if (!flag_openmp) /* flag_openmp_simd */ + { + cp_parser_skip_to_pragma_eol (parser, pragma_tok); + return NULL_TREE; + } + + clauses = cp_parser_omp_all_clauses (parser, mask, p_name, pragma_tok, + cclauses == NULL); + if (cclauses) + { + cp_omp_split_clauses (loc, OMP_MASTER, mask, clauses, cclauses); + clauses = cclauses[C_OMP_CLAUSE_SPLIT_MASKED]; + } + + return c_finish_omp_masked (loc, + cp_parser_omp_structured_block (parser, if_p), + clauses); +} + /* OpenMP 2.5: # pragma omp ordered new-line structured-block @@ -42238,7 +42340,37 @@ cp_parser_omp_parallel (cp_parser *parser, cp_token *pragma_tok, { tree id = cp_lexer_peek_token (parser->lexer)->u.value; const char *p = IDENTIFIER_POINTER (id); - if (cclauses == NULL && strcmp (p, "master") == 0) + if (cclauses == NULL && strcmp (p, "masked") == 0) + { + tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; + cclauses = cclauses_buf; + + cp_lexer_consume_token (parser->lexer); + if (!flag_openmp) /* flag_openmp_simd */ + return cp_parser_omp_masked (parser, pragma_tok, p_name, mask, + cclauses, if_p); + block = begin_omp_parallel (); + save = cp_parser_begin_omp_structured_block (parser); + tree ret = cp_parser_omp_masked (parser, pragma_tok, p_name, mask, + cclauses, if_p); + cp_parser_end_omp_structured_block (parser, save); + stmt = finish_omp_parallel (cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL], + block); + if (ret == NULL_TREE) + return ret; + /* masked does have just filter clause, but during gimplification + isn't represented by a gimplification omp context, so for + #pragma omp parallel masked don't set OMP_PARALLEL_COMBINED, + so that + #pragma omp parallel masked + #pragma omp taskloop simd lastprivate (x) + isn't confused with + #pragma omp parallel masked taskloop simd lastprivate (x) */ + if (OMP_MASKED_COMBINED (ret)) + OMP_PARALLEL_COMBINED (stmt) = 1; + return stmt; + } + else if (cclauses == NULL && strcmp (p, "master") == 0) { tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT]; cclauses = cclauses_buf; @@ -45824,6 +45956,11 @@ cp_parser_omp_construct (cp_parser *parser, cp_token *pragma_tok, bool *if_p) stmt = cp_parser_omp_loop (parser, pragma_tok, p_name, mask, NULL, if_p); break; + case PRAGMA_OMP_MASKED: + strcpy (p_name, "#pragma omp"); + stmt = cp_parser_omp_masked (parser, pragma_tok, p_name, mask, NULL, + if_p); + break; case PRAGMA_OMP_MASTER: strcpy (p_name, "#pragma omp"); stmt = cp_parser_omp_master (parser, pragma_tok, p_name, mask, NULL, @@ -46464,6 +46601,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) case PRAGMA_OMP_DISTRIBUTE: case PRAGMA_OMP_FOR: case PRAGMA_OMP_LOOP: + case PRAGMA_OMP_MASKED: case PRAGMA_OMP_MASTER: case PRAGMA_OMP_PARALLEL: case PRAGMA_OMP_SECTIONS: diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 42ea51c..0870ccd 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -17394,6 +17394,7 @@ tsubst_omp_clauses (tree clauses, enum c_omp_region_type ort, case OMP_CLAUSE_PRIORITY: case OMP_CLAUSE_ORDERED: case OMP_CLAUSE_HINT: + case OMP_CLAUSE_FILTER: case OMP_CLAUSE_NUM_GANGS: case OMP_CLAUSE_NUM_WORKERS: case OMP_CLAUSE_VECTOR_LENGTH: @@ -18786,6 +18787,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, break; case OMP_SECTIONS: + case OMP_MASKED: omp_parallel_combined_clauses = NULL; /* FALLTHRU */ case OMP_SINGLE: diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 2e23818..0198d2d 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -8204,6 +8204,29 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) } break; + case OMP_CLAUSE_FILTER: + t = OMP_CLAUSE_FILTER_EXPR (c); + if (t == error_mark_node) + remove = true; + else if (!type_dependent_expression_p (t) + && !INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "% expression must be integral"); + remove = true; + } + else + { + t = mark_rvalue_use (t); + if (!processing_template_decl) + { + t = maybe_constant_value (t); + t = fold_build_cleanup_point_expr (TREE_TYPE (t), t); + } + OMP_CLAUSE_FILTER_EXPR (c) = t; + } + break; + case OMP_CLAUSE_IS_DEVICE_PTR: case OMP_CLAUSE_USE_DEVICE_PTR: field_ok = (ort & C_ORT_OMP_DECLARE_SIMD) == C_ORT_OMP; diff --git a/gcc/gimple-low.c b/gcc/gimple-low.c index fa7d4de..832d5c3 100644 --- a/gcc/gimple-low.c +++ b/gcc/gimple-low.c @@ -334,6 +334,7 @@ lower_stmt (gimple_stmt_iterator *gsi, struct lower_data *data) case GIMPLE_OMP_SECTION: case GIMPLE_OMP_SINGLE: case GIMPLE_OMP_MASTER: + case GIMPLE_OMP_MASKED: case GIMPLE_OMP_TASKGROUP: case GIMPLE_OMP_ORDERED: case GIMPLE_OMP_SCAN: diff --git a/gcc/gimple-pretty-print.c b/gcc/gimple-pretty-print.c index d6e63d6..1bccad1 100644 --- a/gcc/gimple-pretty-print.c +++ b/gcc/gimple-pretty-print.c @@ -1658,6 +1658,35 @@ dump_gimple_omp_taskgroup (pretty_printer *buffer, const gimple *gs, } } +/* Dump a GIMPLE_OMP_MASKED tuple on the pretty_printer BUFFER. */ + +static void +dump_gimple_omp_masked (pretty_printer *buffer, const gimple *gs, + int spc, dump_flags_t flags) +{ + if (flags & TDF_RAW) + { + dump_gimple_fmt (buffer, spc, flags, "%G <%+BODY <%S>%nCLAUSES <", gs, + gimple_omp_body (gs)); + dump_omp_clauses (buffer, gimple_omp_masked_clauses (gs), spc, flags); + dump_gimple_fmt (buffer, spc, flags, " >"); + } + else + { + pp_string (buffer, "#pragma omp masked"); + dump_omp_clauses (buffer, gimple_omp_masked_clauses (gs), spc, flags); + if (!gimple_seq_empty_p (gimple_omp_body (gs))) + { + newline_and_indent (buffer, spc + 2); + pp_left_brace (buffer); + pp_newline (buffer); + dump_gimple_seq (buffer, gimple_omp_body (gs), spc + 4, flags); + newline_and_indent (buffer, spc + 2); + pp_right_brace (buffer); + } + } +} + /* Dump a GIMPLE_OMP_TARGET tuple on the pretty_printer BUFFER. */ static void @@ -2722,6 +2751,10 @@ pp_gimple_stmt_1 (pretty_printer *buffer, const gimple *gs, int spc, dump_gimple_omp_taskgroup (buffer, gs, spc, flags); break; + case GIMPLE_OMP_MASKED: + dump_gimple_omp_masked (buffer, gs, spc, flags); + break; + case GIMPLE_OMP_MASTER: case GIMPLE_OMP_SECTION: dump_gimple_omp_block (buffer, gs, spc, flags); diff --git a/gcc/gimple-walk.c b/gcc/gimple-walk.c index 18884c4..9dd2e86 100644 --- a/gcc/gimple-walk.c +++ b/gcc/gimple-walk.c @@ -682,6 +682,7 @@ walk_gimple_stmt (gimple_stmt_iterator *gsi, walk_stmt_fn callback_stmt, /* FALL THROUGH. */ case GIMPLE_OMP_CRITICAL: case GIMPLE_OMP_MASTER: + case GIMPLE_OMP_MASKED: case GIMPLE_OMP_TASKGROUP: case GIMPLE_OMP_ORDERED: case GIMPLE_OMP_SCAN: diff --git a/gcc/gimple.c b/gcc/gimple.c index 383da98..23bfc7f 100644 --- a/gcc/gimple.c +++ b/gcc/gimple.c @@ -1038,6 +1038,21 @@ gimple_build_omp_master (gimple_seq body) return p; } +/* Build a GIMPLE_OMP_MASKED statement. + + BODY is the sequence of statements to be executed by the selected thread(s). */ + +gimple * +gimple_build_omp_masked (gimple_seq body, tree clauses) +{ + gimple *p = gimple_alloc (GIMPLE_OMP_MASKED, 0); + gimple_omp_masked_set_clauses (p, clauses); + if (body) + gimple_omp_set_body (p, body); + + return p; +} + /* Build a GIMPLE_OMP_TASKGROUP statement. BODY is the sequence of statements to be executed by the taskgroup @@ -2031,6 +2046,11 @@ gimple_copy (gimple *stmt) gimple_omp_set_body (copy, new_seq); break; + case GIMPLE_OMP_MASKED: + t = unshare_expr (gimple_omp_masked_clauses (stmt)); + gimple_omp_masked_set_clauses (copy, t); + goto copy_omp_body; + case GIMPLE_TRANSACTION: new_seq = gimple_seq_copy (gimple_transaction_body ( as_a (stmt))); diff --git a/gcc/gimple.def b/gcc/gimple.def index 0ac0cf7..e66546c 100644 --- a/gcc/gimple.def +++ b/gcc/gimple.def @@ -279,6 +279,10 @@ DEFGSCODE(GIMPLE_OMP_FOR, "gimple_omp_for", GSS_OMP_FOR) BODY is the sequence of statements to execute in the master section. */ DEFGSCODE(GIMPLE_OMP_MASTER, "gimple_omp_master", GSS_OMP) +/* GIMPLE_OMP_MASKED represents #pragma omp masked. + BODY is the sequence of statements to execute in the masked section. */ +DEFGSCODE(GIMPLE_OMP_MASKED, "gimple_omp_masked", GSS_OMP_SINGLE_LAYOUT) + /* GIMPLE_OMP_TASKGROUP represents #pragma omp taskgroup. BODY is the sequence of statements inside the taskgroup section. CLAUSES is an OMP_CLAUSE chain holding the associated clauses. */ diff --git a/gcc/gimple.h b/gcc/gimple.h index 31d7dd0..7fd483d 100644 --- a/gcc/gimple.h +++ b/gcc/gimple.h @@ -1560,6 +1560,7 @@ gomp_task *gimple_build_omp_task (gimple_seq, tree, tree, tree, tree, tree, tree); gimple *gimple_build_omp_section (gimple_seq); gimple *gimple_build_omp_master (gimple_seq); +gimple *gimple_build_omp_masked (gimple_seq, tree); gimple *gimple_build_omp_taskgroup (gimple_seq, tree); gomp_continue *gimple_build_omp_continue (tree, tree); gomp_ordered *gimple_build_omp_ordered (gimple_seq, tree); @@ -1836,6 +1837,7 @@ gimple_has_substatements (gimple *g) case GIMPLE_TRY: case GIMPLE_OMP_FOR: case GIMPLE_OMP_MASTER: + case GIMPLE_OMP_MASKED: case GIMPLE_OMP_TASKGROUP: case GIMPLE_OMP_ORDERED: case GIMPLE_OMP_SECTION: @@ -5205,6 +5207,40 @@ gimple_omp_taskgroup_set_clauses (gimple *gs, tree clauses) } +/* Return the clauses associated with OMP_MASTER statement GS. */ + +static inline tree +gimple_omp_masked_clauses (const gimple *gs) +{ + GIMPLE_CHECK (gs, GIMPLE_OMP_MASKED); + return + static_cast (gs)->clauses; +} + + +/* Return a pointer to the clauses associated with OMP masked statement + GS. */ + +static inline tree * +gimple_omp_masked_clauses_ptr (gimple *gs) +{ + GIMPLE_CHECK (gs, GIMPLE_OMP_MASKED); + return &static_cast (gs)->clauses; +} + + +/* Set CLAUSES to be the clauses associated with OMP masked statement + GS. */ + +static inline void +gimple_omp_masked_set_clauses (gimple *gs, tree clauses) +{ + GIMPLE_CHECK (gs, GIMPLE_OMP_MASKED); + static_cast (gs)->clauses + = clauses; +} + + /* Return the kind of the OMP_FOR statemement G. */ static inline int @@ -6493,6 +6529,7 @@ gimple_return_set_retval (greturn *gs, tree retval) case GIMPLE_OMP_TEAMS: \ case GIMPLE_OMP_SECTION: \ case GIMPLE_OMP_MASTER: \ + case GIMPLE_OMP_MASKED: \ case GIMPLE_OMP_TASKGROUP: \ case GIMPLE_OMP_ORDERED: \ case GIMPLE_OMP_CRITICAL: \ diff --git a/gcc/gimplify.c b/gcc/gimplify.c index 21ff32e..eadbf83 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -5632,6 +5632,7 @@ is_gimple_stmt (tree t) case OMP_SECTION: case OMP_SINGLE: case OMP_MASTER: + case OMP_MASKED: case OMP_TASKGROUP: case OMP_ORDERED: case OMP_CRITICAL: @@ -10102,6 +10103,7 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, case OMP_CLAUSE_PRIORITY: case OMP_CLAUSE_GRAINSIZE: case OMP_CLAUSE_NUM_TASKS: + case OMP_CLAUSE_FILTER: case OMP_CLAUSE_HINT: case OMP_CLAUSE_ASYNC: case OMP_CLAUSE_WAIT: @@ -10110,9 +10112,20 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, case OMP_CLAUSE_VECTOR_LENGTH: case OMP_CLAUSE_WORKER: case OMP_CLAUSE_VECTOR: - if (gimplify_expr (&OMP_CLAUSE_OPERAND (c, 0), pre_p, NULL, - is_gimple_val, fb_rvalue) == GS_ERROR) - remove = true; + if (OMP_CLAUSE_OPERAND (c, 0) + && !is_gimple_min_invariant (OMP_CLAUSE_OPERAND (c, 0))) + { + if (error_operand_p (OMP_CLAUSE_OPERAND (c, 0))) + { + remove = true; + break; + } + /* All these clauses care about value, not a particular decl, + so try to force it into a SSA_NAME or fresh temporary. */ + OMP_CLAUSE_OPERAND (c, 0) + = get_initialized_tmp_var (OMP_CLAUSE_OPERAND (c, 0), + pre_p, NULL, true); + } break; case OMP_CLAUSE_GANG: @@ -11222,6 +11235,7 @@ gimplify_adjust_omp_clauses (gimple_seq *pre_p, gimple_seq body, tree *list_p, case OMP_CLAUSE_NOGROUP: case OMP_CLAUSE_THREADS: case OMP_CLAUSE_SIMD: + case OMP_CLAUSE_FILTER: case OMP_CLAUSE_HINT: case OMP_CLAUSE_DEFAULTMAP: case OMP_CLAUSE_ORDER: @@ -14766,6 +14780,7 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, case OMP_SECTION: case OMP_MASTER: + case OMP_MASKED: case OMP_ORDERED: case OMP_CRITICAL: case OMP_SCAN: @@ -14788,6 +14803,15 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, case OMP_ORDERED: g = gimplify_omp_ordered (*expr_p, body); break; + case OMP_MASKED: + gimplify_scan_omp_clauses (&OMP_MASKED_CLAUSES (*expr_p), + pre_p, ORT_WORKSHARE, OMP_MASKED); + gimplify_adjust_omp_clauses (pre_p, body, + &OMP_MASKED_CLAUSES (*expr_p), + OMP_MASKED); + g = gimple_build_omp_masked (body, + OMP_MASKED_CLAUSES (*expr_p)); + break; case OMP_CRITICAL: gimplify_scan_omp_clauses (&OMP_CRITICAL_CLAUSES (*expr_p), pre_p, ORT_WORKSHARE, OMP_CRITICAL); @@ -15161,6 +15185,7 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, && code != OMP_FOR && code != OACC_LOOP && code != OMP_MASTER + && code != OMP_MASKED && code != OMP_TASKGROUP && code != OMP_ORDERED && code != OMP_PARALLEL diff --git a/gcc/omp-expand.c b/gcc/omp-expand.c index 9fd1c65..1d4b39e 100644 --- a/gcc/omp-expand.c +++ b/gcc/omp-expand.c @@ -8460,6 +8460,7 @@ expand_omp_synch (struct omp_region *region) si = gsi_last_nondebug_bb (entry_bb); gcc_assert (gimple_code (gsi_stmt (si)) == GIMPLE_OMP_SINGLE || gimple_code (gsi_stmt (si)) == GIMPLE_OMP_MASTER + || gimple_code (gsi_stmt (si)) == GIMPLE_OMP_MASKED || gimple_code (gsi_stmt (si)) == GIMPLE_OMP_TASKGROUP || gimple_code (gsi_stmt (si)) == GIMPLE_OMP_ORDERED || gimple_code (gsi_stmt (si)) == GIMPLE_OMP_CRITICAL @@ -9947,6 +9948,7 @@ expand_omp (struct omp_region *region) } /* FALLTHRU */ case GIMPLE_OMP_MASTER: + case GIMPLE_OMP_MASKED: case GIMPLE_OMP_TASKGROUP: case GIMPLE_OMP_CRITICAL: case GIMPLE_OMP_TEAMS: @@ -10266,6 +10268,7 @@ omp_make_gimple_edges (basic_block bb, struct omp_region **region, case GIMPLE_OMP_SINGLE: case GIMPLE_OMP_TEAMS: case GIMPLE_OMP_MASTER: + case GIMPLE_OMP_MASKED: case GIMPLE_OMP_TASKGROUP: case GIMPLE_OMP_CRITICAL: case GIMPLE_OMP_SECTION: diff --git a/gcc/omp-low.c b/gcc/omp-low.c index 926087d..22ba579 100644 --- a/gcc/omp-low.c +++ b/gcc/omp-low.c @@ -1466,6 +1466,7 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) case OMP_CLAUSE_NUM_WORKERS: case OMP_CLAUSE_VECTOR_LENGTH: case OMP_CLAUSE_DETACH: + case OMP_CLAUSE_FILTER: if (ctx->outer) scan_omp_op (&OMP_CLAUSE_OPERAND (c, 0), ctx->outer); break; @@ -1868,6 +1869,7 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) case OMP_CLAUSE__SIMT_: case OMP_CLAUSE_IF_PRESENT: case OMP_CLAUSE_FINALIZE: + case OMP_CLAUSE_FILTER: case OMP_CLAUSE__CONDTEMP_: break; @@ -3426,6 +3428,7 @@ check_omp_nesting_restrictions (gimple *stmt, omp_context *ctx) case GIMPLE_OMP_SINGLE: case GIMPLE_OMP_ORDERED: case GIMPLE_OMP_MASTER: + case GIMPLE_OMP_MASKED: case GIMPLE_OMP_TASK: case GIMPLE_OMP_CRITICAL: if (is_gimple_call (stmt)) @@ -3436,14 +3439,15 @@ check_omp_nesting_restrictions (gimple *stmt, omp_context *ctx) error_at (gimple_location (stmt), "barrier region may not be closely nested inside " "of work-sharing, %, %, " - "%, %, explicit % or " - "% region"); + "%, %, %, explicit " + "% or % region"); return false; } error_at (gimple_location (stmt), "work-sharing region may not be closely nested inside " "of work-sharing, %, %, %, " - "%, explicit % or % region"); + "%, %, explicit % or " + "% region"); return false; case GIMPLE_OMP_PARALLEL: case GIMPLE_OMP_TEAMS: @@ -3458,6 +3462,7 @@ check_omp_nesting_restrictions (gimple *stmt, omp_context *ctx) } break; case GIMPLE_OMP_MASTER: + case GIMPLE_OMP_MASKED: for (; ctx != NULL; ctx = ctx->outer) switch (gimple_code (ctx->stmt)) { @@ -3470,9 +3475,11 @@ check_omp_nesting_restrictions (gimple *stmt, omp_context *ctx) case GIMPLE_OMP_SINGLE: case GIMPLE_OMP_TASK: error_at (gimple_location (stmt), - "% region may not be closely nested inside " + "%qs region may not be closely nested inside " "of work-sharing, %, explicit % or " - "% region"); + "% region", + gimple_code (stmt) == GIMPLE_OMP_MASTER + ? "master" : "masked"); return false; case GIMPLE_OMP_PARALLEL: case GIMPLE_OMP_TEAMS: @@ -4079,6 +4086,12 @@ scan_omp_1_stmt (gimple_stmt_iterator *gsi, bool *handled_ops_p, scan_omp (gimple_omp_body_ptr (stmt), ctx); break; + case GIMPLE_OMP_MASKED: + ctx = new_omp_context (stmt, ctx); + scan_sharing_clauses (gimple_omp_masked_clauses (stmt), ctx); + scan_omp (gimple_omp_body_ptr (stmt), ctx); + break; + case GIMPLE_OMP_TASKGROUP: ctx = new_omp_context (stmt, ctx); scan_sharing_clauses (gimple_omp_taskgroup_clauses (stmt), ctx); @@ -8675,7 +8688,7 @@ lower_omp_single (gimple_stmt_iterator *gsi_p, omp_context *ctx) } -/* Expand code for an OpenMP master directive. */ +/* Expand code for an OpenMP master or masked directive. */ static void lower_omp_master (gimple_stmt_iterator *gsi_p, omp_context *ctx) @@ -8685,9 +8698,20 @@ lower_omp_master (gimple_stmt_iterator *gsi_p, omp_context *ctx) gbind *bind; location_t loc = gimple_location (stmt); gimple_seq tseq; + tree filter = integer_zero_node; push_gimplify_context (); + if (gimple_code (stmt) == GIMPLE_OMP_MASKED) + { + filter = omp_find_clause (gimple_omp_masked_clauses (stmt), + OMP_CLAUSE_FILTER); + if (filter) + filter = fold_convert (integer_type_node, + OMP_CLAUSE_FILTER_EXPR (filter)); + else + filter = integer_zero_node; + } block = make_node (BLOCK); bind = gimple_build_bind (NULL, NULL, block); gsi_replace (gsi_p, bind, true); @@ -8695,7 +8719,7 @@ lower_omp_master (gimple_stmt_iterator *gsi_p, omp_context *ctx) bfn_decl = builtin_decl_explicit (BUILT_IN_OMP_GET_THREAD_NUM); x = build_call_expr_loc (loc, bfn_decl, 0); - x = build2 (EQ_EXPR, boolean_type_node, x, integer_zero_node); + x = build2 (EQ_EXPR, boolean_type_node, x, filter); x = build3 (COND_EXPR, void_type_node, x, NULL, build_and_jump (&lab)); tseq = NULL; gimplify_and_add (x, &tseq); @@ -13869,6 +13893,7 @@ lower_omp_1 (gimple_stmt_iterator *gsi_p, omp_context *ctx) lower_omp_single (gsi_p, ctx); break; case GIMPLE_OMP_MASTER: + case GIMPLE_OMP_MASKED: ctx = maybe_lookup_ctx (stmt); gcc_assert (ctx); lower_omp_master (gsi_p, ctx); @@ -14246,6 +14271,7 @@ diagnose_sb_1 (gimple_stmt_iterator *gsi_p, bool *handled_ops_p, case GIMPLE_OMP_SINGLE: case GIMPLE_OMP_SECTION: case GIMPLE_OMP_MASTER: + case GIMPLE_OMP_MASKED: case GIMPLE_OMP_ORDERED: case GIMPLE_OMP_SCAN: case GIMPLE_OMP_CRITICAL: @@ -14307,6 +14333,7 @@ diagnose_sb_2 (gimple_stmt_iterator *gsi_p, bool *handled_ops_p, case GIMPLE_OMP_SINGLE: case GIMPLE_OMP_SECTION: case GIMPLE_OMP_MASTER: + case GIMPLE_OMP_MASKED: case GIMPLE_OMP_ORDERED: case GIMPLE_OMP_SCAN: case GIMPLE_OMP_CRITICAL: diff --git a/gcc/testsuite/c-c++-common/goacc/uninit-if-clause.c b/gcc/testsuite/c-c++-common/goacc/uninit-if-clause.c index 7f78d72..683ac1b 100644 --- a/gcc/testsuite/c-c++-common/goacc/uninit-if-clause.c +++ b/gcc/testsuite/c-c++-common/goacc/uninit-if-clause.c @@ -1,6 +1,5 @@ /* { dg-do compile } */ /* { dg-additional-options "-Wuninitialized" } */ -/* { dg-excess-errors "PR70392" { xfail c++ } } */ #include @@ -14,25 +13,25 @@ main (void) #pragma acc parallel if(l) /* { dg-warning "is used uninitialized" } */ ; - #pragma acc parallel if(b) /* { dg-warning "is used uninitialized" "" { xfail c++ } } */ + #pragma acc parallel if(b) /* { dg-warning "is used uninitialized" } */ ; #pragma acc kernels if(l2) /* { dg-warning "is used uninitialized" } */ ; - #pragma acc kernels if(b2) /* { dg-warning "is used uninitialized" "" { xfail c++ } } */ + #pragma acc kernels if(b2) /* { dg-warning "is used uninitialized" } */ ; #pragma acc data if(l3) /* { dg-warning "is used uninitialized" } */ ; - #pragma acc data if(b3) /* { dg-warning "is used uninitialized" "" { xfail c++ } } */ + #pragma acc data if(b3) /* { dg-warning "is used uninitialized" } */ ; #pragma acc update if(l4) self(i) /* { dg-warning "is used uninitialized" } */ ; - #pragma acc update if(b4) self(i2) /* { dg-warning "is used uninitialized" "" { xfail c++ } } */ + #pragma acc update if(b4) self(i2) /* { dg-warning "is used uninitialized" } */ ; } diff --git a/gcc/testsuite/c-c++-common/gomp/clause-dups-1.c b/gcc/testsuite/c-c++-common/gomp/clause-dups-1.c index 3dde058..7b71ad3 100644 --- a/gcc/testsuite/c-c++-common/gomp/clause-dups-1.c +++ b/gcc/testsuite/c-c++-common/gomp/clause-dups-1.c @@ -203,7 +203,8 @@ f1 (int *p) i = p[0]++; #pragma omp atomic capture hint(0) hint (0) /* { dg-error "too many 'hint' clauses" } */ i = p[0]++; - + #pragma omp masked filter (0) filter (0) /* { dg-error "too many 'filter' clauses" } */ + f0 (); } #pragma omp declare simd simdlen (4) simdlen (4) /* { dg-error "too many 'simdlen' clauses" } */ diff --git a/gcc/testsuite/c-c++-common/gomp/clauses-1.c b/gcc/testsuite/c-c++-common/gomp/clauses-1.c index 682442af..378c7bf 100644 --- a/gcc/testsuite/c-c++-common/gomp/clauses-1.c +++ b/gcc/testsuite/c-c++-common/gomp/clauses-1.c @@ -273,6 +273,10 @@ bar (int d, int m, int i1, int i2, int i3, int p, int *idp, int s, private (p) firstprivate (f) if (parallel: i2) default(shared) shared(s) reduction(+:r) \ num_threads (nth) proc_bind(spread) copyin(t) allocate (f) ; + #pragma omp parallel masked \ + private (p) firstprivate (f) if (parallel: i2) default(shared) shared(s) reduction(+:r) \ + num_threads (nth) proc_bind(spread) copyin(t) allocate (f) filter (d) + ; #pragma omp taskgroup task_reduction (+:r2) allocate (r2) #pragma omp master taskloop \ private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) grainsize (g) collapse(1) untied if(taskloop: i1) final(fi) mergeable priority (pp) \ @@ -280,23 +284,47 @@ bar (int d, int m, int i1, int i2, int i3, int p, int *idp, int s, for (int i = 0; i < 64; i++) ll++; #pragma omp taskgroup task_reduction (+:r2) allocate (r2) + #pragma omp masked taskloop \ + private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) grainsize (g) collapse(1) untied if(taskloop: i1) final(fi) mergeable priority (pp) \ + reduction(default, +:r) in_reduction(+:r2) allocate (f) filter (d) + for (int i = 0; i < 64; i++) + ll++; + #pragma omp taskgroup task_reduction (+:r2) allocate (r2) #pragma omp master taskloop simd \ private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) grainsize (g) collapse(1) untied if(taskloop: i1) if(simd: i2) final(fi) mergeable priority (pp) \ safelen(8) simdlen(4) linear(ll: 1) aligned(q: 32) reduction(default, +:r) in_reduction(+:r2) nontemporal(ntm) \ order(concurrent) allocate (f) for (int i = 0; i < 64; i++) ll++; + #pragma omp taskgroup task_reduction (+:r2) allocate (r2) + #pragma omp masked taskloop simd \ + private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) grainsize (g) collapse(1) untied if(taskloop: i1) if(simd: i2) final(fi) mergeable priority (pp) \ + safelen(8) simdlen(4) linear(ll: 1) aligned(q: 32) reduction(default, +:r) in_reduction(+:r2) nontemporal(ntm) \ + order(concurrent) allocate (f) filter (d) + for (int i = 0; i < 64; i++) + ll++; #pragma omp parallel master taskloop \ private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) grainsize (g) collapse(1) untied if(taskloop: i1) final(fi) mergeable priority (pp) \ reduction(default, +:r) if (parallel: i2) num_threads (nth) proc_bind(spread) copyin(t) allocate (f) for (int i = 0; i < 64; i++) ll++; + #pragma omp parallel masked taskloop \ + private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) grainsize (g) collapse(1) untied if(taskloop: i1) final(fi) mergeable priority (pp) \ + reduction(default, +:r) if (parallel: i2) num_threads (nth) proc_bind(spread) copyin(t) allocate (f) filter (d) + for (int i = 0; i < 64; i++) + ll++; #pragma omp parallel master taskloop simd \ private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) grainsize (g) collapse(1) untied if(taskloop: i1) if(simd: i2) final(fi) mergeable priority (pp) \ safelen(8) simdlen(4) linear(ll: 1) aligned(q: 32) reduction(default, +:r) nontemporal(ntm) if (parallel: i2) num_threads (nth) proc_bind(spread) copyin(t) \ order(concurrent) allocate (f) for (int i = 0; i < 64; i++) ll++; + #pragma omp parallel masked taskloop simd \ + private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) grainsize (g) collapse(1) untied if(taskloop: i1) if(simd: i2) final(fi) mergeable priority (pp) \ + safelen(8) simdlen(4) linear(ll: 1) aligned(q: 32) reduction(default, +:r) nontemporal(ntm) if (parallel: i2) num_threads (nth) proc_bind(spread) copyin(t) \ + order(concurrent) allocate (f) filter (d) + for (int i = 0; i < 64; i++) + ll++; #pragma omp taskgroup task_reduction (+:r2) allocate (r2) #pragma omp master taskloop \ private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) num_tasks (nta) collapse(1) untied if(i1) final(fi) mergeable priority (pp) \ @@ -304,23 +332,47 @@ bar (int d, int m, int i1, int i2, int i3, int p, int *idp, int s, for (int i = 0; i < 64; i++) ll++; #pragma omp taskgroup task_reduction (+:r2) allocate (r2) + #pragma omp mastked taskloop \ + private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) num_tasks (nta) collapse(1) untied if(i1) final(fi) mergeable priority (pp) \ + reduction(default, +:r) in_reduction(+:r2) filter (d) + for (int i = 0; i < 64; i++) + ll++; + #pragma omp taskgroup task_reduction (+:r2) allocate (r2) #pragma omp master taskloop simd \ private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) num_tasks (nta) collapse(1) untied if(i1) final(fi) mergeable priority (pp) \ safelen(8) simdlen(4) linear(ll: 1) aligned(q: 32) reduction(default, +:r) in_reduction(+:r2) nontemporal(ntm) \ order(concurrent) allocate (f) for (int i = 0; i < 64; i++) ll++; + #pragma omp taskgroup task_reduction (+:r2) allocate (r2) + #pragma omp masked taskloop simd \ + private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) num_tasks (nta) collapse(1) untied if(i1) final(fi) mergeable priority (pp) \ + safelen(8) simdlen(4) linear(ll: 1) aligned(q: 32) reduction(default, +:r) in_reduction(+:r2) nontemporal(ntm) \ + order(concurrent) allocate (f) filter (d) + for (int i = 0; i < 64; i++) + ll++; #pragma omp parallel master taskloop \ private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) num_tasks (nta) collapse(1) untied if(i1) final(fi) mergeable priority (pp) \ reduction(default, +:r) num_threads (nth) proc_bind(spread) copyin(t) allocate (f) for (int i = 0; i < 64; i++) ll++; + #pragma omp parallel masked taskloop \ + private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) num_tasks (nta) collapse(1) untied if(i1) final(fi) mergeable priority (pp) \ + reduction(default, +:r) num_threads (nth) proc_bind(spread) copyin(t) allocate (f) filter (d) + for (int i = 0; i < 64; i++) + ll++; #pragma omp parallel master taskloop simd \ private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) num_tasks (nta) collapse(1) untied if(i1) final(fi) mergeable priority (pp) \ safelen(8) simdlen(4) linear(ll: 1) aligned(q: 32) reduction(default, +:r) nontemporal(ntm) num_threads (nth) proc_bind(spread) copyin(t) \ order(concurrent) allocate (f) for (int i = 0; i < 64; i++) ll++; + #pragma omp parallel masked taskloop simd \ + private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) num_tasks (nta) collapse(1) untied if(i1) final(fi) mergeable priority (pp) \ + safelen(8) simdlen(4) linear(ll: 1) aligned(q: 32) reduction(default, +:r) nontemporal(ntm) num_threads (nth) proc_bind(spread) copyin(t) \ + order(concurrent) allocate (f) filter (d) + for (int i = 0; i < 64; i++) + ll++; #pragma omp loop bind(thread) order(concurrent) \ private (p) lastprivate (l) collapse(1) reduction(+:r) for (l = 0; l < 64; ++l) diff --git a/gcc/testsuite/c-c++-common/gomp/clauses-5.c b/gcc/testsuite/c-c++-common/gomp/clauses-5.c index 35e16f0..87e53a9 100644 --- a/gcc/testsuite/c-c++-common/gomp/clauses-5.c +++ b/gcc/testsuite/c-c++-common/gomp/clauses-5.c @@ -49,4 +49,6 @@ foo (int *p) ; #pragma omp critical (baz) hint (2, 3) /* { dg-error "expected" } */ ; + #pragma omp masked filter (3, 4) /* { dg-error "expected" } */ + ; } diff --git a/gcc/testsuite/c-c++-common/gomp/masked-1.c b/gcc/testsuite/c-c++-common/gomp/masked-1.c new file mode 100644 index 0000000..36c2e49 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/masked-1.c @@ -0,0 +1,23 @@ +void bar (void); + +void +foo (int x, int *a) +{ + #pragma omp masked + bar (); + #pragma omp masked filter (0) + bar (); + #pragma omp masked filter (7) + bar (); + #pragma omp masked filter (x) + bar (); + #pragma omp masked taskloop simd filter (x) grainsize (12) simdlen (4) + for (int i = 0; i < 128; i++) + a[i] = i; + #pragma omp parallel masked filter (x) firstprivate (x) + bar (); + #pragma omp masked + #pragma omp masked filter (0) + #pragma omp masked filter (x) + ; +} diff --git a/gcc/testsuite/c-c++-common/gomp/masked-2.c b/gcc/testsuite/c-c++-common/gomp/masked-2.c new file mode 100644 index 0000000..7230c82 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/masked-2.c @@ -0,0 +1,11 @@ +void bar (void); +struct S { int s; }; + +void +foo (float f, struct S s) +{ + #pragma omp masked filter (0.0) /* { dg-error "integral|integer" } */ + bar (); + #pragma omp masked filter (s) /* { dg-error "integral|integer" } */ + bar (); +} diff --git a/gcc/testsuite/c-c++-common/gomp/masked-combined-1.c b/gcc/testsuite/c-c++-common/gomp/masked-combined-1.c new file mode 100644 index 0000000..0b3ff58 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/masked-combined-1.c @@ -0,0 +1,37 @@ +void bar (int *); + +void +foo (int *a, int f) +{ + int i, j, k, u = 0, v = 0, w = 0, x = 0, y = 0, z = 0; + #pragma omp parallel masked default(none) private (k) filter (f) firstprivate (f) + bar (&k); + #pragma omp parallel masked default(none) private (k) + bar (&k); + #pragma omp parallel default(none) firstprivate(a, f) shared(x, y, z) + { + #pragma omp masked taskloop reduction (+:x) default(none) firstprivate(a) filter (f) + for (i = 0; i < 64; i++) + x += a[i]; + #pragma omp masked taskloop simd reduction (+:y) default(none) firstprivate(a) private (i) filter (f) + for (i = 0; i < 64; i++) + y += a[i]; + #pragma omp masked taskloop simd reduction (+:y) default(none) firstprivate(a) private (i) + for (i = 0; i < 64; i++) + y += a[i]; + #pragma omp masked taskloop simd collapse(2) reduction (+:z) default(none) firstprivate(a) private (i, j) filter (f) + for (j = 0; j < 1; j++) + for (i = 0; i < 64; ++i) + z += a[i]; + } + #pragma omp parallel masked taskloop reduction (+:u) default(none) firstprivate(a, f) filter (f) + for (i = 0; i < 64; i++) + u += a[i]; + #pragma omp parallel masked taskloop simd reduction (+:v) default(none) firstprivate(a, f) filter (f) + for (i = 0; i < 64; i++) + v += a[i]; + #pragma omp parallel masked taskloop simd collapse(2) reduction (+:w) default(none) firstprivate(a, f) filter (f) + for (j = 0; j < 1; j++) + for (i = 0; i < 64; ++i) + w += a[i]; +} diff --git a/gcc/testsuite/c-c++-common/gomp/masked-combined-2.c b/gcc/testsuite/c-c++-common/gomp/masked-combined-2.c new file mode 100644 index 0000000..1d63969 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/masked-combined-2.c @@ -0,0 +1,13 @@ +void +foo (int *a) +{ + int i, r = 0, s = 0; + #pragma omp taskgroup task_reduction(+:r) + #pragma omp parallel masked taskloop in_reduction(+:r) /* { dg-error "'in_reduction' is not valid for '#pragma omp parallel masked taskloop'" } */ + for (i = 0; i < 64; i++) + r += a[i]; + #pragma omp taskgroup task_reduction(+:s) + #pragma omp parallel masked taskloop simd in_reduction(+:s) /* { dg-error "'in_reduction' is not valid for '#pragma omp parallel masked taskloop simd'" } */ + for (i = 0; i < 64; i++) + s += a[i]; +} diff --git a/gcc/testsuite/g++.dg/gomp/attrs-1.C b/gcc/testsuite/g++.dg/gomp/attrs-1.C index 5c7007b..c348375 100644 --- a/gcc/testsuite/g++.dg/gomp/attrs-1.C +++ b/gcc/testsuite/g++.dg/gomp/attrs-1.C @@ -348,6 +348,10 @@ bar (int d, int m, int i1, int i2, int i3, int p, int *idp, int s, private (p) firstprivate (f) if (parallel: i2) default(shared) shared(s) reduction(+:r) num_threads (nth) proc_bind(spread) copyin(t) allocate (f))]] ; + [[omp::directive (parallel masked + private (p) firstprivate (f) if (parallel: i2) default(shared) shared(s) reduction(+:r) + num_threads (nth) proc_bind(spread) copyin(t) allocate (f) filter (d))]] + ; [[omp::directive (parallel private (p) firstprivate (f) if (parallel: i2) default(shared) shared(s) reduction(+:r) num_threads (nth) proc_bind(spread) copyin(t) allocate (f))]] @@ -358,7 +362,15 @@ bar (int d, int m, int i1, int i2, int i3, int p, int *idp, int s, reduction(default, +:r) in_reduction(+:r2) allocate (f)))]] for (int i = 0; i < 64; i++) ll++; + [[omp::sequence (directive (taskgroup task_reduction (+:r2) allocate (r2)), + omp::directive (masked taskloop + private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) grainsize (g) collapse(1) untied if(taskloop: i1) final(fi) mergeable priority (pp) + reduction(default, +:r) in_reduction(+:r2) allocate (f) filter (d)))]] + for (int i = 0; i < 64; i++) + ll++; [[omp::directive (master)]]; + [[omp::directive (masked)]]; + [[omp::directive (masked filter (d))]]; [[omp::sequence (omp::directive (taskgroup task_reduction (+:r2) allocate (r2)), directive (master taskloop simd private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) grainsize (g) collapse(1) untied if(taskloop: i1) if(simd: i2) final(fi) mergeable priority (pp) @@ -366,23 +378,47 @@ bar (int d, int m, int i1, int i2, int i3, int p, int *idp, int s, order(concurrent) allocate (f)))]] for (int i = 0; i < 64; i++) ll++; + [[omp::sequence (omp::directive (taskgroup task_reduction (+:r2) allocate (r2)), + directive (masked taskloop simd + private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) grainsize (g) collapse(1) untied if(taskloop: i1) if(simd: i2) final(fi) mergeable priority (pp) + safelen(8) simdlen(4) linear(ll: 1) aligned(q: 32) reduction(default, +:r) in_reduction(+:r2) nontemporal(ntm) + order(concurrent) allocate (f) filter (d)))]] + for (int i = 0; i < 64; i++) + ll++; [[omp::directive (parallel master taskloop private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) grainsize (g) collapse(1) untied if(taskloop: i1) final(fi) mergeable priority (pp) reduction(default, +:r) if (parallel: i2) num_threads (nth) proc_bind(spread) copyin(t) allocate (f))]] for (int i = 0; i < 64; i++) ll++; + [[omp::directive (parallel masked taskloop + private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) grainsize (g) collapse(1) untied if(taskloop: i1) final(fi) mergeable priority (pp) + reduction(default, +:r) if (parallel: i2) num_threads (nth) proc_bind(spread) copyin(t) allocate (f) filter (d))]] + for (int i = 0; i < 64; i++) + ll++; [[omp::directive (parallel master taskloop simd private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) grainsize (g) collapse(1) untied if(taskloop: i1) if(simd: i2) final(fi) mergeable priority (pp) safelen(8) simdlen(4) linear(ll: 1) aligned(q: 32) reduction(default, +:r) nontemporal(ntm) if (parallel: i2) num_threads (nth) proc_bind(spread) copyin(t) order(concurrent) allocate (f))]] for (int i = 0; i < 64; i++) ll++; + [[omp::directive (parallel masked taskloop simd + private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) grainsize (g) collapse(1) untied if(taskloop: i1) if(simd: i2) final(fi) mergeable priority (pp) + safelen(8) simdlen(4) linear(ll: 1) aligned(q: 32) reduction(default, +:r) nontemporal(ntm) if (parallel: i2) num_threads (nth) proc_bind(spread) copyin(t) + order(concurrent) allocate (f) filter (d))]] + for (int i = 0; i < 64; i++) + ll++; [[omp::sequence (directive (taskgroup task_reduction (+:r2) allocate (r2)), directive (master taskloop private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) num_tasks (nta) collapse(1) untied if(i1) final(fi) mergeable priority (pp) reduction(default, +:r) in_reduction(+:r2)))]] for (int i = 0; i < 64; i++) ll++; + [[omp::sequence (directive (taskgroup task_reduction (+:r2) allocate (r2)), + directive (masked taskloop + private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) num_tasks (nta) collapse(1) untied if(i1) final(fi) mergeable priority (pp) + reduction(default, +:r) in_reduction(+:r2) filter (d)))]] + for (int i = 0; i < 64; i++) + ll++; [[omp::sequence (omp::directive (taskgroup task_reduction (+:r2) allocate (r2)), omp::directive (master taskloop simd private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) num_tasks (nta) collapse(1) untied if(i1) final(fi) mergeable priority (pp) @@ -390,17 +426,35 @@ bar (int d, int m, int i1, int i2, int i3, int p, int *idp, int s, order(concurrent) allocate (f)))]] for (int i = 0; i < 64; i++) ll++; + [[omp::sequence (omp::directive (taskgroup task_reduction (+:r2) allocate (r2)), + omp::directive (masked taskloop simd + private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) num_tasks (nta) collapse(1) untied if(i1) final(fi) mergeable priority (pp) + safelen(8) simdlen(4) linear(ll: 1) aligned(q: 32) reduction(default, +:r) in_reduction(+:r2) nontemporal(ntm) + order(concurrent) allocate (f) filter (d)))]] + for (int i = 0; i < 64; i++) + ll++; [[omp::directive (parallel master taskloop private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) num_tasks (nta) collapse(1) untied if(i1) final(fi) mergeable priority (pp) reduction(default, +:r) num_threads (nth) proc_bind(spread) copyin(t) allocate (f))]] for (int i = 0; i < 64; i++) ll++; + [[omp::directive (parallel masked taskloop + private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) num_tasks (nta) collapse(1) untied if(i1) final(fi) mergeable priority (pp) + reduction(default, +:r) num_threads (nth) proc_bind(spread) copyin(t) allocate (f) filter (d))]] + for (int i = 0; i < 64; i++) + ll++; [[omp::directive (parallel master taskloop simd private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) num_tasks (nta) collapse(1) untied if(i1) final(fi) mergeable priority (pp) safelen(8) simdlen(4) linear(ll: 1) aligned(q: 32) reduction(default, +:r) nontemporal(ntm) num_threads (nth) proc_bind(spread) copyin(t) order(concurrent) allocate (f))]] for (int i = 0; i < 64; i++) ll++; + [[omp::directive (parallel masked taskloop simd + private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) num_tasks (nta) collapse(1) untied if(i1) final(fi) mergeable priority (pp) + safelen(8) simdlen(4) linear(ll: 1) aligned(q: 32) reduction(default, +:r) nontemporal(ntm) num_threads (nth) proc_bind(spread) copyin(t) + order(concurrent) allocate (f) filter (d))]] + for (int i = 0; i < 64; i++) + ll++; [[omp::directive (loop bind(thread) order(concurrent) private (p) lastprivate (l) collapse(1) reduction(+:r))]] for (l = 0; l < 64; ++l) diff --git a/gcc/testsuite/g++.dg/gomp/attrs-2.C b/gcc/testsuite/g++.dg/gomp/attrs-2.C index 1b59abd..b2fba21 100644 --- a/gcc/testsuite/g++.dg/gomp/attrs-2.C +++ b/gcc/testsuite/g++.dg/gomp/attrs-2.C @@ -348,6 +348,10 @@ bar (int d, int m, int i1, int i2, int i3, int p, int *idp, int s, private (p),firstprivate (f),if (parallel: i2),default(shared),shared(s),reduction(+:r), num_threads (nth),proc_bind(spread),copyin(t),allocate (f))]] ; + [[omp::directive (parallel masked, + private (p),firstprivate (f),if (parallel: i2),default(shared),shared(s),reduction(+:r), + num_threads (nth),proc_bind(spread),copyin(t),allocate (f),filter(d))]] + ; [[omp::directive (parallel, private (p),firstprivate (f),if (parallel: i2),default(shared),shared(s),reduction(+:r), num_threads (nth),proc_bind(spread),copyin(t),allocate (f))]] @@ -358,7 +362,15 @@ bar (int d, int m, int i1, int i2, int i3, int p, int *idp, int s, reduction(default, +:r),in_reduction(+:r2),allocate (f)))]] for (int i = 0; i < 64; i++) ll++; + [[using omp:sequence (directive (taskgroup, task_reduction (+:r2),allocate (r2)), + omp::directive (masked taskloop, + private (p),firstprivate (f),lastprivate (l),shared (s),default(shared),grainsize (g),collapse(1),untied, if(taskloop: i1),final(fi),mergeable, priority (pp), + reduction(default, +:r),in_reduction(+:r2),allocate (f),filter(d)))]] + for (int i = 0; i < 64; i++) + ll++; [[using omp:directive (master)]]; + [[using omp:directive (masked)]]; + [[using omp:directive (masked,filter(d))]]; [[omp::sequence (omp::directive (taskgroup task_reduction (+:r2),allocate (r2)), directive (master taskloop simd, private (p),firstprivate (f),lastprivate (l),shared (s),default(shared),grainsize (g),collapse(1),untied,if(taskloop: i1),if(simd: i2),final(fi),mergeable,priority (pp), @@ -366,23 +378,47 @@ bar (int d, int m, int i1, int i2, int i3, int p, int *idp, int s, order(concurrent),allocate (f)))]] for (int i = 0; i < 64; i++) ll++; + [[omp::sequence (omp::directive (taskgroup task_reduction (+:r2),allocate (r2)), + directive (masked taskloop simd, + private (p),firstprivate (f),lastprivate (l),shared (s),default(shared),grainsize (g),collapse(1),untied,if(taskloop: i1),if(simd: i2),final(fi),mergeable,priority (pp), + safelen(8),simdlen(4),linear(ll: 1),aligned(q: 32),reduction(default, +:r),in_reduction(+:r2),nontemporal(ntm), + order(concurrent),allocate (f),filter(d)))]] + for (int i = 0; i < 64; i++) + ll++; [[omp::directive (parallel master taskloop, private (p),firstprivate (f),lastprivate (l),shared (s),default(shared),grainsize (g),collapse(1),untied,if(taskloop: i1),final(fi),mergeable,priority (pp), reduction(default, +:r),if (parallel: i2),num_threads (nth),proc_bind(spread),copyin(t),allocate (f))]] for (int i = 0; i < 64; i++) ll++; + [[omp::directive (parallel masked taskloop, + private (p),firstprivate (f),lastprivate (l),shared (s),default(shared),grainsize (g),collapse(1),untied,if(taskloop: i1),final(fi),mergeable,priority (pp), + reduction(default, +:r),if (parallel: i2),num_threads (nth),proc_bind(spread),copyin(t),allocate (f),filter(d))]] + for (int i = 0; i < 64; i++) + ll++; [[omp::directive (parallel master taskloop simd, private (p),firstprivate (f),lastprivate (l),shared (s),default(shared),grainsize (g),collapse(1),untied,if(taskloop: i1),if(simd: i2),final(fi),mergeable,priority (pp), safelen(8),simdlen(4),linear(ll: 1),aligned(q: 32),reduction(default, +:r),nontemporal(ntm),if (parallel: i2),num_threads (nth),proc_bind(spread),copyin(t), order(concurrent),allocate (f))]] for (int i = 0; i < 64; i++) ll++; + [[omp::directive (parallel masked taskloop simd, + private (p),firstprivate (f),lastprivate (l),shared (s),default(shared),grainsize (g),collapse(1),untied,if(taskloop: i1),if(simd: i2),final(fi),mergeable,priority (pp), + safelen(8),simdlen(4),linear(ll: 1),aligned(q: 32),reduction(default, +:r),nontemporal(ntm),if (parallel: i2),num_threads (nth),proc_bind(spread),copyin(t), + order(concurrent),allocate (f),filter(d))]] + for (int i = 0; i < 64; i++) + ll++; [[omp::sequence (directive (taskgroup,task_reduction (+:r2),allocate (r2)), directive (master taskloop, private (p),firstprivate (f),lastprivate (l),shared (s),default(shared),num_tasks (nta),collapse(1),untied,if(i1),final(fi),mergeable,priority (pp), reduction(default, +:r),in_reduction(+:r2)))]] for (int i = 0; i < 64; i++) ll++; + [[omp::sequence (directive (taskgroup,task_reduction (+:r2),allocate (r2)), + directive (masked taskloop, + private (p),firstprivate (f),lastprivate (l),shared (s),default(shared),num_tasks (nta),collapse(1),untied,if(i1),final(fi),mergeable,priority (pp), + reduction(default, +:r),in_reduction(+:r2),filter(d)))]] + for (int i = 0; i < 64; i++) + ll++; [[omp::sequence (omp::directive (taskgroup,task_reduction (+:r2),allocate (r2)), omp::directive (master taskloop simd, private (p),firstprivate (f),lastprivate (l),shared (s),default(shared),num_tasks (nta),collapse(1),untied,if(i1),final(fi),mergeable,priority (pp), @@ -390,17 +426,35 @@ bar (int d, int m, int i1, int i2, int i3, int p, int *idp, int s, order(concurrent),allocate (f)))]] for (int i = 0; i < 64; i++) ll++; + [[omp::sequence (omp::directive (taskgroup,task_reduction (+:r2),allocate (r2)), + omp::directive (masked taskloop simd, + private (p),firstprivate (f),lastprivate (l),shared (s),default(shared),num_tasks (nta),collapse(1),untied,if(i1),final(fi),mergeable,priority (pp), + safelen(8),simdlen(4),linear(ll: 1),aligned(q: 32),reduction(default, +:r),in_reduction(+:r2),nontemporal(ntm), + order(concurrent),allocate (f),filter(d)))]] + for (int i = 0; i < 64; i++) + ll++; [[omp::directive (parallel master taskloop, private (p),firstprivate (f),lastprivate (l),shared (s),default(shared),num_tasks (nta),collapse(1),untied if(i1),final(fi),mergeable priority (pp), reduction(default, +:r),num_threads (nth),proc_bind(spread),copyin(t),allocate (f))]] for (int i = 0; i < 64; i++) ll++; + [[omp::directive (parallel masked taskloop, + private (p),firstprivate (f),lastprivate (l),shared (s),default(shared),num_tasks (nta),collapse(1),untied if(i1),final(fi),mergeable priority (pp), + reduction(default, +:r),num_threads (nth),proc_bind(spread),copyin(t),allocate (f),filter(d))]] + for (int i = 0; i < 64; i++) + ll++; [[omp::directive (parallel master taskloop simd, private (p),firstprivate (f),lastprivate (l),shared (s),default(shared),num_tasks (nta),collapse(1),untied if(i1),final(fi),mergeable priority (pp), safelen(8),simdlen(4),linear(ll: 1),aligned(q: 32),reduction(default, +:r),nontemporal(ntm),num_threads (nth),proc_bind(spread),copyin(t), order(concurrent),allocate (f))]] for (int i = 0; i < 64; i++) ll++; + [[omp::directive (parallel masked taskloop simd, + private (p),firstprivate (f),lastprivate (l),shared (s),default(shared),num_tasks (nta),collapse(1),untied if(i1),final(fi),mergeable priority (pp), + safelen(8),simdlen(4),linear(ll: 1),aligned(q: 32),reduction(default, +:r),nontemporal(ntm),num_threads (nth),proc_bind(spread),copyin(t), + order(concurrent),allocate (f),filter(d))]] + for (int i = 0; i < 64; i++) + ll++; [[omp::directive (loop, bind(thread),order(concurrent), private (p),lastprivate (l),collapse(1),reduction(+:r))]] for (l = 0; l < 64; ++l) diff --git a/gcc/testsuite/g++.dg/gomp/block-11.C b/gcc/testsuite/g++.dg/gomp/block-11.C index c280006..cf4b0d3 100644 --- a/gcc/testsuite/g++.dg/gomp/block-11.C +++ b/gcc/testsuite/g++.dg/gomp/block-11.C @@ -1,3 +1,21 @@ +// { dg-do compile } + +void foo() +{ + #pragma omp masked + { + goto bad1; // { dg-message "from here" } + } + + #pragma omp masked filter(1) + { + bad1: // { dg-error "jump" } + // { dg-message "exits OpenMP" "" { target *-*-* } .-1 } + return; // { dg-error "invalid exit" } + } +} + +// { dg-message "error: invalid branch to/from OpenMP structured block" "" { target *-*-* } 7 } /* PR c++/24516 */ /* { dg-do compile } */ diff --git a/gcc/testsuite/g++.dg/gomp/tpl-masked-1.C b/gcc/testsuite/g++.dg/gomp/tpl-masked-1.C new file mode 100644 index 0000000..8574861 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/tpl-masked-1.C @@ -0,0 +1,21 @@ +// { dg-do compile } +// { dg-options "-fopenmp -fdump-tree-gimple" } + +int i; + +template void f1 (bool p, T t) +{ + if (p) + { + #pragma omp masked filter (t) + i++; + } +} + +void f2 () +{ + f1 (true, 0); + f1 (true, 0L); +} + +// { dg-final { scan-tree-dump-times "#pragma omp masked" 2 "gimple" } } diff --git a/gcc/testsuite/gcc.dg/gomp/nesting-1.c b/gcc/testsuite/gcc.dg/gomp/nesting-1.c index 52fcda7..4a471c8 100644 --- a/gcc/testsuite/gcc.dg/gomp/nesting-1.c +++ b/gcc/testsuite/gcc.dg/gomp/nesting-1.c @@ -19,8 +19,10 @@ f1 (void) } #pragma omp single /* { dg-error "may not be closely nested" } */ ; - #pragma omp master /* { dg-error "may not be closely nested" } */ - ; + #pragma omp master /* { dg-error "may not be closely nested" } */ + ; + #pragma omp masked /* { dg-error "may not be closely nested" } */ + ; #pragma omp barrier /* { dg-error "may not be closely nested" } */ } #pragma omp sections @@ -50,6 +52,11 @@ f1 (void) } #pragma omp sections { + #pragma omp masked /* { dg-error "may not be closely nested" } */ + ; + } + #pragma omp sections + { #pragma omp section ; } @@ -81,6 +88,9 @@ f1 (void) #pragma omp section #pragma omp master /* { dg-error "may not be closely nested" } */ ; + #pragma omp section + #pragma omp masked /* { dg-error "may not be closely nested" } */ + ; } #pragma omp single { @@ -97,6 +107,8 @@ f1 (void) ; #pragma omp master /* { dg-error "may not be closely nested" } */ ; + #pragma omp masked /* { dg-error "may not be closely nested" } */ + ; #pragma omp barrier /* { dg-error "may not be closely nested" } */ } #pragma omp master @@ -116,6 +128,23 @@ f1 (void) ; #pragma omp barrier /* { dg-error "may not be closely nested" } */ } + #pragma omp masked filter (1) + { + #pragma omp for /* { dg-error "may not be closely nested" } */ + for (j = 0; j < 3; j++) + ; + #pragma omp sections /* { dg-error "may not be closely nested" } */ + { + ; + #pragma omp section + ; + } + #pragma omp single /* { dg-error "may not be closely nested" } */ + ; + #pragma omp master + ; + #pragma omp barrier /* { dg-error "may not be closely nested" } */ + } #pragma omp task { #pragma omp for /* { dg-error "may not be closely nested" } */ @@ -131,6 +160,8 @@ f1 (void) ; #pragma omp master /* { dg-error "may not be closely nested" } */ ; + #pragma omp masked /* { dg-error "may not be closely nested" } */ + ; #pragma omp barrier /* { dg-error "may not be closely nested" } */ } #pragma omp parallel @@ -148,6 +179,8 @@ f1 (void) ; #pragma omp master ; + #pragma omp masked + ; #pragma omp barrier } } @@ -171,6 +204,8 @@ f2 (void) ; #pragma omp master ; + #pragma omp masked + ; #pragma omp barrier /* { dg-error "may not be closely nested" } */ } } diff --git a/gcc/testsuite/gfortran.dg/goacc/host_data-tree.f95 b/gcc/testsuite/gfortran.dg/goacc/host_data-tree.f95 index 558e800..e575890 100644 --- a/gcc/testsuite/gfortran.dg/goacc/host_data-tree.f95 +++ b/gcc/testsuite/gfortran.dg/goacc/host_data-tree.f95 @@ -12,12 +12,12 @@ program test !$acc host_data use_device(p) if (p == 42) ! { dg-final { scan-tree-dump-times "(?n)D\\.\[0-9\]+ = \\*p == 42;$" 1 "original" } } ! { dg-final { scan-tree-dump-times "(?n)#pragma acc host_data use_device_ptr\\(p\\) if\\(D\\.\[0-9\]+\\)$" 1 "original" } } - ! { dg-final { scan-tree-dump-times "(?n)#pragma omp target oacc_host_data use_device_ptr\\(p\\) if\\(D\\.\[0-9\]+\\)$" 1 "gimple" } } + ! { dg-final { scan-tree-dump-times "(?n)#pragma omp target oacc_host_data use_device_ptr\\(p\\) if\\((?:D\\.|_)\[0-9\]+\\)$" 1 "gimple" } } !$acc end host_data !$acc host_data use_device(p) if_present if (p == 43) ! { dg-final { scan-tree-dump-times "(?n)D\\.\[0-9\]+ = \\*p == 43;$" 1 "original" } } ! { dg-final { scan-tree-dump-times "(?n)#pragma acc host_data use_device_ptr\\(p\\) if\\(D\\.\[0-9\]+\\) if_present$" 1 "original" } } - ! { dg-final { scan-tree-dump-times "(?n)#pragma omp target oacc_host_data use_device_ptr\\(if_present:p\\) if\\(D\\.\[0-9\]+\\) if_present$" 1 "gimple" } } + ! { dg-final { scan-tree-dump-times "(?n)#pragma omp target oacc_host_data use_device_ptr\\(if_present:p\\) if\\((?:D\\.|_)\[0-9\]+\\) if_present$" 1 "gimple" } } !$acc end host_data end program test diff --git a/gcc/testsuite/gfortran.dg/goacc/kernels-tree.f95 b/gcc/testsuite/gfortran.dg/goacc/kernels-tree.f95 index 63ef7e1..688ed0a 100644 --- a/gcc/testsuite/gfortran.dg/goacc/kernels-tree.f95 +++ b/gcc/testsuite/gfortran.dg/goacc/kernels-tree.f95 @@ -37,5 +37,5 @@ end program test ! { dg-final { scan-tree-dump-times "map\\(force_deviceptr:u\\)" 1 "original" } } -! { dg-final { scan-tree-dump-times {(?n)#pragma omp target oacc_data_kernels if\(D\.[0-9]+\)$} 1 "omp_oacc_kernels_decompose" } } -! { dg-final { scan-tree-dump-times {(?n)#pragma omp target oacc_parallel_kernels_gang_single num_gangs\(1\) if\(D\.[0-9]+\) async\(-1\)$} 1 "omp_oacc_kernels_decompose" } } +! { dg-final { scan-tree-dump-times {(?n)#pragma omp target oacc_data_kernels if\((?:D\.|_)[0-9]+\)$} 1 "omp_oacc_kernels_decompose" } } +! { dg-final { scan-tree-dump-times {(?n)#pragma omp target oacc_parallel_kernels_gang_single num_gangs\(1\) if\((?:D\.|_)[0-9]+\) async\(-1\)$} 1 "omp_oacc_kernels_decompose" } } diff --git a/gcc/tree-core.h b/gcc/tree-core.h index 9a1aa9a..9e901ce 100644 --- a/gcc/tree-core.h +++ b/gcc/tree-core.h @@ -476,6 +476,9 @@ enum omp_clause_code { /* OpenMP clause: bind (binding). */ OMP_CLAUSE_BIND, + /* OpenMP clause: filter (integer-expression). */ + OMP_CLAUSE_FILTER, + /* Internally used only clause, holding SIMD uid. */ OMP_CLAUSE__SIMDUID_, diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c index 8e6cdd3..4ba48e0 100644 --- a/gcc/tree-inline.c +++ b/gcc/tree-inline.c @@ -1658,6 +1658,12 @@ remap_gimple_stmt (gimple *stmt, copy_body_data *id) copy = gimple_build_omp_master (s1); break; + case GIMPLE_OMP_MASKED: + s1 = remap_gimple_seq (gimple_omp_body (stmt), id); + copy = gimple_build_omp_masked + (s1, gimple_omp_masked_clauses (stmt)); + break; + case GIMPLE_OMP_TASKGROUP: s1 = remap_gimple_seq (gimple_omp_body (stmt), id); copy = gimple_build_omp_taskgroup @@ -4544,6 +4550,7 @@ estimate_num_insns (gimple *stmt, eni_weights *weights) case GIMPLE_OMP_TASK: case GIMPLE_OMP_CRITICAL: case GIMPLE_OMP_MASTER: + case GIMPLE_OMP_MASKED: case GIMPLE_OMP_TASKGROUP: case GIMPLE_OMP_ORDERED: case GIMPLE_OMP_SCAN: diff --git a/gcc/tree-nested.c b/gcc/tree-nested.c index cc59526..d2b3969 100644 --- a/gcc/tree-nested.c +++ b/gcc/tree-nested.c @@ -1376,6 +1376,7 @@ convert_nonlocal_omp_clauses (tree *pclauses, struct walk_stmt_info *wi) case OMP_CLAUSE_GRAINSIZE: case OMP_CLAUSE_NUM_TASKS: case OMP_CLAUSE_HINT: + case OMP_CLAUSE_FILTER: case OMP_CLAUSE_NUM_GANGS: case OMP_CLAUSE_NUM_WORKERS: case OMP_CLAUSE_VECTOR_LENGTH: @@ -1785,6 +1786,7 @@ convert_nonlocal_reference_stmt (gimple_stmt_iterator *gsi, bool *handled_ops_p, case GIMPLE_OMP_SECTION: case GIMPLE_OMP_MASTER: + case GIMPLE_OMP_MASKED: case GIMPLE_OMP_ORDERED: case GIMPLE_OMP_SCAN: walk_body (convert_nonlocal_reference_stmt, convert_nonlocal_reference_op, @@ -2154,6 +2156,7 @@ convert_local_omp_clauses (tree *pclauses, struct walk_stmt_info *wi) case OMP_CLAUSE_GRAINSIZE: case OMP_CLAUSE_NUM_TASKS: case OMP_CLAUSE_HINT: + case OMP_CLAUSE_FILTER: case OMP_CLAUSE_NUM_GANGS: case OMP_CLAUSE_NUM_WORKERS: case OMP_CLAUSE_VECTOR_LENGTH: @@ -2518,6 +2521,7 @@ convert_local_reference_stmt (gimple_stmt_iterator *gsi, bool *handled_ops_p, case GIMPLE_OMP_SECTION: case GIMPLE_OMP_MASTER: + case GIMPLE_OMP_MASKED: case GIMPLE_OMP_ORDERED: case GIMPLE_OMP_SCAN: walk_body (convert_local_reference_stmt, convert_local_reference_op, @@ -3028,6 +3032,7 @@ convert_gimple_call (gimple_stmt_iterator *gsi, bool *handled_ops_p, case GIMPLE_OMP_SECTION: case GIMPLE_OMP_SINGLE: case GIMPLE_OMP_MASTER: + case GIMPLE_OMP_MASKED: case GIMPLE_OMP_TASKGROUP: case GIMPLE_OMP_ORDERED: case GIMPLE_OMP_SCAN: diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c index 31f886f..5ac4034 100644 --- a/gcc/tree-pretty-print.c +++ b/gcc/tree-pretty-print.c @@ -1085,6 +1085,13 @@ dump_omp_clause (pretty_printer *pp, tree clause, int spc, dump_flags_t flags) pp_right_paren (pp); break; + case OMP_CLAUSE_FILTER: + pp_string (pp, "filter("); + dump_generic_node (pp, OMP_CLAUSE_FILTER_EXPR (clause), + spc, flags, false); + pp_right_paren (pp); + break; + case OMP_CLAUSE_DEFAULTMAP: pp_string (pp, "defaultmap("); switch (OMP_CLAUSE_DEFAULTMAP_BEHAVIOR (clause)) @@ -3586,6 +3593,11 @@ dump_generic_node (pretty_printer *pp, tree node, int spc, dump_flags_t flags, pp_string (pp, "#pragma omp master"); goto dump_omp_body; + case OMP_MASKED: + pp_string (pp, "#pragma omp masked"); + dump_omp_clauses (pp, OMP_MASKED_CLAUSES (node), spc, flags); + goto dump_omp_body; + case OMP_TASKGROUP: pp_string (pp, "#pragma omp taskgroup"); dump_omp_clauses (pp, OMP_TASKGROUP_CLAUSES (node), spc, flags); diff --git a/gcc/tree.c b/gcc/tree.c index e923e67..a0ff794 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -350,6 +350,7 @@ unsigned const char omp_clause_num_ops[] = 0, /* OMP_CLAUSE_DEFAULTMAP */ 0, /* OMP_CLAUSE_ORDER */ 0, /* OMP_CLAUSE_BIND */ + 1, /* OMP_CLAUSE_FILTER */ 1, /* OMP_CLAUSE__SIMDUID_ */ 0, /* OMP_CLAUSE__SIMT_ */ 0, /* OMP_CLAUSE_INDEPENDENT */ @@ -438,6 +439,7 @@ const char * const omp_clause_code_name[] = "defaultmap", "order", "bind", + "filter", "_simduid_", "_simt_", "independent", @@ -11126,6 +11128,7 @@ walk_tree_1 (tree *tp, walk_tree_fn func, void *data, case OMP_CLAUSE_GRAINSIZE: case OMP_CLAUSE_NUM_TASKS: case OMP_CLAUSE_HINT: + case OMP_CLAUSE_FILTER: case OMP_CLAUSE_TO_DECLARE: case OMP_CLAUSE_LINK: case OMP_CLAUSE_DETACH: diff --git a/gcc/tree.def b/gcc/tree.def index eda050b..ff8b5e6 100644 --- a/gcc/tree.def +++ b/gcc/tree.def @@ -1218,6 +1218,11 @@ DEFTREECODE (OMP_SINGLE, "omp_single", tcc_statement, 2) Operand 1: OMP_SINGLE_CLAUSES: List of clauses. */ DEFTREECODE (OMP_TASKGROUP, "omp_taskgroup", tcc_statement, 2) +/* OpenMP - #pragma omp masked + Operand 0: OMP_MASKED_BODY: Masked section body. + Operand 1: OMP_MASKED_CLAUSES: List of clauses. */ +DEFTREECODE (OMP_MASKED, "omp_masked", tcc_statement, 2) + /* OpenMP - #pragma omp scan Operand 0: OMP_SCAN_BODY: Scan body. Operand 1: OMP_SCAN_CLAUSES: List of clauses. */ diff --git a/gcc/tree.h b/gcc/tree.h index 972ceb3..c3f302a 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -1429,6 +1429,9 @@ class auto_suppress_location_wrappers #define OMP_MASTER_BODY(NODE) TREE_OPERAND (OMP_MASTER_CHECK (NODE), 0) +#define OMP_MASKED_BODY(NODE) TREE_OPERAND (OMP_MASKED_CHECK (NODE), 0) +#define OMP_MASKED_CLAUSES(NODE) TREE_OPERAND (OMP_MASKED_CHECK (NODE), 1) + #define OMP_TASKGROUP_BODY(NODE) TREE_OPERAND (OMP_TASKGROUP_CHECK (NODE), 0) #define OMP_TASKGROUP_CLAUSES(NODE) \ TREE_OPERAND (OMP_TASKGROUP_CHECK (NODE), 1) @@ -1508,6 +1511,11 @@ class auto_suppress_location_wrappers #define OMP_MASTER_COMBINED(NODE) \ (OMP_MASTER_CHECK (NODE)->base.private_flag) +/* True on an OMP_MASKED statement if it represents an explicit + combined masked constructs. */ +#define OMP_MASKED_COMBINED(NODE) \ + (OMP_MASKED_CHECK (NODE)->base.private_flag) + /* Memory order for OMP_ATOMIC*. */ #define OMP_ATOMIC_MEMORY_ORDER(NODE) \ (TREE_RANGE_CHECK (NODE, OMP_ATOMIC, \ @@ -1592,6 +1600,8 @@ class auto_suppress_location_wrappers OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_NUM_TASKS), 0) #define OMP_CLAUSE_HINT_EXPR(NODE) \ OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_HINT), 0) +#define OMP_CLAUSE_FILTER_EXPR(NODE) \ + OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_FILTER), 0) #define OMP_CLAUSE_GRAINSIZE_EXPR(NODE) \ OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_GRAINSIZE),0) -- cgit v1.1 From 1196b60f8fc5a169e01ac859712013a4d3d8de96 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Fri, 6 Aug 2021 18:04:43 -0700 Subject: compiler: store pointers to go:notinheap types indirectly This is the gofrontend version of https://golang.org/cl/264480. For golang/go#42076 Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/340609 --- gcc/go/gofrontend/MERGE | 2 +- gcc/go/gofrontend/expressions.cc | 30 ++++++++++++---- gcc/go/gofrontend/types.cc | 75 +++++++++++++++++++++++++++++++++++----- gcc/go/gofrontend/types.h | 3 +- 4 files changed, 92 insertions(+), 18 deletions(-) (limited to 'gcc') diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index be092de..539d886 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -7e092d2cc5af7648036496485b639f2c9db2f2d8 +5edbb624b2595d644eb6842c952a292c41f7d6fa The first line of this file holds the git revision number of the last merge done from the gofrontend repository. diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index 67917da..8d4d168 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -408,7 +408,14 @@ Expression::convert_type_to_interface(Type* lhs_type, Expression* rhs, { // We are assigning a non-pointer value to the interface; the // interface gets a copy of the value in the heap if it escapes. - if (rhs->is_constant()) + + // An exception is &global if global is notinheap, which is a + // pointer value but not a direct-iface type and we can't simply + // take its address. + bool is_address = (rhs->unary_expression() != NULL + && rhs->unary_expression()->op() == OPERATOR_AND); + + if (rhs->is_constant() && !is_address) obj = Expression::make_unary(OPERATOR_AND, rhs, location); else { @@ -11331,6 +11338,7 @@ Call_expression::do_lower(Gogo* gogo, Named_object* function, // We always pass a pointer when calling a method, except for // direct interface types when calling a value method. if (!first_arg->type()->is_error() + && first_arg->type()->points_to() == NULL && !first_arg->type()->is_direct_iface_type()) { first_arg = Expression::make_unary(OPERATOR_AND, first_arg, loc); @@ -18630,12 +18638,20 @@ Interface_mtable_expression::do_get_backend(Translate_context* context) else m = st->method_function(p->name(), &is_ambiguous); go_assert(m != NULL); - Named_object* no = - (this->is_pointer_ - && this->type_->is_direct_iface_type() - && m->is_value_method() - ? m->iface_stub_object() - : m->named_object()); + + // See the comment in Type::method_constructor. + bool use_direct_iface_stub = false; + if (m->is_value_method() + && this->is_pointer_ + && this->type_->is_direct_iface_type()) + use_direct_iface_stub = true; + if (!m->is_value_method() + && this->is_pointer_ + && !this->type_->in_heap()) + use_direct_iface_stub = true; + Named_object* no = (use_direct_iface_stub + ? m->iface_stub_object() + : m->named_object()); go_assert(no->is_function() || no->is_function_declaration()); diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc index 0c44186..e76600d 100644 --- a/gcc/go/gofrontend/types.cc +++ b/gcc/go/gofrontend/types.cc @@ -2464,8 +2464,16 @@ Type::is_direct_iface_type() const bool Type::is_direct_iface_type_helper(Unordered_set(const Type*)* visited) const { - if (this->points_to() != NULL - || this->channel_type() != NULL + if (this->points_to() != NULL) + { + // Pointers to notinheap types must be stored indirectly. See + // https://golang.org/issue/42076. + if (!this->points_to()->in_heap()) + return false; + return true; + } + + if (this->channel_type() != NULL || this->function_type() != NULL || this->map_type() != NULL) return true; @@ -3597,10 +3605,36 @@ Type::method_constructor(Gogo*, Type* method_type, vals->push_back(Expression::make_unary(OPERATOR_AND, s, bloc)); } - bool use_direct_iface_stub = - this->points_to() != NULL - && this->points_to()->is_direct_iface_type() - && m->is_value_method(); + // The direct_iface_stub dereferences the value stored in the + // interface when calling the method. + // + // We need this for a value method if this type is a pointer to a + // direct-iface type. For example, if we have "type C chan int" and M + // is a value method on C, then since a channel is a direct-iface type + // M expects a value of type C. We are generating the method table + // for *C, so the value stored in the interface is *C. We have to + // call the direct-iface stub to dereference *C to get C to pass to M. + // + // We also need this for a pointer method if the pointer itself is not + // a direct-iface type, as arises for notinheap types. In this case + // we have "type NIH ..." where NIH is go:notinheap. Since NIH is + // notinheap, *NIH is a pointer type that is not a direct-iface type, + // so the value stored in the interface is actually **NIH. The method + // expects *NIH, so we have to call the direct-iface stub to + // dereference **NIH to get *NIH to pass to M. (This case doesn't + // arise for value methods because pointer types can't have methods, + // so there is no such thing as a value method for type *NIH.) + + bool use_direct_iface_stub = false; + if (m->is_value_method() + && this->points_to() != NULL + && this->points_to()->is_direct_iface_type()) + use_direct_iface_stub = true; + if (!m->is_value_method() + && this->points_to() != NULL + && !this->is_direct_iface_type()) + use_direct_iface_stub = true; + Named_object* no = (use_direct_iface_stub ? m->iface_stub_object() : (m->needs_stub_method() @@ -10902,6 +10936,20 @@ Named_type::do_needs_key_update() return ret; } +// Return whether this type is permitted in the heap. +bool +Named_type::do_in_heap() const +{ + if (!this->in_heap_) + return false; + if (this->seen_) + return true; + this->seen_ = true; + bool ret = this->type_->in_heap(); + this->seen_ = false; + return ret; +} + // Return a hash code. This is used for method lookup. We simply // hash on the name itself. @@ -11434,7 +11482,7 @@ Type::finalize_methods(Gogo* gogo, const Type* type, Location location, *all_methods = NULL; } Type::build_stub_methods(gogo, type, *all_methods, location); - if (type->is_direct_iface_type()) + if (type->is_direct_iface_type() || !type->in_heap()) Type::build_direct_iface_stub_methods(gogo, type, *all_methods, location); } @@ -11814,12 +11862,23 @@ Type::build_direct_iface_stub_methods(Gogo* gogo, const Type* type, if (methods == NULL) return; + bool is_direct_iface = type->is_direct_iface_type(); + bool in_heap = type->in_heap(); for (Methods::const_iterator p = methods->begin(); p != methods->end(); ++p) { Method* m = p->second; - if (!m->is_value_method()) + + // We need a direct-iface stub for a value method for a + // direct-iface type, and for a pointer method for a not-in-heap + // type. + bool need_stub = false; + if (is_direct_iface && m->is_value_method()) + need_stub = true; + if (!in_heap && !m->is_value_method()) + need_stub = true; + if (!need_stub) continue; Type* receiver_type = const_cast(type); diff --git a/gcc/go/gofrontend/types.h b/gcc/go/gofrontend/types.h index f2880f9..ca1ab49 100644 --- a/gcc/go/gofrontend/types.h +++ b/gcc/go/gofrontend/types.h @@ -3605,8 +3605,7 @@ class Named_type : public Type do_needs_key_update(); bool - do_in_heap() const - { return this->in_heap_ && this->type_->in_heap(); } + do_in_heap() const; unsigned int do_hash_for_method(Gogo*, int) const; -- cgit v1.1 From 72be20e20299ec57b4bc9ba03d5b7d6bf10e97cc Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Fri, 13 Aug 2021 00:16:43 +0000 Subject: Daily bump. --- gcc/ChangeLog | 145 ++++++++++++++++++++++++++++++++++++++++++++++++ gcc/DATESTAMP | 2 +- gcc/c-family/ChangeLog | 11 ++++ gcc/c/ChangeLog | 23 ++++++++ gcc/cp/ChangeLog | 81 +++++++++++++++++++++++++++ gcc/fortran/ChangeLog | 12 ++++ gcc/testsuite/ChangeLog | 119 +++++++++++++++++++++++++++++++++++++++ 7 files changed, 392 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 31f7659..f26544f 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,148 @@ +2021-08-12 Jakub Jelinek + + * tree.def (OMP_MASKED): New tree code. + * tree-core.h (enum omp_clause_code): Add OMP_CLAUSE_FILTER. + * tree.h (OMP_MASKED_BODY, OMP_MASKED_CLAUSES, OMP_MASKED_COMBINED, + OMP_CLAUSE_FILTER_EXPR): Define. + * tree.c (omp_clause_num_ops): Add OMP_CLAUSE_FILTER entry. + (omp_clause_code_name): Likewise. + (walk_tree_1): Handle OMP_CLAUSE_FILTER. + * tree-nested.c (convert_nonlocal_omp_clauses, + convert_local_omp_clauses): Handle OMP_CLAUSE_FILTER. + (convert_nonlocal_reference_stmt, convert_local_reference_stmt, + convert_gimple_call): Handle GIMPLE_OMP_MASTER. + * tree-pretty-print.c (dump_omp_clause): Handle OMP_CLAUSE_FILTER. + (dump_generic_node): Handle OMP_MASTER. + * gimple.def (GIMPLE_OMP_MASKED): New gimple code. + * gimple.c (gimple_build_omp_masked): New function. + (gimple_copy): Handle GIMPLE_OMP_MASKED. + * gimple.h (gimple_build_omp_masked): Declare. + (gimple_has_substatements): Handle GIMPLE_OMP_MASKED. + (gimple_omp_masked_clauses, gimple_omp_masked_clauses_ptr, + gimple_omp_masked_set_clauses): New inline functions. + (CASE_GIMPLE_OMP): Add GIMPLE_OMP_MASKED. + * gimple-pretty-print.c (dump_gimple_omp_masked): New function. + (pp_gimple_stmt_1): Handle GIMPLE_OMP_MASKED. + * gimple-walk.c (walk_gimple_stmt): Likewise. + * gimple-low.c (lower_stmt): Likewise. + * gimplify.c (is_gimple_stmt): Handle OMP_MASTER. + (gimplify_scan_omp_clauses): Handle OMP_CLAUSE_FILTER. For clauses + that take one expression rather than decl or constant, force + gimplification of that into a SSA_NAME or temporary unless min + invariant. + (gimplify_adjust_omp_clauses): Handle OMP_CLAUSE_FILTER. + (gimplify_expr): Handle OMP_MASKED. + * tree-inline.c (remap_gimple_stmt): Handle GIMPLE_OMP_MASKED. + (estimate_num_insns): Likewise. + * omp-low.c (scan_sharing_clauses): Handle OMP_CLAUSE_FILTER. + (check_omp_nesting_restrictions): Handle GIMPLE_OMP_MASKED. Adjust + diagnostics for existence of masked construct. + (scan_omp_1_stmt, lower_omp_master, lower_omp_1, diagnose_sb_1, + diagnose_sb_2): Handle GIMPLE_OMP_MASKED. + * omp-expand.c (expand_omp_synch, expand_omp, omp_make_gimple_edges): + Likewise. + +2021-08-12 UroÅ¡ Bizjak + + PR target/98309 + * config/i386/i386.md (avx512f_scalef2): New insn pattern. + (ldexp3): Use avx512f_scalef2. + (UNSPEC_SCALEF): Move from ... + * config/i386/sse.md (UNSPEC_SCALEF): ... here. + +2021-08-12 Jan Hubicka + + * ipa-split.c (consider_split): Fix condition testing void functions. + +2021-08-12 Aldy Hernandez + + * doc/invoke.texi: Remove docs for threader-mode param. + * flag-types.h (enum threader_mode): Remove. + * params.opt: Remove threader-mode param. + * tree-ssa-threadbackward.c (class back_threader): Remove + path_is_unreachable_p. + Make find_paths private. + Add maybe_thread and thread_through_all_blocks. + Remove reference marker for m_registry. + Remove reference marker for m_profit. + (back_threader::back_threader): Adjust for registry and profit not + being references. + (dump_path): Move down. + (debug): Move down. + (class thread_jumps): Remove. + (class back_threader_registry): Remove m_all_paths. + Remove destructor. + (thread_jumps::thread_through_all_blocks): Move to back_threader + class. + (fsm_find_thread_path): Remove + (back_threader::maybe_thread): New. + (back_threader::thread_through_all_blocks): Move from + thread_jumps. + (back_threader_registry::back_threader_registry): Remove + m_all_paths. + (back_threader_registry::~back_threader_registry): Remove. + (thread_jumps::find_taken_edge): Remove. + (thread_jumps::check_subpath_and_update_thread_path): Remove. + (thread_jumps::maybe_register_path): Remove. + (thread_jumps::handle_phi): Remove. + (handle_assignment_p): Remove. + (thread_jumps::handle_assignment): Remove. + (thread_jumps::fsm_find_control_statement_thread_paths): Remove. + (thread_jumps::find_jump_threads_backwards): Remove. + (thread_jumps::find_jump_threads_backwards_with_ranger): Remove. + (try_thread_blocks): Rename find_jump_threads_backwards to + maybe_thread. + (pass_early_thread_jumps::execute): Same. + +2021-08-12 Tobias Burnus + + * tree-core.h (omp_clause_proc_bind_kind): Add + OMP_CLAUSE_PROC_BIND_PRIMARY. + * tree-pretty-print.c (dump_omp_clause): Add TODO comment to + change 'master' to 'primary' in proc_bind for OpenMP 5.1. + +2021-08-12 Claudiu Zissulescu + + * common/config/arc/arc-common.c (arc_option_init_struct): Remove + fno-common reference. + * config/arc/arc.c (arc_override_options): Remove overriding of + flag_no_common. + +2021-08-12 Jakub Jelinek + + PR target/101860 + * config/i386/i386-expand.c (ix86_expand_vec_one_operand_perm_avx512): + If d->testing_p, return true after performing checks instead of + actually expanding the insn. + (expand_vec_perm_broadcast_1): Handle V32HImode - assert + !TARGET_AVX512BW and return false. + +2021-08-12 Eric Botcazou + + * configure.ac (PE linker --disable-dynamicbase support): New check. + * configure: Regenerate. + * config.in: Likewise. + * config/i386/mingw32.h (LINK_SPEC_DISABLE_DYNAMICBASE): New define. + (LINK_SPEC): Use it. + * config/i386/mingw-w64.h (LINK_SPEC_DISABLE_DYNAMICBASE): Likewise. + (LINK_SPEC): Likewise. + +2021-08-12 liuhongt + + PR target/101846 + * config/i386/sse.md (*avx2_zero_extendv16qiv16hi2_2): New + post_reload define_insn_and_split. + (*avx512bw_zero_extendv32qiv32hi2_2): Ditto. + (*sse4_1_zero_extendv8qiv8hi2_4): Ditto. + (*avx512f_zero_extendv16hiv16si2_2): Ditto. + (*avx2_zero_extendv8hiv8si2_2): Ditto. + (*sse4_1_zero_extendv4hiv4si2_4): Ditto. + (*avx512f_zero_extendv8siv8di2_2): Ditto. + (*avx2_zero_extendv4siv4di2_2): Ditto. + (*sse4_1_zero_extendv2siv2di2_4): Ditto. + (VI248_256, VI248_512, VI148_512, VI148_256, VI148_128): New + mode iterator. + 2021-08-11 Bill Schmidt * config/rs6000/rs6000-builtin-new.def: Add always, power5, and diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index cffca64..3f3eb1e 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20210812 +20210813 diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index 7306b36..9d0868d 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,14 @@ +2021-08-12 Jakub Jelinek + + * c-pragma.h (enum pragma_kind): Add PRAGMA_OMP_MASKED. + (enum pragma_omp_clause): Add PRAGMA_OMP_CLAUSE_FILTER. + * c-pragma.c (omp_pragmas_simd): Add masked construct. + * c-common.h (enum c_omp_clause_split): Add C_OMP_CLAUSE_SPLIT_MASKED + enumerator. + (c_finish_omp_masked): Declare. + * c-omp.c (c_finish_omp_masked): New function. + (c_omp_split_clauses): Handle combined masked constructs. + 2021-07-30 Jakub Jelinek PR c++/101539 diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index 74ab186..ab61ac0 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,26 @@ +2021-08-12 Jakub Jelinek + + * c-parser.c (c_parser_omp_clause_name): Parse filter clause name. + (c_parser_omp_clause_filter): New function. + (c_parser_omp_all_clauses): Handle PRAGMA_OMP_CLAUSE_FILTER. + (OMP_MASKED_CLAUSE_MASK): Define. + (c_parser_omp_masked): New function. + (c_parser_omp_parallel): Handle parallel masked. + (c_parser_omp_construct): Handle PRAGMA_OMP_MASKED. + * c-typeck.c (c_finish_omp_clauses): Handle OMP_CLAUSE_FILTER. + +2021-08-12 Martin Uecker + + PR c/101838 + PR c/29970 + * c-typeck.c (c_expr_sizeof_type): Evaluate + size expressions for structs of variable size. + +2021-08-12 Tobias Burnus + + * c-parser.c (c_parser_omp_clause_proc_bind): Accept + 'primary' as alias for 'master'. + 2021-08-10 Martin Uecker PR c/29970 diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index fd4aa6e..7a4a707 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,84 @@ +2021-08-12 Jakub Jelinek + + * parser.c (cp_parser_omp_clause_name): Parse filter clause name. + (cp_parser_omp_clause_filter): New function. + (cp_parser_omp_all_clauses): Handle PRAGMA_OMP_CLAUSE_FILTER. + (OMP_MASKED_CLAUSE_MASK): Define. + (cp_parser_omp_masked): New function. + (cp_parser_omp_parallel): Handle parallel masked. + (cp_parser_omp_construct, cp_parser_pragma): Handle PRAGMA_OMP_MASKED. + * semantics.c (finish_omp_clauses): Handle OMP_CLAUSE_FILTER. + * pt.c (tsubst_omp_clauses): Likewise. + (tsubst_expr): Handle OMP_MASKED. + +2021-08-12 Sergei Trofimovich + + PR c++/101219 + * pt.c (tsubst_copy_and_build): Use build_ptrmemfunc_access_expr + to construct ptrmemfunc expression instantiation. + +2021-08-12 Tobias Burnus + + * parser.c (cp_parser_omp_clause_proc_bind): Accept + 'primary' as alias for 'master'. + +2021-08-12 Jakub Jelinek + + * cp-tree.h (omp_declare_target_attr): New type. + (struct saved_scope): Change type of omp_declare_target_attribute + from int to vec * and move it. + * parser.c (cp_parser_omp_declare_target): Instead of + incrementing scope_chain->omp_declare_target_attribute, push + a struct containing parser->lexer->in_omp_attribute_pragma to + the vector. + (cp_parser_omp_end_declare_target): Instead of decrementing + scope_chain->omp_declare_target_attribute, pop a structure + from it. Diagnose mismatching declare target vs. + end declare target syntax. + * semantics.c (finish_translation_unit): Use vec_safe_length + and vec_safe_truncate on scope_chain->omp_declare_target_attributes. + * decl2.c (cplus_decl_attributes): Use vec_safe_length + on scope_chain->omp_declare_target_attributes. + +2021-08-12 Jakub Jelinek + + * parser.c (cp_parser_lambda_body): Add temp overrides + for parser->{omp_declare_simd,oacc_routine,omp_attrs_forbidden_p}. + (cp_parser_statement): Restore parser->omp_attrs_forbidden_p for + cp_parser_declaration_statement. + (cp_parser_default_argument): Add temp override for + parser->omp_attrs_forbidden_p. + (cp_parser_late_parsing_omp_declare_simd): Diagnose declare simd + or declare variant in attribute syntax on a declaration immediately + following an OpenMP construct in pragma syntax. + +2021-08-12 Jakub Jelinek + + PR c++/94162 + * method.c (cat_tag_for): Return cc_last for !CLASS_TYPE_P + or for classes not in std namespace. + +2021-08-12 Jakub Jelinek + + * name-lookup.c (finish_using_directive): Diagnose omp::directive + or omp::sequence attributes on using-directive. + +2021-08-12 Jakub Jelinek + + * parser.c (cp_parser_block_declaration): Call + cp_parser_using_directive for C++11 attributes followed by + using namespace tokens. + (cp_parser_using_directive): Parse C++11 attributes at the start + of the directive rather than at the end, only parse GNU attributes + at the end. + +2021-08-12 Patrick Palka + + PR c++/101663 + * constexpr.c (cxx_eval_store_expression): Handle the lval=true + case in the early exit code path for empty stores with mismatched + types. + 2021-08-11 Patrick Palka PR c++/101725 diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index 5f9623b..7e1db26 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,15 @@ +2021-08-12 Tobias Burnus + + * gfortran.h (gfc_omp_proc_bind_kind): Add OMP_PROC_BIND_PRIMARY. + * dump-parse-tree.c (show_omp_clauses): Add TODO comment to + change 'master' to 'primary' in proc_bind for OpenMP 5.1. + * intrinsic.texi (OMP_LIB): Mention OpenMP 5.1; add + omp_proc_bind_primary. + * openmp.c (gfc_match_omp_clauses): Accept + 'primary' as alias for 'master'. + * trans-openmp.c (gfc_trans_omp_clauses): Handle + OMP_PROC_BIND_PRIMARY. + 2021-08-11 Sandra Loosemore * iso-c-binding.def (c_float128, c_float128_complex): Check diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index eaae083..6ee775a 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,122 @@ +2021-08-12 Jakub Jelinek + + * c-c++-common/gomp/clauses-1.c (bar): Add tests for combined masked + constructs with clauses. + * c-c++-common/gomp/clauses-5.c (foo): Add testcase for filter clause. + * c-c++-common/gomp/clause-dups-1.c (f1): Likewise. + * c-c++-common/gomp/masked-1.c: New test. + * c-c++-common/gomp/masked-2.c: New test. + * c-c++-common/gomp/masked-combined-1.c: New test. + * c-c++-common/gomp/masked-combined-2.c: New test. + * c-c++-common/goacc/uninit-if-clause.c: Remove xfails. + * g++.dg/gomp/block-11.C: New test. + * g++.dg/gomp/tpl-masked-1.C: New test. + * g++.dg/gomp/attrs-1.C (bar): Add tests for masked construct and + combined masked constructs with clauses in attribute syntax. + * g++.dg/gomp/attrs-2.C (bar): Likewise. + * gcc.dg/gomp/nesting-1.c (f1, f2): Add tests for masked construct + nesting. + * gfortran.dg/goacc/host_data-tree.f95: Allow also SSA_NAMEs in if + clause. + * gfortran.dg/goacc/kernels-tree.f95: Likewise. + +2021-08-12 Jakub Jelinek + + PR preprocessor/101638 + * gcc.dg/cpp/pr101638.c: New test. + +2021-08-12 Michael Meissner + + * gcc.target/powerpc/fold-vec-load-builtin_vec_xl-char.c: Fix + typo in regular expression. + * gcc.target/powerpc/fold-vec-load-builtin_vec_xl-double.c: + Likewise. + * gcc.target/powerpc/fold-vec-load-builtin_vec_xl-float.c: + Likewise. + * gcc.target/powerpc/fold-vec-load-builtin_vec_xl-int.c: + Likewise. + * gcc.target/powerpc/fold-vec-load-builtin_vec_xl-longlong.c: + Likewise. + * gcc.target/powerpc/fold-vec-load-builtin_vec_xl-short.c: + Likewise. + +2021-08-12 Sergei Trofimovich + + PR c++/101219 + * g++.dg/warn/pr101219.C: New test. + +2021-08-12 Martin Uecker + + PR c/101838 + * gcc.dg/vla-stexp-2.c: New test. + +2021-08-12 Aldy Hernandez + + * gcc.dg/tree-ssa/ssa-dom-thread-7.c: Remove call into the legacy + code and adjust for ranger threader. + +2021-08-12 Tobias Burnus + + * c-c++-common/gomp/pr61486-2.c: Duplicate one proc_bind(master) + testcase and test proc_bind(primary) instead. + * gfortran.dg/gomp/affinity-1.f90: Likewise. + +2021-08-12 Hans-Peter Nilsson + + * gfortran.dg/PR82376.f90: Robustify match. + +2021-08-12 Jakub Jelinek + + PR target/101860 + * gcc.target/i386/avx512f-pr101860.c: New test. + +2021-08-12 Jakub Jelinek + + * g++.dg/gomp/attrs-12.C: New test. + +2021-08-12 Jakub Jelinek + + * g++.dg/gomp/attrs-11.C: Add new tests. + +2021-08-12 Jakub Jelinek + + PR c++/99429 + PR c++/94162 + * g++.dg/cpp2a/spaceship-synth11.C: New test. + * g++.dg/cpp2a/spaceship-synth-neg6.C: New test. + +2021-08-12 Jakub Jelinek + + * g++.dg/gomp/attrs-11.C: Adjust expected diagnostics. + +2021-08-12 Jakub Jelinek + + * g++.dg/lookup/strong-using.C: Add test using [[gnu::strong]] + as well. + * g++.dg/lookup/strong-using2.C: Likewise. + * g++.dg/cpp0x/gen-attrs-58.C: Move alignas(int) before + using namespace. + * g++.dg/cpp0x/gen-attrs-59.C: Move alignas(X) before + using namespace, add tests for alignas before semicolon. + * g++.dg/cpp0x/gen-attrs-76.C: Remove xfails. Add test for + C++11 attributes on using directive before semicolon. + +2021-08-12 liuhongt + + PR target/101846 + * gcc.target/i386/pr101846-1.c: New test. + +2021-08-12 Patrick Palka + + PR c++/101663 + * g++.dg/cpp2a/construct_at.h: New convenience header file that + defines minimal implementations of std::construct_at/destroy_at, + split out from ... + * g++.dg/cpp2a/constexpr-new5.C: ... here. + * g++.dg/cpp2a/constexpr-new6.C: Use the header. + * g++.dg/cpp2a/constexpr-new14.C: Likewise. + * g++.dg/cpp2a/constexpr-new20.C: New test. + 2021-08-11 Patrick Palka PR c++/101725 -- cgit v1.1 From c5b21c3f4c17b0649155035d2f9aa97b2da8a813 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Fri, 30 Jul 2021 14:28:58 -0700 Subject: libgo: update to Go1.17rc2 Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/341629 --- gcc/go/gofrontend/MERGE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 539d886..bcbe1d9 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -5edbb624b2595d644eb6842c952a292c41f7d6fa +33f65dce43bd01c1fa38cd90a78c9aea6ca6dd59 The first line of this file holds the git revision number of the last merge done from the gofrontend repository. -- cgit v1.1 From e37ddb91a83335e58f16ef9ce9080668ad6ad47f Mon Sep 17 00:00:00 2001 From: "prathamesh.kulkarni" Date: Fri, 13 Aug 2021 12:28:50 +0530 Subject: arm: Add check for arm_softfp_ok in pr98435.c. gcc/testsuite/ChangeLog: * gcc.target/arm/simd/pr98435.c: Add dg-require-effective-target arm_softfp_ok. --- gcc/testsuite/gcc.target/arm/simd/pr98435.c | 1 + 1 file changed, 1 insertion(+) (limited to 'gcc') diff --git a/gcc/testsuite/gcc.target/arm/simd/pr98435.c b/gcc/testsuite/gcc.target/arm/simd/pr98435.c index 0af8633..a4c6a1c 100644 --- a/gcc/testsuite/gcc.target/arm/simd/pr98435.c +++ b/gcc/testsuite/gcc.target/arm/simd/pr98435.c @@ -1,5 +1,6 @@ /* { dg-do compile } */ /* { dg-options "-O2 -ffast-math" } */ +/* { dg-require-effective-target arm_softfp_ok } */ /* { dg-require-effective-target arm_v8_2a_bf16_neon_ok } */ /* { dg-add-options arm_v8_2a_bf16_neon } */ /* { dg-additional-options "-mfloat-abi=softfp -march=armv8.2-a+bf16+fp16" } */ -- cgit v1.1 From 4341b1b165751e728692eec12405fc04b2c681aa Mon Sep 17 00:00:00 2001 From: Jan Hubicka Date: Fri, 13 Aug 2021 10:04:52 +0200 Subject: Introduce EAF_NOREAD and cleanup EAF_UNUSED + ipa-modref this patch add EAF_NOREAD (as disucssed on IRC already) and fixes meaning of EAF_UNUSED to be really unused and not "does not escape, is not clobbered, read or returned" since we have separate flags for each of the properties now. Since number of flags has grown I refactored the code a bit to avoid repeated uses of complex flag combinations and also simplified the logic of merging. Merging is bit tricky since we have flags that implies other flags (like NOESCAPE implies NODIRECTESCAPE) but code that sets only NOESCAPE. Perhaps it would make sense to update fnspecs to always set flag along with all the implications, but for now I am handlingit in merge. I made only trivial update to tree-ssa-structalias to handle EAF_NORETURN in normal function handling, but not in pure functions. The problem is that the way constraints are generated for pure functions makes this difficult. I think logical step is to track whether function reads/stores global memory and rewrite the constraint generation so we can handle normal, pure and const in unified manner. Bootstrapped/regtested x86_64-linux, plan to commit it after furhter testing. The patch improves alias oracle stats for cc1plus somewhat. From: Alias oracle query stats: refs_may_alias_p: 72380497 disambiguations, 82649832 queries ref_maybe_used_by_call_p: 495184 disambiguations, 73366950 queries call_may_clobber_ref_p: 259312 disambiguations, 263253 queries nonoverlapping_component_refs_p: 0 disambiguations, 38006 queries nonoverlapping_refs_since_match_p: 21157 disambiguations, 65698 must overlaps, 87756 queries aliasing_component_refs_p: 63141 disambiguations, 2164695 queries TBAA oracle: 25975753 disambiguations 61449632 queries 12138220 are in alias set 0 11316663 queries asked about the same object 144 queries asked about the same alias set 0 access volatile 10472885 are dependent in the DAG 1545967 are aritificially in conflict with void * Modref stats: modref use: 23857 disambiguations, 754515 queries modref clobber: 1392162 disambiguations, 17753512 queries 3450241 tbaa queries (0.194341 per modref query) 534816 base compares (0.030125 per modref query) PTA query stats: pt_solution_includes: 12394915 disambiguations, 20235925 queries pt_solutions_intersect: 1365299 disambiguations, 14638068 queries To: Alias oracle query stats: refs_may_alias_p: 72629640 disambiguations, 82903333 queries ref_maybe_used_by_call_p: 502474 disambiguations, 73612186 queries call_may_clobber_ref_p: 261806 disambiguations, 265659 queries nonoverlapping_component_refs_p: 0 disambiguations, 38007 queries nonoverlapping_refs_since_match_p: 21139 disambiguations, 65772 must overlaps, 87816 queries aliasing_component_refs_p: 63144 disambiguations, 2164330 queries TBAA oracle: 26059018 disambiguations 61571714 queries 12158033 are in alias set 0 11326115 queries asked about the same object 144 queries asked about the same alias set 0 access volatile 10484493 are dependent in the DAG 1543911 are aritificially in conflict with void * Modref stats: modref use: 24008 disambiguations, 712712 queries modref clobber: 1395917 disambiguations, 17163694 queries 3465657 tbaa queries (0.201918 per modref query) 537591 base compares (0.031321 per modref query) PTA query stats: pt_solution_includes: 12468934 disambiguations, 20295402 queries pt_solutions_intersect: 1391917 disambiguations, 14665265 queries I think it is mostly due to better heandling of EAF_NODIRECTESCAPE. Honza gcc/ChangeLog: 2021-08-12 Jan Hubicka * ipa-modref.c (dump_eaf_flags): Dump EAF_NOREAD. (implicit_const_eaf_flags, implicit_pure_eaf_flags, ignore_stores_eaf_flags): New constants. (remove_useless_eaf_flags): New function. (eaf_flags_useful_p): Use it. (deref_flags): Add EAF_NOT_RETURNED if flag is unused; handle EAF_NOREAD. (modref_lattice::init): Add EAF_NOREAD. (modref_lattice::add_escape_point): Do not reacord escape point if result is unused. (modref_lattice::merge): EAF_NOESCAPE implies EAF_NODIRECTESCAPE; use remove_useless_eaf_flags. (modref_lattice::merge_deref): Use ignore_stores_eaf_flags. (modref_lattice::merge_direct_load): Add EAF_NOREAD (analyze_ssa_name_flags): Fix handling EAF_NOT_RETURNED (analyze_parms): Use remove_useless_eaf_flags. (ipa_merge_modref_summary_after_inlining): Use ignore_stores_eaf_flags. (modref_merge_call_site_flags): Add caller and ecf_flags parameter; use remove_useless_eaf_flags. (modref_propagate_flags_in_scc): Update. * ipa-modref.h: Turn eaf_flags_t back to char. * tree-core.h (EAF_NOT_RETURNED): Fix. (EAF_NOREAD): New constant * tree-ssa-alias.c: (ref_maybe_used_by_call_p_1): Check for EAF_NOREAD. * tree-ssa-structalias.c (handle_rhs_call): Handle new flags. (handle_pure_call): Likewise. gcc/testsuite/ChangeLog: 2021-08-12 Jan Hubicka * gcc.dg/tree-ssa/modref-6.c: Update. --- gcc/ipa-modref.c | 169 +++++++++++++++++++++---------- gcc/ipa-modref.h | 2 +- gcc/testsuite/gcc.dg/tree-ssa/modref-6.c | 2 +- gcc/tree-core.h | 5 +- gcc/tree-ssa-alias.c | 2 +- gcc/tree-ssa-structalias.c | 14 ++- 6 files changed, 131 insertions(+), 63 deletions(-) (limited to 'gcc') diff --git a/gcc/ipa-modref.c b/gcc/ipa-modref.c index c65b2f6..fafd804 100644 --- a/gcc/ipa-modref.c +++ b/gcc/ipa-modref.c @@ -158,6 +158,8 @@ dump_eaf_flags (FILE *out, int flags, bool newline = true) fprintf (out, " unused"); if (flags & EAF_NOT_RETURNED) fprintf (out, " not_returned"); + if (flags & EAF_NOREAD) + fprintf (out, " noread"); if (newline) fprintf (out, "\n"); } @@ -278,27 +280,46 @@ modref_summary::~modref_summary () ggc_delete (stores); } +/* All flags that are implied by the ECF_CONST functions. */ +const int implicit_const_eaf_flags = EAF_DIRECT | EAF_NOCLOBBER | EAF_NOESCAPE + | EAF_NODIRECTESCAPE | EAF_NOREAD; +/* All flags that are implied by the ECF_PURE function. */ +const int implicit_pure_eaf_flags = EAF_NOCLOBBER | EAF_NOESCAPE + | EAF_NODIRECTESCAPE; +/* All flags implied when we know we can ignore stores (i.e. when handling + call to noreturn). */ +const int ignore_stores_eaf_flags = EAF_DIRECT | EAF_NOCLOBBER | EAF_NOESCAPE + | EAF_NODIRECTESCAPE; + +/* Remove all flags from EAF_FLAGS that are implied by ECF_FLAGS and not + useful to track. If returns_void is true moreover clear + EAF_NOT_RETURNED. */ +static int +remove_useless_eaf_flags (int eaf_flags, int ecf_flags, bool returns_void) +{ + if (ecf_flags & ECF_NOVOPS) + return 0; + if (ecf_flags & ECF_CONST) + eaf_flags &= ~implicit_const_eaf_flags; + else if (ecf_flags & ECF_PURE) + eaf_flags &= ~implicit_pure_eaf_flags; + else if ((ecf_flags & ECF_NORETURN) || returns_void) + eaf_flags &= ~EAF_NOT_RETURNED; + /* Only NOCLOBBER or DIRECT flags alone are not useful (see comments + in tree-ssa-alias.c). Give up earlier. */ + if ((eaf_flags & ~(EAF_DIRECT | EAF_NOCLOBBER)) == 0) + return 0; + return eaf_flags; +} + /* Return true if FLAGS holds some useful information. */ static bool eaf_flags_useful_p (vec &flags, int ecf_flags) { for (unsigned i = 0; i < flags.length (); i++) - if (ecf_flags & ECF_CONST) - { - if (flags[i] & (EAF_UNUSED | EAF_NOT_RETURNED)) - return true; - } - else if (ecf_flags & ECF_PURE) - { - if (flags[i] & (EAF_UNUSED | EAF_DIRECT | EAF_NOT_RETURNED)) - return true; - } - else - { - if (flags[i]) - return true; - } + if (remove_useless_eaf_flags (flags[i], ecf_flags, false)) + return true; return false; } @@ -1320,17 +1341,35 @@ static int deref_flags (int flags, bool ignore_stores) { int ret = EAF_NODIRECTESCAPE; + /* If argument is unused just account for + the read involved in dereference. */ if (flags & EAF_UNUSED) - ret |= EAF_DIRECT | EAF_NOCLOBBER | EAF_NOESCAPE; + ret |= EAF_DIRECT | EAF_NOCLOBBER | EAF_NOESCAPE | EAF_NOT_RETURNED; else { if ((flags & EAF_NOCLOBBER) || ignore_stores) ret |= EAF_NOCLOBBER; if ((flags & EAF_NOESCAPE) || ignore_stores) ret |= EAF_NOESCAPE; + /* If the value dereferenced is not used for another load or store + we can still consider ARG as used only directly. + + Consider + + int + test (int *a) + { + return *a!=0; + } + + */ + if ((flags & (EAF_NOREAD | EAF_NOT_RETURNED | EAF_NOESCAPE | EAF_DIRECT)) + == (EAF_NOREAD | EAF_NOT_RETURNED | EAF_NOESCAPE | EAF_DIRECT) + && ((flags & EAF_NOCLOBBER) || ignore_stores)) + ret |= EAF_DIRECT; + if (flags & EAF_NOT_RETURNED) + ret |= EAF_NOT_RETURNED; } - if (flags & EAF_NOT_RETURNED) - ret |= EAF_NOT_RETURNED; return ret; } @@ -1355,7 +1394,7 @@ class modref_lattice { public: /* EAF flags of the SSA name. */ - int flags; + eaf_flags_t flags; /* DFS bookkkeeping: we don't do real dataflow yet. */ bool known; bool open; @@ -1379,8 +1418,12 @@ public: void modref_lattice::init () { - flags = EAF_DIRECT | EAF_NOCLOBBER | EAF_NOESCAPE | EAF_UNUSED - | EAF_NODIRECTESCAPE | EAF_NOT_RETURNED; + /* All flags we track. */ + int f = EAF_DIRECT | EAF_NOCLOBBER | EAF_NOESCAPE | EAF_UNUSED + | EAF_NODIRECTESCAPE | EAF_NOT_RETURNED | EAF_NOREAD; + flags = f; + /* Check that eaf_flags_t is wide enough to hold all flags. */ + gcc_checking_assert (f == flags); open = true; known = false; } @@ -1424,8 +1467,8 @@ modref_lattice::add_escape_point (gcall *call, int arg, int min_flags, unsigned int i; /* If we already determined flags to be bad enough, - * we do not need to record. */ - if ((flags & min_flags) == flags) + we do not need to record. */ + if ((flags & min_flags) == flags || (min_flags & EAF_UNUSED)) return false; FOR_EACH_VEC_ELT (escape_points, i, ep) @@ -1455,13 +1498,18 @@ modref_lattice::merge (int f) { if (f & EAF_UNUSED) return false; + /* Noescape implies that value also does not escape directly. + Fnspec machinery does set both so compensate for this. */ + if (f & EAF_NOESCAPE) + f |= EAF_NODIRECTESCAPE; if ((flags & f) != flags) { flags &= f; - /* Only NOCLOBBER or DIRECT flags alone are not useful (see comments - in tree-ssa-alias.c). Give up earlier. */ - if ((flags & ~(EAF_DIRECT | EAF_NOCLOBBER)) == 0) - flags = 0; + /* Prune obvoiusly useless flags; + We do not have ECF_FLAGS handy which is not big problem since + we will do final flags cleanup before producing summary. + Merging should be fast so it can work well with dataflow. */ + flags = remove_useless_eaf_flags (flags, 0, false); if (!flags) escape_points.release (); return true; @@ -1509,7 +1557,7 @@ modref_lattice::merge_deref (const modref_lattice &with, bool ignore_stores) if (with.escape_points[i].direct) min_flags = deref_flags (min_flags, ignore_stores); else if (ignore_stores) - min_flags |= EAF_NOCLOBBER | EAF_NOESCAPE | EAF_NODIRECTESCAPE; + min_flags |= ignore_stores_eaf_flags; changed |= add_escape_point (with.escape_points[i].call, with.escape_points[i].arg, min_flags, @@ -1523,7 +1571,7 @@ modref_lattice::merge_deref (const modref_lattice &with, bool ignore_stores) bool modref_lattice::merge_direct_load () { - return merge (~EAF_UNUSED); + return merge (~(EAF_UNUSED | EAF_NOREAD)); } /* Merge in flags for direct store. */ @@ -1632,6 +1680,9 @@ analyze_ssa_name_flags (tree name, vec &lattice, int depth, fprintf (dump_file, "%*s Analyzing stmt: ", depth * 4, ""); print_gimple_stmt (dump_file, use_stmt, 0); } + /* If we see a direct non-debug use, clear unused bit. + All dereferneces should be accounted below using deref_flags. */ + lattice[index].merge (~EAF_UNUSED); /* Gimple return may load the return value. Returning name counts as an use by tree-ssa-structalias.c */ @@ -1642,7 +1693,7 @@ analyze_ssa_name_flags (tree name, vec &lattice, int depth, else if (memory_access_to (gimple_return_retval (ret), name)) { lattice[index].merge_direct_load (); - lattice[index].merge (~EAF_NOT_RETURNED); + lattice[index].merge (~(EAF_UNUSED | EAF_NOT_RETURNED)); } } /* Account for LHS store, arg loads and flags from callee function. */ @@ -1697,8 +1748,7 @@ analyze_ssa_name_flags (tree name, vec &lattice, int depth, int call_flags = gimple_call_arg_flags (call, i) | EAF_NOT_RETURNED; if (ignore_stores) - call_flags |= EAF_NOCLOBBER | EAF_NOESCAPE - | EAF_NODIRECTESCAPE; + call_flags |= ignore_stores_eaf_flags; if (!record_ipa) lattice[index].merge (call_flags); @@ -1890,14 +1940,12 @@ analyze_parms (modref_summary *summary, modref_summary_lto *summary_lto, analyze_ssa_name_flags (name, lattice, 0, ipa); int flags = lattice[SSA_NAME_VERSION (name)].flags; - /* For pure functions we have implicit NOCLOBBER - and NOESCAPE. */ - if (ecf_flags & ECF_PURE) - flags &= (EAF_UNUSED | EAF_DIRECT | EAF_NOT_RETURNED); - /* Only useful flags for const function are EAF_NOT_RETURNED and - EAF_UNUSED. */ - if (ecf_flags & ECF_CONST) - flags &= (EAF_UNUSED | EAF_NOT_RETURNED); + /* Eliminate useless flags so we do not end up storing unnecessary + summaries. */ + + flags = remove_useless_eaf_flags + (flags, ecf_flags, + VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl)))); if (flags) { @@ -3176,7 +3224,7 @@ ipa_merge_modref_summary_after_inlining (cgraph_edge *edge) if (!ee->direct) flags = deref_flags (flags, ignore_stores); else if (ignore_stores) - flags |= EAF_NOCLOBBER | EAF_NOESCAPE | EAF_NODIRECTESCAPE; + flags |= ignore_stores_eaf_flags; flags |= ee->min_flags; to_info->arg_flags[ee->parm_index] &= flags; if (to_info->arg_flags[ee->parm_index]) @@ -3190,7 +3238,7 @@ ipa_merge_modref_summary_after_inlining (cgraph_edge *edge) if (!ee->direct) flags = deref_flags (flags, ignore_stores); else if (ignore_stores) - flags |= EAF_NOCLOBBER | EAF_NOESCAPE | EAF_NODIRECTESCAPE; + flags |= ignore_stores_eaf_flags; flags |= ee->min_flags; to_info_lto->arg_flags[ee->parm_index] &= flags; if (to_info_lto->arg_flags[ee->parm_index]) @@ -3673,11 +3721,13 @@ modref_merge_call_site_flags (escape_summary *sum, modref_summary_lto *cur_summary_lto, modref_summary *summary, modref_summary_lto *summary_lto, - bool ignore_stores) + tree caller, + int ecf_flags) { escape_entry *ee; unsigned int i; bool changed = false; + bool ignore_stores = ignore_stores_p (caller, ecf_flags); /* If we have no useful info to propagate. */ if ((!cur_summary || !cur_summary->arg_flags.length ()) @@ -3701,21 +3751,27 @@ modref_merge_call_site_flags (escape_summary *sum, } else if (ignore_stores) { - flags |= EAF_NOESCAPE | EAF_NOCLOBBER | EAF_NODIRECTESCAPE; - flags_lto |= EAF_NOESCAPE | EAF_NOCLOBBER | EAF_NODIRECTESCAPE; + flags |= ignore_stores_eaf_flags; + flags_lto |= ignore_stores_eaf_flags; } /* Returning the value is already accounted to at local propagation. */ flags |= ee->min_flags | EAF_NOT_RETURNED; flags_lto |= ee->min_flags | EAF_NOT_RETURNED; + /* Noescape implies that value also does not escape directly. + Fnspec machinery does set both so compensate for this. */ + if (flags & EAF_NOESCAPE) + flags |= EAF_NODIRECTESCAPE; + if (flags_lto & EAF_NOESCAPE) + flags_lto |= EAF_NODIRECTESCAPE; if (!(flags & EAF_UNUSED) && cur_summary && ee->parm_index < cur_summary->arg_flags.length ()) { int f = cur_summary->arg_flags[ee->parm_index]; if ((f & flags) != f) { - f = f & flags; - if ((f & ~(EAF_DIRECT | EAF_NOCLOBBER)) == 0) - f = 0; + f = remove_useless_eaf_flags + (f & flags, ecf_flags, + VOID_TYPE_P (TREE_TYPE (TREE_TYPE (caller)))); cur_summary->arg_flags[ee->parm_index] = f; changed = true; } @@ -3727,9 +3783,9 @@ modref_merge_call_site_flags (escape_summary *sum, int f = cur_summary_lto->arg_flags[ee->parm_index]; if ((f & flags_lto) != f) { - f = f & flags; - if ((f & ~(EAF_DIRECT | EAF_NOCLOBBER)) == 0) - f = 0; + f = remove_useless_eaf_flags + (f & flags_lto, ecf_flags, + VOID_TYPE_P (TREE_TYPE (TREE_TYPE (caller)))); cur_summary_lto->arg_flags[ee->parm_index] = f; changed = true; } @@ -3780,8 +3836,8 @@ modref_propagate_flags_in_scc (cgraph_node *component_node) changed |= modref_merge_call_site_flags (sum, cur_summary, cur_summary_lto, - NULL, NULL, ignore_stores_p (node->decl, - e->indirect_info->ecf_flags)); + NULL, NULL, + node->decl, e->indirect_info->ecf_flags); } if (!cur_summary && !cur_summary_lto) @@ -3790,12 +3846,13 @@ modref_propagate_flags_in_scc (cgraph_node *component_node) for (cgraph_edge *callee_edge = cur->callees; callee_edge; callee_edge = callee_edge->next_callee) { - int flags = flags_from_decl_or_type (callee_edge->callee->decl); + int ecf_flags = flags_from_decl_or_type + (callee_edge->callee->decl); modref_summary *callee_summary = NULL; modref_summary_lto *callee_summary_lto = NULL; struct cgraph_node *callee; - if (flags & (ECF_CONST | ECF_NOVOPS) + if (ecf_flags & (ECF_CONST | ECF_NOVOPS) || !callee_edge->inline_failed) continue; /* Get the callee and its summary. */ @@ -3832,7 +3889,7 @@ modref_propagate_flags_in_scc (cgraph_node *component_node) changed |= modref_merge_call_site_flags (sum, cur_summary, cur_summary_lto, callee_summary, callee_summary_lto, - ignore_stores_p (node->decl, flags)); + node->decl, ecf_flags); if (dump_file && changed) { if (cur_summary) diff --git a/gcc/ipa-modref.h b/gcc/ipa-modref.h index 498cc24..540fdea 100644 --- a/gcc/ipa-modref.h +++ b/gcc/ipa-modref.h @@ -21,7 +21,7 @@ along with GCC; see the file COPYING3. If not see #define IPA_MODREF_H typedef modref_tree modref_records; -typedef unsigned short eaf_flags_t; +typedef unsigned char eaf_flags_t; /* Single function summary. */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/modref-6.c b/gcc/testsuite/gcc.dg/tree-ssa/modref-6.c index 8db9a1d..2d97a49 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/modref-6.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/modref-6.c @@ -32,6 +32,6 @@ int test2() /* Flags for pure call. */ /* { dg-final { scan-tree-dump "parm 0 flags: direct not_returned" "modref1" } } */ /* Flags for const call. */ -/* { dg-final { scan-tree-dump "parm 0 flags: unused not_returned" "modref1" } } */ +/* { dg-final { scan-tree-dump "parm 0 flags: not_returned" "modref1" } } */ /* Overall we want to make "int a" non escaping. */ /* { dg-final { scan-tree-dump "return 42" "optimized" } } */ diff --git a/gcc/tree-core.h b/gcc/tree-core.h index 9e901ce..239a3a3 100644 --- a/gcc/tree-core.h +++ b/gcc/tree-core.h @@ -115,7 +115,10 @@ struct die_struct; #define EAF_NODIRECTESCAPE (1 << 4) /* Nonzero if the argument does not escape to return value. */ -#define EAF_NOT_RETURNED (1 << 8) +#define EAF_NOT_RETURNED (1 << 5) + +/* Nonzero if the argument is not read. */ +#define EAF_NOREAD (1 << 6) /* Call return flags. */ /* Mask for the argument number that is returned. Lower two bits of diff --git a/gcc/tree-ssa-alias.c b/gcc/tree-ssa-alias.c index cbd51ac..ce667ff 100644 --- a/gcc/tree-ssa-alias.c +++ b/gcc/tree-ssa-alias.c @@ -2870,7 +2870,7 @@ process_args: tree op = gimple_call_arg (call, i); int flags = gimple_call_arg_flags (call, i); - if (flags & EAF_UNUSED) + if (flags & (EAF_UNUSED | EAF_NOREAD)) continue; if (TREE_CODE (op) == WITH_SIZE_EXPR) diff --git a/gcc/tree-ssa-structalias.c b/gcc/tree-ssa-structalias.c index c694926..fb0e429 100644 --- a/gcc/tree-ssa-structalias.c +++ b/gcc/tree-ssa-structalias.c @@ -4063,8 +4063,14 @@ handle_rhs_call (gcall *stmt, vec *results) tree arg = gimple_call_arg (stmt, i); int flags = gimple_call_arg_flags (stmt, i); - /* If the argument is not used we can ignore it. */ - if (flags & EAF_UNUSED) + /* If the argument is not used we can ignore it. + Similarly argument is invisile for us if it not clobbered, does not + escape, is not read and can not be returned. */ + if ((flags & EAF_UNUSED) + || ((flags & (EAF_NOCLOBBER | EAF_NOESCAPE | EAF_NOREAD + | EAF_NOT_RETURNED)) + == (EAF_NOCLOBBER | EAF_NOESCAPE | EAF_NOREAD + | EAF_NOT_RETURNED))) continue; /* As we compute ESCAPED context-insensitive we do not gain @@ -4316,7 +4322,9 @@ handle_pure_call (gcall *stmt, vec *results) int flags = gimple_call_arg_flags (stmt, i); /* If the argument is not used we can ignore it. */ - if (flags & EAF_UNUSED) + if ((flags & EAF_UNUSED) + || (flags & (EAF_NOT_RETURNED | EAF_NOREAD)) + == (EAF_NOT_RETURNED | EAF_NOREAD)) continue; if (!uses) { -- cgit v1.1 From 5eb304a3e510742d65dc327b177ef1078fd6349c Mon Sep 17 00:00:00 2001 From: Martin Liska Date: Fri, 13 Aug 2021 11:18:40 +0200 Subject: opts: do not repeat a string in errors gcc/ChangeLog: * opts.c (LIVE_PATCHING_OPTION): Define. (control_options_for_live_patching): Use it in error messages. --- gcc/opts.c | 53 +++++++++++++++++++++++------------------------------ 1 file changed, 23 insertions(+), 30 deletions(-) (limited to 'gcc') diff --git a/gcc/opts.c b/gcc/opts.c index 1f52e11..e050155 100644 --- a/gcc/opts.c +++ b/gcc/opts.c @@ -806,37 +806,39 @@ control_options_for_live_patching (struct gcc_options *opts, switch (level) { case LIVE_PATCHING_INLINE_ONLY_STATIC: +#define LIVE_PATCHING_OPTION "-flive-patching=inline-only-static" if (opts_set->x_flag_ipa_cp_clone && opts->x_flag_ipa_cp_clone) error_at (loc, "%qs is incompatible with %qs", - "-fipa-cp-clone", "-flive-patching=inline-only-static"); + "-fipa-cp-clone", LIVE_PATCHING_OPTION); else opts->x_flag_ipa_cp_clone = 0; if (opts_set->x_flag_ipa_sra && opts->x_flag_ipa_sra) error_at (loc, "%qs is incompatible with %qs", - "-fipa-sra", "-flive-patching=inline-only-static"); + "-fipa-sra", LIVE_PATCHING_OPTION); else opts->x_flag_ipa_sra = 0; if (opts_set->x_flag_partial_inlining && opts->x_flag_partial_inlining) error_at (loc, "%qs is incompatible with %qs", - "-fpartial-inlining", "-flive-patching=inline-only-static"); + "-fpartial-inlining", LIVE_PATCHING_OPTION); else opts->x_flag_partial_inlining = 0; if (opts_set->x_flag_ipa_cp && opts->x_flag_ipa_cp) error_at (loc, "%qs is incompatible with %qs", - "-fipa-cp", "-flive-patching=inline-only-static"); + "-fipa-cp", LIVE_PATCHING_OPTION); else opts->x_flag_ipa_cp = 0; /* FALLTHROUGH. */ case LIVE_PATCHING_INLINE_CLONE: +#undef LIVE_PATCHING_OPTION +#define LIVE_PATCHING_OPTION "-flive-patching=inline-only-static|inline-clone" /* live patching should disable whole-program optimization. */ if (opts_set->x_flag_whole_program && opts->x_flag_whole_program) error_at (loc, "%qs is incompatible with %qs", - "-fwhole-program", - "-flive-patching=inline-only-static|inline-clone"); + "-fwhole-program", LIVE_PATCHING_OPTION); else opts->x_flag_whole_program = 0; @@ -846,71 +848,62 @@ control_options_for_live_patching (struct gcc_options *opts, if (opts_set->x_flag_ipa_pta && opts->x_flag_ipa_pta) error_at (loc, "%qs is incompatible with %qs", - "-fipa-pta", - "-flive-patching=inline-only-static|inline-clone"); + "-fipa-pta", LIVE_PATCHING_OPTION); else opts->x_flag_ipa_pta = 0; if (opts_set->x_flag_ipa_reference && opts->x_flag_ipa_reference) error_at (loc, "%qs is incompatible with %qs", - "-fipa-reference", - "-flive-patching=inline-only-static|inline-clone"); + "-fipa-reference", LIVE_PATCHING_OPTION); else opts->x_flag_ipa_reference = 0; if (opts_set->x_flag_ipa_ra && opts->x_flag_ipa_ra) error_at (loc, "%qs is incompatible with %qs", - "-fipa-ra", - "-flive-patching=inline-only-static|inline-clone"); + "-fipa-ra", LIVE_PATCHING_OPTION); else opts->x_flag_ipa_ra = 0; if (opts_set->x_flag_ipa_icf && opts->x_flag_ipa_icf) error_at (loc, "%qs is incompatible with %qs", - "-fipa-icf", - "-flive-patching=inline-only-static|inline-clone"); + "-fipa-icf", LIVE_PATCHING_OPTION); else opts->x_flag_ipa_icf = 0; if (opts_set->x_flag_ipa_icf_functions && opts->x_flag_ipa_icf_functions) error_at (loc, "%qs is incompatible with %qs", - "-fipa-icf-functions", - "-flive-patching=inline-only-static|inline-clone"); + "-fipa-icf-functions", LIVE_PATCHING_OPTION); else opts->x_flag_ipa_icf_functions = 0; if (opts_set->x_flag_ipa_icf_variables && opts->x_flag_ipa_icf_variables) error_at (loc, "%qs is incompatible with %qs", - "-fipa-icf-variables", - "-flive-patching=inline-only-static|inline-clone"); + "-fipa-icf-variables", LIVE_PATCHING_OPTION); else opts->x_flag_ipa_icf_variables = 0; if (opts_set->x_flag_ipa_bit_cp && opts->x_flag_ipa_bit_cp) error_at (loc, "%qs is incompatible with %qs", - "-fipa-bit-cp", - "-flive-patching=inline-only-static|inline-clone"); + "-fipa-bit-cp", LIVE_PATCHING_OPTION); else opts->x_flag_ipa_bit_cp = 0; if (opts_set->x_flag_ipa_vrp && opts->x_flag_ipa_vrp) error_at (loc, "%qs is incompatible with %qs", - "-fipa-vrp", - "-flive-patching=inline-only-static|inline-clone"); + "-fipa-vrp", LIVE_PATCHING_OPTION); else opts->x_flag_ipa_vrp = 0; if (opts_set->x_flag_ipa_pure_const && opts->x_flag_ipa_pure_const) error_at (loc, "%qs is incompatible with %qs", - "-fipa-pure-const", - "-flive-patching=inline-only-static|inline-clone"); + "-fipa-pure-const", LIVE_PATCHING_OPTION); else opts->x_flag_ipa_pure_const = 0; if (opts_set->x_flag_ipa_modref && opts->x_flag_ipa_modref) error_at (loc, - "%<-fipa-modref%> is incompatible with " - "%<-flive-patching=inline-only-static|inline-clone%>"); + "%<-fipa-modref%> is incompatible with %qs", + LIVE_PATCHING_OPTION); else opts->x_flag_ipa_modref = 0; @@ -920,8 +913,7 @@ control_options_for_live_patching (struct gcc_options *opts, if (opts_set->x_flag_ipa_reference_addressable && opts->x_flag_ipa_reference_addressable) error_at (loc, "%qs is incompatible with %qs", - "-fipa-reference-addressable", - "-flive-patching=inline-only-static|inline-clone"); + "-fipa-reference-addressable", LIVE_PATCHING_OPTION); else opts->x_flag_ipa_reference_addressable = 0; @@ -929,14 +921,15 @@ control_options_for_live_patching (struct gcc_options *opts, if (opts_set->x_flag_ipa_stack_alignment && opts->x_flag_ipa_stack_alignment) error_at (loc, "%qs is incompatible with %qs", - "-fipa-stack-alignment", - "-flive-patching=inline-only-static|inline-clone"); + "-fipa-stack-alignment", LIVE_PATCHING_OPTION); else opts->x_flag_ipa_stack_alignment = 0; break; default: gcc_unreachable (); } + +#undef LIVE_PATCHING_OPTION } /* --help option argument if set. */ -- cgit v1.1 From fa28520fadb9405f4387ceb419b0b7fc3ba0a61f Mon Sep 17 00:00:00 2001 From: Martin Liska Date: Fri, 13 Aug 2021 11:10:56 +0200 Subject: ipa: do not make localaliases for target_clones [PR101261] PR ipa/101261 gcc/ChangeLog: * symtab.c (symtab_node::noninterposable_alias): Do not create local aliases for target_clone functions as the clonning pass rejects aliases. gcc/testsuite/ChangeLog: * gcc.target/i386/pr101261.c: New test. --- gcc/symtab.c | 2 ++ gcc/testsuite/gcc.target/i386/pr101261.c | 11 +++++++++++ 2 files changed, 13 insertions(+) create mode 100644 gcc/testsuite/gcc.target/i386/pr101261.c (limited to 'gcc') diff --git a/gcc/symtab.c b/gcc/symtab.c index 8c4cb70..c7ea8ec 100644 --- a/gcc/symtab.c +++ b/gcc/symtab.c @@ -1959,6 +1959,8 @@ symtab_node::noninterposable_alias (void) /* If aliases aren't supported by the assembler, fail. */ if (!TARGET_SUPPORTS_ALIASES) return NULL; + else if (lookup_attribute ("target_clones", DECL_ATTRIBUTES (node->decl))) + return NULL; /* Otherwise create a new one. */ new_decl = copy_node (node->decl); diff --git a/gcc/testsuite/gcc.target/i386/pr101261.c b/gcc/testsuite/gcc.target/i386/pr101261.c new file mode 100644 index 0000000..d25d1a2 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr101261.c @@ -0,0 +1,11 @@ +/* PR middle-end/101261 */ +/* { dg-do compile { target fpic } } */ +/* { dg-options "-fno-semantic-interposition -fPIC" } */ +/* { dg-require-ifunc "" } */ + +void +__attribute__((target_clones("default", "avx2"))) +dt_ioppr_transform_image_colorspace() +{ + dt_ioppr_transform_image_colorspace(); +} -- cgit v1.1 From 4998404915bba9cb04c438a926cdf7126782a767 Mon Sep 17 00:00:00 2001 From: Martin Liska Date: Thu, 12 Aug 2021 17:26:51 +0200 Subject: ipa: "naked" attribute implies "noipa" attribute PR ipa/101354 gcc/ChangeLog: * attribs.c (decl_attributes): Make naked functions "noipa" functions. --- gcc/attribs.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) (limited to 'gcc') diff --git a/gcc/attribs.c b/gcc/attribs.c index afa485e..0d22c20 100644 --- a/gcc/attribs.c +++ b/gcc/attribs.c @@ -517,14 +517,9 @@ decl_attributes (tree *node, tree attributes, int flags, if (TREE_CODE (*node) == FUNCTION_DECL && attributes && lookup_attribute ("naked", attributes) != NULL - && lookup_attribute_spec (get_identifier ("naked"))) - { - if (lookup_attribute ("noinline", attributes) == NULL) - attributes = tree_cons (get_identifier ("noinline"), NULL, attributes); - - if (lookup_attribute ("noclone", attributes) == NULL) - attributes = tree_cons (get_identifier ("noclone"), NULL, attributes); - } + && lookup_attribute_spec (get_identifier ("naked")) + && lookup_attribute ("noipa", attributes) == NULL) + attributes = tree_cons (get_identifier ("noipa"), NULL, attributes); /* A "noipa" function attribute implies "noinline", "noclone" and "no_icf" for those targets that support it. */ -- cgit v1.1 From e5c00544cce1feb2c8c4e9aad766315d389c69c4 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Fri, 13 Aug 2021 10:15:45 -0700 Subject: runtime: use C cast syntax in stack.c Didn't notice earlier because this code is only used on systems that do not support -fsplit-stack. Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/342051 --- gcc/go/gofrontend/MERGE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index bcbe1d9..3000285 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -33f65dce43bd01c1fa38cd90a78c9aea6ca6dd59 +f2b7a2ce94127ad444a772bd1631516c5c67fb73 The first line of this file holds the git revision number of the last merge done from the gofrontend repository. -- cgit v1.1 From fb85d6eb6c392e829d1ee5b8a2e2b81c53c9840f Mon Sep 17 00:00:00 2001 From: Martin Sebor Date: Fri, 13 Aug 2021 12:21:20 -0600 Subject: Warn for reads from write-only arguments [PR101734]. Resolves: PR middle-end/101734 - missing warning reading from a write-only object gcc/ChangeLog: PR middle-end/101734 * tree-ssa-uninit.c (maybe_warn_read_write_only): New function. (maybe_warn_operand): Call it. gcc/testsuite/ChangeLog: PR middle-end/101734 * gcc.dg/uninit-42.c: New test. --- gcc/testsuite/gcc.dg/uninit-42.c | 87 +++++++++++++++++++++++++++++++++++++++ gcc/tree-ssa-uninit.c | 89 ++++++++++++++++++++++++++++++++++++---- 2 files changed, 167 insertions(+), 9 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/uninit-42.c (limited to 'gcc') diff --git a/gcc/testsuite/gcc.dg/uninit-42.c b/gcc/testsuite/gcc.dg/uninit-42.c new file mode 100644 index 0000000..efaaacd --- /dev/null +++ b/gcc/testsuite/gcc.dg/uninit-42.c @@ -0,0 +1,87 @@ +/* PR middle-end/101734 - missing warning reading from a write-only object + Verify that reading objects pointed to by arguments + declared with attribute access none or write-only is diagnosed by + -Wmaybe-uninitialized. + { dg-do compile } + { dg-options "-Wall" } */ + +#define A(mode, ...) __attribute__ ((access (mode, __VA_ARGS__))) + +void sink (void *, ...); + + +A (write_only, 1, 2) +int nowarn_wo_assign_r0 (int *p, int n) +{ + *p = n; + return *p; +} + +A (write_only, 1, 2) +int nowarn_wo_sink_r0 (int *p, int n) +{ + sink (p, p + 1, p + n); + return *p; +} + +A (write_only, 1, 2) +int warn_wo_r0 (int *p, int n) +{ + return *p; // { dg-warning "'\\*p' may be used uninitialized \\\[-Wmaybe-uninitialized" } +} + + +A (write_only, 1, 2) +int nowarn_wo_w1_r1 (int *p, int n) +{ + p[1] = n; + return p[1]; +} + +A (write_only, 1, 2) +int warn_wo_r1 (int *p, int n) +{ + return p[1]; // { dg-warning "'p\\\[1]' may be used uninitialized" } +} + + +A (write_only, 1, 2) +int nowarn_wo_rwi_rj (int *p, int n, int i, int j) +{ + p[i] = n; + return p[j]; +} + +A (write_only, 1, 2) + int warn_wo_ri (int *p, int n, int i) +{ + return p[i]; // { dg-warning " may be used uninitialized" } +} + + + +A (none, 1, 2) +int* nowarn_none_sink_return (int *p, int n) +{ + sink (p, p + 1, p + n); + return p; +} + +A (none, 1, 2) +int warn_none_r0 (int *p, int n) +{ + (void)&n; + return *p; // { dg-warning "'\\*p' may be used uninitialized" } +} + +A (none, 1, 2) +int warn_none_r1 (int *p, int n) +{ + return p[1]; // { dg-warning "'p\\\[1]' may be used uninitialized" } +} + +A (write_only, 1, 2) +int warn_none_ri (int *p, int n, int i) +{ + return p[i]; // { dg-warning " may be used uninitialized" } +} diff --git a/gcc/tree-ssa-uninit.c b/gcc/tree-ssa-uninit.c index 5d7bc80..d5cdffb 100644 --- a/gcc/tree-ssa-uninit.c +++ b/gcc/tree-ssa-uninit.c @@ -283,6 +283,64 @@ builtin_call_nomodifying_p (gimple *stmt) return true; } +/* If ARG is a FNDECL parameter declared with attribute access none or + write_only issue a warning for its read access via PTR. */ + +static void +maybe_warn_read_write_only (tree fndecl, gimple *stmt, tree arg, tree ptr) +{ + if (!fndecl) + return; + + if (get_no_uninit_warning (arg)) + return; + + tree fntype = TREE_TYPE (fndecl); + if (!fntype) + return; + + /* Initialize a map of attribute access specifications for arguments + to the function function call. */ + rdwr_map rdwr_idx; + init_attr_rdwr_indices (&rdwr_idx, TYPE_ATTRIBUTES (fntype)); + + unsigned argno = 0; + tree parms = DECL_ARGUMENTS (fndecl); + for (tree parm = parms; parm; parm = TREE_CHAIN (parm), ++argno) + { + if (parm != arg) + continue; + + const attr_access* access = rdwr_idx.get (argno); + if (!access) + break; + + if (access->mode != access_none + && access->mode != access_write_only) + continue; + + location_t stmtloc + = linemap_resolve_location (line_table, gimple_location (stmt), + LRK_SPELLING_LOCATION, NULL); + + if (!warning_at (stmtloc, OPT_Wmaybe_uninitialized, + "%qE may be used uninitialized", ptr)) + break; + + suppress_warning (arg, OPT_Wmaybe_uninitialized); + + const char* const access_str = + TREE_STRING_POINTER (access->to_external_string ()); + + location_t parmloc = DECL_SOURCE_LOCATION (parm); + inform (parmloc, "accessing argument %u of a function declared with " + "attribute %<%s%>", + argno + 1, access_str); + + break; + } +} + /* Callback for walk_aliased_vdefs. */ static bool @@ -350,7 +408,9 @@ struct wlimits }; /* Determine if REF references an uninitialized operand and diagnose - it if so. */ + it if so. STMS is the referencing statement. LHS is the result + of the access and may be null. RHS is the variable referenced by + the access; it may not be null. */ static tree maybe_warn_operand (ao_ref &ref, gimple *stmt, tree lhs, tree rhs, @@ -497,14 +557,25 @@ maybe_warn_operand (ao_ref &ref, gimple *stmt, tree lhs, tree rhs, /* Do not warn if it can be initialized outside this function. If we did not reach function entry then we found killing clobbers on all paths to entry. */ - if (!found_alloc - && fentry_reached - /* ??? We'd like to use ref_may_alias_global_p but that - excludes global readonly memory and thus we get bogus - warnings from p = cond ? "a" : "b" for example. */ - && (!VAR_P (base) - || is_global_var (base))) - return NULL_TREE; + if (!found_alloc && fentry_reached) + { + if (TREE_CODE (base) == SSA_NAME) + { + tree var = SSA_NAME_VAR (base); + if (var && TREE_CODE (var) == PARM_DECL) + { + maybe_warn_read_write_only (cfun->decl, stmt, var, rhs); + return NULL_TREE; + } + } + + if (!VAR_P (base) + || is_global_var (base)) + /* ??? We'd like to use ref_may_alias_global_p but that + excludes global readonly memory and thus we get bogus + warnings from p = cond ? "a" : "b" for example. */ + return NULL_TREE; + } /* Strip the address-of expression from arrays passed to functions. */ if (TREE_CODE (rhs) == ADDR_EXPR) -- cgit v1.1 From 58eec9908c01e2f5a6eb9cd76bbf037bbe2cf5e6 Mon Sep 17 00:00:00 2001 From: Michael Meissner Date: Fri, 13 Aug 2021 19:43:27 -0400 Subject: Fix xxeval predicates (PR 99921). I noticed that the xxeval built-in function used the altivec_register_operand predicate. Since it takes vsx registers, this might force the register allocate to issue a move when it could use a traditional floating point register. This patch fixes that. 2021-08-13 Michael Meissner gcc/ PR target/99921 * config/rs6000/altivec.md (xxeval): Use register_predicate instead of altivec_register_predicate. --- gcc/config/rs6000/altivec.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'gcc') diff --git a/gcc/config/rs6000/altivec.md b/gcc/config/rs6000/altivec.md index d70c17e..fd86c300 100644 --- a/gcc/config/rs6000/altivec.md +++ b/gcc/config/rs6000/altivec.md @@ -3875,9 +3875,9 @@ (define_insn "xxeval" [(set (match_operand:V2DI 0 "register_operand" "=wa") - (unspec:V2DI [(match_operand:V2DI 1 "altivec_register_operand" "wa") - (match_operand:V2DI 2 "altivec_register_operand" "wa") - (match_operand:V2DI 3 "altivec_register_operand" "wa") + (unspec:V2DI [(match_operand:V2DI 1 "register_operand" "wa") + (match_operand:V2DI 2 "register_operand" "wa") + (match_operand:V2DI 3 "register_operand" "wa") (match_operand:QI 4 "u8bit_cint_operand" "n")] UNSPEC_XXEVAL))] "TARGET_POWER10" -- cgit v1.1 From 261512fa6d56481dc37589e5cb4e288539155d57 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Sat, 14 Aug 2021 00:16:29 +0000 Subject: Daily bump. --- gcc/ChangeLog | 60 +++++++++++++++++++++++++++++++++++++++++++++++++ gcc/DATESTAMP | 2 +- gcc/testsuite/ChangeLog | 19 ++++++++++++++++ 3 files changed, 80 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index f26544f..63a8a4f 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,63 @@ +2021-08-13 Michael Meissner + + PR target/99921 + * config/rs6000/altivec.md (xxeval): Use register_predicate + instead of altivec_register_predicate. + +2021-08-13 Martin Sebor + + PR middle-end/101734 + * tree-ssa-uninit.c (maybe_warn_read_write_only): New function. + (maybe_warn_operand): Call it. + +2021-08-13 Martin Liska + + PR ipa/101354 + * attribs.c (decl_attributes): Make naked functions "noipa" + functions. + +2021-08-13 Martin Liska + + PR ipa/101261 + * symtab.c (symtab_node::noninterposable_alias): Do not create + local aliases for target_clone functions as the clonning pass + rejects aliases. + +2021-08-13 Martin Liska + + * opts.c (LIVE_PATCHING_OPTION): Define. + (control_options_for_live_patching): Use it in error messages. + +2021-08-13 Jan Hubicka + + * ipa-modref.c (dump_eaf_flags): Dump EAF_NOREAD. + (implicit_const_eaf_flags, implicit_pure_eaf_flags, + ignore_stores_eaf_flags): New constants. + (remove_useless_eaf_flags): New function. + (eaf_flags_useful_p): Use it. + (deref_flags): Add EAF_NOT_RETURNED if flag is unused; + handle EAF_NOREAD. + (modref_lattice::init): Add EAF_NOREAD. + (modref_lattice::add_escape_point): Do not reacord escape point if + result is unused. + (modref_lattice::merge): EAF_NOESCAPE implies EAF_NODIRECTESCAPE; + use remove_useless_eaf_flags. + (modref_lattice::merge_deref): Use ignore_stores_eaf_flags. + (modref_lattice::merge_direct_load): Add EAF_NOREAD + (analyze_ssa_name_flags): Fix handling EAF_NOT_RETURNED + (analyze_parms): Use remove_useless_eaf_flags. + (ipa_merge_modref_summary_after_inlining): Use ignore_stores_eaf_flags. + (modref_merge_call_site_flags): Add caller and ecf_flags parameter; + use remove_useless_eaf_flags. + (modref_propagate_flags_in_scc): Update. + * ipa-modref.h: Turn eaf_flags_t back to char. + * tree-core.h (EAF_NOT_RETURNED): Fix. + (EAF_NOREAD): New constant + * tree-ssa-alias.c: (ref_maybe_used_by_call_p_1): Check for + EAF_NOREAD. + * tree-ssa-structalias.c (handle_rhs_call): Handle new flags. + (handle_pure_call): Likewise. + 2021-08-12 Jakub Jelinek * tree.def (OMP_MASKED): New tree code. diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index 3f3eb1e..0e1f661 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20210813 +20210814 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 6ee775a..20cf4ec 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,22 @@ +2021-08-13 Martin Sebor + + PR middle-end/101734 + * gcc.dg/uninit-42.c: New test. + +2021-08-13 Martin Liska + + PR ipa/101261 + * gcc.target/i386/pr101261.c: New test. + +2021-08-13 Jan Hubicka + + * gcc.dg/tree-ssa/modref-6.c: Update. + +2021-08-13 prathamesh.kulkarni + + * gcc.target/arm/simd/pr98435.c: Add dg-require-effective-target + arm_softfp_ok. + 2021-08-12 Jakub Jelinek * c-c++-common/gomp/clauses-1.c (bar): Add tests for combined masked -- cgit v1.1 From 240f07805db27cfc746276039c5edccb4c031070 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Sat, 14 Aug 2021 11:44:46 +0200 Subject: i386: Fix ICE with V64QImode broadcast permutation with -mavx512f -mno-avx512bw The testcase shows another problem, for TARGET_AVX512BW we have a single insn doing broadcast from the first element, but don't have one for broadcast of 2nd+ element (so for d->perm[0] we must return false), but for TARGET_AVX512F && !TARGET_AVX512BW we don't even have support for that other broadcast. V64QImode case was just added to the AVX2 cases which had gcc_assert (!TARGET_AVX2 || d->perm[0]); but for V64QImode we actually need gcc_assert (!TARGET_AVX512BW || d->perm[0]); 2021-08-14 Jakub Jelinek PR target/101896 * config/i386/i386-expand.c (expand_vec_perm_broadcast_1) : For this mode assert !TARGET_AVX512BW || d->perm[0] rather than !TARGET_AVX2 || d->perm[0]. * gcc.target/i386/avx512f-pr101896.c: New test. --- gcc/config/i386/i386-expand.c | 5 ++++- gcc/testsuite/gcc.target/i386/avx512f-pr101896.c | 5 +++++ 2 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/gcc.target/i386/avx512f-pr101896.c (limited to 'gcc') diff --git a/gcc/config/i386/i386-expand.c b/gcc/config/i386/i386-expand.c index a652b25..4d7349c 100644 --- a/gcc/config/i386/i386-expand.c +++ b/gcc/config/i386/i386-expand.c @@ -20474,7 +20474,6 @@ expand_vec_perm_broadcast_1 (struct expand_vec_perm_d *d) emit_move_insn (d->target, gen_lowpart (d->vmode, dest)); return true; - case E_V64QImode: case E_V32QImode: case E_V16HImode: case E_V8SImode: @@ -20484,6 +20483,10 @@ expand_vec_perm_broadcast_1 (struct expand_vec_perm_d *d) gcc_assert (!TARGET_AVX2 || d->perm[0]); return false; + case E_V64QImode: + gcc_assert (!TARGET_AVX512BW || d->perm[0]); + return false; + case E_V32HImode: gcc_assert (!TARGET_AVX512BW); return false; diff --git a/gcc/testsuite/gcc.target/i386/avx512f-pr101896.c b/gcc/testsuite/gcc.target/i386/avx512f-pr101896.c new file mode 100644 index 0000000..c1805cc --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/avx512f-pr101896.c @@ -0,0 +1,5 @@ +/* PR target/101896 */ +/* { dg-do compile } */ +/* { dg-options "-O2 -mavx512f -mno-avx512bw" } */ + +#include "../../gcc.dg/torture/vshuf-v64qi.c" -- cgit v1.1 From 96194a07bdbc57dd9733892a791d87dbe25f0802 Mon Sep 17 00:00:00 2001 From: Martin Sebor Date: Sat, 14 Aug 2021 13:25:41 -0600 Subject: Diagnose mismatches between array and scalar new and delete [PR101791]. Resolves: PR middle-end/101791 - missing warning on a mismatch between scalar and array forms of new and delete gcc/ChangeLog: PR middle-end/101791 * gimple-ssa-warn-access.cc (new_delete_mismatch_p): Use new argument to valid_new_delete_pair_p. * tree.c (valid_new_delete_pair_p): Add argument. * tree.h (valid_new_delete_pair_p): Same. gcc/testsuite/ChangeLog: PR middle-end/101791 * g++.dg/warn/Wmismatched-new-delete-6.C: New test. * g++.dg/warn/Wmismatched-new-delete-7.C: New test. --- gcc/gimple-ssa-warn-access.cc | 9 +- .../g++.dg/warn/Wmismatched-new-delete-6.C | 158 +++++++++++++++++++++ .../g++.dg/warn/Wmismatched-new-delete-7.C | 91 ++++++++++++ gcc/tree.c | 28 +++- gcc/tree.h | 4 +- 5 files changed, 284 insertions(+), 6 deletions(-) create mode 100644 gcc/testsuite/g++.dg/warn/Wmismatched-new-delete-6.C create mode 100644 gcc/testsuite/g++.dg/warn/Wmismatched-new-delete-7.C (limited to 'gcc') diff --git a/gcc/gimple-ssa-warn-access.cc b/gcc/gimple-ssa-warn-access.cc index a4559dd..93f43b7 100644 --- a/gcc/gimple-ssa-warn-access.cc +++ b/gcc/gimple-ssa-warn-access.cc @@ -1782,9 +1782,14 @@ new_delete_mismatch_p (tree new_decl, tree delete_decl) /* valid_new_delete_pair_p() returns a conservative result (currently it only handles global operators). A true result is reliable but - a false result doesn't necessarily mean the operators don't match. */ - if (valid_new_delete_pair_p (new_name, delete_name)) + a false result doesn't necessarily mean the operators don't match + unless CERTAIN is set. */ + bool certain; + if (valid_new_delete_pair_p (new_name, delete_name, &certain)) return false; + /* CERTAIN is set when the negative result is certain. */ + if (certain) + return true; /* For anything not handled by valid_new_delete_pair_p() such as member operators compare the individual demangled components of the mangled diff --git a/gcc/testsuite/g++.dg/warn/Wmismatched-new-delete-6.C b/gcc/testsuite/g++.dg/warn/Wmismatched-new-delete-6.C new file mode 100644 index 0000000..e19d000 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wmismatched-new-delete-6.C @@ -0,0 +1,158 @@ +/* PR middle-end/101791 - missing warning on a mismatch between scalar + and array forms of new and delete + { dg-do compile } + { dg-options "-Wall" } */ + +typedef __SIZE_TYPE__ size_t; + +namespace std +{ +#if __cplusplus >= 201703L +enum class align_val_t: size_t { }; +#else +enum align_val_t { }; +#endif + +struct nothrow_t { }; +const nothrow_t nothrow = { }; + +} + +void* operator new (size_t); +void* operator new (size_t, std::align_val_t); +void* operator new (size_t, std::nothrow_t) throw (); +void* operator new (size_t, std::align_val_t, std::nothrow_t) throw (); + +void* operator new[] (size_t); +void* operator new[] (size_t, std::align_val_t); +void* operator new[] (size_t, std::nothrow_t) throw (); +void* operator new[] (size_t, std::align_val_t, std::nothrow_t) throw (); + +void operator delete (void*); +void operator delete (void*, size_t); +void operator delete (void*, std::align_val_t); +void operator delete (void*, size_t, std::align_val_t); +void operator delete (void*, std::nothrow_t) throw (); +void operator delete (void*, std::align_val_t, std::nothrow_t) throw (); + +void operator delete[] (void*); +void operator delete[] (void*, size_t); +void operator delete[] (void*, std::align_val_t); +void operator delete[] (void*, size_t, std::align_val_t); +void operator delete[] (void*, std::nothrow_t) throw (); +void operator delete[] (void*, std::align_val_t, std::nothrow_t) throw (); + + +void sink (void*, ...); + + +void nowarn_scalar_scalar () +{ + { + int *p = new int; + sink (p); + delete p; + } + + { + int *p = new (std::align_val_t (8)) int; + sink (p); + delete p; + } + + { + int *p = new (std::nothrow) int; + sink (p); + delete p; + } + + { + int *p = new (std::align_val_t (8), std::nothrow) int; + sink (p); + delete p; + } +} + +void nowarn_array_array () +{ + { + int *p = new int[__LINE__]; + sink (p); + delete[] p; + } + + { + int *p = new (std::align_val_t (8)) int[__LINE__]; + sink (p); + delete[] p; + } + + { + int *p = new (std::nothrow) int[__LINE__]; + sink (p); + delete[] p; + } + + { + int *p = new (std::align_val_t (8), std::nothrow) int[__LINE__]; + sink (p); + delete[] p; + } +} + + + +void nowarn_scalar_array () +{ + { + int *p = new int; // { dg-message "returned from" } + sink (p); + delete[] p; // { dg-warning "\\\[-Wmismatched-new-delete" } + } + + { + int *p = new (std::align_val_t (8)) int; + sink (p); + delete[] p; // { dg-warning "\\\[-Wmismatched-new-delete" } + } + + { + int *p = new (std::nothrow) int; + sink (p); + delete[] p; // { dg-warning "\\\[-Wmismatched-new-delete" } + } + + { + int *p = new (std::align_val_t (8), std::nothrow) int; + sink (p); + delete[] p; // { dg-warning "\\\[-Wmismatched-new-delete" } + } +} + + +void nowarn_array_scalar () +{ + { + int *p = new int[__LINE__]; + sink (p); + delete p; // { dg-warning "\\\[-Wmismatched-new-delete" } + } + + { + int *p = new (std::align_val_t (8)) int[__LINE__]; + sink (p); + delete p; // { dg-warning "\\\[-Wmismatched-new-delete" } + } + + { + int *p = new (std::nothrow) int[__LINE__]; + sink (p); + delete p; // { dg-warning "\\\[-Wmismatched-new-delete" } + } + + { + int *p = new (std::align_val_t (8), std::nothrow) int[__LINE__]; + sink (p); + delete p; // { dg-warning "\\\[-Wmismatched-new-delete" } + } +} diff --git a/gcc/testsuite/g++.dg/warn/Wmismatched-new-delete-7.C b/gcc/testsuite/g++.dg/warn/Wmismatched-new-delete-7.C new file mode 100644 index 0000000..67a5354 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wmismatched-new-delete-7.C @@ -0,0 +1,91 @@ +/* PR middle-end/101791 - missing warning on a mismatch between scalar + and array forms of new and delete + Verify that likely safe calls to technically mismatched member operator + new and delete are not diagnosed. This test might need to be adjusted + if it turns out the assumptions GCC makes are overly conservative. + { dg-do compile } + { dg-options "-Wall" } */ + +typedef __SIZE_TYPE__ size_t; + +namespace std +{ +#if __cplusplus >= 201703L +enum class align_val_t: size_t { }; +#else +enum align_val_t { }; +#endif + +struct nothrow_t { }; +const nothrow_t nothrow = { }; + +} + +void sink (void*, ...); + +struct X { } x; +struct Y { } y; + +struct A +{ + void* operator new (size_t); + void* operator new (size_t, std::align_val_t); + + void* operator new (size_t, X); + void* operator new (size_t, Y); + + void* operator new (size_t, std::align_val_t, X); + void* operator new (size_t, std::nothrow_t, Y); + + /* A single operator delete callable on the result of calls to any + of the operator new overloads above (this may be too optimistic). */ + void operator delete (void*); +}; + +A* nowarn_align () +{ + /* The following are likely okay given A's definition above but would + not be if A also defined an align_val_t overload of operator delete. */ + A *p = new (std::align_val_t (8)) A; + delete p; + + return new (std::align_val_t (16)) A; +} + +A* nowarn_X () +{ + /* The following are also likely okay given A's definition above but + also would not be if A also defined an overload of operator delete + for X. */ + A *p = new (x) A; + delete p; + return new (x) A; +} + +A* nowarn_Y () +{ + // Same as above. + A *p = new (y) A; + delete p; + return new (y) A; +} + + +A* nowarn_align_X () +{ + // Same as above. + A *p = new (std::align_val_t (32), x) A; + delete p; + + return new (std::align_val_t (64), x) A; +} + + +A* nowarn_nothrow_Y () +{ + // Same as above. + A *p = new (std::nothrow, y) A; + delete p; + return new (std::nothrow, y) A; +} + diff --git a/gcc/tree.c b/gcc/tree.c index a0ff794..6ec8a97 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -14314,17 +14314,28 @@ verify_type_context (location_t loc, type_context_kind context, || targetm.verify_type_context (loc, context, type, silent_p)); } -/* Return that NEW_ASM and DELETE_ASM name a valid pair of new and - delete operators. */ +/* Return true if NEW_ASM and DELETE_ASM name a valid pair of new and + delete operators. Return false if they may or may not name such + a pair and, when nonnull, set *PCERTAIN to true if they certainly + do not. */ bool -valid_new_delete_pair_p (tree new_asm, tree delete_asm) +valid_new_delete_pair_p (tree new_asm, tree delete_asm, + bool *pcertain /* = NULL */) { + bool certain; + if (!pcertain) + pcertain = &certain; + const char *new_name = IDENTIFIER_POINTER (new_asm); const char *delete_name = IDENTIFIER_POINTER (delete_asm); unsigned int new_len = IDENTIFIER_LENGTH (new_asm); unsigned int delete_len = IDENTIFIER_LENGTH (delete_asm); + /* The following failures are due to invalid names so they're not + considered certain mismatches. */ + *pcertain = false; + if (new_len < 5 || delete_len < 6) return false; if (new_name[0] == '_') @@ -14337,11 +14348,19 @@ valid_new_delete_pair_p (tree new_asm, tree delete_asm) ++delete_name, --delete_len; if (new_len < 4 || delete_len < 5) return false; + + /* The following failures are due to names of user-defined operators + so they're also not considered certain mismatches. */ + /* *_len is now just the length after initial underscores. */ if (new_name[0] != 'Z' || new_name[1] != 'n') return false; if (delete_name[0] != 'Z' || delete_name[1] != 'd') return false; + + /* The following failures are certain mismatches. */ + *pcertain = true; + /* _Znw must match _Zdl, _Zna must match _Zda. */ if ((new_name[2] != 'w' || delete_name[2] != 'l') && (new_name[2] != 'a' || delete_name[2] != 'a')) @@ -14380,6 +14399,9 @@ valid_new_delete_pair_p (tree new_asm, tree delete_asm) && !memcmp (delete_name + 5, "St11align_val_tRKSt9nothrow_t", 29)) return true; } + + /* The negative result is conservative. */ + *pcertain = false; return false; } diff --git a/gcc/tree.h b/gcc/tree.h index c3f302a..a26500d 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -5406,7 +5406,9 @@ extern bool gimple_canonical_types_compatible_p (const_tree, const_tree, extern bool type_with_interoperable_signedness (const_tree); extern bitmap get_nonnull_args (const_tree); extern int get_range_pos_neg (tree); -extern bool valid_new_delete_pair_p (tree, tree); + +/* Return true for a valid pair of new and delete operators. */ +extern bool valid_new_delete_pair_p (tree, tree, bool * = NULL); /* Return simplified tree code of type that is used for canonical type merging. */ -- cgit v1.1 From eff8110674ef193481d3657456a262beeb9951ff Mon Sep 17 00:00:00 2001 From: Stafford Horne Date: Tue, 6 Apr 2021 05:47:17 +0900 Subject: or1k: Add mcmodel option to handle large GOTs When building libgeos we get an error with: linux-uclibc/9.3.0/crtbeginS.o: in function `__do_global_dtors_aux': crtstuff.c:(.text+0x118): relocation truncated to fit: R_OR1K_GOT16 against symbol `__cxa_finalize' defined in .text section in /home/shorne/work/openrisc/3eb9f9d0f6d8274b2d19753c006bd83f7d536e3c/output/host/or1k-buildroot-linux-uclibc/sysroot/lib/libc.so. This is caused by GOT code having a limit of 64k. In OpenRISC this looks to be the only relocation code pattern to be limited to 64k. This patch allows specifying a new option -mcmodel=large which can be used to generate 2 more instructions to construct 32-bit addresses for up to 4G GOTs. gcc/ChangeLog: PR target/99783 * config/or1k/or1k-opts.h: New file. * config/or1k/or1k.c (or1k_legitimize_address_1, print_reloc): Support generating gotha relocations if -mcmodel=large is specified. * config/or1k/or1k.h (TARGET_CMODEL_SMALL, TARGET_CMODEL_LARGE): New macros. * config/or1k/or1k.opt (mcmodel=): New option. * doc/invoke.texi (OpenRISC Options): Document mcmodel. --- gcc/config/or1k/or1k-opts.h | 30 ++++++++++++++++++++++++++++++ gcc/config/or1k/or1k.c | 11 +++++++++-- gcc/config/or1k/or1k.h | 7 +++++++ gcc/config/or1k/or1k.opt | 19 +++++++++++++++++++ gcc/doc/invoke.texi | 12 +++++++++++- 5 files changed, 76 insertions(+), 3 deletions(-) create mode 100644 gcc/config/or1k/or1k-opts.h (limited to 'gcc') diff --git a/gcc/config/or1k/or1k-opts.h b/gcc/config/or1k/or1k-opts.h new file mode 100644 index 0000000..f791b89 --- /dev/null +++ b/gcc/config/or1k/or1k-opts.h @@ -0,0 +1,30 @@ +/* Definitions for option handling for OpenRISC. + Copyright (C) 2021 Free Software Foundation, Inc. + Contributed by Stafford Horne. + + 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 + . */ + +#ifndef GCC_OR1K_OPTS_H +#define GCC_OR1K_OPTS_H + +/* The OpenRISC code generation models available. */ +enum or1k_cmodel_type { + CMODEL_SMALL, + CMODEL_LARGE +}; + +#endif /* GCC_OR1K_OPTS_H */ diff --git a/gcc/config/or1k/or1k.c b/gcc/config/or1k/or1k.c index e772a7a..27d3fa1 100644 --- a/gcc/config/or1k/or1k.c +++ b/gcc/config/or1k/or1k.c @@ -750,7 +750,14 @@ or1k_legitimize_address_1 (rtx x, rtx scratch) { base = gen_sym_unspec (base, UNSPEC_GOT); crtl->uses_pic_offset_table = 1; - t2 = gen_rtx_LO_SUM (Pmode, pic_offset_table_rtx, base); + if (TARGET_CMODEL_LARGE) + { + emit_insn (gen_rtx_SET (t1, gen_rtx_HIGH (Pmode, base))); + emit_insn (gen_add3_insn (t1, t1, pic_offset_table_rtx)); + t2 = gen_rtx_LO_SUM (Pmode, t1, base); + } + else + t2 = gen_rtx_LO_SUM (Pmode, pic_offset_table_rtx, base); t2 = gen_const_mem (Pmode, t2); emit_insn (gen_rtx_SET (t1, t2)); base = t1; @@ -1089,7 +1096,7 @@ print_reloc (FILE *stream, rtx x, HOST_WIDE_INT add, reloc_kind kind) no special markup. */ static const char * const relocs[RKIND_MAX][RTYPE_MAX] = { { "lo", "got", "gotofflo", "tpofflo", "gottpofflo", "tlsgdlo" }, - { "ha", NULL, "gotoffha", "tpoffha", "gottpoffha", "tlsgdhi" }, + { "ha", "gotha", "gotoffha", "tpoffha", "gottpoffha", "tlsgdhi" }, }; reloc_type type = RTYPE_DIRECT; diff --git a/gcc/config/or1k/or1k.h b/gcc/config/or1k/or1k.h index fe01ab8..669907e 100644 --- a/gcc/config/or1k/or1k.h +++ b/gcc/config/or1k/or1k.h @@ -21,6 +21,8 @@ #ifndef GCC_OR1K_H #define GCC_OR1K_H +#include "config/or1k/or1k-opts.h" + /* Names to predefine in the preprocessor for this target machine. */ #define TARGET_CPU_CPP_BUILTINS() \ do \ @@ -37,6 +39,11 @@ } \ while (0) +#define TARGET_CMODEL_SMALL \ + (or1k_code_model == CMODEL_SMALL) +#define TARGET_CMODEL_LARGE \ + (or1k_code_model == CMODEL_LARGE) + /* Storage layout. */ #define DEFAULT_SIGNED_CHAR 1 diff --git a/gcc/config/or1k/or1k.opt b/gcc/config/or1k/or1k.opt index 6bd0f3e..cc23e3b 100644 --- a/gcc/config/or1k/or1k.opt +++ b/gcc/config/or1k/or1k.opt @@ -21,6 +21,9 @@ ; See the GCC internals manual (options.texi) for a description of ; this file's format. +HeaderInclude +config/or1k/or1k-opts.h + mhard-div Target RejectNegative InverseMask(SOFT_DIV) Enable generation of hardware divide (l.div, l.divu) instructions. This is the @@ -63,6 +66,22 @@ When -mhard-float is selected, enables generation of unordered floating point compare and set flag (lf.sfun*) instructions. By default functions from libgcc are used to perform unordered floating point compare and set flag operations. +mcmodel= +Target RejectNegative Joined Enum(or1k_cmodel_type) Var(or1k_code_model) Init(CMODEL_SMALL) +Specify the code model used for accessing memory addresses. Specifying large +enables generating binaries with large global offset tables. By default the +value is small. + +Enum +Name(or1k_cmodel_type) Type(enum or1k_cmodel_type) +Known code model types (for use with the -mcmodel= option): + +EnumValue +Enum(or1k_cmodel_type) String(small) Value(CMODEL_SMALL) + +EnumValue +Enum(or1k_cmodel_type) String(large) Value(CMODEL_LARGE) + mcmov Target RejectNegative Mask(CMOV) Enable generation of conditional move (l.cmov) instructions. By default the diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 57b97a0..d8a6b0b 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -1141,7 +1141,8 @@ Objective-C and Objective-C++ Dialects}. @gccoptlist{-mboard=@var{name} -mnewlib -mhard-mul -mhard-div @gol -msoft-mul -msoft-div @gol -msoft-float -mhard-float -mdouble-float -munordered-float @gol --mcmov -mror -mrori -msext -msfimm -mshftimm} +-mcmov -mror -mrori -msext -msfimm -mshftimm @gol +-mcmodel=@var{code-model}} @emph{PDP-11 Options} @gccoptlist{-mfpu -msoft-float -mac0 -mno-ac0 -m40 -m45 -m10 @gol @@ -26684,6 +26685,15 @@ Enable generation of shift with immediate (@code{l.srai}, @code{l.srli}, @code{l.slli}) instructions. By default extra instructions will be generated to store the immediate to a register first. +@item -mcmodel=small +@opindex mcmodel=small +Generate OpenRISC code for the small model: The GOT is limited to 64k. This is +the default model. + +@item -mcmodel=large +@opindex mcmodel=large +Generate OpenRISC code for the large model: The GOT may grow up to 4G in size. + @end table -- cgit v1.1 From 7dd8f1982c65866eba435112633db2a34d2814a7 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Sun, 15 Aug 2021 00:16:27 +0000 Subject: Daily bump. --- gcc/ChangeLog | 27 +++++++++++++++++++++++++++ gcc/DATESTAMP | 2 +- gcc/testsuite/ChangeLog | 11 +++++++++++ 3 files changed, 39 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 63a8a4f..a9753a5 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,30 @@ +2021-08-14 Stafford Horne + + PR target/99783 + * config/or1k/or1k-opts.h: New file. + * config/or1k/or1k.c (or1k_legitimize_address_1, print_reloc): + Support generating gotha relocations if -mcmodel=large is + specified. + * config/or1k/or1k.h (TARGET_CMODEL_SMALL, TARGET_CMODEL_LARGE): + New macros. + * config/or1k/or1k.opt (mcmodel=): New option. + * doc/invoke.texi (OpenRISC Options): Document mcmodel. + +2021-08-14 Martin Sebor + + PR middle-end/101791 + * gimple-ssa-warn-access.cc (new_delete_mismatch_p): Use new argument + to valid_new_delete_pair_p. + * tree.c (valid_new_delete_pair_p): Add argument. + * tree.h (valid_new_delete_pair_p): Same. + +2021-08-14 Jakub Jelinek + + PR target/101896 + * config/i386/i386-expand.c (expand_vec_perm_broadcast_1) + : For this mode assert + !TARGET_AVX512BW || d->perm[0] rather than !TARGET_AVX2 || d->perm[0]. + 2021-08-13 Michael Meissner PR target/99921 diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index 0e1f661..bcfecf4 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20210814 +20210815 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 20cf4ec..48eb054 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,14 @@ +2021-08-14 Martin Sebor + + PR middle-end/101791 + * g++.dg/warn/Wmismatched-new-delete-6.C: New test. + * g++.dg/warn/Wmismatched-new-delete-7.C: New test. + +2021-08-14 Jakub Jelinek + + PR target/101896 + * gcc.target/i386/avx512f-pr101896.c: New test. + 2021-08-13 Martin Sebor PR middle-end/101734 -- cgit v1.1 From 829931ec93ab7d5ab73f31be9da504abb6ae459e Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Fri, 13 Aug 2021 17:21:54 -0700 Subject: libgo: various fixes for Solaris support Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/342189 --- gcc/go/gofrontend/MERGE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 3000285..950f179 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -f2b7a2ce94127ad444a772bd1631516c5c67fb73 +77bc32767b61feb6499ca7921e96b356603517dc The first line of this file holds the git revision number of the last merge done from the gofrontend repository. -- cgit v1.1 From 882f1d58bfa56737ff2de84c3cd1e0acfc318b86 Mon Sep 17 00:00:00 2001 From: Jeff Law Date: Sun, 15 Aug 2021 00:13:23 -0400 Subject: Improve many SImode shifts on the H8/300H As I've mentioned before, the H8/300H can only shift a single bit position at a time. Naturally this means many shifts are implemented as loops. There's a variety of special cases that we can do without loops by using rotates, sub-word moves, etc. The general guidance for the port has been to only use inline or special sequences if they're shorter or just one instruction longer than the loop. This was pretty reasonable guidance for QI/HI mode. It was relaxed a bit about 10 years ago for HImode in particular where the kpit team realized they could save 50-100 cycles for some shifts by allowing 2 instructions of code growth over the loop implementation. But they only re-tuned HImode shifts. There's even bigger benefits for re-tuning SImode shifts. There's cases where we can save close to 200 cycles by allowing 2 additional instructions. This patch re-tunes SImode shifts on the H8/300H primarily by inlining more often or using a special sequence + inlining for residuals. Both cases were already supported and this just uses those existing capabilities more often, so it was trivial to implement. I think there's some cases were entirely new special sequences could be used, but I haven't tried those yet. gcc/ * config/h8300/h8300.c (shift_alg_si): Retune H8/300H shifts to allow a bit more code growth, saving many dozens of cycles. (h8300_option_override): Adjus shift_alg_si if optimizing for code size. (get_shift_alg): Use special + inline shifts for residuals in more cases. --- gcc/config/h8300/h8300.c | 52 ++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 41 insertions(+), 11 deletions(-) (limited to 'gcc') diff --git a/gcc/config/h8300/h8300.c b/gcc/config/h8300/h8300.c index d2f6548..7959ad1 100644 --- a/gcc/config/h8300/h8300.c +++ b/gcc/config/h8300/h8300.c @@ -228,18 +228,18 @@ static enum shift_alg shift_alg_si[2][3][32] = { /* 8 9 10 11 12 13 14 15 */ /* 16 17 18 19 20 21 22 23 */ /* 24 25 26 27 28 29 30 31 */ - { INL, INL, INL, INL, INL, LOP, LOP, LOP, + { INL, INL, INL, INL, INL, INL, INL, LOP, SPC, LOP, LOP, LOP, LOP, LOP, LOP, SPC, - SPC, SPC, SPC, SPC, LOP, LOP, LOP, LOP, - SPC, LOP, LOP, LOP, SPC, SPC, SPC, SPC }, /* SHIFT_ASHIFT */ - { INL, INL, INL, INL, INL, LOP, LOP, LOP, + SPC, SPC, SPC, SPC, SPC, SPC, SPC, SPC, + SPC, SPC, SPC, SPC, SPC, SPC, SPC, SPC }, /* SHIFT_ASHIFT */ + { INL, INL, INL, INL, INL, INL, INL, LOP, SPC, LOP, LOP, LOP, LOP, LOP, LOP, SPC, - SPC, SPC, SPC, SPC, LOP, LOP, LOP, LOP, - SPC, LOP, LOP, LOP, SPC, SPC, SPC, SPC }, /* SHIFT_LSHIFTRT */ - { INL, INL, INL, INL, INL, LOP, LOP, LOP, + SPC, SPC, SPC, SPC, SPC, SPC, SPC, SPC, + SPC, SPC, SPC, SPC, SPC, SPC, SPC, SPC }, /* SHIFT_LSHIFTRT */ + { INL, INL, INL, INL, INL, INL, INL, LOP, SPC, LOP, LOP, LOP, LOP, LOP, LOP, LOP, - SPC, SPC, SPC, SPC, LOP, LOP, LOP, LOP, - SPC, LOP, LOP, LOP, LOP, LOP, LOP, SPC }, /* SHIFT_ASHIFTRT */ + SPC, SPC, SPC, SPC, SPC, SPC, SPC, SPC, + SPC, SPC, SPC, SPC, LOP, LOP, LOP, SPC }, /* SHIFT_ASHIFTRT */ }, { /* TARGET_H8300S */ @@ -343,6 +343,36 @@ h8300_option_override (void) shift_alg_hi[H8_300H][SHIFT_ASHIFTRT][13] = SHIFT_LOOP; shift_alg_hi[H8_300H][SHIFT_ASHIFTRT][14] = SHIFT_LOOP; + shift_alg_si[H8_300H][SHIFT_ASHIFT][5] = SHIFT_LOOP; + shift_alg_si[H8_300H][SHIFT_ASHIFT][6] = SHIFT_LOOP; + shift_alg_si[H8_300H][SHIFT_ASHIFT][20] = SHIFT_LOOP; + shift_alg_si[H8_300H][SHIFT_ASHIFT][21] = SHIFT_LOOP; + shift_alg_si[H8_300H][SHIFT_ASHIFT][22] = SHIFT_LOOP; + shift_alg_si[H8_300H][SHIFT_ASHIFT][23] = SHIFT_LOOP; + shift_alg_si[H8_300H][SHIFT_ASHIFT][25] = SHIFT_LOOP; + shift_alg_si[H8_300H][SHIFT_ASHIFT][26] = SHIFT_LOOP; + shift_alg_si[H8_300H][SHIFT_ASHIFT][27] = SHIFT_LOOP; + + shift_alg_si[H8_300H][SHIFT_LSHIFTRT][5] = SHIFT_LOOP; + shift_alg_si[H8_300H][SHIFT_LSHIFTRT][6] = SHIFT_LOOP; + shift_alg_si[H8_300H][SHIFT_LSHIFTRT][20] = SHIFT_LOOP; + shift_alg_si[H8_300H][SHIFT_LSHIFTRT][21] = SHIFT_LOOP; + shift_alg_si[H8_300H][SHIFT_LSHIFTRT][22] = SHIFT_LOOP; + shift_alg_si[H8_300H][SHIFT_LSHIFTRT][23] = SHIFT_LOOP; + shift_alg_si[H8_300H][SHIFT_LSHIFTRT][25] = SHIFT_LOOP; + shift_alg_si[H8_300H][SHIFT_LSHIFTRT][26] = SHIFT_LOOP; + shift_alg_si[H8_300H][SHIFT_LSHIFTRT][27] = SHIFT_LOOP; + + shift_alg_si[H8_300H][SHIFT_ASHIFTRT][5] = SHIFT_LOOP; + shift_alg_si[H8_300H][SHIFT_ASHIFTRT][6] = SHIFT_LOOP; + shift_alg_si[H8_300H][SHIFT_ASHIFTRT][20] = SHIFT_LOOP; + shift_alg_si[H8_300H][SHIFT_ASHIFTRT][21] = SHIFT_LOOP; + shift_alg_si[H8_300H][SHIFT_ASHIFTRT][22] = SHIFT_LOOP; + shift_alg_si[H8_300H][SHIFT_ASHIFTRT][23] = SHIFT_LOOP; + shift_alg_si[H8_300H][SHIFT_ASHIFTRT][25] = SHIFT_LOOP; + shift_alg_si[H8_300H][SHIFT_ASHIFTRT][26] = SHIFT_LOOP; + shift_alg_si[H8_300H][SHIFT_ASHIFTRT][27] = SHIFT_LOOP; + /* H8S */ shift_alg_hi[H8_S][SHIFT_ASHIFTRT][14] = SHIFT_LOOP; } @@ -3784,7 +3814,7 @@ get_shift_alg (enum shift_type shift_type, enum shift_mode shift_mode, gcc_unreachable (); } } - else if ((TARGET_H8300H && count >= 16 && count <= 19) + else if ((TARGET_H8300H && count >= 16 && count <= 23) || (TARGET_H8300S && count >= 16 && count <= 21)) { info->remainder = count - 16; @@ -3804,7 +3834,7 @@ get_shift_alg (enum shift_type shift_type, enum shift_mode shift_mode, goto end; } } - else if ((TARGET_H8300H && count == 24) + else if ((TARGET_H8300H && count >= 24 || count <= 27) || (TARGET_H8300S && count >= 24 && count <= 25)) { info->remainder = count - 24; -- cgit v1.1 From 34ce7f7a9a64dd69dd6a77dfd4a77406c3c71014 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Chigot?= Date: Thu, 12 Aug 2021 13:17:15 -0400 Subject: aix: 64 bit AIX TLS libpthread dependency. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 64bit XCOFF files will generated TLS access, with local-exec or global-exec models, by an access to R13. Thus, there isn't any reference to a TLS symbol. The problem is that it allows programs with TLS to be compiled and linked even without -pthread. Most of the time, it will result in a segfault when trying to access a TLS variable. But sometimes, it might create a memory corruption. This patch forces a reference to __tls_get_addr() to ensure link will fail without -pthread. gcc/ChangeLog: 2021-08-11 Clément Chigot * config/rs6000/rs6000.c (xcoff_tls_exec_model_detected): New. (rs6000_legitimize_tls_address_aix): Use it. (rs6000_xcoff_file_end): Add ".ref __tls_get_addr" when xcoff_tls_exec_model_detected is true. --- gcc/config/rs6000/rs6000.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index 60f406a..e073b26 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -127,6 +127,9 @@ scalar_int_mode rs6000_pmode; bool rs6000_passes_ieee128 = false; #endif +/* Track use of r13 in 64bit AIX TLS. */ +static bool xcoff_tls_exec_model_detected = false; + /* Generate the manged name (i.e. U10__float128) used in GCC 8.1, and not the name used in current releases (i.e. u9__ieee128). */ static bool ieee128_mangling_gcc_8_1; @@ -9397,7 +9400,10 @@ rs6000_legitimize_tls_address_aix (rtx addr, enum tls_model model) emit_insn (gen_tls_get_tpointer (tlsreg)); } else - tlsreg = gen_rtx_REG (DImode, 13); + { + tlsreg = gen_rtx_REG (DImode, 13); + xcoff_tls_exec_model_detected = true; + } /* Load the TOC value into temporary register. */ tmpreg = gen_reg_rtx (Pmode); @@ -21122,6 +21128,12 @@ rs6000_xcoff_file_end (void) fputs (TARGET_32BIT ? "\t.long _section_.text\n" : "\t.llong _section_.text\n", asm_out_file); + + if (xcoff_tls_exec_model_detected) + { + /* Add a .ref to __tls_get_addr to force libpthread dependency. */ + fputs ("\t.extern __tls_get_addr\n\t.ref __tls_get_addr\n", asm_out_file); + } } struct declare_alias_data -- cgit v1.1 From bbf19f9c20515da9fcd23f08c8139427374e8d77 Mon Sep 17 00:00:00 2001 From: Harald Anlauf Date: Sun, 15 Aug 2021 20:13:11 +0200 Subject: Fortran: fix checks for STAT= and ERRMSG= arguments of SYNC ALL/SYNC IMAGES gcc/fortran/ChangeLog: PR fortran/99351 * match.c (sync_statement): Replace %v code by %e in gfc_match to allow for function references as STAT and ERRMSG arguments. * resolve.c (resolve_sync): Adjust checks of STAT= and ERRMSG= to being definable arguments. Function references with a data pointer result are accepted. * trans-stmt.c (gfc_trans_sync): Adjust assertion. gcc/testsuite/ChangeLog: PR fortran/99351 * gfortran.dg/coarray_sync.f90: New test. * gfortran.dg/coarray_3.f90: Adjust error messages. --- gcc/fortran/match.c | 4 +-- gcc/fortran/resolve.c | 28 ++++++++++++------- gcc/fortran/trans-stmt.c | 6 ++-- gcc/testsuite/gfortran.dg/coarray_3.f90 | 4 +-- gcc/testsuite/gfortran.dg/coarray_sync.f90 | 44 ++++++++++++++++++++++++++++++ 5 files changed, 70 insertions(+), 16 deletions(-) create mode 100644 gcc/testsuite/gfortran.dg/coarray_sync.f90 (limited to 'gcc') diff --git a/gcc/fortran/match.c b/gcc/fortran/match.c index b110548..16502da 100644 --- a/gcc/fortran/match.c +++ b/gcc/fortran/match.c @@ -3855,7 +3855,7 @@ sync_statement (gfc_statement st) for (;;) { - m = gfc_match (" stat = %v", &tmp); + m = gfc_match (" stat = %e", &tmp); if (m == MATCH_ERROR) goto syntax; if (m == MATCH_YES) @@ -3875,7 +3875,7 @@ sync_statement (gfc_statement st) break; } - m = gfc_match (" errmsg = %v", &tmp); + m = gfc_match (" errmsg = %e", &tmp); if (m == MATCH_ERROR) goto syntax; if (m == MATCH_YES) diff --git a/gcc/fortran/resolve.c b/gcc/fortran/resolve.c index 5923646..959f0be 100644 --- a/gcc/fortran/resolve.c +++ b/gcc/fortran/resolve.c @@ -10236,19 +10236,27 @@ resolve_sync (gfc_code *code) /* Check STAT. */ gfc_resolve_expr (code->expr2); - if (code->expr2 - && (code->expr2->ts.type != BT_INTEGER || code->expr2->rank != 0 - || code->expr2->expr_type != EXPR_VARIABLE)) - gfc_error ("STAT= argument at %L must be a scalar INTEGER variable", - &code->expr2->where); + if (code->expr2) + { + if (code->expr2->ts.type != BT_INTEGER || code->expr2->rank != 0) + gfc_error ("STAT= argument at %L must be a scalar INTEGER variable", + &code->expr2->where); + else + gfc_check_vardef_context (code->expr2, false, false, false, + _("STAT variable")); + } /* Check ERRMSG. */ gfc_resolve_expr (code->expr3); - if (code->expr3 - && (code->expr3->ts.type != BT_CHARACTER || code->expr3->rank != 0 - || code->expr3->expr_type != EXPR_VARIABLE)) - gfc_error ("ERRMSG= argument at %L must be a scalar CHARACTER variable", - &code->expr3->where); + if (code->expr3) + { + if (code->expr3->ts.type != BT_CHARACTER || code->expr3->rank != 0) + gfc_error ("ERRMSG= argument at %L must be a scalar CHARACTER variable", + &code->expr3->where); + else + gfc_check_vardef_context (code->expr3, false, false, false, + _("ERRMSG variable")); + } } diff --git a/gcc/fortran/trans-stmt.c b/gcc/fortran/trans-stmt.c index 7cbdef7..11df186 100644 --- a/gcc/fortran/trans-stmt.c +++ b/gcc/fortran/trans-stmt.c @@ -1226,7 +1226,8 @@ gfc_trans_sync (gfc_code *code, gfc_exec_op type) if (code->expr2) { - gcc_assert (code->expr2->expr_type == EXPR_VARIABLE); + gcc_assert (code->expr2->expr_type == EXPR_VARIABLE + || code->expr2->expr_type == EXPR_FUNCTION); gfc_init_se (&argse, NULL); gfc_conv_expr_val (&argse, code->expr2); stat = argse.expr; @@ -1236,7 +1237,8 @@ gfc_trans_sync (gfc_code *code, gfc_exec_op type) if (code->expr3 && flag_coarray == GFC_FCOARRAY_LIB) { - gcc_assert (code->expr3->expr_type == EXPR_VARIABLE); + gcc_assert (code->expr3->expr_type == EXPR_VARIABLE + || code->expr3->expr_type == EXPR_FUNCTION); gfc_init_se (&argse, NULL); argse.want_pointer = 1; gfc_conv_expr (&argse, code->expr3); diff --git a/gcc/testsuite/gfortran.dg/coarray_3.f90 b/gcc/testsuite/gfortran.dg/coarray_3.f90 index d152ce1..1c294cd 100644 --- a/gcc/testsuite/gfortran.dg/coarray_3.f90 +++ b/gcc/testsuite/gfortran.dg/coarray_3.f90 @@ -11,11 +11,11 @@ character(len=30) :: str(2) critical fkl ! { dg-error "Syntax error in CRITICAL" } end critical fkl ! { dg-error "Expecting END PROGRAM" } -sync all (stat=1) ! { dg-error "Syntax error in SYNC ALL" } +sync all (stat=1) ! { dg-error "Non-variable expression" } sync all ( stat = n,stat=k) ! { dg-error "Redundant STAT" } sync memory (errmsg=str) ! { dg-error "must be a scalar CHARACTER variable" } sync memory (errmsg=n) ! { dg-error "must be a scalar CHARACTER variable" } -sync images (*, stat=1.0) ! { dg-error "Syntax error in SYNC IMAGES" } +sync images (*, stat=1.0) ! { dg-error "must be a scalar INTEGER variable" } sync images (-1) ! { dg-error "must between 1 and num_images" } sync images (1) sync images ( [ 1 ]) diff --git a/gcc/testsuite/gfortran.dg/coarray_sync.f90 b/gcc/testsuite/gfortran.dg/coarray_sync.f90 new file mode 100644 index 0000000..f3d6be1 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/coarray_sync.f90 @@ -0,0 +1,44 @@ +! { dg-do compile } +! { dg-options "-fcoarray=lib" } +! PR fortran/99351 - ICE in gfc_finish_var_decl, at fortran/trans-decl.c:695 + +module m + character(3), parameter :: c = 'abc' + integer, parameter :: s = 42 + integer, target :: i + character(:), allocatable :: a + target :: a +contains + subroutine s1 + allocate (character(42) :: a) + sync all (stat=i) + sync all (stat=f()) + sync all (errmsg=a) + sync all (errmsg=p()) + sync all (stat=a%len) ! { dg-error "variable definition context" } + sync all (stat=s) ! { dg-error "variable definition context" } + sync all (errmsg=c) ! { dg-error "variable definition context" } + end + subroutine s2 + sync images (*, stat=i) + sync images (*, errmsg=a) + sync images (*, stat=a%len) ! { dg-error "variable definition context" } + sync images (*, stat=s) ! { dg-error "variable definition context" } + sync images (*, errmsg=c) ! { dg-error "variable definition context" } + end + subroutine s3 + sync memory (stat=i,errmsg=p()) + sync memory (stat=f(),errmsg=a) + sync memory (stat=a%len) ! { dg-error "variable definition context" } + sync memory (stat=s) ! { dg-error "variable definition context" } + sync memory (errmsg=c) ! { dg-error "variable definition context" } + end + integer function f() + pointer :: f + f => i + end function f + function p() + character(:), pointer :: p + p => a + end function p +end -- cgit v1.1 From 94974e8b580919ded10c3e73348d7af68e74736a Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Mon, 16 Aug 2021 00:16:32 +0000 Subject: Daily bump. --- gcc/ChangeLog | 16 ++++++++++++++++ gcc/DATESTAMP | 2 +- gcc/fortran/ChangeLog | 10 ++++++++++ gcc/testsuite/ChangeLog | 6 ++++++ 4 files changed, 33 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index a9753a5..545a81d 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,19 @@ +2021-08-15 Clément Chigot + + * config/rs6000/rs6000.c (xcoff_tls_exec_model_detected): New. + (rs6000_legitimize_tls_address_aix): Use it. + (rs6000_xcoff_file_end): Add ".ref __tls_get_addr" when + xcoff_tls_exec_model_detected is true. + +2021-08-15 Jeff Law + + * config/h8300/h8300.c (shift_alg_si): Retune H8/300H shifts + to allow a bit more code growth, saving many dozens of cycles. + (h8300_option_override): Adjus shift_alg_si if optimizing for + code size. + (get_shift_alg): Use special + inline shifts for residuals + in more cases. + 2021-08-14 Stafford Horne PR target/99783 diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index bcfecf4..3d4cb61 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20210815 +20210816 diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index 7e1db26..f4016f6 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,13 @@ +2021-08-15 Harald Anlauf + + PR fortran/99351 + * match.c (sync_statement): Replace %v code by %e in gfc_match to + allow for function references as STAT and ERRMSG arguments. + * resolve.c (resolve_sync): Adjust checks of STAT= and ERRMSG= to + being definable arguments. Function references with a data + pointer result are accepted. + * trans-stmt.c (gfc_trans_sync): Adjust assertion. + 2021-08-12 Tobias Burnus * gfortran.h (gfc_omp_proc_bind_kind): Add OMP_PROC_BIND_PRIMARY. diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 48eb054..92fc81a 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2021-08-15 Harald Anlauf + + PR fortran/99351 + * gfortran.dg/coarray_sync.f90: New test. + * gfortran.dg/coarray_3.f90: Adjust error messages. + 2021-08-14 Martin Sebor PR middle-end/101791 -- cgit v1.1 From fdd40498d1981fde0720a0886d6f59ea5fb7ab40 Mon Sep 17 00:00:00 2001 From: Kito Cheng Date: Tue, 20 Jul 2021 10:53:18 +0800 Subject: RISC-V: Allow multi-lib build with different code model --with-multilib-generator was only support for different ISA/ABI combination, however code model is effect the code gen a lots it should able to handled in multilib mechanism. Adding `--cmodel=` option to `--with-multilib-generator` to generating multilib combination with different code model. E.g. --with-multilib-generator="rv64ima-lp64--;--cmodel=medlow,medany" will generate 3 multi-lib suppport: 1) rv64ima with lp64 2) rv64ima with lp64 and medlow code model 3) rv64ima with lp64 and medany code model gcc/ * config/riscv/multilib-generator: Support code model option for multi-lib. * doc/install.texi: Add document of new option for --with-multilib-generator. --- gcc/config/riscv/multilib-generator | 86 ++++++++++++++++++++++++------------- gcc/doc/install.texi | 17 ++++++++ 2 files changed, 73 insertions(+), 30 deletions(-) (limited to 'gcc') diff --git a/gcc/config/riscv/multilib-generator b/gcc/config/riscv/multilib-generator index a204543..358bda9 100755 --- a/gcc/config/riscv/multilib-generator +++ b/gcc/config/riscv/multilib-generator @@ -40,6 +40,7 @@ import collections import itertools from functools import reduce import subprocess +import argparse # # TODO: Add test for this script. @@ -127,44 +128,69 @@ def expand_combination(ext): return ext -for cfg in sys.argv[1:]: - try: - (arch, abi, extra, ext) = cfg.split('-') - except: - print ("Invalid configure string %s, ---\n" - " and can be empty, " - "e.g. rv32imafd-ilp32--" % cfg) - sys.exit(1) - - arch = arch_canonicalize (arch) - arches[arch] = 1 - abis[abi] = 1 - extra = list(filter(None, extra.split(','))) - ext_combs = expand_combination(ext) - alts = sum([[x] + [x + y for y in ext_combs] for x in [arch] + extra], []) - alts = list(map(arch_canonicalize, alts)) +multilib_cfgs = filter(lambda x:not x.startswith("--"), sys.argv[1:]) +options = filter(lambda x:x.startswith("--"), sys.argv[1:]) + +parser = argparse.ArgumentParser() +parser.add_argument("--cmodel", type=str) +parser.add_argument("cfgs", type=str, nargs='*') +args = parser.parse_args() + +if args.cmodel: + cmodels = [None] + args.cmodel.split(",") +else: + cmodels = [None] + +cmodel_options = '/'.join(['mcmodel=%s' % x for x in cmodels[1:]]) +cmodel_dirnames = ' \\\n'.join(cmodels[1:]) + +for cmodel in cmodels: + for cfg in args.cfgs: + try: + (arch, abi, extra, ext) = cfg.split('-') + except: + print ("Invalid configure string %s, ---\n" + " and can be empty, " + "e.g. rv32imafd-ilp32--" % cfg) + sys.exit(1) + + # Compact code model only support rv64. + if cmodel == "compact" and arch.startswith("rv32"): + continue - # Drop duplicated entry. - alts = unique(alts) + arch = arch_canonicalize (arch) + arches[arch] = 1 + abis[abi] = 1 + extra = list(filter(None, extra.split(','))) + ext_combs = expand_combination(ext) + alts = sum([[x] + [x + y for y in ext_combs] for x in [arch] + extra], []) + alts = list(map(arch_canonicalize, alts)) - for alt in alts: - if alt == arch: - continue - arches[alt] = 1 - reuse.append('march.%s/mabi.%s=march.%s/mabi.%s' % (arch, abi, alt, abi)) - required.append('march=%s/mabi=%s' % (arch, abi)) + # Drop duplicated entry. + alts = unique(alts) + + for alt in alts[1:]: + if alt == arch: + continue + arches[alt] = 1 + reuse.append('march.%s/mabi.%s=march.%s/mabi.%s' % (arch, abi, alt, abi)) + + if cmodel: + required.append('march=%s/mabi=%s/mcmodel=%s' % (arch, abi, cmodel)) + else: + required.append('march=%s/mabi=%s' % (arch, abi)) -arch_options = '/'.join(['march=%s' % x for x in arches.keys()]) -arch_dirnames = ' \\\n'.join(arches.keys()) + arch_options = '/'.join(['march=%s' % x for x in arches.keys()]) + arch_dirnames = ' \\\n'.join(arches.keys()) -abi_options = '/'.join(['mabi=%s' % x for x in abis.keys()]) -abi_dirnames = ' \\\n'.join(abis.keys()) + abi_options = '/'.join(['mabi=%s' % x for x in abis.keys()]) + abi_dirnames = ' \\\n'.join(abis.keys()) prog = sys.argv[0].split('/')[-1] print('# This file was generated by %s with the command:' % prog) print('# %s' % ' '.join(sys.argv)) -print('MULTILIB_OPTIONS = %s %s' % (arch_options, abi_options)) -print('MULTILIB_DIRNAMES = %s %s' % (arch_dirnames, abi_dirnames)) +print('MULTILIB_OPTIONS = %s %s %s' % (arch_options, abi_options, cmodel_options)) +print('MULTILIB_DIRNAMES = %s %s %s' % (arch_dirnames, abi_dirnames, cmodel_dirnames)) print('MULTILIB_REQUIRED = %s' % ' \\\n'.join(required)) print('MULTILIB_REUSE = %s' % ' \\\n'.join(reuse)) diff --git a/gcc/doc/install.texi b/gcc/doc/install.texi index 6eee1bb..8e974d2 100644 --- a/gcc/doc/install.texi +++ b/gcc/doc/install.texi @@ -1328,6 +1328,23 @@ rv64imac with lp64 and rv64imafc with lp64 will reuse this multi-lib set. rv64ima-lp64--f,c,fc @end smallexample +@option{--with-multilib-generator} have an optional configuration argument +@option{--cmodel=val} for code model, this option will expand with other +config options, @var{val} is a comma separated list of possible code model, +currently we support medlow and medany. + +Example 5: Add multi-lib suppport for rv64ima with lp64; rv64ima with lp64 and +medlow code model +@smallexample +rv64ima-lp64--;--cmodel=medlow +@end smallexample + +Example 6: Add multi-lib suppport for rv64ima with lp64; rv64ima with lp64 and +medlow code model; rv64ima with lp64 and medany code model +@smallexample +rv64ima-lp64--;--cmodel=medlow,medany +@end smallexample + @item --with-endian=@var{endians} Specify what endians to use. Currently only implemented for sh*-*-*. -- cgit v1.1 From 53d5b59cb3b417ab8293702aacc75a9bbb3ead78 Mon Sep 17 00:00:00 2001 From: Tobias Burnus Date: Mon, 16 Aug 2021 09:26:26 +0200 Subject: Fortran/OpenMP: Add support for OpenMP 5.1 masked construct Commit r12-2891-gd0befed793b94f3f407be44e6f69f81a02f5f073 added C/C++ support for the masked construct. This patch extends it to Fortran. gcc/fortran/ChangeLog: * dump-parse-tree.c (show_omp_clauses): Handle 'filter' clause. (show_omp_node, show_code_node): Handle (combined) omp masked construct. * frontend-passes.c (gfc_code_walker): Likewise. * gfortran.h (enum gfc_statement): Add ST_OMP_*_MASKED*. (enum gfc_exec_op): Add EXEC_OMP_*_MASKED*. * match.h (gfc_match_omp_masked, gfc_match_omp_masked_taskloop, gfc_match_omp_masked_taskloop_simd, gfc_match_omp_parallel_masked, gfc_match_omp_parallel_masked_taskloop, gfc_match_omp_parallel_masked_taskloop_simd): New prototypes. * openmp.c (enum omp_mask1): Add OMP_CLAUSE_FILTER. (gfc_match_omp_clauses): Match it. (OMP_MASKED_CLAUSES, gfc_match_omp_parallel_masked, gfc_match_omp_parallel_masked_taskloop, gfc_match_omp_parallel_masked_taskloop_simd, gfc_match_omp_masked, gfc_match_omp_masked_taskloop, gfc_match_omp_masked_taskloop_simd): New. (resolve_omp_clauses): Resolve filter clause. (gfc_resolve_omp_parallel_blocks, resolve_omp_do, omp_code_to_statement, gfc_resolve_omp_directive): Handle omp masked constructs. * parse.c (decode_omp_directive, case_exec_markers, gfc_ascii_statement, parse_omp_do, parse_omp_structured_block, parse_executable): Likewise. * resolve.c (gfc_resolve_blocks, gfc_resolve_code): Likewise. * st.c (gfc_free_statement): Likewise. * trans-openmp.c (gfc_trans_omp_clauses): Handle filter clause. (GFC_OMP_SPLIT_MASKED, GFC_OMP_MASK_MASKED): New enum values. (gfc_trans_omp_masked): New. (gfc_split_omp_clauses): Handle combined masked directives. (gfc_trans_omp_master_taskloop): Rename to ... (gfc_trans_omp_master_masked_taskloop): ... this; handle also combined masked directives. (gfc_trans_omp_parallel_master): Rename to ... (gfc_trans_omp_parallel_master_masked): ... this; handle combined masked directives. (gfc_trans_omp_directive): Handle EXEC_OMP_*_MASKED*. * trans.c (trans_code): Likewise. libgomp/ChangeLog: * testsuite/libgomp.fortran/masked-1.f90: New test. gcc/testsuite/ChangeLog: * gfortran.dg/gomp/masked-1.f90: New test. * gfortran.dg/gomp/masked-2.f90: New test. * gfortran.dg/gomp/masked-3.f90: New test. * gfortran.dg/gomp/masked-combined-1.f90: New test. * gfortran.dg/gomp/masked-combined-2.f90: New test. --- gcc/fortran/dump-parse-tree.c | 24 +++ gcc/fortran/frontend-passes.c | 3 + gcc/fortran/gfortran.h | 14 +- gcc/fortran/match.h | 6 + gcc/fortran/openmp.c | 98 ++++++++++++ gcc/fortran/parse.c | 91 ++++++++++- gcc/fortran/resolve.c | 15 ++ gcc/fortran/st.c | 6 + gcc/fortran/trans-openmp.c | 176 +++++++++++++++++---- gcc/fortran/trans.c | 6 + gcc/testsuite/gfortran.dg/gomp/masked-1.f90 | 94 +++++++++++ gcc/testsuite/gfortran.dg/gomp/masked-2.f90 | 46 ++++++ gcc/testsuite/gfortran.dg/gomp/masked-3.f90 | 12 ++ .../gfortran.dg/gomp/masked-combined-1.f90 | 65 ++++++++ .../gfortran.dg/gomp/masked-combined-2.f90 | 24 +++ 15 files changed, 647 insertions(+), 33 deletions(-) create mode 100644 gcc/testsuite/gfortran.dg/gomp/masked-1.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/masked-2.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/masked-3.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/masked-combined-1.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/masked-combined-2.f90 (limited to 'gcc') diff --git a/gcc/fortran/dump-parse-tree.c b/gcc/fortran/dump-parse-tree.c index 360abf1..53c49fe 100644 --- a/gcc/fortran/dump-parse-tree.c +++ b/gcc/fortran/dump-parse-tree.c @@ -1808,6 +1808,12 @@ show_omp_clauses (gfc_omp_clauses *omp_clauses) show_expr (omp_clauses->grainsize); fputc (')', dumpfile); } + if (omp_clauses->filter) + { + fputs (" FILTER(", dumpfile); + show_expr (omp_clauses->filter); + fputc (')', dumpfile); + } if (omp_clauses->hint) { fputs (" HINT(", dumpfile); @@ -1946,6 +1952,9 @@ show_omp_node (int level, gfc_code *c) case EXEC_OMP_DO_SIMD: name = "DO SIMD"; break; case EXEC_OMP_LOOP: name = "LOOP"; break; case EXEC_OMP_FLUSH: name = "FLUSH"; break; + case EXEC_OMP_MASKED: name = "MASKED"; break; + case EXEC_OMP_MASKED_TASKLOOP: name = "MASKED TASKLOOP"; break; + case EXEC_OMP_MASKED_TASKLOOP_SIMD: name = "MASKED TASKLOOP SIMD"; break; case EXEC_OMP_MASTER: name = "MASTER"; break; case EXEC_OMP_MASTER_TASKLOOP: name = "MASTER TASKLOOP"; break; case EXEC_OMP_MASTER_TASKLOOP_SIMD: name = "MASTER TASKLOOP SIMD"; break; @@ -1956,6 +1965,11 @@ show_omp_node (int level, gfc_code *c) case EXEC_OMP_PARALLEL_DO_SIMD: name = "PARALLEL DO SIMD"; break; case EXEC_OMP_PARALLEL_LOOP: name = "PARALLEL LOOP"; break; case EXEC_OMP_PARALLEL_MASTER: name = "PARALLEL MASTER"; break; + case EXEC_OMP_PARALLEL_MASKED: name = "PARALLEL MASK"; break; + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP: + name = "PARALLEL MASK TASKLOOP"; break; + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD: + name = "PARALLEL MASK TASKLOOP SIMD"; break; case EXEC_OMP_PARALLEL_MASTER_TASKLOOP: name = "PARALLEL MASTER TASKLOOP"; break; case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD: @@ -2032,10 +2046,14 @@ show_omp_node (int level, gfc_code *c) case EXEC_OMP_DO_SIMD: case EXEC_OMP_LOOP: case EXEC_OMP_ORDERED: + case EXEC_OMP_MASKED: case EXEC_OMP_PARALLEL: case EXEC_OMP_PARALLEL_DO: case EXEC_OMP_PARALLEL_DO_SIMD: case EXEC_OMP_PARALLEL_LOOP: + case EXEC_OMP_PARALLEL_MASKED: + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP: + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD: case EXEC_OMP_PARALLEL_MASTER: case EXEC_OMP_PARALLEL_MASTER_TASKLOOP: case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD: @@ -3250,6 +3268,9 @@ show_code_node (int level, gfc_code *c) case EXEC_OMP_DO_SIMD: case EXEC_OMP_FLUSH: case EXEC_OMP_LOOP: + case EXEC_OMP_MASKED: + case EXEC_OMP_MASKED_TASKLOOP: + case EXEC_OMP_MASKED_TASKLOOP_SIMD: case EXEC_OMP_MASTER: case EXEC_OMP_MASTER_TASKLOOP: case EXEC_OMP_MASTER_TASKLOOP_SIMD: @@ -3258,6 +3279,9 @@ show_code_node (int level, gfc_code *c) case EXEC_OMP_PARALLEL_DO: case EXEC_OMP_PARALLEL_DO_SIMD: case EXEC_OMP_PARALLEL_LOOP: + case EXEC_OMP_PARALLEL_MASKED: + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP: + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD: case EXEC_OMP_PARALLEL_MASTER: case EXEC_OMP_PARALLEL_MASTER_TASKLOOP: case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD: diff --git a/gcc/fortran/frontend-passes.c b/gcc/fortran/frontend-passes.c index 996dcc2..145bff5 100644 --- a/gcc/fortran/frontend-passes.c +++ b/gcc/fortran/frontend-passes.c @@ -5556,6 +5556,9 @@ gfc_code_walker (gfc_code **c, walk_code_fn_t codefn, walk_expr_fn_t exprfn, case EXEC_OMP_PARALLEL_DO: case EXEC_OMP_PARALLEL_DO_SIMD: case EXEC_OMP_PARALLEL_LOOP: + case EXEC_OMP_PARALLEL_MASKED: + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP: + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD: case EXEC_OMP_PARALLEL_MASTER: case EXEC_OMP_PARALLEL_MASTER_TASKLOOP: case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD: diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h index 8f75dd9..5fde417 100644 --- a/gcc/fortran/gfortran.h +++ b/gcc/fortran/gfortran.h @@ -275,7 +275,13 @@ enum gfc_statement ST_OMP_PARALLEL_LOOP, ST_OMP_END_PARALLEL_LOOP, ST_OMP_TEAMS_LOOP, ST_OMP_END_TEAMS_LOOP, ST_OMP_TARGET_PARALLEL_LOOP, ST_OMP_END_TARGET_PARALLEL_LOOP, ST_OMP_TARGET_TEAMS_LOOP, - ST_OMP_END_TARGET_TEAMS_LOOP, ST_NONE + ST_OMP_END_TARGET_TEAMS_LOOP, ST_OMP_MASKED, ST_OMP_END_MASKED, + ST_OMP_PARALLEL_MASKED, ST_OMP_END_PARALLEL_MASKED, + ST_OMP_PARALLEL_MASKED_TASKLOOP, ST_OMP_END_PARALLEL_MASKED_TASKLOOP, + ST_OMP_PARALLEL_MASKED_TASKLOOP_SIMD, + ST_OMP_END_PARALLEL_MASKED_TASKLOOP_SIMD, ST_OMP_MASKED_TASKLOOP, + ST_OMP_END_MASKED_TASKLOOP, ST_OMP_MASKED_TASKLOOP_SIMD, + ST_OMP_END_MASKED_TASKLOOP_SIMD, ST_NONE }; /* Types of interfaces that we can have. Assignment interfaces are @@ -1466,6 +1472,7 @@ typedef struct gfc_omp_clauses struct gfc_expr *device; struct gfc_expr *thread_limit; struct gfc_expr *grainsize; + struct gfc_expr *filter; struct gfc_expr *hint; struct gfc_expr *num_tasks; struct gfc_expr *priority; @@ -2758,7 +2765,10 @@ enum gfc_exec_op EXEC_OMP_PARALLEL_MASTER, EXEC_OMP_PARALLEL_MASTER_TASKLOOP, EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD, EXEC_OMP_MASTER_TASKLOOP, EXEC_OMP_MASTER_TASKLOOP_SIMD, EXEC_OMP_LOOP, EXEC_OMP_PARALLEL_LOOP, - EXEC_OMP_TEAMS_LOOP, EXEC_OMP_TARGET_PARALLEL_LOOP, EXEC_OMP_TARGET_TEAMS_LOOP + EXEC_OMP_TEAMS_LOOP, EXEC_OMP_TARGET_PARALLEL_LOOP, + EXEC_OMP_TARGET_TEAMS_LOOP, EXEC_OMP_MASKED, EXEC_OMP_PARALLEL_MASKED, + EXEC_OMP_PARALLEL_MASKED_TASKLOOP, EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD, + EXEC_OMP_MASKED_TASKLOOP, EXEC_OMP_MASKED_TASKLOOP_SIMD }; typedef struct gfc_code diff --git a/gcc/fortran/match.h b/gcc/fortran/match.h index bb1f34f..dce6503 100644 --- a/gcc/fortran/match.h +++ b/gcc/fortran/match.h @@ -169,6 +169,9 @@ match gfc_match_omp_do (void); match gfc_match_omp_do_simd (void); match gfc_match_omp_loop (void); match gfc_match_omp_flush (void); +match gfc_match_omp_masked (void); +match gfc_match_omp_masked_taskloop (void); +match gfc_match_omp_masked_taskloop_simd (void); match gfc_match_omp_master (void); match gfc_match_omp_master_taskloop (void); match gfc_match_omp_master_taskloop_simd (void); @@ -178,6 +181,9 @@ match gfc_match_omp_parallel (void); match gfc_match_omp_parallel_do (void); match gfc_match_omp_parallel_do_simd (void); match gfc_match_omp_parallel_loop (void); +match gfc_match_omp_parallel_masked (void); +match gfc_match_omp_parallel_masked_taskloop (void); +match gfc_match_omp_parallel_masked_taskloop_simd (void); match gfc_match_omp_parallel_master (void); match gfc_match_omp_parallel_master_taskloop (void); match gfc_match_omp_parallel_master_taskloop_simd (void); diff --git a/gcc/fortran/openmp.c b/gcc/fortran/openmp.c index ec55865..1bce43c 100644 --- a/gcc/fortran/openmp.c +++ b/gcc/fortran/openmp.c @@ -847,6 +847,7 @@ enum omp_mask1 OMP_CLAUSE_DETACH, /* OpenMP 5.0. */ OMP_CLAUSE_AFFINITY, /* OpenMP 5.0. */ OMP_CLAUSE_BIND, /* OpenMP 5.0. */ + OMP_CLAUSE_FILTER, /* OpenMP 5.1. */ OMP_CLAUSE_NOWAIT, /* This must come last. */ OMP_MASK1_LAST @@ -1772,6 +1773,10 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask, } break; case 'f': + if ((mask & OMP_CLAUSE_FILTER) + && c->filter == NULL + && gfc_match ("filter ( %e )", &c->filter) == MATCH_YES) + continue; if ((mask & OMP_CLAUSE_FINAL) && c->final_expr == NULL && gfc_match ("final ( %e )", &c->final_expr) == MATCH_YES) @@ -3199,6 +3204,8 @@ cleanup: #define OMP_ATOMIC_CLAUSES \ (omp_mask (OMP_CLAUSE_ATOMIC) | OMP_CLAUSE_CAPTURE | OMP_CLAUSE_HINT \ | OMP_CLAUSE_MEMORDER) +#define OMP_MASKED_CLAUSES \ + (omp_mask (OMP_CLAUSE_FILTER)) static match @@ -4158,6 +4165,31 @@ gfc_match_omp_parallel_do_simd (void) match +gfc_match_omp_parallel_masked (void) +{ + return match_omp (EXEC_OMP_PARALLEL_MASKED, + OMP_PARALLEL_CLAUSES | OMP_MASKED_CLAUSES); +} + +match +gfc_match_omp_parallel_masked_taskloop (void) +{ + return match_omp (EXEC_OMP_PARALLEL_MASKED_TASKLOOP, + (OMP_PARALLEL_CLAUSES | OMP_MASKED_CLAUSES + | OMP_TASKLOOP_CLAUSES) + & ~(omp_mask (OMP_CLAUSE_IN_REDUCTION))); +} + +match +gfc_match_omp_parallel_masked_taskloop_simd (void) +{ + return match_omp (EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD, + (OMP_PARALLEL_CLAUSES | OMP_MASKED_CLAUSES + | OMP_TASKLOOP_CLAUSES | OMP_SIMD_CLAUSES) + & ~(omp_mask (OMP_CLAUSE_IN_REDUCTION))); +} + +match gfc_match_omp_parallel_master (void) { return match_omp (EXEC_OMP_PARALLEL_MASTER, OMP_PARALLEL_CLAUSES); @@ -4704,6 +4736,27 @@ gfc_match_omp_workshare (void) match +gfc_match_omp_masked (void) +{ + return match_omp (EXEC_OMP_MASKED, OMP_MASKED_CLAUSES); +} + +match +gfc_match_omp_masked_taskloop (void) +{ + return match_omp (EXEC_OMP_MASKED_TASKLOOP, + OMP_MASKED_CLAUSES | OMP_TASKLOOP_CLAUSES); +} + +match +gfc_match_omp_masked_taskloop_simd (void) +{ + return match_omp (EXEC_OMP_MASKED_TASKLOOP_SIMD, + (OMP_MASKED_CLAUSES | OMP_TASKLOOP_CLAUSES + | OMP_SIMD_CLAUSES)); +} + +match gfc_match_omp_master (void) { if (gfc_match_omp_eos () != MATCH_YES) @@ -5254,6 +5307,7 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses, case EXEC_OMP_PARALLEL: case EXEC_OMP_PARALLEL_DO: + case EXEC_OMP_PARALLEL_MASKED: case EXEC_OMP_PARALLEL_MASTER: case EXEC_OMP_PARALLEL_SECTIONS: case EXEC_OMP_PARALLEL_WORKSHARE: @@ -5268,10 +5322,12 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses, ok = ifc == OMP_IF_PARALLEL || ifc == OMP_IF_SIMD; break; + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP: case EXEC_OMP_PARALLEL_MASTER_TASKLOOP: ok = ifc == OMP_IF_PARALLEL || ifc == OMP_IF_TASKLOOP; break; + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD: case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD: ok = (ifc == OMP_IF_PARALLEL || ifc == OMP_IF_TASKLOOP @@ -5290,11 +5346,13 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses, break; case EXEC_OMP_TASKLOOP: + case EXEC_OMP_MASKED_TASKLOOP: case EXEC_OMP_MASTER_TASKLOOP: ok = ifc == OMP_IF_TASKLOOP; break; case EXEC_OMP_TASKLOOP_SIMD: + case EXEC_OMP_MASKED_TASKLOOP_SIMD: case EXEC_OMP_MASTER_TASKLOOP_SIMD: ok = ifc == OMP_IF_TASKLOOP || ifc == OMP_IF_SIMD; break; @@ -6060,9 +6118,13 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses, && (code->op == EXEC_OMP_LOOP || code->op == EXEC_OMP_TASKLOOP || code->op == EXEC_OMP_TASKLOOP_SIMD + || code->op == EXEC_OMP_MASKED_TASKLOOP + || code->op == EXEC_OMP_MASKED_TASKLOOP_SIMD || code->op == EXEC_OMP_MASTER_TASKLOOP || code->op == EXEC_OMP_MASTER_TASKLOOP_SIMD || code->op == EXEC_OMP_PARALLEL_LOOP + || code->op == EXEC_OMP_PARALLEL_MASKED_TASKLOOP + || code->op == EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD || code->op == EXEC_OMP_PARALLEL_MASTER_TASKLOOP || code->op == EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD || code->op == EXEC_OMP_TARGET_PARALLEL_LOOP @@ -6322,6 +6384,8 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses, resolve_positive_int_expr (omp_clauses->num_teams, "NUM_TEAMS"); if (omp_clauses->device) resolve_nonnegative_int_expr (omp_clauses->device, "DEVICE"); + if (omp_clauses->filter) + resolve_nonnegative_int_expr (omp_clauses->filter, "FILTER"); if (omp_clauses->hint) { resolve_scalar_int_expr (omp_clauses->hint, "HINT"); @@ -6984,8 +7048,12 @@ gfc_resolve_omp_parallel_blocks (gfc_code *code, gfc_namespace *ns) case EXEC_OMP_DISTRIBUTE_PARALLEL_DO_SIMD: case EXEC_OMP_PARALLEL_DO: case EXEC_OMP_PARALLEL_DO_SIMD: + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP: + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD: case EXEC_OMP_PARALLEL_MASTER_TASKLOOP: case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD: + case EXEC_OMP_MASKED_TASKLOOP: + case EXEC_OMP_MASKED_TASKLOOP_SIMD: case EXEC_OMP_MASTER_TASKLOOP: case EXEC_OMP_MASTER_TASKLOOP_SIMD: case EXEC_OMP_TARGET_PARALLEL_DO: @@ -7133,6 +7201,13 @@ resolve_omp_do (gfc_code *code) is_simd = true; break; case EXEC_OMP_PARALLEL_LOOP: name = "!$OMP PARALLEL LOOP"; break; + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP: + name = "!$OMP PARALLEL MASKED TASKLOOP"; + break; + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD: + name = "!$OMP PARALLEL MASKED TASKLOOP SIMD"; + is_simd = true; + break; case EXEC_OMP_PARALLEL_MASTER_TASKLOOP: name = "!$OMP PARALLEL MASTER TASKLOOP"; break; @@ -7140,6 +7215,11 @@ resolve_omp_do (gfc_code *code) name = "!$OMP PARALLEL MASTER TASKLOOP SIMD"; is_simd = true; break; + case EXEC_OMP_MASKED_TASKLOOP: name = "!$OMP MASKED TASKLOOP"; break; + case EXEC_OMP_MASKED_TASKLOOP_SIMD: + name = "!$OMP MASKED TASKLOOP SIMD"; + is_simd = true; + break; case EXEC_OMP_MASTER_TASKLOOP: name = "!$OMP MASTER TASKLOOP"; break; case EXEC_OMP_MASTER_TASKLOOP_SIMD: name = "!$OMP MASTER TASKLOOP SIMD"; @@ -7302,6 +7382,12 @@ omp_code_to_statement (gfc_code *code) { case EXEC_OMP_PARALLEL: return ST_OMP_PARALLEL; + case EXEC_OMP_PARALLEL_MASKED: + return ST_OMP_PARALLEL_MASKED; + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP: + return ST_OMP_PARALLEL_MASKED_TASKLOOP; + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD: + return ST_OMP_PARALLEL_MASKED_TASKLOOP_SIMD; case EXEC_OMP_PARALLEL_MASTER: return ST_OMP_PARALLEL_MASTER; case EXEC_OMP_PARALLEL_MASTER_TASKLOOP: @@ -7316,6 +7402,12 @@ omp_code_to_statement (gfc_code *code) return ST_OMP_ORDERED; case EXEC_OMP_CRITICAL: return ST_OMP_CRITICAL; + case EXEC_OMP_MASKED: + return ST_OMP_MASKED; + case EXEC_OMP_MASKED_TASKLOOP: + return ST_OMP_MASKED_TASKLOOP; + case EXEC_OMP_MASKED_TASKLOOP_SIMD: + return ST_OMP_MASKED_TASKLOOP_SIMD; case EXEC_OMP_MASTER: return ST_OMP_MASTER; case EXEC_OMP_MASTER_TASKLOOP: @@ -7822,8 +7914,12 @@ gfc_resolve_omp_directive (gfc_code *code, gfc_namespace *ns) case EXEC_OMP_PARALLEL_DO: case EXEC_OMP_PARALLEL_DO_SIMD: case EXEC_OMP_PARALLEL_LOOP: + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP: + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD: case EXEC_OMP_PARALLEL_MASTER_TASKLOOP: case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD: + case EXEC_OMP_MASKED_TASKLOOP: + case EXEC_OMP_MASKED_TASKLOOP_SIMD: case EXEC_OMP_MASTER_TASKLOOP: case EXEC_OMP_MASTER_TASKLOOP_SIMD: case EXEC_OMP_SIMD: @@ -7846,8 +7942,10 @@ gfc_resolve_omp_directive (gfc_code *code, gfc_namespace *ns) resolve_omp_do (code); break; case EXEC_OMP_CANCEL: + case EXEC_OMP_MASKED: case EXEC_OMP_PARALLEL_WORKSHARE: case EXEC_OMP_PARALLEL: + case EXEC_OMP_PARALLEL_MASKED: case EXEC_OMP_PARALLEL_MASTER: case EXEC_OMP_PARALLEL_SECTIONS: case EXEC_OMP_SECTIONS: diff --git a/gcc/fortran/parse.c b/gcc/fortran/parse.c index 6d7845e..e1d78de 100644 --- a/gcc/fortran/parse.c +++ b/gcc/fortran/parse.c @@ -920,6 +920,11 @@ decode_omp_directive (void) matchs ("end do simd", gfc_match_omp_end_nowait, ST_OMP_END_DO_SIMD); matcho ("end do", gfc_match_omp_end_nowait, ST_OMP_END_DO); matchs ("end simd", gfc_match_omp_eos_error, ST_OMP_END_SIMD); + matcho ("end masked taskloop simd", gfc_match_omp_eos_error, + ST_OMP_END_MASKED_TASKLOOP_SIMD); + matcho ("end masked taskloop", gfc_match_omp_eos_error, + ST_OMP_END_MASKED_TASKLOOP); + matcho ("end masked", gfc_match_omp_eos_error, ST_OMP_END_MASKED); matcho ("end master taskloop simd", gfc_match_omp_eos_error, ST_OMP_END_MASTER_TASKLOOP_SIMD); matcho ("end master taskloop", gfc_match_omp_eos_error, @@ -929,6 +934,12 @@ decode_omp_directive (void) matchs ("end parallel do simd", gfc_match_omp_eos_error, ST_OMP_END_PARALLEL_DO_SIMD); matcho ("end parallel do", gfc_match_omp_eos_error, ST_OMP_END_PARALLEL_DO); + matcho ("end parallel masked taskloop simd", gfc_match_omp_eos_error, + ST_OMP_END_PARALLEL_MASKED_TASKLOOP_SIMD); + matcho ("end parallel masked taskloop", gfc_match_omp_eos_error, + ST_OMP_END_PARALLEL_MASKED_TASKLOOP); + matcho ("end parallel masked", gfc_match_omp_eos_error, + ST_OMP_END_PARALLEL_MASKED); matcho ("end parallel master taskloop simd", gfc_match_omp_eos_error, ST_OMP_END_PARALLEL_MASTER_TASKLOOP_SIMD); matcho ("end parallel master taskloop", gfc_match_omp_eos_error, @@ -982,6 +993,11 @@ decode_omp_directive (void) matcho ("flush", gfc_match_omp_flush, ST_OMP_FLUSH); break; case 'm': + matcho ("masked taskloop simd", gfc_match_omp_masked_taskloop_simd, + ST_OMP_MASKED_TASKLOOP_SIMD); + matcho ("masked taskloop", gfc_match_omp_masked_taskloop, + ST_OMP_MASKED_TASKLOOP); + matcho ("masked", gfc_match_omp_masked, ST_OMP_MASKED); matcho ("master taskloop simd", gfc_match_omp_master_taskloop_simd, ST_OMP_MASTER_TASKLOOP_SIMD); matcho ("master taskloop", gfc_match_omp_master_taskloop, @@ -1009,6 +1025,14 @@ decode_omp_directive (void) matcho ("parallel do", gfc_match_omp_parallel_do, ST_OMP_PARALLEL_DO); matcho ("parallel loop", gfc_match_omp_parallel_loop, ST_OMP_PARALLEL_LOOP); + matcho ("parallel masked taskloop simd", + gfc_match_omp_parallel_masked_taskloop_simd, + ST_OMP_PARALLEL_MASKED_TASKLOOP_SIMD); + matcho ("parallel masked taskloop", + gfc_match_omp_parallel_masked_taskloop, + ST_OMP_PARALLEL_MASKED_TASKLOOP); + matcho ("parallel masked", gfc_match_omp_parallel_masked, + ST_OMP_PARALLEL_MASKED); matcho ("parallel master taskloop simd", gfc_match_omp_parallel_master_taskloop_simd, ST_OMP_PARALLEL_MASTER_TASKLOOP_SIMD); @@ -1639,11 +1663,15 @@ next_statement (void) #define case_exec_markers case ST_DO: case ST_FORALL_BLOCK: \ case ST_IF_BLOCK: case ST_BLOCK: case ST_ASSOCIATE: \ case ST_WHERE_BLOCK: case ST_SELECT_CASE: case ST_SELECT_TYPE: \ - case ST_SELECT_RANK: case ST_OMP_PARALLEL: case ST_OMP_PARALLEL_MASTER: \ + case ST_SELECT_RANK: case ST_OMP_PARALLEL: case ST_OMP_PARALLEL_MASKED: \ + case ST_OMP_PARALLEL_MASKED_TASKLOOP: \ + case ST_OMP_PARALLEL_MASKED_TASKLOOP_SIMD: case ST_OMP_PARALLEL_MASTER: \ case ST_OMP_PARALLEL_MASTER_TASKLOOP: \ case ST_OMP_PARALLEL_MASTER_TASKLOOP_SIMD: \ case ST_OMP_PARALLEL_SECTIONS: case ST_OMP_SECTIONS: case ST_OMP_ORDERED: \ - case ST_OMP_CRITICAL: case ST_OMP_MASTER: case ST_OMP_MASTER_TASKLOOP: \ + case ST_OMP_CRITICAL: case ST_OMP_MASKED: case ST_OMP_MASKED_TASKLOOP: \ + case ST_OMP_MASKED_TASKLOOP_SIMD: \ + case ST_OMP_MASTER: case ST_OMP_MASTER_TASKLOOP: \ case ST_OMP_MASTER_TASKLOOP_SIMD: case ST_OMP_SINGLE: \ case ST_OMP_DO: case ST_OMP_PARALLEL_DO: case ST_OMP_ATOMIC: \ case ST_OMP_WORKSHARE: case ST_OMP_PARALLEL_WORKSHARE: \ @@ -2376,6 +2404,15 @@ gfc_ascii_statement (gfc_statement st) case ST_OMP_END_LOOP: p = "!$OMP END LOOP"; break; + case ST_OMP_END_MASKED: + p = "!$OMP END MASKED"; + break; + case ST_OMP_END_MASKED_TASKLOOP: + p = "!$OMP END MASKED TASKLOOP"; + break; + case ST_OMP_END_MASKED_TASKLOOP_SIMD: + p = "!$OMP END MASKED TASKLOOP SIMD"; + break; case ST_OMP_END_MASTER: p = "!$OMP END MASTER"; break; @@ -2400,6 +2437,15 @@ gfc_ascii_statement (gfc_statement st) case ST_OMP_END_PARALLEL_LOOP: p = "!$OMP END PARALLEL LOOP"; break; + case ST_OMP_END_PARALLEL_MASKED: + p = "!$OMP END PARALLEL MASKED"; + break; + case ST_OMP_END_PARALLEL_MASKED_TASKLOOP: + p = "!$OMP END PARALLEL MASKED TASKLOOP"; + break; + case ST_OMP_END_PARALLEL_MASKED_TASKLOOP_SIMD: + p = "!$OMP END PARALLEL MASKED TASKLOOP SIMD"; + break; case ST_OMP_END_PARALLEL_MASTER: p = "!$OMP END PARALLEL MASTER"; break; @@ -2499,6 +2545,15 @@ gfc_ascii_statement (gfc_statement st) case ST_OMP_LOOP: p = "!$OMP LOOP"; break; + case ST_OMP_MASKED: + p = "!$OMP MASKED"; + break; + case ST_OMP_MASKED_TASKLOOP: + p = "!$OMP MASKED TASKLOOP"; + break; + case ST_OMP_MASKED_TASKLOOP_SIMD: + p = "!$OMP MASKED TASKLOOP SIMD"; + break; case ST_OMP_MASTER: p = "!$OMP MASTER"; break; @@ -2524,6 +2579,15 @@ gfc_ascii_statement (gfc_statement st) case ST_OMP_PARALLEL_DO_SIMD: p = "!$OMP PARALLEL DO SIMD"; break; + case ST_OMP_PARALLEL_MASKED: + p = "!$OMP PARALLEL MASKED"; + break; + case ST_OMP_PARALLEL_MASKED_TASKLOOP: + p = "!$OMP PARALLEL MASKED TASKLOOP"; + break; + case ST_OMP_PARALLEL_MASKED_TASKLOOP_SIMD: + p = "!$OMP PARALLEL MASKED TASKLOOP SIMD"; + break; case ST_OMP_PARALLEL_MASTER: p = "!$OMP PARALLEL MASTER"; break; @@ -5127,10 +5191,20 @@ parse_omp_do (gfc_statement omp_st) break; case ST_OMP_TASKLOOP: omp_end_st = ST_OMP_END_TASKLOOP; break; case ST_OMP_TASKLOOP_SIMD: omp_end_st = ST_OMP_END_TASKLOOP_SIMD; break; + case ST_OMP_MASKED_TASKLOOP: omp_end_st = ST_OMP_END_MASKED_TASKLOOP; break; + case ST_OMP_MASKED_TASKLOOP_SIMD: + omp_end_st = ST_OMP_END_MASKED_TASKLOOP_SIMD; + break; case ST_OMP_MASTER_TASKLOOP: omp_end_st = ST_OMP_END_MASTER_TASKLOOP; break; case ST_OMP_MASTER_TASKLOOP_SIMD: omp_end_st = ST_OMP_END_MASTER_TASKLOOP_SIMD; break; + case ST_OMP_PARALLEL_MASKED_TASKLOOP: + omp_end_st = ST_OMP_END_PARALLEL_MASKED_TASKLOOP; + break; + case ST_OMP_PARALLEL_MASKED_TASKLOOP_SIMD: + omp_end_st = ST_OMP_END_PARALLEL_MASKED_TASKLOOP_SIMD; + break; case ST_OMP_PARALLEL_MASTER_TASKLOOP: omp_end_st = ST_OMP_END_PARALLEL_MASTER_TASKLOOP; break; @@ -5380,6 +5454,9 @@ parse_omp_structured_block (gfc_statement omp_st, bool workshare_stmts_only) case ST_OMP_PARALLEL: omp_end_st = ST_OMP_END_PARALLEL; break; + case ST_OMP_PARALLEL_MASKED: + omp_end_st = ST_OMP_END_PARALLEL_MASKED; + break; case ST_OMP_PARALLEL_MASTER: omp_end_st = ST_OMP_END_PARALLEL_MASTER; break; @@ -5395,6 +5472,9 @@ parse_omp_structured_block (gfc_statement omp_st, bool workshare_stmts_only) case ST_OMP_CRITICAL: omp_end_st = ST_OMP_END_CRITICAL; break; + case ST_OMP_MASKED: + omp_end_st = ST_OMP_END_MASKED; + break; case ST_OMP_MASTER: omp_end_st = ST_OMP_END_MASTER; break; @@ -5477,6 +5557,7 @@ parse_omp_structured_block (gfc_statement omp_st, bool workshare_stmts_only) break; case ST_OMP_PARALLEL: + case ST_OMP_PARALLEL_MASKED: case ST_OMP_PARALLEL_MASTER: case ST_OMP_PARALLEL_SECTIONS: parse_omp_structured_block (st, false); @@ -5679,11 +5760,13 @@ parse_executable (gfc_statement st) break; case ST_OMP_PARALLEL: + case ST_OMP_PARALLEL_MASKED: case ST_OMP_PARALLEL_MASTER: case ST_OMP_PARALLEL_SECTIONS: case ST_OMP_SECTIONS: case ST_OMP_ORDERED: case ST_OMP_CRITICAL: + case ST_OMP_MASKED: case ST_OMP_MASTER: case ST_OMP_SINGLE: case ST_OMP_TARGET: @@ -5711,8 +5794,12 @@ parse_executable (gfc_statement st) case ST_OMP_PARALLEL_DO: case ST_OMP_PARALLEL_DO_SIMD: case ST_OMP_PARALLEL_LOOP: + case ST_OMP_PARALLEL_MASKED_TASKLOOP: + case ST_OMP_PARALLEL_MASKED_TASKLOOP_SIMD: case ST_OMP_PARALLEL_MASTER_TASKLOOP: case ST_OMP_PARALLEL_MASTER_TASKLOOP_SIMD: + case ST_OMP_MASKED_TASKLOOP: + case ST_OMP_MASKED_TASKLOOP_SIMD: case ST_OMP_MASTER_TASKLOOP: case ST_OMP_MASTER_TASKLOOP_SIMD: case ST_OMP_SIMD: diff --git a/gcc/fortran/resolve.c b/gcc/fortran/resolve.c index 959f0be..8eb8a9a 100644 --- a/gcc/fortran/resolve.c +++ b/gcc/fortran/resolve.c @@ -10818,6 +10818,9 @@ gfc_resolve_blocks (gfc_code *b, gfc_namespace *ns) case EXEC_OMP_DO: case EXEC_OMP_DO_SIMD: case EXEC_OMP_LOOP: + case EXEC_OMP_MASKED: + case EXEC_OMP_MASKED_TASKLOOP: + case EXEC_OMP_MASKED_TASKLOOP_SIMD: case EXEC_OMP_MASTER: case EXEC_OMP_MASTER_TASKLOOP: case EXEC_OMP_MASTER_TASKLOOP_SIMD: @@ -10826,6 +10829,9 @@ gfc_resolve_blocks (gfc_code *b, gfc_namespace *ns) case EXEC_OMP_PARALLEL_DO: case EXEC_OMP_PARALLEL_DO_SIMD: case EXEC_OMP_PARALLEL_LOOP: + case EXEC_OMP_PARALLEL_MASKED: + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP: + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD: case EXEC_OMP_PARALLEL_MASTER: case EXEC_OMP_PARALLEL_MASTER_TASKLOOP: case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD: @@ -11793,6 +11799,9 @@ gfc_resolve_code (gfc_code *code, gfc_namespace *ns) case EXEC_OMP_PARALLEL: case EXEC_OMP_PARALLEL_DO: case EXEC_OMP_PARALLEL_DO_SIMD: + case EXEC_OMP_PARALLEL_MASKED: + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP: + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD: case EXEC_OMP_PARALLEL_MASTER: case EXEC_OMP_PARALLEL_MASTER_TASKLOOP: case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD: @@ -12248,6 +12257,9 @@ start: case EXEC_OMP_MASTER: case EXEC_OMP_MASTER_TASKLOOP: case EXEC_OMP_MASTER_TASKLOOP_SIMD: + case EXEC_OMP_MASKED: + case EXEC_OMP_MASKED_TASKLOOP: + case EXEC_OMP_MASKED_TASKLOOP_SIMD: case EXEC_OMP_ORDERED: case EXEC_OMP_SCAN: case EXEC_OMP_SECTIONS: @@ -12289,6 +12301,9 @@ start: case EXEC_OMP_PARALLEL_DO: case EXEC_OMP_PARALLEL_DO_SIMD: case EXEC_OMP_PARALLEL_LOOP: + case EXEC_OMP_PARALLEL_MASKED: + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP: + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD: case EXEC_OMP_PARALLEL_MASTER: case EXEC_OMP_PARALLEL_MASTER_TASKLOOP: case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD: diff --git a/gcc/fortran/st.c b/gcc/fortran/st.c index 6ae1df6..f61f88a 100644 --- a/gcc/fortran/st.c +++ b/gcc/fortran/st.c @@ -227,13 +227,19 @@ gfc_free_statement (gfc_code *p) case EXEC_OMP_DO_SIMD: case EXEC_OMP_LOOP: case EXEC_OMP_END_SINGLE: + case EXEC_OMP_MASKED_TASKLOOP: + case EXEC_OMP_MASKED_TASKLOOP_SIMD: case EXEC_OMP_MASTER_TASKLOOP: case EXEC_OMP_MASTER_TASKLOOP_SIMD: case EXEC_OMP_ORDERED: + case EXEC_OMP_MASKED: case EXEC_OMP_PARALLEL: case EXEC_OMP_PARALLEL_DO: case EXEC_OMP_PARALLEL_DO_SIMD: case EXEC_OMP_PARALLEL_LOOP: + case EXEC_OMP_PARALLEL_MASKED: + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP: + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD: case EXEC_OMP_PARALLEL_MASTER: case EXEC_OMP_PARALLEL_MASTER_TASKLOOP: case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD: diff --git a/gcc/fortran/trans-openmp.c b/gcc/fortran/trans-openmp.c index 3d3b35e..623c21f 100644 --- a/gcc/fortran/trans-openmp.c +++ b/gcc/fortran/trans-openmp.c @@ -4047,6 +4047,21 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses, omp_clauses = gfc_trans_add_clause (c, omp_clauses); } + if (clauses->filter) + { + tree filter; + + gfc_init_se (&se, NULL); + gfc_conv_expr (&se, clauses->filter); + gfc_add_block_to_block (block, &se.pre); + filter = gfc_evaluate_now (se.expr, block); + gfc_add_block_to_block (block, &se.post); + + c = build_omp_clause (gfc_get_location (&where), OMP_CLAUSE_FILTER); + OMP_CLAUSE_FILTER_EXPR (c) = filter; + omp_clauses = gfc_trans_add_clause (c, omp_clauses); + } + if (clauses->hint) { tree hint; @@ -5390,6 +5405,26 @@ gfc_trans_omp_master (gfc_code *code) } static tree +gfc_trans_omp_masked (gfc_code *code, gfc_omp_clauses *clauses) +{ + stmtblock_t block; + tree body = gfc_trans_code (code->block->next); + if (IS_EMPTY_STMT (body)) + return body; + if (!clauses) + clauses = code->ext.omp_clauses; + gfc_start_block (&block); + tree omp_clauses = gfc_trans_omp_clauses (&block, clauses, code->loc); + tree stmt = make_node (OMP_MASKED); + TREE_TYPE (stmt) = void_type_node; + OMP_MASKED_BODY (stmt) = body; + OMP_MASKED_CLAUSES (stmt) = omp_clauses; + gfc_add_expr_to_block (&block, stmt); + return gfc_finish_block (&block); +} + + +static tree gfc_trans_omp_ordered (gfc_code *code) { if (!flag_openmp) @@ -5432,6 +5467,7 @@ enum GFC_OMP_SPLIT_TEAMS, GFC_OMP_SPLIT_TARGET, GFC_OMP_SPLIT_TASKLOOP, + GFC_OMP_SPLIT_MASKED, GFC_OMP_SPLIT_NUM }; @@ -5443,7 +5479,8 @@ enum GFC_OMP_MASK_DISTRIBUTE = (1 << GFC_OMP_SPLIT_DISTRIBUTE), GFC_OMP_MASK_TEAMS = (1 << GFC_OMP_SPLIT_TEAMS), GFC_OMP_MASK_TARGET = (1 << GFC_OMP_SPLIT_TARGET), - GFC_OMP_MASK_TASKLOOP = (1 << GFC_OMP_SPLIT_TASKLOOP) + GFC_OMP_MASK_TASKLOOP = (1 << GFC_OMP_SPLIT_TASKLOOP), + GFC_OMP_MASK_MASKED = (1 << GFC_OMP_SPLIT_MASKED) }; /* If a var is in lastprivate/firstprivate/reduction but not in a @@ -5632,10 +5669,24 @@ gfc_split_omp_clauses (gfc_code *code, mask = GFC_OMP_MASK_PARALLEL | GFC_OMP_MASK_DO | GFC_OMP_MASK_SIMD; innermost = GFC_OMP_SPLIT_SIMD; break; + case EXEC_OMP_PARALLEL_MASKED: + mask = GFC_OMP_MASK_PARALLEL | GFC_OMP_MASK_MASKED; + innermost = GFC_OMP_SPLIT_MASKED; + break; + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP: + mask = (GFC_OMP_MASK_PARALLEL | GFC_OMP_MASK_MASKED + | GFC_OMP_MASK_TASKLOOP | GFC_OMP_MASK_SIMD); + innermost = GFC_OMP_SPLIT_TASKLOOP; + break; case EXEC_OMP_PARALLEL_MASTER_TASKLOOP: mask = GFC_OMP_MASK_PARALLEL | GFC_OMP_MASK_TASKLOOP | GFC_OMP_MASK_SIMD; innermost = GFC_OMP_SPLIT_TASKLOOP; break; + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD: + mask = (GFC_OMP_MASK_PARALLEL | GFC_OMP_MASK_MASKED + | GFC_OMP_MASK_TASKLOOP | GFC_OMP_MASK_SIMD); + innermost = GFC_OMP_SPLIT_SIMD; + break; case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD: mask = GFC_OMP_MASK_PARALLEL | GFC_OMP_MASK_TASKLOOP | GFC_OMP_MASK_SIMD; innermost = GFC_OMP_SPLIT_SIMD; @@ -5692,10 +5743,18 @@ gfc_split_omp_clauses (gfc_code *code, mask = GFC_OMP_MASK_TARGET | GFC_OMP_MASK_TEAMS | GFC_OMP_MASK_DO; innermost = GFC_OMP_SPLIT_DO; break; + case EXEC_OMP_MASKED_TASKLOOP: + mask = GFC_OMP_SPLIT_MASKED | GFC_OMP_SPLIT_TASKLOOP; + innermost = GFC_OMP_SPLIT_TASKLOOP; + break; case EXEC_OMP_MASTER_TASKLOOP: case EXEC_OMP_TASKLOOP: innermost = GFC_OMP_SPLIT_TASKLOOP; break; + case EXEC_OMP_MASKED_TASKLOOP_SIMD: + mask = GFC_OMP_MASK_MASKED | GFC_OMP_MASK_TASKLOOP | GFC_OMP_MASK_SIMD; + innermost = GFC_OMP_SPLIT_SIMD; + break; case EXEC_OMP_MASTER_TASKLOOP_SIMD: case EXEC_OMP_TASKLOOP_SIMD: mask = GFC_OMP_MASK_TASKLOOP | GFC_OMP_MASK_SIMD; @@ -5814,6 +5873,8 @@ gfc_split_omp_clauses (gfc_code *code, clausesa[GFC_OMP_SPLIT_PARALLEL].if_expr = code->ext.omp_clauses->if_expr; } + if (mask & GFC_OMP_MASK_MASKED) + clausesa[GFC_OMP_SPLIT_MASKED].filter = code->ext.omp_clauses->filter; if ((mask & GFC_OMP_MASK_DO) && !is_loop) { /* First the clauses that are unique to some constructs. */ @@ -5896,16 +5957,18 @@ gfc_split_omp_clauses (gfc_code *code, clausesa[GFC_OMP_SPLIT_TASKLOOP].collapse = code->ext.omp_clauses->collapse; } - /* Private clause is supported on all constructs, - it is enough to put it on the innermost one. For + /* Private clause is supported on all constructs but master/masked, + it is enough to put it on the innermost one except for master/masked. For !$ omp parallel do put it on parallel though, as that's what we did for OpenMP 3.1. */ - clausesa[innermost == GFC_OMP_SPLIT_DO && !is_loop + clausesa[((innermost == GFC_OMP_SPLIT_DO && !is_loop) + || code->op == EXEC_OMP_PARALLEL_MASTER + || code->op == EXEC_OMP_PARALLEL_MASKED) ? (int) GFC_OMP_SPLIT_PARALLEL : innermost].lists[OMP_LIST_PRIVATE] = code->ext.omp_clauses->lists[OMP_LIST_PRIVATE]; /* Firstprivate clause is supported on all constructs but - simd. Put it on the outermost of those and duplicate + simd and masked/master. Put it on the outermost of those and duplicate on parallel and teams. */ if (mask & GFC_OMP_MASK_TARGET) clausesa[GFC_OMP_SPLIT_TARGET].lists[OMP_LIST_FIRSTPRIVATE] @@ -6588,43 +6651,66 @@ gfc_trans_omp_taskloop (gfc_code *code, gfc_exec_op op) } static tree -gfc_trans_omp_master_taskloop (gfc_code *code, gfc_exec_op op) +gfc_trans_omp_master_masked_taskloop (gfc_code *code, gfc_exec_op op) { + gfc_omp_clauses clausesa[GFC_OMP_SPLIT_NUM]; stmtblock_t block; tree stmt; - gfc_start_block (&block); + if (op != EXEC_OMP_MASTER_TASKLOOP_SIMD + && code->op != EXEC_OMP_MASTER_TASKLOOP) + gfc_split_omp_clauses (code, clausesa); + pushlevel (); - if (op == EXEC_OMP_MASTER_TASKLOOP_SIMD) + if (op == EXEC_OMP_MASKED_TASKLOOP_SIMD + || op == EXEC_OMP_MASTER_TASKLOOP_SIMD) stmt = gfc_trans_omp_taskloop (code, EXEC_OMP_TASKLOOP_SIMD); else { - gfc_omp_clauses clausesa[GFC_OMP_SPLIT_NUM]; - gcc_assert (op == EXEC_OMP_MASTER_TASKLOOP); - if (op != code->op) - gfc_split_omp_clauses (code, clausesa); + gcc_assert (op == EXEC_OMP_MASKED_TASKLOOP + || op == EXEC_OMP_MASTER_TASKLOOP); stmt = gfc_trans_omp_do (code, EXEC_OMP_TASKLOOP, NULL, - op != code->op + code->op != EXEC_OMP_MASTER_TASKLOOP ? &clausesa[GFC_OMP_SPLIT_TASKLOOP] : code->ext.omp_clauses, NULL); - if (op != code->op) - gfc_free_split_omp_clauses (code, clausesa); } if (TREE_CODE (stmt) != BIND_EXPR) stmt = build3_v (BIND_EXPR, NULL, stmt, poplevel (1, 0)); else poplevel (0, 0); - stmt = build1_v (OMP_MASTER, stmt); - gfc_add_expr_to_block (&block, stmt); + gfc_start_block (&block); + if (op == EXEC_OMP_MASKED_TASKLOOP || op == EXEC_OMP_MASKED_TASKLOOP_SIMD) + { + tree clauses = gfc_trans_omp_clauses (&block, + &clausesa[GFC_OMP_SPLIT_MASKED], + code->loc); + tree msk = make_node (OMP_MASKED); + TREE_TYPE (msk) = void_type_node; + OMP_MASKED_BODY (msk) = stmt; + OMP_MASKED_CLAUSES (msk) = clauses; + OMP_MASKED_COMBINED (msk) = 1; + gfc_add_expr_to_block (&block, msk); + } + else + { + gcc_assert (op == EXEC_OMP_MASTER_TASKLOOP + || op == EXEC_OMP_MASTER_TASKLOOP_SIMD); + stmt = build1_v (OMP_MASTER, stmt); + gfc_add_expr_to_block (&block, stmt); + } + if (op != EXEC_OMP_MASTER_TASKLOOP_SIMD + && code->op != EXEC_OMP_MASTER_TASKLOOP) + gfc_free_split_omp_clauses (code, clausesa); return gfc_finish_block (&block); } static tree -gfc_trans_omp_parallel_master (gfc_code *code) +gfc_trans_omp_parallel_master_masked (gfc_code *code) { stmtblock_t block; tree stmt, omp_clauses; gfc_omp_clauses clausesa[GFC_OMP_SPLIT_NUM]; + bool parallel_combined = false; if (code->op != EXEC_OMP_PARALLEL_MASTER) gfc_split_omp_clauses (code, clausesa); @@ -6635,19 +6721,33 @@ gfc_trans_omp_parallel_master (gfc_code *code) ? code->ext.omp_clauses : &clausesa[GFC_OMP_SPLIT_PARALLEL], code->loc); - if (code->op != EXEC_OMP_PARALLEL_MASTER) - gfc_free_split_omp_clauses (code, clausesa); pushlevel (); if (code->op == EXEC_OMP_PARALLEL_MASTER) stmt = gfc_trans_omp_master (code); + else if (code->op == EXEC_OMP_PARALLEL_MASKED) + stmt = gfc_trans_omp_masked (code, &clausesa[GFC_OMP_SPLIT_MASKED]); else { - gcc_assert (code->op == EXEC_OMP_PARALLEL_MASTER_TASKLOOP - || code->op == EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD); - gfc_exec_op op = (code->op == EXEC_OMP_PARALLEL_MASTER_TASKLOOP - ? EXEC_OMP_MASTER_TASKLOOP - : EXEC_OMP_MASTER_TASKLOOP_SIMD); - stmt = gfc_trans_omp_master_taskloop (code, op); + gfc_exec_op op; + switch (code->op) + { + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP: + op = EXEC_OMP_MASKED_TASKLOOP; + break; + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD: + op = EXEC_OMP_MASKED_TASKLOOP_SIMD; + break; + case EXEC_OMP_PARALLEL_MASTER_TASKLOOP: + op = EXEC_OMP_MASTER_TASKLOOP; + break; + case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD: + op = EXEC_OMP_MASTER_TASKLOOP_SIMD; + break; + default: + gcc_unreachable (); + } + stmt = gfc_trans_omp_master_masked_taskloop (code, op); + parallel_combined = true; } if (TREE_CODE (stmt) != BIND_EXPR) stmt = build3_v (BIND_EXPR, NULL, stmt, poplevel (1, 0)); @@ -6655,8 +6755,19 @@ gfc_trans_omp_parallel_master (gfc_code *code) poplevel (0, 0); stmt = build2_loc (gfc_get_location (&code->loc), OMP_PARALLEL, void_type_node, stmt, omp_clauses); - OMP_PARALLEL_COMBINED (stmt) = 1; + /* masked does have just filter clause, but during gimplification + isn't represented by a gimplification omp context, so for + !$omp parallel masked don't set OMP_PARALLEL_COMBINED, + so that + !$omp parallel masked + !$omp taskloop simd lastprivate (x) + isn't confused with + !$omp parallel masked taskloop simd lastprivate (x) */ + if (parallel_combined) + OMP_PARALLEL_COMBINED (stmt) = 1; gfc_add_expr_to_block (&block, stmt); + if (code->op != EXEC_OMP_PARALLEL_MASTER) + gfc_free_split_omp_clauses (code, clausesa); return gfc_finish_block (&block); } @@ -6969,11 +7080,15 @@ gfc_trans_omp_directive (gfc_code *code) return gfc_trans_omp_do_simd (code, NULL, NULL, NULL_TREE); case EXEC_OMP_FLUSH: return gfc_trans_omp_flush (code); + case EXEC_OMP_MASKED: + return gfc_trans_omp_masked (code, NULL); case EXEC_OMP_MASTER: return gfc_trans_omp_master (code); + case EXEC_OMP_MASKED_TASKLOOP: + case EXEC_OMP_MASKED_TASKLOOP_SIMD: case EXEC_OMP_MASTER_TASKLOOP: case EXEC_OMP_MASTER_TASKLOOP_SIMD: - return gfc_trans_omp_master_taskloop (code, code->op); + return gfc_trans_omp_master_masked_taskloop (code, code->op); case EXEC_OMP_ORDERED: return gfc_trans_omp_ordered (code); case EXEC_OMP_PARALLEL: @@ -6984,10 +7099,13 @@ gfc_trans_omp_directive (gfc_code *code) return gfc_trans_omp_parallel_do (code, true, NULL, NULL); case EXEC_OMP_PARALLEL_DO_SIMD: return gfc_trans_omp_parallel_do_simd (code, NULL, NULL); + case EXEC_OMP_PARALLEL_MASKED: + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP: + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD: case EXEC_OMP_PARALLEL_MASTER: case EXEC_OMP_PARALLEL_MASTER_TASKLOOP: case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD: - return gfc_trans_omp_parallel_master (code); + return gfc_trans_omp_parallel_master_masked (code); case EXEC_OMP_PARALLEL_SECTIONS: return gfc_trans_omp_parallel_sections (code); case EXEC_OMP_PARALLEL_WORKSHARE: diff --git a/gcc/fortran/trans.c b/gcc/fortran/trans.c index 275d6a2..ce5b2f8 100644 --- a/gcc/fortran/trans.c +++ b/gcc/fortran/trans.c @@ -2156,6 +2156,9 @@ trans_code (gfc_code * code, tree cond) case EXEC_OMP_DO_SIMD: case EXEC_OMP_LOOP: case EXEC_OMP_FLUSH: + case EXEC_OMP_MASKED: + case EXEC_OMP_MASKED_TASKLOOP: + case EXEC_OMP_MASKED_TASKLOOP_SIMD: case EXEC_OMP_MASTER: case EXEC_OMP_MASTER_TASKLOOP: case EXEC_OMP_MASTER_TASKLOOP_SIMD: @@ -2164,6 +2167,9 @@ trans_code (gfc_code * code, tree cond) case EXEC_OMP_PARALLEL_DO: case EXEC_OMP_PARALLEL_DO_SIMD: case EXEC_OMP_PARALLEL_LOOP: + case EXEC_OMP_PARALLEL_MASKED: + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP: + case EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD: case EXEC_OMP_PARALLEL_MASTER: case EXEC_OMP_PARALLEL_MASTER_TASKLOOP: case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD: diff --git a/gcc/testsuite/gfortran.dg/gomp/masked-1.f90 b/gcc/testsuite/gfortran.dg/gomp/masked-1.f90 new file mode 100644 index 0000000..1bd6176 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/masked-1.f90 @@ -0,0 +1,94 @@ +! { dg-additional-options "-ffree-line-length-none" } +subroutine foo (x, a) + implicit none + integer, value :: x + integer, contiguous :: a(0:) + external :: bar + integer :: i + + !$omp masked + call bar () + !$omp end masked + + !$omp masked filter (0) + call bar () + !$omp end masked + + !$omp masked filter (7) + call bar () + !$omp end masked + + !$omp masked filter (x) + call bar () + !$omp end masked + + !$omp masked taskloop simd filter (x) grainsize (12) simdlen (4) + do i = 0, 127 + a(i) = i + end do + !$omp end masked taskloop simd + + !$omp parallel masked filter (x) firstprivate (x) + call bar () + !$omp end parallel masked + + !$omp masked + !$omp masked filter (0) + !$omp masked filter (x) + !$omp end masked + !$omp end masked + !$omp end masked +end + +subroutine foobar (d, f, fi, p, s, g, i1, i2, l, ll, nth, ntm, pp, q, r, r2) + implicit none (type, external) + logical :: i1, i2, fi + integer :: i, d, f, p, s, g, l, ll, nth, ntm, pp, q, r, r2 + allocatable :: q + integer, save :: t + !$omp threadprivate (t) + + !$omp parallel masked & + !$omp& private (p) firstprivate (f) if (parallel: i2) default(shared) shared(s) reduction(+:r) & + !$omp& num_threads (nth) proc_bind(spread) copyin(t) filter (d) ! allocate (f) + ! + !$omp end parallel masked + + !$omp taskgroup task_reduction (+:r2) ! allocate (r2) + !$omp masked taskloop & + !$omp& private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) grainsize (g) collapse(1) untied if(taskloop: i1) final(fi) mergeable priority (pp) & + !$omp& reduction(default, +:r) in_reduction(+:r2) filter (d) ! allocate (f) + do i = 0, 63 + ll = ll + 1 + end do + !$omp end masked taskloop + !$omp end taskgroup + + !$omp taskgroup task_reduction (+:r2) ! allocate (r2) + !$omp masked taskloop simd & + !$omp& private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) grainsize (g) collapse(1) untied if(taskloop: i1) if(simd: i2) final(fi) mergeable priority (pp) & + !$omp& safelen(8) simdlen(4) linear(ll: 1) aligned(q: 32) reduction(default, +:r) in_reduction(+:r2) nontemporal(ntm) & + !$omp& order(concurrent) filter (d) ! allocate (f) + do i = 0, 63 + ll = ll + 1 + end do + !$omp end masked taskloop simd + !$omp end taskgroup + + !$omp parallel masked taskloop & + !$omp& private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) grainsize (g) collapse(1) untied if(taskloop: i1) final(fi) mergeable priority (pp) & + !$omp& reduction(default, +:r) if (parallel: i2) num_threads (nth) proc_bind(spread) copyin(t) filter (d) ! allocate (f) + do i = 0, 63 + ll = ll + 1 + end do + !$omp end parallel masked taskloop + + !$omp parallel masked taskloop simd & + !$omp& private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) grainsize (g) collapse(1) untied if(taskloop: i1) if(simd: i2) final(fi) mergeable priority (pp) & + !$omp& safelen(8) simdlen(4) linear(ll: 1) aligned(q: 32) reduction(default, +:r) nontemporal(ntm) if (parallel: i2) num_threads (nth) proc_bind(spread) copyin(t) & + !$omp& order(concurrent) filter (d) ! allocate (f) + do i = 0, 63 + ll = ll + 1 + end do + !$omp end parallel masked taskloop simd +end subroutine diff --git a/gcc/testsuite/gfortran.dg/gomp/masked-2.f90 b/gcc/testsuite/gfortran.dg/gomp/masked-2.f90 new file mode 100644 index 0000000..95ef78c --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/masked-2.f90 @@ -0,0 +1,46 @@ +module m + implicit none (external, type) + type t + end type t +contains +subroutine foo (x, y, z, a) + external :: bar + type(t) :: x + integer :: y + real :: z + integer :: a(4) + + !$omp masked filter (x) ! { dg-error "FILTER clause at .1. requires a scalar INTEGER expression" } + call bar () + !$omp end masked + + !$omp masked filter (y) ! OK + call bar () + !$omp end masked + + !$omp masked filter (z) ! { dg-error "FILTER clause at .1. requires a scalar INTEGER expression" } + call bar () + !$omp end masked + + !$omp masked filter (a) ! { dg-error "FILTER clause at .1. requires a scalar INTEGER expression" } + call bar () + !$omp end masked + + !$omp masked filter (0.0) ! { dg-error "FILTER clause at .1. requires a scalar INTEGER expression" } + call bar () + !$omp end masked + + !$omp masked filter ([1]) ! { dg-error "FILTER clause at .1. requires a scalar INTEGER expression" } + call bar () + !$omp end masked + + !$omp masked filter (-1) ! { dg-warning "INTEGER expression of FILTER clause at .1. must be non-negative" } + call bar () + !$omp end masked +end +end module + +subroutine bar + !$omp masked filter (0) filter (0) ! { dg-error "27: Failed to match clause" } + call foobar +end diff --git a/gcc/testsuite/gfortran.dg/gomp/masked-3.f90 b/gcc/testsuite/gfortran.dg/gomp/masked-3.f90 new file mode 100644 index 0000000..49c633d --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/masked-3.f90 @@ -0,0 +1,12 @@ +subroutine foo + + !$omp masked + goto 55 ! { dg-error "invalid branch to/from OpenMP structured block" } + ! { dg-warning "Legacy Extension: Label at .1. is not in the same block as the GOTO statement" "" { target *-*-* } .-1 } + !$omp end masked + + !$omp masked +55 continue ! { dg-warning "Legacy Extension: Label at .1. is not in the same block as the GOTO statement" } + return ! { dg-error "invalid branch to/from OpenMP structured block" } + !$omp end masked +end subroutine foo diff --git a/gcc/testsuite/gfortran.dg/gomp/masked-combined-1.f90 b/gcc/testsuite/gfortran.dg/gomp/masked-combined-1.f90 new file mode 100644 index 0000000..23ffb08 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/masked-combined-1.f90 @@ -0,0 +1,65 @@ +subroutine foo (a, f) + implicit none (type, external) + interface + subroutine bar (x) + integer :: x + end subroutine + end interface + + integer, value :: f + integer, contiguous :: a(0:) + integer :: i, j, k, u, v, w, x, y, z + + !$omp parallel masked default(none) private (k) filter (f) firstprivate (f) + call bar (k) + !$omp end parallel masked + + !$omp parallel masked default(none) private (k) + call bar (k) + !$omp end parallel masked + + !$omp parallel default(none) firstprivate(a, f) shared(x, y, z) + !$omp masked taskloop reduction (+:x) default(none) firstprivate(a) filter (f) + do i = 0, 63 + x = x + a(i) + end do + !$omp end masked taskloop + !$omp masked taskloop simd reduction (+:y) default(none) firstprivate(a) private (i) filter (f) + do i = 0, 63 + y = y + a(i) + end do + !$omp end masked taskloop simd + !$omp masked taskloop simd reduction (+:y) default(none) firstprivate(a) private (i) + do i = 0, 63 + y = y + a(i) + end do + !$omp end masked taskloop simd + !$omp masked taskloop simd collapse(2) reduction (+:z) default(none) firstprivate(a) private (i, j) filter (f) + do j = 0, 0 + do i = 0, 63 + z = z + a(i) + end do + end do + !$omp end masked taskloop simd + !$omp end parallel + + !$omp parallel masked taskloop reduction (+:u) default(none) firstprivate(a, f) filter (f) + do i = 0, 63 + u = u + a(i) + end do + !$omp end parallel masked taskloop + + !$omp parallel masked taskloop simd reduction (+:v) default(none) firstprivate(a, f) filter (f) + do i = 0, 63 + v = v + a(i) + end do + !$omp end parallel masked taskloop simd + + !$omp parallel masked taskloop simd collapse(2) reduction (+:w) default(none) firstprivate(a, f) filter (f) + do j = 0, 0 + do i = 0, 63 + w = w + a(i) + end do + end do + !$omp end parallel masked taskloop simd +end diff --git a/gcc/testsuite/gfortran.dg/gomp/masked-combined-2.f90 b/gcc/testsuite/gfortran.dg/gomp/masked-combined-2.f90 new file mode 100644 index 0000000..c94425f --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/masked-combined-2.f90 @@ -0,0 +1,24 @@ +subroutine foo (a) + implicit none (external, type) + integer, contiguous :: a(0:) + integer :: i, r, s + r = 0; s = 0 + + ! In 'parallel masked taskloop', in_reduction is not permitted. + + !$omp taskgroup task_reduction(+:r) + !$omp parallel masked taskloop in_reduction(+:r) ! { dg-error "36: Failed to match clause" } + do i = 0, 63 + r = r + a(i) + end do + !!$omp end parallel masked taskloop + !$omp end taskgroup + + !$omp taskgroup task_reduction(+:s) + !$omp parallel masked taskloop simd in_reduction(+:s) ! { dg-error "41: Failed to match clause" } + do i = 0, 63 + s = s + a(i) + end do + !!$omp end parallel masked taskloop simd + !$omp end taskgroup +end -- cgit v1.1 From faf2b6bc527dff31725dde5538ffff1c92688047 Mon Sep 17 00:00:00 2001 From: liuhongt Date: Mon, 16 Aug 2021 11:16:52 +0800 Subject: Optimize __builtin_shuffle_vector. 1. Support vpermw/vpermb in ix86_expand_vec_one_operand_perm_avx512. 2. Support 256/128-bits vpermi2b ix86_expand_vec_perm_vpermt2. 3. Add define_insn_and_split to optimize specific vector permutation to opmov{dw,wb,qd}. gcc/ChangeLog: PR target/101846 * config/i386/i386-expand.c (ix86_expand_vec_perm_vpermt2): Support vpermi2b for V32QI/V16QImode. (ix86_extract_perm_from_pool_constant): New function. (ix86_expand_vec_one_operand_perm_avx512): Support vpermw/vpermb under TARGET_AVX512BW/TARGET_AVX512VBMI. (expand_vec_perm_1): Adjust comments for upper. * config/i386/i386-protos.h (ix86_extract_perm_from_pool_constant): New declare. * config/i386/predicates.md (permvar_truncate_operand): New predicate. (pshufb_truncv4siv4hi_operand): Ditto. (pshufb_truncv8hiv8qi_operand): Ditto. * config/i386/sse.md (*avx512bw_permvar_truncv16siv16hi_1): New pre_reload define_insn_and_split. (*avx512f_permvar_truncv8siv8hi_1): Ditto. (*avx512f_vpermvar_truncv8div8si_1): Ditto. (*avx512f_permvar_truncv32hiv32qi_1): Ditto. (*avx512f_permvar_truncv16hiv16qi_1): Ditto. (*avx512f_permvar_truncv4div4si_1): Ditto. (*avx512f_pshufb_truncv8hiv8qi_1): Ditto. (*avx512f_pshufb_truncv4siv4hi_1): Ditto. (*avx512f_pshufd_truncv2div2si_1): Ditto. gcc/testsuite/ChangeLog: PR target/101846 * gcc.target/i386/pr101846-2.c: New test. * gcc.target/i386/pr101846-3.c: New test. * gcc.target/i386/pr101846-4.c: New test. --- gcc/config/i386/i386-expand.c | 89 +++++++++++++- gcc/config/i386/i386-protos.h | 1 + gcc/config/i386/predicates.md | 90 ++++++++++++++ gcc/config/i386/sse.md | 190 +++++++++++++++++++++++++++++ gcc/testsuite/gcc.target/i386/pr101846-2.c | 81 ++++++++++++ gcc/testsuite/gcc.target/i386/pr101846-3.c | 73 +++++++++++ gcc/testsuite/gcc.target/i386/pr101846-4.c | 40 ++++++ 7 files changed, 559 insertions(+), 5 deletions(-) create mode 100644 gcc/testsuite/gcc.target/i386/pr101846-2.c create mode 100644 gcc/testsuite/gcc.target/i386/pr101846-3.c create mode 100644 gcc/testsuite/gcc.target/i386/pr101846-4.c (limited to 'gcc') diff --git a/gcc/config/i386/i386-expand.c b/gcc/config/i386/i386-expand.c index 4d7349c..9bf13db 100644 --- a/gcc/config/i386/i386-expand.c +++ b/gcc/config/i386/i386-expand.c @@ -4778,6 +4778,18 @@ ix86_expand_vec_perm_vpermt2 (rtx target, rtx mask, rtx op0, rtx op1, switch (mode) { + case E_V16QImode: + if (TARGET_AVX512VL && TARGET_AVX512VBMI) + gen = gen_avx512vl_vpermt2varv16qi3; + break; + case E_V32QImode: + if (TARGET_AVX512VL && TARGET_AVX512VBMI) + gen = gen_avx512vl_vpermt2varv32qi3; + break; + case E_V64QImode: + if (TARGET_AVX512VBMI) + gen = gen_avx512bw_vpermt2varv64qi3; + break; case E_V8HImode: if (TARGET_AVX512VL && TARGET_AVX512BW) gen = gen_avx512vl_vpermt2varv8hi3; @@ -4786,10 +4798,6 @@ ix86_expand_vec_perm_vpermt2 (rtx target, rtx mask, rtx op0, rtx op1, if (TARGET_AVX512VL && TARGET_AVX512BW) gen = gen_avx512vl_vpermt2varv16hi3; break; - case E_V64QImode: - if (TARGET_AVX512VBMI) - gen = gen_avx512bw_vpermt2varv64qi3; - break; case E_V32HImode: if (TARGET_AVX512BW) gen = gen_avx512bw_vpermt2varv32hi3; @@ -5487,6 +5495,45 @@ ix86_expand_sse_unpack (rtx dest, rtx src, bool unsigned_p, bool high_p) } } +/* Return true if mem is pool constant which contains a const_vector + perm index, assign the index to PERM. */ +bool +ix86_extract_perm_from_pool_constant (int* perm, rtx mem) +{ + machine_mode mode = GET_MODE (mem); + int nelt = GET_MODE_NUNITS (mode); + + if (!INTEGRAL_MODE_P (mode)) + return false; + + /* Needs to be constant pool. */ + if (!(MEM_P (mem)) + || !SYMBOL_REF_P (XEXP (mem, 0)) + || !CONSTANT_POOL_ADDRESS_P (XEXP (mem, 0))) + return false; + + rtx constant = get_pool_constant (XEXP (mem, 0)); + + if (GET_CODE (constant) != CONST_VECTOR) + return false; + + /* There could be some rtx like + (mem/u/c:V16QI (symbol_ref/u:DI ("*.LC1"))) + but with "*.LC1" refer to V2DI constant vector. */ + if (GET_MODE (constant) != mode) + { + constant = simplify_subreg (mode, constant, GET_MODE (constant), 0); + + if (constant == nullptr || GET_CODE (constant) != CONST_VECTOR) + return false; + } + + for (int i = 0; i != nelt; i++) + perm[i] = UINTVAL (XVECEXP (constant, 0, i)); + + return true; +} + /* Split operands 0 and 1 into half-mode parts. Similar to split_double_mode, but works for floating pointer parameters and nonoffsetable memories. For pushes, it returns just stack offsets; the values will be saved @@ -18086,6 +18133,7 @@ ix86_expand_vec_one_operand_perm_avx512 (struct expand_vec_perm_d *d) { machine_mode mode = GET_MODE (d->op0); machine_mode maskmode = mode; + unsigned inner_size = GET_MODE_SIZE (GET_MODE_INNER (mode)); rtx (*gen) (rtx, rtx, rtx) = NULL; rtx target, op0, mask; rtx vec[64]; @@ -18096,6 +18144,18 @@ ix86_expand_vec_one_operand_perm_avx512 (struct expand_vec_perm_d *d) if (!TARGET_AVX512F) return false; + /* Accept VNxHImode and VNxQImode now. */ + if (!TARGET_AVX512VL && GET_MODE_SIZE (mode) < 64) + return false; + + /* vpermw. */ + if (!TARGET_AVX512BW && inner_size == 2) + return false; + + /* vpermb. */ + if (!TARGET_AVX512VBMI && inner_size == 1) + return false; + switch (mode) { case E_V16SImode: @@ -18112,6 +18172,25 @@ ix86_expand_vec_one_operand_perm_avx512 (struct expand_vec_perm_d *d) gen = gen_avx512f_permvarv8df; maskmode = V8DImode; break; + case E_V32HImode: + gen = gen_avx512bw_permvarv32hi; + break; + case E_V16HImode: + gen = gen_avx512vl_permvarv16hi; + break; + case E_V8HImode: + gen = gen_avx512vl_permvarv8hi; + break; + case E_V64QImode: + gen = gen_avx512bw_permvarv64qi; + break; + case E_V32QImode: + gen = gen_avx512vl_permvarv32qi; + break; + case E_V16QImode: + gen = gen_avx512vl_permvarv16qi; + break; + default: return false; } @@ -18301,7 +18380,7 @@ expand_vec_perm_1 (struct expand_vec_perm_d *d) if (expand_vec_perm_palignr (d, true)) return true; - /* Try the AVX512F vperm{s,d} instructions. */ + /* Try the AVX512F vperm{w,b,s,d} instructions */ if (ix86_expand_vec_one_operand_perm_avx512 (d)) return true; diff --git a/gcc/config/i386/i386-protos.h b/gcc/config/i386/i386-protos.h index 07ac02a..2fd1307 100644 --- a/gcc/config/i386/i386-protos.h +++ b/gcc/config/i386/i386-protos.h @@ -260,6 +260,7 @@ extern void ix86_expand_sse2_mulvxdi3 (rtx, rtx, rtx); extern void ix86_expand_sse2_abs (rtx, rtx); extern bool ix86_expand_vector_init_duplicate (bool, machine_mode, rtx, rtx); +extern bool ix86_extract_perm_from_pool_constant (int*, rtx); /* In i386-c.c */ extern void ix86_target_macros (void); diff --git a/gcc/config/i386/predicates.md b/gcc/config/i386/predicates.md index 129205a..9321f33 100644 --- a/gcc/config/i386/predicates.md +++ b/gcc/config/i386/predicates.md @@ -1713,6 +1713,96 @@ return true; }) +;; Return true if OP is a constant pool in perm{w,d,b} which constains index +;; match pmov{dw,wb,qd}. +(define_predicate "permvar_truncate_operand" + (match_code "mem") +{ + int nelt = GET_MODE_NUNITS (mode); + int perm[128]; + int id; + + if (!INTEGRAL_MODE_P (mode) || !VECTOR_MODE_P (mode)) + return false; + + if (nelt < 2) + return false; + + if (!ix86_extract_perm_from_pool_constant (&perm[0], op)) + return false; + + id = exact_log2 (nelt); + + /* Check that the permutation is suitable for pmovz{bw,wd,dq}. + For example V16HImode to V8HImode + { 0 2 4 6 8 10 12 14 * * * * * * * * }. */ + for (int i = 0; i != nelt / 2; i++) + if ((perm[i] & ((1 << id) - 1)) != i * 2) + return false; + + return true; +}) + +;; Return true if OP is a constant pool in shufb which constains index +;; match pmovdw. +(define_predicate "pshufb_truncv4siv4hi_operand" + (match_code "mem") +{ + int perm[128]; + + if (mode != E_V16QImode) + return false; + + if (!ix86_extract_perm_from_pool_constant (&perm[0], op)) + return false; + + /* Check that the permutation is suitable for pmovdw. + For example V4SImode to V4HImode + { 0 1 4 5 8 9 12 13 * * * * * * * * }. + index = i % 2 + (i / 2) * 4. */ + for (int i = 0; i != 8; i++) + { + /* if (SRC2[(i * 8)+7] = 1) then DEST[(i*8)+7..(i*8)+0] := 0; */ + if (perm[i] & 128) + return false; + + if ((perm[i] & 15) != ((i & 1) + (i & 0xFE) * 2)) + return false; + } + + return true; +}) + +;; Return true if OP is a constant pool in shufb which constains index +;; match pmovdw. +(define_predicate "pshufb_truncv8hiv8qi_operand" + (match_code "mem") +{ + int perm[128]; + + if (mode != E_V16QImode) + return false; + + if (!ix86_extract_perm_from_pool_constant (&perm[0], op)) + return false; + + /* Check that the permutation is suitable for pmovwb. + For example V16QImode to V8QImode + { 0 2 4 6 8 10 12 14 * * * * * * * * }. + index = i % 2 + (i / 2) * 4. */ + for (int i = 0; i != 8; i++) + { + /* if (SRC2[(i * 8)+7] = 1) then DEST[(i*8)+7..(i*8)+0] := 0; */ + if (perm[i] & 128) + return false; + + if ((perm[i] & 15) != i * 2) + return false; + } + + return true; +}) + ;; Return true if OP is a parallel for an pmovz{bw,wd,dq} vec_select, ;; where one of the two operands of the vec_concat is const0_operand. (define_predicate "pmovzx_parallel" diff --git a/gcc/config/i386/sse.md b/gcc/config/i386/sse.md index 60e69a4..27e25cc 100644 --- a/gcc/config/i386/sse.md +++ b/gcc/config/i386/sse.md @@ -10977,6 +10977,64 @@ (set_attr "prefix" "evex") (set_attr "mode" "")]) +(define_insn_and_split "*avx512bw_permvar_truncv16siv16hi_1" + [(set (match_operand:V16HI 0 "nonimmediate_operand") + (vec_select:V16HI + (unspec:V32HI + [(match_operand:V32HI 1 "register_operand") + (match_operand:V32HI 2 "permvar_truncate_operand")] + UNSPEC_VPERMVAR) + (parallel [(const_int 0) (const_int 1) + (const_int 2) (const_int 3) + (const_int 4) (const_int 5) + (const_int 6) (const_int 7) + (const_int 8) (const_int 9) + (const_int 10) (const_int 11) + (const_int 12) (const_int 13) + (const_int 14) (const_int 15)])))] + "TARGET_AVX512BW && ix86_pre_reload_split ()" + "#" + "&& 1" + [(set (match_dup 0) + (truncate:V16HI (match_dup 1)))] + "operands[1] = lowpart_subreg (V16SImode, operands[1], V32HImode);") + +(define_insn_and_split "*avx512f_permvar_truncv8siv8hi_1" + [(set (match_operand:V8HI 0 "nonimmediate_operand") + (vec_select:V8HI + (unspec:V16HI + [(match_operand:V16HI 1 "register_operand") + (match_operand:V16HI 2 "permvar_truncate_operand")] + UNSPEC_VPERMVAR) + (parallel [(const_int 0) (const_int 1) + (const_int 2) (const_int 3) + (const_int 4) (const_int 5) + (const_int 6) (const_int 7)])))] + "TARGET_AVX512VL && TARGET_AVX512BW && ix86_pre_reload_split ()" + "#" + "&& 1" + [(set (match_dup 0) + (truncate:V8HI (match_dup 1)))] + "operands[1] = lowpart_subreg (V8SImode, operands[1], V16HImode);") + +(define_insn_and_split "*avx512f_vpermvar_truncv8div8si_1" + [(set (match_operand:V8SI 0 "nonimmediate_operand") + (vec_select:V8SI + (unspec:V16SI + [(match_operand:V16SI 1 "register_operand") + (match_operand:V16SI 2 "permvar_truncate_operand")] + UNSPEC_VPERMVAR) + (parallel [(const_int 0) (const_int 1) + (const_int 2) (const_int 3) + (const_int 4) (const_int 5) + (const_int 6) (const_int 7)])))] + "TARGET_AVX512F && ix86_pre_reload_split ()" + "#" + "&& 1" + [(set (match_dup 0) + (truncate:V8SI (match_dup 1)))] + "operands[1] = lowpart_subreg (V8DImode, operands[1], V16SImode);") + (define_insn "avx512f_2_mask" [(set (match_operand:PMOV_DST_MODE_1 0 "nonimmediate_operand" "=v,m") (vec_merge:PMOV_DST_MODE_1 @@ -11017,6 +11075,36 @@ (set_attr "prefix" "evex") (set_attr "mode" "XI")]) +(define_insn_and_split "*avx512f_permvar_truncv32hiv32qi_1" + [(set (match_operand:V32QI 0 "nonimmediate_operand") + (vec_select:V32QI + (unspec:V64QI + [(match_operand:V64QI 1 "register_operand") + (match_operand:V64QI 2 "permvar_truncate_operand")] + UNSPEC_VPERMVAR) + (parallel [(const_int 0) (const_int 1) + (const_int 2) (const_int 3) + (const_int 4) (const_int 5) + (const_int 6) (const_int 7) + (const_int 8) (const_int 9) + (const_int 10) (const_int 11) + (const_int 12) (const_int 13) + (const_int 14) (const_int 15) + (const_int 16) (const_int 17) + (const_int 18) (const_int 19) + (const_int 20) (const_int 21) + (const_int 22) (const_int 23) + (const_int 24) (const_int 25) + (const_int 26) (const_int 27) + (const_int 28) (const_int 29) + (const_int 30) (const_int 31)])))] + "TARGET_AVX512VBMI && ix86_pre_reload_split ()" + "#" + "&& 1" + [(set (match_dup 0) + (truncate:V32QI (match_dup 1)))] + "operands[1] = lowpart_subreg (V32HImode, operands[1], V64QImode);") + (define_insn "avx512bw_v32hiv32qi2_mask" [(set (match_operand:V32QI 0 "nonimmediate_operand" "=v,m") (vec_merge:V32QI @@ -11062,6 +11150,45 @@ (set_attr "prefix" "evex") (set_attr "mode" "")]) +(define_insn_and_split "*avx512f_permvar_truncv16hiv16qi_1" + [(set (match_operand:V16QI 0 "nonimmediate_operand") + (vec_select:V16QI + (unspec:V32QI + [(match_operand:V32QI 1 "register_operand") + (match_operand:V32QI 2 "permvar_truncate_operand")] + UNSPEC_VPERMVAR) + (parallel [(const_int 0) (const_int 1) + (const_int 2) (const_int 3) + (const_int 4) (const_int 5) + (const_int 6) (const_int 7) + (const_int 8) (const_int 9) + (const_int 10) (const_int 11) + (const_int 12) (const_int 13) + (const_int 14) (const_int 15)])))] + "TARGET_AVX512VL && TARGET_AVX512VBMI + && ix86_pre_reload_split ()" + "#" + "&& 1" + [(set (match_dup 0) + (truncate:V16QI (match_dup 1)))] + "operands[1] = lowpart_subreg (V16HImode, operands[1], V32QImode);") + +(define_insn_and_split "*avx512f_permvar_truncv4div4si_1" + [(set (match_operand:V4SI 0 "nonimmediate_operand") + (vec_select:V4SI + (unspec:V8SI + [(match_operand:V8SI 1 "register_operand") + (match_operand:V8SI 2 "permvar_truncate_operand")] + UNSPEC_VPERMVAR) + (parallel [(const_int 0) (const_int 1) + (const_int 2) (const_int 3)])))] + "TARGET_AVX512VL && ix86_pre_reload_split ()" + "#" + "&& 1" + [(set (match_dup 0) + (truncate:V4SI (match_dup 1)))] + "operands[1] = lowpart_subreg (V4DImode, operands[1], V8SImode);") + (define_insn "_2_mask" [(set (match_operand:PMOV_DST_MODE_2 0 "nonimmediate_operand" "=v,m") (vec_merge:PMOV_DST_MODE_2 @@ -11120,6 +11247,27 @@ (set_attr "prefix" "evex") (set_attr "mode" "TI")]) +(define_insn_and_split "*avx512f_pshufb_truncv8hiv8qi_1" + [(set (match_operand:DI 0 "register_operand") + (vec_select:DI + (subreg:V2DI + (unspec:V16QI + [(match_operand:V16QI 1 "register_operand") + (match_operand:V16QI 2 "pshufb_truncv8hiv8qi_operand")] + UNSPEC_PSHUFB) 0) + (parallel [(const_int 0)])))] + "TARGET_AVX512VL && ix86_pre_reload_split ()" + "#" + "&& 1" + [(const_int 0)] +{ + rtx op1 = gen_reg_rtx (V8QImode); + operands[1] = lowpart_subreg (V8HImode, operands[1], V16QImode); + emit_insn (gen_truncv8hiv8qi2 (op1, operands[1])); + emit_move_insn (operands[0], lowpart_subreg (DImode, op1, V8QImode)); + DONE; +}) + (define_insn "*avx512vl_v2div2qi2_store_1" [(set (match_operand:V2QI 0 "memory_operand" "=m") (any_truncate:V2QI @@ -11475,6 +11623,27 @@ (set_attr "prefix" "evex") (set_attr "mode" "TI")]) +(define_insn_and_split "*avx512f_pshufb_truncv4siv4hi_1" + [(set (match_operand:DI 0 "register_operand") + (vec_select:DI + (subreg:V2DI + (unspec:V16QI + [(match_operand:V16QI 1 "register_operand") + (match_operand:V16QI 2 "pshufb_truncv4siv4hi_operand")] + UNSPEC_PSHUFB) 0) + (parallel [(const_int 0)])))] + "TARGET_AVX512VL && ix86_pre_reload_split ()" + "#" + "&& 1" + [(const_int 0)] +{ + rtx op1 = gen_reg_rtx (V4HImode); + operands[1] = lowpart_subreg (V4SImode, operands[1], V16QImode); + emit_insn (gen_truncv4siv4hi2 (op1, operands[1])); + emit_move_insn (operands[0], lowpart_subreg (DImode, op1, V4HImode)); + DONE; +}) + (define_insn "*avx512vl_v4hi2_store_1" [(set (match_operand:V4HI 0 "memory_operand" "=m") (any_truncate:V4HI @@ -11698,6 +11867,27 @@ (set_attr "prefix" "evex") (set_attr "mode" "TI")]) +(define_insn_and_split "*avx512f_pshufd_truncv2div2si_1" + [(set (match_operand:DI 0 "register_operand") + (vec_select:DI + (subreg:V2DI + (vec_select:V4SI + (match_operand:V4SI 1 "register_operand") + (parallel [(const_int 0) (const_int 2) + (const_int 2) (const_int 3)])) 0) + (parallel [(const_int 0)])))] + "TARGET_AVX512VL && ix86_pre_reload_split ()" + "#" + "&& 1" + [(const_int 0)] +{ + rtx op1 = gen_reg_rtx (V2SImode); + operands[1] = lowpart_subreg (V2DImode, operands[1], V4SImode); + emit_insn (gen_truncv2div2si2 (op1, operands[1])); + emit_move_insn (operands[0], lowpart_subreg (DImode, op1, V2SImode)); + DONE; +}) + (define_insn "*avx512vl_v2div2si2_store_1" [(set (match_operand:V2SI 0 "memory_operand" "=m") (any_truncate:V2SI diff --git a/gcc/testsuite/gcc.target/i386/pr101846-2.c b/gcc/testsuite/gcc.target/i386/pr101846-2.c new file mode 100644 index 0000000..26c9ed5 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr101846-2.c @@ -0,0 +1,81 @@ +/* { dg-do compile } */ +/* { dg-options "-mavx512vl -mavx512vbmi -O2" } */ +/* { dg-final { scan-assembler-times "vpmovwb" "3" } } */ +/* { dg-final { scan-assembler-times "vpmovdw" "3" } } */ +/* { dg-final { scan-assembler-times "vpmovqd" "3" } } */ + +typedef short v4hi __attribute__((vector_size (8))); +typedef short v8hi __attribute__((vector_size (16))); +typedef short v16hi __attribute__((vector_size (32))); +typedef short v32hi __attribute__((vector_size (64))); +typedef char v8qi __attribute__((vector_size (8))); +typedef char v16qi __attribute__((vector_size (16))); +typedef char v32qi __attribute__((vector_size (32))); +typedef char v64qi __attribute__((vector_size (64))); +typedef int v2si __attribute__((vector_size (8))); +typedef int v4si __attribute__((vector_size (16))); +typedef int v8si __attribute__((vector_size (32))); +typedef int v16si __attribute__((vector_size (64))); + +v16hi +foo_dw_512 (v32hi x) +{ + return __builtin_shufflevector (x, x, + 0, 2, 4, 6, 8, 10, 12, 14, + 16, 18, 20, 22, 24, 26, 28, 30); +} + +v8hi +foo_dw_256 (v16hi x) +{ + return __builtin_shufflevector (x, x, 0, 2, 4, 6, 8, 10, 12, 14); +} + +v4hi +foo_dw_128 (v8hi x) +{ + return __builtin_shufflevector (x, x, 0, 2, 4, 6); +} + +v8si +foo_qd_512 (v16si x) +{ + return __builtin_shufflevector (x, x, 0, 2, 4, 6, 8, 10, 12, 14); +} + +v4si +foo_qd_256 (v8si x) +{ + return __builtin_shufflevector (x, x, 0, 2, 4, 6); +} + +v2si +foo_qd_128 (v4si x) +{ + return __builtin_shufflevector (x, x, 0, 2); +} + +v32qi +foo_wb_512 (v64qi x) +{ + return __builtin_shufflevector (x, x, + 0, 2, 4, 6, 8, 10, 12, 14, + 16, 18, 20, 22, 24, 26, 28, 30, + 32, 34, 36, 38, 40, 42, 44, 46, + 48, 50, 52, 54, 56, 58, 60, 62); +} + +v16qi +foo_wb_256 (v32qi x) +{ + return __builtin_shufflevector (x, x, + 0, 2, 4, 6, 8, 10, 12, 14, + 16, 18, 20, 22, 24, 26, 28, 30); +} + +v8qi +foo_wb_128 (v16qi x) +{ + return __builtin_shufflevector (x, x, + 0, 2, 4, 6, 8, 10, 12, 14); +} diff --git a/gcc/testsuite/gcc.target/i386/pr101846-3.c b/gcc/testsuite/gcc.target/i386/pr101846-3.c new file mode 100644 index 0000000..f774018 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr101846-3.c @@ -0,0 +1,73 @@ +/* { dg-do compile } */ +/* { dg-options "-mavx512vl -mavx512vbmi -O2" } */ +/* { dg-final { scan-assembler-times "vpermb" "2" } } */ +/* { dg-final { scan-assembler-times "vpermw" "2" } } */ +/* { dg-final { scan-assembler-times "vpermd" "2" } } */ + +typedef short v4hi __attribute__((vector_size (8))); +typedef short v8hi __attribute__((vector_size (16))); +typedef short v16hi __attribute__((vector_size (32))); +typedef short v32hi __attribute__((vector_size (64))); +typedef char v8qi __attribute__((vector_size (8))); +typedef char v16qi __attribute__((vector_size (16))); +typedef char v32qi __attribute__((vector_size (32))); +typedef char v64qi __attribute__((vector_size (64))); +typedef int v2si __attribute__((vector_size (8))); +typedef int v4si __attribute__((vector_size (16))); +typedef int v8si __attribute__((vector_size (32))); +typedef int v16si __attribute__((vector_size (64))); + +v32hi +foow_512 (v32hi x) +{ + return __builtin_shufflevector (x, x, + 0, 2, 4, 6, 8, 10, 12, 14, + 16, 18, 20, 22, 24, 26, 28, 30, + 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31); +} + +v16hi +foow_256 (v16hi x) +{ + return __builtin_shufflevector (x, x, 0, 2, 4, 6, 8, 10, 12, 14, + 8, 9, 10, 11, 12, 13, 14, 15); +} + + +v16si +food_512 (v16si x) +{ + return __builtin_shufflevector (x, x, 0, 2, 4, 6, 8, 10, 12, 14, + 8, 9, 10, 11, 12, 13, 14, 15); +} + +v8si +food_256 (v8si x) +{ + return __builtin_shufflevector (x, x, 0, 2, 4, 6, 4, 5, 6, 7); +} + +v64qi +foob_512 (v64qi x) +{ + return __builtin_shufflevector (x, x, + 0, 2, 4, 6, 8, 10, 12, 14, + 16, 18, 20, 22, 24, 26, 28, 30, + 32, 34, 36, 38, 40, 42, 44, 46, + 48, 50, 52, 54, 56, 58, 60, 62, + 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63); +} + +v32qi +foob_256 (v32qi x) +{ + return __builtin_shufflevector (x, x, + 0, 2, 4, 6, 8, 10, 12, 14, + 16, 18, 20, 22, 24, 26, 28, 30, + 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31); +} diff --git a/gcc/testsuite/gcc.target/i386/pr101846-4.c b/gcc/testsuite/gcc.target/i386/pr101846-4.c new file mode 100644 index 0000000..2a6163c --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr101846-4.c @@ -0,0 +1,40 @@ +/* { dg-do compile } */ +/* { dg-options "-mavx512vl -mavx512vbmi -O2" } */ +/* { dg-final { scan-assembler-times "vpermi2b" "3" } } */ + +typedef char v16qi __attribute__((vector_size (16))); +typedef char v32qi __attribute__((vector_size (32))); +typedef char v64qi __attribute__((vector_size (64))); + + +v64qi +foob_512 (v64qi x, v64qi y) +{ + return __builtin_shufflevector (x, y, + 0, 2, 4, 6, 8, 10, 12, 14, + 16, 18, 20, 22, 24, 26, 28, 30, + 32, 34, 36, 38, 40, 42, 44, 46, + 48, 50, 52, 54, 56, 58, 60, 62, + 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 74, 77, 79, 74, 72, 70, + 89, 88, 78, 86, 85, 75, 83, 82, + 112, 108, 101, 100, 86, 96, 97, 95); +} + +v32qi +foob_256 (v32qi x, v32qi y) +{ + return __builtin_shufflevector (x, y, + 0, 2, 4, 6, 8, 10, 12, 14, + 16, 18, 20, 22, 24, 26, 28, 30, + 32, 34, 36, 38, 40, 42, 44, 46, + 48, 50, 52, 54, 56, 58, 60, 62); +} + +v16qi +foob_128 (v16qi x, v16qi y) +{ + return __builtin_shufflevector (x, y, + 0, 2, 4, 6, 8, 10, 12, 14, + 16, 18, 20, 22, 24, 26, 28, 30); +} -- cgit v1.1 From b0de3ad2620d665ab481c2f24204f77f386ff6b2 Mon Sep 17 00:00:00 2001 From: Martin Liska Date: Fri, 13 Aug 2021 12:35:47 +0200 Subject: ipa: ICF should check SSA_NAME_IS_DEFAULT_DEF PR ipa/100600 gcc/ChangeLog: * ipa-icf-gimple.c (func_checker::compare_ssa_name): Do not consider equal SSA_NAMEs when one is a param. gcc/testsuite/ChangeLog: * gcc.dg/ipa/pr100600.c: New test. --- gcc/ipa-icf-gimple.c | 3 +++ gcc/testsuite/gcc.dg/ipa/pr100600.c | 22 ++++++++++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 gcc/testsuite/gcc.dg/ipa/pr100600.c (limited to 'gcc') diff --git a/gcc/ipa-icf-gimple.c b/gcc/ipa-icf-gimple.c index edf5f02..cf02626 100644 --- a/gcc/ipa-icf-gimple.c +++ b/gcc/ipa-icf-gimple.c @@ -96,6 +96,9 @@ func_checker::compare_ssa_name (const_tree t1, const_tree t2) unsigned i1 = SSA_NAME_VERSION (t1); unsigned i2 = SSA_NAME_VERSION (t2); + if (SSA_NAME_IS_DEFAULT_DEF (t1) != SSA_NAME_IS_DEFAULT_DEF (t2)) + return false; + if (m_source_ssa_names[i1] == -1) m_source_ssa_names[i1] = i2; else if (m_source_ssa_names[i1] != (int) i2) diff --git a/gcc/testsuite/gcc.dg/ipa/pr100600.c b/gcc/testsuite/gcc.dg/ipa/pr100600.c new file mode 100644 index 0000000..8a3d0e1 --- /dev/null +++ b/gcc/testsuite/gcc.dg/ipa/pr100600.c @@ -0,0 +1,22 @@ +/* PR ipa/100600 */ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +int a, b, c; +long d(long x, long e, long f, long g) { + long h, i; + for (; h < e; h++) { + i = f; + for (; i < g; i++) + c = b + a; + } + return h + i; +} + +long j(long x, long e, long y, long g) { + long h, i; + for (; h < e; h++) + for (; i < g; i++) + c = b + a; + return h + i; +} -- cgit v1.1 From 91292490d573f9f9e4f162d6d8c693a969197f2d Mon Sep 17 00:00:00 2001 From: Martin Liska Date: Thu, 12 Aug 2021 16:01:01 +0200 Subject: ipa: make target_clone default decl local [PR101726] PR ipa/101726 gcc/ChangeLog: * multiple_target.c (create_dispatcher_calls): Make default function local only if it is a definition. --- gcc/multiple_target.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) (limited to 'gcc') diff --git a/gcc/multiple_target.c b/gcc/multiple_target.c index e419265..6c05658 100644 --- a/gcc/multiple_target.c +++ b/gcc/multiple_target.c @@ -170,17 +170,20 @@ create_dispatcher_calls (struct cgraph_node *node) clone_function_name_numbered ( node->decl, "default")); - /* FIXME: copy of cgraph_node::make_local that should be cleaned up - in next stage1. */ - node->make_decl_local (); - node->set_section (NULL); - node->set_comdat_group (NULL); - node->externally_visible = false; - node->forced_by_abi = false; - node->set_section (NULL); - - DECL_ARTIFICIAL (node->decl) = 1; - node->force_output = true; + if (node->definition) + { + /* FIXME: copy of cgraph_node::make_local that should be cleaned up + in next stage1. */ + node->make_decl_local (); + node->set_section (NULL); + node->set_comdat_group (NULL); + node->externally_visible = false; + node->forced_by_abi = false; + node->set_section (NULL); + + DECL_ARTIFICIAL (node->decl) = 1; + node->force_output = true; + } } /* Return length of attribute names string, -- cgit v1.1 From 1afcf5705a0becdca96111a6cb67670217c335b3 Mon Sep 17 00:00:00 2001 From: liuhongt Date: Mon, 16 Aug 2021 17:12:21 +0800 Subject: Fix ICE. gcc/ChangeLog: PR target/101930 * config/i386/i386.md (ldexp3): Force operands[1] to reg. gcc/testsuite/ChangeLog: PR target/101930 * gcc.target/i386/pr101930.c: New test. --- gcc/config/i386/i386.md | 4 +--- gcc/testsuite/gcc.target/i386/pr101930.c | 9 +++++++++ 2 files changed, 10 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/gcc.target/i386/pr101930.c (limited to 'gcc') diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index 4a8e8fe..41d8562 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -17938,9 +17938,7 @@ if (TARGET_AVX512F && TARGET_SSE_MATH) { rtx op2 = gen_reg_rtx (mode); - - if (!nonimmediate_operand (operands[1], mode)) - operands[1] = force_reg (mode, operands[1]); + operands[1] = force_reg (mode, operands[1]); emit_insn (gen_floatsi2 (op2, operands[2])); emit_insn (gen_avx512f_scalef2 (operands[0], operands[1], op2)); diff --git a/gcc/testsuite/gcc.target/i386/pr101930.c b/gcc/testsuite/gcc.target/i386/pr101930.c new file mode 100644 index 0000000..7207dd1 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr101930.c @@ -0,0 +1,9 @@ +/* { dg-do compile } */ +/* { dg-options "-mavx512f -O2 -mfpmath=sse -ffast-math" } */ +double a; +double +__attribute__((noipa)) +foo (int b) +{ + return __builtin_ldexp (a, b); +} -- cgit v1.1 From 049eda8274b7394523238b17ab12c3e2889f253e Mon Sep 17 00:00:00 2001 From: Thomas Schwinge Date: Fri, 6 Aug 2021 12:09:12 +0200 Subject: Avoid 'GTY' use for 'gcc/omp-oacc-neuter-broadcast.cc:field_map' ... and further simplify related things a bit. Fix-up/clean-up for recent commit e2a58ed6dc5293602d0d168475109caa81ad0f0d "openacc: Middle-end worker-partitioning support". gcc/ * omp-oacc-neuter-broadcast.cc (field_map): Move variable into... (execute_omp_oacc_neuter_broadcast): ... here. (install_var_field, build_receiver_ref, build_sender_ref): Take 'field_map_t *' parameter. Adjust all users. (worker_single_copy, neuter_worker_single): Take a 'record_field_map_t *' parameter. Adjust all users. --- gcc/omp-oacc-neuter-broadcast.cc | 48 ++++++++++++++++++++++------------------ 1 file changed, 26 insertions(+), 22 deletions(-) (limited to 'gcc') diff --git a/gcc/omp-oacc-neuter-broadcast.cc b/gcc/omp-oacc-neuter-broadcast.cc index f855538..9bde0ac 100644 --- a/gcc/omp-oacc-neuter-broadcast.cc +++ b/gcc/omp-oacc-neuter-broadcast.cc @@ -538,12 +538,9 @@ typedef hash_map field_map_t; typedef hash_map record_field_map_t; -static GTY(()) record_field_map_t *field_map; - static void -install_var_field (tree var, tree record_type) +install_var_field (tree var, tree record_type, field_map_t *fields) { - field_map_t *fields = *field_map->get (record_type); tree name; char tmp[20]; @@ -959,9 +956,8 @@ oacc_build_component_ref (tree obj, tree field) } static tree -build_receiver_ref (tree record_type, tree var, tree receiver_decl) +build_receiver_ref (tree var, tree receiver_decl, field_map_t *fields) { - field_map_t *fields = *field_map->get (record_type); tree x = build_simple_mem_ref (receiver_decl); tree field = *fields->get (var); TREE_THIS_NOTRAP (x) = 1; @@ -970,9 +966,8 @@ build_receiver_ref (tree record_type, tree var, tree receiver_decl) } static tree -build_sender_ref (tree record_type, tree var, tree sender_decl) +build_sender_ref (tree var, tree sender_decl, field_map_t *fields) { - field_map_t *fields = *field_map->get (record_type); tree field = *fields->get (var); return oacc_build_component_ref (sender_decl, field); } @@ -1010,7 +1005,7 @@ static void worker_single_copy (basic_block from, basic_block to, hash_set *def_escapes_block, hash_set *worker_partitioned_uses, - tree record_type) + tree record_type, record_field_map_t *record_field_map) { /* If we only have virtual defs, we'll have no record type, but we still want to emit single_copy_start and (particularly) single_copy_end to act as @@ -1147,7 +1142,7 @@ worker_single_copy (basic_block from, basic_block to, gcc_assert (TREE_CODE (var) == VAR_DECL); /* If we had no record type, we will have no fields map. */ - field_map_t **fields_p = field_map->get (record_type); + field_map_t **fields_p = record_field_map->get (record_type); field_map_t *fields = fields_p ? *fields_p : NULL; if (worker_partitioned_uses->contains (var) @@ -1158,8 +1153,7 @@ worker_single_copy (basic_block from, basic_block to, /* Receive definition from shared memory block. */ - tree receiver_ref = build_receiver_ref (record_type, var, - receiver_decl); + tree receiver_ref = build_receiver_ref (var, receiver_decl, fields); gassign *recv = gimple_build_assign (neutered_def, receiver_ref); gsi_insert_after (©out_gsi, recv, GSI_CONTINUE_LINKING); @@ -1189,7 +1183,7 @@ worker_single_copy (basic_block from, basic_block to, /* Send definition to shared memory block. */ - tree sender_ref = build_sender_ref (record_type, var, sender_decl); + tree sender_ref = build_sender_ref (var, sender_decl, fields); if (TREE_CODE (var) == SSA_NAME) { @@ -1232,7 +1226,8 @@ static void neuter_worker_single (parallel_g *par, unsigned outer_mask, bitmap worker_single, bitmap vector_single, vec *prop_set, - hash_set *partitioned_var_uses) + hash_set *partitioned_var_uses, + record_field_map_t *record_field_map) { unsigned mask = outer_mask | par->mask; @@ -1322,7 +1317,8 @@ neuter_worker_single (parallel_g *par, unsigned outer_mask, if (has_defs) worker_single_copy (block, block, &def_escapes_block, - &worker_partitioned_uses, record_type); + &worker_partitioned_uses, record_type, + record_field_map); else worker_single_simple (block, block, &def_escapes_block); } @@ -1358,10 +1354,10 @@ neuter_worker_single (parallel_g *par, unsigned outer_mask, if (par->inner) neuter_worker_single (par->inner, mask, worker_single, vector_single, - prop_set, partitioned_var_uses); + prop_set, partitioned_var_uses, record_field_map); if (par->next) neuter_worker_single (par->next, outer_mask, worker_single, vector_single, - prop_set, partitioned_var_uses); + prop_set, partitioned_var_uses, record_field_map); } static int @@ -1402,8 +1398,6 @@ execute_omp_oacc_neuter_broadcast () FOR_ALL_BB_FN (bb, cfun) bb->aux = NULL; - field_map = record_field_map_t::create_ggc (40); - vec prop_set; prop_set.create (last_basic_block_for_fn (cfun)); @@ -1421,6 +1415,8 @@ execute_omp_oacc_neuter_broadcast () find_local_vars_to_propagate (par, mask, &partitioned_var_uses, &gang_private_vars, &prop_set); + record_field_map_t record_field_map; + FOR_ALL_BB_FN (bb, cfun) { propagation_set *ws_prop = prop_set[bb->index]; @@ -1441,12 +1437,16 @@ execute_omp_oacc_neuter_broadcast () field_vec.qsort (sort_by_size_then_ssa_version_or_uid); - field_map->put (record_type, field_map_t::create_ggc (17)); + field_map_t *fields = new field_map_t; + + bool existed; + existed = record_field_map.put (record_type, fields); + gcc_checking_assert (!existed); /* Insert var fields in reverse order, so the last inserted element is the first in the structure. */ for (int i = field_vec.length () - 1; i >= 0; i--) - install_var_field (field_vec[i], record_type); + install_var_field (field_vec[i], record_type, fields); layout_type (record_type); @@ -1455,7 +1455,11 @@ execute_omp_oacc_neuter_broadcast () } neuter_worker_single (par, mask, worker_single, vector_single, &prop_set, - &partitioned_var_uses); + &partitioned_var_uses, &record_field_map); + + for (auto it : record_field_map) + delete it.second; + record_field_map.empty (); prop_set.release (); -- cgit v1.1 From 7b9d99e615212c24cecae4202d8def9aa5e71809 Mon Sep 17 00:00:00 2001 From: Thomas Schwinge Date: Wed, 11 Aug 2021 22:31:55 +0200 Subject: Clarify memory management for 'prop_set' in 'gcc/omp-oacc-neuter-broadcast.cc' Clean-up for recent commit e2a58ed6dc5293602d0d168475109caa81ad0f0d "openacc: Middle-end worker-partitioning support". gcc/ * omp-oacc-neuter-broadcast.cc (execute_omp_oacc_neuter_broadcast): Clarify memory management for 'prop_set'. --- gcc/omp-oacc-neuter-broadcast.cc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'gcc') diff --git a/gcc/omp-oacc-neuter-broadcast.cc b/gcc/omp-oacc-neuter-broadcast.cc index 9bde0ac..d308670 100644 --- a/gcc/omp-oacc-neuter-broadcast.cc +++ b/gcc/omp-oacc-neuter-broadcast.cc @@ -1398,11 +1398,8 @@ execute_omp_oacc_neuter_broadcast () FOR_ALL_BB_FN (bb, cfun) bb->aux = NULL; - vec prop_set; - prop_set.create (last_basic_block_for_fn (cfun)); - - for (int i = 0; i < last_basic_block_for_fn (cfun); i++) - prop_set.quick_push (0); + vec prop_set (vNULL); + prop_set.safe_grow_cleared (last_basic_block_for_fn (cfun), true); find_ssa_names_to_propagate (par, mask, worker_single, vector_single, &prop_set); @@ -1461,6 +1458,9 @@ execute_omp_oacc_neuter_broadcast () delete it.second; record_field_map.empty (); + /* These are supposed to have been 'delete'd by 'neuter_worker_single'. */ + for (auto it : prop_set) + gcc_checking_assert (!it); prop_set.release (); /* This doesn't seem to make a difference. */ -- cgit v1.1 From df98015fb7db2ed754a7c154669bc7777f8e1612 Mon Sep 17 00:00:00 2001 From: Thomas Schwinge Date: Fri, 6 Aug 2021 15:34:25 +0200 Subject: Plug 'par' memory leak in 'gcc/omp-oacc-neuter-broadcast.cc:execute_omp_oacc_neuter_broadcast' Fix-up for recent commit e2a58ed6dc5293602d0d168475109caa81ad0f0d "openacc: Middle-end worker-partitioning support". gcc/ * omp-oacc-neuter-broadcast.cc (execute_omp_oacc_neuter_broadcast): Plug 'par' memory leak. --- gcc/omp-oacc-neuter-broadcast.cc | 2 ++ 1 file changed, 2 insertions(+) (limited to 'gcc') diff --git a/gcc/omp-oacc-neuter-broadcast.cc b/gcc/omp-oacc-neuter-broadcast.cc index d308670..d48627a 100644 --- a/gcc/omp-oacc-neuter-broadcast.cc +++ b/gcc/omp-oacc-neuter-broadcast.cc @@ -1463,6 +1463,8 @@ execute_omp_oacc_neuter_broadcast () gcc_checking_assert (!it); prop_set.release (); + delete par; + /* This doesn't seem to make a difference. */ loops_state_clear (LOOP_CLOSED_SSA); -- cgit v1.1 From 29020d0527512ae0444ad32b1461b7f8526e7427 Mon Sep 17 00:00:00 2001 From: Eric Botcazou Date: Mon, 16 Aug 2021 12:14:12 +0200 Subject: Disable GNAT encodings by default Given the latest work in the compiler and debugger, we no longer need to use most GNAT-specific encodings in the debug info generated for an Ada program, so the attached patch disables them, except with -fgnat-encodings=all. gcc/ * dwarf2out.c (add_data_member_location_attribute): Use GNAT encodings only when -fgnat-encodings=all is specified. (add_bound_info): Likewise. (add_byte_size_attribute): Likewise. (gen_member_die): Likewise. --- gcc/dwarf2out.c | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) (limited to 'gcc') diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c index b91a9b5..4bcd331 100644 --- a/gcc/dwarf2out.c +++ b/gcc/dwarf2out.c @@ -19915,22 +19915,23 @@ add_data_member_location_attribute (dw_die_ref die, { loc_descr = field_byte_offset (decl, ctx, &offset); - /* If loc_descr is available then we know the field offset is dynamic. - However, GDB does not handle dynamic field offsets very well at the - moment. */ - if (loc_descr != NULL && gnat_encodings != DWARF_GNAT_ENCODINGS_MINIMAL) + if (!loc_descr) + ; + + /* If loc_descr is available, then we know the offset is dynamic. */ + else if (gnat_encodings == DWARF_GNAT_ENCODINGS_ALL) { loc_descr = NULL; offset = 0; } - /* Data member location evalutation starts with the base address on the + /* Data member location evaluation starts with the base address on the stack. Compute the field offset and add it to this base address. */ - else if (loc_descr != NULL) + else add_loc_descr (&loc_descr, new_loc_descr (DW_OP_plus, 0, 0)); } - if (! loc_descr) + if (!loc_descr) { /* While DW_AT_data_bit_offset has been added already in DWARF4, e.g. GDB only added support to it in November 2016. For DWARF5 @@ -21389,12 +21390,9 @@ add_bound_info (dw_die_ref subrange_die, enum dwarf_attribute bound_attr, /* FALLTHRU */ default: - /* Because of the complex interaction there can be with other GNAT - encodings, GDB isn't ready yet to handle proper DWARF description - for self-referencial subrange bounds: let GNAT encodings do the - magic in such a case. */ + /* Let GNAT encodings do the magic for self-referential bounds. */ if (is_ada () - && gnat_encodings != DWARF_GNAT_ENCODINGS_MINIMAL + && gnat_encodings == DWARF_GNAT_ENCODINGS_ALL && contains_placeholder_p (bound)) return; @@ -21566,7 +21564,7 @@ add_byte_size_attribute (dw_die_ref die, tree tree_node) /* Support for dynamically-sized objects was introduced in DWARF3. */ else if (TYPE_P (tree_node) && (dwarf_version >= 3 || !dwarf_strict) - && gnat_encodings == DWARF_GNAT_ENCODINGS_MINIMAL) + && gnat_encodings != DWARF_GNAT_ENCODINGS_ALL) { struct loc_descr_context ctx = { const_cast (tree_node), /* context_type */ @@ -25629,11 +25627,11 @@ gen_member_die (tree type, dw_die_ref context_die) splice_child_die (context_die, child); } - /* Do not generate standard DWARF for variant parts if we are generating - the corresponding GNAT encodings: DIEs generated for both would - conflict in our mappings. */ + /* Do not generate DWARF for variant parts if we are generating the + corresponding GNAT encodings: DIEs generated for the two schemes + would conflict in our mappings. */ else if (is_variant_part (member) - && gnat_encodings == DWARF_GNAT_ENCODINGS_MINIMAL) + && gnat_encodings != DWARF_GNAT_ENCODINGS_ALL) { vlr_ctx.variant_part_offset = byte_position (member); gen_variant_part (member, &vlr_ctx, context_die); -- cgit v1.1 From c517cf2e685e2903b591d63c1034ff9726cb3822 Mon Sep 17 00:00:00 2001 From: Martin Liska Date: Fri, 13 Aug 2021 17:22:35 +0200 Subject: Speed up jump table switch detection. PR tree-optimization/100393 gcc/ChangeLog: * tree-switch-conversion.c (group_cluster::dump): Use get_comparison_count. (jump_table_cluster::find_jump_tables): Pre-compute number of comparisons and then decrement it. Cache also max_ratio. (jump_table_cluster::can_be_handled): Change signature. * tree-switch-conversion.h (get_comparison_count): New. --- gcc/tree-switch-conversion.c | 42 +++++++++++++++++++++++------------------- gcc/tree-switch-conversion.h | 14 ++++++++++++-- 2 files changed, 35 insertions(+), 21 deletions(-) (limited to 'gcc') diff --git a/gcc/tree-switch-conversion.c b/gcc/tree-switch-conversion.c index 294b545..244cf4b 100644 --- a/gcc/tree-switch-conversion.c +++ b/gcc/tree-switch-conversion.c @@ -1091,7 +1091,7 @@ group_cluster::dump (FILE *f, bool details) for (unsigned i = 0; i < m_cases.length (); i++) { simple_cluster *sc = static_cast (m_cases[i]); - comparison_count += sc->m_range_p ? 2 : 1; + comparison_count += sc->get_comparison_count (); } unsigned HOST_WIDE_INT range = get_range (get_low (), get_high ()); @@ -1186,11 +1186,24 @@ jump_table_cluster::find_jump_tables (vec &clusters) min.quick_push (min_cluster_item (0, 0, 0)); + unsigned HOST_WIDE_INT max_ratio + = (optimize_insn_for_size_p () + ? param_jump_table_max_growth_ratio_for_size + : param_jump_table_max_growth_ratio_for_speed); + for (unsigned i = 1; i <= l; i++) { /* Set minimal # of clusters with i-th item to infinite. */ min.quick_push (min_cluster_item (INT_MAX, INT_MAX, INT_MAX)); + /* Pre-calculate number of comparisons for the clusters. */ + HOST_WIDE_INT comparison_count = 0; + for (unsigned k = 0; k <= i - 1; k++) + { + simple_cluster *sc = static_cast (clusters[k]); + comparison_count += sc->get_comparison_count (); + } + for (unsigned j = 0; j < i; j++) { unsigned HOST_WIDE_INT s = min[j].m_non_jt_cases; @@ -1201,10 +1214,15 @@ jump_table_cluster::find_jump_tables (vec &clusters) if ((min[j].m_count + 1 < min[i].m_count || (min[j].m_count + 1 == min[i].m_count && s < min[i].m_non_jt_cases)) - && can_be_handled (clusters, j, i - 1)) + && can_be_handled (clusters, j, i - 1, max_ratio, + comparison_count)) min[i] = min_cluster_item (min[j].m_count + 1, j, s); + + simple_cluster *sc = static_cast (clusters[j]); + comparison_count -= sc->get_comparison_count (); } + gcc_checking_assert (comparison_count == 0); gcc_checking_assert (min[i].m_count != INT_MAX); } @@ -1242,7 +1260,9 @@ jump_table_cluster::find_jump_tables (vec &clusters) bool jump_table_cluster::can_be_handled (const vec &clusters, - unsigned start, unsigned end) + unsigned start, unsigned end, + unsigned HOST_WIDE_INT max_ratio, + unsigned HOST_WIDE_INT comparison_count) { /* If the switch is relatively small such that the cost of one indirect jump on the target are higher than the cost of a @@ -1261,10 +1281,6 @@ jump_table_cluster::can_be_handled (const vec &clusters, if (start == end) return true; - unsigned HOST_WIDE_INT max_ratio - = (optimize_insn_for_size_p () - ? param_jump_table_max_growth_ratio_for_size - : param_jump_table_max_growth_ratio_for_speed); unsigned HOST_WIDE_INT range = get_range (clusters[start]->get_low (), clusters[end]->get_high ()); /* Check overflow. */ @@ -1278,18 +1294,6 @@ jump_table_cluster::can_be_handled (const vec &clusters, if (lhs < range) return false; - /* First make quick guess as each cluster - can add at maximum 2 to the comparison_count. */ - if (lhs > 2 * max_ratio * (end - start + 1)) - return false; - - unsigned HOST_WIDE_INT comparison_count = 0; - for (unsigned i = start; i <= end; i++) - { - simple_cluster *sc = static_cast (clusters[i]); - comparison_count += sc->m_range_p ? 2 : 1; - } - return lhs <= max_ratio * comparison_count; } diff --git a/gcc/tree-switch-conversion.h b/gcc/tree-switch-conversion.h index d76f19b..a375e52 100644 --- a/gcc/tree-switch-conversion.h +++ b/gcc/tree-switch-conversion.h @@ -180,6 +180,13 @@ public: return tree_int_cst_equal (get_low (), get_high ()); } + /* Return number of comparisons needed for the case. */ + unsigned + get_comparison_count () + { + return m_range_p ? 2 : 1; + } + /* Low value of the case. */ tree m_low; @@ -267,9 +274,12 @@ public: static vec find_jump_tables (vec &clusters); /* Return true when cluster starting at START and ending at END (inclusive) - can build a jump-table. */ + can build a jump-table. COMPARISON_COUNT is number of comparison + operations needed if the clusters are expanded as decision tree. + MAX_RATIO tells about the maximum code growth (in percent). */ static bool can_be_handled (const vec &clusters, unsigned start, - unsigned end); + unsigned end, unsigned HOST_WIDE_INT max_ratio, + unsigned HOST_WIDE_INT comparison_count); /* Return true if cluster starting at START and ending at END (inclusive) is profitable transformation. */ -- cgit v1.1 From e660441f94f2ca2ca1bd63c922c6a43737c2259e Mon Sep 17 00:00:00 2001 From: Tobias Burnus Date: Mon, 16 Aug 2021 14:00:13 +0200 Subject: [OpenMP] Update omp-low.c's omp_runtime_api_call [PR101931] gcc/ChangeLog: PR middle-end/101931 * omp-low.c (omp_runtime_api_call): Update for routines added in the meanwhile. --- gcc/omp-low.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'gcc') diff --git a/gcc/omp-low.c b/gcc/omp-low.c index 22ba579..bef9940 100644 --- a/gcc/omp-low.c +++ b/gcc/omp-low.c @@ -3863,6 +3863,8 @@ omp_runtime_api_call (const_tree fndecl) { /* This array has 3 sections. First omp_* calls that don't have any suffixes. */ + "omp_alloc", + "omp_free", "target_alloc", "target_associate_ptr", "target_disassociate_ptr", @@ -3873,13 +3875,17 @@ omp_runtime_api_call (const_tree fndecl) NULL, /* Now omp_* calls that are available as omp_* and omp_*_. */ "capture_affinity", + "destroy_allocator", "destroy_lock", "destroy_nest_lock", "display_affinity", + "fulfill_event", "get_active_level", "get_affinity_format", "get_cancellation", + "get_default_allocator", "get_default_device", + "get_device_num", "get_dynamic", "get_initial_device", "get_level", @@ -3895,6 +3901,7 @@ omp_runtime_api_call (const_tree fndecl) "get_partition_num_places", "get_place_num", "get_proc_bind", + "get_supported_active_levels", "get_team_num", "get_thread_limit", "get_thread_num", @@ -3908,6 +3915,7 @@ omp_runtime_api_call (const_tree fndecl) "pause_resource", "pause_resource_all", "set_affinity_format", + "set_default_allocator", "set_lock", "set_nest_lock", "test_lock", @@ -3916,7 +3924,9 @@ omp_runtime_api_call (const_tree fndecl) "unset_nest_lock", NULL, /* And finally calls available as omp_*, omp_*_ and omp_*_8_. */ + "display_env", "get_ancestor_thread_num", + "init_allocator", "get_partition_place_nums", "get_place_num_procs", "get_place_proc_ids", -- cgit v1.1 From be024a1285840bf2fc47fcbde32375468a92ce05 Mon Sep 17 00:00:00 2001 From: Eric Botcazou Date: Mon, 16 Aug 2021 15:26:22 +0200 Subject: Fix regression in debug info for Ada with DWARF 5 add_scalar_info can directly generate a reference to an existing DIE for a scalar attribute, e.g the upper bound of a VLA, but it does so only if this existing DIE has a location or is a constant: if (get_AT (decl_die, DW_AT_location) || get_AT (decl_die, DW_AT_data_member_location) || get_AT (decl_die, DW_AT_const_value)) Now, in DWARF 5, members of a structure that are bitfields no longer have a DW_AT_data_member_location but a DW_AT_data_bit_offset attribute instead, so the condition is bypassed. gcc/ * dwarf2out.c (add_scalar_info): Deal with DW_AT_data_bit_offset. --- gcc/dwarf2out.c | 1 + 1 file changed, 1 insertion(+) (limited to 'gcc') diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c index 4bcd331..ba0a6d6 100644 --- a/gcc/dwarf2out.c +++ b/gcc/dwarf2out.c @@ -21253,6 +21253,7 @@ add_scalar_info (dw_die_ref die, enum dwarf_attribute attr, tree value, { if (get_AT (decl_die, DW_AT_location) || get_AT (decl_die, DW_AT_data_member_location) + || get_AT (decl_die, DW_AT_data_bit_offset) || get_AT (decl_die, DW_AT_const_value)) { add_AT_die_ref (die, attr, decl_die); -- cgit v1.1 From 8cdcea51c0fd753e6a652c9b236e91b3a6e0911c Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Mon, 9 Aug 2021 09:06:14 +0200 Subject: gcov: Add TARGET_GCOV_TYPE_SIZE target hook If -fprofile-update=atomic is used, then the target must provide atomic operations for the counters of the type returned by get_gcov_type(). This is a 64-bit type for targets which have a 64-bit long long type. On 32-bit targets this could be an issue since they may not provide 64-bit atomic operations. Allow targets to override the default type size with the new TARGET_GCOV_TYPE_SIZE target hook. If a 32-bit gcov type size is used, then there is currently a warning in libgcov-driver.c in a dead code block due to sizeof (counter) == sizeof (gcov_unsigned_t): libgcc/libgcov-driver.c: In function 'dump_counter': libgcc/libgcov-driver.c:401:46: warning: right shift count >= width of type [-Wshift-count-overflow] 401 | dump_unsigned ((gcov_unsigned_t)(counter >> 32), dump_fn, arg); | ^~ gcc/c-family/ * c-cppbuiltin.c (c_cpp_builtins): Define __LIBGCC_GCOV_TYPE_SIZE if flag_building_libgcc is true. gcc/ * config/sparc/rtemself.h (SPARC_GCOV_TYPE_SIZE): Define. * config/sparc/sparc.c (sparc_gcov_type_size): New. (TARGET_GCOV_TYPE_SIZE): Redefine if SPARC_GCOV_TYPE_SIZE is defined. * coverage.c (get_gcov_type): Use targetm.gcov_type_size(). * doc/tm.texi (TARGET_GCOV_TYPE_SIZE): Add hook under "Misc". * doc/tm.texi.in: Regenerate. * target.def (gcov_type_size): New target hook. * targhooks.c (default_gcov_type_size): New. * targhooks.h (default_gcov_type_size): Declare. * tree-profile.c (gimple_gen_edge_profiler): Use precision of gcov_type_node. (gimple_gen_time_profiler): Likewise. libgcc/ * libgcov.h (gcov_type): Define using __LIBGCC_GCOV_TYPE_SIZE. (gcov_type_unsigned): Likewise. --- gcc/c-family/c-cppbuiltin.c | 2 ++ gcc/config/sparc/rtemself.h | 2 ++ gcc/config/sparc/sparc.c | 11 +++++++++++ gcc/coverage.c | 2 +- gcc/doc/tm.texi | 11 +++++++++++ gcc/doc/tm.texi.in | 2 ++ gcc/target.def | 12 ++++++++++++ gcc/targhooks.c | 7 +++++++ gcc/targhooks.h | 2 ++ gcc/tree-profile.c | 4 ++-- 10 files changed, 52 insertions(+), 3 deletions(-) (limited to 'gcc') diff --git a/gcc/c-family/c-cppbuiltin.c b/gcc/c-family/c-cppbuiltin.c index f79f939..3fa62bc 100644 --- a/gcc/c-family/c-cppbuiltin.c +++ b/gcc/c-family/c-cppbuiltin.c @@ -1450,6 +1450,8 @@ c_cpp_builtins (cpp_reader *pfile) /* For libgcov. */ builtin_define_with_int_value ("__LIBGCC_VTABLE_USES_DESCRIPTORS__", TARGET_VTABLE_USES_DESCRIPTORS); + builtin_define_with_int_value ("__LIBGCC_GCOV_TYPE_SIZE", + targetm.gcov_type_size()); } /* For use in assembly language. */ diff --git a/gcc/config/sparc/rtemself.h b/gcc/config/sparc/rtemself.h index fa972af..d64ce90 100644 --- a/gcc/config/sparc/rtemself.h +++ b/gcc/config/sparc/rtemself.h @@ -40,3 +40,5 @@ /* Use the default */ #undef LINK_GCC_C_SEQUENCE_SPEC + +#define SPARC_GCOV_TYPE_SIZE 32 diff --git a/gcc/config/sparc/sparc.c b/gcc/config/sparc/sparc.c index 04fc80f..06f41d7 100644 --- a/gcc/config/sparc/sparc.c +++ b/gcc/config/sparc/sparc.c @@ -944,6 +944,17 @@ char sparc_hard_reg_printed[8]; #undef TARGET_ZERO_CALL_USED_REGS #define TARGET_ZERO_CALL_USED_REGS sparc_zero_call_used_regs +#ifdef SPARC_GCOV_TYPE_SIZE +static HOST_WIDE_INT +sparc_gcov_type_size (void) +{ + return SPARC_GCOV_TYPE_SIZE; +} + +#undef TARGET_GCOV_TYPE_SIZE +#define TARGET_GCOV_TYPE_SIZE sparc_gcov_type_size +#endif + struct gcc_target targetm = TARGET_INITIALIZER; /* Return the memory reference contained in X if any, zero otherwise. */ diff --git a/gcc/coverage.c b/gcc/coverage.c index ac9a9fd..10d7f83 100644 --- a/gcc/coverage.c +++ b/gcc/coverage.c @@ -146,7 +146,7 @@ tree get_gcov_type (void) { scalar_int_mode mode - = smallest_int_mode_for_size (LONG_LONG_TYPE_SIZE > 32 ? 64 : 32); + = smallest_int_mode_for_size (targetm.gcov_type_size ()); return lang_hooks.types.type_for_mode (mode, false); } diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index a30fdcb..f68f426 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -12588,3 +12588,14 @@ Return an RTX representing @var{tagged_pointer} with its tag set to zero. Store the result in @var{target} if convenient. The default clears the top byte of the original pointer. @end deftypefn + +@deftypefn {Target Hook} HOST_WIDE_INT TARGET_GCOV_TYPE_SIZE (void) +Returns the gcov type size in bits. This type is used for example for +counters incremented by profiling and code-coverage events. The default +value is 64, if the type size of long long is greater than 32, otherwise the +default value is 32. A 64-bit type is recommended to avoid overflows of the +counters. If the @option{-fprofile-update=atomic} is used, then the +counters are incremented using atomic operations. Targets not supporting +64-bit atomic operations may override the default value and request a 32-bit +type. +@end deftypefn diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in index 611fc50..fdf16b9 100644 --- a/gcc/doc/tm.texi.in +++ b/gcc/doc/tm.texi.in @@ -8180,3 +8180,5 @@ maintainer is familiar with. @hook TARGET_MEMTAG_EXTRACT_TAG @hook TARGET_MEMTAG_UNTAGGED_POINTER + +@hook TARGET_GCOV_TYPE_SIZE diff --git a/gcc/target.def b/gcc/target.def index 7676d5e..28a34f1 100644 --- a/gcc/target.def +++ b/gcc/target.def @@ -7104,6 +7104,18 @@ DEFHOOK void, (void), NULL) +DEFHOOK +(gcov_type_size, + "Returns the gcov type size in bits. This type is used for example for\n\ +counters incremented by profiling and code-coverage events. The default\n\ +value is 64, if the type size of long long is greater than 32, otherwise the\n\ +default value is 32. A 64-bit type is recommended to avoid overflows of the\n\ +counters. If the @option{-fprofile-update=atomic} is used, then the\n\ +counters are incremented using atomic operations. Targets not supporting\n\ +64-bit atomic operations may override the default value and request a 32-bit\n\ +type.", + HOST_WIDE_INT, (void), default_gcov_type_size) + /* Close the 'struct gcc_target' definition. */ HOOK_VECTOR_END (C90_EMPTY_HACK) diff --git a/gcc/targhooks.c b/gcc/targhooks.c index eb51909..c9b5208 100644 --- a/gcc/targhooks.c +++ b/gcc/targhooks.c @@ -2654,4 +2654,11 @@ default_memtag_untagged_pointer (rtx tagged_pointer, rtx target) return untagged_base; } +/* The default implementation of TARGET_GCOV_TYPE_SIZE. */ +HOST_WIDE_INT +default_gcov_type_size (void) +{ + return TYPE_PRECISION (long_long_integer_type_node) > 32 ? 64 : 32; +} + #include "gt-targhooks.h" diff --git a/gcc/targhooks.h b/gcc/targhooks.h index f92e102..92d5199 100644 --- a/gcc/targhooks.h +++ b/gcc/targhooks.h @@ -302,4 +302,6 @@ extern rtx default_memtag_set_tag (rtx, rtx, rtx); extern rtx default_memtag_extract_tag (rtx, rtx); extern rtx default_memtag_untagged_pointer (rtx, rtx); +extern HOST_WIDE_INT default_gcov_type_size (void); + #endif /* GCC_TARGHOOKS_H */ diff --git a/gcc/tree-profile.c b/gcc/tree-profile.c index 5a74cc9..cf46912 100644 --- a/gcc/tree-profile.c +++ b/gcc/tree-profile.c @@ -250,7 +250,7 @@ gimple_gen_edge_profiler (int edgeno, edge e) { /* __atomic_fetch_add (&counter, 1, MEMMODEL_RELAXED); */ tree addr = tree_coverage_counter_addr (GCOV_COUNTER_ARCS, edgeno); - tree f = builtin_decl_explicit (LONG_LONG_TYPE_SIZE > 32 + tree f = builtin_decl_explicit (TYPE_PRECISION (gcov_type_node) > 32 ? BUILT_IN_ATOMIC_FETCH_ADD_8: BUILT_IN_ATOMIC_FETCH_ADD_4); gcall *stmt = gimple_build_call (f, 3, addr, one, @@ -525,7 +525,7 @@ gimple_gen_time_profiler (unsigned tag) tree_time_profiler_counter); gassign *assign = gimple_build_assign (ptr, NOP_EXPR, addr); gsi_insert_before (&gsi, assign, GSI_NEW_STMT); - tree f = builtin_decl_explicit (LONG_LONG_TYPE_SIZE > 32 + tree f = builtin_decl_explicit (TYPE_PRECISION (gcov_type_node) > 32 ? BUILT_IN_ATOMIC_ADD_FETCH_8: BUILT_IN_ATOMIC_ADD_FETCH_4); gcall *stmt = gimple_build_call (f, 3, ptr, one, -- cgit v1.1 From 052bdc7f2ba4b56d1ff9625d69b97c23bc858309 Mon Sep 17 00:00:00 2001 From: Jeff Law Date: Mon, 16 Aug 2021 19:03:56 -0400 Subject: Drop embeded stabs from rl78 port gcc/ * config.gcc (rl78-*-elf*): Do not include dbxelf.h. --- gcc/config.gcc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/config.gcc b/gcc/config.gcc index 93e2b32..7001a79 100644 --- a/gcc/config.gcc +++ b/gcc/config.gcc @@ -3126,7 +3126,7 @@ rs6000-ibm-aix[789].* | powerpc-ibm-aix[789].*) default_use_cxa_atexit=yes ;; rl78-*-elf*) - tm_file="dbxelf.h elfos.h newlib-stdint.h ${tm_file}" + tm_file="elfos.h newlib-stdint.h ${tm_file}" target_has_targetm_common=no c_target_objs="rl78-c.o" cxx_target_objs="rl78-c.o" -- cgit v1.1 From 9d1d9fc8b4a1d0aefd13d573d3957ca5720dd519 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Tue, 17 Aug 2021 00:16:32 +0000 Subject: Daily bump. --- gcc/ChangeLog | 117 ++++++++++++++++++++++++++++++++++++++++++++++++ gcc/DATESTAMP | 2 +- gcc/c-family/ChangeLog | 5 +++ gcc/fortran/ChangeLog | 40 +++++++++++++++++ gcc/testsuite/ChangeLog | 25 +++++++++++ 5 files changed, 188 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 545a81d..3a815ec 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,120 @@ +2021-08-16 Jeff Law + + * config.gcc (rl78-*-elf*): Do not include dbxelf.h. + +2021-08-16 Sebastian Huber + + * config/sparc/rtemself.h (SPARC_GCOV_TYPE_SIZE): Define. + * config/sparc/sparc.c (sparc_gcov_type_size): New. + (TARGET_GCOV_TYPE_SIZE): Redefine if SPARC_GCOV_TYPE_SIZE is defined. + * coverage.c (get_gcov_type): Use targetm.gcov_type_size(). + * doc/tm.texi (TARGET_GCOV_TYPE_SIZE): Add hook under "Misc". + * doc/tm.texi.in: Regenerate. + * target.def (gcov_type_size): New target hook. + * targhooks.c (default_gcov_type_size): New. + * targhooks.h (default_gcov_type_size): Declare. + * tree-profile.c (gimple_gen_edge_profiler): Use precision of + gcov_type_node. + (gimple_gen_time_profiler): Likewise. + +2021-08-16 Eric Botcazou + + * dwarf2out.c (add_scalar_info): Deal with DW_AT_data_bit_offset. + +2021-08-16 Tobias Burnus + + PR middle-end/101931 + * omp-low.c (omp_runtime_api_call): Update for routines + added in the meanwhile. + +2021-08-16 Martin Liska + + PR tree-optimization/100393 + * tree-switch-conversion.c (group_cluster::dump): Use + get_comparison_count. + (jump_table_cluster::find_jump_tables): Pre-compute number of + comparisons and then decrement it. Cache also max_ratio. + (jump_table_cluster::can_be_handled): Change signature. + * tree-switch-conversion.h (get_comparison_count): New. + +2021-08-16 Eric Botcazou + + * dwarf2out.c (add_data_member_location_attribute): Use GNAT + encodings only when -fgnat-encodings=all is specified. + (add_bound_info): Likewise. + (add_byte_size_attribute): Likewise. + (gen_member_die): Likewise. + +2021-08-16 Thomas Schwinge + + * omp-oacc-neuter-broadcast.cc + (execute_omp_oacc_neuter_broadcast): Plug 'par' memory leak. + +2021-08-16 Thomas Schwinge + + * omp-oacc-neuter-broadcast.cc + (execute_omp_oacc_neuter_broadcast): Clarify memory management for + 'prop_set'. + +2021-08-16 Thomas Schwinge + + * omp-oacc-neuter-broadcast.cc (field_map): Move variable into... + (execute_omp_oacc_neuter_broadcast): ... here. + (install_var_field, build_receiver_ref, build_sender_ref): Take + 'field_map_t *' parameter. Adjust all users. + (worker_single_copy, neuter_worker_single): Take a + 'record_field_map_t *' parameter. Adjust all users. + +2021-08-16 liuhongt + + PR target/101930 + * config/i386/i386.md (ldexp3): Force operands[1] to + reg. + +2021-08-16 Martin Liska + + PR ipa/101726 + * multiple_target.c (create_dispatcher_calls): Make default + function local only if it is a definition. + +2021-08-16 Martin Liska + + PR ipa/100600 + * ipa-icf-gimple.c (func_checker::compare_ssa_name): Do not + consider equal SSA_NAMEs when one is a param. + +2021-08-16 liuhongt + + PR target/101846 + * config/i386/i386-expand.c (ix86_expand_vec_perm_vpermt2): + Support vpermi2b for V32QI/V16QImode. + (ix86_extract_perm_from_pool_constant): New function. + (ix86_expand_vec_one_operand_perm_avx512): Support + vpermw/vpermb under TARGET_AVX512BW/TARGET_AVX512VBMI. + (expand_vec_perm_1): Adjust comments for upper. + * config/i386/i386-protos.h (ix86_extract_perm_from_pool_constant): + New declare. + * config/i386/predicates.md (permvar_truncate_operand): New predicate. + (pshufb_truncv4siv4hi_operand): Ditto. + (pshufb_truncv8hiv8qi_operand): Ditto. + * config/i386/sse.md (*avx512bw_permvar_truncv16siv16hi_1): + New pre_reload define_insn_and_split. + (*avx512f_permvar_truncv8siv8hi_1): Ditto. + (*avx512f_vpermvar_truncv8div8si_1): Ditto. + (*avx512f_permvar_truncv32hiv32qi_1): Ditto. + (*avx512f_permvar_truncv16hiv16qi_1): Ditto. + (*avx512f_permvar_truncv4div4si_1): Ditto. + (*avx512f_pshufb_truncv8hiv8qi_1): Ditto. + (*avx512f_pshufb_truncv4siv4hi_1): Ditto. + (*avx512f_pshufd_truncv2div2si_1): Ditto. + +2021-08-16 Kito Cheng + + * config/riscv/multilib-generator: Support code model option for + multi-lib. + * doc/install.texi: Add document of new option for + --with-multilib-generator. + 2021-08-15 Clément Chigot * config/rs6000/rs6000.c (xcoff_tls_exec_model_detected): New. diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index 3d4cb61..e72fc6b 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20210816 +20210817 diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index 9d0868d..a6fdf7b 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,8 @@ +2021-08-16 Sebastian Huber + + * c-cppbuiltin.c (c_cpp_builtins): Define + __LIBGCC_GCOV_TYPE_SIZE if flag_building_libgcc is true. + 2021-08-12 Jakub Jelinek * c-pragma.h (enum pragma_kind): Add PRAGMA_OMP_MASKED. diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index f4016f6..5b3744c 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,43 @@ +2021-08-16 Tobias Burnus + + * dump-parse-tree.c (show_omp_clauses): Handle 'filter' clause. + (show_omp_node, show_code_node): Handle (combined) omp masked construct. + * frontend-passes.c (gfc_code_walker): Likewise. + * gfortran.h (enum gfc_statement): Add ST_OMP_*_MASKED*. + (enum gfc_exec_op): Add EXEC_OMP_*_MASKED*. + * match.h (gfc_match_omp_masked, gfc_match_omp_masked_taskloop, + gfc_match_omp_masked_taskloop_simd, gfc_match_omp_parallel_masked, + gfc_match_omp_parallel_masked_taskloop, + gfc_match_omp_parallel_masked_taskloop_simd): New prototypes. + * openmp.c (enum omp_mask1): Add OMP_CLAUSE_FILTER. + (gfc_match_omp_clauses): Match it. + (OMP_MASKED_CLAUSES, gfc_match_omp_parallel_masked, + gfc_match_omp_parallel_masked_taskloop, + gfc_match_omp_parallel_masked_taskloop_simd, + gfc_match_omp_masked, gfc_match_omp_masked_taskloop, + gfc_match_omp_masked_taskloop_simd): New. + (resolve_omp_clauses): Resolve filter clause. + (gfc_resolve_omp_parallel_blocks, resolve_omp_do, + omp_code_to_statement, gfc_resolve_omp_directive): Handle + omp masked constructs. + * parse.c (decode_omp_directive, case_exec_markers, + gfc_ascii_statement, parse_omp_do, parse_omp_structured_block, + parse_executable): Likewise. + * resolve.c (gfc_resolve_blocks, gfc_resolve_code): Likewise. + * st.c (gfc_free_statement): Likewise. + * trans-openmp.c (gfc_trans_omp_clauses): Handle filter clause. + (GFC_OMP_SPLIT_MASKED, GFC_OMP_MASK_MASKED): New enum values. + (gfc_trans_omp_masked): New. + (gfc_split_omp_clauses): Handle combined masked directives. + (gfc_trans_omp_master_taskloop): Rename to ... + (gfc_trans_omp_master_masked_taskloop): ... this; handle also + combined masked directives. + (gfc_trans_omp_parallel_master): Rename to ... + (gfc_trans_omp_parallel_master_masked): ... this; handle + combined masked directives. + (gfc_trans_omp_directive): Handle EXEC_OMP_*_MASKED*. + * trans.c (trans_code): Likewise. + 2021-08-15 Harald Anlauf PR fortran/99351 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 92fc81a..540de57 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,28 @@ +2021-08-16 liuhongt + + PR target/101930 + * gcc.target/i386/pr101930.c: New test. + +2021-08-16 Martin Liska + + PR ipa/100600 + * gcc.dg/ipa/pr100600.c: New test. + +2021-08-16 liuhongt + + PR target/101846 + * gcc.target/i386/pr101846-2.c: New test. + * gcc.target/i386/pr101846-3.c: New test. + * gcc.target/i386/pr101846-4.c: New test. + +2021-08-16 Tobias Burnus + + * gfortran.dg/gomp/masked-1.f90: New test. + * gfortran.dg/gomp/masked-2.f90: New test. + * gfortran.dg/gomp/masked-3.f90: New test. + * gfortran.dg/gomp/masked-combined-1.f90: New test. + * gfortran.dg/gomp/masked-combined-2.f90: New test. + 2021-08-15 Harald Anlauf PR fortran/99351 -- cgit v1.1 From d56607c16deb278918cf0febba62263c39041039 Mon Sep 17 00:00:00 2001 From: liuhongt Date: Tue, 17 Aug 2021 09:32:35 +0800 Subject: Adjust testcase. This testcase is used to detect reuse of perm mask in the main loop, in epilog, vpermi2b can still be used, so add the option --param=vect-epilogues-nomask=0. gcc/testsuite/ChangeLog: * gcc.target/i386/pr82460-2.c: Adjust testcase by adding --param=vect-epilogues-nomask=0 --- gcc/testsuite/gcc.target/i386/pr82460-2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/testsuite/gcc.target/i386/pr82460-2.c b/gcc/testsuite/gcc.target/i386/pr82460-2.c index 4a45bee..8cdfb54 100644 --- a/gcc/testsuite/gcc.target/i386/pr82460-2.c +++ b/gcc/testsuite/gcc.target/i386/pr82460-2.c @@ -1,6 +1,6 @@ /* PR target/82460 */ /* { dg-do compile } */ -/* { dg-options "-O2 -ftree-vectorize -mavx512vbmi -mprefer-vector-width=none" } */ +/* { dg-options "-O2 -ftree-vectorize -mavx512vbmi -mprefer-vector-width=none --param=vect-epilogues-nomask=0" } */ /* We want to reuse the permutation mask in the loop, so use vpermt2b rather than vpermi2b. */ /* { dg-final { scan-assembler-not {\mvpermi2b\M} } } */ -- cgit v1.1 From 75a7176575c409940b66020def23508f5701f5fb Mon Sep 17 00:00:00 2001 From: Jeff Law Date: Mon, 16 Aug 2021 22:23:30 -0400 Subject: Improve SImode shifts for H8 Similar to the H8/300H patch, this improves SImode shifts for the H8/S. It's not as big a win on the H8/S since we can shift two positions at a time. But that also means that we can handle more residuals with minimal ode growth after a special shift-by-16 or shift-by-24 sequence. I think there's more to do here, but this seemed like as good a checkpoint as any. Tested without regressions. gcc/ * config/h8300/h8300.c (shift_alg_si): Avoid loops for most SImode shifts on the H8/S. (h8300_option_override): Use loops on H8/S more often when optimizing for size. (get_shift_alg): Handle new "special" cases on H8/S. Simplify accordingly. Handle various arithmetic right shifts with special sequences that we couldn't handle before. --- gcc/config/h8300/h8300.c | 69 +++++++++++++++++++++++++++++++++++++----------- 1 file changed, 53 insertions(+), 16 deletions(-) (limited to 'gcc') diff --git a/gcc/config/h8300/h8300.c b/gcc/config/h8300/h8300.c index 7959ad1..0c4e508 100644 --- a/gcc/config/h8300/h8300.c +++ b/gcc/config/h8300/h8300.c @@ -248,17 +248,17 @@ static enum shift_alg shift_alg_si[2][3][32] = { /* 16 17 18 19 20 21 22 23 */ /* 24 25 26 27 28 29 30 31 */ { INL, INL, INL, INL, INL, INL, INL, INL, - INL, INL, INL, LOP, LOP, LOP, LOP, SPC, - SPC, SPC, SPC, SPC, SPC, SPC, LOP, LOP, - SPC, SPC, LOP, LOP, SPC, SPC, SPC, SPC }, /* SHIFT_ASHIFT */ + INL, INL, INL, INL, INL, INL, INL, SPC, + SPC, SPC, SPC, SPC, SPC, SPC, SPC, SPC, + SPC, SPC, SPC, SPC, SPC, SPC, SPC, SPC }, /* SHIFT_ASHIFT */ { INL, INL, INL, INL, INL, INL, INL, INL, - INL, INL, INL, LOP, LOP, LOP, LOP, SPC, - SPC, SPC, SPC, SPC, SPC, SPC, LOP, LOP, - SPC, SPC, LOP, LOP, SPC, SPC, SPC, SPC }, /* SHIFT_LSHIFTRT */ + INL, INL, INL, INL, INL, INL, INL, SPC, + SPC, SPC, SPC, SPC, SPC, SPC, SPC, SPC, + SPC, SPC, SPC, SPC, SPC, SPC, SPC, SPC }, /* SHIFT_LSHIFTRT */ { INL, INL, INL, INL, INL, INL, INL, INL, - INL, INL, INL, LOP, LOP, LOP, LOP, LOP, - SPC, SPC, SPC, SPC, SPC, SPC, LOP, LOP, - SPC, SPC, LOP, LOP, LOP, LOP, LOP, SPC }, /* SHIFT_ASHIFTRT */ + INL, INL, INL, INL, INL, INL, INL, LOP, + SPC, SPC, SPC, SPC, SPC, SPC, SPC, SPC, + SPC, SPC, SPC, SPC, SPC, SPC, SPC, SPC }, /* SHIFT_ASHIFTRT */ } }; @@ -375,6 +375,36 @@ h8300_option_override (void) /* H8S */ shift_alg_hi[H8_S][SHIFT_ASHIFTRT][14] = SHIFT_LOOP; + + shift_alg_si[H8_S][SHIFT_ASHIFT][11] = SHIFT_LOOP; + shift_alg_si[H8_S][SHIFT_ASHIFT][12] = SHIFT_LOOP; + shift_alg_si[H8_S][SHIFT_ASHIFT][13] = SHIFT_LOOP; + shift_alg_si[H8_S][SHIFT_ASHIFT][14] = SHIFT_LOOP; + shift_alg_si[H8_S][SHIFT_ASHIFT][22] = SHIFT_LOOP; + shift_alg_si[H8_S][SHIFT_ASHIFT][23] = SHIFT_LOOP; + shift_alg_si[H8_S][SHIFT_ASHIFT][26] = SHIFT_LOOP; + shift_alg_si[H8_S][SHIFT_ASHIFT][27] = SHIFT_LOOP; + + shift_alg_si[H8_S][SHIFT_LSHIFTRT][11] = SHIFT_LOOP; + shift_alg_si[H8_S][SHIFT_LSHIFTRT][12] = SHIFT_LOOP; + shift_alg_si[H8_S][SHIFT_LSHIFTRT][13] = SHIFT_LOOP; + shift_alg_si[H8_S][SHIFT_LSHIFTRT][14] = SHIFT_LOOP; + shift_alg_si[H8_S][SHIFT_LSHIFTRT][22] = SHIFT_LOOP; + shift_alg_si[H8_S][SHIFT_LSHIFTRT][23] = SHIFT_LOOP; + shift_alg_si[H8_S][SHIFT_LSHIFTRT][26] = SHIFT_LOOP; + shift_alg_si[H8_S][SHIFT_LSHIFTRT][27] = SHIFT_LOOP; + + shift_alg_si[H8_S][SHIFT_ASHIFTRT][11] = SHIFT_LOOP; + shift_alg_si[H8_S][SHIFT_ASHIFTRT][12] = SHIFT_LOOP; + shift_alg_si[H8_S][SHIFT_ASHIFTRT][13] = SHIFT_LOOP; + shift_alg_si[H8_S][SHIFT_ASHIFTRT][14] = SHIFT_LOOP; + shift_alg_si[H8_S][SHIFT_ASHIFTRT][22] = SHIFT_LOOP; + shift_alg_si[H8_S][SHIFT_ASHIFTRT][23] = SHIFT_LOOP; + shift_alg_si[H8_S][SHIFT_ASHIFTRT][26] = SHIFT_LOOP; + shift_alg_si[H8_S][SHIFT_ASHIFTRT][27] = SHIFT_LOOP; + shift_alg_si[H8_S][SHIFT_ASHIFTRT][28] = SHIFT_LOOP; + shift_alg_si[H8_S][SHIFT_ASHIFTRT][29] = SHIFT_LOOP; + shift_alg_si[H8_S][SHIFT_ASHIFTRT][30] = SHIFT_LOOP; } /* Work out a value for MOVE_RATIO. */ @@ -3814,8 +3844,7 @@ get_shift_alg (enum shift_type shift_type, enum shift_mode shift_mode, gcc_unreachable (); } } - else if ((TARGET_H8300H && count >= 16 && count <= 23) - || (TARGET_H8300S && count >= 16 && count <= 21)) + else if (count >= 16 && count <= 23) { info->remainder = count - 16; @@ -3834,8 +3863,7 @@ get_shift_alg (enum shift_type shift_type, enum shift_mode shift_mode, goto end; } } - else if ((TARGET_H8300H && count >= 24 || count <= 27) - || (TARGET_H8300S && count >= 24 && count <= 25)) + else if (count >= 24 && count <= 27) { info->remainder = count - 24; @@ -3874,7 +3902,10 @@ get_shift_alg (enum shift_type shift_type, enum shift_mode shift_mode, info->special = "sub.w\t%f0,%f0\n\trotl.l\t#2,%S0\n\trotl.l\t#2,%S0\n\textu.l\t%S0"; goto end; case SHIFT_ASHIFTRT: - gcc_unreachable (); + info->remainder = count - 24; + info->special = "mov.w\t%e0,%f0\n\tmov.b\t%t0,%s0\n\texts.w\t%f0\n\texts.l\t%S0"; + info->cc_special = OLD_CC_SET_ZNV; + goto end; } } else if (count == 29) @@ -3900,7 +3931,10 @@ get_shift_alg (enum shift_type shift_type, enum shift_mode shift_mode, } goto end; case SHIFT_ASHIFTRT: - gcc_unreachable (); + info->remainder = count - 24; + info->special = "mov.w\t%e0,%f0\n\tmov.b\t%t0,%s0\n\texts.w\t%f0\n\texts.l\t%S0"; + info->cc_special = OLD_CC_SET_ZNV; + goto end; } } else if (count == 30) @@ -3920,7 +3954,10 @@ get_shift_alg (enum shift_type shift_type, enum shift_mode shift_mode, info->special = "sub.w\t%f0,%f0\n\trotl.l\t#2,%S0\n\textu.l\t%S0"; goto end; case SHIFT_ASHIFTRT: - gcc_unreachable (); + info->remainder = count - 24; + info->special = "mov.w\t%e0,%f0\n\tmov.b\t%t0,%s0\n\texts.w\t%f0\n\texts.l\t%S0"; + info->cc_special = OLD_CC_SET_ZNV; + goto end; } } else if (count == 31) -- cgit v1.1 From 0215b3559e55f39f38e10984a804c53907f7491c Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Mon, 16 Aug 2021 15:17:08 +0200 Subject: tree-optimization/101925 - fix VN with reverse storage order This fixes value-numbering breaking reverse storage order accesses due to a missed check. It adds a new overload for reverse_storage_order_for_component_p and sets reversed on the VN IL ops for component and array accesses accordingly. It also compares the reversed reference ops flag on reference lookup. 2021-08-16 Richard Biener PR tree-optimization/101925 * tree-ssa-sccvn.c (copy_reference_ops_from_ref): Set reverse on COMPONENT_REF and ARRAY_REF according to what reverse_storage_order_for_component_p does. (vn_reference_eq): Compare reversed on reference ops. (reverse_storage_order_for_component_p): New overload. (vn_reference_lookup_3): Check reverse_storage_order_for_component_p on the reference looked up. * gcc.dg/sso-16.c: New testcase. --- gcc/testsuite/gcc.dg/sso-16.c | 100 ++++++++++++++++++++++++++++++++++++++++++ gcc/tree-ssa-sccvn.c | 33 +++++++++++++- 2 files changed, 132 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/gcc.dg/sso-16.c (limited to 'gcc') diff --git a/gcc/testsuite/gcc.dg/sso-16.c b/gcc/testsuite/gcc.dg/sso-16.c new file mode 100644 index 0000000..7bf8938 --- /dev/null +++ b/gcc/testsuite/gcc.dg/sso-16.c @@ -0,0 +1,100 @@ +/* { dg-do run } */ +/* { dg-require-effective-target int32plus } */ +/* { dg-options "-O3" } */ + +typedef __INT32_TYPE__ int32_t; + +#define BIG_ENDIAN __attribute__((scalar_storage_order("big-endian"))) + +/* host order version (little endian)*/ +struct _ip6_addr { + union { + char addr8[16]; + int32_t addr32[4]; + } u; +}; + +typedef struct _ip6_addr t_ip6_addr; + +struct _net_addr { + char is_v4; + union { + int32_t addr; + t_ip6_addr addr6; + } u; +}; + +typedef struct _net_addr t_net_addr; + +/* big endian version */ +struct _be_ip6_addr { + union { + char addr8[16]; + } BIG_ENDIAN u; +} BIG_ENDIAN; + +typedef struct _be_ip6_addr t_be_ip6_addr; + +struct _be_net_addr { + char is_v4; + union { + t_be_ip6_addr addr6; + int32_t addr; + } BIG_ENDIAN u; +} BIG_ENDIAN; + +typedef struct _be_net_addr t_be_net_addr; + +/* convert */ +t_be_ip6_addr be_ip6_addr(const t_ip6_addr ip6) +{ + t_be_ip6_addr rc = { + .u.addr8[0] = ip6.u.addr8[0], + .u.addr8[1] = ip6.u.addr8[1], + .u.addr8[2] = ip6.u.addr8[2], + .u.addr8[3] = ip6.u.addr8[3], + .u.addr8[4] = ip6.u.addr8[4], + .u.addr8[5] = ip6.u.addr8[5], + .u.addr8[6] = ip6.u.addr8[6], + .u.addr8[7] = ip6.u.addr8[7], + .u.addr8[8] = ip6.u.addr8[8], + .u.addr8[9] = ip6.u.addr8[9], + .u.addr8[10] = ip6.u.addr8[10], + .u.addr8[11] = ip6.u.addr8[11], + .u.addr8[12] = ip6.u.addr8[12], + .u.addr8[13] = ip6.u.addr8[13], + .u.addr8[14] = ip6.u.addr8[14], + .u.addr8[15] = ip6.u.addr8[15], + }; + return rc; +} + +t_be_net_addr __attribute__((noipa)) be_net_addr(const t_net_addr ip) +{ + t_be_net_addr rc = {.is_v4 = ip.is_v4 }; + if (ip.is_v4) { + rc.u.addr = ip.u.addr; + } else { + rc.u.addr6 = be_ip6_addr(ip.u.addr6); + } + return rc; +} + +int main(void) +{ + t_be_net_addr out = { }; + + t_net_addr in = { + .is_v4 = 0, + .u.addr6.u.addr8 = + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } + }; + + out = be_net_addr(in); + + // actually first 4 bytes are swapped + if (in.u.addr6.u.addr8[0] != out.u.addr6.u.addr8[0]) + __builtin_abort(); + + return 0; +} diff --git a/gcc/tree-ssa-sccvn.c b/gcc/tree-ssa-sccvn.c index 01fffcd..82bd10b 100644 --- a/gcc/tree-ssa-sccvn.c +++ b/gcc/tree-ssa-sccvn.c @@ -797,6 +797,7 @@ vn_reference_eq (const_vn_reference_t const vr1, const_vn_reference_t const vr2) vn_reference_op_t vro1, vro2; vn_reference_op_s tem1, tem2; bool deref1 = false, deref2 = false; + bool reverse1 = false, reverse2 = false; for (; vr1->operands.iterate (i, &vro1); i++) { if (vro1->opcode == MEM_REF) @@ -804,6 +805,7 @@ vn_reference_eq (const_vn_reference_t const vr1, const_vn_reference_t const vr2) /* Do not look through a storage order barrier. */ else if (vro1->opcode == VIEW_CONVERT_EXPR && vro1->reverse) return false; + reverse1 |= vro1->reverse; if (known_eq (vro1->off, -1)) break; off1 += vro1->off; @@ -815,11 +817,12 @@ vn_reference_eq (const_vn_reference_t const vr1, const_vn_reference_t const vr2) /* Do not look through a storage order barrier. */ else if (vro2->opcode == VIEW_CONVERT_EXPR && vro2->reverse) return false; + reverse2 |= vro2->reverse; if (known_eq (vro2->off, -1)) break; off2 += vro2->off; } - if (maybe_ne (off1, off2)) + if (maybe_ne (off1, off2) || reverse1 != reverse2) return false; if (deref1 && vro1->opcode == ADDR_EXPR) { @@ -916,6 +919,9 @@ copy_reference_ops_from_ref (tree ref, vec *result) temp.type = NULL_TREE; temp.op0 = TREE_OPERAND (ref, 1); temp.op1 = TREE_OPERAND (ref, 2); + temp.reverse = (AGGREGATE_TYPE_P (TREE_TYPE (TREE_OPERAND (ref, 0))) + && TYPE_REVERSE_STORAGE_ORDER + (TREE_TYPE (TREE_OPERAND (ref, 0)))); { tree this_offset = component_ref_field_offset (ref); if (this_offset @@ -962,6 +968,9 @@ copy_reference_ops_from_ref (tree ref, vec *result) * vn_ref_op_align_unit (&temp)); off.to_shwi (&temp.off); } + temp.reverse = (AGGREGATE_TYPE_P (TREE_TYPE (TREE_OPERAND (ref, 0))) + && TYPE_REVERSE_STORAGE_ORDER + (TREE_TYPE (TREE_OPERAND (ref, 0)))); } break; case VAR_DECL: @@ -1583,6 +1592,26 @@ contains_storage_order_barrier_p (vec ops) return false; } +/* Return true if OPS represent an access with reverse storage order. */ + +static bool +reverse_storage_order_for_component_p (vec ops) +{ + unsigned i = 0; + if (ops[i].opcode == REALPART_EXPR || ops[i].opcode == IMAGPART_EXPR) + ++i; + switch (ops[i].opcode) + { + case ARRAY_REF: + case COMPONENT_REF: + case BIT_FIELD_REF: + case MEM_REF: + return ops[i].reverse; + default: + return false; + } +} + /* Transform any SSA_NAME's in a vector of vn_reference_op_s structures into their value numbers. This is done in-place, and the vector passed in is returned. *VALUEIZED_ANYTHING will specify @@ -2899,6 +2928,7 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *data_, routines to extract the assigned bits. */ else if (known_eq (ref->size, maxsize) && is_gimple_reg_type (vr->type) + && !reverse_storage_order_for_component_p (vr->operands) && !contains_storage_order_barrier_p (vr->operands) && gimple_assign_single_p (def_stmt) && CHAR_BIT == 8 @@ -3050,6 +3080,7 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *data_, to access pieces from or we can combine to a larger entity. */ else if (known_eq (ref->size, maxsize) && is_gimple_reg_type (vr->type) + && !reverse_storage_order_for_component_p (vr->operands) && !contains_storage_order_barrier_p (vr->operands) && gimple_assign_single_p (def_stmt) && TREE_CODE (gimple_assign_rhs1 (def_stmt)) == SSA_NAME) -- cgit v1.1 From d56599979211266b2f7b7535311205dd758353ac Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Tue, 17 Aug 2021 09:25:56 +0200 Subject: c++: Add C++20 #__VA_OPT__ support The following patch implements C++20 # __VA_OPT__ (...) support. Testcases cover what I came up with myself and what LLVM has for #__VA_OPT__ in its testsuite and the string literals are identical between the two compilers on the va-opt-5.c testcase. 2021-08-17 Jakub Jelinek libcpp/ * macro.c (vaopt_state): Add m_stringify member. (vaopt_state::vaopt_state): Initialize it. (vaopt_state::update): Overwrite it. (vaopt_state::stringify): New method. (stringify_arg): Replace arg argument with first, count arguments and add va_opt argument. Use first instead of arg->first and count instead of arg->count, for va_opt add paste_tokens handling. (paste_tokens): Fix up len calculation. Don't spell rhs twice, instead use %.*s to supply lhs and rhs spelling lengths. Don't call _cpp_backup_tokens here. (paste_all_tokens): Call it here instead. (replace_args): Adjust stringify_arg caller. For vaopt_state::END if stringify is true handle __VA_OPT__ stringification. (create_iso_definition): Handle # __VA_OPT__ similarly to # macro_arg. gcc/testsuite/ * c-c++-common/cpp/va-opt-5.c: New test. * c-c++-common/cpp/va-opt-6.c: New test. --- gcc/testsuite/c-c++-common/cpp/va-opt-5.c | 67 +++++++++++++++++++++++++++++++ gcc/testsuite/c-c++-common/cpp/va-opt-6.c | 17 ++++++++ 2 files changed, 84 insertions(+) create mode 100644 gcc/testsuite/c-c++-common/cpp/va-opt-5.c create mode 100644 gcc/testsuite/c-c++-common/cpp/va-opt-6.c (limited to 'gcc') diff --git a/gcc/testsuite/c-c++-common/cpp/va-opt-5.c b/gcc/testsuite/c-c++-common/cpp/va-opt-5.c new file mode 100644 index 0000000..b687ced --- /dev/null +++ b/gcc/testsuite/c-c++-common/cpp/va-opt-5.c @@ -0,0 +1,67 @@ +/* { dg-do run } */ +/* { dg-options "-std=gnu99" { target c } } */ +/* { dg-options "-std=c++20" { target c++ } } */ + +#define lparen ( +#define a0 fooa0 +#define a1 fooa1 a0 +#define a2 fooa2 a1 +#define a3 fooa3 a2 +#define a() b lparen ) +#define b() c lparen ) +#define c() d lparen ) +#define g h +#define i(j) j +#define f(...) #__VA_OPT__(g i(0)) +#define k(x,...) # __VA_OPT__(x) #x #__VA_OPT__(__VA_ARGS__) +#define l(x,...) #__VA_OPT__(a1 x) +#define m(x,...) "a()" #__VA_OPT__(a3 __VA_ARGS__ x ## __VA_ARGS__ ## x ## c a3) "a()" +#define n(x,...) = #__VA_OPT__(a3 __VA_ARGS__ x ## __VA_ARGS__ ## x ## c a3) #x #__VA_OPT__(a0 __VA_ARGS__ x ## __VA_ARGS__ ## x ## c a0) ; +#define o(x, ...) #__VA_OPT__(x##x x##x) +#define p(x, ...) #__VA_OPT__(_Pragma ("foobar")) +#define q(...) #__VA_OPT__(/* foo */x/* bar */) +const char *v1 = f(); +const char *v2 = f(123); +const char *v3 = k(1); +const char *v4 = k(1, 2, 3 ); +const char *v5 = l(a()); +const char *v6 = l(a1 a(), 1); +const char *v7 = m(); +const char *v8 = m(,); +const char *v9 = m(,a3); +const char *v10 = m(a3,a(),a0); +const char *v11 n() +const char *v12 n(,) +const char *v13 n(,a0) +const char *v14 n(a0, a(),a0) +const char *v15 = o(, 0); +const char *v16 = p(0); +const char *v17 = p(0, 1); +const char *v18 = q(); +const char *v19 = q(1); + +int +main () +{ + if (__builtin_strcmp (v1, "") + || __builtin_strcmp (v2, "g i(0)") + || __builtin_strcmp (v3, "1") + || __builtin_strcmp (v4, "112, 3") + || __builtin_strcmp (v5, "") + || __builtin_strcmp (v6, "a1 fooa1 fooa0 b ( )") + || __builtin_strcmp (v7, "a()a()") + || __builtin_strcmp (v8, "a()a()") + || __builtin_strcmp (v9, "a()a3 fooa3 fooa2 fooa1 fooa0 a3c a3a()") + || __builtin_strcmp (v10, "a()a3 b ( ),fooa0 a3a(),a0a3c a3a()") + || __builtin_strcmp (v11, "") + || __builtin_strcmp (v12, "") + || __builtin_strcmp (v13, "a3 fooa0 a0c a3a0 fooa0 a0c a0") + || __builtin_strcmp (v14, "a3 b ( ),fooa0 a0a(),a0a0c a3a0a0 b ( ),fooa0 a0a(),a0a0c a0") + || __builtin_strcmp (v15, "") + || __builtin_strcmp (v16, "") + || __builtin_strcmp (v17, "_Pragma (\"foobar\")") + || __builtin_strcmp (v18, "") + || __builtin_strcmp (v19, "x")) + __builtin_abort (); + return 0; +} diff --git a/gcc/testsuite/c-c++-common/cpp/va-opt-6.c b/gcc/testsuite/c-c++-common/cpp/va-opt-6.c new file mode 100644 index 0000000..8a7761b --- /dev/null +++ b/gcc/testsuite/c-c++-common/cpp/va-opt-6.c @@ -0,0 +1,17 @@ +/* { dg-do preprocess } */ +/* { dg-options "-std=gnu99" { target c } } */ +/* { dg-options "-std=c++20" { target c++ } } */ + +#define a "" +#define b(...) a ## #__VA_OPT__(1) /* { dg-error "pasting \"a\" and \"\"\"\" does not give a valid preprocessing token" } */ +#define c(...) a ## #__VA_OPT__(1) /* { dg-error "pasting \"a\" and \"\"1\"\" does not give a valid preprocessing token" } */ +#define d(...) #__VA_OPT__(1) ## ! +#define e(...) #__VA_OPT__(1) ## ! +#define f(...) #__VA_OPT__(. ## !) +#define g(...) #__VA_OPT__(. ## !) +b() +c(1) +d( ) /* { dg-error "pasting \"\"\"\" and \"!\" does not give a valid preprocessing token" } */ +e( 1 ) /* { dg-error "pasting \"\"1\"\" and \"!\" does not give a valid preprocessing token" } */ +f() +g(0) /* { dg-error "pasting \".\" and \"!\" does not give a valid preprocessing token" } */ -- cgit v1.1 From e45483c7c4badc4bf2d6ced22360ce1ab172967f Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Tue, 17 Aug 2021 09:30:09 +0200 Subject: openmp: Implement OpenMP 5.1 scope construct This patch implements the OpenMP 5.1 scope construct, which is similar to worksharing constructs in many regards, but isn't one of them. The body of the construct is encountered by all threads though, it can be nested in itself or intermixed with taskgroup and worksharing etc. constructs can appear inside of it (but it can't be nested in worksharing etc. constructs). The main purpose of the construct is to allow reductions (normal and task ones) without the need to close the parallel and reopen another one. If it doesn't have task reductions, it can be implemented without any new library support, with nowait it just does the privatizations at the start if any and reductions before the end of the body, with without nowait emits a normal GOMP_barrier{,_cancel} at the end too. For task reductions, we need to ensure only one thread initializes the task reduction library data structures and other threads copy from that, so a new GOMP_scope_start routine is added to the library for that. It acts as if the start of the scope construct is a nowait worksharing construct (that is ok, it can't be nested in other worksharing constructs and all threads need to encounter the start in the same order) which does the task reduction initialization, but as the body can have other scope constructs and/or worksharing constructs, that is all where we use this dummy worksharing construct. With task reductions, the construct must not have nowait and ends with a GOMP_barrier{,_cancel}, followed by task reductions followed by GOMP_workshare_task_reduction_unregister. Only C/C++ FE support is done. 2021-08-17 Jakub Jelinek gcc/ * tree.def (OMP_SCOPE): New tree code. * tree.h (OMP_SCOPE_BODY, OMP_SCOPE_CLAUSES): Define. * tree-nested.c (convert_nonlocal_reference_stmt, convert_local_reference_stmt, convert_gimple_call): Handle GIMPLE_OMP_SCOPE. * tree-pretty-print.c (dump_generic_node): Handle OMP_SCOPE. * gimple.def (GIMPLE_OMP_SCOPE): New gimple code. * gimple.c (gimple_build_omp_scope): New function. (gimple_copy): Handle GIMPLE_OMP_SCOPE. * gimple.h (gimple_build_omp_scope): Declare. (gimple_has_substatements): Handle GIMPLE_OMP_SCOPE. (gimple_omp_scope_clauses, gimple_omp_scope_clauses_ptr, gimple_omp_scope_set_clauses): New inline functions. (CASE_GIMPLE_OMP): Add GIMPLE_OMP_SCOPE. * gimple-pretty-print.c (dump_gimple_omp_scope): New function. (pp_gimple_stmt_1): Handle GIMPLE_OMP_SCOPE. * gimple-walk.c (walk_gimple_stmt): Likewise. * gimple-low.c (lower_stmt): Likewise. * gimplify.c (is_gimple_stmt): Handle OMP_MASTER. (gimplify_scan_omp_clauses): For task reductions, handle OMP_SCOPE like ORT_WORKSHARE constructs. Adjust diagnostics for % allowing task reductions. Reject inscan reductions on scope. (omp_find_stores_stmt): Handle GIMPLE_OMP_SCOPE. (gimplify_omp_workshare, gimplify_expr): Handle OMP_SCOPE. * tree-inline.c (remap_gimple_stmt): Handle GIMPLE_OMP_SCOPE. (estimate_num_insns): Likewise. * omp-low.c (build_outer_var_ref): Look through GIMPLE_OMP_SCOPE contexts if var isn't privatized there. (check_omp_nesting_restrictions): Handle GIMPLE_OMP_SCOPE. (scan_omp_1_stmt): Likewise. (maybe_add_implicit_barrier_cancel): Look through outer scope constructs. (lower_omp_scope): New function. (lower_omp_task_reductions): Handle OMP_SCOPE. (lower_omp_1): Handle GIMPLE_OMP_SCOPE. (diagnose_sb_1, diagnose_sb_2): Likewise. * omp-expand.c (expand_omp_single): Support also GIMPLE_OMP_SCOPE. (expand_omp): Handle GIMPLE_OMP_SCOPE. (omp_make_gimple_edges): Likewise. * omp-builtins.def (BUILT_IN_GOMP_SCOPE_START): New built-in. gcc/c-family/ * c-pragma.h (enum pragma_kind): Add PRAGMA_OMP_SCOPE. * c-pragma.c (omp_pragmas): Add scope construct. * c-omp.c (omp_directives): Uncomment scope directive entry. gcc/c/ * c-parser.c (OMP_SCOPE_CLAUSE_MASK): Define. (c_parser_omp_scope): New function. (c_parser_omp_construct): Handle PRAGMA_OMP_SCOPE. gcc/cp/ * parser.c (OMP_SCOPE_CLAUSE_MASK): Define. (cp_parser_omp_scope): New function. (cp_parser_omp_construct, cp_parser_pragma): Handle PRAGMA_OMP_SCOPE. * pt.c (tsubst_expr): Handle OMP_SCOPE. gcc/testsuite/ * c-c++-common/gomp/nesting-2.c (foo): Add scope and masked construct tests. * c-c++-common/gomp/scan-1.c (f3): Add scope construct test.. * c-c++-common/gomp/cancel-1.c (f2): Add scope and masked construct tests. * c-c++-common/gomp/reduction-task-2.c (bar): Add scope construct test. Adjust diagnostics for the addition of scope. * c-c++-common/gomp/loop-1.c (f5): Add master, masked and scope construct tests. * c-c++-common/gomp/clause-dups-1.c (f1): Add scope construct test. * gcc.dg/gomp/nesting-1.c (f1, f2, f3): Add scope construct tests. * c-c++-common/gomp/scope-1.c: New test. * c-c++-common/gomp/scope-2.c: New test. * g++.dg/gomp/attrs-1.C (bar): Add scope construct tests. * g++.dg/gomp/attrs-2.C (bar): Likewise. * gfortran.dg/gomp/reduction4.f90: Adjust expected diagnostics. * gfortran.dg/gomp/reduction7.f90: Likewise. libgomp/ * Makefile.am (libgomp_la_SOURCES): Add scope.c * Makefile.in: Regenerated. * libgomp_g.h (GOMP_scope_start): Declare. * libgomp.map: Add GOMP_scope_start@@GOMP_5.1. * scope.c: New file. * testsuite/libgomp.c-c++-common/scope-1.c: New test. * testsuite/libgomp.c-c++-common/task-reduction-16.c: New test. --- gcc/c-family/c-omp.c | 4 +- gcc/c-family/c-pragma.c | 1 + gcc/c-family/c-pragma.h | 1 + gcc/c/c-parser.c | 30 ++++ gcc/cp/parser.c | 28 ++++ gcc/cp/pt.c | 1 + gcc/gimple-low.c | 1 + gcc/gimple-pretty-print.c | 33 ++++ gcc/gimple-walk.c | 1 + gcc/gimple.c | 23 +++ gcc/gimple.def | 5 + gcc/gimple.h | 41 ++++- gcc/gimplify.c | 24 ++- gcc/omp-builtins.def | 2 + gcc/omp-expand.c | 7 +- gcc/omp-low.c | 181 +++++++++++++++++++-- gcc/testsuite/c-c++-common/gomp/cancel-1.c | 22 +++ gcc/testsuite/c-c++-common/gomp/clause-dups-1.c | 2 + gcc/testsuite/c-c++-common/gomp/loop-1.c | 18 ++ gcc/testsuite/c-c++-common/gomp/nesting-2.c | 12 ++ gcc/testsuite/c-c++-common/gomp/reduction-task-2.c | 8 +- gcc/testsuite/c-c++-common/gomp/scan-1.c | 2 + gcc/testsuite/c-c++-common/gomp/scope-1.c | 39 +++++ gcc/testsuite/c-c++-common/gomp/scope-2.c | 41 +++++ gcc/testsuite/g++.dg/gomp/attrs-1.C | 4 + gcc/testsuite/g++.dg/gomp/attrs-2.C | 4 + gcc/testsuite/gcc.dg/gomp/nesting-1.c | 60 +++++++ gcc/testsuite/gfortran.dg/gomp/reduction4.f90 | 2 +- gcc/testsuite/gfortran.dg/gomp/reduction7.f90 | 2 +- gcc/tree-inline.c | 7 + gcc/tree-nested.c | 17 ++ gcc/tree-pretty-print.c | 5 + gcc/tree.def | 5 + gcc/tree.h | 3 + 34 files changed, 608 insertions(+), 28 deletions(-) create mode 100644 gcc/testsuite/c-c++-common/gomp/scope-1.c create mode 100644 gcc/testsuite/c-c++-common/gomp/scope-2.c (limited to 'gcc') diff --git a/gcc/c-family/c-omp.c b/gcc/c-family/c-omp.c index 54eba61..de49d26 100644 --- a/gcc/c-family/c-omp.c +++ b/gcc/c-family/c-omp.c @@ -3018,8 +3018,8 @@ static const struct c_omp_directive omp_directives[] = { C_OMP_DIR_INFORMATIONAL, false }, { "scan", nullptr, nullptr, PRAGMA_OMP_SCAN, C_OMP_DIR_CONSTRUCT, true }, - /* { "scope", nullptr, nullptr, PRAGMA_OMP_SCOPE, - C_OMP_DIR_CONSTRUCT, false }, */ + { "scope", nullptr, nullptr, PRAGMA_OMP_SCOPE, + C_OMP_DIR_CONSTRUCT, false }, { "section", nullptr, nullptr, PRAGMA_OMP_SECTION, C_OMP_DIR_CONSTRUCT, false }, { "sections", nullptr, nullptr, PRAGMA_OMP_SECTIONS, diff --git a/gcc/c-family/c-pragma.c b/gcc/c-family/c-pragma.c index b466a27..5f0096f 100644 --- a/gcc/c-family/c-pragma.c +++ b/gcc/c-family/c-pragma.c @@ -1329,6 +1329,7 @@ static const struct omp_pragma_def omp_pragmas[] = { { "end", PRAGMA_OMP_END_DECLARE_TARGET }, { "flush", PRAGMA_OMP_FLUSH }, { "requires", PRAGMA_OMP_REQUIRES }, + { "scope", PRAGMA_OMP_SCOPE }, { "section", PRAGMA_OMP_SECTION }, { "sections", PRAGMA_OMP_SECTIONS }, { "single", PRAGMA_OMP_SINGLE }, diff --git a/gcc/c-family/c-pragma.h b/gcc/c-family/c-pragma.h index b7ec6e5..2b9e5ea 100644 --- a/gcc/c-family/c-pragma.h +++ b/gcc/c-family/c-pragma.h @@ -63,6 +63,7 @@ enum pragma_kind { PRAGMA_OMP_PARALLEL, PRAGMA_OMP_REQUIRES, PRAGMA_OMP_SCAN, + PRAGMA_OMP_SCOPE, PRAGMA_OMP_SECTION, PRAGMA_OMP_SECTIONS, PRAGMA_OMP_SIMD, diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index ca6e56a..33aeb09 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -19488,6 +19488,33 @@ c_parser_omp_single (location_t loc, c_parser *parser, bool *if_p) return add_stmt (stmt); } +/* OpenMP 5.1: + # pragma omp scope scope-clause[optseq] new-line + structured-block + + LOC is the location of the #pragma. +*/ + +#define OMP_SCOPE_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) + +static tree +c_parser_omp_scope (location_t loc, c_parser *parser, bool *if_p) +{ + tree stmt = make_node (OMP_SCOPE); + SET_EXPR_LOCATION (stmt, loc); + TREE_TYPE (stmt) = void_type_node; + + OMP_SCOPE_CLAUSES (stmt) + = c_parser_omp_all_clauses (parser, OMP_SCOPE_CLAUSE_MASK, + "#pragma omp scope"); + OMP_SCOPE_BODY (stmt) = c_parser_omp_structured_block (parser, if_p); + + return add_stmt (stmt); +} + /* OpenMP 3.0: # pragma omp task task-clause[optseq] new-line @@ -21958,6 +21985,9 @@ c_parser_omp_construct (c_parser *parser, bool *if_p) strcpy (p_name, "#pragma omp"); stmt = c_parser_omp_parallel (loc, parser, p_name, mask, NULL, if_p); break; + case PRAGMA_OMP_SCOPE: + stmt = c_parser_omp_scope (loc, parser, if_p); + break; case PRAGMA_OMP_SECTIONS: strcpy (p_name, "#pragma omp"); stmt = c_parser_omp_sections (loc, parser, p_name, mask, NULL); diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index edb69ae..c31965a 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -42492,6 +42492,30 @@ cp_parser_omp_single (cp_parser *parser, cp_token *pragma_tok, bool *if_p) return add_stmt (stmt); } +/* OpenMP 5.1: + # pragma omp scope scope-clause[optseq] new-line + structured-block */ + +#define OMP_SCOPE_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) + +static tree +cp_parser_omp_scope (cp_parser *parser, cp_token *pragma_tok, bool *if_p) +{ + tree stmt = make_node (OMP_SCOPE); + TREE_TYPE (stmt) = void_type_node; + SET_EXPR_LOCATION (stmt, pragma_tok->location); + + OMP_SCOPE_CLAUSES (stmt) + = cp_parser_omp_all_clauses (parser, OMP_SCOPE_CLAUSE_MASK, + "#pragma omp scope", pragma_tok); + OMP_SCOPE_BODY (stmt) = cp_parser_omp_structured_block (parser, if_p); + + return add_stmt (stmt); +} + /* OpenMP 3.0: # pragma omp task task-clause[optseq] new-line structured-block */ @@ -45971,6 +45995,9 @@ cp_parser_omp_construct (cp_parser *parser, cp_token *pragma_tok, bool *if_p) stmt = cp_parser_omp_parallel (parser, pragma_tok, p_name, mask, NULL, if_p); break; + case PRAGMA_OMP_SCOPE: + stmt = cp_parser_omp_scope (parser, pragma_tok, if_p); + break; case PRAGMA_OMP_SECTIONS: strcpy (p_name, "#pragma omp"); stmt = cp_parser_omp_sections (parser, pragma_tok, p_name, mask, NULL); @@ -46604,6 +46631,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) case PRAGMA_OMP_MASKED: case PRAGMA_OMP_MASTER: case PRAGMA_OMP_PARALLEL: + case PRAGMA_OMP_SCOPE: case PRAGMA_OMP_SECTIONS: case PRAGMA_OMP_SIMD: case PRAGMA_OMP_SINGLE: diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 0870ccd..484723b 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -18791,6 +18791,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, omp_parallel_combined_clauses = NULL; /* FALLTHRU */ case OMP_SINGLE: + case OMP_SCOPE: case OMP_TEAMS: case OMP_CRITICAL: case OMP_TASKGROUP: diff --git a/gcc/gimple-low.c b/gcc/gimple-low.c index 832d5c3..7e39c22 100644 --- a/gcc/gimple-low.c +++ b/gcc/gimple-low.c @@ -329,6 +329,7 @@ lower_stmt (gimple_stmt_iterator *gsi, struct lower_data *data) case GIMPLE_LABEL: case GIMPLE_EH_MUST_NOT_THROW: case GIMPLE_OMP_FOR: + case GIMPLE_OMP_SCOPE: case GIMPLE_OMP_SECTIONS: case GIMPLE_OMP_SECTIONS_SWITCH: case GIMPLE_OMP_SECTION: diff --git a/gcc/gimple-pretty-print.c b/gcc/gimple-pretty-print.c index 1bccad1..53e7759 100644 --- a/gcc/gimple-pretty-print.c +++ b/gcc/gimple-pretty-print.c @@ -1687,6 +1687,35 @@ dump_gimple_omp_masked (pretty_printer *buffer, const gimple *gs, } } +/* Dump a GIMPLE_OMP_SCOPE tuple on the pretty_printer BUFFER. */ + +static void +dump_gimple_omp_scope (pretty_printer *buffer, const gimple *gs, + int spc, dump_flags_t flags) +{ + if (flags & TDF_RAW) + { + dump_gimple_fmt (buffer, spc, flags, "%G <%+BODY <%S>%nCLAUSES <", gs, + gimple_omp_body (gs)); + dump_omp_clauses (buffer, gimple_omp_scope_clauses (gs), spc, flags); + dump_gimple_fmt (buffer, spc, flags, " >"); + } + else + { + pp_string (buffer, "#pragma omp scope"); + dump_omp_clauses (buffer, gimple_omp_scope_clauses (gs), spc, flags); + if (!gimple_seq_empty_p (gimple_omp_body (gs))) + { + newline_and_indent (buffer, spc + 2); + pp_left_brace (buffer); + pp_newline (buffer); + dump_gimple_seq (buffer, gimple_omp_body (gs), spc + 4, flags); + newline_and_indent (buffer, spc + 2); + pp_right_brace (buffer); + } + } +} + /* Dump a GIMPLE_OMP_TARGET tuple on the pretty_printer BUFFER. */ static void @@ -2755,6 +2784,10 @@ pp_gimple_stmt_1 (pretty_printer *buffer, const gimple *gs, int spc, dump_gimple_omp_masked (buffer, gs, spc, flags); break; + case GIMPLE_OMP_SCOPE: + dump_gimple_omp_scope (buffer, gs, spc, flags); + break; + case GIMPLE_OMP_MASTER: case GIMPLE_OMP_SECTION: dump_gimple_omp_block (buffer, gs, spc, flags); diff --git a/gcc/gimple-walk.c b/gcc/gimple-walk.c index 9dd2e86..e15fd469 100644 --- a/gcc/gimple-walk.c +++ b/gcc/gimple-walk.c @@ -689,6 +689,7 @@ walk_gimple_stmt (gimple_stmt_iterator *gsi, walk_stmt_fn callback_stmt, case GIMPLE_OMP_SECTION: case GIMPLE_OMP_PARALLEL: case GIMPLE_OMP_TASK: + case GIMPLE_OMP_SCOPE: case GIMPLE_OMP_SECTIONS: case GIMPLE_OMP_SINGLE: case GIMPLE_OMP_TARGET: diff --git a/gcc/gimple.c b/gcc/gimple.c index 23bfc7f..4e2653c 100644 --- a/gcc/gimple.c +++ b/gcc/gimple.c @@ -1185,6 +1185,24 @@ gimple_build_omp_single (gimple_seq body, tree clauses) } +/* Build a GIMPLE_OMP_SCOPE statement. + + BODY is the sequence of statements that will be executed once. + CLAUSES are any of the OMP scope construct's clauses: private, reduction, + nowait. */ + +gimple * +gimple_build_omp_scope (gimple_seq body, tree clauses) +{ + gimple *p = gimple_alloc (GIMPLE_OMP_SCOPE, 0); + gimple_omp_scope_set_clauses (p, clauses); + if (body) + gimple_omp_set_body (p, body); + + return p; +} + + /* Build a GIMPLE_OMP_TARGET statement. BODY is the sequence of statements that will be executed. @@ -2020,6 +2038,11 @@ gimple_copy (gimple *stmt) } goto copy_omp_body; + case GIMPLE_OMP_SCOPE: + t = unshare_expr (gimple_omp_scope_clauses (stmt)); + gimple_omp_scope_set_clauses (copy, t); + goto copy_omp_body; + case GIMPLE_OMP_TARGET: { gomp_target *omp_target_stmt = as_a (stmt); diff --git a/gcc/gimple.def b/gcc/gimple.def index e66546c..193b250 100644 --- a/gcc/gimple.def +++ b/gcc/gimple.def @@ -340,6 +340,11 @@ DEFGSCODE(GIMPLE_OMP_RETURN, "gimple_omp_return", GSS_OMP_ATOMIC_STORE_LAYOUT) CLAUSES is an OMP_CLAUSE chain holding the associated clauses. */ DEFGSCODE(GIMPLE_OMP_SCAN, "gimple_omp_scan", GSS_OMP_SINGLE_LAYOUT) +/* GIMPLE_OMP_SCOPE represents #pragma omp scope + BODY is the sequence of statements inside the single section. + CLAUSES is an OMP_CLAUSE chain holding the associated clauses. */ +DEFGSCODE(GIMPLE_OMP_SCOPE, "gimple_omp_scope", GSS_OMP_SINGLE_LAYOUT) + /* OMP_SECTION represents #pragma omp section. BODY is the sequence of statements in the section body. */ DEFGSCODE(GIMPLE_OMP_SECTION, "gimple_omp_section", GSS_OMP) diff --git a/gcc/gimple.h b/gcc/gimple.h index 7fd483d..479a1c7 100644 --- a/gcc/gimple.h +++ b/gcc/gimple.h @@ -742,7 +742,7 @@ struct GTY((tag("GSS_OMP_CONTINUE"))) }; /* GIMPLE_OMP_SINGLE, GIMPLE_OMP_ORDERED, GIMPLE_OMP_TASKGROUP, - GIMPLE_OMP_SCAN. */ + GIMPLE_OMP_SCAN, GIMPLE_OMP_MASKED, GIMPLE_OMP_SCOPE. */ struct GTY((tag("GSS_OMP_SINGLE_LAYOUT"))) gimple_statement_omp_single_layout : public gimple_statement_omp @@ -1559,6 +1559,7 @@ gomp_parallel *gimple_build_omp_parallel (gimple_seq, tree, tree, tree); gomp_task *gimple_build_omp_task (gimple_seq, tree, tree, tree, tree, tree, tree); gimple *gimple_build_omp_section (gimple_seq); +gimple *gimple_build_omp_scope (gimple_seq, tree); gimple *gimple_build_omp_master (gimple_seq); gimple *gimple_build_omp_masked (gimple_seq, tree); gimple *gimple_build_omp_taskgroup (gimple_seq, tree); @@ -1843,6 +1844,7 @@ gimple_has_substatements (gimple *g) case GIMPLE_OMP_SECTION: case GIMPLE_OMP_PARALLEL: case GIMPLE_OMP_TASK: + case GIMPLE_OMP_SCOPE: case GIMPLE_OMP_SECTIONS: case GIMPLE_OMP_SINGLE: case GIMPLE_OMP_TARGET: @@ -5207,7 +5209,7 @@ gimple_omp_taskgroup_set_clauses (gimple *gs, tree clauses) } -/* Return the clauses associated with OMP_MASTER statement GS. */ +/* Return the clauses associated with OMP_MASKED statement GS. */ static inline tree gimple_omp_masked_clauses (const gimple *gs) @@ -5241,6 +5243,40 @@ gimple_omp_masked_set_clauses (gimple *gs, tree clauses) } +/* Return the clauses associated with OMP_SCOPE statement GS. */ + +static inline tree +gimple_omp_scope_clauses (const gimple *gs) +{ + GIMPLE_CHECK (gs, GIMPLE_OMP_SCOPE); + return + static_cast (gs)->clauses; +} + + +/* Return a pointer to the clauses associated with OMP scope statement + GS. */ + +static inline tree * +gimple_omp_scope_clauses_ptr (gimple *gs) +{ + GIMPLE_CHECK (gs, GIMPLE_OMP_SCOPE); + return &static_cast (gs)->clauses; +} + + +/* Set CLAUSES to be the clauses associated with OMP scope statement + GS. */ + +static inline void +gimple_omp_scope_set_clauses (gimple *gs, tree clauses) +{ + GIMPLE_CHECK (gs, GIMPLE_OMP_SCOPE); + static_cast (gs)->clauses + = clauses; +} + + /* Return the kind of the OMP_FOR statemement G. */ static inline int @@ -6527,6 +6563,7 @@ gimple_return_set_retval (greturn *gs, tree retval) case GIMPLE_OMP_SINGLE: \ case GIMPLE_OMP_TARGET: \ case GIMPLE_OMP_TEAMS: \ + case GIMPLE_OMP_SCOPE: \ case GIMPLE_OMP_SECTION: \ case GIMPLE_OMP_MASTER: \ case GIMPLE_OMP_MASKED: \ diff --git a/gcc/gimplify.c b/gcc/gimplify.c index eadbf83..070d0e4 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -5628,6 +5628,7 @@ is_gimple_stmt (tree t) case OMP_LOOP: case OACC_LOOP: case OMP_SCAN: + case OMP_SCOPE: case OMP_SECTIONS: case OMP_SECTION: case OMP_SINGLE: @@ -8866,7 +8867,7 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, case OMP_CLAUSE_REDUCTION: if (OMP_CLAUSE_REDUCTION_TASK (c)) { - if (region_type == ORT_WORKSHARE) + if (region_type == ORT_WORKSHARE || code == OMP_SCOPE) { if (nowait == -1) nowait = omp_find_clause (*list_p, @@ -8885,8 +8886,8 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, { error_at (OMP_CLAUSE_LOCATION (c), "invalid % reduction modifier on construct " - "other than %, %qs or %", - lang_GNU_Fortran () ? "do" : "for"); + "other than %, %qs, % or " + "%", lang_GNU_Fortran () ? "do" : "for"); OMP_CLAUSE_REDUCTION_TASK (c) = 0; } } @@ -8917,6 +8918,12 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, "%qs construct", "taskloop"); OMP_CLAUSE_REDUCTION_INSCAN (c) = 0; break; + case OMP_SCOPE: + error_at (OMP_CLAUSE_LOCATION (c), + "% % clause on " + "%qs construct", "scope"); + OMP_CLAUSE_REDUCTION_INSCAN (c) = 0; + break; default: break; } @@ -10453,6 +10460,7 @@ omp_find_stores_stmt (gimple_stmt_iterator *gsi_p, case GIMPLE_OMP_TASK: case GIMPLE_OMP_SECTIONS: case GIMPLE_OMP_SINGLE: + case GIMPLE_OMP_SCOPE: case GIMPLE_OMP_TARGET: case GIMPLE_OMP_TEAMS: case GIMPLE_OMP_CRITICAL: @@ -13375,6 +13383,9 @@ gimplify_omp_workshare (tree *expr_p, gimple_seq *pre_p) case OMP_SINGLE: ort = ORT_WORKSHARE; break; + case OMP_SCOPE: + ort = ORT_TASKGROUP; + break; case OMP_TARGET: ort = OMP_TARGET_COMBINED (expr) ? ORT_COMBINED_TARGET : ORT_TARGET; break; @@ -13487,6 +13498,9 @@ gimplify_omp_workshare (tree *expr_p, gimple_seq *pre_p) case OMP_SINGLE: stmt = gimple_build_omp_single (body, OMP_CLAUSES (expr)); break; + case OMP_SCOPE: + stmt = gimple_build_omp_scope (body, OMP_CLAUSES (expr)); + break; case OMP_TARGET: stmt = gimple_build_omp_target (body, GF_OMP_TARGET_KIND_REGION, OMP_CLAUSES (expr)); @@ -14759,6 +14773,7 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, case OACC_KERNELS: case OACC_PARALLEL: case OACC_SERIAL: + case OMP_SCOPE: case OMP_SECTIONS: case OMP_SINGLE: case OMP_TARGET: @@ -15192,7 +15207,8 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, && code != OMP_SCAN && code != OMP_SECTIONS && code != OMP_SECTION - && code != OMP_SINGLE); + && code != OMP_SINGLE + && code != OMP_SCOPE); } #endif diff --git a/gcc/omp-builtins.def b/gcc/omp-builtins.def index 05b555c..b168575 100644 --- a/gcc/omp-builtins.def +++ b/gcc/omp-builtins.def @@ -422,6 +422,8 @@ DEF_GOMP_BUILTIN (BUILT_IN_GOMP_SINGLE_COPY_START, "GOMP_single_copy_start", BT_FN_PTR, ATTR_NOTHROW_LEAF_LIST) DEF_GOMP_BUILTIN (BUILT_IN_GOMP_SINGLE_COPY_END, "GOMP_single_copy_end", BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST) +DEF_GOMP_BUILTIN (BUILT_IN_GOMP_SCOPE_START, "GOMP_scope_start", + BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST) DEF_GOMP_BUILTIN (BUILT_IN_GOMP_OFFLOAD_REGISTER, "GOMP_offload_register_ver", BT_FN_VOID_UINT_PTR_INT_PTR, ATTR_NOTHROW_LIST) DEF_GOMP_BUILTIN (BUILT_IN_GOMP_OFFLOAD_UNREGISTER, diff --git a/gcc/omp-expand.c b/gcc/omp-expand.c index 1d4b39e..c868b8c 100644 --- a/gcc/omp-expand.c +++ b/gcc/omp-expand.c @@ -8417,7 +8417,7 @@ expand_omp_sections (struct omp_region *region) set_immediate_dominator (CDI_DOMINATORS, default_bb, l0_bb); } -/* Expand code for an OpenMP single directive. We've already expanded +/* Expand code for an OpenMP single or scope directive. We've already expanded much of the code, here we simply place the GOMP_barrier call. */ static void @@ -8430,7 +8430,8 @@ expand_omp_single (struct omp_region *region) exit_bb = region->exit; si = gsi_last_nondebug_bb (entry_bb); - gcc_assert (gimple_code (gsi_stmt (si)) == GIMPLE_OMP_SINGLE); + gcc_assert (gimple_code (gsi_stmt (si)) == GIMPLE_OMP_SINGLE + || gimple_code (gsi_stmt (si)) == GIMPLE_OMP_SCOPE); gsi_remove (&si, true); single_succ_edge (entry_bb)->flags = EDGE_FALLTHRU; @@ -9928,6 +9929,7 @@ expand_omp (struct omp_region *region) break; case GIMPLE_OMP_SINGLE: + case GIMPLE_OMP_SCOPE: expand_omp_single (region); break; @@ -10269,6 +10271,7 @@ omp_make_gimple_edges (basic_block bb, struct omp_region **region, case GIMPLE_OMP_TEAMS: case GIMPLE_OMP_MASTER: case GIMPLE_OMP_MASKED: + case GIMPLE_OMP_SCOPE: case GIMPLE_OMP_TASKGROUP: case GIMPLE_OMP_CRITICAL: case GIMPLE_OMP_SECTION: diff --git a/gcc/omp-low.c b/gcc/omp-low.c index bef9940..a0b41af 100644 --- a/gcc/omp-low.c +++ b/gcc/omp-low.c @@ -663,8 +663,15 @@ build_outer_var_ref (tree var, omp_context *ctx, { tree x; omp_context *outer = ctx->outer; - while (outer && gimple_code (outer->stmt) == GIMPLE_OMP_TASKGROUP) - outer = outer->outer; + for (; outer; outer = outer->outer) + { + if (gimple_code (outer->stmt) == GIMPLE_OMP_TASKGROUP) + continue; + if (gimple_code (outer->stmt) == GIMPLE_OMP_SCOPE + && !maybe_lookup_decl (var, outer)) + continue; + break; + } if (is_global_var (maybe_lookup_decl_in_outer_ctx (var, ctx))) x = var; @@ -3493,6 +3500,40 @@ check_omp_nesting_restrictions (gimple *stmt, omp_context *ctx) break; } break; + case GIMPLE_OMP_SCOPE: + for (; ctx != NULL; ctx = ctx->outer) + switch (gimple_code (ctx->stmt)) + { + case GIMPLE_OMP_FOR: + if (gimple_omp_for_kind (ctx->stmt) != GF_OMP_FOR_KIND_FOR + && gimple_omp_for_kind (ctx->stmt) != GF_OMP_FOR_KIND_TASKLOOP) + break; + /* FALLTHRU */ + case GIMPLE_OMP_SECTIONS: + case GIMPLE_OMP_SINGLE: + case GIMPLE_OMP_TASK: + case GIMPLE_OMP_CRITICAL: + case GIMPLE_OMP_ORDERED: + case GIMPLE_OMP_MASTER: + case GIMPLE_OMP_MASKED: + error_at (gimple_location (stmt), + "% region may not be closely nested inside " + "of work-sharing, %, explicit %, " + "%, %, %, %, " + "or % region"); + return false; + case GIMPLE_OMP_PARALLEL: + case GIMPLE_OMP_TEAMS: + return true; + case GIMPLE_OMP_TARGET: + if (gimple_omp_target_kind (ctx->stmt) + == GF_OMP_TARGET_KIND_REGION) + return true; + break; + default: + break; + } + break; case GIMPLE_OMP_TASK: for (c = gimple_omp_task_clauses (stmt); c; c = OMP_CLAUSE_CHAIN (c)) if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND @@ -4071,6 +4112,12 @@ scan_omp_1_stmt (gimple_stmt_iterator *gsi, bool *handled_ops_p, scan_omp_for (as_a (stmt), ctx); break; + case GIMPLE_OMP_SCOPE: + ctx = new_omp_context (stmt, ctx); + scan_sharing_clauses (gimple_omp_scope_clauses (stmt), ctx); + scan_omp (gimple_omp_body_ptr (stmt), ctx); + break; + case GIMPLE_OMP_SECTIONS: scan_omp_sections (as_a (stmt), ctx); break; @@ -8359,7 +8406,8 @@ maybe_add_implicit_barrier_cancel (omp_context *ctx, gimple *omp_return, gimple_seq_add_stmt (body, g); gimple_seq_add_stmt (body, gimple_build_label (fallthru_label)); } - else if (gimple_code (outer->stmt) != GIMPLE_OMP_TASKGROUP) + else if (gimple_code (outer->stmt) != GIMPLE_OMP_TASKGROUP + && gimple_code (outer->stmt) != GIMPLE_OMP_SCOPE) return; } @@ -8698,6 +8746,97 @@ lower_omp_single (gimple_stmt_iterator *gsi_p, omp_context *ctx) } +/* Lower code for an OMP scope directive. */ + +static void +lower_omp_scope (gimple_stmt_iterator *gsi_p, omp_context *ctx) +{ + tree block; + gimple *scope_stmt = gsi_stmt (*gsi_p); + gbind *bind; + gimple_seq bind_body, bind_body_tail = NULL, dlist; + gimple_seq tred_dlist = NULL; + + push_gimplify_context (); + + block = make_node (BLOCK); + bind = gimple_build_bind (NULL, NULL, block); + gsi_replace (gsi_p, bind, true); + bind_body = NULL; + dlist = NULL; + + tree rclauses + = omp_task_reductions_find_first (gimple_omp_scope_clauses (scope_stmt), + OMP_SCOPE, OMP_CLAUSE_REDUCTION); + if (rclauses) + { + tree type = build_pointer_type (pointer_sized_int_node); + tree temp = create_tmp_var (type); + tree c = build_omp_clause (UNKNOWN_LOCATION, OMP_CLAUSE__REDUCTEMP_); + OMP_CLAUSE_DECL (c) = temp; + OMP_CLAUSE_CHAIN (c) = gimple_omp_scope_clauses (scope_stmt); + gimple_omp_scope_set_clauses (scope_stmt, c); + lower_omp_task_reductions (ctx, OMP_SCOPE, + gimple_omp_scope_clauses (scope_stmt), + &bind_body, &tred_dlist); + rclauses = c; + tree fndecl = builtin_decl_explicit (BUILT_IN_GOMP_SCOPE_START); + gimple *stmt = gimple_build_call (fndecl, 1, temp); + gimple_seq_add_stmt (&bind_body, stmt); + } + + lower_rec_input_clauses (gimple_omp_scope_clauses (scope_stmt), + &bind_body, &dlist, ctx, NULL); + lower_omp (gimple_omp_body_ptr (scope_stmt), ctx); + + gimple_seq_add_stmt (&bind_body, scope_stmt); + + gimple_seq_add_seq (&bind_body, gimple_omp_body (scope_stmt)); + + gimple_omp_set_body (scope_stmt, NULL); + + gimple_seq clist = NULL; + lower_reduction_clauses (gimple_omp_scope_clauses (scope_stmt), + &bind_body, &clist, ctx); + if (clist) + { + tree fndecl = builtin_decl_explicit (BUILT_IN_GOMP_ATOMIC_START); + gcall *g = gimple_build_call (fndecl, 0); + gimple_seq_add_stmt (&bind_body, g); + gimple_seq_add_seq (&bind_body, clist); + fndecl = builtin_decl_explicit (BUILT_IN_GOMP_ATOMIC_END); + g = gimple_build_call (fndecl, 0); + gimple_seq_add_stmt (&bind_body, g); + } + + gimple_seq_add_seq (&bind_body, dlist); + + bind_body = maybe_catch_exception (bind_body); + + bool nowait = omp_find_clause (gimple_omp_scope_clauses (scope_stmt), + OMP_CLAUSE_NOWAIT) != NULL_TREE; + gimple *g = gimple_build_omp_return (nowait); + gimple_seq_add_stmt (&bind_body_tail, g); + gimple_seq_add_seq (&bind_body_tail, tred_dlist); + maybe_add_implicit_barrier_cancel (ctx, g, &bind_body_tail); + if (ctx->record_type) + { + gimple_stmt_iterator gsi = gsi_start (bind_body_tail); + tree clobber = build_clobber (ctx->record_type); + gsi_insert_after (&gsi, gimple_build_assign (ctx->sender_decl, + clobber), GSI_SAME_STMT); + } + gimple_seq_add_seq (&bind_body, bind_body_tail); + + gimple_bind_set_body (bind, bind_body); + + pop_gimplify_context (bind); + + gimple_bind_append_vars (bind, ctx->block_vars); + BLOCK_VARS (block) = ctx->block_vars; + if (BLOCK_VARS (block)) + TREE_USED (block) = 1; +} /* Expand code for an OpenMP master or masked directive. */ static void @@ -8803,7 +8942,7 @@ lower_omp_task_reductions (omp_context *ctx, enum tree_code code, tree clauses, clauses = omp_task_reductions_find_first (clauses, code, ccode); if (clauses == NULL_TREE) return; - if (code == OMP_FOR || code == OMP_SECTIONS) + if (code == OMP_FOR || code == OMP_SECTIONS || code == OMP_SCOPE) { for (omp_context *outer = ctx->outer; outer; outer = outer->outer) if (gimple_code (outer->stmt) == GIMPLE_OMP_PARALLEL @@ -8812,7 +8951,8 @@ lower_omp_task_reductions (omp_context *ctx, enum tree_code code, tree clauses, cancellable = error_mark_node; break; } - else if (gimple_code (outer->stmt) != GIMPLE_OMP_TASKGROUP) + else if (gimple_code (outer->stmt) != GIMPLE_OMP_TASKGROUP + && gimple_code (outer->stmt) != GIMPLE_OMP_SCOPE) break; } tree record_type = lang_hooks.types.make_type (RECORD_TYPE); @@ -8928,11 +9068,11 @@ lower_omp_task_reductions (omp_context *ctx, enum tree_code code, tree clauses, tree lab2 = create_artificial_label (UNKNOWN_LOCATION); tree lab3 = NULL_TREE, lab7 = NULL_TREE; gimple *g; - if (code == OMP_FOR || code == OMP_SECTIONS) + if (code == OMP_FOR || code == OMP_SECTIONS || code == OMP_SCOPE) { - /* For worksharing constructs, only perform it in the master thread, - with the exception of cancelled implicit barriers - then only handle - the current thread. */ + /* For worksharing constructs or scope, only perform it in the master + thread, with the exception of cancelled implicit barriers - then only + handle the current thread. */ tree lab4 = create_artificial_label (UNKNOWN_LOCATION); t = builtin_decl_explicit (BUILT_IN_OMP_GET_THREAD_NUM); tree thr_num = create_tmp_var (integer_type_node); @@ -8947,8 +9087,10 @@ lower_omp_task_reductions (omp_context *ctx, enum tree_code code, tree clauses, lab3 = create_artificial_label (UNKNOWN_LOCATION); if (code == OMP_FOR) c = gimple_omp_for_clauses (ctx->stmt); - else /* if (code == OMP_SECTIONS) */ + else if (code == OMP_SECTIONS) c = gimple_omp_sections_clauses (ctx->stmt); + else /* if (code == OMP_SCOPE) */ + c = gimple_omp_scope_clauses (ctx->stmt); c = OMP_CLAUSE_DECL (omp_find_clause (c, OMP_CLAUSE__REDUCTEMP_)); cancellable = c; g = gimple_build_cond (NE_EXPR, c, build_zero_cst (TREE_TYPE (c)), @@ -9083,8 +9225,11 @@ lower_omp_task_reductions (omp_context *ctx, enum tree_code code, tree clauses, tree bfield = DECL_CHAIN (field); tree cond; - if (code == OMP_PARALLEL || code == OMP_FOR || code == OMP_SECTIONS) - /* In parallel or worksharing all threads unconditionally + if (code == OMP_PARALLEL + || code == OMP_FOR + || code == OMP_SECTIONS + || code == OMP_SCOPE) + /* In parallel, worksharing or scope all threads unconditionally initialize all their task reduction private variables. */ cond = boolean_true_node; else if (TREE_TYPE (ptr) == ptr_type_node) @@ -9325,6 +9470,8 @@ lower_omp_task_reductions (omp_context *ctx, enum tree_code code, tree clauses, c = gimple_omp_for_clauses (ctx->stmt); else if (code == OMP_SECTIONS) c = gimple_omp_sections_clauses (ctx->stmt); + else if (code == OMP_SCOPE) + c = gimple_omp_scope_clauses (ctx->stmt); else c = gimple_omp_taskreg_clauses (ctx->stmt); c = omp_find_clause (c, OMP_CLAUSE__REDUCTEMP_); @@ -9339,7 +9486,7 @@ lower_omp_task_reductions (omp_context *ctx, enum tree_code code, tree clauses, g = gimple_build_cond (NE_EXPR, idx, num_thr_sz, lab1, lab2); gimple_seq_add_stmt (end, g); gimple_seq_add_stmt (end, gimple_build_label (lab2)); - if (code == OMP_FOR || code == OMP_SECTIONS) + if (code == OMP_FOR || code == OMP_SECTIONS || code == OMP_SCOPE) { enum built_in_function bfn = BUILT_IN_GOMP_WORKSHARE_TASK_REDUCTION_UNREGISTER; @@ -13897,6 +14044,11 @@ lower_omp_1 (gimple_stmt_iterator *gsi_p, omp_context *ctx) ctx->cancel_label = create_artificial_label (UNKNOWN_LOCATION); lower_omp_sections (gsi_p, ctx); break; + case GIMPLE_OMP_SCOPE: + ctx = maybe_lookup_ctx (stmt); + gcc_assert (ctx); + lower_omp_scope (gsi_p, ctx); + break; case GIMPLE_OMP_SINGLE: ctx = maybe_lookup_ctx (stmt); gcc_assert (ctx); @@ -14008,6 +14160,7 @@ lower_omp_1 (gimple_stmt_iterator *gsi_p, omp_context *ctx) if (gimple_code (up->stmt) == GIMPLE_OMP_ORDERED || gimple_code (up->stmt) == GIMPLE_OMP_CRITICAL || gimple_code (up->stmt) == GIMPLE_OMP_TASKGROUP + || gimple_code (up->stmt) == GIMPLE_OMP_SCOPE || gimple_code (up->stmt) == GIMPLE_OMP_SECTION || gimple_code (up->stmt) == GIMPLE_OMP_SCAN || (gimple_code (up->stmt) == GIMPLE_OMP_TARGET @@ -14277,6 +14430,7 @@ diagnose_sb_1 (gimple_stmt_iterator *gsi_p, bool *handled_ops_p, case GIMPLE_OMP_PARALLEL: case GIMPLE_OMP_TASK: + case GIMPLE_OMP_SCOPE: case GIMPLE_OMP_SECTIONS: case GIMPLE_OMP_SINGLE: case GIMPLE_OMP_SECTION: @@ -14339,6 +14493,7 @@ diagnose_sb_2 (gimple_stmt_iterator *gsi_p, bool *handled_ops_p, case GIMPLE_OMP_PARALLEL: case GIMPLE_OMP_TASK: + case GIMPLE_OMP_SCOPE: case GIMPLE_OMP_SECTIONS: case GIMPLE_OMP_SINGLE: case GIMPLE_OMP_SECTION: diff --git a/gcc/testsuite/c-c++-common/gomp/cancel-1.c b/gcc/testsuite/c-c++-common/gomp/cancel-1.c index 5255dd3..5d68cd3 100644 --- a/gcc/testsuite/c-c++-common/gomp/cancel-1.c +++ b/gcc/testsuite/c-c++-common/gomp/cancel-1.c @@ -39,6 +39,28 @@ f2 (void) #pragma omp cancellation point sections /* { dg-error "not closely nested inside" } */ #pragma omp cancellation point taskgroup /* { dg-error "not closely nested inside" } */ } + #pragma omp masked + { + #pragma omp cancel parallel /* { dg-error "not closely nested inside" } */ + #pragma omp cancel for /* { dg-error "not closely nested inside" } */ + #pragma omp cancel sections /* { dg-error "not closely nested inside" } */ + #pragma omp cancel taskgroup /* { dg-error "not closely nested inside" } */ + #pragma omp cancellation point parallel /* { dg-error "not closely nested inside" } */ + #pragma omp cancellation point for /* { dg-error "not closely nested inside" } */ + #pragma omp cancellation point sections /* { dg-error "not closely nested inside" } */ + #pragma omp cancellation point taskgroup /* { dg-error "not closely nested inside" } */ + } + #pragma omp scope + { + #pragma omp cancel parallel /* { dg-error "not closely nested inside" } */ + #pragma omp cancel for /* { dg-error "not closely nested inside" } */ + #pragma omp cancel sections /* { dg-error "not closely nested inside" } */ + #pragma omp cancel taskgroup /* { dg-error "not closely nested inside" } */ + #pragma omp cancellation point parallel /* { dg-error "not closely nested inside" } */ + #pragma omp cancellation point for /* { dg-error "not closely nested inside" } */ + #pragma omp cancellation point sections /* { dg-error "not closely nested inside" } */ + #pragma omp cancellation point taskgroup /* { dg-error "not closely nested inside" } */ + } #pragma omp single { #pragma omp cancel parallel /* { dg-error "not closely nested inside" } */ diff --git a/gcc/testsuite/c-c++-common/gomp/clause-dups-1.c b/gcc/testsuite/c-c++-common/gomp/clause-dups-1.c index 7b71ad3..604caf0 100644 --- a/gcc/testsuite/c-c++-common/gomp/clause-dups-1.c +++ b/gcc/testsuite/c-c++-common/gomp/clause-dups-1.c @@ -205,6 +205,8 @@ f1 (int *p) i = p[0]++; #pragma omp masked filter (0) filter (0) /* { dg-error "too many 'filter' clauses" } */ f0 (); + #pragma omp scope nowait nowait /* { dg-error "too many 'nowait' clauses" } */ + ; } #pragma omp declare simd simdlen (4) simdlen (4) /* { dg-error "too many 'simdlen' clauses" } */ diff --git a/gcc/testsuite/c-c++-common/gomp/loop-1.c b/gcc/testsuite/c-c++-common/gomp/loop-1.c index 4fb995c..3454fa8 100644 --- a/gcc/testsuite/c-c++-common/gomp/loop-1.c +++ b/gcc/testsuite/c-c++-common/gomp/loop-1.c @@ -183,6 +183,24 @@ f5 (int *a) } #pragma omp loop for (i = 0; i < 64; i++) + { + #pragma omp master /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" } */ + foo (); + } + #pragma omp loop + for (i = 0; i < 64; i++) + { + #pragma omp masked /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" } */ + foo (); + } + #pragma omp loop + for (i = 0; i < 64; i++) + { + #pragma omp scope /* { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" } */ + foo (); + } + #pragma omp loop + for (i = 0; i < 64; i++) a[i] += omp_get_thread_num (); /* { dg-error "OpenMP runtime API call '\[^\n\r]*omp_get_thread_num\[^\n\r]*' in a region with 'order\\(concurrent\\)' clause" } */ #pragma omp loop for (i = 0; i < 64; i++) diff --git a/gcc/testsuite/c-c++-common/gomp/nesting-2.c b/gcc/testsuite/c-c++-common/gomp/nesting-2.c index 7a03430..420cfd3 100644 --- a/gcc/testsuite/c-c++-common/gomp/nesting-2.c +++ b/gcc/testsuite/c-c++-common/gomp/nesting-2.c @@ -19,6 +19,10 @@ foo (void) #pragma omp barrier /* { dg-error "region may not be closely nested inside of" } */ #pragma omp master /* { dg-error "region may not be closely nested inside of" } */ ; + #pragma omp masked /* { dg-error "region may not be closely nested inside of" } */ + ; + #pragma omp scope /* { dg-error "region may not be closely nested inside of" } */ + ; #pragma omp ordered /* { dg-error "region may not be closely nested inside of" } */ ; #pragma omp ordered threads /* { dg-error "region may not be closely nested inside of" } */ @@ -55,6 +59,10 @@ foo (void) #pragma omp barrier #pragma omp master ; + #pragma omp masked + ; + #pragma omp scope + ; #pragma omp ordered /* { dg-error ".ordered. region must be closely nested inside a loop region with an .ordered. clause" } */ ; #pragma omp ordered threads /* { dg-error ".ordered. region must be closely nested inside a loop region with an .ordered. clause" } */ @@ -89,6 +97,10 @@ foo (void) #pragma omp barrier #pragma omp master ; + #pragma omp masked + ; + #pragma omp scope + ; #pragma omp ordered /* { dg-error ".ordered. region must be closely nested inside a loop region with an .ordered. clause" } */ ; #pragma omp ordered threads /* { dg-error ".ordered. region must be closely nested inside a loop region with an .ordered. clause" } */ diff --git a/gcc/testsuite/c-c++-common/gomp/reduction-task-2.c b/gcc/testsuite/c-c++-common/gomp/reduction-task-2.c index 1e262d3..225abed 100644 --- a/gcc/testsuite/c-c++-common/gomp/reduction-task-2.c +++ b/gcc/testsuite/c-c++-common/gomp/reduction-task-2.c @@ -14,7 +14,9 @@ bar (void) #pragma omp section foo (-3); } - #pragma omp simd reduction (task, +: v) /* { dg-error "invalid 'task' reduction modifier on construct other than 'parallel', 'for' or 'sections'" } */ + #pragma omp scope reduction (task, +: v) nowait /* { dg-error "'task' reduction modifier on a construct with a 'nowait' clause" } */ + foo (-4); + #pragma omp simd reduction (task, +: v) /* { dg-error "invalid 'task' reduction modifier on construct other than 'parallel', 'for', 'sections' or 'scope'" } */ for (i = 0; i < 64; i++) v++; #pragma omp for simd reduction (task, +: v) /* { dg-error "invalid 'task' reduction modifier on construct combined with 'simd'" } */ @@ -26,13 +28,13 @@ bar (void) #pragma omp teams distribute parallel for simd reduction (task, +: v) /* { dg-error "invalid 'task' reduction modifier on construct combined with 'simd'" } */ for (i = 0; i < 64; i++) v++; - #pragma omp taskloop reduction (task, +: v) /* { dg-error "invalid 'task' reduction modifier on construct other than 'parallel', 'for' or 'sections'" } */ + #pragma omp taskloop reduction (task, +: v) /* { dg-error "invalid 'task' reduction modifier on construct other than 'parallel', 'for', 'sections' or 'scope'" } */ for (i = 0; i < 64; i++) foo (i); #pragma omp taskloop simd reduction (task, +: v) /* { dg-error "invalid 'task' reduction modifier on construct combined with 'simd'" } */ for (i = 0; i < 64; i++) v++; - #pragma omp teams reduction (task, +: v) /* { dg-error "invalid 'task' reduction modifier on construct other than 'parallel', 'for' or 'sections'" } */ + #pragma omp teams reduction (task, +: v) /* { dg-error "invalid 'task' reduction modifier on construct other than 'parallel', 'for', 'sections' or 'scope'" } */ foo (i); #pragma omp teams distribute reduction (task, +: v) /* { dg-error "invalid 'task' reduction modifier on construct not combined with 'parallel', 'for' or 'sections'" } */ for (i = 0; i < 64; i++) diff --git a/gcc/testsuite/c-c++-common/gomp/scan-1.c b/gcc/testsuite/c-c++-common/gomp/scan-1.c index 17804e3..95b46cb 100644 --- a/gcc/testsuite/c-c++-common/gomp/scan-1.c +++ b/gcc/testsuite/c-c++-common/gomp/scan-1.c @@ -89,6 +89,8 @@ f3 (int *c, int *d) #pragma omp section ; } + #pragma omp scope reduction (inscan, +: a) /* { dg-error "'inscan' 'reduction' clause on 'scope' construct" } */ + ; #pragma omp target parallel for reduction (inscan, +: a) map (c[:64], d[:64]) /* { dg-error "'inscan' 'reduction' clause on construct other than 'for', 'simd', 'for simd', 'parallel for', 'parallel for simd'" } */ for (i = 0; i < 64; i++) { diff --git a/gcc/testsuite/c-c++-common/gomp/scope-1.c b/gcc/testsuite/c-c++-common/gomp/scope-1.c new file mode 100644 index 0000000..ab7a778 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/scope-1.c @@ -0,0 +1,39 @@ +int r, r2, r3; + +void +foo (void) +{ + int i = 0, j = 0, k = 0; + #pragma omp scope private (i) reduction (+:r) nowait + { + i = 1; + r++; + } + #pragma omp scope private (i) reduction (task, +:r) + #pragma omp scope private (j) reduction (task, +:r2) + #pragma omp scope private (k) reduction (task, +:r3) + { + i = 1; + j = 2; + k = 3; + r++; + r2++; + r3++; + } + #pragma omp parallel + { + #pragma omp scope reduction (+:r) private (i) nowait + { + #pragma omp scope reduction (+:r2) private (j) nowait + { + #pragma omp single + { + i = 1; + j = 2; + r++; + r2++; + } + } + } + } +} diff --git a/gcc/testsuite/c-c++-common/gomp/scope-2.c b/gcc/testsuite/c-c++-common/gomp/scope-2.c new file mode 100644 index 0000000..58517be --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/scope-2.c @@ -0,0 +1,41 @@ +int r, r2, r3 = 1; +int bar (void); + +void +foo (void) +{ + int i = 0, j = 0, k = 0; + #pragma omp parallel + { + if (bar ()) + { + #pragma omp cancel parallel + } + #pragma omp scope reduction (+:r) private (i) + { + #pragma omp scope reduction (+:r2) private (j) + { + #pragma omp single nowait + { + i = 1; + j = 2; + r++; + r2++; + } + } + } + } + #pragma omp parallel + { + if (bar ()) + { + #pragma omp cancel parallel + } + #pragma omp scope reduction (task, +:r) private (i) + #pragma omp scope reduction (task, *:r3) + { + r++; + r3++; + } + } +} diff --git a/gcc/testsuite/g++.dg/gomp/attrs-1.C b/gcc/testsuite/g++.dg/gomp/attrs-1.C index c348375..686acf5 100644 --- a/gcc/testsuite/g++.dg/gomp/attrs-1.C +++ b/gcc/testsuite/g++.dg/gomp/attrs-1.C @@ -554,6 +554,10 @@ bar (int d, int m, int i1, int i2, int i3, int p, int *idp, int s, [[omp::directive (cancellation point parallel)]]; } } + [[omp::directive (scope private (p) reduction(+:r) nowait)]] + ; + [[omp::directive (scope private (p) reduction(task, +:r))]] + ; extern int t2; [[omp::directive (threadprivate (t2))]]; extern int t2; diff --git a/gcc/testsuite/g++.dg/gomp/attrs-2.C b/gcc/testsuite/g++.dg/gomp/attrs-2.C index b2fba21..2190457 100644 --- a/gcc/testsuite/g++.dg/gomp/attrs-2.C +++ b/gcc/testsuite/g++.dg/gomp/attrs-2.C @@ -554,6 +554,10 @@ bar (int d, int m, int i1, int i2, int i3, int p, int *idp, int s, [[omp::directive (cancellation point, parallel)]]; } } + [[omp::directive (scope, private (p), reduction(+:r), nowait)]] + ; + [[using omp:directive (scope, private (p), reduction(task, +:r))]] + ; extern int t2; [[omp::directive (threadprivate (t2))]]; extern int t2; diff --git a/gcc/testsuite/gcc.dg/gomp/nesting-1.c b/gcc/testsuite/gcc.dg/gomp/nesting-1.c index 4a471c8..ed457ce 100644 --- a/gcc/testsuite/gcc.dg/gomp/nesting-1.c +++ b/gcc/testsuite/gcc.dg/gomp/nesting-1.c @@ -24,6 +24,8 @@ f1 (void) #pragma omp masked /* { dg-error "may not be closely nested" } */ ; #pragma omp barrier /* { dg-error "may not be closely nested" } */ + #pragma omp scope /* { dg-error "may not be closely nested" } */ + ; } #pragma omp sections { @@ -57,6 +59,11 @@ f1 (void) } #pragma omp sections { + #pragma omp scope /* { dg-error "may not be closely nested" } */ + ; + } + #pragma omp sections + { #pragma omp section ; } @@ -92,6 +99,12 @@ f1 (void) #pragma omp masked /* { dg-error "may not be closely nested" } */ ; } + #pragma omp sections + { + #pragma omp section + #pragma omp scope /* { dg-error "may not be closely nested" } */ + ; + } #pragma omp single { #pragma omp for /* { dg-error "may not be closely nested" } */ @@ -110,6 +123,8 @@ f1 (void) #pragma omp masked /* { dg-error "may not be closely nested" } */ ; #pragma omp barrier /* { dg-error "may not be closely nested" } */ + #pragma omp scope /* { dg-error "may not be closely nested" } */ + ; } #pragma omp master { @@ -127,6 +142,8 @@ f1 (void) #pragma omp master ; #pragma omp barrier /* { dg-error "may not be closely nested" } */ + #pragma omp scope /* { dg-error "may not be closely nested" } */ + ; } #pragma omp masked filter (1) { @@ -144,6 +161,8 @@ f1 (void) #pragma omp master ; #pragma omp barrier /* { dg-error "may not be closely nested" } */ + #pragma omp scope /* { dg-error "may not be closely nested" } */ + ; } #pragma omp task { @@ -163,6 +182,8 @@ f1 (void) #pragma omp masked /* { dg-error "may not be closely nested" } */ ; #pragma omp barrier /* { dg-error "may not be closely nested" } */ + #pragma omp scope /* { dg-error "may not be closely nested" } */ + ; } #pragma omp parallel { @@ -182,6 +203,39 @@ f1 (void) #pragma omp masked ; #pragma omp barrier + #pragma omp scope + ; + #pragma omp scope + { + #pragma omp scope + ; + } + } + #pragma omp scope + { + #pragma omp for + for (j = 0; j < 3; j++) + ; + #pragma omp sections + { + ; + #pragma omp section + ; + } + #pragma omp single + ; + #pragma omp master + ; + #pragma omp masked + ; + #pragma omp barrier + #pragma omp scope + ; + #pragma omp scope + { + #pragma omp scope + ; + } } } @@ -207,6 +261,8 @@ f2 (void) #pragma omp masked ; #pragma omp barrier /* { dg-error "may not be closely nested" } */ + #pragma omp scope /* { dg-error "may not be closely nested" } */ + ; } } @@ -217,6 +273,8 @@ f3 (void) { #pragma omp ordered /* { dg-error "may not be closely nested" } */ ; + #pragma omp scope /* { dg-error "may not be closely nested" } */ + ; } } @@ -227,6 +285,8 @@ f4 (void) { #pragma omp ordered /* { dg-error "may not be closely nested" } */ ; + #pragma omp scope /* { dg-error "may not be closely nested" } */ + ; } } diff --git a/gcc/testsuite/gfortran.dg/gomp/reduction4.f90 b/gcc/testsuite/gfortran.dg/gomp/reduction4.f90 index 2e8aaa2..52d504b 100644 --- a/gcc/testsuite/gfortran.dg/gomp/reduction4.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/reduction4.f90 @@ -40,7 +40,7 @@ do i=1,10 a = a + 1 end do -!$omp simd reduction(task,+:a) ! { dg-error "invalid 'task' reduction modifier on construct other than 'parallel', 'do' or 'sections'" } +!$omp simd reduction(task,+:a) ! { dg-error "invalid 'task' reduction modifier on construct other than 'parallel', 'do', 'sections' or 'scope'" } do i=1,10 a = a + 1 end do diff --git a/gcc/testsuite/gfortran.dg/gomp/reduction7.f90 b/gcc/testsuite/gfortran.dg/gomp/reduction7.f90 index 7dc50e1..5f0b7bd 100644 --- a/gcc/testsuite/gfortran.dg/gomp/reduction7.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/reduction7.f90 @@ -2,7 +2,7 @@ implicit none integer :: a, b, i a = 0 -!$omp simd reduction(task,+:a) ! { dg-error "invalid 'task' reduction modifier on construct other than 'parallel', 'do' or 'sections'" } +!$omp simd reduction(task,+:a) ! { dg-error "invalid 'task' reduction modifier on construct other than 'parallel', 'do', 'sections' or 'scope'" } do i=1,10 a = a + 1 end do diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c index 4ba48e0..c5d6b1e 100644 --- a/gcc/tree-inline.c +++ b/gcc/tree-inline.c @@ -1664,6 +1664,12 @@ remap_gimple_stmt (gimple *stmt, copy_body_data *id) (s1, gimple_omp_masked_clauses (stmt)); break; + case GIMPLE_OMP_SCOPE: + s1 = remap_gimple_seq (gimple_omp_body (stmt), id); + copy = gimple_build_omp_scope + (s1, gimple_omp_scope_clauses (stmt)); + break; + case GIMPLE_OMP_TASKGROUP: s1 = remap_gimple_seq (gimple_omp_body (stmt), id); copy = gimple_build_omp_taskgroup @@ -4551,6 +4557,7 @@ estimate_num_insns (gimple *stmt, eni_weights *weights) case GIMPLE_OMP_CRITICAL: case GIMPLE_OMP_MASTER: case GIMPLE_OMP_MASKED: + case GIMPLE_OMP_SCOPE: case GIMPLE_OMP_TASKGROUP: case GIMPLE_OMP_ORDERED: case GIMPLE_OMP_SCAN: diff --git a/gcc/tree-nested.c b/gcc/tree-nested.c index d2b3969..c7f50eb 100644 --- a/gcc/tree-nested.c +++ b/gcc/tree-nested.c @@ -1736,6 +1736,14 @@ convert_nonlocal_reference_stmt (gimple_stmt_iterator *gsi, bool *handled_ops_p, info->suppress_expansion = save_suppress; break; + case GIMPLE_OMP_SCOPE: + save_suppress = info->suppress_expansion; + convert_nonlocal_omp_clauses (gimple_omp_scope_clauses_ptr (stmt), wi); + walk_body (convert_nonlocal_reference_stmt, convert_nonlocal_reference_op, + info, gimple_omp_body_ptr (stmt)); + info->suppress_expansion = save_suppress; + break; + case GIMPLE_OMP_TASKGROUP: save_suppress = info->suppress_expansion; convert_nonlocal_omp_clauses (gimple_omp_taskgroup_clauses_ptr (stmt), wi); @@ -2458,6 +2466,14 @@ convert_local_reference_stmt (gimple_stmt_iterator *gsi, bool *handled_ops_p, info->suppress_expansion = save_suppress; break; + case GIMPLE_OMP_SCOPE: + save_suppress = info->suppress_expansion; + convert_local_omp_clauses (gimple_omp_scope_clauses_ptr (stmt), wi); + walk_body (convert_local_reference_stmt, convert_local_reference_op, + info, gimple_omp_body_ptr (stmt)); + info->suppress_expansion = save_suppress; + break; + case GIMPLE_OMP_TASKGROUP: save_suppress = info->suppress_expansion; convert_local_omp_clauses (gimple_omp_taskgroup_clauses_ptr (stmt), wi); @@ -3031,6 +3047,7 @@ convert_gimple_call (gimple_stmt_iterator *gsi, bool *handled_ops_p, case GIMPLE_OMP_SECTIONS: case GIMPLE_OMP_SECTION: case GIMPLE_OMP_SINGLE: + case GIMPLE_OMP_SCOPE: case GIMPLE_OMP_MASTER: case GIMPLE_OMP_MASKED: case GIMPLE_OMP_TASKGROUP: diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c index 5ac4034..0570fdc 100644 --- a/gcc/tree-pretty-print.c +++ b/gcc/tree-pretty-print.c @@ -3657,6 +3657,11 @@ dump_generic_node (pretty_printer *pp, tree node, int spc, dump_flags_t flags, dump_omp_clauses (pp, OMP_SINGLE_CLAUSES (node), spc, flags); goto dump_omp_body; + case OMP_SCOPE: + pp_string (pp, "#pragma omp scope"); + dump_omp_clauses (pp, OMP_SCOPE_CLAUSES (node), spc, flags); + goto dump_omp_body; + case OMP_CLAUSE: /* If we come here, we're dumping something that's not an OMP construct, for example, OMP clauses attached to a function's '__attribute__'. diff --git a/gcc/tree.def b/gcc/tree.def index ff8b5e6..e27bc3e 100644 --- a/gcc/tree.def +++ b/gcc/tree.def @@ -1213,6 +1213,11 @@ DEFTREECODE (OMP_CRITICAL, "omp_critical", tcc_statement, 3) Operand 1: OMP_SINGLE_CLAUSES: List of clauses. */ DEFTREECODE (OMP_SINGLE, "omp_single", tcc_statement, 2) +/* OpenMP - #pragma omp scope + Operand 0: OMP_SCOPE_BODY: Masked section body. + Operand 1: OMP_SCOPE_CLAUSES: List of clauses. */ +DEFTREECODE (OMP_SCOPE, "omp_scope", tcc_statement, 2) + /* OpenMP - #pragma omp taskgroup Operand 0: OMP_TASKGROUP_BODY: Taskgroup body. Operand 1: OMP_SINGLE_CLAUSES: List of clauses. */ diff --git a/gcc/tree.h b/gcc/tree.h index a26500d..78d8a04 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -1427,6 +1427,9 @@ class auto_suppress_location_wrappers #define OMP_SINGLE_BODY(NODE) TREE_OPERAND (OMP_SINGLE_CHECK (NODE), 0) #define OMP_SINGLE_CLAUSES(NODE) TREE_OPERAND (OMP_SINGLE_CHECK (NODE), 1) +#define OMP_SCOPE_BODY(NODE) TREE_OPERAND (OMP_SCOPE_CHECK (NODE), 0) +#define OMP_SCOPE_CLAUSES(NODE) TREE_OPERAND (OMP_SCOPE_CHECK (NODE), 1) + #define OMP_MASTER_BODY(NODE) TREE_OPERAND (OMP_MASTER_CHECK (NODE), 0) #define OMP_MASKED_BODY(NODE) TREE_OPERAND (OMP_MASKED_CHECK (NODE), 0) -- cgit v1.1 From 2e0d7f16da0897fb2eb83f5c1ffe67f0ad747e92 Mon Sep 17 00:00:00 2001 From: Kewen Lin Date: Tue, 17 Aug 2021 03:18:02 -0500 Subject: vect: Add extraction cost for slp reduc As Richi pointed out, currently for BB reductions we don't actually build a SLP node with IFN_REDUC_* information, ideally we may end up with that eventually. For now, it's costed as shuffles and reduc operations, it misses the cost of lane extraction. This patch is to add one time of vec_to_scalar cost for lane extraction, it's to make the costings consistent and conservative for now. gcc/ChangeLog: * tree-vect-slp.c (vectorizable_bb_reduc_epilogue): Add the cost for value extraction. --- gcc/tree-vect-slp.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/tree-vect-slp.c b/gcc/tree-vect-slp.c index d169bed..4dcc70c 100644 --- a/gcc/tree-vect-slp.c +++ b/gcc/tree-vect-slp.c @@ -4861,12 +4861,14 @@ vectorizable_bb_reduc_epilogue (slp_instance instance, return false; /* There's no way to cost a horizontal vector reduction via REDUC_FN so - cost log2 vector operations plus shuffles. */ + cost log2 vector operations plus shuffles and one extraction. */ unsigned steps = floor_log2 (vect_nunits_for_cost (vectype)); record_stmt_cost (cost_vec, steps, vector_stmt, instance->root_stmts[0], vectype, 0, vect_body); record_stmt_cost (cost_vec, steps, vec_perm, instance->root_stmts[0], vectype, 0, vect_body); + record_stmt_cost (cost_vec, 1, vec_to_scalar, instance->root_stmts[0], + vectype, 0, vect_body); return true; } -- cgit v1.1 From 3ed779689631ff8f398dcde06d5efa2a3c43ef27 Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Tue, 17 Aug 2021 11:23:06 +0200 Subject: tree-optimization/101868 - avoid PRE of trapping mems across calls This adds the testcase from the fix for the PR. 2021-08-17 Richard Biener PR tree-optimization/101868 * gcc.dg/lto/pr101868_0.c: New testcase. * gcc.dg/lto/pr101868_1.c: Likewise. * gcc.dg/lto/pr101868_2.c: Likewise. * gcc.dg/lto/pr101868_3.c: Likewise. --- gcc/testsuite/gcc.dg/lto/pr101868_0.c | 33 +++++++++++++++++++++++++++++++++ gcc/testsuite/gcc.dg/lto/pr101868_1.c | 23 +++++++++++++++++++++++ gcc/testsuite/gcc.dg/lto/pr101868_2.c | 11 +++++++++++ gcc/testsuite/gcc.dg/lto/pr101868_3.c | 8 ++++++++ 4 files changed, 75 insertions(+) create mode 100644 gcc/testsuite/gcc.dg/lto/pr101868_0.c create mode 100644 gcc/testsuite/gcc.dg/lto/pr101868_1.c create mode 100644 gcc/testsuite/gcc.dg/lto/pr101868_2.c create mode 100644 gcc/testsuite/gcc.dg/lto/pr101868_3.c (limited to 'gcc') diff --git a/gcc/testsuite/gcc.dg/lto/pr101868_0.c b/gcc/testsuite/gcc.dg/lto/pr101868_0.c new file mode 100644 index 0000000..c84d19b --- /dev/null +++ b/gcc/testsuite/gcc.dg/lto/pr101868_0.c @@ -0,0 +1,33 @@ +/* { dg-lto-do run } */ +/* { dg-lto-options { "-O2 -fno-strict-aliasing -flto" } } */ + +typedef unsigned long VALUE; + +__attribute__ ((cold)) +void rb_check_type(VALUE, int); + +static VALUE +repro(VALUE dummy, VALUE hash) +{ + if (hash == 0) { + rb_check_type(hash, 1); + } + else if (*(long *)hash) { + rb_check_type(hash, 1); + } + + + return *(long *)hash; +} + +static VALUE (*that)(VALUE dummy, VALUE hash) = repro; + +int +main(int argc, char **argv) +{ + argc--; + that(0, argc); + + rb_check_type(argc, argc); + +} diff --git a/gcc/testsuite/gcc.dg/lto/pr101868_1.c b/gcc/testsuite/gcc.dg/lto/pr101868_1.c new file mode 100644 index 0000000..146c14a --- /dev/null +++ b/gcc/testsuite/gcc.dg/lto/pr101868_1.c @@ -0,0 +1,23 @@ +typedef unsigned long VALUE; + + +__attribute__ ((noreturn)) void rexc_raise(VALUE mesg); + +VALUE rb_donothing(VALUE klass); + +static void +funexpected_type(VALUE x, int xt, int t) +{ + rexc_raise(rb_donothing(0)); +} + +__attribute__ ((cold)) +void +rb_check_type(VALUE x, int t) +{ + int xt; + + if (x == 0) { + funexpected_type(x, xt, t); + } +} diff --git a/gcc/testsuite/gcc.dg/lto/pr101868_2.c b/gcc/testsuite/gcc.dg/lto/pr101868_2.c new file mode 100644 index 0000000..e6f01b2 --- /dev/null +++ b/gcc/testsuite/gcc.dg/lto/pr101868_2.c @@ -0,0 +1,11 @@ +typedef unsigned long VALUE; + +static void thing(void) {} +static void (*ptr)(void) = &thing; + +VALUE +rb_donothing(VALUE klass) +{ + ptr(); + return 0; +} diff --git a/gcc/testsuite/gcc.dg/lto/pr101868_3.c b/gcc/testsuite/gcc.dg/lto/pr101868_3.c new file mode 100644 index 0000000..6121762 --- /dev/null +++ b/gcc/testsuite/gcc.dg/lto/pr101868_3.c @@ -0,0 +1,8 @@ +typedef unsigned long VALUE; + +__attribute__((noreturn)) +void +rexc_raise(VALUE mesg) +{ + __builtin_exit(0); +} -- cgit v1.1 From 891bdbf2b0432b4aa3d3e76923617fcb4fd33cf6 Mon Sep 17 00:00:00 2001 From: Andrew MacLeod Date: Tue, 17 Aug 2021 10:50:56 +0200 Subject: Special case -TYPE_MIN_VALUE for flag_wrapv in operator_abs::op1_range. With flag_wrapv, -TYPE_MIN_VALUE = TYPE_MIN_VALUE which is unrepresentable. We currently special case this in the ABS folding routine, but are missing similar treatment in operator_abs::op1_range. Tested on x86-64 Linux. PR tree-optimization/101938 gcc/ChangeLog: * range-op.cc (operator_abs::op1_range): Special case -TYPE_MIN_VALUE for flag_wrapv. gcc/testsuite/ChangeLog: * gcc.dg/pr101938.c: New test. --- gcc/range-op.cc | 6 ++++++ gcc/testsuite/gcc.dg/pr101938.c | 28 ++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 gcc/testsuite/gcc.dg/pr101938.c (limited to 'gcc') diff --git a/gcc/range-op.cc b/gcc/range-op.cc index eb66e12..56eccf4 100644 --- a/gcc/range-op.cc +++ b/gcc/range-op.cc @@ -3642,6 +3642,12 @@ operator_abs::op1_range (irange &r, tree type, r.union_ (int_range<1> (type, -positives.upper_bound (i), -positives.lower_bound (i))); + // With flag_wrapv, -TYPE_MIN_VALUE = TYPE_MIN_VALUE which is + // unrepresentable. Add -TYPE_MIN_VALUE in this case. + wide_int min_value = wi::min_value (TYPE_PRECISION (type), TYPE_SIGN (type)); + wide_int lb = lhs.lower_bound (); + if (!TYPE_OVERFLOW_UNDEFINED (type) && wi::eq_p (lb, min_value)) + r.union_ (int_range<2> (type, lb, lb)); return true; } diff --git a/gcc/testsuite/gcc.dg/pr101938.c b/gcc/testsuite/gcc.dg/pr101938.c new file mode 100644 index 0000000..8277755 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr101938.c @@ -0,0 +1,28 @@ +// { dg-do run } +// { dg-require-effective-target lp64 } +// { dg-options "-O2 -fwrapv" } + +typedef long long int int64; +#define INT64CONST(x) (x##LL) +/* -9223372036854775808ULL */ +#define INT64_MIN (-INT64CONST(0x7FFFFFFFFFFFFFFF) - 1) + +static void __attribute__((noipa)) foo(int64 arg1, int64 arg2) { + int64 a1 = -arg1; + int64 a2 = (arg2 < 0) ? arg2 : -arg2; + + if (a1 > a2) { + int64 swap = arg1; + arg1 = arg2; + arg2 = swap; + } + + if (arg1 == INT64_MIN && arg2 == -1) return; + + __builtin_abort(); +} + +int main() { + foo(-1, INT64_MIN); + return 0; +} -- cgit v1.1 From 568b9c0e8ee482228f6c565730447de5b18e7cb3 Mon Sep 17 00:00:00 2001 From: Alistair Lee Date: Tue, 17 Aug 2021 10:49:35 +0100 Subject: aarch64: Replace some uses of GET_CODE with RTL predicate macros gcc/ 2021-08-17 Alistair_Lee * rtl.h (CONST_VECTOR_P): New macro. * config/aarch64/aarch64.c (aarch64_get_sve_pred_bits): Use RTL code testing macros. (aarch64_ptrue_all_mode): Likewise. (aarch64_expand_mov_immediate): Likewise. (aarch64_const_vec_all_in_range_p): Likewise. (aarch64_rtx_costs): Likewise. (aarch64_legitimate_constant_p): Likewise. (aarch64_simd_valid_immediate): Likewise. (aarch64_simd_make_constant): Likewise. (aarch64_convert_mult_to_shift): Likewise. (aarch64_expand_sve_vec_perm): Likewise. (aarch64_vec_fpconst_pow_of_2): Likewise. --- gcc/config/aarch64/aarch64.c | 28 ++++++++++++++-------------- gcc/rtl.h | 3 +++ 2 files changed, 17 insertions(+), 14 deletions(-) (limited to 'gcc') diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c index 4cd4b03..3213585 100644 --- a/gcc/config/aarch64/aarch64.c +++ b/gcc/config/aarch64/aarch64.c @@ -4174,7 +4174,7 @@ aarch64_force_temporary (machine_mode mode, rtx x, rtx value) static bool aarch64_get_sve_pred_bits (rtx_vector_builder &builder, rtx x) { - if (GET_CODE (x) != CONST_VECTOR) + if (!CONST_VECTOR_P (x)) return false; unsigned int factor = vector_element_size (GET_MODE_NUNITS (VNx16BImode), @@ -4230,7 +4230,7 @@ opt_machine_mode aarch64_ptrue_all_mode (rtx x) { gcc_assert (GET_MODE (x) == VNx16BImode); - if (GET_CODE (x) != CONST_VECTOR + if (!CONST_VECTOR_P (x) || !CONST_VECTOR_DUPLICATE_P (x) || !CONST_INT_P (CONST_VECTOR_ENCODED_ELT (x, 0)) || INTVAL (CONST_VECTOR_ENCODED_ELT (x, 0)) == 0) @@ -5930,7 +5930,7 @@ aarch64_expand_mov_immediate (rtx dest, rtx imm) return; } - if (GET_CODE (imm) == CONST_VECTOR && aarch64_sve_data_mode_p (mode)) + if (CONST_VECTOR_P (imm) && aarch64_sve_data_mode_p (mode)) if (rtx res = aarch64_expand_sve_const_vector (dest, imm)) { if (dest != res) @@ -10634,7 +10634,7 @@ aarch64_const_vec_all_in_range_p (rtx vec, HOST_WIDE_INT minval, HOST_WIDE_INT maxval) { - if (GET_CODE (vec) != CONST_VECTOR + if (!CONST_VECTOR_P (vec) || GET_MODE_CLASS (GET_MODE (vec)) != MODE_VECTOR_INT) return false; @@ -12771,7 +12771,7 @@ aarch64_rtx_costs (rtx x, machine_mode mode, int outer ATTRIBUTE_UNUSED, case SIGN_EXTRACT: /* Bit-field insertion. Strip any redundant widening of the RHS to meet the width of the target. */ - if (GET_CODE (op1) == SUBREG) + if (SUBREG_P (op1)) op1 = SUBREG_REG (op1); if ((GET_CODE (op1) == ZERO_EXTEND || GET_CODE (op1) == SIGN_EXTEND) @@ -13044,7 +13044,7 @@ aarch64_rtx_costs (rtx x, machine_mode mode, int outer ATTRIBUTE_UNUSED, But the integer MINUS logic expects the shift/extend operation in op1. */ if (! (REG_P (op0) - || (GET_CODE (op0) == SUBREG && REG_P (SUBREG_REG (op0))))) + || (SUBREG_P (op0) && REG_P (SUBREG_REG (op0))))) { op0 = XEXP (x, 1); op1 = XEXP (x, 0); @@ -18239,7 +18239,7 @@ aarch64_legitimate_constant_p (machine_mode mode, rtx x) /* Otherwise, accept any CONST_VECTOR that, if all else fails, can at least be forced to memory and loaded from there. */ - if (GET_CODE (x) == CONST_VECTOR) + if (CONST_VECTOR_P (x)) return !targetm.cannot_force_const_mem (mode, x); /* Do not allow vector struct mode constants for Advanced SIMD. @@ -20044,7 +20044,7 @@ aarch64_simd_valid_immediate (rtx op, simd_immediate_info *info, scalar_mode elt_mode = GET_MODE_INNER (mode); rtx base, step; unsigned int n_elts; - if (GET_CODE (op) == CONST_VECTOR + if (CONST_VECTOR_P (op) && CONST_VECTOR_DUPLICATE_P (op)) n_elts = CONST_VECTOR_NPATTERNS (op); else if ((vec_flags & VEC_SVE_DATA) @@ -20066,7 +20066,7 @@ aarch64_simd_valid_immediate (rtx op, simd_immediate_info *info, } return true; } - else if (GET_CODE (op) == CONST_VECTOR + else if (CONST_VECTOR_P (op) && CONST_VECTOR_NUNITS (op).is_constant (&n_elts)) /* N_ELTS set above. */; else @@ -20666,7 +20666,7 @@ aarch64_simd_make_constant (rtx vals) int n_const = 0; int i; - if (GET_CODE (vals) == CONST_VECTOR) + if (CONST_VECTOR_P (vals)) const_vec = vals; else if (GET_CODE (vals) == PARALLEL) { @@ -21207,7 +21207,7 @@ aarch64_sve_expand_vector_init (rtx target, rtx vals) static rtx aarch64_convert_mult_to_shift (rtx value, rtx_code &code) { - if (GET_CODE (value) != CONST_VECTOR) + if (!CONST_VECTOR_P (value)) return NULL_RTX; rtx_vector_builder builder; @@ -22371,7 +22371,7 @@ aarch64_expand_sve_vec_perm (rtx target, rtx op0, rtx op1, rtx sel) rtx sel_reg = force_reg (sel_mode, sel); /* Check if the sel only references the first values vector. */ - if (GET_CODE (sel) == CONST_VECTOR + if (CONST_VECTOR_P (sel) && aarch64_const_vec_all_in_range_p (sel, 0, nunits - 1)) { emit_unspec2 (target, UNSPEC_TBL, op0, sel_reg); @@ -22393,7 +22393,7 @@ aarch64_expand_sve_vec_perm (rtx target, rtx op0, rtx op1, rtx sel) rtx res0 = gen_reg_rtx (data_mode); rtx res1 = gen_reg_rtx (data_mode); rtx neg_num_elems = aarch64_simd_gen_const_vector_dup (sel_mode, -nunits); - if (GET_CODE (sel) != CONST_VECTOR + if (!CONST_VECTOR_P (sel) || !aarch64_const_vec_all_in_range_p (sel, 0, 2 * nunits - 1)) { rtx max_sel = aarch64_simd_gen_const_vector_dup (sel_mode, @@ -24925,7 +24925,7 @@ int aarch64_vec_fpconst_pow_of_2 (rtx x) { int nelts; - if (GET_CODE (x) != CONST_VECTOR + if (!CONST_VECTOR_P (x) || !CONST_VECTOR_NUNITS (x).is_constant (&nelts)) return -1; diff --git a/gcc/rtl.h b/gcc/rtl.h index 5fdcdfc..5473cc9 100644 --- a/gcc/rtl.h +++ b/gcc/rtl.h @@ -830,6 +830,9 @@ struct GTY(()) rtvec_def { #define CONST_DOUBLE_AS_FLOAT_P(X) \ (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) != VOIDmode) +/* Predicate yielding nonzero iff X is an rtx for a constant vector. */ +#define CONST_VECTOR_P(X) (GET_CODE (X) == CONST_VECTOR) + /* Predicate yielding nonzero iff X is a label insn. */ #define LABEL_P(X) (GET_CODE (X) == CODE_LABEL) -- cgit v1.1 From 6d527883072ce96a33169036fca7740172223b52 Mon Sep 17 00:00:00 2001 From: Maxim Kuvyrkov Date: Thu, 29 Aug 2019 15:21:36 +0000 Subject: Improve autoprefetcher heuristic (partly fix regression in PR91598) PR rtl-optimization/91598 * haifa-sched.c (autopref_rank_for_schedule): Prioritize "irrelevant" insns after memory reads and before memory writes. --- gcc/haifa-sched.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/haifa-sched.c b/gcc/haifa-sched.c index 26d1127..5048dd4 100644 --- a/gcc/haifa-sched.c +++ b/gcc/haifa-sched.c @@ -5683,9 +5683,16 @@ autopref_rank_for_schedule (const rtx_insn *insn1, const rtx_insn *insn2) int irrel2 = data2->status == AUTOPREF_MULTIPASS_DATA_IRRELEVANT; if (!irrel1 && !irrel2) + /* Sort memory references from lowest offset to the largest. */ r = data1->offset - data2->offset; - else + else if (write) + /* Schedule "irrelevant" insns before memory stores to resolve + as many producer dependencies of stores as possible. */ r = irrel2 - irrel1; + else + /* Schedule "irrelevant" insns after memory reads to avoid breaking + memory read sequences. */ + r = irrel1 - irrel2; } return r; -- cgit v1.1 From 75b1c753133162cc15cd705825315767e63f071e Mon Sep 17 00:00:00 2001 From: Maxim Kuvyrkov Date: Thu, 29 Aug 2019 15:24:37 +0000 Subject: Add missing entry for rank_for_schedule stats. * haifa-sched.c (enum rfs_decision, rfs_str): Add RFS_AUTOPREF. (rank_for_schedule): Use it. --- gcc/haifa-sched.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'gcc') diff --git a/gcc/haifa-sched.c b/gcc/haifa-sched.c index 5048dd4..dac27fd 100644 --- a/gcc/haifa-sched.c +++ b/gcc/haifa-sched.c @@ -2538,7 +2538,7 @@ model_set_excess_costs (rtx_insn **insns, int count) enum rfs_decision { RFS_LIVE_RANGE_SHRINK1, RFS_LIVE_RANGE_SHRINK2, RFS_SCHED_GROUP, RFS_PRESSURE_DELAY, RFS_PRESSURE_TICK, - RFS_FEEDS_BACKTRACK_INSN, RFS_PRIORITY, RFS_SPECULATION, + RFS_FEEDS_BACKTRACK_INSN, RFS_PRIORITY, RFS_AUTOPREF, RFS_SPECULATION, RFS_SCHED_RANK, RFS_LAST_INSN, RFS_PRESSURE_INDEX, RFS_DEP_COUNT, RFS_TIE, RFS_FUSION, RFS_COST, RFS_N }; @@ -2546,7 +2546,7 @@ enum rfs_decision { static const char *rfs_str[RFS_N] = { "RFS_LIVE_RANGE_SHRINK1", "RFS_LIVE_RANGE_SHRINK2", "RFS_SCHED_GROUP", "RFS_PRESSURE_DELAY", "RFS_PRESSURE_TICK", - "RFS_FEEDS_BACKTRACK_INSN", "RFS_PRIORITY", "RFS_SPECULATION", + "RFS_FEEDS_BACKTRACK_INSN", "RFS_PRIORITY", "RFS_AUTOPREF", "RFS_SPECULATION", "RFS_SCHED_RANK", "RFS_LAST_INSN", "RFS_PRESSURE_INDEX", "RFS_DEP_COUNT", "RFS_TIE", "RFS_FUSION", "RFS_COST" }; @@ -2715,7 +2715,7 @@ rank_for_schedule (const void *x, const void *y) { int autopref = autopref_rank_for_schedule (tmp, tmp2); if (autopref != 0) - return autopref; + return rfs_result (RFS_AUTOPREF, autopref, tmp, tmp2); } /* Prefer speculative insn with greater dependencies weakness. */ -- cgit v1.1 From 92aadbd593c1aef6798e7a64b8f7a91fed32aa68 Mon Sep 17 00:00:00 2001 From: Maxim Kuvyrkov Date: Thu, 29 Aug 2019 15:27:30 +0000 Subject: Improve diff-ability of scheduler logs * haifa-sched.c (advance_one_cycle): Output more context-synchronization lines for diff. --- gcc/haifa-sched.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'gcc') diff --git a/gcc/haifa-sched.c b/gcc/haifa-sched.c index dac27fd..e14051f 100644 --- a/gcc/haifa-sched.c +++ b/gcc/haifa-sched.c @@ -3155,9 +3155,11 @@ advance_state (state_t state) HAIFA_INLINE static void advance_one_cycle (void) { + int i; + advance_state (curr_state); - if (sched_verbose >= 4) - fprintf (sched_dump, ";;\tAdvance the current state.\n"); + for (i = 4; i <= sched_verbose; ++i) + fprintf (sched_dump, ";;\tAdvance the current state: %d.\n", clock_var); } /* Update register pressure after scheduling INSN. */ -- cgit v1.1 From 5ed35a9874ba8c3aa2bbbd720e46783db264b684 Mon Sep 17 00:00:00 2001 From: Jonathan Wright Date: Thu, 12 Aug 2021 12:27:15 +0100 Subject: aarch64: Remove macros for vld2[q]_lane Neon intrinsics Remove macros for vld2[q]_lane Neon intrinsics. This is a preparatory step before adding new modes for structures of Advanced SIMD vectors. gcc/ChangeLog: 2021-08-12 Jonathan Wright * config/aarch64/arm_neon.h (__LD2_LANE_FUNC): Delete. (__LD2Q_LANE_FUNC): Likewise. (vld2_lane_u8): Define without macro. (vld2_lane_u16): Likewise. (vld2_lane_u32): Likewise. (vld2_lane_u64): Likewise. (vld2_lane_s8): Likewise. (vld2_lane_s16): Likewise. (vld2_lane_s32): Likewise. (vld2_lane_s64): Likewise. (vld2_lane_f16): Likewise. (vld2_lane_f32): Likewise. (vld2_lane_f64): Likewise. (vld2_lane_p8): Likewise. (vld2_lane_p16): Likewise. (vld2_lane_p64): Likewise. (vld2q_lane_u8): Likewise. (vld2q_lane_u16): Likewise. (vld2q_lane_u32): Likewise. (vld2q_lane_u64): Likewise. (vld2q_lane_s8): Likewise. (vld2q_lane_s16): Likewise. (vld2q_lane_s32): Likewise. (vld2q_lane_s64): Likewise. (vld2q_lane_f16): Likewise. (vld2q_lane_f32): Likewise. (vld2q_lane_f64): Likewise. (vld2q_lane_p8): Likewise. (vld2q_lane_p16): Likewise. (vld2q_lane_p64): Likewise. (vld2_lane_bf16): Likewise. (vld2q_lane_bf16): Likewise. --- gcc/config/aarch64/arm_neon.h | 558 +++++++++++++++++++++++++++++++++++------- 1 file changed, 474 insertions(+), 84 deletions(-) (limited to 'gcc') diff --git a/gcc/config/aarch64/arm_neon.h b/gcc/config/aarch64/arm_neon.h index 390cf9a..91c072f 100644 --- a/gcc/config/aarch64/arm_neon.h +++ b/gcc/config/aarch64/arm_neon.h @@ -19882,92 +19882,455 @@ vld4q_dup_p64 (const poly64_t * __a) /* vld2_lane */ -#define __LD2_LANE_FUNC(intype, vectype, largetype, ptrtype, mode, \ - qmode, ptrmode, funcsuffix, signedtype) \ -__extension__ extern __inline intype \ -__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) \ -vld2_lane_##funcsuffix (const ptrtype * __ptr, intype __b, const int __c) \ -{ \ - __builtin_aarch64_simd_oi __o; \ - largetype __temp; \ - __temp.val[0] = \ - vcombine_##funcsuffix (__b.val[0], vcreate_##funcsuffix (0)); \ - __temp.val[1] = \ - vcombine_##funcsuffix (__b.val[1], vcreate_##funcsuffix (0)); \ - __o = __builtin_aarch64_set_qregoi##qmode (__o, \ - (signedtype) __temp.val[0], \ - 0); \ - __o = __builtin_aarch64_set_qregoi##qmode (__o, \ - (signedtype) __temp.val[1], \ - 1); \ - __o = __builtin_aarch64_ld2_lane##mode ( \ - (__builtin_aarch64_simd_##ptrmode *) __ptr, __o, __c); \ - __b.val[0] = (vectype) __builtin_aarch64_get_dregoidi (__o, 0); \ - __b.val[1] = (vectype) __builtin_aarch64_get_dregoidi (__o, 1); \ - return __b; \ +__extension__ extern __inline uint8x8x2_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld2_lane_u8 (const uint8_t * __ptr, uint8x8x2_t __b, const int __c) +{ + __builtin_aarch64_simd_oi __o; + uint8x16x2_t __temp; + __temp.val[0] = vcombine_u8 (__b.val[0], vcreate_u8 (0)); + __temp.val[1] = vcombine_u8 (__b.val[1], vcreate_u8 (0)); + __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t) __temp.val[1], 1); + __o = __builtin_aarch64_ld2_lanev8qi ( + (__builtin_aarch64_simd_qi *) __ptr, __o, __c); + __b.val[0] = (uint8x8_t) __builtin_aarch64_get_dregoidi (__o, 0); + __b.val[1] = (uint8x8_t) __builtin_aarch64_get_dregoidi (__o, 1); + return __b; } -__LD2_LANE_FUNC (float16x4x2_t, float16x4_t, float16x8x2_t, float16_t, v4hf, - v8hf, hf, f16, float16x8_t) -__LD2_LANE_FUNC (float32x2x2_t, float32x2_t, float32x4x2_t, float32_t, v2sf, v4sf, - sf, f32, float32x4_t) -__LD2_LANE_FUNC (float64x1x2_t, float64x1_t, float64x2x2_t, float64_t, df, v2df, - df, f64, float64x2_t) -__LD2_LANE_FUNC (poly8x8x2_t, poly8x8_t, poly8x16x2_t, poly8_t, v8qi, v16qi, qi, p8, - int8x16_t) -__LD2_LANE_FUNC (poly16x4x2_t, poly16x4_t, poly16x8x2_t, poly16_t, v4hi, v8hi, hi, - p16, int16x8_t) -__LD2_LANE_FUNC (poly64x1x2_t, poly64x1_t, poly64x2x2_t, poly64_t, di, - v2di_ssps, di, p64, poly64x2_t) -__LD2_LANE_FUNC (int8x8x2_t, int8x8_t, int8x16x2_t, int8_t, v8qi, v16qi, qi, s8, - int8x16_t) -__LD2_LANE_FUNC (int16x4x2_t, int16x4_t, int16x8x2_t, int16_t, v4hi, v8hi, hi, s16, - int16x8_t) -__LD2_LANE_FUNC (int32x2x2_t, int32x2_t, int32x4x2_t, int32_t, v2si, v4si, si, s32, - int32x4_t) -__LD2_LANE_FUNC (int64x1x2_t, int64x1_t, int64x2x2_t, int64_t, di, v2di, di, s64, - int64x2_t) -__LD2_LANE_FUNC (uint8x8x2_t, uint8x8_t, uint8x16x2_t, uint8_t, v8qi, v16qi, qi, u8, - int8x16_t) -__LD2_LANE_FUNC (uint16x4x2_t, uint16x4_t, uint16x8x2_t, uint16_t, v4hi, v8hi, hi, - u16, int16x8_t) -__LD2_LANE_FUNC (uint32x2x2_t, uint32x2_t, uint32x4x2_t, uint32_t, v2si, v4si, si, - u32, int32x4_t) -__LD2_LANE_FUNC (uint64x1x2_t, uint64x1_t, uint64x2x2_t, uint64_t, di, v2di, di, - u64, int64x2_t) +__extension__ extern __inline uint16x4x2_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld2_lane_u16 (const uint16_t * __ptr, uint16x4x2_t __b, const int __c) +{ + __builtin_aarch64_simd_oi __o; + uint16x8x2_t __temp; + __temp.val[0] = vcombine_u16 (__b.val[0], vcreate_u16 (0)); + __temp.val[1] = vcombine_u16 (__b.val[1], vcreate_u16 (0)); + __o = __builtin_aarch64_set_qregoiv8hi (__o, (int16x8_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregoiv8hi (__o, (int16x8_t) __temp.val[1], 1); + __o = __builtin_aarch64_ld2_lanev4hi ( + (__builtin_aarch64_simd_hi *) __ptr, __o, __c); + __b.val[0] = (uint16x4_t) __builtin_aarch64_get_dregoidi (__o, 0); + __b.val[1] = (uint16x4_t) __builtin_aarch64_get_dregoidi (__o, 1); + return __b; +} + +__extension__ extern __inline uint32x2x2_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld2_lane_u32 (const uint32_t * __ptr, uint32x2x2_t __b, const int __c) +{ + __builtin_aarch64_simd_oi __o; + uint32x4x2_t __temp; + __temp.val[0] = vcombine_u32 (__b.val[0], vcreate_u32 (0)); + __temp.val[1] = vcombine_u32 (__b.val[1], vcreate_u32 (0)); + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __temp.val[1], 1); + __o = __builtin_aarch64_ld2_lanev2si ( + (__builtin_aarch64_simd_si *) __ptr, __o, __c); + __b.val[0] = (uint32x2_t) __builtin_aarch64_get_dregoidi (__o, 0); + __b.val[1] = (uint32x2_t) __builtin_aarch64_get_dregoidi (__o, 1); + return __b; +} + +__extension__ extern __inline uint64x1x2_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld2_lane_u64 (const uint64_t * __ptr, uint64x1x2_t __b, const int __c) +{ + __builtin_aarch64_simd_oi __o; + uint64x2x2_t __temp; + __temp.val[0] = vcombine_u64 (__b.val[0], vcreate_u64 (0)); + __temp.val[1] = vcombine_u64 (__b.val[1], vcreate_u64 (0)); + __o = __builtin_aarch64_set_qregoiv2di (__o, (int64x2_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregoiv2di (__o, (int64x2_t) __temp.val[1], 1); + __o = __builtin_aarch64_ld2_lanedi ( + (__builtin_aarch64_simd_di *) __ptr, __o, __c); + __b.val[0] = (uint64x1_t) __builtin_aarch64_get_dregoidi (__o, 0); + __b.val[1] = (uint64x1_t) __builtin_aarch64_get_dregoidi (__o, 1); + return __b; +} + +__extension__ extern __inline int8x8x2_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld2_lane_s8 (const int8_t * __ptr, int8x8x2_t __b, const int __c) +{ + __builtin_aarch64_simd_oi __o; + int8x16x2_t __temp; + __temp.val[0] = vcombine_s8 (__b.val[0], vcreate_s8 (0)); + __temp.val[1] = vcombine_s8 (__b.val[1], vcreate_s8 (0)); + __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t) __temp.val[1], 1); + __o = __builtin_aarch64_ld2_lanev8qi ( + (__builtin_aarch64_simd_qi *) __ptr, __o, __c); + __b.val[0] = (int8x8_t) __builtin_aarch64_get_dregoidi (__o, 0); + __b.val[1] = (int8x8_t) __builtin_aarch64_get_dregoidi (__o, 1); + return __b; +} + +__extension__ extern __inline int16x4x2_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld2_lane_s16 (const int16_t * __ptr, int16x4x2_t __b, const int __c) +{ + __builtin_aarch64_simd_oi __o; + int16x8x2_t __temp; + __temp.val[0] = vcombine_s16 (__b.val[0], vcreate_s16 (0)); + __temp.val[1] = vcombine_s16 (__b.val[1], vcreate_s16 (0)); + __o = __builtin_aarch64_set_qregoiv8hi (__o, (int16x8_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregoiv8hi (__o, (int16x8_t) __temp.val[1], 1); + __o = __builtin_aarch64_ld2_lanev4hi ( + (__builtin_aarch64_simd_hi *) __ptr, __o, __c); + __b.val[0] = (int16x4_t) __builtin_aarch64_get_dregoidi (__o, 0); + __b.val[1] = (int16x4_t) __builtin_aarch64_get_dregoidi (__o, 1); + return __b; +} + +__extension__ extern __inline int32x2x2_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld2_lane_s32 (const int32_t * __ptr, int32x2x2_t __b, const int __c) +{ + __builtin_aarch64_simd_oi __o; + int32x4x2_t __temp; + __temp.val[0] = vcombine_s32 (__b.val[0], vcreate_s32 (0)); + __temp.val[1] = vcombine_s32 (__b.val[1], vcreate_s32 (0)); + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __temp.val[1], 1); + __o = __builtin_aarch64_ld2_lanev2si ( + (__builtin_aarch64_simd_si *) __ptr, __o, __c); + __b.val[0] = (int32x2_t) __builtin_aarch64_get_dregoidi (__o, 0); + __b.val[1] = (int32x2_t) __builtin_aarch64_get_dregoidi (__o, 1); + return __b; +} + +__extension__ extern __inline int64x1x2_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld2_lane_s64 (const int64_t * __ptr, int64x1x2_t __b, const int __c) +{ + __builtin_aarch64_simd_oi __o; + int64x2x2_t __temp; + __temp.val[0] = vcombine_s64 (__b.val[0], vcreate_s64 (0)); + __temp.val[1] = vcombine_s64 (__b.val[1], vcreate_s64 (0)); + __o = __builtin_aarch64_set_qregoiv2di (__o, (int64x2_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregoiv2di (__o, (int64x2_t) __temp.val[1], 1); + __o = __builtin_aarch64_ld2_lanedi ( + (__builtin_aarch64_simd_di *) __ptr, __o, __c); + __b.val[0] = (int64x1_t) __builtin_aarch64_get_dregoidi (__o, 0); + __b.val[1] = (int64x1_t) __builtin_aarch64_get_dregoidi (__o, 1); + return __b; +} + +__extension__ extern __inline float16x4x2_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld2_lane_f16 (const float16_t * __ptr, float16x4x2_t __b, const int __c) +{ + __builtin_aarch64_simd_oi __o; + float16x8x2_t __temp; + __temp.val[0] = vcombine_f16 (__b.val[0], vcreate_f16 (0)); + __temp.val[1] = vcombine_f16 (__b.val[1], vcreate_f16 (0)); + __o = __builtin_aarch64_set_qregoiv8hf (__o, (float16x8_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregoiv8hf (__o, (float16x8_t) __temp.val[1], 1); + __o = __builtin_aarch64_ld2_lanev4hf ( + (__builtin_aarch64_simd_hf *) __ptr, __o, __c); + __b.val[0] = (float16x4_t) __builtin_aarch64_get_dregoidi (__o, 0); + __b.val[1] = (float16x4_t) __builtin_aarch64_get_dregoidi (__o, 1); + return __b; +} + +__extension__ extern __inline float32x2x2_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld2_lane_f32 (const float32_t * __ptr, float32x2x2_t __b, const int __c) +{ + __builtin_aarch64_simd_oi __o; + float32x4x2_t __temp; + __temp.val[0] = vcombine_f32 (__b.val[0], vcreate_f32 (0)); + __temp.val[1] = vcombine_f32 (__b.val[1], vcreate_f32 (0)); + __o = __builtin_aarch64_set_qregoiv4sf (__o, (float32x4_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregoiv4sf (__o, (float32x4_t) __temp.val[1], 1); + __o = __builtin_aarch64_ld2_lanev2sf ( + (__builtin_aarch64_simd_sf *) __ptr, __o, __c); + __b.val[0] = (float32x2_t) __builtin_aarch64_get_dregoidi (__o, 0); + __b.val[1] = (float32x2_t) __builtin_aarch64_get_dregoidi (__o, 1); + return __b; +} + +__extension__ extern __inline float64x1x2_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld2_lane_f64 (const float64_t * __ptr, float64x1x2_t __b, const int __c) +{ + __builtin_aarch64_simd_oi __o; + float64x2x2_t __temp; + __temp.val[0] = vcombine_f64 (__b.val[0], vcreate_f64 (0)); + __temp.val[1] = vcombine_f64 (__b.val[1], vcreate_f64 (0)); + __o = __builtin_aarch64_set_qregoiv2df (__o, (float64x2_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregoiv2df (__o, (float64x2_t) __temp.val[1], 1); + __o = __builtin_aarch64_ld2_lanedf ( + (__builtin_aarch64_simd_df *) __ptr, __o, __c); + __b.val[0] = (float64x1_t) __builtin_aarch64_get_dregoidi (__o, 0); + __b.val[1] = (float64x1_t) __builtin_aarch64_get_dregoidi (__o, 1); + return __b; +} + +__extension__ extern __inline poly8x8x2_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld2_lane_p8 (const poly8_t * __ptr, poly8x8x2_t __b, const int __c) +{ + __builtin_aarch64_simd_oi __o; + poly8x16x2_t __temp; + __temp.val[0] = vcombine_p8 (__b.val[0], vcreate_p8 (0)); + __temp.val[1] = vcombine_p8 (__b.val[1], vcreate_p8 (0)); + __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregoiv16qi (__o, (int8x16_t) __temp.val[1], 1); + __o = __builtin_aarch64_ld2_lanev8qi ( + (__builtin_aarch64_simd_qi *) __ptr, __o, __c); + __b.val[0] = (poly8x8_t) __builtin_aarch64_get_dregoidi (__o, 0); + __b.val[1] = (poly8x8_t) __builtin_aarch64_get_dregoidi (__o, 1); + return __b; +} + +__extension__ extern __inline poly16x4x2_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld2_lane_p16 (const poly16_t * __ptr, poly16x4x2_t __b, const int __c) +{ + __builtin_aarch64_simd_oi __o; + poly16x8x2_t __temp; + __temp.val[0] = vcombine_p16 (__b.val[0], vcreate_p16 (0)); + __temp.val[1] = vcombine_p16 (__b.val[1], vcreate_p16 (0)); + __o = __builtin_aarch64_set_qregoiv8hi (__o, (int16x8_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregoiv8hi (__o, (int16x8_t) __temp.val[1], 1); + __o = __builtin_aarch64_ld2_lanev4hi ( + (__builtin_aarch64_simd_hi *) __ptr, __o, __c); + __b.val[0] = (poly16x4_t) __builtin_aarch64_get_dregoidi (__o, 0); + __b.val[1] = (poly16x4_t) __builtin_aarch64_get_dregoidi (__o, 1); + return __b; +} + +__extension__ extern __inline poly64x1x2_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld2_lane_p64 (const poly64_t * __ptr, poly64x1x2_t __b, const int __c) +{ + __builtin_aarch64_simd_oi __o; + poly64x2x2_t __temp; + __temp.val[0] = vcombine_p64 (__b.val[0], vcreate_p64 (0)); + __temp.val[1] = vcombine_p64 (__b.val[1], vcreate_p64 (0)); + __o = __builtin_aarch64_set_qregoiv2di (__o, (int64x2_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregoiv2di (__o, (int64x2_t) __temp.val[1], 1); + __o = __builtin_aarch64_ld2_lanedi ( + (__builtin_aarch64_simd_di *) __ptr, __o, __c); + __b.val[0] = (poly64x1_t) __builtin_aarch64_get_dregoidi (__o, 0); + __b.val[1] = (poly64x1_t) __builtin_aarch64_get_dregoidi (__o, 1); + return __b; +} /* vld2q_lane */ -#define __LD2Q_LANE_FUNC(intype, vtype, ptrtype, mode, ptrmode, funcsuffix) \ -__extension__ extern __inline intype \ -__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) \ -vld2q_lane_##funcsuffix (const ptrtype * __ptr, intype __b, const int __c) \ -{ \ - __builtin_aarch64_simd_oi __o; \ - intype ret; \ - __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __b.val[0], 0); \ - __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __b.val[1], 1); \ - __o = __builtin_aarch64_ld2_lane##mode ( \ - (__builtin_aarch64_simd_##ptrmode *) __ptr, __o, __c); \ - ret.val[0] = (vtype) __builtin_aarch64_get_qregoiv4si (__o, 0); \ - ret.val[1] = (vtype) __builtin_aarch64_get_qregoiv4si (__o, 1); \ - return ret; \ +__extension__ extern __inline uint8x16x2_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld2q_lane_u8 (const uint8_t * __ptr, uint8x16x2_t __b, const int __c) +{ + __builtin_aarch64_simd_oi __o; + uint8x16x2_t ret; + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_ld2_lanev16qi ( + (__builtin_aarch64_simd_qi *) __ptr, __o, __c); + ret.val[0] = (uint8x16_t) __builtin_aarch64_get_qregoiv4si (__o, 0); + ret.val[1] = (uint8x16_t) __builtin_aarch64_get_qregoiv4si (__o, 1); + return ret; } -__LD2Q_LANE_FUNC (float16x8x2_t, float16x8_t, float16_t, v8hf, hf, f16) -__LD2Q_LANE_FUNC (float32x4x2_t, float32x4_t, float32_t, v4sf, sf, f32) -__LD2Q_LANE_FUNC (float64x2x2_t, float64x2_t, float64_t, v2df, df, f64) -__LD2Q_LANE_FUNC (poly8x16x2_t, poly8x16_t, poly8_t, v16qi, qi, p8) -__LD2Q_LANE_FUNC (poly16x8x2_t, poly16x8_t, poly16_t, v8hi, hi, p16) -__LD2Q_LANE_FUNC (poly64x2x2_t, poly64x2_t, poly64_t, v2di, di, p64) -__LD2Q_LANE_FUNC (int8x16x2_t, int8x16_t, int8_t, v16qi, qi, s8) -__LD2Q_LANE_FUNC (int16x8x2_t, int16x8_t, int16_t, v8hi, hi, s16) -__LD2Q_LANE_FUNC (int32x4x2_t, int32x4_t, int32_t, v4si, si, s32) -__LD2Q_LANE_FUNC (int64x2x2_t, int64x2_t, int64_t, v2di, di, s64) -__LD2Q_LANE_FUNC (uint8x16x2_t, uint8x16_t, uint8_t, v16qi, qi, u8) -__LD2Q_LANE_FUNC (uint16x8x2_t, uint16x8_t, uint16_t, v8hi, hi, u16) -__LD2Q_LANE_FUNC (uint32x4x2_t, uint32x4_t, uint32_t, v4si, si, u32) -__LD2Q_LANE_FUNC (uint64x2x2_t, uint64x2_t, uint64_t, v2di, di, u64) +__extension__ extern __inline uint16x8x2_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld2q_lane_u16 (const uint16_t * __ptr, uint16x8x2_t __b, const int __c) +{ + __builtin_aarch64_simd_oi __o; + uint16x8x2_t ret; + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_ld2_lanev8hi ( + (__builtin_aarch64_simd_hi *) __ptr, __o, __c); + ret.val[0] = (uint16x8_t) __builtin_aarch64_get_qregoiv4si (__o, 0); + ret.val[1] = (uint16x8_t) __builtin_aarch64_get_qregoiv4si (__o, 1); + return ret; +} + +__extension__ extern __inline uint32x4x2_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld2q_lane_u32 (const uint32_t * __ptr, uint32x4x2_t __b, const int __c) +{ + __builtin_aarch64_simd_oi __o; + uint32x4x2_t ret; + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_ld2_lanev4si ( + (__builtin_aarch64_simd_si *) __ptr, __o, __c); + ret.val[0] = (uint32x4_t) __builtin_aarch64_get_qregoiv4si (__o, 0); + ret.val[1] = (uint32x4_t) __builtin_aarch64_get_qregoiv4si (__o, 1); + return ret; +} + +__extension__ extern __inline uint64x2x2_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld2q_lane_u64 (const uint64_t * __ptr, uint64x2x2_t __b, const int __c) +{ + __builtin_aarch64_simd_oi __o; + uint64x2x2_t ret; + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_ld2_lanev2di ( + (__builtin_aarch64_simd_di *) __ptr, __o, __c); + ret.val[0] = (uint64x2_t) __builtin_aarch64_get_qregoiv4si (__o, 0); + ret.val[1] = (uint64x2_t) __builtin_aarch64_get_qregoiv4si (__o, 1); + return ret; +} + +__extension__ extern __inline int8x16x2_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld2q_lane_s8 (const int8_t * __ptr, int8x16x2_t __b, const int __c) +{ + __builtin_aarch64_simd_oi __o; + int8x16x2_t ret; + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_ld2_lanev16qi ( + (__builtin_aarch64_simd_qi *) __ptr, __o, __c); + ret.val[0] = (int8x16_t) __builtin_aarch64_get_qregoiv4si (__o, 0); + ret.val[1] = (int8x16_t) __builtin_aarch64_get_qregoiv4si (__o, 1); + return ret; +} + +__extension__ extern __inline int16x8x2_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld2q_lane_s16 (const int16_t * __ptr, int16x8x2_t __b, const int __c) +{ + __builtin_aarch64_simd_oi __o; + int16x8x2_t ret; + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_ld2_lanev8hi ( + (__builtin_aarch64_simd_hi *) __ptr, __o, __c); + ret.val[0] = (int16x8_t) __builtin_aarch64_get_qregoiv4si (__o, 0); + ret.val[1] = (int16x8_t) __builtin_aarch64_get_qregoiv4si (__o, 1); + return ret; +} + +__extension__ extern __inline int32x4x2_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld2q_lane_s32 (const int32_t * __ptr, int32x4x2_t __b, const int __c) +{ + __builtin_aarch64_simd_oi __o; + int32x4x2_t ret; + __o = __builtin_aarch64_set_qregoiv4si (__o, __b.val[0], 0); + __o = __builtin_aarch64_set_qregoiv4si (__o, __b.val[1], 1); + __o = __builtin_aarch64_ld2_lanev4si ( + (__builtin_aarch64_simd_si *) __ptr, __o, __c); + ret.val[0] = __builtin_aarch64_get_qregoiv4si (__o, 0); + ret.val[1] = __builtin_aarch64_get_qregoiv4si (__o, 1); + return ret; +} + +__extension__ extern __inline int64x2x2_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld2q_lane_s64 (const int64_t * __ptr, int64x2x2_t __b, const int __c) +{ + __builtin_aarch64_simd_oi __o; + int64x2x2_t ret; + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_ld2_lanev2di ( + (__builtin_aarch64_simd_di *) __ptr, __o, __c); + ret.val[0] = (int64x2_t) __builtin_aarch64_get_qregoiv4si (__o, 0); + ret.val[1] = (int64x2_t) __builtin_aarch64_get_qregoiv4si (__o, 1); + return ret; +} + +__extension__ extern __inline float16x8x2_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld2q_lane_f16 (const float16_t * __ptr, float16x8x2_t __b, const int __c) +{ + __builtin_aarch64_simd_oi __o; + float16x8x2_t ret; + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_ld2_lanev8hf ( + (__builtin_aarch64_simd_hf *) __ptr, __o, __c); + ret.val[0] = (float16x8_t) __builtin_aarch64_get_qregoiv4si (__o, 0); + ret.val[1] = (float16x8_t) __builtin_aarch64_get_qregoiv4si (__o, 1); + return ret; +} + +__extension__ extern __inline float32x4x2_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld2q_lane_f32 (const float32_t * __ptr, float32x4x2_t __b, const int __c) +{ + __builtin_aarch64_simd_oi __o; + float32x4x2_t ret; + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_ld2_lanev4sf ( + (__builtin_aarch64_simd_sf *) __ptr, __o, __c); + ret.val[0] = (float32x4_t) __builtin_aarch64_get_qregoiv4si (__o, 0); + ret.val[1] = (float32x4_t) __builtin_aarch64_get_qregoiv4si (__o, 1); + return ret; +} + +__extension__ extern __inline float64x2x2_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld2q_lane_f64 (const float64_t * __ptr, float64x2x2_t __b, const int __c) +{ + __builtin_aarch64_simd_oi __o; + float64x2x2_t ret; + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_ld2_lanev2df ( + (__builtin_aarch64_simd_df *) __ptr, __o, __c); + ret.val[0] = (float64x2_t) __builtin_aarch64_get_qregoiv4si (__o, 0); + ret.val[1] = (float64x2_t) __builtin_aarch64_get_qregoiv4si (__o, 1); + return ret; +} + +__extension__ extern __inline poly8x16x2_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld2q_lane_p8 (const poly8_t * __ptr, poly8x16x2_t __b, const int __c) +{ + __builtin_aarch64_simd_oi __o; + poly8x16x2_t ret; + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_ld2_lanev16qi ( + (__builtin_aarch64_simd_qi *) __ptr, __o, __c); + ret.val[0] = (poly8x16_t) __builtin_aarch64_get_qregoiv4si (__o, 0); + ret.val[1] = (poly8x16_t) __builtin_aarch64_get_qregoiv4si (__o, 1); + return ret; +} + +__extension__ extern __inline poly16x8x2_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld2q_lane_p16 (const poly16_t * __ptr, poly16x8x2_t __b, const int __c) +{ + __builtin_aarch64_simd_oi __o; + poly16x8x2_t ret; + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_ld2_lanev8hi ( + (__builtin_aarch64_simd_hi *) __ptr, __o, __c); + ret.val[0] = (poly16x8_t) __builtin_aarch64_get_qregoiv4si (__o, 0); + ret.val[1] = (poly16x8_t) __builtin_aarch64_get_qregoiv4si (__o, 1); + return ret; +} + +__extension__ extern __inline poly64x2x2_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld2q_lane_p64 (const poly64_t * __ptr, poly64x2x2_t __b, const int __c) +{ + __builtin_aarch64_simd_oi __o; + poly64x2x2_t ret; + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_ld2_lanev2di ( + (__builtin_aarch64_simd_di *) __ptr, __o, __c); + ret.val[0] = (poly64x2_t) __builtin_aarch64_get_qregoiv4si (__o, 0); + ret.val[1] = (poly64x2_t) __builtin_aarch64_get_qregoiv4si (__o, 1); + return ret; +} /* vld3_lane */ @@ -34584,9 +34947,38 @@ vcopyq_laneq_bf16 (bfloat16x8_t __a, const int __lane1, __a, __lane1); } -__LD2_LANE_FUNC (bfloat16x4x2_t, bfloat16x4_t, bfloat16x8x2_t, bfloat16_t, v4bf, - v8bf, bf, bf16, bfloat16x8_t) -__LD2Q_LANE_FUNC (bfloat16x8x2_t, bfloat16x8_t, bfloat16_t, v8bf, bf, bf16) +__extension__ extern __inline bfloat16x4x2_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld2_lane_bf16 (const bfloat16_t * __ptr, bfloat16x4x2_t __b, const int __c) +{ + __builtin_aarch64_simd_oi __o; + bfloat16x8x2_t __temp; + __temp.val[0] = vcombine_bf16 (__b.val[0], vcreate_bf16 (0)); + __temp.val[1] = vcombine_bf16 (__b.val[1], vcreate_bf16 (0)); + __o = __builtin_aarch64_set_qregoiv8bf (__o, (bfloat16x8_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregoiv8bf (__o, (bfloat16x8_t) __temp.val[1], 1); + __o = __builtin_aarch64_ld2_lanev4bf ( + (__builtin_aarch64_simd_bf *) __ptr, __o, __c); + __b.val[0] = (bfloat16x4_t) __builtin_aarch64_get_dregoidi (__o, 0); + __b.val[1] = (bfloat16x4_t) __builtin_aarch64_get_dregoidi (__o, 1); + return __b; +} + +__extension__ extern __inline bfloat16x8x2_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld2q_lane_bf16 (const bfloat16_t * __ptr, bfloat16x8x2_t __b, const int __c) +{ + __builtin_aarch64_simd_oi __o; + bfloat16x8x2_t ret; + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregoiv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_ld2_lanev8bf ( + (__builtin_aarch64_simd_bf *) __ptr, __o, __c); + ret.val[0] = (bfloat16x8_t) __builtin_aarch64_get_qregoiv4si (__o, 0); + ret.val[1] = (bfloat16x8_t) __builtin_aarch64_get_qregoiv4si (__o, 1); + return ret; +} + __LD3_LANE_FUNC (bfloat16x4x3_t, bfloat16x4_t, bfloat16x8x3_t, bfloat16_t, v4bf, v8bf, bf, bf16, bfloat16x8_t) __LD3Q_LANE_FUNC (bfloat16x8x3_t, bfloat16x8_t, bfloat16_t, v8bf, bf, bf16) @@ -34888,8 +35280,6 @@ vaddq_p128 (poly128_t __a, poly128_t __b) #undef __aarch64_vdupq_laneq_u32 #undef __aarch64_vdupq_laneq_u64 -#undef __LD2_LANE_FUNC -#undef __LD2Q_LANE_FUNC #undef __LD3_LANE_FUNC #undef __LD3Q_LANE_FUNC #undef __LD4_LANE_FUNC -- cgit v1.1 From 08f83812e5c5fdd9a7a4a1b9e46bb33725185c5a Mon Sep 17 00:00:00 2001 From: Jonathan Wright Date: Mon, 16 Aug 2021 09:59:44 +0100 Subject: aarch64: Remove macros for vld3[q]_lane Neon intrinsics Remove macros for vld3[q]_lane Neon intrinsics. This is a preparatory step before adding new modes for structures of Advanced SIMD vectors. gcc/ChangeLog: 2021-08-16 Jonathan Wright * config/aarch64/arm_neon.h (__LD3_LANE_FUNC): Delete. (__LD3Q_LANE_FUNC): Delete. (vld3_lane_u8): Define without macro. (vld3_lane_u16): Likewise. (vld3_lane_u32): Likewise. (vld3_lane_u64): Likewise. (vld3_lane_s8): Likewise. (vld3_lane_s16): Likewise. (vld3_lane_s32): Likewise. (vld3_lane_s64): Likewise. (vld3_lane_f16): Likewise. (vld3_lane_f32): Likewise. (vld3_lane_f64): Likewise. (vld3_lane_p8): Likewise. (vld3_lane_p16): Likewise. (vld3_lane_p64): Likewise. (vld3q_lane_u8): Likewise. (vld3q_lane_u16): Likewise. (vld3q_lane_u32): Likewise. (vld3q_lane_u64): Likewise. (vld3q_lane_s8): Likewise. (vld3q_lane_s16): Likewise. (vld3q_lane_s32): Likewise. (vld3q_lane_s64): Likewise. (vld3q_lane_f16): Likewise. (vld3q_lane_f32): Likewise. (vld3q_lane_f64): Likewise. (vld3q_lane_p8): Likewise. (vld3q_lane_p16): Likewise. (vld3q_lane_p64): Likewise. (vld3_lane_bf16): Likewise. (vld3q_lane_bf16): Likewise. --- gcc/config/aarch64/arm_neon.h | 641 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 549 insertions(+), 92 deletions(-) (limited to 'gcc') diff --git a/gcc/config/aarch64/arm_neon.h b/gcc/config/aarch64/arm_neon.h index 91c072f..29b6298 100644 --- a/gcc/config/aarch64/arm_neon.h +++ b/gcc/config/aarch64/arm_neon.h @@ -20334,100 +20334,525 @@ vld2q_lane_p64 (const poly64_t * __ptr, poly64x2x2_t __b, const int __c) /* vld3_lane */ -#define __LD3_LANE_FUNC(intype, vectype, largetype, ptrtype, mode, \ - qmode, ptrmode, funcsuffix, signedtype) \ -__extension__ extern __inline intype \ -__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) \ -vld3_lane_##funcsuffix (const ptrtype * __ptr, intype __b, const int __c) \ -{ \ - __builtin_aarch64_simd_ci __o; \ - largetype __temp; \ - __temp.val[0] = \ - vcombine_##funcsuffix (__b.val[0], vcreate_##funcsuffix (0)); \ - __temp.val[1] = \ - vcombine_##funcsuffix (__b.val[1], vcreate_##funcsuffix (0)); \ - __temp.val[2] = \ - vcombine_##funcsuffix (__b.val[2], vcreate_##funcsuffix (0)); \ - __o = __builtin_aarch64_set_qregci##qmode (__o, \ - (signedtype) __temp.val[0], \ - 0); \ - __o = __builtin_aarch64_set_qregci##qmode (__o, \ - (signedtype) __temp.val[1], \ - 1); \ - __o = __builtin_aarch64_set_qregci##qmode (__o, \ - (signedtype) __temp.val[2], \ - 2); \ - __o = __builtin_aarch64_ld3_lane##mode ( \ - (__builtin_aarch64_simd_##ptrmode *) __ptr, __o, __c); \ - __b.val[0] = (vectype) __builtin_aarch64_get_dregcidi (__o, 0); \ - __b.val[1] = (vectype) __builtin_aarch64_get_dregcidi (__o, 1); \ - __b.val[2] = (vectype) __builtin_aarch64_get_dregcidi (__o, 2); \ - return __b; \ +__extension__ extern __inline uint8x8x3_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld3_lane_u8 (const uint8_t * __ptr, uint8x8x3_t __b, const int __c) +{ + __builtin_aarch64_simd_ci __o; + uint8x16x3_t __temp; + __temp.val[0] = vcombine_u8 (__b.val[0], vcreate_u8 (0)); + __temp.val[1] = vcombine_u8 (__b.val[1], vcreate_u8 (0)); + __temp.val[2] = vcombine_u8 (__b.val[2], vcreate_u8 (0)); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) __temp.val[2], 2); + __o = __builtin_aarch64_ld3_lanev8qi ( + (__builtin_aarch64_simd_qi *) __ptr, __o, __c); + __b.val[0] = (uint8x8_t) __builtin_aarch64_get_dregcidi (__o, 0); + __b.val[1] = (uint8x8_t) __builtin_aarch64_get_dregcidi (__o, 1); + __b.val[2] = (uint8x8_t) __builtin_aarch64_get_dregcidi (__o, 2); + return __b; } -__LD3_LANE_FUNC (float16x4x3_t, float16x4_t, float16x8x3_t, float16_t, v4hf, - v8hf, hf, f16, float16x8_t) -__LD3_LANE_FUNC (float32x2x3_t, float32x2_t, float32x4x3_t, float32_t, v2sf, v4sf, - sf, f32, float32x4_t) -__LD3_LANE_FUNC (float64x1x3_t, float64x1_t, float64x2x3_t, float64_t, df, v2df, - df, f64, float64x2_t) -__LD3_LANE_FUNC (poly8x8x3_t, poly8x8_t, poly8x16x3_t, poly8_t, v8qi, v16qi, qi, p8, - int8x16_t) -__LD3_LANE_FUNC (poly16x4x3_t, poly16x4_t, poly16x8x3_t, poly16_t, v4hi, v8hi, hi, - p16, int16x8_t) -__LD3_LANE_FUNC (poly64x1x3_t, poly64x1_t, poly64x2x3_t, poly64_t, di, - v2di_ssps, di, p64, poly64x2_t) -__LD3_LANE_FUNC (int8x8x3_t, int8x8_t, int8x16x3_t, int8_t, v8qi, v16qi, qi, s8, - int8x16_t) -__LD3_LANE_FUNC (int16x4x3_t, int16x4_t, int16x8x3_t, int16_t, v4hi, v8hi, hi, s16, - int16x8_t) -__LD3_LANE_FUNC (int32x2x3_t, int32x2_t, int32x4x3_t, int32_t, v2si, v4si, si, s32, - int32x4_t) -__LD3_LANE_FUNC (int64x1x3_t, int64x1_t, int64x2x3_t, int64_t, di, v2di, di, s64, - int64x2_t) -__LD3_LANE_FUNC (uint8x8x3_t, uint8x8_t, uint8x16x3_t, uint8_t, v8qi, v16qi, qi, u8, - int8x16_t) -__LD3_LANE_FUNC (uint16x4x3_t, uint16x4_t, uint16x8x3_t, uint16_t, v4hi, v8hi, hi, - u16, int16x8_t) -__LD3_LANE_FUNC (uint32x2x3_t, uint32x2_t, uint32x4x3_t, uint32_t, v2si, v4si, si, - u32, int32x4_t) -__LD3_LANE_FUNC (uint64x1x3_t, uint64x1_t, uint64x2x3_t, uint64_t, di, v2di, di, - u64, int64x2_t) +__extension__ extern __inline uint16x4x3_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld3_lane_u16 (const uint16_t * __ptr, uint16x4x3_t __b, const int __c) +{ + __builtin_aarch64_simd_ci __o; + uint16x8x3_t __temp; + __temp.val[0] = vcombine_u16 (__b.val[0], vcreate_u16 (0)); + __temp.val[1] = vcombine_u16 (__b.val[1], vcreate_u16 (0)); + __temp.val[2] = vcombine_u16 (__b.val[2], vcreate_u16 (0)); + __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) __temp.val[2], 2); + __o = __builtin_aarch64_ld3_lanev4hi ( + (__builtin_aarch64_simd_hi *) __ptr, __o, __c); + __b.val[0] = (uint16x4_t) __builtin_aarch64_get_dregcidi (__o, 0); + __b.val[1] = (uint16x4_t) __builtin_aarch64_get_dregcidi (__o, 1); + __b.val[2] = (uint16x4_t) __builtin_aarch64_get_dregcidi (__o, 2); + return __b; +} + +__extension__ extern __inline uint32x2x3_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld3_lane_u32 (const uint32_t * __ptr, uint32x2x3_t __b, const int __c) +{ + __builtin_aarch64_simd_ci __o; + uint32x4x3_t __temp; + __temp.val[0] = vcombine_u32 (__b.val[0], vcreate_u32 (0)); + __temp.val[1] = vcombine_u32 (__b.val[1], vcreate_u32 (0)); + __temp.val[2] = vcombine_u32 (__b.val[2], vcreate_u32 (0)); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __temp.val[2], 2); + __o = __builtin_aarch64_ld3_lanev2si ( + (__builtin_aarch64_simd_si *) __ptr, __o, __c); + __b.val[0] = (uint32x2_t) __builtin_aarch64_get_dregcidi (__o, 0); + __b.val[1] = (uint32x2_t) __builtin_aarch64_get_dregcidi (__o, 1); + __b.val[2] = (uint32x2_t) __builtin_aarch64_get_dregcidi (__o, 2); + return __b; +} + +__extension__ extern __inline uint64x1x3_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld3_lane_u64 (const uint64_t * __ptr, uint64x1x3_t __b, const int __c) +{ + __builtin_aarch64_simd_ci __o; + uint64x2x3_t __temp; + __temp.val[0] = vcombine_u64 (__b.val[0], vcreate_u64 (0)); + __temp.val[1] = vcombine_u64 (__b.val[1], vcreate_u64 (0)); + __temp.val[2] = vcombine_u64 (__b.val[2], vcreate_u64 (0)); + __o = __builtin_aarch64_set_qregciv2di (__o, (int64x2_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregciv2di (__o, (int64x2_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregciv2di (__o, (int64x2_t) __temp.val[2], 2); + __o = __builtin_aarch64_ld3_lanedi ( + (__builtin_aarch64_simd_di *) __ptr, __o, __c); + __b.val[0] = (uint64x1_t) __builtin_aarch64_get_dregcidi (__o, 0); + __b.val[1] = (uint64x1_t) __builtin_aarch64_get_dregcidi (__o, 1); + __b.val[2] = (uint64x1_t) __builtin_aarch64_get_dregcidi (__o, 2); + return __b; +} + +__extension__ extern __inline int8x8x3_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld3_lane_s8 (const int8_t * __ptr, int8x8x3_t __b, const int __c) +{ + __builtin_aarch64_simd_ci __o; + int8x16x3_t __temp; + __temp.val[0] = vcombine_s8 (__b.val[0], vcreate_s8 (0)); + __temp.val[1] = vcombine_s8 (__b.val[1], vcreate_s8 (0)); + __temp.val[2] = vcombine_s8 (__b.val[2], vcreate_s8 (0)); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) __temp.val[2], 2); + __o = __builtin_aarch64_ld3_lanev8qi ( + (__builtin_aarch64_simd_qi *) __ptr, __o, __c); + __b.val[0] = (int8x8_t) __builtin_aarch64_get_dregcidi (__o, 0); + __b.val[1] = (int8x8_t) __builtin_aarch64_get_dregcidi (__o, 1); + __b.val[2] = (int8x8_t) __builtin_aarch64_get_dregcidi (__o, 2); + return __b; +} + +__extension__ extern __inline int16x4x3_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld3_lane_s16 (const int16_t * __ptr, int16x4x3_t __b, const int __c) +{ + __builtin_aarch64_simd_ci __o; + int16x8x3_t __temp; + __temp.val[0] = vcombine_s16 (__b.val[0], vcreate_s16 (0)); + __temp.val[1] = vcombine_s16 (__b.val[1], vcreate_s16 (0)); + __temp.val[2] = vcombine_s16 (__b.val[2], vcreate_s16 (0)); + __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) __temp.val[2], 2); + __o = __builtin_aarch64_ld3_lanev4hi ( + (__builtin_aarch64_simd_hi *) __ptr, __o, __c); + __b.val[0] = (int16x4_t) __builtin_aarch64_get_dregcidi (__o, 0); + __b.val[1] = (int16x4_t) __builtin_aarch64_get_dregcidi (__o, 1); + __b.val[2] = (int16x4_t) __builtin_aarch64_get_dregcidi (__o, 2); + return __b; +} + +__extension__ extern __inline int32x2x3_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld3_lane_s32 (const int32_t * __ptr, int32x2x3_t __b, const int __c) +{ + __builtin_aarch64_simd_ci __o; + int32x4x3_t __temp; + __temp.val[0] = vcombine_s32 (__b.val[0], vcreate_s32 (0)); + __temp.val[1] = vcombine_s32 (__b.val[1], vcreate_s32 (0)); + __temp.val[2] = vcombine_s32 (__b.val[2], vcreate_s32 (0)); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __temp.val[2], 2); + __o = __builtin_aarch64_ld3_lanev2si ( + (__builtin_aarch64_simd_si *) __ptr, __o, __c); + __b.val[0] = (int32x2_t) __builtin_aarch64_get_dregcidi (__o, 0); + __b.val[1] = (int32x2_t) __builtin_aarch64_get_dregcidi (__o, 1); + __b.val[2] = (int32x2_t) __builtin_aarch64_get_dregcidi (__o, 2); + return __b; +} + +__extension__ extern __inline int64x1x3_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld3_lane_s64 (const int64_t * __ptr, int64x1x3_t __b, const int __c) +{ + __builtin_aarch64_simd_ci __o; + int64x2x3_t __temp; + __temp.val[0] = vcombine_s64 (__b.val[0], vcreate_s64 (0)); + __temp.val[1] = vcombine_s64 (__b.val[1], vcreate_s64 (0)); + __temp.val[2] = vcombine_s64 (__b.val[2], vcreate_s64 (0)); + __o = __builtin_aarch64_set_qregciv2di (__o, (int64x2_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregciv2di (__o, (int64x2_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregciv2di (__o, (int64x2_t) __temp.val[2], 2); + __o = __builtin_aarch64_ld3_lanedi ( + (__builtin_aarch64_simd_di *) __ptr, __o, __c); + __b.val[0] = (int64x1_t) __builtin_aarch64_get_dregcidi (__o, 0); + __b.val[1] = (int64x1_t) __builtin_aarch64_get_dregcidi (__o, 1); + __b.val[2] = (int64x1_t) __builtin_aarch64_get_dregcidi (__o, 2); + return __b; +} + +__extension__ extern __inline float16x4x3_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld3_lane_f16 (const float16_t * __ptr, float16x4x3_t __b, const int __c) +{ + __builtin_aarch64_simd_ci __o; + float16x8x3_t __temp; + __temp.val[0] = vcombine_f16 (__b.val[0], vcreate_f16 (0)); + __temp.val[1] = vcombine_f16 (__b.val[1], vcreate_f16 (0)); + __temp.val[2] = vcombine_f16 (__b.val[2], vcreate_f16 (0)); + __o = __builtin_aarch64_set_qregciv8hf (__o, (float16x8_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregciv8hf (__o, (float16x8_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregciv8hf (__o, (float16x8_t) __temp.val[2], 2); + __o = __builtin_aarch64_ld3_lanev4hf ( + (__builtin_aarch64_simd_hf *) __ptr, __o, __c); + __b.val[0] = (float16x4_t) __builtin_aarch64_get_dregcidi (__o, 0); + __b.val[1] = (float16x4_t) __builtin_aarch64_get_dregcidi (__o, 1); + __b.val[2] = (float16x4_t) __builtin_aarch64_get_dregcidi (__o, 2); + return __b; +} + +__extension__ extern __inline float32x2x3_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld3_lane_f32 (const float32_t * __ptr, float32x2x3_t __b, const int __c) +{ + __builtin_aarch64_simd_ci __o; + float32x4x3_t __temp; + __temp.val[0] = vcombine_f32 (__b.val[0], vcreate_f32 (0)); + __temp.val[1] = vcombine_f32 (__b.val[1], vcreate_f32 (0)); + __temp.val[2] = vcombine_f32 (__b.val[2], vcreate_f32 (0)); + __o = __builtin_aarch64_set_qregciv4sf (__o, (float32x4_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregciv4sf (__o, (float32x4_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregciv4sf (__o, (float32x4_t) __temp.val[2], 2); + __o = __builtin_aarch64_ld3_lanev2sf ( + (__builtin_aarch64_simd_sf *) __ptr, __o, __c); + __b.val[0] = (float32x2_t) __builtin_aarch64_get_dregcidi (__o, 0); + __b.val[1] = (float32x2_t) __builtin_aarch64_get_dregcidi (__o, 1); + __b.val[2] = (float32x2_t) __builtin_aarch64_get_dregcidi (__o, 2); + return __b; +} + +__extension__ extern __inline float64x1x3_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld3_lane_f64 (const float64_t * __ptr, float64x1x3_t __b, const int __c) +{ + __builtin_aarch64_simd_ci __o; + float64x2x3_t __temp; + __temp.val[0] = vcombine_f64 (__b.val[0], vcreate_f64 (0)); + __temp.val[1] = vcombine_f64 (__b.val[1], vcreate_f64 (0)); + __temp.val[2] = vcombine_f64 (__b.val[2], vcreate_f64 (0)); + __o = __builtin_aarch64_set_qregciv2df (__o, (float64x2_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregciv2df (__o, (float64x2_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregciv2df (__o, (float64x2_t) __temp.val[2], 2); + __o = __builtin_aarch64_ld3_lanedi ( + (__builtin_aarch64_simd_di *) __ptr, __o, __c); + __b.val[0] = (float64x1_t) __builtin_aarch64_get_dregcidi (__o, 0); + __b.val[1] = (float64x1_t) __builtin_aarch64_get_dregcidi (__o, 1); + __b.val[2] = (float64x1_t) __builtin_aarch64_get_dregcidi (__o, 2); + return __b; +} + +__extension__ extern __inline poly8x8x3_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld3_lane_p8 (const poly8_t * __ptr, poly8x8x3_t __b, const int __c) +{ + __builtin_aarch64_simd_ci __o; + poly8x16x3_t __temp; + __temp.val[0] = vcombine_p8 (__b.val[0], vcreate_p8 (0)); + __temp.val[1] = vcombine_p8 (__b.val[1], vcreate_p8 (0)); + __temp.val[2] = vcombine_p8 (__b.val[2], vcreate_p8 (0)); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregciv16qi (__o, (int8x16_t) __temp.val[2], 2); + __o = __builtin_aarch64_ld3_lanev8qi ( + (__builtin_aarch64_simd_qi *) __ptr, __o, __c); + __b.val[0] = (poly8x8_t) __builtin_aarch64_get_dregcidi (__o, 0); + __b.val[1] = (poly8x8_t) __builtin_aarch64_get_dregcidi (__o, 1); + __b.val[2] = (poly8x8_t) __builtin_aarch64_get_dregcidi (__o, 2); + return __b; +} + +__extension__ extern __inline poly16x4x3_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld3_lane_p16 (const poly16_t * __ptr, poly16x4x3_t __b, const int __c) +{ + __builtin_aarch64_simd_ci __o; + poly16x8x3_t __temp; + __temp.val[0] = vcombine_p16 (__b.val[0], vcreate_p16 (0)); + __temp.val[1] = vcombine_p16 (__b.val[1], vcreate_p16 (0)); + __temp.val[2] = vcombine_p16 (__b.val[2], vcreate_p16 (0)); + __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregciv8hi (__o, (int16x8_t) __temp.val[2], 2); + __o = __builtin_aarch64_ld3_lanev4hi ( + (__builtin_aarch64_simd_hi *) __ptr, __o, __c); + __b.val[0] = (poly16x4_t) __builtin_aarch64_get_dregcidi (__o, 0); + __b.val[1] = (poly16x4_t) __builtin_aarch64_get_dregcidi (__o, 1); + __b.val[2] = (poly16x4_t) __builtin_aarch64_get_dregcidi (__o, 2); + return __b; +} + +__extension__ extern __inline poly64x1x3_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld3_lane_p64 (const poly64_t * __ptr, poly64x1x3_t __b, const int __c) +{ + __builtin_aarch64_simd_ci __o; + poly64x2x3_t __temp; + __temp.val[0] = vcombine_p64 (__b.val[0], vcreate_p64 (0)); + __temp.val[1] = vcombine_p64 (__b.val[1], vcreate_p64 (0)); + __temp.val[2] = vcombine_p64 (__b.val[2], vcreate_p64 (0)); + __o = __builtin_aarch64_set_qregciv2di (__o, (int64x2_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregciv2di (__o, (int64x2_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregciv2di (__o, (int64x2_t) __temp.val[2], 2); + __o = __builtin_aarch64_ld3_lanedi ( + (__builtin_aarch64_simd_di *) __ptr, __o, __c); + __b.val[0] = (poly64x1_t) __builtin_aarch64_get_dregcidi (__o, 0); + __b.val[1] = (poly64x1_t) __builtin_aarch64_get_dregcidi (__o, 1); + __b.val[2] = (poly64x1_t) __builtin_aarch64_get_dregcidi (__o, 2); + return __b; +} /* vld3q_lane */ -#define __LD3Q_LANE_FUNC(intype, vtype, ptrtype, mode, ptrmode, funcsuffix) \ -__extension__ extern __inline intype \ -__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) \ -vld3q_lane_##funcsuffix (const ptrtype * __ptr, intype __b, const int __c) \ -{ \ - __builtin_aarch64_simd_ci __o; \ - intype ret; \ - __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[0], 0); \ - __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[1], 1); \ - __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[2], 2); \ - __o = __builtin_aarch64_ld3_lane##mode ( \ - (__builtin_aarch64_simd_##ptrmode *) __ptr, __o, __c); \ - ret.val[0] = (vtype) __builtin_aarch64_get_qregciv4si (__o, 0); \ - ret.val[1] = (vtype) __builtin_aarch64_get_qregciv4si (__o, 1); \ - ret.val[2] = (vtype) __builtin_aarch64_get_qregciv4si (__o, 2); \ - return ret; \ +__extension__ extern __inline uint8x16x3_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld3q_lane_u8 (const uint8_t * __ptr, uint8x16x3_t __b, const int __c) +{ + __builtin_aarch64_simd_ci __o; + uint8x16x3_t ret; + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[2], 2); + __o = __builtin_aarch64_ld3_lanev16qi ( + (__builtin_aarch64_simd_qi *) __ptr, __o, __c); + ret.val[0] = (uint8x16_t) __builtin_aarch64_get_qregciv4si (__o, 0); + ret.val[1] = (uint8x16_t) __builtin_aarch64_get_qregciv4si (__o, 1); + ret.val[2] = (uint8x16_t) __builtin_aarch64_get_qregciv4si (__o, 2); + return ret; +} + +__extension__ extern __inline uint16x8x3_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld3q_lane_u16 (const uint16_t * __ptr, uint16x8x3_t __b, const int __c) +{ + __builtin_aarch64_simd_ci __o; + uint16x8x3_t ret; + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[2], 2); + __o = __builtin_aarch64_ld3_lanev8hi ( + (__builtin_aarch64_simd_hi *) __ptr, __o, __c); + ret.val[0] = (uint16x8_t) __builtin_aarch64_get_qregciv4si (__o, 0); + ret.val[1] = (uint16x8_t) __builtin_aarch64_get_qregciv4si (__o, 1); + ret.val[2] = (uint16x8_t) __builtin_aarch64_get_qregciv4si (__o, 2); + return ret; +} + +__extension__ extern __inline uint32x4x3_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld3q_lane_u32 (const uint32_t * __ptr, uint32x4x3_t __b, const int __c) +{ + __builtin_aarch64_simd_ci __o; + uint32x4x3_t ret; + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[2], 2); + __o = __builtin_aarch64_ld3_lanev4si ( + (__builtin_aarch64_simd_si *) __ptr, __o, __c); + ret.val[0] = (uint32x4_t) __builtin_aarch64_get_qregciv4si (__o, 0); + ret.val[1] = (uint32x4_t) __builtin_aarch64_get_qregciv4si (__o, 1); + ret.val[2] = (uint32x4_t) __builtin_aarch64_get_qregciv4si (__o, 2); + return ret; +} + +__extension__ extern __inline uint64x2x3_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld3q_lane_u64 (const uint64_t * __ptr, uint64x2x3_t __b, const int __c) +{ + __builtin_aarch64_simd_ci __o; + uint64x2x3_t ret; + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[2], 2); + __o = __builtin_aarch64_ld3_lanev2di ( + (__builtin_aarch64_simd_di *) __ptr, __o, __c); + ret.val[0] = (uint64x2_t) __builtin_aarch64_get_qregciv4si (__o, 0); + ret.val[1] = (uint64x2_t) __builtin_aarch64_get_qregciv4si (__o, 1); + ret.val[2] = (uint64x2_t) __builtin_aarch64_get_qregciv4si (__o, 2); + return ret; +} + +__extension__ extern __inline int8x16x3_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld3q_lane_s8 (const int8_t * __ptr, int8x16x3_t __b, const int __c) +{ + __builtin_aarch64_simd_ci __o; + int8x16x3_t ret; + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[2], 2); + __o = __builtin_aarch64_ld3_lanev16qi ( + (__builtin_aarch64_simd_qi *) __ptr, __o, __c); + ret.val[0] = (int8x16_t) __builtin_aarch64_get_qregciv4si (__o, 0); + ret.val[1] = (int8x16_t) __builtin_aarch64_get_qregciv4si (__o, 1); + ret.val[2] = (int8x16_t) __builtin_aarch64_get_qregciv4si (__o, 2); + return ret; +} + +__extension__ extern __inline int16x8x3_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld3q_lane_s16 (const int16_t * __ptr, int16x8x3_t __b, const int __c) +{ + __builtin_aarch64_simd_ci __o; + int16x8x3_t ret; + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[2], 2); + __o = __builtin_aarch64_ld3_lanev8hi ( + (__builtin_aarch64_simd_hi *) __ptr, __o, __c); + ret.val[0] = (int16x8_t) __builtin_aarch64_get_qregciv4si (__o, 0); + ret.val[1] = (int16x8_t) __builtin_aarch64_get_qregciv4si (__o, 1); + ret.val[2] = (int16x8_t) __builtin_aarch64_get_qregciv4si (__o, 2); + return ret; +} + +__extension__ extern __inline int32x4x3_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld3q_lane_s32 (const int32_t * __ptr, int32x4x3_t __b, const int __c) +{ + __builtin_aarch64_simd_ci __o; + int32x4x3_t ret; + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[2], 2); + __o = __builtin_aarch64_ld3_lanev4si ( + (__builtin_aarch64_simd_si *) __ptr, __o, __c); + ret.val[0] = (int32x4_t) __builtin_aarch64_get_qregciv4si (__o, 0); + ret.val[1] = (int32x4_t) __builtin_aarch64_get_qregciv4si (__o, 1); + ret.val[2] = (int32x4_t) __builtin_aarch64_get_qregciv4si (__o, 2); + return ret; +} + +__extension__ extern __inline int64x2x3_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld3q_lane_s64 (const int64_t * __ptr, int64x2x3_t __b, const int __c) +{ + __builtin_aarch64_simd_ci __o; + int64x2x3_t ret; + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[2], 2); + __o = __builtin_aarch64_ld3_lanev2di ( + (__builtin_aarch64_simd_di *) __ptr, __o, __c); + ret.val[0] = (int64x2_t) __builtin_aarch64_get_qregciv4si (__o, 0); + ret.val[1] = (int64x2_t) __builtin_aarch64_get_qregciv4si (__o, 1); + ret.val[2] = (int64x2_t) __builtin_aarch64_get_qregciv4si (__o, 2); + return ret; } -__LD3Q_LANE_FUNC (float16x8x3_t, float16x8_t, float16_t, v8hf, hf, f16) -__LD3Q_LANE_FUNC (float32x4x3_t, float32x4_t, float32_t, v4sf, sf, f32) -__LD3Q_LANE_FUNC (float64x2x3_t, float64x2_t, float64_t, v2df, df, f64) -__LD3Q_LANE_FUNC (poly8x16x3_t, poly8x16_t, poly8_t, v16qi, qi, p8) -__LD3Q_LANE_FUNC (poly16x8x3_t, poly16x8_t, poly16_t, v8hi, hi, p16) -__LD3Q_LANE_FUNC (poly64x2x3_t, poly64x2_t, poly64_t, v2di, di, p64) -__LD3Q_LANE_FUNC (int8x16x3_t, int8x16_t, int8_t, v16qi, qi, s8) -__LD3Q_LANE_FUNC (int16x8x3_t, int16x8_t, int16_t, v8hi, hi, s16) -__LD3Q_LANE_FUNC (int32x4x3_t, int32x4_t, int32_t, v4si, si, s32) -__LD3Q_LANE_FUNC (int64x2x3_t, int64x2_t, int64_t, v2di, di, s64) -__LD3Q_LANE_FUNC (uint8x16x3_t, uint8x16_t, uint8_t, v16qi, qi, u8) -__LD3Q_LANE_FUNC (uint16x8x3_t, uint16x8_t, uint16_t, v8hi, hi, u16) -__LD3Q_LANE_FUNC (uint32x4x3_t, uint32x4_t, uint32_t, v4si, si, u32) -__LD3Q_LANE_FUNC (uint64x2x3_t, uint64x2_t, uint64_t, v2di, di, u64) +__extension__ extern __inline float16x8x3_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld3q_lane_f16 (const float16_t * __ptr, float16x8x3_t __b, const int __c) +{ + __builtin_aarch64_simd_ci __o; + float16x8x3_t ret; + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[2], 2); + __o = __builtin_aarch64_ld3_lanev8hf ( + (__builtin_aarch64_simd_hf *) __ptr, __o, __c); + ret.val[0] = (float16x8_t) __builtin_aarch64_get_qregciv4si (__o, 0); + ret.val[1] = (float16x8_t) __builtin_aarch64_get_qregciv4si (__o, 1); + ret.val[2] = (float16x8_t) __builtin_aarch64_get_qregciv4si (__o, 2); + return ret; +} + +__extension__ extern __inline float32x4x3_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld3q_lane_f32 (const float32_t * __ptr, float32x4x3_t __b, const int __c) +{ + __builtin_aarch64_simd_ci __o; + float32x4x3_t ret; + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[2], 2); + __o = __builtin_aarch64_ld3_lanev4sf ( + (__builtin_aarch64_simd_sf *) __ptr, __o, __c); + ret.val[0] = (float32x4_t) __builtin_aarch64_get_qregciv4si (__o, 0); + ret.val[1] = (float32x4_t) __builtin_aarch64_get_qregciv4si (__o, 1); + ret.val[2] = (float32x4_t) __builtin_aarch64_get_qregciv4si (__o, 2); + return ret; +} + +__extension__ extern __inline float64x2x3_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld3q_lane_f64 (const float64_t * __ptr, float64x2x3_t __b, const int __c) +{ + __builtin_aarch64_simd_ci __o; + float64x2x3_t ret; + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[2], 2); + __o = __builtin_aarch64_ld3_lanev2df ( + (__builtin_aarch64_simd_df *) __ptr, __o, __c); + ret.val[0] = (float64x2_t) __builtin_aarch64_get_qregciv4si (__o, 0); + ret.val[1] = (float64x2_t) __builtin_aarch64_get_qregciv4si (__o, 1); + ret.val[2] = (float64x2_t) __builtin_aarch64_get_qregciv4si (__o, 2); + return ret; +} + +__extension__ extern __inline poly8x16x3_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld3q_lane_p8 (const poly8_t * __ptr, poly8x16x3_t __b, const int __c) +{ + __builtin_aarch64_simd_ci __o; + poly8x16x3_t ret; + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[2], 2); + __o = __builtin_aarch64_ld3_lanev16qi ( + (__builtin_aarch64_simd_qi *) __ptr, __o, __c); + ret.val[0] = (poly8x16_t) __builtin_aarch64_get_qregciv4si (__o, 0); + ret.val[1] = (poly8x16_t) __builtin_aarch64_get_qregciv4si (__o, 1); + ret.val[2] = (poly8x16_t) __builtin_aarch64_get_qregciv4si (__o, 2); + return ret; +} + +__extension__ extern __inline poly16x8x3_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld3q_lane_p16 (const poly16_t * __ptr, poly16x8x3_t __b, const int __c) +{ + __builtin_aarch64_simd_ci __o; + poly16x8x3_t ret; + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[2], 2); + __o = __builtin_aarch64_ld3_lanev8hi ( + (__builtin_aarch64_simd_hi *) __ptr, __o, __c); + ret.val[0] = (poly16x8_t) __builtin_aarch64_get_qregciv4si (__o, 0); + ret.val[1] = (poly16x8_t) __builtin_aarch64_get_qregciv4si (__o, 1); + ret.val[2] = (poly16x8_t) __builtin_aarch64_get_qregciv4si (__o, 2); + return ret; +} + +__extension__ extern __inline poly64x2x3_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld3q_lane_p64 (const poly64_t * __ptr, poly64x2x3_t __b, const int __c) +{ + __builtin_aarch64_simd_ci __o; + poly64x2x3_t ret; + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[2], 2); + __o = __builtin_aarch64_ld3_lanev2di ( + (__builtin_aarch64_simd_di *) __ptr, __o, __c); + ret.val[0] = (poly64x2_t) __builtin_aarch64_get_qregciv4si (__o, 0); + ret.val[1] = (poly64x2_t) __builtin_aarch64_get_qregciv4si (__o, 1); + ret.val[2] = (poly64x2_t) __builtin_aarch64_get_qregciv4si (__o, 2); + return ret; +} /* vld4_lane */ @@ -34979,9 +35404,43 @@ vld2q_lane_bf16 (const bfloat16_t * __ptr, bfloat16x8x2_t __b, const int __c) return ret; } -__LD3_LANE_FUNC (bfloat16x4x3_t, bfloat16x4_t, bfloat16x8x3_t, bfloat16_t, v4bf, - v8bf, bf, bf16, bfloat16x8_t) -__LD3Q_LANE_FUNC (bfloat16x8x3_t, bfloat16x8_t, bfloat16_t, v8bf, bf, bf16) +__extension__ extern __inline bfloat16x4x3_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld3_lane_bf16 (const bfloat16_t * __ptr, bfloat16x4x3_t __b, const int __c) +{ + __builtin_aarch64_simd_ci __o; + bfloat16x8x3_t __temp; + __temp.val[0] = vcombine_bf16 (__b.val[0], vcreate_bf16 (0)); + __temp.val[1] = vcombine_bf16 (__b.val[1], vcreate_bf16 (0)); + __temp.val[2] = vcombine_bf16 (__b.val[2], vcreate_bf16 (0)); + __o = __builtin_aarch64_set_qregciv8bf (__o, (bfloat16x8_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregciv8bf (__o, (bfloat16x8_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregciv8bf (__o, (bfloat16x8_t) __temp.val[2], 2); + __o = __builtin_aarch64_ld3_lanev4bf ( + (__builtin_aarch64_simd_bf *) __ptr, __o, __c); + __b.val[0] = (bfloat16x4_t) __builtin_aarch64_get_dregcidi (__o, 0); + __b.val[1] = (bfloat16x4_t) __builtin_aarch64_get_dregcidi (__o, 1); + __b.val[2] = (bfloat16x4_t) __builtin_aarch64_get_dregcidi (__o, 2); + return __b; +} + +__extension__ extern __inline bfloat16x8x3_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld3q_lane_bf16 (const bfloat16_t * __ptr, bfloat16x8x3_t __b, const int __c) +{ + __builtin_aarch64_simd_ci __o; + bfloat16x8x3_t ret; + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_set_qregciv4si (__o, (int32x4_t) __b.val[2], 2); + __o = __builtin_aarch64_ld3_lanev8bf ( + (__builtin_aarch64_simd_bf *) __ptr, __o, __c); + ret.val[0] = (bfloat16x8_t) __builtin_aarch64_get_qregciv4si (__o, 0); + ret.val[1] = (bfloat16x8_t) __builtin_aarch64_get_qregciv4si (__o, 1); + ret.val[2] = (bfloat16x8_t) __builtin_aarch64_get_qregciv4si (__o, 2); + return ret; +} + __LD4_LANE_FUNC (bfloat16x4x4_t, bfloat16x4_t, bfloat16x8x4_t, bfloat16_t, v4bf, v8bf, bf, bf16, bfloat16x8_t) __LD4Q_LANE_FUNC (bfloat16x8x4_t, bfloat16x8_t, bfloat16_t, v8bf, bf, bf16) @@ -35280,8 +35739,6 @@ vaddq_p128 (poly128_t __a, poly128_t __b) #undef __aarch64_vdupq_laneq_u32 #undef __aarch64_vdupq_laneq_u64 -#undef __LD3_LANE_FUNC -#undef __LD3Q_LANE_FUNC #undef __LD4_LANE_FUNC #undef __LD4Q_LANE_FUNC -- cgit v1.1 From d1819df86fbe42125cccb2fc2959a0bf51e524d6 Mon Sep 17 00:00:00 2001 From: Jonathan Wright Date: Mon, 16 Aug 2021 14:37:18 +0100 Subject: aarch64: Remove macros for vld4[q]_lane Neon intrinsics Remove macros for vld4[q]_lane Neon intrinsics. This is a preparatory step before adding new modes for structures of Advanced SIMD vectors. gcc/ChangeLog: 2021-08-16 Jonathan Wright * config/aarch64/arm_neon.h (__LD4_LANE_FUNC): Delete. (__LD4Q_LANE_FUNC): Likewise. (vld4_lane_u8): Define without macro. (vld4_lane_u16): Likewise. (vld4_lane_u32): Likewise. (vld4_lane_u64): Likewise. (vld4_lane_s8): Likewise. (vld4_lane_s16): Likewise. (vld4_lane_s32): Likewise. (vld4_lane_s64): Likewise. (vld4_lane_f16): Likewise. (vld4_lane_f32): Likewise. (vld4_lane_f64): Likewise. (vld4_lane_p8): Likewise. (vld4_lane_p16): Likewise. (vld4_lane_p64): Likewise. (vld4q_lane_u8): Likewise. (vld4q_lane_u16): Likewise. (vld4q_lane_u32): Likewise. (vld4q_lane_u64): Likewise. (vld4q_lane_s8): Likewise. (vld4q_lane_s16): Likewise. (vld4q_lane_s32): Likewise. (vld4q_lane_s64): Likewise. (vld4q_lane_f16): Likewise. (vld4q_lane_f32): Likewise. (vld4q_lane_f64): Likewise. (vld4q_lane_p8): Likewise. (vld4q_lane_p16): Likewise. (vld4q_lane_p64): Likewise. (vld4_lane_bf16): Likewise. (vld4q_lane_bf16): Likewise. --- gcc/config/aarch64/arm_neon.h | 728 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 624 insertions(+), 104 deletions(-) (limited to 'gcc') diff --git a/gcc/config/aarch64/arm_neon.h b/gcc/config/aarch64/arm_neon.h index 29b6298..d8b2970 100644 --- a/gcc/config/aarch64/arm_neon.h +++ b/gcc/config/aarch64/arm_neon.h @@ -20856,110 +20856,595 @@ vld3q_lane_p64 (const poly64_t * __ptr, poly64x2x3_t __b, const int __c) /* vld4_lane */ -#define __LD4_LANE_FUNC(intype, vectype, largetype, ptrtype, mode, \ - qmode, ptrmode, funcsuffix, signedtype) \ -__extension__ extern __inline intype \ -__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) \ -vld4_lane_##funcsuffix (const ptrtype * __ptr, intype __b, const int __c) \ -{ \ - __builtin_aarch64_simd_xi __o; \ - largetype __temp; \ - __temp.val[0] = \ - vcombine_##funcsuffix (__b.val[0], vcreate_##funcsuffix (0)); \ - __temp.val[1] = \ - vcombine_##funcsuffix (__b.val[1], vcreate_##funcsuffix (0)); \ - __temp.val[2] = \ - vcombine_##funcsuffix (__b.val[2], vcreate_##funcsuffix (0)); \ - __temp.val[3] = \ - vcombine_##funcsuffix (__b.val[3], vcreate_##funcsuffix (0)); \ - __o = __builtin_aarch64_set_qregxi##qmode (__o, \ - (signedtype) __temp.val[0], \ - 0); \ - __o = __builtin_aarch64_set_qregxi##qmode (__o, \ - (signedtype) __temp.val[1], \ - 1); \ - __o = __builtin_aarch64_set_qregxi##qmode (__o, \ - (signedtype) __temp.val[2], \ - 2); \ - __o = __builtin_aarch64_set_qregxi##qmode (__o, \ - (signedtype) __temp.val[3], \ - 3); \ - __o = __builtin_aarch64_ld4_lane##mode ( \ - (__builtin_aarch64_simd_##ptrmode *) __ptr, __o, __c); \ - __b.val[0] = (vectype) __builtin_aarch64_get_dregxidi (__o, 0); \ - __b.val[1] = (vectype) __builtin_aarch64_get_dregxidi (__o, 1); \ - __b.val[2] = (vectype) __builtin_aarch64_get_dregxidi (__o, 2); \ - __b.val[3] = (vectype) __builtin_aarch64_get_dregxidi (__o, 3); \ - return __b; \ +__extension__ extern __inline uint8x8x4_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld4_lane_u8 (const uint8_t * __ptr, uint8x8x4_t __b, const int __c) +{ + __builtin_aarch64_simd_xi __o; + uint8x16x4_t __temp; + __temp.val[0] = vcombine_u8 (__b.val[0], vcreate_u8 (0)); + __temp.val[1] = vcombine_u8 (__b.val[1], vcreate_u8 (0)); + __temp.val[2] = vcombine_u8 (__b.val[2], vcreate_u8 (0)); + __temp.val[3] = vcombine_u8 (__b.val[3], vcreate_u8 (0)); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t) __temp.val[2], 2); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t) __temp.val[3], 3); + __o = __builtin_aarch64_ld4_lanev8qi ( + (__builtin_aarch64_simd_qi *) __ptr, __o, __c); + __b.val[0] = (uint8x8_t) __builtin_aarch64_get_dregxidi (__o, 0); + __b.val[1] = (uint8x8_t) __builtin_aarch64_get_dregxidi (__o, 1); + __b.val[2] = (uint8x8_t) __builtin_aarch64_get_dregxidi (__o, 2); + __b.val[3] = (uint8x8_t) __builtin_aarch64_get_dregxidi (__o, 3); + return __b; } -/* vld4q_lane */ +__extension__ extern __inline uint16x4x4_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld4_lane_u16 (const uint16_t * __ptr, uint16x4x4_t __b, const int __c) +{ + __builtin_aarch64_simd_xi __o; + uint16x8x4_t __temp; + __temp.val[0] = vcombine_u16 (__b.val[0], vcreate_u16 (0)); + __temp.val[1] = vcombine_u16 (__b.val[1], vcreate_u16 (0)); + __temp.val[2] = vcombine_u16 (__b.val[2], vcreate_u16 (0)); + __temp.val[3] = vcombine_u16 (__b.val[3], vcreate_u16 (0)); + __o = __builtin_aarch64_set_qregxiv8hi (__o, (int16x8_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregxiv8hi (__o, (int16x8_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregxiv8hi (__o, (int16x8_t) __temp.val[2], 2); + __o = __builtin_aarch64_set_qregxiv8hi (__o, (int16x8_t) __temp.val[3], 3); + __o = __builtin_aarch64_ld4_lanev4hi ( + (__builtin_aarch64_simd_hi *) __ptr, __o, __c); + __b.val[0] = (uint16x4_t) __builtin_aarch64_get_dregxidi (__o, 0); + __b.val[1] = (uint16x4_t) __builtin_aarch64_get_dregxidi (__o, 1); + __b.val[2] = (uint16x4_t) __builtin_aarch64_get_dregxidi (__o, 2); + __b.val[3] = (uint16x4_t) __builtin_aarch64_get_dregxidi (__o, 3); + return __b; +} + +__extension__ extern __inline uint32x2x4_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld4_lane_u32 (const uint32_t * __ptr, uint32x2x4_t __b, const int __c) +{ + __builtin_aarch64_simd_xi __o; + uint32x4x4_t __temp; + __temp.val[0] = vcombine_u32 (__b.val[0], vcreate_u32 (0)); + __temp.val[1] = vcombine_u32 (__b.val[1], vcreate_u32 (0)); + __temp.val[2] = vcombine_u32 (__b.val[2], vcreate_u32 (0)); + __temp.val[3] = vcombine_u32 (__b.val[3], vcreate_u32 (0)); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __temp.val[2], 2); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __temp.val[3], 3); + __o = __builtin_aarch64_ld4_lanev2si ( + (__builtin_aarch64_simd_si *) __ptr, __o, __c); + __b.val[0] = (uint32x2_t) __builtin_aarch64_get_dregxidi (__o, 0); + __b.val[1] = (uint32x2_t) __builtin_aarch64_get_dregxidi (__o, 1); + __b.val[2] = (uint32x2_t) __builtin_aarch64_get_dregxidi (__o, 2); + __b.val[3] = (uint32x2_t) __builtin_aarch64_get_dregxidi (__o, 3); + return __b; +} + +__extension__ extern __inline uint64x1x4_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld4_lane_u64 (const uint64_t * __ptr, uint64x1x4_t __b, const int __c) +{ + __builtin_aarch64_simd_xi __o; + uint64x2x4_t __temp; + __temp.val[0] = vcombine_u64 (__b.val[0], vcreate_u64 (0)); + __temp.val[1] = vcombine_u64 (__b.val[1], vcreate_u64 (0)); + __temp.val[2] = vcombine_u64 (__b.val[2], vcreate_u64 (0)); + __temp.val[3] = vcombine_u64 (__b.val[3], vcreate_u64 (0)); + __o = __builtin_aarch64_set_qregxiv2di (__o, (int64x2_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregxiv2di (__o, (int64x2_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregxiv2di (__o, (int64x2_t) __temp.val[2], 2); + __o = __builtin_aarch64_set_qregxiv2di (__o, (int64x2_t) __temp.val[3], 3); + __o = __builtin_aarch64_ld4_lanedi ( + (__builtin_aarch64_simd_di *) __ptr, __o, __c); + __b.val[0] = (uint64x1_t) __builtin_aarch64_get_dregxidi (__o, 0); + __b.val[1] = (uint64x1_t) __builtin_aarch64_get_dregxidi (__o, 1); + __b.val[2] = (uint64x1_t) __builtin_aarch64_get_dregxidi (__o, 2); + __b.val[3] = (uint64x1_t) __builtin_aarch64_get_dregxidi (__o, 3); + return __b; +} + +__extension__ extern __inline int8x8x4_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld4_lane_s8 (const int8_t * __ptr, int8x8x4_t __b, const int __c) +{ + __builtin_aarch64_simd_xi __o; + int8x16x4_t __temp; + __temp.val[0] = vcombine_s8 (__b.val[0], vcreate_s8 (0)); + __temp.val[1] = vcombine_s8 (__b.val[1], vcreate_s8 (0)); + __temp.val[2] = vcombine_s8 (__b.val[2], vcreate_s8 (0)); + __temp.val[3] = vcombine_s8 (__b.val[3], vcreate_s8 (0)); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t) __temp.val[2], 2); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t) __temp.val[3], 3); + __o = __builtin_aarch64_ld4_lanev8qi ( + (__builtin_aarch64_simd_qi *) __ptr, __o, __c); + __b.val[0] = (int8x8_t) __builtin_aarch64_get_dregxidi (__o, 0); + __b.val[1] = (int8x8_t) __builtin_aarch64_get_dregxidi (__o, 1); + __b.val[2] = (int8x8_t) __builtin_aarch64_get_dregxidi (__o, 2); + __b.val[3] = (int8x8_t) __builtin_aarch64_get_dregxidi (__o, 3); + return __b; +} + +__extension__ extern __inline int16x4x4_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld4_lane_s16 (const int16_t * __ptr, int16x4x4_t __b, const int __c) +{ + __builtin_aarch64_simd_xi __o; + int16x8x4_t __temp; + __temp.val[0] = vcombine_s16 (__b.val[0], vcreate_s16 (0)); + __temp.val[1] = vcombine_s16 (__b.val[1], vcreate_s16 (0)); + __temp.val[2] = vcombine_s16 (__b.val[2], vcreate_s16 (0)); + __temp.val[3] = vcombine_s16 (__b.val[3], vcreate_s16 (0)); + __o = __builtin_aarch64_set_qregxiv8hi (__o, (int16x8_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregxiv8hi (__o, (int16x8_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregxiv8hi (__o, (int16x8_t) __temp.val[2], 2); + __o = __builtin_aarch64_set_qregxiv8hi (__o, (int16x8_t) __temp.val[3], 3); + __o = __builtin_aarch64_ld4_lanev4hi ( + (__builtin_aarch64_simd_hi *) __ptr, __o, __c); + __b.val[0] = (int16x4_t) __builtin_aarch64_get_dregxidi (__o, 0); + __b.val[1] = (int16x4_t) __builtin_aarch64_get_dregxidi (__o, 1); + __b.val[2] = (int16x4_t) __builtin_aarch64_get_dregxidi (__o, 2); + __b.val[3] = (int16x4_t) __builtin_aarch64_get_dregxidi (__o, 3); + return __b; +} + +__extension__ extern __inline int32x2x4_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld4_lane_s32 (const int32_t * __ptr, int32x2x4_t __b, const int __c) +{ + __builtin_aarch64_simd_xi __o; + int32x4x4_t __temp; + __temp.val[0] = vcombine_s32 (__b.val[0], vcreate_s32 (0)); + __temp.val[1] = vcombine_s32 (__b.val[1], vcreate_s32 (0)); + __temp.val[2] = vcombine_s32 (__b.val[2], vcreate_s32 (0)); + __temp.val[3] = vcombine_s32 (__b.val[3], vcreate_s32 (0)); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __temp.val[2], 2); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __temp.val[3], 3); + __o = __builtin_aarch64_ld4_lanev2si ( + (__builtin_aarch64_simd_si *) __ptr, __o, __c); + __b.val[0] = (int32x2_t) __builtin_aarch64_get_dregxidi (__o, 0); + __b.val[1] = (int32x2_t) __builtin_aarch64_get_dregxidi (__o, 1); + __b.val[2] = (int32x2_t) __builtin_aarch64_get_dregxidi (__o, 2); + __b.val[3] = (int32x2_t) __builtin_aarch64_get_dregxidi (__o, 3); + return __b; +} + +__extension__ extern __inline int64x1x4_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld4_lane_s64 (const int64_t * __ptr, int64x1x4_t __b, const int __c) +{ + __builtin_aarch64_simd_xi __o; + int64x2x4_t __temp; + __temp.val[0] = vcombine_s64 (__b.val[0], vcreate_s64 (0)); + __temp.val[1] = vcombine_s64 (__b.val[1], vcreate_s64 (0)); + __temp.val[2] = vcombine_s64 (__b.val[2], vcreate_s64 (0)); + __temp.val[3] = vcombine_s64 (__b.val[3], vcreate_s64 (0)); + __o = __builtin_aarch64_set_qregxiv2di (__o, (int64x2_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregxiv2di (__o, (int64x2_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregxiv2di (__o, (int64x2_t) __temp.val[2], 2); + __o = __builtin_aarch64_set_qregxiv2di (__o, (int64x2_t) __temp.val[3], 3); + __o = __builtin_aarch64_ld4_lanedi ( + (__builtin_aarch64_simd_di *) __ptr, __o, __c); + __b.val[0] = (int64x1_t) __builtin_aarch64_get_dregxidi (__o, 0); + __b.val[1] = (int64x1_t) __builtin_aarch64_get_dregxidi (__o, 1); + __b.val[2] = (int64x1_t) __builtin_aarch64_get_dregxidi (__o, 2); + __b.val[3] = (int64x1_t) __builtin_aarch64_get_dregxidi (__o, 3); + return __b; +} + +__extension__ extern __inline float16x4x4_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld4_lane_f16 (const float16_t * __ptr, float16x4x4_t __b, const int __c) +{ + __builtin_aarch64_simd_xi __o; + float16x8x4_t __temp; + __temp.val[0] = vcombine_f16 (__b.val[0], vcreate_f16 (0)); + __temp.val[1] = vcombine_f16 (__b.val[1], vcreate_f16 (0)); + __temp.val[2] = vcombine_f16 (__b.val[2], vcreate_f16 (0)); + __temp.val[3] = vcombine_f16 (__b.val[3], vcreate_f16 (0)); + __o = __builtin_aarch64_set_qregxiv8hf (__o, (float16x8_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregxiv8hf (__o, (float16x8_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregxiv8hf (__o, (float16x8_t) __temp.val[2], 2); + __o = __builtin_aarch64_set_qregxiv8hf (__o, (float16x8_t) __temp.val[3], 3); + __o = __builtin_aarch64_ld4_lanev4hf ( + (__builtin_aarch64_simd_hf *) __ptr, __o, __c); + __b.val[0] = (float16x4_t) __builtin_aarch64_get_dregxidi (__o, 0); + __b.val[1] = (float16x4_t) __builtin_aarch64_get_dregxidi (__o, 1); + __b.val[2] = (float16x4_t) __builtin_aarch64_get_dregxidi (__o, 2); + __b.val[3] = (float16x4_t) __builtin_aarch64_get_dregxidi (__o, 3); + return __b; +} + +__extension__ extern __inline float32x2x4_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld4_lane_f32 (const float32_t * __ptr, float32x2x4_t __b, const int __c) +{ + __builtin_aarch64_simd_xi __o; + float32x4x4_t __temp; + __temp.val[0] = vcombine_f32 (__b.val[0], vcreate_f32 (0)); + __temp.val[1] = vcombine_f32 (__b.val[1], vcreate_f32 (0)); + __temp.val[2] = vcombine_f32 (__b.val[2], vcreate_f32 (0)); + __temp.val[3] = vcombine_f32 (__b.val[3], vcreate_f32 (0)); + __o = __builtin_aarch64_set_qregxiv4sf (__o, (float32x4_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregxiv4sf (__o, (float32x4_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregxiv4sf (__o, (float32x4_t) __temp.val[2], 2); + __o = __builtin_aarch64_set_qregxiv4sf (__o, (float32x4_t) __temp.val[3], 3); + __o = __builtin_aarch64_ld4_lanev2si ( + (__builtin_aarch64_simd_sf *) __ptr, __o, __c); + __b.val[0] = (float32x2_t) __builtin_aarch64_get_dregxidi (__o, 0); + __b.val[1] = (float32x2_t) __builtin_aarch64_get_dregxidi (__o, 1); + __b.val[2] = (float32x2_t) __builtin_aarch64_get_dregxidi (__o, 2); + __b.val[3] = (float32x2_t) __builtin_aarch64_get_dregxidi (__o, 3); + return __b; +} + +__extension__ extern __inline float64x1x4_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld4_lane_f64 (const float64_t * __ptr, float64x1x4_t __b, const int __c) +{ + __builtin_aarch64_simd_xi __o; + float64x2x4_t __temp; + __temp.val[0] = vcombine_f64 (__b.val[0], vcreate_f64 (0)); + __temp.val[1] = vcombine_f64 (__b.val[1], vcreate_f64 (0)); + __temp.val[2] = vcombine_f64 (__b.val[2], vcreate_f64 (0)); + __temp.val[3] = vcombine_f64 (__b.val[3], vcreate_f64 (0)); + __o = __builtin_aarch64_set_qregxiv2df (__o, (float64x2_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregxiv2df (__o, (float64x2_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregxiv2df (__o, (float64x2_t) __temp.val[2], 2); + __o = __builtin_aarch64_set_qregxiv2df (__o, (float64x2_t) __temp.val[3], 3); + __o = __builtin_aarch64_ld4_lanedf ( + (__builtin_aarch64_simd_df *) __ptr, __o, __c); + __b.val[0] = (float64x1_t) __builtin_aarch64_get_dregxidi (__o, 0); + __b.val[1] = (float64x1_t) __builtin_aarch64_get_dregxidi (__o, 1); + __b.val[2] = (float64x1_t) __builtin_aarch64_get_dregxidi (__o, 2); + __b.val[3] = (float64x1_t) __builtin_aarch64_get_dregxidi (__o, 3); + return __b; +} + +__extension__ extern __inline poly8x8x4_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld4_lane_p8 (const poly8_t * __ptr, poly8x8x4_t __b, const int __c) +{ + __builtin_aarch64_simd_xi __o; + poly8x16x4_t __temp; + __temp.val[0] = vcombine_p8 (__b.val[0], vcreate_p8 (0)); + __temp.val[1] = vcombine_p8 (__b.val[1], vcreate_p8 (0)); + __temp.val[2] = vcombine_p8 (__b.val[2], vcreate_p8 (0)); + __temp.val[3] = vcombine_p8 (__b.val[3], vcreate_p8 (0)); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t) __temp.val[2], 2); + __o = __builtin_aarch64_set_qregxiv16qi (__o, (int8x16_t) __temp.val[3], 3); + __o = __builtin_aarch64_ld4_lanev8qi ( + (__builtin_aarch64_simd_qi *) __ptr, __o, __c); + __b.val[0] = (poly8x8_t) __builtin_aarch64_get_dregxidi (__o, 0); + __b.val[1] = (poly8x8_t) __builtin_aarch64_get_dregxidi (__o, 1); + __b.val[2] = (poly8x8_t) __builtin_aarch64_get_dregxidi (__o, 2); + __b.val[3] = (poly8x8_t) __builtin_aarch64_get_dregxidi (__o, 3); + return __b; +} -__LD4_LANE_FUNC (float16x4x4_t, float16x4_t, float16x8x4_t, float16_t, v4hf, - v8hf, hf, f16, float16x8_t) -__LD4_LANE_FUNC (float32x2x4_t, float32x2_t, float32x4x4_t, float32_t, v2sf, v4sf, - sf, f32, float32x4_t) -__LD4_LANE_FUNC (float64x1x4_t, float64x1_t, float64x2x4_t, float64_t, df, v2df, - df, f64, float64x2_t) -__LD4_LANE_FUNC (poly8x8x4_t, poly8x8_t, poly8x16x4_t, poly8_t, v8qi, v16qi, qi, p8, - int8x16_t) -__LD4_LANE_FUNC (poly16x4x4_t, poly16x4_t, poly16x8x4_t, poly16_t, v4hi, v8hi, hi, - p16, int16x8_t) -__LD4_LANE_FUNC (poly64x1x4_t, poly64x1_t, poly64x2x4_t, poly64_t, di, - v2di_ssps, di, p64, poly64x2_t) -__LD4_LANE_FUNC (int8x8x4_t, int8x8_t, int8x16x4_t, int8_t, v8qi, v16qi, qi, s8, - int8x16_t) -__LD4_LANE_FUNC (int16x4x4_t, int16x4_t, int16x8x4_t, int16_t, v4hi, v8hi, hi, s16, - int16x8_t) -__LD4_LANE_FUNC (int32x2x4_t, int32x2_t, int32x4x4_t, int32_t, v2si, v4si, si, s32, - int32x4_t) -__LD4_LANE_FUNC (int64x1x4_t, int64x1_t, int64x2x4_t, int64_t, di, v2di, di, s64, - int64x2_t) -__LD4_LANE_FUNC (uint8x8x4_t, uint8x8_t, uint8x16x4_t, uint8_t, v8qi, v16qi, qi, u8, - int8x16_t) -__LD4_LANE_FUNC (uint16x4x4_t, uint16x4_t, uint16x8x4_t, uint16_t, v4hi, v8hi, hi, - u16, int16x8_t) -__LD4_LANE_FUNC (uint32x2x4_t, uint32x2_t, uint32x4x4_t, uint32_t, v2si, v4si, si, - u32, int32x4_t) -__LD4_LANE_FUNC (uint64x1x4_t, uint64x1_t, uint64x2x4_t, uint64_t, di, v2di, di, - u64, int64x2_t) +__extension__ extern __inline poly16x4x4_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld4_lane_p16 (const poly16_t * __ptr, poly16x4x4_t __b, const int __c) +{ + __builtin_aarch64_simd_xi __o; + poly16x8x4_t __temp; + __temp.val[0] = vcombine_p16 (__b.val[0], vcreate_p16 (0)); + __temp.val[1] = vcombine_p16 (__b.val[1], vcreate_p16 (0)); + __temp.val[2] = vcombine_p16 (__b.val[2], vcreate_p16 (0)); + __temp.val[3] = vcombine_p16 (__b.val[3], vcreate_p16 (0)); + __o = __builtin_aarch64_set_qregxiv8hi (__o, (int16x8_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregxiv8hi (__o, (int16x8_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregxiv8hi (__o, (int16x8_t) __temp.val[2], 2); + __o = __builtin_aarch64_set_qregxiv8hi (__o, (int16x8_t) __temp.val[3], 3); + __o = __builtin_aarch64_ld4_lanev4hi ( + (__builtin_aarch64_simd_hi *) __ptr, __o, __c); + __b.val[0] = (poly16x4_t) __builtin_aarch64_get_dregxidi (__o, 0); + __b.val[1] = (poly16x4_t) __builtin_aarch64_get_dregxidi (__o, 1); + __b.val[2] = (poly16x4_t) __builtin_aarch64_get_dregxidi (__o, 2); + __b.val[3] = (poly16x4_t) __builtin_aarch64_get_dregxidi (__o, 3); + return __b; +} + +__extension__ extern __inline poly64x1x4_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld4_lane_p64 (const poly64_t * __ptr, poly64x1x4_t __b, const int __c) +{ + __builtin_aarch64_simd_xi __o; + poly64x2x4_t __temp; + __temp.val[0] = vcombine_p64 (__b.val[0], vcreate_p64 (0)); + __temp.val[1] = vcombine_p64 (__b.val[1], vcreate_p64 (0)); + __temp.val[2] = vcombine_p64 (__b.val[2], vcreate_p64 (0)); + __temp.val[3] = vcombine_p64 (__b.val[3], vcreate_p64 (0)); + __o = __builtin_aarch64_set_qregxiv2di (__o, (int64x2_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregxiv2di (__o, (int64x2_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregxiv2di (__o, (int64x2_t) __temp.val[2], 2); + __o = __builtin_aarch64_set_qregxiv2di (__o, (int64x2_t) __temp.val[3], 3); + __o = __builtin_aarch64_ld4_lanedi ( + (__builtin_aarch64_simd_di *) __ptr, __o, __c); + __b.val[0] = (poly64x1_t) __builtin_aarch64_get_dregxidi (__o, 0); + __b.val[1] = (poly64x1_t) __builtin_aarch64_get_dregxidi (__o, 1); + __b.val[2] = (poly64x1_t) __builtin_aarch64_get_dregxidi (__o, 2); + __b.val[3] = (poly64x1_t) __builtin_aarch64_get_dregxidi (__o, 3); + return __b; +} /* vld4q_lane */ -#define __LD4Q_LANE_FUNC(intype, vtype, ptrtype, mode, ptrmode, funcsuffix) \ -__extension__ extern __inline intype \ -__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) \ -vld4q_lane_##funcsuffix (const ptrtype * __ptr, intype __b, const int __c) \ -{ \ - __builtin_aarch64_simd_xi __o; \ - intype ret; \ - __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[0], 0); \ - __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[1], 1); \ - __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[2], 2); \ - __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[3], 3); \ - __o = __builtin_aarch64_ld4_lane##mode ( \ - (__builtin_aarch64_simd_##ptrmode *) __ptr, __o, __c); \ - ret.val[0] = (vtype) __builtin_aarch64_get_qregxiv4si (__o, 0); \ - ret.val[1] = (vtype) __builtin_aarch64_get_qregxiv4si (__o, 1); \ - ret.val[2] = (vtype) __builtin_aarch64_get_qregxiv4si (__o, 2); \ - ret.val[3] = (vtype) __builtin_aarch64_get_qregxiv4si (__o, 3); \ - return ret; \ -} - -__LD4Q_LANE_FUNC (float16x8x4_t, float16x8_t, float16_t, v8hf, hf, f16) -__LD4Q_LANE_FUNC (float32x4x4_t, float32x4_t, float32_t, v4sf, sf, f32) -__LD4Q_LANE_FUNC (float64x2x4_t, float64x2_t, float64_t, v2df, df, f64) -__LD4Q_LANE_FUNC (poly8x16x4_t, poly8x16_t, poly8_t, v16qi, qi, p8) -__LD4Q_LANE_FUNC (poly16x8x4_t, poly16x8_t, poly16_t, v8hi, hi, p16) -__LD4Q_LANE_FUNC (poly64x2x4_t, poly64x2_t, poly64_t, v2di, di, p64) -__LD4Q_LANE_FUNC (int8x16x4_t, int8x16_t, int8_t, v16qi, qi, s8) -__LD4Q_LANE_FUNC (int16x8x4_t, int16x8_t, int16_t, v8hi, hi, s16) -__LD4Q_LANE_FUNC (int32x4x4_t, int32x4_t, int32_t, v4si, si, s32) -__LD4Q_LANE_FUNC (int64x2x4_t, int64x2_t, int64_t, v2di, di, s64) -__LD4Q_LANE_FUNC (uint8x16x4_t, uint8x16_t, uint8_t, v16qi, qi, u8) -__LD4Q_LANE_FUNC (uint16x8x4_t, uint16x8_t, uint16_t, v8hi, hi, u16) -__LD4Q_LANE_FUNC (uint32x4x4_t, uint32x4_t, uint32_t, v4si, si, u32) -__LD4Q_LANE_FUNC (uint64x2x4_t, uint64x2_t, uint64_t, v2di, di, u64) +__extension__ extern __inline uint8x16x4_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld4q_lane_u8 (const uint8_t * __ptr, uint8x16x4_t __b, const int __c) +{ + __builtin_aarch64_simd_xi __o; + uint8x16x4_t ret; + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[2], 2); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[3], 3); + __o = __builtin_aarch64_ld4_lanev16qi ( + (__builtin_aarch64_simd_qi *) __ptr, __o, __c); + ret.val[0] = (uint8x16_t) __builtin_aarch64_get_qregxiv4si (__o, 0); + ret.val[1] = (uint8x16_t) __builtin_aarch64_get_qregxiv4si (__o, 1); + ret.val[2] = (uint8x16_t) __builtin_aarch64_get_qregxiv4si (__o, 2); + ret.val[3] = (uint8x16_t) __builtin_aarch64_get_qregxiv4si (__o, 3); + return ret; +} + +__extension__ extern __inline uint16x8x4_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld4q_lane_u16 (const uint16_t * __ptr, uint16x8x4_t __b, const int __c) +{ + __builtin_aarch64_simd_xi __o; + uint16x8x4_t ret; + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[2], 2); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[3], 3); + __o = __builtin_aarch64_ld4_lanev8hi ( + (__builtin_aarch64_simd_hi *) __ptr, __o, __c); + ret.val[0] = (uint16x8_t) __builtin_aarch64_get_qregxiv4si (__o, 0); + ret.val[1] = (uint16x8_t) __builtin_aarch64_get_qregxiv4si (__o, 1); + ret.val[2] = (uint16x8_t) __builtin_aarch64_get_qregxiv4si (__o, 2); + ret.val[3] = (uint16x8_t) __builtin_aarch64_get_qregxiv4si (__o, 3); + return ret; +} + +__extension__ extern __inline uint32x4x4_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld4q_lane_u32 (const uint32_t * __ptr, uint32x4x4_t __b, const int __c) +{ + __builtin_aarch64_simd_xi __o; + uint32x4x4_t ret; + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[2], 2); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[3], 3); + __o = __builtin_aarch64_ld4_lanev4si ( + (__builtin_aarch64_simd_si *) __ptr, __o, __c); + ret.val[0] = (uint32x4_t) __builtin_aarch64_get_qregxiv4si (__o, 0); + ret.val[1] = (uint32x4_t) __builtin_aarch64_get_qregxiv4si (__o, 1); + ret.val[2] = (uint32x4_t) __builtin_aarch64_get_qregxiv4si (__o, 2); + ret.val[3] = (uint32x4_t) __builtin_aarch64_get_qregxiv4si (__o, 3); + return ret; +} + +__extension__ extern __inline uint64x2x4_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld4q_lane_u64 (const uint64_t * __ptr, uint64x2x4_t __b, const int __c) +{ + __builtin_aarch64_simd_xi __o; + uint64x2x4_t ret; + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[2], 2); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[3], 3); + __o = __builtin_aarch64_ld4_lanev2di ( + (__builtin_aarch64_simd_di *) __ptr, __o, __c); + ret.val[0] = (uint64x2_t) __builtin_aarch64_get_qregxiv4si (__o, 0); + ret.val[1] = (uint64x2_t) __builtin_aarch64_get_qregxiv4si (__o, 1); + ret.val[2] = (uint64x2_t) __builtin_aarch64_get_qregxiv4si (__o, 2); + ret.val[3] = (uint64x2_t) __builtin_aarch64_get_qregxiv4si (__o, 3); + return ret; +} + +__extension__ extern __inline int8x16x4_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld4q_lane_s8 (const int8_t * __ptr, int8x16x4_t __b, const int __c) +{ + __builtin_aarch64_simd_xi __o; + int8x16x4_t ret; + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[2], 2); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[3], 3); + __o = __builtin_aarch64_ld4_lanev16qi ( + (__builtin_aarch64_simd_qi *) __ptr, __o, __c); + ret.val[0] = (int8x16_t) __builtin_aarch64_get_qregxiv4si (__o, 0); + ret.val[1] = (int8x16_t) __builtin_aarch64_get_qregxiv4si (__o, 1); + ret.val[2] = (int8x16_t) __builtin_aarch64_get_qregxiv4si (__o, 2); + ret.val[3] = (int8x16_t) __builtin_aarch64_get_qregxiv4si (__o, 3); + return ret; +} + +__extension__ extern __inline int16x8x4_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld4q_lane_s16 (const int16_t * __ptr, int16x8x4_t __b, const int __c) +{ + __builtin_aarch64_simd_xi __o; + int16x8x4_t ret; + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[2], 2); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[3], 3); + __o = __builtin_aarch64_ld4_lanev8hi ( + (__builtin_aarch64_simd_hi *) __ptr, __o, __c); + ret.val[0] = (int16x8_t) __builtin_aarch64_get_qregxiv4si (__o, 0); + ret.val[1] = (int16x8_t) __builtin_aarch64_get_qregxiv4si (__o, 1); + ret.val[2] = (int16x8_t) __builtin_aarch64_get_qregxiv4si (__o, 2); + ret.val[3] = (int16x8_t) __builtin_aarch64_get_qregxiv4si (__o, 3); + return ret; +} + +__extension__ extern __inline int32x4x4_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld4q_lane_s32 (const int32_t * __ptr, int32x4x4_t __b, const int __c) +{ + __builtin_aarch64_simd_xi __o; + int32x4x4_t ret; + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[2], 2); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[3], 3); + __o = __builtin_aarch64_ld4_lanev4si ( + (__builtin_aarch64_simd_si *) __ptr, __o, __c); + ret.val[0] = (int32x4_t) __builtin_aarch64_get_qregxiv4si (__o, 0); + ret.val[1] = (int32x4_t) __builtin_aarch64_get_qregxiv4si (__o, 1); + ret.val[2] = (int32x4_t) __builtin_aarch64_get_qregxiv4si (__o, 2); + ret.val[3] = (int32x4_t) __builtin_aarch64_get_qregxiv4si (__o, 3); + return ret; +} + +__extension__ extern __inline int64x2x4_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld4q_lane_s64 (const int64_t * __ptr, int64x2x4_t __b, const int __c) +{ + __builtin_aarch64_simd_xi __o; + int64x2x4_t ret; + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[2], 2); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[3], 3); + __o = __builtin_aarch64_ld4_lanev2di ( + (__builtin_aarch64_simd_di *) __ptr, __o, __c); + ret.val[0] = (int64x2_t) __builtin_aarch64_get_qregxiv4si (__o, 0); + ret.val[1] = (int64x2_t) __builtin_aarch64_get_qregxiv4si (__o, 1); + ret.val[2] = (int64x2_t) __builtin_aarch64_get_qregxiv4si (__o, 2); + ret.val[3] = (int64x2_t) __builtin_aarch64_get_qregxiv4si (__o, 3); + return ret; +} + +__extension__ extern __inline float16x8x4_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld4q_lane_f16 (const float16_t * __ptr, float16x8x4_t __b, const int __c) +{ + __builtin_aarch64_simd_xi __o; + float16x8x4_t ret; + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[2], 2); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[3], 3); + __o = __builtin_aarch64_ld4_lanev8hf ( + (__builtin_aarch64_simd_hf *) __ptr, __o, __c); + ret.val[0] = (float16x8_t) __builtin_aarch64_get_qregxiv4si (__o, 0); + ret.val[1] = (float16x8_t) __builtin_aarch64_get_qregxiv4si (__o, 1); + ret.val[2] = (float16x8_t) __builtin_aarch64_get_qregxiv4si (__o, 2); + ret.val[3] = (float16x8_t) __builtin_aarch64_get_qregxiv4si (__o, 3); + return ret; +} + +__extension__ extern __inline float32x4x4_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld4q_lane_f32 (const float32_t * __ptr, float32x4x4_t __b, const int __c) +{ + __builtin_aarch64_simd_xi __o; + float32x4x4_t ret; + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[2], 2); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[3], 3); + __o = __builtin_aarch64_ld4_lanev4sf ( + (__builtin_aarch64_simd_sf *) __ptr, __o, __c); + ret.val[0] = (float32x4_t) __builtin_aarch64_get_qregxiv4si (__o, 0); + ret.val[1] = (float32x4_t) __builtin_aarch64_get_qregxiv4si (__o, 1); + ret.val[2] = (float32x4_t) __builtin_aarch64_get_qregxiv4si (__o, 2); + ret.val[3] = (float32x4_t) __builtin_aarch64_get_qregxiv4si (__o, 3); + return ret; +} + +__extension__ extern __inline float64x2x4_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld4q_lane_f64 (const float64_t * __ptr, float64x2x4_t __b, const int __c) +{ + __builtin_aarch64_simd_xi __o; + float64x2x4_t ret; + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[2], 2); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[3], 3); + __o = __builtin_aarch64_ld4_lanev2df ( + (__builtin_aarch64_simd_di *) __ptr, __o, __c); + ret.val[0] = (float64x2_t) __builtin_aarch64_get_qregxiv4si (__o, 0); + ret.val[1] = (float64x2_t) __builtin_aarch64_get_qregxiv4si (__o, 1); + ret.val[2] = (float64x2_t) __builtin_aarch64_get_qregxiv4si (__o, 2); + ret.val[3] = (float64x2_t) __builtin_aarch64_get_qregxiv4si (__o, 3); + return ret; +} + +__extension__ extern __inline poly8x16x4_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld4q_lane_p8 (const poly8_t * __ptr, poly8x16x4_t __b, const int __c) +{ + __builtin_aarch64_simd_xi __o; + poly8x16x4_t ret; + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[2], 2); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[3], 3); + __o = __builtin_aarch64_ld4_lanev16qi ( + (__builtin_aarch64_simd_qi *) __ptr, __o, __c); + ret.val[0] = (poly8x16_t) __builtin_aarch64_get_qregxiv4si (__o, 0); + ret.val[1] = (poly8x16_t) __builtin_aarch64_get_qregxiv4si (__o, 1); + ret.val[2] = (poly8x16_t) __builtin_aarch64_get_qregxiv4si (__o, 2); + ret.val[3] = (poly8x16_t) __builtin_aarch64_get_qregxiv4si (__o, 3); + return ret; +} + +__extension__ extern __inline poly16x8x4_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld4q_lane_p16 (const poly16_t * __ptr, poly16x8x4_t __b, const int __c) +{ + __builtin_aarch64_simd_xi __o; + poly16x8x4_t ret; + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[2], 2); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[3], 3); + __o = __builtin_aarch64_ld4_lanev8hi ( + (__builtin_aarch64_simd_hi *) __ptr, __o, __c); + ret.val[0] = (poly16x8_t) __builtin_aarch64_get_qregxiv4si (__o, 0); + ret.val[1] = (poly16x8_t) __builtin_aarch64_get_qregxiv4si (__o, 1); + ret.val[2] = (poly16x8_t) __builtin_aarch64_get_qregxiv4si (__o, 2); + ret.val[3] = (poly16x8_t) __builtin_aarch64_get_qregxiv4si (__o, 3); + return ret; +} + +__extension__ extern __inline poly64x2x4_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld4q_lane_p64 (const poly64_t * __ptr, poly64x2x4_t __b, const int __c) +{ + __builtin_aarch64_simd_xi __o; + poly64x2x4_t ret; + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[2], 2); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[3], 3); + __o = __builtin_aarch64_ld4_lanev2di ( + (__builtin_aarch64_simd_di *) __ptr, __o, __c); + ret.val[0] = (poly64x2_t) __builtin_aarch64_get_qregxiv4si (__o, 0); + ret.val[1] = (poly64x2_t) __builtin_aarch64_get_qregxiv4si (__o, 1); + ret.val[2] = (poly64x2_t) __builtin_aarch64_get_qregxiv4si (__o, 2); + ret.val[3] = (poly64x2_t) __builtin_aarch64_get_qregxiv4si (__o, 3); + return ret; +} /* vmax */ @@ -35441,9 +35926,47 @@ vld3q_lane_bf16 (const bfloat16_t * __ptr, bfloat16x8x3_t __b, const int __c) return ret; } -__LD4_LANE_FUNC (bfloat16x4x4_t, bfloat16x4_t, bfloat16x8x4_t, bfloat16_t, v4bf, - v8bf, bf, bf16, bfloat16x8_t) -__LD4Q_LANE_FUNC (bfloat16x8x4_t, bfloat16x8_t, bfloat16_t, v8bf, bf, bf16) +__extension__ extern __inline bfloat16x4x4_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld4_lane_bf16 (const bfloat16_t * __ptr, bfloat16x4x4_t __b, const int __c) +{ + __builtin_aarch64_simd_xi __o; + bfloat16x8x4_t __temp; + __temp.val[0] = vcombine_bf16 (__b.val[0], vcreate_bf16 (0)); + __temp.val[1] = vcombine_bf16 (__b.val[1], vcreate_bf16 (0)); + __temp.val[2] = vcombine_bf16 (__b.val[2], vcreate_bf16 (0)); + __temp.val[3] = vcombine_bf16 (__b.val[3], vcreate_bf16 (0)); + __o = __builtin_aarch64_set_qregxiv8bf (__o, (bfloat16x8_t) __temp.val[0], 0); + __o = __builtin_aarch64_set_qregxiv8bf (__o, (bfloat16x8_t) __temp.val[1], 1); + __o = __builtin_aarch64_set_qregxiv8bf (__o, (bfloat16x8_t) __temp.val[2], 2); + __o = __builtin_aarch64_set_qregxiv8bf (__o, (bfloat16x8_t) __temp.val[3], 3); + __o = __builtin_aarch64_ld4_lanev4bf ( + (__builtin_aarch64_simd_bf *) __ptr, __o, __c); + __b.val[0] = (bfloat16x4_t) __builtin_aarch64_get_dregxidi (__o, 0); + __b.val[1] = (bfloat16x4_t) __builtin_aarch64_get_dregxidi (__o, 1); + __b.val[2] = (bfloat16x4_t) __builtin_aarch64_get_dregxidi (__o, 2); + __b.val[3] = (bfloat16x4_t) __builtin_aarch64_get_dregxidi (__o, 3); + return __b; +} + +__extension__ extern __inline bfloat16x8x4_t +__attribute__ ((__always_inline__, __gnu_inline__,__artificial__)) +vld4q_lane_bf16 (const bfloat16_t * __ptr, bfloat16x8x4_t __b, const int __c) +{ + __builtin_aarch64_simd_xi __o; + bfloat16x8x4_t ret; + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[0], 0); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[1], 1); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[2], 2); + __o = __builtin_aarch64_set_qregxiv4si (__o, (int32x4_t) __b.val[3], 3); + __o = __builtin_aarch64_ld4_lanev8bf ( + (__builtin_aarch64_simd_bf *) __ptr, __o, __c); + ret.val[0] = (bfloat16x8_t) __builtin_aarch64_get_qregxiv4si (__o, 0); + ret.val[1] = (bfloat16x8_t) __builtin_aarch64_get_qregxiv4si (__o, 1); + ret.val[2] = (bfloat16x8_t) __builtin_aarch64_get_qregxiv4si (__o, 2); + ret.val[3] = (bfloat16x8_t) __builtin_aarch64_get_qregxiv4si (__o, 3); + return ret; +} __extension__ extern __inline void __attribute__ ((__always_inline__, __gnu_inline__, __artificial__)) @@ -35739,7 +36262,4 @@ vaddq_p128 (poly128_t __a, poly128_t __b) #undef __aarch64_vdupq_laneq_u32 #undef __aarch64_vdupq_laneq_u64 -#undef __LD4_LANE_FUNC -#undef __LD4Q_LANE_FUNC - #endif -- cgit v1.1 From 3ed8da759b52708f6874af2afc6ab56b1fb00cec Mon Sep 17 00:00:00 2001 From: Alexandre Oliva Date: Sat, 24 Jul 2021 23:05:32 -0300 Subject: don't access cfun in dump_function_to_file dump_function_to_file takes the function to dump as a parameter, and parts of it use the local fun variable where cfun would be used elsewhere. Others use cfun, presumably in error. Fixed to use fun uniformly. Added a few more tests for non-NULL fun before dereferencing it. for gcc/ChangeLog * tree-cfg.c (dump_function_to_file): Use fun, not cfun. --- gcc/tree-cfg.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'gcc') diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c index 9883eaa..61b5391 100644 --- a/gcc/tree-cfg.c +++ b/gcc/tree-cfg.c @@ -8075,9 +8075,9 @@ dump_function_to_file (tree fndecl, FILE *file, dump_flags_t flags) : (fun->curr_properties & PROP_cfg) ? "cfg" : ""); - if (cfun->cfg) + if (fun && fun->cfg) { - basic_block bb = ENTRY_BLOCK_PTR_FOR_FN (cfun); + basic_block bb = ENTRY_BLOCK_PTR_FOR_FN (fun); if (bb->count.initialized_p ()) fprintf (file, ",%s(%" PRIu64 ")", profile_quality_as_string (bb->count.quality ()), @@ -8163,8 +8163,8 @@ dump_function_to_file (tree fndecl, FILE *file, dump_flags_t flags) tree name; - if (gimple_in_ssa_p (cfun)) - FOR_EACH_SSA_NAME (ix, name, cfun) + if (gimple_in_ssa_p (fun)) + FOR_EACH_SSA_NAME (ix, name, fun) { if (!SSA_NAME_VAR (name) /* SSA name with decls without a name still get @@ -8200,7 +8200,7 @@ dump_function_to_file (tree fndecl, FILE *file, dump_flags_t flags) fprintf (file, "}\n"); } - else if (fun->curr_properties & PROP_gimple_any) + else if (fun && (fun->curr_properties & PROP_gimple_any)) { /* The function is now in GIMPLE form but the CFG has not been built yet. Emit the single sequence of GIMPLE statements -- cgit v1.1 From 6bcbf80c6e2bd8a60d88bbcac3d70ffb67f4888f Mon Sep 17 00:00:00 2001 From: Alexandre Oliva Date: Sat, 24 Jul 2021 23:05:33 -0300 Subject: retain debug stmt order when moving to successors We iterate over debug stmts from the last one in new_bb, and we insert them before the first post-label stmt in each dest block, without moving the insertion iterator, so they end up reversed. Moving the insertion iterator fixes this. for gcc/ChangeLog * tree-inline.c (maybe_move_debug_stmts_to_successors): Don't reverse debug stmts. --- gcc/tree-inline.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'gcc') diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c index c5d6b1e..5955ff1 100644 --- a/gcc/tree-inline.c +++ b/gcc/tree-inline.c @@ -2880,7 +2880,7 @@ maybe_move_debug_stmts_to_successors (copy_body_data *id, basic_block new_bb) gimple_set_location (stmt, UNKNOWN_LOCATION); } gsi_remove (&si, false); - gsi_insert_before (&dsi, stmt, GSI_SAME_STMT); + gsi_insert_before (&dsi, stmt, GSI_NEW_STMT); continue; } @@ -2906,7 +2906,7 @@ maybe_move_debug_stmts_to_successors (copy_body_data *id, basic_block new_bb) new_stmt = as_a (gimple_copy (stmt)); else gcc_unreachable (); - gsi_insert_before (&dsi, new_stmt, GSI_SAME_STMT); + gsi_insert_before (&dsi, new_stmt, GSI_NEW_STMT); id->debug_stmts.safe_push (new_stmt); gsi_prev (&ssi); } -- cgit v1.1 From 9c560cf23996271ee26dfc4a1d8484b85173cd12 Mon Sep 17 00:00:00 2001 From: Christophe Lyon Date: Tue, 17 Aug 2021 12:59:26 +0000 Subject: Do not enable DT_INIT_ARRAY/DT_FINI_ARRAY on uclinuxfdpiceabi Commit r12-1328 enabled DT_INIT_ARRAY/DT_FINI_ARRAY for all Linux targets, but this does not work for arm-none-uclinuxfdpiceabi: it makes all the execution tests fail. This patch restores the original behavior for uclinuxfdpiceabi. 2021-08-12 Christophe Lyon gcc/ PR target/100896 * config.gcc (gcc_cv_initfini_array): Leave undefined for uclinuxfdpiceabi targets. --- gcc/config.gcc | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'gcc') diff --git a/gcc/config.gcc b/gcc/config.gcc index 7001a79..d9bfbfd 100644 --- a/gcc/config.gcc +++ b/gcc/config.gcc @@ -851,8 +851,14 @@ case ${target} in tmake_file="${tmake_file} t-glibc" target_has_targetcm=yes target_has_targetdm=yes - # Linux targets always support .init_array. - gcc_cv_initfini_array=yes + case $target in + *-*-*uclibc* | *-*-uclinuxfdpiceabi) + ;; + *) + # Linux targets always support .init_array. + gcc_cv_initfini_array=yes + ;; + esac ;; *-*-netbsd*) tm_p_file="${tm_p_file} netbsd-protos.h" -- cgit v1.1 From f8d535f3fec81c1cc84e22df5500e693544ec65b Mon Sep 17 00:00:00 2001 From: Tobias Burnus Date: Tue, 17 Aug 2021 15:50:11 +0200 Subject: Fortran: Implement OpenMP 5.1 scope construct Fortran version to commit e45483c7c4badc4bf2d6ced22360ce1ab172967f, which implemented OpenMP's scope construct for C and C++. Most testcases are based on the C testcases; it also contains some testcases which existed previously but had no Fortran equivalent. gcc/fortran/ChangeLog: * dump-parse-tree.c (show_omp_node, show_code_node): Handle EXEC_OMP_SCOPE. * gfortran.h (enum gfc_statement): Add ST_OMP_(END_)SCOPE. (enum gfc_exec_op): Add EXEC_OMP_SCOPE. * match.h (gfc_match_omp_scope): New. * openmp.c (OMP_SCOPE_CLAUSES): Define (gfc_match_omp_scope): New. (gfc_match_omp_cancellation_point, gfc_match_omp_end_nowait): Improve error diagnostic. (omp_code_to_statement): Handle ST_OMP_SCOPE. (gfc_resolve_omp_directive): Handle EXEC_OMP_SCOPE. * parse.c (decode_omp_directive, next_statement, gfc_ascii_statement, parse_omp_structured_block, parse_executable): Handle OpenMP's scope construct. * resolve.c (gfc_resolve_blocks): Likewise * st.c (gfc_free_statement): Likewise * trans-openmp.c (gfc_trans_omp_scope): New. (gfc_trans_omp_directive): Call it. * trans.c (trans_code): handle EXEC_OMP_SCOPE. libgomp/ChangeLog: * testsuite/libgomp.fortran/scope-1.f90: New test. * testsuite/libgomp.fortran/task-reduction-16.f90: New test. gcc/testsuite/ChangeLog: * gfortran.dg/gomp/scan-1.f90: * gfortran.dg/gomp/cancel-1.f90: New test. * gfortran.dg/gomp/cancel-4.f90: New test. * gfortran.dg/gomp/loop-4.f90: New test. * gfortran.dg/gomp/nesting-1.f90: New test. * gfortran.dg/gomp/nesting-2.f90: New test. * gfortran.dg/gomp/nesting-3.f90: New test. * gfortran.dg/gomp/nowait-1.f90: New test. * gfortran.dg/gomp/reduction-task-1.f90: New test. * gfortran.dg/gomp/reduction-task-2.f90: New test. * gfortran.dg/gomp/reduction-task-2a.f90: New test. * gfortran.dg/gomp/reduction-task-3.f90: New test. * gfortran.dg/gomp/scope-1.f90: New test. * gfortran.dg/gomp/scope-2.f90: New test. --- gcc/fortran/dump-parse-tree.c | 3 + gcc/fortran/gfortran.h | 4 +- gcc/fortran/match.h | 1 + gcc/fortran/openmp.c | 23 +- gcc/fortran/parse.c | 13 +- gcc/fortran/resolve.c | 2 + gcc/fortran/st.c | 1 + gcc/fortran/trans-openmp.c | 20 + gcc/fortran/trans.c | 1 + gcc/testsuite/gfortran.dg/gomp/cancel-1.f90 | 539 +++++++++++++++++++++ gcc/testsuite/gfortran.dg/gomp/cancel-4.f90 | 9 + gcc/testsuite/gfortran.dg/gomp/loop-4.f90 | 279 +++++++++++ gcc/testsuite/gfortran.dg/gomp/nesting-1.f90 | 68 +++ gcc/testsuite/gfortran.dg/gomp/nesting-2.f90 | 165 +++++++ gcc/testsuite/gfortran.dg/gomp/nesting-3.f90 | 347 +++++++++++++ gcc/testsuite/gfortran.dg/gomp/nowait-1.f90 | 19 + .../gfortran.dg/gomp/reduction-task-1.f90 | 112 +++++ .../gfortran.dg/gomp/reduction-task-2.f90 | 45 ++ .../gfortran.dg/gomp/reduction-task-2a.f90 | 30 ++ .../gfortran.dg/gomp/reduction-task-3.f90 | 15 + gcc/testsuite/gfortran.dg/gomp/scan-1.f90 | 5 + gcc/testsuite/gfortran.dg/gomp/scope-1.f90 | 39 ++ gcc/testsuite/gfortran.dg/gomp/scope-2.f90 | 40 ++ 23 files changed, 1774 insertions(+), 6 deletions(-) create mode 100644 gcc/testsuite/gfortran.dg/gomp/cancel-1.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/cancel-4.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/loop-4.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/nesting-1.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/nesting-2.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/nesting-3.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/nowait-1.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/reduction-task-1.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/reduction-task-2.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/reduction-task-2a.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/reduction-task-3.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/scope-1.f90 create mode 100644 gcc/testsuite/gfortran.dg/gomp/scope-2.f90 (limited to 'gcc') diff --git a/gcc/fortran/dump-parse-tree.c b/gcc/fortran/dump-parse-tree.c index 53c49fe..92d9f9e 100644 --- a/gcc/fortran/dump-parse-tree.c +++ b/gcc/fortran/dump-parse-tree.c @@ -1977,6 +1977,7 @@ show_omp_node (int level, gfc_code *c) case EXEC_OMP_PARALLEL_SECTIONS: name = "PARALLEL SECTIONS"; break; case EXEC_OMP_PARALLEL_WORKSHARE: name = "PARALLEL WORKSHARE"; break; case EXEC_OMP_SCAN: name = "SCAN"; break; + case EXEC_OMP_SCOPE: name = "SCOPE"; break; case EXEC_OMP_SECTIONS: name = "SECTIONS"; break; case EXEC_OMP_SIMD: name = "SIMD"; break; case EXEC_OMP_SINGLE: name = "SINGLE"; break; @@ -2060,6 +2061,7 @@ show_omp_node (int level, gfc_code *c) case EXEC_OMP_PARALLEL_SECTIONS: case EXEC_OMP_PARALLEL_WORKSHARE: case EXEC_OMP_SCAN: + case EXEC_OMP_SCOPE: case EXEC_OMP_SECTIONS: case EXEC_OMP_SIMD: case EXEC_OMP_SINGLE: @@ -3288,6 +3290,7 @@ show_code_node (int level, gfc_code *c) case EXEC_OMP_PARALLEL_SECTIONS: case EXEC_OMP_PARALLEL_WORKSHARE: case EXEC_OMP_SCAN: + case EXEC_OMP_SCOPE: case EXEC_OMP_SECTIONS: case EXEC_OMP_SIMD: case EXEC_OMP_SINGLE: diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h index 5fde417..a7d82ae 100644 --- a/gcc/fortran/gfortran.h +++ b/gcc/fortran/gfortran.h @@ -281,7 +281,7 @@ enum gfc_statement ST_OMP_PARALLEL_MASKED_TASKLOOP_SIMD, ST_OMP_END_PARALLEL_MASKED_TASKLOOP_SIMD, ST_OMP_MASKED_TASKLOOP, ST_OMP_END_MASKED_TASKLOOP, ST_OMP_MASKED_TASKLOOP_SIMD, - ST_OMP_END_MASKED_TASKLOOP_SIMD, ST_NONE + ST_OMP_END_MASKED_TASKLOOP_SIMD, ST_OMP_SCOPE, ST_OMP_END_SCOPE, ST_NONE }; /* Types of interfaces that we can have. Assignment interfaces are @@ -2768,7 +2768,7 @@ enum gfc_exec_op EXEC_OMP_TEAMS_LOOP, EXEC_OMP_TARGET_PARALLEL_LOOP, EXEC_OMP_TARGET_TEAMS_LOOP, EXEC_OMP_MASKED, EXEC_OMP_PARALLEL_MASKED, EXEC_OMP_PARALLEL_MASKED_TASKLOOP, EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD, - EXEC_OMP_MASKED_TASKLOOP, EXEC_OMP_MASKED_TASKLOOP_SIMD + EXEC_OMP_MASKED_TASKLOOP, EXEC_OMP_MASKED_TASKLOOP_SIMD, EXEC_OMP_SCOPE }; typedef struct gfc_code diff --git a/gcc/fortran/match.h b/gcc/fortran/match.h index dce6503..aac16a8 100644 --- a/gcc/fortran/match.h +++ b/gcc/fortran/match.h @@ -190,6 +190,7 @@ match gfc_match_omp_parallel_master_taskloop_simd (void); match gfc_match_omp_parallel_sections (void); match gfc_match_omp_parallel_workshare (void); match gfc_match_omp_requires (void); +match gfc_match_omp_scope (void); match gfc_match_omp_scan (void); match gfc_match_omp_sections (void); match gfc_match_omp_simd (void); diff --git a/gcc/fortran/openmp.c b/gcc/fortran/openmp.c index 1bce43c..9675b65 100644 --- a/gcc/fortran/openmp.c +++ b/gcc/fortran/openmp.c @@ -3150,6 +3150,8 @@ cleanup: #define OMP_LOOP_CLAUSES \ (omp_mask (OMP_CLAUSE_BIND) | OMP_CLAUSE_COLLAPSE | OMP_CLAUSE_ORDER \ | OMP_CLAUSE_PRIVATE | OMP_CLAUSE_LASTPRIVATE | OMP_CLAUSE_REDUCTION) +#define OMP_SCOPE_CLAUSES \ + (omp_mask (OMP_CLAUSE_PRIVATE) | OMP_CLAUSE_REDUCTION) #define OMP_SECTIONS_CLAUSES \ (omp_mask (OMP_CLAUSE_PRIVATE) | OMP_CLAUSE_FIRSTPRIVATE \ | OMP_CLAUSE_LASTPRIVATE | OMP_CLAUSE_REDUCTION) @@ -4488,6 +4490,13 @@ gfc_match_omp_scan (void) match +gfc_match_omp_scope (void) +{ + return match_omp (EXEC_OMP_SCOPE, OMP_SCOPE_CLAUSES); +} + + +match gfc_match_omp_sections (void) { return match_omp (EXEC_OMP_SECTIONS, OMP_SECTIONS_CLAUSES); @@ -4975,7 +4984,11 @@ gfc_match_omp_cancellation_point (void) gfc_omp_clauses *c; enum gfc_omp_cancel_kind kind = gfc_match_omp_cancel_kind (); if (kind == OMP_CANCEL_UNKNOWN) - return MATCH_ERROR; + { + gfc_error ("Expected construct-type PARALLEL, SECTIONS, DO or TASKGROUP " + "in $OMP CANCELLATION POINT statement at %C"); + return MATCH_ERROR; + } if (gfc_match_omp_eos () != MATCH_YES) { gfc_error ("Unexpected junk after $OMP CANCELLATION POINT statement " @@ -4998,7 +5011,10 @@ gfc_match_omp_end_nowait (void) nowait = true; if (gfc_match_omp_eos () != MATCH_YES) { - gfc_error ("Unexpected junk after NOWAIT clause at %C"); + if (nowait) + gfc_error ("Unexpected junk after NOWAIT clause at %C"); + else + gfc_error ("Unexpected junk at %C"); return MATCH_ERROR; } new_st.op = EXEC_OMP_END_NOWAIT; @@ -7448,6 +7464,8 @@ omp_code_to_statement (gfc_code *code) return ST_OMP_DO_SIMD; case EXEC_OMP_SCAN: return ST_OMP_SCAN; + case EXEC_OMP_SCOPE: + return ST_OMP_SCOPE; case EXEC_OMP_SIMD: return ST_OMP_SIMD; case EXEC_OMP_TARGET: @@ -7948,6 +7966,7 @@ gfc_resolve_omp_directive (gfc_code *code, gfc_namespace *ns) case EXEC_OMP_PARALLEL_MASKED: case EXEC_OMP_PARALLEL_MASTER: case EXEC_OMP_PARALLEL_SECTIONS: + case EXEC_OMP_SCOPE: case EXEC_OMP_SECTIONS: case EXEC_OMP_SINGLE: case EXEC_OMP_TARGET: diff --git a/gcc/fortran/parse.c b/gcc/fortran/parse.c index e1d78de..24cc9bf 100644 --- a/gcc/fortran/parse.c +++ b/gcc/fortran/parse.c @@ -951,6 +951,7 @@ decode_omp_directive (void) matcho ("end parallel workshare", gfc_match_omp_eos_error, ST_OMP_END_PARALLEL_WORKSHARE); matcho ("end parallel", gfc_match_omp_eos_error, ST_OMP_END_PARALLEL); + matcho ("end scope", gfc_match_omp_end_nowait, ST_OMP_END_SCOPE); matcho ("end sections", gfc_match_omp_end_nowait, ST_OMP_END_SECTIONS); matcho ("end single", gfc_match_omp_end_single, ST_OMP_END_SINGLE); matcho ("end target data", gfc_match_omp_eos_error, ST_OMP_END_TARGET_DATA); @@ -1052,6 +1053,7 @@ decode_omp_directive (void) break; case 's': matcho ("scan", gfc_match_omp_scan, ST_OMP_SCAN); + matcho ("scope", gfc_match_omp_scope, ST_OMP_SCOPE); matcho ("sections", gfc_match_omp_sections, ST_OMP_SECTIONS); matcho ("section", gfc_match_omp_eos_error, ST_OMP_SECTION); matcho ("single", gfc_match_omp_single, ST_OMP_SINGLE); @@ -1672,7 +1674,7 @@ next_statement (void) case ST_OMP_CRITICAL: case ST_OMP_MASKED: case ST_OMP_MASKED_TASKLOOP: \ case ST_OMP_MASKED_TASKLOOP_SIMD: \ case ST_OMP_MASTER: case ST_OMP_MASTER_TASKLOOP: \ - case ST_OMP_MASTER_TASKLOOP_SIMD: case ST_OMP_SINGLE: \ + case ST_OMP_MASTER_TASKLOOP_SIMD: case ST_OMP_SCOPE: case ST_OMP_SINGLE: \ case ST_OMP_DO: case ST_OMP_PARALLEL_DO: case ST_OMP_ATOMIC: \ case ST_OMP_WORKSHARE: case ST_OMP_PARALLEL_WORKSHARE: \ case ST_OMP_TASK: case ST_OMP_TASKGROUP: case ST_OMP_SIMD: \ @@ -2609,6 +2611,9 @@ gfc_ascii_statement (gfc_statement st) case ST_OMP_SCAN: p = "!$OMP SCAN"; break; + case ST_OMP_SCOPE: + p = "!$OMP SCOPE"; + break; case ST_OMP_SECTIONS: p = "!$OMP SECTIONS"; break; @@ -5463,6 +5468,9 @@ parse_omp_structured_block (gfc_statement omp_st, bool workshare_stmts_only) case ST_OMP_PARALLEL_SECTIONS: omp_end_st = ST_OMP_END_PARALLEL_SECTIONS; break; + case ST_OMP_SCOPE: + omp_end_st = ST_OMP_END_SCOPE; + break; case ST_OMP_SECTIONS: omp_end_st = ST_OMP_END_SECTIONS; break; @@ -5763,11 +5771,12 @@ parse_executable (gfc_statement st) case ST_OMP_PARALLEL_MASKED: case ST_OMP_PARALLEL_MASTER: case ST_OMP_PARALLEL_SECTIONS: - case ST_OMP_SECTIONS: case ST_OMP_ORDERED: case ST_OMP_CRITICAL: case ST_OMP_MASKED: case ST_OMP_MASTER: + case ST_OMP_SCOPE: + case ST_OMP_SECTIONS: case ST_OMP_SINGLE: case ST_OMP_TARGET: case ST_OMP_TARGET_DATA: diff --git a/gcc/fortran/resolve.c b/gcc/fortran/resolve.c index 8eb8a9a..117062b 100644 --- a/gcc/fortran/resolve.c +++ b/gcc/fortran/resolve.c @@ -10839,6 +10839,7 @@ gfc_resolve_blocks (gfc_code *b, gfc_namespace *ns) case EXEC_OMP_PARALLEL_WORKSHARE: case EXEC_OMP_SECTIONS: case EXEC_OMP_SIMD: + case EXEC_OMP_SCOPE: case EXEC_OMP_SINGLE: case EXEC_OMP_TARGET: case EXEC_OMP_TARGET_DATA: @@ -12262,6 +12263,7 @@ start: case EXEC_OMP_MASKED_TASKLOOP_SIMD: case EXEC_OMP_ORDERED: case EXEC_OMP_SCAN: + case EXEC_OMP_SCOPE: case EXEC_OMP_SECTIONS: case EXEC_OMP_SIMD: case EXEC_OMP_SINGLE: diff --git a/gcc/fortran/st.c b/gcc/fortran/st.c index f61f88a..7d87709 100644 --- a/gcc/fortran/st.c +++ b/gcc/fortran/st.c @@ -246,6 +246,7 @@ gfc_free_statement (gfc_code *p) case EXEC_OMP_PARALLEL_SECTIONS: case EXEC_OMP_PARALLEL_WORKSHARE: case EXEC_OMP_SCAN: + case EXEC_OMP_SCOPE: case EXEC_OMP_SECTIONS: case EXEC_OMP_SIMD: case EXEC_OMP_SINGLE: diff --git a/gcc/fortran/trans-openmp.c b/gcc/fortran/trans-openmp.c index 623c21f..e0a0014 100644 --- a/gcc/fortran/trans-openmp.c +++ b/gcc/fortran/trans-openmp.c @@ -6265,6 +6265,24 @@ gfc_trans_omp_parallel_workshare (gfc_code *code) } static tree +gfc_trans_omp_scope (gfc_code *code) +{ + stmtblock_t block; + tree body = gfc_trans_code (code->block->next); + if (IS_EMPTY_STMT (body)) + return body; + gfc_start_block (&block); + tree omp_clauses = gfc_trans_omp_clauses (&block, code->ext.omp_clauses, + code->loc); + tree stmt = make_node (OMP_SCOPE); + TREE_TYPE (stmt) = void_type_node; + OMP_SCOPE_BODY (stmt) = body; + OMP_SCOPE_CLAUSES (stmt) = omp_clauses; + gfc_add_expr_to_block (&block, stmt); + return gfc_finish_block (&block); +} + +static tree gfc_trans_omp_sections (gfc_code *code, gfc_omp_clauses *clauses) { stmtblock_t block, body; @@ -7110,6 +7128,8 @@ gfc_trans_omp_directive (gfc_code *code) return gfc_trans_omp_parallel_sections (code); case EXEC_OMP_PARALLEL_WORKSHARE: return gfc_trans_omp_parallel_workshare (code); + case EXEC_OMP_SCOPE: + return gfc_trans_omp_scope (code); case EXEC_OMP_SECTIONS: return gfc_trans_omp_sections (code, code->ext.omp_clauses); case EXEC_OMP_SINGLE: diff --git a/gcc/fortran/trans.c b/gcc/fortran/trans.c index ce5b2f8..80b724d0 100644 --- a/gcc/fortran/trans.c +++ b/gcc/fortran/trans.c @@ -2175,6 +2175,7 @@ trans_code (gfc_code * code, tree cond) case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD: case EXEC_OMP_PARALLEL_SECTIONS: case EXEC_OMP_PARALLEL_WORKSHARE: + case EXEC_OMP_SCOPE: case EXEC_OMP_SECTIONS: case EXEC_OMP_SIMD: case EXEC_OMP_SINGLE: diff --git a/gcc/testsuite/gfortran.dg/gomp/cancel-1.f90 b/gcc/testsuite/gfortran.dg/gomp/cancel-1.f90 new file mode 100644 index 0000000..d60dd72 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/cancel-1.f90 @@ -0,0 +1,539 @@ +! { dg-additional-options "-cpp" } + +subroutine f1 + !$omp cancel parallel ! { dg-error "orphaned" } + !$omp cancel do ! { dg-error "orphaned" } + !$omp cancel sections ! { dg-error "orphaned" } + !$omp cancel taskgroup ! { dg-error "orphaned" } + !$omp cancellation point parallel ! { dg-error "orphaned" } + !$omp cancellation point do ! { dg-error "orphaned" } + !$omp cancellation point sections ! { dg-error "orphaned" } + !$omp cancellation point taskgroup ! { dg-error "orphaned" } +end + +subroutine f2 + integer :: i, j + j = 0 + !$omp parallel + !$omp cancel parallel + !$omp cancel do ! { dg-error "not closely nested inside" } + !$omp cancel sections ! { dg-error "not closely nested inside" } + !$omp cancel taskgroup ! { dg-error "not closely nested inside" } + !$omp cancellation point parallel + !$omp cancellation point do ! { dg-error "not closely nested inside" } + !$omp cancellation point sections ! { dg-error "not closely nested inside" } + !$omp cancellation point taskgroup ! { dg-error "not closely nested inside" } + + !$omp master + !$omp cancel parallel ! { dg-error "not closely nested inside" } + !$omp cancel do ! { dg-error "not closely nested inside" } + !$omp cancel sections ! { dg-error "not closely nested inside" } + !$omp cancel taskgroup ! { dg-error "not closely nested inside" } + !$omp cancellation point parallel ! { dg-error "not closely nested inside" } + !$omp cancellation point do ! { dg-error "not closely nested inside" } + !$omp cancellation point sections ! { dg-error "not closely nested inside" } + !$omp cancellation point taskgroup ! { dg-error "not closely nested inside" } + !$omp end master + + !$omp masked + !$omp cancel parallel ! { dg-error "not closely nested inside" } + !$omp cancel do ! { dg-error "not closely nested inside" } + !$omp cancel sections ! { dg-error "not closely nested inside" } + !$omp cancel taskgroup ! { dg-error "not closely nested inside" } + !$omp cancellation point parallel ! { dg-error "not closely nested inside" } + !$omp cancellation point do ! { dg-error "not closely nested inside" } + !$omp cancellation point sections ! { dg-error "not closely nested inside" } + !$omp cancellation point taskgroup ! { dg-error "not closely nested inside" } + !$omp end masked + + !$omp scope + !$omp cancel parallel ! { dg-error "not closely nested inside" } + !$omp cancel do ! { dg-error "not closely nested inside" } + !$omp cancel sections ! { dg-error "not closely nested inside" } + !$omp cancel taskgroup ! { dg-error "not closely nested inside" } + !$omp cancellation point parallel ! { dg-error "not closely nested inside" } + !$omp cancellation point do ! { dg-error "not closely nested inside" } + !$omp cancellation point sections ! { dg-error "not closely nested inside" } + !$omp cancellation point taskgroup ! { dg-error "not closely nested inside" } + !$omp end scope + + !$omp single + !$omp cancel parallel ! { dg-error "not closely nested inside" } + !$omp cancel do ! { dg-error "not closely nested inside" } + !$omp cancel sections ! { dg-error "not closely nested inside" } + !$omp cancel taskgroup ! { dg-error "not closely nested inside" } + !$omp cancellation point parallel ! { dg-error "not closely nested inside" } + !$omp cancellation point do ! { dg-error "not closely nested inside" } + !$omp cancellation point sections ! { dg-error "not closely nested inside" } + !$omp cancellation point taskgroup ! { dg-error "not closely nested inside" } + !$omp end single + + !$omp critical + !$omp cancel parallel ! { dg-error "not closely nested inside" } + !$omp cancel do ! { dg-error "not closely nested inside" } + !$omp cancel sections ! { dg-error "not closely nested inside" } + !$omp cancel taskgroup ! { dg-error "not closely nested inside" } + !$omp cancellation point parallel ! { dg-error "not closely nested inside" } + !$omp cancellation point do ! { dg-error "not closely nested inside" } + !$omp cancellation point sections ! { dg-error "not closely nested inside" } + !$omp cancellation point taskgroup ! { dg-error "not closely nested inside" } + !$omp end critical + + !$omp taskgroup + !$omp cancel parallel ! { dg-error "not closely nested inside" } + !$omp cancel do ! { dg-error "not closely nested inside" } + !$omp cancel sections ! { dg-error "not closely nested inside" } + !$omp cancel taskgroup ! { dg-error "not closely nested inside" } + !$omp cancellation point parallel ! { dg-error "not closely nested inside" } + !$omp cancellation point do ! { dg-error "not closely nested inside" } + !$omp cancellation point sections ! { dg-error "not closely nested inside" } + !$omp cancellation point taskgroup ! { dg-error "not closely nested inside" } + !$omp end taskgroup + + !$omp task + !$omp cancel parallel ! { dg-error "not closely nested inside" } + !$omp cancel do ! { dg-error "not closely nested inside" } + !$omp cancel sections ! { dg-error "not closely nested inside" } + !$omp cancel taskgroup ! { dg-error "construct not closely nested inside of .taskgroup. region" } + !$omp cancellation point parallel ! { dg-error "not closely nested inside" } + !$omp cancellation point do ! { dg-error "not closely nested inside" } + !$omp cancellation point sections ! { dg-error "not closely nested inside" } + !$omp cancellation point taskgroup ! { dg-error "construct not closely nested inside of .taskgroup. region" } + !$omp end task + + !$omp taskgroup + !$omp task + !$omp cancel parallel ! { dg-error "not closely nested inside" } + !$omp cancel do ! { dg-error "not closely nested inside" } + !$omp cancel sections ! { dg-error "not closely nested inside" } + !$omp cancel taskgroup + !$omp cancellation point parallel ! { dg-error "not closely nested inside" } + !$omp cancellation point do ! { dg-error "not closely nested inside" } + !$omp cancellation point sections ! { dg-error "not closely nested inside" } + !$omp cancellation point taskgroup + !$omp end task + !$omp end taskgroup + + !$omp taskloop + do i = 0, 9 + !$omp cancel parallel ! { dg-error "not closely nested inside" } + !$omp cancel do ! { dg-error "not closely nested inside" } + !$omp cancel sections ! { dg-error "not closely nested inside" } + !$omp cancel taskgroup + !$omp cancellation point parallel ! { dg-error "not closely nested inside" } + !$omp cancellation point do ! { dg-error "not closely nested inside" } + !$omp cancellation point sections ! { dg-error "not closely nested inside" } + !$omp cancellation point taskgroup + !$omp task + !$omp cancellation point taskgroup + !$omp cancel taskgroup + !$omp end task + end do + !$omp taskloop nogroup + do i = 0, 9 + !$omp cancel parallel ! { dg-error "not closely nested inside" } + !$omp cancel do ! { dg-error "not closely nested inside" } + !$omp cancel sections ! { dg-error "not closely nested inside" } + !$omp cancel taskgroup ! { dg-error "construct not closely nested inside of .taskgroup. region" } + !$omp cancellation point parallel ! { dg-error "not closely nested inside" } + !$omp cancellation point do ! { dg-error "not closely nested inside" } + !$omp cancellation point sections ! { dg-error "not closely nested inside" } + !$omp cancellation point taskgroup! { dg-error "construct not closely nested inside of .taskgroup. region" } + !$omp task + !$omp cancellation point taskgroup! { dg-error "construct not closely nested inside of .taskgroup. region" } + !$omp cancel taskgroup ! { dg-error "construct not closely nested inside of .taskgroup. region" } + !$omp end task + end do + !$omp taskgroup + !$omp task + !$omp task + !$omp cancellation point taskgroup + !$omp cancel taskgroup + !$omp end task + !$omp end task + !$omp taskloop nogroup + do i = 0, 9 + !$omp task + !$omp cancellation point taskgroup + !$omp cancel taskgroup + !$omp end task + !$omp cancellation point taskgroup + !$omp cancel taskgroup + end do + !$omp end taskgroup + + !$omp taskgroup + !$omp parallel + !$omp task + !$omp cancel taskgroup ! { dg-error "construct not closely nested inside of .taskgroup. region" } + !$omp cancellation point taskgroup ! { dg-error "construct not closely nested inside of .taskgroup. region" } + !$omp end task + !$omp taskloop + do i = 0, 9 + !$omp cancel taskgroup + !$omp cancellation point taskgroup + end do + !$omp taskloop nogroup + do i = 0, 9 + !$omp cancel taskgroup ! { dg-error "construct not closely nested inside of .taskgroup. region" } + !$omp cancellation point taskgroup ! { dg-error "construct not closely nested inside of .taskgroup. region" } + end do + !$omp end parallel + !$omp target + !$omp task + !$omp cancel taskgroup ! { dg-error "construct not closely nested inside of .taskgroup. region" } + !$omp cancellation point taskgroup ! { dg-error "construct not closely nested inside of .taskgroup. region" } + !$omp end task + !$omp end target + !$omp target + !$omp teams + !$omp distribute + do i = 0, 9 + !$omp task + !$omp cancellation point taskgroup ! { dg-error "construct not closely nested inside of .taskgroup. region" } + !$omp end task + end do + !$omp end distribute + !$omp end teams + !$omp end target + !$omp target data map(i) + !$omp task + !$omp cancel taskgroup + !$omp cancellation point taskgroup + !$omp end task + !$omp end target data + !$omp end taskgroup + + !$omp taskloop + do i = 0, 9 + !$omp parallel + !$omp task + !$omp cancel taskgroup ! { dg-error "construct not closely nested inside of .taskgroup. region" } + !$omp cancellation point taskgroup ! { dg-error "construct not closely nested inside of .taskgroup. region" } + !$omp end task + !$omp end parallel + !$omp target + !$omp task + !$omp cancel taskgroup ! { dg-error "construct not closely nested inside of .taskgroup. region" } + !$omp cancellation point taskgroup ! { dg-error "construct not closely nested inside of .taskgroup. region" } + !$omp end task + !$omp end target + !$omp target + !$omp teams + !$omp distribute + do j = 0, 9 + !$omp task + !$omp cancel taskgroup ! { dg-error "construct not closely nested inside of .taskgroup. region" } + !$omp cancellation point taskgroup ! { dg-error "construct not closely nested inside of .taskgroup. region" } + !$omp end task + end do + !$omp end distribute + !$omp end teams + !$omp end target + !$omp target data map(i) + !$omp task + !$omp cancel taskgroup + !$omp cancellation point taskgroup + !$omp end task + !$omp end target data + end do + + !$omp do + do i = 0, 9 + !$omp cancel parallel ! { dg-error "not closely nested inside" } + !$omp cancel do + !$omp cancel sections ! { dg-error "not closely nested inside" } + !$omp cancel taskgroup ! { dg-error "not closely nested inside" } + !$omp cancellation point parallel ! { dg-error "not closely nested inside" } + !$omp cancellation point do + !$omp cancellation point sections ! { dg-error "not closely nested inside" } + !$omp cancellation point taskgroup! { dg-error "not closely nested inside" } + end do + + !$omp do ordered + do i = 0, 9 + !$omp ordered + !$omp cancel parallel ! { dg-error "not closely nested inside" } + !$omp cancel do ! { dg-error "not closely nested inside" } + !$omp cancel sections ! { dg-error "not closely nested inside" } + !$omp cancel taskgroup ! { dg-error "not closely nested inside" } + !$omp cancellation point parallel ! { dg-error "not closely nested inside" } + !$omp cancellation point do ! { dg-error "not closely nested inside" } + !$omp cancellation point sections ! { dg-error "not closely nested inside" } + !$omp cancellation point taskgroup! { dg-error "not closely nested inside" } + !$omp end ordered + end do + !$omp end do + !$omp sections + block + !$omp cancel parallel ! { dg-error "not closely nested inside" } + !$omp cancel do ! { dg-error "not closely nested inside" } + !$omp cancel sections + !$omp cancel taskgroup ! { dg-error "not closely nested inside" } + !$omp cancellation point parallel ! { dg-error "not closely nested inside" } + !$omp cancellation point do ! { dg-error "not closely nested inside" } + !$omp cancellation point sections + !$omp cancellation point taskgroup! { dg-error "not closely nested inside" } + end block + !$omp section + block + !$omp cancel parallel ! { dg-error "not closely nested inside" } + !$omp cancel do ! { dg-error "not closely nested inside" } + !$omp cancel sections + !$omp cancel taskgroup ! { dg-error "not closely nested inside" } + !$omp cancellation point parallel ! { dg-error "not closely nested inside" } + !$omp cancellation point do ! { dg-error "not closely nested inside" } + !$omp cancellation point sections + !$omp cancellation point taskgroup! { dg-error "not closely nested inside" } + end block + !$omp target data map(j) + !$omp cancel parallel ! { dg-error "not closely nested inside" } + !$omp cancel do ! { dg-error "not closely nested inside" } + !$omp cancel sections ! { dg-error "not closely nested inside" } + !$omp cancel taskgroup ! { dg-error "not closely nested inside" } + !$omp cancellation point parallel ! { dg-error "not closely nested inside" } + !$omp cancellation point do ! { dg-error "not closely nested inside" } + !$omp cancellation point sections ! { dg-error "not closely nested inside" } + !$omp cancellation point taskgroup ! { dg-error "not closely nested inside" } + !$omp end target data + !$omp target + !$omp cancel parallel ! { dg-error "not closely nested inside" } + !$omp cancel do ! { dg-error "not closely nested inside" } + !$omp cancel sections ! { dg-error "not closely nested inside" } + !$omp cancel taskgroup ! { dg-error "not closely nested inside" } + !$omp cancellation point parallel ! { dg-error "not closely nested inside" } + !$omp cancellation point do ! { dg-error "not closely nested inside" } + !$omp cancellation point sections ! { dg-error "not closely nested inside" } + !$omp cancellation point taskgroup ! { dg-error "not closely nested inside" } + !$omp end target + !$omp end sections + !$omp end parallel + !$omp target data map(j) + !$omp cancel parallel ! { dg-error "not closely nested inside" } + !$omp cancel do ! { dg-error "not closely nested inside" } + !$omp cancel sections ! { dg-error "not closely nested inside" } + !$omp cancel taskgroup ! { dg-error "not closely nested inside" } + !$omp cancellation point parallel ! { dg-error "not closely nested inside" } + !$omp cancellation point do ! { dg-error "not closely nested inside" } + !$omp cancellation point sections ! { dg-error "not closely nested inside" } + !$omp cancellation point taskgroup ! { dg-error "not closely nested inside" } + !$omp end target data + !$omp target + !$omp cancel parallel ! { dg-error "not closely nested inside" } + !$omp cancel do ! { dg-error "not closely nested inside" } + !$omp cancel sections ! { dg-error "not closely nested inside" } + !$omp cancel taskgroup ! { dg-error "not closely nested inside" } + !$omp cancellation point parallel ! { dg-error "not closely nested inside" } + !$omp cancellation point do ! { dg-error "not closely nested inside" } + !$omp cancellation point sections ! { dg-error "not closely nested inside" } + !$omp cancellation point taskgroup ! { dg-error "not closely nested inside" } + !$omp end target + !$omp target teams + !$omp cancel parallel ! { dg-error "only .distribute., .parallel. or .loop. regions are allowed to be strictly nested" } + !$omp cancel do ! { dg-error "only .distribute., .parallel. or .loop. regions are allowed to be strictly nested" } + !$omp cancel sections ! { dg-error "only .distribute., .parallel. or .loop. regions are allowed to be strictly nested" } + !$omp cancel taskgroup ! { dg-error "only .distribute., .parallel. or .loop. regions are allowed to be strictly nested" } + !$omp cancellation point parallel ! { dg-error "only .distribute., .parallel. or .loop. regions are allowed to be strictly nested" } + !$omp cancellation point do ! { dg-error "only .distribute., .parallel. or .loop. regions are allowed to be strictly nested" } + !$omp cancellation point sections ! { dg-error "only .distribute., .parallel. or .loop. regions are allowed to be strictly nested" } + !$omp cancellation point taskgroup ! { dg-error "only .distribute., .parallel. or .loop. regions are allowed to be strictly nested" } + !$omp end target teams + !$omp target teams distribute + do i = 0, 9 + !$omp cancel parallel ! { dg-error "not closely nested inside" } + !$omp cancel do ! { dg-error "not closely nested inside" } + !$omp cancel sections ! { dg-error "not closely nested inside" } + !$omp cancel taskgroup ! { dg-error "not closely nested inside" } + !$omp cancellation point parallel ! { dg-error "not closely nested inside" } + !$omp cancellation point do ! { dg-error "not closely nested inside" } + !$omp cancellation point sections ! { dg-error "not closely nested inside" } + !$omp cancellation point taskgroup ! { dg-error "not closely nested inside" } + end do + !$omp end target teams distribute + !$omp do + do i = 0, 9 + !$omp cancel parallel ! { dg-error "not closely nested inside" } + !$omp cancel do + !$omp cancel sections ! { dg-error "not closely nested inside" } + !$omp cancel taskgroup ! { dg-error "not closely nested inside" } + !$omp cancellation point parallel ! { dg-error "not closely nested inside" } + !$omp cancellation point do + !$omp cancellation point sections ! { dg-error "not closely nested inside" } + !$omp cancellation point taskgroup ! { dg-error "not closely nested inside" } + end do + !$omp do + do i = 0, 9 + !$omp target data map(j) + !$omp cancel parallel ! { dg-error "not closely nested inside" } + !$omp cancel do ! { dg-error "not closely nested inside" } + !$omp cancel sections ! { dg-error "not closely nested inside" } + !$omp cancel taskgroup ! { dg-error "not closely nested inside" } + !$omp cancellation point parallel ! { dg-error "not closely nested inside" } + !$omp cancellation point do ! { dg-error "not closely nested inside" } + !$omp cancellation point sections ! { dg-error "not closely nested inside" } + !$omp cancellation point taskgroup ! { dg-error "not closely nested inside" } + !$omp end target data + end do + !$omp do + do i = 0, 9 + !$omp target + !$omp cancel parallel ! { dg-error "not closely nested inside" } + !$omp cancel do ! { dg-error "not closely nested inside" } + !$omp cancel sections ! { dg-error "not closely nested inside" } + !$omp cancel taskgroup ! { dg-error "not closely nested inside" } + !$omp cancellation point parallel ! { dg-error "not closely nested inside" } + !$omp cancellation point do ! { dg-error "not closely nested inside" } + !$omp cancellation point sections ! { dg-error "not closely nested inside" } + !$omp cancellation point taskgroup ! { dg-error "not closely nested inside" } + !$omp end target + end do + !$omp do ordered + do i = 0, 9 + !$omp ordered + !$omp target data map(j) + !$omp cancel parallel ! { dg-error "not closely nested inside" } + !$omp cancel do ! { dg-error "not closely nested inside" } + !$omp cancel sections ! { dg-error "not closely nested inside" } + !$omp cancel taskgroup ! { dg-error "not closely nested inside" } + !$omp cancellation point parallel ! { dg-error "not closely nested inside" } + !$omp cancellation point do ! { dg-error "not closely nested inside" } + !$omp cancellation point sections ! { dg-error "not closely nested inside" } + !$omp cancellation point taskgroup! { dg-error "not closely nested inside" } + !$omp end target data + !$omp end ordered + end do + do i = 0, 9 + !$omp ordered + !$omp target + !$omp cancel parallel ! { dg-error "not closely nested inside" } + !$omp cancel do ! { dg-error "not closely nested inside" } + !$omp cancel sections ! { dg-error "not closely nested inside" } + !$omp cancel taskgroup ! { dg-error "not closely nested inside" } + !$omp cancellation point parallel ! { dg-error "not closely nested inside" } + !$omp cancellation point do ! { dg-error "not closely nested inside" } + !$omp cancellation point sections ! { dg-error "not closely nested inside" } + !$omp cancellation point taskgroup! { dg-error "not closely nested inside" } + !$omp end target + !$omp end ordered + end do + !$omp sections + block + !$omp cancel parallel ! { dg-error "not closely nested inside" } + !$omp cancel do ! { dg-error "not closely nested inside" } + !$omp cancel sections + !$omp cancel taskgroup ! { dg-error "not closely nested inside" } + !$omp cancellation point parallel ! { dg-error "not closely nested inside" } + !$omp cancellation point do ! { dg-error "not closely nested inside" } + !$omp cancellation point sections + !$omp cancellation point taskgroup ! { dg-error "not closely nested inside" } + end block + !$omp section + block + !$omp cancel parallel ! { dg-error "not closely nested inside" } + !$omp cancel do ! { dg-error "not closely nested inside" } + !$omp cancel sections + !$omp cancel taskgroup ! { dg-error "not closely nested inside" } + !$omp cancellation point parallel ! { dg-error "not closely nested inside" } + !$omp cancellation point do ! { dg-error "not closely nested inside" } + !$omp cancellation point sections + !$omp cancellation point taskgroup ! { dg-error "not closely nested inside" } + end block + !$omp end sections + !$omp sections + !$omp target data map(j) + !$omp cancel parallel ! { dg-error "not closely nested inside" } + !$omp cancel do ! { dg-error "not closely nested inside" } + !$omp cancel sections ! { dg-error "not closely nested inside" } + !$omp cancel taskgroup ! { dg-error "not closely nested inside" } + !$omp cancellation point parallel ! { dg-error "not closely nested inside" } + !$omp cancellation point do ! { dg-error "not closely nested inside" } + !$omp cancellation point sections ! { dg-error "not closely nested inside" } + !$omp cancellation point taskgroup ! { dg-error "not closely nested inside" } + !$omp end target data + !$omp section + !$omp target data map(j) + !$omp cancel parallel ! { dg-error "not closely nested inside" } + !$omp cancel do ! { dg-error "not closely nested inside" } + !$omp cancel sections ! { dg-error "not closely nested inside" } + !$omp cancel taskgroup ! { dg-error "not closely nested inside" } + !$omp cancellation point parallel ! { dg-error "not closely nested inside" } + !$omp cancellation point do ! { dg-error "not closely nested inside" } + !$omp cancellation point sections ! { dg-error "not closely nested inside" } + !$omp cancellation point taskgroup ! { dg-error "not closely nested inside" } + !$omp end target data + !$omp end sections + !$omp sections + !$omp target + !$omp cancel parallel ! { dg-error "not closely nested inside" } + !$omp cancel do ! { dg-error "not closely nested inside" } + !$omp cancel sections ! { dg-error "not closely nested inside" } + !$omp cancel taskgroup ! { dg-error "not closely nested inside" } + !$omp cancellation point parallel ! { dg-error "not closely nested inside" } + !$omp cancellation point do ! { dg-error "not closely nested inside" } + !$omp cancellation point sections ! { dg-error "not closely nested inside" } + !$omp cancellation point taskgroup ! { dg-error "not closely nested inside" } + !$omp end target + !$omp section + !$omp target + !$omp cancel parallel ! { dg-error "not closely nested inside" } + !$omp cancel do ! { dg-error "not closely nested inside" } + !$omp cancel sections ! { dg-error "not closely nested inside" } + !$omp cancel taskgroup ! { dg-error "not closely nested inside" } + !$omp cancellation point parallel ! { dg-error "not closely nested inside" } + !$omp cancellation point do ! { dg-error "not closely nested inside" } + !$omp cancellation point sections ! { dg-error "not closely nested inside" } + !$omp cancellation point taskgroup ! { dg-error "not closely nested inside" } + !$omp end target + !$omp end sections + !$omp task + !$omp cancel parallel ! { dg-error "not closely nested inside" } + !$omp cancel do ! { dg-error "not closely nested inside" } + !$omp cancel sections ! { dg-error "not closely nested inside" } + !$omp cancel taskgroup + !$omp cancellation point parallel ! { dg-error "not closely nested inside" } + !$omp cancellation point do ! { dg-error "not closely nested inside" } + !$omp cancellation point sections ! { dg-error "not closely nested inside" } + !$omp cancellation point taskgroup + !$omp taskgroup + !$omp cancel parallel ! { dg-error "not closely nested inside" } + !$omp cancel do ! { dg-error "not closely nested inside" } + !$omp cancel sections ! { dg-error "not closely nested inside" } + !$omp cancel taskgroup ! { dg-error "not closely nested inside" } + !$omp cancellation point parallel ! { dg-error "not closely nested inside" } + !$omp cancellation point do ! { dg-error "not closely nested inside" } + !$omp cancellation point sections ! { dg-error "not closely nested inside" } + !$omp cancellation point taskgroup ! { dg-error "not closely nested inside" } + !$omp end taskgroup + !$omp end task +end + +subroutine f3 + integer i + !$omp do + do i = 0, 9 + !$omp cancel do ! { dg-warning "nowait" } + end do + !$omp end do nowait + !$omp sections + block + !$omp cancel sections ! { dg-warning "nowait" } + end block + !$omp section + block + !$omp cancel sections ! { dg-warning "nowait" } + end block + !$omp end sections nowait + !$omp do ordered + do i = 0, 9 + !$omp cancel do ! { dg-warning "ordered" } + !$omp ordered + !$omp end ordered + end do +end + + +subroutine f4 +! if (.false.) then +!$omp cancellation point do ! { dg-error "orphaned 'cancellation point' construct" } +! end if +end diff --git a/gcc/testsuite/gfortran.dg/gomp/cancel-4.f90 b/gcc/testsuite/gfortran.dg/gomp/cancel-4.f90 new file mode 100644 index 0000000..0fb814e --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/cancel-4.f90 @@ -0,0 +1,9 @@ +subroutine f4 + !$omp cancellation point ! { dg-error "Expected construct-type PARALLEL, SECTIONS, DO or TASKGROUP in .OMP CANCELLATION POINT statement at" } + if (.false.) then +!$omp cancellation EKAHI ! { dg-error "Unclassifiable OpenMP directive" } + end if +!$omp cancellation HO OKAHI ! { dg-error "Unclassifiable OpenMP directive" } + +!$omp cancellation point ! { dg-error "Expected construct-type PARALLEL, SECTIONS, DO or TASKGROUP in .OMP CANCELLATION POINT statement at" } +end diff --git a/gcc/testsuite/gfortran.dg/gomp/loop-4.f90 b/gcc/testsuite/gfortran.dg/gomp/loop-4.f90 new file mode 100644 index 0000000..7374589 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/loop-4.f90 @@ -0,0 +1,279 @@ +module m + use iso_c_binding, only: c_loc + implicit none (type, external) + integer :: v + interface + subroutine foo (); end + integer function omp_get_thread_num (); end + integer function omp_get_num_threads (); end + integer function omp_get_cancellation (); end + integer(c_int) function omp_target_is_present(ptr, device_num) bind(c) + use, intrinsic :: iso_c_binding, only : c_ptr, c_int + type(c_ptr), value :: ptr + integer(c_int), value :: device_num + end + end interface + +contains +subroutine f1(a) + integer :: a(0:) + integer :: i, j + !$omp simd order(concurrent) + do i = 0, 63 + !$omp loop + do j = 0, 63 + a(64 * i + j) = i + j + end do + end do +end + +subroutine f2 (a) + integer :: a(0:) + integer :: i, j + !$omp do simd order(concurrent) + do i = 0, 63 + !$omp loop + do j = 0, 63 + a(64 * i + j) = i + j + end do + end do +end + +subroutine f3 (a) + integer :: a(0:) + integer :: i, j + !$omp do order(concurrent) + do i = 0, 63 + !$omp loop + do j = 0, 63 + a(64 * i + j) = i + j + end do + end do +end + +subroutine f4 (a) + integer, target :: a(0:) + integer :: i, j + !$omp loop order(concurrent) bind(parallel) + do i = 0, 63 + !$omp parallel + call foo () + !$omp end parallel + end do + !$omp loop order(concurrent) bind(parallel) + do i = 0, 63 + !$omp simd + do j = 0, 63 + a(64 * i + j) = i + j + end do + end do + !$omp loop order(concurrent) bind(parallel) + do i = 0, 63 + !$omp loop + do j = 0, 63 + a(64 * i + j) = i + j + end do + end do + !$omp loop order(concurrent) bind(parallel) + do i = 0, 63 + !$omp critical ! { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" } + call foo () + !$omp end critical + end do + !$omp loop order(concurrent) bind(parallel) + do i = 0, 63 + !$omp ordered simd ! { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" } + call foo () + !$omp end ordered + end do + !$omp loop order(concurrent) bind(parallel) + do i = 0, 63 + !$omp atomic ! { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" } + v = v + 1 + end do + !$omp loop order(concurrent) bind(parallel) + do i = 0, 63 + !$omp atomic read ! { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" } + a(i) = v + end do + !$omp loop order(concurrent) bind(parallel) + do i = 0, 63 + !$omp atomic write ! { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" } + v = a(i) + end do + !$omp loop order(concurrent) bind(parallel) + do i = 0, 63 + a(i) = a(i) + omp_get_thread_num () ! { dg-error "OpenMP runtime API call '\[^\n\r]*omp_get_thread_num\[^\n\r]*' in a region with 'order\\(concurrent\\)' clause" } + end do + !$omp loop order(concurrent) bind(parallel) + do i = 0, 63 + a(i) = a(i) + omp_get_num_threads () ! { dg-error "OpenMP runtime API call '\[^\n\r]*omp_get_num_threads\[^\n\r]*' in a region with 'order\\(concurrent\\)' clause" } + end do + !$omp loop order(concurrent) bind(parallel) + do i = 0, 63 + a(i) = a(i) + omp_target_is_present (c_loc (a(i)), 0) ! { dg-error "OpenMP runtime API call '\[^\n\r]*omp_target_is_present\[^\n\r]*' in a region with 'order\\(concurrent\\)' clause" } + end do + !$omp loop order(concurrent) bind(parallel) + do i = 0, 63 + a(i) = a(i) + omp_get_cancellation () ! { dg-error "OpenMP runtime API call '\[^\n\r]*omp_get_cancellation\[^\n\r]*' in a region with 'order\\(concurrent\\)' clause" } + end do +end + +subroutine f5 (a) + integer, target :: a(0:) + integer :: i, j + !$omp parallel + !$omp loop + do i = 0, 63 + !$omp parallel + call foo () + !$omp end parallel + end do + !$omp loop + do i = 0, 63 + !$omp simd + do j = 0, 63 + a(64 * i + j) = i + j + end do + end do + !$omp loop + do i = 0, 63 + !$omp loop + do j = 0, 63 + a(64 * i + j) = i + j + end do + end do + !$omp loop + do i = 0, 63 + !$omp critical ! { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" } + call foo () + !$omp end critical + end do + !$omp loop + do i = 0, 63 + !$omp ordered simd ! { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" } + call foo () + !$omp end ordered + end do + !$omp loop + do i = 0, 63 + !$omp atomic ! { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" } + v = v + 1 + end do + !$omp loop + do i = 0, 63 + !$omp atomic read ! { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" } + a(i) = v + end do + !$omp loop + do i = 0, 63 + !$omp atomic write ! { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" } + v = a(i) + end do + !$omp loop + do i = 0, 63 + !$omp master ! { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" } + call foo () + !$omp end master + end do + !$omp loop + do i = 0, 63 + !$omp masked ! { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" } + call foo () + !$omp end masked + end do + !$omp loop + do i = 0, 63 + !$omp scope ! { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" } + call foo () + !$omp end scope + end do + !$omp loop + do i = 0, 63 + a(i) = a(i) + omp_get_thread_num () ! { dg-error "OpenMP runtime API call '\[^\n\r]*omp_get_thread_num\[^\n\r]*' in a region with 'order\\(concurrent\\)' clause" } + end do + !$omp loop + do i = 0, 63 + a(i) = a(i) + omp_get_num_threads () ! { dg-error "OpenMP runtime API call '\[^\n\r]*omp_get_num_threads\[^\n\r]*' in a region with 'order\\(concurrent\\)' clause" } + end do + !$omp loop + do i = 0, 63 + a(i) = a(i) + omp_target_is_present (c_loc(a(i)), 0) ! { dg-error "OpenMP runtime API call '\[^\n\r]*omp_target_is_present\[^\n\r]*' in a region with 'order\\(concurrent\\)' clause" } + end do + !$omp loop + do i = 0, 63 + a(i) = a(i) + omp_get_cancellation () ! { dg-error "OpenMP runtime API call '\[^\n\r]*omp_get_cancellation\[^\n\r]*' in a region with 'order\\(concurrent\\)' clause" } + end do + !$omp end parallel +end + +subroutine f6 (a) + integer, target :: a(0:) + integer :: i, j + !$omp master + !$omp loop + do i = 0, 63 + !$omp parallel + call foo () + !$omp end parallel + end do + !$omp loop + do i = 0, 63 + !$omp simd + do j = 0, 63 + a(64 * i + j) = i + j + end do + end do + !$omp loop + do i = 0, 63 + !$omp loop + do j = 0, 63 + a(64 * i + j) = i + j + end do + end do + !$omp loop + do i = 0, 63 + !$omp critical ! { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" } + call foo () + !$omp end critical + end do + !$omp loop + do i = 0, 63 + !$omp ordered simd ! { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" } + call foo () + !$omp end ordered + end do + !$omp loop + do i = 0, 63 + !$omp atomic ! { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" } + v = v + 1 + end do + !$omp loop + do i = 0, 63 + !$omp atomic read ! { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" } + a(i) = v + end do + !$omp loop + do i = 0, 63 + !$omp atomic write ! { dg-error "OpenMP constructs other than 'parallel', 'loop' or 'simd' may not be nested inside a 'loop' region" } + v = a(i) + end do + !$omp loop + do i = 0, 63 + a(i) = a(i) + omp_get_thread_num () ! { dg-error "OpenMP runtime API call '\[^\n\r]*omp_get_thread_num\[^\n\r]*' in a region with 'order\\(concurrent\\)' clause" } + end do + !$omp loop + do i = 0, 63 + a(i) = a(i) + omp_get_num_threads () ! { dg-error "OpenMP runtime API call '\[^\n\r]*omp_get_num_threads\[^\n\r]*' in a region with 'order\\(concurrent\\)' clause" } + end do + !$omp loop + do i = 0, 63 + a(i) = a(i) + omp_target_is_present (c_loc(a(i)), 0) ! { dg-error "OpenMP runtime API call '\[^\n\r]*omp_target_is_present\[^\n\r]*' in a region with 'order\\(concurrent\\)' clause" } + end do + !$omp loop + do i = 0, 63 + a(i) = a(i) + omp_get_cancellation () ! { dg-error "OpenMP runtime API call '\[^\n\r]*omp_get_cancellation\[^\n\r]*' in a region with 'order\\(concurrent\\)' clause" } + end do + !$omp end master +end +end module diff --git a/gcc/testsuite/gfortran.dg/gomp/nesting-1.f90 b/gcc/testsuite/gfortran.dg/gomp/nesting-1.f90 new file mode 100644 index 0000000..af4c2fbf --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/nesting-1.f90 @@ -0,0 +1,68 @@ +module m + implicit none + integer i +contains + +subroutine f_omp_parallel + !$omp parallel + !$omp parallel + !$omp end parallel + + !$omp target + !$omp end target + + !$omp target data map(i) + !$omp end target data + + !$omp target update to(i) + + !$omp target data map(i) + !$omp parallel + !$omp end parallel + + !$omp target + !$omp end target + + !$omp target data map(i) + !$omp end target data + + !$omp target update to(i) + !$omp end target data + !$omp end parallel +end + +subroutine f_omp_target + !$omp target + !$omp parallel + !$omp end parallel + !$omp end target +end + +subroutine f_omp_target_data + !$omp target data map(i) + !$omp parallel + !$omp end parallel + + !$omp target + !$omp end target + + !$omp target data map(i) + !$omp end target data + + !$omp target update to(i) + + !$omp target data map(i) + !$omp parallel + !$omp end parallel + + !$omp target + !$omp end target + + !$omp target data map(i) + !$omp end target data + + !$omp target update to(i) + !$omp end target data + !$omp end target data +end +end module m diff --git a/gcc/testsuite/gfortran.dg/gomp/nesting-2.f90 b/gcc/testsuite/gfortran.dg/gomp/nesting-2.f90 new file mode 100644 index 0000000..2eccdf9 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/nesting-2.f90 @@ -0,0 +1,165 @@ +subroutine foo + integer :: i, j + !$omp taskloop + do i = 0, 63 + !$omp do ! { dg-error "region may not be closely nested inside of" } + do j = 0, 9 + end do + !$omp single ! { dg-error "region may not be closely nested inside of" } + !$omp end single + !$omp sections ! { dg-error "region may not be closely nested inside of" } + !$omp section + block + end block + !$omp end sections + !$omp barrier ! { dg-error "region may not be closely nested inside of" } + !$omp master ! { dg-error "region may not be closely nested inside of" } -- ? + block; end block ! otherwise not generated + !$omp end master + !$omp masked ! { dg-error "region may not be closely nested inside of" } -- ? + block; end block ! otherwise not generated + !$omp end masked + !$omp scope ! { dg-error "region may not be closely nested inside of" } -- ? + block; end block ! otherwise not generated + !$omp end scope + !$omp ordered ! { dg-error "region may not be closely nested inside of" } + !$omp end ordered + !$omp ordered threads ! { dg-error "region may not be closely nested inside of" } + !$omp end ordered + !$omp ordered simd threads ! { dg-error ".ordered. .simd. must be closely nested inside .simd. region" } + !$omp end ordered + !$omp simd + do j = 0, 9 + !$omp ordered simd + !$omp end ordered + end do + !$omp critical + !$omp simd + do j = 0, 9 + !$omp ordered simd + !$omp end ordered + end do + !$omp end critical + end do + !$omp taskloop + do i = 0, 63 + !$omp parallel + !$omp do + do j = 0, 9 + end do + !$omp single + !$omp end single + !$omp sections + !$omp section + block; end block + !$omp end sections + !$omp barrier + !$omp master + block; end block ! otherwise not generated + !$omp end master + !$omp masked + block; end block ! otherwise not generated + !$omp end masked + !$omp scope + block; end block ! otherwise not generated + !$omp end scope + !$omp ordered ! { dg-error ".ordered. region must be closely nested inside a loop region with an .ordered. clause" } + !$omp end ordered + !$omp ordered threads ! { dg-error ".ordered. region must be closely nested inside a loop region with an .ordered. clause" } + !$omp end ordered + !$omp simd + do j = 0, 9 + !$omp ordered simd + !$omp end ordered + end do + !$omp critical + !$omp simd + do j = 0, 9 + !$omp ordered simd + !$omp end ordered + end do + !$omp end critical + !$omp end parallel + end do + !$omp taskloop + do i = 0, 63 + !$omp target + !$omp do + do j = 0, 9 + end do + !$omp single + !$omp end single + !$omp sections + !$omp section + block; end block + !$omp end sections + !$omp barrier + !$omp master + block; end block ! otherwise not generated + !$omp end master + !$omp masked + block; end block ! otherwise not generated + !$omp end masked + !$omp scope + block; end block ! otherwise not generated + !$omp end scope + !$omp ordered ! { dg-error ".ordered. region must be closely nested inside a loop region with an .ordered. clause" } + !$omp end ordered + !$omp ordered threads ! { dg-error ".ordered. region must be closely nested inside a loop region with an .ordered. clause" } + !$omp end ordered + !$omp simd + do j = 0, 9 + !$omp ordered simd + !$omp end ordered + end do + !$omp critical + !$omp simd + do j = 0, 9 + !$omp ordered simd + !$omp end ordered + end do + !$omp end critical + !$omp end target + end do + !$omp ordered + !$omp ordered ! { dg-error "region may not be closely nested inside of" } + !$omp end ordered + !$omp end ordered + !$omp ordered threads + !$omp ordered ! { dg-error "region may not be closely nested inside of" } + !$omp end ordered + !$omp end ordered + !$omp ordered + !$omp ordered threads ! { dg-error "region may not be closely nested inside of" } + !$omp end ordered + !$omp end ordered + !$omp ordered threads + !$omp ordered threads ! { dg-error "region may not be closely nested inside of" } + !$omp end ordered + !$omp end ordered + !$omp critical + !$omp ordered simd ! { dg-error ".ordered. .simd. must be closely nested inside .simd. region" } + !$omp end ordered + !$omp end critical + !$omp do ordered + do i = 0, 63 + !$omp parallel + !$omp ordered threads ! { dg-error ".ordered. region must be closely nested inside a loop region with an .ordered. clause" } + !$omp end ordered + !$omp end parallel + end do + !$omp do ordered + do i = 0, 63 + !$omp parallel + !$omp ordered ! { dg-error ".ordered. region must be closely nested inside a loop region with an .ordered. clause" } + !$omp end ordered + !$omp end parallel + end do + !$omp do ordered(1) + do i = 0, 63 + !$omp parallel + !$omp ordered depend(source) ! { dg-error ".ordered. construct with .depend. clause must be closely nested inside a loop with .ordered. clause with a parameter" } + !$omp ordered depend(sink: i - 1) ! { dg-error ".ordered. construct with .depend. clause must be closely nested inside a loop with .ordered. clause with a parameter" } + !$omp end parallel + end do +end diff --git a/gcc/testsuite/gfortran.dg/gomp/nesting-3.f90 b/gcc/testsuite/gfortran.dg/gomp/nesting-3.f90 new file mode 100644 index 0000000..cd2e39a --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/nesting-3.f90 @@ -0,0 +1,347 @@ +subroutine f1 + integer i, j + !$omp do + do i = 0, 2 + !$omp do ! { dg-error "may not be closely nested" } + do j = 0, 2 + block; end block + end do + !$omp sections ! { dg-error "may not be closely nested" } + block; end block + !$omp section + block; end block + !$omp end sections + !$omp single ! { dg-error "may not be closely nested" } + block; end block + !$omp end single + !$omp master ! { dg-error "may not be closely nested" } + block; end block + !$omp end master + !$omp masked ! { dg-error "may not be closely nested" } + block; end block + !$omp end masked + !$omp barrier ! { dg-error "may not be closely nested" } + !$omp scope ! { dg-error "may not be closely nested" } + block; end block + !$omp end scope + end do + !$omp sections + !$omp do ! { dg-error "may not be closely nested" } + do j = 0, 2 + block; end block + end do + !$omp end sections + !$omp sections + !$omp sections ! { dg-error "may not be closely nested" } + block; end block + !$omp section + block; end block + !$omp end sections + !$omp end sections + !$omp sections + !$omp single ! { dg-error "may not be closely nested" } + block; end block + !$omp end single + !$omp end sections + !$omp sections + !$omp master ! { dg-error "may not be closely nested" } + block; end block + !$omp end master + !$omp end sections + !$omp sections + !$omp masked ! { dg-error "may not be closely nested" } + block; end block + !$omp end masked + !$omp end sections + !$omp sections + !$omp scope ! { dg-error "may not be closely nested" } + block; end block + !$omp end scope + !$omp end sections + !$omp sections + !$omp section + block; end block + !$omp end sections + !$omp sections + !$omp section + !$omp do ! { dg-error "may not be closely nested" } + do j = 0, 2 + block; end block + end do + !$omp end sections + !$omp sections + !$omp section + !$omp sections ! { dg-error "may not be closely nested" } + block; end block + !$omp section + block; end block + !$omp end sections + !$omp end sections + !$omp sections + !$omp section + !$omp single ! { dg-error "may not be closely nested" } + block; end block + !$omp end single + !$omp end sections + !$omp sections + !$omp section + !$omp master ! { dg-error "may not be closely nested" } + block; end block + !$omp end master + !$omp section + !$omp masked ! { dg-error "may not be closely nested" } + block; end block + !$omp end masked + !$omp end sections + !$omp sections + !$omp section + !$omp scope ! { dg-error "may not be closely nested" } + block; end block + !$omp end scope + !$omp end sections + !$omp single + !$omp do ! { dg-error "may not be closely nested" } + do j = 0, 2 + block; end block + end do + !$omp sections ! { dg-error "may not be closely nested" } + block; end block + !$omp section + block; end block + !$omp end sections + !$omp single ! { dg-error "may not be closely nested" } + block; end block + !$omp end single + !$omp master ! { dg-error "may not be closely nested" } + block; end block + !$omp end master + !$omp masked ! { dg-error "may not be closely nested" } + block; end block + !$omp end masked + !$omp barrier ! { dg-error "may not be closely nested" } + !$omp scope ! { dg-error "may not be closely nested" } + block; end block + !$omp end scope + !$omp end single + !$omp master + !$omp do ! { dg-error "may not be closely nested" } + do j = 0, 2 + block; end block + end do + !$omp sections ! { dg-error "may not be closely nested" } + block; end block + !$omp section + block; end block + !$omp end sections + !$omp single ! { dg-error "may not be closely nested" } + block; end block + !$omp end single + !$omp master + block; end block + !$omp end master + !$omp barrier ! { dg-error "may not be closely nested" } + !$omp scope ! { dg-error "may not be closely nested" } + block; end block + !$omp end scope + !$omp end master + !$omp masked filter (1) + !$omp do ! { dg-error "may not be closely nested" } + do j = 0, 2 + block; end block + end do + !$omp sections ! { dg-error "may not be closely nested" } + block; end block + !$omp section + block; end block + !$omp end sections + !$omp single ! { dg-error "may not be closely nested" } + block; end block + !$omp end single + !$omp master + block; end block + !$omp end master + !$omp barrier ! { dg-error "may not be closely nested" } + !$omp scope ! { dg-error "may not be closely nested" } + block; end block + !$omp end scope + !$omp end masked + !$omp task + !$omp do ! { dg-error "may not be closely nested" } + do j = 0, 2 + block; end block + end do + !$omp sections ! { dg-error "may not be closely nested" } + block; end block + !$omp section + block; end block + !$omp end sections + !$omp single ! { dg-error "may not be closely nested" } + block; end block + !$omp end single + !$omp master ! { dg-error "may not be closely nested" } + block; end block + !$omp end master + !$omp masked ! { dg-error "may not be closely nested" } + block; end block + !$omp end masked + !$omp barrier ! { dg-error "may not be closely nested" } + !$omp scope ! { dg-error "may not be closely nested" } + block; end block + !$omp end scope + !$omp end task + !$omp parallel + !$omp do + do j = 0, 2 + block; end block + end do + !$omp sections + block; end block + !$omp section + block; end block + !$omp end sections + !$omp single + block; end block + !$omp end single + !$omp master + block; end block + !$omp end master + !$omp masked + block; end block + !$omp end masked + !$omp barrier + !$omp scope + block; end block + !$omp end scope + !$omp scope + !$omp scope + block; end block + !$omp end scope + !$omp end scope + !$omp end parallel + !$omp scope + !$omp do + do j = 0, 2 + block; end block + end do + !$omp sections + block; end block + !$omp section + block; end block + !$omp end sections + !$omp single + block; end block + !$omp end single + !$omp master + block; end block + !$omp end master + !$omp masked + block; end block + !$omp end masked + !$omp barrier + !$omp scope + block; end block + !$omp end scope + !$omp scope + !$omp scope + block; end block + !$omp end scope + !$omp end scope + !$omp end scope +end + +subroutine f2 + integer i, j + !$omp ordered + !$omp do ! { dg-error "may not be closely nested" } + do j = 0, 2 + block; end block + end do + !$omp sections ! { dg-error "may not be closely nested" } + block; end block + !$omp section + block; end block + !$omp end sections + !$omp single ! { dg-error "may not be closely nested" } + block; end block + !$omp end single + !$omp master + block; end block + !$omp end master + !$omp masked + block; end block + !$omp end masked + !$omp barrier ! { dg-error "may not be closely nested" } + !$omp scope ! { dg-error "may not be closely nested" } + block; end block + !$omp end scope + !$omp end ordered +end + +subroutine f3 (void) + !$omp critical + !$omp ordered ! { dg-error "may not be closely nested" } + block; end block + !$omp end ordered + !$omp scope ! { dg-error "may not be closely nested" } + block; end block + !$omp end scope + !$omp end critical +end + +subroutine f4 (void) + !$omp task + !$omp ordered ! { dg-error "may not be closely nested" } + block; end block + !$omp end ordered + !$omp scope ! { dg-error "may not be closely nested" } + block; end block + !$omp end scope + !$omp end task +end + +subroutine f5 (void) + integer i + !$omp do + do i = 0, 9 + !$omp ordered ! { dg-error "must be closely nested" } + block; end block + !$omp end ordered + end do + !$omp do ordered + do i = 0, 9 + !$omp ordered + block; end block + !$omp end ordered + end do +end + +subroutine f6 (void) + !$omp critical (foo) + !$omp critical (bar) + block; end block + !$omp end critical (bar) + !$omp end critical (foo) + !$omp critical + !$omp critical (baz) + block; end block + !$omp end critical (baz) + !$omp end critical +end + +subroutine f7 (void) + !$omp critical (foo2) + !$omp critical + block; end block + !$omp end critical + !$omp end critical (foo2) + !$omp critical (bar) + !$omp critical (bar) ! { dg-error "may not be nested" } + block; end block + !$omp end critical (bar) + !$omp end critical (bar) + !$omp critical + !$omp critical ! { dg-error "may not be nested" } + block; end block + !$omp end critical + !$omp end critical +end diff --git a/gcc/testsuite/gfortran.dg/gomp/nowait-1.f90 b/gcc/testsuite/gfortran.dg/gomp/nowait-1.f90 new file mode 100644 index 0000000..b47b4a1 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/nowait-1.f90 @@ -0,0 +1,19 @@ +subroutine foo + +!$omp do +do i = 1, 2 +end do +!$omp end do nowait foo ! { dg-error "Unexpected junk after NOWAIT clause" } +!$omp end do ! as previous line is ignored + +!$omp scope + block; end block +!$omp end scope bar ! { dg-error "Unexpected junk at" } +!$omp end scope + +!$omp scope + block; end block +!$omp end scope nowait nowait ! { dg-error "Unexpected junk after NOWAIT clause" } +!$omp end scope + +end diff --git a/gcc/testsuite/gfortran.dg/gomp/reduction-task-1.f90 b/gcc/testsuite/gfortran.dg/gomp/reduction-task-1.f90 new file mode 100644 index 0000000..99c097f --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/reduction-task-1.f90 @@ -0,0 +1,112 @@ +module m + implicit none + integer v + interface + subroutine foo(x) + integer, value :: x + end + end interface +contains + +subroutine bar + integer i + !$omp do reduction (task, +: v) + do i = 0, 63 + call foo (i) + end do + !$omp sections reduction (task, +: v) + call foo (-2) + !$omp section + call foo (-3) + !$omp end sections + !$omp parallel reduction (task, +: v) + call foo (-1) + !$omp end parallel + !$omp parallel do reduction (task, +: v) + do i = 0, 63 + call foo (i) + end do + !$omp end parallel do + !$omp parallel sections reduction (task, +: v) + call foo (-2) + !$omp section + call foo (-3) + !$omp end parallel sections + !$omp teams distribute parallel do reduction (task, +: v) ! { dg-bogus "invalid 'task' reduction modifier on construct other than 'parallel', 'do', 'sections' or 'scope'" "PR101948" { xfail *-*-* } } + do i = 0, 63 + call foo (i) + end do + !$omp end teams distribute parallel do + !$omp do reduction (default, +: v) + do i = 0, 63 + call foo (i) + end do + !$omp sections reduction (default, +: v) + call foo (-2) + !$omp section + call foo (-3) + !$omp end sections + !$omp parallel reduction (default, +: v) + call foo (-1) + !$omp end parallel + !$omp parallel do reduction (default, +: v) + do i = 0, 63 + call foo (i) + end do + !$omp end parallel do + !$omp parallel sections reduction (default, +: v) + call foo (-2) + !$omp section + call foo (-3) + !$omp end parallel sections + !$omp teams distribute parallel do reduction (default, +: v) + do i = 0, 63 + call foo (i) + end do + !$omp end teams distribute parallel do + !$omp do reduction (default, +: v) + do i = 0, 63 + call foo (i) + end do + !$omp end do nowait + !$omp sections reduction (default, +: v) + call foo (-2) + !$omp section + call foo (-3) + !$omp end sections nowait + !$omp simd reduction (default, +: v) + do i = 0, 63 + v = v + 1 + end do + !$omp do simd reduction (default, +: v) + do i = 0, 63 + v = v + 1 + end do + !$omp parallel do simd reduction (default, +: v) + do i = 0, 63 + v = v + 1 + end do + !$omp end parallel do simd + !$omp teams distribute parallel do simd reduction (default, +: v) + do i = 0, 63 + v = v + 1 + end do + !$omp end teams distribute parallel do simd + !$omp taskloop reduction (default, +: v) + do i = 0, 63 + call foo (i) + end do + !$omp taskloop simd reduction (default, +: v) + do i = 0, 63 + v = v + 1 + end do + !$omp teams reduction (default, +: v) + call foo (i) + !$omp end teams + !$omp teams distribute reduction (default, +: v) + do i = 0, 63 + call foo (i) + end do + !$omp end teams distribute +end +end diff --git a/gcc/testsuite/gfortran.dg/gomp/reduction-task-2.f90 b/gcc/testsuite/gfortran.dg/gomp/reduction-task-2.f90 new file mode 100644 index 0000000..c4169bc --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/reduction-task-2.f90 @@ -0,0 +1,45 @@ +module m + integer :: v + interface + subroutine foo(i) + integer :: i + end + end interface +end + +subroutine bar + use m + implicit none + integer :: i + !$omp do reduction (task, +: v) ! { dg-error "'task' reduction modifier on a construct with a 'nowait' clause" } + do i = 0, 63 + call foo (i) + end do + !$omp end do nowait + !$omp sections reduction (task, +: v) ! { dg-error "'task' reduction modifier on a construct with a 'nowait' clause" } + call foo (-2) + !$omp section + call foo (-3) + !$omp end sections nowait + !$omp scope reduction (task, +: v) ! { dg-error "'task' reduction modifier on a construct with a 'nowait' clause" } + call foo (-4) + !$omp end scope nowait + !$omp simd reduction (task, +: v) ! { dg-error "invalid 'task' reduction modifier on construct other than 'parallel', 'do', 'sections' or 'scope'" } + do i = 0, 63 + v = v + 1 + end do + !$omp do simd reduction (task, +: v) ! { dg-error "invalid 'task' reduction modifier on construct other than 'parallel', 'do', 'sections' or 'scope'" } + do i = 0, 63 + v = v + 1 + end do + !$omp parallel do simd reduction (task, +: v) ! { dg-error "invalid 'task' reduction modifier on construct other than 'parallel', 'do', 'sections' or 'scope'" } + do i = 0, 63 + v = v + 1 + end do + !$omp end parallel do simd + !$omp teams distribute parallel do simd reduction (task, +: v) ! { dg-error "invalid 'task' reduction modifier on construct other than 'parallel', 'do', 'sections' or 'scope'" } + do i = 0, 63 + v = v + 1 + end do + !$omp end teams distribute parallel do simd +end diff --git a/gcc/testsuite/gfortran.dg/gomp/reduction-task-2a.f90 b/gcc/testsuite/gfortran.dg/gomp/reduction-task-2a.f90 new file mode 100644 index 0000000..37ce1c8 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/reduction-task-2a.f90 @@ -0,0 +1,30 @@ +module m + integer :: v + interface + subroutine foo(i) + integer :: i + end + end interface +end + +subroutine bar + use m + implicit none + integer :: i + !$omp taskloop reduction (task, +: v) ! { dg-error "Only DEFAULT permitted as reduction-modifier in REDUCTION clause" } + do i = 0, 63 + call foo (i) + end do + !$omp taskloop simd reduction (task, +: v) ! { dg-error "Only DEFAULT permitted as reduction-modifier in REDUCTION clause" } + do i = 0, 63 + v = v + 1 + end do + !$omp teams reduction (task, +: v) ! { dg-error "Only DEFAULT permitted as reduction-modifier in REDUCTION clause" } + call foo (i) + !$omp end teams + !$omp teams distribute reduction (task, +: v) ! { dg-error "Only DEFAULT permitted as reduction-modifier in REDUCTION clause" } + do i = 0, 63 + call foo (i) + end do + !$omp end teams distribute +end diff --git a/gcc/testsuite/gfortran.dg/gomp/reduction-task-3.f90 b/gcc/testsuite/gfortran.dg/gomp/reduction-task-3.f90 new file mode 100644 index 0000000..ebf1f13 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/reduction-task-3.f90 @@ -0,0 +1,15 @@ +! Fortran testcase of reduction-task-3.f90 ( PR c/91149 ) + +module m + integer :: r +end + +subroutine foo + use m + !$omp parallel reduction(task, +: r) + r = r + 1 + !$omp end parallel + !$omp target parallel reduction(task, +: r) + r = r + 1 + !$omp end target parallel +end diff --git a/gcc/testsuite/gfortran.dg/gomp/scan-1.f90 b/gcc/testsuite/gfortran.dg/gomp/scan-1.f90 index 61d8925..f91c7fa 100644 --- a/gcc/testsuite/gfortran.dg/gomp/scan-1.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/scan-1.f90 @@ -105,6 +105,11 @@ subroutine f3 (c, d) ! ... !$omp end teams + !$omp scope reduction (inscan, +: a) + ! { dg-error "'inscan' REDUCTION clause on construct other than DO, SIMD, DO SIMD, PARALLEL DO, PARALLEL DO SIMD" "" { target *-*-* } .-1 } + ! ... + !$omp end scope + !$omp target parallel do reduction (inscan, +: a) map (c, d) ! { dg-error "'inscan' REDUCTION clause on construct other than DO, SIMD, DO SIMD, PARALLEL DO, PARALLEL DO SIMD" "" { target *-*-* } .-1 } do i = 1, 64 diff --git a/gcc/testsuite/gfortran.dg/gomp/scope-1.f90 b/gcc/testsuite/gfortran.dg/gomp/scope-1.f90 new file mode 100644 index 0000000..43ec800 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/scope-1.f90 @@ -0,0 +1,39 @@ +module m + implicit none (external, type) + integer :: r, r2, r3 +contains + +subroutine foo + integer :: i, j, k + i = 0; j = 0; k = 0 + !$omp scope private (i) reduction (+:r) + i = 1 + r = r + 1 + !$omp end scope nowait + + !$omp scope private (i) reduction (task, +:r) + !$omp scope private (j) reduction (task, +:r2) + !$omp scope private (k) reduction (task, +:r3) + i = 1 + j = 2 + k = 3 + r = r + 1 + r2 = r2 + 1 + r3 = r3 + 1 + !$omp end scope + !$omp end scope + !$omp end scope + !$omp parallel + !$omp scope reduction (+:r) private (i) + !$omp scope reduction (+:r2) private (j) + !$omp single + i = 1 + j = 2 + r = r + 1 + r2 = r2 + 1 + !$omp end single + !$omp end scope nowait + !$omp end scope nowait + !$omp end parallel +end +end module diff --git a/gcc/testsuite/gfortran.dg/gomp/scope-2.f90 b/gcc/testsuite/gfortran.dg/gomp/scope-2.f90 new file mode 100644 index 0000000..a097ced --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/scope-2.f90 @@ -0,0 +1,40 @@ +module m + implicit none (type, external) + integer :: r, r2, r3 = 1 + interface + logical function bar(); end + end interface +contains + +subroutine foo + integer :: i, j, k + i = 0; j = 0; k = 0 + !$omp parallel + if (bar ()) then + !$omp cancel parallel + end if + !$omp scope reduction (+:r) private (i) + !$omp scope reduction (+:r2) private (j) + !$omp single + i = 1; + j = 2; + r = r + 1 + r2 = r2 + 1 + !$omp end single nowait + !$omp end scope + !$omp end scope + !$omp end parallel + + !$omp parallel + if (bar ()) then + !$omp cancel parallel + end if + !$omp scope reduction (task, +:r) private (i) + !$omp scope reduction (task, *:r3) + r = r + 1 + r3 = r3 + 1 + !$omp end scope + !$omp end scope + !$omp end parallel +end +end module -- cgit v1.1 From 408579c9c9b8fee20e1d8114489ce2b93872767c Mon Sep 17 00:00:00 2001 From: Roger Sayle Date: Tue, 17 Aug 2021 14:50:54 +0100 Subject: Improved handling of MULT_EXPR in bit CCP. This patch allows GCC to constant fold (i | (i<<16)) | ((i<<24) | (i<<8)), where i is an unsigned char, or the equivalent (i*65537) | (i*16777472), to i*16843009. The trick is to teach tree_nonzero_bits which bits may be set in the result of a multiplication by a constant given which bits are potentially set in the operands. This allows the optimizations recently added to match.pd to catch more cases. The required mask/value pair from a multiplication may be calculated using a classical shift-and-add algorithm, given we already have implementations for both addition and shift by constant. To keep this optimization "cheap", this functionality is only used if the constant multiplier has a few bits set (unless flag_expensive_optimizations), and we provide a special case fast-path implementation for the common case where the (non-constant) operand has no bits that are guaranteed to be set. I have no evidence that this functionality causes performance issues, it's just that sparse multipliers provide the largest benefit to CCP. 2021-08-17 Roger Sayle gcc/ChangeLog * tree-ssa-ccp.c (bit_value_mult_const): New helper function to calculate the mask-value pair result of a multiplication by an unsigned constant. (bit_value_binop) [MULT_EXPR]: Call it from here for multiplications by (sparse) non-negative constants. gcc/testsuite/ChangeLog * gcc.dg/fold-ior-5.c: New test case. --- gcc/testsuite/gcc.dg/fold-ior-5.c | 17 ++++++ gcc/tree-ssa-ccp.c | 105 +++++++++++++++++++++++++++++++------- 2 files changed, 104 insertions(+), 18 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/fold-ior-5.c (limited to 'gcc') diff --git a/gcc/testsuite/gcc.dg/fold-ior-5.c b/gcc/testsuite/gcc.dg/fold-ior-5.c new file mode 100644 index 0000000..8de5697 --- /dev/null +++ b/gcc/testsuite/gcc.dg/fold-ior-5.c @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ + +unsigned int test_ior(unsigned char i) +{ + return (i | (i<<16)) | ((i<<24) | (i<<8)); +} + +unsigned int test_xor(unsigned char i) +{ + return (i ^ (i<<16)) ^ ((i<<24) ^ (i<<8)); +} + +/* { dg-final { scan-tree-dump-not " \\^ " "optimized" } } */ +/* { dg-final { scan-tree-dump-not " \\| " "optimized" } } */ +/* { dg-final { scan-tree-dump-times " \\* 16843009" 2 "optimized" } } */ + diff --git a/gcc/tree-ssa-ccp.c b/gcc/tree-ssa-ccp.c index 003c9c2..8e4d8ae 100644 --- a/gcc/tree-ssa-ccp.c +++ b/gcc/tree-ssa-ccp.c @@ -1389,6 +1389,66 @@ bit_value_unop (enum tree_code code, signop type_sgn, int type_precision, } } +/* Determine the mask pair *VAL and *MASK from multiplying the + argument mask pair RVAL, RMASK by the unsigned constant C. */ +void +bit_value_mult_const (signop sgn, int width, + widest_int *val, widest_int *mask, + const widest_int &rval, const widest_int &rmask, + widest_int c) +{ + widest_int sum_mask = 0; + + /* Ensure rval_lo only contains known bits. */ + widest_int rval_lo = wi::bit_and_not (rval, rmask); + + if (rval_lo != 0) + { + /* General case (some bits of multiplicand are known set). */ + widest_int sum_val = 0; + while (c != 0) + { + /* Determine the lowest bit set in the multiplier. */ + int bitpos = wi::ctz (c); + widest_int term_mask = rmask << bitpos; + widest_int term_val = rval_lo << bitpos; + + /* sum += term. */ + widest_int lo = sum_val + term_val; + widest_int hi = (sum_val | sum_mask) + (term_val | term_mask); + sum_mask |= term_mask | (lo ^ hi); + sum_val = lo; + + /* Clear this bit in the multiplier. */ + c ^= wi::lshift (1, bitpos); + } + /* Correctly extend the result value. */ + *val = wi::ext (sum_val, width, sgn); + } + else + { + /* Special case (no bits of multiplicand are known set). */ + while (c != 0) + { + /* Determine the lowest bit set in the multiplier. */ + int bitpos = wi::ctz (c); + widest_int term_mask = rmask << bitpos; + + /* sum += term. */ + widest_int hi = sum_mask + term_mask; + sum_mask |= term_mask | hi; + + /* Clear this bit in the multiplier. */ + c ^= wi::lshift (1, bitpos); + } + *val = 0; + } + + /* Correctly extend the result mask. */ + *mask = wi::ext (sum_mask, width, sgn); +} + + /* Apply the operation CODE in type TYPE to the value, mask pairs R1VAL, R1MASK and R2VAL, R2MASK representing a values of type R1TYPE and R2TYPE and set the value, mask pair *VAL and *MASK to the result. */ @@ -1533,24 +1593,33 @@ bit_value_binop (enum tree_code code, signop sgn, int width, } case MULT_EXPR: - { - /* Just track trailing zeros in both operands and transfer - them to the other. */ - int r1tz = wi::ctz (r1val | r1mask); - int r2tz = wi::ctz (r2val | r2mask); - if (r1tz + r2tz >= width) - { - *mask = 0; - *val = 0; - } - else if (r1tz + r2tz > 0) - { - *mask = wi::ext (wi::mask (r1tz + r2tz, true), - width, sgn); - *val = 0; - } - break; - } + if (r2mask == 0 + && !wi::neg_p (r2val, sgn) + && (flag_expensive_optimizations || wi::popcount (r2val) < 8)) + bit_value_mult_const (sgn, width, val, mask, r1val, r1mask, r2val); + else if (r1mask == 0 + && !wi::neg_p (r1val, sgn) + && (flag_expensive_optimizations || wi::popcount (r1val) < 8)) + bit_value_mult_const (sgn, width, val, mask, r2val, r2mask, r1val); + else + { + /* Just track trailing zeros in both operands and transfer + them to the other. */ + int r1tz = wi::ctz (r1val | r1mask); + int r2tz = wi::ctz (r2val | r2mask); + if (r1tz + r2tz >= width) + { + *mask = 0; + *val = 0; + } + else if (r1tz + r2tz > 0) + { + *mask = wi::ext (wi::mask (r1tz + r2tz, true), + width, sgn); + *val = 0; + } + } + break; case EQ_EXPR: case NE_EXPR: -- cgit v1.1 From 897a15f355632bdc31871554892eca5512b3c370 Mon Sep 17 00:00:00 2001 From: Roger Sayle Date: Tue, 17 Aug 2021 14:59:14 +0100 Subject: Improved handling of MINUS_EXPR in bit CCP. This patch improves the bit bounds for MINUS_EXPR during tree-ssa's conditional constant propagation (CCP) pass (and as an added bonus adds support for POINTER_DIFF_EXPR). The pessimistic assumptions made by the current algorithm are demonstrated by considering 1 - (x&1). Intuitively this should have possible values 0 and 1, and therefore an unknown mask of 1. Alas by treating subtraction as a negation followed by addition, the second operand first becomes 0 or -1, with an unknown mask of all ones, which results in the addition containing no known bits. Improved bounds are achieved by using the same approach used for PLUS_EXPR, determining the result with the minimum number of borrows, the result from the maximum number of borrows, and examining the bits they have in common. One additional benefit of this approach is that it is applicable to POINTER_DIFF_EXPR, where previously the negation of a pointer didn't/doesn't make sense. A more convincing example, where a transformation missed by .032t.cpp isn't caught a few passes later by .038t.evrp, is the expression (7 - (x&5)) & 2, which (in the new test case) currently survives the tree-level optimizers but with this patch is now simplified to the constant value 2. 2021-08-17 Roger Sayle gcc/ChangeLog * tree-ssa-ccp.c (bit_value_binop) [MINUS_EXPR]: Use same algorithm as PLUS_EXPR to improve subtraction bit bounds. [POINTER_DIFF_EXPR]: Treat as synonymous with MINUS_EXPR. gcc/testsuite/ChangeLog * gcc.dg/tree-ssa/ssa-ccp-40.c: New test case. --- gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-40.c | 11 +++++++++++ gcc/tree-ssa-ccp.c | 21 ++++++++++++--------- 2 files changed, 23 insertions(+), 9 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-40.c (limited to 'gcc') diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-40.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-40.c new file mode 100644 index 0000000..aa7349e1 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-40.c @@ -0,0 +1,11 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ + +int foo(int x) +{ + int p = 7; + int q = p - (x & 5); + return q & 2; +} + +/* { dg-final { scan-tree-dump "return 2;" "optimized" } } */ diff --git a/gcc/tree-ssa-ccp.c b/gcc/tree-ssa-ccp.c index 8e4d8ae..1a63ae5 100644 --- a/gcc/tree-ssa-ccp.c +++ b/gcc/tree-ssa-ccp.c @@ -1458,7 +1458,7 @@ bit_value_binop (enum tree_code code, signop sgn, int width, widest_int *val, widest_int *mask, signop r1type_sgn, int r1type_precision, const widest_int &r1val, const widest_int &r1mask, - signop r2type_sgn, int r2type_precision, + signop r2type_sgn, int r2type_precision ATTRIBUTE_UNUSED, const widest_int &r2val, const widest_int &r2mask) { bool swap_p = false; @@ -1505,7 +1505,7 @@ bit_value_binop (enum tree_code code, signop sgn, int width, } else { - if (wi::neg_p (shift)) + if (wi::neg_p (shift, r2type_sgn)) { shift = -shift; if (code == RROTATE_EXPR) @@ -1542,7 +1542,7 @@ bit_value_binop (enum tree_code code, signop sgn, int width, } else { - if (wi::neg_p (shift)) + if (wi::neg_p (shift, r2type_sgn)) break; if (code == RSHIFT_EXPR) { @@ -1582,13 +1582,16 @@ bit_value_binop (enum tree_code code, signop sgn, int width, } case MINUS_EXPR: + case POINTER_DIFF_EXPR: { - widest_int temv, temm; - bit_value_unop (NEGATE_EXPR, r2type_sgn, r2type_precision, &temv, &temm, - r2type_sgn, r2type_precision, r2val, r2mask); - bit_value_binop (PLUS_EXPR, sgn, width, val, mask, - r1type_sgn, r1type_precision, r1val, r1mask, - r2type_sgn, r2type_precision, temv, temm); + /* Subtraction is derived from the addition algorithm above. */ + widest_int lo = wi::bit_and_not (r1val, r1mask) - (r2val | r2mask); + lo = wi::ext (lo, width, sgn); + widest_int hi = (r1val | r1mask) - wi::bit_and_not (r2val, r2mask); + hi = wi::ext (hi, width, sgn); + *mask = r1mask | r2mask | (lo ^ hi); + *mask = wi::ext (*mask, width, sgn); + *val = lo; break; } -- cgit v1.1 From e7e17be3be3d43640a9a4a33d59315dec69fdda4 Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Tue, 17 Aug 2021 15:50:31 +0200 Subject: Fall back to masked_gather_load/masked_scatter_store This adds a fallback to the masked_ variants for gather_load and scatter_store if the latter are not available. 2021-08-17 Richard Biener * optabs-query.c (supports_vec_gather_load_p): Also check for masked optabs. (supports_vec_scatter_store_p): Likewise. * tree-vect-data-refs.c (vect_gather_scatter_fn_p): Fall back to masked variants if non-masked are not supported. * tree-vect-patterns.c (vect_recog_gather_scatter_pattern): When we need to use masked gather/scatter but do not have a mask set up a constant true one. * tree-vect-stmts.c (vect_check_scalar_mask): Also allow non-SSA_NAME masks. --- gcc/optabs-query.c | 6 ++++-- gcc/tree-vect-data-refs.c | 22 +++++++++++++++++++--- gcc/tree-vect-patterns.c | 7 +++++-- gcc/tree-vect-stmts.c | 8 -------- 4 files changed, 28 insertions(+), 15 deletions(-) (limited to 'gcc') diff --git a/gcc/optabs-query.c b/gcc/optabs-query.c index 05ee5f5..a6dd0fe 100644 --- a/gcc/optabs-query.c +++ b/gcc/optabs-query.c @@ -740,7 +740,8 @@ supports_vec_gather_load_p () this_fn_optabs->supports_vec_gather_load_cached = true; this_fn_optabs->supports_vec_gather_load - = supports_vec_convert_optab_p (gather_load_optab); + = (supports_vec_convert_optab_p (gather_load_optab) + || supports_vec_convert_optab_p (mask_gather_load_optab)); return this_fn_optabs->supports_vec_gather_load; } @@ -757,7 +758,8 @@ supports_vec_scatter_store_p () this_fn_optabs->supports_vec_scatter_store_cached = true; this_fn_optabs->supports_vec_scatter_store - = supports_vec_convert_optab_p (scatter_store_optab); + = (supports_vec_convert_optab_p (scatter_store_optab) + || supports_vec_convert_optab_p (mask_scatter_store_optab)); return this_fn_optabs->supports_vec_scatter_store; } diff --git a/gcc/tree-vect-data-refs.c b/gcc/tree-vect-data-refs.c index d594c0a..b7dde07 100644 --- a/gcc/tree-vect-data-refs.c +++ b/gcc/tree-vect-data-refs.c @@ -3735,11 +3735,17 @@ vect_gather_scatter_fn_p (vec_info *vinfo, bool read_p, bool masked_p, return false; /* Work out which function we need. */ - internal_fn ifn; + internal_fn ifn, alt_ifn; if (read_p) - ifn = masked_p ? IFN_MASK_GATHER_LOAD : IFN_GATHER_LOAD; + { + ifn = masked_p ? IFN_MASK_GATHER_LOAD : IFN_GATHER_LOAD; + alt_ifn = IFN_MASK_GATHER_LOAD; + } else - ifn = masked_p ? IFN_MASK_SCATTER_STORE : IFN_SCATTER_STORE; + { + ifn = masked_p ? IFN_MASK_SCATTER_STORE : IFN_SCATTER_STORE; + alt_ifn = IFN_MASK_SCATTER_STORE; + } for (;;) { @@ -3755,6 +3761,16 @@ vect_gather_scatter_fn_p (vec_info *vinfo, bool read_p, bool masked_p, *offset_vectype_out = offset_vectype; return true; } + else if (!masked_p + && internal_gather_scatter_fn_supported_p (alt_ifn, vectype, + memory_type, + offset_vectype, + scale)) + { + *ifn_out = alt_ifn; + *offset_vectype_out = offset_vectype; + return true; + } if (TYPE_PRECISION (offset_type) >= POINTER_SIZE && TYPE_PRECISION (offset_type) >= element_bits) diff --git a/gcc/tree-vect-patterns.c b/gcc/tree-vect-patterns.c index 25de97b..8997340 100644 --- a/gcc/tree-vect-patterns.c +++ b/gcc/tree-vect-patterns.c @@ -4820,6 +4820,9 @@ vect_recog_gather_scatter_pattern (vec_info *vinfo, if (mask) mask = vect_convert_mask_for_vectype (mask, gs_vectype, stmt_info, loop_vinfo); + else if (gs_info.ifn == IFN_MASK_SCATTER_STORE + || gs_info.ifn == IFN_MASK_GATHER_LOAD) + mask = build_int_cst (TREE_TYPE (truth_type_for (gs_vectype)), -1); /* Get the invariant base and non-invariant offset, converting the latter to the same width as the vector elements. */ @@ -4847,11 +4850,11 @@ vect_recog_gather_scatter_pattern (vec_info *vinfo, { tree rhs = vect_get_store_rhs (stmt_info); if (mask != NULL) - pattern_stmt = gimple_build_call_internal (IFN_MASK_SCATTER_STORE, 5, + pattern_stmt = gimple_build_call_internal (gs_info.ifn, 5, base, offset, scale, rhs, mask); else - pattern_stmt = gimple_build_call_internal (IFN_SCATTER_STORE, 4, + pattern_stmt = gimple_build_call_internal (gs_info.ifn, 4, base, offset, scale, rhs); } gimple_call_set_nothrow (pattern_stmt, true); diff --git a/gcc/tree-vect-stmts.c b/gcc/tree-vect-stmts.c index cc6c091..4e0b2ad 100644 --- a/gcc/tree-vect-stmts.c +++ b/gcc/tree-vect-stmts.c @@ -2510,14 +2510,6 @@ vect_check_scalar_mask (vec_info *vinfo, stmt_vec_info stmt_info, return false; } - if (TREE_CODE (*mask) != SSA_NAME) - { - if (dump_enabled_p ()) - dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location, - "mask argument is not an SSA name.\n"); - return false; - } - /* If the caller is not prepared for adjusting an external/constant SLP mask vector type fail. */ if (slp_node -- cgit v1.1 From 743b8dd6fd757e997eb060d70fd4ae8e04fb56cd Mon Sep 17 00:00:00 2001 From: Iain Sandoe Date: Sat, 31 Jul 2021 16:29:03 +0100 Subject: Darwin, X86, config: Adjust 'as' command lines [PR100340]. Versions of the assembler using clang from XCode 12.5/12.5.1 have a bug which produces different code layout between debug and non-debug input, leading to a compare fail for default configure parameters. This is a workaround fix to disable the optimisation that is responsible for the bug. Signed-off-by: Iain Sandoe PR target/100340 - Bootstrap fails with Clang 12.0.5 (XCode 12.5) PR target/100340 gcc/ChangeLog: * config.in: Regenerate. * config/i386/darwin.h (EXTRA_ASM_OPTS): New (ASM_SPEC): Pass options to disable branch shortening where needed. * configure: Regenerate. * configure.ac: Detect versions of 'as' that support the optimisation which has the bug. --- gcc/config.in | 7 +++++++ gcc/config/i386/darwin.h | 10 +++++++++- gcc/configure | 35 +++++++++++++++++++++++++++++++++++ gcc/configure.ac | 9 +++++++++ 4 files changed, 60 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/config.in b/gcc/config.in index 7f5b01f..d8a810b 100644 --- a/gcc/config.in +++ b/gcc/config.in @@ -616,6 +616,13 @@ #endif +/* Define if your Mac OS X assembler supports -mllvm -x86-pad-for-align=false. + */ +#ifndef USED_FOR_TARGET +#undef HAVE_AS_MLLVM_X86_PAD_FOR_ALIGN +#endif + + /* Define if your Mac OS X assembler supports the -mmacos-version-min option. */ #ifndef USED_FOR_TARGET diff --git a/gcc/config/i386/darwin.h b/gcc/config/i386/darwin.h index bac3219..73b06e2 100644 --- a/gcc/config/i386/darwin.h +++ b/gcc/config/i386/darwin.h @@ -125,10 +125,18 @@ along with GCC; see the file COPYING3. If not see %{mfentry*:%eDarwin does not support -mfentry or associated options}" \ DARWIN_CC1_SPEC +/* This is a workaround for a tool bug: see PR100340. */ + +#ifdef HAVE_AS_MLLVM_X86_PAD_FOR_ALIGN +#define EXTRA_ASM_OPTS " -mllvm -x86-pad-for-align=false" +#else +#define EXTRA_ASM_OPTS "" +#endif + #undef ASM_SPEC #define ASM_SPEC "-arch %(darwin_arch) \ " ASM_OPTIONS " -force_cpusubtype_ALL \ - %{static}" ASM_MMACOSX_VERSION_MIN_SPEC + %{static}" ASM_MMACOSX_VERSION_MIN_SPEC EXTRA_ASM_OPTS #undef ENDFILE_SPEC #define ENDFILE_SPEC \ diff --git a/gcc/configure b/gcc/configure index 08c2867..a2d1003 100755 --- a/gcc/configure +++ b/gcc/configure @@ -27082,6 +27082,41 @@ $as_echo "$as_me: WARNING: LTO for $target requires binutils >= 2.20.1, but vers fi ;; esac + case $target_os in + darwin2[0-9]* | darwin19*) + { $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler for llvm assembler x86-pad-for-align option" >&5 +$as_echo_n "checking assembler for llvm assembler x86-pad-for-align option... " >&6; } +if ${gcc_cv_as_mllvm_x86_pad_for_align+:} false; then : + $as_echo_n "(cached) " >&6 +else + gcc_cv_as_mllvm_x86_pad_for_align=no + if test x$gcc_cv_as != x; then + $as_echo '.text' > conftest.s + if { ac_try='$gcc_cv_as $gcc_cv_as_flags -mllvm -x86-pad-for-align=false -o conftest.o conftest.s >&5' + { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5 + (eval $ac_try) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; } + then + gcc_cv_as_mllvm_x86_pad_for_align=yes + else + echo "configure: failed program was" >&5 + cat conftest.s >&5 + fi + rm -f conftest.o conftest.s + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_as_mllvm_x86_pad_for_align" >&5 +$as_echo "$gcc_cv_as_mllvm_x86_pad_for_align" >&6; } +if test $gcc_cv_as_mllvm_x86_pad_for_align = yes; then + +$as_echo "#define HAVE_AS_MLLVM_X86_PAD_FOR_ALIGN 1" >>confdefs.h + +fi + + ;; + esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler for -xbrace_comment" >&5 $as_echo_n "checking assembler for -xbrace_comment... " >&6; } diff --git a/gcc/configure.ac b/gcc/configure.ac index 653a1cc..ad8fa5a 100644 --- a/gcc/configure.ac +++ b/gcc/configure.ac @@ -4799,6 +4799,15 @@ foo: nop fi ;; esac + case $target_os in + darwin2[[0-9]]* | darwin19*) + gcc_GAS_CHECK_FEATURE([llvm assembler x86-pad-for-align option], + gcc_cv_as_mllvm_x86_pad_for_align,, + [-mllvm -x86-pad-for-align=false], [.text],, + [AC_DEFINE(HAVE_AS_MLLVM_X86_PAD_FOR_ALIGN, 1, + [Define if your Mac OS X assembler supports -mllvm -x86-pad-for-align=false.])]) + ;; + esac gcc_GAS_CHECK_FEATURE([-xbrace_comment], gcc_cv_as_ix86_xbrace_comment,, [-xbrace_comment=no], [.text],, -- cgit v1.1 From 2d9da1c89778be1d6604cc1465b0dd50f241a352 Mon Sep 17 00:00:00 2001 From: Iain Sandoe Date: Fri, 13 Aug 2021 20:20:04 +0100 Subject: Darwin: Reset section names table at the end of compile. For a single use (typical compile) this vector will be reclaimed as GGC. For JIT this is not sufficient since it does not reset the pointer to NULL (and thus we think the the vector is already allocated when a context is reused). The clears the vector and sets the pointer to NULL at the end of object output. Signed-off-by: Iain Sandoe gcc/ChangeLog: * config/darwin.c (darwin_file_end): Reset and reclaim the section names table at the end of compile. --- gcc/config/darwin.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'gcc') diff --git a/gcc/config/darwin.c b/gcc/config/darwin.c index b160c23..5d1d13c 100644 --- a/gcc/config/darwin.c +++ b/gcc/config/darwin.c @@ -3129,6 +3129,14 @@ darwin_file_end (void) re-arranging data. */ if (!DARWIN_SECTION_ANCHORS || !flag_section_anchors) fprintf (asm_out_file, "\t.subsections_via_symbols\n"); + + /* We rely on this being NULL at the start of compilation; reset it here + so that JIT can reuse a context. */ + if (dwarf_sect_names_table != NULL) + { + dwarf_sect_names_table->truncate (0); + dwarf_sect_names_table = NULL; + } } /* TODO: Add a language hook for identifying if a decl is a vtable. */ -- cgit v1.1 From a42467bdb70650cd2f421e67b6c3418f74feaec2 Mon Sep 17 00:00:00 2001 From: Thomas Schwinge Date: Tue, 17 Aug 2021 08:45:18 +0200 Subject: Restore 'gcc.dg/pr78213.c' testing ... after it had gotten disabled in r243681 (Git commit ecfc21ff34ddc6f8aa517251fb51494c68ff741f) "Introduce selftest::locate_file". gcc/testsuite/ * gcc.dg/pr78213.c: Restore testing. --- gcc/testsuite/gcc.dg/pr78213.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) (limited to 'gcc') diff --git a/gcc/testsuite/gcc.dg/pr78213.c b/gcc/testsuite/gcc.dg/pr78213.c index ebc2cce..40dd3c8 100644 --- a/gcc/testsuite/gcc.dg/pr78213.c +++ b/gcc/testsuite/gcc.dg/pr78213.c @@ -1,12 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-fself-test" } */ - -/* When this test was written -fself-test took no argument, but it - has subsequently gained a mandatory argument, giving the path - to selftest support files (within the srcdir). - It's not clear how to provide this path sanely from - within DejaGnu, so for now, this test is disabled. */ -/* { dg-skip-if "" { *-*-* } } */ +/* { dg-options "-fself-test=$srcdir/selftests" } */ /* Verify that -fself-test does not fail on a non empty source. */ -- cgit v1.1 From 0edf2e81bb02cba43b649b3f6e7258b68a779ac0 Mon Sep 17 00:00:00 2001 From: Thomas Schwinge Date: Tue, 17 Aug 2021 10:47:02 +0200 Subject: Turn global 'ggc_force_collect' variable into 'force_collect' parameter to 'ggc_collect' This simplifies the interface and gets us rid of a global variable. No change in behavior. Clean-up for 2004-09-02 CVS commit (Subversion r86974, Git commit 0772402279c0161fe41784911b52c77e12803c42) "Better memory statistics, take 2". gcc/ * ggc.h (ggc_collect): Add 'force_collect' parameter. * ggc-page.c (ggc_collect): Use that one instead of global 'ggc_force_collect'. Adjust all users. * doc/gty.texi (Invoking the garbage collector): Update. * ggc-internal.h (ggc_force_collect): Remove. * ggc-common.c (ggc_force_collect): Likewise. * selftest.h (forcibly_ggc_collect): Remove. * ggc-tests.c (selftest::forcibly_ggc_collect): Likewise. * read-rtl-function.c (test_loading_labels): Adjust. * selftest-run-tests.c (run_tests): Likewise. --- gcc/doc/gty.texi | 5 ++++- gcc/ggc-common.c | 8 +------- gcc/ggc-internal.h | 3 --- gcc/ggc-page.c | 4 ++-- gcc/ggc-tests.c | 29 +++++++++-------------------- gcc/ggc.h | 6 ++++-- gcc/read-rtl-function.c | 2 +- gcc/selftest-run-tests.c | 2 +- gcc/selftest.h | 5 ----- 9 files changed, 22 insertions(+), 42 deletions(-) (limited to 'gcc') diff --git a/gcc/doc/gty.texi b/gcc/doc/gty.texi index cf070c1..b667d1d 100644 --- a/gcc/doc/gty.texi +++ b/gcc/doc/gty.texi @@ -654,7 +654,10 @@ The GCC garbage collector GGC is only invoked explicitly. In contrast with many other garbage collectors, it is not implicitly invoked by allocation routines when a lot of memory has been consumed. So the only way to have GGC reclaim storage is to call the @code{ggc_collect} -function explicitly. This call is an expensive operation, as it may +function explicitly. +When the @var{force_collect} parameter is set or otherwise an internal +heuristic decides whether to actually collect, this call is +potentially an expensive operation, as it may have to scan the entire heap. Beware that local variables (on the GCC call stack) are not followed by such an invocation (as many other garbage collectors do): you should reference all your data from static diff --git a/gcc/ggc-common.c b/gcc/ggc-common.c index 357bda1..f38e4d5 100644 --- a/gcc/ggc-common.c +++ b/gcc/ggc-common.c @@ -31,9 +31,6 @@ along with GCC; see the file COPYING3. If not see #include "plugin.h" #include "options.h" -/* When set, ggc_collect will do collection. */ -bool ggc_force_collect; - /* When true, protect the contents of the identifier hash table. */ bool ggc_protect_identifiers = true; @@ -965,12 +962,9 @@ dump_ggc_loc_statistics () if (! GATHER_STATISTICS) return; - ggc_force_collect = true; - ggc_collect (); + ggc_collect (true); ggc_mem_desc.dump (GGC_ORIGIN); - - ggc_force_collect = false; } /* Record ALLOCATED and OVERHEAD bytes to descriptor NAME:LINE (FUNCTION). */ diff --git a/gcc/ggc-internal.h b/gcc/ggc-internal.h index 39850cd..4dcfb4c 100644 --- a/gcc/ggc-internal.h +++ b/gcc/ggc-internal.h @@ -88,9 +88,6 @@ extern void ggc_pch_read (FILE *, void *); /* Allocation and collection. */ -/* When set, ggc_collect will do collection. */ -extern bool ggc_force_collect; - extern void ggc_record_overhead (size_t, size_t, void * FINAL_MEM_STAT_DECL); extern void ggc_free_overhead (void *); diff --git a/gcc/ggc-page.c b/gcc/ggc-page.c index 1b09f0d..a6fbeca 100644 --- a/gcc/ggc-page.c +++ b/gcc/ggc-page.c @@ -2184,7 +2184,7 @@ validate_free_objects (void) /* Top level mark-and-sweep routine. */ void -ggc_collect (void) +ggc_collect (bool force_collect) { /* Avoid frequent unnecessary work by skipping collection if the total allocations haven't expanded much since the last @@ -2196,7 +2196,7 @@ ggc_collect (void) memory_block_pool::trim (); float min_expand = allocated_last_gc * param_ggc_min_expand / 100; - if (G.allocated < allocated_last_gc + min_expand && !ggc_force_collect) + if (G.allocated < allocated_last_gc + min_expand && !force_collect) return; timevar_push (TV_GC); diff --git a/gcc/ggc-tests.c b/gcc/ggc-tests.c index 4ee9550..2891c20 100644 --- a/gcc/ggc-tests.c +++ b/gcc/ggc-tests.c @@ -22,21 +22,10 @@ along with GCC; see the file COPYING3. If not see #include "coretypes.h" #include "tree-core.h" #include "tree.h" -#include "ggc-internal.h" /* (for ggc_force_collect). */ #include "selftest.h" #if CHECKING_P -/* A helper function for writing ggc tests. */ - -void -selftest::forcibly_ggc_collect () -{ - ggc_force_collect = true; - ggc_collect (); - ggc_force_collect = false; -} - /* The various GTY markers must be outside of a namespace to be seen by gengtype, so we don't put this file within the selftest namespace. */ @@ -58,7 +47,7 @@ test_basic_struct () root_test_struct = ggc_cleared_alloc (); root_test_struct->other = ggc_cleared_alloc (); - selftest::forcibly_ggc_collect (); + ggc_collect (true); ASSERT_TRUE (ggc_marked_p (root_test_struct)); ASSERT_TRUE (ggc_marked_p (root_test_struct->other)); @@ -88,7 +77,7 @@ test_length () for (int i = 0; i < count; i++) root_test_of_length->elem[i] = ggc_cleared_alloc (); - selftest::forcibly_ggc_collect (); + ggc_collect (true); ASSERT_TRUE (ggc_marked_p (root_test_of_length)); for (int i = 0; i < count; i++) @@ -162,7 +151,7 @@ test_union () test_struct *referenced_by_other = ggc_cleared_alloc (); other->m_ptr = referenced_by_other; - selftest::forcibly_ggc_collect (); + ggc_collect (true); ASSERT_TRUE (ggc_marked_p (root_test_of_union_1)); ASSERT_TRUE (ggc_marked_p (ts)); @@ -203,7 +192,7 @@ test_finalization () test_struct_with_dtor::dtor_call_count = 0; - selftest::forcibly_ggc_collect (); + ggc_collect (true); /* Verify that the destructor was run for each instance. */ ASSERT_EQ (count, test_struct_with_dtor::dtor_call_count); @@ -221,7 +210,7 @@ test_deletable_global () test_of_deletable = ggc_cleared_alloc (); ASSERT_TRUE (test_of_deletable != NULL); - selftest::forcibly_ggc_collect (); + ggc_collect (true); ASSERT_EQ (NULL, test_of_deletable); } @@ -294,7 +283,7 @@ test_inheritance () test_some_subclass_as_base_ptr = new some_subclass (); test_some_other_subclass_as_base_ptr = new some_other_subclass (); - selftest::forcibly_ggc_collect (); + ggc_collect (true); /* Verify that the roots and everything referenced by them got marked (both for fields in the base class and those in subclasses). */ @@ -373,7 +362,7 @@ test_chain_next () tail_node = new_node; } - selftest::forcibly_ggc_collect (); + ggc_collect (true); /* If we got here, we survived. */ @@ -440,7 +429,7 @@ test_user_struct () num_calls_to_user_gt_ggc_mx = 0; - selftest::forcibly_ggc_collect (); + ggc_collect (true); ASSERT_TRUE (ggc_marked_p (root_user_struct_ptr)); ASSERT_TRUE (ggc_marked_p (referenced)); @@ -458,7 +447,7 @@ test_tree_marking () { dummy_unittesting_tree = build_int_cst (integer_type_node, 1066); - selftest::forcibly_ggc_collect (); + ggc_collect (true); ASSERT_TRUE (ggc_marked_p (dummy_unittesting_tree)); } diff --git a/gcc/ggc.h b/gcc/ggc.h index 9288471..0f640b2 100644 --- a/gcc/ggc.h +++ b/gcc/ggc.h @@ -262,8 +262,10 @@ extern const char *ggc_alloc_string (const char *contents, int length #define ggc_strdup(S) ggc_alloc_string ((S), -1 MEM_STAT_INFO) /* Invoke the collector. Garbage collection occurs only when this - function is called, not during allocations. */ -extern void ggc_collect (void); + function is called, not during allocations. + Unless FORCE_COLLECT, an internal heuristic decides whether to actually + collect. */ +extern void ggc_collect (bool force_collect = false); /* Return unused memory pages to the system. */ extern void ggc_trim (void); diff --git a/gcc/read-rtl-function.c b/gcc/read-rtl-function.c index ca580d3..0badfb9 100644 --- a/gcc/read-rtl-function.c +++ b/gcc/read-rtl-function.c @@ -1861,7 +1861,7 @@ test_loading_labels () /* Ensure that label names read from a dump are GC-managed and are found through the insn. */ - forcibly_ggc_collect (); + ggc_collect (true); ASSERT_TRUE (ggc_marked_p (insn_200)); ASSERT_TRUE (ggc_marked_p (LABEL_NAME (insn_200))); } diff --git a/gcc/selftest-run-tests.c b/gcc/selftest-run-tests.c index 1b5583e..10881fc 100644 --- a/gcc/selftest-run-tests.c +++ b/gcc/selftest-run-tests.c @@ -128,7 +128,7 @@ selftest::run_tests () issues. For example, if any GC-managed items have buggy (or missing) finalizers, this last collection will ensure that things that were failed to be finalized can be detected by valgrind. */ - forcibly_ggc_collect (); + ggc_collect (true); /* Finished running tests; the test_runner dtor will print a summary. */ } diff --git a/gcc/selftest.h b/gcc/selftest.h index 80459d6..58d8d38 100644 --- a/gcc/selftest.h +++ b/gcc/selftest.h @@ -190,11 +190,6 @@ for_each_line_table_case (void (*testcase) (const line_table_case &)); extern char *read_file (const location &loc, const char *path); -/* A helper function for writing tests that interact with the - garbage collector. */ - -extern void forcibly_ggc_collect (); - /* Convert a path relative to SRCDIR/gcc/testsuite/selftests to a real path (either absolute, or relative to pwd). The result should be freed by the caller. */ -- cgit v1.1 From 798666392b512a585f0de2983a5d3423e960959e Mon Sep 17 00:00:00 2001 From: Matt Jacobson Date: Thu, 29 Jul 2021 09:57:23 +0100 Subject: Objective-C: Default flag_objc_sjlj_exceptions off for NeXT ABI >= 2. Signed-off-by: Matt Jacobson gcc/c-family/ChangeLog: * c-opts.c (c_common_post_options): Default to flag_objc_sjlj_exceptions = 1 only when flag_objc_abi < 2. gcc/objc/ChangeLog: * objc-next-runtime-abi-02.c (objc_next_runtime_abi_02_init): Warn about and reset flag_objc_sjlj_exceptions regardless of flag_objc_exceptions. (next_runtime_02_initialize): Use a checking assert that flag_objc_sjlj_exceptions is off. --- gcc/c-family/c-opts.c | 4 ++-- gcc/objc/objc-next-runtime-abi-02.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'gcc') diff --git a/gcc/c-family/c-opts.c b/gcc/c-family/c-opts.c index 1c4e832c..373af0c 100644 --- a/gcc/c-family/c-opts.c +++ b/gcc/c-family/c-opts.c @@ -852,9 +852,9 @@ c_common_post_options (const char **pfilename) else if (!flag_gnu89_inline && !flag_isoc99) error ("%<-fno-gnu89-inline%> is only supported in GNU99 or C99 mode"); - /* Default to ObjC sjlj exception handling if NeXT runtime. */ + /* Default to ObjC sjlj exception handling if NeXT runtime < v2. */ if (flag_objc_sjlj_exceptions < 0) - flag_objc_sjlj_exceptions = flag_next_runtime; + flag_objc_sjlj_exceptions = (flag_next_runtime && flag_objc_abi < 2); if (flag_objc_exceptions && !flag_objc_sjlj_exceptions) flag_exceptions = 1; diff --git a/gcc/objc/objc-next-runtime-abi-02.c b/gcc/objc/objc-next-runtime-abi-02.c index 963d1bf..c552013 100644 --- a/gcc/objc/objc-next-runtime-abi-02.c +++ b/gcc/objc/objc-next-runtime-abi-02.c @@ -245,7 +245,7 @@ objc_next_runtime_abi_02_init (objc_runtime_hooks *rthooks) { extern_names = ggc_cleared_vec_alloc (SIZEHASHTABLE); - if (flag_objc_exceptions && flag_objc_sjlj_exceptions) + if (flag_objc_sjlj_exceptions) { inform (UNKNOWN_LOCATION, "%<-fobjc-sjlj-exceptions%> is ignored for " @@ -507,7 +507,7 @@ static void next_runtime_02_initialize (void) objc_getPropertyStruct_decl = NULL_TREE; objc_setPropertyStruct_decl = NULL_TREE; - gcc_assert (!flag_objc_sjlj_exceptions); + gcc_checking_assert (!flag_objc_sjlj_exceptions); /* Although we warn that fobjc-exceptions is required for exceptions code, we carry on and create it anyway. */ -- cgit v1.1 From 32c3a75390623a0470df52af13f78baddd562981 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Tue, 17 Aug 2021 21:06:39 +0200 Subject: c++: Implement P0466R5 __cpp_lib_is_layout_compatible compiler helpers [PR101539] The following patch implements __is_layout_compatible trait and __builtin_is_corresponding_member helper function for the std::is_corresponding_member template function. As the current definition of layout compatible type has various problems, which result e.g. in corresponding members in layout compatible types having different member offsets, the patch anticipates some changes to the C++ standard: 1) class or enumeral types aren't layout compatible if they have different alignment or size 2) if two members have different offsets, they can't be corresponding members ([[no_unique_address]] with empty types can change that, or alignas on the member decls) 3) in unions, bitfields can't correspond to non-unions, or bitfields can't correspond to bitfields with different widths, or members with [[no_unique_address]] can't correspond to members without that attribute __builtin_is_corresponding_member for anonymous structs (GCC extension) will recurse into the anonymous structs. For anonymous unions it will emit a sorry if it can't prove such member types can't appear in the anonymous unions or anonymous aggregates in that union, because corresponding member is defined only using common initial sequence which is only defined for std-layout non-union class types and so I have no idea what to do otherwise in that case. 2021-08-17 Jakub Jelinek PR c++/101539 gcc/c-family/ * c-common.h (enum rid): Add RID_IS_LAYOUT_COMPATIBLE. * c-common.c (c_common_reswords): Add __is_layout_compatible. gcc/cp/ * cp-tree.h (enum cp_trait_kind): Add CPTK_IS_LAYOUT_COMPATIBLE. (enum cp_built_in_function): Add CP_BUILT_IN_IS_CORRESPONDING_MEMBER. (fold_builtin_is_corresponding_member, next_common_initial_seqence, layout_compatible_type_p): Declare. * parser.c (cp_parser_primary_expression): Handle RID_IS_LAYOUT_COMPATIBLE. (cp_parser_trait_expr): Likewise. * cp-objcp-common.c (names_builtin_p): Likewise. * constraint.cc (diagnose_trait_expr): Handle CPTK_IS_LAYOUT_COMPATIBLE. * decl.c (cxx_init_decl_processing): Register __builtin_is_corresponding_member builtin. * constexpr.c (cxx_eval_builtin_function_call): Handle CP_BUILT_IN_IS_CORRESPONDING_MEMBER builtin. * semantics.c (is_corresponding_member_union, is_corresponding_member_aggr, fold_builtin_is_corresponding_member): New functions. (trait_expr_value): Handle CPTK_IS_LAYOUT_COMPATIBLE. (finish_trait_expr): Likewise. * typeck.c (next_common_initial_seqence, layout_compatible_type_p): New functions. * cp-gimplify.c (cp_gimplify_expr): Fold CP_BUILT_IN_IS_CORRESPONDING_MEMBER. (cp_fold): Likewise. * tree.c (builtin_valid_in_constant_expr_p): Handle CP_BUILT_IN_IS_CORRESPONDING_MEMBER. * cxx-pretty-print.c (pp_cxx_trait_expression): Handle CPTK_IS_LAYOUT_COMPATIBLE. * class.c (remove_zero_width_bit_fields): Remove. (layout_class_type): Don't call it. gcc/testsuite/ * g++.dg/cpp2a/is-corresponding-member1.C: New test. * g++.dg/cpp2a/is-corresponding-member2.C: New test. * g++.dg/cpp2a/is-corresponding-member3.C: New test. * g++.dg/cpp2a/is-corresponding-member4.C: New test. * g++.dg/cpp2a/is-corresponding-member5.C: New test. * g++.dg/cpp2a/is-corresponding-member6.C: New test. * g++.dg/cpp2a/is-corresponding-member7.C: New test. * g++.dg/cpp2a/is-corresponding-member8.C: New test. * g++.dg/cpp2a/is-layout-compatible1.C: New test. * g++.dg/cpp2a/is-layout-compatible2.C: New test. * g++.dg/cpp2a/is-layout-compatible3.C: New test. --- gcc/c-family/c-common.c | 1 + gcc/c-family/c-common.h | 3 +- gcc/cp/class.c | 30 --- gcc/cp/constexpr.c | 12 + gcc/cp/constraint.cc | 3 + gcc/cp/cp-gimplify.c | 13 + gcc/cp/cp-objcp-common.c | 1 + gcc/cp/cp-tree.h | 5 + gcc/cp/cxx-pretty-print.c | 4 + gcc/cp/decl.c | 7 + gcc/cp/parser.c | 5 + gcc/cp/semantics.c | 268 +++++++++++++++++++++ gcc/cp/tree.c | 1 + gcc/cp/typeck.c | 170 +++++++++++++ .../g++.dg/cpp2a/is-corresponding-member1.C | 61 +++++ .../g++.dg/cpp2a/is-corresponding-member2.C | 158 ++++++++++++ .../g++.dg/cpp2a/is-corresponding-member3.C | 14 ++ .../g++.dg/cpp2a/is-corresponding-member4.C | 25 ++ .../g++.dg/cpp2a/is-corresponding-member5.C | 95 ++++++++ .../g++.dg/cpp2a/is-corresponding-member6.C | 34 +++ .../g++.dg/cpp2a/is-corresponding-member7.C | 71 ++++++ .../g++.dg/cpp2a/is-corresponding-member8.C | 25 ++ gcc/testsuite/g++.dg/cpp2a/is-layout-compatible1.C | 80 ++++++ gcc/testsuite/g++.dg/cpp2a/is-layout-compatible2.C | 36 +++ gcc/testsuite/g++.dg/cpp2a/is-layout-compatible3.C | 64 +++++ 25 files changed, 1155 insertions(+), 31 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp2a/is-corresponding-member1.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/is-corresponding-member2.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/is-corresponding-member3.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/is-corresponding-member4.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/is-corresponding-member5.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/is-corresponding-member6.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/is-corresponding-member7.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/is-corresponding-member8.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/is-layout-compatible1.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/is-layout-compatible2.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/is-layout-compatible3.C (limited to 'gcc') diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index 00ac3c5..017e415 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -420,6 +420,7 @@ const struct c_common_resword c_common_reswords[] = { "__is_empty", RID_IS_EMPTY, D_CXXONLY }, { "__is_enum", RID_IS_ENUM, D_CXXONLY }, { "__is_final", RID_IS_FINAL, D_CXXONLY }, + { "__is_layout_compatible", RID_IS_LAYOUT_COMPATIBLE, D_CXXONLY }, { "__is_literal_type", RID_IS_LITERAL_TYPE, D_CXXONLY }, { "__is_pointer_interconvertible_base_of", RID_IS_POINTER_INTERCONVERTIBLE_BASE_OF, D_CXXONLY }, diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index 025123a..d66bf15 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -173,7 +173,8 @@ enum rid RID_IS_ABSTRACT, RID_IS_AGGREGATE, RID_IS_BASE_OF, RID_IS_CLASS, RID_IS_EMPTY, RID_IS_ENUM, - RID_IS_FINAL, RID_IS_LITERAL_TYPE, + RID_IS_FINAL, RID_IS_LAYOUT_COMPATIBLE, + RID_IS_LITERAL_TYPE, RID_IS_POINTER_INTERCONVERTIBLE_BASE_OF, RID_IS_POD, RID_IS_POLYMORPHIC, RID_IS_SAME_AS, diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 6f31700..7138e30 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -136,7 +136,6 @@ static bool check_field_decl (tree, tree, int *, int *); static void check_field_decls (tree, tree *, int *, int *); static void build_base_fields (record_layout_info, splay_tree, tree *); static void check_methods (tree); -static void remove_zero_width_bit_fields (tree); static bool accessible_nvdtor_p (tree); /* Used by find_flexarrays and related functions. */ @@ -5754,31 +5753,6 @@ type_build_dtor_call (tree t) return false; } -/* Remove all zero-width bit-fields from T. */ - -static void -remove_zero_width_bit_fields (tree t) -{ - tree *fieldsp; - - fieldsp = &TYPE_FIELDS (t); - while (*fieldsp) - { - if (TREE_CODE (*fieldsp) == FIELD_DECL - && DECL_C_BIT_FIELD (*fieldsp) - /* We should not be confused by the fact that grokbitfield - temporarily sets the width of the bit field into - DECL_BIT_FIELD_REPRESENTATIVE (*fieldsp). - check_bitfield_decl eventually sets DECL_SIZE (*fieldsp) - to that width. */ - && (DECL_SIZE (*fieldsp) == NULL_TREE - || integer_zerop (DECL_SIZE (*fieldsp)))) - *fieldsp = DECL_CHAIN (*fieldsp); - else - fieldsp = &DECL_CHAIN (*fieldsp); - } -} - /* Returns TRUE iff we need a cookie when dynamically allocating an array whose elements have the indicated class TYPE. */ @@ -6770,10 +6744,6 @@ layout_class_type (tree t, tree *virtuals_p) normalize_rli (rli); } - /* Delete all zero-width bit-fields from the list of fields. Now - that the type is laid out they are no longer important. */ - remove_zero_width_bit_fields (t); - if (CLASSTYPE_NON_LAYOUT_POD_P (t) || CLASSTYPE_EMPTY_P (t)) { /* T needs a different layout as a base (eliding virtual bases diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 25d84a3..b9c0062 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -1438,6 +1438,18 @@ cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun, = fold_builtin_is_pointer_inverconvertible_with_class (loc, nargs, args); } + else if (fndecl_built_in_p (fun, + CP_BUILT_IN_IS_CORRESPONDING_MEMBER, + BUILT_IN_FRONTEND)) + { + location_t loc = EXPR_LOCATION (t); + if (nargs >= 2) + { + VERIFY_CONSTANT (args[0]); + VERIFY_CONSTANT (args[1]); + } + new_call = fold_builtin_is_corresponding_member (loc, nargs, args); + } else new_call = fold_builtin_call_array (EXPR_LOCATION (t), TREE_TYPE (t), CALL_EXPR_FN (t), nargs, args); diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc index e608c5a..1aaf1e2 100644 --- a/gcc/cp/constraint.cc +++ b/gcc/cp/constraint.cc @@ -3628,6 +3628,9 @@ diagnose_trait_expr (tree expr, tree args) case CPTK_IS_FINAL: inform (loc, " %qT is not a final class", t1); break; + case CPTK_IS_LAYOUT_COMPATIBLE: + inform (loc, " %qT is not layout compatible with %qT", t1, t2); + break; case CPTK_IS_LITERAL_TYPE: inform (loc, " %qT is not a literal type", t1); break; diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c index 6e274ac..bf928a8 100644 --- a/gcc/cp/cp-gimplify.c +++ b/gcc/cp/cp-gimplify.c @@ -658,12 +658,20 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p) *expr_p = fold_builtin_source_location (EXPR_LOCATION (*expr_p)); break; + case CP_BUILT_IN_IS_CORRESPONDING_MEMBER: + *expr_p + = fold_builtin_is_corresponding_member + (EXPR_LOCATION (*expr_p), call_expr_nargs (*expr_p), + &CALL_EXPR_ARG (*expr_p, 0)); + break; case CP_BUILT_IN_IS_POINTER_INTERCONVERTIBLE_WITH_CLASS: *expr_p = fold_builtin_is_pointer_inverconvertible_with_class (EXPR_LOCATION (*expr_p), call_expr_nargs (*expr_p), &CALL_EXPR_ARG (*expr_p, 0)); break; + default: + break; } } break; @@ -2579,6 +2587,11 @@ cp_fold (tree x) case CP_BUILT_IN_SOURCE_LOCATION: x = fold_builtin_source_location (EXPR_LOCATION (x)); break; + case CP_BUILT_IN_IS_CORRESPONDING_MEMBER: + x = fold_builtin_is_corresponding_member + (EXPR_LOCATION (x), call_expr_nargs (x), + &CALL_EXPR_ARG (x, 0)); + break; case CP_BUILT_IN_IS_POINTER_INTERCONVERTIBLE_WITH_CLASS: x = fold_builtin_is_pointer_inverconvertible_with_class (EXPR_LOCATION (x), call_expr_nargs (x), diff --git a/gcc/cp/cp-objcp-common.c b/gcc/cp/cp-objcp-common.c index beef012..98fd962 100644 --- a/gcc/cp/cp-objcp-common.c +++ b/gcc/cp/cp-objcp-common.c @@ -413,6 +413,7 @@ names_builtin_p (const char *name) case RID_IS_EMPTY: case RID_IS_ENUM: case RID_IS_FINAL: + case RID_IS_LAYOUT_COMPATIBLE: case RID_IS_LITERAL_TYPE: case RID_IS_POINTER_INTERCONVERTIBLE_BASE_OF: case RID_IS_POD: diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index bd3f12a..14e2db2 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -1365,6 +1365,7 @@ enum cp_trait_kind CPTK_IS_EMPTY, CPTK_IS_ENUM, CPTK_IS_FINAL, + CPTK_IS_LAYOUT_COMPATIBLE, CPTK_IS_LITERAL_TYPE, CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF, CPTK_IS_POD, @@ -6358,6 +6359,7 @@ struct GTY((chain_next ("%h.next"))) tinst_level { enum cp_built_in_function { CP_BUILT_IN_IS_CONSTANT_EVALUATED, CP_BUILT_IN_INTEGER_PACK, + CP_BUILT_IN_IS_CORRESPONDING_MEMBER, CP_BUILT_IN_IS_POINTER_INTERCONVERTIBLE_WITH_CLASS, CP_BUILT_IN_SOURCE_LOCATION, CP_BUILT_IN_LAST @@ -7574,6 +7576,7 @@ extern tree baselink_for_fns (tree); extern void finish_static_assert (tree, tree, location_t, bool, bool); extern tree finish_decltype_type (tree, bool, tsubst_flags_t); +extern tree fold_builtin_is_corresponding_member (location_t, int, tree *); extern tree fold_builtin_is_pointer_inverconvertible_with_class (location_t, int, tree *); extern tree finish_trait_expr (location_t, enum cp_trait_kind, tree, tree); extern tree build_lambda_expr (void); @@ -7800,6 +7803,8 @@ extern bool comp_except_specs (const_tree, const_tree, int); extern bool comptypes (tree, tree, int); extern bool same_type_ignoring_top_level_qualifiers_p (tree, tree); extern bool similar_type_p (tree, tree); +extern bool next_common_initial_seqence (tree &, tree &); +extern bool layout_compatible_type_p (tree, tree); extern bool compparms (const_tree, const_tree); extern int comp_cv_qualification (const_tree, const_tree); extern int comp_cv_qualification (int, int); diff --git a/gcc/cp/cxx-pretty-print.c b/gcc/cp/cxx-pretty-print.c index b899162..25cabfe 100644 --- a/gcc/cp/cxx-pretty-print.c +++ b/gcc/cp/cxx-pretty-print.c @@ -2645,6 +2645,9 @@ pp_cxx_trait_expression (cxx_pretty_printer *pp, tree t) case CPTK_IS_FINAL: pp_cxx_ws_string (pp, "__is_final"); break; + case CPTK_IS_LAYOUT_COMPATIBLE: + pp_cxx_ws_string (pp, "__is_layout_compatible"); + break; case CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF: pp_cxx_ws_string (pp, "__is_pointer_interconvertible_base_of"); break; @@ -2700,6 +2703,7 @@ pp_cxx_trait_expression (cxx_pretty_printer *pp, tree t) if (kind == CPTK_IS_BASE_OF || kind == CPTK_IS_SAME_AS + || kind == CPTK_IS_LAYOUT_COMPATIBLE || kind == CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF) { pp_cxx_separate_with (pp, ','); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index b3671ee..32d07ba 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -4470,6 +4470,13 @@ cxx_init_decl_processing (void) tree bool_vaftype = build_varargs_function_type_list (boolean_type_node, NULL_TREE); decl + = add_builtin_function ("__builtin_is_corresponding_member", + bool_vaftype, + CP_BUILT_IN_IS_CORRESPONDING_MEMBER, + BUILT_IN_FRONTEND, NULL, NULL_TREE); + set_call_expr_flags (decl, ECF_CONST | ECF_NOTHROW | ECF_LEAF); + + decl = add_builtin_function ("__builtin_is_pointer_interconvertible_with_class", bool_vaftype, CP_BUILT_IN_IS_POINTER_INTERCONVERTIBLE_WITH_CLASS, diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index c31965a..9de72f8 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -5816,6 +5816,7 @@ cp_parser_primary_expression (cp_parser *parser, case RID_IS_EMPTY: case RID_IS_ENUM: case RID_IS_FINAL: + case RID_IS_LAYOUT_COMPATIBLE: case RID_IS_LITERAL_TYPE: case RID_IS_POINTER_INTERCONVERTIBLE_BASE_OF: case RID_IS_POD: @@ -10707,6 +10708,10 @@ cp_parser_trait_expr (cp_parser* parser, enum rid keyword) case RID_IS_FINAL: kind = CPTK_IS_FINAL; break; + case RID_IS_LAYOUT_COMPATIBLE: + kind = CPTK_IS_LAYOUT_COMPATIBLE; + binary = true; + break; case RID_IS_LITERAL_TYPE: kind = CPTK_IS_LITERAL_TYPE; break; diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 0198d2d..e191aa3 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -10693,6 +10693,258 @@ fold_builtin_is_pointer_inverconvertible_with_class (location_t loc, int nargs, build_zero_cst (TREE_TYPE (arg))); } +/* Helper function for is_corresponding_member_aggr. Return true if + MEMBERTYPE pointer-to-data-member ARG can be found in anonymous + union or structure BASETYPE. */ + +static bool +is_corresponding_member_union (tree basetype, tree membertype, tree arg) +{ + for (tree field = TYPE_FIELDS (basetype); field; field = DECL_CHAIN (field)) + if (TREE_CODE (field) != FIELD_DECL || DECL_BIT_FIELD_TYPE (field)) + continue; + else if (same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (field), + membertype)) + { + if (TREE_CODE (arg) != INTEGER_CST + || tree_int_cst_equal (arg, byte_position (field))) + return true; + } + else if (ANON_AGGR_TYPE_P (TREE_TYPE (field))) + { + tree narg = arg; + if (TREE_CODE (basetype) != UNION_TYPE + && TREE_CODE (narg) == INTEGER_CST) + narg = size_binop (MINUS_EXPR, arg, byte_position (field)); + if (is_corresponding_member_union (TREE_TYPE (field), + membertype, narg)) + return true; + } + return false; +} + +/* Helper function for fold_builtin_is_corresponding_member call. + Return boolean_false_node if MEMBERTYPE1 BASETYPE1::*ARG1 and + MEMBERTYPE2 BASETYPE2::*ARG2 aren't corresponding members, + boolean_true_node if they are corresponding members, or for + non-constant ARG2 the highest member offset for corresponding + members. */ + +static tree +is_corresponding_member_aggr (location_t loc, tree basetype1, tree membertype1, + tree arg1, tree basetype2, tree membertype2, + tree arg2) +{ + tree field1 = TYPE_FIELDS (basetype1); + tree field2 = TYPE_FIELDS (basetype2); + tree ret = boolean_false_node; + while (1) + { + bool r = next_common_initial_seqence (field1, field2); + if (field1 == NULL_TREE || field2 == NULL_TREE) + break; + if (r + && same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (field1), + membertype1) + && same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (field2), + membertype2)) + { + tree pos = byte_position (field1); + if (TREE_CODE (arg1) == INTEGER_CST + && tree_int_cst_equal (arg1, pos)) + { + if (TREE_CODE (arg2) == INTEGER_CST) + return boolean_true_node; + return pos; + } + else if (TREE_CODE (arg1) != INTEGER_CST) + ret = pos; + } + else if (ANON_AGGR_TYPE_P (TREE_TYPE (field1)) + && ANON_AGGR_TYPE_P (TREE_TYPE (field2))) + { + if ((!lookup_attribute ("no_unique_address", + DECL_ATTRIBUTES (field1))) + != !lookup_attribute ("no_unique_address", + DECL_ATTRIBUTES (field2))) + break; + if (!tree_int_cst_equal (bit_position (field1), + bit_position (field2))) + break; + bool overlap = true; + tree pos = byte_position (field1); + if (TREE_CODE (arg1) == INTEGER_CST) + { + tree off1 = fold_convert (sizetype, arg1); + tree sz1 = TYPE_SIZE_UNIT (TREE_TYPE (field1)); + if (tree_int_cst_lt (off1, pos) + || tree_int_cst_le (size_binop (PLUS_EXPR, pos, sz1), off1)) + overlap = false; + } + if (TREE_CODE (arg2) == INTEGER_CST) + { + tree off2 = fold_convert (sizetype, arg2); + tree sz2 = TYPE_SIZE_UNIT (TREE_TYPE (field2)); + if (tree_int_cst_lt (off2, pos) + || tree_int_cst_le (size_binop (PLUS_EXPR, pos, sz2), off2)) + overlap = false; + } + if (overlap + && NON_UNION_CLASS_TYPE_P (TREE_TYPE (field1)) + && NON_UNION_CLASS_TYPE_P (TREE_TYPE (field2))) + { + tree narg1 = arg1; + if (TREE_CODE (arg1) == INTEGER_CST) + narg1 = size_binop (MINUS_EXPR, + fold_convert (sizetype, arg1), pos); + tree narg2 = arg2; + if (TREE_CODE (arg2) == INTEGER_CST) + narg2 = size_binop (MINUS_EXPR, + fold_convert (sizetype, arg2), pos); + tree t1 = TREE_TYPE (field1); + tree t2 = TREE_TYPE (field2); + tree nret = is_corresponding_member_aggr (loc, t1, membertype1, + narg1, t2, membertype2, + narg2); + if (nret != boolean_false_node) + { + if (nret == boolean_true_node) + return nret; + if (TREE_CODE (arg1) == INTEGER_CST) + return size_binop (PLUS_EXPR, nret, pos); + ret = size_binop (PLUS_EXPR, nret, pos); + } + } + else if (overlap + && TREE_CODE (TREE_TYPE (field1)) == UNION_TYPE + && TREE_CODE (TREE_TYPE (field2)) == UNION_TYPE) + { + tree narg1 = arg1; + if (TREE_CODE (arg1) == INTEGER_CST) + narg1 = size_binop (MINUS_EXPR, + fold_convert (sizetype, arg1), pos); + tree narg2 = arg2; + if (TREE_CODE (arg2) == INTEGER_CST) + narg2 = size_binop (MINUS_EXPR, + fold_convert (sizetype, arg2), pos); + if (is_corresponding_member_union (TREE_TYPE (field1), + membertype1, narg1) + && is_corresponding_member_union (TREE_TYPE (field2), + membertype2, narg2)) + { + sorry_at (loc, "%<__builtin_is_corresponding_member%> " + "not well defined for anonymous unions"); + return boolean_false_node; + } + } + } + if (!r) + break; + field1 = DECL_CHAIN (field1); + field2 = DECL_CHAIN (field2); + } + return ret; +} + +/* Fold __builtin_is_corresponding_member call. */ + +tree +fold_builtin_is_corresponding_member (location_t loc, int nargs, + tree *args) +{ + /* Unless users call the builtin directly, the following 3 checks should be + ensured from std::is_corresponding_member function template. */ + if (nargs != 2) + { + error_at (loc, "%<__builtin_is_corresponding_member%> " + "needs two arguments"); + return boolean_false_node; + } + tree arg1 = args[0]; + tree arg2 = args[1]; + if (error_operand_p (arg1) || error_operand_p (arg2)) + return boolean_false_node; + if (!TYPE_PTRMEM_P (TREE_TYPE (arg1)) + || !TYPE_PTRMEM_P (TREE_TYPE (arg2))) + { + error_at (loc, "%<__builtin_is_corresponding_member%> " + "argument is not pointer to member"); + return boolean_false_node; + } + + if (!TYPE_PTRDATAMEM_P (TREE_TYPE (arg1)) + || !TYPE_PTRDATAMEM_P (TREE_TYPE (arg2))) + return boolean_false_node; + + tree membertype1 = TREE_TYPE (TREE_TYPE (arg1)); + tree basetype1 = TYPE_OFFSET_BASETYPE (TREE_TYPE (arg1)); + if (!complete_type_or_else (basetype1, NULL_TREE)) + return boolean_false_node; + + tree membertype2 = TREE_TYPE (TREE_TYPE (arg2)); + tree basetype2 = TYPE_OFFSET_BASETYPE (TREE_TYPE (arg2)); + if (!complete_type_or_else (basetype2, NULL_TREE)) + return boolean_false_node; + + if (!NON_UNION_CLASS_TYPE_P (basetype1) + || !NON_UNION_CLASS_TYPE_P (basetype2) + || !std_layout_type_p (basetype1) + || !std_layout_type_p (basetype2)) + return boolean_false_node; + + /* If the member types aren't layout compatible, then they + can't be corresponding members. */ + if (!layout_compatible_type_p (membertype1, membertype2)) + return boolean_false_node; + + if (TREE_CODE (arg1) == PTRMEM_CST) + arg1 = cplus_expand_constant (arg1); + if (TREE_CODE (arg2) == PTRMEM_CST) + arg2 = cplus_expand_constant (arg2); + + if (null_member_pointer_value_p (arg1) + || null_member_pointer_value_p (arg2)) + return boolean_false_node; + + if (TREE_CODE (arg1) == INTEGER_CST + && TREE_CODE (arg2) == INTEGER_CST + && !tree_int_cst_equal (arg1, arg2)) + return boolean_false_node; + + if (TREE_CODE (arg2) == INTEGER_CST + && TREE_CODE (arg1) != INTEGER_CST) + { + std::swap (arg1, arg2); + std::swap (membertype1, membertype2); + std::swap (basetype1, basetype2); + } + + tree ret = is_corresponding_member_aggr (loc, basetype1, membertype1, arg1, + basetype2, membertype2, arg2); + if (TREE_TYPE (ret) == boolean_type_node) + return ret; + /* If both arg1 and arg2 are INTEGER_CSTs, is_corresponding_member_aggr + already returns boolean_{true,false}_node whether those particular + members are corresponding members or not. Otherwise, if only + one of them is INTEGER_CST (canonicalized to first being INTEGER_CST + above), it returns boolean_false_node if it is certainly not a + corresponding member and otherwise we need to do a runtime check that + those two OFFSET_TYPE offsets are equal. + If neither of the operands is INTEGER_CST, is_corresponding_member_aggr + returns the largest offset at which the members would be corresponding + members, so perform arg1 <= ret && arg1 == arg2 runtime check. */ + gcc_assert (TREE_CODE (arg2) != INTEGER_CST); + if (TREE_CODE (arg1) == INTEGER_CST) + return fold_build2 (EQ_EXPR, boolean_type_node, arg1, + fold_convert (TREE_TYPE (arg1), arg2)); + ret = fold_build2 (LE_EXPR, boolean_type_node, + fold_convert (pointer_sized_int_node, arg1), + fold_convert (pointer_sized_int_node, ret)); + return fold_build2 (TRUTH_AND_EXPR, boolean_type_node, ret, + fold_build2 (EQ_EXPR, boolean_type_node, arg1, + fold_convert (TREE_TYPE (arg1), arg2))); +} + /* Actually evaluates the trait. */ static bool @@ -10783,6 +11035,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2) case CPTK_IS_FINAL: return CLASS_TYPE_P (type1) && CLASSTYPE_FINAL (type1); + case CPTK_IS_LAYOUT_COMPATIBLE: + return layout_compatible_type_p (type1, type2); + case CPTK_IS_LITERAL_TYPE: return literal_type_p (type1); @@ -10930,6 +11185,19 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2) case CPTK_IS_SAME_AS: break; + case CPTK_IS_LAYOUT_COMPATIBLE: + if (!array_of_unknown_bound_p (type1) + && TREE_CODE (type1) != VOID_TYPE + && !complete_type_or_else (type1, NULL_TREE)) + /* We already issued an error. */ + return error_mark_node; + if (!array_of_unknown_bound_p (type2) + && TREE_CODE (type2) != VOID_TYPE + && !complete_type_or_else (type2, NULL_TREE)) + /* We already issued an error. */ + return error_mark_node; + break; + default: gcc_unreachable (); } diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index e8831b2..3c62dd7 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -455,6 +455,7 @@ builtin_valid_in_constant_expr_p (const_tree decl) { case CP_BUILT_IN_IS_CONSTANT_EVALUATED: case CP_BUILT_IN_SOURCE_LOCATION: + case CP_BUILT_IN_IS_CORRESPONDING_MEMBER: case CP_BUILT_IN_IS_POINTER_INTERCONVERTIBLE_WITH_CLASS: return true; default: diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 738e69a..a46c6d2 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -1621,6 +1621,176 @@ similar_type_p (tree type1, tree type2) return false; } +/* Helper function for layout_compatible_type_p and + is_corresponding_member_aggr. Advance to next members (NULL if + no further ones) and return true if those members are still part of + the common initial sequence. */ + +bool +next_common_initial_seqence (tree &memb1, tree &memb2) +{ + while (memb1) + { + if (TREE_CODE (memb1) != FIELD_DECL + || (DECL_FIELD_IS_BASE (memb1) && is_empty_field (memb1))) + { + memb1 = DECL_CHAIN (memb1); + continue; + } + if (DECL_FIELD_IS_BASE (memb1)) + { + memb1 = TYPE_FIELDS (TREE_TYPE (memb1)); + continue; + } + break; + } + while (memb2) + { + if (TREE_CODE (memb2) != FIELD_DECL + || (DECL_FIELD_IS_BASE (memb2) && is_empty_field (memb2))) + { + memb2 = DECL_CHAIN (memb2); + continue; + } + if (DECL_FIELD_IS_BASE (memb2)) + { + memb2 = TYPE_FIELDS (TREE_TYPE (memb2)); + continue; + } + break; + } + if (memb1 == NULL_TREE && memb2 == NULL_TREE) + return true; + if (memb1 == NULL_TREE || memb2 == NULL_TREE) + return false; + if (DECL_BIT_FIELD_TYPE (memb1)) + { + if (!DECL_BIT_FIELD_TYPE (memb2)) + return false; + if (!layout_compatible_type_p (DECL_BIT_FIELD_TYPE (memb1), + DECL_BIT_FIELD_TYPE (memb2))) + return false; + if (TYPE_PRECISION (TREE_TYPE (memb1)) + != TYPE_PRECISION (TREE_TYPE (memb2))) + return false; + } + else if (DECL_BIT_FIELD_TYPE (memb2)) + return false; + else if (!layout_compatible_type_p (TREE_TYPE (memb1), TREE_TYPE (memb2))) + return false; + if ((!lookup_attribute ("no_unique_address", DECL_ATTRIBUTES (memb1))) + != !lookup_attribute ("no_unique_address", DECL_ATTRIBUTES (memb2))) + return false; + if (!tree_int_cst_equal (bit_position (memb1), bit_position (memb2))) + return false; + return true; +} + +/* Return true if TYPE1 and TYPE2 are layout-compatible types. */ + +bool +layout_compatible_type_p (tree type1, tree type2) +{ + if (type1 == error_mark_node || type2 == error_mark_node) + return false; + if (type1 == type2) + return true; + if (TREE_CODE (type1) != TREE_CODE (type2)) + return false; + + type1 = cp_build_qualified_type (type1, TYPE_UNQUALIFIED); + type2 = cp_build_qualified_type (type2, TYPE_UNQUALIFIED); + + if (TREE_CODE (type1) == ENUMERAL_TYPE) + return (TYPE_ALIGN (type1) == TYPE_ALIGN (type2) + && tree_int_cst_equal (TYPE_SIZE (type1), TYPE_SIZE (type2)) + && same_type_p (finish_underlying_type (type1), + finish_underlying_type (type2))); + + if (CLASS_TYPE_P (type1) + && std_layout_type_p (type1) + && std_layout_type_p (type2) + && TYPE_ALIGN (type1) == TYPE_ALIGN (type2) + && tree_int_cst_equal (TYPE_SIZE (type1), TYPE_SIZE (type2))) + { + tree field1 = TYPE_FIELDS (type1); + tree field2 = TYPE_FIELDS (type2); + if (TREE_CODE (type1) == RECORD_TYPE) + { + while (1) + { + if (!next_common_initial_seqence (field1, field2)) + return false; + if (field1 == NULL_TREE) + return true; + field1 = DECL_CHAIN (field1); + field2 = DECL_CHAIN (field2); + } + } + /* Otherwise both types must be union types. + The standard says: + "Two standard-layout unions are layout-compatible if they have + the same number of non-static data members and corresponding + non-static data members (in any order) have layout-compatible + types." + but the code anticipates that bitfield vs. non-bitfield, + different bitfield widths or presence/absence of + [[no_unique_address]] should be checked as well. */ + auto_vec vec; + unsigned int count = 0; + for (; field1; field1 = DECL_CHAIN (field1)) + if (TREE_CODE (field1) == FIELD_DECL) + count++; + for (; field2; field2 = DECL_CHAIN (field2)) + if (TREE_CODE (field2) == FIELD_DECL) + vec.safe_push (field2); + /* Discussions on core lean towards treating multiple union fields + of the same type as the same field, so this might need changing + in the future. */ + if (count != vec.length ()) + return false; + for (field1 = TYPE_FIELDS (type1); field1; field1 = DECL_CHAIN (field1)) + { + if (TREE_CODE (field1) != FIELD_DECL) + continue; + unsigned int j; + tree t1 = DECL_BIT_FIELD_TYPE (field1); + if (t1 == NULL_TREE) + t1 = TREE_TYPE (field1); + FOR_EACH_VEC_ELT (vec, j, field2) + { + tree t2 = DECL_BIT_FIELD_TYPE (field2); + if (t2 == NULL_TREE) + t2 = TREE_TYPE (field2); + if (DECL_BIT_FIELD_TYPE (field1)) + { + if (!DECL_BIT_FIELD_TYPE (field2)) + continue; + if (TYPE_PRECISION (TREE_TYPE (field1)) + != TYPE_PRECISION (TREE_TYPE (field2))) + continue; + } + else if (DECL_BIT_FIELD_TYPE (field2)) + continue; + if (!layout_compatible_type_p (t1, t2)) + continue; + if ((!lookup_attribute ("no_unique_address", + DECL_ATTRIBUTES (field1))) + != !lookup_attribute ("no_unique_address", + DECL_ATTRIBUTES (field2))) + continue; + break; + } + if (j == vec.length ()) + return false; + vec.unordered_remove (j); + } + return true; + } + + return same_type_p (type1, type2); +} + /* Returns 1 if TYPE1 is at least as qualified as TYPE2. */ bool diff --git a/gcc/testsuite/g++.dg/cpp2a/is-corresponding-member1.C b/gcc/testsuite/g++.dg/cpp2a/is-corresponding-member1.C new file mode 100644 index 0000000..dd14c44 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/is-corresponding-member1.C @@ -0,0 +1,61 @@ +// P0466R5 +// { dg-do compile { target c++20 } } + +namespace std +{ +template +constexpr bool +is_corresponding_member (M1 S1::*m1, M2 S2::*m2) noexcept +{ + return __builtin_is_corresponding_member (m1, m2); +} +} + +struct A { int a; }; +struct B { const int b; }; +struct C { int a; unsigned int b; int f; A c; int : 0; int d; double e; }; +struct D { const int x; unsigned int y; int g; B z; int u; double w; }; +struct E { int a; [[no_unique_address]] int b; }; +struct F { int c; const int d; }; +struct G { double a; int b; double c; }; +struct H { const volatile double d; int e : 16; double f; }; +struct I { const double g; int h : 15; const double i; }; +struct J : public A {}; +struct K {}; +struct L : public K, public B {}; +union U { int a; }; +struct V { void foo () {}; }; +struct W { int a; private: int b; public: int c; }; +struct Z : public A, public B {}; + +static_assert (std::is_corresponding_member (&A::a, &A::a)); +static_assert (std::is_corresponding_member (&A::a, &B::b)); +static_assert (std::is_corresponding_member (&C::a, &D::x)); +static_assert (std::is_corresponding_member (&C::b, &D::y)); +static_assert (std::is_corresponding_member (&C::f, &D::g)); +static_assert (std::is_corresponding_member (&C::c, &D::z)); +static_assert (!std::is_corresponding_member (&C::d, &D::u)); +static_assert (!std::is_corresponding_member (&C::e, &D::w)); +static_assert (!std::is_corresponding_member (&C::f, &D::x)); +static_assert (!std::is_corresponding_member (&C::a, &D::g)); +static_assert (std::is_corresponding_member (&E::a, &F::c)); +static_assert (!std::is_corresponding_member (&E::b, &F::d)); +static_assert (std::is_corresponding_member (&G::a, &H::d)); +static_assert (!std::is_corresponding_member (&G::c, &H::f)); +static_assert (std::is_corresponding_member (&H::d, &I::g)); +static_assert (!std::is_corresponding_member (&H::f, &I::i)); +static_assert (std::is_corresponding_member (&J::a, &B::b)); +static_assert (std::is_corresponding_member (&J::a, &B::b)); +static_assert (std::is_corresponding_member (&J::a, &L::b)); +static_assert (std::is_corresponding_member (&J::a, &L::b)); +static_assert (std::is_corresponding_member (&L::b, &B::b)); +static_assert (std::is_corresponding_member (&L::b, &B::b)); +static_assert (!std::is_corresponding_member (&U::a, &U::a)); +static_assert (!std::is_corresponding_member (&A::a, (int A::*) nullptr)); +static_assert (!std::is_corresponding_member ((int A::*) nullptr, &A::a)); +static_assert (!std::is_corresponding_member ((int A::*) nullptr, (int A::*) nullptr)); +static_assert (!std::is_corresponding_member (&V::foo, &V::foo)); +static_assert (!std::is_corresponding_member (&W::a, &W::a)); +static_assert (!std::is_corresponding_member (&W::c, &W::c)); +static_assert (std::is_corresponding_member (&Z::a, &Z::b)); +static_assert (!std::is_corresponding_member (&Z::a, &Z::b)); diff --git a/gcc/testsuite/g++.dg/cpp2a/is-corresponding-member2.C b/gcc/testsuite/g++.dg/cpp2a/is-corresponding-member2.C new file mode 100644 index 0000000..1cedbcb --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/is-corresponding-member2.C @@ -0,0 +1,158 @@ +// P0466R5 +// { dg-do run { target c++20 } } + +namespace std +{ +template +constexpr bool +is_corresponding_member (M1 S1::*m1, M2 S2::*m2) noexcept +{ + return __builtin_is_corresponding_member (m1, m2); +} +} + +struct A { int a; }; +struct B { const int b; }; +struct C { int a; unsigned int b; int f; A c; int : 0; int d; double e; }; +struct D { const int x; unsigned int y; int g; B z; int u; double w; }; +struct E { int a; [[no_unique_address]] int b; }; +struct F { int c; const int d; }; +struct G { double a; int b; double c; }; +struct H { const volatile double d; int e : 16; double f; }; +struct I { const double g; int h : 15; const double i; }; +struct J : public A {}; +struct K {}; +struct L : public K, public B {}; +union U { int a; }; +struct V { void foo () {}; }; +struct W { int a; private: int b; public: int c; }; +struct Z : public A, public B {}; + +int +main () +{ + auto t1 = &A::a; + auto t2 = &A::a; + if (!std::is_corresponding_member (t1, t2)) + __builtin_abort (); + auto t3 = &A::a; + auto t4 = &B::b; + if (!std::is_corresponding_member (t3, t4)) + __builtin_abort (); + auto t5 = &C::a; + auto t6 = &D::x; + if (!std::is_corresponding_member (t5, t6)) + __builtin_abort (); + auto t9 = &C::b; + auto t10 = &D::y; + if (!std::is_corresponding_member (t9, t10)) + __builtin_abort (); + auto t11 = &C::f; + auto t12 = &D::g; + if (!std::is_corresponding_member (t11, t12)) + __builtin_abort (); + auto t13 = &C::c; + auto t14 = &D::z; + if (!std::is_corresponding_member (t13, t14)) + __builtin_abort (); + auto t15 = &C::d; + auto t16 = &D::u; + if (std::is_corresponding_member (t15, t16)) + __builtin_abort (); + auto t17 = &C::e; + auto t18 = &D::w; + if (std::is_corresponding_member (t17, t18)) + __builtin_abort (); + auto t19 = &C::f; + auto t20 = &D::x; + if (std::is_corresponding_member (t19, t20)) + __builtin_abort (); + auto t21 = &C::a; + auto t22 = &D::g; + if (std::is_corresponding_member (t21, t22)) + __builtin_abort (); + auto t23 = &E::a; + auto t24 = &F::c; + if (!std::is_corresponding_member (t23, t24)) + __builtin_abort (); + auto t25 = &E::b; + auto t26 = &F::d; + if (std::is_corresponding_member (t25, t26)) + __builtin_abort (); + auto t27 = &G::a; + auto t28 = &H::d; + if (!std::is_corresponding_member (t27, t28)) + __builtin_abort (); + auto t29 = &G::c; + auto t30 = &H::f; + if (std::is_corresponding_member (t29, t30)) + __builtin_abort (); + auto t31 = &H::d; + auto t32 = &I::g; + if (!std::is_corresponding_member (t31, t32)) + __builtin_abort (); + auto t33 = &H::f; + auto t34 = &I::i; + if (std::is_corresponding_member (t33, t34)) + __builtin_abort (); + auto t35 = &J::a; + auto t36 = &B::b; + if (!std::is_corresponding_member (t35, t36)) + __builtin_abort (); + int J::*t37 = &J::a; + const int B::*t38 = &B::b; + if (!std::is_corresponding_member (t37, t38)) + __builtin_abort (); + auto t39 = &J::a; + auto t40 = &L::b; + if (!std::is_corresponding_member (t39, t40)) + __builtin_abort (); + int J::*t41 = &J::a; + const int L::*t42 = &L::b; + if (!std::is_corresponding_member (t41, t42)) + __builtin_abort (); + auto t43 = &L::b; + auto t44 = &B::b; + if (!std::is_corresponding_member (t43, t44)) + __builtin_abort (); + const int L::*t45 = &L::b; + const int B::*t46 = &B::b; + if (!std::is_corresponding_member (t45, t46)) + __builtin_abort (); + auto t47 = &U::a; + auto t48 = &U::a; + if (std::is_corresponding_member (t47, t48)) + __builtin_abort (); + auto t49 = &A::a; + auto t50 = (int A::*) nullptr; + if (std::is_corresponding_member (t49, t50)) + __builtin_abort (); + auto t51 = (int A::*) nullptr; + auto t52 = &A::a; + if (std::is_corresponding_member (t51, t52)) + __builtin_abort (); + auto t53 = (int A::*) nullptr; + auto t54 = (int A::*) nullptr; + if (std::is_corresponding_member (t53, t54)) + __builtin_abort (); + auto t55 = &V::foo; + auto t56 = &V::foo; + if (std::is_corresponding_member (t55, t56)) + __builtin_abort (); + auto t57 = &W::a; + auto t58 = &W::a; + if (std::is_corresponding_member (t57, t58)) + __builtin_abort (); + auto t59 = &W::c; + auto t60 = &W::c; + if (std::is_corresponding_member (t59, t60)) + __builtin_abort (); + auto t61 = &Z::a; + auto t62 = &Z::b; + if (!std::is_corresponding_member (t61, t62)) + __builtin_abort (); + int Z::*t63 = &Z::a; + const int Z::*t64 = &Z::b; + if (std::is_corresponding_member (t63, t64)) + __builtin_abort (); +} diff --git a/gcc/testsuite/g++.dg/cpp2a/is-corresponding-member3.C b/gcc/testsuite/g++.dg/cpp2a/is-corresponding-member3.C new file mode 100644 index 0000000..1ff510c --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/is-corresponding-member3.C @@ -0,0 +1,14 @@ +// P0466R5 +// { dg-do compile { target c++20 } } + +struct A { int a; }; +struct B; + +bool a = __builtin_is_corresponding_member (); // { dg-error "needs two arguments" } +bool b = __builtin_is_corresponding_member (&A::a); // { dg-error "needs two arguments" } +bool c = __builtin_is_corresponding_member (&A::a, &A::a, &A::a); // { dg-error "needs two arguments" } +bool d = __builtin_is_corresponding_member (&A::a, 1); // { dg-error "argument is not pointer to member" } +bool e = __builtin_is_corresponding_member (1.0, &A::a); // { dg-error "argument is not pointer to member" } +bool f = __builtin_is_corresponding_member (1, A{}); // { dg-error "argument is not pointer to member" } +bool g = __builtin_is_corresponding_member (&A::a, (int B::*) nullptr); // { dg-error "invalid use of incomplete type" } +bool h = __builtin_is_corresponding_member ((int B::*) nullptr, &A::a); // { dg-error "invalid use of incomplete type" } diff --git a/gcc/testsuite/g++.dg/cpp2a/is-corresponding-member4.C b/gcc/testsuite/g++.dg/cpp2a/is-corresponding-member4.C new file mode 100644 index 0000000..6b74090 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/is-corresponding-member4.C @@ -0,0 +1,25 @@ +// P0466R5 +// { dg-do compile { target c++20 } } + +namespace std +{ +template +constexpr bool +is_corresponding_member (M1 S1::*m1, M2 S2::*m2) noexcept +{ + return __builtin_is_corresponding_member (m1, m2); // { dg-error "invalid use of incomplete type 'struct B'" } +} +} + +struct A { int a; }; +struct B; +constexpr int B::*n = nullptr; +constexpr auto a = std::is_corresponding_member (&A::a, n); // { dg-error "invalid use of incomplete type 'struct B'" } +constexpr auto b = std::is_corresponding_member (n, &A::a); // { dg-error "invalid use of incomplete type 'struct B'" } + +void +foo (int B::*m) +{ + std::is_corresponding_member (&A::a, m); + std::is_corresponding_member (m, &A::a); +} diff --git a/gcc/testsuite/g++.dg/cpp2a/is-corresponding-member5.C b/gcc/testsuite/g++.dg/cpp2a/is-corresponding-member5.C new file mode 100644 index 0000000..b956309 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/is-corresponding-member5.C @@ -0,0 +1,95 @@ +// P0466R5 +// { dg-do run { target c++20 } } + +namespace std +{ +template +constexpr bool +is_corresponding_member (M1 S1::*m1, M2 S2::*m2) noexcept +{ + return __builtin_is_corresponding_member (m1, m2); +} +} + +struct S {}; +struct T {}; +struct I { int a; }; +struct alignas(16) J { const int b; }; +struct K { char b; char s[15]; I c; short d; }; +struct L { char d; char t[15]; J e; short f; }; +struct U { int a0; [[no_unique_address]] S a1; [[no_unique_address]] S a2; [[no_unique_address]] S a3; short a4; }; +struct V { int b0; [[no_unique_address]] S b1; [[no_unique_address]] T b2; [[no_unique_address]] S b3; short b4; }; +struct U1 { int a0; [[no_unique_address]] S a1; [[no_unique_address]] S a2; [[no_unique_address]] S a3; short a4; }; +struct V1 { int b0; [[no_unique_address]] S b1; [[no_unique_address]] T b2; [[no_unique_address]] S b3; short b4; }; +struct A { int a; union { short b; long c; }; int d; signed char e; int f; }; +struct B { const int a; union { signed long b; short c; }; volatile int d; unsigned char e; int f; }; +struct A1 { int a; union { short b; long c; }; int d; short e; int f; }; +struct B1 { const int a; union { signed long b; short c; }; volatile int d; unsigned short e; int f; }; + +static_assert (std::is_corresponding_member (&I::a, &J::b)); +static_assert (std::is_corresponding_member (&K::b, &L::d)); +static_assert (!std::is_corresponding_member (&K::c, &L::e)); +static_assert (std::is_corresponding_member (&U::a0, &V::b0)); +static_assert (!std::is_corresponding_member (&U::a4, &V::b4)); +static_assert (std::is_corresponding_member (&A::a, &B::a)); +static_assert (std::is_corresponding_member (&A::d, &B::d)); +static_assert (!std::is_corresponding_member (&A::e, &B::e)); +static_assert (!std::is_corresponding_member (&A::f, &B::f)); +static_assert (!std::is_corresponding_member (&A::a, &B::f)); +static_assert (!std::is_corresponding_member (&A::d, &B::a)); +static_assert (!std::is_corresponding_member (&A::a, &B::d)); +static_assert (!std::is_corresponding_member (&A::f, &B::a)); +static_assert (!std::is_corresponding_member (&A1::e, &B1::e)); + +int +main () +{ + auto t1 = &I::a; + auto t2 = &J::b; + if (!std::is_corresponding_member (t1, t2)) + __builtin_abort (); + auto t3 = &K::b; + auto t4 = &L::d; + if (!std::is_corresponding_member (t3, t4)) + __builtin_abort (); + auto t5 = &K::c; + auto t6 = &L::e; + if (std::is_corresponding_member (t5, t6)) + __builtin_abort (); + auto t7 = &U::a0; + auto t8 = &V::b0; + if (!std::is_corresponding_member (t7, t8)) + __builtin_abort (); + auto t9 = &U::a4; + auto t10 = &V::b4; + if (std::is_corresponding_member (t9, t10)) + __builtin_abort (); + auto t11 = &A::a; + auto t12 = &B::a; + auto t13 = &A::d; + auto t14 = &B::d; + auto t15 = &A::e; + auto t16 = &B::e; + auto t17 = &A::f; + auto t18 = &B::f; + if (!std::is_corresponding_member (t11, t12)) + __builtin_abort (); + if (!std::is_corresponding_member (t13, t14)) + __builtin_abort (); + if (std::is_corresponding_member (t15, t16)) + __builtin_abort (); + if (std::is_corresponding_member (t17, t18)) + __builtin_abort (); + if (std::is_corresponding_member (t11, t18)) + __builtin_abort (); + if (std::is_corresponding_member (t13, t12)) + __builtin_abort (); + if (std::is_corresponding_member (t11, t14)) + __builtin_abort (); + if (std::is_corresponding_member (t17, t12)) + __builtin_abort (); + auto t19 = &A1::e; + auto t20 = &B1::e; + if (std::is_corresponding_member (t19, t20)) + __builtin_abort (); +} diff --git a/gcc/testsuite/g++.dg/cpp2a/is-corresponding-member6.C b/gcc/testsuite/g++.dg/cpp2a/is-corresponding-member6.C new file mode 100644 index 0000000..e4f53bb --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/is-corresponding-member6.C @@ -0,0 +1,34 @@ +// P0466R5 +// { dg-do compile { target c++20 } } + +namespace std +{ +template +constexpr bool +is_corresponding_member (M1 S1::*m1, M2 S2::*m2) noexcept +{ + return __builtin_is_corresponding_member (m1, m2); +} +// { dg-message "'__builtin_is_corresponding_member' not well defined for anonymous unions" "" { target *-*-* } .-2 } +} + +struct S {}; +struct T {}; +struct I { int a; }; +struct alignas(16) J { const int b; }; +struct K { char b; char s[15]; alignas(16) I c; short d; }; +struct L { char d; char t[15]; J e; short f; }; +struct U { int a0; [[no_unique_address]] S a1; [[no_unique_address]] S a2; [[no_unique_address]] S a3; short a4; }; +struct V { int b0; [[no_unique_address]] S b1; [[no_unique_address]] T b2; [[no_unique_address]] S b3; short b4; }; +struct U1 { int a0; [[no_unique_address]] S a1; [[no_unique_address]] S a2; [[no_unique_address]] S a3; short a4; }; +struct V1 { int b0; [[no_unique_address]] S b1; [[no_unique_address]] T b2; [[no_unique_address]] S b3; short b4; }; +struct A { int a; union { short b; long c; }; int d; signed char e; int f; }; +struct B { const int a; union { signed long b; short c; }; volatile int d; unsigned char e; int f; }; + +static_assert (!std::is_corresponding_member (&K::d, &L::f)); +static_assert (std::is_corresponding_member (&U::a1, &V::b1)); +static_assert (!std::is_corresponding_member (&U::a2, &V::b2)); +static_assert (!std::is_corresponding_member (&U::a3, &V::b3)); +static_assert (!std::is_corresponding_member (&U1::a3, &V1::b3)); +static_assert (!std::is_corresponding_member (&A::b, &B::c)); +constexpr auto a = std::is_corresponding_member (&A::c, &B::b); // { dg-message "required from here" } diff --git a/gcc/testsuite/g++.dg/cpp2a/is-corresponding-member7.C b/gcc/testsuite/g++.dg/cpp2a/is-corresponding-member7.C new file mode 100644 index 0000000..602ca01 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/is-corresponding-member7.C @@ -0,0 +1,71 @@ +// P0466R5 +// { dg-do run { target c++20 } } +// { dg-options "" } + +namespace std +{ +template +constexpr bool +is_corresponding_member (M1 S1::*m1, M2 S2::*m2) noexcept +{ + return __builtin_is_corresponding_member (m1, m2); +} +} + +struct A { int a; struct { int b; short c; long d; }; int : 0; int e; }; +struct B { const signed int a; struct { int b; signed short c; signed long d; }; volatile int e; }; +struct C { int a; union { struct { short b; long c; }; long d; short e; }; signed int f; }; +struct D { int a; union { long b; short c; struct { short d; signed long e; }; }; int f; }; + +static_assert (std::is_corresponding_member (&A::a, &B::a)); +static_assert (std::is_corresponding_member (&A::b, &B::b)); +static_assert (std::is_corresponding_member (&A::c, &B::c)); +static_assert (std::is_corresponding_member (&A::d, &B::d)); +static_assert (!std::is_corresponding_member (&A::e, &B::e)); +static_assert (!std::is_corresponding_member (&A::a, &B::b)); +static_assert (!std::is_corresponding_member (&A::b, &B::a)); +static_assert (std::is_corresponding_member (&C::a, &D::a)); +static_assert (std::is_corresponding_member (&C::f, &D::f)); +static_assert (!std::is_corresponding_member (&C::a, &D::f)); +static_assert (!std::is_corresponding_member (&C::f, &D::a)); + +int +main () +{ + auto t1 = &A::a; + auto t2 = &B::a; + auto t3 = &A::b; + auto t4 = &B::b; + auto t5 = &A::c; + auto t6 = &B::c; + auto t7 = &A::d; + auto t8 = &B::d; + auto t9 = &A::e; + auto t10 = &B::e; + if (!std::is_corresponding_member (t1, t2)) + __builtin_abort (); + if (!std::is_corresponding_member (t3, t4)) + __builtin_abort (); + if (!std::is_corresponding_member (t5, t6)) + __builtin_abort (); + if (!std::is_corresponding_member (t7, t8)) + __builtin_abort (); + if (std::is_corresponding_member (t9, t10)) + __builtin_abort (); + if (std::is_corresponding_member (t1, t4)) + __builtin_abort (); + if (std::is_corresponding_member (t3, t2)) + __builtin_abort (); + auto t11 = &C::a; + auto t12 = &D::a; + auto t13 = &C::f; + auto t14 = &D::f; + if (!std::is_corresponding_member (t11, t12)) + __builtin_abort (); + if (!std::is_corresponding_member (t13, t14)) + __builtin_abort (); + if (std::is_corresponding_member (t11, t14)) + __builtin_abort (); + if (std::is_corresponding_member (t13, t12)) + __builtin_abort (); +} diff --git a/gcc/testsuite/g++.dg/cpp2a/is-corresponding-member8.C b/gcc/testsuite/g++.dg/cpp2a/is-corresponding-member8.C new file mode 100644 index 0000000..1a33908 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/is-corresponding-member8.C @@ -0,0 +1,25 @@ +// P0466R5 +// { dg-do compile { target c++20 } } +// { dg-options "" } + +namespace std +{ +template +constexpr bool +is_corresponding_member (M1 S1::*m1, M2 S2::*m2) noexcept +{ + return __builtin_is_corresponding_member (m1, m2); +} +// { dg-message "'__builtin_is_corresponding_member' not well defined for anonymous unions" "" { target *-*-* } .-2 } +} + +struct A { int a; struct { short b; short c; long d; }; int : 0; int e; }; +struct B { const signed int a; struct alignas(16) { short b; signed short c; signed long d; }; volatile int e; }; +struct C { int a; union { struct { int b; long c; }; long d; short e; }; signed int f; }; +struct D { int a; union { long b; short c; struct { int d; signed long e; }; }; int f; }; + +static_assert (std::is_corresponding_member (&A::a, &B::a)); +static_assert (!std::is_corresponding_member (&A::b, &B::b)); +static_assert (!std::is_corresponding_member (&A::c, &B::c)); +static_assert (!std::is_corresponding_member (&A::d, &B::d)); +auto a = std::is_corresponding_member (&C::a, &D::a); // { dg-message "required from here" } diff --git a/gcc/testsuite/g++.dg/cpp2a/is-layout-compatible1.C b/gcc/testsuite/g++.dg/cpp2a/is-layout-compatible1.C new file mode 100644 index 0000000..dbc2a9a --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/is-layout-compatible1.C @@ -0,0 +1,80 @@ +// P0466R5 +// { dg-do compile { target c++20 } } + +namespace std +{ +template +struct integral_constant +{ + static constexpr T value = v; +}; + +template +struct is_layout_compatible; + +template +struct is_layout_compatible + : public integral_constant +{ +}; + +template +inline constexpr bool is_layout_compatible_v = __is_layout_compatible (T, U); +} + +struct A { int a; char b; }; +struct B { const int c; volatile char d; }; +struct C { int a : 1; int : 7; int : 0; int b : 2; }; +struct D { int : 1; int c : 7; int : 0; int : 2; }; +struct E { int f : 1; int : 7; int g : 2; }; +struct F { int a; signed char b; }; +union G { int a; long long b; signed char c; unsigned char d; int e; }; +union H { long long f; unsigned char g; int h; int i; signed char j; }; +struct I : public A {}; +struct J {}; +struct K : public J {}; +struct L {}; +struct M : public K, L { const int a; volatile char b; }; +struct N {}; +struct O : public N, M {}; +struct P { int a; private: int b; public: int c; }; +struct Q { int a; private: int b; public: int c; }; +union U1 { int a; private: int b; public: int c; }; +union U2 { int a; private: int b; public: int c; }; +struct S {}; +struct T {}; +struct W; +struct X; +enum E1 : int { E11, E12 }; +enum E2 : int { E21, E22 }; +enum E3 : long { E31, E32 }; +enum E4 { E41, E42 }; +enum E5 { E51, E52 }; + +static_assert (std::is_layout_compatible::value); +static_assert (std::is_layout_compatible_v); +static_assert (std::is_layout_compatible_v); +static_assert (std::is_layout_compatible_v); +static_assert (!std::is_layout_compatible_v); +static_assert (!std::is_layout_compatible_v); +static_assert (std::is_layout_compatible_v); +static_assert (std::is_layout_compatible_v); +static_assert (std::is_layout_compatible_v); +static_assert (std::is_layout_compatible_v); +static_assert (!std::is_layout_compatible_v); +static_assert (std::is_layout_compatible_v); +static_assert (!std::is_layout_compatible_v); +static_assert (!std::is_layout_compatible_v); +static_assert (std::is_layout_compatible_v); +static_assert (std::is_layout_compatible_v); +static_assert (std::is_layout_compatible_v); +static_assert (std::is_layout_compatible_v); +static_assert (std::is_layout_compatible_v); +static_assert (std::is_layout_compatible_v); +static_assert (std::is_layout_compatible_v); +static_assert (!std::is_layout_compatible_v); +static_assert (std::is_layout_compatible_v); +static_assert (!std::is_layout_compatible_v); +static_assert (std::is_layout_compatible_v); +static_assert (!std::is_layout_compatible_v); +static_assert (std::is_layout_compatible_v); diff --git a/gcc/testsuite/g++.dg/cpp2a/is-layout-compatible2.C b/gcc/testsuite/g++.dg/cpp2a/is-layout-compatible2.C new file mode 100644 index 0000000..bf902f3 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/is-layout-compatible2.C @@ -0,0 +1,36 @@ +// P0466R5 +// { dg-do compile { target c++20 } } + +namespace std +{ +template +struct integral_constant +{ + static constexpr T value = v; +}; + +template +struct is_layout_compatible; + +template +struct is_layout_compatible + : public integral_constant +{ +}; + +template +inline constexpr bool is_layout_compatible_v = __is_layout_compatible (T, U); +} +// { dg-error "invalid use of incomplete type 'struct W'" "" { target *-*-* } .-2 } +// { dg-error "invalid use of incomplete type 'struct \[XY]'" "" { target *-*-* } .-3 } +// { dg-error "invalid use of incomplete type 'struct Z'" "" { target *-*-* } .-4 } + +struct W; +struct X; +struct Y; +struct Z; +struct A {}; + +auto a = std::is_layout_compatible_v; +auto b = std::is_layout_compatible_v; +auto c = std::is_layout_compatible_v; diff --git a/gcc/testsuite/g++.dg/cpp2a/is-layout-compatible3.C b/gcc/testsuite/g++.dg/cpp2a/is-layout-compatible3.C new file mode 100644 index 0000000..c548587 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/is-layout-compatible3.C @@ -0,0 +1,64 @@ +// P0466R5 +// { dg-do compile { target c++20 } } + +namespace std +{ +template +struct integral_constant +{ + static constexpr T value = v; +}; + +template +struct is_layout_compatible; + +template +struct is_layout_compatible + : public integral_constant +{ +}; + +template +inline constexpr bool is_layout_compatible_v = __is_layout_compatible (T, U); +} + +// Weird cases. +struct S {}; +struct T {}; +struct I { int a; }; +struct alignas(16) J { const int b; }; +struct K { I c; int d; }; +struct L { J e; int f; }; +union M { I u; }; +union N { J v; }; +union O { int a; int b; }; +union P { int a : 1; int b : 12; }; +enum Q : int { Q1, Q2 }; +enum alignas(16) R : int { R1, R2 }; +struct U { [[no_unique_address]] S a1; [[no_unique_address]] S a2; [[no_unique_address]] S a3; }; +struct V { [[no_unique_address]] S b1; [[no_unique_address]] T b2; [[no_unique_address]] S b3; }; +struct alignas(16) A : public I {}; +struct alignas(16) B {}; +struct C : public B, public I {}; +union D { int a : 3; int b : 9; }; +struct alignas(16) E { alignas(16) int a; alignas(16) int b; }; +struct alignas(16) F { int c; alignas(16) int d; }; +union alignas(16) G { int a; alignas(16) short b; }; +union alignas(16) H { short c; int d; }; +struct A1 { int a; }; +struct B1 { signed int b; }; +struct alignas (16) C1 : public A1 {}; +struct alignas (16) D1 : public B1 {}; + +static_assert (!std::is_layout_compatible_v); +static_assert (!std::is_layout_compatible_v); +static_assert (!std::is_layout_compatible_v); +static_assert (!std::is_layout_compatible_v); +static_assert (!std::is_layout_compatible_v); +static_assert (!std::is_layout_compatible_v); +static_assert (!std::is_layout_compatible_v); +static_assert (!std::is_layout_compatible_v); +static_assert (!std::is_layout_compatible_v); +static_assert (std::is_layout_compatible_v); +static_assert (std::is_layout_compatible_v); +static_assert (std::is_layout_compatible_v); -- cgit v1.1 From b48d4e6818674898f90d9358378c127511ef0f9f Mon Sep 17 00:00:00 2001 From: Martin Sebor Date: Tue, 17 Aug 2021 14:49:05 -0600 Subject: Move more warning code to gimple-ssa-warn-access etc. Also resolves: PR middle-end/101854 - Invalid warning -Wstringop-overflow wrong argument gcc/ChangeLog: PR middle-end/101854 * builtins.c (expand_builtin_alloca): Move warning code to check_alloca in gimple-ssa-warn-access.cc. * calls.c (alloc_max_size): Move code to check_alloca. (get_size_range): Move to pointer-query.cc. (maybe_warn_alloc_args_overflow): Move to gimple-ssa-warn-access.cc. (get_attr_nonstring_decl): Move to tree.c. (fntype_argno_type): Move to gimple-ssa-warn-access.cc. (append_attrname): Same. (maybe_warn_rdwr_sizes): Same. (initialize_argument_information): Move code to gimple-ssa-warn-access.cc. * calls.h (maybe_warn_alloc_args_overflow): Move to gimple-ssa-warn-access.h. (get_attr_nonstring_decl): Move to tree.h. (maybe_warn_nonstring_arg): Move to gimple-ssa-warn-access.h. (enum size_range_flags): Move to pointer-query.h. (get_size_range): Same. * gimple-ssa-warn-access.cc (has_location): Remove unused overload to avoid Clang -Wunused-function. (get_size_range): Declare static. (maybe_emit_free_warning): Rename... (maybe_check_dealloc_call): ...to this for consistency. (class pass_waccess): Add members. (pass_waccess::~pass_waccess): Defined. (alloc_max_size): Move here from calls.c. (maybe_warn_alloc_args_overflow): Same. (check_alloca): New function. (check_alloc_size_call): New function. (check_strncat): Handle another warning flag. (pass_waccess::check_builtin): Handle alloca. (fntype_argno_type): Move here from calls.c. (append_attrname): Same. (maybe_warn_rdwr_sizes): Same. (pass_waccess::check_call): Define. (check_nonstring_args): New function. (pass_waccess::check): Call new member functions. (pass_waccess::execute): Enable ranger. * gimple-ssa-warn-access.h (get_size_range): Move here from calls.h. (maybe_warn_nonstring_arg): Same. * gimple-ssa-warn-restrict.c: Remove #include. * pointer-query.cc (get_size_range): Move here from calls.c. * pointer-query.h (enum size_range_flags): Same. (get_size_range): Same. * tree.c (get_attr_nonstring_decl): Move here from calls.c. * tree.h (get_attr_nonstring_decl): Move here from calls.h. gcc/testsuite/ChangeLog: * gcc.dg/attr-alloc_size-5.c: Adjust optimization to -O1. * gcc.dg/attr-alloc_size-7.c: Use #pragmas to adjust optimization. * gcc.dg/attr-alloc_size-8.c: Adjust optimization to -O1. PR middle-end/101854 * gcc.dg/Wstringop-overflow-72.c: New test. --- gcc/builtins.c | 22 +- gcc/calls.c | 760 --------------------------- gcc/calls.h | 15 +- gcc/gimple-ssa-warn-access.cc | 683 +++++++++++++++++++++++- gcc/gimple-ssa-warn-access.h | 4 +- gcc/gimple-ssa-warn-restrict.c | 1 + gcc/pointer-query.cc | 195 +++++-- gcc/pointer-query.h | 11 + gcc/testsuite/gcc.dg/Wstringop-overflow-72.c | 13 + gcc/testsuite/gcc.dg/attr-alloc_size-5.c | 2 +- gcc/testsuite/gcc.dg/attr-alloc_size-7.c | 45 +- gcc/testsuite/gcc.dg/attr-alloc_size-8.c | 2 +- gcc/tree.c | 54 ++ gcc/tree.h | 6 + 14 files changed, 952 insertions(+), 861 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/Wstringop-overflow-72.c (limited to 'gcc') diff --git a/gcc/builtins.c b/gcc/builtins.c index d2be807f..9954862 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -43,7 +43,7 @@ along with GCC; see the file COPYING3. If not see #include "alias.h" #include "fold-const.h" #include "fold-const-call.h" -#include "gimple-ssa-warn-restrict.h" +#include "gimple-ssa-warn-access.h" #include "stor-layout.h" #include "calls.h" #include "varasm.h" @@ -81,7 +81,6 @@ along with GCC; see the file COPYING3. If not see #include "demangle.h" #include "gimple-range.h" #include "pointer-query.h" -#include "gimple-ssa-warn-access.h" struct target_builtins default_target_builtins; #if SWITCHABLE_TARGET @@ -4896,25 +4895,6 @@ expand_builtin_alloca (tree exp) if (!valid_arglist) return NULL_RTX; - if ((alloca_for_var - && warn_vla_limit >= HOST_WIDE_INT_MAX - && warn_alloc_size_limit < warn_vla_limit) - || (!alloca_for_var - && warn_alloca_limit >= HOST_WIDE_INT_MAX - && warn_alloc_size_limit < warn_alloca_limit - )) - { - /* -Walloca-larger-than and -Wvla-larger-than settings of - less than HOST_WIDE_INT_MAX override the more general - -Walloc-size-larger-than so unless either of the former - options is smaller than the last one (wchich would imply - that the call was already checked), check the alloca - arguments for overflow. */ - tree args[] = { CALL_EXPR_ARG (exp, 0), NULL_TREE }; - int idx[] = { 0, -1 }; - maybe_warn_alloc_args_overflow (fndecl, exp, args, idx); - } - /* Compute the argument. */ op0 = expand_normal (CALL_EXPR_ARG (exp, 0)); diff --git a/gcc/calls.c b/gcc/calls.c index fcb0d6d..e50d3fc 100644 --- a/gcc/calls.c +++ b/gcc/calls.c @@ -17,7 +17,6 @@ You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see . */ -#define INCLUDE_STRING #include "config.h" #include "system.h" #include "coretypes.h" @@ -50,7 +49,6 @@ along with GCC; see the file COPYING3. If not see #include "rtl-iter.h" #include "tree-vrp.h" #include "tree-ssanames.h" -#include "tree-ssa-strlen.h" #include "intl.h" #include "stringpool.h" #include "hash-map.h" @@ -60,8 +58,6 @@ along with GCC; see the file COPYING3. If not see #include "gimple-fold.h" #include "attr-fnspec.h" #include "value-query.h" -#include "pointer-query.h" -#include "gimple-ssa-warn-access.h" #include "tree-pretty-print.h" /* Like PREFERRED_STACK_BOUNDARY but in units of bytes, not bits. */ @@ -1223,397 +1219,6 @@ store_unaligned_arguments_into_pseudos (struct arg_data *args, int num_actuals) } } -/* The limit set by -Walloc-larger-than=. */ -static GTY(()) tree alloc_object_size_limit; - -/* Initialize ALLOC_OBJECT_SIZE_LIMIT based on the -Walloc-size-larger-than= - setting if the option is specified, or to the maximum object size if it - is not. Return the initialized value. */ - -static tree -alloc_max_size (void) -{ - if (alloc_object_size_limit) - return alloc_object_size_limit; - - HOST_WIDE_INT limit = warn_alloc_size_limit; - if (limit == HOST_WIDE_INT_MAX) - limit = tree_to_shwi (TYPE_MAX_VALUE (ptrdiff_type_node)); - - alloc_object_size_limit = build_int_cst (size_type_node, limit); - - return alloc_object_size_limit; -} - -/* Return true when EXP's range can be determined and set RANGE[] to it - after adjusting it if necessary to make EXP a represents a valid size - of object, or a valid size argument to an allocation function declared - with attribute alloc_size (whose argument may be signed), or to a string - manipulation function like memset. - When ALLOW_ZERO is set in FLAGS, allow returning a range of [0, 0] for - a size in an anti-range [1, N] where N > PTRDIFF_MAX. A zero range is - a (nearly) invalid argument to allocation functions like malloc but it - is a valid argument to functions like memset. - When USE_LARGEST is set in FLAGS set RANGE to the largest valid subrange - in a multi-range, otherwise to the smallest valid subrange. */ - -bool -get_size_range (range_query *query, tree exp, gimple *stmt, tree range[2], - int flags /* = 0 */) -{ - if (!exp) - return false; - - if (tree_fits_uhwi_p (exp)) - { - /* EXP is a constant. */ - range[0] = range[1] = exp; - return true; - } - - tree exptype = TREE_TYPE (exp); - bool integral = INTEGRAL_TYPE_P (exptype); - - wide_int min, max; - enum value_range_kind range_type; - - if (!query) - query = get_global_range_query (); - - if (integral) - { - value_range vr; - - query->range_of_expr (vr, exp, stmt); - - if (vr.undefined_p ()) - vr.set_varying (TREE_TYPE (exp)); - range_type = vr.kind (); - min = wi::to_wide (vr.min ()); - max = wi::to_wide (vr.max ()); - } - else - range_type = VR_VARYING; - - if (range_type == VR_VARYING) - { - if (integral) - { - /* Use the full range of the type of the expression when - no value range information is available. */ - range[0] = TYPE_MIN_VALUE (exptype); - range[1] = TYPE_MAX_VALUE (exptype); - return true; - } - - range[0] = NULL_TREE; - range[1] = NULL_TREE; - return false; - } - - unsigned expprec = TYPE_PRECISION (exptype); - - bool signed_p = !TYPE_UNSIGNED (exptype); - - if (range_type == VR_ANTI_RANGE) - { - if (signed_p) - { - if (wi::les_p (max, 0)) - { - /* EXP is not in a strictly negative range. That means - it must be in some (not necessarily strictly) positive - range which includes zero. Since in signed to unsigned - conversions negative values end up converted to large - positive values, and otherwise they are not valid sizes, - the resulting range is in both cases [0, TYPE_MAX]. */ - min = wi::zero (expprec); - max = wi::to_wide (TYPE_MAX_VALUE (exptype)); - } - else if (wi::les_p (min - 1, 0)) - { - /* EXP is not in a negative-positive range. That means EXP - is either negative, or greater than max. Since negative - sizes are invalid make the range [MAX + 1, TYPE_MAX]. */ - min = max + 1; - max = wi::to_wide (TYPE_MAX_VALUE (exptype)); - } - else - { - max = min - 1; - min = wi::zero (expprec); - } - } - else - { - wide_int maxsize = wi::to_wide (max_object_size ()); - min = wide_int::from (min, maxsize.get_precision (), UNSIGNED); - max = wide_int::from (max, maxsize.get_precision (), UNSIGNED); - if (wi::eq_p (0, min - 1)) - { - /* EXP is unsigned and not in the range [1, MAX]. That means - it's either zero or greater than MAX. Even though 0 would - normally be detected by -Walloc-zero, unless ALLOW_ZERO - is set, set the range to [MAX, TYPE_MAX] so that when MAX - is greater than the limit the whole range is diagnosed. */ - wide_int maxsize = wi::to_wide (max_object_size ()); - if (flags & SR_ALLOW_ZERO) - { - if (wi::leu_p (maxsize, max + 1) - || !(flags & SR_USE_LARGEST)) - min = max = wi::zero (expprec); - else - { - min = max + 1; - max = wi::to_wide (TYPE_MAX_VALUE (exptype)); - } - } - else - { - min = max + 1; - max = wi::to_wide (TYPE_MAX_VALUE (exptype)); - } - } - else if ((flags & SR_USE_LARGEST) - && wi::ltu_p (max + 1, maxsize)) - { - /* When USE_LARGEST is set and the larger of the two subranges - is a valid size, use it... */ - min = max + 1; - max = maxsize; - } - else - { - /* ...otherwise use the smaller subrange. */ - max = min - 1; - min = wi::zero (expprec); - } - } - } - - range[0] = wide_int_to_tree (exptype, min); - range[1] = wide_int_to_tree (exptype, max); - - return true; -} - -bool -get_size_range (tree exp, tree range[2], int flags /* = 0 */) -{ - return get_size_range (/*query=*/NULL, exp, /*stmt=*/NULL, range, flags); -} - -/* Diagnose a call EXP to function FN decorated with attribute alloc_size - whose argument numbers given by IDX with values given by ARGS exceed - the maximum object size or cause an unsigned oveflow (wrapping) when - multiplied. FN is null when EXP is a call via a function pointer. - When ARGS[0] is null the function does nothing. ARGS[1] may be null - for functions like malloc, and non-null for those like calloc that - are decorated with a two-argument attribute alloc_size. */ - -void -maybe_warn_alloc_args_overflow (tree fn, tree exp, tree args[2], int idx[2]) -{ - /* The range each of the (up to) two arguments is known to be in. */ - tree argrange[2][2] = { { NULL_TREE, NULL_TREE }, { NULL_TREE, NULL_TREE } }; - - /* Maximum object size set by -Walloc-size-larger-than= or SIZE_MAX / 2. */ - tree maxobjsize = alloc_max_size (); - - location_t loc = EXPR_LOCATION (exp); - - tree fntype = fn ? TREE_TYPE (fn) : TREE_TYPE (TREE_TYPE (exp)); - bool warned = false; - - /* Validate each argument individually. */ - for (unsigned i = 0; i != 2 && args[i]; ++i) - { - if (TREE_CODE (args[i]) == INTEGER_CST) - { - argrange[i][0] = args[i]; - argrange[i][1] = args[i]; - - if (tree_int_cst_lt (args[i], integer_zero_node)) - { - warned = warning_at (loc, OPT_Walloc_size_larger_than_, - "argument %i value %qE is negative", - idx[i] + 1, args[i]); - } - else if (integer_zerop (args[i])) - { - /* Avoid issuing -Walloc-zero for allocation functions other - than __builtin_alloca that are declared with attribute - returns_nonnull because there's no portability risk. This - avoids warning for such calls to libiberty's xmalloc and - friends. - Also avoid issuing the warning for calls to function named - "alloca". */ - if (fn && fndecl_built_in_p (fn, BUILT_IN_ALLOCA) - ? IDENTIFIER_LENGTH (DECL_NAME (fn)) != 6 - : !lookup_attribute ("returns_nonnull", - TYPE_ATTRIBUTES (fntype))) - warned = warning_at (loc, OPT_Walloc_zero, - "argument %i value is zero", - idx[i] + 1); - } - else if (tree_int_cst_lt (maxobjsize, args[i])) - { - /* G++ emits calls to ::operator new[](SIZE_MAX) in C++98 - mode and with -fno-exceptions as a way to indicate array - size overflow. There's no good way to detect C++98 here - so avoid diagnosing these calls for all C++ modes. */ - if (i == 0 - && fn - && !args[1] - && lang_GNU_CXX () - && DECL_IS_OPERATOR_NEW_P (fn) - && integer_all_onesp (args[i])) - continue; - - warned = warning_at (loc, OPT_Walloc_size_larger_than_, - "argument %i value %qE exceeds " - "maximum object size %E", - idx[i] + 1, args[i], maxobjsize); - } - } - else if (TREE_CODE (args[i]) == SSA_NAME - && get_size_range (args[i], argrange[i])) - { - /* Verify that the argument's range is not negative (including - upper bound of zero). */ - if (tree_int_cst_lt (argrange[i][0], integer_zero_node) - && tree_int_cst_le (argrange[i][1], integer_zero_node)) - { - warned = warning_at (loc, OPT_Walloc_size_larger_than_, - "argument %i range [%E, %E] is negative", - idx[i] + 1, - argrange[i][0], argrange[i][1]); - } - else if (tree_int_cst_lt (maxobjsize, argrange[i][0])) - { - warned = warning_at (loc, OPT_Walloc_size_larger_than_, - "argument %i range [%E, %E] exceeds " - "maximum object size %E", - idx[i] + 1, - argrange[i][0], argrange[i][1], - maxobjsize); - } - } - } - - if (!argrange[0]) - return; - - /* For a two-argument alloc_size, validate the product of the two - arguments if both of their values or ranges are known. */ - if (!warned && tree_fits_uhwi_p (argrange[0][0]) - && argrange[1][0] && tree_fits_uhwi_p (argrange[1][0]) - && !integer_onep (argrange[0][0]) - && !integer_onep (argrange[1][0])) - { - /* Check for overflow in the product of a function decorated with - attribute alloc_size (X, Y). */ - unsigned szprec = TYPE_PRECISION (size_type_node); - wide_int x = wi::to_wide (argrange[0][0], szprec); - wide_int y = wi::to_wide (argrange[1][0], szprec); - - wi::overflow_type vflow; - wide_int prod = wi::umul (x, y, &vflow); - - if (vflow) - warned = warning_at (loc, OPT_Walloc_size_larger_than_, - "product %<%E * %E%> of arguments %i and %i " - "exceeds %", - argrange[0][0], argrange[1][0], - idx[0] + 1, idx[1] + 1); - else if (wi::ltu_p (wi::to_wide (maxobjsize, szprec), prod)) - warned = warning_at (loc, OPT_Walloc_size_larger_than_, - "product %<%E * %E%> of arguments %i and %i " - "exceeds maximum object size %E", - argrange[0][0], argrange[1][0], - idx[0] + 1, idx[1] + 1, - maxobjsize); - - if (warned) - { - /* Print the full range of each of the two arguments to make - it clear when it is, in fact, in a range and not constant. */ - if (argrange[0][0] != argrange [0][1]) - inform (loc, "argument %i in the range [%E, %E]", - idx[0] + 1, argrange[0][0], argrange[0][1]); - if (argrange[1][0] != argrange [1][1]) - inform (loc, "argument %i in the range [%E, %E]", - idx[1] + 1, argrange[1][0], argrange[1][1]); - } - } - - if (warned && fn) - { - location_t fnloc = DECL_SOURCE_LOCATION (fn); - - if (DECL_IS_UNDECLARED_BUILTIN (fn)) - inform (loc, - "in a call to built-in allocation function %qD", fn); - else - inform (fnloc, - "in a call to allocation function %qD declared here", fn); - } -} - -/* If EXPR refers to a character array or pointer declared attribute - nonstring return a decl for that array or pointer and set *REF to - the referenced enclosing object or pointer. Otherwise returns - null. */ - -tree -get_attr_nonstring_decl (tree expr, tree *ref) -{ - tree decl = expr; - tree var = NULL_TREE; - if (TREE_CODE (decl) == SSA_NAME) - { - gimple *def = SSA_NAME_DEF_STMT (decl); - - if (is_gimple_assign (def)) - { - tree_code code = gimple_assign_rhs_code (def); - if (code == ADDR_EXPR - || code == COMPONENT_REF - || code == VAR_DECL) - decl = gimple_assign_rhs1 (def); - } - else - var = SSA_NAME_VAR (decl); - } - - if (TREE_CODE (decl) == ADDR_EXPR) - decl = TREE_OPERAND (decl, 0); - - /* To simplify calling code, store the referenced DECL regardless of - the attribute determined below, but avoid storing the SSA_NAME_VAR - obtained above (it's not useful for dataflow purposes). */ - if (ref) - *ref = decl; - - /* Use the SSA_NAME_VAR that was determined above to see if it's - declared nonstring. Otherwise drill down into the referenced - DECL. */ - if (var) - decl = var; - else if (TREE_CODE (decl) == ARRAY_REF) - decl = TREE_OPERAND (decl, 0); - else if (TREE_CODE (decl) == COMPONENT_REF) - decl = TREE_OPERAND (decl, 1); - else if (TREE_CODE (decl) == MEM_REF) - return get_attr_nonstring_decl (TREE_OPERAND (decl, 0), ref); - - if (DECL_P (decl) - && lookup_attribute ("nonstring", DECL_ATTRIBUTES (decl))) - return decl; - - return NULL_TREE; -} - /* Issue an error if CALL_EXPR was flagged as requiring tall-call optimization. */ @@ -1627,310 +1232,6 @@ maybe_complain_about_tail_call (tree call_expr, const char *reason) error_at (EXPR_LOCATION (call_expr), "cannot tail-call: %s", reason); } -/* Returns the type of the argument ARGNO to function with type FNTYPE - or null when the typoe cannot be determined or no such argument exists. */ - -static tree -fntype_argno_type (tree fntype, unsigned argno) -{ - if (!prototype_p (fntype)) - return NULL_TREE; - - tree argtype; - function_args_iterator it; - FOREACH_FUNCTION_ARGS (fntype, argtype, it) - if (argno-- == 0) - return argtype; - - return NULL_TREE; -} - -/* Helper to append the "human readable" attribute access specification - described by ACCESS to the array ATTRSTR with size STRSIZE. Used in - diagnostics. */ - -static inline void -append_attrname (const std::pair &access, - char *attrstr, size_t strsize) -{ - if (access.second.internal_p) - return; - - tree str = access.second.to_external_string (); - gcc_assert (strsize >= (size_t) TREE_STRING_LENGTH (str)); - strcpy (attrstr, TREE_STRING_POINTER (str)); -} - -/* Iterate over attribute access read-only, read-write, and write-only - arguments and diagnose past-the-end accesses and related problems - in the function call EXP. */ - -static void -maybe_warn_rdwr_sizes (rdwr_map *rwm, tree fndecl, tree fntype, tree exp) -{ - auto_diagnostic_group adg; - - /* Set if a warning has been issued for any argument (used to decide - whether to emit an informational note at the end). */ - opt_code opt_warned = N_OPTS; - - /* A string describing the attributes that the warnings issued by this - function apply to. Used to print one informational note per function - call, rather than one per warning. That reduces clutter. */ - char attrstr[80]; - attrstr[0] = 0; - - for (rdwr_map::iterator it = rwm->begin (); it != rwm->end (); ++it) - { - std::pair access = *it; - - /* Get the function call arguments corresponding to the attribute's - positional arguments. When both arguments have been specified - there will be two entries in *RWM, one for each. They are - cross-referenced by their respective argument numbers in - ACCESS.PTRARG and ACCESS.SIZARG. */ - const int ptridx = access.second.ptrarg; - const int sizidx = access.second.sizarg; - - gcc_assert (ptridx != -1); - gcc_assert (access.first == ptridx || access.first == sizidx); - - /* The pointer is set to null for the entry corresponding to - the size argument. Skip it. It's handled when the entry - corresponding to the pointer argument comes up. */ - if (!access.second.ptr) - continue; - - tree ptrtype = fntype_argno_type (fntype, ptridx); - tree argtype = TREE_TYPE (ptrtype); - - /* The size of the access by the call. */ - tree access_size; - if (sizidx == -1) - { - /* If only the pointer attribute operand was specified and - not size, set SIZE to the greater of MINSIZE or size of - one element of the pointed to type to detect smaller - objects (null pointers are diagnosed in this case only - if the pointer is also declared with attribute nonnull. */ - if (access.second.minsize - && access.second.minsize != HOST_WIDE_INT_M1U) - access_size = build_int_cstu (sizetype, access.second.minsize); - else - access_size = size_one_node; - } - else - access_size = rwm->get (sizidx)->size; - - /* Format the value or range to avoid an explosion of messages. */ - char sizstr[80]; - tree sizrng[2] = { size_zero_node, build_all_ones_cst (sizetype) }; - if (get_size_range (access_size, sizrng, true)) - { - char *s0 = print_generic_expr_to_str (sizrng[0]); - if (tree_int_cst_equal (sizrng[0], sizrng[1])) - { - gcc_checking_assert (strlen (s0) < sizeof sizstr); - strcpy (sizstr, s0); - } - else - { - char *s1 = print_generic_expr_to_str (sizrng[1]); - gcc_checking_assert (strlen (s0) + strlen (s1) - < sizeof sizstr - 4); - sprintf (sizstr, "[%s, %s]", s0, s1); - free (s1); - } - free (s0); - } - else - *sizstr = '\0'; - - /* Set if a warning has been issued for the current argument. */ - opt_code arg_warned = no_warning; - location_t loc = EXPR_LOCATION (exp); - tree ptr = access.second.ptr; - if (*sizstr - && tree_int_cst_sgn (sizrng[0]) < 0 - && tree_int_cst_sgn (sizrng[1]) < 0) - { - /* Warn about negative sizes. */ - if (access.second.internal_p) - { - const std::string argtypestr - = access.second.array_as_string (ptrtype); - - if (warning_at (loc, OPT_Wstringop_overflow_, - "bound argument %i value %s is " - "negative for a variable length array " - "argument %i of type %s", - sizidx + 1, sizstr, - ptridx + 1, argtypestr.c_str ())) - arg_warned = OPT_Wstringop_overflow_; - } - else if (warning_at (loc, OPT_Wstringop_overflow_, - "argument %i value %s is negative", - sizidx + 1, sizstr)) - arg_warned = OPT_Wstringop_overflow_; - - if (arg_warned != no_warning) - { - append_attrname (access, attrstr, sizeof attrstr); - /* Remember a warning has been issued and avoid warning - again below for the same attribute. */ - opt_warned = arg_warned; - continue; - } - } - - if (tree_int_cst_sgn (sizrng[0]) >= 0) - { - if (COMPLETE_TYPE_P (argtype)) - { - /* Multiply ACCESS_SIZE by the size of the type the pointer - argument points to. If it's incomplete the size is used - as is. */ - if (tree argsize = TYPE_SIZE_UNIT (argtype)) - if (TREE_CODE (argsize) == INTEGER_CST) - { - const int prec = TYPE_PRECISION (sizetype); - wide_int minsize = wi::to_wide (sizrng[0], prec); - minsize *= wi::to_wide (argsize, prec); - access_size = wide_int_to_tree (sizetype, minsize); - } - } - } - else - access_size = NULL_TREE; - - if (integer_zerop (ptr)) - { - if (sizidx >= 0 && tree_int_cst_sgn (sizrng[0]) > 0) - { - /* Warn about null pointers with positive sizes. This is - different from also declaring the pointer argument with - attribute nonnull when the function accepts null pointers - only when the corresponding size is zero. */ - if (access.second.internal_p) - { - const std::string argtypestr - = access.second.array_as_string (ptrtype); - - if (warning_at (loc, OPT_Wnonnull, - "argument %i of variable length " - "array %s is null but " - "the corresponding bound argument " - "%i value is %s", - ptridx + 1, argtypestr.c_str (), - sizidx + 1, sizstr)) - arg_warned = OPT_Wnonnull; - } - else if (warning_at (loc, OPT_Wnonnull, - "argument %i is null but " - "the corresponding size argument " - "%i value is %s", - ptridx + 1, sizidx + 1, sizstr)) - arg_warned = OPT_Wnonnull; - } - else if (access_size && access.second.static_p) - { - /* Warn about null pointers for [static N] array arguments - but do not warn for ordinary (i.e., nonstatic) arrays. */ - if (warning_at (loc, OPT_Wnonnull, - "argument %i to %<%T[static %E]%> " - "is null where non-null expected", - ptridx + 1, argtype, access_size)) - arg_warned = OPT_Wnonnull; - } - - if (arg_warned != no_warning) - { - append_attrname (access, attrstr, sizeof attrstr); - /* Remember a warning has been issued and avoid warning - again below for the same attribute. */ - opt_warned = OPT_Wnonnull; - continue; - } - } - - access_data data (ptr, access.second.mode, NULL_TREE, false, - NULL_TREE, false); - access_ref* const pobj = (access.second.mode == access_write_only - ? &data.dst : &data.src); - tree objsize = compute_objsize (ptr, 1, pobj); - - /* The size of the destination or source object. */ - tree dstsize = NULL_TREE, srcsize = NULL_TREE; - if (access.second.mode == access_read_only - || access.second.mode == access_none) - { - /* For a read-only argument there is no destination. For - no access, set the source as well and differentiate via - the access flag below. */ - srcsize = objsize; - if (access.second.mode == access_read_only - || access.second.mode == access_none) - { - /* For a read-only attribute there is no destination so - clear OBJSIZE. This emits "reading N bytes" kind of - diagnostics instead of the "writing N bytes" kind, - unless MODE is none. */ - objsize = NULL_TREE; - } - } - else - dstsize = objsize; - - /* Clear the no-warning bit in case it was set by check_access - in a prior iteration so that accesses via different arguments - are diagnosed. */ - suppress_warning (exp, OPT_Wstringop_overflow_, false); - access_mode mode = data.mode; - if (mode == access_deferred) - mode = TYPE_READONLY (argtype) ? access_read_only : access_read_write; - check_access (exp, access_size, /*maxread=*/ NULL_TREE, srcsize, - dstsize, mode, &data); - - if (warning_suppressed_p (exp, OPT_Wstringop_overflow_)) - opt_warned = OPT_Wstringop_overflow_; - if (opt_warned != N_OPTS) - { - if (access.second.internal_p) - inform (loc, "referencing argument %u of type %qT", - ptridx + 1, ptrtype); - else - /* If check_access issued a warning above, append the relevant - attribute to the string. */ - append_attrname (access, attrstr, sizeof attrstr); - } - } - - if (*attrstr) - { - if (fndecl) - inform (DECL_SOURCE_LOCATION (fndecl), - "in a call to function %qD declared with attribute %qs", - fndecl, attrstr); - else - inform (EXPR_LOCATION (fndecl), - "in a call with type %qT and attribute %qs", - fntype, attrstr); - } - else if (opt_warned != N_OPTS) - { - if (fndecl) - inform (DECL_SOURCE_LOCATION (fndecl), - "in a call to function %qD", fndecl); - else - inform (EXPR_LOCATION (fndecl), - "in a call with type %qT", fntype); - } - - /* Set the bit in case if was cleared and not set above. */ - if (opt_warned != N_OPTS) - suppress_warning (exp, opt_warned); -} - /* Fill in ARGS_SIZE and ARGS array based on the parameters found in CALL_EXPR EXP. @@ -2030,27 +1331,6 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED, bitmap_obstack_release (NULL); - tree fntypeattrs = TYPE_ATTRIBUTES (fntype); - /* Extract attribute alloc_size from the type of the called expression - (which could be a function or a function pointer) and if set, store - the indices of the corresponding arguments in ALLOC_IDX, and then - the actual argument(s) at those indices in ALLOC_ARGS. */ - int alloc_idx[2] = { -1, -1 }; - if (tree alloc_size = lookup_attribute ("alloc_size", fntypeattrs)) - { - tree args = TREE_VALUE (alloc_size); - alloc_idx[0] = TREE_INT_CST_LOW (TREE_VALUE (args)) - 1; - if (TREE_CHAIN (args)) - alloc_idx[1] = TREE_INT_CST_LOW (TREE_VALUE (TREE_CHAIN (args))) - 1; - } - - /* Array for up to the two attribute alloc_size arguments. */ - tree alloc_args[] = { NULL_TREE, NULL_TREE }; - - /* Map of attribute accewss specifications for function arguments. */ - rdwr_map rdwr_idx; - init_attr_rdwr_indices (&rdwr_idx, fntypeattrs); - /* I counts args in order (to be) pushed; ARGPOS counts in order written. */ for (argpos = 0; argpos < num_actuals; i--, argpos++) { @@ -2283,44 +1563,7 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED, does pass the promoted mode. */ arg.mode = TYPE_MODE (type); targetm.calls.function_arg_advance (args_so_far, arg); - - /* Store argument values for functions decorated with attribute - alloc_size. */ - if (argpos == alloc_idx[0]) - alloc_args[0] = args[i].tree_value; - else if (argpos == alloc_idx[1]) - alloc_args[1] = args[i].tree_value; - - /* Save the actual argument that corresponds to the access attribute - operand for later processing. */ - if (attr_access *access = rdwr_idx.get (argpos)) - { - if (POINTER_TYPE_P (type)) - { - access->ptr = args[i].tree_value; - // A nonnull ACCESS->SIZE contains VLA bounds. */ - } - else - { - access->size = args[i].tree_value; - gcc_assert (access->ptr == NULL_TREE); - } - } - } - - if (alloc_args[0]) - { - /* Check the arguments of functions decorated with attribute - alloc_size. */ - maybe_warn_alloc_args_overflow (fndecl, exp, alloc_args, alloc_idx); } - - /* Detect passing non-string arguments to functions expecting - nul-terminated strings. */ - maybe_warn_nonstring_arg (fndecl, exp); - - /* Check attribute access arguments. */ - maybe_warn_rdwr_sizes (&rdwr_idx, fndecl, fntype, exp); } /* Update ARGS_SIZE to contain the total size for the argument block. @@ -6020,6 +5263,3 @@ cxx17_empty_base_field_p (const_tree field) && RECORD_OR_UNION_TYPE_P (TREE_TYPE (field)) && !lookup_attribute ("no_unique_address", DECL_ATTRIBUTES (field))); } - -/* Tell the garbage collector about GTY markers in this source file. */ -#include "gt-calls.h" diff --git a/gcc/calls.h b/gcc/calls.h index 4a018f6..9a98f5d 100644 --- a/gcc/calls.h +++ b/gcc/calls.h @@ -130,21 +130,8 @@ extern bool apply_pass_by_reference_rules (CUMULATIVE_ARGS *, function_arg_info &); extern bool reference_callee_copied (CUMULATIVE_ARGS *, const function_arg_info &); -extern void maybe_warn_alloc_args_overflow (tree, tree, tree[2], int[2]); -extern tree get_attr_nonstring_decl (tree, tree * = NULL); -extern bool maybe_warn_nonstring_arg (tree, tree); extern void maybe_complain_about_tail_call (tree, const char *); -enum size_range_flags - { - /* Set to consider zero a valid range. */ - SR_ALLOW_ZERO = 1, - /* Set to use the largest subrange of a set of ranges as opposed - to the smallest. */ - SR_USE_LARGEST = 2 - }; -extern bool get_size_range (tree, tree[2], int = 0); -extern bool get_size_range (class range_query *, tree, gimple *, - tree[2], int = 0); + extern rtx rtx_for_static_chain (const_tree, bool); extern bool cxx17_empty_base_field_p (const_tree); diff --git a/gcc/gimple-ssa-warn-access.cc b/gcc/gimple-ssa-warn-access.cc index 93f43b7..f3efe56 100644 --- a/gcc/gimple-ssa-warn-access.cc +++ b/gcc/gimple-ssa-warn-access.cc @@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see . */ +#define INCLUDE_STRING #include "config.h" #include "system.h" #include "coretypes.h" @@ -36,6 +37,7 @@ #include "fold-const.h" #include "gimple-fold.h" #include "gimple-iterator.h" +#include "langhooks.h" #include "tree-dfa.h" #include "tree-ssa.h" #include "tree-cfg.h" @@ -50,14 +52,6 @@ #include "demangle.h" #include "pointer-query.h" -/* Return true if STMT has an associated location. */ - -static inline location_t -has_location (const gimple *stmt) -{ - return gimple_has_location (stmt); -} - /* Return true if tree node X has an associated location. */ static inline location_t @@ -1177,7 +1171,7 @@ warn_for_access (location_t loc, tree func, tree expr, int opt, /* Helper to set RANGE to the range of BOUND if it's nonnull, bounded by BNDRNG if nonnull and valid. */ -void +static void get_size_range (tree bound, tree range[2], const offset_int bndrng[2]) { if (bound) @@ -2105,14 +2099,14 @@ warn_dealloc_offset (location_t loc, gimple *call, const access_ref &aref) form of C++ operatorn new. */ static void -maybe_emit_free_warning (gcall *call) +maybe_check_dealloc_call (gcall *call) { tree fndecl = gimple_call_fndecl (call); if (!fndecl) return; unsigned argno = fndecl_dealloc_argno (fndecl); - if ((unsigned) gimple_call_num_args (call) <= argno) + if ((unsigned) call_nargs (call) <= argno) return; tree ptr = gimple_call_arg (call, argno); @@ -2246,9 +2240,9 @@ const pass_data pass_data_waccess = { class pass_waccess : public gimple_opt_pass { public: - pass_waccess (gcc::context *ctxt) - : gimple_opt_pass (pass_data_waccess, ctxt), m_ranger () - { } + pass_waccess (gcc::context *); + + ~pass_waccess (); opt_pass *clone () { return new pass_waccess (m_ctxt); } @@ -2258,6 +2252,9 @@ class pass_waccess : public gimple_opt_pass /* Check a call to a built-in function. */ bool check_builtin (gcall *); + /* Check a call to an ordinary function. */ + bool check_call (gcall *); + /* Check statements in a basic block. */ void check (basic_block); @@ -2265,9 +2262,35 @@ class pass_waccess : public gimple_opt_pass void check (gcall *); private: + /* Not copyable or assignable. */ + pass_waccess (pass_waccess &) = delete; + void operator= (pass_waccess &) = delete; + + /* A pointer_query object and its cache to store information about + pointers and their targets in. */ + pointer_query ptr_qry; + pointer_query::cache_type var_cache; + gimple_ranger *m_ranger; }; +/* Construct the pass. */ + +pass_waccess::pass_waccess (gcc::context *ctxt) + : gimple_opt_pass (pass_data_waccess, ctxt), + ptr_qry (m_ranger, &var_cache), + var_cache (), + m_ranger () +{ +} + +/* Release pointer_query cache. */ + +pass_waccess::~pass_waccess () +{ + ptr_qry.flush_cache (); +} + /* Return true when any checks performed by the pass are enabled. */ bool @@ -2278,12 +2301,256 @@ pass_waccess::gate (function *) || warn_mismatched_new_delete); } +/* Initialize ALLOC_OBJECT_SIZE_LIMIT based on the -Walloc-size-larger-than= + setting if the option is specified, or to the maximum object size if it + is not. Return the initialized value. */ + +static tree +alloc_max_size (void) +{ + HOST_WIDE_INT limit = warn_alloc_size_limit; + if (limit == HOST_WIDE_INT_MAX) + limit = tree_to_shwi (TYPE_MAX_VALUE (ptrdiff_type_node)); + + return build_int_cst (size_type_node, limit); +} + +/* Diagnose a call EXP to function FN decorated with attribute alloc_size + whose argument numbers given by IDX with values given by ARGS exceed + the maximum object size or cause an unsigned oveflow (wrapping) when + multiplied. FN is null when EXP is a call via a function pointer. + When ARGS[0] is null the function does nothing. ARGS[1] may be null + for functions like malloc, and non-null for those like calloc that + are decorated with a two-argument attribute alloc_size. */ + +void +maybe_warn_alloc_args_overflow (gimple *stmt, const tree args[2], + const int idx[2]) +{ + /* The range each of the (up to) two arguments is known to be in. */ + tree argrange[2][2] = { { NULL_TREE, NULL_TREE }, { NULL_TREE, NULL_TREE } }; + + /* Maximum object size set by -Walloc-size-larger-than= or SIZE_MAX / 2. */ + tree maxobjsize = alloc_max_size (); + + location_t loc = get_location (stmt); + + tree fn = gimple_call_fndecl (stmt); + tree fntype = fn ? TREE_TYPE (fn) : gimple_call_fntype (stmt); + bool warned = false; + + /* Validate each argument individually. */ + for (unsigned i = 0; i != 2 && args[i]; ++i) + { + if (TREE_CODE (args[i]) == INTEGER_CST) + { + argrange[i][0] = args[i]; + argrange[i][1] = args[i]; + + if (tree_int_cst_lt (args[i], integer_zero_node)) + { + warned = warning_at (loc, OPT_Walloc_size_larger_than_, + "argument %i value %qE is negative", + idx[i] + 1, args[i]); + } + else if (integer_zerop (args[i])) + { + /* Avoid issuing -Walloc-zero for allocation functions other + than __builtin_alloca that are declared with attribute + returns_nonnull because there's no portability risk. This + avoids warning for such calls to libiberty's xmalloc and + friends. + Also avoid issuing the warning for calls to function named + "alloca". */ + if (fn && fndecl_built_in_p (fn, BUILT_IN_ALLOCA) + ? IDENTIFIER_LENGTH (DECL_NAME (fn)) != 6 + : !lookup_attribute ("returns_nonnull", + TYPE_ATTRIBUTES (fntype))) + warned = warning_at (loc, OPT_Walloc_zero, + "argument %i value is zero", + idx[i] + 1); + } + else if (tree_int_cst_lt (maxobjsize, args[i])) + { + /* G++ emits calls to ::operator new[](SIZE_MAX) in C++98 + mode and with -fno-exceptions as a way to indicate array + size overflow. There's no good way to detect C++98 here + so avoid diagnosing these calls for all C++ modes. */ + if (i == 0 + && fn + && !args[1] + && lang_GNU_CXX () + && DECL_IS_OPERATOR_NEW_P (fn) + && integer_all_onesp (args[i])) + continue; + + warned = warning_at (loc, OPT_Walloc_size_larger_than_, + "argument %i value %qE exceeds " + "maximum object size %E", + idx[i] + 1, args[i], maxobjsize); + } + } + else if (TREE_CODE (args[i]) == SSA_NAME + && get_size_range (args[i], argrange[i])) + { + /* Verify that the argument's range is not negative (including + upper bound of zero). */ + if (tree_int_cst_lt (argrange[i][0], integer_zero_node) + && tree_int_cst_le (argrange[i][1], integer_zero_node)) + { + warned = warning_at (loc, OPT_Walloc_size_larger_than_, + "argument %i range [%E, %E] is negative", + idx[i] + 1, + argrange[i][0], argrange[i][1]); + } + else if (tree_int_cst_lt (maxobjsize, argrange[i][0])) + { + warned = warning_at (loc, OPT_Walloc_size_larger_than_, + "argument %i range [%E, %E] exceeds " + "maximum object size %E", + idx[i] + 1, + argrange[i][0], argrange[i][1], + maxobjsize); + } + } + } + + if (!argrange[0]) + return; + + /* For a two-argument alloc_size, validate the product of the two + arguments if both of their values or ranges are known. */ + if (!warned && tree_fits_uhwi_p (argrange[0][0]) + && argrange[1][0] && tree_fits_uhwi_p (argrange[1][0]) + && !integer_onep (argrange[0][0]) + && !integer_onep (argrange[1][0])) + { + /* Check for overflow in the product of a function decorated with + attribute alloc_size (X, Y). */ + unsigned szprec = TYPE_PRECISION (size_type_node); + wide_int x = wi::to_wide (argrange[0][0], szprec); + wide_int y = wi::to_wide (argrange[1][0], szprec); + + wi::overflow_type vflow; + wide_int prod = wi::umul (x, y, &vflow); + + if (vflow) + warned = warning_at (loc, OPT_Walloc_size_larger_than_, + "product %<%E * %E%> of arguments %i and %i " + "exceeds %", + argrange[0][0], argrange[1][0], + idx[0] + 1, idx[1] + 1); + else if (wi::ltu_p (wi::to_wide (maxobjsize, szprec), prod)) + warned = warning_at (loc, OPT_Walloc_size_larger_than_, + "product %<%E * %E%> of arguments %i and %i " + "exceeds maximum object size %E", + argrange[0][0], argrange[1][0], + idx[0] + 1, idx[1] + 1, + maxobjsize); + + if (warned) + { + /* Print the full range of each of the two arguments to make + it clear when it is, in fact, in a range and not constant. */ + if (argrange[0][0] != argrange [0][1]) + inform (loc, "argument %i in the range [%E, %E]", + idx[0] + 1, argrange[0][0], argrange[0][1]); + if (argrange[1][0] != argrange [1][1]) + inform (loc, "argument %i in the range [%E, %E]", + idx[1] + 1, argrange[1][0], argrange[1][1]); + } + } + + if (warned && fn) + { + location_t fnloc = DECL_SOURCE_LOCATION (fn); + + if (DECL_IS_UNDECLARED_BUILTIN (fn)) + inform (loc, + "in a call to built-in allocation function %qD", fn); + else + inform (fnloc, + "in a call to allocation function %qD declared here", fn); + } +} + +/* Check a call to an alloca function for an excessive size. */ + +static void +check_alloca (gimple *stmt) +{ + if ((warn_vla_limit >= HOST_WIDE_INT_MAX + && warn_alloc_size_limit < warn_vla_limit) + || (warn_alloca_limit >= HOST_WIDE_INT_MAX + && warn_alloc_size_limit < warn_alloca_limit)) + { + /* -Walloca-larger-than and -Wvla-larger-than settings of less + than HWI_MAX override the more general -Walloc-size-larger-than + so unless either of the former options is smaller than the last + one (wchich would imply that the call was already checked), check + the alloca arguments for overflow. */ + const tree alloc_args[] = { call_arg (stmt, 0), NULL_TREE }; + const int idx[] = { 0, -1 }; + maybe_warn_alloc_args_overflow (stmt, alloc_args, idx); + } +} + +/* Check a call to an allocation function for an excessive size. */ + +static void +check_alloc_size_call (gimple *stmt) +{ + if (gimple_call_num_args (stmt) < 1) + /* Avoid invalid calls to functions without a prototype. */ + return; + + tree fndecl = gimple_call_fndecl (stmt); + if (fndecl && gimple_call_builtin_p (stmt, BUILT_IN_NORMAL)) + { + /* Alloca is handled separately. */ + switch (DECL_FUNCTION_CODE (fndecl)) + { + case BUILT_IN_ALLOCA: + case BUILT_IN_ALLOCA_WITH_ALIGN: + case BUILT_IN_ALLOCA_WITH_ALIGN_AND_MAX: + return; + default: + break; + } + } + + tree fntype = gimple_call_fntype (stmt); + tree fntypeattrs = TYPE_ATTRIBUTES (fntype); + + tree alloc_size = lookup_attribute ("alloc_size", fntypeattrs); + if (!alloc_size) + return; + + /* Extract attribute alloc_size from the type of the called expression + (which could be a function or a function pointer) and if set, store + the indices of the corresponding arguments in ALLOC_IDX, and then + the actual argument(s) at those indices in ALLOC_ARGS. */ + int idx[2] = { -1, -1 }; + tree alloc_args[] = { NULL_TREE, NULL_TREE }; + + tree args = TREE_VALUE (alloc_size); + idx[0] = TREE_INT_CST_LOW (TREE_VALUE (args)) - 1; + alloc_args[0] = call_arg (stmt, idx[0]); + if (TREE_CHAIN (args)) + { + idx[1] = TREE_INT_CST_LOW (TREE_VALUE (TREE_CHAIN (args))) - 1; + alloc_args[1] = call_arg (stmt, idx[1]); + } + + maybe_warn_alloc_args_overflow (stmt, alloc_args, idx); +} + /* Check a call STMT to strcat() for overflow and warn if it does. */ static void check_strcat (gimple *stmt) { - if (!warn_stringop_overflow) + if (!warn_stringop_overflow && !warn_stringop_overread) return; tree dest = call_arg (stmt, 0); @@ -2308,7 +2575,7 @@ check_strcat (gimple *stmt) static void check_strncat (gimple *stmt) { - if (!warn_stringop_overflow) + if (!warn_stringop_overflow && !warn_stringop_overread) return; tree dest = call_arg (stmt, 0); @@ -2537,6 +2804,12 @@ pass_waccess::check_builtin (gcall *stmt) switch (DECL_FUNCTION_CODE (callee)) { + case BUILT_IN_ALLOCA: + case BUILT_IN_ALLOCA_WITH_ALIGN: + case BUILT_IN_ALLOCA_WITH_ALIGN_AND_MAX: + check_alloca (stmt); + return true; + case BUILT_IN_GETTEXT: case BUILT_IN_PUTS: case BUILT_IN_PUTS_UNLOCKED: @@ -2639,16 +2912,384 @@ pass_waccess::check_builtin (gcall *stmt) return true; } +/* Returns the type of the argument ARGNO to function with type FNTYPE + or null when the typoe cannot be determined or no such argument exists. */ + +static tree +fntype_argno_type (tree fntype, unsigned argno) +{ + if (!prototype_p (fntype)) + return NULL_TREE; + + tree argtype; + function_args_iterator it; + FOREACH_FUNCTION_ARGS (fntype, argtype, it) + if (argno-- == 0) + return argtype; + + return NULL_TREE; +} + +/* Helper to append the "human readable" attribute access specification + described by ACCESS to the array ATTRSTR with size STRSIZE. Used in + diagnostics. */ + +static inline void +append_attrname (const std::pair &access, + char *attrstr, size_t strsize) +{ + if (access.second.internal_p) + return; + + tree str = access.second.to_external_string (); + gcc_assert (strsize >= (size_t) TREE_STRING_LENGTH (str)); + strcpy (attrstr, TREE_STRING_POINTER (str)); +} + +/* Iterate over attribute access read-only, read-write, and write-only + arguments and diagnose past-the-end accesses and related problems + in the function call EXP. */ + +static void +maybe_warn_rdwr_sizes (rdwr_map *rwm, tree fndecl, tree fntype, gimple *stmt) +{ + auto_diagnostic_group adg; + + /* Set if a warning has been issued for any argument (used to decide + whether to emit an informational note at the end). */ + opt_code opt_warned = no_warning; + + /* A string describing the attributes that the warnings issued by this + function apply to. Used to print one informational note per function + call, rather than one per warning. That reduces clutter. */ + char attrstr[80]; + attrstr[0] = 0; + + for (rdwr_map::iterator it = rwm->begin (); it != rwm->end (); ++it) + { + std::pair access = *it; + + /* Get the function call arguments corresponding to the attribute's + positional arguments. When both arguments have been specified + there will be two entries in *RWM, one for each. They are + cross-referenced by their respective argument numbers in + ACCESS.PTRARG and ACCESS.SIZARG. */ + const int ptridx = access.second.ptrarg; + const int sizidx = access.second.sizarg; + + gcc_assert (ptridx != -1); + gcc_assert (access.first == ptridx || access.first == sizidx); + + /* The pointer is set to null for the entry corresponding to + the size argument. Skip it. It's handled when the entry + corresponding to the pointer argument comes up. */ + if (!access.second.ptr) + continue; + + tree ptrtype = fntype_argno_type (fntype, ptridx); + tree argtype = TREE_TYPE (ptrtype); + + /* The size of the access by the call. */ + tree access_size; + if (sizidx == -1) + { + /* If only the pointer attribute operand was specified and + not size, set SIZE to the greater of MINSIZE or size of + one element of the pointed to type to detect smaller + objects (null pointers are diagnosed in this case only + if the pointer is also declared with attribute nonnull. */ + if (access.second.minsize + && access.second.minsize != HOST_WIDE_INT_M1U) + access_size = build_int_cstu (sizetype, access.second.minsize); + else + access_size = size_one_node; + } + else + access_size = rwm->get (sizidx)->size; + + /* Format the value or range to avoid an explosion of messages. */ + char sizstr[80]; + tree sizrng[2] = { size_zero_node, build_all_ones_cst (sizetype) }; + if (get_size_range (access_size, sizrng, true)) + { + char *s0 = print_generic_expr_to_str (sizrng[0]); + if (tree_int_cst_equal (sizrng[0], sizrng[1])) + { + gcc_checking_assert (strlen (s0) < sizeof sizstr); + strcpy (sizstr, s0); + } + else + { + char *s1 = print_generic_expr_to_str (sizrng[1]); + gcc_checking_assert (strlen (s0) + strlen (s1) + < sizeof sizstr - 4); + sprintf (sizstr, "[%s, %s]", s0, s1); + free (s1); + } + free (s0); + } + else + *sizstr = '\0'; + + /* Set if a warning has been issued for the current argument. */ + opt_code arg_warned = no_warning; + location_t loc = get_location (stmt); + tree ptr = access.second.ptr; + if (*sizstr + && tree_int_cst_sgn (sizrng[0]) < 0 + && tree_int_cst_sgn (sizrng[1]) < 0) + { + /* Warn about negative sizes. */ + if (access.second.internal_p) + { + const std::string argtypestr + = access.second.array_as_string (ptrtype); + + if (warning_at (loc, OPT_Wstringop_overflow_, + "bound argument %i value %s is " + "negative for a variable length array " + "argument %i of type %s", + sizidx + 1, sizstr, + ptridx + 1, argtypestr.c_str ())) + arg_warned = OPT_Wstringop_overflow_; + } + else if (warning_at (loc, OPT_Wstringop_overflow_, + "argument %i value %s is negative", + sizidx + 1, sizstr)) + arg_warned = OPT_Wstringop_overflow_; + + if (arg_warned != no_warning) + { + append_attrname (access, attrstr, sizeof attrstr); + /* Remember a warning has been issued and avoid warning + again below for the same attribute. */ + opt_warned = arg_warned; + continue; + } + } + + if (tree_int_cst_sgn (sizrng[0]) >= 0) + { + if (COMPLETE_TYPE_P (argtype)) + { + /* Multiply ACCESS_SIZE by the size of the type the pointer + argument points to. If it's incomplete the size is used + as is. */ + if (tree argsize = TYPE_SIZE_UNIT (argtype)) + if (TREE_CODE (argsize) == INTEGER_CST) + { + const int prec = TYPE_PRECISION (sizetype); + wide_int minsize = wi::to_wide (sizrng[0], prec); + minsize *= wi::to_wide (argsize, prec); + access_size = wide_int_to_tree (sizetype, minsize); + } + } + } + else + access_size = NULL_TREE; + + if (integer_zerop (ptr)) + { + if (sizidx >= 0 && tree_int_cst_sgn (sizrng[0]) > 0) + { + /* Warn about null pointers with positive sizes. This is + different from also declaring the pointer argument with + attribute nonnull when the function accepts null pointers + only when the corresponding size is zero. */ + if (access.second.internal_p) + { + const std::string argtypestr + = access.second.array_as_string (ptrtype); + + if (warning_at (loc, OPT_Wnonnull, + "argument %i of variable length " + "array %s is null but " + "the corresponding bound argument " + "%i value is %s", + ptridx + 1, argtypestr.c_str (), + sizidx + 1, sizstr)) + arg_warned = OPT_Wnonnull; + } + else if (warning_at (loc, OPT_Wnonnull, + "argument %i is null but " + "the corresponding size argument " + "%i value is %s", + ptridx + 1, sizidx + 1, sizstr)) + arg_warned = OPT_Wnonnull; + } + else if (access_size && access.second.static_p) + { + /* Warn about null pointers for [static N] array arguments + but do not warn for ordinary (i.e., nonstatic) arrays. */ + if (warning_at (loc, OPT_Wnonnull, + "argument %i to %<%T[static %E]%> " + "is null where non-null expected", + ptridx + 1, argtype, access_size)) + arg_warned = OPT_Wnonnull; + } + + if (arg_warned != no_warning) + { + append_attrname (access, attrstr, sizeof attrstr); + /* Remember a warning has been issued and avoid warning + again below for the same attribute. */ + opt_warned = OPT_Wnonnull; + continue; + } + } + + access_data data (ptr, access.second.mode, NULL_TREE, false, + NULL_TREE, false); + access_ref* const pobj = (access.second.mode == access_write_only + ? &data.dst : &data.src); + tree objsize = compute_objsize (ptr, 1, pobj); + + /* The size of the destination or source object. */ + tree dstsize = NULL_TREE, srcsize = NULL_TREE; + if (access.second.mode == access_read_only + || access.second.mode == access_none) + { + /* For a read-only argument there is no destination. For + no access, set the source as well and differentiate via + the access flag below. */ + srcsize = objsize; + if (access.second.mode == access_read_only + || access.second.mode == access_none) + { + /* For a read-only attribute there is no destination so + clear OBJSIZE. This emits "reading N bytes" kind of + diagnostics instead of the "writing N bytes" kind, + unless MODE is none. */ + objsize = NULL_TREE; + } + } + else + dstsize = objsize; + + /* Clear the no-warning bit in case it was set by check_access + in a prior iteration so that accesses via different arguments + are diagnosed. */ + suppress_warning (stmt, OPT_Wstringop_overflow_, false); + access_mode mode = data.mode; + if (mode == access_deferred) + mode = TYPE_READONLY (argtype) ? access_read_only : access_read_write; + check_access (stmt, access_size, /*maxread=*/ NULL_TREE, srcsize, + dstsize, mode, &data); + + if (warning_suppressed_p (stmt, OPT_Wstringop_overflow_)) + opt_warned = OPT_Wstringop_overflow_; + if (opt_warned != no_warning) + { + if (access.second.internal_p) + inform (loc, "referencing argument %u of type %qT", + ptridx + 1, ptrtype); + else + /* If check_access issued a warning above, append the relevant + attribute to the string. */ + append_attrname (access, attrstr, sizeof attrstr); + } + } + + if (*attrstr) + { + if (fndecl) + inform (get_location (fndecl), + "in a call to function %qD declared with attribute %qs", + fndecl, attrstr); + else + inform (get_location (stmt), + "in a call with type %qT and attribute %qs", + fntype, attrstr); + } + else if (opt_warned != no_warning) + { + if (fndecl) + inform (get_location (fndecl), + "in a call to function %qD", fndecl); + else + inform (get_location (stmt), + "in a call with type %qT", fntype); + } + + /* Set the bit in case if was cleared and not set above. */ + if (opt_warned != no_warning) + suppress_warning (stmt, opt_warned); +} + +/* Check call STMT to an ordinary (non-built-in) function for invalid + accesses. Return true if a call has been handled. */ + +bool +pass_waccess::check_call (gcall *stmt) +{ + tree fntype = gimple_call_fntype (stmt); + if (!fntype) + return false; + + tree fntypeattrs = TYPE_ATTRIBUTES (fntype); + if (!fntypeattrs) + return false; + + /* Map of attribute accewss specifications for function arguments. */ + rdwr_map rdwr_idx; + init_attr_rdwr_indices (&rdwr_idx, fntypeattrs); + + unsigned nargs = call_nargs (stmt); + for (unsigned i = 0; i != nargs; ++i) + { + tree arg = call_arg (stmt, i); + + /* Save the actual argument that corresponds to the access attribute + operand for later processing. */ + if (attr_access *access = rdwr_idx.get (i)) + { + if (POINTER_TYPE_P (TREE_TYPE (arg))) + { + access->ptr = arg; + // A nonnull ACCESS->SIZE contains VLA bounds. */ + } + else + { + access->size = arg; + gcc_assert (access->ptr == NULL_TREE); + } + } + } + + /* Check attribute access arguments. */ + tree fndecl = gimple_call_fndecl (stmt); + maybe_warn_rdwr_sizes (&rdwr_idx, fndecl, fntype, stmt); + + check_alloc_size_call (stmt); + return true; +} + +/* Check arguments in a call STMT for attribute nonstring. */ + +static void +check_nonstring_args (gcall *stmt) +{ + tree fndecl = gimple_call_fndecl (stmt); + + /* Detect passing non-string arguments to functions expecting + nul-terminated strings. */ + maybe_warn_nonstring_arg (fndecl, stmt); +} + /* Check call STMT for invalid accesses. */ void pass_waccess::check (gcall *stmt) { - if (gimple_call_builtin_p (stmt, BUILT_IN_NORMAL) - && check_builtin (stmt)) - return; + if (gimple_call_builtin_p (stmt, BUILT_IN_NORMAL)) + check_builtin (stmt); - maybe_emit_free_warning (stmt); + if (is_gimple_call (stmt)) + check_call (stmt); + + maybe_check_dealloc_call (stmt); + + check_nonstring_args (stmt); } /* Check basic block BB for invalid accesses. */ @@ -2669,6 +3310,8 @@ pass_waccess::check (basic_block bb) unsigned pass_waccess::execute (function *fun) { + m_ranger = enable_ranger (fun); + basic_block bb; FOR_EACH_BB_FN (bb, fun) check (bb); diff --git a/gcc/gimple-ssa-warn-access.h b/gcc/gimple-ssa-warn-access.h index 8b33ecb..1cd3a28 100644 --- a/gcc/gimple-ssa-warn-access.h +++ b/gcc/gimple-ssa-warn-access.h @@ -31,7 +31,9 @@ extern void warn_string_no_nul (location_t, tree, const char *, tree, tree, tree = NULL_TREE, bool = false, const wide_int[2] = NULL); extern tree unterminated_array (tree, tree * = NULL, bool * = NULL); -extern void get_size_range (tree, tree[2], const offset_int[2]); + +extern bool maybe_warn_nonstring_arg (tree, gimple *); +extern bool maybe_warn_nonstring_arg (tree, tree); class access_data; extern bool maybe_warn_for_bound (opt_code, location_t, gimple *, tree, diff --git a/gcc/gimple-ssa-warn-restrict.c b/gcc/gimple-ssa-warn-restrict.c index 404acb0..d1df9ca 100644 --- a/gcc/gimple-ssa-warn-restrict.c +++ b/gcc/gimple-ssa-warn-restrict.c @@ -29,6 +29,7 @@ #include "pointer-query.h" #include "ssa.h" #include "gimple-pretty-print.h" +#include "gimple-ssa-warn-access.h" #include "gimple-ssa-warn-restrict.h" #include "diagnostic-core.h" #include "fold-const.h" diff --git a/gcc/pointer-query.cc b/gcc/pointer-query.cc index bc7cac0..99caf78 100644 --- a/gcc/pointer-query.cc +++ b/gcc/pointer-query.cc @@ -22,58 +22,21 @@ #include "system.h" #include "coretypes.h" #include "backend.h" -#include "target.h" -#include "rtl.h" #include "tree.h" -#include "memmodel.h" #include "gimple.h" -#include "predict.h" -#include "tm_p.h" #include "stringpool.h" #include "tree-vrp.h" -#include "tree-ssanames.h" -#include "expmed.h" -#include "optabs.h" -#include "emit-rtl.h" -#include "recog.h" #include "diagnostic-core.h" -#include "alias.h" #include "fold-const.h" -#include "fold-const-call.h" -#include "gimple-ssa-warn-restrict.h" -#include "stor-layout.h" -#include "calls.h" -#include "varasm.h" #include "tree-object-size.h" #include "tree-ssa-strlen.h" -#include "realmpfr.h" -#include "cfgrtl.h" -#include "except.h" -#include "dojump.h" -#include "explow.h" -#include "stmt.h" -#include "expr.h" -#include "libfuncs.h" -#include "output.h" -#include "typeclass.h" #include "langhooks.h" -#include "value-prof.h" -#include "builtins.h" #include "stringpool.h" #include "attribs.h" -#include "asan.h" -#include "internal-fn.h" -#include "case-cfn-macros.h" #include "gimple-fold.h" #include "intl.h" -#include "tree-dfa.h" -#include "gimple-iterator.h" -#include "gimple-ssa.h" -#include "tree-ssa-live.h" -#include "tree-outof-ssa.h" #include "attr-fnspec.h" #include "gimple-range.h" - #include "pointer-query.h" static bool compute_objsize_r (tree, int, access_ref *, ssa_name_limit_t &, @@ -311,6 +274,164 @@ gimple_call_return_array (gimple *stmt, offset_int offrng[2], bool *past_end, return NULL_TREE; } +/* Return true when EXP's range can be determined and set RANGE[] to it + after adjusting it if necessary to make EXP a represents a valid size + of object, or a valid size argument to an allocation function declared + with attribute alloc_size (whose argument may be signed), or to a string + manipulation function like memset. + When ALLOW_ZERO is set in FLAGS, allow returning a range of [0, 0] for + a size in an anti-range [1, N] where N > PTRDIFF_MAX. A zero range is + a (nearly) invalid argument to allocation functions like malloc but it + is a valid argument to functions like memset. + When USE_LARGEST is set in FLAGS set RANGE to the largest valid subrange + in a multi-range, otherwise to the smallest valid subrange. */ + +bool +get_size_range (range_query *query, tree exp, gimple *stmt, tree range[2], + int flags /* = 0 */) +{ + if (!exp) + return false; + + if (tree_fits_uhwi_p (exp)) + { + /* EXP is a constant. */ + range[0] = range[1] = exp; + return true; + } + + tree exptype = TREE_TYPE (exp); + bool integral = INTEGRAL_TYPE_P (exptype); + + wide_int min, max; + enum value_range_kind range_type; + + if (!query) + query = get_global_range_query (); + + if (integral) + { + value_range vr; + + query->range_of_expr (vr, exp, stmt); + + if (vr.undefined_p ()) + vr.set_varying (TREE_TYPE (exp)); + range_type = vr.kind (); + min = wi::to_wide (vr.min ()); + max = wi::to_wide (vr.max ()); + } + else + range_type = VR_VARYING; + + if (range_type == VR_VARYING) + { + if (integral) + { + /* Use the full range of the type of the expression when + no value range information is available. */ + range[0] = TYPE_MIN_VALUE (exptype); + range[1] = TYPE_MAX_VALUE (exptype); + return true; + } + + range[0] = NULL_TREE; + range[1] = NULL_TREE; + return false; + } + + unsigned expprec = TYPE_PRECISION (exptype); + + bool signed_p = !TYPE_UNSIGNED (exptype); + + if (range_type == VR_ANTI_RANGE) + { + if (signed_p) + { + if (wi::les_p (max, 0)) + { + /* EXP is not in a strictly negative range. That means + it must be in some (not necessarily strictly) positive + range which includes zero. Since in signed to unsigned + conversions negative values end up converted to large + positive values, and otherwise they are not valid sizes, + the resulting range is in both cases [0, TYPE_MAX]. */ + min = wi::zero (expprec); + max = wi::to_wide (TYPE_MAX_VALUE (exptype)); + } + else if (wi::les_p (min - 1, 0)) + { + /* EXP is not in a negative-positive range. That means EXP + is either negative, or greater than max. Since negative + sizes are invalid make the range [MAX + 1, TYPE_MAX]. */ + min = max + 1; + max = wi::to_wide (TYPE_MAX_VALUE (exptype)); + } + else + { + max = min - 1; + min = wi::zero (expprec); + } + } + else + { + wide_int maxsize = wi::to_wide (max_object_size ()); + min = wide_int::from (min, maxsize.get_precision (), UNSIGNED); + max = wide_int::from (max, maxsize.get_precision (), UNSIGNED); + if (wi::eq_p (0, min - 1)) + { + /* EXP is unsigned and not in the range [1, MAX]. That means + it's either zero or greater than MAX. Even though 0 would + normally be detected by -Walloc-zero, unless ALLOW_ZERO + is set, set the range to [MAX, TYPE_MAX] so that when MAX + is greater than the limit the whole range is diagnosed. */ + wide_int maxsize = wi::to_wide (max_object_size ()); + if (flags & SR_ALLOW_ZERO) + { + if (wi::leu_p (maxsize, max + 1) + || !(flags & SR_USE_LARGEST)) + min = max = wi::zero (expprec); + else + { + min = max + 1; + max = wi::to_wide (TYPE_MAX_VALUE (exptype)); + } + } + else + { + min = max + 1; + max = wi::to_wide (TYPE_MAX_VALUE (exptype)); + } + } + else if ((flags & SR_USE_LARGEST) + && wi::ltu_p (max + 1, maxsize)) + { + /* When USE_LARGEST is set and the larger of the two subranges + is a valid size, use it... */ + min = max + 1; + max = maxsize; + } + else + { + /* ...otherwise use the smaller subrange. */ + max = min - 1; + min = wi::zero (expprec); + } + } + } + + range[0] = wide_int_to_tree (exptype, min); + range[1] = wide_int_to_tree (exptype, max); + + return true; +} + +bool +get_size_range (tree exp, tree range[2], int flags /* = 0 */) +{ + return get_size_range (/*query=*/NULL, exp, /*stmt=*/NULL, range, flags); +} + /* If STMT is a call to an allocation function, returns the constant maximum size of the object allocated by the call represented as sizetype. If nonnull, sets RNG1[] to the range of the size. diff --git a/gcc/pointer-query.h b/gcc/pointer-query.h index 8bd538a..eb7e90d 100644 --- a/gcc/pointer-query.h +++ b/gcc/pointer-query.h @@ -230,6 +230,17 @@ struct access_data access_mode mode; }; +enum size_range_flags + { + /* Set to consider zero a valid range. */ + SR_ALLOW_ZERO = 1, + /* Set to use the largest subrange of a set of ranges as opposed + to the smallest. */ + SR_USE_LARGEST = 2 + }; +extern bool get_size_range (tree, tree[2], int = 0); +extern bool get_size_range (range_query *, tree, gimple *, tree[2], int = 0); + class range_query; extern tree gimple_call_alloc_size (gimple *, wide_int[2] = NULL, range_query * = NULL); diff --git a/gcc/testsuite/gcc.dg/Wstringop-overflow-72.c b/gcc/testsuite/gcc.dg/Wstringop-overflow-72.c new file mode 100644 index 0000000..c10773e --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wstringop-overflow-72.c @@ -0,0 +1,13 @@ +/* PR middle-end/101854 - Invalid warning -Wstringop-overflow wrong argument + { dg-do compile } + { dg-options "-O2 -Wall" } */ + +struct A { int a[5]; }; + +struct A g (int*, int[6][8]); + +struct A f (void) +{ + int a[2]; + return g (a, 0); // { dg-bogus "-Wstringop-overflow" } +} diff --git a/gcc/testsuite/gcc.dg/attr-alloc_size-5.c b/gcc/testsuite/gcc.dg/attr-alloc_size-5.c index 7aa7cbf..4eea625 100644 --- a/gcc/testsuite/gcc.dg/attr-alloc_size-5.c +++ b/gcc/testsuite/gcc.dg/attr-alloc_size-5.c @@ -4,7 +4,7 @@ zero bytes. For standard allocation functions the return value is implementation-defined and so relying on it may be a source of bugs. */ /* { dg-do compile } */ -/* { dg-options "-O2 -Wall -Walloc-zero" } */ +/* { dg-options "-O1 -Wall -Walloc-zero" } */ #define SCHAR_MAX __SCHAR_MAX__ #define SCHAR_MIN (-SCHAR_MAX - 1) diff --git a/gcc/testsuite/gcc.dg/attr-alloc_size-7.c b/gcc/testsuite/gcc.dg/attr-alloc_size-7.c index 68602ec..3adde5c 100644 --- a/gcc/testsuite/gcc.dg/attr-alloc_size-7.c +++ b/gcc/testsuite/gcc.dg/attr-alloc_size-7.c @@ -4,7 +4,7 @@ of the maximum specified by -Walloc-size-larger-than=maximum. */ /* { dg-do compile } */ /* { dg-require-effective-target alloca } */ -/* { dg-options "-O2 -Wall -Walloc-size-larger-than=12345" } */ +/* { dg-options "-O1 -Wall -Walloc-size-larger-than=12345" } */ #define SIZE_MAX __SIZE_MAX__ #define MAXOBJSZ 12345 @@ -13,15 +13,40 @@ typedef __SIZE_TYPE__ size_t; void sink (void*); -static size_t maxobjsize (void) +#pragma GCC push_options +/* Verify that constant evaluation takes place even at -O0. */ +#pragma GCC optimize ("0") + +void test_cst (void *p) { - return MAXOBJSZ; + enum { max = MAXOBJSZ }; + + sink (__builtin_aligned_alloc (1, max)); + sink (__builtin_aligned_alloc (1, max + 1)); /* { dg-warning "argument 2 value .12346\[lu\]*. exceeds maximum object size 12345" } */ + + sink (__builtin_alloca (max)); + sink (__builtin_alloca (max + 2)); /* { dg-warning "argument 1 value .12347\[lu\]*. exceeds maximum object size 12345" } */ + + sink (__builtin_calloc (1, max)); + sink (__builtin_calloc (max, 1)); + + sink (__builtin_calloc (max / 2, 3)); /* { dg-warning "product .6172\[lu\]* \\* 3\[lu\]*. of arguments 1 and 2 exceeds maximum object size 12345" } */ + sink (__builtin_calloc (4, max / 3)); /* { dg-warning "product .4\[lu\]* \\* 4115\[lu\]*. of arguments 1 and 2 exceeds maximum object size 12345" } */ + + sink (__builtin_malloc (max)); + sink (__builtin_malloc (max + 3)); /* { dg-warning "argument 1 value .12348\[lu\]*. exceeds maximum object size 12345" } */ + + sink (__builtin_realloc (p, max)); + sink (__builtin_realloc (p, max + 4)); /* { dg-warning "argument 2 value .12349\[lu\]*. exceeds maximum object size 12345" } */ } -void test_var (void *p) +/* Variable evaluation needs -O1. */ +#pragma GCC pop_options + +__attribute__ ((noipa)) void test_var (void *p) { - size_t max = maxobjsize (); + size_t max = MAXOBJSZ; sink (__builtin_aligned_alloc (1, max)); sink (__builtin_aligned_alloc (1, max + 1)); /* { dg-warning "argument 2 value .12346\[lu\]*. exceeds maximum object size 12345" } */ @@ -43,7 +68,15 @@ void test_var (void *p) } -void test_range (void *p, size_t range) +/* Value range evaluation (apparently) needs -O2 here. */ +#pragma GCC optimize ("2") + +static size_t maxobjsize (void) +{ + return MAXOBJSZ; +} + +__attribute__ ((noipa)) void test_range (void *p, size_t range) { /* Make sure the variable is at least as large as the maximum object size but also make sure that it's guaranteed not to be too big to diff --git a/gcc/testsuite/gcc.dg/attr-alloc_size-8.c b/gcc/testsuite/gcc.dg/attr-alloc_size-8.c index 91d7eb5..7b47b04 100644 --- a/gcc/testsuite/gcc.dg/attr-alloc_size-8.c +++ b/gcc/testsuite/gcc.dg/attr-alloc_size-8.c @@ -4,7 +4,7 @@ two more specific options override the more general latter option. */ /* { dg-do compile } */ /* { dg-require-effective-target alloca } */ -/* { dg-options "-O2 -Walloc-size-larger-than=123 -Walloca-larger-than=234 -Wvla-larger-than=345" } */ +/* { dg-options "-O -Walloc-size-larger-than=123 -Walloca-larger-than=234 -Wvla-larger-than=345" } */ typedef __SIZE_TYPE__ size_t; diff --git a/gcc/tree.c b/gcc/tree.c index 6ec8a97..cba3bca 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -14464,6 +14464,60 @@ fndecl_dealloc_argno (tree fndecl) return UINT_MAX; } +/* If EXPR refers to a character array or pointer declared attribute + nonstring, return a decl for that array or pointer and set *REF + to the referenced enclosing object or pointer. Otherwise return + null. */ + +tree +get_attr_nonstring_decl (tree expr, tree *ref) +{ + tree decl = expr; + tree var = NULL_TREE; + if (TREE_CODE (decl) == SSA_NAME) + { + gimple *def = SSA_NAME_DEF_STMT (decl); + + if (is_gimple_assign (def)) + { + tree_code code = gimple_assign_rhs_code (def); + if (code == ADDR_EXPR + || code == COMPONENT_REF + || code == VAR_DECL) + decl = gimple_assign_rhs1 (def); + } + else + var = SSA_NAME_VAR (decl); + } + + if (TREE_CODE (decl) == ADDR_EXPR) + decl = TREE_OPERAND (decl, 0); + + /* To simplify calling code, store the referenced DECL regardless of + the attribute determined below, but avoid storing the SSA_NAME_VAR + obtained above (it's not useful for dataflow purposes). */ + if (ref) + *ref = decl; + + /* Use the SSA_NAME_VAR that was determined above to see if it's + declared nonstring. Otherwise drill down into the referenced + DECL. */ + if (var) + decl = var; + else if (TREE_CODE (decl) == ARRAY_REF) + decl = TREE_OPERAND (decl, 0); + else if (TREE_CODE (decl) == COMPONENT_REF) + decl = TREE_OPERAND (decl, 1); + else if (TREE_CODE (decl) == MEM_REF) + return get_attr_nonstring_decl (TREE_OPERAND (decl, 0), ref); + + if (DECL_P (decl) + && lookup_attribute ("nonstring", DECL_ATTRIBUTES (decl))) + return decl; + + return NULL_TREE; +} + #if CHECKING_P namespace selftest { diff --git a/gcc/tree.h b/gcc/tree.h index 78d8a04..905417f 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -6488,4 +6488,10 @@ extern void copy_warning (tree, const_tree); value if it isn't. */ extern unsigned fndecl_dealloc_argno (tree); +/* If an expression refers to a character array or pointer declared + attribute nonstring, return a decl for that array or pointer and + if nonnull, set the second argument to the referenced enclosing + object or pointer. Otherwise return null. */ +extern tree get_attr_nonstring_decl (tree, tree * = NULL); + #endif /* GCC_TREE_H */ -- cgit v1.1 From e68c8280fa2e1b7071378cfdd876155c73ec944f Mon Sep 17 00:00:00 2001 From: Andrew MacLeod Date: Fri, 30 Jul 2021 15:15:29 -0400 Subject: Abstract tracing routines into a class. Generalize range tracing into a class and integrae it with gimple_ranger. Remove the old derived trace_ranger class. * Makefile.in (OBJS): Add gimple-range-trace.o. * gimple-range-cache.h (enable_new_values): Remove unused prototype. * gimple-range-fold.cc: Adjust headers. * gimple-range-trace.cc: New. * gimple-range-trace.h: New. * gimple-range.cc (gimple_ranger::gimple_ranger): Enable tracer. (gimple_ranger::range_of_expr): Add tracing. (gimple_ranger::range_on_entry): Ditto. (gimple_ranger::range_on_exit): Ditto. (gimple_ranger::range_on_edge): Ditto. (gimple_ranger::fold_range_internal): Ditto. (gimple_ranger::dump_bb): Do not calculate edge range twice. (trace_ranger::*): Remove. (enable_ranger): Never create a trace_ranger. (debug_seed_ranger): Move to gimple-range-trace.cc. (dump_ranger): Ditto. (debug_ranger): Ditto. * gimple-range.h: Include gimple-range-trace.h. (range_on_entry, range_on_exit): No longer virtual. (class trace_ranger): Remove. (DEBUG_RANGE_CACHE): Move to gimple-range-trace.h. --- gcc/Makefile.in | 1 + gcc/gimple-range-cache.h | 1 - gcc/gimple-range-fold.cc | 4 +- gcc/gimple-range-trace.cc | 206 ++++++++++++++++++++++++ gcc/gimple-range-trace.h | 64 ++++++++ gcc/gimple-range.cc | 393 ++++++++++++---------------------------------- gcc/gimple-range.h | 34 +--- 7 files changed, 377 insertions(+), 326 deletions(-) create mode 100644 gcc/gimple-range-trace.cc create mode 100644 gcc/gimple-range-trace.h (limited to 'gcc') diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 6653e9e..9714fca 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1406,6 +1406,7 @@ OBJS = \ gimple-range-edge.o \ gimple-range-fold.o \ gimple-range-gori.o \ + gimple-range-trace.o \ gimple-ssa-backprop.o \ gimple-ssa-evrp.o \ gimple-ssa-evrp-analyze.o \ diff --git a/gcc/gimple-range-cache.h b/gcc/gimple-range-cache.h index 1e77c9b..3b55673 100644 --- a/gcc/gimple-range-cache.h +++ b/gcc/gimple-range-cache.h @@ -103,7 +103,6 @@ public: bool get_non_stale_global_range (irange &r, tree name); void set_global_range (tree name, const irange &r); - bool enable_new_values (bool state); non_null_ref m_non_null; gori_compute m_gori; diff --git a/gcc/gimple-range-fold.cc b/gcc/gimple-range-fold.cc index d3e3e14..94dd042 100644 --- a/gcc/gimple-range-fold.cc +++ b/gcc/gimple-range-fold.cc @@ -42,9 +42,7 @@ along with GCC; see the file COPYING3. If not see #include "range.h" #include "value-query.h" #include "range-op.h" -#include "gimple-range-fold.h" -#include "gimple-range-edge.h" -#include "gimple-range-gori.h" +#include "gimple-range.h" // Construct a fur_source, and set the m_query field. fur_source::fur_source (range_query *q) diff --git a/gcc/gimple-range-trace.cc b/gcc/gimple-range-trace.cc new file mode 100644 index 0000000..1feb978 --- /dev/null +++ b/gcc/gimple-range-trace.cc @@ -0,0 +1,206 @@ +/* Code for GIMPLE range trace and debugging related routines. + Copyright (C) 2019-2021 Free Software Foundation, Inc. + Contributed by Andrew MacLeod + and Aldy Hernandez . + +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 +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "backend.h" +#include "tree.h" +#include "gimple.h" +#include "ssa.h" +#include "gimple-pretty-print.h" +#include "gimple-iterator.h" +#include "tree-cfg.h" +#include "fold-const.h" +#include "tree-cfg.h" +#include "cfgloop.h" +#include "tree-scalar-evolution.h" +#include "gimple-range.h" + + +// Breakpoint to trap at a specific index. From GDB, this provides a simple +// place to put a breakpoint to stop at a given trace line. +// ie. b range_tracer::breakpoint if index == 45678 + +void +range_tracer::breakpoint (unsigned index ATTRIBUTE_UNUSED) +{ +} + +// Construct a range_tracer with component NAME. + +range_tracer::range_tracer (const char *name) +{ + gcc_checking_assert (strlen(name) < name_len -1); + strcpy (component, name); + indent = 0; + tracing = false; +} + +// This routine does the initial line spacing/indenting for a trace. +// If BLANKS is false, then IDX is printed, otherwise spaces. + +void +range_tracer::print_prefix (unsigned idx, bool blanks) +{ + // Print counter index as well as INDENT spaces. + if (!blanks) + fprintf (dump_file, "%-7u ", idx); + else + fprintf (dump_file, " "); + fprintf (dump_file, "%s ", component); + unsigned x; + for (x = 0; x< indent; x++) + fputc (' ', dump_file); + +} +// If dumping, return the next call index and print the prefix for the next +// output line. If not, retrurn 0. +// Counter is static to monotonically increase across the compilation unit. + +unsigned +range_tracer::do_header (const char *str) +{ + static unsigned trace_count = 0; + + unsigned idx = ++trace_count; + print_prefix (idx, false); + fprintf (dump_file, "%s", str); + indent += bump; + breakpoint (idx); + return idx; +} + +// Print a line without starting or ending a trace. + +void +range_tracer::print (unsigned counter, const char *str) +{ + print_prefix (counter, true); + fprintf (dump_file, "%s", str); +} + +// End a trace and print the CALLER, NAME, and RESULT and range R, + +void +range_tracer::trailer (unsigned counter, const char *caller, bool result, + tree name, const irange &r) +{ + gcc_checking_assert (tracing && counter != 0); + + indent -= bump; + print_prefix (counter, true); + fputs(result ? "TRUE : " : "FALSE : ", dump_file); + fprintf (dump_file, "(%u) ", counter); + fputs (caller, dump_file); + fputs (" (",dump_file); + if (name) + print_generic_expr (dump_file, name, TDF_SLIM); + fputs (") ",dump_file); + if (result) + { + r.dump (dump_file); + fputc('\n', dump_file); + } + else + fputc('\n', dump_file); +} + +// ========================================= +// Debugging helpers. +// ========================================= + +// Query all statements in the IL to precalculate computable ranges in RANGER. + +static DEBUG_FUNCTION void +debug_seed_ranger (gimple_ranger &ranger) +{ + // Recalculate SCEV to make sure the dump lists everything. + if (scev_initialized_p ()) + { + scev_finalize (); + scev_initialize (); + } + + basic_block bb; + int_range_max r; + gimple_stmt_iterator gsi; + FOR_EACH_BB_FN (bb, cfun) + for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) + { + gimple *stmt = gsi_stmt (gsi); + + if (is_gimple_debug (stmt)) + continue; + + ranger.range_of_stmt (r, stmt); + } +} + +// Dump all that ranger knows for the current function. + +DEBUG_FUNCTION void +dump_ranger (FILE *out) +{ + gimple_ranger ranger; + debug_seed_ranger (ranger); + ranger.dump (out); +} + +DEBUG_FUNCTION void +debug_ranger () +{ + dump_ranger (stderr); +} + +// Dump all that ranger knows on a path of BBs. +// +// Note that the blocks are in reverse order, thus the exit block is +// path[0]. + +DEBUG_FUNCTION void +dump_ranger (FILE *dump_file, const vec &path) +{ + if (path.length () == 0) + { + fprintf (dump_file, "empty\n"); + return; + } + + gimple_ranger ranger; + debug_seed_ranger (ranger); + + unsigned i = path.length (); + do + { + i--; + ranger.dump_bb (dump_file, path[i]); + } + while (i > 0); +} + +DEBUG_FUNCTION void +debug_ranger (const vec &path) +{ + dump_ranger (stderr, path); +} + +#include "gimple-range-tests.cc" diff --git a/gcc/gimple-range-trace.h b/gcc/gimple-range-trace.h new file mode 100644 index 0000000..6f89fcc --- /dev/null +++ b/gcc/gimple-range-trace.h @@ -0,0 +1,64 @@ +/* Header file for the GIMPLE range tracing/debugging facilties. + Copyright (C) 2021 Free Software Foundation, Inc. + Contributed by Andrew MacLeod + and Aldy Hernandez . + +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 +. */ + +#ifndef GCC_GIMPLE_RANGE_TRACE_H +#define GCC_GIMPLE_RANGE_TRACE_H + +// This class manages range tracing for the ranger and gori components. +// Tracing will provide a unique integer index whenever a new trace +// is started. This can be used to identify where a calculation has gone wrong. + +class range_tracer +{ +public: + range_tracer (const char *name = ""); + unsigned header (const char *str); + void trailer (unsigned counter, const char *caller, bool result, tree name, + const irange &r); + void print (unsigned counter, const char *str); + inline void enable_trace () { tracing = true; } + inline void disable_trace () { tracing = false; } + virtual void breakpoint (unsigned index); +private: + unsigned do_header (const char *str); + void print_prefix (unsigned idx, bool blanks); + static const unsigned bump = 2; + unsigned indent; + static const unsigned name_len = 100; + char component[name_len]; + bool tracing; +}; + + +// If tracing is enabled, start a new trace header, returning the trace index. +// Otherwise return 0. + +inline unsigned +range_tracer::header (const char *str) +{ + if (tracing) + return do_header (str); + return 0; +} + +#define DEBUG_RANGE_CACHE (dump_file && (param_evrp_mode & EVRP_MODE_DEBUG)) + +#endif // GCC_GIMPLE_RANGE_TRACE_H diff --git a/gcc/gimple-range.cc b/gcc/gimple-range.cc index b210787..60b7d3a 100644 --- a/gcc/gimple-range.cc +++ b/gcc/gimple-range.cc @@ -35,46 +35,61 @@ along with GCC; see the file COPYING3. If not see #include "tree-scalar-evolution.h" #include "gimple-range.h" -gimple_ranger::gimple_ranger () +gimple_ranger::gimple_ranger () : tracer ("") { // If the cache has a relation oracle, use it. m_oracle = m_cache.oracle (); + if (dump_file && (param_evrp_mode & EVRP_MODE_TRACE)) + tracer.enable_trace (); } bool gimple_ranger::range_of_expr (irange &r, tree expr, gimple *stmt) { + unsigned idx; if (!gimple_range_ssa_p (expr)) return get_tree_range (r, expr, stmt); + if ((idx = tracer.header ("range_of_expr("))) + { + print_generic_expr (dump_file, expr, TDF_SLIM); + fputs (")", dump_file); + if (stmt) + { + fputs (" at stmt ", dump_file); + print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM); + } + else + fputs ("\n", dump_file); + } + // If there is no statement, just get the global value. if (!stmt) { if (!m_cache.get_global_range (r, expr)) r = gimple_range_global (expr); - return true; } - // For a debug stmt, pick the best value currently available, do not // trigger new value calculations. PR 100781. - if (is_gimple_debug (stmt)) + else if (is_gimple_debug (stmt)) + m_cache.range_of_expr (r, expr, stmt); + else { - m_cache.range_of_expr (r, expr, stmt); - return true; - } - basic_block bb = gimple_bb (stmt); - gimple *def_stmt = SSA_NAME_DEF_STMT (expr); + basic_block bb = gimple_bb (stmt); + gimple *def_stmt = SSA_NAME_DEF_STMT (expr); - // If name is defined in this block, try to get an range from S. - if (def_stmt && gimple_bb (def_stmt) == bb) - { - range_of_stmt (r, def_stmt, expr); - m_cache.m_non_null.adjust_range (r, expr, bb, true); + // If name is defined in this block, try to get an range from S. + if (def_stmt && gimple_bb (def_stmt) == bb) + { + range_of_stmt (r, def_stmt, expr); + m_cache.m_non_null.adjust_range (r, expr, bb, true); + } + // Otherwise OP comes from outside this block, use range on entry. + else + range_on_entry (r, bb, expr); } - else - // Otherwise OP comes from outside this block, use range on entry. - range_on_entry (r, bb, expr); - + if (idx) + tracer.trailer (idx, "range_of_expr", true, expr, r); return true; } @@ -86,6 +101,13 @@ gimple_ranger::range_on_entry (irange &r, basic_block bb, tree name) int_range_max entry_range; gcc_checking_assert (gimple_range_ssa_p (name)); + unsigned idx; + if ((idx = tracer.header ("range_on_entry ("))) + { + print_generic_expr (dump_file, name, TDF_SLIM); + fprintf (dump_file, ") to BB %d\n", bb->index); + } + // Start with any known range range_of_stmt (r, SSA_NAME_DEF_STMT (name), name); @@ -94,6 +116,9 @@ gimple_ranger::range_on_entry (irange &r, basic_block bb, tree name) r.intersect (entry_range); m_cache.m_non_null.adjust_range (r, name, bb, true); + + if (idx) + tracer.trailer (idx, "range_on_entry", true, name, r); } // Calculate the range for NAME at the end of block BB and return it in R. @@ -106,6 +131,13 @@ gimple_ranger::range_on_exit (irange &r, basic_block bb, tree name) gcc_checking_assert (bb != EXIT_BLOCK_PTR_FOR_FN (cfun)); gcc_checking_assert (gimple_range_ssa_p (name)); + unsigned idx; + if ((idx = tracer.header ("range_on_exit ("))) + { + print_generic_expr (dump_file, name, TDF_SLIM); + fprintf (dump_file, ") from BB %d\n", bb->index); + } + gimple *s = SSA_NAME_DEF_STMT (name); basic_block def_bb = gimple_bb (s); // If this is not the definition block, get the range on the last stmt in @@ -119,6 +151,9 @@ gimple_ranger::range_on_exit (irange &r, basic_block bb, tree name) range_on_entry (r, bb, name); gcc_checking_assert (r.undefined_p () || range_compatible_p (r.type (), TREE_TYPE (name))); + + if (idx) + tracer.trailer (idx, "range_on_exit", true, name, r); } // Calculate a range for NAME on edge E and return it in R. @@ -133,6 +168,13 @@ gimple_ranger::range_on_edge (irange &r, edge e, tree name) if (!gimple_range_ssa_p (name)) return range_of_expr (r, name); + unsigned idx; + if ((idx = tracer.header ("range_on_edge ("))) + { + print_generic_expr (dump_file, name, TDF_SLIM); + fprintf (dump_file, ") on edge %d->%d\n", e->src->index, e->dest->index); + } + range_on_exit (r, e->src, name); gcc_checking_assert (r.undefined_p () || range_compatible_p (r.type(), TREE_TYPE (name))); @@ -141,6 +183,8 @@ gimple_ranger::range_on_edge (irange &r, edge e, tree name) if (m_cache.range_on_edge (edge_range, e, name)) r.intersect (edge_range); + if (idx) + tracer.trailer (idx, "range_on_edge", true, name, r); return true; } @@ -163,33 +207,50 @@ gimple_ranger::fold_range_internal (irange &r, gimple *s, tree name) bool gimple_ranger::range_of_stmt (irange &r, gimple *s, tree name) { + bool res; r.set_undefined (); + unsigned idx; + if ((idx = tracer.header ("range_of_stmt ("))) + { + if (name) + print_generic_expr (dump_file, name, TDF_SLIM); + fputs (") at stmt ", dump_file); + print_gimple_stmt (dump_file, s, 0, TDF_SLIM); + } + if (!name) name = gimple_get_lhs (s); // If no name, simply call the base routine. if (!name) - return fold_range_internal (r, s, NULL_TREE); - - if (!gimple_range_ssa_p (name)) - return false; - + res = fold_range_internal (r, s, NULL_TREE); + else if (!gimple_range_ssa_p (name)) + res = false; // Check if the stmt has already been processed, and is not stale. - if (m_cache.get_non_stale_global_range (r, name)) - return true; - - // Otherwise calculate a new value. - int_range_max tmp; - fold_range_internal (tmp, s, name); - - // Combine the new value with the old value. This is required because - // the way value propagation works, when the IL changes on the fly we - // can sometimes get different results. See PR 97741. - r.intersect (tmp); - m_cache.set_global_range (name, r); + else if (m_cache.get_non_stale_global_range (r, name)) + { + if (idx) + tracer.trailer (idx, " cached", true, name, r); + return true; + } + else + { + // Otherwise calculate a new value. + int_range_max tmp; + fold_range_internal (tmp, s, name); + + // Combine the new value with the old value. This is required because + // the way value propagation works, when the IL changes on the fly we + // can sometimes get different results. See PR 97741. + r.intersect (tmp); + m_cache.set_global_range (name, r); + res = true; + } - return true; + if (idx) + tracer.trailer (idx, "range_of_stmt", res, name, r); + return res; } // This routine will export whatever global ranges are known to GCC @@ -243,7 +304,7 @@ gimple_ranger::dump_bb (FILE *f, basic_block bb) unsigned x; edge_iterator ei; edge e; - int_range_max range; + int_range_max range, tmp_range; fprintf (f, "\n=========== BB %d ============\n", bb->index); m_cache.dump_bb (f, bb); @@ -282,10 +343,9 @@ gimple_ranger::dump_bb (FILE *f, basic_block bb) // the on entry cache for either end of the edge is // set. if ((s && bb == gimple_bb (s)) || - m_cache.block_range (range, bb, name, false) || - m_cache.block_range (range, e->dest, name, false)) + m_cache.block_range (tmp_range, bb, name, false) || + m_cache.block_range (tmp_range, e->dest, name, false)) { - m_cache.range_on_edge (range, e, name); if (!range.varying_p ()) { fprintf (f, "%d->%d ", e->src->index, @@ -321,182 +381,12 @@ gimple_ranger::dump (FILE *f) m_cache.dump (f); } -// trace_ranger implementation. - - -trace_ranger::trace_ranger () -{ - indent = 0; - trace_count = 0; -} - -// If dumping, return true and print the prefix for the next output line. - -bool -trace_ranger::dumping (unsigned counter, bool trailing) -{ - if (dump_file && (dump_flags & TDF_DETAILS)) - { - // Print counter index as well as INDENT spaces. - if (!trailing) - fprintf (dump_file, " %-7u ", counter); - else - fprintf (dump_file, " "); - unsigned x; - for (x = 0; x< indent; x++) - fputc (' ', dump_file); - return true; - } - return false; -} - -// After calling a routine, if dumping, print the CALLER, NAME, and RESULT, -// returning RESULT. - -bool -trace_ranger::trailer (unsigned counter, const char *caller, bool result, - tree name, const irange &r) -{ - if (dumping (counter, true)) - { - indent -= bump; - fputs(result ? "TRUE : " : "FALSE : ", dump_file); - fprintf (dump_file, "(%u) ", counter); - fputs (caller, dump_file); - fputs (" (",dump_file); - if (name) - print_generic_expr (dump_file, name, TDF_SLIM); - fputs (") ",dump_file); - if (result) - { - r.dump (dump_file); - fputc('\n', dump_file); - } - else - fputc('\n', dump_file); - // Marks the end of a request. - if (indent == 0) - fputc('\n', dump_file); - } - return result; -} - -// Tracing version of range_on_edge. Call it with printing wrappers. - -bool -trace_ranger::range_on_edge (irange &r, edge e, tree name) -{ - unsigned idx = ++trace_count; - if (dumping (idx)) - { - fprintf (dump_file, "range_on_edge ("); - print_generic_expr (dump_file, name, TDF_SLIM); - fprintf (dump_file, ") on edge %d->%d\n", e->src->index, e->dest->index); - indent += bump; - } - - bool res = gimple_ranger::range_on_edge (r, e, name); - trailer (idx, "range_on_edge", true, name, r); - return res; -} - -// Tracing version of range_on_entry. Call it with printing wrappers. - -void -trace_ranger::range_on_entry (irange &r, basic_block bb, tree name) -{ - unsigned idx = ++trace_count; - if (dumping (idx)) - { - fprintf (dump_file, "range_on_entry ("); - print_generic_expr (dump_file, name, TDF_SLIM); - fprintf (dump_file, ") to BB %d\n", bb->index); - indent += bump; - } - - gimple_ranger::range_on_entry (r, bb, name); - - trailer (idx, "range_on_entry", true, name, r); -} - -// Tracing version of range_on_exit. Call it with printing wrappers. - -void -trace_ranger::range_on_exit (irange &r, basic_block bb, tree name) -{ - unsigned idx = ++trace_count; - if (dumping (idx)) - { - fprintf (dump_file, "range_on_exit ("); - print_generic_expr (dump_file, name, TDF_SLIM); - fprintf (dump_file, ") from BB %d\n", bb->index); - indent += bump; - } - - gimple_ranger::range_on_exit (r, bb, name); - - trailer (idx, "range_on_exit", true, name, r); -} - -// Tracing version of range_of_stmt. Call it with printing wrappers. - -bool -trace_ranger::range_of_stmt (irange &r, gimple *s, tree name) -{ - bool res; - unsigned idx = ++trace_count; - if (dumping (idx)) - { - fprintf (dump_file, "range_of_stmt ("); - if (name) - print_generic_expr (dump_file, name, TDF_SLIM); - fputs (") at stmt ", dump_file); - print_gimple_stmt (dump_file, s, 0, TDF_SLIM); - indent += bump; - } - - res = gimple_ranger::range_of_stmt (r, s, name); - - return trailer (idx, "range_of_stmt", res, name, r); -} - -// Tracing version of range_of_expr. Call it with printing wrappers. - -bool -trace_ranger::range_of_expr (irange &r, tree name, gimple *s) -{ - bool res; - unsigned idx = ++trace_count; - if (dumping (idx)) - { - fprintf (dump_file, "range_of_expr("); - print_generic_expr (dump_file, name, TDF_SLIM); - fputs (")", dump_file); - if (s) - { - fputs (" at stmt ", dump_file); - print_gimple_stmt (dump_file, s, 0, TDF_SLIM); - } - else - fputs ("\n", dump_file); - indent += bump; - } - - res = gimple_ranger::range_of_expr (r, name, s); - - return trailer (idx, "range_of_expr", res, name, r); -} - gimple_ranger * enable_ranger (struct function *fun) { gimple_ranger *r; - if (param_evrp_mode & EVRP_MODE_TRACE) - r = new trace_ranger; - else - r = new gimple_ranger; - + r = new gimple_ranger; fun->x_range_query = r; return r; @@ -509,84 +399,3 @@ disable_ranger (struct function *fun) fun->x_range_query = &global_ranges; } - -// ========================================= -// Debugging helpers. -// ========================================= - -// Query all statements in the IL to precalculate computable ranges in RANGER. - -static DEBUG_FUNCTION void -debug_seed_ranger (gimple_ranger &ranger) -{ - // Recalculate SCEV to make sure the dump lists everything. - if (scev_initialized_p ()) - { - scev_finalize (); - scev_initialize (); - } - - basic_block bb; - int_range_max r; - gimple_stmt_iterator gsi; - FOR_EACH_BB_FN (bb, cfun) - for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) - { - gimple *stmt = gsi_stmt (gsi); - - if (is_gimple_debug (stmt)) - continue; - - ranger.range_of_stmt (r, stmt); - } -} - -// Dump all that ranger knows for the current function. - -DEBUG_FUNCTION void -dump_ranger (FILE *out) -{ - gimple_ranger ranger; - debug_seed_ranger (ranger); - ranger.dump (out); -} - -DEBUG_FUNCTION void -debug_ranger () -{ - dump_ranger (stderr); -} - -// Dump all that ranger knows on a path of BBs. -// -// Note that the blocks are in reverse order, thus the exit block is -// path[0]. - -DEBUG_FUNCTION void -dump_ranger (FILE *dump_file, const vec &path) -{ - if (path.length () == 0) - { - fprintf (dump_file, "empty\n"); - return; - } - - gimple_ranger ranger; - debug_seed_ranger (ranger); - - unsigned i = path.length (); - do - { - i--; - ranger.dump_bb (dump_file, path[i]); - } - while (i > 0); -} - -DEBUG_FUNCTION void -debug_ranger (const vec &path) -{ - dump_ranger (stderr, path); -} - -#include "gimple-range-tests.cc" diff --git a/gcc/gimple-range.h b/gcc/gimple-range.h index aa62039..41845b1 100644 --- a/gcc/gimple-range.h +++ b/gcc/gimple-range.h @@ -22,10 +22,10 @@ along with GCC; see the file COPYING3. If not see #ifndef GCC_GIMPLE_RANGE_H #define GCC_GIMPLE_RANGE_H - #include "range.h" #include "value-query.h" #include "range-op.h" +#include "gimple-range-trace.h" #include "gimple-range-edge.h" #include "gimple-range-fold.h" #include "gimple-range-gori.h" @@ -43,7 +43,6 @@ along with GCC; see the file COPYING3. If not see // type is not supported, then false is returned. Non-statement // related methods return whatever the current global value is. - class gimple_ranger : public range_query { public: @@ -51,8 +50,8 @@ public: virtual bool range_of_stmt (irange &r, gimple *, tree name = NULL) OVERRIDE; virtual bool range_of_expr (irange &r, tree name, gimple * = NULL) OVERRIDE; virtual bool range_on_edge (irange &r, edge e, tree name) OVERRIDE; - virtual void range_on_entry (irange &r, basic_block bb, tree name); - virtual void range_on_exit (irange &r, basic_block bb, tree name); + void range_on_entry (irange &r, basic_block bb, tree name); + void range_on_exit (irange &r, basic_block bb, tree name); void export_global_ranges (); inline gori_compute &gori () { return m_cache.m_gori; } virtual void dump (FILE *f) OVERRIDE; @@ -60,34 +59,9 @@ public: protected: bool fold_range_internal (irange &r, gimple *s, tree name); ranger_cache m_cache; + range_tracer tracer; }; - -// This class overloads the ranger routines to provide tracing facilties -// Entry and exit values to each of the APIs is placed in the dumpfile. - -class trace_ranger : public gimple_ranger -{ -public: - trace_ranger (); - virtual bool range_of_stmt (irange &r, gimple *s, tree name = NULL_TREE); - virtual bool range_of_expr (irange &r, tree name, gimple *s = NULL); - virtual bool range_on_edge (irange &r, edge e, tree name); - virtual void range_on_entry (irange &r, basic_block bb, tree name); - virtual void range_on_exit (irange &r, basic_block bb, tree name); -private: - static const unsigned bump = 2; - unsigned indent; - unsigned trace_count; // Current trace index count. - - bool dumping (unsigned counter, bool trailing = false); - bool trailer (unsigned counter, const char *caller, bool result, tree name, - const irange &r); -}; - -// Flag to enable debugging the various internal Caches. -#define DEBUG_RANGE_CACHE (dump_file && (param_evrp_mode & EVRP_MODE_DEBUG)) - extern gimple_ranger *enable_ranger (struct function *); extern void disable_ranger (struct function *); -- cgit v1.1 From 0bb74a28e1318cbac9c895f1079b384a42513a9c Mon Sep 17 00:00:00 2001 From: Andrew MacLeod Date: Thu, 12 Aug 2021 14:02:20 -0400 Subject: Change evrp-mode options. Remove tracing in hybrid mode. Add trace/gori/cache tracing options. tracing options are now 'trace', 'gori', 'cache', or all combined in 'debug' * flag-types.h (enum evrp_mode): Adjust evrp-mode values. * gimple-range-cache.cc (DEBUG_RANGE_CACHE): Relocate from. * gimple-range-trace.h (DEBUG_RANGE_CACHE): Here. * params.opt (--param=evrp-mode): Adjust options. --- gcc/flag-types.h | 11 ++++++----- gcc/gimple-range-cache.cc | 3 +++ gcc/gimple-range-trace.h | 3 --- gcc/params.opt | 11 +++++++---- 4 files changed, 16 insertions(+), 12 deletions(-) (limited to 'gcc') diff --git a/gcc/flag-types.h b/gcc/flag-types.h index e43d1de..4fb1cb4 100644 --- a/gcc/flag-types.h +++ b/gcc/flag-types.h @@ -444,14 +444,15 @@ enum parloops_schedule_type /* EVRP mode. */ enum evrp_mode { - EVRP_MODE_EVRP_FIRST = 0, + EVRP_MODE_RVRP_ONLY = 0, EVRP_MODE_EVRP_ONLY = 1, - EVRP_MODE_RVRP_ONLY = 2, + EVRP_MODE_EVRP_FIRST = 2, EVRP_MODE_RVRP_FIRST = 3, EVRP_MODE_TRACE = 4, - EVRP_MODE_DEBUG = 8 | EVRP_MODE_TRACE, - EVRP_MODE_RVRP_TRACE = EVRP_MODE_RVRP_ONLY | EVRP_MODE_TRACE, - EVRP_MODE_RVRP_DEBUG = EVRP_MODE_RVRP_ONLY | EVRP_MODE_DEBUG + EVRP_MODE_CACHE = (8 | EVRP_MODE_TRACE), + EVRP_MODE_GORI = 16, + EVRP_MODE_TRACE_GORI = (EVRP_MODE_TRACE | EVRP_MODE_GORI), + EVRP_MODE_DEBUG = (EVRP_MODE_GORI | EVRP_MODE_CACHE) }; /* Modes of OpenACC 'kernels' constructs handling. */ diff --git a/gcc/gimple-range-cache.cc b/gcc/gimple-range-cache.cc index 91541f1..4138d05 100644 --- a/gcc/gimple-range-cache.cc +++ b/gcc/gimple-range-cache.cc @@ -30,6 +30,9 @@ along with GCC; see the file COPYING3. If not see #include "gimple-range.h" #include "tree-cfg.h" +#define DEBUG_RANGE_CACHE (dump_file && (param_evrp_mode & EVRP_MODE_CACHE) \ + == EVRP_MODE_CACHE) + // During contructor, allocate the vector of ssa_names. non_null_ref::non_null_ref () diff --git a/gcc/gimple-range-trace.h b/gcc/gimple-range-trace.h index 6f89fcc..d2d1a8b 100644 --- a/gcc/gimple-range-trace.h +++ b/gcc/gimple-range-trace.h @@ -58,7 +58,4 @@ range_tracer::header (const char *str) return do_header (str); return 0; } - -#define DEBUG_RANGE_CACHE (dump_file && (param_evrp_mode & EVRP_MODE_DEBUG)) - #endif // GCC_GIMPLE_RANGE_TRACE_H diff --git a/gcc/params.opt b/gcc/params.opt index 92b003e..f926488 100644 --- a/gcc/params.opt +++ b/gcc/params.opt @@ -132,7 +132,7 @@ Maximum number of basic blocks before EVRP uses a sparse cache. -param=evrp-mode= Common Joined Var(param_evrp_mode) Enum(evrp_mode) Init(EVRP_MODE_RVRP_ONLY) Param Optimization ---param=evrp-mode=[legacy|ranger|legacy-first|ranger-first|ranger-trace|ranger-debug|trace|debug] Specifies the mode Early VRP should operate in. +--param=evrp-mode=[legacy|ranger|legacy-first|ranger-first|trace|gori|cache|tracegori|debug] Specifies the mode Early VRP should operate in. Enum Name(evrp_mode) Type(enum evrp_mode) UnknownError(unknown evrp mode %qs) @@ -150,13 +150,16 @@ EnumValue Enum(evrp_mode) String(ranger-first) Value(EVRP_MODE_RVRP_FIRST) EnumValue -Enum(evrp_mode) String(ranger-trace) Value(EVRP_MODE_RVRP_TRACE) +Enum(evrp_mode) String(trace) Value(EVRP_MODE_TRACE) EnumValue -Enum(evrp_mode) String(ranger-debug) Value(EVRP_MODE_RVRP_DEBUG) +Enum(evrp_mode) String(cache) Value(EVRP_MODE_CACHE) EnumValue -Enum(evrp_mode) String(trace) Value(EVRP_MODE_TRACE) +Enum(evrp_mode) String(gori) Value(EVRP_MODE_GORI) + +EnumValue +Enum(evrp_mode) String(tracegori) Value(EVRP_MODE_TRACE_GORI) EnumValue Enum(evrp_mode) String(debug) Value(EVRP_MODE_DEBUG) -- cgit v1.1 From 4759e1e0453bef163d8dbeebbb96dc40b049c117 Mon Sep 17 00:00:00 2001 From: Andrew MacLeod Date: Thu, 12 Aug 2021 12:29:48 -0400 Subject: Add GORI tracing faciltiies. Debugging range-ops and gori unwinding needed some help. * gimple-range-gori.cc (gori_compute::gori_compute): Enable tracing. (gori_compute::compute_operand_range): Add tracing. (gori_compute::logical_combine): Ditto. (gori_compute::compute_logical_operands): Ditto. (gori_compute::compute_operand1_range): Ditto. (gori_compute::compute_operand2_range): Ditto. (gori_compute::outgoing_edge_range_p): Ditto. * gimple-range-gori.h (class gori_compute): Add range_tracer. --- gcc/gimple-range-gori.cc | 172 ++++++++++++++++++++++++++++++++++++++++------- gcc/gimple-range-gori.h | 1 + 2 files changed, 149 insertions(+), 24 deletions(-) (limited to 'gcc') diff --git a/gcc/gimple-range-gori.cc b/gcc/gimple-range-gori.cc index c124b3c..f788295 100644 --- a/gcc/gimple-range-gori.cc +++ b/gcc/gimple-range-gori.cc @@ -634,11 +634,13 @@ debug (gori_map &g) // Construct a gori_compute object. -gori_compute::gori_compute () +gori_compute::gori_compute () : tracer ("GORI ") { // Create a boolean_type true and false range. m_bool_zero = int_range<2> (boolean_false_node, boolean_false_node); m_bool_one = int_range<2> (boolean_true_node, boolean_true_node); + if (dump_file && (param_evrp_mode & EVRP_MODE_GORI)) + tracer.enable_trace (); } // Given the switch S, return an evaluation in R for NAME when the lhs @@ -712,29 +714,43 @@ gori_compute::compute_operand_range (irange &r, gimple *stmt, if (!op1_in_chain && !op2_in_chain) return false; + bool res; // Process logicals as they have special handling. if (is_gimple_logical_p (stmt)) { + unsigned idx; + if ((idx = tracer.header ("compute_operand "))) + { + print_generic_expr (dump_file, name, TDF_SLIM); + fprintf (dump_file, " with LHS = "); + lhs.dump (dump_file); + fprintf (dump_file, " at stmt "); + print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM); + } + int_range_max op1_trange, op1_frange; int_range_max op2_trange, op2_frange; compute_logical_operands (op1_trange, op1_frange, stmt, lhs, name, src, op1, op1_in_chain); compute_logical_operands (op2_trange, op2_frange, stmt, lhs, name, src, op2, op2_in_chain); - return logical_combine (r, gimple_expr_code (stmt), lhs, - op1_trange, op1_frange, op2_trange, op2_frange); + res = logical_combine (r, gimple_expr_code (stmt), lhs, + op1_trange, op1_frange, op2_trange, op2_frange); + if (idx) + tracer.trailer (idx, "compute_operand", res, name, r); } - // Follow the appropriate operands now. - if (op1_in_chain && op2_in_chain) - return compute_operand1_and_operand2_range (r, stmt, lhs, name, src); - if (op1_in_chain) - return compute_operand1_range (r, stmt, lhs, name, src); - if (op2_in_chain) - return compute_operand2_range (r, stmt, lhs, name, src); + else if (op1_in_chain && op2_in_chain) + res = compute_operand1_and_operand2_range (r, stmt, lhs, name, src); + else if (op1_in_chain) + res = compute_operand1_range (r, stmt, lhs, name, src); + else if (op2_in_chain) + res = compute_operand2_range (r, stmt, lhs, name, src); + else + gcc_unreachable (); // If neither operand is derived, this statement tells us nothing. - return false; + return res; } @@ -767,6 +783,38 @@ gori_compute::logical_combine (irange &r, enum tree_code code, && op2_true.varying_p () && op2_false.varying_p ()) return false; + unsigned idx; + if ((idx = tracer.header ("logical_combine"))) + { + switch (code) + { + case TRUTH_OR_EXPR: + case BIT_IOR_EXPR: + fprintf (dump_file, " || "); + break; + case TRUTH_AND_EXPR: + case BIT_AND_EXPR: + fprintf (dump_file, " && "); + break; + default: + break; + } + fprintf (dump_file, " with LHS = "); + lhs.dump (dump_file); + fputc ('\n', dump_file); + + tracer.print (idx, "op1_true = "); + op1_true.dump (dump_file); + fprintf (dump_file, " op1_false = "); + op1_false.dump (dump_file); + fputc ('\n', dump_file); + tracer.print (idx, "op2_true = "); + op2_true.dump (dump_file); + fprintf (dump_file, " op2_false = "); + op2_false.dump (dump_file); + fputc ('\n', dump_file); + } + // This is not a simple fold of a logical expression, rather it // determines ranges which flow through the logical expression. // @@ -804,6 +852,7 @@ gori_compute::logical_combine (irange &r, enum tree_code code, // would be lost. if (!range_is_either_true_or_false (lhs)) { + bool res; int_range_max r1; if (logical_combine (r1, code, m_bool_zero, op1_true, op1_false, op2_true, op2_false) @@ -811,9 +860,12 @@ gori_compute::logical_combine (irange &r, enum tree_code code, op2_true, op2_false)) { r.union_ (r1); - return true; + res = true; } - return false; + else + res = false; + if (idx) + tracer.trailer (idx, "logical_combine", res, NULL_TREE, r); } switch (code) @@ -873,6 +925,8 @@ gori_compute::logical_combine (irange &r, enum tree_code code, gcc_unreachable (); } + if (idx) + tracer.trailer (idx, "logical_combine", true, NULL_TREE, r); return true; } @@ -895,6 +949,13 @@ gori_compute::compute_logical_operands (irange &true_range, irange &false_range, // use its known value on entry to the block. src.get_operand (true_range, name); false_range = true_range; + unsigned idx; + if ((idx = tracer.header ("logical_operand"))) + { + print_generic_expr (dump_file, op, TDF_SLIM); + fprintf (dump_file, " not in computation chain. Queried.\n"); + tracer.trailer (idx, "logical_operand", true, NULL_TREE, true_range); + } return; } @@ -958,15 +1019,43 @@ gori_compute::compute_operand1_range (irange &r, gimple *stmt, return false; } + unsigned idx; + if ((idx = tracer.header ("compute op 1 ("))) + { + print_generic_expr (dump_file, op1, TDF_SLIM); + fprintf (dump_file, ") at "); + print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM); + tracer.print (idx, "LHS ="); + lhs.dump (dump_file); + if (op2 && TREE_CODE (op2) == SSA_NAME) + { + fprintf (dump_file, ", "); + print_generic_expr (dump_file, op2, TDF_SLIM); + fprintf (dump_file, " = "); + op2_range.dump (dump_file); + } + fprintf (dump_file, "\n"); + tracer.print (idx, "Computes "); + print_generic_expr (dump_file, op1, TDF_SLIM); + fprintf (dump_file, " = "); + r.dump (dump_file); + fprintf (dump_file, " intersect Known range : "); + op1_range.dump (dump_file); + fputc ('\n', dump_file); + } // Intersect the calculated result with the known result and return if done. if (op1 == name) { r.intersect (op1_range); + if (idx) + tracer.trailer (idx, "produces ", true, name, r); return true; } // If the calculation continues, we're using op1_range as the new LHS. op1_range.intersect (r); + if (idx) + tracer.trailer (idx, "produces ", true, op1, op1_range); gimple *src_stmt = SSA_NAME_DEF_STMT (op1); gcc_checking_assert (src_stmt); @@ -995,15 +1084,43 @@ gori_compute::compute_operand2_range (irange &r, gimple *stmt, if (!gimple_range_calc_op2 (r, stmt, lhs, op1_range)) return false; + unsigned idx; + if ((idx = tracer.header ("compute op 2 ("))) + { + print_generic_expr (dump_file, op2, TDF_SLIM); + fprintf (dump_file, ") at "); + print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM); + tracer.print (idx, "LHS = "); + lhs.dump (dump_file); + if (TREE_CODE (op1) == SSA_NAME) + { + fprintf (dump_file, ", "); + print_generic_expr (dump_file, op1, TDF_SLIM); + fprintf (dump_file, " = "); + op1_range.dump (dump_file); + } + fprintf (dump_file, "\n"); + tracer.print (idx, "Computes "); + print_generic_expr (dump_file, op2, TDF_SLIM); + fprintf (dump_file, " = "); + r.dump (dump_file); + fprintf (dump_file, " intersect Known range : "); + op2_range.dump (dump_file); + fputc ('\n', dump_file); + } // Intersect the calculated result with the known result and return if done. if (op2 == name) { r.intersect (op2_range); + if (idx) + tracer.trailer (idx, " produces ", true, NULL_TREE, r); return true; } // If the calculation continues, we're using op2_range as the new LHS. op2_range.intersect (r); + if (idx) + tracer.trailer (idx, " produces ", true, op2, op2_range); gimple *src_stmt = SSA_NAME_DEF_STMT (op2); gcc_checking_assert (src_stmt); // gcc_checking_assert (!is_import_p (op2, find.bb)); @@ -1095,6 +1212,7 @@ gori_compute::outgoing_edge_range_p (irange &r, edge e, tree name, range_query &q) { int_range_max lhs; + unsigned idx; gcc_checking_assert (gimple_range_ssa_p (name)); // Determine if there is an outgoing edge. @@ -1122,7 +1240,15 @@ gori_compute::outgoing_edge_range_p (irange &r, edge e, tree name, // If NAME can be calculated on the edge, use that. if (is_export_p (name, e->src)) { - if (compute_operand_range (r, stmt, lhs, name, src)) + bool res; + if ((idx = tracer.header ("outgoing_edge"))) + { + fprintf (dump_file, " for "); + print_generic_expr (dump_file, name, TDF_SLIM); + fprintf (dump_file, " on edge %d->%d\n", + e->src->index, e->dest->index); + } + if ((res = compute_operand_range (r, stmt, lhs, name, src))) { // Sometimes compatible types get interchanged. See PR97360. // Make sure we are returning the type of the thing we asked for. @@ -1132,28 +1258,26 @@ gori_compute::outgoing_edge_range_p (irange &r, edge e, tree name, TREE_TYPE (name))); range_cast (r, TREE_TYPE (name)); } - return true; } + if (idx) + tracer.trailer (idx, "outgoing_edge", res, name, r); + return res; } // If NAME isn't exported, check if it can be recomputed. else if (may_recompute_p (name, e)) { gimple *def_stmt = SSA_NAME_DEF_STMT (name); - if (dump_file && (dump_flags & TDF_DETAILS)) + if ((idx = tracer.header ("recomputation"))) { - fprintf (dump_file, "recomputation attempt on edge %d->%d for ", + fprintf (dump_file, " attempt on edge %d->%d for ", e->src->index, e->dest->index); - print_generic_expr (dump_file, name, TDF_SLIM); + print_gimple_stmt (dump_file, def_stmt, 0, TDF_SLIM); } // Simply calculate DEF_STMT on edge E using the range query Q. fold_range (r, def_stmt, e, &q); - if (dump_file && (dump_flags & TDF_DETAILS)) - { - fprintf (dump_file, " : Calculated :"); - r.dump (dump_file); - fputc ('\n', dump_file); - } + if (idx) + tracer.trailer (idx, "recomputation", true, name, r); return true; } return false; diff --git a/gcc/gimple-range-gori.h b/gcc/gimple-range-gori.h index ad83324..688468c 100644 --- a/gcc/gimple-range-gori.h +++ b/gcc/gimple-range-gori.h @@ -180,6 +180,7 @@ private: int_range<2> m_bool_one; // Boolean true cached. gimple_outgoing_range outgoing; // Edge values for COND_EXPR & SWITCH_EXPR. + range_tracer tracer; }; // These routines provide a GIMPLE interface to the range-ops code. -- cgit v1.1 From 2d14d64bf2d42a87ec58dd3760be12aeaa4a4279 Mon Sep 17 00:00:00 2001 From: GCC Administrator Date: Wed, 18 Aug 2021 00:16:48 +0000 Subject: Daily bump. --- gcc/ChangeLog | 374 ++++++++++++++++++++++++++++++++++++++++++++++++ gcc/DATESTAMP | 2 +- gcc/c-family/ChangeLog | 17 +++ gcc/c/ChangeLog | 6 + gcc/cp/ChangeLog | 41 ++++++ gcc/fortran/ChangeLog | 22 +++ gcc/objc/ChangeLog | 8 ++ gcc/testsuite/ChangeLog | 100 +++++++++++++ 8 files changed, 569 insertions(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 3a815ec..b26f256 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,377 @@ +2021-08-17 Andrew MacLeod + + * gimple-range-gori.cc (gori_compute::gori_compute): Enable tracing. + (gori_compute::compute_operand_range): Add tracing. + (gori_compute::logical_combine): Ditto. + (gori_compute::compute_logical_operands): Ditto. + (gori_compute::compute_operand1_range): Ditto. + (gori_compute::compute_operand2_range): Ditto. + (gori_compute::outgoing_edge_range_p): Ditto. + * gimple-range-gori.h (class gori_compute): Add range_tracer. + +2021-08-17 Andrew MacLeod + + * flag-types.h (enum evrp_mode): Adjust evrp-mode values. + * gimple-range-cache.cc (DEBUG_RANGE_CACHE): Relocate from. + * gimple-range-trace.h (DEBUG_RANGE_CACHE): Here. + * params.opt (--param=evrp-mode): Adjust options. + +2021-08-17 Andrew MacLeod + + * Makefile.in (OBJS): Add gimple-range-trace.o. + * gimple-range-cache.h (enable_new_values): Remove unused prototype. + * gimple-range-fold.cc: Adjust headers. + * gimple-range-trace.cc: New. + * gimple-range-trace.h: New. + * gimple-range.cc (gimple_ranger::gimple_ranger): Enable tracer. + (gimple_ranger::range_of_expr): Add tracing. + (gimple_ranger::range_on_entry): Ditto. + (gimple_ranger::range_on_exit): Ditto. + (gimple_ranger::range_on_edge): Ditto. + (gimple_ranger::fold_range_internal): Ditto. + (gimple_ranger::dump_bb): Do not calculate edge range twice. + (trace_ranger::*): Remove. + (enable_ranger): Never create a trace_ranger. + (debug_seed_ranger): Move to gimple-range-trace.cc. + (dump_ranger): Ditto. + (debug_ranger): Ditto. + * gimple-range.h: Include gimple-range-trace.h. + (range_on_entry, range_on_exit): No longer virtual. + (class trace_ranger): Remove. + (DEBUG_RANGE_CACHE): Move to gimple-range-trace.h. + +2021-08-17 Martin Sebor + + PR middle-end/101854 + * builtins.c (expand_builtin_alloca): Move warning code to check_alloca + in gimple-ssa-warn-access.cc. + * calls.c (alloc_max_size): Move code to check_alloca. + (get_size_range): Move to pointer-query.cc. + (maybe_warn_alloc_args_overflow): Move to gimple-ssa-warn-access.cc. + (get_attr_nonstring_decl): Move to tree.c. + (fntype_argno_type): Move to gimple-ssa-warn-access.cc. + (append_attrname): Same. + (maybe_warn_rdwr_sizes): Same. + (initialize_argument_information): Move code to + gimple-ssa-warn-access.cc. + * calls.h (maybe_warn_alloc_args_overflow): Move to + gimple-ssa-warn-access.h. + (get_attr_nonstring_decl): Move to tree.h. + (maybe_warn_nonstring_arg): Move to gimple-ssa-warn-access.h. + (enum size_range_flags): Move to pointer-query.h. + (get_size_range): Same. + * gimple-ssa-warn-access.cc (has_location): Remove unused overload + to avoid Clang -Wunused-function. + (get_size_range): Declare static. + (maybe_emit_free_warning): Rename... + (maybe_check_dealloc_call): ...to this for consistency. + (class pass_waccess): Add members. + (pass_waccess::~pass_waccess): Defined. + (alloc_max_size): Move here from calls.c. + (maybe_warn_alloc_args_overflow): Same. + (check_alloca): New function. + (check_alloc_size_call): New function. + (check_strncat): Handle another warning flag. + (pass_waccess::check_builtin): Handle alloca. + (fntype_argno_type): Move here from calls.c. + (append_attrname): Same. + (maybe_warn_rdwr_sizes): Same. + (pass_waccess::check_call): Define. + (check_nonstring_args): New function. + (pass_waccess::check): Call new member functions. + (pass_waccess::execute): Enable ranger. + * gimple-ssa-warn-access.h (get_size_range): Move here from calls.h. + (maybe_warn_nonstring_arg): Same. + * gimple-ssa-warn-restrict.c: Remove #include. + * pointer-query.cc (get_size_range): Move here from calls.c. + * pointer-query.h (enum size_range_flags): Same. + (get_size_range): Same. + * tree.c (get_attr_nonstring_decl): Move here from calls.c. + * tree.h (get_attr_nonstring_decl): Move here from calls.h. + +2021-08-17 Thomas Schwinge + + * ggc.h (ggc_collect): Add 'force_collect' parameter. + * ggc-page.c (ggc_collect): Use that one instead of global + 'ggc_force_collect'. Adjust all users. + * doc/gty.texi (Invoking the garbage collector): Update. + * ggc-internal.h (ggc_force_collect): Remove. + * ggc-common.c (ggc_force_collect): Likewise. + * selftest.h (forcibly_ggc_collect): Remove. + * ggc-tests.c (selftest::forcibly_ggc_collect): Likewise. + * read-rtl-function.c (test_loading_labels): Adjust. + * selftest-run-tests.c (run_tests): Likewise. + +2021-08-17 Iain Sandoe + + * config/darwin.c (darwin_file_end): Reset and reclaim the + section names table at the end of compile. + +2021-08-17 Iain Sandoe + + PR target/100340 + * config.in: Regenerate. + * config/i386/darwin.h (EXTRA_ASM_OPTS): New + (ASM_SPEC): Pass options to disable branch shortening where + needed. + * configure: Regenerate. + * configure.ac: Detect versions of 'as' that support the + optimisation which has the bug. + +2021-08-17 Richard Biener + + * optabs-query.c (supports_vec_gather_load_p): Also check + for masked optabs. + (supports_vec_scatter_store_p): Likewise. + * tree-vect-data-refs.c (vect_gather_scatter_fn_p): Fall + back to masked variants if non-masked are not supported. + * tree-vect-patterns.c (vect_recog_gather_scatter_pattern): + When we need to use masked gather/scatter but do not have + a mask set up a constant true one. + * tree-vect-stmts.c (vect_check_scalar_mask): Also allow + non-SSA_NAME masks. + +2021-08-17 Roger Sayle + + * tree-ssa-ccp.c (bit_value_binop) [MINUS_EXPR]: Use same + algorithm as PLUS_EXPR to improve subtraction bit bounds. + [POINTER_DIFF_EXPR]: Treat as synonymous with MINUS_EXPR. + +2021-08-17 Roger Sayle + + * tree-ssa-ccp.c (bit_value_mult_const): New helper function to + calculate the mask-value pair result of a multiplication by an + unsigned constant. + (bit_value_binop) [MULT_EXPR]: Call it from here for + multiplications by (sparse) non-negative constants. + +2021-08-17 Christophe Lyon + + PR target/100896 + * config.gcc (gcc_cv_initfini_array): Leave undefined for + uclinuxfdpiceabi targets. + +2021-08-17 Alexandre Oliva + + * tree-inline.c (maybe_move_debug_stmts_to_successors): Don't + reverse debug stmts. + +2021-08-17 Alexandre Oliva + + * tree-cfg.c (dump_function_to_file): Use fun, not cfun. + +2021-08-17 Jonathan Wright + + * config/aarch64/arm_neon.h (__LD4_LANE_FUNC): Delete. + (__LD4Q_LANE_FUNC): Likewise. + (vld4_lane_u8): Define without macro. + (vld4_lane_u16): Likewise. + (vld4_lane_u32): Likewise. + (vld4_lane_u64): Likewise. + (vld4_lane_s8): Likewise. + (vld4_lane_s16): Likewise. + (vld4_lane_s32): Likewise. + (vld4_lane_s64): Likewise. + (vld4_lane_f16): Likewise. + (vld4_lane_f32): Likewise. + (vld4_lane_f64): Likewise. + (vld4_lane_p8): Likewise. + (vld4_lane_p16): Likewise. + (vld4_lane_p64): Likewise. + (vld4q_lane_u8): Likewise. + (vld4q_lane_u16): Likewise. + (vld4q_lane_u32): Likewise. + (vld4q_lane_u64): Likewise. + (vld4q_lane_s8): Likewise. + (vld4q_lane_s16): Likewise. + (vld4q_lane_s32): Likewise. + (vld4q_lane_s64): Likewise. + (vld4q_lane_f16): Likewise. + (vld4q_lane_f32): Likewise. + (vld4q_lane_f64): Likewise. + (vld4q_lane_p8): Likewise. + (vld4q_lane_p16): Likewise. + (vld4q_lane_p64): Likewise. + (vld4_lane_bf16): Likewise. + (vld4q_lane_bf16): Likewise. + +2021-08-17 Jonathan Wright + + * config/aarch64/arm_neon.h (__LD3_LANE_FUNC): Delete. + (__LD3Q_LANE_FUNC): Delete. + (vld3_lane_u8): Define without macro. + (vld3_lane_u16): Likewise. + (vld3_lane_u32): Likewise. + (vld3_lane_u64): Likewise. + (vld3_lane_s8): Likewise. + (vld3_lane_s16): Likewise. + (vld3_lane_s32): Likewise. + (vld3_lane_s64): Likewise. + (vld3_lane_f16): Likewise. + (vld3_lane_f32): Likewise. + (vld3_lane_f64): Likewise. + (vld3_lane_p8): Likewise. + (vld3_lane_p16): Likewise. + (vld3_lane_p64): Likewise. + (vld3q_lane_u8): Likewise. + (vld3q_lane_u16): Likewise. + (vld3q_lane_u32): Likewise. + (vld3q_lane_u64): Likewise. + (vld3q_lane_s8): Likewise. + (vld3q_lane_s16): Likewise. + (vld3q_lane_s32): Likewise. + (vld3q_lane_s64): Likewise. + (vld3q_lane_f16): Likewise. + (vld3q_lane_f32): Likewise. + (vld3q_lane_f64): Likewise. + (vld3q_lane_p8): Likewise. + (vld3q_lane_p16): Likewise. + (vld3q_lane_p64): Likewise. + (vld3_lane_bf16): Likewise. + (vld3q_lane_bf16): Likewise. + +2021-08-17 Jonathan Wright + + * config/aarch64/arm_neon.h (__LD2_LANE_FUNC): Delete. + (__LD2Q_LANE_FUNC): Likewise. + (vld2_lane_u8): Define without macro. + (vld2_lane_u16): Likewise. + (vld2_lane_u32): Likewise. + (vld2_lane_u64): Likewise. + (vld2_lane_s8): Likewise. + (vld2_lane_s16): Likewise. + (vld2_lane_s32): Likewise. + (vld2_lane_s64): Likewise. + (vld2_lane_f16): Likewise. + (vld2_lane_f32): Likewise. + (vld2_lane_f64): Likewise. + (vld2_lane_p8): Likewise. + (vld2_lane_p16): Likewise. + (vld2_lane_p64): Likewise. + (vld2q_lane_u8): Likewise. + (vld2q_lane_u16): Likewise. + (vld2q_lane_u32): Likewise. + (vld2q_lane_u64): Likewise. + (vld2q_lane_s8): Likewise. + (vld2q_lane_s16): Likewise. + (vld2q_lane_s32): Likewise. + (vld2q_lane_s64): Likewise. + (vld2q_lane_f16): Likewise. + (vld2q_lane_f32): Likewise. + (vld2q_lane_f64): Likewise. + (vld2q_lane_p8): Likewise. + (vld2q_lane_p16): Likewise. + (vld2q_lane_p64): Likewise. + (vld2_lane_bf16): Likewise. + (vld2q_lane_bf16): Likewise. + +2021-08-17 Maxim Kuvyrkov + + * haifa-sched.c (advance_one_cycle): Output more context-synchronization + lines for diff. + +2021-08-17 Maxim Kuvyrkov + + * haifa-sched.c (enum rfs_decision, rfs_str): Add RFS_AUTOPREF. + (rank_for_schedule): Use it. + +2021-08-17 Maxim Kuvyrkov + + PR rtl-optimization/91598 + * haifa-sched.c (autopref_rank_for_schedule): Prioritize "irrelevant" + insns after memory reads and before memory writes. + +2021-08-17 Alistair_Lee + + * rtl.h (CONST_VECTOR_P): New macro. + * config/aarch64/aarch64.c (aarch64_get_sve_pred_bits): Use RTL + code testing macros. + (aarch64_ptrue_all_mode): Likewise. + (aarch64_expand_mov_immediate): Likewise. + (aarch64_const_vec_all_in_range_p): Likewise. + (aarch64_rtx_costs): Likewise. + (aarch64_legitimate_constant_p): Likewise. + (aarch64_simd_valid_immediate): Likewise. + (aarch64_simd_make_constant): Likewise. + (aarch64_convert_mult_to_shift): Likewise. + (aarch64_expand_sve_vec_perm): Likewise. + (aarch64_vec_fpconst_pow_of_2): Likewise. + +2021-08-17 Andrew MacLeod + + PR tree-optimization/101938 + * range-op.cc (operator_abs::op1_range): Special case + -TYPE_MIN_VALUE for flag_wrapv. + +2021-08-17 Kewen Lin + + * tree-vect-slp.c (vectorizable_bb_reduc_epilogue): Add the cost for + value extraction. + +2021-08-17 Jakub Jelinek + + * tree.def (OMP_SCOPE): New tree code. + * tree.h (OMP_SCOPE_BODY, OMP_SCOPE_CLAUSES): Define. + * tree-nested.c (convert_nonlocal_reference_stmt, + convert_local_reference_stmt, convert_gimple_call): Handle + GIMPLE_OMP_SCOPE. + * tree-pretty-print.c (dump_generic_node): Handle OMP_SCOPE. + * gimple.def (GIMPLE_OMP_SCOPE): New gimple code. + * gimple.c (gimple_build_omp_scope): New function. + (gimple_copy): Handle GIMPLE_OMP_SCOPE. + * gimple.h (gimple_build_omp_scope): Declare. + (gimple_has_substatements): Handle GIMPLE_OMP_SCOPE. + (gimple_omp_scope_clauses, gimple_omp_scope_clauses_ptr, + gimple_omp_scope_set_clauses): New inline functions. + (CASE_GIMPLE_OMP): Add GIMPLE_OMP_SCOPE. + * gimple-pretty-print.c (dump_gimple_omp_scope): New function. + (pp_gimple_stmt_1): Handle GIMPLE_OMP_SCOPE. + * gimple-walk.c (walk_gimple_stmt): Likewise. + * gimple-low.c (lower_stmt): Likewise. + * gimplify.c (is_gimple_stmt): Handle OMP_MASTER. + (gimplify_scan_omp_clauses): For task reductions, handle OMP_SCOPE + like ORT_WORKSHARE constructs. Adjust diagnostics for % + allowing task reductions. Reject inscan reductions on scope. + (omp_find_stores_stmt): Handle GIMPLE_OMP_SCOPE. + (gimplify_omp_workshare, gimplify_expr): Handle OMP_SCOPE. + * tree-inline.c (remap_gimple_stmt): Handle GIMPLE_OMP_SCOPE. + (estimate_num_insns): Likewise. + * omp-low.c (build_outer_var_ref): Look through GIMPLE_OMP_SCOPE + contexts if var isn't privatized there. + (check_omp_nesting_restrictions): Handle GIMPLE_OMP_SCOPE. + (scan_omp_1_stmt): Likewise. + (maybe_add_implicit_barrier_cancel): Look through outer + scope constructs. + (lower_omp_scope): New function. + (lower_omp_task_reductions): Handle OMP_SCOPE. + (lower_omp_1): Handle GIMPLE_OMP_SCOPE. + (diagnose_sb_1, diagnose_sb_2): Likewise. + * omp-expand.c (expand_omp_single): Support also GIMPLE_OMP_SCOPE. + (expand_omp): Handle GIMPLE_OMP_SCOPE. + (omp_make_gimple_edges): Likewise. + * omp-builtins.def (BUILT_IN_GOMP_SCOPE_START): New built-in. + +2021-08-17 Richard Biener + + PR tree-optimization/101925 + * tree-ssa-sccvn.c (copy_reference_ops_from_ref): Set + reverse on COMPONENT_REF and ARRAY_REF according to + what reverse_storage_order_for_component_p does. + (vn_reference_eq): Compare reversed on reference ops. + (reverse_storage_order_for_component_p): New overload. + (vn_reference_lookup_3): Check reverse_storage_order_for_component_p + on the reference looked up. + +2021-08-17 Jeff Law + + * config/h8300/h8300.c (shift_alg_si): Avoid loops for most SImode + shifts on the H8/S. + (h8300_option_override): Use loops on H8/S more often when optimizing + for size. + (get_shift_alg): Handle new "special" cases on H8/S. Simplify + accordingly. Handle various arithmetic right shifts with special + sequences that we couldn't handle before. + 2021-08-16 Jeff Law * config.gcc (rl78-*-elf*): Do not include dbxelf.h. diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index e72fc6b..70b09db 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20210817 +20210818 diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index a6fdf7b..5595994 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,20 @@ +2021-08-17 Jakub Jelinek + + PR c++/101539 + * c-common.h (enum rid): Add RID_IS_LAYOUT_COMPATIBLE. + * c-common.c (c_common_reswords): Add __is_layout_compatible. + +2021-08-17 Matt Jacobson + + * c-opts.c (c_common_post_options): Default to + flag_objc_sjlj_exceptions = 1 only when flag_objc_abi < 2. + +2021-08-17 Jakub Jelinek + + * c-pragma.h (enum pragma_kind): Add PRAGMA_OMP_SCOPE. + * c-pragma.c (omp_pragmas): Add scope construct. + * c-omp.c (omp_directives): Uncomment scope directive entry. + 2021-08-16 Sebastian Huber * c-cppbuiltin.c (c_cpp_builtins): Define diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index ab61ac0..caeac5b 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,9 @@ +2021-08-17 Jakub Jelinek + + * c-parser.c (OMP_SCOPE_CLAUSE_MASK): Define. + (c_parser_omp_scope): New function. + (c_parser_omp_construct): Handle PRAGMA_OMP_SCOPE. + 2021-08-12 Jakub Jelinek * c-parser.c (c_parser_omp_clause_name): Parse filter clause name. diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 7a4a707..a2d47b3 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,44 @@ +2021-08-17 Jakub Jelinek + + PR c++/101539 + * cp-tree.h (enum cp_trait_kind): Add CPTK_IS_LAYOUT_COMPATIBLE. + (enum cp_built_in_function): Add CP_BUILT_IN_IS_CORRESPONDING_MEMBER. + (fold_builtin_is_corresponding_member, next_common_initial_seqence, + layout_compatible_type_p): Declare. + * parser.c (cp_parser_primary_expression): Handle + RID_IS_LAYOUT_COMPATIBLE. + (cp_parser_trait_expr): Likewise. + * cp-objcp-common.c (names_builtin_p): Likewise. + * constraint.cc (diagnose_trait_expr): Handle + CPTK_IS_LAYOUT_COMPATIBLE. + * decl.c (cxx_init_decl_processing): Register + __builtin_is_corresponding_member builtin. + * constexpr.c (cxx_eval_builtin_function_call): Handle + CP_BUILT_IN_IS_CORRESPONDING_MEMBER builtin. + * semantics.c (is_corresponding_member_union, + is_corresponding_member_aggr, fold_builtin_is_corresponding_member): + New functions. + (trait_expr_value): Handle CPTK_IS_LAYOUT_COMPATIBLE. + (finish_trait_expr): Likewise. + * typeck.c (next_common_initial_seqence, layout_compatible_type_p): + New functions. + * cp-gimplify.c (cp_gimplify_expr): Fold + CP_BUILT_IN_IS_CORRESPONDING_MEMBER. + (cp_fold): Likewise. + * tree.c (builtin_valid_in_constant_expr_p): Handle + CP_BUILT_IN_IS_CORRESPONDING_MEMBER. + * cxx-pretty-print.c (pp_cxx_trait_expression): Handle + CPTK_IS_LAYOUT_COMPATIBLE. + * class.c (remove_zero_width_bit_fields): Remove. + (layout_class_type): Don't call it. + +2021-08-17 Jakub Jelinek + + * parser.c (OMP_SCOPE_CLAUSE_MASK): Define. + (cp_parser_omp_scope): New function. + (cp_parser_omp_construct, cp_parser_pragma): Handle PRAGMA_OMP_SCOPE. + * pt.c (tsubst_expr): Handle OMP_SCOPE. + 2021-08-12 Jakub Jelinek * parser.c (cp_parser_omp_clause_name): Parse filter clause name. diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index 5b3744c..86a2bda 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,25 @@ +2021-08-17 Tobias Burnus + + * dump-parse-tree.c (show_omp_node, show_code_node): Handle + EXEC_OMP_SCOPE. + * gfortran.h (enum gfc_statement): Add ST_OMP_(END_)SCOPE. + (enum gfc_exec_op): Add EXEC_OMP_SCOPE. + * match.h (gfc_match_omp_scope): New. + * openmp.c (OMP_SCOPE_CLAUSES): Define + (gfc_match_omp_scope): New. + (gfc_match_omp_cancellation_point, gfc_match_omp_end_nowait): + Improve error diagnostic. + (omp_code_to_statement): Handle ST_OMP_SCOPE. + (gfc_resolve_omp_directive): Handle EXEC_OMP_SCOPE. + * parse.c (decode_omp_directive, next_statement, + gfc_ascii_statement, parse_omp_structured_block, + parse_executable): Handle OpenMP's scope construct. + * resolve.c (gfc_resolve_blocks): Likewise + * st.c (gfc_free_statement): Likewise + * trans-openmp.c (gfc_trans_omp_scope): New. + (gfc_trans_omp_directive): Call it. + * trans.c (trans_code): handle EXEC_OMP_SCOPE. + 2021-08-16 Tobias Burnus * dump-parse-tree.c (show_omp_clauses): Handle 'filter' clause. diff --git a/gcc/objc/ChangeLog b/gcc/objc/ChangeLog index bb84045..8adde0d 100644 --- a/gcc/objc/ChangeLog +++ b/gcc/objc/ChangeLog @@ -1,3 +1,11 @@ +2021-08-17 Matt Jacobson + + * objc-next-runtime-abi-02.c + (objc_next_runtime_abi_02_init): Warn about and reset + flag_objc_sjlj_exceptions regardless of flag_objc_exceptions. + (next_runtime_02_initialize): Use a checking assert that + flag_objc_sjlj_exceptions is off. + 2021-06-28 Martin Sebor * objc-act.c (objc_maybe_build_modify_expr): Replace direct uses diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 540de57..e5dcd4a 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,103 @@ +2021-08-17 Martin Sebor + + PR middle-end/101854 + * gcc.dg/attr-alloc_size-5.c: Adjust optimization to -O1. + * gcc.dg/attr-alloc_size-7.c: Use #pragmas to adjust optimization. + * gcc.dg/attr-alloc_size-8.c: Adjust optimization to -O1. + * gcc.dg/Wstringop-overflow-72.c: New test. + +2021-08-17 Jakub Jelinek + + PR c++/101539 + * g++.dg/cpp2a/is-corresponding-member1.C: New test. + * g++.dg/cpp2a/is-corresponding-member2.C: New test. + * g++.dg/cpp2a/is-corresponding-member3.C: New test. + * g++.dg/cpp2a/is-corresponding-member4.C: New test. + * g++.dg/cpp2a/is-corresponding-member5.C: New test. + * g++.dg/cpp2a/is-corresponding-member6.C: New test. + * g++.dg/cpp2a/is-corresponding-member7.C: New test. + * g++.dg/cpp2a/is-corresponding-member8.C: New test. + * g++.dg/cpp2a/is-layout-compatible1.C: New test. + * g++.dg/cpp2a/is-layout-compatible2.C: New test. + * g++.dg/cpp2a/is-layout-compatible3.C: New test. + +2021-08-17 Thomas Schwinge + + * gcc.dg/pr78213.c: Restore testing. + +2021-08-17 Roger Sayle + + * gcc.dg/tree-ssa/ssa-ccp-40.c: New test case. + +2021-08-17 Roger Sayle + + * gcc.dg/fold-ior-5.c: New test case. + +2021-08-17 Tobias Burnus + + * gfortran.dg/gomp/scan-1.f90: + * gfortran.dg/gomp/cancel-1.f90: New test. + * gfortran.dg/gomp/cancel-4.f90: New test. + * gfortran.dg/gomp/loop-4.f90: New test. + * gfortran.dg/gomp/nesting-1.f90: New test. + * gfortran.dg/gomp/nesting-2.f90: New test. + * gfortran.dg/gomp/nesting-3.f90: New test. + * gfortran.dg/gomp/nowait-1.f90: New test. + * gfortran.dg/gomp/reduction-task-1.f90: New test. + * gfortran.dg/gomp/reduction-task-2.f90: New test. + * gfortran.dg/gomp/reduction-task-2a.f90: New test. + * gfortran.dg/gomp/reduction-task-3.f90: New test. + * gfortran.dg/gomp/scope-1.f90: New test. + * gfortran.dg/gomp/scope-2.f90: New test. + +2021-08-17 Andrew MacLeod + + PR tree-optimization/101938 + * gcc.dg/pr101938.c: New test. + +2021-08-17 Richard Biener + + PR tree-optimization/101868 + * gcc.dg/lto/pr101868_0.c: New testcase. + * gcc.dg/lto/pr101868_1.c: Likewise. + * gcc.dg/lto/pr101868_2.c: Likewise. + * gcc.dg/lto/pr101868_3.c: Likewise. + +2021-08-17 Jakub Jelinek + + * c-c++-common/gomp/nesting-2.c (foo): Add scope and masked + construct tests. + * c-c++-common/gomp/scan-1.c (f3): Add scope construct test.. + * c-c++-common/gomp/cancel-1.c (f2): Add scope and masked + construct tests. + * c-c++-common/gomp/reduction-task-2.c (bar): Add scope construct + test. Adjust diagnostics for the addition of scope. + * c-c++-common/gomp/loop-1.c (f5): Add master, masked and scope + construct tests. + * c-c++-common/gomp/clause-dups-1.c (f1): Add scope construct test. + * gcc.dg/gomp/nesting-1.c (f1, f2, f3): Add scope construct tests. + * c-c++-common/gomp/scope-1.c: New test. + * c-c++-common/gomp/scope-2.c: New test. + * g++.dg/gomp/attrs-1.C (bar): Add scope construct tests. + * g++.dg/gomp/attrs-2.C (bar): Likewise. + * gfortran.dg/gomp/reduction4.f90: Adjust expected diagnostics. + * gfortran.dg/gomp/reduction7.f90: Likewise. + +2021-08-17 Jakub Jelinek + + * c-c++-common/cpp/va-opt-5.c: New test. + * c-c++-common/cpp/va-opt-6.c: New test. + +2021-08-17 Richard Biener + + PR tree-optimization/101925 + * gcc.dg/sso-16.c: New testcase. + +2021-08-17 liuhongt + + * gcc.target/i386/pr82460-2.c: Adjust testcase by adding + --param=vect-epilogues-nomask=0 + 2021-08-16 liuhongt PR target/101930 -- cgit v1.1 From 97d51c1764554fcef05fe94ee6445f5d2252bcff Mon Sep 17 00:00:00 2001 From: liuhongt Date: Tue, 17 Aug 2021 13:11:26 +0800 Subject: Add x86 tune to enable v2df vector reduction by paddpd. The tune is disabled by default. gcc/ChangeLog: PR target/97147 * config/i386/i386.h (TARGET_V2DF_REDUCTION_PREFER_HADDPD): New macro. * config/i386/sse.md (*sse3_haddv2df3_low): Add TARGET_V2DF_REDUCTION_PREFER_HADDPD. (*sse3_hsubv2df3_low): Ditto. * config/i386/x86-tune.def (X86_TUNE_V2DF_REDUCTION_PREFER_HADDPD): New tune. gcc/testsuite/ChangeLog: PR target/97147 * gcc.target/i386/pr54400.c: Adjust testcase. * gcc.target/i386/pr94147.c: New test. --- gcc/config/i386/i386.h | 2 ++ gcc/config/i386/sse.md | 4 ++-- gcc/config/i386/x86-tune.def | 5 +++++ gcc/testsuite/gcc.target/i386/pr54400.c | 2 +- gcc/testsuite/gcc.target/i386/pr94147.c | 22 ++++++++++++++++++++++ 5 files changed, 32 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/gcc.target/i386/pr94147.c (limited to 'gcc') diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h index 21fe51b..b3e57a8 100644 --- a/gcc/config/i386/i386.h +++ b/gcc/config/i386/i386.h @@ -418,6 +418,8 @@ extern unsigned char ix86_tune_features[X86_TUNE_LAST]; ix86_tune_features[X86_TUNE_EMIT_VZEROUPPER] #define TARGET_EXPAND_ABS \ ix86_tune_features[X86_TUNE_EXPAND_ABS] +#define TARGET_V2DF_REDUCTION_PREFER_HADDPD \ + ix86_tune_features[X86_TUNE_V2DF_REDUCTION_PREFER_HADDPD] /* Feature tests against the various architecture variations. */ enum ix86_arch_indices { diff --git a/gcc/config/i386/sse.md b/gcc/config/i386/sse.md index 27e25cc..1388968 100644 --- a/gcc/config/i386/sse.md +++ b/gcc/config/i386/sse.md @@ -2771,7 +2771,7 @@ (vec_select:DF (match_dup 1) (parallel [(match_operand:SI 3 "const_0_to_1_operand")]))))] - "TARGET_SSE3 + "TARGET_SSE3 && TARGET_V2DF_REDUCTION_PREFER_HADDPD && INTVAL (operands[2]) != INTVAL (operands[3])" "@ haddpd\t{%0, %0|%0, %0} @@ -2790,7 +2790,7 @@ (vec_select:DF (match_dup 1) (parallel [(const_int 1)]))))] - "TARGET_SSE3" + "TARGET_SSE3 && TARGET_V2DF_REDUCTION_PREFER_HADDPD" "@ hsubpd\t{%0, %0|%0, %0} vhsubpd\t{%1, %1, %0|%0, %1, %1}" diff --git a/gcc/config/i386/x86-tune.def b/gcc/config/i386/x86-tune.def index eb057a6..8f55da8 100644 --- a/gcc/config/i386/x86-tune.def +++ b/gcc/config/i386/x86-tune.def @@ -452,6 +452,11 @@ DEF_TUNE (X86_TUNE_AVOID_128FMA_CHAINS, "avoid_fma_chains", m_ZNVER) smaller FMA chain. */ DEF_TUNE (X86_TUNE_AVOID_256FMA_CHAINS, "avoid_fma256_chains", m_ZNVER2 | m_ZNVER3) +/* X86_TUNE_V2DF_REDUCTION_PREFER_PHADDPD: Prefer haddpd + for v2df vector reduction. */ +DEF_TUNE (X86_TUNE_V2DF_REDUCTION_PREFER_HADDPD, + "v2df_reduction_prefer_haddpd", m_NONE) + /*****************************************************************************/ /* AVX instruction selection tuning (some of SSE flags affects AVX, too) */ /*****************************************************************************/ diff --git a/gcc/testsuite/gcc.target/i386/pr54400.c b/gcc/testsuite/gcc.target/i386/pr54400.c index 5ed5ba0..3a45037 100644 --- a/gcc/testsuite/gcc.target/i386/pr54400.c +++ b/gcc/testsuite/gcc.target/i386/pr54400.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -msse3 -mfpmath=sse" } */ +/* { dg-options "-O2 -msse3 -mfpmath=sse -mtune-ctrl=v2df_reduction_prefer_haddpd" } */ #include diff --git a/gcc/testsuite/gcc.target/i386/pr94147.c b/gcc/testsuite/gcc.target/i386/pr94147.c new file mode 100644 index 0000000..8ff5c34 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr94147.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -msse3 -mfpmath=sse" } */ + +#include + +double f (__m128d p) +{ + return p[0] - p[1]; +} + +double g1 (__m128d p) +{ + return p[0] + p[1]; +} + +double g2 (__m128d p) +{ + return p[1] + p[0]; +} + +/* { dg-final { scan-assembler-not "hsubpd" } } */ +/* { dg-final { scan-assembler-not "haddpd" } } */ -- cgit v1.1 From 1bf976a5de69ecd9b1e10eb7515357b98e78faf7 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Wed, 18 Aug 2021 10:20:50 +0200 Subject: openmp: Actually ignore pragma_stmt pragmas for which c_parser_pragma returns false Unlike the C++ FE, the C FE ignored pragmas (as if they weren't there) in pragma_stmt contexts if c*_parser_pragma returns false only when after labels, not inside of substatements of selection or loop statements. After making just that change, several gomp/goacc testcases started failing, because extra diagnostics has been emitted (in C, in C++ it was emitted already before). Say void foo (int x) { if (x) #pragma omp barrier } used to in C emit just an error that the pragma is not allowed in such contexts, but in C++ emitted both that and a parsing error that if (x) } is invalid. So, the rest of this patch is mostly about returning true after we report that that certain pragma is not allowed in pragma_stmt contexts, because for error-recovery it seems better to treat the pragma in that case as something that is the substatement of such if etc. c*_parser_pragma return value is only ever used for pragma_stmt context, in which false means act as if the pragma isn't there (e.g. has been handled already by preprocessor etc.), and true which means it was there. 2021-08-18 Jakub Jelinek gcc/c/ * c-parser.c (c_parser_statement_after_labels): Add restart label near the start of the function. If c_parser_pragma returns false, goto restart. (c_parser_pragma): For PRAGMA_OMP_CANCELLATION_POINT return what c_parser_omp_cancellation_point returned. For PRAGMA_OMP_DECLARE return what c_parser_omp_declare returned. Return true instead of false after emitting errors that the directive is not allowed in pragma_stmt context. (c_parser_omp_ordered): Return true instead of false after emitting errors that the directive is not allowed in pragma_stmt context. (c_parser_omp_target_update): Likewise. (c_parser_omp_target_enter_data, c_parser_omp_target_exit_data): Change return type from tree to bool, return false if the directive should be ignored in pragma_stmt contexts. (c_parser_omp_target): Adjust callers of c_parser_omp_target_*_data, return their result directly. (c_parser_omp_cancellation_point): Change return type from void to bool, return false if the directive should be ignored in pragma_stmt contexts. (c_parser_omp_declare): Likewise. gcc/cp/ * parser.c (cp_parser_omp_ordered): Return true instead of false after emitting errors that the directive is not allowed in pragma_stmt context. (cp_parser_omp_target_update): Likewise. (cp_parser_omp_cancellation_point): Change return type from void to bool, return false if the directive should be ignored in pragma_stmt contexts. (cp_parser_omp_target_enter_data, cp_parser_omp_target_exit_data): Change return type from tree to bool, return false if the directive should be ignored in pragma_stmt contexts. (cp_parser_omp_target): Adjust callers of cp_parser_omp_target_*_data, return their result directly. (cp_parser_pragma): For PRAGMA_OMP_CANCELLATION_POINT return what cp_parser_omp_cancellation_point returned. Return true instead of false after emitting errors that the directive is not allowed in pragma_stmt context. gcc/testsuite/ * c-c++-common/gomp/pr63326.c: Don't expect extra "before" errors in C++. * g++.dg/gomp/attrs-7.C: Don't expect one extra error. * g++.dg/gomp/barrier-2.C: Likewise. * gcc.dg/gomp/declare-simd-5.c: Likewise. * gcc.dg/gomp/barrier-2.c: Likewise. * gcc.dg/gomp/declare-variant-2.c: Likewise. --- gcc/c/c-parser.c | 70 +++++++++++++-------------- gcc/cp/parser.c | 62 ++++++++++++++---------- gcc/testsuite/c-c++-common/gomp/pr63326.c | 44 ++++++++--------- gcc/testsuite/g++.dg/gomp/attrs-7.C | 3 +- gcc/testsuite/g++.dg/gomp/barrier-2.C | 2 +- gcc/testsuite/gcc.dg/gomp/barrier-2.c | 3 +- gcc/testsuite/gcc.dg/gomp/declare-simd-5.c | 2 +- gcc/testsuite/gcc.dg/gomp/declare-variant-2.c | 2 +- 8 files changed, 99 insertions(+), 89 deletions(-) (limited to 'gcc') diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index 33aeb09..565efc4 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -1582,10 +1582,10 @@ static void c_parser_omp_cancel (c_parser *); enum pragma_context { pragma_external, pragma_struct, pragma_param, pragma_stmt, pragma_compound }; static bool c_parser_pragma (c_parser *, enum pragma_context, bool *); -static void c_parser_omp_cancellation_point (c_parser *, enum pragma_context); +static bool c_parser_omp_cancellation_point (c_parser *, enum pragma_context); static bool c_parser_omp_target (c_parser *, enum pragma_context, bool *); static void c_parser_omp_end_declare_target (c_parser *); -static void c_parser_omp_declare (c_parser *, enum pragma_context); +static bool c_parser_omp_declare (c_parser *, enum pragma_context); static void c_parser_omp_requires (c_parser *); static bool c_parser_omp_ordered (c_parser *, enum pragma_context, bool *); static void c_parser_oacc_routine (c_parser *, enum pragma_context); @@ -6100,6 +6100,7 @@ c_parser_statement_after_labels (c_parser *parser, bool *if_p, if (c_parser_peek_token (parser)->type != CPP_OPEN_BRACE) add_debug_begin_stmt (loc); + restart: switch (c_parser_peek_token (parser)->type) { case CPP_OPEN_BRACE: @@ -6246,7 +6247,8 @@ c_parser_statement_after_labels (c_parser *parser, bool *if_p, c_parser_consume_token (parser); break; case CPP_PRAGMA: - c_parser_pragma (parser, pragma_stmt, if_p); + if (!c_parser_pragma (parser, pragma_stmt, if_p)) + goto restart; break; default: expr_stmt: @@ -12346,7 +12348,7 @@ c_parser_pragma (c_parser *parser, enum pragma_context context, bool *if_p) "%<#pragma %s%> may only be used in compound " "statements", construct); c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL); - return false; + return true; } goto bad_stmt; } @@ -12437,8 +12439,7 @@ c_parser_pragma (c_parser *parser, enum pragma_context context, bool *if_p) return false; case PRAGMA_OMP_CANCELLATION_POINT: - c_parser_omp_cancellation_point (parser, context); - return false; + return c_parser_omp_cancellation_point (parser, context); case PRAGMA_OMP_THREADPRIVATE: c_parser_omp_threadprivate (parser); @@ -12466,8 +12467,7 @@ c_parser_pragma (c_parser *parser, enum pragma_context context, bool *if_p) return false; case PRAGMA_OMP_DECLARE: - c_parser_omp_declare (parser, context); - return false; + return c_parser_omp_declare (parser, context); case PRAGMA_OMP_REQUIRES: if (context != pragma_external) @@ -12505,7 +12505,7 @@ c_parser_pragma (c_parser *parser, enum pragma_context context, bool *if_p) else c_parser_do_statement (parser, ivdep, unroll); } - return false; + return true; case PRAGMA_UNROLL: { @@ -12529,7 +12529,7 @@ c_parser_pragma (c_parser *parser, enum pragma_context context, bool *if_p) else c_parser_do_statement (parser, ivdep, unroll); } - return false; + return true; case PRAGMA_GCC_PCH_PREPROCESS: c_parser_error (parser, "%<#pragma GCC pch_preprocess%> must be first"); @@ -19125,7 +19125,7 @@ c_parser_omp_ordered (c_parser *parser, enum pragma_context context, "%<#pragma omp ordered%> with % clause may " "only be used in compound statements"); c_parser_skip_to_pragma_eol (parser, false); - return false; + return true; } tree clauses @@ -19655,7 +19655,7 @@ c_parser_omp_cancel (c_parser *parser) | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SECTIONS) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_TASKGROUP)) -static void +static bool c_parser_omp_cancellation_point (c_parser *parser, enum pragma_context context) { location_t loc = c_parser_peek_token (parser)->location; @@ -19676,7 +19676,7 @@ c_parser_omp_cancellation_point (c_parser *parser, enum pragma_context context) { c_parser_error (parser, "expected %"); c_parser_skip_to_pragma_eol (parser); - return; + return false; } if (context != pragma_compound) @@ -19688,7 +19688,7 @@ c_parser_omp_cancellation_point (c_parser *parser, enum pragma_context context) else c_parser_error (parser, "expected declaration specifiers"); c_parser_skip_to_pragma_eol (parser, false); - return; + return true; } clauses @@ -19696,6 +19696,7 @@ c_parser_omp_cancellation_point (c_parser *parser, enum pragma_context context) "#pragma omp cancellation point"); c_finish_omp_cancellation_point (loc, clauses); + return true; } /* OpenMP 4.0: @@ -19981,7 +19982,7 @@ c_parser_omp_target_update (location_t loc, c_parser *parser, error_at (loc, "%<#pragma %s%> may only be used in compound statements", "omp target update"); c_parser_skip_to_pragma_eol (parser, false); - return false; + return true; } tree clauses @@ -20014,7 +20015,7 @@ c_parser_omp_target_update (location_t loc, c_parser *parser, | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) -static tree +static bool c_parser_omp_target_enter_data (location_t loc, c_parser *parser, enum pragma_context context) { @@ -20032,7 +20033,7 @@ c_parser_omp_target_enter_data (location_t loc, c_parser *parser, { c_parser_error (parser, "expected %"); c_parser_skip_to_pragma_eol (parser); - return NULL_TREE; + return false; } if (context == pragma_stmt) @@ -20040,7 +20041,7 @@ c_parser_omp_target_enter_data (location_t loc, c_parser *parser, error_at (loc, "%<#pragma %s%> may only be used in compound statements", "omp target enter data"); c_parser_skip_to_pragma_eol (parser, false); - return NULL_TREE; + return true; } tree clauses @@ -20079,7 +20080,7 @@ c_parser_omp_target_enter_data (location_t loc, c_parser *parser, error_at (loc, "%<#pragma omp target enter data%> must contain at least " "one % clause"); - return NULL_TREE; + return true; } tree stmt = make_node (OMP_TARGET_ENTER_DATA); @@ -20087,7 +20088,7 @@ c_parser_omp_target_enter_data (location_t loc, c_parser *parser, OMP_TARGET_ENTER_DATA_CLAUSES (stmt) = clauses; SET_EXPR_LOCATION (stmt, loc); add_stmt (stmt); - return stmt; + return true; } /* OpenMP 4.5: @@ -20100,7 +20101,7 @@ c_parser_omp_target_enter_data (location_t loc, c_parser *parser, | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) -static tree +static bool c_parser_omp_target_exit_data (location_t loc, c_parser *parser, enum pragma_context context) { @@ -20118,7 +20119,7 @@ c_parser_omp_target_exit_data (location_t loc, c_parser *parser, { c_parser_error (parser, "expected %"); c_parser_skip_to_pragma_eol (parser); - return NULL_TREE; + return false; } if (context == pragma_stmt) @@ -20126,7 +20127,7 @@ c_parser_omp_target_exit_data (location_t loc, c_parser *parser, error_at (loc, "%<#pragma %s%> may only be used in compound statements", "omp target exit data"); c_parser_skip_to_pragma_eol (parser, false); - return NULL_TREE; + return true; } tree clauses @@ -20167,7 +20168,7 @@ c_parser_omp_target_exit_data (location_t loc, c_parser *parser, error_at (loc, "%<#pragma omp target exit data%> must contain at least one " "% clause"); - return NULL_TREE; + return true; } tree stmt = make_node (OMP_TARGET_EXIT_DATA); @@ -20175,7 +20176,7 @@ c_parser_omp_target_exit_data (location_t loc, c_parser *parser, OMP_TARGET_EXIT_DATA_CLAUSES (stmt) = clauses; SET_EXPR_LOCATION (stmt, loc); add_stmt (stmt); - return stmt; + return true; } /* OpenMP 4.0: @@ -20333,14 +20334,12 @@ c_parser_omp_target (c_parser *parser, enum pragma_context context, bool *if_p) else if (strcmp (p, "enter") == 0) { c_parser_consume_token (parser); - c_parser_omp_target_enter_data (loc, parser, context); - return false; + return c_parser_omp_target_enter_data (loc, parser, context); } else if (strcmp (p, "exit") == 0) { c_parser_consume_token (parser); - c_parser_omp_target_exit_data (loc, parser, context); - return false; + return c_parser_omp_target_exit_data (loc, parser, context); } else if (strcmp (p, "update") == 0) { @@ -21599,7 +21598,7 @@ c_parser_omp_declare_reduction (c_parser *parser, enum pragma_context context) OpenMP 5.0 #pragma omp declare variant (identifier) match (context-selector) */ -static void +static bool c_parser_omp_declare (c_parser *parser, enum pragma_context context) { c_parser_consume_pragma (parser); @@ -21611,37 +21610,38 @@ c_parser_omp_declare (c_parser *parser, enum pragma_context context) /* c_parser_consume_token (parser); done in c_parser_omp_declare_simd. */ c_parser_omp_declare_simd (parser, context); - return; + return true; } if (strcmp (p, "reduction") == 0) { c_parser_consume_token (parser); c_parser_omp_declare_reduction (parser, context); - return; + return false; } if (!flag_openmp) /* flag_openmp_simd */ { c_parser_skip_to_pragma_eol (parser, false); - return; + return false; } if (strcmp (p, "target") == 0) { c_parser_consume_token (parser); c_parser_omp_declare_target (parser); - return; + return false; } if (strcmp (p, "variant") == 0) { /* c_parser_consume_token (parser); done in c_parser_omp_declare_simd. */ c_parser_omp_declare_simd (parser, context); - return; + return true; } } c_parser_error (parser, "expected %, %, " "% or %"); c_parser_skip_to_pragma_eol (parser); + return false; } /* OpenMP 5.0 diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 9de72f8..8f2d0fc 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -42137,7 +42137,7 @@ cp_parser_omp_ordered (cp_parser *parser, cp_token *pragma_tok, "% clause may only be used in compound " "statements"); cp_parser_skip_to_pragma_eol (parser, pragma_tok); - return false; + return true; } tree clauses = cp_parser_omp_all_clauses (parser, @@ -42661,7 +42661,7 @@ cp_parser_omp_cancel (cp_parser *parser, cp_token *pragma_tok) | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SECTIONS) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_TASKGROUP)) -static void +static bool cp_parser_omp_cancellation_point (cp_parser *parser, cp_token *pragma_tok, enum pragma_context context) { @@ -42683,7 +42683,7 @@ cp_parser_omp_cancellation_point (cp_parser *parser, cp_token *pragma_tok, { cp_parser_error (parser, "expected %"); cp_parser_skip_to_pragma_eol (parser, pragma_tok); - return; + return false; } if (context != pragma_compound) @@ -42695,7 +42695,7 @@ cp_parser_omp_cancellation_point (cp_parser *parser, cp_token *pragma_tok, else cp_parser_error (parser, "expected declaration specifiers"); cp_parser_skip_to_pragma_eol (parser, pragma_tok); - return; + return true; } clauses = cp_parser_omp_all_clauses (parser, @@ -42703,6 +42703,7 @@ cp_parser_omp_cancellation_point (cp_parser *parser, cp_token *pragma_tok, "#pragma omp cancellation point", pragma_tok); finish_omp_cancellation_point (clauses); + return true; } /* OpenMP 4.0: @@ -42998,7 +42999,7 @@ cp_parser_omp_target_data (cp_parser *parser, cp_token *pragma_tok, bool *if_p) | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) -static tree +static bool cp_parser_omp_target_enter_data (cp_parser *parser, cp_token *pragma_tok, enum pragma_context context) { @@ -43018,7 +43019,7 @@ cp_parser_omp_target_enter_data (cp_parser *parser, cp_token *pragma_tok, { cp_parser_error (parser, "expected %"); cp_parser_skip_to_pragma_eol (parser, pragma_tok); - return NULL_TREE; + return false; } if (context == pragma_stmt) @@ -43027,7 +43028,7 @@ cp_parser_omp_target_enter_data (cp_parser *parser, cp_token *pragma_tok, "%<#pragma %s%> may only be used in compound statements", "omp target enter data"); cp_parser_skip_to_pragma_eol (parser, pragma_tok); - return NULL_TREE; + return true; } tree clauses @@ -43067,14 +43068,15 @@ cp_parser_omp_target_enter_data (cp_parser *parser, cp_token *pragma_tok, error_at (pragma_tok->location, "%<#pragma omp target enter data%> must contain at least " "one % clause"); - return NULL_TREE; + return true; } tree stmt = make_node (OMP_TARGET_ENTER_DATA); TREE_TYPE (stmt) = void_type_node; OMP_TARGET_ENTER_DATA_CLAUSES (stmt) = clauses; SET_EXPR_LOCATION (stmt, pragma_tok->location); - return add_stmt (stmt); + add_stmt (stmt); + return true; } /* OpenMP 4.5: @@ -43088,7 +43090,7 @@ cp_parser_omp_target_enter_data (cp_parser *parser, cp_token *pragma_tok, | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) -static tree +static bool cp_parser_omp_target_exit_data (cp_parser *parser, cp_token *pragma_tok, enum pragma_context context) { @@ -43108,7 +43110,7 @@ cp_parser_omp_target_exit_data (cp_parser *parser, cp_token *pragma_tok, { cp_parser_error (parser, "expected %"); cp_parser_skip_to_pragma_eol (parser, pragma_tok); - return NULL_TREE; + return false; } if (context == pragma_stmt) @@ -43117,7 +43119,7 @@ cp_parser_omp_target_exit_data (cp_parser *parser, cp_token *pragma_tok, "%<#pragma %s%> may only be used in compound statements", "omp target exit data"); cp_parser_skip_to_pragma_eol (parser, pragma_tok); - return NULL_TREE; + return true; } tree clauses @@ -43159,14 +43161,15 @@ cp_parser_omp_target_exit_data (cp_parser *parser, cp_token *pragma_tok, error_at (pragma_tok->location, "%<#pragma omp target exit data%> must contain at least " "one % clause"); - return NULL_TREE; + return true; } tree stmt = make_node (OMP_TARGET_EXIT_DATA); TREE_TYPE (stmt) = void_type_node; OMP_TARGET_EXIT_DATA_CLAUSES (stmt) = clauses; SET_EXPR_LOCATION (stmt, pragma_tok->location); - return add_stmt (stmt); + add_stmt (stmt); + return true; } /* OpenMP 4.0: @@ -43190,7 +43193,7 @@ cp_parser_omp_target_update (cp_parser *parser, cp_token *pragma_tok, "%<#pragma %s%> may only be used in compound statements", "omp target update"); cp_parser_skip_to_pragma_eol (parser, pragma_tok); - return false; + return true; } tree clauses @@ -43202,7 +43205,7 @@ cp_parser_omp_target_update (cp_parser *parser, cp_token *pragma_tok, error_at (pragma_tok->location, "%<#pragma omp target update%> must contain at least one " "% or % clauses"); - return false; + return true; } tree stmt = make_node (OMP_TARGET_UPDATE); @@ -43210,7 +43213,7 @@ cp_parser_omp_target_update (cp_parser *parser, cp_token *pragma_tok, OMP_TARGET_UPDATE_CLAUSES (stmt) = clauses; SET_EXPR_LOCATION (stmt, pragma_tok->location); add_stmt (stmt); - return false; + return true; } /* OpenMP 4.0: @@ -43364,14 +43367,12 @@ cp_parser_omp_target (cp_parser *parser, cp_token *pragma_tok, else if (strcmp (p, "enter") == 0) { cp_lexer_consume_token (parser->lexer); - cp_parser_omp_target_enter_data (parser, pragma_tok, context); - return false; + return cp_parser_omp_target_enter_data (parser, pragma_tok, context); } else if (strcmp (p, "exit") == 0) { cp_lexer_consume_token (parser->lexer); - cp_parser_omp_target_exit_data (parser, pragma_tok, context); - return false; + return cp_parser_omp_target_exit_data (parser, pragma_tok, context); } else if (strcmp (p, "update") == 0) { @@ -46432,7 +46433,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) cp_token *pragma_tok; unsigned int id; tree stmt; - bool ret; + bool ret = false; pragma_tok = cp_lexer_consume_token (parser->lexer); gcc_assert (pragma_tok->type == CPP_PRAGMA); @@ -46457,6 +46458,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) case pragma_stmt: error_at (pragma_tok->location, "%<#pragma %s%> may only be " "used in compound statements", "omp barrier"); + ret = true; break; default: goto bad_stmt; @@ -46472,6 +46474,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) case pragma_stmt: error_at (pragma_tok->location, "%<#pragma %s%> may only be " "used in compound statements", "omp depobj"); + ret = true; break; default: goto bad_stmt; @@ -46487,6 +46490,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) case pragma_stmt: error_at (pragma_tok->location, "%<#pragma %s%> may only be " "used in compound statements", "omp flush"); + ret = true; break; default: goto bad_stmt; @@ -46503,6 +46507,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) error_at (pragma_tok->location, "%<#pragma %s%> may only be used in compound statements", "omp taskwait"); + ret = true; break; default: goto bad_stmt; @@ -46519,6 +46524,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) error_at (pragma_tok->location, "%<#pragma %s%> may only be used in compound statements", "omp taskyield"); + ret = true; break; default: goto bad_stmt; @@ -46535,6 +46541,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) error_at (pragma_tok->location, "%<#pragma %s%> may only be used in compound statements", "omp cancel"); + ret = true; break; default: goto bad_stmt; @@ -46542,8 +46549,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) break; case PRAGMA_OMP_CANCELLATION_POINT: - cp_parser_omp_cancellation_point (parser, pragma_tok, context); - return false; + return cp_parser_omp_cancellation_point (parser, pragma_tok, context); case PRAGMA_OMP_THREADPRIVATE: cp_parser_omp_threadprivate (parser, pragma_tok); @@ -46562,6 +46568,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) error_at (pragma_tok->location, "%<#pragma %s%> may only be used in compound statements", "acc enter data"); + ret = true; break; } else if (context != pragma_compound) @@ -46575,6 +46582,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) error_at (pragma_tok->location, "%<#pragma %s%> may only be used in compound statements", "acc exit data"); + ret = true; break; } else if (context != pragma_compound) @@ -46587,6 +46595,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) { error_at (pragma_tok->location, "%<#pragma acc routine%> must be at file scope"); + ret = true; break; } cp_parser_oacc_routine (parser, pragma_tok, context); @@ -46598,6 +46607,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) error_at (pragma_tok->location, "%<#pragma %s%> may only be used in compound statements", "acc update"); + ret = true; break; } else if (context != pragma_compound) @@ -46611,6 +46621,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) error_at (pragma_tok->location, "%<#pragma %s%> may only be used in compound statements", "acc wait"); + ret = true; break; } else if (context != pragma_compound) @@ -46657,6 +46668,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) error_at (pragma_tok->location, "%<#pragma omp requires%> may only be used at file or " "namespace scope"); + ret = true; break; } return cp_parser_omp_requires (parser, pragma_tok); @@ -46769,7 +46781,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) } cp_parser_skip_to_pragma_eol (parser, pragma_tok); - return false; + return ret; } /* The interface the pragma parsers have to the lexer. */ diff --git a/gcc/testsuite/c-c++-common/gomp/pr63326.c b/gcc/testsuite/c-c++-common/gomp/pr63326.c index 3e62723..48ab4f6 100644 --- a/gcc/testsuite/c-c++-common/gomp/pr63326.c +++ b/gcc/testsuite/c-c++-common/gomp/pr63326.c @@ -156,64 +156,64 @@ f4 (int x) { do #pragma omp barrier /* { dg-error "may only be used in compound statements" } */ - while (0); /* { dg-error "before" "" { target c++ } } */ - } /* { dg-error "before" "" { target c++ } } */ + while (0); + } { do #pragma omp flush /* { dg-error "may only be used in compound statements" } */ - while (0); /* { dg-error "before" "" { target c++ } } */ - } /* { dg-error "before" "" { target c++ } } */ + while (0); + } { do #pragma omp taskwait /* { dg-error "may only be used in compound statements" } */ - while (0); /* { dg-error "before" "" { target c++ } } */ - } /* { dg-error "before" "" { target c++ } } */ + while (0); + } { do #pragma omp taskyield /* { dg-error "may only be used in compound statements" } */ - while (0); /* { dg-error "before" "" { target c++ } } */ - } /* { dg-error "before" "" { target c++ } } */ + while (0); + } #pragma omp parallel { do #pragma omp cancel parallel /* { dg-error "may only be used in compound statements" } */ - while (0); /* { dg-error "before" "" { target c++ } } */ - } /* { dg-error "before" "" { target c++ } } */ + while (0); + } #pragma omp parallel { do #pragma omp cancellation point parallel /* { dg-error "may only be used in compound statements" } */ - while (0); /* { dg-error "before" "" { target c++ } } */ - } /* { dg-error "before" "" { target c++ } } */ + while (0); + } #pragma omp for ordered(1) for (i = 0; i < 16; i++) { { do #pragma omp ordered depend(source) /* { dg-error "may only be used in compound statements" } */ - while (0); /* { dg-error "before" "" { target c++ } } */ - } /* { dg-error "before" "" { target c++ } } */ + while (0); + } { do #pragma omp ordered depend(sink: i-1) /* { dg-error "may only be used in compound statements" } */ - while (0); /* { dg-error "before" "" { target c++ } } */ - } /* { dg-error "before" "" { target c++ } } */ + while (0); + } } { do #pragma omp target enter data map(to:i) /* { dg-error "may only be used in compound statements" } */ - while (0); /* { dg-error "before" "" { target c++ } } */ - } /* { dg-error "before" "" { target c++ } } */ + while (0); + } { do #pragma omp target update to(i) /* { dg-error "may only be used in compound statements" } */ - while (0); /* { dg-error "before" "" { target c++ } } */ - } /* { dg-error "before" "" { target c++ } } */ + while (0); + } { do #pragma omp target exit data map(from:i) /* { dg-error "may only be used in compound statements" } */ - while (0); /* { dg-error "before" "" { target c++ } } */ - } /* { dg-error "before" "" { target c++ } } */ + while (0); + } } void diff --git a/gcc/testsuite/g++.dg/gomp/attrs-7.C b/gcc/testsuite/g++.dg/gomp/attrs-7.C index 598c32a..cf84281 100644 --- a/gcc/testsuite/g++.dg/gomp/attrs-7.C +++ b/gcc/testsuite/g++.dg/gomp/attrs-7.C @@ -11,8 +11,7 @@ foo () // { dg-error "#pragma omp section" "" { target *-*-* } .-1 } // { dg-error "#pragma omp flush" "" { target *-*-* } .-2 } [[omp::sequence (directive (flush), omp::directive (section))]]; // { dg-error "must be the only specified attribute on a statement" } - // { dg-error "#pragma omp section" "" { target *-*-* } .-1 } - // { dg-error "#pragma omp flush" "" { target *-*-* } .-2 } + // { dg-error "#pragma omp flush" "" { target *-*-* } .-1 } [[gnu::cold, omp::directive (section)]]; // { dg-error "must be the only specified attribute on a statement" } // { dg-error "#pragma omp section" "" { target *-*-* } .-1 } [[omp::directive (section)]] [[gnu::cold]]; // { dg-error "must be the only specified attribute on a statement" } diff --git a/gcc/testsuite/g++.dg/gomp/barrier-2.C b/gcc/testsuite/g++.dg/gomp/barrier-2.C index 1d929d2..6f3fded 100644 --- a/gcc/testsuite/g++.dg/gomp/barrier-2.C +++ b/gcc/testsuite/g++.dg/gomp/barrier-2.C @@ -9,4 +9,4 @@ void f3(bool p) { if (p) #pragma omp barrier // { dg-error "compound statements" } -} // { dg-error "" } +} diff --git a/gcc/testsuite/gcc.dg/gomp/barrier-2.c b/gcc/testsuite/gcc.dg/gomp/barrier-2.c index c0d62f5..ef605a0 100644 --- a/gcc/testsuite/gcc.dg/gomp/barrier-2.c +++ b/gcc/testsuite/gcc.dg/gomp/barrier-2.c @@ -16,8 +16,7 @@ void f1(void) void f2(void) { - label: /* { dg-error "label at end of compound statement" } */ - /* { dg-warning "defined but not used" "" { target *-*-* } .-1 } */ + label: /* { dg-warning "defined but not used" } */ #pragma omp barrier /* { dg-error "may only be used in compound statements" } */ } diff --git a/gcc/testsuite/gcc.dg/gomp/declare-simd-5.c b/gcc/testsuite/gcc.dg/gomp/declare-simd-5.c index b9a4161..9397820 100644 --- a/gcc/testsuite/gcc.dg/gomp/declare-simd-5.c +++ b/gcc/testsuite/gcc.dg/gomp/declare-simd-5.c @@ -15,7 +15,7 @@ f1 (int x) lab: #pragma omp declare simd simdlen (8) aligned (b : 8 * sizeof (int)) extern int f5 (int a, int *b, int c); /* { dg-error "must be followed by function declaration or definition" } */ - x++; /* { dg-error "a label can only be part of a statement and a declaration is not a statement" "" { target *-*-* } .-1 } */ + x++; } return x; } diff --git a/gcc/testsuite/gcc.dg/gomp/declare-variant-2.c b/gcc/testsuite/gcc.dg/gomp/declare-variant-2.c index 39c2c1d..3da5dc7 100644 --- a/gcc/testsuite/gcc.dg/gomp/declare-variant-2.c +++ b/gcc/testsuite/gcc.dg/gomp/declare-variant-2.c @@ -17,7 +17,7 @@ f1 (int x) lab: #pragma omp declare variant (fn0) match (user={condition(0)}) extern int f5 (int a, int *b, int c); /* { dg-error "must be followed by function declaration or definition" } */ - x++; /* { dg-error "a label can only be part of a statement and a declaration is not a statement" "" { target *-*-* } .-1 } */ + x++; } return x; } -- cgit v1.1 From 5079b7781a2c506dcdfb241347d74c7891268225 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Wed, 18 Aug 2021 11:10:43 +0200 Subject: openmp: Add nothing directive support As has been clarified, it is intentional that nothing directive is accepted in substatements of selection and looping statements and after labels and is handled as if the directive just isn't there, so that void foo (int x) { if (x) #pragma omp metadirective when (...:nothing) when (...:parallel) bar (); } behaves consistently; declarative and stand-alone directives aren't allowed at that point, but constructs are parsed with the following statement as the construct body and nothing or missing default on metadirective therefore should handle the following statement as part of the if substatement instead of having nothing as the substatement and bar done unconditionally after the if. 2021-08-18 Jakub Jelinek gcc/c-family/ * c-pragma.h (enum pragma_kind): Add PRAGMA_OMP_NOTHING. * c-pragma.c (omp_pragmas): Add nothing directive. * c-omp.c (omp_directives): Uncomment nothing directive entry. gcc/c/ * c-parser.c (c_parser_omp_nothing): New function. (c_parser_pragma): Handle PRAGMA_OMP_NOTHING. gcc/cp/ * parser.c (cp_parser_omp_nothing): New function. (cp_parser_pragma): Handle PRAGMA_OMP_NOTHING. gcc/testsuite/ * c-c++-common/gomp/nothing-1.c: New test. * g++.dg/gomp/attrs-1.C (bar): Add nothing directive test. * g++.dg/gomp/attrs-2.C (bar): Likewise. * g++.dg/gomp/attrs-9.C: Likewise. libgomp/ * testsuite/libgomp.c-c++-common/nothing-1.c: New test. --- gcc/c-family/c-omp.c | 4 ++-- gcc/c-family/c-pragma.c | 1 + gcc/c-family/c-pragma.h | 1 + gcc/c/c-parser.c | 15 ++++++++++++ gcc/cp/parser.c | 14 +++++++++++ gcc/testsuite/c-c++-common/gomp/nothing-1.c | 37 +++++++++++++++++++++++++++++ gcc/testsuite/g++.dg/gomp/attrs-1.C | 1 + gcc/testsuite/g++.dg/gomp/attrs-2.C | 1 + gcc/testsuite/g++.dg/gomp/attrs-9.C | 1 + 9 files changed, 73 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/c-c++-common/gomp/nothing-1.c (limited to 'gcc') diff --git a/gcc/c-family/c-omp.c b/gcc/c-family/c-omp.c index de49d26..d4e98bf 100644 --- a/gcc/c-family/c-omp.c +++ b/gcc/c-family/c-omp.c @@ -3007,8 +3007,8 @@ static const struct c_omp_directive omp_directives[] = { C_OMP_DIR_CONSTRUCT, true }, /* { "metadirective", nullptr, nullptr, PRAGMA_OMP_METADIRECTIVE, C_OMP_DIR_???, ??? }, */ - /* { "nothing", nullptr, nullptr, PRAGMA_OMP_NOTHING, - C_OMP_DIR_UTILITY, false }, */ + { "nothing", nullptr, nullptr, PRAGMA_OMP_NOTHING, + C_OMP_DIR_UTILITY, false }, /* ordered with depend clause is C_OMP_DIR_STANDALONE. */ { "ordered", nullptr, nullptr, PRAGMA_OMP_ORDERED, C_OMP_DIR_CONSTRUCT, true }, diff --git a/gcc/c-family/c-pragma.c b/gcc/c-family/c-pragma.c index 5f0096f..238309d 100644 --- a/gcc/c-family/c-pragma.c +++ b/gcc/c-family/c-pragma.c @@ -1328,6 +1328,7 @@ static const struct omp_pragma_def omp_pragmas[] = { { "depobj", PRAGMA_OMP_DEPOBJ }, { "end", PRAGMA_OMP_END_DECLARE_TARGET }, { "flush", PRAGMA_OMP_FLUSH }, + { "nothing", PRAGMA_OMP_NOTHING }, { "requires", PRAGMA_OMP_REQUIRES }, { "scope", PRAGMA_OMP_SCOPE }, { "section", PRAGMA_OMP_SECTION }, diff --git a/gcc/c-family/c-pragma.h b/gcc/c-family/c-pragma.h index 2b9e5ea..dc9e8a6 100644 --- a/gcc/c-family/c-pragma.h +++ b/gcc/c-family/c-pragma.h @@ -57,6 +57,7 @@ enum pragma_kind { PRAGMA_OMP_FLUSH, PRAGMA_OMP_FOR, PRAGMA_OMP_LOOP, + PRAGMA_OMP_NOTHING, PRAGMA_OMP_MASKED, PRAGMA_OMP_MASTER, PRAGMA_OMP_ORDERED, diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index 565efc4..d5f51b1 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -1578,6 +1578,7 @@ static tree c_parser_omp_for_loop (location_t, c_parser *, enum tree_code, static void c_parser_omp_taskwait (c_parser *); static void c_parser_omp_taskyield (c_parser *); static void c_parser_omp_cancel (c_parser *); +static void c_parser_omp_nothing (c_parser *); enum pragma_context { pragma_external, pragma_struct, pragma_param, pragma_stmt, pragma_compound }; @@ -12480,6 +12481,10 @@ c_parser_pragma (c_parser *parser, enum pragma_context context, bool *if_p) c_parser_omp_requires (parser); return false; + case PRAGMA_OMP_NOTHING: + c_parser_omp_nothing (parser); + return false; + case PRAGMA_OMP_ORDERED: return c_parser_omp_ordered (parser, context, if_p); @@ -21908,6 +21913,16 @@ c_parser_omp_taskloop (location_t loc, c_parser *parser, return ret; } +/* OpenMP 5.1 + #pragma omp nothing new-line */ + +static void +c_parser_omp_nothing (c_parser *parser) +{ + c_parser_consume_pragma (parser); + c_parser_skip_to_pragma_eol (parser); +} + /* Main entry point to parsing most OpenMP pragmas. */ static void diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 8f2d0fc..04116fb 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -45564,6 +45564,16 @@ cp_parser_omp_requires (cp_parser *parser, cp_token *pragma_tok) } +/* OpenMP 5.1: + #pragma omp nothing new-line */ + +static void +cp_parser_omp_nothing (cp_parser *parser, cp_token *pragma_tok) +{ + cp_parser_skip_to_pragma_eol (parser, pragma_tok); +} + + /* OpenMP 4.5: #pragma omp taskloop taskloop-clause[optseq] new-line for-loop @@ -46673,6 +46683,10 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) } return cp_parser_omp_requires (parser, pragma_tok); + case PRAGMA_OMP_NOTHING: + cp_parser_omp_nothing (parser, pragma_tok); + return false; + case PRAGMA_OMP_ORDERED: if (context != pragma_stmt && context != pragma_compound) goto bad_stmt; diff --git a/gcc/testsuite/c-c++-common/gomp/nothing-1.c b/gcc/testsuite/c-c++-common/gomp/nothing-1.c new file mode 100644 index 0000000..d50c92a --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/nothing-1.c @@ -0,0 +1,37 @@ +#pragma omp nothing + +struct S +{ + #pragma omp nothing + int s; +}; + +int +foo (int i) +{ + #pragma omp nothing + if (0) + #pragma omp nothing + i++; + if (1) + ; + else + #pragma omp nothing + i++; + switch (0) + #pragma omp nothing + { + default: + break; + } + while (0) + #pragma omp nothing + i++; + for (; 0;) + #pragma omp nothing + i++; + lab: + #pragma omp nothing + i++; + return i; +} diff --git a/gcc/testsuite/g++.dg/gomp/attrs-1.C b/gcc/testsuite/g++.dg/gomp/attrs-1.C index 686acf5..435d54f 100644 --- a/gcc/testsuite/g++.dg/gomp/attrs-1.C +++ b/gcc/testsuite/g++.dg/gomp/attrs-1.C @@ -111,6 +111,7 @@ void bar (int d, int m, int i1, int i2, int i3, int p, int *idp, int s, int nte, int tl, int nth, int g, int nta, int fi, int pp, int *q, int *dd, int ntm) { + [[omp::directive (nothing)]]; [[omp::directive (for simd private (p) firstprivate (f) lastprivate (l) linear (ll:1) reduction(+:r) schedule(static, 4) collapse(1) nowait safelen(8) simdlen(4) aligned(q: 32) nontemporal(ntm) if(i1) order(concurrent) allocate (f))]] diff --git a/gcc/testsuite/g++.dg/gomp/attrs-2.C b/gcc/testsuite/g++.dg/gomp/attrs-2.C index 2190457..bea657f 100644 --- a/gcc/testsuite/g++.dg/gomp/attrs-2.C +++ b/gcc/testsuite/g++.dg/gomp/attrs-2.C @@ -111,6 +111,7 @@ void bar (int d, int m, int i1, int i2, int i3, int p, int *idp, int s, int nte, int tl, int nth, int g, int nta, int fi, int pp, int *q, int *dd, int ntm) { + [[omp::directive (nothing)]]; [[omp::directive (for simd, private (p),firstprivate (f),lastprivate (l),linear (ll:1),reduction(+:r),schedule(static, 4),collapse(1),nowait, safelen(8),simdlen(4),aligned(q: 32),nontemporal(ntm),if(i1),order(concurrent),allocate (f))]] diff --git a/gcc/testsuite/g++.dg/gomp/attrs-9.C b/gcc/testsuite/g++.dg/gomp/attrs-9.C index 0af556c..08cd2b1 100644 --- a/gcc/testsuite/g++.dg/gomp/attrs-9.C +++ b/gcc/testsuite/g++.dg/gomp/attrs-9.C @@ -13,3 +13,4 @@ int b, c; int d; [[omp::directive (end declare target)]]; [[omp::directive (end declare target)]]; +[[omp::directive (nothing)]]; -- cgit v1.1 From 602fca427df6c5f7452677cfcdd16a5b9a3ca86a Mon Sep 17 00:00:00 2001 From: Thomas Schwinge Date: Tue, 17 Aug 2021 21:15:46 +0200 Subject: Turn 'bool force_collect' parameter to 'ggc_collect' into an 'enum ggc_collect mode' ... to make the meaning more explicit to the reader of the code. Follow-up to recent commit 0edf2e81bb02cba43b649b3f6e7258b68a779ac0 "Turn global 'ggc_force_collect' variable into 'force_collect' parameter to 'ggc_collect'". gcc/ * ggc.h (enum ggc_collect): New. (ggc_collect): Use it. * ggc-page.c: Adjust. * ggc-common.c: Likewise. * ggc-tests.c: Likewise. * read-rtl-function.c: Likewise. * selftest-run-tests.c: Likewise. * doc/gty.texi (Invoking the garbage collector): Likewise. Suggested-by: David Malcolm --- gcc/doc/gty.texi | 6 +++--- gcc/ggc-common.c | 2 +- gcc/ggc-page.c | 5 +++-- gcc/ggc-tests.c | 18 +++++++++--------- gcc/ggc.h | 10 ++++++---- gcc/read-rtl-function.c | 2 +- gcc/selftest-run-tests.c | 2 +- 7 files changed, 24 insertions(+), 21 deletions(-) (limited to 'gcc') diff --git a/gcc/doc/gty.texi b/gcc/doc/gty.texi index b667d1d..2ad7793 100644 --- a/gcc/doc/gty.texi +++ b/gcc/doc/gty.texi @@ -655,9 +655,9 @@ with many other garbage collectors, it is not implicitly invoked by allocation routines when a lot of memory has been consumed. So the only way to have GGC reclaim storage is to call the @code{ggc_collect} function explicitly. -When the @var{force_collect} parameter is set or otherwise an internal -heuristic decides whether to actually collect, this call is -potentially an expensive operation, as it may +With @var{mode} @code{GGC_COLLECT_FORCE} or otherwise (default +@code{GGC_COLLECT_HEURISTIC}) when the internal heuristic decides to +collect, this call is potentially an expensive operation, as it may have to scan the entire heap. Beware that local variables (on the GCC call stack) are not followed by such an invocation (as many other garbage collectors do): you should reference all your data from static diff --git a/gcc/ggc-common.c b/gcc/ggc-common.c index f38e4d5..32ba5be 100644 --- a/gcc/ggc-common.c +++ b/gcc/ggc-common.c @@ -962,7 +962,7 @@ dump_ggc_loc_statistics () if (! GATHER_STATISTICS) return; - ggc_collect (true); + ggc_collect (GGC_COLLECT_FORCE); ggc_mem_desc.dump (GGC_ORIGIN); } diff --git a/gcc/ggc-page.c b/gcc/ggc-page.c index a6fbeca..1c49643 100644 --- a/gcc/ggc-page.c +++ b/gcc/ggc-page.c @@ -2184,7 +2184,7 @@ validate_free_objects (void) /* Top level mark-and-sweep routine. */ void -ggc_collect (bool force_collect) +ggc_collect (enum ggc_collect mode) { /* Avoid frequent unnecessary work by skipping collection if the total allocations haven't expanded much since the last @@ -2196,7 +2196,8 @@ ggc_collect (bool force_collect) memory_block_pool::trim (); float min_expand = allocated_last_gc * param_ggc_min_expand / 100; - if (G.allocated < allocated_last_gc + min_expand && !force_collect) + if (mode == GGC_COLLECT_HEURISTIC + && G.allocated < allocated_last_gc + min_expand) return; timevar_push (TV_GC); diff --git a/gcc/ggc-tests.c b/gcc/ggc-tests.c index 2891c20..e83f701 100644 --- a/gcc/ggc-tests.c +++ b/gcc/ggc-tests.c @@ -47,7 +47,7 @@ test_basic_struct () root_test_struct = ggc_cleared_alloc (); root_test_struct->other = ggc_cleared_alloc (); - ggc_collect (true); + ggc_collect (GGC_COLLECT_FORCE); ASSERT_TRUE (ggc_marked_p (root_test_struct)); ASSERT_TRUE (ggc_marked_p (root_test_struct->other)); @@ -77,7 +77,7 @@ test_length () for (int i = 0; i < count; i++) root_test_of_length->elem[i] = ggc_cleared_alloc (); - ggc_collect (true); + ggc_collect (GGC_COLLECT_FORCE); ASSERT_TRUE (ggc_marked_p (root_test_of_length)); for (int i = 0; i < count; i++) @@ -151,7 +151,7 @@ test_union () test_struct *referenced_by_other = ggc_cleared_alloc (); other->m_ptr = referenced_by_other; - ggc_collect (true); + ggc_collect (GGC_COLLECT_FORCE); ASSERT_TRUE (ggc_marked_p (root_test_of_union_1)); ASSERT_TRUE (ggc_marked_p (ts)); @@ -192,7 +192,7 @@ test_finalization () test_struct_with_dtor::dtor_call_count = 0; - ggc_collect (true); + ggc_collect (GGC_COLLECT_FORCE); /* Verify that the destructor was run for each instance. */ ASSERT_EQ (count, test_struct_with_dtor::dtor_call_count); @@ -210,7 +210,7 @@ test_deletable_global () test_of_deletable = ggc_cleared_alloc (); ASSERT_TRUE (test_of_deletable != NULL); - ggc_collect (true); + ggc_collect (GGC_COLLECT_FORCE); ASSERT_EQ (NULL, test_of_deletable); } @@ -283,7 +283,7 @@ test_inheritance () test_some_subclass_as_base_ptr = new some_subclass (); test_some_other_subclass_as_base_ptr = new some_other_subclass (); - ggc_collect (true); + ggc_collect (GGC_COLLECT_FORCE); /* Verify that the roots and everything referenced by them got marked (both for fields in the base class and those in subclasses). */ @@ -362,7 +362,7 @@ test_chain_next () tail_node = new_node; } - ggc_collect (true); + ggc_collect (GGC_COLLECT_FORCE); /* If we got here, we survived. */ @@ -429,7 +429,7 @@ test_user_struct () num_calls_to_user_gt_ggc_mx = 0; - ggc_collect (true); + ggc_collect (GGC_COLLECT_FORCE); ASSERT_TRUE (ggc_marked_p (root_user_struct_ptr)); ASSERT_TRUE (ggc_marked_p (referenced)); @@ -447,7 +447,7 @@ test_tree_marking () { dummy_unittesting_tree = build_int_cst (integer_type_node, 1066); - ggc_collect (true); + ggc_collect (GGC_COLLECT_FORCE); ASSERT_TRUE (ggc_marked_p (dummy_unittesting_tree)); } diff --git a/gcc/ggc.h b/gcc/ggc.h index 0f640b2..5e921d9 100644 --- a/gcc/ggc.h +++ b/gcc/ggc.h @@ -262,10 +262,12 @@ extern const char *ggc_alloc_string (const char *contents, int length #define ggc_strdup(S) ggc_alloc_string ((S), -1 MEM_STAT_INFO) /* Invoke the collector. Garbage collection occurs only when this - function is called, not during allocations. - Unless FORCE_COLLECT, an internal heuristic decides whether to actually - collect. */ -extern void ggc_collect (bool force_collect = false); + function is called, not during allocations. */ +enum ggc_collect { + GGC_COLLECT_HEURISTIC, + GGC_COLLECT_FORCE +}; +extern void ggc_collect (enum ggc_collect mode = GGC_COLLECT_HEURISTIC); /* Return unused memory pages to the system. */ extern void ggc_trim (void); diff --git a/gcc/read-rtl-function.c b/gcc/read-rtl-function.c index 0badfb9..941d1e1 100644 --- a/gcc/read-rtl-function.c +++ b/gcc/read-rtl-function.c @@ -1861,7 +1861,7 @@ test_loading_labels () /* Ensure that label names read from a dump are GC-managed and are found through the insn. */ - ggc_collect (true); + ggc_collect (GGC_COLLECT_FORCE); ASSERT_TRUE (ggc_marked_p (insn_200)); ASSERT_TRUE (ggc_marked_p (LABEL_NAME (insn_200))); } diff --git a/gcc/selftest-run-tests.c b/gcc/selftest-run-tests.c index 10881fc..6a8f291 100644 --- a/gcc/selftest-run-tests.c +++ b/gcc/selftest-run-tests.c @@ -128,7 +128,7 @@ selftest::run_tests () issues. For example, if any GC-managed items have buggy (or missing) finalizers, this last collection will ensure that things that were failed to be finalized can be detected by valgrind. */ - ggc_collect (true); + ggc_collect (GGC_COLLECT_FORCE); /* Finished running tests; the test_runner dtor will print a summary. */ } -- cgit v1.1 From e4f16e9f357a38ec702fb69a0ffab9d292a6af9b Mon Sep 17 00:00:00 2001 From: Thomas Schwinge Date: Fri, 13 Aug 2021 17:53:12 +0200 Subject: Add more self-tests for 'hash_map' with Value type with non-trivial constructor/destructor ... to document the current behavior. gcc/ * hash-map-tests.c (test_map_of_type_with_ctor_and_dtor): Extend. (test_map_of_type_with_ctor_and_dtor_expand): Add function. (hash_map_tests_c_tests): Call it. --- gcc/hash-map-tests.c | 152 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 152 insertions(+) (limited to 'gcc') diff --git a/gcc/hash-map-tests.c b/gcc/hash-map-tests.c index 5b6b192..257f2be 100644 --- a/gcc/hash-map-tests.c +++ b/gcc/hash-map-tests.c @@ -278,6 +278,156 @@ test_map_of_type_with_ctor_and_dtor () ASSERT_TRUE (val_t::ndefault + val_t::ncopy == val_t::ndtor); } + + + /* Verify basic construction and destruction of Value objects. */ + { + /* Configure, arbitrary. */ + const size_t N_init = 0; + const int N_elem = 28; + + void *a[N_elem]; + for (size_t i = 0; i < N_elem; ++i) + a[i] = &a[i]; + + val_t::ndefault = 0; + val_t::ncopy = 0; + val_t::nassign = 0; + val_t::ndtor = 0; + Map m (N_init); + ASSERT_EQ (val_t::ndefault + + val_t::ncopy + + val_t::nassign + + val_t::ndtor, 0); + + for (int i = 0; i < N_elem; ++i) + { + m.get_or_insert (a[i]); + ASSERT_EQ (val_t::ndefault, 1 + i); + ASSERT_EQ (val_t::ncopy, 0); + ASSERT_EQ (val_t::nassign, 0); + ASSERT_EQ (val_t::ndtor, i); + + m.remove (a[i]); + ASSERT_EQ (val_t::ndefault, 1 + i); + ASSERT_EQ (val_t::ncopy, 0); + ASSERT_EQ (val_t::nassign, 0); + ASSERT_EQ (val_t::ndtor, 1 + i); + } + } +} + +/* Verify aspects of 'hash_table::expand'. */ + +static void +test_map_of_type_with_ctor_and_dtor_expand (bool remove_some_inline) +{ + /* Configure, so that hash table expansion triggers a few times. */ + const size_t N_init = 0; + const int N_elem = 70; + size_t expand_c_expected = 4; + size_t expand_c = 0; + + void *a[N_elem]; + for (size_t i = 0; i < N_elem; ++i) + a[i] = &a[i]; + + typedef hash_map Map; + + /* Note that we are starting with a fresh 'Map'. Even if an existing one has + been cleared out completely, there remain 'deleted' elements, and these + would disturb the following logic, where we don't have access to the + actual 'm_n_deleted' value. */ + size_t m_n_deleted = 0; + + val_t::ndefault = 0; + val_t::ncopy = 0; + val_t::nassign = 0; + val_t::ndtor = 0; + Map m (N_init); + + /* In the following, in particular related to 'expand', we're adapting from + the internal logic of 'hash_table', glossing over "some details" not + relevant for this testing here. */ + + /* Per 'hash_table::hash_table'. */ + size_t m_size; + { + unsigned int size_prime_index_ = hash_table_higher_prime_index (N_init); + m_size = prime_tab[size_prime_index_].prime; + } + + int n_expand_moved = 0; + + for (int i = 0; i < N_elem; ++i) + { + size_t elts = m.elements (); + + /* Per 'hash_table::find_slot_with_hash'. */ + size_t m_n_elements = elts + m_n_deleted; + bool expand = m_size * 3 <= m_n_elements * 4; + + m.get_or_insert (a[i]); + if (expand) + { + ++expand_c; + + /* Per 'hash_table::expand'. */ + { + unsigned int nindex = hash_table_higher_prime_index (elts * 2); + m_size = prime_tab[nindex].prime; + } + m_n_deleted = 0; + + /* All non-deleted elements have been moved. */ + n_expand_moved += i; + if (remove_some_inline) + n_expand_moved -= (i + 2) / 3; + } + + ASSERT_EQ (val_t::ndefault, 1 + i); + ASSERT_EQ (val_t::ncopy, n_expand_moved); + ASSERT_EQ (val_t::nassign, 0); + if (remove_some_inline) + ASSERT_EQ (val_t::ndtor, (i + 2) / 3); + else + ASSERT_EQ (val_t::ndtor, 0); + + /* Remove some inline. This never triggers an 'expand' here, but via + 'm_n_deleted' does influence any following one. */ + if (remove_some_inline + && !(i % 3)) + { + m.remove (a[i]); + /* Per 'hash_table::remove_elt_with_hash'. */ + m_n_deleted++; + + ASSERT_EQ (val_t::ndefault, 1 + i); + ASSERT_EQ (val_t::ncopy, n_expand_moved); + ASSERT_EQ (val_t::nassign, 0); + ASSERT_EQ (val_t::ndtor, 1 + (i + 2) / 3); + } + } + ASSERT_EQ (expand_c, expand_c_expected); + + int ndefault = val_t::ndefault; + int ncopy = val_t::ncopy; + int nassign = val_t::nassign; + int ndtor = val_t::ndtor; + + for (int i = 0; i < N_elem; ++i) + { + if (remove_some_inline + && !(i % 3)) + continue; + + m.remove (a[i]); + ++ndtor; + ASSERT_EQ (val_t::ndefault, ndefault); + ASSERT_EQ (val_t::ncopy, ncopy); + ASSERT_EQ (val_t::nassign, nassign); + ASSERT_EQ (val_t::ndtor, ndtor); + } } /* Test calling empty on a hash_map that has a key type with non-zero @@ -309,6 +459,8 @@ hash_map_tests_c_tests () test_map_of_strings_to_int (); test_map_of_int_to_strings (); test_map_of_type_with_ctor_and_dtor (); + test_map_of_type_with_ctor_and_dtor_expand (false); + test_map_of_type_with_ctor_and_dtor_expand (true); test_nonzero_empty_key (); } -- cgit v1.1 From e12946df34c997e96c3bc7eb5a0247e889ddb7ea Mon Sep 17 00:00:00 2001 From: Jan Hubicka Date: Wed, 18 Aug 2021 13:25:28 +0200 Subject: Add EAF_NOREAD check to tree-ssa-uninit gcc/ChangeLog: 2021-08-18 Jan Hubicka * tree-ssa-uninit.c (maybe_warn_pass_by_reference): Check also EAF_NOREAD. --- gcc/tree-ssa-uninit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc') diff --git a/gcc/tree-ssa-uninit.c b/gcc/tree-ssa-uninit.c index d5cdffb..ad2cf48 100644 --- a/gcc/tree-ssa-uninit.c +++ b/gcc/tree-ssa-uninit.c @@ -712,7 +712,7 @@ maybe_warn_pass_by_reference (gcall *stmt, wlimits &wlims) wlims.always_executed = false; /* Ignore args we are not going to read from. */ - if (gimple_call_arg_flags (stmt, argno - 1) & EAF_UNUSED) + if (gimple_call_arg_flags (stmt, argno - 1) & (EAF_UNUSED | EAF_NOREAD)) continue; tree arg = gimple_call_arg (stmt, argno - 1); -- cgit v1.1 From 88ef1a14bb4ba2bb9e6742bb5ed29d83b30723d0 Mon Sep 17 00:00:00 2001 From: Eric Botcazou Date: Wed, 18 Aug 2021 14:22:07 +0200 Subject: Fix thinko in latest change for GNAT encodings gcc/ada/ * gcc-interface/decl.c (gnat_to_gnu_entity) : Fix thinko in latest change. --- gcc/ada/gcc-interface/decl.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'gcc') diff --git a/gcc/ada/gcc-interface/decl.c b/gcc/ada/gcc-interface/decl.c index 4b6479b..5cedb74 100644 --- a/gcc/ada/gcc-interface/decl.c +++ b/gcc/ada/gcc-interface/decl.c @@ -1998,10 +1998,10 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, bool definition) so we use an intermediate step for standard DWARF. */ if (debug_info_p) { - if (gnat_encodings == DWARF_GNAT_ENCODINGS_ALL) - add_parallel_type (gnu_type, DECL_PARALLEL_TYPE (t)); - else + if (gnat_encodings != DWARF_GNAT_ENCODINGS_ALL) SET_TYPE_DEBUG_TYPE (gnu_type, gnu_field_type); + else if (DECL_PARALLEL_TYPE (t)) + add_parallel_type (gnu_type, DECL_PARALLEL_TYPE (t)); } } -- cgit v1.1 From a6b3db3e8625a3cba1240f0b5e1a29bd6c68b8ca Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Wed, 18 Aug 2021 08:37:42 -0400 Subject: c++: ignore explicit dguides during NTTP CTAD [PR101883] Since (template) argument passing is a copy-initialization context, we mustn't consider explicit deduction guides when deducing a CTAD placeholder type of an NTTP. PR c++/101883 gcc/cp/ChangeLog: * pt.c (convert_template_argument): Pass LOOKUP_IMPLICIT to do_auto_deduction. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/nontype-class49.C: New test. --- gcc/cp/pt.c | 3 ++- gcc/testsuite/g++.dg/cpp2a/nontype-class49.C | 8 ++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/g++.dg/cpp2a/nontype-class49.C (limited to 'gcc') diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 484723b..0c14966 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -8486,7 +8486,8 @@ convert_template_argument (tree parm, can happen in the context of -fnew-ttp-matching. */; else if (tree a = type_uses_auto (t)) { - t = do_auto_deduction (t, arg, a, complain, adc_unify, args); + t = do_auto_deduction (t, arg, a, complain, adc_unify, args, + LOOKUP_IMPLICIT); if (t == error_mark_node) return error_mark_node; } diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-class49.C b/gcc/testsuite/g++.dg/cpp2a/nontype-class49.C new file mode 100644 index 0000000..c83e407 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/nontype-class49.C @@ -0,0 +1,8 @@ +// PR c++/101883 +// { dg-do compile { target c++20 } } + +template struct C { constexpr C(int) { } }; +explicit C(int) -> C; + +template struct X { }; +X<1> x; // { dg-error "deduction|no match" } -- cgit v1.1 From be4a4fb516688d7cfe28a80a4aa333f4ecf0b518 Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Wed, 18 Aug 2021 08:37:45 -0400 Subject: c++: aggregate CTAD and brace elision [PR101344] Here the problem is ultimately that collect_ctor_idx_types always recurses into an eligible sub-CONSTRUCTOR regardless of whether the corresponding pair of braces was elided in the original initializer. This causes us to reject some completely-braced forms of aggregate CTAD as in the first testcase below, because collect_ctor_idx_types effectively assumes that the original initializer is always minimally braced (and so the aggregate deduction candidate is given a function type that's incompatible with the original completely-braced initializer). In order to fix this, collect_ctor_idx_types needs to somehow know the shape of the original initializer when iterating over the reshaped initializer. To that end this patch makes reshape_init flag sub-ctors that were built to undo brace elision in the original ctor, so that collect_ctor_idx_types that determine whether to recurse into a sub-ctor by simply inspecting this flag. This happens to also fix PR101820, which is about aggregate CTAD using designated initializers, for much the same reasons. A curious case is the "intermediately-braced" initialization of 'e3' (which we reject) in the first testcase below. It seems to me we're behaving as specified here (according to [over.match.class.deduct]/1) because the initializer element x_1={1, 2, 3, 4} corresponds to the subobject e_1=E::t, hence the type T_1 of the first function parameter of the aggregate deduction candidate is T(&&)[2][2], but T can't be deduced from x_1 using this parameter type (as opposed to say T(&&)[4]). PR c++/101344 PR c++/101820 gcc/cp/ChangeLog: * cp-tree.h (CONSTRUCTOR_BRACES_ELIDED_P): Define. * decl.c (reshape_init_r): Set it. * pt.c (collect_ctor_idx_types): Recurse into a sub-CONSTRUCTOR iff CONSTRUCTOR_BRACES_ELIDED_P. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/class-deduction-aggr11.C: New test. * g++.dg/cpp2a/class-deduction-aggr12.C: New test. --- gcc/cp/cp-tree.h | 6 +++++ gcc/cp/decl.c | 18 +++++++++++--- gcc/cp/pt.c | 7 +----- .../g++.dg/cpp2a/class-deduction-aggr11.C | 29 ++++++++++++++++++++++ .../g++.dg/cpp2a/class-deduction-aggr12.C | 15 +++++++++++ 5 files changed, 65 insertions(+), 10 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr11.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr12.C (limited to 'gcc') diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 14e2db2..7ba02be 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -4503,6 +4503,12 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter) #define CONSTRUCTOR_IS_PAREN_INIT(NODE) \ (CONSTRUCTOR_CHECK(NODE)->base.private_flag) +/* True if reshape_init built this CONSTRUCTOR to undo the brace elision + of another CONSTRUCTOR. This flag is used during C++20 aggregate + CTAD. */ +#define CONSTRUCTOR_BRACES_ELIDED_P(NODE) \ + (CONSTRUCTOR_CHECK (NODE)->base.protected_flag) + /* True if NODE represents a conversion for direct-initialization in a template. Set by perform_implicit_conversion_flags. */ #define IMPLICIT_CONV_EXPR_DIRECT_INIT(NODE) \ diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 32d07ba..3414cbd 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -6657,7 +6657,8 @@ reshape_init_r (tree type, reshape_iter *d, tree first_initializer_p, /* A non-aggregate type is always initialized with a single initializer. */ if (!CP_AGGREGATE_TYPE_P (type) - /* As is an array with dependent bound. */ + /* As is an array with dependent bound, which we can see + during C++20 aggregate CTAD. */ || (cxx_dialect >= cxx20 && TREE_CODE (type) == ARRAY_TYPE && uses_template_parms (TYPE_DOMAIN (type)))) @@ -6774,6 +6775,7 @@ reshape_init_r (tree type, reshape_iter *d, tree first_initializer_p, initializer already, and there is not a CONSTRUCTOR, it means that there is a missing set of braces (that is, we are processing the case for which reshape_init exists). */ + bool braces_elided_p = false; if (!first_initializer_p) { if (TREE_CODE (stripped_init) == CONSTRUCTOR) @@ -6809,17 +6811,25 @@ reshape_init_r (tree type, reshape_iter *d, tree first_initializer_p, warning (OPT_Wmissing_braces, "missing braces around initializer for %qT", type); + braces_elided_p = true; } /* Dispatch to specialized routines. */ + tree new_init; if (CLASS_TYPE_P (type)) - return reshape_init_class (type, d, first_initializer_p, complain); + new_init = reshape_init_class (type, d, first_initializer_p, complain); else if (TREE_CODE (type) == ARRAY_TYPE) - return reshape_init_array (type, d, first_initializer_p, complain); + new_init = reshape_init_array (type, d, first_initializer_p, complain); else if (VECTOR_TYPE_P (type)) - return reshape_init_vector (type, d, complain); + new_init = reshape_init_vector (type, d, complain); else gcc_unreachable(); + + if (braces_elided_p + && TREE_CODE (new_init) == CONSTRUCTOR) + CONSTRUCTOR_BRACES_ELIDED_P (new_init) = true; + + return new_init; } /* Undo the brace-elision allowed by [dcl.init.aggr] in a diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 0c14966..020a4bf 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -28837,12 +28837,7 @@ collect_ctor_idx_types (tree ctor, tree list, tree elt = NULL_TREE) { tree ftype = elt ? elt : TREE_TYPE (idx); if (BRACE_ENCLOSED_INITIALIZER_P (val) - && CONSTRUCTOR_NELTS (val) - /* As in reshape_init_r, a non-aggregate or array-of-dependent-bound - type gets a single initializer. */ - && CP_AGGREGATE_TYPE_P (ftype) - && !(TREE_CODE (ftype) == ARRAY_TYPE - && uses_template_parms (TYPE_DOMAIN (ftype)))) + && CONSTRUCTOR_BRACES_ELIDED_P (val)) { tree subelt = NULL_TREE; if (TREE_CODE (ftype) == ARRAY_TYPE) diff --git a/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr11.C b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr11.C new file mode 100644 index 0000000..c4806de --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr11.C @@ -0,0 +1,29 @@ +// PR c++/101344 +// { dg-do compile { target c++20 } } + +template +struct A { int m; int t[2]; }; + +A a1{1, {2, 3}}; // previously rejected +A a2{1, 2, 3}; + +struct B { int x, y; }; + +template +struct C { int m; struct { int x, y; } t; }; + +A b1{1, {2, 3}}; // previously rejected +A b2{1, 2, 3}; + +template +struct D { T t[2]; }; + +D d1{1, 2}; +D d2{{1, 2}}; // previously rejected + +template +struct E { T t[2][2]; }; + +E e1{1, 2, 3, 4}; +E e2{{{1, 2}, {3, 4}}}; // previously rejected +E e3{{1, 2, 3, 4}}; // { dg-error "deduction|no match" } diff --git a/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr12.C b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr12.C new file mode 100644 index 0000000..ebe73c1 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr12.C @@ -0,0 +1,15 @@ +// PR c++/101820 +// { dg-do compile { target c++20 } } + +struct Inner { int i = 0; }; + +template +struct Outer { Inner s{}; }; + +Outer o1{ .s = {} }; // works +Outer o2{ .s = Inner{ .i = 1} }; // works +Outer o3{ .s = { .i = 1} }; // does not + +Outer o4{ .s{} }; // works +Outer o5{ .s{Inner{ .i = 1} } }; // works +Outer o6{ .s{ .i = 1} }; // does not -- cgit v1.1 From f74433e70ae94a3b5291e45fea488b1cfdee4a34 Mon Sep 17 00:00:00 2001 From: Tobias Burnus Date: Wed, 18 Aug 2021 15:21:18 +0200 Subject: Fortran: Add OpenMP's nothing directive support Fortran version of commit 5079b7781a2c506dcdfb241347d74c7891268225 gcc/fortran/ChangeLog: * match.h (gfc_match_omp_nothing): New. * openmp.c (gfc_match_omp_nothing): New. * parse.c (decode_omp_directive): Match 'nothing' directive. gcc/testsuite/ChangeLog: * gfortran.dg/nothing-1.f90: New test. * gfortran.dg/nothing-2.f90: New test. --- gcc/fortran/match.h | 1 + gcc/fortran/openmp.c | 11 +++++++++++ gcc/fortran/parse.c | 3 +++ gcc/testsuite/gfortran.dg/nothing-1.f90 | 28 ++++++++++++++++++++++++++++ gcc/testsuite/gfortran.dg/nothing-2.f90 | 7 +++++++ 5 files changed, 50 insertions(+) create mode 100644 gcc/testsuite/gfortran.dg/nothing-1.f90 create mode 100644 gcc/testsuite/gfortran.dg/nothing-2.f90 (limited to 'gcc') diff --git a/gcc/fortran/match.h b/gcc/fortran/match.h index aac16a8..5127b4b 100644 --- a/gcc/fortran/match.h +++ b/gcc/fortran/match.h @@ -175,6 +175,7 @@ match gfc_match_omp_masked_taskloop_simd (void); match gfc_match_omp_master (void); match gfc_match_omp_master_taskloop (void); match gfc_match_omp_master_taskloop_simd (void); +match gfc_match_omp_nothing (void); match gfc_match_omp_ordered (void); match gfc_match_omp_ordered_depend (void); match gfc_match_omp_parallel (void); diff --git a/gcc/fortran/openmp.c b/gcc/fortran/openmp.c index 9675b65..fd219dc 100644 --- a/gcc/fortran/openmp.c +++ b/gcc/fortran/openmp.c @@ -4797,6 +4797,17 @@ gfc_match_omp_ordered (void) return match_omp (EXEC_OMP_ORDERED, OMP_ORDERED_CLAUSES); } +match +gfc_match_omp_nothing (void) +{ + if (gfc_match_omp_eos () != MATCH_YES) + { + gfc_error ("Unexpected junk after $OMP NOTHING statement at %C"); + return MATCH_ERROR; + } + /* Will use ST_NONE; therefore, no EXEC_OMP_ is needed. */ + return MATCH_YES; +} match gfc_match_omp_ordered_depend (void) diff --git a/gcc/fortran/parse.c b/gcc/fortran/parse.c index 24cc9bf..d004732 100644 --- a/gcc/fortran/parse.c +++ b/gcc/fortran/parse.c @@ -1005,6 +1005,9 @@ decode_omp_directive (void) ST_OMP_MASTER_TASKLOOP); matcho ("master", gfc_match_omp_master, ST_OMP_MASTER); break; + case 'n': + matcho ("nothing", gfc_match_omp_nothing, ST_NONE); + break; case 'l': matcho ("loop", gfc_match_omp_loop, ST_OMP_LOOP); break; diff --git a/gcc/testsuite/gfortran.dg/nothing-1.f90 b/gcc/testsuite/gfortran.dg/nothing-1.f90 new file mode 100644 index 0000000..9fc24d4 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/nothing-1.f90 @@ -0,0 +1,28 @@ +module m + implicit none (type, external) + !$omp nothing + + type t + !$omp nothing + integer s + end type + +contains + +integer function foo (i) + integer :: i + + !$omp nothing + if (.false.) & +& & !$omp nothing + i = i + 1 + +! In the following, '& & !$' is not a valid OpenMP sentinel and, +! hence, the line is regarded as comment + if (.false.) & +& & !$omp nothing + then + end if + foo = i +end +end module diff --git a/gcc/testsuite/gfortran.dg/nothing-2.f90 b/gcc/testsuite/gfortran.dg/nothing-2.f90 new file mode 100644 index 0000000..74a4a5a --- /dev/null +++ b/gcc/testsuite/gfortran.dg/nothing-2.f90 @@ -0,0 +1,7 @@ +pure subroutine foo + !$omp nothing ! { dg-error "OpenMP directives other than SIMD or DECLARE TARGET at .1. may not appear in PURE procedures" } +end subroutine + +subroutine bar + !$omp nothing foo ! { dg-error "Unexpected junk after $OMP NOTHING statement" } +end -- cgit v1.1