diff --git a/gcc/c-family/c-omp.c b/gcc/c-family/c-omp.c index fb1a0d6041ec7cd215b83ac6f48bdfdae332f314..0945a1e5cc45372e2e61a1e539f5ac78f8d7878e 100644 --- a/gcc/c-family/c-omp.c +++ b/gcc/c-family/c-omp.c @@ -1733,10 +1733,21 @@ c_omp_split_clauses (location_t loc, enum tree_code code, { /* This must be #pragma omp target simd. */ s = C_OMP_CLAUSE_SPLIT_TARGET; + OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT (clauses) = 1; + OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT_TARGET (clauses) = 1; break; } c = build_omp_clause (OMP_CLAUSE_LOCATION (clauses), OMP_CLAUSE_FIRSTPRIVATE); + /* firstprivate should not be applied to target if it is + also lastprivate or on the combined/composite construct, + or if it is mentioned in map clause. OMP_CLAUSE_DECLs + may need to go through FE handling though (instantiation, + C++ non-static data members, array section lowering), so + add the clause with OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT and + let *finish_omp_clauses and the gimplifier handle it + right. */ + OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT (c) = 1; OMP_CLAUSE_DECL (c) = OMP_CLAUSE_DECL (clauses); OMP_CLAUSE_CHAIN (c) = cclauses[C_OMP_CLAUSE_SPLIT_TARGET]; cclauses[C_OMP_CLAUSE_SPLIT_TARGET] = c; diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c index c3b85da11250a07993b00cc6042ef8edc924ab51..fc64ef96fb8c3eb7fac0cfc4880b575a086874ee 100644 --- a/gcc/c/c-typeck.c +++ b/gcc/c/c-typeck.c @@ -13936,6 +13936,7 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) has been seen, -2 if mixed inscan/normal reduction diagnosed. */ int reduction_seen = 0; bool allocate_seen = false; + bool firstprivate_implicit_moved = false; bitmap_obstack_initialize (NULL); bitmap_initialize (&generic_head, &bitmap_default_obstack); @@ -14377,6 +14378,29 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) break; case OMP_CLAUSE_FIRSTPRIVATE: + if (OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT (c) + && !firstprivate_implicit_moved) + { + firstprivate_implicit_moved = true; + /* Move firstprivate clauses with + OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT set to the end of + clauses chain. */ + tree cl = NULL, *pc1 = pc, *pc2 = &cl; + while (*pc1) + if (OMP_CLAUSE_CODE (*pc1) == OMP_CLAUSE_FIRSTPRIVATE + && OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT (*pc1)) + { + *pc2 = *pc1; + pc2 = &OMP_CLAUSE_CHAIN (*pc2); + *pc1 = OMP_CLAUSE_CHAIN (*pc1); + } + else + pc1 = &OMP_CLAUSE_CHAIN (*pc1); + *pc2 = NULL; + *pc1 = cl; + if (pc1 != pc) + continue; + } t = OMP_CLAUSE_DECL (c); need_complete = true; need_implicitly_determined = true; @@ -14398,6 +14422,9 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) if (ort == C_ORT_ACC) error_at (OMP_CLAUSE_LOCATION (c), "%qD appears more than once in data clauses", t); + else if (OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT (c) + && !OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT_TARGET (c)) + /* Silently drop the clause. */; else error_at (OMP_CLAUSE_LOCATION (c), "%qD appears both in data and map clauses", t); diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 0d590c318fb0d3a5832959eae85c289a53a2b80d..fffbe40613e904e970cadbff513b0c9ae05654fe 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -6519,6 +6519,7 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) bool allocate_seen = false; tree detach_seen = NULL_TREE; bool mergeable_seen = false; + bool firstprivate_implicit_moved = false; bitmap_obstack_initialize (NULL); bitmap_initialize (&generic_head, &bitmap_default_obstack); @@ -6843,6 +6844,29 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) break; case OMP_CLAUSE_FIRSTPRIVATE: + if (OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT (c) + && !firstprivate_implicit_moved) + { + firstprivate_implicit_moved = true; + /* Move firstprivate clauses with + OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT set to the end of + clauses chain. */ + tree cl = NULL, *pc1 = pc, *pc2 = &cl; + while (*pc1) + if (OMP_CLAUSE_CODE (*pc1) == OMP_CLAUSE_FIRSTPRIVATE + && OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT (*pc1)) + { + *pc2 = *pc1; + pc2 = &OMP_CLAUSE_CHAIN (*pc2); + *pc1 = OMP_CLAUSE_CHAIN (*pc1); + } + else + pc1 = &OMP_CLAUSE_CHAIN (*pc1); + *pc2 = NULL; + *pc1 = cl; + if (pc1 != pc) + continue; + } t = omp_clause_decl_field (OMP_CLAUSE_DECL (c)); if (t) omp_note_field_privatization (t, OMP_CLAUSE_DECL (c)); @@ -6884,6 +6908,9 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) if (ort == C_ORT_ACC) error_at (OMP_CLAUSE_LOCATION (c), "%qD appears more than once in data clauses", t); + else if (OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT (c) + && !OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT_TARGET (c)) + /* Silently drop the clause. */; else error_at (OMP_CLAUSE_LOCATION (c), "%qD appears both in data and map clauses", t); diff --git a/gcc/gimplify.c b/gcc/gimplify.c index 28bf1b0ba25d2037b0a5e6c4fbcbd6841c98d4ab..b62ea0efc1cb589c0d254f32deefcd197ca8eb5a 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -126,7 +126,10 @@ enum gimplify_omp_var_data /* Flag for GOVD_MAP: (struct) vars that have pointer attachments for fields. */ - GOVD_MAP_HAS_ATTACHMENTS = 8388608, + GOVD_MAP_HAS_ATTACHMENTS = 0x4000000, + + /* Flag for GOVD_FIRSTPRIVATE: OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT. */ + GOVD_FIRSTPRIVATE_IMPLICIT = 0x8000000, GOVD_DATA_SHARE_CLASS = (GOVD_SHARED | GOVD_PRIVATE | GOVD_FIRSTPRIVATE | GOVD_LASTPRIVATE | GOVD_REDUCTION | GOVD_LINEAR @@ -8586,13 +8589,24 @@ omp_lastprivate_for_combined_outer_constructs (struct gimplify_omp_ctx *octx, omp_add_variable (octx, decl, GOVD_LASTPRIVATE | GOVD_SEEN); continue; } - if (octx->region_type == ORT_COMBINED_TARGET - && splay_tree_lookup (octx->variables, - (splay_tree_key) decl) == NULL) + if (octx->region_type == ORT_COMBINED_TARGET) { - omp_add_variable (octx, decl, GOVD_MAP | GOVD_SEEN); - octx = octx->outer_context; - break; + splay_tree_node n = splay_tree_lookup (octx->variables, + (splay_tree_key) decl); + if (n == NULL) + { + omp_add_variable (octx, decl, GOVD_MAP | GOVD_SEEN); + octx = octx->outer_context; + } + else if (!implicit_p + && (n->value & GOVD_FIRSTPRIVATE_IMPLICIT)) + { + n->value &= ~(GOVD_FIRSTPRIVATE + | GOVD_FIRSTPRIVATE_IMPLICIT + | GOVD_EXPLICIT); + omp_add_variable (octx, decl, GOVD_MAP | GOVD_SEEN); + octx = octx->outer_context; + } } break; } @@ -8673,6 +8687,11 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, case OMP_CLAUSE_FIRSTPRIVATE: flags = GOVD_FIRSTPRIVATE | GOVD_EXPLICIT; check_non_private = "firstprivate"; + if (OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT (c)) + { + gcc_assert (code == OMP_TARGET); + flags |= GOVD_FIRSTPRIVATE_IMPLICIT; + } goto do_add; case OMP_CLAUSE_LASTPRIVATE: if (OMP_CLAUSE_LASTPRIVATE_CONDITIONAL (c)) @@ -10532,6 +10551,18 @@ gimplify_adjust_omp_clauses (gimple_seq *pre_p, gimple_seq body, tree *list_p, remove = true; break; } + if (OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT (c)) + { + decl = OMP_CLAUSE_DECL (c); + n = splay_tree_lookup (ctx->variables, (splay_tree_key) decl); + if ((n->value & GOVD_MAP) != 0) + { + remove = true; + break; + } + OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT_TARGET (c) = 0; + OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT (c) = 0; + } /* FALLTHRU */ case OMP_CLAUSE_PRIVATE: case OMP_CLAUSE_SHARED: diff --git a/gcc/testsuite/c-c++-common/gomp/pr99928-15.c b/gcc/testsuite/c-c++-common/gomp/pr99928-15.c new file mode 100644 index 0000000000000000000000000000000000000000..f0c6232d27c6fb1b4e72b4552148d1c7e268a02f --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/pr99928-15.c @@ -0,0 +1,26 @@ +/* PR middle-end/99928 */ + +int v; + +void +foo (void) +{ + #pragma omp target parallel firstprivate (v) map(tofrom: v) /* { dg-bogus "'v' appears both in data and map clauses" } */ + v++; +} + +void +bar (void) +{ + #pragma omp target firstprivate (v) map (tofrom: v) /* { dg-error "'v' appears both in data and map clauses" } */ + v++; +} + +void +baz (void) +{ + int j; + #pragma omp target simd firstprivate (v) map (tofrom: v) private (j) /* { dg-error "'v' appears both in data and map clauses" } */ + for (int i = 0; i < 1; i++) + j = v; +} diff --git a/gcc/testsuite/c-c++-common/gomp/pr99928-3.c b/gcc/testsuite/c-c++-common/gomp/pr99928-3.c index 67f590bb7ef4a40679de965d57ff46876defbdf2..cf9c72d75b88f06c9df740d04e5915f75fae70ab 100644 --- a/gcc/testsuite/c-c++-common/gomp/pr99928-3.c +++ b/gcc/testsuite/c-c++-common/gomp/pr99928-3.c @@ -82,8 +82,8 @@ bar (void) #pragma omp section l07 = 2; } - /* { dg-final { scan-tree-dump "omp target\[^\n\r]*map\\(tofrom:l08" "gimple" { xfail *-*-* } } } */ - /* { dg-final { scan-tree-dump-not "omp target\[^\n\r]*firstprivate\\(l08\\)" "gimple" { xfail *-*-* } } } */ + /* { dg-final { scan-tree-dump "omp target\[^\n\r]*map\\(tofrom:l08" "gimple" } } */ + /* { dg-final { scan-tree-dump-not "omp target\[^\n\r]*firstprivate\\(l08\\)" "gimple" } } */ /* { dg-final { scan-tree-dump "omp parallel\[^\n\r]*firstprivate\\(l08\\)" "gimple" } } *//* FIXME: This should be on for instead. */ /* { dg-final { scan-tree-dump "omp parallel\[^\n\r]*lastprivate\\(l08\\)" "gimple" } } *//* FIXME: This should be on for instead. */ /* { dg-final { scan-tree-dump-not "omp for\[^\n\r]*firstprivate\\(l08\\)" "gimple" } } *//* FIXME. */ @@ -91,8 +91,8 @@ bar (void) #pragma omp target parallel for firstprivate (l08) lastprivate (l08) for (int i = 0; i < 64; i++) l08 = i; - /* { dg-final { scan-tree-dump "omp target\[^\n\r]*map\\(tofrom:l09" "gimple" { xfail *-*-* } } } */ - /* { dg-final { scan-tree-dump-not "omp target\[^\n\r]*firstprivate\\(l09\\)" "gimple" { xfail *-*-* } } } */ + /* { dg-final { scan-tree-dump "omp target\[^\n\r]*map\\(tofrom:l09" "gimple" } } */ + /* { dg-final { scan-tree-dump-not "omp target\[^\n\r]*firstprivate\\(l09\\)" "gimple" } } */ /* { dg-final { scan-tree-dump "omp parallel\[^\n\r]*firstprivate\\(l09\\)" "gimple" } } *//* FIXME: This should be on for instead. */ /* { dg-final { scan-tree-dump "omp parallel\[^\n\r]*lastprivate\\(l09\\)" "gimple" } } *//* FIXME: This should be on for instead. */ /* { dg-final { scan-tree-dump-not "omp for\[^\n\r]*firstprivate\\(l09\\)" "gimple" } } *//* FIXME. */ @@ -102,8 +102,8 @@ bar (void) #pragma omp target parallel for simd firstprivate (l09) lastprivate (l09) for (int i = 0; i < 64; i++) l09 = i; - /* { dg-final { scan-tree-dump "omp target\[^\n\r]*map\\(tofrom:l10" "gimple" { xfail *-*-* } } } */ - /* { dg-final { scan-tree-dump-not "omp target\[^\n\r]*firstprivate\\(l10\\)" "gimple" { xfail *-*-* } } } */ + /* { dg-final { scan-tree-dump "omp target\[^\n\r]*map\\(tofrom:l10" "gimple" } } */ + /* { dg-final { scan-tree-dump-not "omp target\[^\n\r]*firstprivate\\(l10\\)" "gimple" } } */ /* { dg-final { scan-tree-dump-not "omp simd\[^\n\r]*firstprivate\\(l10\\)" "gimple" } } */ /* { dg-final { scan-tree-dump "omp simd\[^\n\r]*lastprivate\\(l10\\)" "gimple" } } */ #pragma omp target simd firstprivate (l10) lastprivate (l10) diff --git a/gcc/tree.h b/gcc/tree.h index 64612cfa3680b497c3cffe360132ba0f35aa6af0..37aca8963fe4e61a99f6276b86ef6b5beea287ca 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -1538,6 +1538,11 @@ class auto_suppress_location_wrappers #define OMP_CLAUSE_FIRSTPRIVATE_NO_REFERENCE(NODE) \ TREE_PRIVATE (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_FIRSTPRIVATE)) +/* True on a FIRSTPRIVATE clause with OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT also + set if target construct is the only one that accepts the clause. */ +#define OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT_TARGET(NODE) \ + TREE_PROTECTED (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_FIRSTPRIVATE)) + /* True on a LASTPRIVATE clause if a FIRSTPRIVATE clause for the same decl is present in the chain. */ #define OMP_CLAUSE_LASTPRIVATE_FIRSTPRIVATE(NODE) \