diff options
author | Chung-Lin Tang <cltang@codesourcery.com> | 2021-12-08 23:58:55 +0800 |
---|---|---|
committer | Chung-Lin Tang <cltang@codesourcery.com> | 2021-12-09 00:01:10 +0800 |
commit | 6c0399378e77d02962e5d49f7b72d6fa8ebe5e07 (patch) | |
tree | 1b5644f24197dedde1aa8dbf1d8b983d14ab5b19 /gcc/gimplify.c | |
parent | 6b49d50a27428e9de0ae2913651a6379744f3067 (diff) | |
download | gcc-6c0399378e77d02962e5d49f7b72d6fa8ebe5e07.zip gcc-6c0399378e77d02962e5d49f7b72d6fa8ebe5e07.tar.gz gcc-6c0399378e77d02962e5d49f7b72d6fa8ebe5e07.tar.bz2 |
OpenMP 5.0: Remove array section base-pointer mapping semantics and other front-end adjustments
This patch implements three pieces of functionality:
(1) Adjust array section mapping to have standards conforming behavior,
mapping array sections should *NOT* also map the base-pointer:
struct S { int *ptr; ... };
struct S s;
Instead of generating this during gimplify:
map(to:*_1 [len: 400]) map(attach:s.ptr [bias: 0])
Now, adjust to:
(i.e. do not map the base-pointer together. The attach operation is still
generated, and if s.ptr is already mapped prior, attachment will happen)
The correct way of achieving the base-pointer-also-mapped behavior would be to
use:
(A small Fortran front-end patch to trans-openmp.c:gfc_trans_omp_array_section
is also included, which removes generation of a GOMP_MAP_ALWAYS_POINTER for
array types, which appears incorrect and causes a regression in
libgomp.fortranlibgomp.fortran/struct-elem-map-1.f90)
(2) Related to the first item above, are fixes in libgomp/target.c to not
overwrite attached pointers when handling device<->host copies, mainly for the
"always" case.
(3) The third is a set of changes to the C/C++ front-ends to extend the allowed
component access syntax in map clauses. These changes are enabled for both
OpenACC and OpenMP.
gcc/c/ChangeLog:
* c-parser.c (struct omp_dim): New struct type for use inside
c_parser_omp_variable_list.
(c_parser_omp_variable_list): Allow multiple levels of array and
component accesses in array section base-pointer expression.
(c_parser_omp_clause_to): Set 'allow_deref' to true in call to
c_parser_omp_var_list_parens.
(c_parser_omp_clause_from): Likewise.
* c-typeck.c (handle_omp_array_sections_1): Extend allowed range
of base-pointer expressions involving INDIRECT/MEM/ARRAY_REF and
POINTER_PLUS_EXPR.
(c_finish_omp_clauses): Extend allowed ranged of expressions
involving INDIRECT/MEM/ARRAY_REF and POINTER_PLUS_EXPR.
gcc/cp/ChangeLog:
* parser.c (struct omp_dim): New struct type for use inside
cp_parser_omp_var_list_no_open.
(cp_parser_omp_var_list_no_open): Allow multiple levels of array and
component accesses in array section base-pointer expression.
(cp_parser_omp_all_clauses): Set 'allow_deref' to true in call to
cp_parser_omp_var_list for to/from clauses.
* semantics.c (handle_omp_array_sections_1): Extend allowed range
of base-pointer expressions involving INDIRECT/MEM/ARRAY_REF and
POINTER_PLUS_EXPR.
(handle_omp_array_sections): Adjust pointer map generation of
references.
(finish_omp_clauses): Extend allowed ranged of expressions
involving INDIRECT/MEM/ARRAY_REF and POINTER_PLUS_EXPR.
gcc/fortran/ChangeLog:
* trans-openmp.c (gfc_trans_omp_array_section): Do not generate
GOMP_MAP_ALWAYS_POINTER map for main array maps of ARRAY_TYPE type.
gcc/ChangeLog:
* gimplify.c (extract_base_bit_offset): Add 'tree *offsetp' parameter,
accomodate case where 'offset' return of get_inner_reference is
non-NULL.
(is_or_contains_p): Further robustify conditions.
(omp_target_reorder_clauses): In alloc/to/from sorting phase, also
move following GOMP_MAP_ALWAYS_POINTER maps along. Add new sorting
phase where we make sure pointers with an attach/detach map are ordered
correctly.
(gimplify_scan_omp_clauses): Add modifications to avoid creating
GOMP_MAP_STRUCT and associated alloc map for attach/detach maps.
gcc/testsuite/ChangeLog:
* c-c++-common/goacc/deep-copy-arrayofstruct.c: Adjust testcase.
* c-c++-common/gomp/target-enter-data-1.c: New testcase.
* c-c++-common/gomp/target-implicit-map-2.c: New testcase.
libgomp/ChangeLog:
* target.c (gomp_map_vars_existing): Make sure attached pointer is
not overwritten during cross-host/device copying.
(gomp_update): Likewise.
(gomp_exit_data): Likewise.
* testsuite/libgomp.c++/target-11.C: Adjust testcase.
* testsuite/libgomp.c++/target-12.C: Likewise.
* testsuite/libgomp.c++/target-15.C: Likewise.
* testsuite/libgomp.c++/target-16.C: Likewise.
* testsuite/libgomp.c++/target-17.C: Likewise.
* testsuite/libgomp.c++/target-21.C: Likewise.
* testsuite/libgomp.c++/target-23.C: Likewise.
* testsuite/libgomp.c/target-23.c: Likewise.
* testsuite/libgomp.c/target-29.c: Likewise.
* testsuite/libgomp.c-c++-common/target-implicit-map-2.c: New testcase.
Diffstat (limited to 'gcc/gimplify.c')
-rw-r--r-- | gcc/gimplify.c | 220 |
1 files changed, 187 insertions, 33 deletions
diff --git a/gcc/gimplify.c b/gcc/gimplify.c index 0a55bf7..b118c72 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -8660,7 +8660,7 @@ insert_struct_comp_map (enum tree_code code, tree c, tree struct_node, static tree extract_base_bit_offset (tree base, tree *base_ref, poly_int64 *bitposp, - poly_offset_int *poffsetp) + poly_offset_int *poffsetp, tree *offsetp) { tree offset; poly_int64 bitsize, bitpos; @@ -8707,10 +8707,11 @@ extract_base_bit_offset (tree base, tree *base_ref, poly_int64 *bitposp, && TREE_CODE (TREE_TYPE (TREE_OPERAND (base, 0))) == REFERENCE_TYPE) base = TREE_OPERAND (base, 0); - gcc_assert (offset == NULL_TREE || poly_int_tree_p (offset)); - - if (offset) - poffset = wi::to_poly_offset (offset); + if (offset && poly_int_tree_p (offset)) + { + poffset = wi::to_poly_offset (offset); + offset = NULL_TREE; + } else poffset = 0; @@ -8719,6 +8720,7 @@ extract_base_bit_offset (tree base, tree *base_ref, poly_int64 *bitposp, *bitposp = bitpos; *poffsetp = poffset; + *offsetp = offset; /* Set *BASE_REF if BASE was a dereferenced reference variable. */ if (base_ref && orig_base != base) @@ -8732,12 +8734,22 @@ extract_base_bit_offset (tree base, tree *base_ref, poly_int64 *bitposp, static bool is_or_contains_p (tree expr, tree base_ptr) { - while (expr != base_ptr) - if (TREE_CODE (base_ptr) == COMPONENT_REF) - base_ptr = TREE_OPERAND (base_ptr, 0); - else - break; - return expr == base_ptr; + if ((TREE_CODE (expr) == INDIRECT_REF && TREE_CODE (base_ptr) == MEM_REF) + || (TREE_CODE (expr) == MEM_REF && TREE_CODE (base_ptr) == INDIRECT_REF)) + return operand_equal_p (TREE_OPERAND (expr, 0), + TREE_OPERAND (base_ptr, 0)); + while (!operand_equal_p (expr, base_ptr)) + { + if (TREE_CODE (base_ptr) == COMPOUND_EXPR) + base_ptr = TREE_OPERAND (base_ptr, 1); + if (TREE_CODE (base_ptr) == COMPONENT_REF + || TREE_CODE (base_ptr) == POINTER_PLUS_EXPR + || TREE_CODE (base_ptr) == SAVE_EXPR) + base_ptr = TREE_OPERAND (base_ptr, 0); + else + break; + } + return operand_equal_p (expr, base_ptr); } /* Implement OpenMP 5.x map ordering rules for target directives. There are @@ -8817,21 +8829,107 @@ omp_target_reorder_clauses (tree *list_p) tree base_ptr = TREE_OPERAND (decl, 0); STRIP_TYPE_NOPS (base_ptr); for (unsigned int j = i + 1; j < atf.length (); j++) - { - tree *cp2 = atf[j]; - tree decl2 = OMP_CLAUSE_DECL (*cp2); - if (is_or_contains_p (decl2, base_ptr)) - { - /* Move *cp2 to before *cp. */ - tree c = *cp2; - *cp2 = OMP_CLAUSE_CHAIN (c); - OMP_CLAUSE_CHAIN (c) = *cp; - *cp = c; - atf[j] = NULL; + if (atf[j]) + { + tree *cp2 = atf[j]; + tree decl2 = OMP_CLAUSE_DECL (*cp2); + + decl2 = OMP_CLAUSE_DECL (*cp2); + if (is_or_contains_p (decl2, base_ptr)) + { + /* Move *cp2 to before *cp. */ + tree c = *cp2; + *cp2 = OMP_CLAUSE_CHAIN (c); + OMP_CLAUSE_CHAIN (c) = *cp; + *cp = c; + + if (*cp2 != NULL_TREE + && OMP_CLAUSE_CODE (*cp2) == OMP_CLAUSE_MAP + && OMP_CLAUSE_MAP_KIND (*cp2) == GOMP_MAP_ALWAYS_POINTER) + { + tree c2 = *cp2; + *cp2 = OMP_CLAUSE_CHAIN (c2); + OMP_CLAUSE_CHAIN (c2) = OMP_CLAUSE_CHAIN (c); + OMP_CLAUSE_CHAIN (c) = c2; + } + + atf[j] = NULL; } - } + } } } + + /* For attach_detach map clauses, if there is another map that maps the + attached/detached pointer, make sure that map is ordered before the + attach_detach. */ + atf.truncate (0); + for (tree *cp = list_p; *cp; cp = &OMP_CLAUSE_CHAIN (*cp)) + if (OMP_CLAUSE_CODE (*cp) == OMP_CLAUSE_MAP) + { + /* Collect alloc, to, from, to/from clauses, and + always_pointer/attach_detach clauses. */ + gomp_map_kind k = OMP_CLAUSE_MAP_KIND (*cp); + if (k == GOMP_MAP_ALLOC + || k == GOMP_MAP_TO + || k == GOMP_MAP_FROM + || k == GOMP_MAP_TOFROM + || k == GOMP_MAP_ALWAYS_TO + || k == GOMP_MAP_ALWAYS_FROM + || k == GOMP_MAP_ALWAYS_TOFROM + || k == GOMP_MAP_ATTACH_DETACH + || k == GOMP_MAP_ALWAYS_POINTER) + atf.safe_push (cp); + } + + for (unsigned int i = 0; i < atf.length (); i++) + if (atf[i]) + { + tree *cp = atf[i]; + tree ptr = OMP_CLAUSE_DECL (*cp); + STRIP_TYPE_NOPS (ptr); + if (OMP_CLAUSE_MAP_KIND (*cp) == GOMP_MAP_ATTACH_DETACH) + for (unsigned int j = i + 1; j < atf.length (); j++) + { + tree *cp2 = atf[j]; + tree decl2 = OMP_CLAUSE_DECL (*cp2); + if (OMP_CLAUSE_MAP_KIND (*cp2) != GOMP_MAP_ATTACH_DETACH + && OMP_CLAUSE_MAP_KIND (*cp2) != GOMP_MAP_ALWAYS_POINTER + && is_or_contains_p (decl2, ptr)) + { + /* Move *cp2 to before *cp. */ + tree c = *cp2; + *cp2 = OMP_CLAUSE_CHAIN (c); + OMP_CLAUSE_CHAIN (c) = *cp; + *cp = c; + atf[j] = NULL; + + /* If decl2 is of the form '*decl2_opnd0', and followed by an + ALWAYS_POINTER or ATTACH_DETACH of 'decl2_opnd0', move the + pointer operation along with *cp2. This can happen for C++ + reference sequences. */ + if (j + 1 < atf.length () + && (TREE_CODE (decl2) == INDIRECT_REF + || TREE_CODE (decl2) == MEM_REF)) + { + tree *cp3 = atf[j + 1]; + tree decl3 = OMP_CLAUSE_DECL (*cp3); + tree decl2_opnd0 = TREE_OPERAND (decl2, 0); + if ((OMP_CLAUSE_MAP_KIND (*cp3) == GOMP_MAP_ALWAYS_POINTER + || OMP_CLAUSE_MAP_KIND (*cp3) == GOMP_MAP_ATTACH_DETACH) + && operand_equal_p (decl3, decl2_opnd0)) + { + /* Also move *cp3 to before *cp. */ + c = *cp3; + *cp2 = OMP_CLAUSE_CHAIN (c); + OMP_CLAUSE_CHAIN (c) = *cp; + *cp = c; + atf[j + 1] = NULL; + j += 1; + } + } + } + } + } } /* DECL is supposed to have lastprivate semantics in the outer contexts @@ -8923,6 +9021,7 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, struct gimplify_omp_ctx *ctx, *outer_ctx; tree c; hash_map<tree_operand_hash, tree> *struct_map_to_clause = NULL; + hash_map<tree_operand_hash, tree *> *struct_seen_clause = NULL; hash_set<tree> *struct_deref_set = NULL; tree *prev_list_p = NULL, *orig_list_p = list_p; int handled_depend_iterators = -1; @@ -9398,6 +9497,7 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, } bool indir_p = false; bool component_ref_p = false; + tree indir_base = NULL_TREE; tree orig_decl = decl; tree decl_ref = NULL_TREE; if ((region_type & (ORT_ACC | ORT_TARGET | ORT_TARGET_DATA)) != 0 @@ -9416,6 +9516,7 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, == POINTER_TYPE)) { indir_p = true; + indir_base = decl; decl = TREE_OPERAND (decl, 0); STRIP_NOPS (decl); } @@ -9462,7 +9563,9 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, != GOMP_MAP_POINTER) || OMP_CLAUSE_DECL (next_clause) != decl) && (!struct_deref_set - || !struct_deref_set->contains (decl))) + || !struct_deref_set->contains (decl)) + && (!struct_map_to_clause + || !struct_map_to_clause->get (indir_base))) { if (!struct_deref_set) struct_deref_set = new hash_set<tree> (); @@ -9506,7 +9609,8 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, if ((DECL_P (decl) || (component_ref_p && (INDIRECT_REF_P (decl) - || TREE_CODE (decl) == MEM_REF))) + || TREE_CODE (decl) == MEM_REF + || TREE_CODE (decl) == ARRAY_REF))) && OMP_CLAUSE_MAP_KIND (c) != GOMP_MAP_TO_PSET && OMP_CLAUSE_MAP_KIND (c) != GOMP_MAP_ATTACH && OMP_CLAUSE_MAP_KIND (c) != GOMP_MAP_DETACH @@ -9541,7 +9645,15 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, remove = true; break; } - if (OMP_CLAUSE_CHAIN (*prev_list_p) != c) + + /* The below prev_list_p based error recovery code is + currently no longer valid for OpenMP. */ + if (code != OMP_TARGET + && code != OMP_TARGET_DATA + && code != OMP_TARGET_UPDATE + && code != OMP_TARGET_ENTER_DATA + && code != OMP_TARGET_EXIT_DATA + && OMP_CLAUSE_CHAIN (*prev_list_p) != c) { tree ch = OMP_CLAUSE_CHAIN (*prev_list_p); if (ch == NULL_TREE || OMP_CLAUSE_CHAIN (ch) != c) @@ -9554,13 +9666,15 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, poly_offset_int offset1; poly_int64 bitpos1; + tree tree_offset1; tree base_ref; tree base = extract_base_bit_offset (OMP_CLAUSE_DECL (c), &base_ref, - &bitpos1, &offset1); + &bitpos1, &offset1, + &tree_offset1); - gcc_assert (base == decl); + bool do_map_struct = (base == decl && !tree_offset1); splay_tree_node n = (DECL_P (decl) @@ -9592,6 +9706,32 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, OMP_CLAUSE_SET_MAP_KIND (c, k); has_attachments = true; } + + /* We currently don't handle non-constant offset accesses wrt to + GOMP_MAP_STRUCT elements. */ + if (!do_map_struct) + goto skip_map_struct; + + /* Nor for attach_detach for OpenMP. */ + if ((code == OMP_TARGET + || code == OMP_TARGET_DATA + || code == OMP_TARGET_UPDATE + || code == OMP_TARGET_ENTER_DATA + || code == OMP_TARGET_EXIT_DATA) + && attach_detach) + { + if (DECL_P (decl)) + { + if (struct_seen_clause == NULL) + struct_seen_clause + = new hash_map<tree_operand_hash, tree *>; + if (!struct_seen_clause->get (decl)) + struct_seen_clause->put (decl, list_p); + } + + goto skip_map_struct; + } + if ((DECL_P (decl) && (n == NULL || (n->value & GOVD_MAP) == 0)) || (!DECL_P (decl) @@ -9631,9 +9771,14 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, struct_map_to_clause->put (decl, l); if (ptr || attach_detach) { - insert_struct_comp_map (code, c, l, *prev_list_p, + tree **sc = (struct_seen_clause + ? struct_seen_clause->get (decl) + : NULL); + tree *insert_node_pos = sc ? *sc : prev_list_p; + + insert_struct_comp_map (code, c, l, *insert_node_pos, NULL); - *prev_list_p = l; + *insert_node_pos = l; prev_list_p = NULL; } else @@ -9719,9 +9864,11 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, tree sc_decl = OMP_CLAUSE_DECL (*sc); poly_offset_int offsetn; poly_int64 bitposn; + tree tree_offsetn; tree base = extract_base_bit_offset (sc_decl, NULL, - &bitposn, &offsetn); + &bitposn, &offsetn, + &tree_offsetn); if (base != decl) break; if (scp) @@ -9809,16 +9956,21 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, continue; } } + skip_map_struct: + ; } else if ((code == OACC_ENTER_DATA || code == OACC_EXIT_DATA || code == OACC_DATA || code == OACC_PARALLEL || code == OACC_KERNELS - || code == OACC_SERIAL) + || code == OACC_SERIAL + || code == OMP_TARGET_ENTER_DATA + || code == OMP_TARGET_EXIT_DATA) && OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ATTACH_DETACH) { - gomp_map_kind k = (code == OACC_EXIT_DATA + gomp_map_kind k = ((code == OACC_EXIT_DATA + || code == OMP_TARGET_EXIT_DATA) ? GOMP_MAP_DETACH : GOMP_MAP_ATTACH); OMP_CLAUSE_SET_MAP_KIND (c, k); } @@ -10650,6 +10802,8 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, ctx->clauses = *orig_list_p; gimplify_omp_ctxp = ctx; + if (struct_seen_clause) + delete struct_seen_clause; if (struct_map_to_clause) delete struct_map_to_clause; if (struct_deref_set) |