public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] openmp: Add support for 'present' modifier
@ 2023-02-03 13:44 Kwok Cheung Yeung
  2023-02-09 21:17 ` [OG12][committed] openmp: Add support for the " Kwok Cheung Yeung
  2023-02-17 11:45 ` [PATCHv2] openmp: Add support for " Kwok Cheung Yeung
  0 siblings, 2 replies; 13+ messages in thread
From: Kwok Cheung Yeung @ 2023-02-03 13:44 UTC (permalink / raw)
  To: Jakub Jelinek, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 1850 bytes --]

Hello

This patch implements support for the OpenMP 5.1 'present' modifier in 
C, C++ and Fortran. 'present' can be used in the 'map' clause for the 
'target', 'target data', 'target data enter' and 'target data exit' 
constructs, and the 'to'/'from' clauses of 'target update'. It can be 
used in conjunction with other modifiers too (currently only 'always' on 
map clauses).

It can also be used in defaultmap, which applies 'present, alloc' to the 
default clauses.

It behaves similarly to the OpenACC 'present' clause, and causes an 
fatal runtime error when the referenced data is not already present in 
device memory. Similarly to the OpenACC error message, the error is 
expressed in terms of the equivalent OpenMP function !omp_target_is_present.

Regarding the representation of the map kind - the bit space is getting 
a bit crowded. I have made bit 7 (GOMP_MAP_FLAG_FORCE) into another 
special bit (GOMP_MAP_FLAG_SPECIAL_5), and redefined GOMP_MAP_FLAG_FORCE 
to be GOMP_MAP_FLAG_SPECIAL_5 with no other special flags set. The 
'present' modifier is represented by setting GOMP_MAP_FLAG_SPECIAL_5 | 
GOMP_MAP_FLAG_SPECIAL_0 - this does not interfere with 'always' 
(GOMP_MAP_FLAG_SPECIAL_2) or 'implicit' (GOMP_MAP_FLAG_SPECIAL_3 | 
GOMP_MAP_FLAG_SPECIAL_4) which is used by clauses generated by defaultmap.

During gimplification of defaultmap, the present defaultmap is 
represented by setting GOVD_MAP_FORCE_PRESENT (as that is presently only 
used in OpenACC and has a similar meaning). GOVD_MAP_ALLOC ONLY will be 
added, and this is eventually lowered to a GOMP_MAP_PRESENT_ALLOC map 
kind for the default clauses.

Bootstrapped on x86-64, no regressions in GCC testsuite, libgomp tested 
with x86-64 (no offloading), AMD GCN and NVPTX offloading. This is too 
late for GCC 13 now, but will this be okay for GCC 14?

Thanks

Kwok

[-- Attachment #2: 0001-openmp-Add-support-for-the-present-modifier.patch --]
[-- Type: text/plain, Size: 69570 bytes --]

From ba9368f88514a27f374d84e53e36ce36fa9ac5bc Mon Sep 17 00:00:00 2001
From: Kwok Cheung Yeung <kcy@codesourcery.com>
Date: Fri, 3 Feb 2023 13:04:21 +0000
Subject: [PATCH] openmp: Add support for the 'present' modifier

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-02-01  Kwok Cheung Yeung  <kcy@codesourcery.com>

	gcc/c/
	* c-parser.cc (c_parser_omp_variable_list): Set default motion
	modifier.
	(c_parser_omp_var_list_parens): Add new parameter with default.  Parse
	'present' motion modifier and apply.
	(c_parser_omp_clause_defaultmap): Parse 'present' in defaultmap.
	(c_parser_omp_clause_map): Parse 'present' modifier in map clauses.
	(c_parser_omp_clause_to): Allow use of 'present' in variable list.
	(c_parser_omp_clause_from): Likewise.
	(c_parser_omp_target_data): Allow map clauses with 'present'
	modifiers.
	(c_parser_omp_target_enter_data): Likewise.
	(c_parser_omp_target_exit_data): Likewise.
	(c_parser_omp_target): Likewise.

	gcc/cp/
	* parser.cc (cp_parser_omp_var_list_no_open): Add new parameter with
	default.  Parse	'present' motion modifier and apply.
	(cp_parser_omp_clause_defaultmap): Parse 'present' in defaultmap.
	(cp_parser_omp_clause_map): Parse 'present' modifier in map clauses.
	(cp_parser_omp_all_clauses): Allow use of 'present' in 'to' and 'from'
	clauses.
	(cp_parser_omp_target_data): Allow map clauses with 'present'
	modifiers.
	(cp_parser_omp_target_enter_data): Likewise.
	(cp_parser_omp_target_exit_data): Likewise.
	* semantics.cc (finish_omp_target): Accept map clauses with 'present'
	modifiers.

	gcc/fortran/
	* gfortran.h (enum gfc_omp_map_op): Add entries with 'present'
	modifiers.
	(enum gfc_omp_motion_modifier): New.
	(struct gfc_omp_namelist): Add motion_modifier field.
	* openmp.cc (gfc_match_omp_variable_list): Add new parameter with
	default.  Parse 'present' motion modifier and apply.
	(gfc_match_omp_clauses): Parse 'present' in defaultmap, 'from'
	clauses, 'map' clauses and 'to' 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): Set GOVD flags for present defaultmaps.
	(gimplify_adjust_omp_clauses_1): Set map kind for present defaultmaps.
	(gimplify_adjust_omp_clauses): Reorder present maps to come first.
	* 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.
	(enum omp_clause_motion_modifier): New.
	(struct tree_omp_clause): Add motion_modifier field.
	* tree-pretty-print.cc (dump_omp_clause): Handle 'map', 'to' and
	'from' clauses with 'present' modifier.  Handle present defaultmap.
	* tree.h (OMP_CLAUSE_MOTION_MODIFIER): New.
	(OMP_CLAUSE_SET_MOTION_MODIFIER): New.

	gcc/testsuite/
	* c-c++-common/gomp/defaultmap-4.c: New.
	* c-c++-common/gomp/map-6.c: Update expected error messages.
	* c-c++-common/gomp/map-8.c: New.
	* c-c++-common/gomp/target-update-1.c: New.
	* gfortran.dg/gomp/defaultmap-1.f90: Update expected error messages.
	* gfortran.dg/gomp/defaultmap-8.f90: New.
	* gfortran.dg/gomp/map-9.f90: New.
	* gfortran.dg/gomp/target-update-1.f90: New.

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

	libgomp/
	* 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): Emit runtime error if memory region not
	present.
	(gomp_update): Likewise.
	(gomp_target_rev): Likewise.
	* testsuite/libgomp.c-c++-common/target-present-1.c: New.
	* testsuite/libgomp.c-c++-common/target-present-2.c: New.
	* testsuite/libgomp.c-c++-common/target-present-3.c: New.
	* testsuite/libgomp.fortran/target-present-1.f90: New.
	* testsuite/libgomp.fortran/target-present-2.f90: New.
	* testsuite/libgomp.fortran/target-present-3.f90: New.
---
 gcc/c/c-parser.cc                             | 106 ++++++++++++++++--
 gcc/cp/parser.cc                              | 103 +++++++++++++++--
 gcc/cp/semantics.cc                           |   7 ++
 gcc/fortran/gfortran.h                        |  16 ++-
 gcc/fortran/openmp.cc                         |  77 +++++++++++--
 gcc/fortran/trans-openmp.cc                   |  30 +++++
 gcc/gimplify.cc                               |  71 ++++++++++++
 gcc/omp-low.cc                                |  26 ++++-
 .../c-c++-common/gomp/defaultmap-4.c          |  24 ++++
 gcc/testsuite/c-c++-common/gomp/map-6.c       |   4 +-
 gcc/testsuite/c-c++-common/gomp/map-8.c       |  32 ++++++
 .../c-c++-common/gomp/target-update-1.c       |  15 +++
 .../gfortran.dg/gomp/defaultmap-1.f90         |   2 +-
 .../gfortran.dg/gomp/defaultmap-8.f90         |  26 +++++
 gcc/testsuite/gfortran.dg/gomp/map-9.f90      |  34 ++++++
 .../gfortran.dg/gomp/target-update-1.f90      |  13 +++
 gcc/tree-core.h                               |   9 +-
 gcc/tree-pretty-print.cc                      |  28 +++++
 gcc/tree.h                                    |   6 +
 include/gomp-constants.h                      |  47 ++++++--
 libgomp/target.c                              |  66 ++++++++++-
 .../libgomp.c-c++-common/target-present-1.c   |  27 +++++
 .../libgomp.c-c++-common/target-present-2.c   |  27 +++++
 .../libgomp.c-c++-common/target-present-3.c   |  27 +++++
 .../libgomp.fortran/target-present-1.f90      |  30 +++++
 .../libgomp.fortran/target-present-2.f90      |  30 +++++
 .../libgomp.fortran/target-present-3.f90      |  22 ++++
 27 files changed, 858 insertions(+), 47 deletions(-)
 create mode 100644 gcc/testsuite/c-c++-common/gomp/defaultmap-4.c
 create mode 100644 gcc/testsuite/c-c++-common/gomp/map-8.c
 create mode 100644 gcc/testsuite/c-c++-common/gomp/target-update-1.c
 create mode 100644 gcc/testsuite/gfortran.dg/gomp/defaultmap-8.f90
 create mode 100644 gcc/testsuite/gfortran.dg/gomp/map-9.f90
 create mode 100644 gcc/testsuite/gfortran.dg/gomp/target-update-1.f90
 create mode 100644 libgomp/testsuite/libgomp.c-c++-common/target-present-1.c
 create mode 100644 libgomp/testsuite/libgomp.c-c++-common/target-present-2.c
 create mode 100644 libgomp/testsuite/libgomp.c-c++-common/target-present-3.c
 create mode 100644 libgomp/testsuite/libgomp.fortran/target-present-1.f90
 create mode 100644 libgomp/testsuite/libgomp.fortran/target-present-2.f90
 create mode 100644 libgomp/testsuite/libgomp.fortran/target-present-3.f90

diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index 803b04b8dc1..54e35ce2583 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -14025,6 +14025,8 @@ c_parser_omp_variable_list (c_parser *parser,
 	      tree u = build_omp_clause (clause_loc, kind);
 	      OMP_CLAUSE_DECL (u) = t;
 	      OMP_CLAUSE_CHAIN (u) = list;
+	      if (kind == OMP_CLAUSE_FROM || kind == OMP_CLAUSE_TO)
+		OMP_CLAUSE_SET_MOTION_MODIFIER (u, OMP_CLAUSE_MOTION_NONE);
 	      list = u;
 	    }
 	}
@@ -14052,7 +14054,8 @@ c_parser_omp_variable_list (c_parser *parser,
 
 static tree
 c_parser_omp_var_list_parens (c_parser *parser, enum omp_clause_code kind,
-			      tree list, bool allow_deref = false)
+			      tree list, bool allow_deref = false,
+			      bool allow_present = false)
 {
   /* The clauses location.  */
   location_t loc = c_parser_peek_token (parser)->location;
@@ -14060,7 +14063,26 @@ c_parser_omp_var_list_parens (c_parser *parser, enum omp_clause_code kind,
   matching_parens parens;
   if (parens.require_open (parser))
     {
+      bool present = false;
+
+      if (allow_present)
+	{
+	   c_token *token = c_parser_peek_token (parser);
+
+	   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);
+	    }
+	}
       list = c_parser_omp_variable_list (parser, loc, kind, list, allow_deref);
+
+      if (present)
+	for (tree clause = list; clause; clause = OMP_CLAUSE_CHAIN (clause))
+	  OMP_CLAUSE_SET_MOTION_MODIFIER (clause, OMP_CLAUSE_MOTION_PRESENT);
       parens.skip_until_found_close (parser);
     }
   return list;
@@ -14944,6 +14966,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;
@@ -17114,6 +17143,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);
@@ -17145,11 +17175,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;
 	}
@@ -17161,14 +17201,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)
@@ -17429,7 +17480,8 @@ c_parser_omp_clause_device_type (c_parser *parser, tree list)
 static tree
 c_parser_omp_clause_to (c_parser *parser, tree list)
 {
-  return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_TO, list, true);
+  return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_TO, list, true,
+				       true);
 }
 
 /* OpenMP 4.0:
@@ -17438,7 +17490,8 @@ c_parser_omp_clause_to (c_parser *parser, tree list)
 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);
+  return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_FROM, list, true,
+				       true);
 }
 
 /* OpenMP 4.0:
@@ -21713,11 +21766,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:
@@ -21863,7 +21923,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:
@@ -21874,6 +21937,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:
@@ -21961,6 +22032,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;
@@ -21973,6 +22046,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:
@@ -22218,11 +22299,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:
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index b38c22e9a3d..f3b329743a0 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -37602,11 +37602,33 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind,
 
 static tree
 cp_parser_omp_var_list (cp_parser *parser, enum omp_clause_code kind, tree list,
-			bool allow_deref = false)
+			bool allow_deref = false, bool allow_present = false)
 {
   if (cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN))
-    return cp_parser_omp_var_list_no_open (parser, kind, list, NULL,
-					   allow_deref);
+    {
+      bool present = false;
+
+      if (allow_present)
+	{
+	   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);
+	    }
+	}
+
+      list = cp_parser_omp_var_list_no_open (parser, kind, list, NULL,
+					     allow_deref);
+
+      if (present)
+	for (tree clause = list; clause; clause = OMP_CLAUSE_CHAIN (clause))
+	  OMP_CLAUSE_SET_MOTION_MODIFIER (clause, OMP_CLAUSE_MOTION_PRESENT);
+    }
   return list;
 }
 
@@ -38658,6 +38680,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;
@@ -40411,6 +40440,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);
@@ -40447,11 +40477,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,
@@ -40467,15 +40510,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
@@ -41253,12 +41306,12 @@ cp_parser_omp_all_clauses (cp_parser *parser, omp_clause_mask mask,
 	    }
 	  else
 	    clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_TO, clauses,
-					      true);
+					      true, true);
 	  c_name = "to";
 	  break;
 	case PRAGMA_OMP_CLAUSE_FROM:
 	  clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_FROM, clauses,
-					    true);
+					    true, true);
 	  c_name = "from";
 	  break;
 	case PRAGMA_OMP_CLAUSE_UNIFORM:
@@ -44999,11 +45052,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:
@@ -45106,7 +45166,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:
@@ -45117,6 +45180,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:
@@ -45209,6 +45280,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;
@@ -45221,6 +45294,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:
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 1656d02d6d1..e694275ce52 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -9988,11 +9988,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:
diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h
index 9884a55882b..f2f2997876a 100644
--- a/gcc/fortran/gfortran.h
+++ b/gcc/fortran/gfortran.h
@@ -1303,7 +1303,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
@@ -1337,6 +1344,12 @@ enum gfc_omp_linear_op
   OMP_LINEAR_UVAL
 };
 
+enum gfc_omp_motion_modifier
+{
+  OMP_MOTION_NONE,
+  OMP_MOTION_PRESENT
+};
+
 /* For use in OpenMP clauses in case we need extra information
    (aligned clause alignment, linear clause step, etc.).  */
 
@@ -1355,6 +1368,7 @@ typedef struct gfc_omp_namelist
 	  ENUM_BITFIELD (gfc_omp_linear_op) op:4;
 	  bool old_modifier;
 	} linear;
+      gfc_omp_motion_modifier motion_modifier;
       struct gfc_common_head *common;
       bool lastprivate_conditional;
     } u;
diff --git a/gcc/fortran/openmp.cc b/gcc/fortran/openmp.cc
index cc1eab90b8c..e0a38284dda 100644
--- a/gcc/fortran/openmp.cc
+++ b/gcc/fortran/openmp.cc
@@ -394,7 +394,8 @@ gfc_match_omp_variable_list (const char *str, gfc_omp_namelist **list,
 			     gfc_omp_namelist ***headp = NULL,
 			     bool allow_sections = false,
 			     bool allow_derived = false,
-			     bool *has_all_memory = NULL)
+			     bool *has_all_memory = NULL,
+			     bool allow_motion_modifier = false)
 {
   gfc_omp_namelist *head, *tail, *p;
   locus old_loc, cur_loc;
@@ -402,6 +403,7 @@ gfc_match_omp_variable_list (const char *str, gfc_omp_namelist **list,
   gfc_symbol *sym;
   match m;
   gfc_symtree *st;
+  bool present = false;
 
   head = tail = NULL;
 
@@ -437,6 +439,12 @@ gfc_match_omp_variable_list (const char *str, gfc_omp_namelist **list,
 	  tail->where = cur_loc;
 	  goto next_item;
 	}
+      else if (allow_motion_modifier && m == MATCH_YES && strcmp (n, "present") == 0
+	       && gfc_match_char (':') == MATCH_YES)
+	{
+	  present = true;
+	  m = gfc_match_name (n);
+	}
       if (m == MATCH_YES)
 	{
 	  gfc_symtree *st;
@@ -537,6 +545,13 @@ gfc_match_omp_variable_list (const char *str, gfc_omp_namelist **list,
   *list = head;
   if (headp)
     *headp = list;
+
+  if (present)
+    {
+      gfc_omp_namelist *n;
+      for (n = head; n; n = n->next)
+	n->u.motion_modifier = OMP_MOTION_PRESENT;
+    }
   return MATCH_YES;
 
 syntax:
@@ -2087,6 +2102,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)
@@ -2094,7 +2111,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 ())
@@ -2520,7 +2537,8 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask,
 	  if ((mask & OMP_CLAUSE_FROM)
 	      && (gfc_match_omp_variable_list ("from (",
 					      &c->lists[OMP_LIST_FROM], false,
-					      NULL, &head, true, true)
+					      NULL, &head, true, true, NULL,
+					      true)
 		  == MATCH_YES))
 	    continue;
 	  break;
@@ -2877,6 +2895,7 @@ 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;
 
@@ -2893,20 +2912,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_close_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)
@@ -3458,7 +3495,8 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask,
 	  else if ((mask & OMP_CLAUSE_TO)
 	      && (gfc_match_omp_variable_list ("to (",
 					      &c->lists[OMP_LIST_TO], false,
-					      NULL, &head, true, true)
+					      NULL, &head, true, true, NULL,
+					      true)
 		  == MATCH_YES))
 	    continue;
 	  break;
@@ -7804,11 +7842,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, "
@@ -7824,6 +7869,8 @@ 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:
 			  break;
 			case OMP_MAP_TOFROM:
@@ -7832,6 +7879,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 "
@@ -7844,6 +7897,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;
@@ -7853,6 +7908,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 "
diff --git a/gcc/fortran/trans-openmp.cc b/gcc/fortran/trans-openmp.cc
index 87213de0918..5792fc2513e 100644
--- a/gcc/fortran/trans-openmp.cc
+++ b/gcc/fortran/trans-openmp.cc
@@ -3066,6 +3066,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;
@@ -3705,6 +3729,9 @@ 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.motion_modifier == OMP_MOTION_PRESENT)
+		OMP_CLAUSE_SET_MOTION_MODIFIER (node,
+						OMP_CLAUSE_MOTION_PRESENT);
 	      omp_clauses = gfc_trans_add_clause (node, omp_clauses);
 	    }
 	  break;
@@ -4246,6 +4273,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;
diff --git a/gcc/gimplify.cc b/gcc/gimplify.cc
index 1b362dd83e3..162136100df 100644
--- a/gcc/gimplify.cc
+++ b/gcc/gimplify.cc
@@ -7904,6 +7904,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);
@@ -9062,6 +9067,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:
@@ -9293,6 +9305,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:
@@ -11972,6 +11991,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)
 		  {
@@ -12416,6 +12438,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 ();
 	}
@@ -13102,6 +13127,52 @@ gimplify_adjust_omp_clauses (gimple_seq *pre_p, gimple_seq body, tree *list_p,
   data.pre_p = pre_p;
   splay_tree_foreach (ctx->variables, gimplify_adjust_omp_clauses_1, &data);
 
+  /* OpenMP map clauses with 'present' need to go in front of those without.  */
+  if ((gimplify_omp_ctxp->region_type & ORT_ACC) == 0)
+    {
+      tree present_map_head = NULL;
+      tree *present_map_tail_p = &present_map_head;
+      tree *first_map_clause_p = NULL;
+
+      for (tree *c_p = data.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;
+	}
+    }
+
   if (has_inscan_reductions)
     for (c = *orig_list_p; c; c = OMP_CLAUSE_CHAIN (c))
       if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LINEAR
diff --git a/gcc/omp-low.cc b/gcc/omp-low.cc
index fef41a013ec..c1ac34e5ec0 100644
--- a/gcc/omp-low.cc
+++ b/gcc/omp-low.cc
@@ -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_MODIFIER (c) == OMP_CLAUSE_MOTION_PRESENT
+		    ? GOMP_MAP_PRESENT_TO : GOMP_MAP_TO;
 		tkind_zero = tkind;
 		break;
 	      case OMP_CLAUSE_FROM:
-		tkind = GOMP_MAP_FROM;
+		tkind
+		  = OMP_CLAUSE_MOTION_MODIFIER (c) == OMP_CLAUSE_MOTION_PRESENT
+		    ? 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
index 00000000000..1afff7ea38f
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/defaultmap-4.c
@@ -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" } } */
diff --git a/gcc/testsuite/c-c++-common/gomp/map-6.c b/gcc/testsuite/c-c++-common/gomp/map-6.c
index 6ee59714847..b4683ddbabf 100644
--- a/gcc/testsuite/c-c++-common/gomp/map-6.c
+++ b/gcc/testsuite/c-c++-common/gomp/map-6.c
@@ -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 } } */ 
diff --git a/gcc/testsuite/c-c++-common/gomp/map-8.c b/gcc/testsuite/c-c++-common/gomp/map-8.c
new file mode 100644
index 00000000000..4b4bd6d2aa3
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/map-8.c
@@ -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
index 00000000000..0233fe5a7af
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/target-update-1.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-fdump-tree-gimple" } */
+
+#define N 1000
+
+void
+foo (void)
+{
+  int a[N], b[N];
+
+  /* Should be able to parse present in to/from clauses of 'target update'.  */
+  #pragma omp target update to(present: a) from(present: b)
+}
+
+/* { dg-final { scan-tree-dump "pragma omp target update from\\(present:b \\\[len: \[0-9\]+\\\]\\) to\\(present:a \\\[len: \[0-9\]+\\\]\\)" "gimple" } } */
diff --git a/gcc/testsuite/gfortran.dg/gomp/defaultmap-1.f90 b/gcc/testsuite/gfortran.dg/gomp/defaultmap-1.f90
index 299d971f23c..1f1b8528aef 100644
--- a/gcc/testsuite/gfortran.dg/gomp/defaultmap-1.f90
+++ b/gcc/testsuite/gfortran.dg/gomp/defaultmap-1.f90
@@ -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
index 00000000000..669a623f746
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/defaultmap-8.f90
@@ -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-9.f90 b/gcc/testsuite/gfortran.dg/gomp/map-9.f90
new file mode 100644
index 00000000000..cc87212f8d0
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/map-9.f90
@@ -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/target-update-1.f90 b/gcc/testsuite/gfortran.dg/gomp/target-update-1.f90
new file mode 100644
index 00000000000..a382b87f229
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/target-update-1.f90
@@ -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), i
+
+  ! Should be able to parse present in to/from clauses of 'target update'.
+  !$omp target update to(present: a) from(present: b)
+end program
+
+! { dg-final { scan-tree-dump "pragma omp target update to\\(present:a \\\[len: \[0-9\]+\\\]\\) from\\(present:b \\\[len: \[0-9\]+\\\]\\)" "gimple" } }
diff --git a/gcc/tree-core.h b/gcc/tree-core.h
index 8124a1328d4..45a01a890b7 100644
--- a/gcc/tree-core.h
+++ b/gcc/tree-core.h
@@ -573,7 +573,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 {
@@ -582,6 +583,11 @@ enum omp_clause_bind_kind {
   OMP_CLAUSE_BIND_THREAD
 };
 
+enum omp_clause_motion_modifier {
+  OMP_CLAUSE_MOTION_NONE,
+  OMP_CLAUSE_MOTION_PRESENT
+};
+
 /* memory-order-clause on OpenMP atomic/flush constructs or
    argument of atomic_default_mem_order clause.  */
 enum omp_memory_order {
@@ -1646,6 +1652,7 @@ struct GTY(()) tree_omp_clause {
     enum omp_clause_defaultmap_kind defaultmap_kind;
     enum omp_clause_bind_kind      bind_kind;
     enum omp_clause_device_type_kind device_type_kind;
+    enum omp_clause_motion_modifier motion_modifier;
   } GTY ((skip)) subcode;
 
   /* The gimplification of OMP_CLAUSE_REDUCTION_{INIT,MERGE} for omp-low's
diff --git a/gcc/tree-pretty-print.cc b/gcc/tree-pretty-print.cc
index 7947f9647a1..99f8acc3acc 100644
--- a/gcc/tree-pretty-print.cc
+++ b/gcc/tree-pretty-print.cc
@@ -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_MODIFIER (clause) == OMP_CLAUSE_MOTION_PRESENT)
+	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_MODIFIER (clause) == OMP_CLAUSE_MOTION_PRESENT)
+	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;
diff --git a/gcc/tree.h b/gcc/tree.h
index e730a2a3e56..f256cb41733 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -1742,6 +1742,12 @@ 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_MODIFIER(NODE) \
+  ((enum omp_clause_motion_modifier) OMP_CLAUSE_RANGE_CHECK (NODE, OMP_CLAUSE_FROM, OMP_CLAUSE_TO)->omp_clause.subcode.motion_modifier)
+#define OMP_CLAUSE_SET_MOTION_MODIFIER(NODE, MOTION_MODIFIER) \
+  (OMP_CLAUSE_RANGE_CHECK (NODE, OMP_CLAUSE_FROM, OMP_CLAUSE_TO)->omp_clause.subcode.motion_modifier \
+   = (MOTION_MODIFIER))
+
 /* 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.  */
diff --git a/include/gomp-constants.h b/include/gomp-constants.h
index 3f72a15ef55..44cb0bbb994 100644
--- a/include/gomp-constants.h
+++ b/include/gomp-constants.h
@@ -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 \
@@ -55,9 +56,14 @@
 					 | 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.  */
diff --git a/libgomp/target.c b/libgomp/target.c
index b16ee761a95..3af6402cc83 100644
--- a/libgomp/target.c
+++ b/libgomp/target.c
@@ -360,6 +360,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;
@@ -592,7 +594,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.  */
@@ -1707,6 +1709,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: !omp_target_is_present "
+				"(%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,
@@ -2116,6 +2132,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: !omp_target_is_present "
+			    "(%p, %d)",
+			    (void *) hostaddrs[i], devicep->target_id);
+	      }
+	  }
       }
   gomp_mutex_unlock (&devicep->lock);
 }
@@ -3424,7 +3454,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:
@@ -3436,6 +3467,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
@@ -3456,7 +3493,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 *) devaddrs[i],
+				(uint64_t) sizes[i]);
+#else
+		    gomp_fatal ("present clause: no corresponding data on "
+				"parent device at %p with size %lu",
+				(void *) 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)
@@ -3474,8 +3527,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))
 		  {
 		    if (dev_to_host_cpy)
 		      dev_to_host_cpy ((void *) (uintptr_t) devaddrs[i],
@@ -3654,6 +3706,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
index 00000000000..bbc4559b12e
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c-c++-common/target-present-1.c
@@ -0,0 +1,27 @@
+/* { dg-do run { target offload_target_any } } */
+/* { 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: !omp_target_is_present \\\(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
index 00000000000..6259c959c04
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c-c++-common/target-present-2.c
@@ -0,0 +1,27 @@
+/* { dg-do run { target offload_target_any } } */
+/* { 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: !omp_target_is_present \\\(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
index 00000000000..89e648645b2
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c-c++-common/target-present-3.c
@@ -0,0 +1,27 @@
+/* { dg-do run { target offload_target_any } } */
+/* { 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: !omp_target_is_present \\\(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
index 00000000000..80046011b25
--- /dev/null
+++ b/libgomp/testsuite/libgomp.fortran/target-present-1.f90
@@ -0,0 +1,30 @@
+! { dg-do run { target offload_target_any } }
+! { 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: !omp_target_is_present \\\(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
index 00000000000..0a38dea1e41
--- /dev/null
+++ b/libgomp/testsuite/libgomp.fortran/target-present-2.f90
@@ -0,0 +1,30 @@
+! { dg-do run { target offload_target_any } }
+! { 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: !omp_target_is_present \\\(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
index 00000000000..c4deb8652d1
--- /dev/null
+++ b/libgomp/testsuite/libgomp.fortran/target-present-3.f90
@@ -0,0 +1,22 @@
+! { dg-do run { target offload_target_any } }
+! { 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: !omp_target_is_present \\\(0x\[0-9a-f\]+, \[0-9\]+\\\)" }
+    !$omp target update to (present: b)
+  !$omp target exit data map (from: c)
+end program
-- 
2.34.1


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [OG12][committed] openmp: Add support for the 'present' modifier
@ 2023-02-09 21:17 ` Kwok Cheung Yeung
  2023-02-14 22:44   ` [og12] Address cast to pointer from integer of different size in 'libgomp/target.c:gomp_target_rev' (was: [OG12][committed] openmp: Add support for the 'present' modifier) Thomas Schwinge
                     ` (3 more replies)
  0 siblings, 4 replies; 13+ messages in thread
From: Kwok Cheung Yeung @ 2023-02-09 21:17 UTC (permalink / raw)
  To: gcc-patches

Hello

I've ported my patch for supporting the OpenMP 5.1 'present' modifier 
and committed it to the devel/omp/gcc-12 development branch:

229b705862c openmp: Add support for the 'present' modifier

Tested with offloading on amdgcn and nvptx.

Kwok

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [og12] Address cast to pointer from integer of different size in 'libgomp/target.c:gomp_target_rev' (was: [OG12][committed] openmp: Add support for the 'present' modifier)
  2023-02-09 21:17 ` [OG12][committed] openmp: Add support for the " Kwok Cheung Yeung
@ 2023-02-14 22:44   ` Thomas Schwinge
  2023-02-15  0:00   ` [OG12][committed] openmp: Add support for the 'present' modifier Kwok Cheung Yeung
                     ` (2 subsequent siblings)
  3 siblings, 0 replies; 13+ messages in thread
From: Thomas Schwinge @ 2023-02-14 22:44 UTC (permalink / raw)
  To: Kwok Cheung Yeung, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 1054 bytes --]

Hi!

On 2023-02-09T21:17:44+0000, Kwok Cheung Yeung <kcy@codesourcery.com> wrote:
> I've ported my patch for supporting the OpenMP 5.1 'present' modifier
> and committed it to the devel/omp/gcc-12 development branch:
>
> 229b705862c openmp: Add support for the 'present' modifier
>
> Tested with offloading on amdgcn and nvptx.

I've pushed to devel/omp/gcc-12 branch
commit cd377354c5faa326bdfa5f10e4193c1d1a686801
"Address cast to pointer from integer of different size in 'libgomp/target.c:gomp_target_rev'",
see attached.


Note that this likewise applies to the current upstream submission:
<https://inbox.sourceware.org/gcc-patches/6eb5d0dd-da2a-6d8e-eaa2-d14bf708cf36@codesourcery.com>
"openmp: Add support for 'present' modifier".


Grüße
 Thomas


-----------------
Siemens Electronic Design Automation GmbH; Anschrift: Arnulfstraße 201, 80634 München; Gesellschaft mit beschränkter Haftung; Geschäftsführer: Thomas Heurung, Frank Thürauf; Sitz der Gesellschaft: München; Registergericht München, HRB 106955

[-- Attachment #2: 0001-Address-cast-to-pointer-from-integer-of-different-si.patch --]
[-- Type: text/x-diff, Size: 2259 bytes --]

From cd377354c5faa326bdfa5f10e4193c1d1a686801 Mon Sep 17 00:00:00 2001
From: Thomas Schwinge <thomas@codesourcery.com>
Date: Tue, 14 Feb 2023 23:34:45 +0100
Subject: [PATCH] Address cast to pointer from integer of different size in
 'libgomp/target.c:gomp_target_rev'
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

For example, for '-m32' multilib of x86_64-pc-linux-gnu:

    [...]/libgomp/target.c: In function ‘gomp_target_rev’:
    [...]/libgomp/target.c:3699:33: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast]
     3699 |                                 (void *) devaddrs[i],
          |                                 ^

Fix-up for recent og12 commit 229b705862c1d7f9634f72272b77c22970baf821
"openmp: Add support for the 'present' modifier".

	libgomp/
	* target.c (gomp_target_rev): Address cast to pointer from integer
	of different size.
---
 libgomp/ChangeLog.omp | 5 +++++
 libgomp/target.c      | 4 ++--
 2 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/libgomp/ChangeLog.omp b/libgomp/ChangeLog.omp
index 484367d9975..67065f59922 100644
--- a/libgomp/ChangeLog.omp
+++ b/libgomp/ChangeLog.omp
@@ -1,3 +1,8 @@
+2023-02-14  Thomas Schwinge  <thomas@codesourcery.com>
+
+	* target.c (gomp_target_rev): Address cast to pointer from integer
+	of different size.
+
 2023-02-09  Kwok Cheung Yeung  <kcy@codesourcery.com>
 
 	* target.c (gomp_to_device_kind_p): Add map kinds with 'present'
diff --git a/libgomp/target.c b/libgomp/target.c
index 426383a451b..6edfc9214e4 100644
--- a/libgomp/target.c
+++ b/libgomp/target.c
@@ -3696,12 +3696,12 @@ gomp_target_rev (uint64_t fn_ptr, uint64_t mapnum, uint64_t devaddrs_ptr,
 #ifdef HAVE_INTTYPES_H
 		    gomp_fatal ("present clause: no corresponding data on "
 				"parent device at %p with size %"PRIu64,
-				(void *) devaddrs[i],
+				(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 *) devaddrs[i],
+				(void *) (uintptr_t) devaddrs[i],
 				(unsigned long) sizes[i]);
 #endif
 		    break;
-- 
2.25.1


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [OG12][committed] openmp: Add support for the 'present' modifier
  2023-02-09 21:17 ` [OG12][committed] openmp: Add support for the " Kwok Cheung Yeung
  2023-02-14 22:44   ` [og12] Address cast to pointer from integer of different size in 'libgomp/target.c:gomp_target_rev' (was: [OG12][committed] openmp: Add support for the 'present' modifier) Thomas Schwinge
@ 2023-02-15  0:00   ` Kwok Cheung Yeung
  2023-02-15 19:02   ` [og12] Fix 'libgomp.{c-c++-common,fortran}/target-present-*' test cases (was: [OG12][committed] openmp: Add support for the 'present' modifier) Thomas Schwinge
  2023-06-12 16:44   ` [committed] OpenMP: Cleanups related to the 'present' modifier Tobias Burnus
  3 siblings, 0 replies; 13+ messages in thread
From: Kwok Cheung Yeung @ 2023-02-15  0:00 UTC (permalink / raw)
  To: gcc-patches, tobias

[-- Attachment #1: Type: text/plain, Size: 223 bytes --]

Hi

I have also committed the following patch to devel/omp/gcc-12 to show 
the 'present' modifier in the Fortran parse tree dump.

e7279cc2eda openmp: Add support for 'present' modifier in the Fortran 
parse tree dump

Kwok

[-- Attachment #2: 0001-openmp-Add-support-for-present-modifier-in-the-Fortr.patch --]
[-- Type: text/plain, Size: 3001 bytes --]

From e7279cc2eda2a0c50cff19ee4e02eea3d7808f68 Mon Sep 17 00:00:00 2001
From: Kwok Cheung Yeung <kcy@codesourcery.com>
Date: Tue, 14 Feb 2023 21:24:19 +0000
Subject: [PATCH] openmp: Add support for 'present' modifier in the Fortran
 parse tree dump

2023-02-14  Kwok Cheung Yeung  <kcy@codesourcery.com>

	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.
---
 gcc/fortran/ChangeLog.omp      |  7 +++++++
 gcc/fortran/dump-parse-tree.cc | 15 +++++++++++++++
 2 files changed, 22 insertions(+)

diff --git a/gcc/fortran/ChangeLog.omp b/gcc/fortran/ChangeLog.omp
index 44bc0ea1e2a..579d8ee7c97 100644
--- a/gcc/fortran/ChangeLog.omp
+++ b/gcc/fortran/ChangeLog.omp
@@ -1,3 +1,10 @@
+2023-02-14  Kwok Cheung Yeung  <kcy@codesourcery.com>
+
+	* dump-parse-tree.cc (show_omp_namelist): Display 'present' map
+	modifier.
+	(show_omp_clauses): Display 'present' motion modifier for 'to'
+	and 'from' clauses.
+
 2023-02-09  Kwok Cheung Yeung  <kcy@codesourcery.com>
 
 	* gfortran.h (enum gfc_omp_map_op): Add entries with 'present'
diff --git a/gcc/fortran/dump-parse-tree.cc b/gcc/fortran/dump-parse-tree.cc
index 4da4d813d1d..7dad3ac0307 100644
--- a/gcc/fortran/dump-parse-tree.cc
+++ b/gcc/fortran/dump-parse-tree.cc
@@ -1453,9 +1453,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,10 @@ 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.motion_modifier
+	       == OMP_MOTION_PRESENT)
+	  fputs ("present:", dumpfile);
 	show_omp_namelist (list_type, omp_clauses->lists[list_type]);
 	fputc (')', dumpfile);
       }
-- 
2.34.1


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [og12] Fix 'libgomp.{c-c++-common,fortran}/target-present-*' test cases (was: [OG12][committed] openmp: Add support for the 'present' modifier)
  2023-02-09 21:17 ` [OG12][committed] openmp: Add support for the " Kwok Cheung Yeung
  2023-02-14 22:44   ` [og12] Address cast to pointer from integer of different size in 'libgomp/target.c:gomp_target_rev' (was: [OG12][committed] openmp: Add support for the 'present' modifier) Thomas Schwinge
  2023-02-15  0:00   ` [OG12][committed] openmp: Add support for the 'present' modifier Kwok Cheung Yeung
@ 2023-02-15 19:02   ` Thomas Schwinge
  2023-06-07 11:25     ` [committed] testsuite/libgomp.*/target-present-*.{c,f90}: Improve and fix (was: Re: [og12] Fix 'libgomp.{c-c++-common,fortran}/target-present-*' test cases) Tobias Burnus
  2023-06-07 11:26     ` Tobias Burnus
  2023-06-12 16:44   ` [committed] OpenMP: Cleanups related to the 'present' modifier Tobias Burnus
  3 siblings, 2 replies; 13+ messages in thread
From: Thomas Schwinge @ 2023-02-15 19:02 UTC (permalink / raw)
  To: Kwok Cheung Yeung, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 1026 bytes --]

Hi!

On 2023-02-09T21:17:44+0000, Kwok Cheung Yeung <kcy@codesourcery.com> wrote:
> I've ported my patch for supporting the OpenMP 5.1 'present' modifier
> and committed it to the devel/omp/gcc-12 development branch:
>
> 229b705862c openmp: Add support for the 'present' modifier
>
> Tested with offloading on amdgcn and nvptx.

I've pushed to devel/omp/gcc-12 branch
commit bbda035ee62ba4db21356136c97e9d83a97ba7d1
"Fix 'libgomp.{c-c++-common,fortran}/target-present-*' test cases",
see attached.


Note that this likewise applies to the current upstream submission:
<https://inbox.sourceware.org/gcc-patches/6eb5d0dd-da2a-6d8e-eaa2-d14bf708cf36@codesourcery.com>
"openmp: Add support for 'present' modifier".


Grüße
 Thomas


-----------------
Siemens Electronic Design Automation GmbH; Anschrift: Arnulfstraße 201, 80634 München; Gesellschaft mit beschränkter Haftung; Geschäftsführer: Thomas Heurung, Frank Thürauf; Sitz der Gesellschaft: München; Registergericht München, HRB 106955

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Fix-libgomp.-c-c-common-fortran-target-present-test-.patch --]
[-- Type: text/x-diff, Size: 11213 bytes --]

From bbda035ee62ba4db21356136c97e9d83a97ba7d1 Mon Sep 17 00:00:00 2001
From: Thomas Schwinge <thomas@codesourcery.com>
Date: Wed, 15 Feb 2023 12:39:19 +0100
Subject: [PATCH] Fix 'libgomp.{c-c++-common,fortran}/target-present-*' test
 cases

Their execution isn't expected to error out if we've been *compiling for any
offload target*, but rather if they're *executing on a non-shared memory
offload device*.  For example, if (any) offloading is configured but not
effective (no device available, for example), you'd get:

    PASS: libgomp.c/../libgomp.c-c++-common/target-present-1.c (test for excess errors)
    FAIL: libgomp.c/../libgomp.c-c++-common/target-present-1.c execution test
    PASS: libgomp.c/../libgomp.c-c++-common/target-present-2.c (test for excess errors)
    FAIL: libgomp.c/../libgomp.c-c++-common/target-present-2.c execution test
    PASS: libgomp.c/../libgomp.c-c++-common/target-present-3.c (test for excess errors)
    FAIL: libgomp.c/../libgomp.c-c++-common/target-present-3.c execution test

    PASS: libgomp.c++/../libgomp.c-c++-common/target-present-1.c (test for excess errors)
    FAIL: libgomp.c++/../libgomp.c-c++-common/target-present-1.c execution test
    PASS: libgomp.c++/../libgomp.c-c++-common/target-present-2.c (test for excess errors)
    FAIL: libgomp.c++/../libgomp.c-c++-common/target-present-2.c execution test
    PASS: libgomp.c++/../libgomp.c-c++-common/target-present-3.c (test for excess errors)
    FAIL: libgomp.c++/../libgomp.c-c++-common/target-present-3.c execution test

    PASS: libgomp.fortran/target-present-1.f90   -O0  (test for excess errors)
    FAIL: libgomp.fortran/target-present-1.f90   -O0  execution test
    [...]
    PASS: libgomp.fortran/target-present-2.f90   -O0  (test for excess errors)
    FAIL: libgomp.fortran/target-present-2.f90   -O0  execution test
    [...]
    PASS: libgomp.fortran/target-present-3.f90   -O0  (test for excess errors)
    FAIL: libgomp.fortran/target-present-3.f90   -O0  execution test
    [...]

Also, verify reaching a checkpoint before the expected error condition -- and
fix up one case where that didn't happen; missing OpenMP 'map' clauses
('libgomp.fortran/target-present-2.f90').

Fix-up for recent og12 commit 229b705862c1d7f9634f72272b77c22970baf821
"openmp: Add support for the 'present' modifier"

	libgomp/
	* testsuite/libgomp.c-c++-common/target-present-1.c: Fix.
	* testsuite/libgomp.c-c++-common/target-present-2.c: Likewise.
	* testsuite/libgomp.c-c++-common/target-present-3.c: Likewise.
	* testsuite/libgomp.fortran/target-present-1.f90: Likewise.
	* testsuite/libgomp.fortran/target-present-2.f90: Likewise.
	* testsuite/libgomp.fortran/target-present-3.f90: Likewise.
---
 libgomp/ChangeLog.omp                               |  9 +++++++++
 .../libgomp.c-c++-common/target-present-1.c         |  9 ++++++---
 .../libgomp.c-c++-common/target-present-2.c         | 11 +++++++----
 .../libgomp.c-c++-common/target-present-3.c         |  9 +++++----
 .../testsuite/libgomp.fortran/target-present-1.f90  |  9 ++++++---
 .../testsuite/libgomp.fortran/target-present-2.f90  | 13 ++++++++-----
 .../testsuite/libgomp.fortran/target-present-3.f90  |  9 ++++++---
 7 files changed, 47 insertions(+), 22 deletions(-)

diff --git a/libgomp/ChangeLog.omp b/libgomp/ChangeLog.omp
index b638cdbb41e..5257ee00e0c 100644
--- a/libgomp/ChangeLog.omp
+++ b/libgomp/ChangeLog.omp
@@ -1,3 +1,12 @@
+2023-02-15  Thomas Schwinge  <thomas@codesourcery.com>
+
+	* testsuite/libgomp.c-c++-common/target-present-1.c: Fix.
+	* testsuite/libgomp.c-c++-common/target-present-2.c: Likewise.
+	* testsuite/libgomp.c-c++-common/target-present-3.c: Likewise.
+	* testsuite/libgomp.fortran/target-present-1.f90: Likewise.
+	* testsuite/libgomp.fortran/target-present-2.f90: Likewise.
+	* testsuite/libgomp.fortran/target-present-3.f90: Likewise.
+
 2023-02-15  Tobias Burnus  <tobias@codesourcery.com>
 
 	Backported from master:
diff --git a/libgomp/testsuite/libgomp.c-c++-common/target-present-1.c b/libgomp/testsuite/libgomp.c-c++-common/target-present-1.c
index bbc4559b12e..55aecd1c8d1 100644
--- a/libgomp/testsuite/libgomp.c-c++-common/target-present-1.c
+++ b/libgomp/testsuite/libgomp.c-c++-common/target-present-1.c
@@ -1,5 +1,4 @@
-/* { dg-do run { target offload_target_any } } */
-/* { dg-shouldfail "present error triggered" } */
+#include <stdio.h>
 
 #define N 100
 
@@ -18,8 +17,12 @@ int main (void)
       for (int i = 0; i < N; i++)
 	c[i] = a[i];
 
+    fprintf (stderr, "CheCKpOInT\n");
+    /* { dg-output "CheCKpOInT(\n|\r\n|\r).*" } */
+
     /* b has not been allocated, so this should result in an error.  */
-    /* { dg-output "libgomp: present clause: !omp_target_is_present \\\(0x\[0-9a-f\]+, \[0-9\]+\\\)" } */
+    /* { dg-output "libgomp: present clause: !omp_target_is_present \\\(0x\[0-9a-f\]+, \[0-9\]+\\\)" { target offload_device_nonshared_as } }
+       { dg-shouldfail "present error triggered" { offload_device_nonshared_as } } */
     #pragma omp target map (present, to: b)
       for (int i = 0; i < N; i++)
 	c[i] += b[i];
diff --git a/libgomp/testsuite/libgomp.c-c++-common/target-present-2.c b/libgomp/testsuite/libgomp.c-c++-common/target-present-2.c
index 6259c959c04..1ce919e62ce 100644
--- a/libgomp/testsuite/libgomp.c-c++-common/target-present-2.c
+++ b/libgomp/testsuite/libgomp.c-c++-common/target-present-2.c
@@ -1,5 +1,4 @@
-/* { dg-do run { target offload_target_any } } */
-/* { dg-shouldfail "present error triggered" } */
+#include <stdio.h>
 
 #define N 100
 
@@ -13,13 +12,17 @@ int main (void)
   }
 
   #pragma omp target enter data map (alloc: a, c)
-    /* a has already been allocated, so this should be okay.  */
+    /* a, c have already been allocated, so this should be okay.  */
     #pragma omp target defaultmap (present)
       for (int i = 0; i < N; i++)
 	c[i] = a[i];
 
+    fprintf (stderr, "CheCKpOInT\n");
+    /* { dg-output "CheCKpOInT(\n|\r\n|\r).*" } */
+
     /* b has not been allocated, so this should result in an error.  */
-    /* { dg-output "libgomp: present clause: !omp_target_is_present \\\(0x\[0-9a-f\]+, \[0-9\]+\\\)" } */
+    /* { dg-output "libgomp: present clause: !omp_target_is_present \\\(0x\[0-9a-f\]+, \[0-9\]+\\\)" { target offload_device_nonshared_as } }
+       { dg-shouldfail "present error triggered" { offload_device_nonshared_as } } */
     #pragma omp target defaultmap (present)
       for (int i = 0; i < N; i++)
 	c[i] += b[i];
diff --git a/libgomp/testsuite/libgomp.c-c++-common/target-present-3.c b/libgomp/testsuite/libgomp.c-c++-common/target-present-3.c
index 89e648645b2..886969c4c4a 100644
--- a/libgomp/testsuite/libgomp.c-c++-common/target-present-3.c
+++ b/libgomp/testsuite/libgomp.c-c++-common/target-present-3.c
@@ -1,6 +1,3 @@
-/* { dg-do run { target offload_target_any } } */
-/* { dg-shouldfail "present error triggered" } */
-
 #include <stdio.h>
 
 #define N 100
@@ -19,8 +16,12 @@ int main (void)
   /* This should work as a has already been allocated.  */
   #pragma omp target update to (present: a)
 
+  fprintf (stderr, "CheCKpOInT\n");
+  /* { dg-output "CheCKpOInT(\n|\r\n|\r).*" } */
+
   /* This should fail as b has not been allocated.  */
-  /* { dg-output "libgomp: present clause: !omp_target_is_present \\\(0x\[0-9a-f\]+, \[0-9\]+\\\)" } */
+  /* { dg-output "libgomp: present clause: !omp_target_is_present \\\(0x\[0-9a-f\]+, \[0-9\]+\\\)" { target offload_device_nonshared_as } }
+     { dg-shouldfail "present error triggered" { offload_device_nonshared_as } } */
   #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
index 80046011b25..c56b76e0233 100644
--- a/libgomp/testsuite/libgomp.fortran/target-present-1.f90
+++ b/libgomp/testsuite/libgomp.fortran/target-present-1.f90
@@ -1,5 +1,4 @@
-! { dg-do run { target offload_target_any } }
-! { dg-shouldfail "present error triggered" }
+! { dg-do run }
 
 program main
   implicit none
@@ -19,8 +18,12 @@ program main
       end do
     !$omp end target
 
+    print *, "CheCKpOInT"
+    ! { dg-output "CheCKpOInT(\n|\r\n|\r).*" }
+
     ! b has not been allocated, so this should result in an error.
-    ! { dg-output "libgomp: present clause: !omp_target_is_present \\\(0x\[0-9a-f\]+, \[0-9\]+\\\)" }
+    ! { dg-output "libgomp: present clause: !omp_target_is_present \\\(0x\[0-9a-f\]+, \[0-9\]+\\\)" { target offload_device_nonshared_as } }
+    ! { dg-shouldfail "present error triggered" { offload_device_nonshared_as } }
     !$omp target map (present, to: b)
       do i = 1, N
 	c(i) = c(i) + b(i)
diff --git a/libgomp/testsuite/libgomp.fortran/target-present-2.f90 b/libgomp/testsuite/libgomp.fortran/target-present-2.f90
index 0a38dea1e41..f62e0c22468 100644
--- a/libgomp/testsuite/libgomp.fortran/target-present-2.f90
+++ b/libgomp/testsuite/libgomp.fortran/target-present-2.f90
@@ -1,5 +1,4 @@
-! { dg-do run { target offload_target_any } }
-! { dg-shouldfail "present error triggered" }
+! { dg-do run }
 
 program main
   implicit none
@@ -11,16 +10,20 @@ program main
     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 enter data map (alloc: a, c, i)
+    ! a, c, i have 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
 
+    print *, "CheCKpOInT"
+    ! { dg-output "CheCKpOInT(\n|\r\n|\r).*" }
+
     ! b has not been allocated, so this should result in an error.
-    ! { dg-output "libgomp: present clause: !omp_target_is_present \\\(0x\[0-9a-f\]+, \[0-9\]+\\\)" }
+    ! { dg-output "libgomp: present clause: !omp_target_is_present \\\(0x\[0-9a-f\]+, \[0-9\]+\\\)" { target offload_device_nonshared_as } }
+    ! { dg-shouldfail "present error triggered" { offload_device_nonshared_as } }
     !$omp target defaultmap (present)
       do i = 1, N
 	c(i) = c(i) + b(i)
diff --git a/libgomp/testsuite/libgomp.fortran/target-present-3.f90 b/libgomp/testsuite/libgomp.fortran/target-present-3.f90
index c4deb8652d1..b186c1c5462 100644
--- a/libgomp/testsuite/libgomp.fortran/target-present-3.f90
+++ b/libgomp/testsuite/libgomp.fortran/target-present-3.f90
@@ -1,5 +1,4 @@
-! { dg-do run { target offload_target_any } }
-! { dg-shouldfail "present error triggered" }
+! { dg-do run }
 
 program main
   implicit none
@@ -15,8 +14,12 @@ program main
     ! This should work as a has already been allocated.
     !$omp target update to (present: a)
 
+    print *, "CheCKpOInT"
+    ! { dg-output "CheCKpOInT(\n|\r\n|\r).*" }
+
     ! This should fail as b has not been allocated.
-    ! { dg-output "libgomp: present clause: !omp_target_is_present \\\(0x\[0-9a-f\]+, \[0-9\]+\\\)" }
+    ! { dg-output "libgomp: present clause: !omp_target_is_present \\\(0x\[0-9a-f\]+, \[0-9\]+\\\)" { target offload_device_nonshared_as } }
+    ! { dg-shouldfail "present error triggered" { offload_device_nonshared_as } }
     !$omp target update to (present: b)
   !$omp target exit data map (from: c)
 end program
-- 
2.25.1


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCHv2] openmp: Add support for 'present' modifier
  2023-02-03 13:44 [PATCH] openmp: Add support for 'present' modifier Kwok Cheung Yeung
  2023-02-09 21:17 ` [OG12][committed] openmp: Add support for the " Kwok Cheung Yeung
@ 2023-02-17 11:45 ` Kwok Cheung Yeung
  2023-04-28 17:26   ` Tobias Burnus
  1 sibling, 1 reply; 13+ messages in thread
From: Kwok Cheung Yeung @ 2023-02-17 11:45 UTC (permalink / raw)
  To: gcc-patches, Jakub Jelinek

[-- Attachment #1: Type: text/plain, Size: 493 bytes --]

Hello

This is a revised version of the patch for the 'present' modifier for 
OpenMP. Compared to the first version, three improvements have been made:

- A bug which caused bootstrapping with a '-m32' multilib on x86-64 to 
fail due to pointer size issues has been fixed.
- The Fortran parse tree dump now shows clauses with 'present' applied.
- The reordering of OpenMP clauses has been moved to 
gimplify_scan_omp_clauses, where the other clause reordering rules are 
applied.

Thanks

Kwok

[-- Attachment #2: 0001-openmp-Add-support-for-the-present-modifier.patch --]
[-- Type: text/plain, Size: 71383 bytes --]

From 24b6225578bb08bbd745d6ec653aab60802dd220 Mon Sep 17 00:00:00 2001
From: Kwok Cheung Yeung <kcy@codesourcery.com>
Date: Fri, 3 Feb 2023 13:04:21 +0000
Subject: [PATCH] openmp: Add support for the 'present' modifier

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-02-01  Kwok Cheung Yeung  <kcy@codesourcery.com>

	gcc/c/
	* c-parser.cc (c_parser_omp_variable_list): Set default motion
	modifier.
	(c_parser_omp_var_list_parens): Add new parameter with default.  Parse
	'present' motion modifier and apply.
	(c_parser_omp_clause_defaultmap): Parse 'present' in defaultmap.
	(c_parser_omp_clause_map): Parse 'present' modifier in map clauses.
	(c_parser_omp_clause_to): Allow use of 'present' in variable list.
	(c_parser_omp_clause_from): Likewise.
	(c_parser_omp_target_data): Allow map clauses with 'present'
	modifiers.
	(c_parser_omp_target_enter_data): Likewise.
	(c_parser_omp_target_exit_data): Likewise.
	(c_parser_omp_target): Likewise.

	gcc/cp/
	* parser.cc (cp_parser_omp_var_list_no_open): Add new parameter with
	default.  Parse	'present' motion modifier and apply.
	(cp_parser_omp_clause_defaultmap): Parse 'present' in defaultmap.
	(cp_parser_omp_clause_map): Parse 'present' modifier in map clauses.
	(cp_parser_omp_all_clauses): Allow use of 'present' in 'to' and 'from'
	clauses.
	(cp_parser_omp_target_data): Allow map clauses with 'present'
	modifiers.
	(cp_parser_omp_target_enter_data): Likewise.
	(cp_parser_omp_target_exit_data): Likewise.
	* semantics.cc (finish_omp_target): Accept map clauses with 'present'
	modifiers.

	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.
	(enum gfc_omp_motion_modifier): New.
	(struct gfc_omp_namelist): Add motion_modifier field.
	* openmp.cc (gfc_match_omp_variable_list): Add new parameter with
	default.  Parse 'present' motion modifier and apply.
	(gfc_match_omp_clauses): Parse 'present' in defaultmap, 'from'
	clauses, 'map' clauses and 'to' 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.
	(enum omp_clause_motion_modifier): New.
	(struct tree_omp_clause): Add motion_modifier field.
	* tree-pretty-print.cc (dump_omp_clause): Handle 'map', 'to' and
	'from' clauses with 'present' modifier.  Handle present defaultmap.
	* tree.h (OMP_CLAUSE_MOTION_MODIFIER): New.
	(OMP_CLAUSE_SET_MOTION_MODIFIER): New.

	gcc/testsuite/
	* c-c++-common/gomp/defaultmap-4.c: New.
	* c-c++-common/gomp/map-6.c: Update expected error messages.
	* c-c++-common/gomp/map-8.c: New.
	* c-c++-common/gomp/target-update-1.c: New.
	* gfortran.dg/gomp/defaultmap-1.f90: Update expected error messages.
	* gfortran.dg/gomp/defaultmap-8.f90: New.
	* gfortran.dg/gomp/map-9.f90: New.
	* gfortran.dg/gomp/target-update-1.f90: New.

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

	libgomp/
	* 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): Emit runtime error if memory region not
	present.
	(gomp_update): Likewise.
	(gomp_target_rev): Likewise.
	* testsuite/libgomp.c-c++-common/target-present-1.c: New.
	* testsuite/libgomp.c-c++-common/target-present-2.c: New.
	* testsuite/libgomp.c-c++-common/target-present-3.c: New.
	* testsuite/libgomp.fortran/target-present-1.f90: New.
	* testsuite/libgomp.fortran/target-present-2.f90: New.
	* testsuite/libgomp.fortran/target-present-3.f90: New.
---
 gcc/c/c-parser.cc                             | 106 ++++++++++++++++--
 gcc/cp/parser.cc                              | 103 +++++++++++++++--
 gcc/cp/semantics.cc                           |   7 ++
 gcc/fortran/dump-parse-tree.cc                |  15 +++
 gcc/fortran/gfortran.h                        |  16 ++-
 gcc/fortran/openmp.cc                         |  77 +++++++++++--
 gcc/fortran/trans-openmp.cc                   |  30 +++++
 gcc/gimplify.cc                               |  69 ++++++++++++
 gcc/omp-low.cc                                |  26 ++++-
 .../c-c++-common/gomp/defaultmap-4.c          |  24 ++++
 gcc/testsuite/c-c++-common/gomp/map-6.c       |   4 +-
 gcc/testsuite/c-c++-common/gomp/map-8.c       |  32 ++++++
 .../c-c++-common/gomp/target-update-1.c       |  15 +++
 .../gfortran.dg/gomp/defaultmap-1.f90         |   2 +-
 .../gfortran.dg/gomp/defaultmap-8.f90         |  26 +++++
 gcc/testsuite/gfortran.dg/gomp/map-9.f90      |  34 ++++++
 .../gfortran.dg/gomp/target-update-1.f90      |  13 +++
 gcc/tree-core.h                               |   9 +-
 gcc/tree-pretty-print.cc                      |  28 +++++
 gcc/tree.h                                    |   6 +
 include/gomp-constants.h                      |  47 ++++++--
 libgomp/target.c                              |  66 ++++++++++-
 .../libgomp.c-c++-common/target-present-1.c   |  27 +++++
 .../libgomp.c-c++-common/target-present-2.c   |  27 +++++
 .../libgomp.c-c++-common/target-present-3.c   |  27 +++++
 .../libgomp.fortran/target-present-1.f90      |  30 +++++
 .../libgomp.fortran/target-present-2.f90      |  30 +++++
 .../libgomp.fortran/target-present-3.f90      |  22 ++++
 28 files changed, 871 insertions(+), 47 deletions(-)
 create mode 100644 gcc/testsuite/c-c++-common/gomp/defaultmap-4.c
 create mode 100644 gcc/testsuite/c-c++-common/gomp/map-8.c
 create mode 100644 gcc/testsuite/c-c++-common/gomp/target-update-1.c
 create mode 100644 gcc/testsuite/gfortran.dg/gomp/defaultmap-8.f90
 create mode 100644 gcc/testsuite/gfortran.dg/gomp/map-9.f90
 create mode 100644 gcc/testsuite/gfortran.dg/gomp/target-update-1.f90
 create mode 100644 libgomp/testsuite/libgomp.c-c++-common/target-present-1.c
 create mode 100644 libgomp/testsuite/libgomp.c-c++-common/target-present-2.c
 create mode 100644 libgomp/testsuite/libgomp.c-c++-common/target-present-3.c
 create mode 100644 libgomp/testsuite/libgomp.fortran/target-present-1.f90
 create mode 100644 libgomp/testsuite/libgomp.fortran/target-present-2.f90
 create mode 100644 libgomp/testsuite/libgomp.fortran/target-present-3.f90

diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index 43427886ad4..057a2c03937 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -14014,6 +14014,8 @@ c_parser_omp_variable_list (c_parser *parser,
 	      tree u = build_omp_clause (clause_loc, kind);
 	      OMP_CLAUSE_DECL (u) = t;
 	      OMP_CLAUSE_CHAIN (u) = list;
+	      if (kind == OMP_CLAUSE_FROM || kind == OMP_CLAUSE_TO)
+		OMP_CLAUSE_SET_MOTION_MODIFIER (u, OMP_CLAUSE_MOTION_NONE);
 	      list = u;
 	    }
 	}
@@ -14041,7 +14043,8 @@ c_parser_omp_variable_list (c_parser *parser,
 
 static tree
 c_parser_omp_var_list_parens (c_parser *parser, enum omp_clause_code kind,
-			      tree list, bool allow_deref = false)
+			      tree list, bool allow_deref = false,
+			      bool allow_present = false)
 {
   /* The clauses location.  */
   location_t loc = c_parser_peek_token (parser)->location;
@@ -14049,7 +14052,26 @@ c_parser_omp_var_list_parens (c_parser *parser, enum omp_clause_code kind,
   matching_parens parens;
   if (parens.require_open (parser))
     {
+      bool present = false;
+
+      if (allow_present)
+	{
+	   c_token *token = c_parser_peek_token (parser);
+
+	   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);
+	    }
+	}
       list = c_parser_omp_variable_list (parser, loc, kind, list, allow_deref);
+
+      if (present)
+	for (tree clause = list; clause; clause = OMP_CLAUSE_CHAIN (clause))
+	  OMP_CLAUSE_SET_MOTION_MODIFIER (clause, OMP_CLAUSE_MOTION_PRESENT);
       parens.skip_until_found_close (parser);
     }
   return list;
@@ -14933,6 +14955,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;
@@ -17103,6 +17132,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);
@@ -17134,11 +17164,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;
 	}
@@ -17150,14 +17190,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)
@@ -17418,7 +17469,8 @@ c_parser_omp_clause_device_type (c_parser *parser, tree list)
 static tree
 c_parser_omp_clause_to (c_parser *parser, tree list)
 {
-  return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_TO, list, true);
+  return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_TO, list, true,
+				       true);
 }
 
 /* OpenMP 4.0:
@@ -17427,7 +17479,8 @@ c_parser_omp_clause_to (c_parser *parser, tree list)
 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);
+  return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_FROM, list, true,
+				       true);
 }
 
 /* OpenMP 4.0:
@@ -21744,11 +21797,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:
@@ -21894,7 +21954,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:
@@ -21905,6 +21968,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:
@@ -21992,6 +22063,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;
@@ -22004,6 +22077,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:
@@ -22249,11 +22330,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:
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 1a124f5395e..720827a942a 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -37644,11 +37644,33 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind,
 
 static tree
 cp_parser_omp_var_list (cp_parser *parser, enum omp_clause_code kind, tree list,
-			bool allow_deref = false)
+			bool allow_deref = false, bool allow_present = false)
 {
   if (cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN))
-    return cp_parser_omp_var_list_no_open (parser, kind, list, NULL,
-					   allow_deref);
+    {
+      bool present = false;
+
+      if (allow_present)
+	{
+	   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);
+	    }
+	}
+
+      list = cp_parser_omp_var_list_no_open (parser, kind, list, NULL,
+					     allow_deref);
+
+      if (present)
+	for (tree clause = list; clause; clause = OMP_CLAUSE_CHAIN (clause))
+	  OMP_CLAUSE_SET_MOTION_MODIFIER (clause, OMP_CLAUSE_MOTION_PRESENT);
+    }
   return list;
 }
 
@@ -38700,6 +38722,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;
@@ -40453,6 +40482,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);
@@ -40489,11 +40519,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,
@@ -40509,15 +40552,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
@@ -41295,12 +41348,12 @@ cp_parser_omp_all_clauses (cp_parser *parser, omp_clause_mask mask,
 	    }
 	  else
 	    clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_TO, clauses,
-					      true);
+					      true, true);
 	  c_name = "to";
 	  break;
 	case PRAGMA_OMP_CLAUSE_FROM:
 	  clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_FROM, clauses,
-					    true);
+					    true, true);
 	  c_name = "from";
 	  break;
 	case PRAGMA_OMP_CLAUSE_UNIFORM:
@@ -45131,11 +45184,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:
@@ -45238,7 +45298,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:
@@ -45249,6 +45312,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:
@@ -45341,6 +45412,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;
@@ -45353,6 +45426,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:
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index c2df0b69b30..6ba76ebeea6 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -9993,11 +9993,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:
diff --git a/gcc/fortran/dump-parse-tree.cc b/gcc/fortran/dump-parse-tree.cc
index 164710fe98a..b0b439ff0f3 100644
--- a/gcc/fortran/dump-parse-tree.cc
+++ b/gcc/fortran/dump-parse-tree.cc
@@ -1453,9 +1453,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;
@@ -1778,6 +1789,10 @@ 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.motion_modifier
+	       == OMP_MOTION_PRESENT)
+	  fputs ("present:", dumpfile);
 	show_omp_namelist (list_type, omp_clauses->lists[list_type]);
 	fputc (')', dumpfile);
       }
diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h
index a893ee06f3d..e4681f0443f 100644
--- a/gcc/fortran/gfortran.h
+++ b/gcc/fortran/gfortran.h
@@ -1306,7 +1306,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
@@ -1340,6 +1347,12 @@ enum gfc_omp_linear_op
   OMP_LINEAR_UVAL
 };
 
+enum gfc_omp_motion_modifier
+{
+  OMP_MOTION_NONE,
+  OMP_MOTION_PRESENT
+};
+
 /* For use in OpenMP clauses in case we need extra information
    (aligned clause alignment, linear clause step, etc.).  */
 
@@ -1358,6 +1371,7 @@ typedef struct gfc_omp_namelist
 	  ENUM_BITFIELD (gfc_omp_linear_op) op:4;
 	  bool old_modifier;
 	} linear;
+      gfc_omp_motion_modifier motion_modifier;
       struct gfc_common_head *common;
       bool lastprivate_conditional;
     } u;
diff --git a/gcc/fortran/openmp.cc b/gcc/fortran/openmp.cc
index abca146d78e..77598190600 100644
--- a/gcc/fortran/openmp.cc
+++ b/gcc/fortran/openmp.cc
@@ -394,7 +394,8 @@ gfc_match_omp_variable_list (const char *str, gfc_omp_namelist **list,
 			     gfc_omp_namelist ***headp = NULL,
 			     bool allow_sections = false,
 			     bool allow_derived = false,
-			     bool *has_all_memory = NULL)
+			     bool *has_all_memory = NULL,
+			     bool allow_motion_modifier = false)
 {
   gfc_omp_namelist *head, *tail, *p;
   locus old_loc, cur_loc;
@@ -402,6 +403,7 @@ gfc_match_omp_variable_list (const char *str, gfc_omp_namelist **list,
   gfc_symbol *sym;
   match m;
   gfc_symtree *st;
+  bool present = false;
 
   head = tail = NULL;
 
@@ -437,6 +439,12 @@ gfc_match_omp_variable_list (const char *str, gfc_omp_namelist **list,
 	  tail->where = cur_loc;
 	  goto next_item;
 	}
+      else if (allow_motion_modifier && m == MATCH_YES && strcmp (n, "present") == 0
+	       && gfc_match_char (':') == MATCH_YES)
+	{
+	  present = true;
+	  m = gfc_match_name (n);
+	}
       if (m == MATCH_YES)
 	{
 	  gfc_symtree *st;
@@ -537,6 +545,13 @@ gfc_match_omp_variable_list (const char *str, gfc_omp_namelist **list,
   *list = head;
   if (headp)
     *headp = list;
+
+  if (present)
+    {
+      gfc_omp_namelist *n;
+      for (n = head; n; n = n->next)
+	n->u.motion_modifier = OMP_MOTION_PRESENT;
+    }
   return MATCH_YES;
 
 syntax:
@@ -2087,6 +2102,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)
@@ -2094,7 +2111,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 ())
@@ -2520,7 +2537,8 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask,
 	  if ((mask & OMP_CLAUSE_FROM)
 	      && (gfc_match_omp_variable_list ("from (",
 					      &c->lists[OMP_LIST_FROM], false,
-					      NULL, &head, true, true)
+					      NULL, &head, true, true, NULL,
+					      true)
 		  == MATCH_YES))
 	    continue;
 	  break;
@@ -2877,6 +2895,7 @@ 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;
 
@@ -2893,20 +2912,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_close_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)
@@ -3458,7 +3495,8 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask,
 	  else if ((mask & OMP_CLAUSE_TO)
 	      && (gfc_match_omp_variable_list ("to (",
 					      &c->lists[OMP_LIST_TO], false,
-					      NULL, &head, true, true)
+					      NULL, &head, true, true, NULL,
+					      true)
 		  == MATCH_YES))
 	    continue;
 	  break;
@@ -7805,11 +7843,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, "
@@ -7825,6 +7870,8 @@ 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:
 			  break;
 			case OMP_MAP_TOFROM:
@@ -7833,6 +7880,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 "
@@ -7845,6 +7898,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;
@@ -7854,6 +7909,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 "
diff --git a/gcc/fortran/trans-openmp.cc b/gcc/fortran/trans-openmp.cc
index 2d16f3be8ea..35f9669c6c0 100644
--- a/gcc/fortran/trans-openmp.cc
+++ b/gcc/fortran/trans-openmp.cc
@@ -3066,6 +3066,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;
@@ -3705,6 +3729,9 @@ 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.motion_modifier == OMP_MOTION_PRESENT)
+		OMP_CLAUSE_SET_MOTION_MODIFIER (node,
+						OMP_CLAUSE_MOTION_PRESENT);
 	      omp_clauses = gfc_trans_add_clause (node, omp_clauses);
 	    }
 	  break;
@@ -4246,6 +4273,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;
diff --git a/gcc/gimplify.cc b/gcc/gimplify.cc
index 96845154a92..10495fbd77e 100644
--- a/gcc/gimplify.cc
+++ b/gcc/gimplify.cc
@@ -7904,6 +7904,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);
@@ -9062,6 +9067,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:
@@ -9293,6 +9305,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:
@@ -10776,6 +10795,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)
     {
@@ -11972,6 +12035,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)
 		  {
@@ -12416,6 +12482,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 ();
 	}
diff --git a/gcc/omp-low.cc b/gcc/omp-low.cc
index fef41a013ec..c1ac34e5ec0 100644
--- a/gcc/omp-low.cc
+++ b/gcc/omp-low.cc
@@ -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_MODIFIER (c) == OMP_CLAUSE_MOTION_PRESENT
+		    ? GOMP_MAP_PRESENT_TO : GOMP_MAP_TO;
 		tkind_zero = tkind;
 		break;
 	      case OMP_CLAUSE_FROM:
-		tkind = GOMP_MAP_FROM;
+		tkind
+		  = OMP_CLAUSE_MOTION_MODIFIER (c) == OMP_CLAUSE_MOTION_PRESENT
+		    ? 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
index 00000000000..1afff7ea38f
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/defaultmap-4.c
@@ -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" } } */
diff --git a/gcc/testsuite/c-c++-common/gomp/map-6.c b/gcc/testsuite/c-c++-common/gomp/map-6.c
index 6ee59714847..b4683ddbabf 100644
--- a/gcc/testsuite/c-c++-common/gomp/map-6.c
+++ b/gcc/testsuite/c-c++-common/gomp/map-6.c
@@ -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 } } */ 
diff --git a/gcc/testsuite/c-c++-common/gomp/map-8.c b/gcc/testsuite/c-c++-common/gomp/map-8.c
new file mode 100644
index 00000000000..4b4bd6d2aa3
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/map-8.c
@@ -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
index 00000000000..0233fe5a7af
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/target-update-1.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-fdump-tree-gimple" } */
+
+#define N 1000
+
+void
+foo (void)
+{
+  int a[N], b[N];
+
+  /* Should be able to parse present in to/from clauses of 'target update'.  */
+  #pragma omp target update to(present: a) from(present: b)
+}
+
+/* { dg-final { scan-tree-dump "pragma omp target update from\\(present:b \\\[len: \[0-9\]+\\\]\\) to\\(present:a \\\[len: \[0-9\]+\\\]\\)" "gimple" } } */
diff --git a/gcc/testsuite/gfortran.dg/gomp/defaultmap-1.f90 b/gcc/testsuite/gfortran.dg/gomp/defaultmap-1.f90
index 299d971f23c..1f1b8528aef 100644
--- a/gcc/testsuite/gfortran.dg/gomp/defaultmap-1.f90
+++ b/gcc/testsuite/gfortran.dg/gomp/defaultmap-1.f90
@@ -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
index 00000000000..669a623f746
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/defaultmap-8.f90
@@ -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-9.f90 b/gcc/testsuite/gfortran.dg/gomp/map-9.f90
new file mode 100644
index 00000000000..cc87212f8d0
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/map-9.f90
@@ -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/target-update-1.f90 b/gcc/testsuite/gfortran.dg/gomp/target-update-1.f90
new file mode 100644
index 00000000000..a382b87f229
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/target-update-1.f90
@@ -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), i
+
+  ! Should be able to parse present in to/from clauses of 'target update'.
+  !$omp target update to(present: a) from(present: b)
+end program
+
+! { dg-final { scan-tree-dump "pragma omp target update to\\(present:a \\\[len: \[0-9\]+\\\]\\) from\\(present:b \\\[len: \[0-9\]+\\\]\\)" "gimple" } }
diff --git a/gcc/tree-core.h b/gcc/tree-core.h
index acd8deea34e..e50df80b22c 100644
--- a/gcc/tree-core.h
+++ b/gcc/tree-core.h
@@ -573,7 +573,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 {
@@ -582,6 +583,11 @@ enum omp_clause_bind_kind {
   OMP_CLAUSE_BIND_THREAD
 };
 
+enum omp_clause_motion_modifier {
+  OMP_CLAUSE_MOTION_NONE,
+  OMP_CLAUSE_MOTION_PRESENT
+};
+
 /* memory-order-clause on OpenMP atomic/flush constructs or
    argument of atomic_default_mem_order clause.  */
 enum omp_memory_order {
@@ -1646,6 +1652,7 @@ struct GTY(()) tree_omp_clause {
     enum omp_clause_defaultmap_kind defaultmap_kind;
     enum omp_clause_bind_kind      bind_kind;
     enum omp_clause_device_type_kind device_type_kind;
+    enum omp_clause_motion_modifier motion_modifier;
   } GTY ((skip)) subcode;
 
   /* The gimplification of OMP_CLAUSE_REDUCTION_{INIT,MERGE} for omp-low's
diff --git a/gcc/tree-pretty-print.cc b/gcc/tree-pretty-print.cc
index 7947f9647a1..99f8acc3acc 100644
--- a/gcc/tree-pretty-print.cc
+++ b/gcc/tree-pretty-print.cc
@@ -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_MODIFIER (clause) == OMP_CLAUSE_MOTION_PRESENT)
+	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_MODIFIER (clause) == OMP_CLAUSE_MOTION_PRESENT)
+	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;
diff --git a/gcc/tree.h b/gcc/tree.h
index c656cd5b7bf..eb573a01b55 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -1742,6 +1742,12 @@ 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_MODIFIER(NODE) \
+  ((enum omp_clause_motion_modifier) OMP_CLAUSE_RANGE_CHECK (NODE, OMP_CLAUSE_FROM, OMP_CLAUSE_TO)->omp_clause.subcode.motion_modifier)
+#define OMP_CLAUSE_SET_MOTION_MODIFIER(NODE, MOTION_MODIFIER) \
+  (OMP_CLAUSE_RANGE_CHECK (NODE, OMP_CLAUSE_FROM, OMP_CLAUSE_TO)->omp_clause.subcode.motion_modifier \
+   = (MOTION_MODIFIER))
+
 /* 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.  */
diff --git a/include/gomp-constants.h b/include/gomp-constants.h
index 1b9b07dc245..49b7dd86ff5 100644
--- a/include/gomp-constants.h
+++ b/include/gomp-constants.h
@@ -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 \
@@ -55,9 +56,14 @@
 					 | 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.  */
diff --git a/libgomp/target.c b/libgomp/target.c
index 483851c95ac..358a1c267f7 100644
--- a/libgomp/target.c
+++ b/libgomp/target.c
@@ -360,6 +360,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;
@@ -592,7 +594,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.  */
@@ -1708,6 +1710,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: !omp_target_is_present "
+				"(%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,
@@ -2117,6 +2133,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: !omp_target_is_present "
+			    "(%p, %d)",
+			    (void *) hostaddrs[i], devicep->target_id);
+	      }
+	  }
       }
   gomp_mutex_unlock (&devicep->lock);
 }
@@ -3425,7 +3455,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:
@@ -3437,6 +3468,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
@@ -3457,7 +3494,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)
@@ -3475,8 +3528,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))
 		  {
 		    if (dev_to_host_cpy)
 		      dev_to_host_cpy ((void *) (uintptr_t) devaddrs[i],
@@ -3661,6 +3713,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
index 00000000000..bbc4559b12e
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c-c++-common/target-present-1.c
@@ -0,0 +1,27 @@
+/* { dg-do run { target offload_target_any } } */
+/* { 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: !omp_target_is_present \\\(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
index 00000000000..6259c959c04
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c-c++-common/target-present-2.c
@@ -0,0 +1,27 @@
+/* { dg-do run { target offload_target_any } } */
+/* { 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: !omp_target_is_present \\\(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
index 00000000000..89e648645b2
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c-c++-common/target-present-3.c
@@ -0,0 +1,27 @@
+/* { dg-do run { target offload_target_any } } */
+/* { 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: !omp_target_is_present \\\(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
index 00000000000..80046011b25
--- /dev/null
+++ b/libgomp/testsuite/libgomp.fortran/target-present-1.f90
@@ -0,0 +1,30 @@
+! { dg-do run { target offload_target_any } }
+! { 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: !omp_target_is_present \\\(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
index 00000000000..0a38dea1e41
--- /dev/null
+++ b/libgomp/testsuite/libgomp.fortran/target-present-2.f90
@@ -0,0 +1,30 @@
+! { dg-do run { target offload_target_any } }
+! { 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: !omp_target_is_present \\\(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
index 00000000000..c4deb8652d1
--- /dev/null
+++ b/libgomp/testsuite/libgomp.fortran/target-present-3.f90
@@ -0,0 +1,22 @@
+! { dg-do run { target offload_target_any } }
+! { 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: !omp_target_is_present \\\(0x\[0-9a-f\]+, \[0-9\]+\\\)" }
+    !$omp target update to (present: b)
+  !$omp target exit data map (from: c)
+end program
-- 
2.34.1


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCHv2] openmp: Add support for 'present' modifier
  2023-02-17 11:45 ` [PATCHv2] openmp: Add support for " Kwok Cheung Yeung
@ 2023-04-28 17:26   ` Tobias Burnus
  2023-06-06 14:55     ` [committed] " Tobias Burnus
  0 siblings, 1 reply; 13+ messages in thread
From: Tobias Burnus @ 2023-04-28 17:26 UTC (permalink / raw)
  To: Kwok Cheung Yeung, gcc-patches, Jakub Jelinek

Hi Kwok,

On 17.02.23 12:45, Kwok Cheung Yeung wrote:
> This is a revised version of the patch for the 'present' modifier for
> OpenMP. Compared to the first version, three improvements have been made:
>
> - A bug which caused bootstrapping with a '-m32' multilib on x86-64 to
> fail due to pointer size issues has been fixed.
> - The Fortran parse tree dump now shows clauses with 'present' applied.
> - The reordering of OpenMP clauses has been moved to
> gimplify_scan_omp_clauses, where the other clause reordering rules are
> applied.

thanks for the patch; I have a bunch of smaller review comments, requiring small
code changes or more tedious but still simple changes.

Namely:

In the ChangeLog:
>          (c_parser_omp_target_data): Allow map clauses with 'present'
>          modifiers.
>          (c_parser_omp_target_enter_data): Likewise.
>          (c_parser_omp_target_exit_data): Likewise.
>          (c_parser_omp_target): Likewise.

Those be combined; a separate entry is only required per file not per
function name.

> +             if (kind == OMP_CLAUSE_FROM || kind == OMP_CLAUSE_TO)
> +               OMP_CLAUSE_SET_MOTION_MODIFIER (u, OMP_CLAUSE_MOTION_NONE);

This should not be needed as 'build_omp_clause' memset '\0' the data and
OMP_CLAUSE_MOTION_NONE == 0 (as it should).

However, as you really only have two values, denoting that the modifier has
been specified or not, you should really use an available existing flag. For instance,
other code uses base.deprecated_flag – which could also be used here.

Macro wise, this would then permit to use:
   OMP_CLAUSE_MOTION_PRESENT (node) = 1;
or
   OMP_CLAUSE_TO_PRESENT (node) = 1;
   OMP_CLAUSE_FROM_PRESENT (node) = 1;
and 'if (OMP_... (node))' which is shorter and is IMHO to be also more readable.

* * *

I think c_parser_omp_var_list_parens / cp_parser_omp_var_list / gfc_match_omp_variable_list
should not be modified.

For C/C++, you just could do the '(' + {'present', ':' } parsing before the call to
   c_parser_omp_variable_list / cp_parser_omp_var_list_no_open
and then loop over 'list' after the call - and similarly for Fortran.

And besides not cluttering a generic function, we will also soon add support for
'mapper' (→ Julian's patch set adds generic mapper support) and 'iterator' is also
missing. And we really do not want those in the generic function!

> +       kind = always_present_modifier ? GOMP_MAP_ALWAYS_PRESENT_FROM
> +              : present_modifier ? GOMP_MAP_PRESENT_FROM
> +              : always_modifier ? GOMP_MAP_ALWAYS_FROM
> +              : GOMP_MAP_FROM;

Can you wrap the RHS in parenthesis, i.e. 'kind = (' ... ');' to aid some
editors in terms of indenting. (I assume 'emacs' is that editor, which I don't use.)

> +               tkind
> +                 = OMP_CLAUSE_MOTION_MODIFIER (c) == OMP_CLAUSE_MOTION_PRESENT
> +                   ? GOMP_MAP_PRESENT_TO : GOMP_MAP_TO;

Likewise.


* * *

> @@ -1358,6 +1371,7 @@ typedef struct gfc_omp_namelist
>            ENUM_BITFIELD (gfc_omp_linear_op) op:4;
>            bool old_modifier;
>          } linear;
> +      gfc_omp_motion_modifier motion_modifier;
>         struct gfc_common_head *common;
>         bool lastprivate_conditional;
>       } u;


I think a 'bool present;' would do here. Can you additionally move the
pointers first and then the bitfields/enums later? That way,
less space is wasted by padding and we might even save space despite
adding another variable.

> @@ -2893,20 +2912,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_close_locus = current_locus;
> +                   }
> ...

This code is broken in terms of error diagnostic. You need to handle this
differently to get diagostic for:
   'map(present, present : var)'

Can you fix the code + add a testcase (e.g. by augmenting the 'always' testcase
files testsuite/gfortran.dg/gomp/map-{7,8}.f90).


> +                   gomp_fatal ("present clause: !omp_target_is_present "

I personally find the error a bit unclear. How about something more explicit
like: 'present clause: not present on the device' - or something like that?

> +/* { dg-do run { target offload_target_any } } */


This needs to be '{ target offload_device }' - i.e. the default device needs to be
an offload device (!= the initial device).

(Side note: We may need to consider whether offload_device_nonshared_as might make sense, but
the current omp_target_is_present and omp_target_(dis)associate_ptr implies that
we will still go though this route with USM for explicitly mapped variables
(but do not do any actual mapping in that case).
But that we can handle, once the USM code gets merged and we get FAILs.)

Tobias

-----------------
Siemens Electronic Design Automation GmbH; Anschrift: Arnulfstraße 201, 80634 München; Gesellschaft mit beschränkter Haftung; Geschäftsführer: Thomas Heurung, Frank Thürauf; Sitz der Gesellschaft: München; Registergericht München, HRB 106955

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [committed] Re: [PATCHv2] openmp: Add support for 'present' modifier
  2023-04-28 17:26   ` Tobias Burnus
@ 2023-06-06 14:55     ` Tobias Burnus
  0 siblings, 0 replies; 13+ messages in thread
From: Tobias Burnus @ 2023-06-06 14:55 UTC (permalink / raw)
  To: Kwok Cheung Yeung, gcc-patches, Jakub Jelinek

[-- Attachment #1: Type: text/plain, Size: 1018 bytes --]

Hi all,

This adds OpenMP 5.1's 'present' modifier to the to/from/map clauses
and 'defaultmap(present)'.

I have now committed that patch as r14-1579-g4ede915d5dde935a16df2c6640aee5ab22348d30,
or as attached.

Or rather: I have done so after revising the patch for the issues I noted before;
while doing so and when adding a bunch of additional tests, I found a few additional
issues, which have been fixed as well. Somehow, there cannot be too many testcases ...

Tobias

See previously in this thread for my review comments and Kwok's patch remarks, i.e.

On 28.04.23 19:26, Tobias Burnus wrote:
> On 17.02.23 12:45, Kwok Cheung Yeung wrote:
>> This is a revised version of the patch for the 'present' modifier for
>> OpenMP.
-----------------
Siemens Electronic Design Automation GmbH; Anschrift: Arnulfstraße 201, 80634 München; Gesellschaft mit beschränkter Haftung; Geschäftsführer: Thomas Heurung, Frank Thürauf; Sitz der Gesellschaft: München; Registergericht München, HRB 106955

[-- Attachment #2: committed.diff --]
[-- Type: text/x-patch, Size: 87882 bytes --]

commit 4ede915d5dde935a16df2c6640aee5ab22348d30
Author: Tobias Burnus <tobias@codesourcery.com>
Date:   Tue Jun 6 16:47:16 2023 +0200

    openmp: Add support for the 'present' modifier
    
    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.
---
 gcc/c/c-parser.cc                                  | 123 ++++++++++++++++++---
 gcc/cp/parser.cc                                   | 114 +++++++++++++++++--
 gcc/cp/semantics.cc                                |   7 ++
 gcc/fortran/dump-parse-tree.cc                     |  14 +++
 gcc/fortran/gfortran.h                             |  10 +-
 gcc/fortran/openmp.cc                              |  98 +++++++++++++---
 gcc/fortran/trans-openmp.cc                        |  29 +++++
 gcc/gimplify.cc                                    |  69 ++++++++++++
 gcc/omp-low.cc                                     |  26 ++++-
 gcc/testsuite/c-c++-common/gomp/defaultmap-4.c     |  24 ++++
 gcc/testsuite/c-c++-common/gomp/map-6.c            |  70 +++++++++++-
 gcc/testsuite/c-c++-common/gomp/map-9.c            |  32 ++++++
 gcc/testsuite/c-c++-common/gomp/target-update-1.c  |  15 +++
 gcc/testsuite/gfortran.dg/gomp/defaultmap-1.f90    |   2 +-
 gcc/testsuite/gfortran.dg/gomp/defaultmap-8.f90    |  26 +++++
 gcc/testsuite/gfortran.dg/gomp/map-11.f90          |  34 ++++++
 gcc/testsuite/gfortran.dg/gomp/map-12.f90          |  67 +++++++++++
 gcc/testsuite/gfortran.dg/gomp/map-7.f90           |  30 ++++-
 gcc/testsuite/gfortran.dg/gomp/map-8.f90           |  11 ++
 gcc/testsuite/gfortran.dg/gomp/target-update-1.f90 |  13 +++
 gcc/tree-core.h                                    |   3 +-
 gcc/tree-pretty-print.cc                           |  28 +++++
 gcc/tree.h                                         |   3 +
 include/gomp-constants.h                           |  47 ++++++--
 libgomp/libgomp.texi                               |   4 +-
 libgomp/target.c                                   |  66 ++++++++++-
 .../libgomp.c-c++-common/target-present-1.c        |  27 +++++
 .../libgomp.c-c++-common/target-present-2.c        |  27 +++++
 .../libgomp.c-c++-common/target-present-3.c        |  27 +++++
 .../testsuite/libgomp.fortran/target-present-1.f90 |  30 +++++
 .../testsuite/libgomp.fortran/target-present-2.f90 |  30 +++++
 .../testsuite/libgomp.fortran/target-present-3.f90 |  22 ++++
 32 files changed, 1064 insertions(+), 64 deletions(-)

diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index 5baa501dbee..72f6fbae6a6 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -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:
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 1c9aa671851..d77fbd20e56 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -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:
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 0843b5eae73..c04514679f0 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -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:
diff --git a/gcc/fortran/dump-parse-tree.cc b/gcc/fortran/dump-parse-tree.cc
index 6d75cc29f60..99c8bdaadce 100644
--- a/gcc/fortran/dump-parse-tree.cc
+++ b/gcc/fortran/dump-parse-tree.cc
@@ -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);
       }
diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h
index 3e5f942d7fd..33ca4986f69 100644
--- a/gcc/fortran/gfortran.h
+++ b/gcc/fortran/gfortran.h
@@ -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
     {
diff --git a/gcc/fortran/openmp.cc b/gcc/fortran/openmp.cc
index 4c30548567f..8efc4b3ecfa 100644
--- a/gcc/fortran/openmp.cc
+++ b/gcc/fortran/openmp.cc
@@ -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 "
diff --git a/gcc/fortran/trans-openmp.cc b/gcc/fortran/trans-openmp.cc
index 42b608f3d36..4aa16fa88da 100644
--- a/gcc/fortran/trans-openmp.cc
+++ b/gcc/fortran/trans-openmp.cc
@@ -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;
diff --git a/gcc/gimplify.cc b/gcc/gimplify.cc
index 4aa6229fc74..91640deecea 100644
--- a/gcc/gimplify.cc
+++ b/gcc/gimplify.cc
@@ -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 ();
 	}
diff --git a/gcc/omp-low.cc b/gcc/omp-low.cc
index 9db33d2a48b..1857b5b960f 100644
--- a/gcc/omp-low.cc
+++ b/gcc/omp-low.cc
@@ -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
index 00000000000..1afff7ea38f
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/defaultmap-4.c
@@ -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" } } */
diff --git a/gcc/testsuite/c-c++-common/gomp/map-6.c b/gcc/testsuite/c-c++-common/gomp/map-6.c
index 6ee59714847..8c5b7f7cca1 100644
--- a/gcc/testsuite/c-c++-common/gomp/map-6.c
+++ b/gcc/testsuite/c-c++-common/gomp/map-6.c
@@ -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
index 00000000000..4b4bd6d2aa3
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/map-9.c
@@ -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
index 00000000000..4408ab75255
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/target-update-1.c
@@ -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" } } */
diff --git a/gcc/testsuite/gfortran.dg/gomp/defaultmap-1.f90 b/gcc/testsuite/gfortran.dg/gomp/defaultmap-1.f90
index 299d971f23c..1f1b8528aef 100644
--- a/gcc/testsuite/gfortran.dg/gomp/defaultmap-1.f90
+++ b/gcc/testsuite/gfortran.dg/gomp/defaultmap-1.f90
@@ -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
index 00000000000..669a623f746
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/defaultmap-8.f90
@@ -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
index 00000000000..9eb956f1aa1
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/map-11.f90
@@ -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
index 00000000000..74bd01f5f5a
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/map-12.f90
@@ -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" } }
diff --git a/gcc/testsuite/gfortran.dg/gomp/map-7.f90 b/gcc/testsuite/gfortran.dg/gomp/map-7.f90
index 009c6d49547..317090acb50 100644
--- a/gcc/testsuite/gfortran.dg/gomp/map-7.f90
+++ b/gcc/testsuite/gfortran.dg/gomp/map-7.f90
@@ -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" } }
diff --git a/gcc/testsuite/gfortran.dg/gomp/map-8.f90 b/gcc/testsuite/gfortran.dg/gomp/map-8.f90
index 92b802c67ed..15ebdd68b95 100644
--- a/gcc/testsuite/gfortran.dg/gomp/map-8.f90
+++ b/gcc/testsuite/gfortran.dg/gomp/map-8.f90
@@ -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
index 00000000000..f99bffe2e0b
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/target-update-1.f90
@@ -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" } }
diff --git a/gcc/tree-core.h b/gcc/tree-core.h
index 6dd7b680b57..c48a12b378f 100644
--- a/gcc/tree-core.h
+++ b/gcc/tree-core.h
@@ -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 {
diff --git a/gcc/tree-pretty-print.cc b/gcc/tree-pretty-print.cc
index db2a58a857d..25d191b10fd 100644
--- a/gcc/tree-pretty-print.cc
+++ b/gcc/tree-pretty-print.cc
@@ -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;
diff --git a/gcc/tree.h b/gcc/tree.h
index eee7d3e19cd..1854fe4a7d4 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -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.  */
diff --git a/include/gomp-constants.h b/include/gomp-constants.h
index 1b9b07dc245..49b7dd86ff5 100644
--- a/include/gomp-constants.h
+++ b/include/gomp-constants.h
@@ -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 \
@@ -55,9 +56,14 @@
 					 | 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.  */
diff --git a/libgomp/libgomp.texi b/libgomp/libgomp.texi
index 3ea17a4cbdb..76c56a73969 100644
--- a/libgomp/libgomp.texi
+++ b/libgomp/libgomp.texi
@@ -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
 
 
diff --git a/libgomp/target.c b/libgomp/target.c
index 32389540acc..a9e8005c588 100644
--- a/libgomp/target.c
+++ b/libgomp/target.c
@@ -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
index 00000000000..12f154c91a8
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c-c++-common/target-present-1.c
@@ -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
index 00000000000..d4debbab10b
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c-c++-common/target-present-2.c
@@ -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
index 00000000000..9d8d8f8a335
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c-c++-common/target-present-3.c
@@ -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
index 00000000000..349dcb118b2
--- /dev/null
+++ b/libgomp/testsuite/libgomp.fortran/target-present-1.f90
@@ -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
index 00000000000..07e79d1b576
--- /dev/null
+++ b/libgomp/testsuite/libgomp.fortran/target-present-2.f90
@@ -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
index 00000000000..a2709eb6f17
--- /dev/null
+++ b/libgomp/testsuite/libgomp.fortran/target-present-3.f90
@@ -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

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [committed] testsuite/libgomp.*/target-present-*.{c,f90}: Improve and fix (was: Re: [og12] Fix 'libgomp.{c-c++-common,fortran}/target-present-*' test cases)
  2023-02-15 19:02   ` [og12] Fix 'libgomp.{c-c++-common,fortran}/target-present-*' test cases (was: [OG12][committed] openmp: Add support for the 'present' modifier) Thomas Schwinge
@ 2023-06-07 11:25     ` Tobias Burnus
  2023-06-07 11:26     ` Tobias Burnus
  1 sibling, 0 replies; 13+ messages in thread
From: Tobias Burnus @ 2023-06-07 11:25 UTC (permalink / raw)
  To: gcc-patches; +Cc: Thomas Schwinge

This patch fixes a corner case issue (missing list items in a map clause)
and ensures that such an issue is caught.

Committed to mainline as https://gcc.gnu.org/r14-1605-gdd958667821e38

It is a forward port of Thomas' OG12 then OG13 commit which fixed
a run-time issue which the mainline version does not have; still fixing
the map issue (and doing the check-point check) is a good idea and,
hence, the patch was applied to mainline as well.

OG13 commit: https://gcc.gnu.org/g:f719ab9a3ac51d798b012a5ab7757af2b81b4ae2
OG12 commit, see Thomas email earlier in this thread.

Tobias

On 15.02.23 20:02, Thomas Schwinge wrote:
> On 2023-02-09T21:17:44+0000, Kwok Cheung Yeung <kcy@codesourcery.com> wrote:
>> [...]
> I've pushed to devel/omp/gcc-12 branch
> commit bbda035ee62ba4db21356136c97e9d83a97ba7d1
> "Fix 'libgomp.{c-c++-common,fortran}/target-present-*' test cases",
> see attached. [...]
-----------------
Siemens Electronic Design Automation GmbH; Anschrift: Arnulfstraße 201, 80634 München; Gesellschaft mit beschränkter Haftung; Geschäftsführer: Thomas Heurung, Frank Thürauf; Sitz der Gesellschaft: München; Registergericht München, HRB 106955

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [committed] testsuite/libgomp.*/target-present-*.{c,f90}: Improve and fix (was: Re: [og12] Fix 'libgomp.{c-c++-common,fortran}/target-present-*' test cases)
  2023-02-15 19:02   ` [og12] Fix 'libgomp.{c-c++-common,fortran}/target-present-*' test cases (was: [OG12][committed] openmp: Add support for the 'present' modifier) Thomas Schwinge
  2023-06-07 11:25     ` [committed] testsuite/libgomp.*/target-present-*.{c,f90}: Improve and fix (was: Re: [og12] Fix 'libgomp.{c-c++-common,fortran}/target-present-*' test cases) Tobias Burnus
@ 2023-06-07 11:26     ` Tobias Burnus
  1 sibling, 0 replies; 13+ messages in thread
From: Tobias Burnus @ 2023-06-07 11:26 UTC (permalink / raw)
  To: gcc-patches; +Cc: Thomas Schwinge

[-- Attachment #1: Type: text/plain, Size: 1205 bytes --]

This patch fixes a corner case issue (missing list items in a map clause)
and ensures that such an issue is caught.

Committed to mainline as https://gcc.gnu.org/r14-1605-gdd958667821e38

It is a forward port of Thomas' OG12 then OG13 commit which fixed
a run-time issue which the mainline version does not have; still fixing
the map issue (and doing the check-point check) is a good idea and,
hence, a likewise patch has now been applied to mainline as well.

OG13 commit: https://gcc.gnu.org/g:f719ab9a3ac51d798b012a5ab7757af2b81b4ae2
OG12 commit, see Thomas email earlier in this thread.

Tobias

On 15.02.23 20:02, Thomas Schwinge wrote:
> On 2023-02-09T21:17:44+0000, Kwok Cheung Yeung <kcy@codesourcery.com> wrote:
>> [...]
> I've pushed to devel/omp/gcc-12 branch
> commit bbda035ee62ba4db21356136c97e9d83a97ba7d1
> "Fix 'libgomp.{c-c++-common,fortran}/target-present-*' test cases",
> see attached. [...]
-----------------
Siemens Electronic Design Automation GmbH; Anschrift: Arnulfstraße 201, 80634 München; Gesellschaft mit beschränkter Haftung; Geschäftsführer: Thomas Heurung, Frank Thürauf; Sitz der Gesellschaft: München; Registergericht München, HRB 106955

[-- Attachment #2: committed.diff --]
[-- Type: text/x-patch, Size: 9514 bytes --]

commit dd958667821e38b7d6b8efe448044901b4762b3a
Author: Tobias Burnus <tobias@codesourcery.com>
Date:   Wed Jun 7 13:22:13 2023 +0200

    testsuite/libgomp.*/target-present-*.{c,f90}: Improve and fix
    
    One of the testcases lacked variables in a map clause such that
    the fail occurred too early. Additionally, it would have failed
    for all those non-host devices where 'present' is always true, i.e.
    non-host devices which can access all of the host memory
    (shared-memory devices). [There are currently none.]
    
    The commit now runs the code on all devices, which should succeed
    for host fallback and for shared-memory devices, finding potenial issues
    that way. Additionally, a checkpoint (required stdout output) is used
    to ensure that the execution won't fail (with the same error) before
    reaching the expected fail location.
    
    2023-06-07  Thomas Schwinge  <thomas@codesourcery.com>
                Tobias Burnus  <tobias@codesourcery.com>
    
    libgomp/
            * testsuite/libgomp.c-c++-common/target-present-1.c: Run code
            also for non-offload_device targets; check that it runs
            successfully for those and for all until a checkpoint for all
            * testsuite/libgomp.c-c++-common/target-present-2.c: Likewise.
            * testsuite/libgomp.c-c++-common/target-present-3.c: Likewise.
            * testsuite/libgomp.fortran/target-present-1.f90: Likewise.
            * testsuite/libgomp.fortran/target-present-3.f90: Likewise.
            * testsuite/libgomp.fortran/target-present-2.f90: Likewise;
            add missing vars to map clause.
---
 libgomp/testsuite/libgomp.c-c++-common/target-present-1.c |  9 ++++++---
 libgomp/testsuite/libgomp.c-c++-common/target-present-2.c | 11 +++++++----
 libgomp/testsuite/libgomp.c-c++-common/target-present-3.c |  9 +++++----
 libgomp/testsuite/libgomp.fortran/target-present-1.f90    |  9 +++++----
 libgomp/testsuite/libgomp.fortran/target-present-2.f90    | 13 +++++++------
 libgomp/testsuite/libgomp.fortran/target-present-3.f90    |  9 +++++----
 6 files changed, 35 insertions(+), 25 deletions(-)

diff --git a/libgomp/testsuite/libgomp.c-c++-common/target-present-1.c b/libgomp/testsuite/libgomp.c-c++-common/target-present-1.c
index 12f154c91a8..aa343197e35 100644
--- a/libgomp/testsuite/libgomp.c-c++-common/target-present-1.c
+++ b/libgomp/testsuite/libgomp.c-c++-common/target-present-1.c
@@ -1,5 +1,4 @@
-/* { dg-do run { target offload_device } } */
-/* { dg-shouldfail "present error triggered" } */
+#include <stdio.h>
 
 #define N 100
 
@@ -18,8 +17,12 @@ int main (void)
       for (int i = 0; i < N; i++)
 	c[i] = a[i];
 
+    fprintf (stderr, "CheCKpOInT\n");
+    /* { dg-output "CheCKpOInT(\n|\r\n|\r).*" } */
+
     /* 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\]+\\\)" } */
+    /* { dg-output "libgomp: present clause: not present on the device \\\(0x\[0-9a-f\]+, \[0-9\]+\\\)" { target offload_device_nonshared_as } } */
+    /* { dg-shouldfail "present error triggered" { offload_device_nonshared_as } } */
     #pragma omp target map (present, to: b)
       for (int i = 0; i < N; i++)
 	c[i] += b[i];
diff --git a/libgomp/testsuite/libgomp.c-c++-common/target-present-2.c b/libgomp/testsuite/libgomp.c-c++-common/target-present-2.c
index d4debbab10b..ad11023b2d6 100644
--- a/libgomp/testsuite/libgomp.c-c++-common/target-present-2.c
+++ b/libgomp/testsuite/libgomp.c-c++-common/target-present-2.c
@@ -1,5 +1,4 @@
-/* { dg-do run { target offload_device } } */
-/* { dg-shouldfail "present error triggered" } */
+#include <stdio.h>
 
 #define N 100
 
@@ -13,13 +12,17 @@ int main (void)
   }
 
   #pragma omp target enter data map (alloc: a, c)
-    /* a has already been allocated, so this should be okay.  */
+    /* a and c have already been allocated, so this should be okay.  */
     #pragma omp target defaultmap (present)
       for (int i = 0; i < N; i++)
 	c[i] = a[i];
 
+    fprintf (stderr, "CheCKpOInT\n");
+    /* { dg-output "CheCKpOInT(\n|\r\n|\r).*" } */
+
     /* 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\]+\\\)" } */
+    /* { dg-output "libgomp: present clause: not present on the device \\\(0x\[0-9a-f\]+, \[0-9\]+\\\)" { target offload_device_nonshared_as } } */
+    /* { dg-shouldfail "present error triggered" { offload_device_nonshared_as } } */
     #pragma omp target defaultmap (present)
       for (int i = 0; i < N; i++)
 	c[i] += b[i];
diff --git a/libgomp/testsuite/libgomp.c-c++-common/target-present-3.c b/libgomp/testsuite/libgomp.c-c++-common/target-present-3.c
index 9d8d8f8a335..455519af405 100644
--- a/libgomp/testsuite/libgomp.c-c++-common/target-present-3.c
+++ b/libgomp/testsuite/libgomp.c-c++-common/target-present-3.c
@@ -1,6 +1,3 @@
-/* { dg-do run { target offload_device } } */
-/* { dg-shouldfail "present error triggered" } */
-
 #include <stdio.h>
 
 #define N 100
@@ -19,8 +16,12 @@ int main (void)
   /* This should work as a has already been allocated.  */
   #pragma omp target update to (present: a)
 
+  fprintf (stderr, "CheCKpOInT\n");
+  /* { dg-output "CheCKpOInT(\n|\r\n|\r).*" } */
+
   /* 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\]+\\\)" } */
+  /* { dg-output "libgomp: present clause: not present on the device \\\(0x\[0-9a-f\]+, \[0-9\]+\\\)" { target offload_device_nonshared_as } } */
+  /* { dg-shouldfail "present error triggered" { offload_device_nonshared_as } } */
   #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
index 349dcb118b2..768166fcff7 100644
--- a/libgomp/testsuite/libgomp.fortran/target-present-1.f90
+++ b/libgomp/testsuite/libgomp.fortran/target-present-1.f90
@@ -1,6 +1,3 @@
-! { dg-do run { target offload_device } }
-! { dg-shouldfail "present error triggered" }
-
 program main
   implicit none
   integer, parameter :: N = 100
@@ -19,8 +16,12 @@ program main
       end do
     !$omp end target
 
+    print *, "CheCKpOInT"
+    ! { dg-output "CheCKpOInT(\n|\r\n|\r).*" }
+
     ! 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\]+\\\)" }
+    ! { dg-output "libgomp: present clause: not present on the device \\\(0x\[0-9a-f\]+, \[0-9\]+\\\)" { target offload_device_nonshared_as } }
+    ! { dg-shouldfail "present error triggered" { offload_device_nonshared_as } }
     !$omp target map (present, to: b)
       do i = 1, N
         c(i) = c(i) + b(i)
diff --git a/libgomp/testsuite/libgomp.fortran/target-present-2.f90 b/libgomp/testsuite/libgomp.fortran/target-present-2.f90
index 07e79d1b576..8f2c24ef5f2 100644
--- a/libgomp/testsuite/libgomp.fortran/target-present-2.f90
+++ b/libgomp/testsuite/libgomp.fortran/target-present-2.f90
@@ -1,6 +1,3 @@
-! { dg-do run { target offload_device } }
-! { dg-shouldfail "present error triggered" }
-
 program main
   implicit none
   integer, parameter :: N = 100
@@ -11,16 +8,20 @@ program main
     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 enter data map (alloc: a, c, i)
+    ! a, c, and i have 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
 
+    print *, "CheCKpOInT"
+    ! { dg-output "CheCKpOInT(\n|\r\n|\r).*" }
+
     ! 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\]+\\\)" }
+    ! { dg-output "libgomp: present clause: not present on the device \\\(0x\[0-9a-f\]+, \[0-9\]+\\\)" { target offload_device_nonshared_as } }
+    ! { dg-shouldfail "present error triggered" { offload_device_nonshared_as } }
     !$omp target defaultmap (present)
       do i = 1, N
         c(i) = c(i) + b(i)
diff --git a/libgomp/testsuite/libgomp.fortran/target-present-3.f90 b/libgomp/testsuite/libgomp.fortran/target-present-3.f90
index a2709eb6f17..eb29c907624 100644
--- a/libgomp/testsuite/libgomp.fortran/target-present-3.f90
+++ b/libgomp/testsuite/libgomp.fortran/target-present-3.f90
@@ -1,6 +1,3 @@
-! { dg-do run { target offload_device } }
-! { dg-shouldfail "present error triggered" }
-
 program main
   implicit none
   integer, parameter :: N = 100
@@ -15,8 +12,12 @@ program main
     ! This should work as a has already been allocated.
     !$omp target update to (present: a)
 
+    print *, "CheCKpOInT"
+    ! { dg-output "CheCKpOInT(\n|\r\n|\r).*" }
+
     ! 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\]+\\\)" }
+    ! { dg-output "libgomp: present clause: not present on the device \\\(0x\[0-9a-f\]+, \[0-9\]+\\\)" { target offload_device_nonshared_as } }
+    ! { dg-shouldfail "present error triggered" { offload_device_nonshared_as } }
     !$omp target update to (present: b)
   !$omp target exit data map (from: c)
 end program

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [committed] OpenMP: Cleanups related to the 'present' modifier
@ 2023-06-12 16:44   ` Tobias Burnus
  2023-06-14  8:42     ` Thomas Schwinge
  0 siblings, 1 reply; 13+ messages in thread
From: Tobias Burnus @ 2023-06-12 16:44 UTC (permalink / raw)
  To: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 1094 bytes --]

Cleanup follow up to
   r14-1579-g4ede915d5dde93 "openmp: Add support for the 'present' modifier"
committed 6 days ago.

Namely:
* Replace for the program → libgomp ABI GOMP_MAP_PRESENT_[ALLOC,TO,FROM,TOFROM]
   by the preexisting GOMP_MAP_FORCE_PRESENT but keep the other enum values
   (and use them until gimplifcation).

* Improve wording if a non-existing/unsupported map-type modifier was used
   by not referring to 'omp target' as it could be also target (enter/exit) data.
   + Add a testcase for enter/exit data + data.

* Unify + improve wording shown for 'present' when not present on the device.

* Extend in the testcases to check that data actually gets copied with
   'target update' and 'map when the 'present' modifier is present.

Committed as Rev. r14-1736-g38944ec2a6fa10

Tobias
-----------------
Siemens Electronic Design Automation GmbH; Anschrift: Arnulfstraße 201, 80634 München; Gesellschaft mit beschränkter Haftung; Geschäftsführer: Thomas Heurung, Frank Thürauf; Sitz der Gesellschaft: München; Registergericht München, HRB 106955

[-- Attachment #2: committed.diff --]
[-- Type: text/x-patch, Size: 40444 bytes --]

commit 38944ec2a6fa108d24e5cfbb24c52020f9aa3015
Author: Tobias Burnus <tobias@codesourcery.com>
Date:   Mon Jun 12 18:15:28 2023 +0200

    OpenMP: Cleanups related to the 'present' modifier
    
    Reduce number of enum values passed to libgomp as
    GOMP_MAP_PRESENT_{TO,TOFROM,FROM,ALLOC} have the same semantic as
    GOMP_MAP_FORCE_PRESENT (i.e. abort if not present, otherwise ignore);
    that's different to GOMP_MAP_ALWAYS_PRESENT_{TO,TOFROM,FROM} which also
    abort if not present but copy data when present. This is is a follow-up to
    the commit r14-1579-g4ede915d5dde93 done 6 days ago.
    
    Additionally, the commit improves a libgomp run-time and a C/C++ compile-time
    error wording and extends testcases a tiny bit.
    
    gcc/c/ChangeLog:
    
            * c-parser.cc (c_parser_omp_clause_map): Reword error message for
            clearness especially with 'omp target (enter/exit) data.'
    
    gcc/cp/ChangeLog:
    
            * parser.cc (cp_parser_omp_clause_map): Reword error message for
            clearness especially with 'omp target (enter/exit) data.'
            * semantics.cc (handle_omp_array_sections): Handle
            GOMP_MAP_{ALWAYS_,}PRESENT_{TO,TOFROM,FROM,ALLOC} enum values.
    
    gcc/ChangeLog:
    
            * gimplify.cc (gimplify_adjust_omp_clauses_1): Use
            GOMP_MAP_FORCE_PRESENT for 'present alloc' implicit mapping.
            (gimplify_adjust_omp_clauses): Change
            GOMP_MAP_PRESENT_{TO,TOFROM,FROM,ALLOC} to the equivalent
            GOMP_MAP_FORCE_PRESENT.
            * omp-low.cc (lower_omp_target): Remove handling of no-longer valid
            GOMP_MAP_PRESENT_{TO,TOFROM,FROM,ALLOC}; update map kinds used for
            to/from clauses with present modifier.
    
    include/ChangeLog:
    
            * gomp-constants.h (enum gomp_map_kind): Change the enum values
            GOMP_MAP_PRESENT_{TO,TOFROM,FROM,ALLOC} to be compiler only.
            (GOMP_MAP_PRESENT_P): Update to include also GOMP_MAP_FORCE_PRESENT.
    
    libgomp/ChangeLog:
    
            * target.c (gomp_to_device_kind_p, gomp_map_vars_internal): Replace
            GOMP_MAP_PRESENT_{FROM,TO,TOFROM,ACLLOC} by GOMP_MAP_FORCE_PRESENT.
            (gomp_map_vars_internal, gomp_update): Likewise; unify and improve
            error message.
            * testsuite/libgomp.c-c++-common/target-present-2.c: Update for
            changed error message.
            * testsuite/libgomp.fortran/target-present-1.f90: Likewise.
            * testsuite/libgomp.fortran/target-present-2.f90: Likewise.
            * testsuite/libgomp.oacc-c-c++-common/present-1.c: Likewise.
            * testsuite/libgomp.c-c++-common/target-present-1.c: Likewise and
            extend testcase to check that data is copied when needed.
            * testsuite/libgomp.c-c++-common/target-present-3.c: Likewise.
            * testsuite/libgomp.fortran/target-present-3.f90: Likewise.
    
    gcc/testsuite/ChangeLog:
    
            * c-c++-common/gomp/defaultmap-4.c: Update scan-tree-dump.
            * c-c++-common/gomp/map-9.c: Likewise.
            * gfortran.dg/gomp/defaultmap-8.f90: Likewise.
            * gfortran.dg/gomp/map-11.f90: Likewise.
            * gfortran.dg/gomp/target-update-1.f90: Likewise.
            * gfortran.dg/gomp/map-12.f90: Likewise; also check original dump.
            * c-c++-common/gomp/map-6.c: Update dg-error and also check
            clause error with 'target (enter/exit) data'.
---
 gcc/c/c-parser.cc                                  |  5 +-
 gcc/cp/parser.cc                                   |  5 +-
 gcc/cp/semantics.cc                                |  7 +++
 gcc/gimplify.cc                                    | 13 ++++-
 gcc/omp-low.cc                                     | 14 ++----
 gcc/testsuite/c-c++-common/gomp/defaultmap-4.c     |  4 +-
 gcc/testsuite/c-c++-common/gomp/map-6.c            | 14 +++++-
 gcc/testsuite/c-c++-common/gomp/map-9.c            |  8 ++--
 gcc/testsuite/gfortran.dg/gomp/defaultmap-8.f90    |  4 +-
 gcc/testsuite/gfortran.dg/gomp/map-11.f90          |  8 ++--
 gcc/testsuite/gfortran.dg/gomp/map-12.f90          | 35 +++++++-------
 gcc/testsuite/gfortran.dg/gomp/target-update-1.f90 |  2 +-
 include/gomp-constants.h                           | 19 ++++----
 libgomp/target.c                                   | 55 ++++++++++------------
 .../libgomp.c-c++-common/target-present-1.c        | 20 ++++++--
 .../libgomp.c-c++-common/target-present-2.c        |  2 +-
 .../libgomp.c-c++-common/target-present-3.c        | 15 +++++-
 .../testsuite/libgomp.fortran/target-present-1.f90 |  2 +-
 .../testsuite/libgomp.fortran/target-present-2.f90 |  2 +-
 .../testsuite/libgomp.fortran/target-present-3.f90 | 19 ++++++--
 .../libgomp.oacc-c-c++-common/present-1.c          |  2 +-
 21 files changed, 153 insertions(+), 102 deletions(-)

diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index 72f6fbae6a6..61487cc7481 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -17160,9 +17160,8 @@ c_parser_omp_clause_map (c_parser *parser, tree list)
 	}
       else
 	{
-	  c_parser_error (parser, "%<#pragma omp target%> with "
-				  "modifier other than %<always%>, %<close%> "
-				  "or %<present%> on %<map%> clause");
+	  c_parser_error (parser, "%<map%> clause with map-type modifier other "
+				  "than %<always%>, %<close%> or %<present%>");
 	  parens.skip_until_found_close (parser);
 	  return list;
 	}
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 09cba713437..f5f9f5a4510 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -40625,9 +40625,8 @@ cp_parser_omp_clause_map (cp_parser *parser, tree list)
        }
       else
 	{
-	  cp_parser_error (parser, "%<#pragma omp target%> with "
-				   "modifier other than %<always%>, %<close%> "
-				   "or %<present%> on %<map%> clause");
+	  cp_parser_error (parser, "%<map%> clause with map-type modifier other"
+				   " than %<always%>, %<close%> or %<present%>");
 	  cp_parser_skip_to_closing_parenthesis (parser,
 						 /*recovering=*/true,
 						 /*or_comma=*/false,
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index a2e74a5d2c7..8fb47fd179e 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -5819,6 +5819,13 @@ handle_omp_array_sections (tree c, enum c_omp_region_type ort)
 	    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_DELETE:
 	    case GOMP_MAP_FORCE_TO:
diff --git a/gcc/gimplify.cc b/gcc/gimplify.cc
index 91640deecea..0e24b915b8f 100644
--- a/gcc/gimplify.cc
+++ b/gcc/gimplify.cc
@@ -12479,7 +12479,7 @@ gimplify_adjust_omp_clauses_1 (splay_tree_node n, void *data)
 	  kind = GOMP_MAP_FORCE_PRESENT;
 	  break;
 	case GOVD_MAP_FORCE_PRESENT | GOVD_MAP_ALLOC_ONLY:
-	  kind = GOMP_MAP_PRESENT_ALLOC;
+	  kind = GOMP_MAP_FORCE_PRESENT;
 	  break;
 	default:
 	  gcc_unreachable ();
@@ -12797,6 +12797,17 @@ gimplify_adjust_omp_clauses (gimple_seq *pre_p, gimple_seq body, tree *list_p,
 	  break;
 
 	case OMP_CLAUSE_MAP:
+	  switch (OMP_CLAUSE_MAP_KIND (c))
+	    {
+	    case GOMP_MAP_PRESENT_ALLOC:
+	    case GOMP_MAP_PRESENT_TO:
+	    case GOMP_MAP_PRESENT_FROM:
+	    case GOMP_MAP_PRESENT_TOFROM:
+	      OMP_CLAUSE_SET_MAP_KIND (c, GOMP_MAP_FORCE_PRESENT);
+	      break;
+	    default:
+	      break;
+	    }
 	  if (code == OMP_TARGET_EXIT_DATA
 	      && OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ALWAYS_POINTER)
 	    {
diff --git a/gcc/omp-low.cc b/gcc/omp-low.cc
index 1857b5b960f..b882df048ef 100644
--- a/gcc/omp-low.cc
+++ b/gcc/omp-low.cc
@@ -12800,10 +12800,7 @@ 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_FORCE_PRESENT:
 	  case GOMP_MAP_ALWAYS_PRESENT_FROM:
 	  case GOMP_MAP_ALWAYS_PRESENT_TO:
 	  case GOMP_MAP_ALWAYS_PRESENT_TOFROM:
@@ -12822,7 +12819,6 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx)
 	  case GOMP_MAP_FORCE_TO:
 	  case GOMP_MAP_FORCE_FROM:
 	  case GOMP_MAP_FORCE_TOFROM:
-	  case GOMP_MAP_FORCE_PRESENT:
 	  case GOMP_MAP_FORCE_DEVICEPTR:
 	  case GOMP_MAP_DEVICE_RESIDENT:
 	  case GOMP_MAP_LINK:
@@ -13349,10 +13345,6 @@ 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:
@@ -13397,13 +13389,13 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx)
 	      case OMP_CLAUSE_TO:
 		tkind
 		  = (OMP_CLAUSE_MOTION_PRESENT (c)
-		     ? GOMP_MAP_PRESENT_TO : GOMP_MAP_TO);
+		     ? GOMP_MAP_ALWAYS_PRESENT_TO : GOMP_MAP_TO);
 		tkind_zero = tkind;
 		break;
 	      case OMP_CLAUSE_FROM:
 		tkind
 		  = (OMP_CLAUSE_MOTION_PRESENT (c)
-		     ? GOMP_MAP_PRESENT_FROM : GOMP_MAP_FROM);
+		     ? GOMP_MAP_ALWAYS_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
index 1afff7ea38f..b84f89b0c7c 100644
--- a/gcc/testsuite/c-c++-common/gomp/defaultmap-4.c
+++ b/gcc/testsuite/c-c++-common/gomp/defaultmap-4.c
@@ -20,5 +20,5 @@ foo (void)
       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" } } */
+/* { dg-final { scan-tree-dump "pragma omp target.*defaultmap\\(present:aggregate\\) map\\(force_present:c \\\[len: \[0-9\]+\\\]\\\[implicit\\\]\\) map\\(force_present:b \\\[len: \[0-9\]+\\\]\\\[implicit\\\]\\) map\\(force_present:a \\\[len: \[0-9\]+\\\]\\\[implicit\\\]\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "pragma omp target.*defaultmap\\(present:aggregate\\) map\\(force_present:b \\\[len: \[0-9\]+\\\]\\\[implicit\\\]\\) map\\(force_present:a \\\[len: \[0-9\]+\\\]\\\[implicit\\\]\\) map\\(from:c \\\[len: \[0-9\]+\\\]\\)" "gimple" } } */
diff --git a/gcc/testsuite/c-c++-common/gomp/map-6.c b/gcc/testsuite/c-c++-common/gomp/map-6.c
index 8c5b7f7cca1..5152d9d7c21 100644
--- a/gcc/testsuite/c-c++-common/gomp/map-6.c
+++ b/gcc/testsuite/c-c++-common/gomp/map-6.c
@@ -13,12 +13,22 @@ 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', 'close' or 'present'" } */
+  #pragma omp target map (a to: b) /* { dg-error "'map' clause with map-type 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', 'close' or 'present'" } */
+  #pragma omp target map (close, a to: b) /* { dg-error "'map' clause with map-type modifier other than 'always', 'close' or 'present'" } */
   ;
 
+  #pragma omp target enter data map(b7) map (close, a to: b) /* { dg-error "'map' clause with map-type modifier other than 'always', 'close' or 'present'" } */
+  ;
+
+  #pragma omp target exit data map(b7) map (close, a from: b) /* { dg-error "'map' clause with map-type modifier other than 'always', 'close' or 'present'" } */
+  ;
+
+  #pragma omp target data map(b7) map (close, a from: b) /* { dg-error "'map' clause with map-type modifier other than 'always', 'close' or 'present'" } */
+  ;
+
+
   #pragma omp target map (close a) /* { dg-error "'close' undeclared" "" { target c } } */ 
   /* { dg-error "'close' has not been declared" "" { target c++ } .-1 } */ 
   /* { dg-error "expected '\\)' before 'a'" "" { target *-*-* } .-2 } */
diff --git a/gcc/testsuite/c-c++-common/gomp/map-9.c b/gcc/testsuite/c-c++-common/gomp/map-9.c
index 4b4bd6d2aa3..fcf3125ceee 100644
--- a/gcc/testsuite/c-c++-common/gomp/map-9.c
+++ b/gcc/testsuite/c-c++-common/gomp/map-9.c
@@ -25,8 +25,8 @@ foo (void)
       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 enter data map\\(force_present:b \\\[len: \[0-9\]+\\\]\\) map\\(force_present:a \\\[len: \[0-9\]+\\\]\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "pragma omp target data map\\(force_present:b \\\[len: \[0-9\]+\\\]\\) map\\(force_present:a \\\[len: \[0-9\]+\\\]\\) map\\(always,present,from:c \\\[len: \[0-9\]+\\\]\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "pragma omp target.*map\\(force_present:c \\\[len: \[0-9\]+\\\]\\) map\\(force_present:b \\\[len: \[0-9\]+\\\]\\) map\\(force_present: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" } } */
+/* { dg-final { scan-tree-dump "pragma omp target.*map\\(force_present:b \\\[len: \[0-9\]+\\\]\\) map\\(from:c \\\[len: \[0-9\]+\\\]\\) map\\(to:a \\\[len: \[0-9\]+\\\]\\)" "gimple" } } */
diff --git a/gcc/testsuite/gfortran.dg/gomp/defaultmap-8.f90 b/gcc/testsuite/gfortran.dg/gomp/defaultmap-8.f90
index 669a623f746..e26d1e004b1 100644
--- a/gcc/testsuite/gfortran.dg/gomp/defaultmap-8.f90
+++ b/gcc/testsuite/gfortran.dg/gomp/defaultmap-8.f90
@@ -22,5 +22,5 @@ program main
   !$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" } }
+! { dg-final { scan-tree-dump "pragma omp target.*defaultmap\\(present:aggregate\\).*map\\(force_present:c \\\[len: \[0-9\]+\\\]\\\[implicit\\\]\\) map\\(force_present:b \\\[len: \[0-9\]+\\\]\\\[implicit\\\]\\) map\\(force_present:a \\\[len: \[0-9\]+\\\]\\\[implicit\\\]\\)" "gimple" } }
+! { dg-final { scan-tree-dump "pragma omp target.*map\\(force_present:b \\\[len: \[0-9\]+\\\]\\\[implicit\\\]\\) map\\(force_present: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
index 9eb956f1aa1..7ef9d46f2f8 100644
--- a/gcc/testsuite/gfortran.dg/gomp/map-11.f90
+++ b/gcc/testsuite/gfortran.dg/gomp/map-11.f90
@@ -27,8 +27,8 @@ program main
   !$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 enter data map\\(force_present:a \\\[len: \[0-9\]+\\\]\\) map\\(force_present:b \\\[len: \[0-9\]+\\\]\\)" "gimple" } }
+! { dg-final { scan-tree-dump "pragma omp target data map\\(force_present:a \\\[len: \[0-9\]+\\\]\\) map\\(force_present:b \\\[len: \[0-9\]+\\\]\\) map\\(always,present,from:c \\\[len: \[0-9\]+\\\]\\)" "gimple" } }
+! { dg-final { scan-tree-dump "pragma omp target.*map\\(force_present:a \\\[len: \[0-9\]+\\\]\\) map\\(force_present:b \\\[len: \[0-9\]+\\\]\\) map\\(force_present: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" } }
+! { dg-final { scan-tree-dump "pragma omp target.*map\\(force_present: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
index 74bd01f5f5a..ac9a0f8aae0 100644
--- a/gcc/testsuite/gfortran.dg/gomp/map-12.f90
+++ b/gcc/testsuite/gfortran.dg/gomp/map-12.f90
@@ -1,4 +1,4 @@
-! { dg-additional-options "-fdump-tree-omplower" }
+! { dg-additional-options "-fdump-tree-omplower -fdump-tree-original" }
 
 subroutine foo
   implicit none
@@ -40,28 +40,29 @@ subroutine foo
   !$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\\)\[\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\\(alloc:a\\) map\\(to:b\\) map\\(to:b1\\)\[\r\n\]" 2 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp target enter data map\\(alloc:a\\) map\\(always,to:b\\) map\\(always,to:b1\\)\[\r\n\]" 2 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp target enter data map\\(present,alloc:a\\) map\\(present,to:b\\) map\\(present,to:b1\\)\[\r\n\]" 2 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp target enter data map\\(present,alloc:a\\) map\\(always,present,to:b\\) map\\(always,present,to:b1\\)\[\r\n\]" 2 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp target exit data map\\(delete:a\\) map\\(release:b\\) map\\(from:b1\\)\[\r\n\]" 2 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp target exit data map\\(delete:a\\) map\\(release:b\\) map\\(always,from:b1\\)\[\r\n\]" 2 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp target exit data map\\(delete:a\\) map\\(release:b\\) map\\(present,from:b1\\)\[\r\n\]" 2 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp target exit data map\\(delete:a\\) map\\(release:b\\) map\\(always,present,from:b1\\)\[\r\n\]" 2 "original" } }
+
 
 ! { 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\\(force_present: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 enter data map\\(force_present:a \\\[len: 4\\\]\\) map\\(force_present:b \\\[len: 4\\\]\\) map\\(force_present:b1 \\\[len: 4\\\]\\)\[\r\n\]" 2 "omplower" } }
+! { dg-final { scan-tree-dump-times "#pragma omp target enter data map\\(force_present: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\\(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\\(force_present: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" } }
diff --git a/gcc/testsuite/gfortran.dg/gomp/target-update-1.f90 b/gcc/testsuite/gfortran.dg/gomp/target-update-1.f90
index f99bffe2e0b..a9db2f1a39f 100644
--- a/gcc/testsuite/gfortran.dg/gomp/target-update-1.f90
+++ b/gcc/testsuite/gfortran.dg/gomp/target-update-1.f90
@@ -10,4 +10,4 @@ program main
   !$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" } }
+! { 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\\(d \\\[len: \[0-9\]+\\\]\\) from\\(present:b \\\[len: \[0-9\]+\\\]\\)" "gimple" } }
diff --git a/include/gomp-constants.h b/include/gomp-constants.h
index 49b7dd86ff5..8d4e8e81303 100644
--- a/include/gomp-constants.h
+++ b/include/gomp-constants.h
@@ -136,14 +136,6 @@ 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),
@@ -205,7 +197,13 @@ enum gomp_map_kind
     /* An attach or detach operation.  Rewritten to the appropriate type during
        gimplification, depending on directive (i.e. "enter data" or
        parallel/kernels region vs. "exit data").  */
-    GOMP_MAP_ATTACH_DETACH =		(GOMP_MAP_LAST | 3)
+    GOMP_MAP_ATTACH_DETACH =		(GOMP_MAP_LAST | 3),
+    /* Must already be present - all of following map to GOMP_MAP_FORCE_PRESENT
+       as no data transfer is needed.  */
+    GOMP_MAP_PRESENT_ALLOC =		(GOMP_MAP_LAST | 4),
+    GOMP_MAP_PRESENT_TO =		(GOMP_MAP_LAST | 5),
+    GOMP_MAP_PRESENT_FROM =		(GOMP_MAP_LAST | 6),
+    GOMP_MAP_PRESENT_TOFROM =		(GOMP_MAP_LAST | 7)
   };
 
 #define GOMP_MAP_COPY_TO_P(X) \
@@ -243,7 +241,8 @@ enum gomp_map_kind
   (((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)
+  (((X) & GOMP_MAP_FLAG_PRESENT) == GOMP_MAP_FLAG_PRESENT \
+   || (X) == GOMP_MAP_FORCE_PRESENT)
 
 
 /* Asynchronous behavior.  Keep in sync with
diff --git a/libgomp/target.c b/libgomp/target.c
index a9e8005c588..e3c4121a09f 100644
--- a/libgomp/target.c
+++ b/libgomp/target.c
@@ -358,8 +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:
+    case GOMP_MAP_FORCE_PRESENT:
       return false;
     default:
       return true;
@@ -1699,37 +1699,29 @@ gomp_map_vars_internal (struct gomp_device_descr *devicep,
 		    i = j - 1;
 		    break;
 		  case GOMP_MAP_FORCE_PRESENT:
+		  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.  */
 		      size_t size = k->host_end - k->host_start;
 		      gomp_mutex_unlock (&devicep->lock);
 #ifdef HAVE_INTTYPES_H
-		      gomp_fatal ("present clause: !acc_is_present (%p, "
-				  "%"PRIu64" (0x%"PRIx64"))",
-				  (void *) k->host_start,
-				  (uint64_t) size, (uint64_t) size);
+		      gomp_fatal ("present clause: not present on the device "
+				  "(addr: %p, size: %"PRIu64" (0x%"PRIx64"), "
+				  "dev: %d)", (void *) k->host_start,
+				  (uint64_t) size, (uint64_t) size,
+				  devicep->target_id);
 #else
-		      gomp_fatal ("present clause: !acc_is_present (%p, "
-				  "%lu (0x%lx))", (void *) k->host_start,
-				  (unsigned long) size, (unsigned long) size);
+		      gomp_fatal ("present clause: not present on the device "
+				  "(addr: %p, size: %lu (0x%lx), dev: %d)",
+				  (void *) k->host_start,
+				  (unsigned long) size, (unsigned long) size,
+				  devicep->target_id);
 #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,
@@ -2149,9 +2141,18 @@ gomp_update (struct gomp_device_descr *devicep, size_t mapnum, void **hostaddrs,
 		/* We already looked up the memory region above and it
 		   was missing.  */
 		gomp_mutex_unlock (&devicep->lock);
+#ifdef HAVE_INTTYPES_H
 		gomp_fatal ("present clause: not present on the device "
-			    "(%p, %d)",
-			    (void *) hostaddrs[i], devicep->target_id);
+			    "(addr: %p, size: %"PRIu64" (0x%"PRIx64"), "
+			    "dev: %d)", (void *) hostaddrs[i],
+			    (uint64_t) sizes[i], (uint64_t) sizes[i],
+			    devicep->target_id);
+#else
+		gomp_fatal ("present clause: not present on the device "
+			    "(addr: %p, size: %lu (0x%lx), dev: %d)",
+			    (void *) hostaddrs[i], (unsigned long) sizes[i],
+			    (unsigned long) sizes[i], devicep->target_id);
+#endif
 	      }
 	  }
       }
@@ -3465,9 +3466,7 @@ 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_FORCE_PRESENT:
 	      case GOMP_MAP_ALWAYS_PRESENT_FROM:
 	      case GOMP_MAP_ALWAYS_PRESENT_TO:
 	      case GOMP_MAP_ALWAYS_PRESENT_TOFROM:
@@ -3710,8 +3709,6 @@ 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;
diff --git a/libgomp/testsuite/libgomp.c-c++-common/target-present-1.c b/libgomp/testsuite/libgomp.c-c++-common/target-present-1.c
index aa343197e35..5eaa9cd1ad3 100644
--- a/libgomp/testsuite/libgomp.c-c++-common/target-present-1.c
+++ b/libgomp/testsuite/libgomp.c-c++-common/target-present-1.c
@@ -4,24 +4,34 @@
 
 int main (void)
 {
-  int a[N], b[N], c[N];
+  int a[N], b[N], c[N], d[N];
 
   for (int i = 0; i < N; i++) {
     a[i] = i * 2;
     b[i] = i * 3 + 1;
+    d[i] = i * 5;
   }
 
-  #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)
+  #pragma omp target enter data map (alloc: c, d) map(to: a)
+    #pragma omp target map (present, always, to: d)
+      for (int i = 0; i < N; i++)
+	if (d[i] != i * 5)
+	  __builtin_abort ();
+
+    /* a has already been mapped and 'c' allocated so this should be okay.  */
+    #pragma omp target map (present, to: a) map(present, always, from: c)
       for (int i = 0; i < N; i++)
 	c[i] = a[i];
 
+    for (int i = 0; i < N; i++)
+      if (c[i] != i * 2)
+	__builtin_abort ();
+
     fprintf (stderr, "CheCKpOInT\n");
     /* { dg-output "CheCKpOInT(\n|\r\n|\r).*" } */
 
     /* 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\]+\\\)" { target offload_device_nonshared_as } } */
+    /* { dg-output "libgomp: present clause: not present on the device \\(addr: 0x\[0-9a-f\]+, size: \[0-9\]+ \\(0x\[0-9a-f\]+\\), dev: \[0-9\]+\\\)" { target offload_device_nonshared_as } } */
     /* { dg-shouldfail "present error triggered" { offload_device_nonshared_as } } */
     #pragma omp target map (present, to: b)
       for (int i = 0; i < N; i++)
diff --git a/libgomp/testsuite/libgomp.c-c++-common/target-present-2.c b/libgomp/testsuite/libgomp.c-c++-common/target-present-2.c
index ad11023b2d6..07ae90b5aaa 100644
--- a/libgomp/testsuite/libgomp.c-c++-common/target-present-2.c
+++ b/libgomp/testsuite/libgomp.c-c++-common/target-present-2.c
@@ -21,7 +21,7 @@ int main (void)
     /* { dg-output "CheCKpOInT(\n|\r\n|\r).*" } */
 
     /* 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\]+\\\)" { target offload_device_nonshared_as } } */
+    /* { dg-output "libgomp: present clause: not present on the device \\(addr: 0x\[0-9a-f\]+, size: \[0-9\]+ \\(0x\[0-9a-f\]+\\), dev: \[0-9\]+\\\)" { target offload_device_nonshared_as } } */
     /* { dg-shouldfail "present error triggered" { offload_device_nonshared_as } } */
     #pragma omp target defaultmap (present)
       for (int i = 0; i < N; i++)
diff --git a/libgomp/testsuite/libgomp.c-c++-common/target-present-3.c b/libgomp/testsuite/libgomp.c-c++-common/target-present-3.c
index 455519af405..582247dc05e 100644
--- a/libgomp/testsuite/libgomp.c-c++-common/target-present-3.c
+++ b/libgomp/testsuite/libgomp.c-c++-common/target-present-3.c
@@ -16,11 +16,24 @@ int main (void)
   /* This should work as a has already been allocated.  */
   #pragma omp target update to (present: a)
 
+  #pragma omp target map(present,alloc: a, c)
+  for (int i = 0; i < N; i++) {
+    if (a[i] != i * 2)
+      __builtin_abort ();
+    c[i] = 23*i;
+  }
+
+  #pragma omp target update from(present : c)
+  for (int i = 0; i < N; i++) {
+    if (c[i] != 23*i)
+      __builtin_abort ();
+  }
+
   fprintf (stderr, "CheCKpOInT\n");
   /* { dg-output "CheCKpOInT(\n|\r\n|\r).*" } */
 
   /* 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\]+\\\)" { target offload_device_nonshared_as } } */
+    /* { dg-output "libgomp: present clause: not present on the device \\(addr: 0x\[0-9a-f\]+, size: \[0-9\]+ \\(0x\[0-9a-f\]+\\), dev: \[0-9\]+\\\)" { target offload_device_nonshared_as } } */
   /* { dg-shouldfail "present error triggered" { offload_device_nonshared_as } } */
   #pragma omp target update to (present: b)
 
diff --git a/libgomp/testsuite/libgomp.fortran/target-present-1.f90 b/libgomp/testsuite/libgomp.fortran/target-present-1.f90
index 768166fcff7..fc13609d528 100644
--- a/libgomp/testsuite/libgomp.fortran/target-present-1.f90
+++ b/libgomp/testsuite/libgomp.fortran/target-present-1.f90
@@ -20,7 +20,7 @@ program main
     ! { dg-output "CheCKpOInT(\n|\r\n|\r).*" }
 
     ! 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\]+\\\)" { target offload_device_nonshared_as } }
+    ! { dg-output "libgomp: present clause: not present on the device \\(addr: 0x\[0-9a-f\]+, size: \[0-9\]+ \\(0x\[0-9a-f\]+\\), dev: \[0-9\]+\\\)" { target offload_device_nonshared_as } }
     ! { dg-shouldfail "present error triggered" { offload_device_nonshared_as } }
     !$omp target map (present, to: b)
       do i = 1, N
diff --git a/libgomp/testsuite/libgomp.fortran/target-present-2.f90 b/libgomp/testsuite/libgomp.fortran/target-present-2.f90
index 8f2c24ef5f2..524d01d9465 100644
--- a/libgomp/testsuite/libgomp.fortran/target-present-2.f90
+++ b/libgomp/testsuite/libgomp.fortran/target-present-2.f90
@@ -20,7 +20,7 @@ program main
     ! { dg-output "CheCKpOInT(\n|\r\n|\r).*" }
 
     ! 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\]+\\\)" { target offload_device_nonshared_as } }
+    ! { dg-output "libgomp: present clause: not present on the device \\(addr: 0x\[0-9a-f\]+, size: \[0-9\]+ \\(0x\[0-9a-f\]+\\), dev: \[0-9\]+\\\)" { target offload_device_nonshared_as } }
     ! { dg-shouldfail "present error triggered" { offload_device_nonshared_as } }
     !$omp target defaultmap (present)
       do i = 1, N
diff --git a/libgomp/testsuite/libgomp.fortran/target-present-3.f90 b/libgomp/testsuite/libgomp.fortran/target-present-3.f90
index eb29c907624..dd4af4c1651 100644
--- a/libgomp/testsuite/libgomp.fortran/target-present-3.f90
+++ b/libgomp/testsuite/libgomp.fortran/target-present-3.f90
@@ -9,14 +9,27 @@ program main
   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 work as a has already been allocated.
+  !$omp target update to (present: a)
+
+  !$omp target map(present, alloc: a, c)
+    do i = 1, N
+      if (a(i) /= i * 2) stop 1
+      c(i) = 23 * i
+    end do
+  !$omp end target
+
+  !$omp target update from (present: c)
+    do i = 1, N
+      if (c(i) /= 23 * i) stop 1
+    end do
 
     print *, "CheCKpOInT"
     ! { dg-output "CheCKpOInT(\n|\r\n|\r).*" }
 
     ! 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\]+\\\)" { target offload_device_nonshared_as } }
+    ! { dg-output "libgomp: present clause: not present on the device \\(addr: 0x\[0-9a-f\]+, size: \[0-9\]+ \\(0x\[0-9a-f\]+\\), dev: \[0-9\]+\\\)" { target offload_device_nonshared_as } }
     ! { dg-shouldfail "present error triggered" { offload_device_nonshared_as } }
     !$omp target update to (present: b)
   !$omp target exit data map (from: c)
diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/present-1.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/present-1.c
index 61c8109a7e0..02fbfdaf9ed 100644
--- a/libgomp/testsuite/libgomp.oacc-c-c++-common/present-1.c
+++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/present-1.c
@@ -48,5 +48,5 @@ main (int argc, char **argv)
 }
 
 /* { dg-output "CheCKpOInT(\n|\r\n|\r).*" } */
-/* { dg-output "present clause: !acc_is_present" } */
+/* { dg-output "libgomp: present clause: not present on the device \\(addr: 0x\[0-9a-f\]+, size: \[0-9\]+ \\(0x\[0-9a-f\]+\\), dev: \[0-9\]+\\\)" } */
 /* { dg-shouldfail "" } */

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [committed] OpenMP: Cleanups related to the 'present' modifier
  2023-06-12 16:44   ` [committed] OpenMP: Cleanups related to the 'present' modifier Tobias Burnus
@ 2023-06-14  8:42     ` Thomas Schwinge
  2023-06-14 10:00       ` Tobias Burnus
  0 siblings, 1 reply; 13+ messages in thread
From: Thomas Schwinge @ 2023-06-14  8:42 UTC (permalink / raw)
  To: Tobias Burnus, gcc-patches; +Cc: Jakub Jelinek, Kwok Cheung Yeung

Hi Tobias!

On 2023-06-12T18:44:23+0200, Tobias Burnus <tobias@codesourcery.com> wrote:
> Cleanup follow up to
>    r14-1579-g4ede915d5dde93 "openmp: Add support for the 'present' modifier"
> committed 6 days ago.
>
> Namely:
> * Replace for the program → libgomp ABI GOMP_MAP_PRESENT_[ALLOC,TO,FROM,TOFROM]
>    by the preexisting GOMP_MAP_FORCE_PRESENT but keep the other enum values
>    (and use them until gimplifcation).
>
> * Improve wording if a non-existing/unsupported map-type modifier was used
>    by not referring to 'omp target' as it could be also target (enter/exit) data.
>    + Add a testcase for enter/exit data + data.
>
> * Unify + improve wording shown for 'present' when not present on the device.
>
> * Extend in the testcases to check that data actually gets copied with
>    'target update' and 'map when the 'present' modifier is present.
>
> Committed as Rev. r14-1736-g38944ec2a6fa10

>     OpenMP: Cleanups related to the 'present' modifier
>
>     Reduce number of enum values passed to libgomp as
>     GOMP_MAP_PRESENT_{TO,TOFROM,FROM,ALLOC} have the same semantic as
>     GOMP_MAP_FORCE_PRESENT (i.e. abort if not present, otherwise ignore);
>     that's different to GOMP_MAP_ALWAYS_PRESENT_{TO,TOFROM,FROM} which also
>     abort if not present but copy data when present. This is is a follow-up to
>     the commit r14-1579-g4ede915d5dde93 done 6 days ago.

Great, that matches how I thought this should be done (re our 2023-06-07
GCC IRC discussion).

>     Additionally, the commit [...]
>     extends testcases a tiny bit.

>     gcc/testsuite/ChangeLog:

>             * gfortran.dg/gomp/target-update-1.f90: Likewise.

That one addressed fixed <https://gcc.gnu.org/110178>
"gfortran.dg/gomp/target-update-1.f90 fails after r14-1579-g4ede915d5dde93".

> --- a/include/gomp-constants.h
> +++ b/include/gomp-constants.h

|  #define GOMP_MAP_FLAG_PRESENT                (GOMP_MAP_FLAG_SPECIAL_5 \
|                                        | GOMP_MAP_FLAG_SPECIAL_0)

Couldn't/shouldn't we now get rid of this 'GOMP_MAP_FLAG_PRESENT'...

|  #define GOMP_MAP_FLAG_ALWAYS_PRESENT (GOMP_MAP_FLAG_SPECIAL_2 \
|                                        | GOMP_MAP_FLAG_PRESENT)

..., as it is only used in 'GOMP_MAP_FLAG_ALWAYS_PRESENT' here...

> @@ -136,14 +136,6 @@ 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),
> @@ -205,7 +197,13 @@ enum gomp_map_kind
>      /* An attach or detach operation.  Rewritten to the appropriate type during
>         gimplification, depending on directive (i.e. "enter data" or
>         parallel/kernels region vs. "exit data").  */
> -    GOMP_MAP_ATTACH_DETACH =         (GOMP_MAP_LAST | 3)
> +    GOMP_MAP_ATTACH_DETACH =         (GOMP_MAP_LAST | 3),
> +    /* Must already be present - all of following map to GOMP_MAP_FORCE_PRESENT
> +       as no data transfer is needed.  */
> +    GOMP_MAP_PRESENT_ALLOC =         (GOMP_MAP_LAST | 4),
> +    GOMP_MAP_PRESENT_TO =            (GOMP_MAP_LAST | 5),
> +    GOMP_MAP_PRESENT_FROM =          (GOMP_MAP_LAST | 6),
> +    GOMP_MAP_PRESENT_TOFROM =                (GOMP_MAP_LAST | 7)
>    };
>
>  #define GOMP_MAP_COPY_TO_P(X) \
> @@ -243,7 +241,8 @@ enum gomp_map_kind
>    (((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)
> +  (((X) & GOMP_MAP_FLAG_PRESENT) == GOMP_MAP_FLAG_PRESENT \
> +   || (X) == GOMP_MAP_FORCE_PRESENT)

..., and this 'GOMP_MAP_PRESENT_P' should look for
'GOMP_MAP_FLAG_ALWAYS_PRESENT' instead of 'GOMP_MAP_FLAG_PRESENT' (plus
'GOMP_MAP_FORCE_PRESENT')?

Instead of the current effective 'GOMP_MAP_FLAG_ALWAYS_PRESENT':

    GOMP_MAP_FLAG_SPECIAL_0
    | GOMP_MAP_FLAG_SPECIAL_2
    | GOMP_MAP_FLAG_SPECIAL_5

..., it could/should use a simpler flag combination?  (My idea is that
this later make usage of flag bits for other purposes easier -- but I've
not verified that in depth.)


Grüße
 Thomas
-----------------
Siemens Electronic Design Automation GmbH; Anschrift: Arnulfstraße 201, 80634 München; Gesellschaft mit beschränkter Haftung; Geschäftsführer: Thomas Heurung, Frank Thürauf; Sitz der Gesellschaft: München; Registergericht München, HRB 106955

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [committed] OpenMP: Cleanups related to the 'present' modifier
  2023-06-14  8:42     ` Thomas Schwinge
@ 2023-06-14 10:00       ` Tobias Burnus
  0 siblings, 0 replies; 13+ messages in thread
From: Tobias Burnus @ 2023-06-14 10:00 UTC (permalink / raw)
  To: Thomas Schwinge, gcc-patches; +Cc: Jakub Jelinek

[-- Attachment #1: Type: text/plain, Size: 1467 bytes --]

On 14.06.23 10:42, Thomas Schwinge wrote:
> Couldn't/shouldn't we now get rid of this 'GOMP_MAP_FLAG_PRESENT'...
...
>>   #define GOMP_MAP_PRESENT_P(X) \
>> -  (((X) & GOMP_MAP_FLAG_PRESENT) == GOMP_MAP_FLAG_PRESENT)
>> +  (((X) & GOMP_MAP_FLAG_PRESENT) == GOMP_MAP_FLAG_PRESENT \
>> +   || (X) == GOMP_MAP_FORCE_PRESENT)
> ..., and this 'GOMP_MAP_PRESENT_P' should look for
> 'GOMP_MAP_FLAG_ALWAYS_PRESENT' instead of 'GOMP_MAP_FLAG_PRESENT' (plus
> 'GOMP_MAP_FORCE_PRESENT')?
>
> Instead of the current effective 'GOMP_MAP_FLAG_ALWAYS_PRESENT':
>
>      GOMP_MAP_FLAG_SPECIAL_0
>      | GOMP_MAP_FLAG_SPECIAL_2
>      | GOMP_MAP_FLAG_SPECIAL_5
>
> ..., it could/should use a simpler flag combination?  (My idea is that
> this later make usage of flag bits for other purposes easier -- but I've
> not verified that in depth.)

I concur that it would be useful to save that space. We do not fully
rule out other combinations as we can always move to check single values
instead of comparing bit patterns, but I concur, reserving flags would
be useful.

Can you propose some bit pattern to use? Attached are the currently used
ones (binary, hex, and decimal).

Tobias
-----------------
Siemens Electronic Design Automation GmbH; Anschrift: Arnulfstraße 201, 80634 München; Gesellschaft mit beschränkter Haftung; Geschäftsführer: Thomas Heurung, Frank Thürauf; Sitz der Gesellschaft: München; Registergericht München, HRB 106955

[-- Attachment #2: bitpattern.txt --]
[-- Type: text/plain, Size: 1890 bytes --]

100000000	0x100	256	GOMP_MAP_LAST
000000000	0x000	  0	GOMP_MAP_ALLOC
000000001	0x001	  1	GOMP_MAP_TO
000000010	0x002	  2	GOMP_MAP_FROM
000000011	0x003	  3	GOMP_MAP_TOFROM
000000100	0x004	  4	GOMP_MAP_POINTER
000000101	0x005	  5	GOMP_MAP_TO_PSET
000000110	0x006	  6	GOMP_MAP_FORCE_PRESENT
000000111	0x007	  7	GOMP_MAP_DELETE
000001000	0x008	  8	GOMP_MAP_FORCE_DEVICEPTR
000001001	0x009	  9	GOMP_MAP_DEVICE_RESIDENT
000001010	0x00a	 10	GOMP_MAP_LINK
000001011	0x00b	 11	GOMP_MAP_IF_PRESENT
000001100	0x00c	 12	GOMP_MAP_FIRSTPRIVATE
000001101	0x00d	 13	GOMP_MAP_FIRSTPRIVATE_INT
000001110	0x00e	 14	GOMP_MAP_USE_DEVICE_PTR
000001111	0x00f	 15	GOMP_MAP_ZERO_LEN_ARRAY_SECTION
010000000	0x080	128	GOMP_MAP_FORCE_ALLOC
010000001	0x081	129	GOMP_MAP_FORCE_TO
010000010	0x082	130	GOMP_MAP_FORCE_FROM
010000011	0x083	131	GOMP_MAP_FORCE_TOFROM
000010000	0x010	 16	GOMP_MAP_USE_DEVICE_PTR_IF_PRESENT
000010001	0x011	 17	GOMP_MAP_ALWAYS_TO
000010010	0x012	 18	GOMP_MAP_ALWAYS_FROM
000010011	0x013	 19	GOMP_MAP_ALWAYS_TOFROM
010010101	0x095	149	GOMP_MAP_ALWAYS_PRESENT_TO
010010110	0x096	150	GOMP_MAP_ALWAYS_PRESENT_FROM
010010111	0x097	151	GOMP_MAP_ALWAYS_PRESENT_TOFROM
000011100	0x01c	 28	GOMP_MAP_STRUCT
000011101	0x01d	 29	GOMP_MAP_ALWAYS_POINTER
000011110	0x01e	 30	GOMP_MAP_POINTER_TO_ZERO_LENGTH_ARRAY_SECTION
000011111	0x01f	 31	GOMP_MAP_DELETE_ZERO_LEN_ARRAY_SECTION
000010111	0x017	 23	GOMP_MAP_RELEASE
001010000	0x050	 80	GOMP_MAP_ATTACH
001010001	0x051	 81	GOMP_MAP_DETACH
011010001	0x0d1	209	GOMP_MAP_FORCE_DETACH
001010010	0x052	 82	GOMP_MAP_ATTACH_ZERO_LENGTH_ARRAY_SECTION
100000001	0x101	257	GOMP_MAP_FIRSTPRIVATE_POINTER
100000010	0x102	258	GOMP_MAP_FIRSTPRIVATE_REFERENCE
100000011	0x103	259	GOMP_MAP_ATTACH_DETACH
100000100	0x104	260	GOMP_MAP_PRESENT_ALLOC
100000101	0x105	261	GOMP_MAP_PRESENT_TO
100000110	0x106	262	GOMP_MAP_PRESENT_FROM
100000111	0x107	263	GOMP_MAP_PRESENT_TOFROM

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2023-06-14 10:00 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-02-03 13:44 [PATCH] openmp: Add support for 'present' modifier Kwok Cheung Yeung
2023-02-09 21:17 ` [OG12][committed] openmp: Add support for the " Kwok Cheung Yeung
2023-02-14 22:44   ` [og12] Address cast to pointer from integer of different size in 'libgomp/target.c:gomp_target_rev' (was: [OG12][committed] openmp: Add support for the 'present' modifier) Thomas Schwinge
2023-02-15  0:00   ` [OG12][committed] openmp: Add support for the 'present' modifier Kwok Cheung Yeung
2023-02-15 19:02   ` [og12] Fix 'libgomp.{c-c++-common,fortran}/target-present-*' test cases (was: [OG12][committed] openmp: Add support for the 'present' modifier) Thomas Schwinge
2023-06-07 11:25     ` [committed] testsuite/libgomp.*/target-present-*.{c,f90}: Improve and fix (was: Re: [og12] Fix 'libgomp.{c-c++-common,fortran}/target-present-*' test cases) Tobias Burnus
2023-06-07 11:26     ` Tobias Burnus
2023-06-12 16:44   ` [committed] OpenMP: Cleanups related to the 'present' modifier Tobias Burnus
2023-06-14  8:42     ` Thomas Schwinge
2023-06-14 10:00       ` Tobias Burnus
2023-02-17 11:45 ` [PATCHv2] openmp: Add support for " Kwok Cheung Yeung
2023-04-28 17:26   ` Tobias Burnus
2023-06-06 14:55     ` [committed] " Tobias Burnus

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).