Hi! As the testcases show, #pragma omp declare target has now a new form (well, two; with some issues on it pending), where it is used just as a single declarative directive rather than a pair of them and allows marking vars and functions by name as "omp declare target" vars/functions (which the middle-end etc. already handles), but also "omp declare target link", which is a deferred var, that is not initially mapped (on devices without shared memory with host), but has to be mapped explicitly.
This patch only marks them with the new attribute, the actual middle-end implementation needs to be implemented. I believe OpenACC has something similar, but no idea if it is already implemented. Anyway, I think the implementation should be that in some pass running on the ACCEL_COMPILER side (guarded by separate address space aka non-HSA) we actually replace the variables with pointers to variables, then need to somehow also mark those in the offloading tables, so that the library registers them (the locations of the pointers to the vars), but also marks them for special treatment, and then when actually trying to map them (or their parts, guess that needs to be discussed) we allocate them or whatever is requested and store the device pointer into the corresponding variable. Ilya, Thomas, thoughts on this? 2015-07-17 Jakub Jelinek <ja...@redhat.com> * tree-core.h (enum omp_clause_code): Add OMP_CLAUSE_TO_DECLARE and OMP_CLAUSE_LINK. * tree.c (omp_clause_num_ops, omp_clause_code_name): Add entries for OMP_CLAUSE_{TO_DECLARE,LINK}. (walk_tree_1): Handle OMP_CLAUSE_{TO_DECLARE,LINK}. * tree-nested.c (convert_nonlocal_omp_clauses, convert_local_omp_clauses): Likewise. * tree-pretty-print.c (dump_omp_clause): Likewise. c-family/ * c-pragma.h (enum pragma_omp_clause): Add PRAGMA_OMP_CLAUSE_LINK. c/ * c-parser.c (c_parser_omp_clause_name): Handle link clause. (c_parser_omp_variable_list): Formatting fix. (c_parser_omp_all_clauses): Handle PRAGMA_OMP_CLAUSE_LINK. For PRAGMA_OMP_CLAUSE_TO, parse it as OMP_CLAUSE_TO_DECLARE rather than OMP_CLAUSE_TO if it is a declare target directive clause. (OMP_DECLARE_TARGET_CLAUSE_MASK): Define. (c_parser_omp_declare_target): Parse directive with clauses forms. * c-typeck.c (c_finish_omp_clauses): Handle OMP_CLAUSE_{TO_DECLARE,LINK}. cp/ * parser.c (cp_parser_omp_clause_name): Handle link clause. (cp_parser_omp_var_list_no_open): Formatting fix. (cp_parser_omp_all_clauses): Handle PRAGMA_OMP_CLAUSE_LINK. For PRAGMA_OMP_CLAUSE_TO, parse it as OMP_CLAUSE_TO_DECLARE rather than OMP_CLAUSE_TO if it is a declare target directive clause. (OMP_DECLARE_TARGET_CLAUSE_MASK): Define. (cp_parser_omp_declare_target): Parse directive with clauses forms. * semantics.c (finish_omp_clauses): Handle OMP_CLAUSE_{TO_DECLARE,LINK}. testsuite/ * c-c++-common/gomp/declare-target-1.c: New test. * c-c++-common/gomp/declare-target-2.c: New test. --- gcc/tree-core.h.jj 2015-07-15 13:02:31.000000000 +0200 +++ gcc/tree-core.h 2015-07-17 09:30:44.944431669 +0200 @@ -256,6 +256,13 @@ enum omp_clause_code { /* OpenMP clause: uniform (argument-list). */ OMP_CLAUSE_UNIFORM, + /* OpenMP clause: to (extended-list). + Only when it appears in declare target. */ + OMP_CLAUSE_TO_DECLARE, + + /* OpenMP clause: link (variable-list). */ + OMP_CLAUSE_LINK, + /* OpenMP clause: from (variable-list). */ OMP_CLAUSE_FROM, --- gcc/tree.c.jj 2015-07-14 14:49:57.000000000 +0200 +++ gcc/tree.c 2015-07-17 09:33:51.270692623 +0200 @@ -288,6 +288,8 @@ unsigned const char omp_clause_num_ops[] 2, /* OMP_CLAUSE_ALIGNED */ 1, /* OMP_CLAUSE_DEPEND */ 1, /* OMP_CLAUSE_UNIFORM */ + 1, /* OMP_CLAUSE_TO_DECLARE */ + 1, /* OMP_CLAUSE_LINK */ 2, /* OMP_CLAUSE_FROM */ 2, /* OMP_CLAUSE_TO */ 2, /* OMP_CLAUSE_MAP */ @@ -357,6 +359,8 @@ const char * const omp_clause_code_name[ "aligned", "depend", "uniform", + "to", + "link", "from", "to", "map", @@ -11392,6 +11396,8 @@ walk_tree_1 (tree *tp, walk_tree_fn func case OMP_CLAUSE_GRAINSIZE: case OMP_CLAUSE_NUM_TASKS: case OMP_CLAUSE_HINT: + case OMP_CLAUSE_TO_DECLARE: + case OMP_CLAUSE_LINK: case OMP_CLAUSE_USE_DEVICE_PTR: case OMP_CLAUSE_IS_DEVICE_PTR: case OMP_CLAUSE__LOOPTEMP_: --- gcc/tree-nested.c.jj 2015-07-14 14:49:57.000000000 +0200 +++ gcc/tree-nested.c 2015-07-17 09:35:11.905507270 +0200 @@ -1098,6 +1098,8 @@ convert_nonlocal_omp_clauses (tree *pcla case OMP_CLAUSE_FIRSTPRIVATE: case OMP_CLAUSE_COPYPRIVATE: case OMP_CLAUSE_SHARED: + case OMP_CLAUSE_TO_DECLARE: + case OMP_CLAUSE_LINK: case OMP_CLAUSE_USE_DEVICE_PTR: case OMP_CLAUSE_IS_DEVICE_PTR: do_decl_clause: @@ -1745,6 +1747,8 @@ convert_local_omp_clauses (tree *pclause case OMP_CLAUSE_FIRSTPRIVATE: case OMP_CLAUSE_COPYPRIVATE: case OMP_CLAUSE_SHARED: + case OMP_CLAUSE_TO_DECLARE: + case OMP_CLAUSE_LINK: case OMP_CLAUSE_USE_DEVICE_PTR: case OMP_CLAUSE_IS_DEVICE_PTR: do_decl_clause: --- gcc/tree-pretty-print.c.jj 2015-07-15 13:02:31.000000000 +0200 +++ gcc/tree-pretty-print.c 2015-07-17 09:36:30.822347172 +0200 @@ -344,6 +344,12 @@ dump_omp_clause (pretty_printer *pp, tre case OMP_CLAUSE_USE_DEVICE: name = "use_device"; goto print_remap; + case OMP_CLAUSE_TO_DECLARE: + name = "to"; + goto print_remap; + case OMP_CLAUSE_LINK: + name = "link"; + goto print_remap; print_remap: pp_string (pp, name); pp_left_paren (pp); --- gcc/c-family/c-pragma.h.jj 2015-07-14 14:49:57.000000000 +0200 +++ gcc/c-family/c-pragma.h 2015-07-17 09:21:03.190983600 +0200 @@ -101,6 +101,7 @@ typedef enum pragma_omp_clause { PRAGMA_OMP_CLAUSE_IS_DEVICE_PTR, PRAGMA_OMP_CLAUSE_LASTPRIVATE, PRAGMA_OMP_CLAUSE_LINEAR, + PRAGMA_OMP_CLAUSE_LINK, PRAGMA_OMP_CLAUSE_MAP, PRAGMA_OMP_CLAUSE_MERGEABLE, PRAGMA_OMP_CLAUSE_NOGROUP, --- gcc/c/c-parser.c.jj 2015-07-16 18:09:25.000000000 +0200 +++ gcc/c/c-parser.c 2015-07-17 14:11:08.553694975 +0200 @@ -9953,6 +9953,8 @@ c_parser_omp_clause_name (c_parser *pars result = PRAGMA_OMP_CLAUSE_LASTPRIVATE; else if (!strcmp ("linear", p)) result = PRAGMA_OMP_CLAUSE_LINEAR; + else if (!strcmp ("link", p)) + result = PRAGMA_OMP_CLAUSE_LINK; break; case 'm': if (!strcmp ("map", p)) @@ -10235,7 +10237,7 @@ c_parser_omp_variable_list (c_parser *pa && !TREE_READONLY (low_bound)) { error_at (clause_loc, - "%qD is not a constant", low_bound); + "%qD is not a constant", low_bound); t = error_mark_node; } @@ -10243,7 +10245,7 @@ c_parser_omp_variable_list (c_parser *pa && !TREE_READONLY (length)) { error_at (clause_loc, - "%qD is not a constant", length); + "%qD is not a constant", length); t = error_mark_node; } } @@ -12600,8 +12602,18 @@ c_parser_omp_all_clauses (c_parser *pars if (!first) goto clause_not_first; break; + case PRAGMA_OMP_CLAUSE_LINK: + clauses + = c_parser_omp_var_list_parens (parser, OMP_CLAUSE_LINK, clauses); + c_name = "link"; + break; case PRAGMA_OMP_CLAUSE_TO: - clauses = c_parser_omp_clause_to (parser, clauses); + if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINK)) != 0) + clauses + = c_parser_omp_var_list_parens (parser, OMP_CLAUSE_TO_DECLARE, + clauses); + else + clauses = c_parser_omp_clause_to (parser, clauses); c_name = "to"; break; case PRAGMA_OMP_CLAUSE_FROM: @@ -15313,13 +15325,64 @@ c_finish_omp_declare_simd (c_parser *par /* OpenMP 4.0: # pragma omp declare target new-line declarations and definitions - # pragma omp end declare target new-line */ + # pragma omp end declare target new-line + + OpenMP 4.1: + # pragma omp declare target ( extended-list ) new-line + + # pragma omp declare target declare-target-clauses[seq] new-line */ + +#define OMP_DECLARE_TARGET_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_TO) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINK)) static void c_parser_omp_declare_target (c_parser *parser) { - c_parser_skip_to_pragma_eol (parser); - current_omp_declare_target_attribute++; + location_t loc = c_parser_peek_token (parser)->location; + tree clauses = NULL_TREE; + if (c_parser_next_token_is (parser, CPP_NAME)) + clauses = c_parser_omp_all_clauses (parser, OMP_DECLARE_TARGET_CLAUSE_MASK, + "#pragma omp declare target"); + else if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)) + { + clauses = c_parser_omp_var_list_parens (parser, OMP_CLAUSE_TO_DECLARE, + clauses); + c_parser_skip_to_pragma_eol (parser); + } + else + { + c_parser_skip_to_pragma_eol (parser); + current_omp_declare_target_attribute++; + return; + } + if (current_omp_declare_target_attribute) + error_at (loc, "%<#pragma omp declare target%> with clauses in between " + "%<#pragma omp declare target%> without clauses and " + "%<#pragma omp end declare target%>"); + for (tree c = clauses; c; c = OMP_CLAUSE_CHAIN (c)) + { + tree t = OMP_CLAUSE_DECL (c), id; + tree at1 = lookup_attribute ("omp declare target", DECL_ATTRIBUTES (t)); + tree at2 = lookup_attribute ("omp declare target link", + DECL_ATTRIBUTES (t)); + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LINK) + { + id = get_identifier ("omp declare target link"); + std::swap (at1, at2); + } + else + id = get_identifier ("omp declare target"); + if (at2) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qD specified both in declare target %<link%> and %<to%>" + " clauses", t); + continue; + } + if (!at1) + DECL_ATTRIBUTES (t) = tree_cons (id, NULL_TREE, DECL_ATTRIBUTES (t)); + } } static void --- gcc/c/c-typeck.c.jj 2015-07-15 13:00:32.000000000 +0200 +++ gcc/c/c-typeck.c 2015-07-17 13:06:58.297769199 +0200 @@ -12576,6 +12576,36 @@ c_finish_omp_clauses (tree clauses, bool bitmap_set_bit (&map_head, DECL_UID (t)); break; + case OMP_CLAUSE_TO_DECLARE: + t = OMP_CLAUSE_DECL (c); + if (TREE_CODE (t) == FUNCTION_DECL) + break; + /* FALLTHRU */ + case OMP_CLAUSE_LINK: + t = OMP_CLAUSE_DECL (c); + if (!VAR_P (t)) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE is not a variable in clause %qs", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + remove = true; + } + else if (DECL_THREAD_LOCAL_P (t)) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qD is threadprivate variable in %qs clause", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + remove = true; + } + else if (!lang_hooks.types.omp_mappable_type (TREE_TYPE (t))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qD does not have a mappable type in %qs clause", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + remove = true; + } + break; + case OMP_CLAUSE_UNIFORM: t = OMP_CLAUSE_DECL (c); if (TREE_CODE (t) != PARM_DECL) --- gcc/cp/parser.c.jj 2015-07-16 18:09:25.000000000 +0200 +++ gcc/cp/parser.c 2015-07-17 14:04:34.945101113 +0200 @@ -27748,6 +27748,8 @@ cp_parser_omp_clause_name (cp_parser *pa result = PRAGMA_OMP_CLAUSE_LASTPRIVATE; else if (!strcmp ("linear", p)) result = PRAGMA_OMP_CLAUSE_LINEAR; + else if (!strcmp ("link", p)) + result = PRAGMA_OMP_CLAUSE_LINK; break; case 'm': if (!strcmp ("map", p)) @@ -27987,7 +27989,7 @@ cp_parser_omp_var_list_no_open (cp_parse && !TREE_READONLY (low_bound)) { error_at (token->location, - "%qD is not a constant", low_bound); + "%qD is not a constant", low_bound); decl = error_mark_node; } @@ -27995,7 +27997,7 @@ cp_parser_omp_var_list_no_open (cp_parse && !TREE_READONLY (length)) { error_at (token->location, - "%qD is not a constant", length); + "%qD is not a constant", length); decl = error_mark_node; } } @@ -30198,14 +30200,20 @@ cp_parser_omp_all_clauses (cp_parser *pa if (!first) goto clause_not_first; break; + case PRAGMA_OMP_CLAUSE_LINK: + clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_LINK, clauses); + c_name = "to"; + break; case PRAGMA_OMP_CLAUSE_TO: - clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_TO, - clauses); + if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINK)) != 0) + clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_TO_DECLARE, + clauses); + else + clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_TO, clauses); c_name = "to"; break; case PRAGMA_OMP_CLAUSE_FROM: - clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_FROM, - clauses); + clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_FROM, clauses); c_name = "from"; break; case PRAGMA_OMP_CLAUSE_UNIFORM: @@ -33168,13 +33176,65 @@ cp_parser_late_parsing_omp_declare_simd /* OpenMP 4.0: # pragma omp declare target new-line declarations and definitions - # pragma omp end declare target new-line */ + # pragma omp end declare target new-line + + OpenMP 4.1: + # pragma omp declare target ( extended-list ) new-line + + # pragma omp declare target declare-target-clauses[seq] new-line */ + +#define OMP_DECLARE_TARGET_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_TO) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINK)) static void cp_parser_omp_declare_target (cp_parser *parser, cp_token *pragma_tok) { - cp_parser_skip_to_pragma_eol (parser, pragma_tok); - scope_chain->omp_declare_target_attribute++; + tree clauses = NULL_TREE; + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) + clauses + = cp_parser_omp_all_clauses (parser, OMP_DECLARE_TARGET_CLAUSE_MASK, + "#pragma omp declare target", pragma_tok); + else if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN)) + { + clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_TO_DECLARE, + clauses); + cp_parser_skip_to_pragma_eol (parser, pragma_tok); + } + else + { + cp_parser_skip_to_pragma_eol (parser, pragma_tok); + scope_chain->omp_declare_target_attribute++; + return; + } + if (scope_chain->omp_declare_target_attribute) + error_at (pragma_tok->location, + "%<#pragma omp declare target%> with clauses in between " + "%<#pragma omp declare target%> without clauses and " + "%<#pragma omp end declare target%>"); + for (tree c = clauses; c; c = OMP_CLAUSE_CHAIN (c)) + { + tree t = OMP_CLAUSE_DECL (c), id; + tree at1 = lookup_attribute ("omp declare target", DECL_ATTRIBUTES (t)); + tree at2 = lookup_attribute ("omp declare target link", + DECL_ATTRIBUTES (t)); + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LINK) + { + id = get_identifier ("omp declare target link"); + std::swap (at1, at2); + } + else + id = get_identifier ("omp declare target"); + if (at2) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qD specified both in declare target %<link%> and %<to%>" + " clauses", t); + continue; + } + if (!at1) + DECL_ATTRIBUTES (t) = tree_cons (id, NULL_TREE, DECL_ATTRIBUTES (t)); + } } static void --- gcc/cp/semantics.c.jj 2015-07-16 17:56:41.000000000 +0200 +++ gcc/cp/semantics.c 2015-07-17 13:59:27.177346223 +0200 @@ -6266,6 +6266,36 @@ finish_omp_clauses (tree clauses, bool a bitmap_set_bit (&map_head, DECL_UID (t)); break; + case OMP_CLAUSE_TO_DECLARE: + t = OMP_CLAUSE_DECL (c); + if (TREE_CODE (t) == FUNCTION_DECL) + break; + /* FALLTHRU */ + case OMP_CLAUSE_LINK: + t = OMP_CLAUSE_DECL (c); + if (!VAR_P (t)) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE is not a variable in clause %qs", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + remove = true; + } + else if (DECL_THREAD_LOCAL_P (t)) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qD is threadprivate variable in %qs clause", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + remove = true; + } + else if (!cp_omp_mappable_type (TREE_TYPE (t))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qD does not have a mappable type in %qs clause", t, + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); + remove = true; + } + break; + case OMP_CLAUSE_UNIFORM: t = OMP_CLAUSE_DECL (c); if (TREE_CODE (t) != PARM_DECL) --- gcc/testsuite/c-c++-common/gomp/declare-target-1.c.jj 2015-07-17 14:07:10.523953776 +0200 +++ gcc/testsuite/c-c++-common/gomp/declare-target-1.c 2015-07-17 14:07:30.472678409 +0200 @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-options "-fopenmp" } */ + +int foo (void), bar (void); +extern int a; +int b; +char d; +#pragma omp declare target +long c; +#pragma omp end declare target + +#pragma omp declare target (bar, a) +#pragma omp declare target to (b) link (d) to (foo) --- gcc/testsuite/c-c++-common/gomp/declare-target-2.c.jj 2015-07-17 14:23:16.246720738 +0200 +++ gcc/testsuite/c-c++-common/gomp/declare-target-2.c 2015-07-17 14:21:32.000000000 +0200 @@ -0,0 +1,27 @@ +/* { dg-do compile } */ +/* { dg-options "-fopenmp" } */ + +extern int a; +#pragma omp declare target +#pragma omp declare target to (a) /* { dg-error "with clauses in between" } */ +#pragma omp end declare target +int b; +#pragma omp declare target to (b) link (b) /* { dg-error "specified both in declare target" } */ +int c; +#pragma omp declare target (c) +#pragma omp declare target link (c) /* { dg-error "specified both in declare target" } */ +int foo (void); +#pragma omp declare target link (foo) /* { dg-error "is not a variable in clause" } */ +struct S; +extern struct S d[]; /* { dg-error "array type has incomplete element type" "" { target c } } */ +#pragma omp declare target to (d) /* { dg-error "does not have a mappable type in" } */ +extern struct S e; +#pragma omp declare target link (e) /* { dg-error "does not have a mappable type in" } */ +extern int f[]; +#pragma omp declare target to (f) /* { dg-error "does not have a mappable type in" } */ +int g, h; +#pragma omp threadprivate (g, h) +#pragma omp declare target to (g) /* { dg-error "is threadprivate variable in" } */ +#pragma omp declare target link (h) /* { dg-error "is threadprivate variable in" } */ +int j[10]; +#pragma omp declare target to (j[0:4]) /* { dg-error "expected" } */ Jakub