diff options
Diffstat (limited to 'gcc/gimplify.c')
-rw-r--r-- | gcc/gimplify.c | 640 |
1 files changed, 553 insertions, 87 deletions
diff --git a/gcc/gimplify.c b/gcc/gimplify.c index 03203c0..319e200 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -84,6 +84,9 @@ enum gimplify_omp_var_data GOVD_MAP_0LEN_ARRAY = 32768, + /* Flag for GOVD_MAP, if it is always, to or always, tofrom mapping. */ + GOVD_MAP_ALWAYS_TO = 65536, + GOVD_DATA_SHARE_CLASS = (GOVD_SHARED | GOVD_PRIVATE | GOVD_FIRSTPRIVATE | GOVD_LASTPRIVATE | GOVD_REDUCTION | GOVD_LINEAR | GOVD_LOCAL) @@ -5847,9 +5850,10 @@ omp_default_clause (struct gimplify_omp_ctx *ctx, tree decl, { splay_tree_node n2; - if ((octx->region_type & (ORT_TARGET_DATA | ORT_TARGET)) != 0) - continue; n2 = splay_tree_lookup (octx->variables, (splay_tree_key) decl); + if ((octx->region_type & (ORT_TARGET_DATA | ORT_TARGET)) != 0 + && (n2 == NULL || (n2->value & GOVD_DATA_SHARE_CLASS) == 0)) + continue; if (n2 && (n2->value & GOVD_DATA_SHARE_CLASS) != GOVD_SHARED) { flags |= GOVD_FIRSTPRIVATE; @@ -5964,8 +5968,13 @@ omp_notice_variable (struct gimplify_omp_ctx *ctx, tree decl, bool in_code) else if (is_scalar) nflags |= GOVD_FIRSTPRIVATE; } + tree type = TREE_TYPE (decl); if (nflags == flags - && !lang_hooks.types.omp_mappable_type (TREE_TYPE (decl))) + && 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); @@ -6084,6 +6093,9 @@ omp_is_private (struct gimplify_omp_ctx *ctx, tree decl, int simd) else if ((n->value & GOVD_REDUCTION) != 0) error ("iteration variable %qE should not be reduction", DECL_NAME (decl)); + else if (simd == 0 && (n->value & GOVD_LINEAR) != 0) + error ("iteration variable %qE should not be linear", + DECL_NAME (decl)); else if (simd == 1 && (n->value & GOVD_LASTPRIVATE) != 0) error ("iteration variable %qE should not be lastprivate", DECL_NAME (decl)); @@ -6141,10 +6153,12 @@ omp_check_private (struct gimplify_omp_ctx *ctx, tree decl, bool copyprivate) return true; } - if ((ctx->region_type & (ORT_TARGET | ORT_TARGET_DATA)) != 0) + n = splay_tree_lookup (ctx->variables, (splay_tree_key) decl); + + if ((ctx->region_type & (ORT_TARGET | ORT_TARGET_DATA)) != 0 + && (n == NULL || (n->value & GOVD_DATA_SHARE_CLASS) == 0)) continue; - n = splay_tree_lookup (ctx->variables, (splay_tree_key) decl); if (n != NULL) { if ((n->value & GOVD_LOCAL) != 0 @@ -6175,12 +6189,12 @@ omp_no_lastprivate (struct gimplify_omp_ctx *ctx) if (!ctx->combined_loop) return false; if (ctx->distribute) - return true; + return lang_GNU_Fortran (); break; case ORT_COMBINED_PARALLEL: break; case ORT_COMBINED_TEAMS: - return true; + return lang_GNU_Fortran (); default: return false; } @@ -6215,7 +6229,7 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, struct gimplify_omp_ctx *ctx, *outer_ctx; tree c; hash_map<tree, tree> *struct_map_to_clause = NULL; - tree *orig_list_p = list_p; + tree *prev_list_p = NULL; ctx = new_omp_context (region_type); outer_ctx = ctx->outer_context; @@ -6277,16 +6291,25 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, else if (error_operand_p (decl)) goto do_add; else if (outer_ctx - && outer_ctx->region_type == ORT_COMBINED_PARALLEL + && (outer_ctx->region_type == ORT_COMBINED_PARALLEL + || outer_ctx->region_type == ORT_COMBINED_TEAMS) && splay_tree_lookup (outer_ctx->variables, (splay_tree_key) decl) == NULL) - omp_add_variable (outer_ctx, decl, GOVD_SHARED | GOVD_SEEN); + { + omp_add_variable (outer_ctx, decl, GOVD_SHARED | GOVD_SEEN); + if (outer_ctx->outer_context) + omp_notice_variable (outer_ctx->outer_context, decl, true); + } else if (outer_ctx && (outer_ctx->region_type & ORT_TASK) != 0 && outer_ctx->combined_loop && splay_tree_lookup (outer_ctx->variables, (splay_tree_key) decl) == NULL) - omp_add_variable (outer_ctx, decl, GOVD_LASTPRIVATE | GOVD_SEEN); + { + omp_add_variable (outer_ctx, decl, GOVD_LASTPRIVATE | GOVD_SEEN); + if (outer_ctx->outer_context) + omp_notice_variable (outer_ctx->outer_context, decl, true); + } else if (outer_ctx && outer_ctx->region_type == ORT_WORKSHARE && outer_ctx->combined_loop @@ -6300,8 +6323,14 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, == ORT_COMBINED_PARALLEL) && splay_tree_lookup (outer_ctx->outer_context->variables, (splay_tree_key) decl) == NULL) - omp_add_variable (outer_ctx->outer_context, decl, - GOVD_SHARED | GOVD_SEEN); + { + struct gimplify_omp_ctx *octx = outer_ctx->outer_context; + omp_add_variable (octx, decl, GOVD_SHARED | GOVD_SEEN); + if (octx->outer_context) + omp_notice_variable (octx->outer_context, decl, true); + } + else if (outer_ctx->outer_context) + omp_notice_variable (outer_ctx->outer_context, decl, true); } goto do_add; case OMP_CLAUSE_REDUCTION: @@ -6324,6 +6353,23 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, omp_notice_variable (ctx, v, true); } decl = TREE_OPERAND (decl, 0); + if (TREE_CODE (decl) == POINTER_PLUS_EXPR) + { + if (gimplify_expr (&TREE_OPERAND (decl, 1), pre_p, + NULL, is_gimple_val, fb_rvalue) + == GS_ERROR) + { + remove = true; + break; + } + v = TREE_OPERAND (decl, 1); + if (DECL_P (v)) + { + omp_firstprivatize_variable (ctx, v); + omp_notice_variable (ctx, v, true); + } + decl = TREE_OPERAND (decl, 0); + } if (TREE_CODE (decl) == ADDR_EXPR || TREE_CODE (decl) == INDIRECT_REF) decl = TREE_OPERAND (decl, 0); @@ -6397,9 +6443,7 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, { if (octx->outer_context && (octx->outer_context->region_type - == ORT_COMBINED_PARALLEL - || (octx->outer_context->region_type - == ORT_COMBINED_TEAMS))) + == ORT_COMBINED_PARALLEL)) octx = octx->outer_context; else if (omp_check_private (octx, decl, false)) break; @@ -6414,8 +6458,15 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, && octx == outer_ctx) flags = GOVD_SEEN | GOVD_SHARED; else if (octx + && octx->region_type == ORT_COMBINED_TEAMS) + flags = GOVD_SEEN | GOVD_SHARED; + else if (octx && octx->region_type == ORT_COMBINED_TARGET) - flags &= ~GOVD_LASTPRIVATE; + { + flags &= ~GOVD_LASTPRIVATE; + if (flags == GOVD_SEEN) + break; + } else break; splay_tree_node on @@ -6458,7 +6509,9 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, case OMP_TARGET_DATA: case OMP_TARGET_ENTER_DATA: case OMP_TARGET_EXIT_DATA: - if (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_FIRSTPRIVATE_POINTER) + if (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_FIRSTPRIVATE_POINTER + || (OMP_CLAUSE_MAP_KIND (c) + == GOMP_MAP_FIRSTPRIVATE_REFERENCE)) /* For target {,enter ,exit }data only the array slice is mapped, but not the pointer to it. */ remove = true; @@ -6477,7 +6530,9 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, remove = true; break; } - else if (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_FIRSTPRIVATE_POINTER + else if ((OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_FIRSTPRIVATE_POINTER + || (OMP_CLAUSE_MAP_KIND (c) + == GOMP_MAP_FIRSTPRIVATE_REFERENCE)) && TREE_CODE (OMP_CLAUSE_SIZE (c)) != INTEGER_CST) { OMP_CLAUSE_SIZE (c) @@ -6536,6 +6591,25 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, break; } + if (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ALWAYS_POINTER) + { + /* Error recovery. */ + if (prev_list_p == NULL) + { + remove = true; + break; + } + if (OMP_CLAUSE_CHAIN (*prev_list_p) != c) + { + tree ch = OMP_CLAUSE_CHAIN (*prev_list_p); + if (ch == NULL_TREE || OMP_CLAUSE_CHAIN (ch) != c) + { + remove = true; + break; + } + } + } + tree offset; HOST_WIDE_INT bitsize, bitpos; machine_mode mode; @@ -6555,56 +6629,64 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, splay_tree_node n = splay_tree_lookup (ctx->variables, (splay_tree_key)decl); bool ptr = (OMP_CLAUSE_MAP_KIND (c) - == GOMP_MAP_FIRSTPRIVATE_POINTER); - if (n == NULL || (n->value & (ptr ? GOVD_PRIVATE - : GOVD_MAP)) == 0) + == GOMP_MAP_ALWAYS_POINTER); + if (n == NULL || (n->value & GOVD_MAP) == 0) { + tree l = build_omp_clause (OMP_CLAUSE_LOCATION (c), + OMP_CLAUSE_MAP); + OMP_CLAUSE_SET_MAP_KIND (l, GOMP_MAP_STRUCT); + OMP_CLAUSE_DECL (l) = decl; + OMP_CLAUSE_SIZE (l) = size_int (1); + if (struct_map_to_clause == NULL) + struct_map_to_clause = new hash_map<tree, tree>; + struct_map_to_clause->put (decl, l); if (ptr) { + enum gomp_map_kind mkind + = code == OMP_TARGET_EXIT_DATA + ? GOMP_MAP_RELEASE : GOMP_MAP_ALLOC; tree c2 = build_omp_clause (OMP_CLAUSE_LOCATION (c), - OMP_CLAUSE_PRIVATE); - OMP_CLAUSE_DECL (c2) = decl; - OMP_CLAUSE_CHAIN (c2) = *orig_list_p; - *orig_list_p = c2; - if (struct_map_to_clause == NULL) - struct_map_to_clause = new hash_map<tree, tree>; - tree *osc; - if (n == NULL || (n->value & GOVD_MAP) == 0) - osc = NULL; - else - osc = struct_map_to_clause->get (decl); - if (osc == NULL) - struct_map_to_clause->put (decl, - tree_cons (NULL_TREE, - c, - NULL_TREE)); - else - *osc = tree_cons (*osc, c, NULL_TREE); - flags = GOVD_PRIVATE | GOVD_EXPLICIT; - goto do_add_decl; + OMP_CLAUSE_MAP); + OMP_CLAUSE_SET_MAP_KIND (c2, mkind); + OMP_CLAUSE_DECL (c2) + = unshare_expr (OMP_CLAUSE_DECL (c)); + OMP_CLAUSE_CHAIN (c2) = *prev_list_p; + OMP_CLAUSE_SIZE (c2) + = TYPE_SIZE_UNIT (ptr_type_node); + OMP_CLAUSE_CHAIN (l) = c2; + if (OMP_CLAUSE_CHAIN (*prev_list_p) != c) + { + tree c4 = OMP_CLAUSE_CHAIN (*prev_list_p); + tree c3 + = build_omp_clause (OMP_CLAUSE_LOCATION (c), + OMP_CLAUSE_MAP); + OMP_CLAUSE_SET_MAP_KIND (c3, mkind); + OMP_CLAUSE_DECL (c3) + = unshare_expr (OMP_CLAUSE_DECL (c4)); + OMP_CLAUSE_SIZE (c3) + = TYPE_SIZE_UNIT (ptr_type_node); + OMP_CLAUSE_CHAIN (c3) = *prev_list_p; + OMP_CLAUSE_CHAIN (c2) = c3; + } + *prev_list_p = l; + prev_list_p = NULL; + } + else + { + OMP_CLAUSE_CHAIN (l) = c; + *list_p = l; + list_p = &OMP_CLAUSE_CHAIN (l); } - *list_p = build_omp_clause (OMP_CLAUSE_LOCATION (c), - OMP_CLAUSE_MAP); - OMP_CLAUSE_SET_MAP_KIND (*list_p, GOMP_MAP_STRUCT); - OMP_CLAUSE_DECL (*list_p) = decl; - OMP_CLAUSE_SIZE (*list_p) = size_int (1); - OMP_CLAUSE_CHAIN (*list_p) = c; - if (struct_map_to_clause == NULL) - struct_map_to_clause = new hash_map<tree, tree>; - struct_map_to_clause->put (decl, *list_p); - list_p = &OMP_CLAUSE_CHAIN (*list_p); flags = GOVD_MAP | GOVD_EXPLICIT; - if (OMP_CLAUSE_MAP_KIND (c) & GOMP_MAP_FLAG_ALWAYS) + if (GOMP_MAP_ALWAYS_P (OMP_CLAUSE_MAP_KIND (c)) || ptr) flags |= GOVD_SEEN; goto do_add_decl; } else { tree *osc = struct_map_to_clause->get (decl); - tree *sc = NULL, *pt = NULL; - if (!ptr && TREE_CODE (*osc) == TREE_LIST) - osc = &TREE_PURPOSE (*osc); - if (OMP_CLAUSE_MAP_KIND (c) & GOMP_MAP_FLAG_ALWAYS) + tree *sc = NULL, *scp = NULL; + if (GOMP_MAP_ALWAYS_P (OMP_CLAUSE_MAP_KIND (c)) || ptr) n->value |= GOVD_SEEN; offset_int o1, o2; if (offset) @@ -6613,18 +6695,16 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, o1 = 0; if (bitpos) o1 = o1 + bitpos / BITS_PER_UNIT; - if (ptr) - pt = osc; - else - sc = &OMP_CLAUSE_CHAIN (*osc); - for (; ptr ? (*pt && (sc = &TREE_VALUE (*pt))) - : *sc != c; - ptr ? (pt = &TREE_CHAIN (*pt)) - : (sc = &OMP_CLAUSE_CHAIN (*sc))) - if (TREE_CODE (OMP_CLAUSE_DECL (*sc)) != COMPONENT_REF - && (TREE_CODE (OMP_CLAUSE_DECL (*sc)) - != INDIRECT_REF) - && TREE_CODE (OMP_CLAUSE_DECL (*sc)) != ARRAY_REF) + for (sc = &OMP_CLAUSE_CHAIN (*osc); + *sc != c; sc = &OMP_CLAUSE_CHAIN (*sc)) + if (ptr && sc == prev_list_p) + break; + else if (TREE_CODE (OMP_CLAUSE_DECL (*sc)) + != COMPONENT_REF + && (TREE_CODE (OMP_CLAUSE_DECL (*sc)) + != INDIRECT_REF) + && (TREE_CODE (OMP_CLAUSE_DECL (*sc)) + != ARRAY_REF)) break; else { @@ -6653,6 +6733,8 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, &volatilep, false); if (base != decl) break; + if (scp) + continue; gcc_assert (offset == NULL_TREE || TREE_CODE (offset) == INTEGER_CST); tree d1 = OMP_CLAUSE_DECL (*sc); @@ -6691,19 +6773,68 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, o2 = o2 + bitpos2 / BITS_PER_UNIT; if (wi::ltu_p (o1, o2) || (wi::eq_p (o1, o2) && bitpos < bitpos2)) - break; + { + if (ptr) + scp = sc; + else + break; + } } + if (remove) + break; + OMP_CLAUSE_SIZE (*osc) + = size_binop (PLUS_EXPR, OMP_CLAUSE_SIZE (*osc), + size_one_node); if (ptr) { - if (!remove) - *pt = tree_cons (TREE_PURPOSE (*osc), c, *pt); - break; + tree c2 = build_omp_clause (OMP_CLAUSE_LOCATION (c), + OMP_CLAUSE_MAP); + tree cl = NULL_TREE; + enum gomp_map_kind mkind + = code == OMP_TARGET_EXIT_DATA + ? GOMP_MAP_RELEASE : GOMP_MAP_ALLOC; + OMP_CLAUSE_SET_MAP_KIND (c2, mkind); + OMP_CLAUSE_DECL (c2) + = unshare_expr (OMP_CLAUSE_DECL (c)); + OMP_CLAUSE_CHAIN (c2) = scp ? *scp : *prev_list_p; + OMP_CLAUSE_SIZE (c2) + = TYPE_SIZE_UNIT (ptr_type_node); + cl = scp ? *prev_list_p : c2; + if (OMP_CLAUSE_CHAIN (*prev_list_p) != c) + { + tree c4 = OMP_CLAUSE_CHAIN (*prev_list_p); + tree c3 + = build_omp_clause (OMP_CLAUSE_LOCATION (c), + OMP_CLAUSE_MAP); + OMP_CLAUSE_SET_MAP_KIND (c3, mkind); + OMP_CLAUSE_DECL (c3) + = unshare_expr (OMP_CLAUSE_DECL (c4)); + OMP_CLAUSE_SIZE (c3) + = TYPE_SIZE_UNIT (ptr_type_node); + OMP_CLAUSE_CHAIN (c3) = *prev_list_p; + if (!scp) + OMP_CLAUSE_CHAIN (c2) = c3; + else + cl = c3; + } + if (scp) + *scp = c2; + if (sc == prev_list_p) + { + *sc = cl; + prev_list_p = NULL; + } + else + { + *prev_list_p = OMP_CLAUSE_CHAIN (c); + list_p = prev_list_p; + prev_list_p = NULL; + OMP_CLAUSE_CHAIN (c) = *sc; + *sc = cl; + continue; + } } - if (!remove) - OMP_CLAUSE_SIZE (*osc) - = size_binop (PLUS_EXPR, OMP_CLAUSE_SIZE (*osc), - size_one_node); - if (!remove && *sc != c) + else if (*sc != c) { *list_p = OMP_CLAUSE_CHAIN (c); OMP_CLAUSE_CHAIN (c) = *sc; @@ -6712,9 +6843,19 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, } } } + if (!remove + && OMP_CLAUSE_MAP_KIND (c) != GOMP_MAP_ALWAYS_POINTER + && OMP_CLAUSE_CHAIN (c) + && OMP_CLAUSE_CODE (OMP_CLAUSE_CHAIN (c)) == OMP_CLAUSE_MAP + && (OMP_CLAUSE_MAP_KIND (OMP_CLAUSE_CHAIN (c)) + == GOMP_MAP_ALWAYS_POINTER)) + prev_list_p = list_p; break; } flags = GOVD_MAP | GOVD_EXPLICIT; + if (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ALWAYS_TO + || OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ALWAYS_TOFROM) + flags |= GOVD_MAP_ALWAYS_TO; goto do_add; case OMP_CLAUSE_DEPEND: @@ -6923,7 +7064,12 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, || decl == OMP_CLAUSE_DECL (c) || (TREE_CODE (OMP_CLAUSE_DECL (c)) == MEM_REF && (TREE_CODE (TREE_OPERAND (OMP_CLAUSE_DECL (c), 0)) - == ADDR_EXPR))) + == ADDR_EXPR + || (TREE_CODE (TREE_OPERAND (OMP_CLAUSE_DECL (c), 0)) + == POINTER_PLUS_EXPR + && (TREE_CODE (TREE_OPERAND (TREE_OPERAND + (OMP_CLAUSE_DECL (c), 0), 0)) + == ADDR_EXPR))))) && omp_check_private (ctx, decl, false)) { error ("%s variable %qE is private in outer context", @@ -7192,6 +7338,25 @@ gimplify_adjust_omp_clauses_1 (splay_tree_node n, void *data) OMP_CLAUSE_CHAIN (nc) = OMP_CLAUSE_CHAIN (clause); OMP_CLAUSE_CHAIN (clause) = nc; } + else if (gimplify_omp_ctxp->target_firstprivatize_array_bases + && lang_hooks.decls.omp_privatize_by_reference (decl)) + { + OMP_CLAUSE_DECL (clause) = build_simple_mem_ref (decl); + OMP_CLAUSE_SIZE (clause) + = unshare_expr (TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (decl)))); + struct gimplify_omp_ctx *ctx = gimplify_omp_ctxp; + gimplify_omp_ctxp = ctx->outer_context; + gimplify_expr (&OMP_CLAUSE_SIZE (clause), + pre_p, NULL, is_gimple_val, fb_rvalue); + gimplify_omp_ctxp = ctx; + tree nc = build_omp_clause (OMP_CLAUSE_LOCATION (clause), + OMP_CLAUSE_MAP); + OMP_CLAUSE_DECL (nc) = decl; + OMP_CLAUSE_SIZE (nc) = size_zero_node; + OMP_CLAUSE_SET_MAP_KIND (nc, GOMP_MAP_FIRSTPRIVATE_REFERENCE); + OMP_CLAUSE_CHAIN (nc) = OMP_CLAUSE_CHAIN (clause); + OMP_CLAUSE_CHAIN (clause) = nc; + } else OMP_CLAUSE_SIZE (clause) = DECL_SIZE_UNIT (decl); } @@ -7265,6 +7430,15 @@ gimplify_adjust_omp_clauses (gimple_seq *pre_p, tree *list_p, else OMP_CLAUSE_CODE (c) = OMP_CLAUSE_PRIVATE; } + else if (code == OMP_DISTRIBUTE + && OMP_CLAUSE_LASTPRIVATE_FIRSTPRIVATE (c)) + { + remove = true; + error_at (OMP_CLAUSE_LOCATION (c), + "same variable used in %<firstprivate%> and " + "%<lastprivate%> clauses on %<distribute%> " + "construct"); + } break; case OMP_CLAUSE_ALIGNED: @@ -7310,6 +7484,12 @@ gimplify_adjust_omp_clauses (gimple_seq *pre_p, tree *list_p, break; case OMP_CLAUSE_MAP: + if (code == OMP_TARGET_EXIT_DATA + && OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ALWAYS_POINTER) + { + remove = true; + break; + } decl = OMP_CLAUSE_DECL (c); if (!DECL_P (decl)) { @@ -7339,8 +7519,7 @@ gimplify_adjust_omp_clauses (gimple_seq *pre_p, tree *list_p, n = splay_tree_lookup (ctx->variables, (splay_tree_key) decl); if ((ctx->region_type & ORT_TARGET) != 0 && !(n->value & GOVD_SEEN) - && ((OMP_CLAUSE_MAP_KIND (c) & GOMP_MAP_FLAG_ALWAYS) == 0 - || OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_STRUCT)) + && GOMP_MAP_ALWAYS_P (OMP_CLAUSE_MAP_KIND (c)) == 0) { remove = true; /* For struct element mapping, if struct is never referenced @@ -7361,7 +7540,9 @@ gimplify_adjust_omp_clauses (gimple_seq *pre_p, tree *list_p, else if (DECL_SIZE (decl) && TREE_CODE (DECL_SIZE (decl)) != INTEGER_CST && OMP_CLAUSE_MAP_KIND (c) != GOMP_MAP_POINTER - && OMP_CLAUSE_MAP_KIND (c) != GOMP_MAP_FIRSTPRIVATE_POINTER) + && OMP_CLAUSE_MAP_KIND (c) != GOMP_MAP_FIRSTPRIVATE_POINTER + && (OMP_CLAUSE_MAP_KIND (c) + != GOMP_MAP_FIRSTPRIVATE_REFERENCE)) { /* For GOMP_MAP_FORCE_DEVICEPTR, we'll never enter here, because for these, TREE_CODE (DECL_SIZE (decl)) will always be @@ -7404,9 +7585,9 @@ gimplify_adjust_omp_clauses (gimple_seq *pre_p, tree *list_p, { if (OMP_CLAUSE_SIZE (c) == NULL_TREE) OMP_CLAUSE_SIZE (c) = DECL_SIZE_UNIT (decl); - if ((n->value & GOVD_SEEN) - && (n->value & (GOVD_PRIVATE | GOVD_FIRSTPRIVATE))) - OMP_CLAUSE_MAP_PRIVATE (c) = 1; + gcc_assert ((n->value & GOVD_SEEN) == 0 + || ((n->value & (GOVD_PRIVATE | GOVD_FIRSTPRIVATE)) + == 0)); } break; @@ -7878,6 +8059,26 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) OMP_CLAUSE_LINEAR_NO_COPYOUT (c) = 1; flags |= GOVD_LINEAR_LASTPRIVATE_NO_OUTER; } + else + { + struct gimplify_omp_ctx *octx = outer->outer_context; + if (octx + && octx->region_type == ORT_COMBINED_PARALLEL + && octx->outer_context + && (octx->outer_context->region_type + == ORT_WORKSHARE) + && octx->outer_context->combined_loop) + { + octx = octx->outer_context; + n = splay_tree_lookup (octx->variables, + (splay_tree_key)decl); + if (n != NULL && (n->value & GOVD_LOCAL) != 0) + { + OMP_CLAUSE_LINEAR_NO_COPYOUT (c) = 1; + flags |= GOVD_LINEAR_LASTPRIVATE_NO_OUTER; + } + } + } } } @@ -7912,7 +8113,41 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) { omp_add_variable (outer, decl, GOVD_LASTPRIVATE | GOVD_SEEN); - if (outer->outer_context) + if (outer->region_type == ORT_COMBINED_PARALLEL + && outer->outer_context + && (outer->outer_context->region_type + == ORT_WORKSHARE) + && outer->outer_context->combined_loop) + { + outer = outer->outer_context; + n = splay_tree_lookup (outer->variables, + (splay_tree_key)decl); + if (omp_check_private (outer, decl, false)) + outer = NULL; + else if (n == NULL + || ((n->value & GOVD_DATA_SHARE_CLASS) + == 0)) + omp_add_variable (outer, decl, + GOVD_LASTPRIVATE + | GOVD_SEEN); + else + outer = NULL; + } + if (outer && outer->outer_context + && (outer->outer_context->region_type + == ORT_COMBINED_TEAMS)) + { + outer = outer->outer_context; + n = splay_tree_lookup (outer->variables, + (splay_tree_key)decl); + if (n == NULL + || (n->value & GOVD_DATA_SHARE_CLASS) == 0) + omp_add_variable (outer, decl, + GOVD_SHARED | GOVD_SEEN); + else + outer = NULL; + } + if (outer && outer->outer_context) omp_notice_variable (outer->outer_context, decl, true); } @@ -7961,7 +8196,41 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) { omp_add_variable (outer, decl, GOVD_LASTPRIVATE | GOVD_SEEN); - if (outer->outer_context) + if (outer->region_type == ORT_COMBINED_PARALLEL + && outer->outer_context + && (outer->outer_context->region_type + == ORT_WORKSHARE) + && outer->outer_context->combined_loop) + { + outer = outer->outer_context; + n = splay_tree_lookup (outer->variables, + (splay_tree_key)decl); + if (omp_check_private (outer, decl, false)) + outer = NULL; + else if (n == NULL + || ((n->value & GOVD_DATA_SHARE_CLASS) + == 0)) + omp_add_variable (outer, decl, + GOVD_LASTPRIVATE + | GOVD_SEEN); + else + outer = NULL; + } + if (outer && outer->outer_context + && (outer->outer_context->region_type + == ORT_COMBINED_TEAMS)) + { + outer = outer->outer_context; + n = splay_tree_lookup (outer->variables, + (splay_tree_key)decl); + if (n == NULL + || (n->value & GOVD_DATA_SHARE_CLASS) == 0) + omp_add_variable (outer, decl, + GOVD_SHARED | GOVD_SEEN); + else + outer = NULL; + } + if (outer && outer->outer_context) omp_notice_variable (outer->outer_context, decl, true); } @@ -8399,6 +8668,201 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) return GS_ALL_DONE; } +/* Helper function of optimize_target_teams, find OMP_TEAMS inside + of OMP_TARGET's body. */ + +static tree +find_omp_teams (tree *tp, int *walk_subtrees, void *) +{ + *walk_subtrees = 0; + switch (TREE_CODE (*tp)) + { + case OMP_TEAMS: + return *tp; + case BIND_EXPR: + case STATEMENT_LIST: + *walk_subtrees = 1; + break; + default: + break; + } + return NULL_TREE; +} + +/* Helper function of optimize_target_teams, determine if the expression + can be computed safely before the target construct on the host. */ + +static tree +computable_teams_clause (tree *tp, int *walk_subtrees, void *) +{ + splay_tree_node n; + + if (TYPE_P (*tp)) + { + *walk_subtrees = 0; + return NULL_TREE; + } + switch (TREE_CODE (*tp)) + { + case VAR_DECL: + case PARM_DECL: + case RESULT_DECL: + *walk_subtrees = 0; + if (error_operand_p (*tp) + || !INTEGRAL_TYPE_P (TREE_TYPE (*tp)) + || DECL_HAS_VALUE_EXPR_P (*tp) + || DECL_THREAD_LOCAL_P (*tp) + || TREE_SIDE_EFFECTS (*tp) + || TREE_THIS_VOLATILE (*tp)) + return *tp; + if (is_global_var (*tp) + && (lookup_attribute ("omp declare target", DECL_ATTRIBUTES (*tp)) + || lookup_attribute ("omp declare target link", + DECL_ATTRIBUTES (*tp)))) + return *tp; + n = splay_tree_lookup (gimplify_omp_ctxp->variables, + (splay_tree_key) *tp); + if (n == NULL) + { + if (gimplify_omp_ctxp->target_map_scalars_firstprivate) + return NULL_TREE; + return *tp; + } + else if (n->value & GOVD_LOCAL) + return *tp; + else if (n->value & GOVD_FIRSTPRIVATE) + return NULL_TREE; + else if ((n->value & (GOVD_MAP | GOVD_MAP_ALWAYS_TO)) + == (GOVD_MAP | GOVD_MAP_ALWAYS_TO)) + return NULL_TREE; + return *tp; + case INTEGER_CST: + if (!INTEGRAL_TYPE_P (TREE_TYPE (*tp))) + return *tp; + return NULL_TREE; + case TARGET_EXPR: + if (TARGET_EXPR_INITIAL (*tp) + || TREE_CODE (TARGET_EXPR_SLOT (*tp)) != VAR_DECL) + return *tp; + return computable_teams_clause (&TARGET_EXPR_SLOT (*tp), + walk_subtrees, NULL); + /* Allow some reasonable subset of integral arithmetics. */ + case PLUS_EXPR: + case MINUS_EXPR: + case MULT_EXPR: + case TRUNC_DIV_EXPR: + case CEIL_DIV_EXPR: + case FLOOR_DIV_EXPR: + case ROUND_DIV_EXPR: + case TRUNC_MOD_EXPR: + case CEIL_MOD_EXPR: + case FLOOR_MOD_EXPR: + case ROUND_MOD_EXPR: + case RDIV_EXPR: + case EXACT_DIV_EXPR: + case MIN_EXPR: + case MAX_EXPR: + case LSHIFT_EXPR: + case RSHIFT_EXPR: + case BIT_IOR_EXPR: + case BIT_XOR_EXPR: + case BIT_AND_EXPR: + case NEGATE_EXPR: + case ABS_EXPR: + case BIT_NOT_EXPR: + case NON_LVALUE_EXPR: + CASE_CONVERT: + if (!INTEGRAL_TYPE_P (TREE_TYPE (*tp))) + return *tp; + return NULL_TREE; + /* And disallow anything else, except for comparisons. */ + default: + if (COMPARISON_CLASS_P (*tp)) + return NULL_TREE; + return *tp; + } +} + +/* Try to determine if the num_teams and/or thread_limit expressions + can have their values determined already before entering the + target construct. + INTEGER_CSTs trivially are, + integral decls that are firstprivate (explicitly or implicitly) + or explicitly map(always, to:) or map(always, tofrom:) on the target + region too, and expressions involving simple arithmetics on those + too, function calls are not ok, dereferencing something neither etc. + Add NUM_TEAMS and THREAD_LIMIT clauses to the OMP_CLAUSES of + EXPR based on what we find: + 0 stands for clause not specified at all, use implementation default + -1 stands for value that can't be determined easily before entering + the target construct. + If teams construct is not present at all, use 1 for num_teams + and 0 for thread_limit (only one team is involved, and the thread + limit is implementation defined. */ + +static void +optimize_target_teams (tree target, gimple_seq *pre_p) +{ + tree body = OMP_BODY (target); + tree teams = walk_tree (&body, find_omp_teams, NULL, NULL); + tree num_teams = integer_zero_node; + tree thread_limit = integer_zero_node; + location_t num_teams_loc = EXPR_LOCATION (target); + location_t thread_limit_loc = EXPR_LOCATION (target); + tree c, *p, expr; + struct gimplify_omp_ctx *target_ctx = gimplify_omp_ctxp; + + if (teams == NULL_TREE) + num_teams = integer_one_node; + else + for (c = OMP_TEAMS_CLAUSES (teams); c; c = OMP_CLAUSE_CHAIN (c)) + { + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_NUM_TEAMS) + { + p = &num_teams; + num_teams_loc = OMP_CLAUSE_LOCATION (c); + } + else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_THREAD_LIMIT) + { + p = &thread_limit; + thread_limit_loc = OMP_CLAUSE_LOCATION (c); + } + else + continue; + expr = OMP_CLAUSE_OPERAND (c, 0); + if (TREE_CODE (expr) == INTEGER_CST) + { + *p = expr; + continue; + } + if (walk_tree (&expr, computable_teams_clause, NULL, NULL)) + { + *p = integer_minus_one_node; + continue; + } + *p = expr; + gimplify_omp_ctxp = gimplify_omp_ctxp->outer_context; + if (gimplify_expr (p, pre_p, NULL, is_gimple_val, fb_rvalue) + == GS_ERROR) + { + gimplify_omp_ctxp = target_ctx; + *p = integer_minus_one_node; + continue; + } + gimplify_omp_ctxp = target_ctx; + if (!DECL_P (expr) && TREE_CODE (expr) != TARGET_EXPR) + OMP_CLAUSE_OPERAND (c, 0) = *p; + } + c = build_omp_clause (thread_limit_loc, OMP_CLAUSE_THREAD_LIMIT); + OMP_CLAUSE_THREAD_LIMIT_EXPR (c) = thread_limit; + OMP_CLAUSE_CHAIN (c) = OMP_TARGET_CLAUSES (target); + OMP_TARGET_CLAUSES (target) = c; + c = build_omp_clause (num_teams_loc, OMP_CLAUSE_NUM_TEAMS); + OMP_CLAUSE_NUM_TEAMS_EXPR (c) = num_teams; + OMP_CLAUSE_CHAIN (c) = OMP_TARGET_CLAUSES (target); + OMP_TARGET_CLAUSES (target) = c; +} + /* Gimplify the gross structure of several OMP constructs. */ static void @@ -8434,6 +8898,8 @@ gimplify_omp_workshare (tree *expr_p, gimple_seq *pre_p) } gimplify_scan_omp_clauses (&OMP_CLAUSES (expr), pre_p, ort, TREE_CODE (expr)); + if (TREE_CODE (expr) == OMP_TARGET) + optimize_target_teams (expr, pre_p); if ((ort & (ORT_TARGET | ORT_TARGET_DATA)) != 0) { push_gimplify_context (); |