aboutsummaryrefslogtreecommitdiff
path: root/gcc/c-family/c-omp.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/c-family/c-omp.cc')
-rw-r--r--gcc/c-family/c-omp.cc865
1 files changed, 803 insertions, 62 deletions
diff --git a/gcc/c-family/c-omp.cc b/gcc/c-family/c-omp.cc
index a92c6e3..a3cd1ae 100644
--- a/gcc/c-family/c-omp.cc
+++ b/gcc/c-family/c-omp.cc
@@ -764,9 +764,7 @@ c_finish_omp_depobj (location_t loc, tree depobj,
kind = OMP_CLAUSE_DEPEND_KIND (clause);
t = OMP_CLAUSE_DECL (clause);
gcc_assert (t);
- if (TREE_CODE (t) == TREE_LIST
- && TREE_PURPOSE (t)
- && TREE_CODE (TREE_PURPOSE (t)) == TREE_VEC)
+ if (OMP_ITERATOR_DECL_P (t))
{
error_at (OMP_CLAUSE_LOCATION (clause),
"%<iterator%> modifier may not be specified on "
@@ -2178,6 +2176,7 @@ c_omp_split_clauses (location_t loc, enum tree_code code,
case OMP_CLAUSE_HAS_DEVICE_ADDR:
case OMP_CLAUSE_DEFAULTMAP:
case OMP_CLAUSE_DEPEND:
+ case OMP_CLAUSE_USES_ALLOCATORS:
s = C_OMP_CLAUSE_SPLIT_TARGET;
break;
case OMP_CLAUSE_DOACROSS:
@@ -3546,7 +3545,9 @@ c_omp_address_inspector::map_supported_p ()
|| TREE_CODE (t) == POINTER_PLUS_EXPR
|| TREE_CODE (t) == NON_LVALUE_EXPR
|| TREE_CODE (t) == OMP_ARRAY_SECTION
- || TREE_CODE (t) == NOP_EXPR)
+ || TREE_CODE (t) == NOP_EXPR
+ || TREE_CODE (t) == VIEW_CONVERT_EXPR
+ || TREE_CODE (t) == ADDR_EXPR)
if (TREE_CODE (t) == COMPOUND_EXPR)
t = TREE_OPERAND (t, 1);
else
@@ -3641,11 +3642,12 @@ c_omp_address_inspector::maybe_zero_length_array_section (tree clause)
expression types here, because e.g. you can't have an array of
references. */
-static tree
-omp_expand_access_chain (tree c, tree expr, vec<omp_addr_token *> &addr_tokens,
- unsigned *idx, c_omp_region_type ort)
+static tree *
+omp_expand_access_chain (tree *pc, tree expr,
+ vec<omp_addr_token *> &addr_tokens, unsigned *idx, c_omp_region_type ort)
{
using namespace omp_addr_tokenizer;
+ tree c = *pc;
location_t loc = OMP_CLAUSE_LOCATION (c);
unsigned i = *idx;
tree c2 = NULL_TREE;
@@ -3688,39 +3690,114 @@ omp_expand_access_chain (tree c, tree expr, vec<omp_addr_token *> &addr_tokens,
break;
default:
- return error_mark_node;
+ return NULL;
}
if (c2)
{
OMP_CLAUSE_CHAIN (c2) = OMP_CLAUSE_CHAIN (c);
OMP_CLAUSE_CHAIN (c) = c2;
- c = c2;
+ pc = &OMP_CLAUSE_CHAIN (c);
}
*idx = ++i;
if (i < addr_tokens.length ()
&& addr_tokens[i]->type == ACCESS_METHOD)
- return omp_expand_access_chain (c, expr, addr_tokens, idx, ort);
+ return omp_expand_access_chain (pc, expr, addr_tokens, idx, ort);
- return c;
+ return pc;
+}
+
+static tree *
+omp_expand_grid_dim (location_t loc, tree *pc, tree decl)
+{
+ if (TREE_CODE (decl) == OMP_ARRAY_SECTION)
+ pc = omp_expand_grid_dim (loc, pc, TREE_OPERAND (decl, 0));
+ else
+ return pc;
+
+ tree c = *pc;
+ tree low_bound = TREE_OPERAND (decl, 1);
+ tree length = TREE_OPERAND (decl, 2);
+ tree stride = TREE_OPERAND (decl, 3);
+
+ tree cd = build_omp_clause (loc, OMP_CLAUSE_MAP);
+ OMP_CLAUSE_SET_MAP_KIND (cd, GOMP_MAP_GRID_DIM);
+ OMP_CLAUSE_DECL (cd) = unshare_expr (low_bound);
+ OMP_CLAUSE_SIZE (cd) = unshare_expr (length);
+
+ if (stride && !integer_onep (stride))
+ {
+ tree cs = build_omp_clause (loc, OMP_CLAUSE_MAP);
+ OMP_CLAUSE_SET_MAP_KIND (cs, GOMP_MAP_GRID_STRIDE);
+ OMP_CLAUSE_DECL (cs) = unshare_expr (stride);
+
+ OMP_CLAUSE_CHAIN (cs) = OMP_CLAUSE_CHAIN (c);
+ OMP_CLAUSE_CHAIN (cd) = cs;
+ OMP_CLAUSE_CHAIN (c) = cd;
+ pc = &OMP_CLAUSE_CHAIN (cd);
+ }
+ else
+ {
+ OMP_CLAUSE_CHAIN (cd) = OMP_CLAUSE_CHAIN (c);
+ OMP_CLAUSE_CHAIN (c) = cd;
+ pc = &OMP_CLAUSE_CHAIN (c);
+ }
+
+ return pc;
+}
+
+tree *
+omp_handle_noncontig_array (location_t loc, tree *pc, tree c, tree base)
+{
+ tree type;
+
+ if (POINTER_TYPE_P (TREE_TYPE (base)))
+ type = TREE_TYPE (TREE_TYPE (base));
+ else
+ type = strip_array_types (TREE_TYPE (base));
+
+ tree c_map = build_omp_clause (loc, OMP_CLAUSE_MAP);
+
+ OMP_CLAUSE_DECL (c_map) = unshare_expr (base);
+ /* Use the element size (or pointed-to type size) here. */
+ OMP_CLAUSE_SIZE (c_map) = TYPE_SIZE_UNIT (type);
+
+ switch (OMP_CLAUSE_CODE (c))
+ {
+ case OMP_CLAUSE_TO:
+ OMP_CLAUSE_SET_MAP_KIND (c_map, GOMP_MAP_TO_GRID);
+ break;
+ case OMP_CLAUSE_FROM:
+ OMP_CLAUSE_SET_MAP_KIND (c_map, GOMP_MAP_FROM_GRID);
+ break;
+ default:
+ gcc_unreachable ();
+ }
+
+ OMP_CLAUSE_CHAIN (c_map) = OMP_CLAUSE_CHAIN (c);
+
+ *pc = c_map;
+
+ return omp_expand_grid_dim (loc, pc, OMP_CLAUSE_DECL (c));
}
/* Translate "array_base_decl access_method" to OMP mapping clauses. */
-tree
-c_omp_address_inspector::expand_array_base (tree c,
+tree *
+c_omp_address_inspector::expand_array_base (tree *pc,
vec<omp_addr_token *> &addr_tokens,
tree expr, unsigned *idx,
c_omp_region_type ort)
{
using namespace omp_addr_tokenizer;
+ tree c = *pc;
location_t loc = OMP_CLAUSE_LOCATION (c);
int i = *idx;
tree decl = addr_tokens[i + 1]->expr;
bool decl_p = DECL_P (decl);
- bool declare_target_p = (decl_p
+ bool declare_target_p = (DECL_P (decl)
&& is_global_var (decl)
&& lookup_attribute ("omp declare target",
DECL_ATTRIBUTES (decl)));
@@ -3731,6 +3808,7 @@ c_omp_address_inspector::expand_array_base (tree c,
unsigned consume_tokens = 2;
bool target_p = (ort & C_ORT_TARGET) != 0;
bool openmp_p = (ort & C_ORT_OMP) != 0;
+ unsigned acc = i + 1;
gcc_assert (i == 0);
@@ -3741,10 +3819,18 @@ c_omp_address_inspector::expand_array_base (tree c,
{
i += 2;
*idx = i;
- return c;
+ return pc;
+ }
+
+ if (!map_p && chain_p)
+ {
+ /* See comment in c_omp_address_inspector::expand_component_selector. */
+ while (acc + 1 < addr_tokens.length ()
+ && addr_tokens[acc + 1]->type == ACCESS_METHOD)
+ acc++;
}
- switch (addr_tokens[i + 1]->u.access_kind)
+ switch (addr_tokens[acc]->u.access_kind)
{
case ACCESS_DIRECT:
if (decl_p && !target_p)
@@ -3867,7 +3953,8 @@ c_omp_address_inspector::expand_array_base (tree c,
/* The code handling "firstprivatize_array_bases" in gimplify.cc is
relevant here. What do we need to create for arrays at this
stage? (This condition doesn't feel quite right. FIXME?) */
- if (!target_p
+ if (openmp_p
+ && !target_p
&& (TREE_CODE (TREE_TYPE (addr_tokens[i + 1]->expr))
== ARRAY_TYPE))
break;
@@ -3878,7 +3965,7 @@ c_omp_address_inspector::expand_array_base (tree c,
virtual_origin);
tree data_addr = omp_accessed_addr (addr_tokens, i + 1, expr);
c2 = build_omp_clause (loc, OMP_CLAUSE_MAP);
- if (decl_p && target_p)
+ if (decl_p && (!openmp_p || target_p))
{
/* See comment for ACCESS_INDEXED_REF_TO_ARRAY above. */
enum gomp_map_kind k = chain_p ? GOMP_MAP_POINTER
@@ -3934,9 +4021,11 @@ c_omp_address_inspector::expand_array_base (tree c,
tree data_addr = omp_accessed_addr (addr_tokens, last_access, expr);
c2 = build_omp_clause (loc, OMP_CLAUSE_MAP);
/* For OpenACC, use FIRSTPRIVATE_POINTER for decls even on non-compute
- regions (e.g. "acc data" constructs). It'll be removed anyway in
- gimplify.cc, but doing it this way maintains diagnostic
- behaviour. */
+ regions (e.g. "acc data" constructs). It is used during "lexical
+ inheritance" of mapping clauses on enclosed target
+ (parallel/serial/kernels) regions, i.e. creating "present" mappings
+ for sections of pointer-based arrays. It's also used for
+ diagnostics. */
if (decl_p && (target_p || !openmp_p) && !chain_p && !declare_target_p)
OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_FIRSTPRIVATE_POINTER);
else
@@ -4013,9 +4102,43 @@ c_omp_address_inspector::expand_array_base (tree c,
}
break;
+ case ACCESS_NONCONTIG_ARRAY:
+ {
+ gcc_assert (!map_p);
+
+ tree base = addr_tokens[acc]->expr;
+
+ if (decl_p)
+ c_common_mark_addressable_vec (base);
+
+ pc = omp_handle_noncontig_array (loc, pc, c, base);
+ consume_tokens = (acc + 1) - i;
+ chain_p = false;
+ }
+ break;
+
+ case ACCESS_NONCONTIG_REF_TO_ARRAY:
+ {
+ gcc_assert (!map_p);
+
+ if (decl_p)
+ c_common_mark_addressable_vec (addr_tokens[acc]->expr);
+
+ /* Or here. */
+ gcc_assert (!chain_p);
+
+ tree base = addr_tokens[i + 1]->expr;
+ base = convert_from_reference (base);
+
+ pc = omp_handle_noncontig_array (loc, pc, c, base);
+ consume_tokens = (acc + 1) - i;
+ chain_p = false;
+ }
+ break;
+
default:
*idx = i + consume_tokens;
- return error_mark_node;
+ return NULL;
}
if (c3)
@@ -4028,43 +4151,65 @@ c_omp_address_inspector::expand_array_base (tree c,
OMP_CLAUSE_MAP_IMPLICIT (c2) = 1;
OMP_CLAUSE_MAP_IMPLICIT (c3) = 1;
}
- c = c3;
+ pc = &OMP_CLAUSE_CHAIN (c2);
}
else if (c2)
{
+ if (OMP_CLAUSE_MAP_READONLY (c))
+ OMP_CLAUSE_MAP_POINTS_TO_READONLY (c2) = 1;
OMP_CLAUSE_CHAIN (c2) = OMP_CLAUSE_CHAIN (c);
OMP_CLAUSE_CHAIN (c) = c2;
if (implicit_p)
OMP_CLAUSE_MAP_IMPLICIT (c2) = 1;
- c = c2;
+ pc = &OMP_CLAUSE_CHAIN (c);
}
i += consume_tokens;
*idx = i;
if (chain_p && map_p)
- return omp_expand_access_chain (c, expr, addr_tokens, idx, ort);
+ return omp_expand_access_chain (pc, expr, addr_tokens, idx, ort);
- return c;
+ return pc;
}
/* Translate "component_selector access_method" to OMP mapping clauses. */
-tree
-c_omp_address_inspector::expand_component_selector (tree c,
+tree *
+c_omp_address_inspector::expand_component_selector (tree *pc,
vec<omp_addr_token *>
&addr_tokens,
tree expr, unsigned *idx,
c_omp_region_type ort)
{
using namespace omp_addr_tokenizer;
+ tree c = *pc;
location_t loc = OMP_CLAUSE_LOCATION (c);
unsigned i = *idx;
tree c2 = NULL_TREE, c3 = NULL_TREE;
bool chain_p = omp_access_chain_p (addr_tokens, i + 1);
bool map_p = OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP;
+ unsigned acc = i + 1;
+
+ if (!map_p && chain_p)
+ {
+ /* We have a non-map clause (i.e. to/from for an "update" directive),
+ and we might have a noncontiguous array section at the end of a
+ chain of other accesses, e.g. pointer indirections like this:
+
+ struct_base_decl access_pointer access_pointer component_selector
+ access_pointer access_pointer access_noncontig_array
- switch (addr_tokens[i + 1]->u.access_kind)
+ We only need to process the last access in this case, so skip
+ over previous accesses. */
+
+ while (acc + 1 < addr_tokens.length ()
+ && addr_tokens[acc + 1]->type == ACCESS_METHOD)
+ acc++;
+ chain_p = false;
+ }
+
+ switch (addr_tokens[acc]->u.access_kind)
{
case ACCESS_DIRECT:
case ACCESS_INDEXED_ARRAY:
@@ -4074,7 +4219,7 @@ c_omp_address_inspector::expand_component_selector (tree c,
{
/* Copy the referenced object. Note that we also do this for !MAP_P
clauses. */
- tree obj = convert_from_reference (addr_tokens[i + 1]->expr);
+ tree obj = convert_from_reference (addr_tokens[acc]->expr);
OMP_CLAUSE_DECL (c) = obj;
OMP_CLAUSE_SIZE (c) = TYPE_SIZE_UNIT (TREE_TYPE (obj));
@@ -4083,7 +4228,7 @@ c_omp_address_inspector::expand_component_selector (tree c,
c2 = build_omp_clause (loc, OMP_CLAUSE_MAP);
OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_ATTACH_DETACH);
- OMP_CLAUSE_DECL (c2) = addr_tokens[i + 1]->expr;
+ OMP_CLAUSE_DECL (c2) = addr_tokens[acc]->expr;
OMP_CLAUSE_SIZE (c2) = size_zero_node;
}
break;
@@ -4094,15 +4239,15 @@ c_omp_address_inspector::expand_component_selector (tree c,
break;
tree virtual_origin
- = convert_from_reference (addr_tokens[i + 1]->expr);
+ = convert_from_reference (addr_tokens[acc]->expr);
virtual_origin = build_fold_addr_expr (virtual_origin);
virtual_origin = fold_convert_loc (loc, ptrdiff_type_node,
virtual_origin);
- tree data_addr = omp_accessed_addr (addr_tokens, i + 1, expr);
+ tree data_addr = omp_accessed_addr (addr_tokens, acc, expr);
c2 = build_omp_clause (loc, OMP_CLAUSE_MAP);
OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_ATTACH_DETACH);
- OMP_CLAUSE_DECL (c2) = addr_tokens[i + 1]->expr;
+ OMP_CLAUSE_DECL (c2) = addr_tokens[acc]->expr;
OMP_CLAUSE_SIZE (c2)
= fold_build2_loc (loc, MINUS_EXPR, ptrdiff_type_node,
fold_convert_loc (loc, ptrdiff_type_node,
@@ -4119,12 +4264,12 @@ c_omp_address_inspector::expand_component_selector (tree c,
tree virtual_origin
= fold_convert_loc (loc, ptrdiff_type_node,
- addr_tokens[i + 1]->expr);
- tree data_addr = omp_accessed_addr (addr_tokens, i + 1, expr);
+ addr_tokens[acc]->expr);
+ tree data_addr = omp_accessed_addr (addr_tokens, acc, expr);
c2 = build_omp_clause (loc, OMP_CLAUSE_MAP);
OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_ATTACH_DETACH);
- OMP_CLAUSE_DECL (c2) = addr_tokens[i + 1]->expr;
+ OMP_CLAUSE_DECL (c2) = addr_tokens[acc]->expr;
OMP_CLAUSE_SIZE (c2)
= fold_build2_loc (loc, MINUS_EXPR, ptrdiff_type_node,
fold_convert_loc (loc, ptrdiff_type_node,
@@ -4139,10 +4284,10 @@ c_omp_address_inspector::expand_component_selector (tree c,
if (!map_p)
break;
- tree ptr = convert_from_reference (addr_tokens[i + 1]->expr);
+ tree ptr = convert_from_reference (addr_tokens[acc]->expr);
tree virtual_origin = fold_convert_loc (loc, ptrdiff_type_node,
ptr);
- tree data_addr = omp_accessed_addr (addr_tokens, i + 1, expr);
+ tree data_addr = omp_accessed_addr (addr_tokens, acc, expr);
/* Attach the pointer... */
c2 = build_omp_clause (OMP_CLAUSE_LOCATION (c), OMP_CLAUSE_MAP);
@@ -4157,14 +4302,39 @@ c_omp_address_inspector::expand_component_selector (tree c,
/* ...and also the reference. */
c3 = build_omp_clause (OMP_CLAUSE_LOCATION (c), OMP_CLAUSE_MAP);
OMP_CLAUSE_SET_MAP_KIND (c3, GOMP_MAP_ATTACH_DETACH);
- OMP_CLAUSE_DECL (c3) = addr_tokens[i + 1]->expr;
+ OMP_CLAUSE_DECL (c3) = addr_tokens[acc]->expr;
OMP_CLAUSE_SIZE (c3) = size_zero_node;
}
break;
+ case ACCESS_NONCONTIG_ARRAY:
+ {
+ gcc_assert (!map_p);
+
+ /* We don't expect to see further accesses here. */
+ gcc_assert (!chain_p);
+
+ pc = omp_handle_noncontig_array (loc, pc, c, addr_tokens[acc]->expr);
+ }
+ break;
+
+ case ACCESS_NONCONTIG_REF_TO_ARRAY:
+ {
+ gcc_assert (!map_p);
+
+ /* Or here. */
+ gcc_assert (!chain_p);
+
+ tree base = addr_tokens[acc]->expr;
+ base = convert_from_reference (base);
+
+ pc = omp_handle_noncontig_array (loc, pc, c, base);
+ }
+ break;
+
default:
- *idx = i + 2;
- return error_mark_node;
+ *idx = acc + 1;
+ return NULL;
}
if (c3)
@@ -4172,29 +4342,30 @@ c_omp_address_inspector::expand_component_selector (tree c,
OMP_CLAUSE_CHAIN (c3) = OMP_CLAUSE_CHAIN (c);
OMP_CLAUSE_CHAIN (c2) = c3;
OMP_CLAUSE_CHAIN (c) = c2;
- c = c3;
+ pc = &OMP_CLAUSE_CHAIN (c2);
}
else if (c2)
{
+ if (OMP_CLAUSE_MAP_READONLY (c))
+ OMP_CLAUSE_MAP_POINTS_TO_READONLY (c2) = 1;
OMP_CLAUSE_CHAIN (c2) = OMP_CLAUSE_CHAIN (c);
OMP_CLAUSE_CHAIN (c) = c2;
- c = c2;
+ pc = &OMP_CLAUSE_CHAIN (c);
}
- i += 2;
- *idx = i;
+ *idx = acc + 1;
if (chain_p && map_p)
- return omp_expand_access_chain (c, expr, addr_tokens, idx, ort);
+ return omp_expand_access_chain (pc, expr, addr_tokens, idx, ort);
- return c;
+ return pc;
}
/* Expand a map clause into a group of mapping clauses, creating nodes to
attach/detach pointers and so forth as necessary. */
-tree
-c_omp_address_inspector::expand_map_clause (tree c, tree expr,
+tree *
+c_omp_address_inspector::expand_map_clause (tree *pc, tree expr,
vec<omp_addr_token *> &addr_tokens,
c_omp_region_type ort)
{
@@ -4210,18 +4381,18 @@ c_omp_address_inspector::expand_map_clause (tree c, tree expr,
&& addr_tokens[i]->u.structure_base_kind == BASE_DECL
&& addr_tokens[i + 1]->type == ACCESS_METHOD)
{
- c = expand_array_base (c, addr_tokens, expr, &i, ort);
- if (c == error_mark_node)
- return error_mark_node;
+ pc = expand_array_base (pc, addr_tokens, expr, &i, ort);
+ if (pc == NULL)
+ return NULL;
}
else if (remaining >= 2
&& addr_tokens[i]->type == ARRAY_BASE
&& addr_tokens[i]->u.structure_base_kind == BASE_ARBITRARY_EXPR
&& addr_tokens[i + 1]->type == ACCESS_METHOD)
{
- c = expand_array_base (c, addr_tokens, expr, &i, ort);
- if (c == error_mark_node)
- return error_mark_node;
+ pc = expand_array_base (pc, addr_tokens, expr, &i, ort);
+ if (pc == NULL)
+ return NULL;
}
else if (remaining >= 2
&& addr_tokens[i]->type == STRUCTURE_BASE
@@ -4248,18 +4419,18 @@ c_omp_address_inspector::expand_map_clause (tree c, tree expr,
i++;
break;
default:
- return error_mark_node;
+ return NULL;
}
}
else if (remaining >= 2
&& addr_tokens[i]->type == COMPONENT_SELECTOR
&& addr_tokens[i + 1]->type == ACCESS_METHOD)
{
- c = expand_component_selector (c, addr_tokens, expr, &i, ort);
+ pc = expand_component_selector (pc, addr_tokens, expr, &i, ort);
/* We used 'expr', so these must have been the last tokens. */
gcc_assert (i == length);
- if (c == error_mark_node)
- return error_mark_node;
+ if (pc == NULL)
+ return NULL;
}
else if (remaining >= 3
&& addr_tokens[i]->type == COMPONENT_SELECTOR
@@ -4277,9 +4448,579 @@ c_omp_address_inspector::expand_map_clause (tree c, tree expr,
}
if (i == length)
- return c;
+ return pc;
- return error_mark_node;
+ return NULL;
+}
+
+/* Given a mapper function MAPPER_FN, recursively scan through the map clauses
+ for that mapper, and if any of those should use a (named or unnamed) mapper
+ themselves, add it to MLIST. */
+
+void
+c_omp_find_nested_mappers (omp_mapper_list<tree> *mlist, tree mapper_fn)
+{
+ tree mapper = lang_hooks.decls.omp_extract_mapper_directive (mapper_fn);
+ tree mapper_name = NULL_TREE;
+
+ if (mapper == error_mark_node)
+ return;
+
+ gcc_assert (TREE_CODE (mapper) == OMP_DECLARE_MAPPER);
+
+ for (tree clause = OMP_DECLARE_MAPPER_CLAUSES (mapper);
+ clause;
+ clause = OMP_CLAUSE_CHAIN (clause))
+ {
+ tree expr = OMP_CLAUSE_DECL (clause);
+ enum gomp_map_kind clause_kind = OMP_CLAUSE_MAP_KIND (clause);
+ tree elem_type;
+
+ if (clause_kind == GOMP_MAP_PUSH_MAPPER_NAME)
+ {
+ mapper_name = expr;
+ continue;
+ }
+ else if (clause_kind == GOMP_MAP_POP_MAPPER_NAME)
+ {
+ mapper_name = NULL_TREE;
+ continue;
+ }
+
+ gcc_assert (TREE_CODE (expr) != TREE_LIST);
+ if (TREE_CODE (expr) == OMP_ARRAY_SECTION)
+ {
+ while (TREE_CODE (expr) == OMP_ARRAY_SECTION)
+ expr = TREE_OPERAND (expr, 0);
+
+ elem_type = TREE_TYPE (expr);
+ }
+ else
+ elem_type = TREE_TYPE (expr);
+
+ /* This might be too much... or not enough? */
+ while (TREE_CODE (elem_type) == ARRAY_TYPE
+ || TREE_CODE (elem_type) == POINTER_TYPE
+ || TREE_CODE (elem_type) == REFERENCE_TYPE)
+ elem_type = TREE_TYPE (elem_type);
+
+ elem_type = TYPE_MAIN_VARIANT (elem_type);
+
+ if (AGGREGATE_TYPE_P (elem_type)
+ && !mlist->contains (mapper_name, elem_type))
+ {
+ tree nested_mapper_fn
+ = lang_hooks.decls.omp_mapper_lookup (mapper_name, elem_type);
+
+ if (nested_mapper_fn)
+ {
+ mlist->add_mapper (mapper_name, elem_type, nested_mapper_fn);
+ c_omp_find_nested_mappers (mlist, nested_mapper_fn);
+ }
+ else if (mapper_name)
+ {
+ error ("mapper %qE not found for type %qT", mapper_name,
+ elem_type);
+ continue;
+ }
+ }
+ }
+}
+
+struct remap_mapper_decl_info
+{
+ tree dummy_var;
+ tree expr;
+};
+
+/* Helper for rewriting DUMMY_VAR into EXPR in a map clause decl. */
+
+static tree
+remap_mapper_decl_1 (tree *tp, int *walk_subtrees, void *data)
+{
+ remap_mapper_decl_info *map_info = (remap_mapper_decl_info *) data;
+
+ if (operand_equal_p (*tp, map_info->dummy_var))
+ {
+ *tp = map_info->expr;
+ *walk_subtrees = 0;
+ }
+
+ return NULL_TREE;
+}
+
+static enum gomp_map_kind
+omp_split_map_kind (enum gomp_map_kind op, bool *force_p, bool *always_p,
+ bool *present_p)
+{
+ *force_p = *always_p = *present_p = false;
+
+ switch (op)
+ {
+ case GOMP_MAP_FORCE_ALLOC:
+ case GOMP_MAP_FORCE_TO:
+ case GOMP_MAP_FORCE_FROM:
+ case GOMP_MAP_FORCE_TOFROM:
+ case GOMP_MAP_FORCE_PRESENT:
+ *force_p = true;
+ break;
+ case GOMP_MAP_ALWAYS_TO:
+ case GOMP_MAP_ALWAYS_FROM:
+ case GOMP_MAP_ALWAYS_TOFROM:
+ *always_p = true;
+ break;
+ case GOMP_MAP_ALWAYS_PRESENT_TO:
+ case GOMP_MAP_ALWAYS_PRESENT_FROM:
+ case GOMP_MAP_ALWAYS_PRESENT_TOFROM:
+ *always_p = true;
+ /* Fallthrough. */
+ case GOMP_MAP_PRESENT_ALLOC:
+ case GOMP_MAP_PRESENT_TO:
+ case GOMP_MAP_PRESENT_FROM:
+ case GOMP_MAP_PRESENT_TOFROM:
+ *present_p = true;
+ break;
+ default:
+ ;
+ }
+
+ switch (op)
+ {
+ case GOMP_MAP_ALLOC:
+ case GOMP_MAP_FORCE_ALLOC:
+ case GOMP_MAP_PRESENT_ALLOC:
+ return GOMP_MAP_ALLOC;
+ case GOMP_MAP_TO:
+ case GOMP_MAP_FORCE_TO:
+ case GOMP_MAP_ALWAYS_TO:
+ case GOMP_MAP_PRESENT_TO:
+ case GOMP_MAP_ALWAYS_PRESENT_TO:
+ return GOMP_MAP_TO;
+ case GOMP_MAP_FROM:
+ case GOMP_MAP_FORCE_FROM:
+ case GOMP_MAP_ALWAYS_FROM:
+ case GOMP_MAP_PRESENT_FROM:
+ case GOMP_MAP_ALWAYS_PRESENT_FROM:
+ return GOMP_MAP_FROM;
+ case GOMP_MAP_TOFROM:
+ case GOMP_MAP_FORCE_TOFROM:
+ case GOMP_MAP_ALWAYS_TOFROM:
+ case GOMP_MAP_PRESENT_TOFROM:
+ case GOMP_MAP_ALWAYS_PRESENT_TOFROM:
+ return GOMP_MAP_TOFROM;
+ default:
+ ;
+ }
+
+ return op;
+}
+
+static enum gomp_map_kind
+omp_join_map_kind (enum gomp_map_kind op, bool force_p, bool always_p,
+ bool present_p)
+{
+ gcc_assert (!force_p || !(always_p || present_p));
+
+ switch (op)
+ {
+ case GOMP_MAP_ALLOC:
+ if (force_p)
+ return GOMP_MAP_FORCE_ALLOC;
+ else if (present_p)
+ return GOMP_MAP_PRESENT_ALLOC;
+ break;
+
+ case GOMP_MAP_TO:
+ if (force_p)
+ return GOMP_MAP_FORCE_TO;
+ else if (always_p && present_p)
+ return GOMP_MAP_ALWAYS_PRESENT_TO;
+ else if (always_p)
+ return GOMP_MAP_ALWAYS_TO;
+ else if (present_p)
+ return GOMP_MAP_PRESENT_TO;
+ break;
+
+ case GOMP_MAP_FROM:
+ if (force_p)
+ return GOMP_MAP_FORCE_FROM;
+ else if (always_p && present_p)
+ return GOMP_MAP_ALWAYS_PRESENT_FROM;
+ else if (always_p)
+ return GOMP_MAP_ALWAYS_FROM;
+ else if (present_p)
+ return GOMP_MAP_PRESENT_FROM;
+ break;
+
+ case GOMP_MAP_TOFROM:
+ if (force_p)
+ return GOMP_MAP_FORCE_TOFROM;
+ else if (always_p && present_p)
+ return GOMP_MAP_ALWAYS_PRESENT_TOFROM;
+ else if (always_p)
+ return GOMP_MAP_ALWAYS_TOFROM;
+ else if (present_p)
+ return GOMP_MAP_PRESENT_TOFROM;
+ break;
+
+ default:
+ ;
+ }
+
+ return op;
+}
+
+/* Map kind decay (OpenMP 5.2, 5.8.8 "declare mapper Directive"). Return the
+ map kind to use given MAPPER_KIND specified in the mapper and INVOKED_AS
+ specified on the clause that invokes the mapper. See also
+ fortran/trans-openmp.cc:omp_map_decayed_kind. */
+
+static enum gomp_map_kind
+omp_map_decayed_kind (enum gomp_map_kind mapper_kind,
+ enum gomp_map_kind invoked_as, bool exit_p)
+{
+ if (invoked_as == GOMP_MAP_RELEASE || invoked_as == GOMP_MAP_DELETE)
+ return invoked_as;
+
+ bool force_p, always_p, present_p;
+
+ invoked_as = omp_split_map_kind (invoked_as, &force_p, &always_p, &present_p);
+ gomp_map_kind decay_to;
+
+ switch (mapper_kind)
+ {
+ case GOMP_MAP_ALLOC:
+ if (exit_p && invoked_as == GOMP_MAP_FROM)
+ decay_to = GOMP_MAP_RELEASE;
+ else
+ decay_to = GOMP_MAP_ALLOC;
+ break;
+
+ case GOMP_MAP_TO:
+ if (invoked_as == GOMP_MAP_FROM)
+ decay_to = exit_p ? GOMP_MAP_RELEASE : GOMP_MAP_ALLOC;
+ else if (invoked_as == GOMP_MAP_ALLOC)
+ decay_to = GOMP_MAP_ALLOC;
+ else
+ decay_to = GOMP_MAP_TO;
+ break;
+
+ case GOMP_MAP_FROM:
+ if (invoked_as == GOMP_MAP_ALLOC || invoked_as == GOMP_MAP_TO)
+ decay_to = GOMP_MAP_ALLOC;
+ else
+ decay_to = GOMP_MAP_FROM;
+ break;
+
+ case GOMP_MAP_TOFROM:
+ case GOMP_MAP_UNSET:
+ decay_to = invoked_as;
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ return omp_join_map_kind (decay_to, force_p, always_p, present_p);
+}
+
+/* Return a name to use for a "basic" map kind, e.g. as output from
+ omp_split_map_kind above. */
+
+static const char *
+omp_basic_map_kind_name (enum gomp_map_kind kind)
+{
+ switch (kind)
+ {
+ case GOMP_MAP_ALLOC:
+ return "alloc";
+ case GOMP_MAP_TO:
+ return "to";
+ case GOMP_MAP_FROM:
+ return "from";
+ case GOMP_MAP_TOFROM:
+ return "tofrom";
+ case GOMP_MAP_RELEASE:
+ return "release";
+ case GOMP_MAP_DELETE:
+ return "delete";
+ default:
+ gcc_unreachable ();
+ }
+}
+
+/* Instantiate a mapper MAPPER for expression EXPR, adding new clauses to
+ OUTLIST. OUTER_KIND is the mapping kind to use if not already specified in
+ the mapper declaration. */
+
+static tree *
+omp_instantiate_mapper (location_t loc, tree *outlist, tree mapper, tree expr,
+ enum gomp_map_kind outer_kind,
+ enum c_omp_region_type ort)
+{
+ tree clauses = OMP_DECLARE_MAPPER_CLAUSES (mapper);
+ tree dummy_var = OMP_DECLARE_MAPPER_DECL (mapper);
+ tree mapper_name = NULL_TREE;
+ tree iterator = *outlist ? OMP_CLAUSE_ITERATORS (*outlist) : NULL_TREE;
+
+ remap_mapper_decl_info map_info;
+ map_info.dummy_var = dummy_var;
+ map_info.expr = expr;
+
+ for (tree c = clauses; c; c = OMP_CLAUSE_CHAIN (c))
+ {
+ tree unshared = unshare_expr (c);
+ enum gomp_map_kind clause_kind = OMP_CLAUSE_MAP_KIND (c);
+ tree t = OMP_CLAUSE_DECL (unshared);
+ tree type = NULL_TREE;
+ bool nonunit_array_with_mapper = false;
+
+ if (clause_kind == GOMP_MAP_PUSH_MAPPER_NAME)
+ {
+ mapper_name = t;
+ continue;
+ }
+ else if (clause_kind == GOMP_MAP_POP_MAPPER_NAME)
+ {
+ mapper_name = NULL_TREE;
+ continue;
+ }
+
+ if (TREE_CODE (t) == OMP_ARRAY_SECTION)
+ {
+ tree t2 = lang_hooks.decls.omp_map_array_section (loc, t);
+
+ if (t2 == t)
+ {
+ nonunit_array_with_mapper = true;
+ /* We'd want use the mapper for the element type if this worked:
+ look that one up. */
+ type = TREE_TYPE (TREE_TYPE (t));
+ }
+ else
+ {
+ t = t2;
+ type = TREE_TYPE (t);
+ }
+ }
+ else
+ type = TREE_TYPE (t);
+
+ gcc_assert (type);
+
+ if (type == error_mark_node)
+ continue;
+
+ walk_tree (&unshared, remap_mapper_decl_1, &map_info, NULL);
+
+ OMP_CLAUSE_LOCATION (unshared) = loc;
+
+ enum gomp_map_kind decayed_kind
+ = omp_map_decayed_kind (clause_kind, outer_kind,
+ (ort & C_ORT_EXIT_DATA) != 0
+ || (outer_kind == GOMP_MAP_FROM
+ && (ort & C_ORT_UPDATE) != 0));
+ OMP_CLAUSE_SET_MAP_KIND (unshared, decayed_kind);
+
+ type = TYPE_MAIN_VARIANT (type);
+
+ tree mapper_fn = lang_hooks.decls.omp_mapper_lookup (mapper_name, type);
+
+ if (mapper_fn && nonunit_array_with_mapper)
+ {
+ sorry ("user-defined mapper with non-unit length array section");
+ continue;
+ }
+ else if (mapper_fn)
+ {
+ tree nested_mapper
+ = lang_hooks.decls.omp_extract_mapper_directive (mapper_fn);
+ if (nested_mapper != mapper)
+ {
+ outlist = omp_instantiate_mapper (loc, outlist, nested_mapper,
+ t, outer_kind, ort);
+ continue;
+ }
+ }
+ else if (mapper_name)
+ {
+ error ("mapper %qE not found for type %qT", mapper_name, type);
+ continue;
+ }
+
+ if (ort & C_ORT_UPDATE)
+ {
+ bool force_p, always_p, present_p;
+ decayed_kind
+ = omp_split_map_kind (decayed_kind, &force_p, &always_p,
+ &present_p);
+ /* We don't expect to see these flags here. */
+ gcc_assert (!force_p && !always_p);
+ /* For a "target update" operation, we want to turn the map node
+ expanded from the mapper back into a OMP_CLAUSE_TO or
+ OMP_CLAUSE_FROM node. If we can do neither, emit a warning and
+ drop the clause. */
+ switch (decayed_kind)
+ {
+ case GOMP_MAP_TO:
+ case GOMP_MAP_FROM:
+ {
+ tree xfer
+ = build_omp_clause (loc, (decayed_kind == GOMP_MAP_TO
+ ? OMP_CLAUSE_TO : OMP_CLAUSE_FROM));
+ OMP_CLAUSE_DECL (xfer) = OMP_CLAUSE_DECL (unshared);
+ OMP_CLAUSE_SIZE (xfer) = OMP_CLAUSE_SIZE (unshared);
+ /* For FROM/TO clauses, "present" is represented by a flag.
+ Set it for the expanded clause here. */
+ if (present_p)
+ OMP_CLAUSE_MOTION_PRESENT (xfer) = 1;
+ *outlist = xfer;
+ outlist = &OMP_CLAUSE_CHAIN (xfer);
+ }
+ break;
+ default:
+ clause_kind
+ = omp_split_map_kind (clause_kind, &force_p, &always_p,
+ &present_p);
+ warning_at (loc, 0, "dropping %qs clause during mapper expansion "
+ "in %<#pragma omp target update%>",
+ omp_basic_map_kind_name (clause_kind));
+ inform (OMP_CLAUSE_LOCATION (c), "for map clause here");
+ }
+ }
+ else
+ {
+ OMP_CLAUSE_ITERATORS (unshared) = iterator;
+ *outlist = unshared;
+ outlist = &OMP_CLAUSE_CHAIN (unshared);
+ }
+ }
+
+ return outlist;
+}
+
+/* Given a list of CLAUSES, scan each clause and invoke a user-defined mapper
+ appropriate to the type of the data in that clause, if such a mapper is
+ visible in the current parsing context. */
+
+tree
+c_omp_instantiate_mappers (tree clauses, enum c_omp_region_type ort)
+{
+ tree c, *pc, mapper_name = NULL_TREE;
+
+ for (pc = &clauses, c = clauses; c; c = *pc)
+ {
+ bool using_mapper = false;
+ bool update_p = false, update_present_p = false;
+
+ switch (OMP_CLAUSE_CODE (c))
+ {
+ case OMP_CLAUSE_TO:
+ case OMP_CLAUSE_FROM:
+ update_p = true;
+ if (OMP_CLAUSE_MOTION_PRESENT (c))
+ update_present_p = true;
+ /* Fallthrough. */
+ case OMP_CLAUSE_MAP:
+ {
+ tree t = OMP_CLAUSE_DECL (c);
+ tree type = NULL_TREE;
+ bool nonunit_array_with_mapper = false;
+
+ if (!update_p
+ && (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_PUSH_MAPPER_NAME
+ || OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_POP_MAPPER_NAME))
+ {
+ if (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_PUSH_MAPPER_NAME)
+ mapper_name = OMP_CLAUSE_DECL (c);
+ else
+ mapper_name = NULL_TREE;
+ pc = &OMP_CLAUSE_CHAIN (c);
+ continue;
+ }
+
+ if (TREE_CODE (t) == OMP_ARRAY_SECTION)
+ {
+ location_t loc = OMP_CLAUSE_LOCATION (c);
+ tree t2 = lang_hooks.decls.omp_map_array_section (loc, t);
+
+ if (t2 == t)
+ {
+ /* !!! Array sections of size >1 with mappers for elements
+ are hard to support. Do something here. */
+ nonunit_array_with_mapper = true;
+ type = TREE_TYPE (TREE_TYPE (t));
+ }
+ else
+ {
+ t = t2;
+ type = TREE_TYPE (t);
+ }
+ }
+ else
+ type = TREE_TYPE (t);
+
+ if (type == NULL_TREE || type == error_mark_node)
+ {
+ pc = &OMP_CLAUSE_CHAIN (c);
+ continue;
+ }
+
+ enum gomp_map_kind kind;
+ if (update_p)
+ {
+ if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_TO)
+ kind = update_present_p ? GOMP_MAP_PRESENT_TO
+ : GOMP_MAP_TO;
+ else
+ kind = update_present_p ? GOMP_MAP_PRESENT_FROM
+ : GOMP_MAP_FROM;
+ }
+ else
+ {
+ kind = OMP_CLAUSE_MAP_KIND (c);
+ if (kind == GOMP_MAP_UNSET)
+ kind = GOMP_MAP_TOFROM;
+ }
+
+ type = TYPE_MAIN_VARIANT (type);
+
+ tree mapper_fn
+ = lang_hooks.decls.omp_mapper_lookup (mapper_name, type);
+
+ if (mapper_fn && nonunit_array_with_mapper)
+ {
+ sorry ("user-defined mapper with non-unit length "
+ "array section");
+ using_mapper = true;
+ }
+ else if (mapper_fn)
+ {
+ tree mapper
+ = lang_hooks.decls.omp_extract_mapper_directive (mapper_fn);
+ pc = omp_instantiate_mapper (OMP_CLAUSE_LOCATION (c),
+ pc, mapper, t, kind, ort);
+ using_mapper = true;
+ }
+ else if (mapper_name)
+ {
+ error ("mapper %qE not found for type %qT", mapper_name, type);
+ using_mapper = true;
+ }
+ }
+ break;
+
+ default:
+ ;
+ }
+
+ if (using_mapper)
+ *pc = OMP_CLAUSE_CHAIN (c);
+ else
+ pc = &OMP_CLAUSE_CHAIN (c);
+ }
+
+ return clauses;
}
const struct c_omp_directive c_omp_directives[] = {