]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
openmp: Add support for the 'present' modifier
authorTobias Burnus <tobias@codesourcery.com>
Tue, 6 Jun 2023 14:47:16 +0000 (16:47 +0200)
committerTobias Burnus <tobias@codesourcery.com>
Tue, 6 Jun 2023 14:49:22 +0000 (16:49 +0200)
This implements support for the OpenMP 5.1 'present' modifier, which can be
used in map clauses in the 'target', 'target data', 'target data enter' and
'target data exit' constructs, and in the 'to' and 'from' clauses of the
'target update' construct.  It is also supported in defaultmap.

The modifier triggers a fatal runtime error if the data specified by the
clause is not already present on the target device.  It can also be combined
with 'always' in map clauses.

2023-06-06  Kwok Cheung Yeung  <kcy@codesourcery.com>
    Tobias Burnus  <tobias@codesourcery.com>

gcc/c/
* c-parser.cc (c_parser_omp_clause_defaultmap,
c_parser_omp_clause_map): Parse 'present'.
(c_parser_omp_clause_to, c_parser_omp_clause_from): Remove.
(c_parser_omp_clause_from_to): New; parse to/from clauses with
optional present modifer.
(c_parser_omp_all_clauses): Update call.
(c_parser_omp_target_data, c_parser_omp_target_enter_data,
c_parser_omp_target_exit_data): Handle new map enum values
for 'present' mapping.

gcc/cp/
* parser.cc (cp_parser_omp_clause_defaultmap,
cp_parser_omp_clause_map): Parse 'present'.
(cp_parser_omp_clause_from_to): New; parse to/from
clauses with optional 'present' modifier.
(cp_parser_omp_all_clauses): Update call.
(cp_parser_omp_target_data, cp_parser_omp_target_enter_data,
cp_parser_omp_target_exit_data): Handle new enum value for
'present' mapping.
* semantics.cc (finish_omp_target): Likewise.

gcc/fortran/
* dump-parse-tree.cc (show_omp_namelist): Display 'present' map
modifier.
(show_omp_clauses): Display 'present' motion modifier for 'to'
and 'from' clauses.

* gfortran.h (enum gfc_omp_map_op): Add entries with 'present'
modifiers.
(struct gfc_omp_namelist): Add 'present_modifer'.
* openmp.cc (gfc_match_motion_var_list): New, handles optional
'present' modifier for to/from clauses.
(gfc_match_omp_clauses): Call it for to/from clauses; parse 'present'
in defaultmap and map clauses.
(resolve_omp_clauses): Allow 'present' modifiers on 'target',
'target data', 'target enter' and 'target exit' directives.
* trans-openmp.cc (gfc_trans_omp_clauses): Apply 'present' modifiers
to tree node for 'map', 'to' and 'from' clauses.  Apply 'present' for
defaultmap.

gcc/
* gimplify.cc (omp_notice_variable): Apply GOVD_MAP_ALLOC_ONLY flag
and defaultmap flags if the defaultmap has GOVD_MAP_FORCE_PRESENT flag
set.
(omp_get_attachment): Handle map clauses with 'present' modifier.
(omp_group_base): Likewise.
(gimplify_scan_omp_clauses): Reorder present maps to come first.
Set GOVD flags for present defaultmaps.
(gimplify_adjust_omp_clauses_1): Set map kind for present defaultmaps.
* omp-low.cc (scan_sharing_clauses): Handle 'always, present' map
clauses.
(lower_omp_target): Handle map clauses with 'present' modifier.
Handle 'to' and 'from' clauses with 'present'.
* tree-core.h (enum omp_clause_defaultmap_kind): Add
OMP_CLAUSE_DEFAULTMAP_PRESENT defaultmap kind.
* tree-pretty-print.cc (dump_omp_clause): Handle 'map', 'to' and
'from' clauses with 'present' modifier.  Handle present defaultmap.
* tree.h (OMP_CLAUSE_MOTION_PRESENT): New #define.

include/
* gomp-constants.h (GOMP_MAP_FLAG_SPECIAL_5): New.
(GOMP_MAP_FLAG_FORCE): Redefine.
(GOMP_MAP_FLAG_PRESENT, GOMP_MAP_FLAG_ALWAYS_PRESENT): New.
(enum gomp_map_kind): Add map kinds with 'present' modifiers.
(GOMP_MAP_COPY_TO_P, GOMP_MAP_COPY_FROM_P): Evaluate to true for
map variants with 'present'
(GOMP_MAP_ALWAYS_TO_P, GOMP_MAP_ALWAYS_FROM_P): Evaluate to true
for map variants with 'always, present' modifiers.
(GOMP_MAP_ALWAYS): Redefine.
(GOMP_MAP_FORCE_P, GOMP_MAP_PRESENT_P): New.

libgomp/
* libgomp.texi (OpenMP 5.1 Impl. status): Set 'present' support for
defaultmap to 'Y', add 'Y' entry for 'present' on to/from/map clauses.
* target.c (gomp_to_device_kind_p): Add map kinds with 'present'
modifier.
(gomp_map_vars_existing): Use new GOMP_MAP_FORCE_P macro.
(gomp_map_vars_internal, gomp_update, gomp_target_rev):
Emit runtime error if memory region not present.
* testsuite/libgomp.c-c++-common/target-present-1.c: New test.
* testsuite/libgomp.c-c++-common/target-present-2.c: New test.
* testsuite/libgomp.c-c++-common/target-present-3.c: New test.
* testsuite/libgomp.fortran/target-present-1.f90: New test.
* testsuite/libgomp.fortran/target-present-2.f90: New test.
* testsuite/libgomp.fortran/target-present-3.f90: New test.

gcc/testsuite/

* c-c++-common/gomp/map-6.c: Update dg-error, extend to test for
duplicated 'present' and extend scan-dump tests for 'present'.
* gfortran.dg/gomp/defaultmap-1.f90: Update dg-error.
* gfortran.dg/gomp/map-7.f90: Extend parse and dump test for
'present'.
* gfortran.dg/gomp/map-8.f90: Extend for duplicate 'present'
modifier checking.
* c-c++-common/gomp/defaultmap-4.c: New test.
* c-c++-common/gomp/map-9.c: New test.
* c-c++-common/gomp/target-update-1.c: New test.
* gfortran.dg/gomp/defaultmap-8.f90: New test.
* gfortran.dg/gomp/map-11.f90: New test.
* gfortran.dg/gomp/map-12.f90: New test.
* gfortran.dg/gomp/target-update-1.f90: New test.

32 files changed:
gcc/c/c-parser.cc
gcc/cp/parser.cc
gcc/cp/semantics.cc
gcc/fortran/dump-parse-tree.cc
gcc/fortran/gfortran.h
gcc/fortran/openmp.cc
gcc/fortran/trans-openmp.cc
gcc/gimplify.cc
gcc/omp-low.cc
gcc/testsuite/c-c++-common/gomp/defaultmap-4.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/gomp/map-6.c
gcc/testsuite/c-c++-common/gomp/map-9.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/gomp/target-update-1.c [new file with mode: 0644]
gcc/testsuite/gfortran.dg/gomp/defaultmap-1.f90
gcc/testsuite/gfortran.dg/gomp/defaultmap-8.f90 [new file with mode: 0644]
gcc/testsuite/gfortran.dg/gomp/map-11.f90 [new file with mode: 0644]
gcc/testsuite/gfortran.dg/gomp/map-12.f90 [new file with mode: 0644]
gcc/testsuite/gfortran.dg/gomp/map-7.f90
gcc/testsuite/gfortran.dg/gomp/map-8.f90
gcc/testsuite/gfortran.dg/gomp/target-update-1.f90 [new file with mode: 0644]
gcc/tree-core.h
gcc/tree-pretty-print.cc
gcc/tree.h
include/gomp-constants.h
libgomp/libgomp.texi
libgomp/target.c
libgomp/testsuite/libgomp.c-c++-common/target-present-1.c [new file with mode: 0644]
libgomp/testsuite/libgomp.c-c++-common/target-present-2.c [new file with mode: 0644]
libgomp/testsuite/libgomp.c-c++-common/target-present-3.c [new file with mode: 0644]
libgomp/testsuite/libgomp.fortran/target-present-1.f90 [new file with mode: 0644]
libgomp/testsuite/libgomp.fortran/target-present-2.f90 [new file with mode: 0644]
libgomp/testsuite/libgomp.fortran/target-present-3.f90 [new file with mode: 0644]

index 5baa501dbeea9c745c623b7dfe1fdde8abf5bc65..72f6fbae6a69349a3eec06f99b717526eb6e9cd6 100644 (file)
@@ -14939,6 +14939,13 @@ c_parser_omp_clause_defaultmap (c_parser *parser, tree list)
        goto invalid_behavior;
       break;
 
+    case 'p':
+      if (strcmp ("present", p) == 0)
+       behavior = OMP_CLAUSE_DEFAULTMAP_PRESENT;
+      else
+       goto invalid_behavior;
+      break;
+
     case 't':
       if (strcmp ("tofrom", p) == 0)
        behavior = OMP_CLAUSE_DEFAULTMAP_TOFROM;
@@ -17109,6 +17116,7 @@ c_parser_omp_clause_map (c_parser *parser, tree list)
 
   int always_modifier = 0;
   int close_modifier = 0;
+  int present_modifier = 0;
   for (int pos = 1; pos < map_kind_pos; ++pos)
     {
       c_token *tok = c_parser_peek_token (parser);
@@ -17140,11 +17148,21 @@ c_parser_omp_clause_map (c_parser *parser, tree list)
            }
          close_modifier++;
        }
+      else if (strcmp ("present", p) == 0)
+       {
+         if (present_modifier)
+           {
+             c_parser_error (parser, "too many %<present%> modifiers");
+             parens.skip_until_found_close (parser);
+             return list;
+           }
+         present_modifier++;
+       }
       else
        {
          c_parser_error (parser, "%<#pragma omp target%> with "
-                                 "modifier other than %<always%> or "
-                                 "%<close%> on %<map%> clause");
+                                 "modifier other than %<always%>, %<close%> "
+                                 "or %<present%> on %<map%> clause");
          parens.skip_until_found_close (parser);
          return list;
        }
@@ -17156,14 +17174,25 @@ c_parser_omp_clause_map (c_parser *parser, tree list)
       && c_parser_peek_2nd_token (parser)->type == CPP_COLON)
     {
       const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+      int always_present_modifier = always_modifier && present_modifier;
+
       if (strcmp ("alloc", p) == 0)
-       kind = GOMP_MAP_ALLOC;
+       kind = present_modifier ? GOMP_MAP_PRESENT_ALLOC : GOMP_MAP_ALLOC;
       else if (strcmp ("to", p) == 0)
-       kind = always_modifier ? GOMP_MAP_ALWAYS_TO : GOMP_MAP_TO;
+       kind = (always_present_modifier ? GOMP_MAP_ALWAYS_PRESENT_TO
+               : present_modifier ? GOMP_MAP_PRESENT_TO
+               : always_modifier ? GOMP_MAP_ALWAYS_TO
+               : GOMP_MAP_TO);
       else if (strcmp ("from", p) == 0)
-       kind = always_modifier ? GOMP_MAP_ALWAYS_FROM : GOMP_MAP_FROM;
+       kind = (always_present_modifier ? GOMP_MAP_ALWAYS_PRESENT_FROM
+               : present_modifier ? GOMP_MAP_PRESENT_FROM
+               : always_modifier ? GOMP_MAP_ALWAYS_FROM
+               : GOMP_MAP_FROM);
       else if (strcmp ("tofrom", p) == 0)
-       kind = always_modifier ? GOMP_MAP_ALWAYS_TOFROM : GOMP_MAP_TOFROM;
+       kind = (always_present_modifier ? GOMP_MAP_ALWAYS_PRESENT_TOFROM
+               : present_modifier ? GOMP_MAP_PRESENT_TOFROM
+               : always_modifier ? GOMP_MAP_ALWAYS_TOFROM
+               : GOMP_MAP_TOFROM);
       else if (strcmp ("release", p) == 0)
        kind = GOMP_MAP_RELEASE;
       else if (strcmp ("delete", p) == 0)
@@ -17419,21 +17448,42 @@ c_parser_omp_clause_device_type (c_parser *parser, tree list)
 }
 
 /* OpenMP 4.0:
-   to ( variable-list ) */
+   from ( variable-list )
+   to ( variable-list )
+
+   OpenMP 5.1:
+   from ( [present :] variable-list )
+   to ( [present :] variable-list ) */
 
 static tree
-c_parser_omp_clause_to (c_parser *parser, tree list)
+c_parser_omp_clause_from_to (c_parser *parser, enum omp_clause_code kind,
+                            tree list)
 {
-  return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_TO, list, true);
-}
+  location_t loc = c_parser_peek_token (parser)->location;
+  matching_parens parens;
+  if (!parens.require_open (parser))
+    return list;
 
-/* OpenMP 4.0:
-   from ( variable-list ) */
+  bool present = false;
+  c_token *token = c_parser_peek_token (parser);
 
-static tree
-c_parser_omp_clause_from (c_parser *parser, tree list)
-{
-  return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_FROM, list, true);
+  if (token->type == CPP_NAME
+      && strcmp (IDENTIFIER_POINTER (token->value), "present") == 0
+      && c_parser_peek_2nd_token (parser)->type == CPP_COLON)
+    {
+      present = true;
+      c_parser_consume_token (parser);
+      c_parser_consume_token (parser);
+    }
+
+  tree nl = c_parser_omp_variable_list (parser, loc, kind, list);
+  parens.skip_until_found_close (parser);
+
+  if (present)
+    for (tree c = nl; c != list; c = OMP_CLAUSE_CHAIN (c))
+      OMP_CLAUSE_MOTION_PRESENT (c) = 1;
+
+  return nl;
 }
 
 /* OpenMP 4.0:
@@ -17940,11 +17990,13 @@ c_parser_omp_all_clauses (c_parser *parser, omp_clause_mask mask,
              clauses = nl;
            }
          else
-           clauses = c_parser_omp_clause_to (parser, clauses);
+           clauses = c_parser_omp_clause_from_to (parser, OMP_CLAUSE_TO,
+                                                  clauses);
          c_name = "to";
          break;
        case PRAGMA_OMP_CLAUSE_FROM:
-         clauses = c_parser_omp_clause_from (parser, clauses);
+         clauses = c_parser_omp_clause_from_to (parser, OMP_CLAUSE_FROM,
+                                                clauses);
          c_name = "from";
          break;
        case PRAGMA_OMP_CLAUSE_UNIFORM:
@@ -21768,11 +21820,18 @@ c_parser_omp_target_data (location_t loc, c_parser *parser, bool *if_p)
          {
          case GOMP_MAP_TO:
          case GOMP_MAP_ALWAYS_TO:
+         case GOMP_MAP_PRESENT_TO:
+         case GOMP_MAP_ALWAYS_PRESENT_TO:
          case GOMP_MAP_FROM:
          case GOMP_MAP_ALWAYS_FROM:
+         case GOMP_MAP_PRESENT_FROM:
+         case GOMP_MAP_ALWAYS_PRESENT_FROM:
          case GOMP_MAP_TOFROM:
          case GOMP_MAP_ALWAYS_TOFROM:
+         case GOMP_MAP_PRESENT_TOFROM:
+         case GOMP_MAP_ALWAYS_PRESENT_TOFROM:
          case GOMP_MAP_ALLOC:
+         case GOMP_MAP_PRESENT_ALLOC:
            map_seen = 3;
            break;
          case GOMP_MAP_FIRSTPRIVATE_POINTER:
@@ -21918,7 +21977,10 @@ c_parser_omp_target_enter_data (location_t loc, c_parser *parser,
          {
          case GOMP_MAP_TO:
          case GOMP_MAP_ALWAYS_TO:
+         case GOMP_MAP_PRESENT_TO:
+         case GOMP_MAP_ALWAYS_PRESENT_TO:
          case GOMP_MAP_ALLOC:
+         case GOMP_MAP_PRESENT_ALLOC:
            map_seen = 3;
            break;
          case GOMP_MAP_TOFROM:
@@ -21929,6 +21991,14 @@ c_parser_omp_target_enter_data (location_t loc, c_parser *parser,
            OMP_CLAUSE_SET_MAP_KIND (*pc, GOMP_MAP_ALWAYS_TO);
            map_seen = 3;
            break;
+         case GOMP_MAP_PRESENT_TOFROM:
+           OMP_CLAUSE_SET_MAP_KIND (*pc, GOMP_MAP_PRESENT_TO);
+           map_seen = 3;
+           break;
+         case GOMP_MAP_ALWAYS_PRESENT_TOFROM:
+           OMP_CLAUSE_SET_MAP_KIND (*pc, GOMP_MAP_ALWAYS_PRESENT_TO);
+           map_seen = 3;
+           break;
          case GOMP_MAP_FIRSTPRIVATE_POINTER:
          case GOMP_MAP_ALWAYS_POINTER:
          case GOMP_MAP_ATTACH_DETACH:
@@ -22016,6 +22086,8 @@ c_parser_omp_target_exit_data (location_t loc, c_parser *parser,
          {
          case GOMP_MAP_FROM:
          case GOMP_MAP_ALWAYS_FROM:
+         case GOMP_MAP_PRESENT_FROM:
+         case GOMP_MAP_ALWAYS_PRESENT_FROM:
          case GOMP_MAP_RELEASE:
          case GOMP_MAP_DELETE:
            map_seen = 3;
@@ -22028,6 +22100,14 @@ c_parser_omp_target_exit_data (location_t loc, c_parser *parser,
            OMP_CLAUSE_SET_MAP_KIND (*pc, GOMP_MAP_ALWAYS_FROM);
            map_seen = 3;
            break;
+         case GOMP_MAP_PRESENT_TOFROM:
+           OMP_CLAUSE_SET_MAP_KIND (*pc, GOMP_MAP_PRESENT_FROM);
+           map_seen = 3;
+           break;
+         case GOMP_MAP_ALWAYS_PRESENT_TOFROM:
+           OMP_CLAUSE_SET_MAP_KIND (*pc, GOMP_MAP_ALWAYS_PRESENT_FROM);
+           map_seen = 3;
+           break;
          case GOMP_MAP_FIRSTPRIVATE_POINTER:
          case GOMP_MAP_ALWAYS_POINTER:
          case GOMP_MAP_ATTACH_DETACH:
@@ -22273,11 +22353,18 @@ check_clauses:
          {
          case GOMP_MAP_TO:
          case GOMP_MAP_ALWAYS_TO:
+         case GOMP_MAP_PRESENT_TO:
+         case GOMP_MAP_ALWAYS_PRESENT_TO:
          case GOMP_MAP_FROM:
          case GOMP_MAP_ALWAYS_FROM:
+         case GOMP_MAP_PRESENT_FROM:
+         case GOMP_MAP_ALWAYS_PRESENT_FROM:
          case GOMP_MAP_TOFROM:
          case GOMP_MAP_ALWAYS_TOFROM:
+         case GOMP_MAP_PRESENT_TOFROM:
+         case GOMP_MAP_ALWAYS_PRESENT_TOFROM:
          case GOMP_MAP_ALLOC:
+         case GOMP_MAP_PRESENT_ALLOC:
          case GOMP_MAP_FIRSTPRIVATE_POINTER:
          case GOMP_MAP_ALWAYS_POINTER:
          case GOMP_MAP_ATTACH_DETACH:
index 1c9aa6718518428767371514d337588324e0c5cf..d77fbd20e56e751ef9d829a4ba0699b69b2045b6 100644 (file)
@@ -38779,6 +38779,13 @@ cp_parser_omp_clause_defaultmap (cp_parser *parser, tree list,
        goto invalid_behavior;
       break;
 
+    case 'p':
+      if (strcmp ("present", p) == 0)
+       behavior = OMP_CLAUSE_DEFAULTMAP_PRESENT;
+      else
+       goto invalid_behavior;
+      break;
+
     case 't':
       if (strcmp ("tofrom", p) == 0)
        behavior = OMP_CLAUSE_DEFAULTMAP_TOFROM;
@@ -40486,6 +40493,41 @@ cp_parser_omp_clause_doacross (cp_parser *parser, tree list, location_t loc)
   return nlist;
 }
 
+/* OpenMP 4.0:
+   from ( variable-list )
+   to ( variable-list )
+
+   OpenMP 5.1:
+   from ( [present :] variable-list )
+   to ( [present :] variable-list ) */
+
+static tree
+cp_parser_omp_clause_from_to (cp_parser *parser, enum omp_clause_code kind,
+                             tree list)
+{
+  if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN))
+    return list;
+
+  bool present = false;
+  cp_token *token = cp_lexer_peek_token (parser->lexer);
+
+  if (token->type == CPP_NAME
+      && strcmp (IDENTIFIER_POINTER (token->u.value), "present") == 0
+      && cp_lexer_nth_token_is (parser->lexer, 2, CPP_COLON))
+    {
+      present = true;
+      cp_lexer_consume_token (parser->lexer);
+      cp_lexer_consume_token (parser->lexer);
+    }
+
+  tree nl = cp_parser_omp_var_list_no_open (parser, kind, list, NULL, true);
+  if (present)
+    for (tree c = nl; c != list; c = OMP_CLAUSE_CHAIN (c))
+      OMP_CLAUSE_MOTION_PRESENT (c) = 1;
+
+  return nl;
+}
+
 /* OpenMP 4.0:
    map ( map-kind : variable-list )
    map ( variable-list )
@@ -40532,6 +40574,7 @@ cp_parser_omp_clause_map (cp_parser *parser, tree list)
 
   bool always_modifier = false;
   bool close_modifier = false;
+  bool present_modifier = false;
   for (int pos = 1; pos < map_kind_pos; ++pos)
     {
       cp_token *tok = cp_lexer_peek_token (parser->lexer);
@@ -40568,11 +40611,24 @@ cp_parser_omp_clause_map (cp_parser *parser, tree list)
            }
          close_modifier = true;
        }
+      else if (strcmp ("present", p) == 0)
+       {
+         if (present_modifier)
+           {
+             cp_parser_error (parser, "too many %<present%> modifiers");
+             cp_parser_skip_to_closing_parenthesis (parser,
+                                                    /*recovering=*/true,
+                                                    /*or_comma=*/false,
+                                                    /*consume_paren=*/true);
+             return list;
+           }
+         present_modifier = true;
+       }
       else
        {
          cp_parser_error (parser, "%<#pragma omp target%> with "
-                                  "modifier other than %<always%> or "
-                                  "%<close%> on %<map%> clause");
+                                  "modifier other than %<always%>, %<close%> "
+                                  "or %<present%> on %<map%> clause");
          cp_parser_skip_to_closing_parenthesis (parser,
                                                 /*recovering=*/true,
                                                 /*or_comma=*/false,
@@ -40588,15 +40644,25 @@ cp_parser_omp_clause_map (cp_parser *parser, tree list)
     {
       tree id = cp_lexer_peek_token (parser->lexer)->u.value;
       const char *p = IDENTIFIER_POINTER (id);
+      int always_present_modifier = always_modifier && present_modifier;
 
       if (strcmp ("alloc", p) == 0)
-       kind = GOMP_MAP_ALLOC;
+       kind = present_modifier ? GOMP_MAP_PRESENT_ALLOC : GOMP_MAP_ALLOC;
       else if (strcmp ("to", p) == 0)
-       kind = always_modifier ? GOMP_MAP_ALWAYS_TO : GOMP_MAP_TO;
+       kind = (always_present_modifier ? GOMP_MAP_ALWAYS_PRESENT_TO
+               : present_modifier ? GOMP_MAP_PRESENT_TO
+               : always_modifier ? GOMP_MAP_ALWAYS_TO
+               : GOMP_MAP_TO);
       else if (strcmp ("from", p) == 0)
-       kind = always_modifier ? GOMP_MAP_ALWAYS_FROM : GOMP_MAP_FROM;
+       kind = (always_present_modifier ? GOMP_MAP_ALWAYS_PRESENT_FROM
+               : present_modifier ? GOMP_MAP_PRESENT_FROM
+               : always_modifier ? GOMP_MAP_ALWAYS_FROM
+               : GOMP_MAP_FROM);
       else if (strcmp ("tofrom", p) == 0)
-       kind = always_modifier ? GOMP_MAP_ALWAYS_TOFROM : GOMP_MAP_TOFROM;
+       kind = (always_present_modifier ? GOMP_MAP_ALWAYS_PRESENT_TOFROM
+               : present_modifier ? GOMP_MAP_PRESENT_TOFROM
+               : always_modifier ? GOMP_MAP_ALWAYS_TOFROM
+               : GOMP_MAP_TOFROM);
       else if (strcmp ("release", p) == 0)
        kind = GOMP_MAP_RELEASE;
       else
@@ -41373,13 +41439,13 @@ cp_parser_omp_all_clauses (cp_parser *parser, omp_clause_mask mask,
              clauses = nl;
            }
          else
-           clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_TO, clauses,
-                                             true);
+           clauses = cp_parser_omp_clause_from_to (parser, OMP_CLAUSE_TO,
+                                                   clauses);
          c_name = "to";
          break;
        case PRAGMA_OMP_CLAUSE_FROM:
-         clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_FROM, clauses,
-                                           true);
+         clauses = cp_parser_omp_clause_from_to (parser, OMP_CLAUSE_FROM,
+                                                 clauses);
          c_name = "from";
          break;
        case PRAGMA_OMP_CLAUSE_UNIFORM:
@@ -45231,11 +45297,18 @@ cp_parser_omp_target_data (cp_parser *parser, cp_token *pragma_tok, bool *if_p)
          {
          case GOMP_MAP_TO:
          case GOMP_MAP_ALWAYS_TO:
+         case GOMP_MAP_PRESENT_TO:
+         case GOMP_MAP_ALWAYS_PRESENT_TO:
          case GOMP_MAP_FROM:
          case GOMP_MAP_ALWAYS_FROM:
+         case GOMP_MAP_PRESENT_FROM:
+         case GOMP_MAP_ALWAYS_PRESENT_FROM:
          case GOMP_MAP_TOFROM:
          case GOMP_MAP_ALWAYS_TOFROM:
+         case GOMP_MAP_PRESENT_TOFROM:
+         case GOMP_MAP_ALWAYS_PRESENT_TOFROM:
          case GOMP_MAP_ALLOC:
+         case GOMP_MAP_PRESENT_ALLOC:
            map_seen = 3;
            break;
          case GOMP_MAP_FIRSTPRIVATE_POINTER:
@@ -45338,7 +45411,10 @@ cp_parser_omp_target_enter_data (cp_parser *parser, cp_token *pragma_tok,
          {
          case GOMP_MAP_TO:
          case GOMP_MAP_ALWAYS_TO:
+         case GOMP_MAP_PRESENT_TO:
+         case GOMP_MAP_ALWAYS_PRESENT_TO:
          case GOMP_MAP_ALLOC:
+         case GOMP_MAP_PRESENT_ALLOC:
            map_seen = 3;
            break;
          case GOMP_MAP_TOFROM:
@@ -45349,6 +45425,14 @@ cp_parser_omp_target_enter_data (cp_parser *parser, cp_token *pragma_tok,
            OMP_CLAUSE_SET_MAP_KIND (*pc, GOMP_MAP_ALWAYS_TO);
            map_seen = 3;
            break;
+         case GOMP_MAP_PRESENT_TOFROM:
+           OMP_CLAUSE_SET_MAP_KIND (*pc, GOMP_MAP_PRESENT_TO);
+           map_seen = 3;
+           break;
+         case GOMP_MAP_ALWAYS_PRESENT_TOFROM:
+           OMP_CLAUSE_SET_MAP_KIND (*pc, GOMP_MAP_ALWAYS_PRESENT_TO);
+           map_seen = 3;
+           break;
          case GOMP_MAP_FIRSTPRIVATE_POINTER:
          case GOMP_MAP_FIRSTPRIVATE_REFERENCE:
          case GOMP_MAP_ALWAYS_POINTER:
@@ -45441,6 +45525,8 @@ cp_parser_omp_target_exit_data (cp_parser *parser, cp_token *pragma_tok,
          {
          case GOMP_MAP_FROM:
          case GOMP_MAP_ALWAYS_FROM:
+         case GOMP_MAP_PRESENT_FROM:
+         case GOMP_MAP_ALWAYS_PRESENT_FROM:
          case GOMP_MAP_RELEASE:
          case GOMP_MAP_DELETE:
            map_seen = 3;
@@ -45453,6 +45539,14 @@ cp_parser_omp_target_exit_data (cp_parser *parser, cp_token *pragma_tok,
            OMP_CLAUSE_SET_MAP_KIND (*pc, GOMP_MAP_ALWAYS_FROM);
            map_seen = 3;
            break;
+         case GOMP_MAP_PRESENT_TOFROM:
+           OMP_CLAUSE_SET_MAP_KIND (*pc, GOMP_MAP_PRESENT_FROM);
+           map_seen = 3;
+           break;
+         case GOMP_MAP_ALWAYS_PRESENT_TOFROM:
+           OMP_CLAUSE_SET_MAP_KIND (*pc, GOMP_MAP_ALWAYS_PRESENT_FROM);
+           map_seen = 3;
+           break;
          case GOMP_MAP_FIRSTPRIVATE_POINTER:
          case GOMP_MAP_FIRSTPRIVATE_REFERENCE:
          case GOMP_MAP_ALWAYS_POINTER:
index 0843b5eae7366458c4c6cd18ec347d15d8c302f7..c04514679f0dc68a0122fcf3a961d26bf501d16a 100644 (file)
@@ -10030,11 +10030,18 @@ finish_omp_target (location_t loc, tree clauses, tree body, bool combined_p)
          {
          case GOMP_MAP_TO:
          case GOMP_MAP_ALWAYS_TO:
+         case GOMP_MAP_PRESENT_TO:
+         case GOMP_MAP_ALWAYS_PRESENT_TO:
          case GOMP_MAP_FROM:
          case GOMP_MAP_ALWAYS_FROM:
+         case GOMP_MAP_PRESENT_FROM:
+         case GOMP_MAP_ALWAYS_PRESENT_FROM:
          case GOMP_MAP_TOFROM:
          case GOMP_MAP_ALWAYS_TOFROM:
+         case GOMP_MAP_PRESENT_TOFROM:
+         case GOMP_MAP_ALWAYS_PRESENT_TOFROM:
          case GOMP_MAP_ALLOC:
+         case GOMP_MAP_PRESENT_ALLOC:
          case GOMP_MAP_FIRSTPRIVATE_POINTER:
          case GOMP_MAP_FIRSTPRIVATE_REFERENCE:
          case GOMP_MAP_ALWAYS_POINTER:
index 6d75cc29f60396ced29bfce6373fc543e8042390..99c8bdaadce9febf47f94117a68e3f473d35bfbc 100644 (file)
@@ -1468,9 +1468,20 @@ show_omp_namelist (int list_type, gfc_omp_namelist *n)
          case OMP_MAP_TO: fputs ("to:", dumpfile); break;
          case OMP_MAP_FROM: fputs ("from:", dumpfile); break;
          case OMP_MAP_TOFROM: fputs ("tofrom:", dumpfile); break;
+         case OMP_MAP_PRESENT_ALLOC: fputs ("present,alloc:", dumpfile); break;
+         case OMP_MAP_PRESENT_TO: fputs ("present,to:", dumpfile); break;
+         case OMP_MAP_PRESENT_FROM: fputs ("present,from:", dumpfile); break;
+         case OMP_MAP_PRESENT_TOFROM:
+           fputs ("present,tofrom:", dumpfile); break;
          case OMP_MAP_ALWAYS_TO: fputs ("always,to:", dumpfile); break;
          case OMP_MAP_ALWAYS_FROM: fputs ("always,from:", dumpfile); break;
          case OMP_MAP_ALWAYS_TOFROM: fputs ("always,tofrom:", dumpfile); break;
+         case OMP_MAP_ALWAYS_PRESENT_TO:
+           fputs ("always,present,to:", dumpfile); break;
+         case OMP_MAP_ALWAYS_PRESENT_FROM:
+           fputs ("always,present,from:", dumpfile); break;
+         case OMP_MAP_ALWAYS_PRESENT_TOFROM:
+           fputs ("always,present,tofrom:", dumpfile); break;
          case OMP_MAP_DELETE: fputs ("delete:", dumpfile); break;
          case OMP_MAP_RELEASE: fputs ("release:", dumpfile); break;
          default: break;
@@ -1793,6 +1804,9 @@ show_omp_clauses (gfc_omp_clauses *omp_clauses)
          fputs ("inscan, ", dumpfile);
        if (list_type == OMP_LIST_REDUCTION_TASK)
          fputs ("task, ", dumpfile);
+       if ((list_type == OMP_LIST_TO || list_type == OMP_LIST_FROM)
+           && omp_clauses->lists[list_type]->u.present_modifier)
+         fputs ("present:", dumpfile);
        show_omp_namelist (list_type, omp_clauses->lists[list_type]);
        fputc (')', dumpfile);
       }
index 3e5f942d7fdeea70479abbed6d34009ac3fd92f8..33ca4986f69b769e60ac5d47ab96d9265d971cbb 100644 (file)
@@ -1308,7 +1308,14 @@ enum gfc_omp_map_op
   OMP_MAP_RELEASE,
   OMP_MAP_ALWAYS_TO,
   OMP_MAP_ALWAYS_FROM,
-  OMP_MAP_ALWAYS_TOFROM
+  OMP_MAP_ALWAYS_TOFROM,
+  OMP_MAP_PRESENT_ALLOC,
+  OMP_MAP_PRESENT_TO,
+  OMP_MAP_PRESENT_FROM,
+  OMP_MAP_PRESENT_TOFROM,
+  OMP_MAP_ALWAYS_PRESENT_TO,
+  OMP_MAP_ALWAYS_PRESENT_FROM,
+  OMP_MAP_ALWAYS_PRESENT_TOFROM
 };
 
 enum gfc_omp_defaultmap
@@ -1362,6 +1369,7 @@ typedef struct gfc_omp_namelist
        } linear;
       struct gfc_common_head *common;
       bool lastprivate_conditional;
+      bool present_modifier;
     } u;
   union
     {
index 4c30548567f62c936a5b698268cdb9bd46d78038..8efc4b3ecfacc9fdade8bc7068ff9541cb7fe12f 100644 (file)
@@ -1336,6 +1336,30 @@ failed:
   return MATCH_NO;
 }
 
+/* Match target update's to/from( [present:] var-list).  */
+
+static match
+gfc_match_motion_var_list (const char *str, gfc_omp_namelist **list,
+                          gfc_omp_namelist ***headp)
+{
+  match m = gfc_match (str);
+  if (m != MATCH_YES)
+    return m;
+
+  match m_present = gfc_match (" present : ");
+
+  m = gfc_match_omp_variable_list ("", list, false, NULL, headp, true, true);
+  if (m != MATCH_YES)
+    return m;
+  if (m_present == MATCH_YES)
+    {
+      gfc_omp_namelist *n;
+      for (n = **headp; n; n = n->next)
+       n->u.present_modifier = true;
+    }
+  return MATCH_YES;
+}
+
 /* reduction ( reduction-modifier, reduction-operator : variable-list )
    in_reduction ( reduction-operator : variable-list )
    task_reduction ( reduction-operator : variable-list )  */
@@ -2098,6 +2122,8 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask,
                behavior = OMP_DEFAULTMAP_FROM;
              else if (gfc_match ("firstprivate ") == MATCH_YES)
                behavior = OMP_DEFAULTMAP_FIRSTPRIVATE;
+             else if (gfc_match ("present ") == MATCH_YES)
+               behavior = OMP_DEFAULTMAP_PRESENT;
              else if (gfc_match ("none ") == MATCH_YES)
                behavior = OMP_DEFAULTMAP_NONE;
              else if (gfc_match ("default ") == MATCH_YES)
@@ -2105,7 +2131,7 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask,
              else
                {
                  gfc_error ("Expected ALLOC, TO, FROM, TOFROM, FIRSTPRIVATE, "
-                          "NONE or DEFAULT at %C");
+                            "PRESENT, NONE or DEFAULT at %C");
                  break;
                }
              if (')' == gfc_peek_ascii_char ())
@@ -2529,10 +2555,8 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask,
                                              true) == MATCH_YES)
            continue;
          if ((mask & OMP_CLAUSE_FROM)
-             && (gfc_match_omp_variable_list ("from (",
-                                             &c->lists[OMP_LIST_FROM], false,
-                                             NULL, &head, true, true)
-                 == MATCH_YES))
+             && gfc_match_motion_var_list ("from (", &c->lists[OMP_LIST_FROM],
+                                            &head) == MATCH_YES)
            continue;
          break;
        case 'g':
@@ -2888,8 +2912,10 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask,
              locus old_loc2 = gfc_current_locus;
              int always_modifier = 0;
              int close_modifier = 0;
+             int present_modifier = 0;
              locus second_always_locus = old_loc2;
              locus second_close_locus = old_loc2;
+             locus second_present_locus = old_loc2;
 
              for (;;)
                {
@@ -2904,20 +2930,38 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask,
                      if (close_modifier++ == 1)
                        second_close_locus = current_locus;
                    }
+                 else if (gfc_match ("present ") == MATCH_YES)
+                   {
+                     if (present_modifier++ == 1)
+                       second_present_locus = current_locus;
+                   }
                  else
                    break;
                  gfc_match (", ");
                }
 
              gfc_omp_map_op map_op = OMP_MAP_TOFROM;
+             int always_present_modifier
+               = always_modifier && present_modifier;
+
              if (gfc_match ("alloc : ") == MATCH_YES)
-               map_op = OMP_MAP_ALLOC;
+               map_op = (present_modifier ? OMP_MAP_PRESENT_ALLOC
+                         : OMP_MAP_ALLOC);
              else if (gfc_match ("tofrom : ") == MATCH_YES)
-               map_op = always_modifier ? OMP_MAP_ALWAYS_TOFROM : OMP_MAP_TOFROM;
+               map_op = (always_present_modifier ? OMP_MAP_ALWAYS_PRESENT_TOFROM
+                         : present_modifier ? OMP_MAP_PRESENT_TOFROM
+                         : always_modifier ? OMP_MAP_ALWAYS_TOFROM
+                         : OMP_MAP_TOFROM);
              else if (gfc_match ("to : ") == MATCH_YES)
-               map_op = always_modifier ? OMP_MAP_ALWAYS_TO : OMP_MAP_TO;
+               map_op = (always_present_modifier ? OMP_MAP_ALWAYS_PRESENT_TO
+                         : present_modifier ? OMP_MAP_PRESENT_TO
+                         : always_modifier ? OMP_MAP_ALWAYS_TO
+                         : OMP_MAP_TO);
              else if (gfc_match ("from : ") == MATCH_YES)
-               map_op = always_modifier ? OMP_MAP_ALWAYS_FROM : OMP_MAP_FROM;
+               map_op = (always_present_modifier ? OMP_MAP_ALWAYS_PRESENT_FROM
+                         : present_modifier ? OMP_MAP_PRESENT_FROM
+                         : always_modifier ? OMP_MAP_ALWAYS_FROM
+                         : OMP_MAP_FROM);
              else if (gfc_match ("release : ") == MATCH_YES)
                map_op = OMP_MAP_RELEASE;
              else if (gfc_match ("delete : ") == MATCH_YES)
@@ -2941,6 +2985,12 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask,
                             &second_close_locus);
                  break;
                }
+             if (present_modifier > 1)
+               {
+                 gfc_error ("too many %<present%> modifiers at %L",
+                            &second_present_locus);
+                 break;
+               }
 
              head = NULL;
              if (gfc_match_omp_variable_list ("", &c->lists[OMP_LIST_MAP],
@@ -3467,10 +3517,8 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask,
                continue;
            }
          else if ((mask & OMP_CLAUSE_TO)
-             && (gfc_match_omp_variable_list ("to (",
-                                             &c->lists[OMP_LIST_TO], false,
-                                             NULL, &head, true, true)
-                 == MATCH_YES))
+                  && gfc_match_motion_var_list ("to (", &c->lists[OMP_LIST_TO],
+                                                &head) == MATCH_YES)
            continue;
          break;
        case 'u':
@@ -8092,11 +8140,18 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses,
                        {
                        case OMP_MAP_TO:
                        case OMP_MAP_ALWAYS_TO:
+                       case OMP_MAP_PRESENT_TO:
+                       case OMP_MAP_ALWAYS_PRESENT_TO:
                        case OMP_MAP_FROM:
                        case OMP_MAP_ALWAYS_FROM:
+                       case OMP_MAP_PRESENT_FROM:
+                       case OMP_MAP_ALWAYS_PRESENT_FROM:
                        case OMP_MAP_TOFROM:
                        case OMP_MAP_ALWAYS_TOFROM:
+                       case OMP_MAP_PRESENT_TOFROM:
+                       case OMP_MAP_ALWAYS_PRESENT_TOFROM:
                        case OMP_MAP_ALLOC:
+                       case OMP_MAP_PRESENT_ALLOC:
                          break;
                        default:
                          gfc_error ("TARGET%s with map-type other than TO, "
@@ -8112,7 +8167,10 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses,
                        {
                        case OMP_MAP_TO:
                        case OMP_MAP_ALWAYS_TO:
+                       case OMP_MAP_PRESENT_TO:
+                       case OMP_MAP_ALWAYS_PRESENT_TO:
                        case OMP_MAP_ALLOC:
+                       case OMP_MAP_PRESENT_ALLOC:
                          break;
                        case OMP_MAP_TOFROM:
                          n->u.map_op = OMP_MAP_TO;
@@ -8120,6 +8178,12 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses,
                        case OMP_MAP_ALWAYS_TOFROM:
                          n->u.map_op = OMP_MAP_ALWAYS_TO;
                          break;
+                       case OMP_MAP_PRESENT_TOFROM:
+                         n->u.map_op = OMP_MAP_PRESENT_TO;
+                         break;
+                       case OMP_MAP_ALWAYS_PRESENT_TOFROM:
+                         n->u.map_op = OMP_MAP_ALWAYS_PRESENT_TO;
+                         break;
                        default:
                          gfc_error ("TARGET ENTER DATA with map-type other "
                                     "than TO, TOFROM or ALLOC on MAP clause "
@@ -8132,6 +8196,8 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses,
                        {
                        case OMP_MAP_FROM:
                        case OMP_MAP_ALWAYS_FROM:
+                       case OMP_MAP_PRESENT_FROM:
+                       case OMP_MAP_ALWAYS_PRESENT_FROM:
                        case OMP_MAP_RELEASE:
                        case OMP_MAP_DELETE:
                          break;
@@ -8141,6 +8207,12 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses,
                        case OMP_MAP_ALWAYS_TOFROM:
                          n->u.map_op = OMP_MAP_ALWAYS_FROM;
                          break;
+                       case OMP_MAP_PRESENT_TOFROM:
+                         n->u.map_op = OMP_MAP_PRESENT_FROM;
+                         break;
+                       case OMP_MAP_ALWAYS_PRESENT_TOFROM:
+                         n->u.map_op = OMP_MAP_ALWAYS_PRESENT_FROM;
+                         break;
                        default:
                          gfc_error ("TARGET EXIT DATA with map-type other "
                                     "than FROM, TOFROM, RELEASE, or DELETE on "
index 42b608f3d36cbf9013f89d9d313107d84bf208c4..4aa16fa88da940555a94abbb21a654eb41700d25 100644 (file)
@@ -3099,6 +3099,30 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses,
                  always_modifier = true;
                  OMP_CLAUSE_SET_MAP_KIND (node, GOMP_MAP_ALWAYS_TOFROM);
                  break;
+               case OMP_MAP_PRESENT_ALLOC:
+                 OMP_CLAUSE_SET_MAP_KIND (node, GOMP_MAP_PRESENT_ALLOC);
+                 break;
+               case OMP_MAP_PRESENT_TO:
+                 OMP_CLAUSE_SET_MAP_KIND (node, GOMP_MAP_PRESENT_TO);
+                 break;
+               case OMP_MAP_PRESENT_FROM:
+                 OMP_CLAUSE_SET_MAP_KIND (node, GOMP_MAP_PRESENT_FROM);
+                 break;
+               case OMP_MAP_PRESENT_TOFROM:
+                 OMP_CLAUSE_SET_MAP_KIND (node, GOMP_MAP_PRESENT_TOFROM);
+                 break;
+               case OMP_MAP_ALWAYS_PRESENT_TO:
+                 always_modifier = true;
+                 OMP_CLAUSE_SET_MAP_KIND (node, GOMP_MAP_ALWAYS_PRESENT_TO);
+                 break;
+               case OMP_MAP_ALWAYS_PRESENT_FROM:
+                 always_modifier = true;
+                 OMP_CLAUSE_SET_MAP_KIND (node, GOMP_MAP_ALWAYS_PRESENT_FROM);
+                 break;
+               case OMP_MAP_ALWAYS_PRESENT_TOFROM:
+                 always_modifier = true;
+                 OMP_CLAUSE_SET_MAP_KIND (node, GOMP_MAP_ALWAYS_PRESENT_TOFROM);
+                 break;
                case OMP_MAP_RELEASE:
                  OMP_CLAUSE_SET_MAP_KIND (node, GOMP_MAP_RELEASE);
                  break;
@@ -3894,6 +3918,8 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses,
                  gcc_assert (POINTER_TYPE_P (TREE_TYPE (ptr)));
                  OMP_CLAUSE_DECL (node) = build_fold_indirect_ref (ptr);
                }
+             if (n->u.present_modifier)
+               OMP_CLAUSE_MOTION_PRESENT (node) = 1;
              omp_clauses = gfc_trans_add_clause (node, omp_clauses);
            }
          break;
@@ -4435,6 +4461,9 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses,
        case OMP_DEFAULTMAP_FIRSTPRIVATE:
          behavior = OMP_CLAUSE_DEFAULTMAP_FIRSTPRIVATE;
          break;
+       case OMP_DEFAULTMAP_PRESENT:
+         behavior = OMP_CLAUSE_DEFAULTMAP_PRESENT;
+         break;
        case OMP_DEFAULTMAP_NONE: behavior = OMP_CLAUSE_DEFAULTMAP_NONE; break;
        case OMP_DEFAULTMAP_DEFAULT:
          behavior = OMP_CLAUSE_DEFAULTMAP_DEFAULT;
index 4aa6229fc7451abc011c845d41afca9e0f1da04f..91640deecea25ea3388284e3977a45f200afb883 100644 (file)
@@ -7926,6 +7926,11 @@ omp_notice_variable (struct gimplify_omp_ctx *ctx, tree decl, bool in_code)
                  else if (ctx->defaultmap[gdmk]
                           & (GOVD_MAP_0LEN_ARRAY | GOVD_FIRSTPRIVATE))
                    nflags |= ctx->defaultmap[gdmk];
+                 else if (ctx->defaultmap[gdmk] & GOVD_MAP_FORCE_PRESENT)
+                   {
+                     gcc_assert (ctx->defaultmap[gdmk] & GOVD_MAP);
+                     nflags |= ctx->defaultmap[gdmk] | GOVD_MAP_ALLOC_ONLY;
+                   }
                  else
                    {
                      gcc_assert (ctx->defaultmap[gdmk] & GOVD_MAP);
@@ -9100,6 +9105,13 @@ omp_get_attachment (omp_mapping_group *grp)
     case GOMP_MAP_FORCE_TO:
     case GOMP_MAP_FORCE_TOFROM:
     case GOMP_MAP_FORCE_PRESENT:
+    case GOMP_MAP_PRESENT_ALLOC:
+    case GOMP_MAP_PRESENT_FROM:
+    case GOMP_MAP_PRESENT_TO:
+    case GOMP_MAP_PRESENT_TOFROM:
+    case GOMP_MAP_ALWAYS_PRESENT_FROM:
+    case GOMP_MAP_ALWAYS_PRESENT_TO:
+    case GOMP_MAP_ALWAYS_PRESENT_TOFROM:
     case GOMP_MAP_ALLOC:
     case GOMP_MAP_RELEASE:
     case GOMP_MAP_DELETE:
@@ -9331,6 +9343,13 @@ omp_group_base (omp_mapping_group *grp, unsigned int *chained,
     case GOMP_MAP_FORCE_TO:
     case GOMP_MAP_FORCE_TOFROM:
     case GOMP_MAP_FORCE_PRESENT:
+    case GOMP_MAP_PRESENT_ALLOC:
+    case GOMP_MAP_PRESENT_FROM:
+    case GOMP_MAP_PRESENT_TO:
+    case GOMP_MAP_PRESENT_TOFROM:
+    case GOMP_MAP_ALWAYS_PRESENT_FROM:
+    case GOMP_MAP_ALWAYS_PRESENT_TO:
+    case GOMP_MAP_ALWAYS_PRESENT_TOFROM:
     case GOMP_MAP_ALLOC:
     case GOMP_MAP_RELEASE:
     case GOMP_MAP_DELETE:
@@ -10812,6 +10831,50 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p,
          delete grpmap;
          delete groups;
        }
+
+      /* OpenMP map clauses with 'present' need to go in front of those
+        without.  */
+      tree present_map_head = NULL;
+      tree *present_map_tail_p = &present_map_head;
+      tree *first_map_clause_p = NULL;
+
+      for (tree *c_p = list_p; *c_p; )
+       {
+         tree c = *c_p;
+         tree *next_c_p = &OMP_CLAUSE_CHAIN (c);
+
+         if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP)
+           {
+             if (!first_map_clause_p)
+               first_map_clause_p = c_p;
+             switch (OMP_CLAUSE_MAP_KIND (c))
+               {
+               case GOMP_MAP_PRESENT_ALLOC:
+               case GOMP_MAP_PRESENT_FROM:
+               case GOMP_MAP_PRESENT_TO:
+               case GOMP_MAP_PRESENT_TOFROM:
+                 next_c_p = c_p;
+                 *c_p = OMP_CLAUSE_CHAIN (c);
+
+                 OMP_CLAUSE_CHAIN (c) = NULL;
+                 *present_map_tail_p = c;
+                 present_map_tail_p = &OMP_CLAUSE_CHAIN (c);
+
+                 break;
+
+               default:
+                 break;
+               }
+           }
+
+         c_p = next_c_p;
+       }
+      if (first_map_clause_p && present_map_head)
+       {
+         tree next = *first_map_clause_p;
+         *first_map_clause_p = present_map_head;
+         *present_map_tail_p = next;
+       }
     }
   else if (region_type & ORT_ACC)
     {
@@ -11968,6 +12031,9 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p,
              case OMP_CLAUSE_DEFAULTMAP_NONE:
                ctx->defaultmap[gdmk] = 0;
                break;
+             case OMP_CLAUSE_DEFAULTMAP_PRESENT:
+               ctx->defaultmap[gdmk] = GOVD_MAP | GOVD_MAP_FORCE_PRESENT;
+               break;
              case OMP_CLAUSE_DEFAULTMAP_DEFAULT:
                switch (gdmk)
                  {
@@ -12412,6 +12478,9 @@ gimplify_adjust_omp_clauses_1 (splay_tree_node n, void *data)
        case GOVD_MAP_FORCE_PRESENT:
          kind = GOMP_MAP_FORCE_PRESENT;
          break;
+       case GOVD_MAP_FORCE_PRESENT | GOVD_MAP_ALLOC_ONLY:
+         kind = GOMP_MAP_PRESENT_ALLOC;
+         break;
        default:
          gcc_unreachable ();
        }
index 9db33d2a48bc429a66e031dbbe4037708f63de6a..1857b5b960f305afb12f998f13db6e53cd29013a 100644 (file)
@@ -1576,6 +1576,9 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
              && OMP_CLAUSE_MAP_KIND (c) != GOMP_MAP_ALWAYS_TO
              && OMP_CLAUSE_MAP_KIND (c) != GOMP_MAP_ALWAYS_FROM
              && OMP_CLAUSE_MAP_KIND (c) != GOMP_MAP_ALWAYS_TOFROM
+             && OMP_CLAUSE_MAP_KIND (c) != GOMP_MAP_ALWAYS_PRESENT_TO
+             && OMP_CLAUSE_MAP_KIND (c) != GOMP_MAP_ALWAYS_PRESENT_FROM
+             && OMP_CLAUSE_MAP_KIND (c) != GOMP_MAP_ALWAYS_PRESENT_TOFROM
              && OMP_CLAUSE_MAP_KIND (c) != GOMP_MAP_TO_PSET
              && is_global_var (maybe_lookup_decl_in_outer_ctx (decl, ctx))
              && varpool_node::get_create (decl)->offloadable
@@ -12797,6 +12800,14 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx)
          case GOMP_MAP_ALWAYS_TO:
          case GOMP_MAP_ALWAYS_FROM:
          case GOMP_MAP_ALWAYS_TOFROM:
+         case GOMP_MAP_PRESENT_ALLOC:
+         case GOMP_MAP_PRESENT_FROM:
+         case GOMP_MAP_PRESENT_TO:
+         case GOMP_MAP_PRESENT_TOFROM:
+         case GOMP_MAP_ALWAYS_PRESENT_FROM:
+         case GOMP_MAP_ALWAYS_PRESENT_TO:
+         case GOMP_MAP_ALWAYS_PRESENT_TOFROM:
+
          case GOMP_MAP_FIRSTPRIVATE_POINTER:
          case GOMP_MAP_FIRSTPRIVATE_REFERENCE:
          case GOMP_MAP_STRUCT:
@@ -13338,6 +13349,13 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx)
                    case GOMP_MAP_ALWAYS_TO:
                    case GOMP_MAP_ALWAYS_FROM:
                    case GOMP_MAP_ALWAYS_TOFROM:
+                   case GOMP_MAP_PRESENT_ALLOC:
+                   case GOMP_MAP_PRESENT_TO:
+                   case GOMP_MAP_PRESENT_FROM:
+                   case GOMP_MAP_PRESENT_TOFROM:
+                   case GOMP_MAP_ALWAYS_PRESENT_TO:
+                   case GOMP_MAP_ALWAYS_PRESENT_FROM:
+                   case GOMP_MAP_ALWAYS_PRESENT_TOFROM:
                    case GOMP_MAP_RELEASE:
                    case GOMP_MAP_FORCE_TO:
                    case GOMP_MAP_FORCE_FROM:
@@ -13377,11 +13395,15 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx)
                tkind_zero = tkind;
                break;
              case OMP_CLAUSE_TO:
-               tkind = GOMP_MAP_TO;
+               tkind
+                 = (OMP_CLAUSE_MOTION_PRESENT (c)
+                    ? GOMP_MAP_PRESENT_TO : GOMP_MAP_TO);
                tkind_zero = tkind;
                break;
              case OMP_CLAUSE_FROM:
-               tkind = GOMP_MAP_FROM;
+               tkind
+                 = (OMP_CLAUSE_MOTION_PRESENT (c)
+                    ? GOMP_MAP_PRESENT_FROM : GOMP_MAP_FROM);
                tkind_zero = tkind;
                break;
              default:
diff --git a/gcc/testsuite/c-c++-common/gomp/defaultmap-4.c b/gcc/testsuite/c-c++-common/gomp/defaultmap-4.c
new file mode 100644 (file)
index 0000000..1afff7e
--- /dev/null
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-fdump-tree-gimple" } */
+
+#define N 1000
+
+void
+foo (void)
+{
+  int a[N], b[N], c[N];
+
+  /* Should generate implicit 'map(present, alloc)' clauses.  */
+  #pragma omp target defaultmap (present: aggregate)
+    for (int i = 0; i < N; i++)
+      c[i] = a[i] + b[i];
+
+  /* Should generate implicit 'map(present, alloc)' clauses,
+     and they should go before other non-present clauses.  */
+  #pragma omp target map(from: c) defaultmap (present: aggregate)
+    for (int i = 0; i < N; i++)
+      c[i] = a[i] + b[i];
+}
+
+/* { dg-final { scan-tree-dump "pragma omp target.*defaultmap\\(present:aggregate\\) map\\(present,alloc:c \\\[len: \[0-9\]+\\\]\\\[implicit\\\]\\) map\\(present,alloc:b \\\[len: \[0-9\]+\\\]\\\[implicit\\\]\\) map\\(present,alloc:a \\\[len: \[0-9\]+\\\]\\\[implicit\\\]\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "pragma omp target.*defaultmap\\(present:aggregate\\) map\\(present,alloc:b \\\[len: \[0-9\]+\\\]\\\[implicit\\\]\\) map\\(present,alloc:a \\\[len: \[0-9\]+\\\]\\\[implicit\\\]\\) map\\(from:c \\\[len: \[0-9\]+\\\]\\)" "gimple" } } */
index 6ee59714847268f74f7acce4583d9d8af3216795..8c5b7f7cca101684cb9ca8f8861b4cb7e794c129 100644 (file)
@@ -13,10 +13,10 @@ foo (void)
   #pragma omp target map (to:a)
   ;
 
-  #pragma omp target map (a to: b) /* { dg-error "'#pragma omp target' with modifier other than 'always' or 'close'" } */
+  #pragma omp target map (a to: b) /* { dg-error "'#pragma omp target' with modifier other than 'always', 'close' or 'present'" } */
   ;
 
-  #pragma omp target map (close, a to: b) /* { dg-error "'#pragma omp target' with modifier other than 'always' or 'close'" } */
+  #pragma omp target map (close, a to: b) /* { dg-error "'#pragma omp target' with modifier other than 'always', 'close' or 'present'" } */
   ;
 
   #pragma omp target map (close a) /* { dg-error "'close' undeclared" "" { target c } } */ 
@@ -80,9 +80,56 @@ foo (void)
   #pragma omp target map (close close to:a) /* { dg-error "too many 'close' modifiers" } */
   ;
 
-  #pragma omp target map (always to : a) map (close to : b)
+  #pragma omp target map (present , present , to:a) /* { dg-error "too many 'present' modifiers" } */
   ;
 
+  #pragma omp target map (present  present , to:a) /* { dg-error "too many 'present' modifiers" } */
+  ;
+
+  #pragma omp target map (present , present  to:a) /* { dg-error "too many 'present' modifiers" } */
+  ;
+
+  #pragma omp target map (present  present  to:a) /* { dg-error "too many 'present' modifiers" } */
+  ;
+
+  #pragma omp target map (always to : a) map (close to : b) map (present,tofrom : b1) map(always,present,alloc : b2) map(close, from: b3)
+  ;
+
+  #pragma omp target data map(tofrom:b1)
+  ;
+  #pragma omp target data map(close,tofrom:b1)
+  ;
+  #pragma omp target data map(close always,tofrom:b1)
+  ;
+  #pragma omp target data map(close always,tofrom:b1)
+  ;
+  #pragma omp target data map(close present,tofrom:b1)
+  ;
+  #pragma omp target data map(close present,tofrom:b1)
+  ;
+  #pragma omp target data map(always close present,tofrom:b1)
+  ;
+  #pragma omp target data map(always close present,tofrom:b1)
+  ;
+
+  #pragma omp target enter data map(alloc: a) map(to:b) map(tofrom:b1)
+  #pragma omp target enter data map(close, alloc: a) map(close,to:b) map(close,tofrom:b1)
+  #pragma omp target enter data map(always,alloc: a) map(always,to:b) map(close always,tofrom:b1)
+  #pragma omp target enter data map(always,close,alloc: a) map(close,always,to:b) map(close always,tofrom:b1)
+  #pragma omp target enter data map(present,alloc: a) map(present,to:b) map(close present,tofrom:b1)
+  #pragma omp target enter data map(present,close,alloc: a) map(close,present,to:b) map(close present,tofrom:b1)
+  #pragma omp target enter data map(present,always,alloc: a) map(always,present,to:b) map(always close present,tofrom:b1)
+  #pragma omp target enter data map(present,always,close,alloc: a) map(close,present,always,to:b) map(always close present,tofrom:b1)
+
+  #pragma omp target exit data map(delete: a) map(release:b) map(from:b1)
+  #pragma omp target exit data map(close,delete: a) map(close,release:b) map(close,from:b1)
+  #pragma omp target exit data map(always,delete: a) map(always,release:b) map(close always,from:b1)
+  #pragma omp target exit data map(always,close,delete: a) map(close,always,release:b) map(close always,from:b1)
+  #pragma omp target exit data map(present,delete: a) map(present,release:b) map(close present,from:b1)
+  #pragma omp target exit data map(present,close,delete: a) map(close,present,release:b) map(close present,from:b1)
+  #pragma omp target exit data map(present,always,delete: a) map(always,present,release:b) map(always close present,from:b1)
+  #pragma omp target exit data map(present,always,close,delete: a) map(close,present,always,release:b) map(always close present,from:b1)
+
   int close = 0;
   #pragma omp target map (close) 
   ;
@@ -133,3 +180,20 @@ foo (void)
 /* { dg-final { scan-tree-dump "pragma omp target map\\(always,to:b5" "original" } } */
 /* { dg-final { scan-tree-dump "pragma omp target map\\(always,to:b6" "original" } } */
 /* { dg-final { scan-tree-dump "pragma omp target map\\(always,to:b7\\) map\\(always,to:close\\) map\\(always,to:always\\)" "original" } } */
+
+/* Note: 'always,alloc' is the same as 'alloc'; hence, there is no 'always' for 'b'. Additionally, 'close' is ignored. */
+
+/* { dg-final { scan-tree-dump "#pragma omp target map\\(from:b3\\) map\\(present,alloc:b2\\) map\\(present,tofrom:b1\\) map\\(to:b\\) map\\(always,to:a\\)" "original" } } */
+
+/* { dg-final { scan-tree-dump-times "#pragma omp target data map\\(tofrom:b1\\)\[\r\n\]" 2 "original" } } */
+/* { dg-final { scan-tree-dump-times "#pragma omp target data map\\(always,tofrom:b1\\)\[\r\n\]" 2 "original" } } */
+/* { dg-final { scan-tree-dump-times "#pragma omp target data map\\(present,tofrom:b1\\)\[\r\n\]" 2 "original" } } */
+/* { dg-final { scan-tree-dump-times "#pragma omp target data map\\(always,present,tofrom:b1\\)\[\r\n\]" 2 "original" } } */
+/* { dg-final { scan-tree-dump-times "#pragma omp target enter data map\\(to:b1\\) map\\(to:b\\) map\\(alloc:a\\)\[\r\n\]" 2 "original" } } */
+/* { dg-final { scan-tree-dump-times "#pragma omp target enter data map\\(always,to:b1\\) map\\(always,to:b\\) map\\(alloc:a\\)\[\r\n\]" 2 "original" } } */
+/* { dg-final { scan-tree-dump-times "#pragma omp target enter data map\\(present,to:b1\\) map\\(present,to:b\\) map\\(present,alloc:a\\)\[\r\n\]" 2 "original" } } */
+/* { dg-final { scan-tree-dump-times "#pragma omp target enter data map\\(always,present,to:b1\\) map\\(always,present,to:b\\) map\\(present,alloc:a\\)\[\r\n\]" 2 "original" } } */
+/* { dg-final { scan-tree-dump-times "#pragma omp target exit data map\\(from:b1\\) map\\(release:b\\) map\\(delete:a\\)\[\r\n\]" 2 "original" } } */
+/* { dg-final { scan-tree-dump-times "#pragma omp target exit data map\\(always,from:b1\\) map\\(release:b\\) map\\(delete:a\\)\[\r\n\]" 2 "original" } } */
+/* { dg-final { scan-tree-dump-times "#pragma omp target exit data map\\(present,from:b1\\) map\\(release:b\\) map\\(delete:a\\)\[\r\n\]" 2 "original" } } */
+/* { dg-final { scan-tree-dump-times "#pragma omp target exit data map\\(always,present,from:b1\\) map\\(release:b\\) map\\(delete:a\\)\[\r\n\]" 2 "original" } } */
diff --git a/gcc/testsuite/c-c++-common/gomp/map-9.c b/gcc/testsuite/c-c++-common/gomp/map-9.c
new file mode 100644 (file)
index 0000000..4b4bd6d
--- /dev/null
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-fdump-tree-gimple" } */
+
+#define N 1000
+
+void
+foo (void)
+{
+  int a[N], b[N], c[N];
+
+  /* Should be able to parse 'present' map modifier.  */
+  #pragma omp target enter data map (present, to: a, b)
+
+  #pragma omp target data map (present, to: a, b) map (always, present, from: c)
+
+  #pragma omp target map (present, to: a, b) map (present, from: c)
+    for (int i = 0; i < N; i++)
+      c[i] = a[i] + b[i];
+
+  #pragma omp target exit data map (always, present, from: c)
+
+  /* Map clauses with 'present' modifier should go ahead of those without.  */
+  #pragma omp target map (to: a) map (present, to: b) map (from: c)
+    for (int i = 0; i < N; i++)
+      c[i] = a[i] + b[i];
+}
+
+/* { dg-final { scan-tree-dump "pragma omp target enter data map\\(present,to:b \\\[len: \[0-9\]+\\\]\\) map\\(present,to:a \\\[len: \[0-9\]+\\\]\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "pragma omp target data map\\(present,to:b \\\[len: \[0-9\]+\\\]\\) map\\(present,to:a \\\[len: \[0-9\]+\\\]\\) map\\(always,present,from:c \\\[len: \[0-9\]+\\\]\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "pragma omp target.*map\\(present,from:c \\\[len: \[0-9\]+\\\]\\) map\\(present,to:b \\\[len: \[0-9\]+\\\]\\) map\\(present,to:a \\\[len: \[0-9\]+\\\]\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "pragma omp target exit data map\\(always,present,from:c \\\[len: \[0-9\]+\\\]\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "pragma omp target.*map\\(present,to:b \\\[len: \[0-9\]+\\\]\\) map\\(from:c \\\[len: \[0-9\]+\\\]\\) map\\(to:a \\\[len: \[0-9\]+\\\]\\)" "gimple" } } */
diff --git a/gcc/testsuite/c-c++-common/gomp/target-update-1.c b/gcc/testsuite/c-c++-common/gomp/target-update-1.c
new file mode 100644 (file)
index 0000000..4408ab7
--- /dev/null
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-fdump-tree-gimple" } */
+
+#define N 1000
+
+void
+foo (void)
+{
+  int a[N], b[N], c, d, e;
+
+  /* Should be able to parse present in to/from clauses of 'target update'.  */
+  #pragma omp target update to(c) to(present: a) from(d) from(present: b) to(e)
+}
+
+/* { dg-final { scan-tree-dump "#pragma omp target update to\\(e \\\[len: \[0-9\]+\\\]\\) from\\(present:b \\\[len: \[0-9\]+\\\]\\) from\\(d \\\[len: \[0-9\]+\\\]\\) to\\(present:a \\\[len: \[0-9\]+\\\]\\) to\\(c \\\[len: \[0-9\]+\\\]\\)" "gimple" } } */
index 299d971f23cbacfd65a4a651ea2ccb51b7b0cdcf..1f1b8528aef012cec98f9c1248e9c4452ed336ee 100644 (file)
@@ -2,7 +2,7 @@
 
 implicit none
 
-!$omp target defaultmap(bar)  ! { dg-error "25: Expected ALLOC, TO, FROM, TOFROM, FIRSTPRIVATE, NONE or DEFAULT" }
+!$omp target defaultmap(bar)  ! { dg-error "25: Expected ALLOC, TO, FROM, TOFROM, FIRSTPRIVATE, PRESENT, NONE or DEFAULT" }
 
 !$omp target defaultmap ( alloc: foo)  ! { dg-error "34: Expected SCALAR, AGGREGATE, ALLOCATABLE or POINTER" }
 
diff --git a/gcc/testsuite/gfortran.dg/gomp/defaultmap-8.f90 b/gcc/testsuite/gfortran.dg/gomp/defaultmap-8.f90
new file mode 100644 (file)
index 0000000..669a623
--- /dev/null
@@ -0,0 +1,26 @@
+! { dg-do compile }
+! { dg-additional-options "-fdump-tree-gimple" }
+
+program main
+  implicit none
+  integer, parameter :: N = 1000
+  integer :: a(N), b(N), c(N), i
+  
+  ! Should generate implicit 'map(present, alloc)' clauses.
+  !$omp target defaultmap (present: aggregate)
+    do i = 1, N
+      c(i) = a(i) + b(i)
+    end do
+  !$omp end target
+
+  ! Should generate implicit 'map(present, alloc)' clauses,
+  ! and they should go before other non-present clauses.
+  !$omp target map(from: c) defaultmap (present: aggregate)
+    do i = 1, N
+      c(i) = a(i) + b(i)
+    end do
+  !$omp end target
+end program
+  
+! { dg-final { scan-tree-dump "pragma omp target.*defaultmap\\(present:aggregate\\).*map\\(present,alloc:c \\\[len: \[0-9\]+\\\]\\\[implicit\\\]\\) map\\(present,alloc:b \\\[len: \[0-9\]+\\\]\\\[implicit\\\]\\) map\\(present,alloc:a \\\[len: \[0-9\]+\\\]\\\[implicit\\\]\\)" "gimple" } }
+! { dg-final { scan-tree-dump "pragma omp target.*map\\(present,alloc:b \\\[len: \[0-9\]+\\\]\\\[implicit\\\]\\) map\\(present,alloc:a \\\[len: \[0-9\]+\\\]\\\[implicit\\\]\\) map\\(from:c \\\[len: \[0-9\]+\\\]\\) defaultmap\\(present:aggregate\\)" "gimple" } }
diff --git a/gcc/testsuite/gfortran.dg/gomp/map-11.f90 b/gcc/testsuite/gfortran.dg/gomp/map-11.f90
new file mode 100644 (file)
index 0000000..9eb956f
--- /dev/null
@@ -0,0 +1,34 @@
+! { dg-do compile }
+! { dg-additional-options "-fdump-tree-gimple" }
+
+program main
+  implicit none
+  integer, parameter :: N = 1000
+  integer :: a(N), b(N), c(N), i
+
+  ! Should be able to parse 'present' map modifier.
+  !$omp target enter data map (present, to: a, b)
+
+  !$omp target data map (present, to: a, b) map (always, present, from: c)
+    !$omp target map (present, to: a, b) map (present, from: c)
+      do i = 1, N
+        c(i) = a(i) + b(i)
+      end do
+    !$omp end target
+  !$omp end target data
+
+  !$omp target exit data map (always, present, from: c)
+
+  ! Map clauses with 'present' modifier should go ahead of those without.
+  !$omp target map (to: a) map (present, to: b) map (from: c)
+    do i = 1, N
+      c(i) = a(i) + b(i)
+    end do
+  !$omp end target
+end program
+
+! { dg-final { scan-tree-dump "pragma omp target enter data map\\(present,to:a \\\[len: \[0-9\]+\\\]\\) map\\(present,to:b \\\[len: \[0-9\]+\\\]\\)" "gimple" } }
+! { dg-final { scan-tree-dump "pragma omp target data map\\(present,to:a \\\[len: \[0-9\]+\\\]\\) map\\(present,to:b \\\[len: \[0-9\]+\\\]\\) map\\(always,present,from:c \\\[len: \[0-9\]+\\\]\\)" "gimple" } }
+! { dg-final { scan-tree-dump "pragma omp target.*map\\(present,to:a \\\[len: \[0-9\]+\\\]\\) map\\(present,to:b \\\[len: \[0-9\]+\\\]\\) map\\(present,from:c \\\[len: \[0-9\]+\\\]\\)" "gimple" } }
+! { dg-final { scan-tree-dump "pragma omp target exit data map\\(always,present,from:c \\\[len: \[0-9\]+\\\]\\)" "gimple" } }
+! { dg-final { scan-tree-dump "pragma omp target.*map\\(present,to:b \\\[len: \[0-9\]+\\\]\\) map\\(to:a \\\[len: \[0-9\]+\\\]\\) map\\(from:c \\\[len: \[0-9\]+\\\]\\)" "gimple" } }
diff --git a/gcc/testsuite/gfortran.dg/gomp/map-12.f90 b/gcc/testsuite/gfortran.dg/gomp/map-12.f90
new file mode 100644 (file)
index 0000000..74bd01f
--- /dev/null
@@ -0,0 +1,67 @@
+! { dg-additional-options "-fdump-tree-omplower" }
+
+subroutine foo
+  implicit none
+  integer :: a, b, b1
+
+  !$omp target data map(tofrom:b1)
+    block; end block
+  !$omp target data map(close,tofrom:b1)
+    block; end block
+  !$omp target data map(close always,tofrom:b1)
+    block; end block
+  !$omp target data map(close always,tofrom:b1)
+    block; end block
+  !$omp target data map(close present,tofrom:b1)
+    block; end block
+  !$omp target data map(close present,tofrom:b1)
+    block; end block
+  !$omp target data map(always close present,tofrom:b1)
+    block; end block
+  !$omp target data map(always close present,tofrom:b1)
+    block; end block
+
+  !$omp target enter data map(alloc: a) map(to:b) map(tofrom:b1)
+  !$omp target enter data map(close, alloc: a) map(close,to:b) map(close,tofrom:b1)
+  !$omp target enter data map(always,alloc: a) map(always,to:b) map(close always,tofrom:b1)
+  !$omp target enter data map(always,close,alloc: a) map(close,always,to:b) map(close always,tofrom:b1)
+  !$omp target enter data map(present,alloc: a) map(present,to:b) map(close present,tofrom:b1)
+  !$omp target enter data map(present,close,alloc: a) map(close,present,to:b) map(close present,tofrom:b1)
+  !$omp target enter data map(present,always,alloc: a) map(always,present,to:b) map(always close present,tofrom:b1)
+  !$omp target enter data map(present,always,close,alloc: a) map(close,present,always,to:b) map(always close present,tofrom:b1)
+
+  !$omp target exit data map(delete: a) map(release:b) map(from:b1)
+  !$omp target exit data map(close,delete: a) map(close,release:b) map(close,from:b1)
+  !$omp target exit data map(always,delete: a) map(always,release:b) map(close always,from:b1)
+  !$omp target exit data map(always,close,delete: a) map(close,always,release:b) map(close always,from:b1)
+  !$omp target exit data map(present,delete: a) map(present,release:b) map(close present,from:b1)
+  !$omp target exit data map(present,close,delete: a) map(close,present,release:b) map(close present,from:b1)
+  !$omp target exit data map(present,always,delete: a) map(always,present,release:b) map(always close present,from:b1)
+  !$omp target exit data map(present,always,close,delete: a) map(close,present,always,release:b) map(always close present,from:b1)
+end subroutine
+
+
+! { dg-final { scan-tree-dump-times "#pragma omp target data map\\(tofrom:b1 \\\[len: 4\\\]\\)\[\r\n\]" 2 "omplower" } }
+! { dg-final { scan-tree-dump-times "#pragma omp target data map\\(tofrom:b1 \\\[len: 4\\\]\\)\[\r\n\]" 2 "omplower" } }
+! { dg-final { scan-tree-dump-times "#pragma omp target data map\\(always,tofrom:b1 \\\[len: 4\\\]\\)\[\r\n\]" 2 "omplower" } }
+! { dg-final { scan-tree-dump-times "#pragma omp target data map\\(always,tofrom:b1 \\\[len: 4\\\]\\)\[\r\n\]" 2 "omplower" } }
+! { dg-final { scan-tree-dump-times "#pragma omp target data map\\(present,tofrom:b1 \\\[len: 4\\\]\\)\[\r\n\]" 2 "omplower" } }
+! { dg-final { scan-tree-dump-times "#pragma omp target data map\\(present,tofrom:b1 \\\[len: 4\\\]\\)\[\r\n\]" 2 "omplower" } }
+! { dg-final { scan-tree-dump-times "#pragma omp target data map\\(always,present,tofrom:b1 \\\[len: 4\\\]\\)\[\r\n\]" 2 "omplower" } }
+! { dg-final { scan-tree-dump-times "#pragma omp target data map\\(always,present,tofrom:b1 \\\[len: 4\\\]\\)\[\r\n\]" 2 "omplower" } }
+! { dg-final { scan-tree-dump-times "#pragma omp target enter data map\\(to:b \\\[len: 4\\\]\\) map\\(to:b1 \\\[len: 4\\\]\\) map\\(alloc:a \\\[len: 4\\\]\\)\[\r\n\]" 2 "omplower" } }
+! { dg-final { scan-tree-dump-times "#pragma omp target enter data map\\(to:b \\\[len: 4\\\]\\) map\\(to:b1 \\\[len: 4\\\]\\) map\\(alloc:a \\\[len: 4\\\]\\)\[\r\n\]" 2 "omplower" } }
+! { dg-final { scan-tree-dump-times "#pragma omp target enter data map\\(always,to:b \\\[len: 4\\\]\\) map\\(always,to:b1 \\\[len: 4\\\]\\) map\\(alloc:a \\\[len: 4\\\]\\)\[\r\n\]" 2 "omplower" } }
+! { dg-final { scan-tree-dump-times "#pragma omp target enter data map\\(always,to:b \\\[len: 4\\\]\\) map\\(always,to:b1 \\\[len: 4\\\]\\) map\\(alloc:a \\\[len: 4\\\]\\)\[\r\n\]" 2 "omplower" } }
+! { dg-final { scan-tree-dump-times "#pragma omp target enter data map\\(present,alloc:a \\\[len: 4\\\]\\) map\\(present,to:b \\\[len: 4\\\]\\) map\\(present,to:b1 \\\[len: 4\\\]\\)\[\r\n\]" 2 "omplower" } }
+! { dg-final { scan-tree-dump-times "#pragma omp target enter data map\\(present,alloc:a \\\[len: 4\\\]\\) map\\(present,to:b \\\[len: 4\\\]\\) map\\(present,to:b1 \\\[len: 4\\\]\\)\[\r\n\]" 2 "omplower" } }
+! { dg-final { scan-tree-dump-times "#pragma omp target enter data map\\(present,alloc:a \\\[len: 4\\\]\\) map\\(always,present,to:b \\\[len: 4\\\]\\) map\\(always,present,to:b1 \\\[len: 4\\\]\\)\[\r\n\]" 2 "omplower" } }
+! { dg-final { scan-tree-dump-times "#pragma omp target enter data map\\(present,alloc:a \\\[len: 4\\\]\\) map\\(always,present,to:b \\\[len: 4\\\]\\) map\\(always,present,to:b1 \\\[len: 4\\\]\\)\[\r\n\]" 2 "omplower" } }
+! { dg-final { scan-tree-dump-times "#pragma omp target exit data map\\(from:b1 \\\[len: 4\\\]\\) map\\(delete:a \\\[len: 4\\\]\\) map\\(release:b \\\[len: 4\\\]\\)\[\r\n\]" 2 "omplower" } }
+! { dg-final { scan-tree-dump-times "#pragma omp target exit data map\\(from:b1 \\\[len: 4\\\]\\) map\\(delete:a \\\[len: 4\\\]\\) map\\(release:b \\\[len: 4\\\]\\)\[\r\n\]" 2 "omplower" } }
+! { dg-final { scan-tree-dump-times "#pragma omp target exit data map\\(always,from:b1 \\\[len: 4\\\]\\) map\\(delete:a \\\[len: 4\\\]\\) map\\(release:b \\\[len: 4\\\]\\)\[\r\n\]" 2 "omplower" } }
+! { dg-final { scan-tree-dump-times "#pragma omp target exit data map\\(always,from:b1 \\\[len: 4\\\]\\) map\\(delete:a \\\[len: 4\\\]\\) map\\(release:b \\\[len: 4\\\]\\)\[\r\n\]" 2 "omplower" } }
+! { dg-final { scan-tree-dump-times "#pragma omp target exit data map\\(present,from:b1 \\\[len: 4\\\]\\) map\\(delete:a \\\[len: 4\\\]\\) map\\(release:b \\\[len: 4\\\]\\)\[\r\n\]" 2 "omplower" } }
+! { dg-final { scan-tree-dump-times "#pragma omp target exit data map\\(present,from:b1 \\\[len: 4\\\]\\) map\\(delete:a \\\[len: 4\\\]\\) map\\(release:b \\\[len: 4\\\]\\)\[\r\n\]" 2 "omplower" } }
+! { dg-final { scan-tree-dump-times "#pragma omp target exit data map\\(always,present,from:b1 \\\[len: 4\\\]\\) map\\(delete:a \\\[len: 4\\\]\\) map\\(release:b \\\[len: 4\\\]\\)\[\r\n\]" 2 "omplower" } }
+! { dg-final { scan-tree-dump-times "#pragma omp target exit data map\\(always,present,from:b1 \\\[len: 4\\\]\\) map\\(delete:a \\\[len: 4\\\]\\) map\\(release:b \\\[len: 4\\\]\\)\[\r\n\]" 2 "omplower" } }
index 009c6d495472b6c3daf5dab833c2c0f218a0e50c..317090acb508a76c60fd02049956af46b8c29d42 100644 (file)
@@ -2,7 +2,7 @@
 
 implicit none
 
-integer :: a, b, close, always, to
+integer :: a, b, close, always, to, present
 
 !$omp target map(close)
 !$omp end target
@@ -10,17 +10,43 @@ integer :: a, b, close, always, to
 !$omp target map(always)
 !$omp end target
 
+!$omp target map(present)
+!$omp end target
+
 !$omp target map(always, close)
 !$omp end target
 
+!$omp target map(always, close, present)
+!$omp end target
+
 !$omp target map(always, close, to : always, close, a)
 !$omp end target
 
+!$omp target map(always, close, present, to : always, close, present, a)
+!$omp end target
+
+
 !$omp target map(to, always, close)
 !$omp end target
 
+!$omp target map(present, to, always, close)
+!$omp end target
+
+!$omp target map ( present , from : present) map(close , alloc : close) , map ( always, tofrom: always )
+!$omp end target
+
 end
 
 ! { dg-final { scan-tree-dump-not "map\\(\[^\n\r)]*close\[^\n\r)]*to:" "original" } }
-! { dg-final { scan-tree-dump "#pragma omp target map\\(always,to:always\\) map\\(always,to:close\\) map\\(always,to:a\\)" "original" } }
 ! { dg-final { scan-tree-dump-not "map\\(\[^\n\r)]*close\[^\n\r)]*to:" "original" } }
+
+! { dg-final { scan-tree-dump-times "#pragma omp target map\\(tofrom:close\\)\[\n\r]" 1 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp target map\\(tofrom:always\\)\[\n\r]" 1 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp target map\\(tofrom:present\\)\[\n\r]" 1 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp target map\\(tofrom:always\\) map\\(tofrom:close\\)\[\n\r]" 1 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp target map\\(tofrom:always\\) map\\(tofrom:close\\) map\\(tofrom:present\\)\[\n\r]" 1 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp target map\\(always,to:always\\) map\\(always,to:close\\) map\\(always,to:a\\)\[\n\r]" 1 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp target map\\(always,present,to:always\\) map\\(always,present,to:close\\) map\\(always,present,to:present\\) map\\(always,present,to:a\\)\[\n\r]" 1 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp target map\\(tofrom:to\\) map\\(tofrom:always\\) map\\(tofrom:close\\)\[\n\r]" 1 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp target map\\(tofrom:present\\) map\\(tofrom:to\\) map\\(tofrom:always\\) map\\(tofrom:close\\)\[\n\r]" 1 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp target map\\(present,from:present\\) map\\(alloc:close\\) map\\(always,tofrom:always\\)\[\n\r]" 1 "original" } }
index 92b802c67ed004a7d0db5a6f74edc92a46a1f5fa..15ebdd68b95ba25f84d4413e7588b5b60c092864 100644 (file)
@@ -28,7 +28,18 @@ integer :: a
 !$omp target map(close close to : a) ! { dg-error "too many 'close' modifiers" }
 ! !$omp end target
 
+!$omp target map(present present, to : a) ! { dg-error "too many 'present' modifiers" }
+! !$omp end target
+!$omp target map(present, present to : a) ! { dg-error "too many 'present' modifiers" }
+! !$omp end target
+!$omp target map(present present to : a) ! { dg-error "too many 'present' modifiers" }
+! !$omp end target
+
+
 !$omp target map(close close always always to : a) ! { dg-error "too many 'always' modifiers" }
 ! !$omp end target
 
+!$omp target map(present close always present to : a) ! { dg-error "too many 'present' modifiers" }
+! !$omp end target
+
 end
diff --git a/gcc/testsuite/gfortran.dg/gomp/target-update-1.f90 b/gcc/testsuite/gfortran.dg/gomp/target-update-1.f90
new file mode 100644 (file)
index 0000000..f99bffe
--- /dev/null
@@ -0,0 +1,13 @@
+! { dg-do compile }
+! { dg-additional-options "-fdump-tree-gimple" }
+
+program main
+  implicit none
+  integer, parameter :: N = 1000
+  integer :: a(N), b(N), c, d, e
+
+  ! Should be able to parse present in to/from clauses of 'target update'.
+  !$omp target update to(c) to(present: a) from(d) from(present: b) to(e)
+end program
+
+! { dg-final { scan-tree-dump "#pragma omp target update to\\(c \\\[len: \[0-9\]+\\\]\\) to\\(present:a \\\[len: \[0-9\]+\\\]\\) to\\(e \\\[len: \[0-9\]+\\\]\\) from\\(present:b \\\[len: \[0-9\]+\\\]\\) from\\(d \\\[len: \[0-9\]+\\\]\\)" "gimple" } }
index 6dd7b680b57494c73dec4e932ff7220fb6a2586c..c48a12b378f0b3086747bee43b38e2da3f90b24d 100644 (file)
@@ -572,7 +572,8 @@ enum omp_clause_defaultmap_kind {
   OMP_CLAUSE_DEFAULTMAP_NONE = 6 * (OMP_CLAUSE_DEFAULTMAP_CATEGORY_MASK + 1),
   OMP_CLAUSE_DEFAULTMAP_DEFAULT
     = 7 * (OMP_CLAUSE_DEFAULTMAP_CATEGORY_MASK + 1),
-  OMP_CLAUSE_DEFAULTMAP_MASK = 7 * (OMP_CLAUSE_DEFAULTMAP_CATEGORY_MASK + 1)
+  OMP_CLAUSE_DEFAULTMAP_PRESENT = 8 * (OMP_CLAUSE_DEFAULTMAP_CATEGORY_MASK + 1),
+  OMP_CLAUSE_DEFAULTMAP_MASK = 15 * (OMP_CLAUSE_DEFAULTMAP_CATEGORY_MASK + 1)
 };
 
 enum omp_clause_bind_kind {
index db2a58a857d5eb87bed5c5e002b0c983b68725d6..25d191b10fd7e2a7e469c415398c615cb5a32b6b 100644 (file)
@@ -991,6 +991,27 @@ dump_omp_clause (pretty_printer *pp, tree clause, int spc, dump_flags_t flags)
        case GOMP_MAP_ATTACH_ZERO_LENGTH_ARRAY_SECTION:
          pp_string (pp, "attach_zero_length_array_section");
          break;
+       case GOMP_MAP_PRESENT_ALLOC:
+         pp_string (pp, "present,alloc");
+         break;
+       case GOMP_MAP_PRESENT_TO:
+         pp_string (pp, "present,to");
+         break;
+       case GOMP_MAP_PRESENT_FROM:
+         pp_string (pp, "present,from");
+         break;
+       case GOMP_MAP_PRESENT_TOFROM:
+         pp_string (pp, "present,tofrom");
+         break;
+       case GOMP_MAP_ALWAYS_PRESENT_TO:
+         pp_string (pp, "always,present,to");
+         break;
+       case GOMP_MAP_ALWAYS_PRESENT_FROM:
+         pp_string (pp, "always,present,from");
+         break;
+       case GOMP_MAP_ALWAYS_PRESENT_TOFROM:
+         pp_string (pp, "always,present,tofrom");
+         break;
        default:
          gcc_unreachable ();
        }
@@ -1038,12 +1059,16 @@ dump_omp_clause (pretty_printer *pp, tree clause, int spc, dump_flags_t flags)
 
     case OMP_CLAUSE_FROM:
       pp_string (pp, "from(");
+      if (OMP_CLAUSE_MOTION_PRESENT (clause))
+       pp_string (pp, "present:");
       dump_generic_node (pp, OMP_CLAUSE_DECL (clause),
                         spc, flags, false);
       goto print_clause_size;
 
     case OMP_CLAUSE_TO:
       pp_string (pp, "to(");
+      if (OMP_CLAUSE_MOTION_PRESENT (clause))
+       pp_string (pp, "present:");
       dump_generic_node (pp, OMP_CLAUSE_DECL (clause),
                         spc, flags, false);
       goto print_clause_size;
@@ -1210,6 +1235,9 @@ dump_omp_clause (pretty_printer *pp, tree clause, int spc, dump_flags_t flags)
        case OMP_CLAUSE_DEFAULTMAP_NONE:
          pp_string (pp, "none");
          break;
+       case OMP_CLAUSE_DEFAULTMAP_PRESENT:
+         pp_string (pp, "present");
+         break;
        case OMP_CLAUSE_DEFAULTMAP_DEFAULT:
          pp_string (pp, "default");
          break;
index eee7d3e19cd4ccafa03c9f73528fafdcafc11f5f..1854fe4a7d4d25b0cb55ee70402d5721f8b629ba 100644 (file)
@@ -1773,6 +1773,9 @@ class auto_suppress_location_wrappers
   (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_MAP)->omp_clause.subcode.map_kind \
    = (unsigned int) (MAP_KIND))
 
+#define OMP_CLAUSE_MOTION_PRESENT(NODE) \
+  (OMP_CLAUSE_RANGE_CHECK (NODE, OMP_CLAUSE_FROM, OMP_CLAUSE_TO)->base.deprecated_flag)
+
 /* Nonzero if this map clause is for array (rather than pointer) based array
    section with zero bias.  Both the non-decl OMP_CLAUSE_MAP and corresponding
    OMP_CLAUSE_MAP with GOMP_MAP_POINTER are marked with this flag.  */
index 1b9b07dc245249a081d396b4c8b0634aa14bf523..49b7dd86ff5b09cc069411094b39f21119fe53bf 100644 (file)
@@ -42,6 +42,7 @@
 #define GOMP_MAP_FLAG_SPECIAL_2                (1 << 4)
 #define GOMP_MAP_FLAG_SPECIAL_3                (1 << 5)
 #define GOMP_MAP_FLAG_SPECIAL_4                (1 << 6)
+#define GOMP_MAP_FLAG_SPECIAL_5                (1 << 7)
 #define GOMP_MAP_FLAG_SPECIAL          (GOMP_MAP_FLAG_SPECIAL_1 \
                                         | GOMP_MAP_FLAG_SPECIAL_0)
 #define GOMP_MAP_DEEP_COPY             (GOMP_MAP_FLAG_SPECIAL_4 \
                                         | GOMP_MAP_FLAG_SPECIAL_1 \
                                         | GOMP_MAP_FLAG_SPECIAL_2 \
                                         | GOMP_MAP_FLAG_SPECIAL_3 \
-                                        | GOMP_MAP_FLAG_SPECIAL_4)
+                                        | GOMP_MAP_FLAG_SPECIAL_4 \
+                                        | GOMP_MAP_FLAG_SPECIAL_5)
 /* Flag to force a specific behavior (or else, trigger a run-time error).  */
-#define GOMP_MAP_FLAG_FORCE            (1 << 7)
+#define GOMP_MAP_FLAG_FORCE            (GOMP_MAP_FLAG_SPECIAL_5)
+#define GOMP_MAP_FLAG_PRESENT          (GOMP_MAP_FLAG_SPECIAL_5 \
+                                        | GOMP_MAP_FLAG_SPECIAL_0)
+#define GOMP_MAP_FLAG_ALWAYS_PRESENT   (GOMP_MAP_FLAG_SPECIAL_2 \
+                                        | GOMP_MAP_FLAG_PRESENT)
 
 enum gomp_map_kind
   {
@@ -130,6 +136,23 @@ enum gomp_map_kind
        device.  */
     GOMP_MAP_ALWAYS_TOFROM =           (GOMP_MAP_FLAG_SPECIAL_2
                                         | GOMP_MAP_TOFROM),
+    /* Must already be present.  */
+    GOMP_MAP_PRESENT_ALLOC =           (GOMP_MAP_FLAG_PRESENT | GOMP_MAP_ALLOC),
+    /* Must already be present, copy to device.  */
+    GOMP_MAP_PRESENT_TO =              (GOMP_MAP_FLAG_PRESENT | GOMP_MAP_TO),
+    /* Must already be present, copy from device.  */
+    GOMP_MAP_PRESENT_FROM =            (GOMP_MAP_FLAG_PRESENT | GOMP_MAP_FROM),
+    /* Must already be present, copy to and from device.  */
+    GOMP_MAP_PRESENT_TOFROM =          (GOMP_MAP_FLAG_PRESENT | GOMP_MAP_TOFROM),
+    /* Must already be present, unconditionally copy to device.  */
+    GOMP_MAP_ALWAYS_PRESENT_TO =       (GOMP_MAP_FLAG_ALWAYS_PRESENT
+                                        | GOMP_MAP_TO),
+    /* Must already be present, unconditionally copy from device.  */
+    GOMP_MAP_ALWAYS_PRESENT_FROM =     (GOMP_MAP_FLAG_ALWAYS_PRESENT
+                                        | GOMP_MAP_FROM),
+    /* Must already be present, unconditionally copy to and from device.  */
+    GOMP_MAP_ALWAYS_PRESENT_TOFROM =   (GOMP_MAP_FLAG_ALWAYS_PRESENT
+                                        | GOMP_MAP_TOFROM),
     /* Map a sparse struct; the address is the base of the structure, alignment
        it's required alignment, and size is the number of adjacent entries
        that belong to the struct.  The adjacent entries should be sorted by
@@ -186,11 +209,11 @@ enum gomp_map_kind
   };
 
 #define GOMP_MAP_COPY_TO_P(X) \
-  (!((X) & GOMP_MAP_FLAG_SPECIAL) \
+  ((!((X) & GOMP_MAP_FLAG_SPECIAL) || GOMP_MAP_PRESENT_P (X)) \
    && ((X) & GOMP_MAP_FLAG_TO))
 
 #define GOMP_MAP_COPY_FROM_P(X) \
-  (!((X) & GOMP_MAP_FLAG_SPECIAL) \
+  ((!((X) & GOMP_MAP_FLAG_SPECIAL) || GOMP_MAP_PRESENT_P (X)) \
    && ((X) & GOMP_MAP_FLAG_FROM))
 
 #define GOMP_MAP_ALWAYS_POINTER_P(X) \
@@ -201,17 +224,27 @@ enum gomp_map_kind
    || (X) == GOMP_MAP_POINTER_TO_ZERO_LENGTH_ARRAY_SECTION)
 
 #define GOMP_MAP_ALWAYS_TO_P(X) \
-  (((X) == GOMP_MAP_ALWAYS_TO) || ((X) == GOMP_MAP_ALWAYS_TOFROM))
+  (((X) == GOMP_MAP_ALWAYS_TO) || ((X) == GOMP_MAP_ALWAYS_TOFROM) \
+   || ((X) == GOMP_MAP_ALWAYS_PRESENT_TO) \
+   || ((X) == GOMP_MAP_ALWAYS_PRESENT_TOFROM))
 
 #define GOMP_MAP_ALWAYS_FROM_P(X) \
-  (((X) == GOMP_MAP_ALWAYS_FROM) || ((X) == GOMP_MAP_ALWAYS_TOFROM))
+  (((X) == GOMP_MAP_ALWAYS_FROM) || ((X) == GOMP_MAP_ALWAYS_TOFROM) \
+   || ((X) == GOMP_MAP_ALWAYS_PRESENT_FROM) \
+   || ((X) == GOMP_MAP_ALWAYS_PRESENT_TOFROM))
 
 #define GOMP_MAP_ALWAYS_P(X) \
-  (GOMP_MAP_ALWAYS_TO_P (X) || ((X) == GOMP_MAP_ALWAYS_FROM))
+  (GOMP_MAP_ALWAYS_TO_P (X) || GOMP_MAP_ALWAYS_FROM_P (X))
 
 #define GOMP_MAP_IMPLICIT_P(X) \
   (((X) & GOMP_MAP_FLAG_SPECIAL_BITS) == GOMP_MAP_IMPLICIT)
 
+#define GOMP_MAP_FORCE_P(X) \
+  (((X) & GOMP_MAP_FLAG_SPECIAL_BITS) == GOMP_MAP_FLAG_FORCE)
+
+#define GOMP_MAP_PRESENT_P(X) \
+  (((X) & GOMP_MAP_FLAG_PRESENT) == GOMP_MAP_FLAG_PRESENT)
+
 
 /* Asynchronous behavior.  Keep in sync with
    libgomp/{openacc.h,openacc.f90,openacc_lib.h}:acc_async_t.  */
index 3ea17a4cbdbfe0f709327243468b197b2579ed51..76c56a73969494312c72347fcda39db69636bf40 100644 (file)
@@ -311,7 +311,7 @@ The OpenMP 4.5 specification is fully supported.
 @item @code{inoutset} argument to the @code{depend} clause @tab Y @tab
 @item @code{private} and @code{firstprivate} argument to @code{default}
       clause in C and C++ @tab Y @tab
-@item @code{present} argument to @code{defaultmap} clause @tab N @tab
+@item @code{present} argument to @code{defaultmap} clause @tab Y @tab
 @item @code{omp_set_num_teams}, @code{omp_set_teams_thread_limit},
       @code{omp_get_max_teams}, @code{omp_get_teams_thread_limit} runtime
       routines @tab Y @tab
@@ -353,6 +353,8 @@ to address of matching mapped list item per 5.1, Sect. 2.21.7.2 @tab N @tab
 @item Optional comma between directive and clause in the @code{#pragma} form @tab Y @tab
 @item @code{indirect} clause in @code{declare target} @tab N @tab
 @item @code{device_type(nohost)}/@code{device_type(host)} for variables @tab N @tab
+@item @code{present} modifier to the @code{map}, @code{to} and @code{from}
+      clauses @tab Y @tab
 @end multitable
 
 
index 32389540accd306cc1aeaa468d6f7583bedacc75..a9e8005c5881cf6e8fb60326fc8f980ded5a0e11 100644 (file)
@@ -358,6 +358,8 @@ gomp_to_device_kind_p (int kind)
     case GOMP_MAP_FORCE_ALLOC:
     case GOMP_MAP_FORCE_FROM:
     case GOMP_MAP_ALWAYS_FROM:
+    case GOMP_MAP_PRESENT_FROM:
+    case GOMP_MAP_ALWAYS_PRESENT_FROM:
       return false;
     default:
       return true;
@@ -593,7 +595,7 @@ gomp_map_vars_existing (struct gomp_device_descr *devicep,
   else
     tgt_var->length = newn->host_end - newn->host_start;
 
-  if ((kind & GOMP_MAP_FLAG_FORCE)
+  if (GOMP_MAP_FORCE_P (kind)
       /* For implicit maps, old contained in new is valid.  */
       || !(implicit_subset
           /* Otherwise, new contained inside old is considered valid.  */
@@ -1714,6 +1716,20 @@ gomp_map_vars_internal (struct gomp_device_descr *devicep,
 #endif
                    }
                    break;
+                 case GOMP_MAP_PRESENT_ALLOC:
+                 case GOMP_MAP_PRESENT_TO:
+                 case GOMP_MAP_PRESENT_FROM:
+                 case GOMP_MAP_PRESENT_TOFROM:
+                 case GOMP_MAP_ALWAYS_PRESENT_TO:
+                 case GOMP_MAP_ALWAYS_PRESENT_FROM:
+                 case GOMP_MAP_ALWAYS_PRESENT_TOFROM:
+                   /* We already looked up the memory region above and it
+                      was missing.  */
+                   gomp_mutex_unlock (&devicep->lock);
+                   gomp_fatal ("present clause: not present on the device "
+                               "(%p, %d)",
+                               (void *) k->host_start, devicep->target_id);
+                   break;
                  case GOMP_MAP_FORCE_DEVICEPTR:
                    assert (k->host_end - k->host_start == sizeof (void *));
                    gomp_copy_host2dev (devicep, aq,
@@ -2124,6 +2140,20 @@ gomp_update (struct gomp_device_descr *devicep, size_t mapnum, void **hostaddrs,
                  gomp_copy_dev2host (devicep, NULL, hostaddr, devaddr, size);
              }
          }
+       else
+         {
+           int kind = get_kind (short_mapkind, kinds, i);
+
+           if (GOMP_MAP_PRESENT_P (kind))
+             {
+               /* We already looked up the memory region above and it
+                  was missing.  */
+               gomp_mutex_unlock (&devicep->lock);
+               gomp_fatal ("present clause: not present on the device "
+                           "(%p, %d)",
+                           (void *) hostaddrs[i], devicep->target_id);
+             }
+         }
       }
   gomp_mutex_unlock (&devicep->lock);
 }
@@ -3422,7 +3452,8 @@ gomp_target_rev (uint64_t fn_ptr, uint64_t mapnum, uint64_t devaddrs_ptr,
              case GOMP_MAP_DELETE:
              case GOMP_MAP_RELEASE:
              case GOMP_MAP_DELETE_ZERO_LEN_ARRAY_SECTION:
-               /* Assume it is present; look it up - but ignore otherwise. */
+               /* Assume it is present; look it up - but ignore unless the
+                  present clause is there. */
              case GOMP_MAP_ALLOC:
              case GOMP_MAP_FROM:
              case GOMP_MAP_FORCE_ALLOC:
@@ -3434,6 +3465,12 @@ gomp_target_rev (uint64_t fn_ptr, uint64_t mapnum, uint64_t devaddrs_ptr,
              case GOMP_MAP_FORCE_TOFROM:
              case GOMP_MAP_ALWAYS_TO:
              case GOMP_MAP_ALWAYS_TOFROM:
+             case GOMP_MAP_PRESENT_FROM:
+             case GOMP_MAP_PRESENT_TO:
+             case GOMP_MAP_PRESENT_TOFROM:
+             case GOMP_MAP_ALWAYS_PRESENT_FROM:
+             case GOMP_MAP_ALWAYS_PRESENT_TO:
+             case GOMP_MAP_ALWAYS_PRESENT_TOFROM:
              case GOMP_MAP_ZERO_LEN_ARRAY_SECTION:
                cdata[i].devaddr = devaddrs[i];
                bool zero_len = (kind == GOMP_MAP_DELETE_ZERO_LEN_ARRAY_SECTION
@@ -3454,7 +3491,23 @@ gomp_target_rev (uint64_t fn_ptr, uint64_t mapnum, uint64_t devaddrs_ptr,
                                              devaddrs[i] + sizes[i], zero_len);
                    cdata[i].present = n2 != NULL;
                  }
-               if (!cdata[i].present
+               if (!cdata[i].present && GOMP_MAP_PRESENT_P (kind))
+                 {
+                   gomp_mutex_unlock (&devicep->lock);
+#ifdef HAVE_INTTYPES_H
+                   gomp_fatal ("present clause: no corresponding data on "
+                               "parent device at %p with size %"PRIu64,
+                               (void *) (uintptr_t) devaddrs[i],
+                               (uint64_t) sizes[i]);
+#else
+                   gomp_fatal ("present clause: no corresponding data on "
+                               "parent device at %p with size %lu",
+                               (void *) (uintptr_t) devaddrs[i],
+                               (unsigned long) sizes[i]);
+#endif
+                   break;
+                 }
+               else if (!cdata[i].present
                    && kind != GOMP_MAP_DELETE
                    && kind != GOMP_MAP_RELEASE
                    && kind != GOMP_MAP_DELETE_ZERO_LEN_ARRAY_SECTION)
@@ -3472,8 +3525,7 @@ gomp_target_rev (uint64_t fn_ptr, uint64_t mapnum, uint64_t devaddrs_ptr,
                     && (kind == GOMP_MAP_TO || kind == GOMP_MAP_TOFROM))
                    || kind == GOMP_MAP_FORCE_TO
                    || kind == GOMP_MAP_FORCE_TOFROM
-                   || kind == GOMP_MAP_ALWAYS_TO
-                   || kind == GOMP_MAP_ALWAYS_TOFROM)
+                   || GOMP_MAP_ALWAYS_TO_P (kind))
                  {
                    gomp_copy_dev2host (devicep, aq,
                                        (void *) (uintptr_t) devaddrs[i],
@@ -3658,6 +3710,10 @@ gomp_target_rev (uint64_t fn_ptr, uint64_t mapnum, uint64_t devaddrs_ptr,
              case GOMP_MAP_FORCE_TOFROM:
              case GOMP_MAP_ALWAYS_FROM:
              case GOMP_MAP_ALWAYS_TOFROM:
+             case GOMP_MAP_PRESENT_FROM:
+             case GOMP_MAP_PRESENT_TOFROM:
+             case GOMP_MAP_ALWAYS_PRESENT_FROM:
+             case GOMP_MAP_ALWAYS_PRESENT_TOFROM:
                copy = true;
                /* FALLTHRU */
              case GOMP_MAP_FROM:
diff --git a/libgomp/testsuite/libgomp.c-c++-common/target-present-1.c b/libgomp/testsuite/libgomp.c-c++-common/target-present-1.c
new file mode 100644 (file)
index 0000000..12f154c
--- /dev/null
@@ -0,0 +1,27 @@
+/* { dg-do run { target offload_device } } */
+/* { dg-shouldfail "present error triggered" } */
+
+#define N 100
+
+int main (void)
+{
+  int a[N], b[N], c[N];
+
+  for (int i = 0; i < N; i++) {
+    a[i] = i * 2;
+    b[i] = i * 3 + 1;
+  }
+
+  #pragma omp target enter data map (alloc: a, c)
+    /* a has already been allocated, so this should be okay.  */
+    #pragma omp target map (present, to: a)
+      for (int i = 0; i < N; i++)
+       c[i] = a[i];
+
+    /* b has not been allocated, so this should result in an error.  */
+    /* { dg-output "libgomp: present clause: not present on the device \\\(0x\[0-9a-f\]+, \[0-9\]+\\\)" } */
+    #pragma omp target map (present, to: b)
+      for (int i = 0; i < N; i++)
+       c[i] += b[i];
+  #pragma omp target exit data map (from: c)
+}
diff --git a/libgomp/testsuite/libgomp.c-c++-common/target-present-2.c b/libgomp/testsuite/libgomp.c-c++-common/target-present-2.c
new file mode 100644 (file)
index 0000000..d4debba
--- /dev/null
@@ -0,0 +1,27 @@
+/* { dg-do run { target offload_device } } */
+/* { dg-shouldfail "present error triggered" } */
+
+#define N 100
+
+int main (void)
+{
+  int a[N], b[N], c[N];
+
+  for (int i = 0; i < N; i++) {
+    a[i] = i * 2;
+    b[i] = i * 3 + 1;
+  }
+
+  #pragma omp target enter data map (alloc: a, c)
+    /* a has already been allocated, so this should be okay.  */
+    #pragma omp target defaultmap (present)
+      for (int i = 0; i < N; i++)
+       c[i] = a[i];
+
+    /* b has not been allocated, so this should result in an error.  */
+    /* { dg-output "libgomp: present clause: not present on the device \\\(0x\[0-9a-f\]+, \[0-9\]+\\\)" } */
+    #pragma omp target defaultmap (present)
+      for (int i = 0; i < N; i++)
+       c[i] += b[i];
+  #pragma omp target exit data map (from: c)
+}
diff --git a/libgomp/testsuite/libgomp.c-c++-common/target-present-3.c b/libgomp/testsuite/libgomp.c-c++-common/target-present-3.c
new file mode 100644 (file)
index 0000000..9d8d8f8
--- /dev/null
@@ -0,0 +1,27 @@
+/* { dg-do run { target offload_device } } */
+/* { dg-shouldfail "present error triggered" } */
+
+#include <stdio.h>
+
+#define N 100
+
+int main (void)
+{
+  int a[N], b[N], c[N];
+
+  for (int i = 0; i < N; i++) {
+    a[i] = i * 2;
+    b[i] = i * 3 + 1;
+  }
+
+  #pragma omp target enter data map (alloc: a, c)
+
+  /* This should work as a has already been allocated.  */
+  #pragma omp target update to (present: a)
+
+  /* This should fail as b has not been allocated.  */
+  /* { dg-output "libgomp: present clause: not present on the device \\\(0x\[0-9a-f\]+, \[0-9\]+\\\)" } */
+  #pragma omp target update to (present: b)
+
+  #pragma omp target exit data map (from: c)
+}
diff --git a/libgomp/testsuite/libgomp.fortran/target-present-1.f90 b/libgomp/testsuite/libgomp.fortran/target-present-1.f90
new file mode 100644 (file)
index 0000000..349dcb1
--- /dev/null
@@ -0,0 +1,30 @@
+! { dg-do run { target offload_device } }
+! { dg-shouldfail "present error triggered" }
+
+program main
+  implicit none
+  integer, parameter :: N = 100
+  integer :: a(N), b(N), c(N), i
+
+  do i = 1, N
+    a(i) = i * 2
+    b(i) = i * 3 + 1
+  end do
+
+  !$omp target enter data map (alloc: a)
+    ! a has already been allocated, so this should be okay.
+    !$omp target map (present, to: a)
+      do i = 1, N
+        c(i) = a(i)
+      end do
+    !$omp end target
+
+    ! b has not been allocated, so this should result in an error.
+    ! { dg-output "libgomp: present clause: not present on the device \\\(0x\[0-9a-f\]+, \[0-9\]+\\\)" }
+    !$omp target map (present, to: b)
+      do i = 1, N
+        c(i) = c(i) + b(i)
+      end do
+    !$omp end target
+  !$omp target exit data map (from: c)
+end program
diff --git a/libgomp/testsuite/libgomp.fortran/target-present-2.f90 b/libgomp/testsuite/libgomp.fortran/target-present-2.f90
new file mode 100644 (file)
index 0000000..07e79d1
--- /dev/null
@@ -0,0 +1,30 @@
+! { dg-do run { target offload_device } }
+! { dg-shouldfail "present error triggered" }
+
+program main
+  implicit none
+  integer, parameter :: N = 100
+  integer :: a(N), b(N), c(N), i
+
+  do i = 1, N
+    a(i) = i * 2
+    b(i) = i * 3 + 1
+  end do
+
+  !$omp target enter data map (alloc: a)
+    ! a has already been allocated, so this should be okay.
+    !$omp target defaultmap (present)
+      do i = 1, N
+        c(i) = a(i)
+      end do
+    !$omp end target
+
+    ! b has not been allocated, so this should result in an error.
+    ! { dg-output "libgomp: present clause: not present on the device \\\(0x\[0-9a-f\]+, \[0-9\]+\\\)" }
+    !$omp target defaultmap (present)
+      do i = 1, N
+        c(i) = c(i) + b(i)
+      end do
+    !$omp end target
+!$omp target exit data map (from: c)
+end program
diff --git a/libgomp/testsuite/libgomp.fortran/target-present-3.f90 b/libgomp/testsuite/libgomp.fortran/target-present-3.f90
new file mode 100644 (file)
index 0000000..a2709eb
--- /dev/null
@@ -0,0 +1,22 @@
+! { dg-do run { target offload_device } }
+! { dg-shouldfail "present error triggered" }
+
+program main
+  implicit none
+  integer, parameter :: N = 100
+  integer :: a(N), b(N), c(N), i
+
+  do i = 1, N
+    a(i) = i * 2
+    b(i) = i * 3 + 1
+  end do
+
+  !$omp target enter data map (alloc: a, c)
+    ! This should work as a has already been allocated.
+    !$omp target update to (present: a)
+
+    ! This should fail as b has not been allocated.
+    ! { dg-output "libgomp: present clause: not present on the device \\\(0x\[0-9a-f\]+, \[0-9\]+\\\)" }
+    !$omp target update to (present: b)
+  !$omp target exit data map (from: c)
+end program