diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc index 25296a9de8f5bcbd4a7542668c93781d02d6c023..1ed1113f9e3989376eb34cc5922e85df4c27540a 100644 --- a/gcc/cp/decl.cc +++ b/gcc/cp/decl.cc @@ -8401,6 +8401,13 @@ omp_declare_variant_finalize_one (tree decl, tree attr) if (!omp_context_selector_matches (ctx)) return true; TREE_PURPOSE (TREE_VALUE (attr)) = variant; + + // Prepend adjust_args list to variant attributes + tree adjust_args_list = TREE_CHAIN (TREE_CHAIN (chain)); + if (adjust_args_list != NULL_TREE) + DECL_ATTRIBUTES (variant) = tree_cons ( + get_identifier ("omp declare variant variant adjust_args"), + TREE_VALUE (adjust_args_list), DECL_ATTRIBUTES (variant)); } } else if (!processing_template_decl) diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index 07b12224615ae9b5dd8123a49f2f44a67f38ae24..ed10f58422ea02c23afdf98632849c6e7f2551a5 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -19,6 +19,7 @@ along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ #include "config.h" +#include "omp-selectors.h" #define INCLUDE_MEMORY #include "system.h" #include "coretypes.h" @@ -2603,7 +2604,7 @@ static cp_ref_qualifier cp_parser_ref_qualifier_opt static tree cp_parser_tx_qualifier_opt (cp_parser *); static tree cp_parser_late_return_type_opt - (cp_parser *, cp_declarator *, tree &); + (cp_parser *, cp_declarator *, tree &, tree); static tree cp_parser_declarator_id (cp_parser *, bool); static tree cp_parser_type_id @@ -2638,7 +2639,7 @@ static void cp_parser_ctor_initializer_opt_and_function_body (cp_parser *, bool); static tree cp_parser_late_parsing_omp_declare_simd - (cp_parser *, tree); + (cp_parser *, tree, tree); static tree cp_parser_late_parsing_oacc_routine (cp_parser *, tree); @@ -24327,7 +24328,7 @@ cp_parser_direct_declarator (cp_parser* parser, tree requires_clause = NULL_TREE; late_return = cp_parser_late_return_type_opt (parser, declarator, - requires_clause); + requires_clause, params); cp_finalize_omp_declare_simd (parser, &odsd); @@ -25192,8 +25193,8 @@ parsing_function_declarator () function. */ static tree -cp_parser_late_return_type_opt (cp_parser* parser, cp_declarator *declarator, - tree& requires_clause) +cp_parser_late_return_type_opt (cp_parser *parser, cp_declarator *declarator, + tree &requires_clause, tree parms) { cp_token *token; tree type = NULL_TREE; @@ -25229,8 +25230,8 @@ cp_parser_late_return_type_opt (cp_parser* parser, cp_declarator *declarator, if (declare_simd_p) declarator->attributes - = cp_parser_late_parsing_omp_declare_simd (parser, - declarator->attributes); + = cp_parser_late_parsing_omp_declare_simd (parser, declarator->attributes, + parms); if (oacc_routine_p) declarator->attributes = cp_parser_late_parsing_oacc_routine (parser, @@ -38349,6 +38350,8 @@ cp_parser_omp_clause_name (cp_parser *parser) case 'n': if (!strcmp ("no_create", p)) result = PRAGMA_OACC_CLAUSE_NO_CREATE; + else if (!strcmp ("nocontext", p)) + result = PRAGMA_OMP_CLAUSE_NOCONTEXT; else if (!strcmp ("nogroup", p)) result = PRAGMA_OMP_CLAUSE_NOGROUP; else if (!strcmp ("nohost", p)) @@ -38357,6 +38360,8 @@ cp_parser_omp_clause_name (cp_parser *parser) result = PRAGMA_OMP_CLAUSE_NONTEMPORAL; else if (!strcmp ("notinbranch", p)) result = PRAGMA_OMP_CLAUSE_NOTINBRANCH; + else if (!strcmp ("novariants", p)) + result = PRAGMA_OMP_CLAUSE_NOVARIANTS; else if (!strcmp ("nowait", p)) result = PRAGMA_OMP_CLAUSE_NOWAIT; else if (!strcmp ("num_gangs", p)) @@ -40803,6 +40808,56 @@ cp_parser_omp_clause_partial (cp_parser *parser, tree list, location_t loc) return c; } +/* OpenMP 5.1 + novariants ( scalar-expression ) */ + +static tree +cp_parser_omp_clause_novariants (cp_parser *parser, tree list, location_t loc) +{ + matching_parens parens; + if (!parens.require_open (parser)) + return list; + + tree 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_NOVARIANTS, "novariants", loc); + + tree c = build_omp_clause (loc, OMP_CLAUSE_NOVARIANTS); + OMP_CLAUSE_NOVARIANTS_EXPR (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + + return c; +} + +/* OpenMP 5.1 + nocontext ( scalar-expression ) */ + +static tree +cp_parser_omp_clause_nocontext (cp_parser *parser, tree list, location_t loc) +{ + matching_parens parens; + if (!parens.require_open (parser)) + return list; + + tree 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_NOCONTEXT, "nocontext", loc); + + tree c = build_omp_clause (loc, OMP_CLAUSE_NOCONTEXT); + OMP_CLAUSE_NOCONTEXT_EXPR (c) = t; + OMP_CLAUSE_CHAIN (c) = list; + + return c; +} + /* OpenMP 4.0: aligned ( variable-list ) aligned ( variable-list : constant-expression ) */ @@ -42910,6 +42965,16 @@ cp_parser_omp_all_clauses (cp_parser *parser, omp_clause_mask mask, clauses = cp_parser_omp_clause_full (clauses, token->location); c_name = "full"; break; + case PRAGMA_OMP_CLAUSE_NOVARIANTS: + clauses = cp_parser_omp_clause_novariants (parser, clauses, + token->location); + c_name = "novariants"; + break; + case PRAGMA_OMP_CLAUSE_NOCONTEXT: + clauses + = cp_parser_omp_clause_nocontext (parser, clauses, token->location); + c_name = "nocontext"; + break; default: cp_parser_error (parser, "expected an OpenMP clause"); goto saw_error; @@ -49151,12 +49216,160 @@ cp_parser_omp_assumes (cp_parser *parser, cp_token *pragma_tok) return false; } +/* Parse a function dispatch structured block: + + lvalue-expression = target-call ( [expression-list] ); + or + target-call ( [expression-list] ); + + Inspired from cp_parser_assignment_expression and + cp_parser_postfix_expression. +*/ + +static tree +cp_parser_omp_dispatch_body (cp_parser *parser) +{ + /* Parse the binary expressions (lvalue-expression or target-call). */ + cp_expr expr = cp_parser_binary_expression (parser, false, false, false, + PREC_NOT_OPERATOR, NULL); + if (TREE_CODE (STRIP_REFERENCE_REF (expr.get_value ())) == CALL_EXPR + || TREE_CODE (expr) == ERROR_MARK) + return expr; + + /* We have the lvalue, now deal with the assignment. */ + + if (!cp_parser_require (parser, CPP_EQ, RT_EQ)) + return error_mark_node; + + /* Peek at the next token. */ + cp_token *token = cp_lexer_peek_token (parser->lexer); + location_t loc = token->location; + + /* Parse function call. */ + cp_expr rhs = cp_parser_postfix_expression (parser, false, false, false, + false, nullptr); + if (rhs == error_mark_node) + return rhs; + + if (TREE_CODE (STRIP_REFERENCE_REF (rhs.get_value ())) != CALL_EXPR) + { + error_at (EXPR_LOC_OR_LOC (rhs, rhs.get_location ()), + "expected target-function call"); + return error_mark_node; + } + + /* Build the assignment expression. Its default + location: + LHS = RHS + ~~~~^~~~~ + is the location of the '=' token as the + caret, ranging from the start of the lhs to the + end of the rhs. */ + loc = make_location (loc, expr.get_start (), rhs.get_finish ()); + expr = build_x_modify_expr (loc, expr, NOP_EXPR, rhs, NULL_TREE, + complain_flags (false)); + /* TODO: build_x_modify_expr doesn't honor the location, + so we must set it here. */ + expr.set_location (loc); + + return expr; +} + +/* OpenMP 5.1: + # pragma omp dispatch dispatch-clause[optseq] new-line + expression-stmt + + LOC is the location of the #pragma. +*/ + +#define OMP_DISPATCH_CLAUSE_MASK \ + ((OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOVARIANTS) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOCONTEXT) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IS_DEVICE_PTR) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) + +static tree +cp_parser_omp_dispatch (cp_parser *parser, cp_token *pragma_tok) +{ + location_t loc = cp_lexer_peek_token (parser->lexer)->location; + tree stmt = make_node (OMP_DISPATCH); + SET_EXPR_LOCATION (stmt, loc); + TREE_TYPE (stmt) = void_type_node; + + OMP_DISPATCH_CLAUSES (stmt) + = cp_parser_omp_all_clauses (parser, OMP_DISPATCH_CLAUSE_MASK, + "#pragma omp dispatch", pragma_tok); + + // Extract depend clauses and create taskwait + tree depend_clauses = NULL_TREE; + tree *depend_clauses_ptr = &depend_clauses; + for (tree c = OMP_DISPATCH_CLAUSES (stmt); c; c = OMP_CLAUSE_CHAIN (c)) + { + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND) + { + *depend_clauses_ptr = c; + depend_clauses_ptr = &OMP_CLAUSE_CHAIN (c); + } + } + if (depend_clauses != NULL_TREE) + { + tree stmt = make_node (OMP_TASK); + TREE_TYPE (stmt) = void_node; + OMP_TASK_CLAUSES (stmt) = depend_clauses; + OMP_TASK_BODY (stmt) = NULL_TREE; + SET_EXPR_LOCATION (stmt, loc); + add_stmt (stmt); + } + + // Parse expression statement + loc = cp_lexer_peek_token (parser->lexer)->location; + tree dispatch_body = cp_parser_omp_dispatch_body (parser); + if (dispatch_body == error_mark_node) + { + inform (loc, + "%<#pragma omp dispatch%> must be followed by a direct function " + "call with optional assignment"); + cp_parser_skip_to_end_of_block_or_statement (parser); + return NULL_TREE; + } + + // Walk the tree to find the dispatch function call and wrap it into an IFN + tree *dispatch_call; + switch (TREE_CODE (STRIP_REFERENCE_REF (dispatch_body))) + { + case MODIFY_EXPR: + dispatch_call = &TREE_OPERAND (dispatch_body, 1); + break; + case MODOP_EXPR: + dispatch_call = &TREE_OPERAND (dispatch_body, 2); + break; + case CALL_EXPR: + dispatch_call = &dispatch_body; + break; + default: + gcc_unreachable (); + } + if (TREE_CODE (*dispatch_call) == FLOAT_EXPR + || TREE_CODE (*dispatch_call) == CONVERT_EXPR) + dispatch_call = &TREE_OPERAND (*dispatch_call, 0); + *dispatch_call = build_call_expr_internal_loc (loc, IFN_GOMP_DISPATCH, + TREE_TYPE (*dispatch_call), 1, + *dispatch_call); + + cp_parser_consume_semicolon_at_end_of_statement (parser); + OMP_DISPATCH_BODY (stmt) = dispatch_body; + + return add_stmt (stmt); +} + /* Finalize #pragma omp declare variant after a fndecl has been parsed, and put that into "omp declare variant base" attribute. */ static tree cp_finish_omp_declare_variant (cp_parser *parser, cp_token *pragma_tok, - tree attrs) + tree attrs, tree parms) { matching_parens parens; if (!parens.require_open (parser)) @@ -49214,44 +49427,196 @@ cp_finish_omp_declare_variant (cp_parser *parser, cp_token *pragma_tok, location_t finish_loc = get_finish (varid.get_location ()); location_t varid_loc = make_location (caret_loc, start_loc, finish_loc); - 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); + vec<tree> adjust_args_list = vNULL; + bool has_match = false, has_adjust_args = false; + location_t adjust_args_loc = UNKNOWN_LOCATION; + tree need_device_ptr_list = make_node (TREE_LIST); - const char *clause = ""; - location_t match_loc = cp_lexer_peek_token (parser->lexer)->location; - if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) - clause = IDENTIFIER_POINTER (cp_lexer_peek_token (parser->lexer)->u.value); - if (strcmp (clause, "match")) + do { - cp_parser_error (parser, "expected %<match%>"); - goto fail; - } + 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); + const char *clause = ""; + location_t match_loc = cp_lexer_peek_token (parser->lexer)->location; + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) + clause + = IDENTIFIER_POINTER (cp_lexer_peek_token (parser->lexer)->u.value); - if (!parens.require_open (parser)) - goto fail; + enum clause + { + match, + adjust_args + } ccode; - tree ctx = cp_parser_omp_context_selector_specification (parser, true); - if (ctx == error_mark_node) - goto fail; - ctx = omp_check_context_selector (match_loc, ctx); - if (ctx != error_mark_node && variant != error_mark_node) - { - tree match_loc_node = maybe_wrap_with_location (integer_zero_node, - match_loc); - tree loc_node = maybe_wrap_with_location (integer_zero_node, varid_loc); - loc_node = tree_cons (match_loc_node, - build_int_cst (integer_type_node, idk), - build_tree_list (loc_node, integer_zero_node)); - attrs = tree_cons (get_identifier ("omp declare variant base"), - tree_cons (variant, ctx, loc_node), attrs); - if (processing_template_decl) - ATTR_IS_DEPENDENT (attrs) = 1; + if (strcmp (clause, "match") == 0) + ccode = match; + else if (strcmp (clause, "adjust_args") == 0) + { + ccode = adjust_args; + adjust_args_loc = match_loc; + } + else + { + cp_parser_error (parser, "expected %<match%> clause"); + goto fail; + } + + cp_lexer_consume_token (parser->lexer); + + if (!parens.require_open (parser)) + goto fail; + + if (ccode == match) + { + if (has_match) + error_at (match_loc, "too many %<match%> clauses"); + has_match = true; + tree ctx + = cp_parser_omp_context_selector_specification (parser, true); + if (ctx == error_mark_node) + goto fail; + ctx = omp_check_context_selector (match_loc, ctx); + if (ctx != error_mark_node && variant != error_mark_node) + { + tree match_loc_node + = maybe_wrap_with_location (integer_zero_node, match_loc); + tree loc_node + = maybe_wrap_with_location (integer_zero_node, varid_loc); + loc_node + = tree_cons (match_loc_node, + build_int_cst (integer_type_node, idk), + build_tree_list (loc_node, integer_zero_node)); + attrs = tree_cons (get_identifier ("omp declare variant base"), + tree_cons (variant, ctx, loc_node), attrs); + if (processing_template_decl) + ATTR_IS_DEPENDENT (attrs) = 1; + } + if (!parens.require_close (parser)) + goto fail; + } + else if (ccode == adjust_args) + { + has_adjust_args = true; + cp_token *adjust_op_tok = cp_lexer_peek_token (parser->lexer); + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME) + && cp_lexer_nth_token_is (parser->lexer, 2, CPP_COLON)) + { + const char *p = IDENTIFIER_POINTER (adjust_op_tok->u.value); + if (strcmp (p, "need_device_ptr") == 0 + || strcmp (p, "nothing") == 0) + { + cp_lexer_consume_token (parser->lexer); // need_device_ptr + cp_lexer_consume_token (parser->lexer); // : + location_t arg_loc + = cp_lexer_peek_token (parser->lexer)->location; + + tree arg; + tree list + = cp_parser_omp_var_list_no_open (parser, OMP_CLAUSE_ERROR, + NULL_TREE, NULL); + + for (tree c = list; c != NULL_TREE; c = TREE_CHAIN (c)) + { + tree decl = TREE_PURPOSE (c); + int idx; + for (arg = parms, idx = 0; arg != NULL; + arg = TREE_CHAIN (arg), idx++) + if (TREE_VALUE (arg) == decl) + break; + if (arg == NULL_TREE) + { + error_at (arg_loc, "%qD is not a function argument", + decl); + continue; + } + arg = TREE_VALUE (arg); + if (adjust_args_list.contains (arg)) + { + // TODO fix location + error_at (arg_loc, "%qD is specified more than once", + decl); + continue; + } + if (strcmp (p, "need_device_ptr") == 0) + { + bool is_ptr_or_template + = TEMPLATE_PARM_P (TREE_TYPE (arg)) + || POINTER_TYPE_P (TREE_TYPE (arg)); + if (!is_ptr_or_template) + { + error_at (arg_loc, "%qD is not a C pointer", + decl); + continue; + } + } + adjust_args_list.safe_push (arg); + if (strcmp (p, "need_device_ptr") == 0) + { + need_device_ptr_list = chainon ( + need_device_ptr_list, + build_tree_list ( + NULL_TREE, + build_int_cst ( + integer_type_node, + idx))); // Store 0-based argument index, + // as in gimplify_call_expr + } + } + } + else + { + error_at (adjust_op_tok->location, + "expected %<nothing%> or %<need_device_ptr%>"); + goto fail; + } + } + else + { + error_at (adjust_op_tok->location, + "expected %<nothing%> or %<need_device_ptr%> followed " + "by %<:%>"); + goto fail; + } + } + } while (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL)); + + if (has_adjust_args) + { + if (!has_match) + { + error_at (adjust_args_loc, + "an %<adjust_args%> clause requires a %<match%> clause"); + } + else + { + tree ctx = TREE_VALUE (TREE_VALUE (attrs)); + if (!omp_get_context_selector (ctx, OMP_TRAIT_SET_CONSTRUCT, + OMP_TRAIT_CONSTRUCT_DISPATCH)) + error_at ( + adjust_args_loc, + "an %<adjust_args%> clause can only be specified if the " + "%<dispatch%> selector of the construct selector set appears " + "in the %<match%> clause"); + else if (TREE_CHAIN (need_device_ptr_list) != NULL_TREE) + { + // We might not have a DECL for the variant yet. So we store the + // need_device_ptr list in the base function attribute, after loc + // nodes. + gcc_assert (TREE_PURPOSE (attrs) + == get_identifier ("omp declare variant base")); + gcc_assert (TREE_PURPOSE (TREE_VALUE (attrs)) == variant); + TREE_VALUE (attrs) = chainon ( + TREE_VALUE (attrs), + build_tree_list ( + NULL_TREE, + build_tree_list (need_device_ptr_list, + NULL_TREE /*need_device_addr */))); + } + } } - parens.require_close (parser); cp_parser_skip_to_pragma_eol (parser, pragma_tok); return attrs; } @@ -49261,7 +49626,8 @@ cp_finish_omp_declare_variant (cp_parser *parser, cp_token *pragma_tok, been parsed, and put that into "omp declare simd" attribute. */ static tree -cp_parser_late_parsing_omp_declare_simd (cp_parser *parser, tree attrs) +cp_parser_late_parsing_omp_declare_simd (cp_parser *parser, tree attrs, + tree parms) { struct cp_token_cache *ce; cp_omp_declare_simd_data *data = parser->omp_declare_simd; @@ -49305,7 +49671,7 @@ 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); + = cp_finish_omp_declare_variant (parser, pragma_tok, attrs, parms); } cp_parser_pop_lexer (parser); } @@ -49436,9 +49802,8 @@ cp_parser_late_parsing_omp_declare_simd (cp_parser *parser, tree attrs) else { gcc_assert (strcmp (kind, "variant") == 0); - attrs - = cp_finish_omp_declare_variant (parser, pragma_tok, - attrs); + attrs = cp_finish_omp_declare_variant (parser, pragma_tok, + attrs, parms); } gcc_assert (parser->lexer != lexer); vec_safe_truncate (lexer->buffer, 0); @@ -50291,7 +50656,11 @@ cp_parser_omp_declare_reduction (cp_parser *parser, cp_token *pragma_tok, #pragma omp declare target new-line OpenMP 5.0 - #pragma omp declare variant (identifier) match (context-selector) */ + #pragma omp declare variant (identifier) match (context-selector) + + OpenMP 5.1 + #pragma omp declare variant (identifier) match (context-selector) \ + adjust_args (adjust-op:argument-list) */ static bool cp_parser_omp_declare (cp_parser *parser, cp_token *pragma_tok, @@ -51155,6 +51524,9 @@ cp_parser_omp_construct (cp_parser *parser, cp_token *pragma_tok, bool *if_p) case PRAGMA_OMP_UNROLL: stmt = cp_parser_omp_unroll (parser, pragma_tok, if_p); break; + case PRAGMA_OMP_DISPATCH: + stmt = cp_parser_omp_dispatch (parser, pragma_tok); + break; default: gcc_unreachable (); } @@ -51851,6 +52223,10 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) "%<#pragma omp sections%> construct"); break; + case PRAGMA_OMP_DISPATCH: + cp_parser_omp_dispatch (parser, pragma_tok); + return true; + case PRAGMA_IVDEP: case PRAGMA_UNROLL: case PRAGMA_NOVECTOR: diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 35ec7eba0bada694aa9c84d6c7bb6796d0379b92..e4375c204b5296bd4dc54e8f3c5e8629cd6b0e5d 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -17799,6 +17799,16 @@ tsubst_omp_clauses (tree clauses, enum c_omp_region_type ort, = tsubst_expr (OMP_CLAUSE_SIZES_LIST (oc), args, complain, in_decl); break; + case OMP_CLAUSE_NOCONTEXT: + OMP_CLAUSE_NOCONTEXT_EXPR (nc) + = tsubst_expr (OMP_CLAUSE_NOCONTEXT_EXPR (oc), args, complain, + in_decl); + break; + case OMP_CLAUSE_NOVARIANTS: + OMP_CLAUSE_NOVARIANTS_EXPR (nc) + = tsubst_expr (OMP_CLAUSE_NOVARIANTS_EXPR (oc), args, complain, + in_decl); + break; case OMP_CLAUSE_REDUCTION: case OMP_CLAUSE_IN_REDUCTION: case OMP_CLAUSE_TASK_REDUCTION: @@ -19462,6 +19472,16 @@ tsubst_stmt (tree t, tree args, tsubst_flags_t complain, tree in_decl) add_stmt (t); break; + case OMP_DISPATCH: + tmp = tsubst_omp_clauses (OMP_DISPATCH_CLAUSES (t), C_ORT_OMP, args, + complain, in_decl); + stmt = RECUR (OMP_DISPATCH_BODY (t)); + t = copy_node (t); + OMP_DISPATCH_BODY (t) = stmt; + OMP_DISPATCH_CLAUSES (t) = tmp; + add_stmt (t); + break; + case OMP_ATOMIC: gcc_assert (OMP_ATOMIC_DEPENDENT_P (t)); tmp = NULL_TREE; @@ -21205,6 +21225,14 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) } break; + case IFN_GOMP_DISPATCH: + ret = build_call_expr_internal_loc (EXPR_LOCATION (t), + IFN_GOMP_DISPATCH, + TREE_TYPE (call_args[0]), 1, + call_args[0]); + RETURN (ret); + break; + default: /* Unsupported internal function with arguments. */ gcc_unreachable (); diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc index ecdd3da9ea25fdf39d01ff1656e9b17d99eac29b..83f6fe5245fece2a8dede1f94a1272b7b12268ae 100644 --- a/gcc/cp/semantics.cc +++ b/gcc/cp/semantics.cc @@ -7753,6 +7753,26 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) OMP_CLAUSE_FINAL_EXPR (c) = t; break; + case OMP_CLAUSE_NOCONTEXT: + t = OMP_CLAUSE_NOCONTEXT_EXPR (c); + t = maybe_convert_cond (t); + if (t == error_mark_node) + remove = true; + else if (!processing_template_decl) + t = fold_build_cleanup_point_expr (TREE_TYPE (t), t); + OMP_CLAUSE_NOCONTEXT_EXPR (c) = t; + break; + + case OMP_CLAUSE_NOVARIANTS: + t = OMP_CLAUSE_NOVARIANTS_EXPR (c); + t = maybe_convert_cond (t); + if (t == error_mark_node) + remove = true; + else if (!processing_template_decl) + t = fold_build_cleanup_point_expr (TREE_TYPE (t), t); + OMP_CLAUSE_NOVARIANTS_EXPR (c) = t; + break; + case OMP_CLAUSE_GANG: /* Operand 1 is the gang static: argument. */ t = OMP_CLAUSE_OPERAND (c, 1); diff --git a/gcc/testsuite/g++.dg/gomp/adjust-args-1.C b/gcc/testsuite/g++.dg/gomp/adjust-args-1.C new file mode 100644 index 0000000000000000000000000000000000000000..29fde1464f4420567e9df5401011dec3f612771c --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/adjust-args-1.C @@ -0,0 +1,39 @@ +/* Test parsing of OMP clause adjust_args */ +/* { dg-do compile } */ + +int b; + +int f0 (void *a); +int g (void *a); +int f1 (int); + +#pragma omp declare variant (f0) match (construct={target}) adjust_args (nothing: a) /* { dg-error "an 'adjust_args' clause can only be specified if the 'dispatch' selector of the construct selector set appears in the 'match' clause" } */ +int f2 (void *a); +#pragma omp declare variant (f0) match (construct={dispatch,target}) adjust_args (need_device_ptr: a) /* { dg-error "'int f0.void..' used as a variant with incompatible 'construct' selector sets" } */ +int f2a (void *a); +#pragma omp declare variant (f0) match (construct={target,dispatch}) adjust_args (need_device_ptr: a) /* { dg-error "'int f0.void..' used as a variant with incompatible 'construct' selector sets" } */ +int f2b (void *a); +#pragma omp declare variant (f0) match (construct={dispatch},device={arch(gcn)}) adjust_args (need_device_ptr: a) /* { dg-error "'int f0.void..' used as a variant with incompatible 'construct' selector sets" } */ +int f2c (void *a); +#pragma omp declare variant (f1) match (construct={dispatch}) adjust_args (other: a) /* { dg-error "expected 'nothing' or 'need_device_ptr'" } */ +int f3 (int a); +#pragma omp declare variant (f0) adjust_args (nothing: a) /* { dg-error "an 'adjust_args' clause requires a 'match' clause" } */ +int f4 (void *a); +#pragma omp declare variant (f1) match (construct={dispatch}) adjust_args () /* { dg-error "expected 'nothing' or 'need_device_ptr' followed by ':'" } */ +int f5 (int a); +#pragma omp declare variant (f1) match (construct={dispatch}) adjust_args (nothing) /* { dg-error "expected 'nothing' or 'need_device_ptr' followed by ':'" } */ +int f6 (int a); +#pragma omp declare variant (f1) match (construct={dispatch}) adjust_args (nothing:) /* { dg-error "expected unqualified-id before '\\)' token" } */ +int f7 (int a); +#pragma omp declare variant (f1) match (construct={dispatch}) adjust_args (nothing: z) /* { dg-error "'z' has not been declared" } */ +int f8 (int a); +#pragma omp declare variant (f1) match (construct={dispatch}) adjust_args (need_device_ptr: a) /* { dg-error "'a' is not a C pointer" } */ +int f9 (int a); +#pragma omp declare variant (f1) match (construct={dispatch}) adjust_args (nothing: a) adjust_args (nothing: a) /* { dg-error "'a' is specified more than once" } */ +int f10 (int a); +#pragma omp declare variant (g) match (construct={dispatch}) adjust_args (nothing: a) adjust_args (need_device_ptr: a) /* { dg-error "'a' is specified more than once" } */ +int f11 (void *a); +#pragma omp declare variant (g) match (construct={dispatch}) adjust_args (need_device_ptr: b) /* { dg-error "'b' is not a function argument" } */ +int f12 (void *a); +#pragma omp declare variant (g) match (construct={dispatch}) adjust_args (need_device_ptr: this) /* { dg-error "expected unqualified-id before 'this'" } */ +int f13 (void *a); diff --git a/gcc/testsuite/g++.dg/gomp/adjust-args-2.C b/gcc/testsuite/g++.dg/gomp/adjust-args-2.C new file mode 100644 index 0000000000000000000000000000000000000000..a78f06ec19371888e5634d943ffeb1945693c40e --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/adjust-args-2.C @@ -0,0 +1,51 @@ +struct S { + int a; + int g (const void *b); + #pragma omp declare variant (g) match (construct={dispatch}) adjust_args (need_device_ptr: b) + int f0(const void *b); + int operator()() { return a; } + bool operator!() { return !a; } +}; + +template <typename T> +T f0(T a, T *b); + +#pragma omp declare variant (f0) match (construct={dispatch}) adjust_args (need_device_ptr: a, b) +template <typename T> +T f1(T a, T *b); + +namespace N { + class C{ + public: + void g(C *c); + #pragma omp declare variant (g) match (construct={dispatch}) adjust_args (need_device_ptr: c) + void f0(C *c); + }; + void g(C *c); + #pragma omp declare variant (g) match (construct={dispatch}) adjust_args (need_device_ptr: c) + void f0(C *c); +} + +#pragma omp declare variant (g) match (construct={dispatch}) adjust_args (need_device_ptr: c) +void f3(N::C *c); +void f4(S *&s); +#pragma omp declare variant (f4) match (construct={dispatch}) adjust_args (need_device_ptr: s) +void f5(S *&s); + +void test() { + S s, *sp; + N::C c; + int *a, b; + #pragma omp dispatch + s.f0(a); + #pragma omp dispatch + f1(b, a); + #pragma omp dispatch + c.f0(&c); + #pragma omp dispatch + N::f0(&c); + #pragma omp dispatch + f3(&c); + #pragma omp dispatch + f5(sp); +} diff --git a/gcc/testsuite/g++.dg/gomp/adjust-args-3.C b/gcc/testsuite/g++.dg/gomp/adjust-args-3.C new file mode 100644 index 0000000000000000000000000000000000000000..3f9a0cd0071321d17b9d03238ceaa86387bdc961 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/adjust-args-3.C @@ -0,0 +1,6 @@ +// Check that an adjust_args clause does not lead to an ICE when the match +// clause is missing. + +void f(int *, int *, int *); +#pragma omp declare variant(f) adjust_args(need_device_ptr: xxx) /* { dg-error "an 'adjust_args' clause requires a 'match' clause" } */ +void g(int *xxx, int *yyy, int *zzz); diff --git a/gcc/testsuite/g++.dg/gomp/dispatch-1.C b/gcc/testsuite/g++.dg/gomp/dispatch-1.C new file mode 100644 index 0000000000000000000000000000000000000000..fb467afcd85be798db0c4c0296b49cfacb1ce0f2 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/dispatch-1.C @@ -0,0 +1,53 @@ +struct S { + int a; + void f0(double); + int operator()() { return a; } + bool operator!() { return !a; } +}; + +int f0(int); +template <typename T> +T f1(T a, T b); +void (*f2)(void); + +namespace N { + class C{}; + void f0(C); + int a; +} + +int test() { + int result; + double d = 5.0; + N::C c; + S s; + S* sp = &s; + int &r = result; + #pragma omp dispatch + result = f0(5); + #pragma omp dispatch + r = f0(5); + #pragma omp dispatch + N::a = ::f0(5); + #pragma omp dispatch + sp->a = f1<int>(5, 10); + #pragma omp dispatch + s.a = f1(5, 10); + #pragma omp dispatch + f2(); + #pragma omp dispatch + N::f0(c); + #pragma omp dispatch + f0(c); + #pragma omp dispatch + s.f0(d); + #pragma omp dispatch + sp->f0(d); + #pragma omp dispatch + sp->f0(d); + #pragma omp dispatch + s(); + #pragma omp dispatch + !s; + return result; +} diff --git a/gcc/testsuite/g++.dg/gomp/dispatch-2.C b/gcc/testsuite/g++.dg/gomp/dispatch-2.C new file mode 100644 index 0000000000000000000000000000000000000000..c987a371b9702d935a40631b0d431334287c5762 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/dispatch-2.C @@ -0,0 +1,62 @@ +/* Test parsing of #pragma omp dispatch */ +/* { dg-do compile } */ + +struct S { + int a; + int b; + virtual int f (double); +}; + +int f0 (int); + +void f1 (void) +{ + int a, b; + double x; + int arr[1]; + S s; + +#pragma omp dispatch + int c = f0 (a); /* { dg-error "expected primary-expression before 'int'" } */ +#pragma omp dispatch + int f2 (int d); /* { dg-error "expected primary-expression before 'int'" } */ +#pragma omp dispatch + a = b; /* { dg-error "expected target-function call" } */ +#pragma omp dispatch + s.a = f0(a) + b; /* { dg-error "expected ';' before '\\+' token" } */ +#pragma omp dispatch + b = !f0(a); /* { dg-error "expected primary-expression before '!' token" } */ +#pragma omp dispatch + s.b += f0(s.a); /* { dg-error "expected '=' before '\\+=' token" } */ +#pragma omp dispatch +#pragma omp threadprivate(a) /* { dg-error "'#pragma' is not allowed here" } */ + a = f0(b); +#pragma omp dispatch + a = s.f(x); /* { dg-error "'f' is a virtual function but only a direct call is allowed in a dispatch construct" } */ + +#pragma omp dispatch nocontext(s) /* { dg-error "could not convert 's' from 'S' to 'bool'" } */ + f0(a); +#pragma omp dispatch nocontext(a, b) /* { dg-error "expected '\\)' before ','" } */ + f0(a); +#pragma omp dispatch nocontext(a) nocontext(b) /* { dg-error "too many 'nocontext' clauses" } */ + f0(a); +#pragma omp dispatch novariants(s) /* { dg-error "could not convert 's' from 'S' to 'bool'" } */ + f0(a); +#pragma omp dispatch novariants(a, b) /* { dg-error "expected '\\)' before ','" } */ + f0(a); +#pragma omp dispatch novariants(a) novariants(b) /* { dg-error "too many 'novariants' clauses" } */ + f0(a); +#pragma omp dispatch nowait nowait /* { dg-error "too many 'nowait' clauses" } */ + f0(a); +#pragma omp dispatch device(x) /* { dg-error "'device' id must be integral" } */ + f0(a); +#pragma omp dispatch device(arr) /* { dg-error "'device' id must be integral" } */ + f0(a); +#pragma omp dispatch is_device_ptr(x) /* { dg-error "'is_device_ptr' variable is neither a pointer, nor an array nor reference to pointer" } */ + f0(a); +#pragma omp dispatch is_device_ptr(&x) /* { dg-error "expected unqualified-id before '&' token" } */ + f0(a); +#pragma omp dispatch depend(inout: s.f) /* { dg-error "'s.S::f' is not lvalue expression nor array section in 'depend' clause" } */ + f0(a); + +} diff --git a/gcc/testsuite/g++.dg/gomp/dispatch-3.C b/gcc/testsuite/g++.dg/gomp/dispatch-3.C new file mode 100644 index 0000000000000000000000000000000000000000..03fd7dc6f6ce8e46a8765738297e01aa7ea33d98 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/dispatch-3.C @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-fdump-tree-original -fdump-tree-gimple" } */ + +/* Check that the right call to f is wrapped in a GOMP_DISPATCH internal function + before translation and that it is stripped during gimplification. */ + +int &f(int); +void g(int *x) +{ + #pragma omp dispatch + x[f(1)] = f(f(2)); + // ^ only this call to f is a dispatch call +} + +/* { dg-final { scan-tree-dump "\.GOMP_DISPATCH \\(\\*f \\(\\*f \\(2\\)\\)\\)" "original" } } */ +/* { dg-final { scan-tree-dump-times "\.GOMP_DISPATCH" 1 "original" } } */ +/* { dg-final { scan-tree-dump-not "\.GOMP_DISPATCH" "gimple" } } */ diff --git a/gcc/testsuite/g++.dg/gomp/dispatch-4.C b/gcc/testsuite/g++.dg/gomp/dispatch-4.C new file mode 100644 index 0000000000000000000000000000000000000000..a0fe6c746c4b8fb03a0ef7550a4c90267c0d03d9 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/dispatch-4.C @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-fdump-tree-gimple" } */ + +/* Check that no host-to-device pointer conversion happens for a nullptr + argument. */ + +#include <cstddef> + +int variant_fn(int *, int * = NULL); + +#pragma omp declare variant(variant_fn) match(construct={dispatch}) adjust_args(need_device_ptr : x, y) +int bar(int *x, int *y = NULL); + +void sub(int *a, int *b) +{ + int x; + #pragma omp dispatch + x = bar(a); +} + +/* { dg-final { scan-tree-dump-times "__builtin_omp_get_mapped_ptr" 1 "gimple" } } */ +/* { dg-final { scan-tree-dump-not "__builtin_omp_get_mapped_ptr \\(OB" "gimple" } } */ diff --git a/gcc/testsuite/g++.dg/gomp/dispatch-5.C b/gcc/testsuite/g++.dg/gomp/dispatch-5.C new file mode 100644 index 0000000000000000000000000000000000000000..268bbac5d7667a53369883c7b13bae4ea57be727 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/dispatch-5.C @@ -0,0 +1,17 @@ +/* { dg-do compile } */ + +/* Check that the parser does not issue an error when a variant returns a + reference. */ + +int& variant_fn(); + +#pragma omp declare variant(variant_fn) match(construct={target}) +int& bar(); + +void sub(int a) +{ + #pragma omp dispatch + bar(); + #pragma omp dispatch + a = bar(); +} diff --git a/gcc/testsuite/g++.dg/gomp/dispatch-6.C b/gcc/testsuite/g++.dg/gomp/dispatch-6.C new file mode 100644 index 0000000000000000000000000000000000000000..675b1ec8d9ae690c2a662fc60724d1a4edc12249 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/dispatch-6.C @@ -0,0 +1,29 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-fdump-tree-original" } */ + +/* Check that templates are properly handled. */ + +template<typename T> +T templ_var_fn(T x); + +#pragma omp declare variant(templ_var_fn) match(construct={dispatch}) adjust_args(need_device_ptr: x) +template<typename T> +T templ_base_fn(T x); + +template<typename T, typename TB> +void f(int *y, TB x) +{ +#pragma omp dispatch nocontext (x) + y = templ_base_fn<T> (y); +#pragma omp dispatch novariants (x) + y = templ_base_fn<T> (y); +} + +void bar() +{ + int a; + bool b = true; + f<int*,bool> (&a, b); +} + +/* { dg-final { scan-tree-dump-times "y = \.GOMP_DISPATCH \\(templ_base_fn<int\\*> \\(y\\)\\)" 2 "original" } } */ diff --git a/gcc/testsuite/g++.dg/gomp/dispatch-7.C b/gcc/testsuite/g++.dg/gomp/dispatch-7.C new file mode 100644 index 0000000000000000000000000000000000000000..193cca8601506c096f2d3a4cfb5371d2e207597a --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/dispatch-7.C @@ -0,0 +1,43 @@ +// { dg-do compile { target c++11 } } + + +template<typename T> +T templ_var_fn(T x); + + +template<typename T> [[omp::directive (declare variant(templ_var_fn) match(construct={dispatch}) adjust_args(need_device_ptr: x))]] +T templ_base_fn(T x); + +template<typename T, typename TB> +void f(int *y, TB x) +{ +[[omp::directive (dispatch nocontext (x))]] + y = templ_base_fn<T> (y); +[[omp::directive (dispatch novariants (x))]] + y = templ_base_fn<T> (y); +} + +void bar() +{ + int a; + bool b = true; + f<int*,bool> (&a, b); +} + + +void variant_fn(int *x, int *y, int *z); + +[[omp::directive (declare variant(variant_fn) match(construct={dispatch}) adjust_args(need_device_ptr: x,y) adjust_args(nothing: z))]] +void bar(int *x, int *y, int *z); + +void sub(int *x, int *y, int *z) +{ + [[omp::directive (dispatch is_device_ptr(y))]] + bar(x, y, z); + [[omp::directive (dispatch device(0))]] + bar(x, y, z); + [[omp::directive (dispatch nocontext(1) novariants(1))]] + bar(x, y, z); + [[omp::directive (dispatch depend(inout: x) nowait)]] + bar(x, y, z); +}