Hi! OpenMP 5.0 will extend the defaultmap clause from always just the default(tofrom:scalar) form to have various default behaviors before the : and various categories after the : (plus no : category to cover all categories).
There are some issues I've raised on omp-lang, this patch implements what I think is the general intent. Tested on x86_64-linux, committed to gomp-5_0-branch. 2018-05-03 Jakub Jelinek <ja...@redhat.com> * tree-core.h (enum omp_clause_defaultmap_kind): New. (struct tree_omp_clause): Add subcode.defaultmap_kind. * tree.h (OMP_CLAUSE_DEFAULTMAP_KIND, OMP_CLAUSE_DEFAULTMAP_CATEGORY, OMP_CLAUSE_DEFAULTMAP_BEHAVIOR, OMP_CLAUSE_DEFAULTMAP_SET_KIND): Define. * tree-pretty-print.c (dump_omp_clause): Handle new kinds of OMP_CLAUSE_DEFAULTMAP. * gimplify.c (enum gimplify_omp_var_data): Add GOVD_MAP_ALLOC_ONLY and GOVD_MAP_FROM_ONLY. (enum gimplify_defaultmap_kind): New. (struct gimplify_omp_ctx): Remove target_map_scalars_firstprivate and target_map_pointers_as_0len_arrays members, add defaultmap. (new_omp_context): Initialize defaultmap member. (omp_firstprivatize_variable): Test ctx->defaultmap[GDMK_SCALAR] instead of ctx->omp_firstprivatize_variable. (computable_teams_clause): Likewise. (omp_notice_variable): Handle new defaultmap clause kinds. (gimplify_scan_omp_clauses): Likewise. (gimplify_adjust_omp_clauses_1): Handle GOVD_MAP_ALLOC_ONLY and GOVD_MAP_FROM_ONLY. c/ * c-parser.c (c_parser_omp_clause_defaultmap): Parse new kinds of defaultmap clause. cp/ * parser.c (cp_parser_omp_clause_defaultmap): Parse new kinds of defaultmap clause. fortran/ * trans-openmp.c (gfc_trans_omp_clauses): Use OMP_CLAUSE_DEFAULTMAP_SET_KIND. testsuite/ * c-c++-common/gomp/defaultmap-1.c: New test. * c-c++-common/gomp/defaultmap-2.c: New test. * c-c++-common/gomp/defaultmap-3.c: New test. --- gcc/tree-core.h.jj 2018-04-30 14:21:18.317028050 +0200 +++ gcc/tree-core.h 2018-05-02 17:29:55.902260817 +0200 @@ -507,6 +507,25 @@ enum omp_clause_default_kind { OMP_CLAUSE_DEFAULT_LAST }; +enum omp_clause_defaultmap_kind { + OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED, + OMP_CLAUSE_DEFAULTMAP_CATEGORY_SCALAR, + OMP_CLAUSE_DEFAULTMAP_CATEGORY_AGGREGATE, + OMP_CLAUSE_DEFAULTMAP_CATEGORY_ALLOCATABLE, + OMP_CLAUSE_DEFAULTMAP_CATEGORY_POINTER, + OMP_CLAUSE_DEFAULTMAP_CATEGORY_MASK = 7, + OMP_CLAUSE_DEFAULTMAP_ALLOC = 1 * (OMP_CLAUSE_DEFAULTMAP_CATEGORY_MASK + 1), + OMP_CLAUSE_DEFAULTMAP_TO = 2 * (OMP_CLAUSE_DEFAULTMAP_CATEGORY_MASK + 1), + OMP_CLAUSE_DEFAULTMAP_FROM = 3 * (OMP_CLAUSE_DEFAULTMAP_CATEGORY_MASK + 1), + OMP_CLAUSE_DEFAULTMAP_TOFROM = 4 * (OMP_CLAUSE_DEFAULTMAP_CATEGORY_MASK + 1), + OMP_CLAUSE_DEFAULTMAP_FIRSTPRIVATE + = 5 * (OMP_CLAUSE_DEFAULTMAP_CATEGORY_MASK + 1), + OMP_CLAUSE_DEFAULTMAP_NONE = 6 * (OMP_CLAUSE_DEFAULTMAP_CATEGORY_MASK + 1), + OMP_CLAUSE_DEFAULTMAP_DEFAULT + = 7 * (OMP_CLAUSE_DEFAULTMAP_CATEGORY_MASK + 1), + OMP_CLAUSE_DEFAULTMAP_MASK = 7 * (OMP_CLAUSE_DEFAULTMAP_CATEGORY_MASK + 1) +}; + /* There is a TYPE_QUAL value for each type qualifier. They can be combined by bitwise-or to form the complete set of qualifiers for a type. */ @@ -1476,6 +1495,7 @@ struct GTY(()) tree_omp_clause { enum tree_code reduction_code; enum omp_clause_linear_kind linear_kind; enum tree_code if_modifier; + enum omp_clause_defaultmap_kind defaultmap_kind; /* The dimension a OMP_CLAUSE__GRIDDIM_ clause of a gridified target construct describes. */ unsigned int dimension; --- gcc/tree.h.jj 2018-04-30 13:49:45.209825769 +0200 +++ gcc/tree.h 2018-05-02 17:51:03.371341293 +0200 @@ -1695,6 +1695,18 @@ extern tree maybe_wrap_with_location (tr #define OMP_CLAUSE_DEFAULT_KIND(NODE) \ (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_DEFAULT)->omp_clause.subcode.default_kind) +#define OMP_CLAUSE_DEFAULTMAP_KIND(NODE) \ + (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_DEFAULTMAP)->omp_clause.subcode.defaultmap_kind) +#define OMP_CLAUSE_DEFAULTMAP_CATEGORY(NODE) \ + ((enum omp_clause_defaultmap_kind) \ + (OMP_CLAUSE_DEFAULTMAP_KIND (NODE) & OMP_CLAUSE_DEFAULTMAP_CATEGORY_MASK)) +#define OMP_CLAUSE_DEFAULTMAP_BEHAVIOR(NODE) \ + ((enum omp_clause_defaultmap_kind) \ + (OMP_CLAUSE_DEFAULTMAP_KIND (NODE) & OMP_CLAUSE_DEFAULTMAP_MASK)) +#define OMP_CLAUSE_DEFAULTMAP_SET_KIND(NODE, BEHAVIOR, CATEGORY) \ + (OMP_CLAUSE_DEFAULTMAP_KIND (NODE) \ + = (enum omp_clause_defaultmap_kind) (CATEGORY | BEHAVIOR)) + #define OMP_CLAUSE_TILE_LIST(NODE) \ OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_TILE), 0) #define OMP_CLAUSE_TILE_ITERVAR(NODE) \ --- gcc/tree-pretty-print.c.jj 2018-04-30 13:49:23.109778102 +0200 +++ gcc/tree-pretty-print.c 2018-05-02 17:35:03.111530014 +0200 @@ -901,7 +901,53 @@ dump_omp_clause (pretty_printer *pp, tre break; case OMP_CLAUSE_DEFAULTMAP: - pp_string (pp, "defaultmap(tofrom:scalar)"); + pp_string (pp, "defaultmap("); + switch (OMP_CLAUSE_DEFAULTMAP_BEHAVIOR (clause)) + { + case OMP_CLAUSE_DEFAULTMAP_ALLOC: + pp_string (pp, "alloc"); + break; + case OMP_CLAUSE_DEFAULTMAP_TO: + pp_string (pp, "to"); + break; + case OMP_CLAUSE_DEFAULTMAP_FROM: + pp_string (pp, "from"); + break; + case OMP_CLAUSE_DEFAULTMAP_TOFROM: + pp_string (pp, "tofrom"); + break; + case OMP_CLAUSE_DEFAULTMAP_FIRSTPRIVATE: + pp_string (pp, "firstprivate"); + break; + case OMP_CLAUSE_DEFAULTMAP_NONE: + pp_string (pp, "none"); + break; + case OMP_CLAUSE_DEFAULTMAP_DEFAULT: + pp_string (pp, "default"); + break; + default: + gcc_unreachable (); + } + switch (OMP_CLAUSE_DEFAULTMAP_CATEGORY (clause)) + { + case OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED: + break; + case OMP_CLAUSE_DEFAULTMAP_CATEGORY_SCALAR: + pp_string (pp, ":scalar"); + break; + case OMP_CLAUSE_DEFAULTMAP_CATEGORY_AGGREGATE: + pp_string (pp, ":aggregate"); + break; + case OMP_CLAUSE_DEFAULTMAP_CATEGORY_ALLOCATABLE: + pp_string (pp, ":allocatable"); + break; + case OMP_CLAUSE_DEFAULTMAP_CATEGORY_POINTER: + pp_string (pp, ":pointer"); + break; + default: + gcc_unreachable (); + } + pp_right_paren (pp); break; case OMP_CLAUSE__SIMDUID_: --- gcc/gimplify.c.jj 2018-04-30 14:20:12.673001091 +0200 +++ gcc/gimplify.c 2018-05-03 15:22:54.521416751 +0200 @@ -105,6 +105,12 @@ enum gimplify_omp_var_data /* Flag for GOVD_MAP: must be present already. */ GOVD_MAP_FORCE_PRESENT = 524288, + /* Flag for GOVD_MAP: only allocate. */ + GOVD_MAP_ALLOC_ONLY = 1048576, + + /* Flag for GOVD_MAP: only copy back. */ + GOVD_MAP_FROM_ONLY = 2097152, + GOVD_DATA_SHARE_CLASS = (GOVD_SHARED | GOVD_PRIVATE | GOVD_FIRSTPRIVATE | GOVD_LASTPRIVATE | GOVD_REDUCTION | GOVD_LINEAR | GOVD_LOCAL) @@ -176,6 +182,14 @@ struct gimplify_ctx unsigned in_switch_expr : 1; }; +enum gimplify_defaultmap_kind +{ + GDMK_SCALAR, + GDMK_AGGREGATE, + GDMK_ALLOCATABLE, + GDMK_POINTER +}; + struct gimplify_omp_ctx { struct gimplify_omp_ctx *outer_context; @@ -188,9 +202,8 @@ struct gimplify_omp_ctx enum omp_region_type region_type; bool combined_loop; bool distribute; - bool target_map_scalars_firstprivate; - bool target_map_pointers_as_0len_arrays; bool target_firstprivatize_array_bases; + int defaultmap[4]; }; static struct gimplify_ctx *gimplify_ctxp; @@ -413,6 +426,10 @@ new_omp_context (enum omp_region_type re c->default_kind = OMP_CLAUSE_DEFAULT_SHARED; else c->default_kind = OMP_CLAUSE_DEFAULT_UNSPECIFIED; + c->defaultmap[GDMK_SCALAR] = GOVD_MAP; + c->defaultmap[GDMK_AGGREGATE] = GOVD_MAP; + c->defaultmap[GDMK_ALLOCATABLE] = GOVD_MAP; + c->defaultmap[GDMK_POINTER] = GOVD_MAP; return c; } @@ -6685,7 +6702,7 @@ omp_firstprivatize_variable (struct gimp } else if ((ctx->region_type & ORT_TARGET) != 0) { - if (ctx->target_map_scalars_firstprivate) + if (ctx->defaultmap[GDMK_SCALAR] & GOVD_FIRSTPRIVATE) omp_add_variable (ctx, decl, GOVD_FIRSTPRIVATE); else omp_add_variable (ctx, decl, GOVD_MAP | GOVD_MAP_TO_ONLY); @@ -7217,11 +7234,9 @@ omp_notice_variable (struct gimplify_omp if (n == NULL) { unsigned nflags = flags; - if (ctx->target_map_pointers_as_0len_arrays - || ctx->target_map_scalars_firstprivate) + if ((ctx->region_type & ORT_ACC) == 0) { bool is_declare_target = false; - bool is_scalar = false; if (is_global_var (decl) && varpool_node::get_create (decl)->offloadable) { @@ -7238,18 +7253,34 @@ omp_notice_variable (struct gimplify_omp } is_declare_target = octx == NULL; } - if (!is_declare_target && ctx->target_map_scalars_firstprivate) - is_scalar = lang_hooks.decls.omp_scalar_p (decl); - if (is_declare_target) - ; - else if (ctx->target_map_pointers_as_0len_arrays - && (TREE_CODE (TREE_TYPE (decl)) == POINTER_TYPE - || (TREE_CODE (TREE_TYPE (decl)) == REFERENCE_TYPE - && TREE_CODE (TREE_TYPE (TREE_TYPE (decl))) - == POINTER_TYPE))) - nflags |= GOVD_MAP | GOVD_MAP_0LEN_ARRAY; - else if (is_scalar) - nflags |= GOVD_FIRSTPRIVATE; + if (!is_declare_target) + { + int gdmk; + if (TREE_CODE (TREE_TYPE (decl)) == POINTER_TYPE + || (TREE_CODE (TREE_TYPE (decl)) == REFERENCE_TYPE + && (TREE_CODE (TREE_TYPE (TREE_TYPE (decl))) + == POINTER_TYPE))) + gdmk = GDMK_POINTER; + else if (lang_hooks.decls.omp_scalar_p (decl)) + gdmk = GDMK_SCALAR; + else + gdmk = GDMK_AGGREGATE; + if (ctx->defaultmap[gdmk] == 0) + { + tree d = lang_hooks.decls.omp_report_decl (decl); + error ("%qE not specified in enclosing %<target%>", + DECL_NAME (d)); + error_at (ctx->location, "enclosing %<target%>"); + } + else if (ctx->defaultmap[gdmk] + & (GOVD_MAP_0LEN_ARRAY | GOVD_FIRSTPRIVATE)) + nflags |= ctx->defaultmap[gdmk]; + else + { + gcc_assert (ctx->defaultmap[gdmk] & GOVD_MAP); + nflags |= ctx->defaultmap[gdmk] & ~GOVD_MAP; + } + } } struct gimplify_omp_ctx *octx = ctx->outer_context; @@ -7280,28 +7311,28 @@ omp_notice_variable (struct gimplify_omp } } - { - tree type = TREE_TYPE (decl); + if ((nflags & ~(GOVD_MAP_TO_ONLY | GOVD_MAP_FROM_ONLY + | GOVD_MAP_ALLOC_ONLY)) == flags) + { + tree type = TREE_TYPE (decl); - if (nflags == flags - && gimplify_omp_ctxp->target_firstprivatize_array_bases - && lang_hooks.decls.omp_privatize_by_reference (decl)) - type = TREE_TYPE (type); - if (nflags == flags - && !lang_hooks.types.omp_mappable_type (type)) - { - error ("%qD referenced in target region does not have " - "a mappable type", decl); - nflags |= GOVD_MAP | GOVD_EXPLICIT; - } - else if (nflags == flags) - { - if ((ctx->region_type & ORT_ACC) != 0) - nflags = oacc_default_clause (ctx, decl, flags); - else - nflags |= GOVD_MAP; - } - } + if (gimplify_omp_ctxp->target_firstprivatize_array_bases + && lang_hooks.decls.omp_privatize_by_reference (decl)) + type = TREE_TYPE (type); + if (!lang_hooks.types.omp_mappable_type (type)) + { + error ("%qD referenced in target region does not have " + "a mappable type", decl); + nflags |= GOVD_MAP | GOVD_EXPLICIT; + } + else + { + if ((ctx->region_type & ORT_ACC) != 0) + nflags = oacc_default_clause (ctx, decl, flags); + else + nflags |= GOVD_MAP; + } + } found_outer: omp_add_variable (ctx, decl, nflags); } @@ -7545,8 +7576,8 @@ gimplify_scan_omp_clauses (tree *list_p, if (code == OMP_TARGET) { if (!lang_GNU_Fortran ()) - ctx->target_map_pointers_as_0len_arrays = true; - ctx->target_map_scalars_firstprivate = true; + ctx->defaultmap[GDMK_POINTER] = GOVD_MAP | GOVD_MAP_0LEN_ARRAY; + ctx->defaultmap[GDMK_SCALAR] = GOVD_FIRSTPRIVATE; } if (!lang_GNU_Fortran ()) switch (code) @@ -8599,7 +8630,69 @@ gimplify_scan_omp_clauses (tree *list_p, break; case OMP_CLAUSE_DEFAULTMAP: - ctx->target_map_scalars_firstprivate = false; + enum gimplify_defaultmap_kind gdmkmin, gdmkmax; + switch (OMP_CLAUSE_DEFAULTMAP_CATEGORY (c)) + { + case OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED: + gdmkmin = GDMK_SCALAR; + gdmkmax = GDMK_POINTER; + break; + case OMP_CLAUSE_DEFAULTMAP_CATEGORY_SCALAR: + gdmkmin = gdmkmax = GDMK_SCALAR; + break; + case OMP_CLAUSE_DEFAULTMAP_CATEGORY_AGGREGATE: + gdmkmin = gdmkmax = GDMK_AGGREGATE; + break; + case OMP_CLAUSE_DEFAULTMAP_CATEGORY_ALLOCATABLE: + gdmkmin = gdmkmax = GDMK_ALLOCATABLE; + break; + case OMP_CLAUSE_DEFAULTMAP_CATEGORY_POINTER: + gdmkmin = gdmkmax = GDMK_POINTER; + break; + default: + gcc_unreachable (); + } + for (int gdmk = gdmkmin; gdmk <= gdmkmax; gdmk++) + switch (OMP_CLAUSE_DEFAULTMAP_BEHAVIOR (c)) + { + case OMP_CLAUSE_DEFAULTMAP_ALLOC: + ctx->defaultmap[gdmk] = GOVD_MAP | GOVD_MAP_ALLOC_ONLY; + break; + case OMP_CLAUSE_DEFAULTMAP_TO: + ctx->defaultmap[gdmk] = GOVD_MAP | GOVD_MAP_TO_ONLY; + break; + case OMP_CLAUSE_DEFAULTMAP_FROM: + ctx->defaultmap[gdmk] = GOVD_MAP | GOVD_MAP_FROM_ONLY; + break; + case OMP_CLAUSE_DEFAULTMAP_TOFROM: + ctx->defaultmap[gdmk] = GOVD_MAP; + break; + case OMP_CLAUSE_DEFAULTMAP_FIRSTPRIVATE: + ctx->defaultmap[gdmk] = GOVD_FIRSTPRIVATE; + break; + case OMP_CLAUSE_DEFAULTMAP_NONE: + ctx->defaultmap[gdmk] = 0; + break; + case OMP_CLAUSE_DEFAULTMAP_DEFAULT: + switch (gdmk) + { + case GDMK_SCALAR: + ctx->defaultmap[gdmk] = GOVD_FIRSTPRIVATE; + break; + case GDMK_AGGREGATE: + case GDMK_ALLOCATABLE: + ctx->defaultmap[gdmk] = GOVD_MAP; + break; + case GDMK_POINTER: + ctx->defaultmap[gdmk] = GOVD_MAP | GOVD_MAP_0LEN_ARRAY; + break; + default: + gcc_unreachable (); + } + break; + default: + gcc_unreachable (); + } break; case OMP_CLAUSE_ALIGNED: @@ -8898,7 +8991,9 @@ gimplify_adjust_omp_clauses_1 (splay_tre /* Not all combinations of these GOVD_MAP flags are actually valid. */ switch (flags & (GOVD_MAP_TO_ONLY | GOVD_MAP_FORCE - | GOVD_MAP_FORCE_PRESENT)) + | GOVD_MAP_FORCE_PRESENT + | GOVD_MAP_ALLOC_ONLY + | GOVD_MAP_FROM_ONLY)) { case 0: kind = GOMP_MAP_TOFROM; @@ -8909,6 +9004,12 @@ gimplify_adjust_omp_clauses_1 (splay_tre case GOVD_MAP_TO_ONLY: kind = GOMP_MAP_TO; break; + case GOVD_MAP_FROM_ONLY: + kind = GOMP_MAP_FROM; + break; + case GOVD_MAP_ALLOC_ONLY: + kind = GOMP_MAP_ALLOC; + break; case GOVD_MAP_TO_ONLY | GOVD_MAP_FORCE: kind = GOMP_MAP_TO | GOMP_MAP_FLAG_FORCE; break; @@ -10589,7 +10690,7 @@ computable_teams_clause (tree *tp, int * (splay_tree_key) *tp); if (n == NULL) { - if (gimplify_omp_ctxp->target_map_scalars_firstprivate) + if (gimplify_omp_ctxp->defaultmap[GDMK_SCALAR] & GOVD_FIRSTPRIVATE) return NULL_TREE; return *tp; } --- gcc/c/c-parser.c.jj 2018-04-30 15:07:52.972514234 +0200 +++ gcc/c/c-parser.c 2018-05-03 17:16:15.668780501 +0200 @@ -12463,7 +12463,10 @@ c_parser_omp_clause_hint (c_parser *pars } /* OpenMP 4.5: - defaultmap ( tofrom : scalar ) */ + defaultmap ( tofrom : scalar ) + + OpenMP 5.0: + defaultmap ( implicit-behavior [ : variable-category ] ) */ static tree c_parser_omp_clause_defaultmap (c_parser *parser, tree list) @@ -12471,39 +12474,155 @@ c_parser_omp_clause_defaultmap (c_parser location_t loc = c_parser_peek_token (parser)->location; tree c; const char *p; + enum omp_clause_defaultmap_kind behavior = OMP_CLAUSE_DEFAULTMAP_DEFAULT; + enum omp_clause_defaultmap_kind category + = OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED; matching_parens parens; if (!parens.require_open (parser)) return list; - if (!c_parser_next_token_is (parser, CPP_NAME)) + if (c_parser_next_token_is_keyword (parser, RID_DEFAULT)) + p = "default"; + else if (!c_parser_next_token_is (parser, CPP_NAME)) { - c_parser_error (parser, "expected %<tofrom%>"); + invalid_behavior: + c_parser_error (parser, "expected %<alloc%>, %<to%>, %<from%>, " + "%<tofrom%>, %<firstprivate%>, %<none%> " + "or %<default%>"); goto out_err; } - p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); - if (strcmp (p, "tofrom") != 0) + else + p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + + switch (p[0]) { - c_parser_error (parser, "expected %<tofrom%>"); - goto out_err; + case 'a': + if (strcmp ("alloc", p) == 0) + behavior = OMP_CLAUSE_DEFAULTMAP_ALLOC; + else + goto invalid_behavior; + break; + + case 'd': + if (strcmp ("default", p) == 0) + behavior = OMP_CLAUSE_DEFAULTMAP_DEFAULT; + else + goto invalid_behavior; + break; + + case 'f': + if (strcmp ("firstprivate", p) == 0) + behavior = OMP_CLAUSE_DEFAULTMAP_FIRSTPRIVATE; + else if (strcmp ("from", p) == 0) + behavior = OMP_CLAUSE_DEFAULTMAP_FROM; + else + goto invalid_behavior; + break; + + case 'n': + if (strcmp ("none", p) == 0) + behavior = OMP_CLAUSE_DEFAULTMAP_NONE; + else + goto invalid_behavior; + break; + + case 't': + if (strcmp ("tofrom", p) == 0) + behavior = OMP_CLAUSE_DEFAULTMAP_TOFROM; + else if (strcmp ("to", p) == 0) + behavior = OMP_CLAUSE_DEFAULTMAP_TO; + else + goto invalid_behavior; + break; + + default: + goto invalid_behavior; } c_parser_consume_token (parser); - if (!c_parser_require (parser, CPP_COLON, "expected %<:%>")) - goto out_err; - if (!c_parser_next_token_is (parser, CPP_NAME)) - { - c_parser_error (parser, "expected %<scalar%>"); - goto out_err; - } - p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); - if (strcmp (p, "scalar") != 0) + + if (!c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) { - c_parser_error (parser, "expected %<scalar%>"); - goto out_err; + if (!c_parser_require (parser, CPP_COLON, "expected %<:%>")) + goto out_err; + if (!c_parser_next_token_is (parser, CPP_NAME)) + { + invalid_category: + c_parser_error (parser, "expected %<scalar%>, %<aggregate%> or " + "%<pointer%>"); + goto out_err; + } + p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + switch (p[0]) + { + case 'a': + if (strcmp ("aggregate", p) == 0) + category = OMP_CLAUSE_DEFAULTMAP_CATEGORY_AGGREGATE; + else + goto invalid_category; + break; + + case 'p': + if (strcmp ("pointer", p) == 0) + category = OMP_CLAUSE_DEFAULTMAP_CATEGORY_POINTER; + else + goto invalid_category; + break; + + case 's': + if (strcmp ("scalar", p) == 0) + category = OMP_CLAUSE_DEFAULTMAP_CATEGORY_SCALAR; + else + goto invalid_category; + break; + + default: + goto invalid_category; + } + + c_parser_consume_token (parser); } - c_parser_consume_token (parser); parens.skip_until_found_close (parser); - check_no_duplicate_clause (list, OMP_CLAUSE_DEFAULTMAP, "defaultmap"); + + for (c = list; c ; c = OMP_CLAUSE_CHAIN (c)) + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEFAULTMAP + && (category == OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED + || OMP_CLAUSE_DEFAULTMAP_CATEGORY (c) == category + || (OMP_CLAUSE_DEFAULTMAP_CATEGORY (c) + == OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED))) + { + enum omp_clause_defaultmap_kind cat = category; + location_t loc = OMP_CLAUSE_LOCATION (c); + if (cat == OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED) + cat = OMP_CLAUSE_DEFAULTMAP_CATEGORY (c); + p = NULL; + switch (cat) + { + case OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED: + p = NULL; + break; + case OMP_CLAUSE_DEFAULTMAP_CATEGORY_AGGREGATE: + p = "aggregate"; + break; + case OMP_CLAUSE_DEFAULTMAP_CATEGORY_POINTER: + p = "pointer"; + break; + case OMP_CLAUSE_DEFAULTMAP_CATEGORY_SCALAR: + p = "scalar"; + break; + default: + gcc_unreachable (); + } + if (p) + error_at (loc, "too many %<defaultmap%> clauses with %qs category", + p); + else + error_at (loc, "too many %<defaultmap%> clauses with unspecified " + "category"); + break; + } + c = build_omp_clause (loc, OMP_CLAUSE_DEFAULTMAP); + OMP_CLAUSE_DEFAULTMAP_SET_KIND (c, behavior, category); OMP_CLAUSE_CHAIN (c) = list; return c; --- gcc/cp/parser.c.jj 2018-04-30 16:11:55.438350128 +0200 +++ gcc/cp/parser.c 2018-05-03 17:18:14.432877678 +0200 @@ -32567,7 +32567,10 @@ cp_parser_omp_clause_hint (cp_parser *pa } /* OpenMP 4.5: - defaultmap ( tofrom : scalar ) */ + defaultmap ( tofrom : scalar ) + + OpenMP 5.0: + defaultmap ( implicit-behavior [ : variable-category ] ) */ static tree cp_parser_omp_clause_defaultmap (cp_parser *parser, tree list, @@ -32575,47 +32578,163 @@ cp_parser_omp_clause_defaultmap (cp_pars { tree c, id; const char *p; + enum omp_clause_defaultmap_kind behavior = OMP_CLAUSE_DEFAULTMAP_DEFAULT; + enum omp_clause_defaultmap_kind category + = OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED; matching_parens parens; if (!parens.require_open (parser)) return list; - if (!cp_lexer_next_token_is (parser->lexer, CPP_NAME)) + if (cp_lexer_next_token_is_keyword (parser->lexer, RID_DEFAULT)) + p = "default"; + else if (!cp_lexer_next_token_is (parser->lexer, CPP_NAME)) { - cp_parser_error (parser, "expected %<tofrom%>"); + invalid_behavior: + cp_parser_error (parser, "expected %<alloc%>, %<to%>, %<from%>, " + "%<tofrom%>, %<firstprivate%>, %<none%> " + "or %<default%>"); goto out_err; } - id = cp_lexer_peek_token (parser->lexer)->u.value; - p = IDENTIFIER_POINTER (id); - if (strcmp (p, "tofrom") != 0) + else { - cp_parser_error (parser, "expected %<tofrom%>"); - goto out_err; + id = cp_lexer_peek_token (parser->lexer)->u.value; + p = IDENTIFIER_POINTER (id); } - cp_lexer_consume_token (parser->lexer); - if (!cp_parser_require (parser, CPP_COLON, RT_COLON)) - goto out_err; - if (!cp_lexer_next_token_is (parser->lexer, CPP_NAME)) + switch (p[0]) { - cp_parser_error (parser, "expected %<scalar%>"); - goto out_err; + case 'a': + if (strcmp ("alloc", p) == 0) + behavior = OMP_CLAUSE_DEFAULTMAP_ALLOC; + else + goto invalid_behavior; + break; + + case 'd': + if (strcmp ("default", p) == 0) + behavior = OMP_CLAUSE_DEFAULTMAP_DEFAULT; + else + goto invalid_behavior; + break; + + case 'f': + if (strcmp ("firstprivate", p) == 0) + behavior = OMP_CLAUSE_DEFAULTMAP_FIRSTPRIVATE; + else if (strcmp ("from", p) == 0) + behavior = OMP_CLAUSE_DEFAULTMAP_FROM; + else + goto invalid_behavior; + break; + + case 'n': + if (strcmp ("none", p) == 0) + behavior = OMP_CLAUSE_DEFAULTMAP_NONE; + else + goto invalid_behavior; + break; + + case 't': + if (strcmp ("tofrom", p) == 0) + behavior = OMP_CLAUSE_DEFAULTMAP_TOFROM; + else if (strcmp ("to", p) == 0) + behavior = OMP_CLAUSE_DEFAULTMAP_TO; + else + goto invalid_behavior; + break; + + default: + goto invalid_behavior; } - id = cp_lexer_peek_token (parser->lexer)->u.value; - p = IDENTIFIER_POINTER (id); - if (strcmp (p, "scalar") != 0) + cp_lexer_consume_token (parser->lexer); + + if (!cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_PAREN)) { - cp_parser_error (parser, "expected %<scalar%>"); - goto out_err; + if (!cp_parser_require (parser, CPP_COLON, RT_COLON)) + goto out_err; + + if (!cp_lexer_next_token_is (parser->lexer, CPP_NAME)) + { + invalid_category: + cp_parser_error (parser, "expected %<scalar%>, %<aggregate%> or " + "%<pointer%>"); + goto out_err; + } + id = cp_lexer_peek_token (parser->lexer)->u.value; + p = IDENTIFIER_POINTER (id); + + switch (p[0]) + { + case 'a': + if (strcmp ("aggregate", p) == 0) + category = OMP_CLAUSE_DEFAULTMAP_CATEGORY_AGGREGATE; + else + goto invalid_category; + break; + + case 'p': + if (strcmp ("pointer", p) == 0) + category = OMP_CLAUSE_DEFAULTMAP_CATEGORY_POINTER; + else + goto invalid_category; + break; + + case 's': + if (strcmp ("scalar", p) == 0) + category = OMP_CLAUSE_DEFAULTMAP_CATEGORY_SCALAR; + else + goto invalid_category; + break; + + default: + goto invalid_category; + } + + cp_lexer_consume_token (parser->lexer); } - cp_lexer_consume_token (parser->lexer); if (!parens.require_close (parser)) goto out_err; - check_no_duplicate_clause (list, OMP_CLAUSE_DEFAULTMAP, "defaultmap", - location); + for (c = list; c ; c = OMP_CLAUSE_CHAIN (c)) + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEFAULTMAP + && (category == OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED + || OMP_CLAUSE_DEFAULTMAP_CATEGORY (c) == category + || (OMP_CLAUSE_DEFAULTMAP_CATEGORY (c) + == OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED))) + { + enum omp_clause_defaultmap_kind cat = category; + location_t loc = OMP_CLAUSE_LOCATION (c); + if (cat == OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED) + cat = OMP_CLAUSE_DEFAULTMAP_CATEGORY (c); + p = NULL; + switch (cat) + { + case OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED: + p = NULL; + break; + case OMP_CLAUSE_DEFAULTMAP_CATEGORY_AGGREGATE: + p = "aggregate"; + break; + case OMP_CLAUSE_DEFAULTMAP_CATEGORY_POINTER: + p = "pointer"; + break; + case OMP_CLAUSE_DEFAULTMAP_CATEGORY_SCALAR: + p = "scalar"; + break; + default: + gcc_unreachable (); + } + if (p) + error_at (loc, "too many %<defaultmap%> clauses with %qs category", + p); + else + error_at (loc, "too many %<defaultmap%> clauses with unspecified " + "category"); + break; + } c = build_omp_clause (location, OMP_CLAUSE_DEFAULTMAP); + OMP_CLAUSE_DEFAULTMAP_SET_KIND (c, behavior, category); OMP_CLAUSE_CHAIN (c) = list; return c; --- gcc/fortran/trans-openmp.c.jj 2018-04-30 14:19:46.187990214 +0200 +++ gcc/fortran/trans-openmp.c 2018-05-02 17:52:01.091390796 +0200 @@ -2866,6 +2866,8 @@ gfc_trans_omp_clauses (stmtblock_t *bloc if (clauses->defaultmap) { c = build_omp_clause (where.lb->location, OMP_CLAUSE_DEFAULTMAP); + OMP_CLAUSE_DEFAULTMAP_SET_KIND (c, OMP_CLAUSE_DEFAULTMAP_TOFROM, + OMP_CLAUSE_DEFAULTMAP_CATEGORY_SCALAR); omp_clauses = gfc_trans_add_clause (c, omp_clauses); } if (clauses->depend_source) --- gcc/testsuite/c-c++-common/gomp/defaultmap-1.c.jj 2018-05-03 15:55:27.383889617 +0200 +++ gcc/testsuite/c-c++-common/gomp/defaultmap-1.c 2018-05-03 15:56:34.444943107 +0200 @@ -0,0 +1,30 @@ +void +foo (void) +{ + #pragma omp target defaultmap(alloc) defaultmap(alloc) /* { dg-error "too many 'defaultmap' clauses with unspecified category" } */ + ; + #pragma omp target defaultmap(to) defaultmap(from) /* { dg-error "too many 'defaultmap' clauses with unspecified category" } */ + ; + #pragma omp target defaultmap(tofrom) defaultmap(firstprivate:scalar) /* { dg-error "too many 'defaultmap' clauses with 'scalar' category" } */ + ; + #pragma omp target defaultmap(none:aggregate) defaultmap(alloc:scalar) defaultmap(none:scalar) /* { dg-error "too many 'defaultmap' clauses with 'scalar' category" } */ + ; + #pragma omp target defaultmap(none : pointer) defaultmap ( none ) /* { dg-error "too many 'defaultmap' clauses with 'pointer' category" } */ + ; + #pragma omp target defaultmap() /* { dg-error "expected" } */ + ; + #pragma omp target defaultmap(for) /* { dg-error "expected" } */ + ; + #pragma omp target defaultmap(blah) /* { dg-error "expected" } */ + ; + #pragma omp target defaultmap(tofrom:) /* { dg-error "expected" } */ + ; + #pragma omp target defaultmap(tofrom scalar) /* { dg-error "expected" } */ + ; + #pragma omp target defaultmap(tofrom,scalar) /* { dg-error "expected" } */ + ; + #pragma omp target defaultmap(default ;) /* { dg-error "expected" } */ + ; + #pragma omp target defaultmap(default : qux) /* { dg-error "expected" } */ + ; +} --- gcc/testsuite/c-c++-common/gomp/defaultmap-2.c.jj 2018-05-03 16:49:20.433478764 +0200 +++ gcc/testsuite/c-c++-common/gomp/defaultmap-2.c 2018-05-03 17:28:24.478376850 +0200 @@ -0,0 +1,131 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-fdump-tree-gimple" } */ + +struct S { int s; }; +void foo (char *); +void bar (int, char *, struct S, int *); +#pragma omp declare target to (bar) +#define N 16 + +void +f1 (int sc1, struct S ag1, int *pt1) +{ + char ar1[N]; + foo (ar1); + #pragma omp target + bar (sc1, ar1, ag1, pt1); +/* { dg-final { scan-tree-dump "firstprivate\\(sc1\\)" "gimple" } } */ +/* { dg-final { scan-tree-dump "map\\(tofrom:ar1" "gimple" } } */ +/* { dg-final { scan-tree-dump "map\\(tofrom:ag1" "gimple" } } */ +/* { dg-final { scan-tree-dump "map\\(firstprivate:pt1 .pointer assign" "gimple" } } */ +} + +void +f2 (int sc2, struct S ag2, int *pt2) +{ + char ar2[N]; + foo (ar2); + #pragma omp target firstprivate (sc2, ar2, ag2, pt2) defaultmap (none) + bar (sc2, ar2, ag2, pt2); +/* { dg-final { scan-tree-dump "firstprivate\\(sc2\\)" "gimple" } } */ +/* { dg-final { scan-tree-dump "firstprivate\\(ar2\\)" "gimple" } } */ +/* { dg-final { scan-tree-dump "firstprivate\\(ag2\\)" "gimple" } } */ +/* { dg-final { scan-tree-dump "firstprivate\\(pt2\\)" "gimple" } } */ +} + +void +f3 (int sc3, struct S ag3, int *pt3) +{ + char ar3[N]; + foo (ar3); + #pragma omp target defaultmap(none:scalar) defaultmap(none:aggregate) \ + map (sc3, ar3, ag3, pt3) defaultmap(none:pointer) + bar (sc3, ar3, ag3, pt3); +/* { dg-final { scan-tree-dump "map\\(tofrom:sc3" "gimple" } } */ +/* { dg-final { scan-tree-dump "map\\(tofrom:ar3" "gimple" } } */ +/* { dg-final { scan-tree-dump "map\\(tofrom:ag3" "gimple" } } */ +/* { dg-final { scan-tree-dump "map\\(tofrom:pt3" "gimple" } } */ +} + +void +f4 (int sc4, struct S ag4, int *pt4) +{ + char ar4[N]; + foo (ar4); + #pragma omp target defaultmap(tofrom:scalar) + bar (sc4, ar4, ag4, pt4); +/* { dg-final { scan-tree-dump "map\\(tofrom:sc4" "gimple" } } */ +/* { dg-final { scan-tree-dump "map\\(tofrom:ar4" "gimple" } } */ +/* { dg-final { scan-tree-dump "map\\(tofrom:ag4" "gimple" } } */ +/* { dg-final { scan-tree-dump "map\\(firstprivate:pt4 .pointer assign" "gimple" } } */ +} + +void +f5 (int sc5, struct S ag5, int *pt5) +{ + char ar5[N]; + foo (ar5); + #pragma omp target defaultmap(to) + bar (sc5, ar5, ag5, pt5); +/* { dg-final { scan-tree-dump "map\\(to:sc5" "gimple" } } */ +/* { dg-final { scan-tree-dump "map\\(to:ar5" "gimple" } } */ +/* { dg-final { scan-tree-dump "map\\(to:ag5" "gimple" } } */ +/* { dg-final { scan-tree-dump "map\\(to:pt5" "gimple" } } */ +} + +void +f6 (int sc6, struct S ag6, int *pt6) +{ + char ar6[N]; + foo (ar6); + #pragma omp target defaultmap(firstprivate) + bar (sc6, ar6, ag6, pt6); +/* { dg-final { scan-tree-dump "firstprivate\\(sc6\\)" "gimple" } } */ +/* { dg-final { scan-tree-dump "firstprivate\\(ar6\\)" "gimple" } } */ +/* { dg-final { scan-tree-dump "firstprivate\\(ag6\\)" "gimple" } } */ +/* { dg-final { scan-tree-dump "firstprivate\\(pt6\\)" "gimple" } } */ +} + +void +f7 (int sc7, struct S ag7, int *pt7) +{ + char ar7[N]; + foo (ar7); + #pragma omp target defaultmap(alloc: scalar) defaultmap(from: aggregate) defaultmap(default: pointer) + { + int *q = &sc7; + *q = 6; + ag7.s = 5; + int i; + for (i = 0; i < N; ++i) + ar7[i] = 7; + bar (sc7, ar7, ag7, pt7); + } +/* { dg-final { scan-tree-dump "map\\(alloc:sc7" "gimple" } } */ +/* { dg-final { scan-tree-dump "map\\(from:ar7" "gimple" } } */ +/* { dg-final { scan-tree-dump "map\\(from:ag7" "gimple" } } */ +/* { dg-final { scan-tree-dump "map\\(firstprivate:pt7 .pointer assign" "gimple" } } */ +} + +void +f8 (int sc8, struct S ag8, int *pt8) +{ + char ar8[N]; + foo (ar8); + #pragma omp target defaultmap(firstprivate:aggregate) defaultmap(none:scalar) \ + defaultmap(tofrom:pointer) map(to: sc8) + bar (sc8, ar8, ag8, pt8); +/* { dg-final { scan-tree-dump "map\\(to:sc8" "gimple" } } */ +/* { dg-final { scan-tree-dump "firstprivate\\(ar8\\)" "gimple" } } */ +/* { dg-final { scan-tree-dump "firstprivate\\(ag8\\)" "gimple" } } */ +/* { dg-final { scan-tree-dump "map\\(tofrom:pt8" "gimple" } } */ +} + +void +f9 (int sc9, struct S ag9) +{ + char ar9[sc9 + 2]; + foo (ar9); + #pragma omp target defaultmap(none) map(to: ar9, ag9) firstprivate (sc9) + bar (sc9, ar9, ag9, &sc9); +} --- gcc/testsuite/c-c++-common/gomp/defaultmap-3.c.jj 2018-05-03 17:29:17.108419915 +0200 +++ gcc/testsuite/c-c++-common/gomp/defaultmap-3.c 2018-05-03 18:17:47.035727866 +0200 @@ -0,0 +1,34 @@ +/* { dg-do compile } */ + +struct S { int s; }; +void foo (char *); +void bar (int, char *, struct S, int *); +#pragma omp declare target to (bar) +#define N 16 + +void +f1 (int sc1, struct S ag1, int *pt1) +{ + char ar1[N]; + foo (ar1); + #pragma omp target defaultmap(default:scalar) defaultmap(to:aggregate) defaultmap(none:pointer) /* { dg-error "enclosing 'target'" } */ + bar (sc1, ar1, ag1, pt1); /* { dg-error "'pt1' not specified in enclosing 'target'" } */ +} + +void +f2 (int sc2, struct S ag2, int *pt2) +{ + char ar2[N]; + foo (ar2); + #pragma omp target defaultmap(none:scalar) defaultmap(from:aggregate) defaultmap(default:pointer) /* { dg-error "enclosing 'target'" } */ + bar (sc2, ar2, ag2, pt2); /* { dg-error "'sc2' not specified in enclosing 'target'" } */ +} + +void +f3 (int sc3, struct S ag3, int *pt3) +{ + char ar3[N]; + foo (ar3); + #pragma omp target defaultmap(firstprivate:scalar) defaultmap(none:aggregate) defaultmap(to:pointer) /* { dg-error "enclosing 'target'" } */ + bar (sc3, ar3, ag3, pt3); /* { dg-error "'ar3' not specified in enclosing 'target'" } */ +} /* { dg-error "'ag3' not specified in enclosing 'target'" "" { target *-*-* } .-1 } */ Jakub