[PATCH v3 09/11] FYI/unfinished: OpenMP: lvalue parsing for map clauses (C++)
Julian Brown
julian@codesourcery.com
Tue Sep 13 21:03:19 GMT 2022
This patch changes parsing for OpenMP map clauses in C++ to use the
generic expression parser, hence adds support for parsing general
lvalues (as required by OpenMP 5.0+).
This patch hasn't been fully revised following previous review comments
yet, but I'm including it in support of the following (declare mapper)
patch, and to demonstrate the cases in baseptrs-4.C that work with the
lvalue-parsing support enabled.
---
gcc/c-family/c-omp.cc | 1 +
gcc/cp/error.cc | 9 +
gcc/cp/parser.cc | 141 +++++++++++++--
gcc/cp/parser.h | 3 +
gcc/cp/semantics.cc | 7 +-
gcc/gimplify.cc | 39 ++++-
gcc/testsuite/c-c++-common/gomp/map-6.c | 4 +-
gcc/testsuite/g++.dg/gomp/ind-base-3.C | 38 ++++
gcc/testsuite/g++.dg/gomp/map-assignment-1.C | 12 ++
gcc/testsuite/g++.dg/gomp/map-inc-1.C | 10 ++
gcc/testsuite/g++.dg/gomp/map-lvalue-ref-1.C | 19 ++
gcc/testsuite/g++.dg/gomp/map-ptrmem-1.C | 37 ++++
gcc/testsuite/g++.dg/gomp/map-ptrmem-2.C | 40 +++++
.../g++.dg/gomp/map-static-cast-lvalue-1.C | 17 ++
gcc/testsuite/g++.dg/gomp/map-ternary-1.C | 20 +++
gcc/testsuite/g++.dg/gomp/member-array-2.C | 92 ++++++++++
gcc/testsuite/g++.dg/gomp/pr67522.C | 2 +-
gcc/tree-pretty-print.cc | 14 ++
gcc/tree.def | 3 +
libgomp/testsuite/libgomp.c++/baseptrs-4.C | 26 ++-
libgomp/testsuite/libgomp.c++/ind-base-1.C | 162 ++++++++++++++++++
libgomp/testsuite/libgomp.c++/ind-base-2.C | 49 ++++++
libgomp/testsuite/libgomp.c++/map-comma-1.C | 15 ++
.../testsuite/libgomp.c++/map-rvalue-ref-1.C | 22 +++
libgomp/testsuite/libgomp.c++/struct-ref-1.C | 97 +++++++++++
.../libgomp.c-c++-common/array-field-1.c | 35 ++++
.../libgomp.c-c++-common/array-of-struct-1.c | 65 +++++++
.../libgomp.c-c++-common/array-of-struct-2.c | 65 +++++++
28 files changed, 1009 insertions(+), 35 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/gomp/ind-base-3.C
create mode 100644 gcc/testsuite/g++.dg/gomp/map-assignment-1.C
create mode 100644 gcc/testsuite/g++.dg/gomp/map-inc-1.C
create mode 100644 gcc/testsuite/g++.dg/gomp/map-lvalue-ref-1.C
create mode 100644 gcc/testsuite/g++.dg/gomp/map-ptrmem-1.C
create mode 100644 gcc/testsuite/g++.dg/gomp/map-ptrmem-2.C
create mode 100644 gcc/testsuite/g++.dg/gomp/map-static-cast-lvalue-1.C
create mode 100644 gcc/testsuite/g++.dg/gomp/map-ternary-1.C
create mode 100644 gcc/testsuite/g++.dg/gomp/member-array-2.C
create mode 100644 libgomp/testsuite/libgomp.c++/ind-base-1.C
create mode 100644 libgomp/testsuite/libgomp.c++/ind-base-2.C
create mode 100644 libgomp/testsuite/libgomp.c++/map-comma-1.C
create mode 100644 libgomp/testsuite/libgomp.c++/map-rvalue-ref-1.C
create mode 100644 libgomp/testsuite/libgomp.c++/struct-ref-1.C
create mode 100644 libgomp/testsuite/libgomp.c-c++-common/array-field-1.c
create mode 100644 libgomp/testsuite/libgomp.c-c++-common/array-of-struct-1.c
create mode 100644 libgomp/testsuite/libgomp.c-c++-common/array-of-struct-2.c
diff --git a/gcc/c-family/c-omp.cc b/gcc/c-family/c-omp.cc
index a2373fda537..e3cda716532 100644
--- a/gcc/c-family/c-omp.cc
+++ b/gcc/c-family/c-omp.cc
@@ -3220,6 +3220,7 @@ c_omp_address_inspector::map_supported_p ()
|| TREE_CODE (t) == SAVE_EXPR
|| TREE_CODE (t) == POINTER_PLUS_EXPR
|| TREE_CODE (t) == NON_LVALUE_EXPR
+ || TREE_CODE (t) == OMP_ARRAY_SECTION
|| TREE_CODE (t) == NOP_EXPR)
if (TREE_CODE (t) == COMPOUND_EXPR)
t = TREE_OPERAND (t, 1);
diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc
index 94181e76d0e..5a7f41c1ca0 100644
--- a/gcc/cp/error.cc
+++ b/gcc/cp/error.cc
@@ -2471,6 +2471,15 @@ dump_expr (cxx_pretty_printer *pp, tree t, int flags)
pp_cxx_right_bracket (pp);
break;
+ case OMP_ARRAY_SECTION:
+ dump_expr (pp, TREE_OPERAND (t, 0), flags);
+ pp_cxx_left_bracket (pp);
+ dump_expr (pp, TREE_OPERAND (t, 1), flags);
+ pp_colon (pp);
+ dump_expr (pp, TREE_OPERAND (t, 2), flags);
+ pp_cxx_right_bracket (pp);
+ break;
+
case UNARY_PLUS_EXPR:
dump_unary_op (pp, "+", t, flags);
break;
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 68fc78e7c5c..5468502cd26 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -4320,6 +4320,9 @@ cp_parser_new (cp_lexer *lexer)
parser->omp_declare_simd = NULL;
parser->oacc_routine = NULL;
+ /* Allow array slice in expression. */
+ parser->omp_array_section_p = false;
+
/* Not declaring an implicit function template. */
parser->auto_is_implicit_function_template_parm_p = false;
parser->fully_implicit_function_template_p = false;
@@ -8100,6 +8103,7 @@ cp_parser_postfix_open_square_expression (cp_parser *parser,
releasing_vec expression_list = NULL;
location_t loc = cp_lexer_peek_token (parser->lexer)->location;
bool saved_greater_than_is_operator_p;
+ bool saved_colon_corrects_to_scope_p;
/* Consume the `[' token. */
cp_lexer_consume_token (parser->lexer);
@@ -8107,6 +8111,9 @@ cp_parser_postfix_open_square_expression (cp_parser *parser,
saved_greater_than_is_operator_p = parser->greater_than_is_operator_p;
parser->greater_than_is_operator_p = true;
+ saved_colon_corrects_to_scope_p = parser->colon_corrects_to_scope_p;
+ parser->colon_corrects_to_scope_p = false;
+
/* Parse the index expression. */
/* ??? For offsetof, there is a question of what to allow here. If
offsetof is not being used in an integral constant expression context,
@@ -8117,7 +8124,8 @@ cp_parser_postfix_open_square_expression (cp_parser *parser,
constant expressions here. */
if (for_offsetof)
index = cp_parser_constant_expression (parser);
- else
+ else if (!parser->omp_array_section_p
+ || cp_lexer_next_token_is_not (parser->lexer, CPP_COLON))
{
if (cxx_dialect >= cxx23
&& cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_SQUARE))
@@ -8174,6 +8182,32 @@ cp_parser_postfix_open_square_expression (cp_parser *parser,
parser->greater_than_is_operator_p = saved_greater_than_is_operator_p;
+ if (parser->omp_array_section_p
+ && cp_lexer_next_token_is (parser->lexer, CPP_COLON))
+ {
+ cp_lexer_consume_token (parser->lexer);
+ tree length = NULL_TREE;
+ if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_SQUARE))
+ length = cp_parser_expression (parser);
+
+ parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p;
+
+ if ((index && error_operand_p (index))
+ || (length && error_operand_p (length)))
+ return error_mark_node;
+
+ cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE);
+
+ /* NOTE: We are reusing using the type of the whole array as the type of
+ the array section here, which isn't necessarily entirely correct.
+ Might need revisiting. */
+ return build3_loc (input_location, OMP_ARRAY_SECTION,
+ TREE_TYPE (postfix_expression),
+ postfix_expression, index, length);
+ }
+
+ parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p;
+
/* Look for the closing `]'. */
cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE);
@@ -36808,7 +36842,7 @@ struct omp_dim
static tree
cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind,
tree list, bool *colon,
- bool allow_deref = false)
+ bool map_lvalue = false)
{
auto_vec<omp_dim> dims;
bool array_section_p;
@@ -36819,12 +36853,95 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind,
parser->colon_corrects_to_scope_p = false;
*colon = false;
}
+ begin_scope (sk_omp, NULL);
while (1)
{
tree name, decl;
if (kind == OMP_CLAUSE_DEPEND || kind == OMP_CLAUSE_AFFINITY)
cp_parser_parse_tentatively (parser);
+ else if (map_lvalue && kind == OMP_CLAUSE_MAP)
+ {
+ auto s = make_temp_override (parser->omp_array_section_p, true);
+ token = cp_lexer_peek_token (parser->lexer);
+ location_t loc = token->location;
+ decl = cp_parser_assignment_expression (parser);
+
+ dims.truncate (0);
+ if (TREE_CODE (decl) == OMP_ARRAY_SECTION)
+ {
+ while (TREE_CODE (decl) == OMP_ARRAY_SECTION)
+ {
+ tree low_bound = TREE_OPERAND (decl, 1);
+ tree length = TREE_OPERAND (decl, 2);
+ dims.safe_push (omp_dim (low_bound, length, loc, false));
+ decl = TREE_OPERAND (decl, 0);
+ }
+
+ while (TREE_CODE (decl) == ARRAY_REF
+ || TREE_CODE (decl) == INDIRECT_REF
+ || TREE_CODE (decl) == COMPOUND_EXPR)
+ {
+ if (REFERENCE_REF_P (decl))
+ break;
+
+ if (TREE_CODE (decl) == COMPOUND_EXPR)
+ {
+ decl = TREE_OPERAND (decl, 1);
+ STRIP_NOPS (decl);
+ }
+ else if (TREE_CODE (decl) == INDIRECT_REF)
+ {
+ dims.safe_push (omp_dim (integer_zero_node,
+ integer_one_node, loc, true));
+ decl = TREE_OPERAND (decl, 0);
+ }
+ else /* ARRAY_REF. */
+ {
+ tree index = TREE_OPERAND (decl, 1);
+ dims.safe_push (omp_dim (index, integer_one_node, loc,
+ true));
+ decl = TREE_OPERAND (decl, 0);
+ }
+ }
+
+ /* Bare references have their own special handling, so remove
+ the explicit dereference added by convert_from_reference. */
+ if (REFERENCE_REF_P (decl))
+ decl = TREE_OPERAND (decl, 0);
+
+ for (int i = dims.length () - 1; i >= 0; i--)
+ decl = tree_cons (dims[i].low_bound, dims[i].length, decl);
+ }
+ else if (TREE_CODE (decl) == INDIRECT_REF)
+ {
+ bool ref_p = REFERENCE_REF_P (decl);
+
+ /* Turn *foo into the representation previously used for
+ foo[0]. */
+ decl = TREE_OPERAND (decl, 0);
+ STRIP_NOPS (decl);
+
+ /* ...but don't add the [0:1] representation for references
+ (because they have special handling elsewhere). */
+ if (!ref_p)
+ decl = tree_cons (integer_zero_node, integer_one_node, decl);
+ }
+ else if (TREE_CODE (decl) == ARRAY_REF)
+ {
+ tree idx = TREE_OPERAND (decl, 1);
+
+ decl = TREE_OPERAND (decl, 0);
+ STRIP_NOPS (decl);
+
+ decl = tree_cons (idx, integer_one_node, decl);
+ }
+ else if (TREE_CODE (decl) == NON_LVALUE_EXPR
+ || CONVERT_EXPR_P (decl))
+ decl = TREE_OPERAND (decl, 0);
+
+ goto build_clause;
+ }
token = cp_lexer_peek_token (parser->lexer);
if (kind != 0
&& cp_parser_is_keyword (token, RID_THIS))
@@ -36903,8 +37020,7 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind,
case OMP_CLAUSE_TO:
start_component_ref:
while (cp_lexer_next_token_is (parser->lexer, CPP_DOT)
- || (allow_deref
- && cp_lexer_next_token_is (parser->lexer, CPP_DEREF)))
+ || cp_lexer_next_token_is (parser->lexer, CPP_DEREF))
{
cpp_ttype ttype
= cp_lexer_next_token_is (parser->lexer, CPP_DOT)
@@ -36991,9 +37107,7 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind,
|| kind == OMP_CLAUSE_TO)
&& !array_section_p
&& (cp_lexer_next_token_is (parser->lexer, CPP_DOT)
- || (allow_deref
- && cp_lexer_next_token_is (parser->lexer,
- CPP_DEREF))))
+ || cp_lexer_next_token_is (parser->lexer, CPP_DEREF)))
{
for (unsigned i = 0; i < dims.length (); i++)
{
@@ -37027,6 +37141,7 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind,
cp_parser_parse_definitely (parser);
}
+ build_clause:
tree u = build_omp_clause (token->location, kind);
OMP_CLAUSE_DECL (u) = decl;
OMP_CLAUSE_CHAIN (u) = list;
@@ -37048,6 +37163,7 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind,
{
*colon = true;
cp_parser_require (parser, CPP_COLON, RT_COLON);
+ finish_scope ();
return list;
}
@@ -37068,6 +37184,7 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind,
goto get_comma;
}
+ finish_scope ();
return list;
}
@@ -37076,11 +37193,11 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind,
static tree
cp_parser_omp_var_list (cp_parser *parser, enum omp_clause_code kind, tree list,
- bool allow_deref = false)
+ bool map_lvalue = false)
{
if (cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN))
return cp_parser_omp_var_list_no_open (parser, kind, list, NULL,
- allow_deref);
+ map_lvalue);
return list;
}
@@ -37147,7 +37264,7 @@ cp_parser_oacc_data_clause (cp_parser *parser, pragma_omp_clause c_kind,
gcc_unreachable ();
}
tree nl, c;
- nl = cp_parser_omp_var_list (parser, OMP_CLAUSE_MAP, list, true);
+ nl = cp_parser_omp_var_list (parser, OMP_CLAUSE_MAP, list, false);
for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c))
OMP_CLAUSE_SET_MAP_KIND (c, kind);
@@ -40639,12 +40756,12 @@ cp_parser_omp_all_clauses (cp_parser *parser, omp_clause_mask mask,
}
else
clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_TO, clauses,
- true);
+ false);
c_name = "to";
break;
case PRAGMA_OMP_CLAUSE_FROM:
clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_FROM, clauses,
- true);
+ false);
c_name = "from";
break;
case PRAGMA_OMP_CLAUSE_UNIFORM:
diff --git a/gcc/cp/parser.h b/gcc/cp/parser.h
index d688fd18fd5..7ae507bb135 100644
--- a/gcc/cp/parser.h
+++ b/gcc/cp/parser.h
@@ -404,6 +404,9 @@ struct GTY(()) cp_parser {
/* TRUE if omp::directive or omp::sequence attributes may not appear. */
bool omp_attrs_forbidden_p;
+ /* TRUE if an OpenMP array section is allowed. */
+ bool omp_array_section_p;
+
/* Tracks the function's template parameter list when declaring a function
using generic type parameters. This is either a new chain in the case of a
fully implicit function template or an extension of the function's existing
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 9e245fd725f..8ed93ce8383 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -5142,7 +5142,9 @@ handle_omp_array_sections_1 (tree c, tree t, vec<tree> &types,
ret = t_refto;
if (TREE_CODE (t) == FIELD_DECL)
ret = finish_non_static_data_member (t, NULL_TREE, NULL_TREE);
- else if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL)
+ else if (!VAR_P (t)
+ && (ort == C_ORT_ACC || !EXPR_P (t))
+ && TREE_CODE (t) != PARM_DECL)
{
if (processing_template_decl && TREE_CODE (t) != OVERLOAD)
return NULL_TREE;
@@ -8146,7 +8148,8 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
&& (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_POINTER
|| OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ALWAYS_POINTER
- || OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ATTACH_DETACH))
+ || OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ATTACH_DETACH
+ || (ort != C_ORT_ACC && EXPR_P (t))))
break;
if (DECL_P (t))
error_at (OMP_CLAUSE_LOCATION (c),
diff --git a/gcc/gimplify.cc b/gcc/gimplify.cc
index e341269d0f6..46c4d31684f 100644
--- a/gcc/gimplify.cc
+++ b/gcc/gimplify.cc
@@ -10753,7 +10753,10 @@ omp_accumulate_sibling_list (enum omp_region_type region_type,
OMP_CLAUSE_SIZE (c2)
= fold_build2_loc (OMP_CLAUSE_LOCATION (grp_end), MINUS_EXPR,
ptrdiff_type_node, baddr, decladdr);
- /* Insert after struct node. */
+ /* Insert after struct node. If the mapping kind is GOMP_MAP_ATTACH,
+ we are only putting this here until the end of
+ omp_build_struct_sibling_lists, at which point we maybe adjust
+ the bias and move the node to the end of the clause list. */
OMP_CLAUSE_CHAIN (c2) = OMP_CLAUSE_CHAIN (l);
OMP_CLAUSE_CHAIN (l) = c2;
@@ -11022,6 +11025,31 @@ omp_accumulate_sibling_list (enum omp_region_type region_type,
return continue_at;
}
+/* Return the base (pointer to struct or class) of a pointer-to-member access
+ expression, or NULL_TREE if EXPR is something else. */
+
+static bool
+omp_ptrmem_p (tree expr)
+{
+ if (TREE_CODE (expr) != INDIRECT_REF)
+ return false;
+
+ expr = TREE_OPERAND (expr, 0);
+
+ if (TREE_CODE (expr) == NON_LVALUE_EXPR)
+ expr = TREE_OPERAND (expr, 0);
+
+ if (TREE_CODE (expr) == POINTER_PLUS_EXPR)
+ {
+ tree base = TREE_OPERAND (expr, 0);
+ STRIP_NOPS (base);
+ if (AGGREGATE_TYPE_P (TREE_TYPE (TREE_TYPE (base))))
+ return true;
+ }
+
+ return false;
+}
+
/* Scan through GROUPS, and create sorted structure sibling lists without
gimplifying. */
@@ -11132,7 +11160,14 @@ omp_build_struct_sibling_lists (enum tree_code code,
STRIP_NOPS (decl);
- if (TREE_CODE (decl) != COMPONENT_REF)
+ if (omp_ptrmem_p (decl))
+ {
+ /* Pointer-to-member mapping types are not yet supported. */
+ sorry_at (OMP_CLAUSE_LOCATION (c), "unsupported map expression %qE",
+ decl);
+ continue;
+ }
+ else if (TREE_CODE (decl) != COMPONENT_REF)
continue;
/* If we're mapping the whole struct in another node, skip creation of
diff --git a/gcc/testsuite/c-c++-common/gomp/map-6.c b/gcc/testsuite/c-c++-common/gomp/map-6.c
index 6ee59714847..c749db845b0 100644
--- a/gcc/testsuite/c-c++-common/gomp/map-6.c
+++ b/gcc/testsuite/c-c++-common/gomp/map-6.c
@@ -20,12 +20,12 @@ foo (void)
;
#pragma omp target map (close a) /* { dg-error "'close' undeclared" "" { target c } } */
- /* { dg-error "'close' has not been declared" "" { target c++ } .-1 } */
+ /* { dg-error "'close' was not declared in this scope" "" { target c++ } .-1 } */
/* { dg-error "expected '\\)' before 'a'" "" { target *-*-* } .-2 } */
;
#pragma omp target map (always a) /* { dg-error "'always' undeclared" "" { target c } } */
- /* { dg-error "'always' has not been declared" "" { target c++ } .-1 } */
+ /* { dg-error "'always' was not declared in this scope" "" { target c++ } .-1 } */
/* { dg-error "expected '\\)' before 'a'" "" { target *-*-* } .-2 } */
;
diff --git a/gcc/testsuite/g++.dg/gomp/ind-base-3.C b/gcc/testsuite/g++.dg/gomp/ind-base-3.C
new file mode 100644
index 00000000000..dbabaf7680c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/ind-base-3.C
@@ -0,0 +1,38 @@
+#include <cassert>
+
+struct S {
+ int x[10];
+};
+
+S *
+choose (S *a, S *b, int c)
+{
+ if (c < 5)
+ return a;
+ else
+ return b;
+}
+
+int main (int argc, char *argv[])
+{
+ S a, b;
+
+ for (int i = 0; i < 10; i++)
+ a.x[i] = b.x[i] = 0;
+
+ for (int i = 0; i < 10; i++)
+ {
+#pragma omp target map(choose(&a, &b, i)->x[:10])
+/* { dg-message {sorry, unimplemented: unsupported map expression 'choose\(\(& a\), \(& b\), i\)->S::x\[0\]'} "" { target *-*-* } .-1 } */
+/* { dg-message {sorry, unimplemented: unsupported map expression 'choose\(\(& a\), \(& b\), i\)'} "" { target *-*-* } .-2 } */
+ for (int j = 0; j < 10; j++)
+ choose (&a, &b, i)->x[j]++;
+ }
+
+ for (int i = 0; i < 10; i++)
+ assert (a.x[i] == 5 && b.x[i] == 5);
+
+ return 0;
+}
+
+
diff --git a/gcc/testsuite/g++.dg/gomp/map-assignment-1.C b/gcc/testsuite/g++.dg/gomp/map-assignment-1.C
new file mode 100644
index 00000000000..5979ec379f1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/map-assignment-1.C
@@ -0,0 +1,12 @@
+#include <cassert>
+
+int main (int argc, char *argv[])
+{
+ int a = 5, b = 2;
+#pragma omp target map(a += b)
+ /* { dg-message {sorry, unimplemented: unsupported map expression '\(a = \(a \+ b\)\)'} "" { target *-*-* } .-1 } */
+ {
+ a++;
+ }
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/gomp/map-inc-1.C b/gcc/testsuite/g++.dg/gomp/map-inc-1.C
new file mode 100644
index 00000000000..b469a4bd548
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/map-inc-1.C
@@ -0,0 +1,10 @@
+int main (int argc, char *argv[])
+{
+ int a = 5;
+#pragma omp target map(++a)
+ /* { dg-message {sorry, unimplemented: unsupported map expression '\+\+ a'} "" { target *-*-* } .-1 } */
+ {
+ a++;
+ }
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/gomp/map-lvalue-ref-1.C b/gcc/testsuite/g++.dg/gomp/map-lvalue-ref-1.C
new file mode 100644
index 00000000000..d720d4318ae
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/map-lvalue-ref-1.C
@@ -0,0 +1,19 @@
+#include <cassert>
+
+int glob = 10;
+
+int& foo ()
+{
+ return glob;
+}
+
+int main (int argc, char *argv[])
+{
+#pragma omp target map(foo())
+ /* { dg-message {sorry, unimplemented: unsupported map expression 'foo\(\)'} "" { target *-*-* } .-1 } */
+ {
+ foo()++;
+ }
+ assert (glob == 11);
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/gomp/map-ptrmem-1.C b/gcc/testsuite/g++.dg/gomp/map-ptrmem-1.C
new file mode 100644
index 00000000000..c4023f59fc6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/map-ptrmem-1.C
@@ -0,0 +1,37 @@
+#include <cassert>
+
+struct S {
+ int x;
+ int *ptr;
+};
+
+int
+main (int argc, char *argv[])
+{
+ S s;
+ int S::* xp = &S::x;
+ int* S::* ptrp = &S::ptr;
+
+ s.ptr = new int[64];
+
+ s.*xp = 6;
+ for (int i = 0; i < 64; i++)
+ (s.*ptrp)[i] = i;
+
+#pragma omp target map(s.*xp, s.*ptrp, (s.*ptrp)[:64])
+ /* { dg-message {sorry, unimplemented: pointer-to-member mapping '\*\(\*\(\(\(int\*\*\)\(& s\)\) \+ \(\(sizetype\)ptrp\)\)\)' not supported} "" { target *-*-* } .-1 } */
+ /* { dg-message {sorry, unimplemented: pointer-to-member mapping '\*\(\(\(int\*\*\)\(& s\)\) \+ \(\(sizetype\)ptrp\)\)' not supported} "" { target *-*-* } .-2 } */
+ /* { dg-message {sorry, unimplemented: pointer-to-member mapping '\*\(\(\(int\*\)\(& s\)\) \+ \(\(sizetype\)xp\)\)' not supported} "" { target *-*-* } .-3 } */
+#pragma omp teams distribute parallel for
+ for (int i = 0; i < 64; i++)
+ {
+ (s.*xp)++;
+ (s.*ptrp)[i]++;
+ }
+
+ assert (s.*xp == 70);
+ for (int i = 0; i < 64; i++)
+ assert ((s.*ptrp)[i] == i + 1);
+
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/gomp/map-ptrmem-2.C b/gcc/testsuite/g++.dg/gomp/map-ptrmem-2.C
new file mode 100644
index 00000000000..fbf379da0eb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/map-ptrmem-2.C
@@ -0,0 +1,40 @@
+#include <cassert>
+
+struct S {
+ int x;
+ int *ptr;
+};
+
+int
+main (int argc, char *argv[])
+{
+ S *s = new S;
+ int S::* xp = &S::x;
+ int* S::* ptrp = &S::ptr;
+
+ s->ptr = new int[64];
+
+ s->*xp = 4;
+ for (int i = 0; i < 64; i++)
+ (s->*ptrp)[i] = i;
+
+#pragma omp target map(s->*xp, s->*ptrp, (s->*ptrp)[:64])
+ /* { dg-message {sorry, unimplemented: pointer-to-member mapping '\*\(\(\(int\*\*\)s\) \+ \(\(sizetype\)ptrp\)\)' not supported} "" { target *-*-* } .-1 } */
+ /* { dg-message {sorry, unimplemented: pointer-to-member mapping '\*\(\(\(int\*\)s\) \+ \(\(sizetype\)xp\)\)' not supported} "" { target *-*-* } .-2 } */
+ /* { dg-message {sorry, unimplemented: pointer-to-member mapping '\*\(\*\(\(\(int\*\*\)s\) \+ \(\(sizetype\)ptrp\)\)\)' not supported} "" { target *-*-* } .-3 } */
+#pragma omp teams distribute parallel for
+ for (int i = 0; i < 64; i++)
+ {
+ (s->*xp)++;
+ (s->*ptrp)[i]++;
+ }
+
+ assert (s->*xp == 68);
+ for (int i = 0; i < 64; i++)
+ assert ((s->*ptrp)[i] == i + 1);
+
+ delete s->ptr;
+ delete s;
+
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/gomp/map-static-cast-lvalue-1.C b/gcc/testsuite/g++.dg/gomp/map-static-cast-lvalue-1.C
new file mode 100644
index 00000000000..3af9668202c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/map-static-cast-lvalue-1.C
@@ -0,0 +1,17 @@
+#include <cassert>
+
+int foo (int x)
+{
+#pragma omp target map(static_cast<int&>(x))
+ /* { dg-message {sorry, unimplemented: unsupported map expression '& x'} "" { target *-*-* } .-1 } */
+ {
+ x += 3;
+ }
+ return x;
+}
+
+int main (int argc, char *argv[])
+{
+ assert (foo (5) == 8);
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/gomp/map-ternary-1.C b/gcc/testsuite/g++.dg/gomp/map-ternary-1.C
new file mode 100644
index 00000000000..7b365a909bb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/map-ternary-1.C
@@ -0,0 +1,20 @@
+#include <cassert>
+
+int foo (bool yesno)
+{
+ int x = 5, y = 7;
+#pragma omp target map(yesno ? x : y)
+ /* { dg-message {sorry, unimplemented: unsupported map expression '\(yesno \? x : y\)'} "" { target *-*-* } .-1 } */
+ {
+ x += 3;
+ y += 5;
+ }
+ return yesno ? x : y;
+}
+
+int main (int argc, char *argv[])
+{
+ assert (foo (true) == 8);
+ assert (foo (false) == 12);
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/gomp/member-array-2.C b/gcc/testsuite/g++.dg/gomp/member-array-2.C
new file mode 100644
index 00000000000..e60bb5585a1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/member-array-2.C
@@ -0,0 +1,92 @@
+#include <cassert>
+
+typedef int intarr100[100];
+
+class C {
+ int arr[100];
+ int *ptr;
+
+public:
+ C();
+ ~C();
+ void zero ();
+ void do_operation ();
+ void check (int, int);
+ intarr100 &get_arr () { return arr; }
+ int *get_ptr() { return ptr; }
+};
+
+C::C()
+{
+ ptr = new int[100];
+ for (int i = 0; i < 100; i++)
+ arr[i] = 0;
+}
+
+C::~C()
+{
+ delete ptr;
+}
+
+void
+C::zero ()
+{
+ for (int i = 0; i < 100; i++)
+ arr[i] = ptr[i] = 0;
+}
+
+void
+C::do_operation ()
+{
+#pragma omp target map(arr, ptr, ptr[:100])
+#pragma omp teams distribute parallel for
+ for (int i = 0; i < 100; i++)
+ {
+ arr[i] = arr[i] + 3;
+ ptr[i] = ptr[i] + 5;
+ }
+}
+
+void
+C::check (int arrval, int ptrval)
+{
+ for (int i = 0; i < 100; i++)
+ {
+ assert (arr[i] == arrval);
+ assert (ptr[i] == ptrval);
+ }
+}
+
+int
+main (int argc, char *argv[])
+{
+ C c;
+
+ c.zero ();
+ c.do_operation ();
+ c.check (3, 5);
+
+ /* It might sort of make sense to be able to do this, but we don't support
+ it for now. */
+ #pragma omp target map(c.get_arr()[:100])
+ /* { dg-message {sorry, unimplemented: unsupported map expression 'c\.C::get_arr\(\)\[0\]'} "" { target *-*-* } .-1 } */
+ /* { dg-message {sorry, unimplemented: unsupported map expression 'c\.C::get_arr\(\)'} "" { target *-*-* } .-2 } */
+ #pragma omp teams distribute parallel for
+ for (int i = 0; i < 100; i++)
+ c.get_arr()[i] += 2;
+
+ c.check (5, 5);
+
+ /* Same for this. */
+ #pragma omp target map(c.get_ptr(), c.get_ptr()[:100])
+ /* { dg-message {sorry, unimplemented: unsupported map expression 'c\.C::get_ptr\(\)'} "" { target *-*-* } .-1 } */
+ /* { dg-message {sorry, unimplemented: unsupported map expression '\* c\.C::get_ptr\(\)'} "" { target *-*-* } .-2 } */
+ #pragma omp teams distribute parallel for
+ for (int i = 0; i < 100; i++)
+ c.get_ptr()[i] += 3;
+
+ c.check (5, 8);
+
+ return 0;
+}
+
diff --git a/gcc/testsuite/g++.dg/gomp/pr67522.C b/gcc/testsuite/g++.dg/gomp/pr67522.C
index da8cb74d1fa..4a901ba68c7 100644
--- a/gcc/testsuite/g++.dg/gomp/pr67522.C
+++ b/gcc/testsuite/g++.dg/gomp/pr67522.C
@@ -12,7 +12,7 @@ foo (void)
for (int i = 0; i < 16; i++)
;
- #pragma omp target map (S[0:10]) // { dg-error "is not a variable in" }
+ #pragma omp target map (S[0:10]) // { dg-error "expected primary-expression before '\\\[' token" }
;
#pragma omp task depend (inout: S[0:10]) // { dg-error "is not a variable in" }
diff --git a/gcc/tree-pretty-print.cc b/gcc/tree-pretty-print.cc
index 47371d8bcbe..ccbafa98699 100644
--- a/gcc/tree-pretty-print.cc
+++ b/gcc/tree-pretty-print.cc
@@ -2522,6 +2522,20 @@ dump_generic_node (pretty_printer *pp, tree node, int spc, dump_flags_t flags,
}
break;
+ case OMP_ARRAY_SECTION:
+ op0 = TREE_OPERAND (node, 0);
+ if (op_prio (op0) < op_prio (node))
+ pp_left_paren (pp);
+ dump_generic_node (pp, op0, spc, flags, false);
+ if (op_prio (op0) < op_prio (node))
+ pp_right_paren (pp);
+ pp_left_bracket (pp);
+ dump_generic_node (pp, TREE_OPERAND (node, 1), spc, flags, false);
+ pp_colon (pp);
+ dump_generic_node (pp, TREE_OPERAND (node, 2), spc, flags, false);
+ pp_right_bracket (pp);
+ break;
+
case CONSTRUCTOR:
{
unsigned HOST_WIDE_INT ix;
diff --git a/gcc/tree.def b/gcc/tree.def
index 62650b6934b..f015021e9dc 100644
--- a/gcc/tree.def
+++ b/gcc/tree.def
@@ -1310,6 +1310,9 @@ DEFTREECODE (OMP_ATOMIC_CAPTURE_NEW, "omp_atomic_capture_new", tcc_statement, 2)
/* OpenMP clauses. */
DEFTREECODE (OMP_CLAUSE, "omp_clause", tcc_exceptional, 0)
+/* An OpenMP array section. */
+DEFTREECODE (OMP_ARRAY_SECTION, "omp_array_section", tcc_expression, 3)
+
/* TRANSACTION_EXPR tree code.
Operand 0: BODY: contains body of the transaction. */
DEFTREECODE (TRANSACTION_EXPR, "transaction_expr", tcc_expression, 1)
diff --git a/libgomp/testsuite/libgomp.c++/baseptrs-4.C b/libgomp/testsuite/libgomp.c++/baseptrs-4.C
index 196029ac186..d5ca79c3344 100644
--- a/libgomp/testsuite/libgomp.c++/baseptrs-4.C
+++ b/libgomp/testsuite/libgomp.c++/baseptrs-4.C
@@ -11,11 +11,9 @@
#define REF2PTR_DECL_BASE
#define ARRAY_DECL_BASE
-// Needs map clause "lvalue"-parsing support.
-//#define REF2ARRAY_DECL_BASE
+#define REF2ARRAY_DECL_BASE
#define PTR_OFFSET_DECL_BASE
-// Needs map clause "lvalue"-parsing support.
-//#define REF2PTR_OFFSET_DECL_BASE
+#define REF2PTR_OFFSET_DECL_BASE
#define MAP_SECTIONS
@@ -30,25 +28,21 @@
#define ARRAY_DECL_MEMBER_SLICE
#define ARRAY_DECL_MEMBER_SLICE_BASEPTR
-// Needs map clause "lvalue"-parsing support.
-//#define REF2ARRAY_DECL_MEMBER_SLICE
-//#define REF2ARRAY_DECL_MEMBER_SLICE_BASEPTR
+#define REF2ARRAY_DECL_MEMBER_SLICE
+#define REF2ARRAY_DECL_MEMBER_SLICE_BASEPTR
#define PTR_OFFSET_DECL_MEMBER_SLICE
#define PTR_OFFSET_DECL_MEMBER_SLICE_BASEPTR
-// Needs map clause "lvalue"-parsing support.
-//#define REF2PTR_OFFSET_DECL_MEMBER_SLICE
-//#define REF2PTR_OFFSET_DECL_MEMBER_SLICE_BASEPTR
+#define REF2PTR_OFFSET_DECL_MEMBER_SLICE
+#define REF2PTR_OFFSET_DECL_MEMBER_SLICE_BASEPTR
#define PTRARRAY_DECL_MEMBER_SLICE
#define PTRARRAY_DECL_MEMBER_SLICE_BASEPTR
-// Needs map clause "lvalue"-parsing support.
-//#define REF2PTRARRAY_DECL_MEMBER_SLICE
-//#define REF2PTRARRAY_DECL_MEMBER_SLICE_BASEPTR
+#define REF2PTRARRAY_DECL_MEMBER_SLICE
+#define REF2PTRARRAY_DECL_MEMBER_SLICE_BASEPTR
#define PTRPTR_OFFSET_DECL_MEMBER_SLICE
#define PTRPTR_OFFSET_DECL_MEMBER_SLICE_BASEPTR
-// Needs map clause "lvalue"-parsing support.
-//#define REF2PTRPTR_OFFSET_DECL_MEMBER_SLICE
-//#define REF2PTRPTR_OFFSET_DECL_MEMBER_SLICE_BASEPTR
+#define REF2PTRPTR_OFFSET_DECL_MEMBER_SLICE
+#define REF2PTRPTR_OFFSET_DECL_MEMBER_SLICE_BASEPTR
#define NONREF_COMPONENT_BASE
#define NONREF_COMPONENT_MEMBER_SLICE
diff --git a/libgomp/testsuite/libgomp.c++/ind-base-1.C b/libgomp/testsuite/libgomp.c++/ind-base-1.C
new file mode 100644
index 00000000000..4566854e60a
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c++/ind-base-1.C
@@ -0,0 +1,162 @@
+// { dg-do run }
+// { dg-options "-fopenmp" }
+
+#include <cassert>
+
+struct S
+{
+ int x[10];
+};
+
+struct T
+{
+ struct S *s;
+};
+
+struct U
+{
+ struct T *t;
+};
+
+void
+foo_siblist (void)
+{
+ U *u = new U;
+ u->t = new T;
+ u->t->s = new S;
+ for (int i = 0; i < 10; i++)
+ u->t->s->x[i] = 0;
+#pragma omp target map(u->t, *(u->t), u->t->s, *u->t->s)
+ for (int i = 0; i < 10; i++)
+ u->t->s->x[i] = i * 3;
+ for (int i = 0; i < 10; i++)
+ assert (u->t->s->x[i] == i * 3);
+ delete u->t->s;
+ delete u->t;
+ delete u;
+}
+
+void
+foo (void)
+{
+ U *u = new U;
+ u->t = new T;
+ u->t->s = new S;
+ for (int i = 0; i < 10; i++)
+ u->t->s->x[i] = 0;
+#pragma omp target map(*u, u->t, *(u->t), u->t->s, *u->t->s)
+ for (int i = 0; i < 10; i++)
+ u->t->s->x[i] = i * 3;
+ for (int i = 0; i < 10; i++)
+ assert (u->t->s->x[i] == i * 3);
+ delete u->t->s;
+ delete u->t;
+ delete u;
+}
+
+void
+foo_tofrom (void)
+{
+ U *u = new U;
+ u->t = new T;
+ u->t->s = new S;
+ for (int i = 0; i < 10; i++)
+ u->t->s->x[i] = 0;
+#pragma omp target map(u, *u, u->t, *(u->t), u->t->s, *u->t->s)
+ for (int i = 0; i < 10; i++)
+ u->t->s->x[i] = i * 3;
+ for (int i = 0; i < 10; i++)
+ assert (u->t->s->x[i] == i * 3);
+ delete u->t->s;
+ delete u->t;
+ delete u;
+}
+
+void
+bar (void)
+{
+ U *u = new U;
+ U **up = &u;
+ u->t = new T;
+ u->t->s = new S;
+ for (int i = 0; i < 10; i++)
+ (*up)->t->s->x[i] = 0;
+#pragma omp target map(*up, (*up)->t, *(*up)->t, (*up)->t->s, *(*up)->t->s)
+ for (int i = 0; i < 10; i++)
+ (*up)->t->s->x[i] = i * 3;
+ for (int i = 0; i < 10; i++)
+ assert ((*up)->t->s->x[i] == i * 3);
+ delete u->t->s;
+ delete u->t;
+ delete u;
+}
+
+void
+bar_pp (void)
+{
+ U *u = new U;
+ U **up = &u;
+ u->t = new T;
+ u->t->s = new S;
+ for (int i = 0; i < 10; i++)
+ (*up)->t->s->x[i] = 0;
+#pragma omp target map(*up, **up, (*up)->t, *(*up)->t, (*up)->t->s, *(*up)->t->s)
+ for (int i = 0; i < 10; i++)
+ (*up)->t->s->x[i] = i * 3;
+ for (int i = 0; i < 10; i++)
+ assert ((*up)->t->s->x[i] == i * 3);
+ delete u->t->s;
+ delete u->t;
+ delete u;
+}
+
+void
+bar_tofrom (void)
+{
+ U *u = new U;
+ U **up = &u;
+ u->t = new T;
+ u->t->s = new S;
+ for (int i = 0; i < 10; i++)
+ (*up)->t->s->x[i] = 0;
+#pragma omp target map(*up, up, (*up)->t, *(*up)->t, (*up)->t->s, *(*up)->t->s)
+ for (int i = 0; i < 10; i++)
+ (*up)->t->s->x[i] = i * 3;
+ for (int i = 0; i < 10; i++)
+ assert ((*up)->t->s->x[i] == i * 3);
+ delete u->t->s;
+ delete u->t;
+ delete u;
+}
+
+void
+bar_tofrom_pp (void)
+{
+ U *u = new U;
+ U **up = &u;
+ u->t = new T;
+ u->t->s = new S;
+ for (int i = 0; i < 10; i++)
+ (*up)->t->s->x[i] = 0;
+#pragma omp target map(**up, *up, up, (*up)->t, *(*up)->t, (*up)->t->s, \
+ *(*up)->t->s)
+ for (int i = 0; i < 10; i++)
+ (*up)->t->s->x[i] = i * 3;
+ for (int i = 0; i < 10; i++)
+ assert ((*up)->t->s->x[i] == i * 3);
+ delete u->t->s;
+ delete u->t;
+ delete u;
+}
+
+int main (int argc, char *argv[])
+{
+ foo_siblist ();
+ foo ();
+ foo_tofrom ();
+ bar ();
+ bar_pp ();
+ bar_tofrom ();
+ bar_tofrom_pp ();
+ return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c++/ind-base-2.C b/libgomp/testsuite/libgomp.c++/ind-base-2.C
new file mode 100644
index 00000000000..706a1205c00
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c++/ind-base-2.C
@@ -0,0 +1,49 @@
+// { dg-do run }
+// { dg-options "-fopenmp" }
+
+#include <cassert>
+
+struct S
+{
+ int x[10];
+};
+
+struct T
+{
+ struct S ***s;
+};
+
+struct U
+{
+ struct T **t;
+};
+
+void
+foo (void)
+{
+ U *u = new U;
+ T *real_t = new T;
+ S *real_s = new S;
+ T **t_pp = &real_t;
+ S **s_pp = &real_s;
+ S ***s_ppp = &s_pp;
+ u->t = t_pp;
+ (*u->t)->s = s_ppp;
+ for (int i = 0; i < 10; i++)
+ (**((*u->t)->s))->x[i] = 0;
+#pragma omp target map(u->t, *u->t, (*u->t)->s, *(*u->t)->s, **(*u->t)->s, \
+ (**(*u->t)->s)->x[0:10])
+ for (int i = 0; i < 10; i++)
+ (**((*u->t)->s))->x[i] = i * 3;
+ for (int i = 0; i < 10; i++)
+ assert ((**((*u->t)->s))->x[i] == i * 3);
+ delete real_s;
+ delete real_t;
+ delete u;
+}
+
+int main (int argc, char *argv[])
+{
+ foo ();
+ return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c++/map-comma-1.C b/libgomp/testsuite/libgomp.c++/map-comma-1.C
new file mode 100644
index 00000000000..ee03c5ac1aa
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c++/map-comma-1.C
@@ -0,0 +1,15 @@
+/* { dg-do run } */
+
+#include <cassert>
+
+int main (int argc, char *argv[])
+{
+ int a = 5, b = 7;
+#pragma omp target map((a, b))
+ {
+ a++;
+ b++;
+ }
+ assert (a == 5 && b == 8);
+ return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c++/map-rvalue-ref-1.C b/libgomp/testsuite/libgomp.c++/map-rvalue-ref-1.C
new file mode 100644
index 00000000000..93811da4000
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c++/map-rvalue-ref-1.C
@@ -0,0 +1,22 @@
+/* { dg-do run } */
+
+#include <cassert>
+
+int foo (int &&x)
+{
+ int y;
+#pragma omp target map(x, y)
+ {
+ x++;
+ y = x;
+ }
+ return y;
+}
+
+int main (int argc, char *argv[])
+{
+ int y = 5;
+ y = foo (y + 3);
+ assert (y == 9);
+ return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c++/struct-ref-1.C b/libgomp/testsuite/libgomp.c++/struct-ref-1.C
new file mode 100644
index 00000000000..d3874650017
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c++/struct-ref-1.C
@@ -0,0 +1,97 @@
+// { dg-do run }
+// { dg-options "-fopenmp" }
+
+#include <cassert>
+
+struct S
+{
+ int x[10];
+};
+
+void
+foo (S *s, int x)
+{
+ S *&r = s;
+ for (int i = 0; i < x; i++)
+ s[0].x[i] = s[1].x[i] = 0;
+ #pragma omp target map (s, x)
+ ;
+ #pragma omp target map (s[0], x)
+ for (int i = 0; i < x; i++)
+ s[0].x[i] = i;
+ #pragma omp target map (s[1], x)
+ for (int i = 0; i < x; i++)
+ s[1].x[i] = i * 2;
+ for (int i = 0; i < x; i++)
+ {
+ assert (s[0].x[i] == i);
+ assert (s[1].x[i] == i * 2);
+ s[0].x[i] = 0;
+ s[1].x[i] = 0;
+ }
+ #pragma omp target map (r, x)
+ ;
+ #pragma omp target map (r[0], x)
+ for (int i = 0; i < x; i++)
+ r[0].x[i] = i;
+ #pragma omp target map (r[1], x)
+ for (int i = 0; i < x; i++)
+ r[1].x[i] = i * 2;
+ for (int i = 0; i < x; i++)
+ {
+ assert (r[0].x[i] == i);
+ assert (r[1].x[i] == i * 2);
+ }
+}
+
+template <int N>
+struct T
+{
+ int x[N];
+};
+
+template <int N>
+void
+bar (T<N> *t, int x)
+{
+ T<N> *&r = t;
+ for (int i = 0; i < x; i++)
+ t[0].x[i] = t[1].x[i] = 0;
+ #pragma omp target map (t, x)
+ ;
+ #pragma omp target map (t[0], x)
+ for (int i = 0; i < x; i++)
+ t[0].x[i] = i;
+ #pragma omp target map (t[1], x)
+ for (int i = 0; i < x; i++)
+ t[1].x[i] = i * 2;
+ for (int i = 0; i < x; i++)
+ {
+ assert (t[0].x[i] == i);
+ assert (t[1].x[i] == i * 2);
+ t[0].x[i] = 0;
+ t[1].x[i] = 0;
+ }
+ #pragma omp target map (r, x)
+ ;
+ #pragma omp target map (r[0], x)
+ for (int i = 0; i < x; i++)
+ r[0].x[i] = i;
+ #pragma omp target map (r[1], x)
+ for (int i = 0; i < x; i++)
+ r[1].x[i] = i * 2;
+ for (int i = 0; i < x; i++)
+ {
+ assert (r[0].x[i] == i);
+ assert (r[1].x[i] == i * 2);
+ }
+}
+
+int main (int argc, char *argv[])
+{
+ S s[2];
+ foo (s, 10);
+ T<10> t[2];
+ bar (t, 10);
+ return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c-c++-common/array-field-1.c b/libgomp/testsuite/libgomp.c-c++-common/array-field-1.c
new file mode 100644
index 00000000000..6dd8b5c48e1
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c-c++-common/array-field-1.c
@@ -0,0 +1,35 @@
+/* { dg-do run } */
+
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#define N 16
+
+struct Z {
+ int *ptr;
+ int arr[N];
+ int c;
+};
+
+int main (int argc, char *argv[])
+{
+ struct Z *myz;
+ myz = (struct Z *) calloc (1, sizeof *myz);
+
+#pragma omp target map(tofrom:myz->arr[0:N], myz->c)
+ {
+ for (int i = 0; i < N; i++)
+ myz->arr[i]++;
+ myz->c++;
+ }
+
+ for (int i = 0; i < N; i++)
+ assert (myz->arr[i] == 1);
+ assert (myz->c == 1);
+
+ free (myz);
+
+ return 0;
+}
+
diff --git a/libgomp/testsuite/libgomp.c-c++-common/array-of-struct-1.c b/libgomp/testsuite/libgomp.c-c++-common/array-of-struct-1.c
new file mode 100644
index 00000000000..726eede6c31
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c-c++-common/array-of-struct-1.c
@@ -0,0 +1,65 @@
+/* { dg-do run } */
+
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#define N 16
+
+/* NOTE: This test is the same as array-of-struct-2.c, except the fields of
+ this struct are in a different order. */
+
+struct Z {
+ int arr[N];
+ int *ptr;
+ int c;
+};
+
+void
+foo (struct Z *zarr, int len)
+{
+#pragma omp target map(to:zarr, zarr[5].ptr) map(tofrom:zarr[5].ptr[0:len])
+ {
+ for (int i = 0; i < len; i++)
+ zarr[5].ptr[i]++;
+ }
+
+#pragma omp target map(to:zarr) map(tofrom:zarr[4].arr[0:len])
+ {
+ for (int i = 0; i < len; i++)
+ zarr[4].arr[i]++;
+ }
+
+#pragma omp target map (to:zarr[3].ptr) map(tofrom:zarr[3].ptr[0:len])
+ {
+ for (int i = 0; i < len; i++)
+ zarr[3].ptr[i]++;
+ }
+
+#pragma omp target map(tofrom:zarr[2].arr[0:len])
+ {
+ for (int i = 0; i < len; i++)
+ zarr[2].arr[i]++;
+ }
+}
+
+int main (int argc, char *argv[])
+{
+ struct Z zs[10];
+ memset (zs, 0, sizeof zs);
+
+ for (int i = 0; i < 10; i++)
+ zs[i].ptr = (int *) calloc (N, sizeof (int));
+
+ foo (zs, N);
+
+ for (int i = 0; i < N; i++)
+ {
+ assert (zs[2].arr[i] == 1);
+ assert (zs[4].arr[i] == 1);
+ assert (zs[3].ptr[i] == 1);
+ assert (zs[5].ptr[i] == 1);
+ }
+
+ return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c-c++-common/array-of-struct-2.c b/libgomp/testsuite/libgomp.c-c++-common/array-of-struct-2.c
new file mode 100644
index 00000000000..c4b77cd13f1
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c-c++-common/array-of-struct-2.c
@@ -0,0 +1,65 @@
+/* { dg-do run } */
+
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#define N 16
+
+/* NOTE: This test is the same as array-of-struct-1.c, except the fields of
+ this struct are in a different order. */
+
+struct Z {
+ int *ptr;
+ int arr[N];
+ int c;
+};
+
+void
+foo (struct Z *zarr, int len)
+{
+#pragma omp target map(to:zarr, zarr[5].ptr) map(tofrom:zarr[5].ptr[0:len])
+ {
+ for (int i = 0; i < len; i++)
+ zarr[5].ptr[i]++;
+ }
+
+#pragma omp target map(to:zarr) map(tofrom:zarr[4].arr[0:len])
+ {
+ for (int i = 0; i < len; i++)
+ zarr[4].arr[i]++;
+ }
+
+#pragma omp target map (to:zarr[3].ptr) map(tofrom:zarr[3].ptr[0:len])
+ {
+ for (int i = 0; i < len; i++)
+ zarr[3].ptr[i]++;
+ }
+
+#pragma omp target map(tofrom:zarr[2].arr[0:len])
+ {
+ for (int i = 0; i < len; i++)
+ zarr[2].arr[i]++;
+ }
+}
+
+int main (int argc, char *argv[])
+{
+ struct Z zs[10];
+ memset (zs, 0, sizeof zs);
+
+ for (int i = 0; i < 10; i++)
+ zs[i].ptr = (int *) calloc (N, sizeof (int));
+
+ foo (zs, N);
+
+ for (int i = 0; i < N; i++)
+ {
+ assert (zs[2].arr[i] == 1);
+ assert (zs[4].arr[i] == 1);
+ assert (zs[3].ptr[i] == 1);
+ assert (zs[5].ptr[i] == 1);
+ }
+
+ return 0;
+}
--
2.29.2
More information about the Gcc-patches
mailing list