public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [gomp4.1] Initial support for some OpenMP 4.1 construct parsing
@ 2015-04-29 11:44 Jakub Jelinek
  2015-04-29 11:55 ` Thomas Schwinge
  0 siblings, 1 reply; 33+ messages in thread
From: Jakub Jelinek @ 2015-04-29 11:44 UTC (permalink / raw)
  To: Kirill Yukhin, Thomas Schwinge, Richard Henderson; +Cc: gcc-patches

Hi!

Here is what I've committed to gomp-4_1-branch, a new branch for OpenMP 4.1
support.  The intent is to develop OpenMP 4.1 support on the branch and
merge to trunk either when OpenMP 4.1 standard is released, or when
sufficiently close to the release, ideally before end of stage1.

I'll probably work on taskloop construct next.

2015-04-29  Jakub Jelinek  <jakub@redhat.com>

gcc/
	* gimple.h (enum gf_mask): Increment GF_OMP_TARGET_KIND_MASK
	to 15 from 7.  Add GF_OMP_TARGET_KIND_ENTER_DATA and
	GF_OMP_TARGET_KIND_EXIT_DATA, renumber GF_OMP_TARGET_KIND_OACC*.
	* tree.h (OMP_ORDERED_CLAUSES, OMP_TARGET_ENTER_DATA_CLAUSES,
	OMP_TARGET_EXIT_DATA_CLAUSES, OMP_CLAUSE_NUM_TASKS_EXPR,
	OMP_CLAUSE_GRAINSIZE_EXPR, OMP_CLAUSE_PRIORITY_EXPR,
	OMP_CLAUSE_ORDERED_EXPR): Define.
	* tree.def (OMP_TASKLOOP, OMP_TARGET_ENTER_DATA,
	OMP_TARGET_EXIT_DATA): New tree codes.
	(OMP_ORDERED): Add second operand - OMP_ORDERED_CLAUSES.  Move
	before OMP_SINGLE, so that OMP_CLAUSES can be used on it too.
	* gimplify.c (gimplify_scan_omp_clauses): Handle
	OMP_CLAUSE_{PRIORITY,GRAINSIZE,NUM_TASKS,NOGROUP,THREADS,SIMD,SIMDLEN}
	clauses.
	(gimplify_adjust_omp_clauses): Likewise.
	(gimplify_omp_target_update): Handle OMP_TARGET_ENTER_DATA
	and OMP_TARGET_EXIT_DATA.
	(gimplify_expr): Likewise.
	* tree.c (omp_clause_num_ops): Change OMP_CLAUSE_ORDERED operand
	count to 1 from 0.  Add entries for
	OMP_CLAUSE_{PRIORITY,GRAINSIZE,NUM_TASKS,NOGROUP,THREADS,SIMD}.
	(omp_clause_code_name): Add names for
	OMP_CLAUSE_{PRIORITY,GRAINSIZE,NUM_TASKS,NOGROUP,THREADS,SIMD}
	clauses.
	(walk_tree_1): Handle
	OMP_CLAUSE_{PRIORITY,GRAINSIZE,NUM_TASKS,NOGROUP,THREADS,SIMD}
	clauses.  Handle OMP_CLAUSE_ORDERED as other 1 operand clauses.
	* tree-nested.c (convert_nonlocal_omp_clauses): Handle
	OMP_CLAUSE_{PRIORITY,GRAINSIZE,NUM_TASKS,NOGROUP,THREADS,SIMD,SIMDLEN}
	clauses.
	(convert_local_omp_clauses): Likewise.
	* gimple-pretty-print.c (dump_gimple_omp_target): Handle
	GF_OMP_TARGET_KIND_ENTER_DATA and GF_OMP_TARGET_KIND_EXIT_DATA.
	* tree-core.h (enum omp_clause_code): Add
	OMP_CLAUSE_{PRIORITY,GRAINSIZE,NUM_TASKS,NOGROUP,THREADS,SIMD}.
	(enum omp_clause_depend_kind): Add OMP_CLAUSE_DEPEND_{SOURCE,SINK}.
	* omp-low.c (scan_sharing_clauses): Handle
	OMP_CLAUSE_{PRIORITY,GRAINSIZE,NUM_TASKS,NOGROUP,THREADS,SIMD,SIMDLEN}
	clauses.
	(check_omp_nesting_restrictions): Handle
	GF_OMP_TARGET_KIND_ENTER_DATA and GF_OMP_TARGET_KIND_EXIT_DATA.
	Formatting fixes.
	(expand_omp_target): Handle GF_OMP_TARGET_KIND_ENTER_DATA and
	GF_OMP_TARGET_KIND_EXIT_DATA.
	(build_omp_regions_1, make_gimple_omp_edges): Likewise.
	(lower_omp_target): Likewise.  Don't assert is_gimple_omp_oacc
	for certain OpenMP 4.1 map kinds + modifiers.
	* tree-pretty-print.c (dump_omp_clause): Handle
	OMP_CLAUSE_ORDERED_EXPR on OMP_CLAUSE_ORDERED.  Handle
	OMP_CLAUSE_DEPEND_SOURCE on OMP_CLAUSE_DEPEND.  Adjust printing
	OpenMP 4.1 new map kinds and modifiers.  Handle
	OMP_CLAUSE_{PRIORITY,GRAINSIZE,NUM_TASKS,NOGROUP,THREADS,SIMD}
	clauses.
	(dump_generic_node): Handle OMP_{TASKLOOP,TARGET_{ENTER,EXIT}_DATA}.
	Dump OMP_ORDERED_CLAUSES for OMP_ORDERED.
gcc/c-family/
	* c-omp.c (c_finish_omp_ordered): Add CLAUSES argument, adjust
	for building 2 operand tree instead of single operand tree.
	(c_omp_split_clauses): Add taskloop simd splitting support.
	* c-pragma.h (enum pragma_kind): Add PRAGMA_OMP_TASKLOOP.
	(enum pragma_omp_clause): Add
	PRAGMA_OMP_CLAUSE_{PRIORITY,GRAINSIZE,NUM_TASKS,NOGROUP,THREADS,SIMD}.
	* c-common.h (enum c_omp_clause_split): Add C_OMP_CLAUSE_SPLIT_TASKLOOP
	as alias to C_OMP_CLAUSE_SPLIT_FOR.
	(c_finish_omp_ordered): Adjust prototype for CLAUSES argument addition.
gcc/c/
	* c-typeck.c (c_finish_omp_clauses): Allow NULL OMP_CLAUSE_DECL
	for OMP_CLAUSE_DEPEND_SOURCE.  Diagnose simdlen > safelen.  Handle
	OMP_CLAUSE_{PRIORITY,GRAINSIZE,NUM_TASKS,NOGROUP,THREADS,SIMD}
	clauses.
	* c-parser.c (c_parser_pragma): Handle PRAGMA_OMP_ORDERED.
	(c_parser_omp_clause_name): Handle grainsize, nogroup, num_tasks,
	priority, simd and threads clauses.
	(c_parser_omp_clause_num_tasks, c_parser_omp_clause_grainsize,
	c_parser_omp_clause_priority): New functions.
	(c_parser_omp_clause_ordered): Handle parsing of optional argument.
	(c_parser_omp_clause_nogroup, c_parser_omp_clause_orderedkind):
	New functions.
	(c_parser_omp_clause_depend): Handle parsing of depend(source)
	and partially handle depend(sink:vec).
	(c_parser_omp_clause_map): Parse optional always map type modifier.
	Handle parsing of delete map kind.
	(c_parser_omp_all_clauses): Handle
	PRAGMA_OMP_CLAUSE_{GRAINSIZE,NUM_TASKS,PRIORITY,NOGROUP,THREADS,SIMD}.
	(OMP_SIMD_CLAUSE_MASK): Add simdlen clause.
	(OMP_FOR_CLAUSE_MASK): Add linear clause.
	(OMP_ORDERED_CLAUSE_MASK, OMP_ORDERED_DEPEND_CLAUSE_MASK): Define.
	(c_parser_omp_ordered): Handle parsing of the clauses, and if depend
	clause is present, parse it as standalone directive.  Remove LOC
	argument, add CONTEXT argument.
	(OMP_TASK_CLAUSE_MASK): Add priority clause.
	(c_parser_omp_target_data): Diagnose if no map clauses are present.
	(OMP_TARGET_ENTER_DATA_CLAUSE_MASK): Define.
	(c_parser_omp_target_enter_data): New function.
	OMP_TARGET_EXIT_DATA_CLAUSE_MASK): Define.
	(c_parser_omp_target_exit_data): New function.
	(OMP_TARGET_CLAUSE_MASK): Add nowait and depend clauses.
	(c_parser_omp_target): Handle #pragma omp target {enter,exit} data.
	(OMP_TASKLOOP_CLAUSE_MASK): Define.
	(c_parser_omp_taskloop): New function.
	(c_parser_omp_construct): Don't handle PRAGMA_OMP_ORDERED here.
	Handle PRAGMA_OMP_TASKLOOP.
gcc/cp/
	* parser.c (cp_parser_omp_clause_ordered): Clear
	OMP_CLAUSE_ORDERED_EXPR.
	(cp_parser_omp_ordered): Pass NULL_TREE as clauses
	to c_finish_omp_ordered.
gcc/fortran/
	* trans-openmp.c (gfc_trans_omp_clauses): Clear
	OMP_CLAUSE_ORDERED_EXPR.
	(gfc_trans_omp_ordered): Adjust for OMP_ORDERED change from 1
	operand to 2 operands.
gcc/testsuite/
	* c-c++-common/gomp/cancel-1.c (f2): Add map clause to all
	#pragma omp target data directives.
	* c-c++-common/gomp/nesting-warn-1.c (f_omp_target): Likewise.
	* c-c++-common/gomp/nesting-1.c (f_omp_parallel, f_omp_target,
	f_omp_target_data): Likewise.
libgomp/
	* omp.h.in (omp_get_max_task_priority): New prototype.
	* omp_lib.h.in (omp_get_max_task_priority): New extern.
	* omp_lib.f90.in (omp_get_max_task_priority): New interface.
	* fortran.c (omp_get_max_task_priority_): New function.
	(omp_get_max_task_priority): Add ialias_redirect.
	* libgomp.map (OMP_4.1): Export omp_get_max_task_priority
	and omp_get_max_task_priority_.
	* env.c (gomp_max_task_priority_var): New variable.
	(handle_omp_display_env): Print OMP_MAX_TASK_PRIORITY.
	(initialize_env): Handle OMP_MAX_TASK_PRIORITY env var.
	(omp_get_max_task_priority): New function.

--- libgomp/omp.h.in.jj	2015-04-29 10:58:01.195752796 +0200
+++ libgomp/omp.h.in	2015-04-29 11:03:04.609991598 +0200
@@ -120,6 +120,7 @@ extern int omp_get_num_teams (void) __GO
 extern int omp_get_team_num (void) __GOMP_NOTHROW;
 
 extern int omp_is_initial_device (void) __GOMP_NOTHROW;
+extern int omp_get_max_task_priority (void) __GOMP_NOTHROW;
 
 #ifdef __cplusplus
 }
--- libgomp/omp_lib.h.in.jj	2015-04-29 10:58:01.204752655 +0200
+++ libgomp/omp_lib.h.in	2015-04-29 11:03:04.609991598 +0200
@@ -96,3 +96,6 @@
 
       external omp_is_initial_device
       logical(4) omp_is_initial_device
+
+      external omp_get_max_task_priority
+      integer(4) omp_get_max_task_priority
--- libgomp/fortran.c.jj	2015-04-29 10:58:01.205752639 +0200
+++ libgomp/fortran.c	2015-04-29 11:03:04.610991582 +0200
@@ -74,6 +74,7 @@ ialias_redirect (omp_get_num_devices)
 ialias_redirect (omp_get_num_teams)
 ialias_redirect (omp_get_team_num)
 ialias_redirect (omp_is_initial_device)
+ialias_redirect (omp_get_max_task_priority)
 #endif
 
 #ifndef LIBGOMP_GNU_SYMBOL_VERSIONING
@@ -493,3 +494,9 @@ omp_is_initial_device_ (void)
 {
   return omp_is_initial_device ();
 }
+
+int32_t
+omp_get_max_task_priority_ (void)
+{
+  return omp_get_max_task_priority ();
+}
--- libgomp/libgomp.map.jj	2015-04-29 10:58:01.205752639 +0200
+++ libgomp/libgomp.map	2015-04-29 11:03:04.610991582 +0200
@@ -134,6 +134,12 @@ OMP_4.0 {
 	omp_is_initial_device_;
 } OMP_3.1;
 
+OMP_4.1 {
+  global:
+	omp_get_max_task_priority;
+	omp_get_max_task_priority_;
+} OMP_4.0;
+
 GOMP_1.0 {
   global:
 	GOMP_atomic_end;
--- libgomp/omp_lib.f90.in.jj	2015-04-29 10:58:01.194752811 +0200
+++ libgomp/omp_lib.f90.in	2015-04-29 11:03:04.610991582 +0200
@@ -337,4 +337,10 @@
           end function omp_is_initial_device
         end interface
 
+        interface
+          function omp_get_max_task_priority ()
+            integer (4) :: omp_get_max_task_priority
+          end function omp_get_max_task_priority
+        end interface
+
       end module omp_lib
--- libgomp/env.c.jj	2015-04-29 10:58:01.206752623 +0200
+++ libgomp/env.c	2015-04-29 11:03:04.611991566 +0200
@@ -68,6 +68,7 @@ struct gomp_task_icv gomp_global_icv = {
 
 unsigned long gomp_max_active_levels_var = INT_MAX;
 bool gomp_cancel_var = false;
+int gomp_max_task_priority_var = 0;
 #ifndef HAVE_SYNC_BUILTINS
 gomp_mutex_t gomp_managed_threads_lock;
 #endif
@@ -1157,6 +1158,8 @@ handle_omp_display_env (unsigned long st
 	   gomp_cancel_var ? "TRUE" : "FALSE");
   fprintf (stderr, "  OMP_DEFAULT_DEVICE = '%d'\n",
 	   gomp_global_icv.default_device_var);
+  fprintf (stderr, "  OMP_MAX_TASK_PRIORITY = '%d'\n",
+	   gomp_max_task_priority_var);
 
   if (verbose)
     {
@@ -1189,6 +1192,7 @@ initialize_env (void)
   parse_boolean ("OMP_NESTED", &gomp_global_icv.nest_var);
   parse_boolean ("OMP_CANCELLATION", &gomp_cancel_var);
   parse_int ("OMP_DEFAULT_DEVICE", &gomp_global_icv.default_device_var, true);
+  parse_int ("OMP_MAX_TASK_PRIORITY", &gomp_max_task_priority_var, true);
   parse_unsigned_long ("OMP_MAX_ACTIVE_LEVELS", &gomp_max_active_levels_var,
 		       true);
   if (parse_unsigned_long ("OMP_THREAD_LIMIT", &thread_limit_var, false))
@@ -1402,6 +1406,12 @@ omp_get_cancellation (void)
   return gomp_cancel_var;
 }
 
+int
+omp_get_max_task_priority (void)
+{
+  return gomp_max_task_priority_var;
+}
+
 omp_proc_bind_t
 omp_get_proc_bind (void)
 {
@@ -1469,3 +1479,4 @@ ialias (omp_get_num_devices)
 ialias (omp_get_num_teams)
 ialias (omp_get_team_num)
 ialias (omp_is_initial_device)
+ialias (omp_get_max_task_priority)
--- gcc/gimple.h.jj	2015-04-29 10:58:01.665745421 +0200
+++ gcc/gimple.h	2015-04-29 11:03:04.612991551 +0200
@@ -100,15 +100,17 @@ enum gf_mask {
     GF_OMP_FOR_KIND_CILKSIMD	= GF_OMP_FOR_SIMD | 1,
     GF_OMP_FOR_COMBINED		= 1 << 3,
     GF_OMP_FOR_COMBINED_INTO	= 1 << 4,
-    GF_OMP_TARGET_KIND_MASK	= (1 << 3) - 1,
+    GF_OMP_TARGET_KIND_MASK	= (1 << 4) - 1,
     GF_OMP_TARGET_KIND_REGION	= 0,
     GF_OMP_TARGET_KIND_DATA	= 1,
     GF_OMP_TARGET_KIND_UPDATE	= 2,
-    GF_OMP_TARGET_KIND_OACC_PARALLEL = 3,
-    GF_OMP_TARGET_KIND_OACC_KERNELS = 4,
-    GF_OMP_TARGET_KIND_OACC_DATA = 5,
-    GF_OMP_TARGET_KIND_OACC_UPDATE = 6,
-    GF_OMP_TARGET_KIND_OACC_ENTER_EXIT_DATA = 7,
+    GF_OMP_TARGET_KIND_ENTER_DATA = 3,
+    GF_OMP_TARGET_KIND_EXIT_DATA = 4,
+    GF_OMP_TARGET_KIND_OACC_PARALLEL = 5,
+    GF_OMP_TARGET_KIND_OACC_KERNELS = 6,
+    GF_OMP_TARGET_KIND_OACC_DATA = 7,
+    GF_OMP_TARGET_KIND_OACC_UPDATE = 8,
+    GF_OMP_TARGET_KIND_OACC_ENTER_EXIT_DATA = 9,
 
     /* True on an GIMPLE_OMP_RETURN statement if the return does not require
        a thread synchronization via some sort of barrier.  The exact barrier
--- gcc/cp/parser.c.jj	2015-04-29 10:58:01.661745483 +0200
+++ gcc/cp/parser.c	2015-04-29 11:03:04.621991409 +0200
@@ -28407,6 +28407,7 @@ cp_parser_omp_clause_ordered (cp_parser
 			     "ordered", location);
 
   c = build_omp_clause (location, OMP_CLAUSE_ORDERED);
+  OMP_CLAUSE_ORDERED_EXPR (c) = NULL_TREE;
   OMP_CLAUSE_CHAIN (c) = list;
   return c;
 }
@@ -30796,7 +30797,8 @@ cp_parser_omp_ordered (cp_parser *parser
 {
   location_t loc = cp_lexer_peek_token (parser->lexer)->location;
   cp_parser_require_pragma_eol (parser, pragma_tok);
-  return c_finish_omp_ordered (loc, cp_parser_omp_structured_block (parser));
+  return c_finish_omp_ordered (loc, NULL_TREE,
+			       cp_parser_omp_structured_block (parser));
 }
 
 /* OpenMP 2.5:
--- gcc/tree.h.jj	2015-04-29 10:58:01.659745515 +0200
+++ gcc/tree.h	2015-04-29 11:03:04.623991378 +0200
@@ -1268,6 +1268,7 @@ extern void protected_set_expr_location
 #define OMP_TASKGROUP_BODY(NODE)   TREE_OPERAND (OMP_TASKGROUP_CHECK (NODE), 0)
 
 #define OMP_ORDERED_BODY(NODE)	   TREE_OPERAND (OMP_ORDERED_CHECK (NODE), 0)
+#define OMP_ORDERED_CLAUSES(NODE)  TREE_OPERAND (OMP_ORDERED_CHECK (NODE), 1)
 
 #define OMP_CRITICAL_BODY(NODE)    TREE_OPERAND (OMP_CRITICAL_CHECK (NODE), 0)
 #define OMP_CRITICAL_NAME(NODE)    TREE_OPERAND (OMP_CRITICAL_CHECK (NODE), 1)
@@ -1286,6 +1287,12 @@ extern void protected_set_expr_location
 #define OMP_TARGET_UPDATE_CLAUSES(NODE)\
   TREE_OPERAND (OMP_TARGET_UPDATE_CHECK (NODE), 0)
 
+#define OMP_TARGET_ENTER_DATA_CLAUSES(NODE)\
+  TREE_OPERAND (OMP_TARGET_ENTER_DATA_CHECK (NODE), 0)
+
+#define OMP_TARGET_EXIT_DATA_CLAUSES(NODE)\
+  TREE_OPERAND (OMP_TARGET_EXIT_DATA_CHECK (NODE), 0)
+
 #define OMP_CLAUSE_SIZE(NODE)						\
   OMP_CLAUSE_OPERAND (OMP_CLAUSE_RANGE_CHECK (OMP_CLAUSE_CHECK (NODE),	\
 					      OMP_CLAUSE_FROM,		\
@@ -1356,6 +1363,14 @@ extern void protected_set_expr_location
   OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_NUM_THREADS),0)
 #define OMP_CLAUSE_SCHEDULE_CHUNK_EXPR(NODE) \
   OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_SCHEDULE), 0)
+#define OMP_CLAUSE_NUM_TASKS_EXPR(NODE) \
+  OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_NUM_TASKS),0)
+
+#define OMP_CLAUSE_GRAINSIZE_EXPR(NODE) \
+  OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_GRAINSIZE),0)
+
+#define OMP_CLAUSE_PRIORITY_EXPR(NODE) \
+  OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_PRIORITY),0)
 
 /* OpenACC clause expressions  */
 #define OMP_CLAUSE_GANG_EXPR(NODE) \
@@ -1411,6 +1426,9 @@ extern void protected_set_expr_location
 #define OMP_CLAUSE_COLLAPSE_COUNT(NODE) \
   OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_COLLAPSE), 2)
 
+#define OMP_CLAUSE_ORDERED_EXPR(NODE) \
+  OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_ORDERED), 0)
+
 #define OMP_CLAUSE_REDUCTION_CODE(NODE)	\
   (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_REDUCTION)->omp_clause.subcode.reduction_code)
 #define OMP_CLAUSE_REDUCTION_INIT(NODE) \
--- gcc/tree.def.jj	2015-04-29 10:58:01.663745452 +0200
+++ gcc/tree.def	2015-04-29 11:34:18.293302684 +0200
@@ -1106,6 +1106,10 @@ DEFTREECODE (CILK_FOR, "cilk_for", tcc_s
    Operands like for OMP_FOR.  */
 DEFTREECODE (OMP_DISTRIBUTE, "omp_distribute", tcc_statement, 6)
 
+/* OpenMP - #pragma omp taskloop [clause1 ... clauseN]
+   Operands like for OMP_FOR.  */
+DEFTREECODE (OMP_TASKLOOP, "omp_taskloop", tcc_statement, 6)
+
 /* OpenMP - #pragma acc loop [clause1 ... clauseN]
    Operands like for OMP_FOR.  */
 DEFTREECODE (OACC_LOOP, "oacc_loop", tcc_statement, 6)
@@ -1130,6 +1134,11 @@ DEFTREECODE (OMP_TARGET, "omp_target", t
    Operand 1: OMP_SECTIONS_CLAUSES: List of clauses.  */
 DEFTREECODE (OMP_SECTIONS, "omp_sections", tcc_statement, 2)
 
+/* OpenMP - #pragma omp ordered
+   Operand 0: OMP_ORDERED_BODY: Master section body.
+   Operand 1: OMP_ORDERED_CLAUSES: List of clauses.  */
+DEFTREECODE (OMP_ORDERED, "omp_ordered", tcc_statement, 2)
+
 /* OpenMP - #pragma omp single
    Operand 0: OMP_SINGLE_BODY: Single section body.
    Operand 1: OMP_SINGLE_CLAUSES: List of clauses.  */
@@ -1147,10 +1156,6 @@ DEFTREECODE (OMP_MASTER, "omp_master", t
    Operand 0: OMP_TASKGROUP_BODY: Taskgroup body.  */
 DEFTREECODE (OMP_TASKGROUP, "omp_taskgroup", tcc_statement, 1)
 
-/* OpenMP - #pragma omp ordered
-   Operand 0: OMP_ORDERED_BODY: Master section body.  */
-DEFTREECODE (OMP_ORDERED, "omp_ordered", tcc_statement, 1)
-
 /* OpenMP - #pragma omp critical [name]
    Operand 0: OMP_CRITICAL_BODY: Critical section body.
    Operand 1: OMP_CRITICAL_NAME: Identifier for critical section.  */
@@ -1181,6 +1186,14 @@ DEFTREECODE (OACC_UPDATE, "oacc_update",
    Operand 0: OMP_TARGET_UPDATE_CLAUSES: List of clauses.  */
 DEFTREECODE (OMP_TARGET_UPDATE, "omp_target_update", tcc_statement, 1)
 
+/* OpenMP - #pragma omp target enter data [clause1 ... clauseN]
+   Operand 0: OMP_TARGET_ENTER_DATA_CLAUSES: List of clauses.  */
+DEFTREECODE (OMP_TARGET_ENTER_DATA, "omp_target_enter_data", tcc_statement, 1)
+
+/* OpenMP - #pragma omp target exit data [clause1 ... clauseN]
+   Operand 0: OMP_TARGET_EXIT_DATA_CLAUSES: List of clauses.  */
+DEFTREECODE (OMP_TARGET_EXIT_DATA, "omp_target_exit_data", tcc_statement, 1)
+
 /* OMP_ATOMIC through OMP_ATOMIC_CAPTURE_NEW must be consecutive,
    or OMP_ATOMIC_SEQ_CST needs adjusting.  */
 
--- gcc/testsuite/c-c++-common/gomp/cancel-1.c.jj	2015-04-29 10:58:01.492748135 +0200
+++ gcc/testsuite/c-c++-common/gomp/cancel-1.c	2015-04-29 11:03:04.624991362 +0200
@@ -17,7 +17,7 @@ f1 (void)
 void
 f2 (void)
 {
-  int i;
+  int i, j = 0;
   #pragma omp parallel
   {
     #pragma omp cancel parallel
@@ -132,7 +132,7 @@ f2 (void)
 	#pragma omp cancellation point taskgroup/* { dg-error "not closely nested inside" } */
       }
     }
-    #pragma omp target data
+    #pragma omp target data map(j)
     {
       #pragma omp cancel parallel		/* { dg-error "not closely nested inside" } */
       #pragma omp cancel for			/* { dg-error "not closely nested inside" } */
@@ -155,7 +155,7 @@ f2 (void)
       #pragma omp cancellation point taskgroup	/* { dg-error "not closely nested inside" } */
     }
   }
-  #pragma omp target data
+  #pragma omp target data map(j)
   {
     #pragma omp cancel parallel			/* { dg-error "not closely nested inside" } */
     #pragma omp cancel for			/* { dg-error "not closely nested inside" } */
@@ -214,7 +214,7 @@ f2 (void)
     }
   #pragma omp for
   for (i = 0; i < 10; i++)
-    #pragma omp target data
+    #pragma omp target data map(j)
     {
       #pragma omp cancel parallel		/* { dg-error "not closely nested inside" } */
       #pragma omp cancel for			/* { dg-error "not closely nested inside" } */
@@ -241,7 +241,7 @@ f2 (void)
   #pragma omp for ordered
   for (i = 0; i < 10; i++)
     #pragma omp ordered
-      #pragma omp target data
+      #pragma omp target data map(j)
       {
 	#pragma omp cancel parallel		/* { dg-error "not closely nested inside" } */
 	#pragma omp cancel for			/* { dg-error "not closely nested inside" } */
@@ -292,7 +292,7 @@ f2 (void)
   }
   #pragma omp sections
   {
-    #pragma omp target data
+    #pragma omp target data map(j)
     {
       #pragma omp cancel parallel		/* { dg-error "not closely nested inside" } */
       #pragma omp cancel for			/* { dg-error "not closely nested inside" } */
@@ -304,7 +304,7 @@ f2 (void)
       #pragma omp cancellation point taskgroup	/* { dg-error "not closely nested inside" } */
     }
     #pragma omp section
-    #pragma omp target data
+    #pragma omp target data map(j)
     {
       #pragma omp cancel parallel		/* { dg-error "not closely nested inside" } */
       #pragma omp cancel for			/* { dg-error "not closely nested inside" } */
--- gcc/testsuite/c-c++-common/gomp/nesting-warn-1.c.jj	2015-04-29 10:58:01.491748151 +0200
+++ gcc/testsuite/c-c++-common/gomp/nesting-warn-1.c	2015-04-29 11:03:04.625991347 +0200
@@ -7,7 +7,7 @@ f_omp_target (void)
   {
 #pragma omp target /* { dg-warning "target construct inside of target region" } */
     ;
-#pragma omp target data /* { dg-warning "target data construct inside of target region" } */
+#pragma omp target data map(i) /* { dg-warning "target data construct inside of target region" } */
     ;
 #pragma omp target update to(i) /* { dg-warning "target update construct inside of target region" } */
 
@@ -15,7 +15,7 @@ f_omp_target (void)
     {
 #pragma omp target /* { dg-warning "target construct inside of target region" } */
       ;
-#pragma omp target data /* { dg-warning "target data construct inside of target region" } */
+#pragma omp target data map(i) /* { dg-warning "target data construct inside of target region" } */
       ;
 #pragma omp target update to(i) /* { dg-warning "target update construct inside of target region" } */
     }
--- gcc/testsuite/c-c++-common/gomp/nesting-1.c.jj	2015-04-29 10:58:01.491748151 +0200
+++ gcc/testsuite/c-c++-common/gomp/nesting-1.c	2015-04-29 11:03:04.625991347 +0200
@@ -11,12 +11,12 @@ f_omp_parallel (void)
 #pragma omp target
     ;
 
-#pragma omp target data
+#pragma omp target data map(i)
     ;
 
 #pragma omp target update to(i)
 
-#pragma omp target data
+#pragma omp target data map(i)
     {
 #pragma omp parallel
       ;
@@ -24,7 +24,7 @@ f_omp_parallel (void)
 #pragma omp target
       ;
 
-#pragma omp target data
+#pragma omp target data map(i)
       ;
 
 #pragma omp target update to(i)
@@ -45,7 +45,7 @@ f_omp_target (void)
 void
 f_omp_target_data (void)
 {
-#pragma omp target data
+#pragma omp target data map(i)
   {
 #pragma omp parallel
     ;
@@ -53,12 +53,12 @@ f_omp_target_data (void)
 #pragma omp target
     ;
 
-#pragma omp target data
+#pragma omp target data map(i)
     ;
 
 #pragma omp target update to(i)
 
-#pragma omp target data
+#pragma omp target data map(i)
     {
 #pragma omp parallel
       ;
@@ -66,7 +66,7 @@ f_omp_target_data (void)
 #pragma omp target
       ;
 
-#pragma omp target data
+#pragma omp target data map(i)
       ;
 
 #pragma omp target update to(i)
--- gcc/gimplify.c.jj	2015-04-29 10:59:42.520162806 +0200
+++ gcc/gimplify.c	2015-04-29 11:03:04.628991299 +0200
@@ -6336,6 +6336,9 @@ gimplify_scan_omp_clauses (tree *list_p,
 	case OMP_CLAUSE_THREAD_LIMIT:
 	case OMP_CLAUSE_DIST_SCHEDULE:
 	case OMP_CLAUSE_DEVICE:
+	case OMP_CLAUSE_PRIORITY:
+	case OMP_CLAUSE_GRAINSIZE:
+	case OMP_CLAUSE_NUM_TASKS:
 	case OMP_CLAUSE__CILK_FOR_COUNT_:
 	case OMP_CLAUSE_ASYNC:
 	case OMP_CLAUSE_WAIT:
@@ -6369,6 +6372,10 @@ gimplify_scan_omp_clauses (tree *list_p,
 	case OMP_CLAUSE_MERGEABLE:
 	case OMP_CLAUSE_PROC_BIND:
 	case OMP_CLAUSE_SAFELEN:
+	case OMP_CLAUSE_SIMDLEN:
+	case OMP_CLAUSE_NOGROUP:
+	case OMP_CLAUSE_THREADS:
+	case OMP_CLAUSE_SIMD:
 	  break;
 
 	case OMP_CLAUSE_ALIGNED:
@@ -6739,7 +6746,14 @@ gimplify_adjust_omp_clauses (gimple_seq
 	case OMP_CLAUSE_MERGEABLE:
 	case OMP_CLAUSE_PROC_BIND:
 	case OMP_CLAUSE_SAFELEN:
+	case OMP_CLAUSE_SIMDLEN:
 	case OMP_CLAUSE_DEPEND:
+	case OMP_CLAUSE_PRIORITY:
+	case OMP_CLAUSE_GRAINSIZE:
+	case OMP_CLAUSE_NUM_TASKS:
+	case OMP_CLAUSE_NOGROUP:
+	case OMP_CLAUSE_THREADS:
+	case OMP_CLAUSE_SIMD:
 	case OMP_CLAUSE__CILK_FOR_COUNT_:
 	case OMP_CLAUSE_ASYNC:
 	case OMP_CLAUSE_WAIT:
@@ -7433,6 +7447,14 @@ gimplify_omp_target_update (tree *expr_p
       clauses = OMP_TARGET_UPDATE_CLAUSES (expr);
       kind = GF_OMP_TARGET_KIND_UPDATE;
       break;
+    case OMP_TARGET_ENTER_DATA:
+      clauses = OMP_TARGET_ENTER_DATA_CLAUSES (expr);
+      kind = GF_OMP_TARGET_KIND_ENTER_DATA;
+      break;
+    case OMP_TARGET_EXIT_DATA:
+      clauses = OMP_TARGET_EXIT_DATA_CLAUSES (expr);
+      kind = GF_OMP_TARGET_KIND_EXIT_DATA;
+      break;
     default:
       gcc_unreachable ();
     }
@@ -8426,6 +8448,8 @@ gimplify_expr (tree *expr_p, gimple_seq
 	case OACC_EXIT_DATA:
 	case OACC_UPDATE:
 	case OMP_TARGET_UPDATE:
+	case OMP_TARGET_ENTER_DATA:
+	case OMP_TARGET_EXIT_DATA:
 	  gimplify_omp_target_update (expr_p, pre_p);
 	  ret = GS_ALL_DONE;
 	  break;
--- gcc/tree.c.jj	2015-04-29 10:59:22.836471684 +0200
+++ gcc/tree.c	2015-04-29 11:03:04.631991252 +0200
@@ -342,7 +342,7 @@ unsigned const char omp_clause_num_ops[]
   1, /* OMP_CLAUSE_NUM_THREADS  */
   1, /* OMP_CLAUSE_SCHEDULE  */
   0, /* OMP_CLAUSE_NOWAIT  */
-  0, /* OMP_CLAUSE_ORDERED  */
+  1, /* OMP_CLAUSE_ORDERED  */
   0, /* OMP_CLAUSE_DEFAULT  */
   3, /* OMP_CLAUSE_COLLAPSE  */
   0, /* OMP_CLAUSE_UNTIED   */
@@ -361,6 +361,12 @@ unsigned const char omp_clause_num_ops[]
   0, /* OMP_CLAUSE_PARALLEL  */
   0, /* OMP_CLAUSE_SECTIONS  */
   0, /* OMP_CLAUSE_TASKGROUP  */
+  1, /* OMP_CLAUSE_PRIORITY  */
+  1, /* OMP_CLAUSE_GRAINSIZE  */
+  1, /* OMP_CLAUSE_NUM_TASKS  */
+  0, /* OMP_CLAUSE_NOGROUP  */
+  0, /* OMP_CLAUSE_THREADS  */
+  0, /* OMP_CLAUSE_SIMD  */
   1, /* OMP_CLAUSE__SIMDUID_  */
   1, /* OMP_CLAUSE__CILK_FOR_COUNT_  */
   0, /* OMP_CLAUSE_INDEPENDENT  */
@@ -420,6 +426,12 @@ const char * const omp_clause_code_name[
   "parallel",
   "sections",
   "taskgroup",
+  "priority",
+  "grainsize",
+  "num_tasks",
+  "nogroup",
+  "threads",
+  "simd",
   "_simduid_",
   "_Cilk_for_count_",
   "independent",
@@ -11234,6 +11246,10 @@ walk_tree_1 (tree *tp, walk_tree_fn func
 	case OMP_CLAUSE_DIST_SCHEDULE:
 	case OMP_CLAUSE_SAFELEN:
 	case OMP_CLAUSE_SIMDLEN:
+	case OMP_CLAUSE_ORDERED:
+	case OMP_CLAUSE_PRIORITY:
+	case OMP_CLAUSE_GRAINSIZE:
+	case OMP_CLAUSE_NUM_TASKS:
 	case OMP_CLAUSE__LOOPTEMP_:
 	case OMP_CLAUSE__SIMDUID_:
 	case OMP_CLAUSE__CILK_FOR_COUNT_:
@@ -11242,7 +11258,6 @@ walk_tree_1 (tree *tp, walk_tree_fn func
 
 	case OMP_CLAUSE_INDEPENDENT:
 	case OMP_CLAUSE_NOWAIT:
-	case OMP_CLAUSE_ORDERED:
 	case OMP_CLAUSE_DEFAULT:
 	case OMP_CLAUSE_UNTIED:
 	case OMP_CLAUSE_MERGEABLE:
@@ -11253,6 +11268,9 @@ walk_tree_1 (tree *tp, walk_tree_fn func
 	case OMP_CLAUSE_PARALLEL:
 	case OMP_CLAUSE_SECTIONS:
 	case OMP_CLAUSE_TASKGROUP:
+	case OMP_CLAUSE_NOGROUP:
+	case OMP_CLAUSE_THREADS:
+	case OMP_CLAUSE_SIMD:
 	case OMP_CLAUSE_AUTO:
 	case OMP_CLAUSE_SEQ:
 	  WALK_SUBTREE_TAIL (OMP_CLAUSE_CHAIN (*tp));
--- gcc/tree-nested.c.jj	2015-04-29 10:58:01.664745436 +0200
+++ gcc/tree-nested.c	2015-04-29 11:03:04.632991237 +0200
@@ -1145,6 +1145,10 @@ convert_nonlocal_omp_clauses (tree *pcla
 	case OMP_CLAUSE_NUM_TEAMS:
 	case OMP_CLAUSE_THREAD_LIMIT:
 	case OMP_CLAUSE_SAFELEN:
+	case OMP_CLAUSE_SIMDLEN:
+	case OMP_CLAUSE_PRIORITY:
+	case OMP_CLAUSE_GRAINSIZE:
+	case OMP_CLAUSE_NUM_TASKS:
 	case OMP_CLAUSE__CILK_FOR_COUNT_:
 	  wi->val_only = true;
 	  wi->is_lhs = false;
@@ -1209,6 +1213,9 @@ convert_nonlocal_omp_clauses (tree *pcla
 	case OMP_CLAUSE_UNTIED:
 	case OMP_CLAUSE_MERGEABLE:
 	case OMP_CLAUSE_PROC_BIND:
+	case OMP_CLAUSE_NOGROUP:
+	case OMP_CLAUSE_THREADS:
+	case OMP_CLAUSE_SIMD:
 	  break;
 
 	default:
@@ -1778,6 +1785,10 @@ convert_local_omp_clauses (tree *pclause
 	case OMP_CLAUSE_NUM_TEAMS:
 	case OMP_CLAUSE_THREAD_LIMIT:
 	case OMP_CLAUSE_SAFELEN:
+	case OMP_CLAUSE_SIMDLEN:
+	case OMP_CLAUSE_PRIORITY:
+	case OMP_CLAUSE_GRAINSIZE:
+	case OMP_CLAUSE_NUM_TASKS:
 	case OMP_CLAUSE__CILK_FOR_COUNT_:
 	  wi->val_only = true;
 	  wi->is_lhs = false;
@@ -1847,6 +1858,9 @@ convert_local_omp_clauses (tree *pclause
 	case OMP_CLAUSE_UNTIED:
 	case OMP_CLAUSE_MERGEABLE:
 	case OMP_CLAUSE_PROC_BIND:
+	case OMP_CLAUSE_NOGROUP:
+	case OMP_CLAUSE_THREADS:
+	case OMP_CLAUSE_SIMD:
 	  break;
 
 	default:
--- gcc/gimple-pretty-print.c.jj	2015-04-29 10:58:01.663745452 +0200
+++ gcc/gimple-pretty-print.c	2015-04-29 11:03:04.632991237 +0200
@@ -1350,6 +1350,12 @@ dump_gimple_omp_target (pretty_printer *
     case GF_OMP_TARGET_KIND_UPDATE:
       kind = " update";
       break;
+    case GF_OMP_TARGET_KIND_ENTER_DATA:
+      kind = " enter data";
+      break;
+    case GF_OMP_TARGET_KIND_EXIT_DATA:
+      kind = " exit data";
+      break;
     case GF_OMP_TARGET_KIND_OACC_KERNELS:
       kind = " oacc_kernels";
       break;
--- gcc/c/c-typeck.c.jj	2015-04-29 10:59:21.436493652 +0200
+++ gcc/c/c-typeck.c	2015-04-29 11:03:04.636991174 +0200
@@ -12053,6 +12053,7 @@ c_finish_omp_clauses (tree clauses)
   bitmap_head generic_head, firstprivate_head, lastprivate_head;
   bitmap_head aligned_head;
   tree c, t, *pc;
+  tree simdlen = NULL_TREE, safelen = NULL_TREE;
   bool branch_seen = false;
   bool copyprivate_seen = false;
   tree *nowait_clause = NULL;
@@ -12345,6 +12346,12 @@ c_finish_omp_clauses (tree clauses)
 
 	case OMP_CLAUSE_DEPEND:
 	  t = OMP_CLAUSE_DECL (c);
+	  if (t == NULL_TREE)
+	    {
+	      gcc_assert (OMP_CLAUSE_DEPEND_KIND (c)
+			  == OMP_CLAUSE_DEPEND_SOURCE);
+	      break;
+	    }
 	  if (TREE_CODE (t) == TREE_LIST)
 	    {
 	      if (handle_omp_array_sections (c))
@@ -12466,8 +12473,6 @@ c_finish_omp_clauses (tree clauses)
 	case OMP_CLAUSE_COLLAPSE:
 	case OMP_CLAUSE_FINAL:
 	case OMP_CLAUSE_MERGEABLE:
-	case OMP_CLAUSE_SAFELEN:
-	case OMP_CLAUSE_SIMDLEN:
 	case OMP_CLAUSE_DEVICE:
 	case OMP_CLAUSE_DIST_SCHEDULE:
 	case OMP_CLAUSE_PARALLEL:
@@ -12475,6 +12480,12 @@ c_finish_omp_clauses (tree clauses)
 	case OMP_CLAUSE_SECTIONS:
 	case OMP_CLAUSE_TASKGROUP:
 	case OMP_CLAUSE_PROC_BIND:
+	case OMP_CLAUSE_PRIORITY:
+	case OMP_CLAUSE_GRAINSIZE:
+	case OMP_CLAUSE_NUM_TASKS:
+	case OMP_CLAUSE_NOGROUP:
+	case OMP_CLAUSE_THREADS:
+	case OMP_CLAUSE_SIMD:
 	case OMP_CLAUSE__CILK_FOR_COUNT_:
 	case OMP_CLAUSE_NUM_GANGS:
 	case OMP_CLAUSE_NUM_WORKERS:
@@ -12489,6 +12500,15 @@ c_finish_omp_clauses (tree clauses)
 	  pc = &OMP_CLAUSE_CHAIN (c);
 	  continue;
 
+	case OMP_CLAUSE_SAFELEN:
+	  safelen = c;
+	  pc = &OMP_CLAUSE_CHAIN (c);
+	  continue;
+	case OMP_CLAUSE_SIMDLEN:
+	  simdlen = c;
+	  pc = &OMP_CLAUSE_CHAIN (c);
+	  continue;
+
 	case OMP_CLAUSE_INBRANCH:
 	case OMP_CLAUSE_NOTINBRANCH:
 	  if (branch_seen)
@@ -12558,6 +12578,18 @@ c_finish_omp_clauses (tree clauses)
 	pc = &OMP_CLAUSE_CHAIN (c);
     }
 
+  if (simdlen
+      && safelen
+      && tree_int_cst_lt (OMP_CLAUSE_SAFELEN_EXPR (safelen),
+			  OMP_CLAUSE_SIMDLEN_EXPR (simdlen)))
+    {
+      error_at (OMP_CLAUSE_LOCATION (simdlen),
+		"%<simdlen%> clause value is bigger than "
+		"%<safelen%> clause value");
+      OMP_CLAUSE_SIMDLEN_EXPR (simdlen)
+	= OMP_CLAUSE_SAFELEN_EXPR (safelen);
+    }
+
   bitmap_obstack_release (NULL);
   return clauses;
 }
--- gcc/c/c-parser.c.jj	2015-04-29 10:59:20.760504260 +0200
+++ gcc/c/c-parser.c	2015-04-29 11:03:04.641991095 +0200
@@ -1270,6 +1270,7 @@ static bool c_parser_pragma (c_parser *,
 static bool c_parser_omp_target (c_parser *, enum pragma_context);
 static void c_parser_omp_end_declare_target (c_parser *);
 static void c_parser_omp_declare (c_parser *, enum pragma_context);
+static bool c_parser_omp_ordered (c_parser *, enum pragma_context);
 
 /* These Objective-C parser functions are only ever called when
    compiling Objective-C.  */
@@ -9713,6 +9714,11 @@ c_parser_pragma (c_parser *parser, enum
     case PRAGMA_OMP_DECLARE_REDUCTION:
       c_parser_omp_declare (parser, context);
       return false;
+
+    case PRAGMA_OMP_ORDERED:
+      c_parser_omp_ordered (parser, context);
+      return false;
+
     case PRAGMA_IVDEP:
       c_parser_consume_pragma (parser);
       c_parser_skip_to_pragma_eol (parser);
@@ -9897,6 +9903,8 @@ c_parser_omp_clause_name (c_parser *pars
 	case 'g':
 	  if (!strcmp ("gang", p))
 	    result = PRAGMA_OACC_CLAUSE_GANG;
+	  else if (!strcmp ("grainsize", p))
+	    result = PRAGMA_OMP_CLAUSE_GRAINSIZE;
 	  break;
 	case 'h':
 	  if (!strcmp ("host", p))
@@ -9921,12 +9929,16 @@ c_parser_omp_clause_name (c_parser *pars
 	    result = PRAGMA_CILK_CLAUSE_MASK;
 	  break;
 	case 'n':
-	  if (!strcmp ("notinbranch", p))
+	  if (!strcmp ("nogroup", p))
+	    result = PRAGMA_OMP_CLAUSE_NOGROUP;
+	  else if (!strcmp ("notinbranch", p))
 	    result = PRAGMA_OMP_CLAUSE_NOTINBRANCH;
 	  else if (!strcmp ("nowait", p))
 	    result = PRAGMA_OMP_CLAUSE_NOWAIT;
 	  else if (!strcmp ("num_gangs", p))
 	    result = PRAGMA_OACC_CLAUSE_NUM_GANGS;
+	  else if (!strcmp ("num_tasks", p))
+	    result = PRAGMA_OMP_CLAUSE_NUM_TASKS;
 	  else if (!strcmp ("num_teams", p))
 	    result = PRAGMA_OMP_CLAUSE_NUM_TEAMS;
 	  else if (!strcmp ("num_threads", p))
@@ -9957,6 +9969,8 @@ c_parser_omp_clause_name (c_parser *pars
 	  else if (!strcmp ("present_or_create", p)
 		   || !strcmp ("pcreate", p))
 	    result = PRAGMA_OACC_CLAUSE_PRESENT_OR_CREATE;
+	  else if (!strcmp ("priority", p))
+	    result = PRAGMA_OMP_CLAUSE_PRIORITY;
 	  else if (!strcmp ("private", p))
 	    result = PRAGMA_OMP_CLAUSE_PRIVATE;
 	  else if (!strcmp ("proc_bind", p))
@@ -9977,6 +9991,8 @@ c_parser_omp_clause_name (c_parser *pars
 	    result = PRAGMA_OACC_CLAUSE_SEQ;
 	  else if (!strcmp ("shared", p))
 	    result = PRAGMA_OMP_CLAUSE_SHARED;
+	  else if (!strcmp ("simd", p))
+	    result = PRAGMA_OMP_CLAUSE_SIMD;
 	  else if (!strcmp ("simdlen", p))
 	    result = PRAGMA_OMP_CLAUSE_SIMDLEN;
 	  else if (!strcmp ("self", p))
@@ -9987,6 +10003,8 @@ c_parser_omp_clause_name (c_parser *pars
 	    result = PRAGMA_OMP_CLAUSE_TASKGROUP;
 	  else if (!strcmp ("thread_limit", p))
 	    result = PRAGMA_OMP_CLAUSE_THREAD_LIMIT;
+	  else if (!strcmp ("threads", p))
+	    result = PRAGMA_OMP_CLAUSE_THREADS;
 	  else if (!strcmp ("to", p))
 	    result = PRAGMA_OMP_CLAUSE_TO;
 	  break;
@@ -10651,6 +10669,139 @@ c_parser_omp_clause_num_threads (c_parse
   return list;
 }
 
+/* OpenMP 4.1:
+   num_tasks ( expression ) */
+
+static tree
+c_parser_omp_clause_num_tasks (c_parser *parser, tree list)
+{
+  location_t num_threads_loc = c_parser_peek_token (parser)->location;
+  if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+    {
+      location_t expr_loc = c_parser_peek_token (parser)->location;
+      tree c, t = c_parser_expression (parser).value;
+      mark_exp_read (t);
+      t = c_fully_fold (t, false, NULL);
+
+      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+
+      if (!INTEGRAL_TYPE_P (TREE_TYPE (t)))
+	{
+	  c_parser_error (parser, "expected integer expression");
+	  return list;
+	}
+
+      /* Attempt to statically determine when the number isn't positive.  */
+      c = fold_build2_loc (expr_loc, LE_EXPR, boolean_type_node, t,
+			   build_int_cst (TREE_TYPE (t), 0));
+      if (CAN_HAVE_LOCATION_P (c))
+	SET_EXPR_LOCATION (c, expr_loc);
+      if (c == boolean_true_node)
+	{
+	  warning_at (expr_loc, 0, "%<num_tasks%> value must be positive");
+	  t = integer_one_node;
+	}
+
+      check_no_duplicate_clause (list, OMP_CLAUSE_NUM_TASKS, "num_tasks");
+
+      c = build_omp_clause (num_threads_loc, OMP_CLAUSE_NUM_TASKS);
+      OMP_CLAUSE_NUM_TASKS_EXPR (c) = t;
+      OMP_CLAUSE_CHAIN (c) = list;
+      list = c;
+    }
+
+  return list;
+}
+
+/* OpenMP 4.1:
+   grainsize ( expression ) */
+
+static tree
+c_parser_omp_clause_grainsize (c_parser *parser, tree list)
+{
+  location_t num_threads_loc = c_parser_peek_token (parser)->location;
+  if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+    {
+      location_t expr_loc = c_parser_peek_token (parser)->location;
+      tree c, t = c_parser_expression (parser).value;
+      mark_exp_read (t);
+      t = c_fully_fold (t, false, NULL);
+
+      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+
+      if (!INTEGRAL_TYPE_P (TREE_TYPE (t)))
+	{
+	  c_parser_error (parser, "expected integer expression");
+	  return list;
+	}
+
+      /* Attempt to statically determine when the number isn't positive.  */
+      c = fold_build2_loc (expr_loc, LE_EXPR, boolean_type_node, t,
+			   build_int_cst (TREE_TYPE (t), 0));
+      if (CAN_HAVE_LOCATION_P (c))
+	SET_EXPR_LOCATION (c, expr_loc);
+      if (c == boolean_true_node)
+	{
+	  warning_at (expr_loc, 0, "%<grainsize%> value must be positive");
+	  t = integer_one_node;
+	}
+
+      check_no_duplicate_clause (list, OMP_CLAUSE_GRAINSIZE, "grainsize");
+
+      c = build_omp_clause (num_threads_loc, OMP_CLAUSE_GRAINSIZE);
+      OMP_CLAUSE_GRAINSIZE_EXPR (c) = t;
+      OMP_CLAUSE_CHAIN (c) = list;
+      list = c;
+    }
+
+  return list;
+}
+
+/* OpenMP 4.1:
+   priority ( expression ) */
+
+static tree
+c_parser_omp_clause_priority (c_parser *parser, tree list)
+{
+  location_t num_threads_loc = c_parser_peek_token (parser)->location;
+  if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+    {
+      location_t expr_loc = c_parser_peek_token (parser)->location;
+      tree c, t = c_parser_expression (parser).value;
+      mark_exp_read (t);
+      t = c_fully_fold (t, false, NULL);
+
+      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+
+      if (!INTEGRAL_TYPE_P (TREE_TYPE (t)))
+	{
+	  c_parser_error (parser, "expected integer expression");
+	  return list;
+	}
+
+      /* Attempt to statically determine when the number isn't
+	 non-negative.  */
+      c = fold_build2_loc (expr_loc, LT_EXPR, boolean_type_node, t,
+			   build_int_cst (TREE_TYPE (t), 0));
+      if (CAN_HAVE_LOCATION_P (c))
+	SET_EXPR_LOCATION (c, expr_loc);
+      if (c == boolean_true_node)
+	{
+	  warning_at (expr_loc, 0, "%<priority%> value must be non-negative");
+	  t = integer_one_node;
+	}
+
+      check_no_duplicate_clause (list, OMP_CLAUSE_PRIORITY, "priority");
+
+      c = build_omp_clause (num_threads_loc, OMP_CLAUSE_PRIORITY);
+      OMP_CLAUSE_PRIORITY_EXPR (c) = t;
+      OMP_CLAUSE_CHAIN (c) = list;
+      list = c;
+    }
+
+  return list;
+}
+
 /* OpenACC:
    num_workers ( expression ) */
 
@@ -10746,19 +10897,44 @@ c_parser_oacc_clause_wait (c_parser *par
 }
 
 /* OpenMP 2.5:
-   ordered */
+   ordered
+
+   OpenMP 4.1:
+   ordered ( constant-expression ) */
 
 static tree
 c_parser_omp_clause_ordered (c_parser *parser, tree list)
 {
-  tree c;
-
   check_no_duplicate_clause (list, OMP_CLAUSE_ORDERED, "ordered");
 
-  c = build_omp_clause (c_parser_peek_token (parser)->location,
-			OMP_CLAUSE_ORDERED);
+  tree c, num = NULL_TREE;
+  HOST_WIDE_INT n;
+  location_t loc = c_parser_peek_token (parser)->location;
+  if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
+    {
+      c_parser_consume_token (parser);
+      num = c_parser_expr_no_commas (parser, NULL).value;
+      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+    }
+  if (num == error_mark_node)
+    return list;
+  if (num)
+    {
+      mark_exp_read (num);
+      num = c_fully_fold (num, false, NULL);
+      if (!INTEGRAL_TYPE_P (TREE_TYPE (num))
+	  || !tree_fits_shwi_p (num)
+	  || (n = tree_to_shwi (num)) <= 0
+	  || (int) n != n)
+	{
+	  error_at (loc, "ordered argument needs positive "
+			 "constant integer expression");
+	  return list;
+	}
+    }
+  c = build_omp_clause (loc, OMP_CLAUSE_ORDERED);
+  OMP_CLAUSE_ORDERED_EXPR (c) = num;
   OMP_CLAUSE_CHAIN (c) = list;
-
   return c;
 }
 
@@ -11073,6 +11249,33 @@ c_parser_omp_clause_cancelkind (c_parser
   return c;
 }
 
+/* OpenMP 4.1:
+   nogroup */
+
+static tree
+c_parser_omp_clause_nogroup (c_parser *parser ATTRIBUTE_UNUSED, tree list)
+{
+  check_no_duplicate_clause (list, OMP_CLAUSE_NOGROUP, "nogroup");
+  tree c = build_omp_clause (c_parser_peek_token (parser)->location,
+			     OMP_CLAUSE_NOGROUP);
+  OMP_CLAUSE_CHAIN (c) = list;
+  return c;
+}
+
+/* OpenMP 4.1:
+   simd
+   threads */
+
+static tree
+c_parser_omp_clause_orderedkind (c_parser *parser ATTRIBUTE_UNUSED,
+				 enum omp_clause_code code, tree list)
+{
+  check_no_duplicate_clause (list, code, omp_clause_code_name[code]);
+  tree c = build_omp_clause (c_parser_peek_token (parser)->location, code);
+  OMP_CLAUSE_CHAIN (c) = list;
+  return c;
+}
+
 /* OpenMP 4.0:
    num_teams ( expression ) */
 
@@ -11324,7 +11527,13 @@ c_parser_omp_clause_simdlen (c_parser *p
    depend ( depend-kind: variable-list )
 
    depend-kind:
-     in | out | inout  */
+     in | out | inout
+
+   OpenMP 4.1:
+   depend ( depend-loop-kind [ : vec ] )
+
+   depend-loop-kind:
+     source | sink  */
 
 static tree
 c_parser_omp_clause_depend (c_parser *parser, tree list)
@@ -11345,6 +11554,10 @@ c_parser_omp_clause_depend (c_parser *pa
 	kind = OMP_CLAUSE_DEPEND_INOUT;
       else if (strcmp ("out", p) == 0)
 	kind = OMP_CLAUSE_DEPEND_OUT;
+      else if (strcmp ("source", p) == 0)
+	kind = OMP_CLAUSE_DEPEND_SOURCE;
+      else if (strcmp ("sink", p) == 0)
+	kind = OMP_CLAUSE_DEPEND_SINK;
       else
 	goto invalid_kind;
     }
@@ -11352,6 +11565,19 @@ c_parser_omp_clause_depend (c_parser *pa
     goto invalid_kind;
 
   c_parser_consume_token (parser);
+
+  if (kind == OMP_CLAUSE_DEPEND_SOURCE)
+    {
+      c = build_omp_clause (clause_loc, OMP_CLAUSE_DEPEND);
+      OMP_CLAUSE_DEPEND_KIND (c) = kind;
+      OMP_CLAUSE_DECL (c) = NULL_TREE;
+      OMP_CLAUSE_CHAIN (c) = list;
+      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+      return c;
+    }
+
+  /* FIXME: Handle OMP_CLAUSE_DEPEND_SINK.  */
+
   if (!c_parser_require (parser, CPP_COLON, "expected %<:%>"))
     goto resync_fail;
 
@@ -11376,18 +11602,60 @@ c_parser_omp_clause_depend (c_parser *pa
    map ( variable-list )
 
    map-kind:
-     alloc | to | from | tofrom  */
+     alloc | to | from | tofrom
+
+   OpenMP 4.1:
+   map-kind:
+     alloc | to | from | tofrom | delete
+
+   map ( always [,] map-kind: variable-list ) */
 
 static tree
 c_parser_omp_clause_map (c_parser *parser, tree list)
 {
   location_t clause_loc = c_parser_peek_token (parser)->location;
   enum gomp_map_kind kind = GOMP_MAP_TOFROM;
+  int always = 0;
+  enum c_id_kind always_id_kind = C_ID_NONE;
+  location_t always_loc = UNKNOWN_LOCATION;
+  tree always_id = NULL_TREE;
   tree nl, c;
 
   if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
     return list;
 
+  if (c_parser_next_token_is (parser, CPP_NAME))
+    {
+      c_token *tok = c_parser_peek_token (parser);
+      const char *p = IDENTIFIER_POINTER (tok->value);
+      always_id_kind = tok->id_kind;
+      always_loc = tok->location;
+      always_id = tok->value;
+      if (strcmp ("always", p) == 0)
+	{
+	  c_token *sectok = c_parser_peek_2nd_token (parser);
+	  if (sectok->type == CPP_COMMA)
+	    {
+	      c_parser_consume_token (parser);
+	      c_parser_consume_token (parser);
+	      always = 2;
+	    }
+	  else if (sectok->type == CPP_NAME)
+	    {
+	      p = IDENTIFIER_POINTER (sectok->value);
+	      if (strcmp ("alloc", p) == 0
+		  || strcmp ("to", p) == 0
+		  || strcmp ("from", p) == 0
+		  || strcmp ("tofrom", p) == 0
+		  || strcmp ("delete", p) == 0)
+		{
+		  c_parser_consume_token (parser);
+		  always = 1;
+		}
+	    }
+	}
+    }
+
   if (c_parser_next_token_is (parser, CPP_NAME)
       && c_parser_peek_2nd_token (parser)->type == CPP_COLON)
     {
@@ -11400,6 +11668,8 @@ c_parser_omp_clause_map (c_parser *parse
 	kind = GOMP_MAP_FROM;
       else if (strcmp ("tofrom", p) == 0)
 	kind = GOMP_MAP_TOFROM;
+      else if (strcmp ("delete", p) == 0)
+	kind = GOMP_MAP_FORCE_DEALLOC;
       else
 	{
 	  c_parser_error (parser, "invalid map kind");
@@ -11407,9 +11677,40 @@ c_parser_omp_clause_map (c_parser *parse
 				     "expected %<)%>");
 	  return list;
 	}
+      if (always)
+	kind = (enum gomp_map_kind) (kind | GOMP_MAP_FLAG_FORCE);
       c_parser_consume_token (parser);
       c_parser_consume_token (parser);
     }
+  else if (always)
+    {
+      if (always_id_kind != C_ID_ID)
+	{
+	  c_parser_error (parser, "expected identifier");
+	  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+	  return list;
+	}
+
+      tree t = lookup_name (always_id);
+      if (t == NULL_TREE)
+	{
+	  undeclared_variable (always_loc, always_id);
+	  t = error_mark_node;
+	}
+      if (t != error_mark_node)
+	{
+	  tree u = build_omp_clause (clause_loc, OMP_CLAUSE_MAP);
+	  OMP_CLAUSE_DECL (u) = t;
+	  OMP_CLAUSE_CHAIN (u) = list;
+	  OMP_CLAUSE_SET_MAP_KIND (u, kind);
+	  list = u;
+	}
+      if (always == 1)
+	{
+	  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+	  return list;
+	}
+    }
 
   nl = c_parser_omp_variable_list (parser, clause_loc, OMP_CLAUSE_MAP, list);
 
@@ -11772,6 +12073,10 @@ c_parser_omp_all_clauses (c_parser *pars
 	  clauses = c_parser_omp_clause_final (parser, clauses);
 	  c_name = "final";
 	  break;
+	case PRAGMA_OMP_CLAUSE_GRAINSIZE:
+	  clauses = c_parser_omp_clause_grainsize (parser, clauses);
+	  c_name = "grainsize";
+	  break;
 	case PRAGMA_OMP_CLAUSE_IF:
 	  clauses = c_parser_omp_clause_if (parser, clauses);
 	  c_name = "if";
@@ -11788,6 +12093,10 @@ c_parser_omp_all_clauses (c_parser *pars
 	  clauses = c_parser_omp_clause_nowait (parser, clauses);
 	  c_name = "nowait";
 	  break;
+	case PRAGMA_OMP_CLAUSE_NUM_TASKS:
+	  clauses = c_parser_omp_clause_num_tasks (parser, clauses);
+	  c_name = "num_tasks";
+	  break;
 	case PRAGMA_OMP_CLAUSE_NUM_THREADS:
 	  clauses = c_parser_omp_clause_num_threads (parser, clauses);
 	  c_name = "num_threads";
@@ -11796,6 +12105,10 @@ c_parser_omp_all_clauses (c_parser *pars
 	  clauses = c_parser_omp_clause_ordered (parser, clauses);
 	  c_name = "ordered";
 	  break;
+	case PRAGMA_OMP_CLAUSE_PRIORITY:
+	  clauses = c_parser_omp_clause_priority (parser, clauses);
+	  c_name = "priority";
+	  break;
 	case PRAGMA_OMP_CLAUSE_PRIVATE:
 	  clauses = c_parser_omp_clause_private (parser, clauses);
 	  c_name = "private";
@@ -11927,6 +12240,22 @@ c_parser_omp_all_clauses (c_parser *pars
 	  clauses = c_parser_omp_clause_simdlen (parser, clauses);
 	  c_name = "simdlen";
 	  break;
+	case PRAGMA_OMP_CLAUSE_NOGROUP:
+	  clauses = c_parser_omp_clause_nogroup (parser, clauses);
+	  c_name = "nogroup";
+	  break;
+	case PRAGMA_OMP_CLAUSE_THREADS:
+	  clauses
+	    = c_parser_omp_clause_orderedkind (parser, OMP_CLAUSE_THREADS,
+					       clauses);
+	  c_name = "threads";
+	  break;
+	case PRAGMA_OMP_CLAUSE_SIMD:
+	  clauses
+	    = c_parser_omp_clause_orderedkind (parser, OMP_CLAUSE_SIMD,
+					       clauses);
+	  c_name = "simd";
+	  break;
 	default:
 	  c_parser_error (parser, "expected %<#pragma omp%> clause");
 	  goto saw_error;
@@ -13129,6 +13458,7 @@ omp_split_clauses (location_t loc, enum
 
 #define OMP_SIMD_CLAUSE_MASK					\
 	( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SAFELEN)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SIMDLEN)	\
 	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINEAR)	\
 	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALIGNED)	\
 	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE)	\
@@ -13176,6 +13506,7 @@ c_parser_omp_simd (location_t loc, c_par
 	( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE)	\
 	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE)	\
 	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LASTPRIVATE)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINEAR)	\
 	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION)	\
 	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ORDERED)	\
 	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SCHEDULE)	\
@@ -13259,14 +13590,59 @@ c_parser_omp_master (location_t loc, c_p
    # pragma omp ordered new-line
      structured-block
 
-   LOC is the location of the #pragma itself.
-*/
+   OpenMP 4.1:
+   # pragma omp ordered ordered-clauses new-line
+     structured-block
 
-static tree
-c_parser_omp_ordered (location_t loc, c_parser *parser)
+   # pragma omp ordered depend-clauses new-line  */
+
+#define OMP_ORDERED_CLAUSE_MASK					\
+	( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_THREADS)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SIMD))
+
+#define OMP_ORDERED_DEPEND_CLAUSE_MASK				\
+	(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND)
+
+static bool
+c_parser_omp_ordered (c_parser *parser, enum pragma_context context)
 {
-  c_parser_skip_to_pragma_eol (parser);
-  return c_finish_omp_ordered (loc, c_parser_omp_structured_block (parser));
+  location_t loc = c_parser_peek_token (parser)->location;
+  c_parser_consume_pragma (parser);
+
+  if (context != pragma_stmt && context != pragma_compound)
+    {
+      c_parser_error (parser, "expected declaration specifiers");
+      c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL);
+      return false;
+    }
+
+  if (c_parser_next_token_is (parser, CPP_NAME))
+    {
+      const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+
+      if (!strcmp ("depend", p))
+	{
+	  if (context == pragma_stmt)
+	    {
+	      error_at (loc,
+			"%<#pragma omp ordered%> with %<depend> clause may "
+			"only be used in compound statements");
+	      c_parser_skip_to_pragma_eol (parser);
+	      return false;
+	    }
+
+	  tree clauses
+	    = c_parser_omp_all_clauses (parser,
+					OMP_ORDERED_DEPEND_CLAUSE_MASK,
+					"#pragma omp ordered");
+	  return c_finish_omp_ordered (loc, clauses, NULL_TREE);
+	}
+    }
+
+  tree clauses = c_parser_omp_all_clauses (parser, OMP_ORDERED_CLAUSE_MASK,
+					   "#pragma omp ordered");
+  return c_finish_omp_ordered (loc, clauses,
+			       c_parser_omp_structured_block (parser));
 }
 
 /* OpenMP 2.5:
@@ -13522,7 +13898,8 @@ c_parser_omp_single (location_t loc, c_p
 	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SHARED)	\
 	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FINAL)	\
 	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MERGEABLE)	\
-	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND))
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIORITY))
 
 static tree
 c_parser_omp_task (location_t loc, c_parser *parser)
@@ -13806,12 +14183,20 @@ c_parser_omp_teams (location_t loc, c_pa
 static tree
 c_parser_omp_target_data (location_t loc, c_parser *parser)
 {
-  tree stmt = make_node (OMP_TARGET_DATA);
-  TREE_TYPE (stmt) = void_type_node;
-
-  OMP_TARGET_DATA_CLAUSES (stmt)
+  tree clauses
     = c_parser_omp_all_clauses (parser, OMP_TARGET_DATA_CLAUSE_MASK,
 				"#pragma omp target data");
+  if (find_omp_clause (clauses, OMP_CLAUSE_MAP) == NULL_TREE)
+    {
+      error_at (loc,
+		"%<#pragma omp target data%> must contain at least one "
+		"%<map%> clause");
+      return NULL_TREE;
+    }
+
+  tree stmt = make_node (OMP_TARGET_DATA);
+  TREE_TYPE (stmt) = void_type_node;
+  OMP_TARGET_DATA_CLAUSES (stmt) = clauses;
   keep_next_level ();
   tree block = c_begin_compound_stmt (true);
   add_stmt (c_parser_omp_structured_block (parser));
@@ -13863,6 +14248,169 @@ c_parser_omp_target_update (location_t l
   return false;
 }
 
+/* OpenMP 4.1:
+   # pragma omp target enter data target-data-clause[optseq] new-line  */
+
+#define OMP_TARGET_ENTER_DATA_CLAUSE_MASK			\
+	( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP)		\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF)		\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT))
+
+static tree
+c_parser_omp_target_enter_data (location_t loc, c_parser *parser,
+				enum pragma_context context)
+{
+  bool data_seen = false;
+  if (c_parser_next_token_is (parser, CPP_NAME))
+    {
+      const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+      if (strcmp (p, "data") == 0)
+	{
+	  c_parser_consume_token (parser);
+	  data_seen = true;
+	}
+    }
+  if (!data_seen)
+    {
+      c_parser_error (parser, "expected %<data%>");
+      c_parser_skip_to_pragma_eol (parser);
+      return NULL_TREE;
+    }
+
+  if (context == pragma_stmt)
+    {
+      error_at (loc,
+		"%<#pragma omp target enter data%> may only be "
+		"used in compound statements");
+      c_parser_skip_to_pragma_eol (parser);
+      return NULL_TREE;
+    }
+
+  tree clauses
+    = c_parser_omp_all_clauses (parser, OMP_TARGET_ENTER_DATA_CLAUSE_MASK,
+				"#pragma omp target enter data");
+  int map_seen = 0;
+  for (tree *pc = &clauses; *pc;)
+    {
+      if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_MAP)
+	switch (OMP_CLAUSE_MAP_KIND (*pc) & ~GOMP_MAP_FLAG_FORCE)
+	  {
+	  case GOMP_MAP_TO:
+	  case GOMP_MAP_ALLOC:
+	    map_seen = 3;
+	    break;
+	  default:
+	    map_seen |= 1;
+	    error_at (OMP_CLAUSE_LOCATION (*pc),
+		      "%<#pragma omp target enter data%> with map-type other "
+		      "than %<to%> or %<alloc%> on %<map%> clause");
+	    *pc = OMP_CLAUSE_CHAIN (*pc);
+	    continue;
+	  }
+      pc = &OMP_CLAUSE_CHAIN (*pc);
+    }
+
+  if (map_seen != 3)
+    {
+      if (map_seen == 0)
+	error_at (loc,
+		  "%<#pragma omp target enter data%> must contain at least "
+		  "one %<map%> clause");
+      return NULL_TREE;
+    }
+
+  tree stmt = make_node (OMP_TARGET_ENTER_DATA);
+  TREE_TYPE (stmt) = void_type_node;
+  OMP_TARGET_ENTER_DATA_CLAUSES (stmt) = clauses;
+  SET_EXPR_LOCATION (stmt, loc);
+  add_stmt (stmt);
+  return stmt;
+}
+
+/* OpenMP 4.1:
+   # pragma omp target exit data target-data-clause[optseq] new-line  */
+
+#define OMP_TARGET_EXIT_DATA_CLAUSE_MASK			\
+	( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP)		\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF)		\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT))
+
+static tree
+c_parser_omp_target_exit_data (location_t loc, c_parser *parser,
+			       enum pragma_context context)
+{
+  bool data_seen = false;
+  if (c_parser_next_token_is (parser, CPP_NAME))
+    {
+      const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+      if (strcmp (p, "data") == 0)
+	{
+	  c_parser_consume_token (parser);
+	  data_seen = true;
+	}
+    }
+  if (!data_seen)
+    {
+      c_parser_error (parser, "expected %<data%>");
+      c_parser_skip_to_pragma_eol (parser);
+      return NULL_TREE;
+    }
+
+  if (context == pragma_stmt)
+    {
+      error_at (loc,
+		"%<#pragma omp target exit data%> may only be "
+		"used in compound statements");
+      c_parser_skip_to_pragma_eol (parser);
+      return NULL_TREE;
+    }
+
+  tree clauses
+    = c_parser_omp_all_clauses (parser, OMP_TARGET_EXIT_DATA_CLAUSE_MASK,
+				"#pragma omp target exit data");
+
+  int map_seen = 0;
+  for (tree *pc = &clauses; *pc;)
+    {
+      if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_MAP)
+	switch (OMP_CLAUSE_MAP_KIND (*pc) & ~GOMP_MAP_FLAG_FORCE)
+	  {
+	  case GOMP_MAP_FROM:
+	  case GOMP_MAP_FORCE_DEALLOC & ~GOMP_MAP_FLAG_FORCE:
+	    map_seen = 3;
+	    break;
+	  default:
+	    map_seen |= 1;
+	    error_at (OMP_CLAUSE_LOCATION (*pc),
+		      "%<#pragma omp target exit data%> with map-type other "
+		      "than %<from%> or %<delete%> on %<map%> clause");
+	    *pc = OMP_CLAUSE_CHAIN (*pc);
+	    continue;
+	  }
+      pc = &OMP_CLAUSE_CHAIN (*pc);
+    }
+
+  if (map_seen != 3)
+    {
+      if (map_seen == 0)
+	error_at (loc,
+		  "%<#pragma omp target exit data%> must contain at least one "
+		  "%<map%> clause");
+      return NULL_TREE;
+    }
+
+  tree stmt = make_node (OMP_TARGET_EXIT_DATA);
+  TREE_TYPE (stmt) = void_type_node;
+  OMP_TARGET_EXIT_DATA_CLAUSES (stmt) = clauses;
+  SET_EXPR_LOCATION (stmt, loc);
+  add_stmt (stmt);
+  return stmt;
+}
+
 /* OpenMP 4.0:
    # pragma omp target target-clause[optseq] new-line
      structured-block  */
@@ -13870,7 +14418,9 @@ c_parser_omp_target_update (location_t l
 #define OMP_TARGET_CLAUSE_MASK					\
 	( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE)	\
 	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP)		\
-	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF))
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF)		\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT))
 
 static bool
 c_parser_omp_target (c_parser *parser, enum pragma_context context)
@@ -13929,6 +14479,18 @@ c_parser_omp_target (c_parser *parser, e
 	  c_parser_omp_target_data (loc, parser);
 	  return true;
 	}
+      else if (strcmp (p, "enter") == 0)
+	{
+	  c_parser_consume_token (parser);
+	  c_parser_omp_target_enter_data (loc, parser, context);
+	  return true;
+	}
+      else if (strcmp (p, "exit") == 0)
+	{
+	  c_parser_consume_token (parser);
+	  c_parser_omp_target_exit_data (loc, parser, context);
+	  return true;
+	}
       else if (strcmp (p, "update") == 0)
 	{
 	  c_parser_consume_token (parser);
@@ -14619,6 +15181,81 @@ c_parser_omp_declare (c_parser *parser,
   c_parser_skip_to_pragma_eol (parser);
 }
 
+/* OpenMP 4.1:
+   #pragma omp taskloop taskloop-clause[optseq] new-line
+     for-loop  */
+
+#define OMP_TASKLOOP_CLAUSE_MASK				\
+	( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SHARED)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LASTPRIVATE)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULT)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_GRAINSIZE)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_TASKS)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF)		\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FINAL)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MERGEABLE)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOGROUP))
+
+static tree
+c_parser_omp_taskloop (location_t loc, c_parser *parser,
+		       char *p_name, omp_clause_mask mask, tree *cclauses)
+{
+  tree clauses, block, ret;
+
+  strcat (p_name, " taskloop");
+  mask |= OMP_TASKLOOP_CLAUSE_MASK;
+
+  if (c_parser_next_token_is (parser, CPP_NAME))
+    {
+      const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+
+      if (strcmp (p, "simd") == 0)
+	{
+	  tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT];
+	  if (cclauses == NULL)
+	    cclauses = cclauses_buf;
+	  mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION);
+	  c_parser_consume_token (parser);
+	  if (!flag_openmp)  /* flag_openmp_simd  */
+	    return c_parser_omp_simd (loc, parser, p_name, mask, cclauses);
+	  block = c_begin_compound_stmt (true);
+	  ret = c_parser_omp_simd (loc, parser, p_name, mask, cclauses);
+	  block = c_end_compound_stmt (loc, block, true);
+	  if (ret == NULL)
+	    return ret;
+	  ret = make_node (OMP_TASKLOOP);
+	  TREE_TYPE (ret) = void_type_node;
+	  OMP_FOR_BODY (ret) = block;
+	  OMP_FOR_CLAUSES (ret) = cclauses[C_OMP_CLAUSE_SPLIT_TASKLOOP];
+	  SET_EXPR_LOCATION (ret, loc);
+	  add_stmt (ret);
+	  return ret;
+	}
+    }
+  if (!flag_openmp)  /* flag_openmp_simd  */
+    {
+      c_parser_skip_to_pragma_eol (parser, false);
+      return NULL_TREE;
+    }
+
+  clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL);
+  if (cclauses)
+    {
+      omp_split_clauses (loc, OMP_TASKLOOP, mask, clauses, cclauses);
+      clauses = cclauses[C_OMP_CLAUSE_SPLIT_TASKLOOP];
+    }
+
+  block = c_begin_compound_stmt (true);
+  ret = c_parser_omp_for_loop (loc, parser, OMP_TASKLOOP, clauses, NULL);
+  block = c_end_compound_stmt (loc, block, true);
+  add_stmt (block);
+
+  return ret;
+}
+
 /* Main entry point to parsing most OpenMP pragmas.  */
 
 static void
@@ -14676,9 +15313,6 @@ c_parser_omp_construct (c_parser *parser
     case PRAGMA_OMP_MASTER:
       stmt = c_parser_omp_master (loc, parser);
       break;
-    case PRAGMA_OMP_ORDERED:
-      stmt = c_parser_omp_ordered (loc, parser);
-      break;
     case PRAGMA_OMP_PARALLEL:
       strcpy (p_name, "#pragma omp");
       stmt = c_parser_omp_parallel (loc, parser, p_name, mask, NULL);
@@ -14700,6 +15334,10 @@ c_parser_omp_construct (c_parser *parser
     case PRAGMA_OMP_TASKGROUP:
       stmt = c_parser_omp_taskgroup (parser);
       break;
+    case PRAGMA_OMP_TASKLOOP:
+      strcpy (p_name, "#pragma omp");
+      stmt = c_parser_omp_taskloop (loc, parser, p_name, mask, NULL);
+      break;
     case PRAGMA_OMP_TEAMS:
       strcpy (p_name, "#pragma omp");
       stmt = c_parser_omp_teams (loc, parser, p_name, mask, NULL);
--- gcc/c-family/c-omp.c.jj	2015-04-29 10:58:01.644745750 +0200
+++ gcc/c-family/c-omp.c	2015-04-29 11:03:04.641991095 +0200
@@ -122,9 +122,12 @@ c_finish_omp_critical (location_t loc, t
    that follows the pragma.  LOC is the location of the #pragma.  */
 
 tree
-c_finish_omp_ordered (location_t loc, tree stmt)
+c_finish_omp_ordered (location_t loc, tree clauses, tree stmt)
 {
-  tree t = build1 (OMP_ORDERED, void_type_node, stmt);
+  tree t = make_node (OMP_ORDERED);
+  TREE_TYPE (t) = void_type_node;
+  OMP_ORDERED_BODY (t) = stmt;
+  OMP_ORDERED_CLAUSES (t) = clauses;
   SET_EXPR_LOCATION (t, loc);
   return add_stmt (t);
 }
@@ -687,7 +690,7 @@ c_finish_omp_for (location_t locus, enum
     }
 }
 
-/* Right now we have 14 different combined constructs, this
+/* Right now we have 15 different combined constructs, this
    function attempts to split or duplicate clauses for combined
    constructs.  CODE is the innermost construct in the combined construct,
    and MASK allows to determine which constructs are combined together,
@@ -707,7 +710,8 @@ c_finish_omp_for (location_t locus, enum
    #pragma omp target teams
    #pragma omp target teams distribute
    #pragma omp target teams distribute parallel for
-   #pragma omp target teams distribute parallel for simd  */
+   #pragma omp target teams distribute parallel for simd
+   #pragma omp taskloop simd  */
 
 void
 c_omp_split_clauses (location_t loc, enum tree_code code,
@@ -766,11 +770,20 @@ c_omp_split_clauses (location_t loc, enu
 	  s = C_OMP_CLAUSE_SPLIT_FOR;
 	  break;
 	case OMP_CLAUSE_SAFELEN:
+	case OMP_CLAUSE_SIMDLEN:
 	case OMP_CLAUSE_LINEAR:
 	case OMP_CLAUSE_ALIGNED:
 	  s = C_OMP_CLAUSE_SPLIT_SIMD;
 	  break;
-	/* Duplicate this to all of distribute, for and simd.  */
+	case OMP_CLAUSE_GRAINSIZE:
+	case OMP_CLAUSE_NUM_TASKS:
+	case OMP_CLAUSE_FINAL:
+	case OMP_CLAUSE_UNTIED:
+	case OMP_CLAUSE_MERGEABLE:
+	case OMP_CLAUSE_NOGROUP:
+	  s = C_OMP_CLAUSE_SPLIT_TASKLOOP;
+	  break;
+	/* Duplicate this to all of taskloop, distribute, for and simd.  */
 	case OMP_CLAUSE_COLLAPSE:
 	  if (code == OMP_SIMD)
 	    {
@@ -797,6 +810,9 @@ c_omp_split_clauses (location_t loc, enu
 	      else
 		s = C_OMP_CLAUSE_SPLIT_FOR;
 	    }
+	  else if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOGROUP))
+		   != 0)
+	    s = C_OMP_CLAUSE_SPLIT_TASKLOOP;
 	  else
 	    s = C_OMP_CLAUSE_SPLIT_DISTRIBUTE;
 	  break;
@@ -861,6 +877,13 @@ c_omp_split_clauses (location_t loc, enu
 	      gcc_assert (code == OMP_SIMD);
 	      s = C_OMP_CLAUSE_SPLIT_TEAMS;
 	    }
+	  else if ((mask & (OMP_CLAUSE_MASK_1
+			    << PRAGMA_OMP_CLAUSE_NOGROUP)) != 0)
+	    {
+	      /* This must be #pragma omp taskloop simd.  */
+	      gcc_assert (code == OMP_SIMD);
+	      s = C_OMP_CLAUSE_SPLIT_TASKLOOP;
+	    }
 	  else
 	    {
 	      /* This must be #pragma omp for simd.  */
@@ -905,6 +928,12 @@ c_omp_split_clauses (location_t loc, enu
 	      s = C_OMP_CLAUSE_SPLIT_TEAMS;
 	      break;
 	    }
+	  if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOGROUP))
+	      != 0)
+	    {
+	      s = C_OMP_CLAUSE_SPLIT_TASKLOOP;
+	      break;
+	    }
 	  if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_TEAMS))
 	      != 0)
 	    {
@@ -965,9 +994,12 @@ c_omp_split_clauses (location_t loc, enu
 	    s = C_OMP_CLAUSE_SPLIT_TEAMS;
 	  break;
 	case OMP_CLAUSE_IF:
-	  /* FIXME: This is currently being discussed.  */
-	  if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_THREADS))
+	  if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOGROUP))
 	      != 0)
+	    s = C_OMP_CLAUSE_SPLIT_TASKLOOP;
+	  /* FIXME: This is currently being discussed.  */
+	  else if ((mask & (OMP_CLAUSE_MASK_1
+			    << PRAGMA_OMP_CLAUSE_NUM_THREADS)) != 0)
 	    s = C_OMP_CLAUSE_SPLIT_PARALLEL;
 	  else
 	    s = C_OMP_CLAUSE_SPLIT_TARGET;
--- gcc/c-family/c-pragma.h.jj	2015-04-29 10:58:01.645745734 +0200
+++ gcc/c-family/c-pragma.h	2015-04-29 11:03:04.642991080 +0200
@@ -36,6 +36,7 @@ typedef enum pragma_kind {
   PRAGMA_OACC_PARALLEL,
   PRAGMA_OACC_UPDATE,
   PRAGMA_OACC_WAIT,
+
   PRAGMA_OMP_ATOMIC,
   PRAGMA_OMP_BARRIER,
   PRAGMA_OMP_CANCEL,
@@ -56,6 +57,7 @@ typedef enum pragma_kind {
   PRAGMA_OMP_TARGET,
   PRAGMA_OMP_TASK,
   PRAGMA_OMP_TASKGROUP,
+  PRAGMA_OMP_TASKLOOP,
   PRAGMA_OMP_TASKWAIT,
   PRAGMA_OMP_TASKYIELD,
   PRAGMA_OMP_THREADPRIVATE,
@@ -74,7 +76,7 @@ typedef enum pragma_kind {
 } pragma_kind;
 
 
-/* All clauses defined by OpenACC 2.0, and OpenMP 2.5, 3.0, 3.1, and 4.0.
+/* All clauses defined by OpenACC 2.0, and OpenMP 2.5, 3.0, 3.1, 4.0 and 4.1.
    Used internally by both C and C++ parsers.  */
 typedef enum pragma_omp_clause {
   PRAGMA_OMP_CLAUSE_NONE = 0,
@@ -91,18 +93,22 @@ typedef enum pragma_omp_clause {
   PRAGMA_OMP_CLAUSE_FIRSTPRIVATE,
   PRAGMA_OMP_CLAUSE_FOR,
   PRAGMA_OMP_CLAUSE_FROM,
+  PRAGMA_OMP_CLAUSE_GRAINSIZE,
   PRAGMA_OMP_CLAUSE_IF,
   PRAGMA_OMP_CLAUSE_INBRANCH,
   PRAGMA_OMP_CLAUSE_LASTPRIVATE,
   PRAGMA_OMP_CLAUSE_LINEAR,
   PRAGMA_OMP_CLAUSE_MAP,
   PRAGMA_OMP_CLAUSE_MERGEABLE,
+  PRAGMA_OMP_CLAUSE_NOGROUP,
   PRAGMA_OMP_CLAUSE_NOTINBRANCH,
   PRAGMA_OMP_CLAUSE_NOWAIT,
+  PRAGMA_OMP_CLAUSE_NUM_TASKS,
   PRAGMA_OMP_CLAUSE_NUM_TEAMS,
   PRAGMA_OMP_CLAUSE_NUM_THREADS,
   PRAGMA_OMP_CLAUSE_ORDERED,
   PRAGMA_OMP_CLAUSE_PARALLEL,
+  PRAGMA_OMP_CLAUSE_PRIORITY,
   PRAGMA_OMP_CLAUSE_PRIVATE,
   PRAGMA_OMP_CLAUSE_PROC_BIND,
   PRAGMA_OMP_CLAUSE_REDUCTION,
@@ -110,13 +116,15 @@ typedef enum pragma_omp_clause {
   PRAGMA_OMP_CLAUSE_SCHEDULE,
   PRAGMA_OMP_CLAUSE_SECTIONS,
   PRAGMA_OMP_CLAUSE_SHARED,
+  PRAGMA_OMP_CLAUSE_SIMD,
   PRAGMA_OMP_CLAUSE_SIMDLEN,
   PRAGMA_OMP_CLAUSE_TASKGROUP,
   PRAGMA_OMP_CLAUSE_THREAD_LIMIT,
+  PRAGMA_OMP_CLAUSE_THREADS,
   PRAGMA_OMP_CLAUSE_TO,
   PRAGMA_OMP_CLAUSE_UNIFORM,
   PRAGMA_OMP_CLAUSE_UNTIED,
-  
+
   /* Clauses for Cilk Plus SIMD-enabled function.  */
   PRAGMA_CILK_CLAUSE_NOMASK,
   PRAGMA_CILK_CLAUSE_MASK,
--- gcc/c-family/c-common.h.jj	2015-04-29 10:59:19.553523200 +0200
+++ gcc/c-family/c-common.h	2015-04-29 11:03:04.642991080 +0200
@@ -1228,13 +1228,14 @@ enum c_omp_clause_split
   C_OMP_CLAUSE_SPLIT_FOR,
   C_OMP_CLAUSE_SPLIT_SIMD,
   C_OMP_CLAUSE_SPLIT_COUNT,
-  C_OMP_CLAUSE_SPLIT_SECTIONS = C_OMP_CLAUSE_SPLIT_FOR
+  C_OMP_CLAUSE_SPLIT_SECTIONS = C_OMP_CLAUSE_SPLIT_FOR,
+  C_OMP_CLAUSE_SPLIT_TASKLOOP = C_OMP_CLAUSE_SPLIT_FOR
 };
 
 extern tree c_finish_omp_master (location_t, tree);
 extern tree c_finish_omp_taskgroup (location_t, tree);
 extern tree c_finish_omp_critical (location_t, tree, tree);
-extern tree c_finish_omp_ordered (location_t, tree);
+extern tree c_finish_omp_ordered (location_t, tree, tree);
 extern void c_finish_omp_barrier (location_t);
 extern tree c_finish_omp_atomic (location_t, enum tree_code, enum tree_code,
 				 tree, tree, tree, tree, tree, bool, bool);
--- gcc/tree-core.h.jj	2015-04-29 10:58:01.646745719 +0200
+++ gcc/tree-core.h	2015-04-29 11:03:04.643991064 +0200
@@ -310,7 +310,7 @@ enum omp_clause_code {
   /* OpenMP clause: nowait.  */
   OMP_CLAUSE_NOWAIT,
 
-  /* OpenMP clause: ordered.  */
+  /* OpenMP clause: ordered [(constant-integer-expression)].  */
   OMP_CLAUSE_ORDERED,
 
   /* OpenMP clause: default.  */
@@ -367,6 +367,24 @@ enum omp_clause_code {
   /* OpenMP clause: taskgroup.  */
   OMP_CLAUSE_TASKGROUP,
 
+  /* OpenMP clause: priority (integer-expression).  */
+  OMP_CLAUSE_PRIORITY,
+
+  /* OpenMP clause: grainsize (integer-expression).  */
+  OMP_CLAUSE_GRAINSIZE,
+
+  /* OpenMP clause: num_tasks (integer-expression).  */
+  OMP_CLAUSE_NUM_TASKS,
+
+  /* OpenMP clause: nogroup.  */
+  OMP_CLAUSE_NOGROUP,
+
+  /* OpenMP clause: threads.  */
+  OMP_CLAUSE_THREADS,
+
+  /* OpenMP clause: simd.  */
+  OMP_CLAUSE_SIMD,
+
   /* Internally used only clause, holding SIMD uid.  */
   OMP_CLAUSE__SIMDUID_,
 
@@ -1227,6 +1245,8 @@ enum omp_clause_depend_kind
   OMP_CLAUSE_DEPEND_IN,
   OMP_CLAUSE_DEPEND_OUT,
   OMP_CLAUSE_DEPEND_INOUT,
+  OMP_CLAUSE_DEPEND_SOURCE,
+  OMP_CLAUSE_DEPEND_SINK,
   OMP_CLAUSE_DEPEND_LAST
 };
 
--- gcc/omp-low.c.jj	2015-04-29 10:58:01.489748182 +0200
+++ gcc/omp-low.c	2015-04-29 11:03:04.646991017 +0200
@@ -1809,6 +1809,9 @@ scan_sharing_clauses (tree clauses, omp_
 	case OMP_CLAUSE_SCHEDULE:
 	case OMP_CLAUSE_DIST_SCHEDULE:
 	case OMP_CLAUSE_DEPEND:
+	case OMP_CLAUSE_PRIORITY:
+	case OMP_CLAUSE_GRAINSIZE:
+	case OMP_CLAUSE_NUM_TASKS:
 	case OMP_CLAUSE__CILK_FOR_COUNT_:
 	case OMP_CLAUSE_NUM_GANGS:
 	case OMP_CLAUSE_NUM_WORKERS:
@@ -1908,6 +1911,10 @@ scan_sharing_clauses (tree clauses, omp_
 	case OMP_CLAUSE_MERGEABLE:
 	case OMP_CLAUSE_PROC_BIND:
 	case OMP_CLAUSE_SAFELEN:
+	case OMP_CLAUSE_SIMDLEN:
+	case OMP_CLAUSE_THREADS:
+	case OMP_CLAUSE_SIMD:
+	case OMP_CLAUSE_NOGROUP:
 	case OMP_CLAUSE_ASYNC:
 	case OMP_CLAUSE_WAIT:
 	case OMP_CLAUSE_GANG:
@@ -2033,11 +2040,18 @@ scan_sharing_clauses (tree clauses, omp_
 	case OMP_CLAUSE_MERGEABLE:
 	case OMP_CLAUSE_PROC_BIND:
 	case OMP_CLAUSE_SAFELEN:
+	case OMP_CLAUSE_SIMDLEN:
 	case OMP_CLAUSE_ALIGNED:
 	case OMP_CLAUSE_DEPEND:
 	case OMP_CLAUSE__LOOPTEMP_:
 	case OMP_CLAUSE_TO:
 	case OMP_CLAUSE_FROM:
+	case OMP_CLAUSE_PRIORITY:
+	case OMP_CLAUSE_GRAINSIZE:
+	case OMP_CLAUSE_NUM_TASKS:
+	case OMP_CLAUSE_THREADS:
+	case OMP_CLAUSE_SIMD:
+	case OMP_CLAUSE_NOGROUP:
 	case OMP_CLAUSE__CILK_FOR_COUNT_:
 	case OMP_CLAUSE_ASYNC:
 	case OMP_CLAUSE_WAIT:
@@ -3030,19 +3044,26 @@ check_omp_nesting_restrictions (gimple s
 	    case GF_OMP_TARGET_KIND_REGION: stmt_name = "target"; break;
 	    case GF_OMP_TARGET_KIND_DATA: stmt_name = "target data"; break;
 	    case GF_OMP_TARGET_KIND_UPDATE: stmt_name = "target update"; break;
+	    case GF_OMP_TARGET_KIND_ENTER_DATA:
+	      stmt_name = "target enter data"; break;
+	    case GF_OMP_TARGET_KIND_EXIT_DATA:
+	      stmt_name = "target exit data"; break;
 	    case GF_OMP_TARGET_KIND_OACC_PARALLEL: stmt_name = "parallel"; break;
 	    case GF_OMP_TARGET_KIND_OACC_KERNELS: stmt_name = "kernels"; break;
 	    case GF_OMP_TARGET_KIND_OACC_DATA: stmt_name = "data"; break;
 	    case GF_OMP_TARGET_KIND_OACC_UPDATE: stmt_name = "update"; break;
-	    case GF_OMP_TARGET_KIND_OACC_ENTER_EXIT_DATA: stmt_name = "enter/exit data"; break;
+	    case GF_OMP_TARGET_KIND_OACC_ENTER_EXIT_DATA:
+	      stmt_name = "enter/exit data"; break;
 	    default: gcc_unreachable ();
 	    }
 	  switch (gimple_omp_target_kind (ctx->stmt))
 	    {
 	    case GF_OMP_TARGET_KIND_REGION: ctx_stmt_name = "target"; break;
 	    case GF_OMP_TARGET_KIND_DATA: ctx_stmt_name = "target data"; break;
-	    case GF_OMP_TARGET_KIND_OACC_PARALLEL: ctx_stmt_name = "parallel"; break;
-	    case GF_OMP_TARGET_KIND_OACC_KERNELS: ctx_stmt_name = "kernels"; break;
+	    case GF_OMP_TARGET_KIND_OACC_PARALLEL:
+	      ctx_stmt_name = "parallel"; break;
+	    case GF_OMP_TARGET_KIND_OACC_KERNELS:
+	      ctx_stmt_name = "kernels"; break;
 	    case GF_OMP_TARGET_KIND_OACC_DATA: ctx_stmt_name = "data"; break;
 	    default: gcc_unreachable ();
 	    }
@@ -8785,6 +8806,8 @@ expand_omp_target (struct omp_region *re
     {
     case GF_OMP_TARGET_KIND_REGION:
     case GF_OMP_TARGET_KIND_UPDATE:
+    case GF_OMP_TARGET_KIND_ENTER_DATA:
+    case GF_OMP_TARGET_KIND_EXIT_DATA:
     case GF_OMP_TARGET_KIND_OACC_PARALLEL:
     case GF_OMP_TARGET_KIND_OACC_KERNELS:
     case GF_OMP_TARGET_KIND_OACC_UPDATE:
@@ -8994,6 +9017,11 @@ expand_omp_target (struct omp_region *re
     case GF_OMP_TARGET_KIND_UPDATE:
       start_ix = BUILT_IN_GOMP_TARGET_UPDATE;
       break;
+    case GF_OMP_TARGET_KIND_ENTER_DATA:
+    case GF_OMP_TARGET_KIND_EXIT_DATA:
+      /* FIXME */
+      start_ix = BUILT_IN_GOMP_TARGET_UPDATE;
+      break;
     case GF_OMP_TARGET_KIND_OACC_PARALLEL:
     case GF_OMP_TARGET_KIND_OACC_KERNELS:
       start_ix = BUILT_IN_GOACC_PARALLEL;
@@ -9396,6 +9424,8 @@ build_omp_regions_1 (basic_block bb, str
 		case GF_OMP_TARGET_KIND_OACC_DATA:
 		  break;
 		case GF_OMP_TARGET_KIND_UPDATE:
+		case GF_OMP_TARGET_KIND_ENTER_DATA:
+		case GF_OMP_TARGET_KIND_EXIT_DATA:
 		case GF_OMP_TARGET_KIND_OACC_UPDATE:
 		case GF_OMP_TARGET_KIND_OACC_ENTER_EXIT_DATA:
 		  /* ..., other than for those stand-alone directives...  */
@@ -11198,6 +11228,8 @@ lower_omp_target (gimple_stmt_iterator *
     {
     case GF_OMP_TARGET_KIND_REGION:
     case GF_OMP_TARGET_KIND_UPDATE:
+    case GF_OMP_TARGET_KIND_ENTER_DATA:
+    case GF_OMP_TARGET_KIND_EXIT_DATA:
     case GF_OMP_TARGET_KIND_OACC_PARALLEL:
     case GF_OMP_TARGET_KIND_OACC_KERNELS:
     case GF_OMP_TARGET_KIND_OACC_UPDATE:
@@ -11251,13 +11283,13 @@ lower_omp_target (gimple_stmt_iterator *
 	  case GOMP_MAP_TOFROM:
 	  case GOMP_MAP_POINTER:
 	  case GOMP_MAP_TO_PSET:
-	    break;
 	  case GOMP_MAP_FORCE_ALLOC:
 	  case GOMP_MAP_FORCE_TO:
 	  case GOMP_MAP_FORCE_FROM:
 	  case GOMP_MAP_FORCE_TOFROM:
 	  case GOMP_MAP_FORCE_PRESENT:
 	  case GOMP_MAP_FORCE_DEALLOC:
+	    break;
 	  case GOMP_MAP_FORCE_DEVICEPTR:
 	    gcc_assert (is_gimple_omp_oacc (stmt));
 	    break;
@@ -11488,6 +11520,9 @@ lower_omp_target (gimple_stmt_iterator *
 	      default:
 		gcc_unreachable ();
 	      }
+	    /* FIXME: Temporary hack.  */
+	    if (talign_shift == 3)
+	      tkind &= ~GOMP_MAP_FLAG_FORCE;
 	    gcc_checking_assert (tkind
 				 < (HOST_WIDE_INT_C (1U) << talign_shift));
 	    talign = ceil_log2 (talign);
@@ -12244,6 +12279,8 @@ make_gimple_omp_edges (basic_block bb, s
 	case GF_OMP_TARGET_KIND_OACC_DATA:
 	  break;
 	case GF_OMP_TARGET_KIND_UPDATE:
+	case GF_OMP_TARGET_KIND_ENTER_DATA:
+	case GF_OMP_TARGET_KIND_EXIT_DATA:
 	case GF_OMP_TARGET_KIND_OACC_UPDATE:
 	case GF_OMP_TARGET_KIND_OACC_ENTER_EXIT_DATA:
 	  cur_region = cur_region->outer;
--- gcc/fortran/trans-openmp.c.jj	2015-04-29 10:59:40.236198646 +0200
+++ gcc/fortran/trans-openmp.c	2015-04-29 11:15:45.535945145 +0200
@@ -2356,6 +2356,7 @@ gfc_trans_omp_clauses (stmtblock_t *bloc
   if (clauses->ordered)
     {
       c = build_omp_clause (where.lb->location, OMP_CLAUSE_ORDERED);
+      OMP_CLAUSE_ORDERED_EXPR (c) = NULL_TREE;
       omp_clauses = gfc_trans_add_clause (c, omp_clauses);
     }
 
@@ -2531,6 +2532,7 @@ gfc_trans_omp_clauses (stmtblock_t *bloc
   if (clauses->seq)
     {
       c = build_omp_clause (where.lb->location, OMP_CLAUSE_ORDERED);
+      OMP_CLAUSE_ORDERED_EXPR (c) = NULL_TREE;
       omp_clauses = gfc_trans_add_clause (c, omp_clauses);
     }
   if (clauses->independent)
@@ -3494,7 +3496,8 @@ gfc_trans_omp_master (gfc_code *code)
 static tree
 gfc_trans_omp_ordered (gfc_code *code)
 {
-  return build1_v (OMP_ORDERED, gfc_trans_code (code->block->next));
+  return build2_loc (input_location, OMP_ORDERED, void_type_node,
+		     gfc_trans_code (code->block->next), NULL_TREE);
 }
 
 static tree
--- gcc/tree-pretty-print.c.jj	2015-04-29 10:58:01.663745452 +0200
+++ gcc/tree-pretty-print.c	2015-04-29 11:03:04.648990986 +0200
@@ -404,6 +404,13 @@ dump_omp_clause (pretty_printer *pp, tre
       break;
     case OMP_CLAUSE_ORDERED:
       pp_string (pp, "ordered");
+      if (OMP_CLAUSE_ORDERED_EXPR (clause))
+	{
+	  pp_left_paren (pp);
+	  dump_generic_node (pp, OMP_CLAUSE_ORDERED_EXPR (clause),
+			     spc, flags, false);
+	  pp_right_paren (pp);
+	}
       break;
 
     case OMP_CLAUSE_DEFAULT:
@@ -522,6 +529,9 @@ dump_omp_clause (pretty_printer *pp, tre
 	case OMP_CLAUSE_DEPEND_INOUT:
 	  pp_string (pp, "inout");
 	  break;
+	case OMP_CLAUSE_DEPEND_SOURCE:
+	  pp_string (pp, "source)");
+	  return;
 	default:
 	  gcc_unreachable ();
 	}
@@ -550,22 +560,22 @@ dump_omp_clause (pretty_printer *pp, tre
 	  pp_string (pp, "tofrom");
 	  break;
 	case GOMP_MAP_FORCE_ALLOC:
-	  pp_string (pp, "force_alloc");
+	  pp_string (pp, "always,alloc");
 	  break;
 	case GOMP_MAP_FORCE_TO:
-	  pp_string (pp, "force_to");
+	  pp_string (pp, "always,to");
 	  break;
 	case GOMP_MAP_FORCE_FROM:
-	  pp_string (pp, "force_from");
+	  pp_string (pp, "always,from");
 	  break;
 	case GOMP_MAP_FORCE_TOFROM:
-	  pp_string (pp, "force_tofrom");
+	  pp_string (pp, "always,tofrom");
 	  break;
 	case GOMP_MAP_FORCE_PRESENT:
 	  pp_string (pp, "force_present");
 	  break;
 	case GOMP_MAP_FORCE_DEALLOC:
-	  pp_string (pp, "force_dealloc");
+	  pp_string (pp, "always,delete");
 	  break;
 	case GOMP_MAP_FORCE_DEVICEPTR:
 	  pp_string (pp, "force_deviceptr");
@@ -678,6 +688,27 @@ dump_omp_clause (pretty_printer *pp, tre
       pp_right_paren (pp);
       break;
 
+    case OMP_CLAUSE_PRIORITY:
+      pp_string (pp, "priority(");
+      dump_generic_node (pp, OMP_CLAUSE_PRIORITY_EXPR (clause),
+			 spc, flags, false);
+      pp_right_paren (pp);
+      break;
+
+    case OMP_CLAUSE_GRAINSIZE:
+      pp_string (pp, "grainsize(");
+      dump_generic_node (pp, OMP_CLAUSE_GRAINSIZE_EXPR (clause),
+			 spc, flags, false);
+      pp_right_paren (pp);
+      break;
+
+    case OMP_CLAUSE_NUM_TASKS:
+      pp_string (pp, "num_tasks(");
+      dump_generic_node (pp, OMP_CLAUSE_NUM_TASKS_EXPR (clause),
+			 spc, flags, false);
+      pp_right_paren (pp);
+      break;
+
     case OMP_CLAUSE__SIMDUID_:
       pp_string (pp, "_simduid_(");
       dump_generic_node (pp, OMP_CLAUSE__SIMDUID__DECL (clause),
@@ -796,6 +827,15 @@ dump_omp_clause (pretty_printer *pp, tre
     case OMP_CLAUSE_TASKGROUP:
       pp_string (pp, "taskgroup");
       break;
+    case OMP_CLAUSE_NOGROUP:
+      pp_string (pp, "nogroup");
+      break;
+    case OMP_CLAUSE_THREADS:
+      pp_string (pp, "threads");
+      break;
+    case OMP_CLAUSE_SIMD:
+      pp_string (pp, "simd");
+      break;
     case OMP_CLAUSE_INDEPENDENT:
       pp_string (pp, "independent");
       break;
@@ -2652,6 +2692,10 @@ dump_generic_node (pretty_printer *pp, t
       pp_string (pp, "#pragma omp distribute");
       goto dump_omp_loop;
 
+    case OMP_TASKLOOP:
+      pp_string (pp, "#pragma omp taskloop");
+      goto dump_omp_loop;
+
     case OACC_LOOP:
       pp_string (pp, "#pragma acc loop");
       goto dump_omp_loop;
@@ -2666,6 +2710,18 @@ dump_generic_node (pretty_printer *pp, t
       dump_omp_clauses (pp, OMP_TARGET_DATA_CLAUSES (node), spc, flags);
       goto dump_omp_body;
 
+    case OMP_TARGET_ENTER_DATA:
+      pp_string (pp, "#pragma omp target enter data");
+      dump_omp_clauses (pp, OMP_TARGET_ENTER_DATA_CLAUSES (node), spc, flags);
+      is_expr = false;
+      break;
+
+    case OMP_TARGET_EXIT_DATA:
+      pp_string (pp, "#pragma omp target exit data");
+      dump_omp_clauses (pp, OMP_TARGET_EXIT_DATA_CLAUSES (node), spc, flags);
+      is_expr = false;
+      break;
+
     case OMP_TARGET:
       pp_string (pp, "#pragma omp target");
       dump_omp_clauses (pp, OMP_TARGET_CLAUSES (node), spc, flags);
@@ -2766,6 +2822,7 @@ dump_generic_node (pretty_printer *pp, t
 
     case OMP_ORDERED:
       pp_string (pp, "#pragma omp ordered");
+      dump_omp_clauses (pp, OMP_ORDERED_CLAUSES (node), spc, flags);
       goto dump_omp_body;
 
     case OMP_CRITICAL:

	Jakub

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

* Re: [gomp4.1] Initial support for some OpenMP 4.1 construct parsing
  2015-04-29 11:44 [gomp4.1] Initial support for some OpenMP 4.1 construct parsing Jakub Jelinek
@ 2015-04-29 11:55 ` Thomas Schwinge
  2015-04-29 12:31   ` Jakub Jelinek
  0 siblings, 1 reply; 33+ messages in thread
From: Thomas Schwinge @ 2015-04-29 11:55 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: gcc-patches, Kirill Yukhin, Richard Henderson

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

Hi Jakub!

(I have not yet read any version of the OpenMP 4.1 standard.)

On Wed, 29 Apr 2015 13:14:06 +0200, Jakub Jelinek <jakub@redhat.com> wrote:
> --- gcc/tree.def.jj	2015-04-29 10:58:01.663745452 +0200
> +++ gcc/tree.def	2015-04-29 11:34:18.293302684 +0200

> +/* OpenMP - #pragma omp target enter data [clause1 ... clauseN]
> +   Operand 0: OMP_TARGET_ENTER_DATA_CLAUSES: List of clauses.  */
> +DEFTREECODE (OMP_TARGET_ENTER_DATA, "omp_target_enter_data", tcc_statement, 1)
> +
> +/* OpenMP - #pragma omp target exit data [clause1 ... clauseN]
> +   Operand 0: OMP_TARGET_EXIT_DATA_CLAUSES: List of clauses.  */
> +DEFTREECODE (OMP_TARGET_EXIT_DATA, "omp_target_exit_data", tcc_statement, 1)

;-) Heh, OpenMP catching up with OpenACC?

> --- gcc/c/c-parser.c.jj	2015-04-29 10:59:20.760504260 +0200
> +++ gcc/c/c-parser.c	2015-04-29 11:03:04.641991095 +0200

>     map ( variable-list )
>  
>     map-kind:
> -     alloc | to | from | tofrom  */
> +     alloc | to | from | tofrom
> +
> +   OpenMP 4.1:
> +   map-kind:
> +     alloc | to | from | tofrom | delete
> +
> +   map ( always [,] map-kind: variable-list ) */

"Funnily", OpenACC 2.5 is said to be dropping the "always" semantics that
OpenMP 4.1 is now adding...  That is, OpenACC 2.5's "copy" will then be
the same as "present_or_copy", and so on.

>  static tree
>  c_parser_omp_target_data (location_t loc, c_parser *parser)
>  {
> -  tree stmt = make_node (OMP_TARGET_DATA);
> -  TREE_TYPE (stmt) = void_type_node;
> -
> -  OMP_TARGET_DATA_CLAUSES (stmt)
> +  tree clauses
>      = c_parser_omp_all_clauses (parser, OMP_TARGET_DATA_CLAUSE_MASK,
>  				"#pragma omp target data");
> +  if (find_omp_clause (clauses, OMP_CLAUSE_MAP) == NULL_TREE)
> +    {
> +      error_at (loc,
> +		"%<#pragma omp target data%> must contain at least one "
> +		"%<map%> clause");
> +      return NULL_TREE;
> +    }
> +
> +  tree stmt = make_node (OMP_TARGET_DATA);
> +  TREE_TYPE (stmt) = void_type_node;
> +  OMP_TARGET_DATA_CLAUSES (stmt) = clauses;

Even if it doesn't make a lot of sense, my reading of OpenMP 4.0 has been
that a target data construct without any map clauses is still valid.
(But I have not verified that now.)

> --- gcc/omp-low.c.jj	2015-04-29 10:58:01.489748182 +0200
> +++ gcc/omp-low.c	2015-04-29 11:03:04.646991017 +0200
> @@ -8994,6 +9017,11 @@ expand_omp_target (struct omp_region *re
>      case GF_OMP_TARGET_KIND_UPDATE:
>        start_ix = BUILT_IN_GOMP_TARGET_UPDATE;
>        break;
> +    case GF_OMP_TARGET_KIND_ENTER_DATA:
> +    case GF_OMP_TARGET_KIND_EXIT_DATA:
> +      /* FIXME */
> +      start_ix = BUILT_IN_GOMP_TARGET_UPDATE;
> +      break;

Actually, I've also wondered (but never verified) whether all of the
OpenACC enter, exit, and update constructs can be implemented via the
same libgomp API.

> @@ -11488,6 +11520,9 @@ lower_omp_target (gimple_stmt_iterator *
>  	      default:
>  		gcc_unreachable ();
>  	      }
> +	    /* FIXME: Temporary hack.  */
> +	    if (talign_shift == 3)
> +	      tkind &= ~GOMP_MAP_FLAG_FORCE;
>  	    gcc_checking_assert (tkind
>  				 < (HOST_WIDE_INT_C (1U) << talign_shift));
>  	    talign = ceil_log2 (talign);

Assuming you'll be changing the relevant functions' APIs, and assigning
new ABI versions, don't forget to also drop the unused offload_table
formal parameter (assuming that it remains unused).

> --- gcc/tree-pretty-print.c.jj	2015-04-29 10:58:01.663745452 +0200
> +++ gcc/tree-pretty-print.c	2015-04-29 11:03:04.648990986 +0200
> @@ -550,22 +560,22 @@ dump_omp_clause (pretty_printer *pp, tre
>  	  pp_string (pp, "tofrom");
>  	  break;
>  	case GOMP_MAP_FORCE_ALLOC:
> -	  pp_string (pp, "force_alloc");
> +	  pp_string (pp, "always,alloc");
>  	  break;
>  	case GOMP_MAP_FORCE_TO:
> -	  pp_string (pp, "force_to");
> +	  pp_string (pp, "always,to");
>  	  break;
>  	case GOMP_MAP_FORCE_FROM:
> -	  pp_string (pp, "force_from");
> +	  pp_string (pp, "always,from");
>  	  break;
>  	case GOMP_MAP_FORCE_TOFROM:
> -	  pp_string (pp, "force_tofrom");
> +	  pp_string (pp, "always,tofrom");
>  	  break;
>  	case GOMP_MAP_FORCE_PRESENT:
>  	  pp_string (pp, "force_present");
>  	  break;
>  	case GOMP_MAP_FORCE_DEALLOC:
> -	  pp_string (pp, "force_dealloc");
> +	  pp_string (pp, "always,delete");
>  	  break;
>  	case GOMP_MAP_FORCE_DEVICEPTR:
>  	  pp_string (pp, "force_deviceptr");

Makes some sense to me to use the same "always,*" syntax also for the
other "force_*" ones, given that these are artificial ("non-OpenACC")
descriptions anyway.


Grüße,
 Thomas

[-- Attachment #2: Type: application/pgp-signature, Size: 472 bytes --]

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

* Re: [gomp4.1] Initial support for some OpenMP 4.1 construct parsing
  2015-04-29 11:55 ` Thomas Schwinge
@ 2015-04-29 12:31   ` Jakub Jelinek
  2015-04-29 15:20     ` Thomas Schwinge
  2015-06-09 18:39     ` Ilya Verbin
  0 siblings, 2 replies; 33+ messages in thread
From: Jakub Jelinek @ 2015-04-29 12:31 UTC (permalink / raw)
  To: Thomas Schwinge; +Cc: gcc-patches, Kirill Yukhin, Richard Henderson

On Wed, Apr 29, 2015 at 01:52:24PM +0200, Thomas Schwinge wrote:
> Hi Jakub!
> 
> (I have not yet read any version of the OpenMP 4.1 standard.)

There is no OpenMP 4.1 standard, just the public TR3 released in November
last year, and then some non-public WIP.

> > +  tree stmt = make_node (OMP_TARGET_DATA);
> > +  TREE_TYPE (stmt) = void_type_node;
> > +  OMP_TARGET_DATA_CLAUSES (stmt) = clauses;
> 
> Even if it doesn't make a lot of sense, my reading of OpenMP 4.0 has been
> that a target data construct without any map clauses is still valid.
> (But I have not verified that now.)

Yes, it is valid in OpenMP 4.0.  But in GCC we're just supporting the latest
standard, there is no -fopenmp={2.5,3.0,3.1,4.0,4.1} like there is
-std=c{89,99,11}.

> > --- gcc/omp-low.c.jj	2015-04-29 10:58:01.489748182 +0200
> > +++ gcc/omp-low.c	2015-04-29 11:03:04.646991017 +0200
> > @@ -8994,6 +9017,11 @@ expand_omp_target (struct omp_region *re
> >      case GF_OMP_TARGET_KIND_UPDATE:
> >        start_ix = BUILT_IN_GOMP_TARGET_UPDATE;
> >        break;
> > +    case GF_OMP_TARGET_KIND_ENTER_DATA:
> > +    case GF_OMP_TARGET_KIND_EXIT_DATA:
> > +      /* FIXME */
> > +      start_ix = BUILT_IN_GOMP_TARGET_UPDATE;
> > +      break;
> 
> Actually, I've also wondered (but never verified) whether all of the
> OpenACC enter, exit, and update constructs can be implemented via the
> same libgomp API.

Well, the behavior is different.  The draft requires only alloc or to
(or always, variants) for enter data and only from or delete (or always,
variants) for exit data, so in theory it is possible to figure that from
the call without extra args, but not so for update - enter data is supposed
to increment reference counts, exit data decrement.  And, we'll need new
arguments for async (pass through info that it is async (nowait) or sync,
and the depend clause address(es)).

> 
> > @@ -11488,6 +11520,9 @@ lower_omp_target (gimple_stmt_iterator *
> >  	      default:
> >  		gcc_unreachable ();
> >  	      }
> > +	    /* FIXME: Temporary hack.  */
> > +	    if (talign_shift == 3)
> > +	      tkind &= ~GOMP_MAP_FLAG_FORCE;
> >  	    gcc_checking_assert (tkind
> >  				 < (HOST_WIDE_INT_C (1U) << talign_shift));
> >  	    talign = ceil_log2 (talign);
> 
> Assuming you'll be changing the relevant functions' APIs, and assigning
> new ABI versions, don't forget to also drop the unused offload_table
> formal parameter (assuming that it remains unused).

Yeah, we'll need new GOMP_target{,_data,_end_data,_update} replacements.

> > --- gcc/tree-pretty-print.c.jj	2015-04-29 10:58:01.663745452 +0200
> > +++ gcc/tree-pretty-print.c	2015-04-29 11:03:04.648990986 +0200
> > @@ -550,22 +560,22 @@ dump_omp_clause (pretty_printer *pp, tre
> >  	  pp_string (pp, "tofrom");
> >  	  break;
> >  	case GOMP_MAP_FORCE_ALLOC:
> > -	  pp_string (pp, "force_alloc");
> > +	  pp_string (pp, "always,alloc");
> >  	  break;
> >  	case GOMP_MAP_FORCE_TO:
> > -	  pp_string (pp, "force_to");
> > +	  pp_string (pp, "always,to");
> >  	  break;
> >  	case GOMP_MAP_FORCE_FROM:
> > -	  pp_string (pp, "force_from");
> > +	  pp_string (pp, "always,from");
> >  	  break;
> >  	case GOMP_MAP_FORCE_TOFROM:
> > -	  pp_string (pp, "force_tofrom");
> > +	  pp_string (pp, "always,tofrom");
> >  	  break;
> >  	case GOMP_MAP_FORCE_PRESENT:
> >  	  pp_string (pp, "force_present");
> >  	  break;
> >  	case GOMP_MAP_FORCE_DEALLOC:
> > -	  pp_string (pp, "force_dealloc");
> > +	  pp_string (pp, "always,delete");
> >  	  break;
> >  	case GOMP_MAP_FORCE_DEVICEPTR:
> >  	  pp_string (pp, "force_deviceptr");
> 
> Makes some sense to me to use the same "always,*" syntax also for the
> other "force_*" ones, given that these are artificial ("non-OpenACC")
> descriptions anyway.

Ok.  Are the GOMP_MAP_FORCE_* artificial too?  If yes, I can change that
to GOMP_MAP_ALWAYS_*.

Anyway, for most of the further 4.1 offloading I'll defer to Ilya Verbin and
Kyrill as agreed privately on IRC, I'll focus for now on the task / doacross
etc. stuff for now (and, hopefully if enough of the OpenACC stuff is merged
in soon, restart work on the OpenMP 4.0 / NVPTX offloading too, but that not
on this branch).

	Jakub

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

* Re: [gomp4.1] Initial support for some OpenMP 4.1 construct parsing
  2015-04-29 12:31   ` Jakub Jelinek
@ 2015-04-29 15:20     ` Thomas Schwinge
  2015-06-09 18:39     ` Ilya Verbin
  1 sibling, 0 replies; 33+ messages in thread
From: Thomas Schwinge @ 2015-04-29 15:20 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: gcc-patches, Kirill Yukhin, Richard Henderson

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

Hi Jakub!

On Wed, 29 Apr 2015 14:06:44 +0200, Jakub Jelinek <jakub@redhat.com> wrote:
> On Wed, Apr 29, 2015 at 01:52:24PM +0200, Thomas Schwinge wrote:
> > > --- gcc/tree-pretty-print.c.jj	2015-04-29 10:58:01.663745452 +0200
> > > +++ gcc/tree-pretty-print.c	2015-04-29 11:03:04.648990986 +0200
> > > @@ -550,22 +560,22 @@ dump_omp_clause (pretty_printer *pp, tre
> > >  	  pp_string (pp, "tofrom");
> > >  	  break;
> > >  	case GOMP_MAP_FORCE_ALLOC:
> > > -	  pp_string (pp, "force_alloc");
> > > +	  pp_string (pp, "always,alloc");
> > >  	  break;
> > >  	case GOMP_MAP_FORCE_TO:
> > > -	  pp_string (pp, "force_to");
> > > +	  pp_string (pp, "always,to");
> > >  	  break;
> > >  	case GOMP_MAP_FORCE_FROM:
> > > -	  pp_string (pp, "force_from");
> > > +	  pp_string (pp, "always,from");
> > >  	  break;
> > >  	case GOMP_MAP_FORCE_TOFROM:
> > > -	  pp_string (pp, "force_tofrom");
> > > +	  pp_string (pp, "always,tofrom");
> > >  	  break;
> > >  	case GOMP_MAP_FORCE_PRESENT:
> > >  	  pp_string (pp, "force_present");
> > >  	  break;
> > >  	case GOMP_MAP_FORCE_DEALLOC:
> > > -	  pp_string (pp, "force_dealloc");
> > > +	  pp_string (pp, "always,delete");
> > >  	  break;
> > >  	case GOMP_MAP_FORCE_DEVICEPTR:
> > >  	  pp_string (pp, "force_deviceptr");
> > 
> > Makes some sense to me to use the same "always,*" syntax also for the
> > other "force_*" ones, given that these are artificial ("non-OpenACC")
> > descriptions anyway.
> 
> Ok.  Are the GOMP_MAP_FORCE_* artificial too?  If yes, I can change that
> to GOMP_MAP_ALWAYS_*.

Yes, fine with me.  (Though, what about that »names are sticky« thing,
<http://news.gmane.org/find-root.php?message_id=%3C523AC6FF.6030007%40acm.org%3E>?)


Grüße,
 Thomas

[-- Attachment #2: Type: application/pgp-signature, Size: 472 bytes --]

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

* Re: [gomp4.1] Initial support for some OpenMP 4.1 construct parsing
  2015-04-29 12:31   ` Jakub Jelinek
  2015-04-29 15:20     ` Thomas Schwinge
@ 2015-06-09 18:39     ` Ilya Verbin
  2015-06-09 20:25       ` Jakub Jelinek
  2015-06-11 12:52       ` [gomp4.1] map clause parsing improvements Jakub Jelinek
  1 sibling, 2 replies; 33+ messages in thread
From: Ilya Verbin @ 2015-06-09 18:39 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: Thomas Schwinge, gcc-patches, Kirill Yukhin, Richard Henderson

On Wed, Apr 29, 2015 at 14:06:44 +0200, Jakub Jelinek wrote:
> [...] The draft requires only alloc or to
> (or always, variants) for enter data and only from or delete (or always,
> variants) for exit data, so in theory it is possible to figure that from
> the call without extra args, but not so for update - enter data is supposed
> to increment reference counts, exit data decrement. [...]

TR3.pdf also says about 'release' map-type for exit data, but it is not
described in the document.

> [...] And, we'll need new
> arguments for async (pass through info that it is async (nowait) or sync,
> and the depend clause address(es)).

I don't quite understand from "If a depend clause is present, then it is treated
as if it had appeared on the implicit task construct that encloses the target
construct", is

  #pragma omp target depend(inout: x)

equivalent to

  #pragma omp task depend(inout: x)
  #pragma omp target

or not?

In other words, can't we just generate GOMP_task (...) with GOMP_target (...)
inside, without any new arguments?

Thanks,
  -- Ilya

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

* Re: [gomp4.1] Initial support for some OpenMP 4.1 construct parsing
  2015-06-09 18:39     ` Ilya Verbin
@ 2015-06-09 20:25       ` Jakub Jelinek
  2015-06-25 19:47         ` Ilya Verbin
  2015-06-11 12:52       ` [gomp4.1] map clause parsing improvements Jakub Jelinek
  1 sibling, 1 reply; 33+ messages in thread
From: Jakub Jelinek @ 2015-06-09 20:25 UTC (permalink / raw)
  To: Ilya Verbin
  Cc: Thomas Schwinge, gcc-patches, Kirill Yukhin, Richard Henderson

On Tue, Jun 09, 2015 at 09:36:08PM +0300, Ilya Verbin wrote:
> On Wed, Apr 29, 2015 at 14:06:44 +0200, Jakub Jelinek wrote:
> > [...] The draft requires only alloc or to
> > (or always, variants) for enter data and only from or delete (or always,
> > variants) for exit data, so in theory it is possible to figure that from
> > the call without extra args, but not so for update - enter data is supposed
> > to increment reference counts, exit data decrement. [...]
> 
> TR3.pdf also says about 'release' map-type for exit data, but it is not
> described in the document.

Seems that is the case even in the latest draft.  Can you file a ticket
for this or discuss on omp-lang?  Or should I?

> > [...] And, we'll need new
> > arguments for async (pass through info that it is async (nowait) or sync,
> > and the depend clause address(es)).
> 
> I don't quite understand from "If a depend clause is present, then it is treated
> as if it had appeared on the implicit task construct that encloses the target
> construct", is
> 
>   #pragma omp target depend(inout: x)
> 
> equivalent to
> 
>   #pragma omp task depend(inout: x)
>   #pragma omp target
> 
> or not?
> 
> In other words, can't we just generate GOMP_task (...) with GOMP_target (...)
> inside, without any new arguments?

No, that would be an explicit task.  Furthermore, the implicit task isn't
on the host side, but on the offloading device side.  The implicit task is
what is executed when you enter the #pragma omp target.  Ignoring the teams
construct which is there mainly for NVidia GPGPUs, when you enter the
#pragma omp target construct, there is an implicit parallel with
num_threads(1) (like there is an implicit parallel with num_threads(1)
when you enter main () of a host program), and that implicit parallel has
a single implicit task, which executes the statements inside of #pragma
omp target body, until you encounter #pragma omp teams or #pragma omp
parallel.  And the above statement simply says that no statements from
the #pragma omp target body are executed until the depend dependency is
satisfied.  Whether these dependencies are host addresses, or offloading
device addresses, is something that really needs to be figured out, I admit
I haven't read the whole async offloading text carefully yet, nor
participated in the telecons about it. 

	Jakub

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

* [gomp4.1] map clause parsing improvements
  2015-06-09 18:39     ` Ilya Verbin
  2015-06-09 20:25       ` Jakub Jelinek
@ 2015-06-11 12:52       ` Jakub Jelinek
  2015-10-19 10:34         ` Thomas Schwinge
  1 sibling, 1 reply; 33+ messages in thread
From: Jakub Jelinek @ 2015-06-11 12:52 UTC (permalink / raw)
  To: Ilya Verbin, Thomas Schwinge; +Cc: gcc-patches, Kirill Yukhin

On Tue, Jun 09, 2015 at 09:36:08PM +0300, Ilya Verbin wrote:
> On Wed, Apr 29, 2015 at 14:06:44 +0200, Jakub Jelinek wrote:
> > [...] The draft requires only alloc or to
> > (or always, variants) for enter data and only from or delete (or always,
> > variants) for exit data, so in theory it is possible to figure that from
> > the call without extra args, but not so for update - enter data is supposed
> > to increment reference counts, exit data decrement. [...]
> 
> TR3.pdf also says about 'release' map-type for exit data, but it is not
> described in the document.

So, I've committed a patch to add parsing release map-kind, and fix up or add
verification in C/C++ FE what map-kinds are used.

Furthermore, it seems the OpenMP 4.1 always modifier is something completely
unrelated to the OpenACC force flag, in OpenMP 4.1 everything is reference
count based, and always seems to make a difference only for from/to/tofrom,
where it says that the copying is done unconditionally; thus the patch uses
a different bit for that.

For array sections resulting in GOMP_MAP_POINTER kind perhaps we'll also
need an always variant for it, and supposedly on the exit data construct
we'll want to turn GOMP_MAP_POINTER into GOMP_MAP_RELEASE or GOMP_MAP_DELETE
depending on what it was originally.

2015-06-11  Jakub Jelinek  <jakub@redhat.com>

include/
	* gomp-constants.h (GOMP_MAP_FLAG_ALWAYS): Define.
	(enum gomp_map_kind): Add GOMP_MAP_ALWAYS_TO, GOMP_MAP_ALWAYS_FROM,
	GOMP_MAP_ALWAYS_TOFROM, GOMP_MAP_DELETE, GOMP_MAP_RELEASE.
gcc/
	* omp-low.c (lower_omp_target): Accept GOMP_MAP_RELEASE,
	GOMP_MAP_ALWAYS_TO, GOMP_MAP_ALWAYS_FROM and GOMP_MAP_ALWAYS_TOFROM.
	Accept GOMP_MAP_FORCE* except for FORCE_DEALLOC only for OpenACC.
	* tree-pretty-print.c (dump_omp_clause): Print GOMP_MAP_FORCE_*
	as force_*, handle GOMP_MAP_ALWAYS_*.
gcc/c/
	* c-parser.c (c_parser_omp_clause_map): Handle release
	map kind.  Adjust to use GOMP_MAP_ALWAYS_* and only on
	clauses where it makes sense.
	(c_parser_omp_target_data): Diagnose invalid map-kind
	for the construct.
	(c_parser_omp_target_enter_data): Adjust for new encoding
	of always,from, always,to and always,tofrom.  Accept
	GOMP_MAP_POINTER.
	(c_parser_omp_target_exit_data): Likewise.
	(c_parser_omp_target): Diagnose invalid map-kind for the
	construct.
gcc/cp/
	* parser.c (cp_parser_omp_clause_map): Handle release
	map kind.  Adjust to use GOMP_MAP_ALWAYS_* and only on
	clauses where it makes sense.
	(cp_parser_omp_target_data): Diagnose invalid map-kind
	for the construct.
	(cp_parser_omp_target_enter_data): Adjust for new encoding
	of always,from, always,to and always,tofrom.  Accept
	GOMP_MAP_POINTER.
	(cp_parser_omp_target_exit_data): Likewise.
	(cp_parser_omp_target): Diagnose invalid map-kind for the
	construct.

--- include/gomp-constants.h.jj	2015-05-21 11:12:09.000000000 +0200
+++ include/gomp-constants.h	2015-06-11 11:24:32.041654947 +0200
@@ -41,6 +41,8 @@
 #define GOMP_MAP_FLAG_SPECIAL_1		(1 << 3)
 #define GOMP_MAP_FLAG_SPECIAL		(GOMP_MAP_FLAG_SPECIAL_1 \
 					 | GOMP_MAP_FLAG_SPECIAL_0)
+/* OpenMP always flag.  */
+#define GOMP_MAP_FLAG_ALWAYS		(1 << 6)
 /* Flag to force a specific behavior (or else, trigger a run-time error).  */
 #define GOMP_MAP_FLAG_FORCE		(1 << 7)
 
@@ -77,7 +79,21 @@ enum gomp_map_kind
     /* ..., and copy from device.  */
     GOMP_MAP_FORCE_FROM =		(GOMP_MAP_FLAG_FORCE | GOMP_MAP_FROM),
     /* ..., and copy to and from device.  */
-    GOMP_MAP_FORCE_TOFROM =		(GOMP_MAP_FLAG_FORCE | GOMP_MAP_TOFROM)
+    GOMP_MAP_FORCE_TOFROM =		(GOMP_MAP_FLAG_FORCE | GOMP_MAP_TOFROM),
+    /* If not already present, allocate.  And unconditionally copy to
+       device.  */
+    GOMP_MAP_ALWAYS_TO =		(GOMP_MAP_FLAG_ALWAYS | GOMP_MAP_TO),
+    /* If not already present, allocate.  And unconditionally copy from
+       device.  */
+    GOMP_MAP_ALWAYS_FROM =		(GOMP_MAP_FLAG_ALWAYS | GOMP_MAP_FROM),
+    /* If not already present, allocate.  And unconditionally copy to and from
+       device.  */
+    GOMP_MAP_ALWAYS_TOFROM =		(GOMP_MAP_FLAG_ALWAYS | GOMP_MAP_TOFROM),
+    /* OpenMP 4.1 alias for forced deallocation.  */
+    GOMP_MAP_DELETE =			GOMP_MAP_FORCE_DEALLOC,
+    /* Decrement usage count and deallocate if zero.  */
+    GOMP_MAP_RELEASE =			(GOMP_MAP_FLAG_ALWAYS
+					 | GOMP_MAP_FORCE_DEALLOC)
   };
 
 #define GOMP_MAP_COPY_TO_P(X) \
--- gcc/omp-low.c.jj	2015-06-10 19:50:26.000000000 +0200
+++ gcc/omp-low.c	2015-06-11 11:35:02.515892363 +0200
@@ -12511,13 +12511,17 @@ lower_omp_target (gimple_stmt_iterator *
 	  case GOMP_MAP_TOFROM:
 	  case GOMP_MAP_POINTER:
 	  case GOMP_MAP_TO_PSET:
+	  case GOMP_MAP_FORCE_DEALLOC:
+	  case GOMP_MAP_RELEASE:
+	  case GOMP_MAP_ALWAYS_TO:
+	  case GOMP_MAP_ALWAYS_FROM:
+	  case GOMP_MAP_ALWAYS_TOFROM:
+	    break;
 	  case GOMP_MAP_FORCE_ALLOC:
 	  case GOMP_MAP_FORCE_TO:
 	  case GOMP_MAP_FORCE_FROM:
 	  case GOMP_MAP_FORCE_TOFROM:
 	  case GOMP_MAP_FORCE_PRESENT:
-	  case GOMP_MAP_FORCE_DEALLOC:
-	    break;
 	  case GOMP_MAP_FORCE_DEVICEPTR:
 	    gcc_assert (is_gimple_omp_oacc (stmt));
 	    break;
--- gcc/tree-pretty-print.c.jj	2015-05-19 18:56:43.000000000 +0200
+++ gcc/tree-pretty-print.c	2015-06-11 11:32:39.814102121 +0200
@@ -560,26 +560,38 @@ dump_omp_clause (pretty_printer *pp, tre
 	  pp_string (pp, "tofrom");
 	  break;
 	case GOMP_MAP_FORCE_ALLOC:
-	  pp_string (pp, "always,alloc");
+	  pp_string (pp, "force_alloc");
 	  break;
 	case GOMP_MAP_FORCE_TO:
-	  pp_string (pp, "always,to");
+	  pp_string (pp, "force_to");
 	  break;
 	case GOMP_MAP_FORCE_FROM:
-	  pp_string (pp, "always,from");
+	  pp_string (pp, "force_from");
 	  break;
 	case GOMP_MAP_FORCE_TOFROM:
-	  pp_string (pp, "always,tofrom");
+	  pp_string (pp, "force_tofrom");
 	  break;
 	case GOMP_MAP_FORCE_PRESENT:
 	  pp_string (pp, "force_present");
 	  break;
 	case GOMP_MAP_FORCE_DEALLOC:
-	  pp_string (pp, "always,delete");
+	  pp_string (pp, "delete");
 	  break;
 	case GOMP_MAP_FORCE_DEVICEPTR:
 	  pp_string (pp, "force_deviceptr");
 	  break;
+	case GOMP_MAP_ALWAYS_TO:
+	  pp_string (pp, "always,to");
+	  break;
+	case GOMP_MAP_ALWAYS_FROM:
+	  pp_string (pp, "always,from");
+	  break;
+	case GOMP_MAP_ALWAYS_TOFROM:
+	  pp_string (pp, "always,tofrom");
+	  break;
+	case GOMP_MAP_RELEASE:
+	  pp_string (pp, "release");
+	  break;
 	default:
 	  gcc_unreachable ();
 	}
--- gcc/c/c-parser.c.jj	2015-06-10 14:52:06.000000000 +0200
+++ gcc/c/c-parser.c	2015-06-11 13:02:30.788629315 +0200
@@ -11661,7 +11661,7 @@ c_parser_omp_clause_depend (c_parser *pa
 
    OpenMP 4.1:
    map-kind:
-     alloc | to | from | tofrom | delete
+     alloc | to | from | tofrom | release | delete
 
    map ( always [,] map-kind: variable-list ) */
 
@@ -11702,6 +11702,7 @@ c_parser_omp_clause_map (c_parser *parse
 		  || strcmp ("to", p) == 0
 		  || strcmp ("from", p) == 0
 		  || strcmp ("tofrom", p) == 0
+		  || strcmp ("release", p) == 0
 		  || strcmp ("delete", p) == 0)
 		{
 		  c_parser_consume_token (parser);
@@ -11718,13 +11719,15 @@ c_parser_omp_clause_map (c_parser *parse
       if (strcmp ("alloc", p) == 0)
 	kind = GOMP_MAP_ALLOC;
       else if (strcmp ("to", p) == 0)
-	kind = GOMP_MAP_TO;
+	kind = always ? GOMP_MAP_ALWAYS_TO : GOMP_MAP_TO;
       else if (strcmp ("from", p) == 0)
-	kind = GOMP_MAP_FROM;
+	kind = always ? GOMP_MAP_ALWAYS_FROM : GOMP_MAP_FROM;
       else if (strcmp ("tofrom", p) == 0)
-	kind = GOMP_MAP_TOFROM;
+	kind = always ? GOMP_MAP_ALWAYS_TOFROM : GOMP_MAP_TOFROM;
+      else if (strcmp ("release", p) == 0)
+	kind = GOMP_MAP_RELEASE;
       else if (strcmp ("delete", p) == 0)
-	kind = GOMP_MAP_FORCE_DEALLOC;
+	kind = GOMP_MAP_DELETE;
       else
 	{
 	  c_parser_error (parser, "invalid map kind");
@@ -11732,8 +11735,6 @@ c_parser_omp_clause_map (c_parser *parse
 				     "expected %<)%>");
 	  return list;
 	}
-      if (always)
-	kind = (enum gomp_map_kind) (kind | GOMP_MAP_FLAG_FORCE);
       c_parser_consume_token (parser);
       c_parser_consume_token (parser);
     }
@@ -14237,11 +14238,40 @@ c_parser_omp_target_data (location_t loc
   tree clauses
     = c_parser_omp_all_clauses (parser, OMP_TARGET_DATA_CLAUSE_MASK,
 				"#pragma omp target data");
-  if (find_omp_clause (clauses, OMP_CLAUSE_MAP) == NULL_TREE)
+  int map_seen = 0;
+  for (tree *pc = &clauses; *pc;)
     {
-      error_at (loc,
-		"%<#pragma omp target data%> must contain at least one "
-		"%<map%> clause");
+      if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_MAP)
+	switch (OMP_CLAUSE_MAP_KIND (*pc))
+	  {
+	  case GOMP_MAP_TO:
+	  case GOMP_MAP_ALWAYS_TO:
+	  case GOMP_MAP_FROM:
+	  case GOMP_MAP_ALWAYS_FROM:
+	  case GOMP_MAP_TOFROM:
+	  case GOMP_MAP_ALWAYS_TOFROM:
+	  case GOMP_MAP_ALLOC:
+	  case GOMP_MAP_POINTER:
+	    map_seen = 3;
+	    break;
+	  default:
+	    map_seen |= 1;
+	    error_at (OMP_CLAUSE_LOCATION (*pc),
+		      "%<#pragma omp target data%> with map-type other "
+		      "than %<to%>, %<from%>, %<tofrom%> or %<alloc%> "
+		      "on %<map%> clause");
+	    *pc = OMP_CLAUSE_CHAIN (*pc);
+	    continue;
+	  }
+      pc = &OMP_CLAUSE_CHAIN (*pc);
+    }
+
+  if (map_seen != 3)
+    {
+      if (map_seen == 0)
+	error_at (loc,
+		  "%<#pragma omp target data%> must contain at least "
+		  "one %<map%> clause");
       return NULL_TREE;
     }
 
@@ -14348,10 +14378,12 @@ c_parser_omp_target_enter_data (location
   for (tree *pc = &clauses; *pc;)
     {
       if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_MAP)
-	switch (OMP_CLAUSE_MAP_KIND (*pc) & ~GOMP_MAP_FLAG_FORCE)
+	switch (OMP_CLAUSE_MAP_KIND (*pc))
 	  {
 	  case GOMP_MAP_TO:
+	  case GOMP_MAP_ALWAYS_TO:
 	  case GOMP_MAP_ALLOC:
+	  case GOMP_MAP_POINTER:
 	    map_seen = 3;
 	    break;
 	  default:
@@ -14430,17 +14462,21 @@ c_parser_omp_target_exit_data (location_
   for (tree *pc = &clauses; *pc;)
     {
       if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_MAP)
-	switch (OMP_CLAUSE_MAP_KIND (*pc) & ~GOMP_MAP_FLAG_FORCE)
+	switch (OMP_CLAUSE_MAP_KIND (*pc))
 	  {
 	  case GOMP_MAP_FROM:
-	  case GOMP_MAP_FORCE_DEALLOC & ~GOMP_MAP_FLAG_FORCE:
+	  case GOMP_MAP_ALWAYS_FROM:
+	  case GOMP_MAP_RELEASE:
+	  case GOMP_MAP_DELETE:
+	  case GOMP_MAP_POINTER:
 	    map_seen = 3;
 	    break;
 	  default:
 	    map_seen |= 1;
 	    error_at (OMP_CLAUSE_LOCATION (*pc),
 		      "%<#pragma omp target exit data%> with map-type other "
-		      "than %<from%> or %<delete%> on %<map%> clause");
+		      "than %<from%>, %<release> or %<delete%> on %<map%>"
+		      " clause");
 	    *pc = OMP_CLAUSE_CHAIN (*pc);
 	    continue;
 	  }
@@ -14480,6 +14516,7 @@ c_parser_omp_target (c_parser *parser, e
 {
   location_t loc = c_parser_peek_token (parser)->location;
   c_parser_consume_pragma (parser);
+  tree *pc = NULL, stmt, block;
 
   if (context != pragma_stmt && context != pragma_compound)
     {
@@ -14519,7 +14556,8 @@ c_parser_omp_target (c_parser *parser, e
 	  OMP_TARGET_CLAUSES (stmt) = cclauses[C_OMP_CLAUSE_SPLIT_TARGET];
 	  OMP_TARGET_BODY (stmt) = block;
 	  add_stmt (stmt);
-	  return true;
+	  pc = &OMP_TARGET_CLAUSES (stmt);
+	  goto check_clauses;
 	}
       else if (!flag_openmp)  /* flag_openmp_simd  */
 	{
@@ -14551,19 +14589,46 @@ c_parser_omp_target (c_parser *parser, e
 	}
     }
 
-  tree stmt = make_node (OMP_TARGET);
+  stmt = make_node (OMP_TARGET);
   TREE_TYPE (stmt) = void_type_node;
 
   OMP_TARGET_CLAUSES (stmt)
     = c_parser_omp_all_clauses (parser, OMP_TARGET_CLAUSE_MASK,
 				"#pragma omp target");
+  pc = &OMP_TARGET_CLAUSES (stmt);
   keep_next_level ();
-  tree block = c_begin_compound_stmt (true);
+  block = c_begin_compound_stmt (true);
   add_stmt (c_parser_omp_structured_block (parser));
   OMP_TARGET_BODY (stmt) = c_end_compound_stmt (loc, block, true);
 
   SET_EXPR_LOCATION (stmt, loc);
   add_stmt (stmt);
+
+check_clauses:
+  while (*pc)
+    {
+      if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_MAP)
+	switch (OMP_CLAUSE_MAP_KIND (*pc))
+	  {
+	  case GOMP_MAP_TO:
+	  case GOMP_MAP_ALWAYS_TO:
+	  case GOMP_MAP_FROM:
+	  case GOMP_MAP_ALWAYS_FROM:
+	  case GOMP_MAP_TOFROM:
+	  case GOMP_MAP_ALWAYS_TOFROM:
+	  case GOMP_MAP_ALLOC:
+	  case GOMP_MAP_POINTER:
+	    break;
+	  default:
+	    error_at (OMP_CLAUSE_LOCATION (*pc),
+		      "%<#pragma omp target%> with map-type other "
+		      "than %<to%>, %<from%>, %<tofrom%> or %<alloc%> "
+		      "on %<map%> clause");
+	    *pc = OMP_CLAUSE_CHAIN (*pc);
+	    continue;
+	  }
+      pc = &OMP_CLAUSE_CHAIN (*pc);
+    }
   return true;
 }
 
--- gcc/cp/parser.c.jj	2015-06-03 19:48:09.000000000 +0200
+++ gcc/cp/parser.c	2015-06-11 13:03:19.746878152 +0200
@@ -29150,7 +29150,7 @@ cp_parser_omp_clause_depend (cp_parser *
 
    OpenMP 4.1:
    map-kind:
-     alloc | to | from | tofrom | delete
+     alloc | to | from | tofrom | release | delete
 
    map ( always [,] map-kind: variable-list ) */
 
@@ -29195,13 +29195,15 @@ cp_parser_omp_clause_map (cp_parser *par
       if (strcmp ("alloc", p) == 0)
 	kind = GOMP_MAP_ALLOC;
       else if (strcmp ("to", p) == 0)
-	kind = GOMP_MAP_TO;
+	kind = always ? GOMP_MAP_ALWAYS_TO : GOMP_MAP_TO;
       else if (strcmp ("from", p) == 0)
-	kind = GOMP_MAP_FROM;
+	kind = always ? GOMP_MAP_ALWAYS_FROM : GOMP_MAP_FROM;
       else if (strcmp ("tofrom", p) == 0)
-	kind = GOMP_MAP_TOFROM;
+	kind = always ? GOMP_MAP_ALWAYS_TOFROM : GOMP_MAP_TOFROM;
+      else if (strcmp ("release", p) == 0)
+	kind = GOMP_MAP_RELEASE;
       else if (strcmp ("delete", p) == 0)
-	kind = GOMP_MAP_FORCE_DEALLOC;
+	kind = GOMP_MAP_DELETE;
       else
 	{
 	  cp_parser_error (parser, "invalid map kind");
@@ -29210,8 +29212,6 @@ cp_parser_omp_clause_map (cp_parser *par
 						 /*consume_paren=*/true);
 	  return list;
 	}
-      if (always)
-	kind = (enum gomp_map_kind) (kind | GOMP_MAP_FLAG_FORCE);
       cp_lexer_consume_token (parser->lexer);
       cp_lexer_consume_token (parser->lexer);
     }
@@ -31690,11 +31690,40 @@ cp_parser_omp_target_data (cp_parser *pa
   tree clauses
     = cp_parser_omp_all_clauses (parser, OMP_TARGET_DATA_CLAUSE_MASK,
 				 "#pragma omp target data", pragma_tok);
-  if (find_omp_clause (clauses, OMP_CLAUSE_MAP) == NULL_TREE)
+  int map_seen = 0;
+  for (tree *pc = &clauses; *pc;)
     {
-      error_at (pragma_tok->location,
-		"%<#pragma omp target data%> must contain at least one "
-		"%<map%> clause");
+      if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_MAP)
+       switch (OMP_CLAUSE_MAP_KIND (*pc))
+	 {
+	 case GOMP_MAP_TO:
+	 case GOMP_MAP_ALWAYS_TO:
+	 case GOMP_MAP_FROM:
+	 case GOMP_MAP_ALWAYS_FROM:
+	 case GOMP_MAP_TOFROM:
+	 case GOMP_MAP_ALWAYS_TOFROM:
+	 case GOMP_MAP_ALLOC:
+	 case GOMP_MAP_POINTER:
+	   map_seen = 3;
+	   break;
+	 default:
+	   map_seen |= 1;
+	   error_at (OMP_CLAUSE_LOCATION (*pc),
+		     "%<#pragma omp target data%> with map-type other "
+		     "than %<to%>, %<from%>, %<tofrom%> or %<alloc%> "
+		     "on %<map%> clause");
+	   *pc = OMP_CLAUSE_CHAIN (*pc);
+	   continue;
+	 }
+      pc = &OMP_CLAUSE_CHAIN (*pc);
+    }
+
+  if (map_seen != 3)
+    {
+      if (map_seen == 0)
+	error_at (pragma_tok->location,
+		  "%<#pragma omp target data%> must contain at least "
+		  "one %<map%> clause");
       return NULL_TREE;
     }
 
@@ -31759,10 +31788,12 @@ cp_parser_omp_target_enter_data (cp_pars
   for (tree *pc = &clauses; *pc;)
     {
       if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_MAP)
-       switch (OMP_CLAUSE_MAP_KIND (*pc) & ~GOMP_MAP_FLAG_FORCE)
+       switch (OMP_CLAUSE_MAP_KIND (*pc))
 	 {
 	 case GOMP_MAP_TO:
+	 case GOMP_MAP_ALWAYS_TO:
 	 case GOMP_MAP_ALLOC:
+	 case GOMP_MAP_POINTER:
 	   map_seen = 3;
 	   break;
 	 default:
@@ -31842,17 +31873,21 @@ cp_parser_omp_target_exit_data (cp_parse
   for (tree *pc = &clauses; *pc;)
     {
       if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_MAP)
-       switch (OMP_CLAUSE_MAP_KIND (*pc) & ~GOMP_MAP_FLAG_FORCE)
+       switch (OMP_CLAUSE_MAP_KIND (*pc))
 	 {
 	 case GOMP_MAP_FROM:
-	 case GOMP_MAP_FORCE_DEALLOC & ~GOMP_MAP_FLAG_FORCE:
+	 case GOMP_MAP_ALWAYS_FROM:
+	 case GOMP_MAP_RELEASE:
+	 case GOMP_MAP_DELETE:
+	 case GOMP_MAP_POINTER:
 	   map_seen = 3;
 	   break;
 	 default:
 	   map_seen |= 1;
 	   error_at (OMP_CLAUSE_LOCATION (*pc),
 		     "%<#pragma omp target exit data%> with map-type other "
-		     "than %<from%> or %<delete%> on %<map%> clause");
+		     "than %<from%>, %<release%> or %<delete%> on %<map%>"
+		     " clause");
 	   *pc = OMP_CLAUSE_CHAIN (*pc);
 	   continue;
 	 }
@@ -31934,6 +31969,8 @@ static bool
 cp_parser_omp_target (cp_parser *parser, cp_token *pragma_tok,
 		      enum pragma_context context)
 {
+  tree *pc = NULL, stmt;
+
   if (context != pragma_stmt && context != pragma_compound)
     {
       cp_parser_error (parser, "expected declaration specifiers");
@@ -31975,7 +32012,8 @@ cp_parser_omp_target (cp_parser *parser,
 	  OMP_TARGET_CLAUSES (stmt) = cclauses[C_OMP_CLAUSE_SPLIT_TARGET];
 	  OMP_TARGET_BODY (stmt) = body;
 	  add_stmt (stmt);
-	  return true;
+	  pc = &OMP_TARGET_CLAUSES (stmt);
+	  goto check_clauses;
 	}
       else if (!flag_openmp)  /* flag_openmp_simd  */
 	{
@@ -32007,17 +32045,44 @@ cp_parser_omp_target (cp_parser *parser,
 	}
     }
 
-  tree stmt = make_node (OMP_TARGET);
+  stmt = make_node (OMP_TARGET);
   TREE_TYPE (stmt) = void_type_node;
 
   OMP_TARGET_CLAUSES (stmt)
     = cp_parser_omp_all_clauses (parser, OMP_TARGET_CLAUSE_MASK,
 				 "#pragma omp target", pragma_tok);
+  pc = &OMP_TARGET_CLAUSES (stmt);
   keep_next_level (true);
   OMP_TARGET_BODY (stmt) = cp_parser_omp_structured_block (parser);
 
   SET_EXPR_LOCATION (stmt, pragma_tok->location);
   add_stmt (stmt);
+
+check_clauses:
+  while (*pc)
+    {
+      if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_MAP)
+	switch (OMP_CLAUSE_MAP_KIND (*pc))
+	  {
+	  case GOMP_MAP_TO:
+	  case GOMP_MAP_ALWAYS_TO:
+	  case GOMP_MAP_FROM:
+	  case GOMP_MAP_ALWAYS_FROM:
+	  case GOMP_MAP_TOFROM:
+	  case GOMP_MAP_ALWAYS_TOFROM:
+	  case GOMP_MAP_ALLOC:
+	  case GOMP_MAP_POINTER:
+	    break;
+	  default:
+	    error_at (OMP_CLAUSE_LOCATION (*pc),
+		      "%<#pragma omp target%> with map-type other "
+		      "than %<to%>, %<from%>, %<tofrom%> or %<alloc%> "
+		      "on %<map%> clause");
+	    *pc = OMP_CLAUSE_CHAIN (*pc);
+	    continue;
+	  }
+      pc = &OMP_CLAUSE_CHAIN (*pc);
+    }
   return true;
 }
 


	Jakub

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

* Re: [gomp4.1] Initial support for some OpenMP 4.1 construct parsing
  2015-06-09 20:25       ` Jakub Jelinek
@ 2015-06-25 19:47         ` Ilya Verbin
  2015-06-25 20:31           ` Jakub Jelinek
  0 siblings, 1 reply; 33+ messages in thread
From: Ilya Verbin @ 2015-06-25 19:47 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: gcc-patches, Kirill Yukhin

On Tue, Jun 09, 2015 at 22:24:26 +0200, Jakub Jelinek wrote:
> On Tue, Jun 09, 2015 at 09:36:08PM +0300, Ilya Verbin wrote:
> > I don't quite understand from "If a depend clause is present, then it is treated
> > as if it had appeared on the implicit task construct that encloses the target
> > construct", is
> > 
> >   #pragma omp target depend(inout: x)
> > 
> > equivalent to
> > 
> >   #pragma omp task depend(inout: x)
> >   #pragma omp target
> > 
> > or not?
> > 
> > In other words, can't we just generate GOMP_task (...) with GOMP_target (...)
> > inside, without any new arguments?
> 
> No, that would be an explicit task.  Furthermore, the implicit task isn't
> on the host side, but on the offloading device side.  The implicit task is
> what is executed when you enter the #pragma omp target.  Ignoring the teams
> construct which is there mainly for NVidia GPGPUs, when you enter the
> #pragma omp target construct, there is an implicit parallel with
> num_threads(1) (like there is an implicit parallel with num_threads(1)
> when you enter main () of a host program), and that implicit parallel has
> a single implicit task, which executes the statements inside of #pragma
> omp target body, until you encounter #pragma omp teams or #pragma omp
> parallel.  And the above statement simply says that no statements from
> the #pragma omp target body are executed until the depend dependency is
> satisfied.  Whether these dependencies are host addresses, or offloading
> device addresses, is something that really needs to be figured out, I admit
> I haven't read the whole async offloading text carefully yet, nor
> participated in the telecons about it. 

So, as I understood, three tasks will be generated almost simultaneously in
foo1: one on host and two on target.
Target task 1 will be executed immediately.
Host task will wait for task 1 to be completed on target.
(Or it is not possible to mix "omp target" and "omp task" dependencies?)
And task 2 will wait on target for task 1.

void foo1 ()
{
  int x;

  #pragma omp parallel
  #pragma omp single
    {
      #pragma omp target nowait depend(out: x)
	fprintf (stderr, "target task 1\n");

      #pragma omp task depend(in: x)
	fprintf (stderr, "host task\n");

      #pragma omp target depend(in: x)
	fprintf (stderr, "target task 2\n");
    }
}

I just can't understand why do we need target tasks, i.e. why a host task with a
target region inside can't wait for another host task, like in foo2?

void foo2 ()
{
  int x;

  #pragma omp parallel
  #pragma omp single
    {
      #pragma omp task depend(out: x)
      #pragma omp target
	fprintf (stderr, "host task with tgt 1\n");

      #pragma omp task depend(in: x)
	fprintf (stderr, "host task\n");

      #pragma omp task depend(in: x) 
      #pragma omp target
	fprintf (stderr, "host task with tgt 2\n");
    }
}

Thanks,
  -- Ilya

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

* Re: [gomp4.1] Initial support for some OpenMP 4.1 construct parsing
  2015-06-25 19:47         ` Ilya Verbin
@ 2015-06-25 20:31           ` Jakub Jelinek
  2015-07-17 16:47             ` Ilya Verbin
  0 siblings, 1 reply; 33+ messages in thread
From: Jakub Jelinek @ 2015-06-25 20:31 UTC (permalink / raw)
  To: Ilya Verbin; +Cc: gcc-patches, Kirill Yukhin

On Thu, Jun 25, 2015 at 10:45:29PM +0300, Ilya Verbin wrote:
> So, as I understood, three tasks will be generated almost simultaneously in
> foo1: one on host and two on target.
> Target task 1 will be executed immediately.
> Host task will wait for task 1 to be completed on target.
> (Or it is not possible to mix "omp target" and "omp task" dependencies?)
> And task 2 will wait on target for task 1.

My understanding is that you don't create any extra tasks,
but rather you pointer translate the host address from the start of the
variable (or array section; thus the depend clause argument) into
target address, and check if it can be offloaded right away (no need
to wait for dependencies).  If yes, you just offload it, with nowait
without waiting in the caller till it finishes.  If not, you arrange
that when some other offloaded job finishes that provides the dependency,
your scheduled job is executed.
So, the task on the target is the implicit one, what executes the
body of the target region.
In tasking (task.c) dependencies are only honored for sibling tasks,
whether the different target implicit tasks are sibling is questionable and
supposedly should be clarified, but I can't imagine they aren't meant to.
So, you don't really need to care about the task.c dependencies, target.c
could have its own ones if it is easier to write it that way.
Supposedly for nowait you want to spawn or queue the job and return right
away, and for queued job stick it into some data structure (supposedly
inside of libgomp on the host) that when the library is (asynchronously)
notified that some offloaded job finished you check the data structures
and spawn something different.  Or have the data structures on the offloaded
device instead?

In any case, I'd look what the Mentor folks are doing for OpenACC async
offloading, what libmicoffload allows you to do and figure out something
from that.

It is not entirely clear to me if the host tasks and threads that execute the
async #pragma omp target {,enter data,exit data,update} depend(...) {,nowait}
constructs are relevant to it at all, but I bet one task/thread could
supposedly invoke something and a different one invoke something that
depends on it, or waits for its completion (exit data?).

And, wonder how is this really meant to work with host fallback.  Bet that
really needs to be clarified on omp-lang.

	Jakub

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

* Re: [gomp4.1] Initial support for some OpenMP 4.1 construct parsing
  2015-06-25 20:31           ` Jakub Jelinek
@ 2015-07-17 16:47             ` Ilya Verbin
  2015-07-17 16:54               ` Jakub Jelinek
  0 siblings, 1 reply; 33+ messages in thread
From: Ilya Verbin @ 2015-07-17 16:47 UTC (permalink / raw)
  To: Jakub Jelinek, Thomas Schwinge; +Cc: gcc-patches, Kirill Yukhin

On Thu, Jun 25, 2015 at 22:10:58 +0200, Jakub Jelinek wrote:
> On Thu, Jun 25, 2015 at 10:45:29PM +0300, Ilya Verbin wrote:
> > So, as I understood, three tasks will be generated almost simultaneously in
> > foo1: one on host and two on target.
> > Target task 1 will be executed immediately.
> > Host task will wait for task 1 to be completed on target.
> > (Or it is not possible to mix "omp target" and "omp task" dependencies?)
> > And task 2 will wait on target for task 1.
> 
> My understanding is that you don't create any extra tasks,
> but rather you pointer translate the host address from the start of the
> variable (or array section; thus the depend clause argument) into
> target address, and check if it can be offloaded right away (no need
> to wait for dependencies).  If yes, you just offload it, with nowait
> without waiting in the caller till it finishes.  If not, you arrange
> that when some other offloaded job finishes that provides the dependency,
> your scheduled job is executed.
> So, the task on the target is the implicit one, what executes the
> body of the target region.
> In tasking (task.c) dependencies are only honored for sibling tasks,
> whether the different target implicit tasks are sibling is questionable and
> supposedly should be clarified, but I can't imagine they aren't meant to.
> So, you don't really need to care about the task.c dependencies, target.c
> could have its own ones if it is easier to write it that way.
> Supposedly for nowait you want to spawn or queue the job and return right
> away, and for queued job stick it into some data structure (supposedly
> inside of libgomp on the host) that when the library is (asynchronously)
> notified that some offloaded job finished you check the data structures
> and spawn something different.  Or have the data structures on the offloaded
> device instead?
> 
> In any case, I'd look what the Mentor folks are doing for OpenACC async
> offloading, what libmicoffload allows you to do and figure out something
> from that.

One big question is who will maintain the list of scheduled job, its
dependencies, etc. - libgomp or each target plugin?


OpenACC has async queues:
#pragma acc parallel async(2) wait(1)

But it's not possible to have 2 waits like:
#pragma acc parallel async(3) wait(1) wait(2)

(GOMP_OFFLOAD_openacc_async_wait_async has only one argument with the number of
queue to wait)

Thomas, please correct me if I'm wrong.

In this regard, OpenMP is more complicated, since it allows e.g.:
#pragma omp target nowait depend(in: a, b) depend(out: c, d)

Currently I'm trying to figure out what liboffloadmic can do.


BTW, do you plan to remove GOMP_MAP_POINTER mappings from array sections?
The enter/exit patch for libgomp depends on this change.

  -- Ilya

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

* Re: [gomp4.1] Initial support for some OpenMP 4.1 construct parsing
  2015-07-17 16:47             ` Ilya Verbin
@ 2015-07-17 16:54               ` Jakub Jelinek
  2015-07-20 16:18                 ` Jakub Jelinek
  2015-07-20 19:40                 ` [gomp4.1] Initial support for some OpenMP 4.1 construct parsing Ilya Verbin
  0 siblings, 2 replies; 33+ messages in thread
From: Jakub Jelinek @ 2015-07-17 16:54 UTC (permalink / raw)
  To: Ilya Verbin; +Cc: Thomas Schwinge, gcc-patches, Kirill Yukhin

On Fri, Jul 17, 2015 at 07:31:36PM +0300, Ilya Verbin wrote:
> One big question is who will maintain the list of scheduled job, its
> dependencies, etc. - libgomp or each target plugin?
> 
> 
> OpenACC has async queues:
> #pragma acc parallel async(2) wait(1)
> 
> But it's not possible to have 2 waits like:
> #pragma acc parallel async(3) wait(1) wait(2)
> 
> (GOMP_OFFLOAD_openacc_async_wait_async has only one argument with the number of
> queue to wait)
> 
> Thomas, please correct me if I'm wrong.
> 
> In this regard, OpenMP is more complicated, since it allows e.g.:
> #pragma omp target nowait depend(in: a, b) depend(out: c, d)

If it is each plugin, then supposedly it should use (if possible) some
common libgomp routine to maintain the queues, duplicating the dependency
graph handling code in each plugins might be too ugly.

> Currently I'm trying to figure out what liboffloadmic can do.
> 
> 
> BTW, do you plan to remove GOMP_MAP_POINTER mappings from array sections?
> The enter/exit patch for libgomp depends on this change.

My current plan (for Monday and onwards) is to first implement firstprivate
on target construct, once that works hack on the GOMP_MAP_POINTER
replacement, and then rewrite the gimplification rules for target construct
for the new 2.15.5 rules (so that this one does not really break all the
target tests we need the first two working somehow).

	Jakub

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

* Re: [gomp4.1] Initial support for some OpenMP 4.1 construct parsing
  2015-07-17 16:54               ` Jakub Jelinek
@ 2015-07-20 16:18                 ` Jakub Jelinek
  2015-07-20 18:31                   ` Jakub Jelinek
  2015-07-20 19:40                 ` [gomp4.1] Initial support for some OpenMP 4.1 construct parsing Ilya Verbin
  1 sibling, 1 reply; 33+ messages in thread
From: Jakub Jelinek @ 2015-07-20 16:18 UTC (permalink / raw)
  To: Ilya Verbin; +Cc: Thomas Schwinge, gcc-patches, Kirill Yukhin

On Fri, Jul 17, 2015 at 06:43:06PM +0200, Jakub Jelinek wrote:
> > BTW, do you plan to remove GOMP_MAP_POINTER mappings from array sections?
> > The enter/exit patch for libgomp depends on this change.
> 
> My current plan (for Monday and onwards) is to first implement firstprivate
> on target construct, once that works hack on the GOMP_MAP_POINTER
> replacement, and then rewrite the gimplification rules for target construct
> for the new 2.15.5 rules (so that this one does not really break all the
> target tests we need the first two working somehow).

Ok, so here is the first part of that, GOMP_MAP_FIRSTPRIVATE support as a
way to support firstprivate/is_device_ptr clauses on target construct (and private
clause too, though that is compiler only change).
firstprivate VLAs aren't supported yet, but that will be a compiler only
change.

I'll commit this patch tomorrow.

2015-07-20  Jakub Jelinek  <jakub@redhat.com>

gcc/
	* omp-low.c (scan_sharing_clauses): Handle firstprivate
	and is_device_ptr clauses on target region.
	(lower_omp_target): Handle OMP_CLAUSE_FIRSTPRIVATE,
	OMP_CLAUSE_IS_DEVICE_PTR and OMP_CLAUSE_PRIVATE.
include/
	* gomp-constants.h (enum gomp_map_kind): Add GOMP_MAP_FIRSTPRIVATE.
libgomp/
	* target.c (gomp_map_vars): Handle GOMP_MAP_FIRSTPRIVATE.
	* testsuite/libgomp.c/target-13.c: New test.
	* testsuite/libgomp.c/target-14.c: New test.
	* testsuite/libgomp.c++/target-5.C: New test.
	* testsuite/libgomp.c++/target-6.C: New test.

--- gcc/omp-low.c.jj	2015-07-16 18:09:25.000000000 +0200
+++ gcc/omp-low.c	2015-07-20 17:43:33.271401254 +0200
@@ -1930,6 +1930,10 @@ scan_sharing_clauses (tree clauses, omp_
 	      else if (!global)
 		install_var_field (decl, by_ref, 3, ctx);
 	    }
+	  else if ((OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FIRSTPRIVATE
+		    || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IS_DEVICE_PTR)
+		   && is_gimple_omp_offloaded (ctx->stmt))
+	    install_var_field (decl, !is_reference (decl), 3, ctx);
 	  install_var_local (decl, ctx);
 	  if (is_gimple_omp_oacc (ctx->stmt)
 	      && OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION)
@@ -12929,6 +12933,21 @@ lower_omp_target (gimple_stmt_iterator *
 	    DECL_HAS_VALUE_EXPR_P (new_var) = 1;
 	  }
 	map_cnt++;
+	break;
+
+      case OMP_CLAUSE_FIRSTPRIVATE:
+      case OMP_CLAUSE_IS_DEVICE_PTR:
+	map_cnt++;
+	var = OMP_CLAUSE_DECL (c);
+	if (!is_reference (var)
+	    && !is_gimple_reg_type (TREE_TYPE (var)))
+	  {
+	    x = build_receiver_ref (var, true, ctx);
+	    tree new_var = lookup_decl (var, ctx);
+	    SET_DECL_VALUE_EXPR (new_var, x);
+	    DECL_HAS_VALUE_EXPR_P (new_var) = 1;
+	  }
+	break;
       }
 
   if (offloaded)
@@ -12994,7 +13013,8 @@ lower_omp_target (gimple_stmt_iterator *
       for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c))
 	switch (OMP_CLAUSE_CODE (c))
 	  {
-	    tree ovar, nc;
+	    tree ovar, nc, s, purpose, var, x;
+	    unsigned int talign;
 
 	  default:
 	    break;
@@ -13037,13 +13057,13 @@ lower_omp_target (gimple_stmt_iterator *
 		  continue;
 	      }
 
-	    unsigned int talign = TYPE_ALIGN_UNIT (TREE_TYPE (ovar));
+	    talign = TYPE_ALIGN_UNIT (TREE_TYPE (ovar));
 	    if (DECL_P (ovar) && DECL_ALIGN_UNIT (ovar) > talign)
 	      talign = DECL_ALIGN_UNIT (ovar);
 	    if (nc)
 	      {
-		tree var = lookup_decl_in_outer_ctx (ovar, ctx);
-		tree x = build_sender_ref (ovar, ctx);
+		var = lookup_decl_in_outer_ctx (ovar, ctx);
+		x = build_sender_ref (ovar, ctx);
 		if (maybe_lookup_oacc_reduction (var, ctx))
 		  {
 		    gcc_checking_assert (offloaded
@@ -13092,11 +13112,11 @@ lower_omp_target (gimple_stmt_iterator *
 		    gimplify_assign (x, var, &ilist);
 		  }
 	      }
-	    tree s = OMP_CLAUSE_SIZE (c);
+	    s = OMP_CLAUSE_SIZE (c);
 	    if (s == NULL_TREE)
 	      s = TYPE_SIZE_UNIT (TREE_TYPE (ovar));
 	    s = fold_convert (size_type_node, s);
-	    tree purpose = size_int (map_idx++);
+	    purpose = size_int (map_idx++);
 	    CONSTRUCTOR_APPEND_ELT (vsize, purpose, s);
 	    if (TREE_CODE (s) != INTEGER_CST)
 	      TREE_STATIC (TREE_VEC_ELT (t, 1)) = 0;
@@ -13126,6 +13146,52 @@ lower_omp_target (gimple_stmt_iterator *
 				    build_int_cstu (tkind_type, tkind));
 	    if (nc && nc != c)
 	      c = nc;
+	    break;
+
+	  case OMP_CLAUSE_FIRSTPRIVATE:
+	  case OMP_CLAUSE_IS_DEVICE_PTR:
+	    ovar = OMP_CLAUSE_DECL (c);
+	    if (is_reference (ovar))
+	      talign = TYPE_ALIGN_UNIT (TREE_TYPE (TREE_TYPE (ovar)));
+	    else
+	      talign = DECL_ALIGN_UNIT (ovar);
+	    var = lookup_decl_in_outer_ctx (ovar, ctx);
+	    x = build_sender_ref (ovar, ctx);
+	    if (is_reference (var))
+	      gimplify_assign (x, var, &ilist);
+	    else if (is_gimple_reg (var))
+	      {
+		tree avar = create_tmp_var (TREE_TYPE (var));
+		mark_addressable (avar);
+		gimplify_assign (avar, var, &ilist);
+		avar = build_fold_addr_expr (avar);
+		gimplify_assign (x, avar, &ilist);
+	      }
+	    else
+	      {
+		var = build_fold_addr_expr (var);
+		gimplify_assign (x, var, &ilist);
+	      }
+	    if (is_reference (var))
+	      s = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (ovar)));
+	    else
+	      s = TYPE_SIZE_UNIT (TREE_TYPE (ovar));
+	    s = fold_convert (size_type_node, s);
+	    purpose = size_int (map_idx++);
+	    CONSTRUCTOR_APPEND_ELT (vsize, purpose, s);
+	    if (TREE_CODE (s) != INTEGER_CST)
+	      TREE_STATIC (TREE_VEC_ELT (t, 1)) = 0;
+
+	    tkind = GOMP_MAP_FIRSTPRIVATE;
+	    gcc_checking_assert (tkind
+				 < (HOST_WIDE_INT_C (1U) << talign_shift));
+	    talign = ceil_log2 (talign);
+	    tkind |= talign << talign_shift;
+	    gcc_checking_assert (tkind
+				 <= tree_to_uhwi (TYPE_MAX_VALUE (tkind_type)));
+	    CONSTRUCTOR_APPEND_ELT (vkind, purpose,
+				    build_int_cstu (tkind_type, tkind));
+	    break;
 	  }
 
       gcc_assert (map_idx == map_cnt);
@@ -13173,6 +13239,57 @@ lower_omp_target (gimple_stmt_iterator *
 
   if (offloaded)
     {
+      for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c))
+	switch (OMP_CLAUSE_CODE (c))
+	  {
+	    tree var;
+	  default:
+	    break;
+	  case OMP_CLAUSE_FIRSTPRIVATE:
+	  case OMP_CLAUSE_IS_DEVICE_PTR:
+	    var = OMP_CLAUSE_DECL (c);
+	    if (is_reference (var)
+		|| is_gimple_reg_type (TREE_TYPE (var)))
+	      {
+		tree new_var = lookup_decl (var, ctx);
+		tree x = build_receiver_ref (var, !is_reference (var), ctx);
+		gimplify_expr (&x, &new_body, NULL, is_gimple_val, fb_rvalue);
+		gimple_seq_add_stmt (&new_body,
+				     gimple_build_assign (new_var, x));
+	      }
+	    break;
+	  case OMP_CLAUSE_PRIVATE:
+	    var = OMP_CLAUSE_DECL (c);
+	    if (is_reference (var))
+	      {
+		location_t clause_loc = OMP_CLAUSE_LOCATION (c);
+		tree new_var = lookup_decl (var, ctx);
+		tree x = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (new_var)));
+		if (TREE_CONSTANT (x))
+		  {
+		    const char *name = NULL;
+		    if (DECL_NAME (var))
+		      name = IDENTIFIER_POINTER (DECL_NAME (new_var));
+
+		    x = create_tmp_var_raw (TREE_TYPE (TREE_TYPE (new_var)),
+					    name);
+		    gimple_add_tmp_var (x);
+		    TREE_ADDRESSABLE (x) = 1;
+		    x = build_fold_addr_expr_loc (clause_loc, x);
+		  }
+		else
+		  {
+		    tree atmp = builtin_decl_explicit (BUILT_IN_ALLOCA);
+		    x = build_call_expr_loc (clause_loc, atmp, 1, x);
+		  }
+
+		x = fold_convert_loc (clause_loc, TREE_TYPE (new_var), x);
+		gimplify_expr (&x, &new_body, NULL, is_gimple_val, fb_rvalue);
+		gimple_seq_add_stmt (&new_body,
+				     gimple_build_assign (new_var, x));
+	      }
+	    break;
+	  }
       gimple_seq_add_seq (&new_body, tgt_body);
       new_body = maybe_catch_exception (new_body);
     }
--- include/gomp-constants.h.jj	2015-06-23 16:23:45.000000000 +0200
+++ include/gomp-constants.h	2015-07-20 12:27:58.103210763 +0200
@@ -72,6 +72,8 @@ enum gomp_map_kind
     /* Is a device pointer.  OMP_CLAUSE_SIZE for these is unused; is implicitly
        POINTER_SIZE_UNITS.  */
     GOMP_MAP_FORCE_DEVICEPTR =		(GOMP_MAP_FLAG_SPECIAL_1 | 0),
+    /* Do not map, copy bits for firstprivate instead.  */
+    GOMP_MAP_FIRSTPRIVATE =		(GOMP_MAP_FLAG_SPECIAL | 0),
     /* Allocate.  */
     GOMP_MAP_FORCE_ALLOC =		(GOMP_MAP_FLAG_FORCE | GOMP_MAP_ALLOC),
     /* ..., and copy to device.  */
--- libgomp/target.c.jj	2015-07-15 13:00:32.000000000 +0200
+++ libgomp/target.c	2015-07-20 16:03:20.745931639 +0200
@@ -243,6 +243,7 @@ gomp_map_vars (struct gomp_device_descr
 	       bool short_mapkind, bool is_target)
 {
   size_t i, tgt_align, tgt_size, not_found_cnt = 0;
+  bool has_firstprivate = false;
   const int rshift = short_mapkind ? 8 : 3;
   const int typemask = short_mapkind ? 0xff : 0x7;
   struct splay_tree_s *mem_map = &devicep->mem_map;
@@ -280,6 +281,18 @@ gomp_map_vars (struct gomp_device_descr
 	cur_node.host_end = cur_node.host_start + sizes[i];
       else
 	cur_node.host_end = cur_node.host_start + sizeof (void *);
+      if ((kind & typemask) == GOMP_MAP_FIRSTPRIVATE)
+	{
+	  tgt->list[i].key = NULL;
+
+	  size_t align = (size_t) 1 << (kind >> rshift);
+	  if (tgt_align < align)
+	    tgt_align = align;
+	  tgt_size = (tgt_size + align - 1) & ~(align - 1);
+	  tgt_size += cur_node.host_end - cur_node.host_start;
+	  has_firstprivate = true;
+	  continue;
+	}
       splay_tree_key n = splay_tree_lookup (mem_map, &cur_node);
       if (n)
 	gomp_map_vars_existing (devicep, n, &cur_node, &tgt->list[i],
@@ -348,9 +361,10 @@ gomp_map_vars (struct gomp_device_descr
     tgt_size = mapnum * sizeof (void *);
 
   tgt->array = NULL;
-  if (not_found_cnt)
+  if (not_found_cnt || has_firstprivate)
     {
-      tgt->array = gomp_malloc (not_found_cnt * sizeof (*tgt->array));
+      if (not_found_cnt)
+	tgt->array = gomp_malloc (not_found_cnt * sizeof (*tgt->array));
       splay_tree_node array = tgt->array;
       size_t j;
 
@@ -360,6 +374,18 @@ gomp_map_vars (struct gomp_device_descr
 	    int kind = get_kind (short_mapkind, kinds, i);
 	    if (hostaddrs[i] == NULL)
 	      continue;
+	    if ((kind & typemask) == GOMP_MAP_FIRSTPRIVATE)
+	      {
+		size_t align = (size_t) 1 << (kind >> rshift);
+		tgt_size = (tgt_size + align - 1) & ~(align - 1);
+		tgt->list[i].offset = tgt_size;
+		size_t len = sizes[i];
+		devicep->host2dev_func (devicep->target_id,
+					(void *) (tgt->tgt_start + tgt_size),
+					(void *) hostaddrs[i], len);
+		tgt_size += len;
+		continue;
+	      }
 	    splay_tree_key k = &array->key;
 	    k->host_start = (uintptr_t) hostaddrs[i];
 	    if (!GOMP_MAP_POINTER_P (kind & typemask))
@@ -491,7 +517,13 @@ gomp_map_vars (struct gomp_device_descr
       for (i = 0; i < mapnum; i++)
 	{
 	  if (tgt->list[i].key == NULL)
-	    cur_node.tgt_offset = (uintptr_t) NULL;
+	    {
+	      if (hostaddrs[i] == NULL)
+		cur_node.tgt_offset = (uintptr_t) NULL;
+	      else
+		cur_node.tgt_offset = tgt->tgt_start
+				      + tgt->list[i].offset;
+	    }
 	  else
 	    cur_node.tgt_offset = tgt->list[i].key->tgt->tgt_start
 				  + tgt->list[i].key->tgt_offset;
--- libgomp/testsuite/libgomp.c/target-13.c.jj	2015-07-20 16:07:28.259375318 +0200
+++ libgomp/testsuite/libgomp.c/target-13.c	2015-07-20 16:26:05.828330031 +0200
@@ -0,0 +1,45 @@
+#ifdef __cplusplus
+extern "C"
+#else
+extern
+#endif
+void abort (void);
+struct S { int s, t; };
+
+void
+foo ()
+{
+  int x = 5, y = 6, err = 0;
+  struct S u = { 7, 8 }, v = { 9, 10 };
+  double s = 11.5, t = 12.5;
+  #pragma omp target private (x, u, s) firstprivate (y, v, t) map(from:err)
+  {
+    x = y;
+    u = v;
+    s = t;
+    err = (x != 6 || y != 6
+	   || u.s != 9 || u.t != 10 || v.s != 9 || v.t != 10
+	   || s != 12.5 || t != 12.5);
+    x += 1;
+    y += 2;
+    u.s += 3;
+    v.t += 4;
+    s += 2.5;
+    t += 3.0;
+    if (x != 7 || y != 8
+	|| u.s != 12 || u.t != 10 || v.s != 9 || v.t != 14
+	|| s != 15.0 || t != 15.5)
+      err = 1;
+  }
+  if (err || x != 5 || y != 6
+      || u.s != 7 || u.t != 8 || v.s != 9 || v.t != 10
+      || s != 11.5 || t != 12.5)
+    abort ();
+}
+
+int
+main ()
+{
+  foo ();
+  return 0;
+}
--- libgomp/testsuite/libgomp.c/target-14.c.jj	2015-07-20 17:44:51.443299100 +0200
+++ libgomp/testsuite/libgomp.c/target-14.c	2015-07-20 17:49:20.745483458 +0200
@@ -0,0 +1,38 @@
+#include <omp.h>
+#include <stdlib.h>
+
+int
+main ()
+{
+  int d = omp_get_default_device ();
+  int id = omp_get_initial_device ();
+  int err;
+  void *p;
+
+  if (d < 0 || d >= omp_get_num_devices ())
+    d = id;
+
+  p = omp_target_alloc (128 * sizeof (int), d);
+  if (p == NULL)
+    return 0;
+
+  #pragma omp target is_device_ptr (p) if (d >= 0) device (d >= 0 ? d : 0)
+  {
+    int i, *q = (int *) p;
+    for (i = 0; i < 128; i++)
+      q[i] = i + 7;
+  }
+  #pragma omp target is_device_ptr (p) if (d >= 0) device (d >= 0 ? d : 0) map(from:err)
+  {
+    int i;
+    err = 0;
+    for (i = 0; i < 128; i++)
+      if (((int *) p)[i] != i + 7)
+	err = 1;
+  }
+  if (err)
+    abort ();
+
+  omp_target_free (p, d);
+  return 0;
+}
--- libgomp/testsuite/libgomp.c++/target-5.C.jj	2015-07-20 16:23:39.592423836 +0200
+++ libgomp/testsuite/libgomp.c++/target-5.C	2015-07-20 16:26:31.049968908 +0200
@@ -0,0 +1 @@
+#include "../libgomp.c/target-13.c"
--- libgomp/testsuite/libgomp.c++/target-6.C.jj	2015-07-20 16:26:44.196780672 +0200
+++ libgomp/testsuite/libgomp.c++/target-6.C	2015-07-20 17:36:18.357533147 +0200
@@ -0,0 +1,64 @@
+extern "C" void abort (void);
+struct S { int s, t; };
+
+void
+foo (int &x, int &y, S &u, S &v, double &s, double &t)
+{
+  int err = 0, i;
+  int a[y - 2], b[y - 2];
+  int (&c)[y - 2] = a, (&d)[y - 2] = b;
+  for (i = 0; i < y - 2; i++)
+    {
+      c[i] = i;
+      d[i] = 3 + i;
+    }
+  #pragma omp target private (x, u, s, c, i) firstprivate (y, v, t, d) map(from:err)
+  {
+    x = y;
+    u = v;
+    s = t;
+    for (i = 0; i < y - 2; i++)
+      c[i] = d[i];
+    err = (x != 6 || y != 6
+	   || u.s != 9 || u.t != 10 || v.s != 9 || v.t != 10
+	   || s != 12.5 || t != 12.5);
+    for (i = 0; i < y - 2; i++)
+      if (d[i] != 3 + i || c[i] != 3 + i)
+	err = 1;
+      else
+	{
+	  c[i] += 2 * i;
+	  d[i] += i;
+	}
+    x += 1;
+    y += 2;
+    u.s += 3;
+    v.t += 4;
+    s += 2.5;
+    t += 3.0;
+    if (x != 7 || y != 8
+	|| u.s != 12 || u.t != 10 || v.s != 9 || v.t != 14
+	|| s != 15.0 || t != 15.5)
+      err = 1;
+    for (i = 0; i < y - 4; i++)
+      if (d[i] != 3 + 2 * i || c[i] != 3 + 3 * i)
+	err = 1;
+  }
+  if (err || x != 5 || y != 6
+      || u.s != 7 || u.t != 8 || v.s != 9 || v.t != 10
+      || s != 11.5 || t != 12.5)
+    abort ();
+  for (i = 0; i < y - 2; i++)
+    if (d[i] != 3 + i || c[i] != i)
+      abort ();
+}
+
+int
+main ()
+{
+  int x = 5, y = 6;
+  S u = { 7, 8 }, v = { 9, 10 };
+  double s = 11.5, t = 12.5;
+  foo (x, y, u, v, s, t);
+  return 0;
+}


	Jakub

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

* Re: [gomp4.1] Initial support for some OpenMP 4.1 construct parsing
  2015-07-20 16:18                 ` Jakub Jelinek
@ 2015-07-20 18:31                   ` Jakub Jelinek
  2015-07-23  0:50                     ` Jakub Jelinek
  0 siblings, 1 reply; 33+ messages in thread
From: Jakub Jelinek @ 2015-07-20 18:31 UTC (permalink / raw)
  To: Ilya Verbin; +Cc: Thomas Schwinge, gcc-patches, Kirill Yukhin

Hi!

And here is untested incremental libgomp side of the proposed
GOMP_MAP_FIRSTPRIVATE_POINTER.
I'll probably tweak it so that if GOMP_MAP_FIRSTPRIVATE
is followed by one or more GOMP_MAP_FIRSTPRIVATE_POINTER where
the pointers fall into the extents of the firstprivate object,
it will make the whole object firstprivate and then overwrite
the pointers in it (somewhat similar to GOMP_MAP_TO_PSET).

--- include/gomp-constants.h.jj	2015-07-20 12:27:58.000000000 +0200
+++ include/gomp-constants.h	2015-07-20 19:43:47.734326985 +0200
@@ -74,6 +74,8 @@ enum gomp_map_kind
     GOMP_MAP_FORCE_DEVICEPTR =		(GOMP_MAP_FLAG_SPECIAL_1 | 0),
     /* Do not map, copy bits for firstprivate instead.  */
     GOMP_MAP_FIRSTPRIVATE =		(GOMP_MAP_FLAG_SPECIAL | 0),
+    /* Do not map, but pointer assign a pointer instead.  */
+    GOMP_MAP_FIRSTPRIVATE_POINTER =	(GOMP_MAP_FLAG_SPECIAL | 1),
     /* Allocate.  */
     GOMP_MAP_FORCE_ALLOC =		(GOMP_MAP_FLAG_FORCE | GOMP_MAP_ALLOC),
     /* ..., and copy to device.  */
--- libgomp/target.c.jj	2015-07-20 16:03:20.000000000 +0200
+++ libgomp/target.c	2015-07-20 19:57:38.735556137 +0200
@@ -276,12 +276,8 @@ gomp_map_vars (struct gomp_device_descr
 	  tgt->list[i].key = NULL;
 	  continue;
 	}
-      cur_node.host_start = (uintptr_t) hostaddrs[i];
-      if (!GOMP_MAP_POINTER_P (kind & typemask))
-	cur_node.host_end = cur_node.host_start + sizes[i];
-      else
-	cur_node.host_end = cur_node.host_start + sizeof (void *);
-      if ((kind & typemask) == GOMP_MAP_FIRSTPRIVATE)
+      if ((kind & typemask) == GOMP_MAP_FIRSTPRIVATE
+	  || (kind & typemask) == GOMP_MAP_FIRSTPRIVATE_POINTER)
 	{
 	  tgt->list[i].key = NULL;
 
@@ -289,10 +285,18 @@ gomp_map_vars (struct gomp_device_descr
 	  if (tgt_align < align)
 	    tgt_align = align;
 	  tgt_size = (tgt_size + align - 1) & ~(align - 1);
-	  tgt_size += cur_node.host_end - cur_node.host_start;
+	  if ((kind & typemask) == GOMP_MAP_FIRSTPRIVATE_POINTER)
+	    tgt_size += sizeof (void *);
+	  else
+	    tgt_size += sizes[i];
 	  has_firstprivate = true;
 	  continue;
 	}
+      cur_node.host_start = (uintptr_t) hostaddrs[i];
+      if (!GOMP_MAP_POINTER_P (kind & typemask))
+	cur_node.host_end = cur_node.host_start + sizes[i];
+      else
+	cur_node.host_end = cur_node.host_start + sizeof (void *);
       splay_tree_key n = splay_tree_lookup (mem_map, &cur_node);
       if (n)
 	gomp_map_vars_existing (devicep, n, &cur_node, &tgt->list[i],
@@ -374,15 +378,28 @@ gomp_map_vars (struct gomp_device_descr
 	    int kind = get_kind (short_mapkind, kinds, i);
 	    if (hostaddrs[i] == NULL)
 	      continue;
-	    if ((kind & typemask) == GOMP_MAP_FIRSTPRIVATE)
+	    if ((kind & typemask) == GOMP_MAP_FIRSTPRIVATE
+		|| (kind & typemask) == GOMP_MAP_FIRSTPRIVATE_POINTER)
 	      {
 		size_t align = (size_t) 1 << (kind >> rshift);
 		tgt_size = (tgt_size + align - 1) & ~(align - 1);
 		tgt->list[i].offset = tgt_size;
-		size_t len = sizes[i];
-		devicep->host2dev_func (devicep->target_id,
-					(void *) (tgt->tgt_start + tgt_size),
-					(void *) hostaddrs[i], len);
+		size_t len;
+		if ((kind & typemask) == GOMP_MAP_FIRSTPRIVATE_POINTER)
+		  {
+		    len = sizeof (void *);
+		    gomp_map_pointer (tgt, (uintptr_t)
+					   *(void **) (hostaddrs[i]),
+				      tgt_size, sizes[i]);
+		  }
+		else
+		  {
+		    len = sizes[i];
+		    devicep->host2dev_func (devicep->target_id,
+					    (void *) (tgt->tgt_start
+						      + tgt_size),
+					    (void *) hostaddrs[i], len);
+		  }
 		tgt_size += len;
 		continue;
 	      }


	Jakub

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

* Re: [gomp4.1] Initial support for some OpenMP 4.1 construct parsing
  2015-07-17 16:54               ` Jakub Jelinek
  2015-07-20 16:18                 ` Jakub Jelinek
@ 2015-07-20 19:40                 ` Ilya Verbin
  2015-08-24 12:38                   ` Jakub Jelinek
  1 sibling, 1 reply; 33+ messages in thread
From: Ilya Verbin @ 2015-07-20 19:40 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: gcc-patches, Kirill Yukhin

On Fri, Jul 17, 2015 at 18:43:06 +0200, Jakub Jelinek wrote:
> On Fri, Jul 17, 2015 at 07:31:36PM +0300, Ilya Verbin wrote:
> > One big question is who will maintain the list of scheduled job, its
> > dependencies, etc. - libgomp or each target plugin?
> > 
> > 
> > OpenACC has async queues:
> > #pragma acc parallel async(2) wait(1)
> > 
> > But it's not possible to have 2 waits like:
> > #pragma acc parallel async(3) wait(1) wait(2)
> > 
> > (GOMP_OFFLOAD_openacc_async_wait_async has only one argument with the number of
> > queue to wait)
> > 
> > Thomas, please correct me if I'm wrong.
> > 
> > In this regard, OpenMP is more complicated, since it allows e.g.:
> > #pragma omp target nowait depend(in: a, b) depend(out: c, d)
> 
> If it is each plugin, then supposedly it should use (if possible) some
> common libgomp routine to maintain the queues, duplicating the dependency
> graph handling code in each plugins might be too ugly.
> 
> > Currently I'm trying to figure out what liboffloadmic can do.

Latest liboffloadmic (I'm preparing an update for trunk) can take some pointer
*ptr* as argument of __offload_offload, which is used for execution and data
transfer.  When given job is finished, it will call some callback in libgomp on
host, passing *ptr* back to it, thus libgomp can distinguish which job has
been finished.  BTW, which word to use here to avoid confusion? (task? job?)

I'm going to prototype something in libgomp using this interface.

  -- Ilya

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

* Re: [gomp4.1] Initial support for some OpenMP 4.1 construct parsing
  2015-07-20 18:31                   ` Jakub Jelinek
@ 2015-07-23  0:50                     ` Jakub Jelinek
  2015-07-24 20:33                       ` Jakub Jelinek
  0 siblings, 1 reply; 33+ messages in thread
From: Jakub Jelinek @ 2015-07-23  0:50 UTC (permalink / raw)
  To: Ilya Verbin; +Cc: Thomas Schwinge, gcc-patches, Kirill Yukhin

On Mon, Jul 20, 2015 at 08:10:41PM +0200, Jakub Jelinek wrote:
> And here is untested incremental libgomp side of the proposed
> GOMP_MAP_FIRSTPRIVATE_POINTER.

Actually, that seems unnecessary, for the array section maps we already
have there a pointer, so we can easily implement that just on the
compiler side.

Here is a WIP patch.

Unfortunately, in order not to break numerous examples-4/ testcases that
were doing target data map of array sections with target region without
any explicit maps, with the new way where target{, enter, exit} data
no longer map the base pointer, I had to implement the new implicit
pointer mapping semantics (map (alloc:ptr[0:0])) already in this patch.

And, that patch really requires that if there is ptr[0:something] for
something > 0 already mapped that we use the ptr[0:something] mapping rather
than ptr[0:0].  See the libgomp changes for that.

Unfortunately, that occassionally breaks the target8.f90 testcase at -O0,
where we map zero-sized FRAME.6 object which happens to be adjacent to the
array.  And that reveals IMNSHO very serious flaw in the current standard
draft, no idea what can be done about that...

--- libgomp/testsuite/libgomp.c++/target-7.C.jj	2015-07-22 11:36:53.042867520 +0200
+++ libgomp/testsuite/libgomp.c++/target-7.C	2015-07-22 11:32:00.000000000 +0200
@@ -0,0 +1,90 @@
+extern "C" void abort ();
+
+void
+foo (int *x, int *&y, int (&z)[15])
+{
+  int a[10], b[15], err, i;
+  for (i = 0; i < 10; i++)
+    a[i] = 7 * i;
+  for (i = 0; i < 15; i++)
+    b[i] = 8 * i;
+  #pragma omp target map(to:x[5:10], y[5:10], z[5:10], a[0:10], b[5:10]) map(from:err)
+  {
+    err = 0;
+    for (i = 0; i < 10; i++)
+      if (x[5 + i] != 20 + 4 * i
+	  || y[5 + i] != 25 + 5 * i
+	  || z[5 + i] != 30 + 6 * i
+	  || a[i] != 7 * i
+	  || b[5 + i] != 40 + 8 * i)
+	err = 1;
+  }
+  if (err)
+    abort ();
+}
+
+void
+bar (int n, int v)
+{
+  int a[n], b[n], c[n], d[n], e[n], err, i;
+  int (*x)[n] = &c;
+  int (*y2)[n] = &d;
+  int (*&y)[n] = y2;
+  int (&z)[n] = e;
+  for (i = 0; i < n; i++)
+    {
+      (*x)[i] = 4 * i;
+      (*y)[i] = 5 * i;
+      z[i] = 6 * i;
+      a[i] = 7 * i;
+      b[i] = 8 * i;
+    }
+  #pragma omp target map(to:x[0][5:10], y[0][5:10], z[5:10], a[0:10], b[5:10]) map(from:err)
+  {
+    err = 0;
+    for (i = 0; i < 10; i++)
+      if ((*x)[5 + i] != 20 + 4 * i
+	  || (*y)[5 + i] != 25 + 5 * i
+	  || z[5 + i] != 30 + 6 * i
+	  || a[i] != 7 * i
+	  || b[5 + i] != 40 + 8 * i)
+	err = 1;
+  }
+  if (err)
+    abort ();
+  for (i = 0; i < n; i++)
+    {
+      (*x)[i] = 9 * i;
+      (*y)[i] = 10 * i;
+      z[i] = 11 * i;
+      a[i] = 12 * i;
+      b[i] = 13 * i;
+    }
+  #pragma omp target map(to:x[0][v:v+5], y[0][v:v+5], z[v:v+5], a[v-5:v+5], b[v:v+5]) map(from:err)
+  {
+    err = 0;
+    for (i = 0; i < 10; i++)
+      if ((*x)[5 + i] != 45 + 9 * i
+	  || (*y)[5 + i] != 50 + 10 * i
+	  || z[5 + i] != 55 + 11 * i
+	  || a[i] != 12 * i
+	  || b[5 + i] != 65 + 13 * i)
+	err = 1;
+  }
+  if (err)
+    abort ();
+}
+
+int
+main ()
+{
+  int x[15], y2[15], z[15], *y = y2, i;
+  for (i = 0; i < 15; i++)
+    {
+      x[i] = 4 * i;
+      y[i] = 5 * i;
+      z[i] = 6 * i;
+    }
+  foo (x, y, z);
+  bar (15, 5);
+}
--- libgomp/testsuite/libgomp.c/target-15.c.jj	2015-07-22 11:37:11.655612690 +0200
+++ libgomp/testsuite/libgomp.c/target-15.c	2015-07-22 11:38:54.590203394 +0200
@@ -0,0 +1,74 @@
+extern void abort ();
+
+void
+foo (int *x)
+{
+  int a[10], b[15], err, i;
+  for (i = 0; i < 10; i++)
+    a[i] = 7 * i;
+  for (i = 0; i < 15; i++)
+    b[i] = 8 * i;
+  #pragma omp target map(to:x[5:10], a[0:10], b[5:10]) map(from:err)
+  {
+    err = 0;
+    for (i = 0; i < 10; i++)
+      if (x[5 + i] != 20 + 4 * i
+	  || a[i] != 7 * i
+	  || b[5 + i] != 40 + 8 * i)
+	err = 1;
+  }
+  if (err)
+    abort ();
+}
+
+void
+bar (int n, int v)
+{
+  int a[n], b[n], c[n], d[n], e[n], err, i;
+  int (*x)[n] = &c;
+  for (i = 0; i < n; i++)
+    {
+      (*x)[i] = 4 * i;
+      a[i] = 7 * i;
+      b[i] = 8 * i;
+    }
+  #pragma omp target map(to:x[0][5:10], a[0:10], b[5:10]) map(from:err)
+  {
+    err = 0;
+    for (i = 0; i < 10; i++)
+      if ((*x)[5 + i] != 20 + 4 * i
+	  || a[i] != 7 * i
+	  || b[5 + i] != 40 + 8 * i)
+	err = 1;
+  }
+  if (err)
+    abort ();
+  for (i = 0; i < n; i++)
+    {
+      (*x)[i] = 9 * i;
+      a[i] = 12 * i;
+      b[i] = 13 * i;
+    }
+  #pragma omp target map(to:x[0][v:v+5], a[v-5:v+5], b[v:v+5]) map(from:err)
+  {
+    err = 0;
+    for (i = 0; i < 10; i++)
+      if ((*x)[5 + i] != 45 + 9 * i
+	  || a[i] != 12 * i
+	  || b[5 + i] != 65 + 13 * i)
+	err = 1;
+  }
+  if (err)
+    abort ();
+}
+
+int
+main ()
+{
+  int x[15], i;
+  for (i = 0; i < 15; i++)
+    x[i] = 4 * i;
+  foo (x);
+  bar (15, 5);
+  return 0;
+}
--- libgomp/target.c.jj	2015-07-21 09:07:23.690851224 +0200
+++ libgomp/target.c	2015-07-22 21:12:22.438213557 +0200
@@ -142,7 +142,26 @@ resolve_device (int device_id)
 }
 
 
-/* Handle the case where splay_tree_lookup found oldn for newn.
+static inline splay_tree_key
+gomp_map_lookup (splay_tree mem_map, splay_tree_key key)
+{
+  if (key->host_start != key->host_end)
+    return splay_tree_lookup (mem_map, key);
+
+  key->host_end++;
+  splay_tree_key n = splay_tree_lookup (mem_map, key);
+  key->host_end--;
+  if (n)
+    return n;
+  key->host_start--;
+  n = splay_tree_lookup (mem_map, key);
+  key->host_start++;
+  if (n)
+    return n;
+  return splay_tree_lookup (mem_map, key);
+}
+
+/* Handle the case where gmp_map_lookup found oldn for newn.
    Helper function of gomp_map_vars.  */
 
 static inline void
@@ -204,20 +223,8 @@ gomp_map_pointer (struct target_mem_desc
     }
   /* Add bias to the pointer value.  */
   cur_node.host_start += bias;
-  cur_node.host_end = cur_node.host_start + 1;
-  splay_tree_key n = splay_tree_lookup (mem_map, &cur_node);
-  if (n == NULL)
-    {
-      /* Could be possibly zero size array section.  */
-      cur_node.host_end--;
-      n = splay_tree_lookup (mem_map, &cur_node);
-      if (n == NULL)
-	{
-	  cur_node.host_start--;
-	  n = splay_tree_lookup (mem_map, &cur_node);
-	  cur_node.host_start++;
-	}
-    }
+  cur_node.host_end = cur_node.host_start;
+  splay_tree_key n = gomp_map_lookup (mem_map, &cur_node);
   if (n == NULL)
     {
       gomp_mutex_unlock (&devicep->lock);
@@ -293,7 +300,7 @@ gomp_map_vars (struct gomp_device_descr
 	  has_firstprivate = true;
 	  continue;
 	}
-      splay_tree_key n = splay_tree_lookup (mem_map, &cur_node);
+      splay_tree_key n = gomp_map_lookup (mem_map, &cur_node);
       if (n)
 	gomp_map_vars_existing (devicep, n, &cur_node, &tgt->list[i],
 				kind & typemask);
@@ -392,7 +399,7 @@ gomp_map_vars (struct gomp_device_descr
 	      k->host_end = k->host_start + sizes[i];
 	    else
 	      k->host_end = k->host_start + sizeof (void *);
-	    splay_tree_key n = splay_tree_lookup (mem_map, k);
+	    splay_tree_key n = gomp_map_lookup (mem_map, k);
 	    if (n)
 	      gomp_map_vars_existing (devicep, n, k, &tgt->list[i],
 				      kind & typemask);
@@ -526,7 +533,8 @@ gomp_map_vars (struct gomp_device_descr
 	    }
 	  else
 	    cur_node.tgt_offset = tgt->list[i].key->tgt->tgt_start
-				  + tgt->list[i].key->tgt_offset;
+				  + tgt->list[i].key->tgt_offset
+				  + tgt->list[i].offset;
 	  /* FIXME: see above FIXME comment.  */
 	  devicep->host2dev_func (devicep->target_id,
 				  (void *) (tgt->tgt_start
@@ -1289,20 +1297,8 @@ omp_target_is_present (void *ptr, size_t
   struct splay_tree_key_s cur_node;
 
   cur_node.host_start = (uintptr_t) ptr + offset;
-  cur_node.host_end = cur_node.host_start + 1;
-  splay_tree_key n = splay_tree_lookup (mem_map, &cur_node);
-  if (n == NULL)
-    {
-      /* Could be possibly zero size array section.  */
-      cur_node.host_end--;
-      n = splay_tree_lookup (mem_map, &cur_node);
-      if (n == NULL)
-	{
-	  cur_node.host_start--;
-	  n = splay_tree_lookup (mem_map, &cur_node);
-	  cur_node.host_start++;
-	}
-    }
+  cur_node.host_end = cur_node.host_start;
+  splay_tree_key n = gomp_map_lookup (mem_map, &cur_node);
   int ret = n != NULL;
   gomp_mutex_unlock (&devicep->lock);
   return ret;
@@ -1524,7 +1520,7 @@ omp_target_associate_ptr (void *host_ptr
 
   cur_node.host_start = (uintptr_t) host_ptr;
   cur_node.host_end = cur_node.host_start + size;
-  splay_tree_key n = splay_tree_lookup (mem_map, &cur_node);
+  splay_tree_key n = gomp_map_lookup (mem_map, &cur_node);
   if (n)
     {
       if (n->tgt->tgt_start + n->tgt_offset
@@ -1584,13 +1580,8 @@ omp_target_disassociate_ptr (void *ptr,
   int ret = EINVAL;
 
   cur_node.host_start = (uintptr_t) ptr;
-  cur_node.host_end = cur_node.host_start + 1;
-  splay_tree_key n = splay_tree_lookup (mem_map, &cur_node);
-  if (n == NULL)
-    {
-      cur_node.host_end--;
-      n = splay_tree_lookup (mem_map, &cur_node);
-    }
+  cur_node.host_end = cur_node.host_start;
+  splay_tree_key n = gomp_map_lookup (mem_map, &cur_node);
   if (n
       && n->host_start == cur_node.host_start
       && n->refcount == REFCOUNT_INFINITY
--- libgomp/libgomp.h.jj	2015-07-15 13:00:32.000000000 +0200
+++ libgomp/libgomp.h	2015-07-22 21:09:39.023307107 +0200
@@ -647,11 +647,9 @@ struct target_var_desc {
   bool copy_from;
   /* True if data always should be copied from device to host at the end.  */
   bool always_copy_from;
-  /* Used for unmapping of array sections, can be nonzero only when
-     always_copy_from is true.  */
+  /* Relative offset against key host_start.  */
   uintptr_t offset;
-  /* Used for unmapping of array sections, can be less than the size of the
-     whole object only when always_copy_from is true.  */
+  /* Actual length.  */
   uintptr_t length;
 };
 
--- include/gomp-constants.h.jj	2015-07-21 09:07:23.689851239 +0200
+++ include/gomp-constants.h	2015-07-21 15:01:05.384829637 +0200
@@ -95,7 +95,11 @@ enum gomp_map_kind
     GOMP_MAP_DELETE =			GOMP_MAP_FORCE_DEALLOC,
     /* Decrement usage count and deallocate if zero.  */
     GOMP_MAP_RELEASE =			(GOMP_MAP_FLAG_ALWAYS
-					 | GOMP_MAP_FORCE_DEALLOC)
+					 | GOMP_MAP_FORCE_DEALLOC),
+
+    /* Internal to GCC, not used in libgomp.  */
+    /* Do not map, but pointer assign a pointer instead.  */
+    GOMP_MAP_FIRSTPRIVATE_POINTER =	(GOMP_MAP_LAST | 1)
   };
 
 #define GOMP_MAP_COPY_TO_P(X) \
--- gcc/cp/parser.c.jj	2015-07-21 09:06:42.000000000 +0200
+++ gcc/cp/parser.c	2015-07-21 12:55:03.966656803 +0200
@@ -32276,27 +32276,28 @@ cp_parser_omp_target_data (cp_parser *pa
   for (tree *pc = &clauses; *pc;)
     {
       if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_MAP)
-       switch (OMP_CLAUSE_MAP_KIND (*pc))
-	 {
-	 case GOMP_MAP_TO:
-	 case GOMP_MAP_ALWAYS_TO:
-	 case GOMP_MAP_FROM:
-	 case GOMP_MAP_ALWAYS_FROM:
-	 case GOMP_MAP_TOFROM:
-	 case GOMP_MAP_ALWAYS_TOFROM:
-	 case GOMP_MAP_ALLOC:
-	 case GOMP_MAP_POINTER:
-	   map_seen = 3;
-	   break;
-	 default:
-	   map_seen |= 1;
-	   error_at (OMP_CLAUSE_LOCATION (*pc),
-		     "%<#pragma omp target data%> with map-type other "
-		     "than %<to%>, %<from%>, %<tofrom%> or %<alloc%> "
-		     "on %<map%> clause");
-	   *pc = OMP_CLAUSE_CHAIN (*pc);
-	   continue;
-	 }
+	switch (OMP_CLAUSE_MAP_KIND (*pc))
+	  {
+	  case GOMP_MAP_TO:
+	  case GOMP_MAP_ALWAYS_TO:
+	  case GOMP_MAP_FROM:
+	  case GOMP_MAP_ALWAYS_FROM:
+	  case GOMP_MAP_TOFROM:
+	  case GOMP_MAP_ALWAYS_TOFROM:
+	  case GOMP_MAP_ALLOC:
+	    map_seen = 3;
+	    break;
+	  case GOMP_MAP_FIRSTPRIVATE_POINTER:
+	    break;
+	  default:
+	    map_seen |= 1;
+	    error_at (OMP_CLAUSE_LOCATION (*pc),
+		      "%<#pragma omp target data%> with map-type other "
+		      "than %<to%>, %<from%>, %<tofrom%> or %<alloc%> "
+		      "on %<map%> clause");
+	    *pc = OMP_CLAUSE_CHAIN (*pc);
+	    continue;
+	  }
       pc = &OMP_CLAUSE_CHAIN (*pc);
     }
 
@@ -32370,22 +32371,23 @@ cp_parser_omp_target_enter_data (cp_pars
   for (tree *pc = &clauses; *pc;)
     {
       if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_MAP)
-       switch (OMP_CLAUSE_MAP_KIND (*pc))
-	 {
-	 case GOMP_MAP_TO:
-	 case GOMP_MAP_ALWAYS_TO:
-	 case GOMP_MAP_ALLOC:
-	 case GOMP_MAP_POINTER:
-	   map_seen = 3;
-	   break;
-	 default:
-	   map_seen |= 1;
-	   error_at (OMP_CLAUSE_LOCATION (*pc),
-		     "%<#pragma omp target enter data%> with map-type other "
-		     "than %<to%> or %<alloc%> on %<map%> clause");
-	   *pc = OMP_CLAUSE_CHAIN (*pc);
-	   continue;
-	 }
+	switch (OMP_CLAUSE_MAP_KIND (*pc))
+	  {
+	  case GOMP_MAP_TO:
+	  case GOMP_MAP_ALWAYS_TO:
+	  case GOMP_MAP_ALLOC:
+	    map_seen = 3;
+	    break;
+	  case GOMP_MAP_FIRSTPRIVATE_POINTER:
+	    break;
+	  default:
+	    map_seen |= 1;
+	    error_at (OMP_CLAUSE_LOCATION (*pc),
+		      "%<#pragma omp target enter data%> with map-type other "
+		      "than %<to%> or %<alloc%> on %<map%> clause");
+	    *pc = OMP_CLAUSE_CHAIN (*pc);
+	    continue;
+	  }
       pc = &OMP_CLAUSE_CHAIN (*pc);
     }
 
@@ -32455,24 +32457,25 @@ cp_parser_omp_target_exit_data (cp_parse
   for (tree *pc = &clauses; *pc;)
     {
       if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_MAP)
-       switch (OMP_CLAUSE_MAP_KIND (*pc))
-	 {
-	 case GOMP_MAP_FROM:
-	 case GOMP_MAP_ALWAYS_FROM:
-	 case GOMP_MAP_RELEASE:
-	 case GOMP_MAP_DELETE:
-	 case GOMP_MAP_POINTER:
-	   map_seen = 3;
-	   break;
-	 default:
-	   map_seen |= 1;
-	   error_at (OMP_CLAUSE_LOCATION (*pc),
-		     "%<#pragma omp target exit data%> with map-type other "
-		     "than %<from%>, %<release%> or %<delete%> on %<map%>"
-		     " clause");
-	   *pc = OMP_CLAUSE_CHAIN (*pc);
-	   continue;
-	 }
+	switch (OMP_CLAUSE_MAP_KIND (*pc))
+	  {
+	  case GOMP_MAP_FROM:
+	  case GOMP_MAP_ALWAYS_FROM:
+	  case GOMP_MAP_RELEASE:
+	  case GOMP_MAP_DELETE:
+	    map_seen = 3;
+	    break;
+	  case GOMP_MAP_FIRSTPRIVATE_POINTER:
+	    break;
+	  default:
+	    map_seen |= 1;
+	    error_at (OMP_CLAUSE_LOCATION (*pc),
+		      "%<#pragma omp target exit data%> with map-type other "
+		      "than %<from%>, %<release%> or %<delete%> on %<map%>"
+		      " clause");
+	    *pc = OMP_CLAUSE_CHAIN (*pc);
+	    continue;
+	  }
       pc = &OMP_CLAUSE_CHAIN (*pc);
     }
 
@@ -32697,7 +32700,7 @@ check_clauses:
 	  case GOMP_MAP_TOFROM:
 	  case GOMP_MAP_ALWAYS_TOFROM:
 	  case GOMP_MAP_ALLOC:
-	  case GOMP_MAP_POINTER:
+	  case GOMP_MAP_FIRSTPRIVATE_POINTER:
 	    break;
 	  default:
 	    error_at (OMP_CLAUSE_LOCATION (*pc),
--- gcc/cp/semantics.c.jj	2015-07-17 13:59:27.000000000 +0200
+++ gcc/cp/semantics.c	2015-07-22 13:01:26.296499686 +0200
@@ -4650,7 +4650,7 @@ handle_omp_array_sections_1 (tree c, tre
 /* Handle array sections for clause C.  */
 
 static bool
-handle_omp_array_sections (tree c)
+handle_omp_array_sections (tree c, bool is_omp)
 {
   bool maybe_zero_len = false;
   unsigned int first_non_one = 0;
@@ -4828,8 +4828,9 @@ handle_omp_array_sections (tree c)
 	    return false;
 	  tree c2 = build_omp_clause (OMP_CLAUSE_LOCATION (c),
 				      OMP_CLAUSE_MAP);
-	  OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_POINTER);
-	  if (!cxx_mark_addressable (t))
+	  OMP_CLAUSE_SET_MAP_KIND (c2, is_omp ? GOMP_MAP_FIRSTPRIVATE_POINTER
+					      : GOMP_MAP_POINTER);
+	  if (!is_omp && !cxx_mark_addressable (t))
 	    return false;
 	  OMP_CLAUSE_DECL (c2) = t;
 	  t = build_fold_addr_expr (first);
@@ -4847,7 +4848,8 @@ handle_omp_array_sections (tree c)
 	  OMP_CLAUSE_CHAIN (c2) = OMP_CLAUSE_CHAIN (c);
 	  OMP_CLAUSE_CHAIN (c) = c2;
 	  ptr = OMP_CLAUSE_DECL (c2);
-	  if (TREE_CODE (TREE_TYPE (ptr)) == REFERENCE_TYPE
+	  if (!is_omp
+	      && TREE_CODE (TREE_TYPE (ptr)) == REFERENCE_TYPE
 	      && POINTER_TYPE_P (TREE_TYPE (TREE_TYPE (ptr))))
 	    {
 	      tree c3 = build_omp_clause (OMP_CLAUSE_LOCATION (c),
@@ -5569,7 +5571,7 @@ finish_omp_clauses (tree clauses, bool a
 	  t = OMP_CLAUSE_DECL (c);
 	  if (TREE_CODE (t) == TREE_LIST)
 	    {
-	      if (handle_omp_array_sections (c))
+	      if (handle_omp_array_sections (c, allow_fields))
 		{
 		  remove = true;
 		  break;
@@ -6155,7 +6157,7 @@ finish_omp_clauses (tree clauses, bool a
 	    }
 	  if (TREE_CODE (t) == TREE_LIST)
 	    {
-	      if (handle_omp_array_sections (c))
+	      if (handle_omp_array_sections (c, allow_fields))
 		remove = true;
 	      break;
 	    }
@@ -6189,7 +6191,7 @@ finish_omp_clauses (tree clauses, bool a
 	  t = OMP_CLAUSE_DECL (c);
 	  if (TREE_CODE (t) == TREE_LIST)
 	    {
-	      if (handle_omp_array_sections (c))
+	      if (handle_omp_array_sections (c, allow_fields))
 		remove = true;
 	      else
 		{
@@ -6242,7 +6244,9 @@ finish_omp_clauses (tree clauses, bool a
 		   && !cxx_mark_addressable (t))
 	    remove = true;
 	  else if (!(OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
-		     && OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_POINTER)
+		     && (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_POINTER
+			 || (OMP_CLAUSE_MAP_KIND (c)
+			     == GOMP_MAP_FIRSTPRIVATE_POINTER)))
 		   && !type_dependent_expression_p (t)
 		   && !cp_omp_mappable_type ((TREE_CODE (TREE_TYPE (t))
 					      == REFERENCE_TYPE)
--- gcc/tree.h.jj	2015-07-16 17:56:41.000000000 +0200
+++ gcc/tree.h	2015-07-21 16:40:35.759401307 +0200
@@ -1445,7 +1445,7 @@ extern void protected_set_expr_location
   ((enum gomp_map_kind) OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_MAP)->omp_clause.subcode.map_kind)
 #define OMP_CLAUSE_SET_MAP_KIND(NODE, MAP_KIND) \
   (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_MAP)->omp_clause.subcode.map_kind \
-   = (unsigned char) (MAP_KIND))
+   = (unsigned int) (MAP_KIND))
 
 /* 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
--- gcc/gimplify.c.jj	2015-07-16 17:56:41.000000000 +0200
+++ gcc/gimplify.c	2015-07-22 18:27:58.545933111 +0200
@@ -90,6 +90,8 @@ enum gimplify_omp_var_data
   /* Flag for GOVD_LINEAR or GOVD_LASTPRIVATE: no outer reference.  */
   GOVD_LINEAR_LASTPRIVATE_NO_OUTER = 16384,
 
+  GOVD_MAP_0LEN_ARRAY = 32768,
+
   GOVD_DATA_SHARE_CLASS = (GOVD_SHARED | GOVD_PRIVATE | GOVD_FIRSTPRIVATE
 			   | GOVD_LASTPRIVATE | GOVD_REDUCTION | GOVD_LINEAR
 			   | GOVD_LOCAL)
@@ -156,6 +158,8 @@ struct gimplify_omp_ctx
   enum omp_region_type region_type;
   bool combined_loop;
   bool distribute;
+  bool target_map_scalars_firstprivate;
+  bool target_map_pointers_as_0len_arrays;
 };
 
 static struct gimplify_ctx *gimplify_ctxp;
@@ -5821,6 +5825,38 @@ omp_notice_variable (struct gimplify_omp
 		     "a mappable type", decl);
 	      omp_add_variable (ctx, decl, GOVD_MAP | GOVD_EXPLICIT | flags);
 	    }
+	  else if (ctx->target_map_pointers_as_0len_arrays
+		   || ctx->target_map_scalars_firstprivate)
+	    {
+	      bool is_declare_target = false;
+	      if (is_global_var (decl)
+		  && varpool_node::get_create (decl)->offloadable)
+		{
+		  struct gimplify_omp_ctx *octx;
+		  for (octx = ctx->outer_context;
+		       octx; octx = octx->outer_context)
+		    {
+		      n = splay_tree_lookup (octx->variables,
+					     (splay_tree_key)decl);
+		      if (n
+			  && (n->value & GOVD_DATA_SHARE_CLASS) != GOVD_SHARED
+			  && (n->value & GOVD_DATA_SHARE_CLASS) != 0)
+			break;
+		    }
+		  is_declare_target = octx == NULL;
+		}
+	      if (is_declare_target)
+		omp_add_variable (ctx, decl, GOVD_MAP | flags);
+	      else if (ctx->target_map_pointers_as_0len_arrays
+		       && (TREE_CODE (TREE_TYPE (decl)) == POINTER_TYPE
+			   || (TREE_CODE (TREE_TYPE (decl)) == REFERENCE_TYPE
+			       && TREE_CODE (TREE_TYPE (TREE_TYPE (decl)))
+				  == POINTER_TYPE)))
+		omp_add_variable (ctx, decl, GOVD_MAP | GOVD_MAP_0LEN_ARRAY
+					     | flags);
+	      else
+		omp_add_variable (ctx, decl, GOVD_MAP | flags);
+	    }
 	  else
 	    omp_add_variable (ctx, decl, GOVD_MAP | flags);
 	}
@@ -6144,6 +6180,13 @@ gimplify_scan_omp_clauses (tree *list_p,
 
   ctx = new_omp_context (region_type);
   outer_ctx = ctx->outer_context;
+  if (code == OMP_TARGET && !lang_GNU_Fortran ())
+    {
+      ctx->target_map_pointers_as_0len_arrays = true;
+      /* FIXME: For Fortran we want to set this too, when
+	 the Fortran FE is updated to OpenMP 4.1.  */
+      ctx->target_map_scalars_firstprivate = true;
+    }
 
   while ((c = *list_p) != NULL)
     {
@@ -6319,10 +6362,24 @@ gimplify_scan_omp_clauses (tree *list_p,
 	case OMP_CLAUSE_MAP:
 	  decl = OMP_CLAUSE_DECL (c);
 	  if (error_operand_p (decl))
+	    remove = true;
+	  switch (code)
 	    {
-	      remove = true;
+	    case OMP_TARGET:
+	      break;
+	    case OMP_TARGET_DATA:
+	    case OMP_TARGET_ENTER_DATA:
+	    case OMP_TARGET_EXIT_DATA:
+	      if (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_FIRSTPRIVATE_POINTER)
+		/* For target {,enter ,exit }data only the array slice is
+		   mapped, but not the pointer to it.  */
+		remove = true;
+	      break;
+	    default:
 	      break;
 	    }
+	  if (remove)
+	    break;
 	  if (OMP_CLAUSE_SIZE (c) == NULL_TREE)
 	    OMP_CLAUSE_SIZE (c) = DECL_P (decl) ? DECL_SIZE_UNIT (decl)
 				  : TYPE_SIZE_UNIT (TREE_TYPE (decl));
@@ -6332,6 +6389,14 @@ gimplify_scan_omp_clauses (tree *list_p,
 	      remove = true;
 	      break;
 	    }
+	  else if (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_FIRSTPRIVATE_POINTER
+		   && TREE_CODE (OMP_CLAUSE_SIZE (c)) != INTEGER_CST)
+	    {
+	      OMP_CLAUSE_SIZE (c)
+		= get_initialized_tmp_var (OMP_CLAUSE_SIZE (c), pre_p, NULL);
+	      omp_add_variable (ctx, OMP_CLAUSE_SIZE (c),
+				GOVD_FIRSTPRIVATE | GOVD_SEEN);
+	    }
 	  if (!DECL_P (decl))
 	    {
 	      if (gimplify_expr (&OMP_CLAUSE_DECL (c), pre_p,
@@ -6643,7 +6708,10 @@ gimplify_scan_omp_clauses (tree *list_p,
 	case OMP_CLAUSE_NOGROUP:
 	case OMP_CLAUSE_THREADS:
 	case OMP_CLAUSE_SIMD:
+	  break;
+
 	case OMP_CLAUSE_DEFAULTMAP:
+	  ctx->target_map_scalars_firstprivate = false;
 	  break;
 
 	case OMP_CLAUSE_ALIGNED:
@@ -6759,6 +6827,29 @@ gimplify_adjust_omp_clauses_1 (splay_tre
     OMP_CLAUSE_PRIVATE_DEBUG (clause) = 1;
   else if (code == OMP_CLAUSE_PRIVATE && (flags & GOVD_PRIVATE_OUTER_REF))
     OMP_CLAUSE_PRIVATE_OUTER_REF (clause) = 1;
+  else if (code == OMP_CLAUSE_MAP && (flags & GOVD_MAP_0LEN_ARRAY) != 0)
+    {
+      tree nc = build_omp_clause (input_location, OMP_CLAUSE_MAP);
+      OMP_CLAUSE_DECL (nc) = decl;
+      if (TREE_CODE (TREE_TYPE (decl)) == REFERENCE_TYPE
+	  && TREE_CODE (TREE_TYPE (TREE_TYPE (decl))) == POINTER_TYPE)
+	OMP_CLAUSE_DECL (clause)
+	  = build_simple_mem_ref_loc (input_location, decl);
+      OMP_CLAUSE_DECL (clause)
+	= build2 (MEM_REF, char_type_node, OMP_CLAUSE_DECL (clause),
+		  build_int_cst (build_pointer_type (char_type_node), 0));
+      OMP_CLAUSE_SIZE (clause) = size_zero_node;
+      OMP_CLAUSE_SIZE (nc) = size_zero_node;
+      OMP_CLAUSE_SET_MAP_KIND (clause, GOMP_MAP_ALLOC);
+      OMP_CLAUSE_SET_MAP_KIND (nc, GOMP_MAP_FIRSTPRIVATE_POINTER);
+      OMP_CLAUSE_CHAIN (nc) = *list_p;
+      OMP_CLAUSE_CHAIN (clause) = nc;
+      struct gimplify_omp_ctx *ctx = gimplify_omp_ctxp;
+      gimplify_omp_ctxp = ctx->outer_context;
+      gimplify_expr (&TREE_OPERAND (OMP_CLAUSE_DECL (clause), 0),
+		     pre_p, NULL, is_gimple_val, fb_rvalue);
+      gimplify_omp_ctxp = ctx;
+    }
   else if (code == OMP_CLAUSE_MAP)
     {
       OMP_CLAUSE_SET_MAP_KIND (clause,
@@ -6915,7 +7006,8 @@ gimplify_adjust_omp_clauses (gimple_seq
 	    remove = true;
 	  else if (DECL_SIZE (decl)
 		   && TREE_CODE (DECL_SIZE (decl)) != INTEGER_CST
-		   && OMP_CLAUSE_MAP_KIND (c) != GOMP_MAP_POINTER)
+		   && OMP_CLAUSE_MAP_KIND (c) != GOMP_MAP_POINTER
+		   && OMP_CLAUSE_MAP_KIND (c) != GOMP_MAP_FIRSTPRIVATE_POINTER)
 	    {
 	      /* For GOMP_MAP_FORCE_DEVICEPTR, we'll never enter here, because
 		 for these, TREE_CODE (DECL_SIZE (decl)) will always be
--- gcc/c/c-tree.h.jj	2015-07-01 12:50:49.000000000 +0200
+++ gcc/c/c-tree.h	2015-07-22 12:47:49.185826677 +0200
@@ -649,7 +649,7 @@ extern tree c_begin_omp_task (void);
 extern tree c_finish_omp_task (location_t, tree, tree);
 extern void c_finish_omp_cancel (location_t, tree);
 extern void c_finish_omp_cancellation_point (location_t, tree);
-extern tree c_finish_omp_clauses (tree, bool = false);
+extern tree c_finish_omp_clauses (tree, bool, bool = false);
 extern tree c_build_va_arg (location_t, tree, tree);
 extern tree c_finish_transaction (location_t, tree, int);
 extern bool c_tree_equal (tree, tree);
--- gcc/c/c-typeck.c.jj	2015-07-17 13:06:58.000000000 +0200
+++ gcc/c/c-typeck.c	2015-07-22 13:00:21.130399057 +0200
@@ -11850,7 +11850,7 @@ handle_omp_array_sections_1 (tree c, tre
 /* Handle array sections for clause C.  */
 
 static bool
-handle_omp_array_sections (tree c)
+handle_omp_array_sections (tree c, bool is_omp)
 {
   bool maybe_zero_len = false;
   unsigned int first_non_one = 0;
@@ -12031,8 +12031,10 @@ handle_omp_array_sections (tree c)
 	return false;
       gcc_assert (OMP_CLAUSE_MAP_KIND (c) != GOMP_MAP_FORCE_DEVICEPTR);
       tree c2 = build_omp_clause (OMP_CLAUSE_LOCATION (c), OMP_CLAUSE_MAP);
-      OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_POINTER);
-      if (!c_mark_addressable (t))
+      OMP_CLAUSE_SET_MAP_KIND (c2, is_omp
+				   ? GOMP_MAP_FIRSTPRIVATE_POINTER
+				   : GOMP_MAP_POINTER);
+      if (!is_omp && !c_mark_addressable (t))
 	return false;
       OMP_CLAUSE_DECL (c2) = t;
       t = build_fold_addr_expr (first);
@@ -12097,7 +12099,7 @@ c_find_omp_placeholder_r (tree *tp, int
    Remove any elements from the list that are invalid.  */
 
 tree
-c_finish_omp_clauses (tree clauses, bool declare_simd)
+c_finish_omp_clauses (tree clauses, bool is_omp, bool declare_simd)
 {
   bitmap_head generic_head, firstprivate_head, lastprivate_head;
   bitmap_head aligned_head, map_head;
@@ -12136,7 +12138,7 @@ c_finish_omp_clauses (tree clauses, bool
 	  t = OMP_CLAUSE_DECL (c);
 	  if (TREE_CODE (t) == TREE_LIST)
 	    {
-	      if (handle_omp_array_sections (c))
+	      if (handle_omp_array_sections (c, is_omp))
 		{
 		  remove = true;
 		  break;
@@ -12496,7 +12498,7 @@ c_finish_omp_clauses (tree clauses, bool
 	    }
 	  if (TREE_CODE (t) == TREE_LIST)
 	    {
-	      if (handle_omp_array_sections (c))
+	      if (handle_omp_array_sections (c, is_omp))
 		remove = true;
 	      break;
 	    }
@@ -12519,7 +12521,7 @@ c_finish_omp_clauses (tree clauses, bool
 	  t = OMP_CLAUSE_DECL (c);
 	  if (TREE_CODE (t) == TREE_LIST)
 	    {
-	      if (handle_omp_array_sections (c))
+	      if (handle_omp_array_sections (c, is_omp))
 		remove = true;
 	      else
 		{
@@ -12556,6 +12558,8 @@ c_finish_omp_clauses (tree clauses, bool
 	  else if (!(OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
 		     && (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_POINTER
 			 || (OMP_CLAUSE_MAP_KIND (c)
+			     == GOMP_MAP_FIRSTPRIVATE_POINTER)
+			 || (OMP_CLAUSE_MAP_KIND (c)
 			     == GOMP_MAP_FORCE_DEVICEPTR)))
 		   && !lang_hooks.types.omp_mappable_type (TREE_TYPE (t)))
 	    {
--- gcc/c/c-parser.c.jj	2015-07-21 09:06:42.000000000 +0200
+++ gcc/c/c-parser.c	2015-07-22 12:28:35.987814464 +0200
@@ -12435,7 +12435,7 @@ c_parser_oacc_all_clauses (c_parser *par
   c_parser_skip_to_pragma_eol (parser);
 
   if (finish_p)
-    return c_finish_omp_clauses (clauses);
+    return c_finish_omp_clauses (clauses, false);
 
   return clauses;
 }
@@ -12720,8 +12720,8 @@ c_parser_omp_all_clauses (c_parser *pars
   if (finish_p)
     {
       if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_UNIFORM)) != 0)
-	return c_finish_omp_clauses (clauses, true);
-      return c_finish_omp_clauses (clauses);
+	return c_finish_omp_clauses (clauses, true, true);
+      return c_finish_omp_clauses (clauses, true);
     }
 
   return clauses;
@@ -12755,7 +12755,7 @@ c_parser_oacc_cache (location_t loc, c_p
   tree stmt, clauses;
 
   clauses = c_parser_omp_var_list_parens (parser, OMP_CLAUSE__CACHE_, NULL);
-  clauses = c_finish_omp_clauses (clauses);
+  clauses = c_finish_omp_clauses (clauses, false);
 
   c_parser_skip_to_pragma_eol (parser);
 
@@ -13902,7 +13902,7 @@ omp_split_clauses (location_t loc, enum
   c_omp_split_clauses (loc, code, mask, clauses, cclauses);
   for (i = 0; i < C_OMP_CLAUSE_SPLIT_COUNT; i++)
     if (cclauses[i])
-      cclauses[i] = c_finish_omp_clauses (cclauses[i]);
+      cclauses[i] = c_finish_omp_clauses (cclauses[i], true);
 }
 
 /* OpenMP 4.0:
@@ -14668,9 +14668,10 @@ c_parser_omp_target_data (location_t loc
 	  case GOMP_MAP_TOFROM:
 	  case GOMP_MAP_ALWAYS_TOFROM:
 	  case GOMP_MAP_ALLOC:
-	  case GOMP_MAP_POINTER:
 	    map_seen = 3;
 	    break;
+	  case GOMP_MAP_FIRSTPRIVATE_POINTER:
+	    break;
 	  default:
 	    map_seen |= 1;
 	    error_at (OMP_CLAUSE_LOCATION (*pc),
@@ -14800,9 +14801,10 @@ c_parser_omp_target_enter_data (location
 	  case GOMP_MAP_TO:
 	  case GOMP_MAP_ALWAYS_TO:
 	  case GOMP_MAP_ALLOC:
-	  case GOMP_MAP_POINTER:
 	    map_seen = 3;
 	    break;
+	  case GOMP_MAP_FIRSTPRIVATE_POINTER:
+	    break;
 	  default:
 	    map_seen |= 1;
 	    error_at (OMP_CLAUSE_LOCATION (*pc),
@@ -14885,9 +14887,10 @@ c_parser_omp_target_exit_data (location_
 	  case GOMP_MAP_ALWAYS_FROM:
 	  case GOMP_MAP_RELEASE:
 	  case GOMP_MAP_DELETE:
-	  case GOMP_MAP_POINTER:
 	    map_seen = 3;
 	    break;
+	  case GOMP_MAP_FIRSTPRIVATE_POINTER:
+	    break;
 	  default:
 	    map_seen |= 1;
 	    error_at (OMP_CLAUSE_LOCATION (*pc),
@@ -15078,7 +15081,7 @@ check_clauses:
 	  case GOMP_MAP_TOFROM:
 	  case GOMP_MAP_ALWAYS_TOFROM:
 	  case GOMP_MAP_ALLOC:
-	  case GOMP_MAP_POINTER:
+	  case GOMP_MAP_FIRSTPRIVATE_POINTER:
 	    break;
 	  default:
 	    error_at (OMP_CLAUSE_LOCATION (*pc),
@@ -16379,7 +16382,7 @@ c_parser_cilk_for (c_parser *parser, tre
   tree clauses = build_omp_clause (EXPR_LOCATION (grain), OMP_CLAUSE_SCHEDULE);
   OMP_CLAUSE_SCHEDULE_KIND (clauses) = OMP_CLAUSE_SCHEDULE_CILKFOR;
   OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (clauses) = grain;
-  clauses = c_finish_omp_clauses (clauses);
+  clauses = c_finish_omp_clauses (clauses, false);
 
   tree block = c_begin_compound_stmt (true);
   tree sb = push_stmt_list ();
@@ -16444,7 +16447,7 @@ c_parser_cilk_for (c_parser *parser, tre
       OMP_CLAUSE_OPERAND (c, 0)
 	= cilk_for_number_of_iterations (omp_for);
       OMP_CLAUSE_CHAIN (c) = clauses;
-      OMP_PARALLEL_CLAUSES (omp_par) = c_finish_omp_clauses (c);
+      OMP_PARALLEL_CLAUSES (omp_par) = c_finish_omp_clauses (c, true);
       add_stmt (omp_par);
     }
 
--- gcc/tree-core.h.jj	2015-07-17 09:30:44.000000000 +0200
+++ gcc/tree-core.h	2015-07-21 16:28:48.524156167 +0200
@@ -1354,7 +1354,7 @@ struct GTY(()) tree_omp_clause {
     enum omp_clause_schedule_kind  schedule_kind;
     enum omp_clause_depend_kind    depend_kind;
     /* See include/gomp-constants.h for enum gomp_map_kind's values.  */
-    unsigned char		   map_kind;
+    unsigned int		   map_kind;
     enum omp_clause_proc_bind_kind proc_bind_kind;
     enum tree_code                 reduction_code;
     enum omp_clause_linear_kind    linear_kind;
--- gcc/omp-low.c.jj	2015-07-21 09:07:23.000000000 +0200
+++ gcc/omp-low.c	2015-07-22 13:30:17.507589880 +0200
@@ -2025,6 +2025,21 @@ scan_sharing_clauses (tree clauses, omp_
 		  && !OMP_CLAUSE_MAP_ZERO_BIAS_ARRAY_SECTION (c))
 		break;
 	    }
+	  if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
+	      && OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_FIRSTPRIVATE_POINTER)
+	    {
+	      if (DECL_SIZE (decl)
+		  && TREE_CODE (DECL_SIZE (decl)) != INTEGER_CST)
+		{
+		  tree decl2 = DECL_VALUE_EXPR (decl);
+		  gcc_assert (TREE_CODE (decl2) == INDIRECT_REF);
+		  decl2 = TREE_OPERAND (decl2, 0);
+		  gcc_assert (DECL_P (decl2));
+		  install_var_local (decl2, ctx);
+		}
+	      install_var_local (decl, ctx);
+	      break;
+	    }
 	  if (DECL_P (decl))
 	    {
 	      if (DECL_SIZE (decl)
@@ -2201,7 +2216,8 @@ scan_sharing_clauses (tree clauses, omp_
 	    break;
 	  if (DECL_P (decl))
 	    {
-	      if (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_POINTER
+	      if ((OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_POINTER
+		   || OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_FIRSTPRIVATE_POINTER)
 		  && TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE
 		  && !COMPLETE_TYPE_P (TREE_TYPE (decl)))
 		{
@@ -12883,6 +12899,7 @@ lower_omp_target (gimple_stmt_iterator *
 	  case GOMP_MAP_ALWAYS_TO:
 	  case GOMP_MAP_ALWAYS_FROM:
 	  case GOMP_MAP_ALWAYS_TOFROM:
+	  case GOMP_MAP_FIRSTPRIVATE_POINTER:
 	    break;
 	  case GOMP_MAP_FORCE_ALLOC:
 	  case GOMP_MAP_FORCE_TO:
@@ -12918,6 +12935,25 @@ lower_omp_target (gimple_stmt_iterator *
 	    var = var2;
 	  }
 
+	if (offloaded
+	    && OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_FIRSTPRIVATE_POINTER)
+	  {
+	    if (TREE_CODE (TREE_TYPE (var)) == ARRAY_TYPE)
+	      {
+		tree type = build_pointer_type (TREE_TYPE (var));
+		tree new_var = lookup_decl (var, ctx);
+		const char *name = NULL;
+		if (DECL_NAME (new_var))
+		  name = IDENTIFIER_POINTER (DECL_NAME (new_var));
+		x = create_tmp_var_raw (type, name);
+		gimple_add_tmp_var (x);
+		x = build_simple_mem_ref (x);
+		SET_DECL_VALUE_EXPR (new_var, x);
+		DECL_HAS_VALUE_EXPR_P (new_var) = 1;
+	      }
+	    continue;
+	  }
+
 	if (!maybe_lookup_field (var, ctx))
 	  continue;
 
@@ -12925,6 +12961,7 @@ lower_omp_target (gimple_stmt_iterator *
 	  {
 	    x = build_receiver_ref (var, true, ctx);
 	    tree new_var = lookup_decl (var, ctx);
+
 	    if (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_POINTER
 		&& !OMP_CLAUSE_MAP_ZERO_BIAS_ARRAY_SECTION (c)
 		&& TREE_CODE (TREE_TYPE (var)) == ARRAY_TYPE)
@@ -13044,6 +13081,10 @@ lower_omp_target (gimple_stmt_iterator *
 	      }
 	    else
 	      {
+		if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
+		    && OMP_CLAUSE_MAP_KIND (c)
+		       == GOMP_MAP_FIRSTPRIVATE_POINTER)
+		  break;
 		if (DECL_SIZE (ovar)
 		    && TREE_CODE (DECL_SIZE (ovar)) != INTEGER_CST)
 		  {
@@ -13239,6 +13280,7 @@ lower_omp_target (gimple_stmt_iterator *
 
   if (offloaded)
     {
+      tree prev = NULL_TREE;
       for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c))
 	switch (OMP_CLAUSE_CODE (c))
 	  {
@@ -13290,6 +13332,93 @@ lower_omp_target (gimple_stmt_iterator *
 	      }
 	    break;
 	  }
+      /* Handle GOMP_MAP_FIRSTPRIVATE_POINTER in second pass,
+	 so that firstprivate vars holding OMP_CLAUSE_SIZE if needed
+	 are already handled.  */
+      for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c))
+	switch (OMP_CLAUSE_CODE (c))
+	  {
+	    tree var;
+	  default:
+	    break;
+	  case OMP_CLAUSE_MAP:
+	    if (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_FIRSTPRIVATE_POINTER)
+	      {
+		location_t clause_loc = OMP_CLAUSE_LOCATION (c);
+		gcc_assert (prev);
+		var = OMP_CLAUSE_DECL (c);
+		if (DECL_SIZE (var)
+		    && TREE_CODE (DECL_SIZE (var)) != INTEGER_CST)
+		  {
+		    tree var2 = DECL_VALUE_EXPR (var);
+		    gcc_assert (TREE_CODE (var2) == INDIRECT_REF);
+		    var2 = TREE_OPERAND (var2, 0);
+		    gcc_assert (DECL_P (var2));
+		    var = var2;
+		  }
+		tree new_var = lookup_decl (var, ctx), x;
+		tree type = TREE_TYPE (new_var);
+		bool is_ref = is_reference (var);
+		bool ref_to_array = false;
+		if (is_ref)
+		  {
+		    type = TREE_TYPE (type);
+		    if (TREE_CODE (type) == ARRAY_TYPE)
+		      {
+			type = build_pointer_type (type);
+			ref_to_array = true;
+		      }
+		  }
+		else if (TREE_CODE (type) == ARRAY_TYPE)
+		  {
+		    tree decl2 = DECL_VALUE_EXPR (new_var);
+		    gcc_assert (TREE_CODE (decl2) == MEM_REF);
+		    decl2 = TREE_OPERAND (decl2, 0);
+		    gcc_assert (DECL_P (decl2));
+		    new_var = decl2;
+		    type = TREE_TYPE (new_var);
+		  }
+		x = build_receiver_ref (OMP_CLAUSE_DECL (prev), false, ctx);
+		x = fold_convert_loc (clause_loc, type, x);
+		if (!integer_zerop (OMP_CLAUSE_SIZE (c)))
+		  {
+		    tree bias = OMP_CLAUSE_SIZE (c);
+		    if (DECL_P (bias))
+		      bias = lookup_decl (bias, ctx);
+		    bias = fold_convert_loc (clause_loc, sizetype, bias);
+		    bias = fold_build1_loc (clause_loc, NEGATE_EXPR, sizetype,
+					    bias);
+		    x = fold_build2_loc (clause_loc, POINTER_PLUS_EXPR,
+					 TREE_TYPE (x), x, bias);
+		  }
+		if (ref_to_array)
+		  x = fold_convert_loc (clause_loc, TREE_TYPE (new_var), x);
+		gimplify_expr (&x, &new_body, NULL, is_gimple_val, fb_rvalue);
+		if (is_ref && !ref_to_array)
+		  {
+		    const char *name = NULL;
+		    if (DECL_NAME (var))
+		      name = IDENTIFIER_POINTER (DECL_NAME (new_var));
+
+		    tree t = create_tmp_var_raw (type, name);
+		    gimple_add_tmp_var (t);
+		    TREE_ADDRESSABLE (t) = 1;
+		    gimple_seq_add_stmt (&new_body,
+					 gimple_build_assign (t, x));
+		    x = build_fold_addr_expr_loc (clause_loc, t);
+		  }
+		gimple_seq_add_stmt (&new_body,
+				     gimple_build_assign (new_var, x));
+		prev = NULL_TREE;
+	      }
+	    else if (OMP_CLAUSE_CHAIN (c)
+		     && OMP_CLAUSE_CODE (OMP_CLAUSE_CHAIN (c))
+			== OMP_CLAUSE_MAP
+		     && OMP_CLAUSE_MAP_KIND (OMP_CLAUSE_CHAIN (c))
+			== GOMP_MAP_FIRSTPRIVATE_POINTER)
+	      prev = c;
+	    break;
+	  }
       gimple_seq_add_seq (&new_body, tgt_body);
       new_body = maybe_catch_exception (new_body);
     }
--- gcc/tree-pretty-print.c.jj	2015-07-21 09:06:42.000000000 +0200
+++ gcc/tree-pretty-print.c	2015-07-22 13:53:51.406065024 +0200
@@ -639,6 +639,9 @@ dump_omp_clause (pretty_printer *pp, tre
 	case GOMP_MAP_RELEASE:
 	  pp_string (pp, "release");
 	  break;
+	case GOMP_MAP_FIRSTPRIVATE_POINTER:
+	  pp_string (pp, "firstprivate");
+	  break;
 	default:
 	  gcc_unreachable ();
 	}
@@ -649,7 +652,9 @@ dump_omp_clause (pretty_printer *pp, tre
       if (OMP_CLAUSE_SIZE (clause))
 	{
 	  if (OMP_CLAUSE_CODE (clause) == OMP_CLAUSE_MAP
-	      && OMP_CLAUSE_MAP_KIND (clause) == GOMP_MAP_POINTER)
+	      && (OMP_CLAUSE_MAP_KIND (clause) == GOMP_MAP_POINTER
+		  || OMP_CLAUSE_MAP_KIND (clause)
+		     == GOMP_MAP_FIRSTPRIVATE_POINTER))
 	    pp_string (pp, " [pointer assign, bias: ");
 	  else if (OMP_CLAUSE_CODE (clause) == OMP_CLAUSE_MAP
 		   && OMP_CLAUSE_MAP_KIND (clause) == GOMP_MAP_TO_PSET)


	Jakub

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

* Re: [gomp4.1] Initial support for some OpenMP 4.1 construct parsing
  2015-07-23  0:50                     ` Jakub Jelinek
@ 2015-07-24 20:33                       ` Jakub Jelinek
  2015-07-29 17:30                         ` [gomp4.1] Various accelerator updates from OpenMP 4.1 Jakub Jelinek
  0 siblings, 1 reply; 33+ messages in thread
From: Jakub Jelinek @ 2015-07-24 20:33 UTC (permalink / raw)
  To: Ilya Verbin; +Cc: Thomas Schwinge, gcc-patches, Kirill Yukhin

On Wed, Jul 22, 2015 at 11:13:48PM +0200, Jakub Jelinek wrote:
> On Mon, Jul 20, 2015 at 08:10:41PM +0200, Jakub Jelinek wrote:
> > And here is untested incremental libgomp side of the proposed
> > GOMP_MAP_FIRSTPRIVATE_POINTER.
> 
> Actually, that seems unnecessary, for the array section maps we already
> have there a pointer, so we can easily implement that just on the
> compiler side.
> 
> Here is a WIP patch.

Another version.
What to do with zero-length array sections vs. objects is still under heated
debates, so target8.f90 keeps failing intermittently.
There is also a problem with the firstprivate implementation on #pragma omp
target for host fallback, will need to figure out something for that (the
implementation attempts to avoid double copying).  I'm considering
optimizing integral (up to bitsize of pointer)/pointer firstprivate using some new kind
GOMP_MAP_FIRSTPRIVATE_SCALAR or so, where the pointer would not be pointer
to the scalar, but the scalar itself cast to uintptr_t and then to pointer.
And then for GOMP_MAP_FIRSTPRIVATE probably even for shared space I have to
handle them (allocate using alloca, copy).

--- libgomp/testsuite/libgomp.c++/target-7.C.jj	2015-07-22 11:36:53.042867520 +0200
+++ libgomp/testsuite/libgomp.c++/target-7.C	2015-07-22 11:32:00.000000000 +0200
@@ -0,0 +1,90 @@
+extern "C" void abort ();
+
+void
+foo (int *x, int *&y, int (&z)[15])
+{
+  int a[10], b[15], err, i;
+  for (i = 0; i < 10; i++)
+    a[i] = 7 * i;
+  for (i = 0; i < 15; i++)
+    b[i] = 8 * i;
+  #pragma omp target map(to:x[5:10], y[5:10], z[5:10], a[0:10], b[5:10]) map(from:err)
+  {
+    err = 0;
+    for (i = 0; i < 10; i++)
+      if (x[5 + i] != 20 + 4 * i
+	  || y[5 + i] != 25 + 5 * i
+	  || z[5 + i] != 30 + 6 * i
+	  || a[i] != 7 * i
+	  || b[5 + i] != 40 + 8 * i)
+	err = 1;
+  }
+  if (err)
+    abort ();
+}
+
+void
+bar (int n, int v)
+{
+  int a[n], b[n], c[n], d[n], e[n], err, i;
+  int (*x)[n] = &c;
+  int (*y2)[n] = &d;
+  int (*&y)[n] = y2;
+  int (&z)[n] = e;
+  for (i = 0; i < n; i++)
+    {
+      (*x)[i] = 4 * i;
+      (*y)[i] = 5 * i;
+      z[i] = 6 * i;
+      a[i] = 7 * i;
+      b[i] = 8 * i;
+    }
+  #pragma omp target map(to:x[0][5:10], y[0][5:10], z[5:10], a[0:10], b[5:10]) map(from:err)
+  {
+    err = 0;
+    for (i = 0; i < 10; i++)
+      if ((*x)[5 + i] != 20 + 4 * i
+	  || (*y)[5 + i] != 25 + 5 * i
+	  || z[5 + i] != 30 + 6 * i
+	  || a[i] != 7 * i
+	  || b[5 + i] != 40 + 8 * i)
+	err = 1;
+  }
+  if (err)
+    abort ();
+  for (i = 0; i < n; i++)
+    {
+      (*x)[i] = 9 * i;
+      (*y)[i] = 10 * i;
+      z[i] = 11 * i;
+      a[i] = 12 * i;
+      b[i] = 13 * i;
+    }
+  #pragma omp target map(to:x[0][v:v+5], y[0][v:v+5], z[v:v+5], a[v-5:v+5], b[v:v+5]) map(from:err)
+  {
+    err = 0;
+    for (i = 0; i < 10; i++)
+      if ((*x)[5 + i] != 45 + 9 * i
+	  || (*y)[5 + i] != 50 + 10 * i
+	  || z[5 + i] != 55 + 11 * i
+	  || a[i] != 12 * i
+	  || b[5 + i] != 65 + 13 * i)
+	err = 1;
+  }
+  if (err)
+    abort ();
+}
+
+int
+main ()
+{
+  int x[15], y2[15], z[15], *y = y2, i;
+  for (i = 0; i < 15; i++)
+    {
+      x[i] = 4 * i;
+      y[i] = 5 * i;
+      z[i] = 6 * i;
+    }
+  foo (x, y, z);
+  bar (15, 5);
+}
--- libgomp/testsuite/libgomp.c++/target-2.C.jj	2015-06-30 14:24:03.000000000 +0200
+++ libgomp/testsuite/libgomp.c++/target-2.C	2015-07-23 17:48:08.978674497 +0200
@@ -33,7 +33,8 @@ fn2 (int x, double (&dr) [1024], double
   int j;
   fn1 (hr + 2 * x, ir + 2 * x, x);
   #pragma omp target map(to: br[:x], cr[0:x], dr[x:x], er[x:x]) \
-		     map(to: fr[0:x], gr[0:x], hr[2 * x:x], ir[2 * x:x])
+		     map(to: fr[0:x], gr[0:x], hr[2 * x:x], ir[2 * x:x]) \
+		     map(tofrom: s)
     #pragma omp parallel for reduction(+:s)
       for (j = 0; j < x; j++)
 	s += br[j] * cr[j] + dr[x + j] + er[x + j]
--- libgomp/testsuite/libgomp.c/target-7.c.jj	2015-04-24 12:30:40.000000000 +0200
+++ libgomp/testsuite/libgomp.c/target-7.c	2015-07-23 17:12:33.159753962 +0200
@@ -37,63 +37,63 @@ foo (int f)
     abort ();
   #pragma omp target data device (d) map (to: h)
   {
-    #pragma omp target device (d)
+    #pragma omp target device (d) map (h)
     if (omp_get_level () != 0 || (f && !omp_is_initial_device ()) || h++ != 5)
       abort ();
     #pragma omp target update device (d) from (h)
   }
   #pragma omp target data if (v > 1) map (to: h)
   {
-    #pragma omp target if (v > 1)
+    #pragma omp target if (v > 1) map(h)
     if (omp_get_level () != 0 || !omp_is_initial_device () || h++ != 6)
       abort ();
     #pragma omp target update if (v > 1) from (h)
   }
   #pragma omp target data device (d) if (v > 1) map (to: h)
   {
-    #pragma omp target device (d) if (v > 1)
+    #pragma omp target device (d) if (v > 1) map(h)
     if (omp_get_level () != 0 || !omp_is_initial_device () || h++ != 7)
       abort ();
     #pragma omp target update device (d) if (v > 1) from (h)
   }
   #pragma omp target data if (v <= 1) map (to: h)
   {
-    #pragma omp target if (v <= 1)
+    #pragma omp target if (v <= 1) map (tofrom: h)
     if (omp_get_level () != 0 || h++ != 8)
       abort ();
     #pragma omp target update if (v <= 1) from (h)
   }
   #pragma omp target data device (d) if (v <= 1) map (to: h)
   {
-    #pragma omp target device (d) if (v <= 1)
+    #pragma omp target device (d) if (v <= 1) map (h)
     if (omp_get_level () != 0 || (f && !omp_is_initial_device ()) || h++ != 9)
       abort ();
     #pragma omp target update device (d) if (v <= 1) from (h)
   }
   #pragma omp target data if (0) map (to: h)
   {
-    #pragma omp target if (0)
+    #pragma omp target if (0) map (h)
     if (omp_get_level () != 0 || !omp_is_initial_device () || h++ != 10)
       abort ();
     #pragma omp target update if (0) from (h)
   }
   #pragma omp target data device (d) if (0) map (to: h)
   {
-    #pragma omp target device (d) if (0)
+    #pragma omp target device (d) if (0) map (h)
     if (omp_get_level () != 0 || !omp_is_initial_device () || h++ != 11)
       abort ();
     #pragma omp target update device (d) if (0) from (h)
   }
   #pragma omp target data if (1) map (to: h)
   {
-    #pragma omp target if (1)
+    #pragma omp target if (1) map (tofrom: h)
     if (omp_get_level () != 0 || h++ != 12)
       abort ();
     #pragma omp target update if (1) from (h)
   }
   #pragma omp target data device (d) if (1) map (to: h)
   {
-    #pragma omp target device (d) if (1)
+    #pragma omp target device (d) if (1) map (tofrom: h)
     if (omp_get_level () != 0 || (f && !omp_is_initial_device ()) || h++ != 13)
       abort ();
     #pragma omp target update device (d) if (1) from (h)
--- libgomp/testsuite/libgomp.c/target-15.c.jj	2015-07-22 11:37:11.655612690 +0200
+++ libgomp/testsuite/libgomp.c/target-15.c	2015-07-23 21:53:37.354632916 +0200
@@ -0,0 +1,74 @@
+extern void abort (void);
+
+void
+foo (int *x)
+{
+  int a[10], b[15], err, i;
+  for (i = 0; i < 10; i++)
+    a[i] = 7 * i;
+  for (i = 0; i < 15; i++)
+    b[i] = 8 * i;
+  #pragma omp target map(to:x[5:10], a[0:10], b[5:10]) map(from:err)
+  {
+    err = 0;
+    for (i = 0; i < 10; i++)
+      if (x[5 + i] != 20 + 4 * i
+	  || a[i] != 7 * i
+	  || b[5 + i] != 40 + 8 * i)
+	err = 1;
+  }
+  if (err)
+    abort ();
+}
+
+void
+bar (int n, int v)
+{
+  int a[n], b[n], c[n], d[n], e[n], err, i;
+  int (*x)[n] = &c;
+  for (i = 0; i < n; i++)
+    {
+      (*x)[i] = 4 * i;
+      a[i] = 7 * i;
+      b[i] = 8 * i;
+    }
+  #pragma omp target map(to:x[0][5:10], a[0:10], b[5:10]) map(from:err)
+  {
+    err = 0;
+    for (i = 0; i < 10; i++)
+      if ((*x)[5 + i] != 20 + 4 * i
+	  || a[i] != 7 * i
+	  || b[5 + i] != 40 + 8 * i)
+	err = 1;
+  }
+  if (err)
+    abort ();
+  for (i = 0; i < n; i++)
+    {
+      (*x)[i] = 9 * i;
+      a[i] = 12 * i;
+      b[i] = 13 * i;
+    }
+  #pragma omp target map(to:x[0][v:v+5], a[v-5:v+5], b[v:v+5]) map(from:err)
+  {
+    err = 0;
+    for (i = 0; i < 10; i++)
+      if ((*x)[5 + i] != 45 + 9 * i
+	  || a[i] != 12 * i
+	  || b[5 + i] != 65 + 13 * i)
+	err = 1;
+  }
+  if (err)
+    abort ();
+}
+
+int
+main ()
+{
+  int x[15], i;
+  for (i = 0; i < 15; i++)
+    x[i] = 4 * i;
+  foo (x);
+  bar (15, 5);
+  return 0;
+}
--- libgomp/testsuite/libgomp.c/target-2.c.jj	2015-04-24 12:30:40.000000000 +0200
+++ libgomp/testsuite/libgomp.c/target-2.c	2015-07-23 17:09:27.987350372 +0200
@@ -23,7 +23,7 @@ fn2 (int x)
   int i;
   fn1 (b, c, x);
   fn1 (e, d + x, x);
-  #pragma omp target map(to: b, c[:x], d[x:x], e)
+  #pragma omp target map(to: b, c[:x], d[x:x], e) map(tofrom: s)
     #pragma omp parallel for reduction(+:s)
       for (i = 0; i < x; i++)
 	s += b[i] * c[i] + d[x + i] + sizeof (b) - sizeof (c);
@@ -38,7 +38,7 @@ fn3 (int x)
   int i;
   fn1 (b, c, x);
   fn1 (e, d, x);
-  #pragma omp target
+  #pragma omp target map(tofrom: s)
     #pragma omp parallel for reduction(+:s)
       for (i = 0; i < x; i++)
 	s += b[i] * c[i] + d[i];
@@ -56,7 +56,7 @@ fn4 (int x)
   #pragma omp target data map(from: b, c[:x], d[x:x], e)
     {
       #pragma omp target update to(b, c[:x], d[x:x], e)
-      #pragma omp target map(c[:x], d[x:x])
+      #pragma omp target map(c[:x], d[x:x], s)
 	#pragma omp parallel for reduction(+:s)
 	  for (i = 0; i < x; i++)
 	    {
--- libgomp/testsuite/libgomp.c/target-17.c.jj	2015-07-24 19:50:14.275109272 +0200
+++ libgomp/testsuite/libgomp.c/target-17.c	2015-07-24 19:47:57.000000000 +0200
@@ -0,0 +1,99 @@
+extern void abort (void);
+
+void
+foo (int n)
+{
+  int a[n], i, err;
+  for (i = 0; i < n; i++)
+    a[i] = 5 * i;
+  #pragma omp target map(to:a) map(from:err) private(i)
+  {
+    err = 0;
+    for (i = 0; i < n; i++)
+      if (a[i] != 5 * i)
+	err = 1;
+  }
+  if (err)
+    abort ();
+  for (i = 0; i < n; i++)
+    a[i] += i;
+  #pragma omp target map(from:err) private(i)
+  {
+    err = 0;
+    for (i = 0; i < n; i++)
+      if (a[i] != 6 * i)
+	err = 1;
+  }
+  if (err)
+    abort ();
+  for (i = 0; i < n; i++)
+    a[i] += i;
+  #pragma omp target firstprivate (a) map(from:err) private(i)
+  {
+    err = 0;
+    for (i = 0; i < n; i++)
+      if (a[i] != 7 * i)
+	err = 1;
+  }
+  if (err)
+    abort ();
+  int on = n;
+  #pragma omp target firstprivate (n) map(tofrom: n)
+  {
+    n++;
+  }
+  if (on != n)
+    abort ();
+  #pragma omp target map(tofrom: n) private (n)
+  {
+    n = 25;
+  }
+  if (on != n)
+    abort ();
+  for (i = 0; i < n; i++)
+    a[i] += i;
+  #pragma omp target map(to:a) firstprivate (a) map(from:err) private(i)
+  {
+    err = 0;
+    for (i = 0; i < n; i++)
+      if (a[i] != 8 * i)
+	err = 1;
+  }
+  if (err)
+    abort ();
+  for (i = 0; i < n; i++)
+    a[i] += i;
+  #pragma omp target firstprivate (a) map(to:a) map(from:err) private(i)
+  {
+    err = 0;
+    for (i = 0; i < n; i++)
+      if (a[i] != 9 * i)
+	err = 1;
+  }
+  if (err)
+    abort ();
+  for (i = 0; i < n; i++)
+    a[i] += i;
+  #pragma omp target map(tofrom:a) map(from:err) private(a, i)
+  {
+    err = 0;
+    for (i = 0; i < n; i++)
+      a[i] = 7;
+    #pragma omp parallel for reduction(|:err)
+    for (i = 0; i < n; i++)
+      if (a[i] != 7)
+        err |= 1;
+  }
+  if (err)
+    abort ();
+  for (i = 0; i < n; i++)
+    if (a[i] != 10 * i)
+      abort ();
+}
+
+int
+main ()
+{
+  foo (9);
+  return 0;
+}
--- libgomp/testsuite/libgomp.c/examples-4/e.54.2.c.jj	2015-04-24 12:30:40.000000000 +0200
+++ libgomp/testsuite/libgomp.c/examples-4/e.54.2.c	2015-07-23 16:02:02.343554209 +0200
@@ -32,7 +32,7 @@ float dotprod (float B[], float C[], int
   int i, i0;
   float sum = 0;
 
-  #pragma omp target map(to: B[0:n], C[0:n])
+  #pragma omp target map(to: B[0:n], C[0:n]) map(tofrom: sum)
     #pragma omp teams num_teams(num_teams) thread_limit(block_threads) \
 		      reduction(+:sum)
       #pragma omp distribute
--- libgomp/testsuite/libgomp.c/examples-4/e.57.1.c.jj	2015-04-24 12:30:40.000000000 +0200
+++ libgomp/testsuite/libgomp.c/examples-4/e.57.1.c	2015-07-23 17:37:01.880139916 +0200
@@ -10,11 +10,11 @@ int main ()
   int b = 0;
   int c, d;
 
-  #pragma omp target if(a > 200 && a < 400)
+  #pragma omp target if(a > 200 && a < 400) map(from: c)
     c = omp_is_initial_device ();
 
   #pragma omp target data map(to: b) if(a > 200 && a < 400)
-    #pragma omp target
+    #pragma omp target map(from: b, d)
       {
 	b = 100;
 	d = omp_is_initial_device ();
@@ -26,11 +26,11 @@ int main ()
   a += 200;
   b = 0;
 
-  #pragma omp target if(a > 200 && a < 400)
+  #pragma omp target if(a > 200 && a < 400) map(from: c)
     c = omp_is_initial_device ();
 
   #pragma omp target data map(to: b) if(a > 200 && a < 400)
-    #pragma omp target
+    #pragma omp target map(from: b, d)
       {
 	b = 100;
 	d = omp_is_initial_device ();
@@ -42,11 +42,11 @@ int main ()
   a += 200;
   b = 0;
 
-  #pragma omp target if(a > 200 && a < 400)
+  #pragma omp target if(a > 200 && a < 400) map(from: c)
     c = omp_is_initial_device ();
 
   #pragma omp target data map(to: b) if(a > 200 && a < 400)
-    #pragma omp target
+    #pragma omp target map(from: b, d)
       {
 	b = 100;
 	d = omp_is_initial_device ();
--- libgomp/testsuite/libgomp.c/examples-4/e.57.3.c.jj	2015-04-24 12:30:40.000000000 +0200
+++ libgomp/testsuite/libgomp.c/examples-4/e.57.3.c	2015-07-23 16:08:48.176775074 +0200
@@ -9,7 +9,7 @@ int main ()
   int res;
   int default_device = omp_get_default_device ();
 
-  #pragma omp target
+  #pragma omp target map(from: res)
     res = omp_is_initial_device ();
 
   if (res)
@@ -17,7 +17,7 @@ int main ()
 
   omp_set_default_device (omp_get_num_devices ());
 
-  #pragma omp target
+  #pragma omp target map(from: res)
     res = omp_is_initial_device ();
 
   if (!res)
--- libgomp/testsuite/libgomp.c/examples-4/e.53.4.c.jj	2015-04-24 12:30:40.000000000 +0200
+++ libgomp/testsuite/libgomp.c/examples-4/e.53.4.c	2015-07-23 16:00:22.468976440 +0200
@@ -41,7 +41,7 @@ float accum (int k)
   int i;
   float tmp = 0.0;
 
-  #pragma omp target
+  #pragma omp target map(tofrom:tmp)
     #pragma omp parallel for reduction(+:tmp)
       for (i = 0; i < N; i++)
 	tmp += Pfun (i, k);
--- libgomp/testsuite/libgomp.c/examples-4/e.54.4.c.jj	2015-04-24 12:30:40.000000000 +0200
+++ libgomp/testsuite/libgomp.c/examples-4/e.54.4.c	2015-07-23 16:03:21.446427770 +0200
@@ -31,7 +31,7 @@ float dotprod (float B[], float C[], int
   int i;
   float sum = 0;
 
-  #pragma omp target map(to: B[0:n], C[0:n])
+  #pragma omp target map(to: B[0:n], C[0:n]) map(tofrom:sum)
     #pragma omp teams num_teams(8) thread_limit(16)
       #pragma omp distribute parallel for reduction(+:sum) \
 					  dist_schedule(static, 1024) \
--- libgomp/testsuite/libgomp.c/examples-4/e.53.5.c.jj	2015-06-17 21:00:36.000000000 +0200
+++ libgomp/testsuite/libgomp.c/examples-4/e.53.5.c	2015-07-23 16:01:17.802188485 +0200
@@ -48,7 +48,7 @@ float accum ()
   int i, k;
   float tmp = 0.0;
 
-  #pragma omp target
+  #pragma omp target map(tofrom:tmp)
     #pragma omp parallel for reduction(+:tmp)
       for (i = 0; i < N; i++)
 	{
--- libgomp/testsuite/libgomp.c/examples-4/e.53.1.c.jj	2015-04-24 12:30:40.000000000 +0200
+++ libgomp/testsuite/libgomp.c/examples-4/e.53.1.c	2015-07-23 15:59:44.430518114 +0200
@@ -20,7 +20,7 @@ int fib_wrapper (int n)
 {
   int x = 0;
 
-  #pragma omp target if(n > THRESHOLD)
+  #pragma omp target if(n > THRESHOLD) map(from:x)
     x = fib (n);
 
   return x;
--- libgomp/testsuite/libgomp.c/examples-4/e.51.3.c.jj	2015-04-24 12:30:40.000000000 +0200
+++ libgomp/testsuite/libgomp.c/examples-4/e.51.3.c	2015-07-23 15:58:15.867779262 +0200
@@ -47,7 +47,7 @@ void gramSchmidt (int Q[][COLS], const i
       {
 	int tmp = 0;
 
-	#pragma omp target
+	#pragma omp target map(tofrom:tmp)
 	  #pragma omp parallel for reduction(+:tmp)
 	    for (i = 0; i < rows; i++)
 	      tmp += (Q[i][k] * Q[i][k]);
--- libgomp/testsuite/libgomp.c/examples-4/e.54.3.c.jj	2015-04-24 12:30:40.000000000 +0200
+++ libgomp/testsuite/libgomp.c/examples-4/e.54.3.c	2015-07-23 16:02:28.060187999 +0200
@@ -31,7 +31,7 @@ float dotprod (float B[], float C[], int
   int i;
   float sum = 0;
 
-  #pragma omp target teams map(to: B[0:n], C[0:n])
+  #pragma omp target teams map(to: B[0:n], C[0:n]) map(tofrom: sum)
     #pragma omp distribute parallel for reduction(+:sum)
       for (i = 0; i < n; i++)
 	sum += B[i] * C[i];
--- libgomp/testsuite/libgomp.c/target-1.c.jj	2015-04-24 12:30:40.000000000 +0200
+++ libgomp/testsuite/libgomp.c/target-1.c	2015-07-23 17:08:32.474133124 +0200
@@ -34,7 +34,7 @@ fn2 (int x, int y, int z)
   fn1 (b, c, x);
   #pragma omp target data map(to: b)
   {
-    #pragma omp target map(tofrom: c)
+    #pragma omp target map(tofrom: c, s)
       #pragma omp teams num_teams(y) thread_limit(z) reduction(+:s) firstprivate(x)
 	#pragma omp distribute dist_schedule(static, 4) collapse(1)
 	  for (j=0; j < x; j += y)
@@ -52,7 +52,7 @@ fn3 (int x)
   double b[1024], c[1024], s = 0;
   int i;
   fn1 (b, c, x);
-  #pragma omp target map(to: b, c)
+  #pragma omp target map(to: b, c) map(tofrom:s)
     #pragma omp parallel for reduction(+:s)
       for (i = 0; i < x; i++)
 	tgt (), s += b[i] * c[i];
@@ -66,7 +66,8 @@ fn4 (int x, double *p)
   int i;
   fn1 (b, c, x);
   fn1 (d + x, p + x, x);
-  #pragma omp target map(to: b, c[0:x], d[x:x]) map(to:p[x:64 + (x & 31)])
+  #pragma omp target map(to: b, c[0:x], d[x:x]) map(to:p[x:64 + (x & 31)]) \
+		     map(tofrom: s)
     #pragma omp parallel for reduction(+:s)
       for (i = 0; i < x; i++)
 	s += b[i] * c[i] + d[x + i] + p[x + i];
--- libgomp/testsuite/libgomp.c/target-16.c.jj	2015-07-23 21:53:28.905753778 +0200
+++ libgomp/testsuite/libgomp.c/target-16.c	2015-07-24 12:20:32.048722516 +0200
@@ -0,0 +1,45 @@
+extern void abort (void);
+
+void
+foo (int n)
+{
+  int a[n], i, err;
+  for (i = 0; i < n; i++)
+    a[i] = 7 * i;
+  #pragma omp target firstprivate (a) map(from:err) private (i)
+  {
+    err = 0;
+    for (i = 0; i < n; i++)
+      if (a[i] != 7 * i)
+	err = 1;
+  }
+  if (err)
+    abort ();
+}
+
+void
+bar (int n)
+{
+  int a[n], i, err;
+  #pragma omp target private (a) map(from:err)
+  {
+    #pragma omp parallel for
+    for (i = 0; i < n; i++)
+      a[i] = 7 * i;
+    err = 0;
+    #pragma omp parallel for reduction(|:err)
+    for (i = 0; i < n; i++)
+      if (a[i] != 7 * i)
+	err |= 1;
+  }
+  if (err)
+    abort ();
+}
+
+int
+main ()
+{
+  foo (7);
+  bar (7);
+  return 0;
+}
--- libgomp/target.c.jj	2015-07-21 09:07:23.690851224 +0200
+++ libgomp/target.c	2015-07-22 21:12:22.438213557 +0200
@@ -142,7 +142,26 @@ resolve_device (int device_id)
 }
 
 
-/* Handle the case where splay_tree_lookup found oldn for newn.
+static inline splay_tree_key
+gomp_map_lookup (splay_tree mem_map, splay_tree_key key)
+{
+  if (key->host_start != key->host_end)
+    return splay_tree_lookup (mem_map, key);
+
+  key->host_end++;
+  splay_tree_key n = splay_tree_lookup (mem_map, key);
+  key->host_end--;
+  if (n)
+    return n;
+  key->host_start--;
+  n = splay_tree_lookup (mem_map, key);
+  key->host_start++;
+  if (n)
+    return n;
+  return splay_tree_lookup (mem_map, key);
+}
+
+/* Handle the case where gmp_map_lookup found oldn for newn.
    Helper function of gomp_map_vars.  */
 
 static inline void
@@ -204,20 +223,8 @@ gomp_map_pointer (struct target_mem_desc
     }
   /* Add bias to the pointer value.  */
   cur_node.host_start += bias;
-  cur_node.host_end = cur_node.host_start + 1;
-  splay_tree_key n = splay_tree_lookup (mem_map, &cur_node);
-  if (n == NULL)
-    {
-      /* Could be possibly zero size array section.  */
-      cur_node.host_end--;
-      n = splay_tree_lookup (mem_map, &cur_node);
-      if (n == NULL)
-	{
-	  cur_node.host_start--;
-	  n = splay_tree_lookup (mem_map, &cur_node);
-	  cur_node.host_start++;
-	}
-    }
+  cur_node.host_end = cur_node.host_start;
+  splay_tree_key n = gomp_map_lookup (mem_map, &cur_node);
   if (n == NULL)
     {
       gomp_mutex_unlock (&devicep->lock);
@@ -293,7 +300,7 @@ gomp_map_vars (struct gomp_device_descr
 	  has_firstprivate = true;
 	  continue;
 	}
-      splay_tree_key n = splay_tree_lookup (mem_map, &cur_node);
+      splay_tree_key n = gomp_map_lookup (mem_map, &cur_node);
       if (n)
 	gomp_map_vars_existing (devicep, n, &cur_node, &tgt->list[i],
 				kind & typemask);
@@ -392,7 +399,7 @@ gomp_map_vars (struct gomp_device_descr
 	      k->host_end = k->host_start + sizes[i];
 	    else
 	      k->host_end = k->host_start + sizeof (void *);
-	    splay_tree_key n = splay_tree_lookup (mem_map, k);
+	    splay_tree_key n = gomp_map_lookup (mem_map, k);
 	    if (n)
 	      gomp_map_vars_existing (devicep, n, k, &tgt->list[i],
 				      kind & typemask);
@@ -526,7 +533,8 @@ gomp_map_vars (struct gomp_device_descr
 	    }
 	  else
 	    cur_node.tgt_offset = tgt->list[i].key->tgt->tgt_start
-				  + tgt->list[i].key->tgt_offset;
+				  + tgt->list[i].key->tgt_offset
+				  + tgt->list[i].offset;
 	  /* FIXME: see above FIXME comment.  */
 	  devicep->host2dev_func (devicep->target_id,
 				  (void *) (tgt->tgt_start
@@ -1289,20 +1297,8 @@ omp_target_is_present (void *ptr, size_t
   struct splay_tree_key_s cur_node;
 
   cur_node.host_start = (uintptr_t) ptr + offset;
-  cur_node.host_end = cur_node.host_start + 1;
-  splay_tree_key n = splay_tree_lookup (mem_map, &cur_node);
-  if (n == NULL)
-    {
-      /* Could be possibly zero size array section.  */
-      cur_node.host_end--;
-      n = splay_tree_lookup (mem_map, &cur_node);
-      if (n == NULL)
-	{
-	  cur_node.host_start--;
-	  n = splay_tree_lookup (mem_map, &cur_node);
-	  cur_node.host_start++;
-	}
-    }
+  cur_node.host_end = cur_node.host_start;
+  splay_tree_key n = gomp_map_lookup (mem_map, &cur_node);
   int ret = n != NULL;
   gomp_mutex_unlock (&devicep->lock);
   return ret;
@@ -1524,7 +1520,7 @@ omp_target_associate_ptr (void *host_ptr
 
   cur_node.host_start = (uintptr_t) host_ptr;
   cur_node.host_end = cur_node.host_start + size;
-  splay_tree_key n = splay_tree_lookup (mem_map, &cur_node);
+  splay_tree_key n = gomp_map_lookup (mem_map, &cur_node);
   if (n)
     {
       if (n->tgt->tgt_start + n->tgt_offset
@@ -1584,13 +1580,8 @@ omp_target_disassociate_ptr (void *ptr,
   int ret = EINVAL;
 
   cur_node.host_start = (uintptr_t) ptr;
-  cur_node.host_end = cur_node.host_start + 1;
-  splay_tree_key n = splay_tree_lookup (mem_map, &cur_node);
-  if (n == NULL)
-    {
-      cur_node.host_end--;
-      n = splay_tree_lookup (mem_map, &cur_node);
-    }
+  cur_node.host_end = cur_node.host_start;
+  splay_tree_key n = gomp_map_lookup (mem_map, &cur_node);
   if (n
       && n->host_start == cur_node.host_start
       && n->refcount == REFCOUNT_INFINITY
--- libgomp/libgomp.h.jj	2015-07-15 13:00:32.000000000 +0200
+++ libgomp/libgomp.h	2015-07-22 21:09:39.023307107 +0200
@@ -647,11 +647,9 @@ struct target_var_desc {
   bool copy_from;
   /* True if data always should be copied from device to host at the end.  */
   bool always_copy_from;
-  /* Used for unmapping of array sections, can be nonzero only when
-     always_copy_from is true.  */
+  /* Relative offset against key host_start.  */
   uintptr_t offset;
-  /* Used for unmapping of array sections, can be less than the size of the
-     whole object only when always_copy_from is true.  */
+  /* Actual length.  */
   uintptr_t length;
 };
 
--- include/gomp-constants.h.jj	2015-07-21 09:07:23.689851239 +0200
+++ include/gomp-constants.h	2015-07-21 15:01:05.384829637 +0200
@@ -95,7 +95,11 @@ enum gomp_map_kind
     GOMP_MAP_DELETE =			GOMP_MAP_FORCE_DEALLOC,
     /* Decrement usage count and deallocate if zero.  */
     GOMP_MAP_RELEASE =			(GOMP_MAP_FLAG_ALWAYS
-					 | GOMP_MAP_FORCE_DEALLOC)
+					 | GOMP_MAP_FORCE_DEALLOC),
+
+    /* Internal to GCC, not used in libgomp.  */
+    /* Do not map, but pointer assign a pointer instead.  */
+    GOMP_MAP_FIRSTPRIVATE_POINTER =	(GOMP_MAP_LAST | 1)
   };
 
 #define GOMP_MAP_COPY_TO_P(X) \
--- gcc/cp/parser.c.jj	2015-07-21 09:06:42.000000000 +0200
+++ gcc/cp/parser.c	2015-07-23 12:46:22.172652420 +0200
@@ -32276,27 +32276,28 @@ cp_parser_omp_target_data (cp_parser *pa
   for (tree *pc = &clauses; *pc;)
     {
       if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_MAP)
-       switch (OMP_CLAUSE_MAP_KIND (*pc))
-	 {
-	 case GOMP_MAP_TO:
-	 case GOMP_MAP_ALWAYS_TO:
-	 case GOMP_MAP_FROM:
-	 case GOMP_MAP_ALWAYS_FROM:
-	 case GOMP_MAP_TOFROM:
-	 case GOMP_MAP_ALWAYS_TOFROM:
-	 case GOMP_MAP_ALLOC:
-	 case GOMP_MAP_POINTER:
-	   map_seen = 3;
-	   break;
-	 default:
-	   map_seen |= 1;
-	   error_at (OMP_CLAUSE_LOCATION (*pc),
-		     "%<#pragma omp target data%> with map-type other "
-		     "than %<to%>, %<from%>, %<tofrom%> or %<alloc%> "
-		     "on %<map%> clause");
-	   *pc = OMP_CLAUSE_CHAIN (*pc);
-	   continue;
-	 }
+	switch (OMP_CLAUSE_MAP_KIND (*pc))
+	  {
+	  case GOMP_MAP_TO:
+	  case GOMP_MAP_ALWAYS_TO:
+	  case GOMP_MAP_FROM:
+	  case GOMP_MAP_ALWAYS_FROM:
+	  case GOMP_MAP_TOFROM:
+	  case GOMP_MAP_ALWAYS_TOFROM:
+	  case GOMP_MAP_ALLOC:
+	    map_seen = 3;
+	    break;
+	  case GOMP_MAP_FIRSTPRIVATE_POINTER:
+	    break;
+	  default:
+	    map_seen |= 1;
+	    error_at (OMP_CLAUSE_LOCATION (*pc),
+		      "%<#pragma omp target data%> with map-type other "
+		      "than %<to%>, %<from%>, %<tofrom%> or %<alloc%> "
+		      "on %<map%> clause");
+	    *pc = OMP_CLAUSE_CHAIN (*pc);
+	    continue;
+	  }
       pc = &OMP_CLAUSE_CHAIN (*pc);
     }
 
@@ -32370,22 +32371,23 @@ cp_parser_omp_target_enter_data (cp_pars
   for (tree *pc = &clauses; *pc;)
     {
       if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_MAP)
-       switch (OMP_CLAUSE_MAP_KIND (*pc))
-	 {
-	 case GOMP_MAP_TO:
-	 case GOMP_MAP_ALWAYS_TO:
-	 case GOMP_MAP_ALLOC:
-	 case GOMP_MAP_POINTER:
-	   map_seen = 3;
-	   break;
-	 default:
-	   map_seen |= 1;
-	   error_at (OMP_CLAUSE_LOCATION (*pc),
-		     "%<#pragma omp target enter data%> with map-type other "
-		     "than %<to%> or %<alloc%> on %<map%> clause");
-	   *pc = OMP_CLAUSE_CHAIN (*pc);
-	   continue;
-	 }
+	switch (OMP_CLAUSE_MAP_KIND (*pc))
+	  {
+	  case GOMP_MAP_TO:
+	  case GOMP_MAP_ALWAYS_TO:
+	  case GOMP_MAP_ALLOC:
+	    map_seen = 3;
+	    break;
+	  case GOMP_MAP_FIRSTPRIVATE_POINTER:
+	    break;
+	  default:
+	    map_seen |= 1;
+	    error_at (OMP_CLAUSE_LOCATION (*pc),
+		      "%<#pragma omp target enter data%> with map-type other "
+		      "than %<to%> or %<alloc%> on %<map%> clause");
+	    *pc = OMP_CLAUSE_CHAIN (*pc);
+	    continue;
+	  }
       pc = &OMP_CLAUSE_CHAIN (*pc);
     }
 
@@ -32455,24 +32457,25 @@ cp_parser_omp_target_exit_data (cp_parse
   for (tree *pc = &clauses; *pc;)
     {
       if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_MAP)
-       switch (OMP_CLAUSE_MAP_KIND (*pc))
-	 {
-	 case GOMP_MAP_FROM:
-	 case GOMP_MAP_ALWAYS_FROM:
-	 case GOMP_MAP_RELEASE:
-	 case GOMP_MAP_DELETE:
-	 case GOMP_MAP_POINTER:
-	   map_seen = 3;
-	   break;
-	 default:
-	   map_seen |= 1;
-	   error_at (OMP_CLAUSE_LOCATION (*pc),
-		     "%<#pragma omp target exit data%> with map-type other "
-		     "than %<from%>, %<release%> or %<delete%> on %<map%>"
-		     " clause");
-	   *pc = OMP_CLAUSE_CHAIN (*pc);
-	   continue;
-	 }
+	switch (OMP_CLAUSE_MAP_KIND (*pc))
+	  {
+	  case GOMP_MAP_FROM:
+	  case GOMP_MAP_ALWAYS_FROM:
+	  case GOMP_MAP_RELEASE:
+	  case GOMP_MAP_DELETE:
+	    map_seen = 3;
+	    break;
+	  case GOMP_MAP_FIRSTPRIVATE_POINTER:
+	    break;
+	  default:
+	    map_seen |= 1;
+	    error_at (OMP_CLAUSE_LOCATION (*pc),
+		      "%<#pragma omp target exit data%> with map-type other "
+		      "than %<from%>, %<release%> or %<delete%> on %<map%>"
+		      " clause");
+	    *pc = OMP_CLAUSE_CHAIN (*pc);
+	    continue;
+	  }
       pc = &OMP_CLAUSE_CHAIN (*pc);
     }
 
@@ -32637,6 +32640,7 @@ cp_parser_omp_target (cp_parser *parser,
 	  TREE_TYPE (stmt) = void_type_node;
 	  OMP_TARGET_CLAUSES (stmt) = cclauses[C_OMP_CLAUSE_SPLIT_TARGET];
 	  OMP_TARGET_BODY (stmt) = body;
+	  OMP_TARGET_COMBINED (stmt) = 1;
 	  add_stmt (stmt);
 	  pc = &OMP_TARGET_CLAUSES (stmt);
 	  goto check_clauses;
@@ -32697,7 +32701,7 @@ check_clauses:
 	  case GOMP_MAP_TOFROM:
 	  case GOMP_MAP_ALWAYS_TOFROM:
 	  case GOMP_MAP_ALLOC:
-	  case GOMP_MAP_POINTER:
+	  case GOMP_MAP_FIRSTPRIVATE_POINTER:
 	    break;
 	  default:
 	    error_at (OMP_CLAUSE_LOCATION (*pc),
--- gcc/cp/semantics.c.jj	2015-07-17 13:59:27.000000000 +0200
+++ gcc/cp/semantics.c	2015-07-22 13:01:26.296499686 +0200
@@ -4650,7 +4650,7 @@ handle_omp_array_sections_1 (tree c, tre
 /* Handle array sections for clause C.  */
 
 static bool
-handle_omp_array_sections (tree c)
+handle_omp_array_sections (tree c, bool is_omp)
 {
   bool maybe_zero_len = false;
   unsigned int first_non_one = 0;
@@ -4828,8 +4828,9 @@ handle_omp_array_sections (tree c)
 	    return false;
 	  tree c2 = build_omp_clause (OMP_CLAUSE_LOCATION (c),
 				      OMP_CLAUSE_MAP);
-	  OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_POINTER);
-	  if (!cxx_mark_addressable (t))
+	  OMP_CLAUSE_SET_MAP_KIND (c2, is_omp ? GOMP_MAP_FIRSTPRIVATE_POINTER
+					      : GOMP_MAP_POINTER);
+	  if (!is_omp && !cxx_mark_addressable (t))
 	    return false;
 	  OMP_CLAUSE_DECL (c2) = t;
 	  t = build_fold_addr_expr (first);
@@ -4847,7 +4848,8 @@ handle_omp_array_sections (tree c)
 	  OMP_CLAUSE_CHAIN (c2) = OMP_CLAUSE_CHAIN (c);
 	  OMP_CLAUSE_CHAIN (c) = c2;
 	  ptr = OMP_CLAUSE_DECL (c2);
-	  if (TREE_CODE (TREE_TYPE (ptr)) == REFERENCE_TYPE
+	  if (!is_omp
+	      && TREE_CODE (TREE_TYPE (ptr)) == REFERENCE_TYPE
 	      && POINTER_TYPE_P (TREE_TYPE (TREE_TYPE (ptr))))
 	    {
 	      tree c3 = build_omp_clause (OMP_CLAUSE_LOCATION (c),
@@ -5569,7 +5571,7 @@ finish_omp_clauses (tree clauses, bool a
 	  t = OMP_CLAUSE_DECL (c);
 	  if (TREE_CODE (t) == TREE_LIST)
 	    {
-	      if (handle_omp_array_sections (c))
+	      if (handle_omp_array_sections (c, allow_fields))
 		{
 		  remove = true;
 		  break;
@@ -6155,7 +6157,7 @@ finish_omp_clauses (tree clauses, bool a
 	    }
 	  if (TREE_CODE (t) == TREE_LIST)
 	    {
-	      if (handle_omp_array_sections (c))
+	      if (handle_omp_array_sections (c, allow_fields))
 		remove = true;
 	      break;
 	    }
@@ -6189,7 +6191,7 @@ finish_omp_clauses (tree clauses, bool a
 	  t = OMP_CLAUSE_DECL (c);
 	  if (TREE_CODE (t) == TREE_LIST)
 	    {
-	      if (handle_omp_array_sections (c))
+	      if (handle_omp_array_sections (c, allow_fields))
 		remove = true;
 	      else
 		{
@@ -6242,7 +6244,9 @@ finish_omp_clauses (tree clauses, bool a
 		   && !cxx_mark_addressable (t))
 	    remove = true;
 	  else if (!(OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
-		     && OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_POINTER)
+		     && (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_POINTER
+			 || (OMP_CLAUSE_MAP_KIND (c)
+			     == GOMP_MAP_FIRSTPRIVATE_POINTER)))
 		   && !type_dependent_expression_p (t)
 		   && !cp_omp_mappable_type ((TREE_CODE (TREE_TYPE (t))
 					      == REFERENCE_TYPE)
--- gcc/tree.h.jj	2015-07-16 17:56:41.000000000 +0200
+++ gcc/tree.h	2015-07-24 15:27:17.485633106 +0200
@@ -1341,6 +1341,11 @@ extern void protected_set_expr_location
 #define OMP_TEAMS_COMBINED(NODE) \
   (OMP_TEAMS_CHECK (NODE)->base.private_flag)
 
+/* True on an OMP_TARGET statement if it represents explicit
+   combined target teams, target parallel or target simd constructs.  */
+#define OMP_TARGET_COMBINED(NODE) \
+  (OMP_TARGET_CHECK (NODE)->base.private_flag)
+
 /* True if OMP_ATOMIC* is supposed to be sequentially consistent
    as opposed to relaxed.  */
 #define OMP_ATOMIC_SEQ_CST(NODE) \
@@ -1445,13 +1450,17 @@ extern void protected_set_expr_location
   ((enum gomp_map_kind) OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_MAP)->omp_clause.subcode.map_kind)
 #define OMP_CLAUSE_SET_MAP_KIND(NODE, MAP_KIND) \
   (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_MAP)->omp_clause.subcode.map_kind \
-   = (unsigned char) (MAP_KIND))
+   = (unsigned int) (MAP_KIND))
 
 /* 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.  */
 #define OMP_CLAUSE_MAP_ZERO_BIAS_ARRAY_SECTION(NODE) \
   (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_MAP)->base.public_flag)
+/* Nonzero if the same decl appears both in OMP_CLAUSE_MAP and either
+   OMP_CLAUSE_PRIVATE or OMP_CLAUSE_FIRSTPRIVATE.  */
+#define OMP_CLAUSE_MAP_PRIVATE(NODE) \
+  TREE_PRIVATE (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_MAP))
 
 #define OMP_CLAUSE_PROC_BIND_KIND(NODE) \
   (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_PROC_BIND)->omp_clause.subcode.proc_bind_kind)
--- gcc/gimplify.c.jj	2015-07-16 17:56:41.000000000 +0200
+++ gcc/gimplify.c	2015-07-24 17:41:57.778481242 +0200
@@ -90,6 +90,8 @@ enum gimplify_omp_var_data
   /* Flag for GOVD_LINEAR or GOVD_LASTPRIVATE: no outer reference.  */
   GOVD_LINEAR_LASTPRIVATE_NO_OUTER = 16384,
 
+  GOVD_MAP_0LEN_ARRAY = 32768,
+
   GOVD_DATA_SHARE_CLASS = (GOVD_SHARED | GOVD_PRIVATE | GOVD_FIRSTPRIVATE
 			   | GOVD_LASTPRIVATE | GOVD_REDUCTION | GOVD_LINEAR
 			   | GOVD_LOCAL)
@@ -110,6 +112,7 @@ enum omp_region_type
   ORT_TARGET_DATA = 16,
   /* Data region with offloading.  */
   ORT_TARGET = 32,
+  ORT_COMBINED_TARGET = 33,
   /* Dummy OpenMP region, used to disable expansion of
      DECL_VALUE_EXPRs in taskloop pre body.  */
   ORT_NONE = 64
@@ -156,6 +159,9 @@ struct gimplify_omp_ctx
   enum omp_region_type region_type;
   bool combined_loop;
   bool distribute;
+  bool target_map_scalars_firstprivate;
+  bool target_map_pointers_as_0len_arrays;
+  bool target_firstprivatize_array_bases;
 };
 
 static struct gimplify_ctx *gimplify_ctxp;
@@ -2260,7 +2266,7 @@ maybe_fold_stmt (gimple_stmt_iterator *g
 {
   struct gimplify_omp_ctx *ctx;
   for (ctx = gimplify_omp_ctxp; ctx; ctx = ctx->outer_context)
-    if (ctx->region_type == ORT_TARGET)
+    if ((ctx->region_type & ORT_TARGET) != 0)
       return false;
   return fold_stmt (gsi);
 }
@@ -5561,8 +5567,13 @@ omp_firstprivatize_variable (struct gimp
 	  else
 	    return;
 	}
-      else if (ctx->region_type == ORT_TARGET)
-	omp_add_variable (ctx, decl, GOVD_MAP | GOVD_MAP_TO_ONLY);
+      else if ((ctx->region_type & ORT_TARGET) != 0)
+	{
+	  if (ctx->target_map_scalars_firstprivate)
+	    omp_add_variable (ctx, decl, GOVD_FIRSTPRIVATE);
+	  else
+	    omp_add_variable (ctx, decl, GOVD_MAP | GOVD_MAP_TO_ONLY);
+	}
       else if (ctx->region_type != ORT_WORKSHARE
 	       && ctx->region_type != ORT_SIMD
 	       && ctx->region_type != ORT_TARGET_DATA)
@@ -5648,7 +5659,7 @@ omp_add_variable (struct gimplify_omp_ct
     flags |= GOVD_SEEN;
 
   n = splay_tree_lookup (ctx->variables, (splay_tree_key)decl);
-  if (n != NULL && n->value != GOVD_ALIGNED)
+  if (n != NULL && (n->value & GOVD_DATA_SHARE_CLASS) != 0)
     {
       /* We shouldn't be re-adding the decl with the same data
 	 sharing class.  */
@@ -5678,6 +5689,9 @@ omp_add_variable (struct gimplify_omp_ct
 	    nflags = GOVD_MAP | GOVD_MAP_TO_ONLY | GOVD_EXPLICIT;
 	  else if (flags & GOVD_PRIVATE)
 	    nflags = GOVD_PRIVATE;
+	  else if ((ctx->region_type & ORT_TARGET) != 0
+		   && (flags & GOVD_FIRSTPRIVATE))
+	    nflags = GOVD_PRIVATE | GOVD_EXPLICIT;
 	  else
 	    nflags = GOVD_FIRSTPRIVATE;
 	  nflags |= flags & GOVD_SEEN;
@@ -5746,7 +5760,7 @@ omp_notice_threadprivate_variable (struc
   struct gimplify_omp_ctx *octx;
 
   for (octx = ctx; octx; octx = octx->outer_context)
-    if (octx->region_type == ORT_TARGET)
+    if ((octx->region_type & ORT_TARGET) != 0)
       {
 	n = splay_tree_lookup (octx->variables, (splay_tree_key)decl);
 	if (n == NULL)
@@ -5810,19 +5824,66 @@ omp_notice_variable (struct gimplify_omp
     }
 
   n = splay_tree_lookup (ctx->variables, (splay_tree_key)decl);
-  if (ctx->region_type == ORT_TARGET)
+  if ((ctx->region_type & ORT_TARGET) != 0)
     {
       ret = lang_hooks.decls.omp_disregard_value_expr (decl, true);
       if (n == NULL)
 	{
-	  if (!lang_hooks.types.omp_mappable_type (TREE_TYPE (decl)))
+	  unsigned nflags = flags;
+	  if (ctx->target_map_pointers_as_0len_arrays
+	      || ctx->target_map_scalars_firstprivate)
+	    {
+	      bool is_declare_target = false;
+	      bool is_scalar = false;
+	      if (is_global_var (decl)
+		  && varpool_node::get_create (decl)->offloadable)
+		{
+		  struct gimplify_omp_ctx *octx;
+		  for (octx = ctx->outer_context;
+		       octx; octx = octx->outer_context)
+		    {
+		      n = splay_tree_lookup (octx->variables,
+					     (splay_tree_key)decl);
+		      if (n
+			  && (n->value & GOVD_DATA_SHARE_CLASS) != GOVD_SHARED
+			  && (n->value & GOVD_DATA_SHARE_CLASS) != 0)
+			break;
+		    }
+		  is_declare_target = octx == NULL;
+		}
+	      if (!is_declare_target && ctx->target_map_scalars_firstprivate)
+		{
+		  tree type = TREE_TYPE (decl);
+		  if (TREE_CODE (type) == REFERENCE_TYPE)
+		    type = TREE_TYPE (type);
+		  if (TREE_CODE (type) == COMPLEX_TYPE)
+		    type = TREE_TYPE (type);
+		  if (INTEGRAL_TYPE_P (type)
+		      || SCALAR_FLOAT_TYPE_P (type)
+		      || TREE_CODE (type) == POINTER_TYPE)
+		    is_scalar = true;
+		}
+	      if (is_declare_target)
+		;
+	      else if (ctx->target_map_pointers_as_0len_arrays
+		       && (TREE_CODE (TREE_TYPE (decl)) == POINTER_TYPE
+			   || (TREE_CODE (TREE_TYPE (decl)) == REFERENCE_TYPE
+			       && TREE_CODE (TREE_TYPE (TREE_TYPE (decl)))
+				  == POINTER_TYPE)))
+		nflags |= GOVD_MAP | GOVD_MAP_0LEN_ARRAY;
+	      else if (is_scalar)
+		nflags |= GOVD_FIRSTPRIVATE;
+	    }
+	  if (nflags == flags
+	      && !lang_hooks.types.omp_mappable_type (TREE_TYPE (decl)))
 	    {
 	      error ("%qD referenced in target region does not have "
 		     "a mappable type", decl);
-	      omp_add_variable (ctx, decl, GOVD_MAP | GOVD_EXPLICIT | flags);
+	      nflags |= GOVD_MAP | GOVD_EXPLICIT;
 	    }
-	  else
-	    omp_add_variable (ctx, decl, GOVD_MAP | flags);
+	  else if (nflags == flags)
+	    nflags |= GOVD_MAP;
+	  omp_add_variable (ctx, decl, nflags);
 	}
       else
 	{
@@ -6144,6 +6205,24 @@ gimplify_scan_omp_clauses (tree *list_p,
 
   ctx = new_omp_context (region_type);
   outer_ctx = ctx->outer_context;
+  if (code == OMP_TARGET && !lang_GNU_Fortran ())
+    {
+      ctx->target_map_pointers_as_0len_arrays = true;
+      /* FIXME: For Fortran we want to set this too, when
+	 the Fortran FE is updated to OpenMP 4.1.  */
+      ctx->target_map_scalars_firstprivate = true;
+    }
+  if (!lang_GNU_Fortran ())
+    switch (code)
+      {
+      case OMP_TARGET:
+      case OMP_TARGET_DATA:
+      case OMP_TARGET_ENTER_DATA:
+      case OMP_TARGET_EXIT_DATA:
+	ctx->target_firstprivatize_array_bases = true;
+      default:
+	break;
+      }
 
   while ((c = *list_p) != NULL)
     {
@@ -6290,11 +6369,18 @@ gimplify_scan_omp_clauses (tree *list_p,
 			   && ctx->region_type == ORT_WORKSHARE
 			   && octx == outer_ctx)
 		    flags = GOVD_SEEN | GOVD_SHARED;
+		  else if (octx
+			   && octx->region_type == ORT_COMBINED_TARGET)
+		    flags &= ~GOVD_LASTPRIVATE;
 		  else
 		    break;
-		  gcc_checking_assert (splay_tree_lookup (octx->variables,
-							  (splay_tree_key)
-							  decl) == NULL);
+		  splay_tree_node on
+		    = splay_tree_lookup (octx->variables,
+					 (splay_tree_key) decl);
+		  gcc_assert (on == NULL
+			      || (octx->region_type == ORT_COMBINED_TARGET
+				  && (on->value
+				      & GOVD_DATA_SHARE_CLASS) == 0));
 		  omp_add_variable (octx, decl, flags);
 		  if (octx->outer_context == NULL)
 		    break;
@@ -6319,10 +6405,24 @@ gimplify_scan_omp_clauses (tree *list_p,
 	case OMP_CLAUSE_MAP:
 	  decl = OMP_CLAUSE_DECL (c);
 	  if (error_operand_p (decl))
+	    remove = true;
+	  switch (code)
 	    {
-	      remove = true;
+	    case OMP_TARGET:
+	      break;
+	    case OMP_TARGET_DATA:
+	    case OMP_TARGET_ENTER_DATA:
+	    case OMP_TARGET_EXIT_DATA:
+	      if (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_FIRSTPRIVATE_POINTER)
+		/* For target {,enter ,exit }data only the array slice is
+		   mapped, but not the pointer to it.  */
+		remove = true;
+	      break;
+	    default:
 	      break;
 	    }
+	  if (remove)
+	    break;
 	  if (OMP_CLAUSE_SIZE (c) == NULL_TREE)
 	    OMP_CLAUSE_SIZE (c) = DECL_P (decl) ? DECL_SIZE_UNIT (decl)
 				  : TYPE_SIZE_UNIT (TREE_TYPE (decl));
@@ -6332,6 +6432,14 @@ gimplify_scan_omp_clauses (tree *list_p,
 	      remove = true;
 	      break;
 	    }
+	  else if (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_FIRSTPRIVATE_POINTER
+		   && TREE_CODE (OMP_CLAUSE_SIZE (c)) != INTEGER_CST)
+	    {
+	      OMP_CLAUSE_SIZE (c)
+		= get_initialized_tmp_var (OMP_CLAUSE_SIZE (c), pre_p, NULL);
+	      omp_add_variable (ctx, OMP_CLAUSE_SIZE (c),
+				GOVD_FIRSTPRIVATE | GOVD_SEEN);
+	    }
 	  if (!DECL_P (decl))
 	    {
 	      if (gimplify_expr (&OMP_CLAUSE_DECL (c), pre_p,
@@ -6643,7 +6751,10 @@ gimplify_scan_omp_clauses (tree *list_p,
 	case OMP_CLAUSE_NOGROUP:
 	case OMP_CLAUSE_THREADS:
 	case OMP_CLAUSE_SIMD:
+	  break;
+
 	case OMP_CLAUSE_DEFAULTMAP:
+	  ctx->target_map_scalars_firstprivate = false;
 	  break;
 
 	case OMP_CLAUSE_ALIGNED:
@@ -6759,6 +6870,29 @@ gimplify_adjust_omp_clauses_1 (splay_tre
     OMP_CLAUSE_PRIVATE_DEBUG (clause) = 1;
   else if (code == OMP_CLAUSE_PRIVATE && (flags & GOVD_PRIVATE_OUTER_REF))
     OMP_CLAUSE_PRIVATE_OUTER_REF (clause) = 1;
+  else if (code == OMP_CLAUSE_MAP && (flags & GOVD_MAP_0LEN_ARRAY) != 0)
+    {
+      tree nc = build_omp_clause (input_location, OMP_CLAUSE_MAP);
+      OMP_CLAUSE_DECL (nc) = decl;
+      if (TREE_CODE (TREE_TYPE (decl)) == REFERENCE_TYPE
+	  && TREE_CODE (TREE_TYPE (TREE_TYPE (decl))) == POINTER_TYPE)
+	OMP_CLAUSE_DECL (clause)
+	  = build_simple_mem_ref_loc (input_location, decl);
+      OMP_CLAUSE_DECL (clause)
+	= build2 (MEM_REF, char_type_node, OMP_CLAUSE_DECL (clause),
+		  build_int_cst (build_pointer_type (char_type_node), 0));
+      OMP_CLAUSE_SIZE (clause) = size_zero_node;
+      OMP_CLAUSE_SIZE (nc) = size_zero_node;
+      OMP_CLAUSE_SET_MAP_KIND (clause, GOMP_MAP_ALLOC);
+      OMP_CLAUSE_SET_MAP_KIND (nc, GOMP_MAP_FIRSTPRIVATE_POINTER);
+      OMP_CLAUSE_CHAIN (nc) = *list_p;
+      OMP_CLAUSE_CHAIN (clause) = nc;
+      struct gimplify_omp_ctx *ctx = gimplify_omp_ctxp;
+      gimplify_omp_ctxp = ctx->outer_context;
+      gimplify_expr (&TREE_OPERAND (OMP_CLAUSE_DECL (clause), 0),
+		     pre_p, NULL, is_gimple_val, fb_rvalue);
+      gimplify_omp_ctxp = ctx;
+    }
   else if (code == OMP_CLAUSE_MAP)
     {
       OMP_CLAUSE_SET_MAP_KIND (clause,
@@ -6785,7 +6919,10 @@ gimplify_adjust_omp_clauses_1 (splay_tre
 				      OMP_CLAUSE_MAP);
 	  OMP_CLAUSE_DECL (nc) = decl;
 	  OMP_CLAUSE_SIZE (nc) = size_zero_node;
-	  OMP_CLAUSE_SET_MAP_KIND (nc, GOMP_MAP_POINTER);
+	  if (gimplify_omp_ctxp->target_firstprivatize_array_bases)
+	    OMP_CLAUSE_SET_MAP_KIND (nc, GOMP_MAP_FIRSTPRIVATE_POINTER);
+	  else
+	    OMP_CLAUSE_SET_MAP_KIND (nc, GOMP_MAP_POINTER);
 	  OMP_CLAUSE_CHAIN (nc) = OMP_CLAUSE_CHAIN (clause);
 	  OMP_CLAUSE_CHAIN (clause) = nc;
 	}
@@ -6910,12 +7047,14 @@ gimplify_adjust_omp_clauses (gimple_seq
 	  if (!DECL_P (decl))
 	    break;
 	  n = splay_tree_lookup (ctx->variables, (splay_tree_key) decl);
-	  if (ctx->region_type == ORT_TARGET && !(n->value & GOVD_SEEN)
+	  if ((ctx->region_type & ORT_TARGET) != 0
+	      && !(n->value & GOVD_SEEN)
 	      && !(OMP_CLAUSE_MAP_KIND (c) & GOMP_MAP_FLAG_ALWAYS))
 	    remove = true;
 	  else if (DECL_SIZE (decl)
 		   && TREE_CODE (DECL_SIZE (decl)) != INTEGER_CST
-		   && OMP_CLAUSE_MAP_KIND (c) != GOMP_MAP_POINTER)
+		   && OMP_CLAUSE_MAP_KIND (c) != GOMP_MAP_POINTER
+		   && OMP_CLAUSE_MAP_KIND (c) != GOMP_MAP_FIRSTPRIVATE_POINTER)
 	    {
 	      /* For GOMP_MAP_FORCE_DEVICEPTR, we'll never enter here, because
 		 for these, TREE_CODE (DECL_SIZE (decl)) will always be
@@ -6935,17 +7074,33 @@ gimplify_adjust_omp_clauses (gimple_seq
 		  omp_notice_variable (ctx->outer_context,
 				       OMP_CLAUSE_SIZE (c), true);
 		}
-	      tree nc = build_omp_clause (OMP_CLAUSE_LOCATION (c),
-					  OMP_CLAUSE_MAP);
-	      OMP_CLAUSE_DECL (nc) = decl;
-	      OMP_CLAUSE_SIZE (nc) = size_zero_node;
-	      OMP_CLAUSE_SET_MAP_KIND (nc, GOMP_MAP_POINTER);
-	      OMP_CLAUSE_CHAIN (nc) = OMP_CLAUSE_CHAIN (c);
-	      OMP_CLAUSE_CHAIN (c) = nc;
-	      c = nc;
+	      if (((ctx->region_type & ORT_TARGET) != 0
+		   || !ctx->target_firstprivatize_array_bases)
+		  && ((n->value & GOVD_SEEN) == 0
+		      || (n->value & (GOVD_PRIVATE | GOVD_FIRSTPRIVATE)) == 0))
+		{
+		  tree nc = build_omp_clause (OMP_CLAUSE_LOCATION (c),
+					      OMP_CLAUSE_MAP);
+		  OMP_CLAUSE_DECL (nc) = decl;
+		  OMP_CLAUSE_SIZE (nc) = size_zero_node;
+		  if (ctx->target_firstprivatize_array_bases)
+		    OMP_CLAUSE_SET_MAP_KIND (nc,
+					     GOMP_MAP_FIRSTPRIVATE_POINTER);
+		  else
+		    OMP_CLAUSE_SET_MAP_KIND (nc, GOMP_MAP_POINTER);
+		  OMP_CLAUSE_CHAIN (nc) = OMP_CLAUSE_CHAIN (c);
+		  OMP_CLAUSE_CHAIN (c) = nc;
+		  c = nc;
+		}
+	    }
+	  else
+	    {
+	      if (OMP_CLAUSE_SIZE (c) == NULL_TREE)
+		OMP_CLAUSE_SIZE (c) = DECL_SIZE_UNIT (decl);
+	      if ((n->value & GOVD_SEEN)
+		  && (n->value & (GOVD_PRIVATE | GOVD_FIRSTPRIVATE)))
+		OMP_CLAUSE_MAP_PRIVATE (c) = 1;
 	    }
-	  else if (OMP_CLAUSE_SIZE (c) == NULL_TREE)
-	    OMP_CLAUSE_SIZE (c) = DECL_SIZE_UNIT (decl);
 	  break;
 
 	case OMP_CLAUSE_TO:
@@ -7888,9 +8043,11 @@ gimplify_omp_workshare (tree *expr_p, gi
     case OMP_SINGLE:
       ort = ORT_WORKSHARE;
       break;
+    case OMP_TARGET:
+      ort = OMP_TARGET_COMBINED (expr) ? ORT_COMBINED_TARGET : ORT_TARGET;
+      break;
     case OACC_KERNELS:
     case OACC_PARALLEL:
-    case OMP_TARGET:
       ort = ORT_TARGET;
       break;
     case OACC_DATA:
@@ -7905,7 +8062,7 @@ gimplify_omp_workshare (tree *expr_p, gi
     }
   gimplify_scan_omp_clauses (&OMP_CLAUSES (expr), pre_p, ort,
 			     TREE_CODE (expr));
-  if (ort == ORT_TARGET || ort == ORT_TARGET_DATA)
+  if ((ort & (ORT_TARGET | ORT_TARGET_DATA)) != 0)
     {
       push_gimplify_context ();
       gimple g = gimplify_and_return_first (OMP_BODY (expr), &body);
--- gcc/c/c-tree.h.jj	2015-07-01 12:50:49.000000000 +0200
+++ gcc/c/c-tree.h	2015-07-22 12:47:49.185826677 +0200
@@ -649,7 +649,7 @@ extern tree c_begin_omp_task (void);
 extern tree c_finish_omp_task (location_t, tree, tree);
 extern void c_finish_omp_cancel (location_t, tree);
 extern void c_finish_omp_cancellation_point (location_t, tree);
-extern tree c_finish_omp_clauses (tree, bool = false);
+extern tree c_finish_omp_clauses (tree, bool, bool = false);
 extern tree c_build_va_arg (location_t, tree, tree);
 extern tree c_finish_transaction (location_t, tree, int);
 extern bool c_tree_equal (tree, tree);
--- gcc/c/c-typeck.c.jj	2015-07-17 13:06:58.000000000 +0200
+++ gcc/c/c-typeck.c	2015-07-22 13:00:21.130399057 +0200
@@ -11850,7 +11850,7 @@ handle_omp_array_sections_1 (tree c, tre
 /* Handle array sections for clause C.  */
 
 static bool
-handle_omp_array_sections (tree c)
+handle_omp_array_sections (tree c, bool is_omp)
 {
   bool maybe_zero_len = false;
   unsigned int first_non_one = 0;
@@ -12031,8 +12031,10 @@ handle_omp_array_sections (tree c)
 	return false;
       gcc_assert (OMP_CLAUSE_MAP_KIND (c) != GOMP_MAP_FORCE_DEVICEPTR);
       tree c2 = build_omp_clause (OMP_CLAUSE_LOCATION (c), OMP_CLAUSE_MAP);
-      OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_POINTER);
-      if (!c_mark_addressable (t))
+      OMP_CLAUSE_SET_MAP_KIND (c2, is_omp
+				   ? GOMP_MAP_FIRSTPRIVATE_POINTER
+				   : GOMP_MAP_POINTER);
+      if (!is_omp && !c_mark_addressable (t))
 	return false;
       OMP_CLAUSE_DECL (c2) = t;
       t = build_fold_addr_expr (first);
@@ -12097,7 +12099,7 @@ c_find_omp_placeholder_r (tree *tp, int
    Remove any elements from the list that are invalid.  */
 
 tree
-c_finish_omp_clauses (tree clauses, bool declare_simd)
+c_finish_omp_clauses (tree clauses, bool is_omp, bool declare_simd)
 {
   bitmap_head generic_head, firstprivate_head, lastprivate_head;
   bitmap_head aligned_head, map_head;
@@ -12136,7 +12138,7 @@ c_finish_omp_clauses (tree clauses, bool
 	  t = OMP_CLAUSE_DECL (c);
 	  if (TREE_CODE (t) == TREE_LIST)
 	    {
-	      if (handle_omp_array_sections (c))
+	      if (handle_omp_array_sections (c, is_omp))
 		{
 		  remove = true;
 		  break;
@@ -12496,7 +12498,7 @@ c_finish_omp_clauses (tree clauses, bool
 	    }
 	  if (TREE_CODE (t) == TREE_LIST)
 	    {
-	      if (handle_omp_array_sections (c))
+	      if (handle_omp_array_sections (c, is_omp))
 		remove = true;
 	      break;
 	    }
@@ -12519,7 +12521,7 @@ c_finish_omp_clauses (tree clauses, bool
 	  t = OMP_CLAUSE_DECL (c);
 	  if (TREE_CODE (t) == TREE_LIST)
 	    {
-	      if (handle_omp_array_sections (c))
+	      if (handle_omp_array_sections (c, is_omp))
 		remove = true;
 	      else
 		{
@@ -12556,6 +12558,8 @@ c_finish_omp_clauses (tree clauses, bool
 	  else if (!(OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
 		     && (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_POINTER
 			 || (OMP_CLAUSE_MAP_KIND (c)
+			     == GOMP_MAP_FIRSTPRIVATE_POINTER)
+			 || (OMP_CLAUSE_MAP_KIND (c)
 			     == GOMP_MAP_FORCE_DEVICEPTR)))
 		   && !lang_hooks.types.omp_mappable_type (TREE_TYPE (t)))
 	    {
--- gcc/c/c-parser.c.jj	2015-07-21 09:06:42.000000000 +0200
+++ gcc/c/c-parser.c	2015-07-23 12:51:02.636583031 +0200
@@ -12435,7 +12435,7 @@ c_parser_oacc_all_clauses (c_parser *par
   c_parser_skip_to_pragma_eol (parser);
 
   if (finish_p)
-    return c_finish_omp_clauses (clauses);
+    return c_finish_omp_clauses (clauses, false);
 
   return clauses;
 }
@@ -12720,8 +12720,8 @@ c_parser_omp_all_clauses (c_parser *pars
   if (finish_p)
     {
       if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_UNIFORM)) != 0)
-	return c_finish_omp_clauses (clauses, true);
-      return c_finish_omp_clauses (clauses);
+	return c_finish_omp_clauses (clauses, true, true);
+      return c_finish_omp_clauses (clauses, true);
     }
 
   return clauses;
@@ -12755,7 +12755,7 @@ c_parser_oacc_cache (location_t loc, c_p
   tree stmt, clauses;
 
   clauses = c_parser_omp_var_list_parens (parser, OMP_CLAUSE__CACHE_, NULL);
-  clauses = c_finish_omp_clauses (clauses);
+  clauses = c_finish_omp_clauses (clauses, false);
 
   c_parser_skip_to_pragma_eol (parser);
 
@@ -13902,7 +13902,7 @@ omp_split_clauses (location_t loc, enum
   c_omp_split_clauses (loc, code, mask, clauses, cclauses);
   for (i = 0; i < C_OMP_CLAUSE_SPLIT_COUNT; i++)
     if (cclauses[i])
-      cclauses[i] = c_finish_omp_clauses (cclauses[i]);
+      cclauses[i] = c_finish_omp_clauses (cclauses[i], true);
 }
 
 /* OpenMP 4.0:
@@ -14668,9 +14668,10 @@ c_parser_omp_target_data (location_t loc
 	  case GOMP_MAP_TOFROM:
 	  case GOMP_MAP_ALWAYS_TOFROM:
 	  case GOMP_MAP_ALLOC:
-	  case GOMP_MAP_POINTER:
 	    map_seen = 3;
 	    break;
+	  case GOMP_MAP_FIRSTPRIVATE_POINTER:
+	    break;
 	  default:
 	    map_seen |= 1;
 	    error_at (OMP_CLAUSE_LOCATION (*pc),
@@ -14800,9 +14801,10 @@ c_parser_omp_target_enter_data (location
 	  case GOMP_MAP_TO:
 	  case GOMP_MAP_ALWAYS_TO:
 	  case GOMP_MAP_ALLOC:
-	  case GOMP_MAP_POINTER:
 	    map_seen = 3;
 	    break;
+	  case GOMP_MAP_FIRSTPRIVATE_POINTER:
+	    break;
 	  default:
 	    map_seen |= 1;
 	    error_at (OMP_CLAUSE_LOCATION (*pc),
@@ -14885,9 +14887,10 @@ c_parser_omp_target_exit_data (location_
 	  case GOMP_MAP_ALWAYS_FROM:
 	  case GOMP_MAP_RELEASE:
 	  case GOMP_MAP_DELETE:
-	  case GOMP_MAP_POINTER:
 	    map_seen = 3;
 	    break;
+	  case GOMP_MAP_FIRSTPRIVATE_POINTER:
+	    break;
 	  default:
 	    map_seen |= 1;
 	    error_at (OMP_CLAUSE_LOCATION (*pc),
@@ -15016,6 +15019,7 @@ c_parser_omp_target (c_parser *parser, e
 	  TREE_TYPE (stmt) = void_type_node;
 	  OMP_TARGET_CLAUSES (stmt) = cclauses[C_OMP_CLAUSE_SPLIT_TARGET];
 	  OMP_TARGET_BODY (stmt) = block;
+	  OMP_TARGET_COMBINED (stmt) = 1;
 	  add_stmt (stmt);
 	  pc = &OMP_TARGET_CLAUSES (stmt);
 	  goto check_clauses;
@@ -15078,7 +15082,7 @@ check_clauses:
 	  case GOMP_MAP_TOFROM:
 	  case GOMP_MAP_ALWAYS_TOFROM:
 	  case GOMP_MAP_ALLOC:
-	  case GOMP_MAP_POINTER:
+	  case GOMP_MAP_FIRSTPRIVATE_POINTER:
 	    break;
 	  default:
 	    error_at (OMP_CLAUSE_LOCATION (*pc),
@@ -16379,7 +16383,7 @@ c_parser_cilk_for (c_parser *parser, tre
   tree clauses = build_omp_clause (EXPR_LOCATION (grain), OMP_CLAUSE_SCHEDULE);
   OMP_CLAUSE_SCHEDULE_KIND (clauses) = OMP_CLAUSE_SCHEDULE_CILKFOR;
   OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (clauses) = grain;
-  clauses = c_finish_omp_clauses (clauses);
+  clauses = c_finish_omp_clauses (clauses, false);
 
   tree block = c_begin_compound_stmt (true);
   tree sb = push_stmt_list ();
@@ -16444,7 +16448,7 @@ c_parser_cilk_for (c_parser *parser, tre
       OMP_CLAUSE_OPERAND (c, 0)
 	= cilk_for_number_of_iterations (omp_for);
       OMP_CLAUSE_CHAIN (c) = clauses;
-      OMP_PARALLEL_CLAUSES (omp_par) = c_finish_omp_clauses (c);
+      OMP_PARALLEL_CLAUSES (omp_par) = c_finish_omp_clauses (c, true);
       add_stmt (omp_par);
     }
 
--- gcc/tree-core.h.jj	2015-07-17 09:30:44.000000000 +0200
+++ gcc/tree-core.h	2015-07-21 16:28:48.524156167 +0200
@@ -1354,7 +1354,7 @@ struct GTY(()) tree_omp_clause {
     enum omp_clause_schedule_kind  schedule_kind;
     enum omp_clause_depend_kind    depend_kind;
     /* See include/gomp-constants.h for enum gomp_map_kind's values.  */
-    unsigned char		   map_kind;
+    unsigned int		   map_kind;
     enum omp_clause_proc_bind_kind proc_bind_kind;
     enum tree_code                 reduction_code;
     enum omp_clause_linear_kind    linear_kind;
--- gcc/omp-low.c.jj	2015-07-21 09:07:23.000000000 +0200
+++ gcc/omp-low.c	2015-07-24 18:12:01.474522499 +0200
@@ -1071,24 +1071,35 @@ lookup_field (tree var, omp_context *ctx
 }
 
 static inline tree
-lookup_sfield (tree var, omp_context *ctx)
+lookup_sfield (splay_tree_key key, omp_context *ctx)
 {
   splay_tree_node n;
   n = splay_tree_lookup (ctx->sfield_map
-			 ? ctx->sfield_map : ctx->field_map,
-			 (splay_tree_key) var);
+			 ? ctx->sfield_map : ctx->field_map, key);
   return (tree) n->value;
 }
 
 static inline tree
-maybe_lookup_field (tree var, omp_context *ctx)
+lookup_sfield (tree var, omp_context *ctx)
+{
+  return lookup_sfield ((splay_tree_key) var, ctx);
+}
+
+static inline tree
+maybe_lookup_field (splay_tree_key key, omp_context *ctx)
 {
   splay_tree_node n;
-  n = splay_tree_lookup (ctx->field_map, (splay_tree_key) var);
+  n = splay_tree_lookup (ctx->field_map, key);
   return n ? (tree) n->value : NULL_TREE;
 }
 
 static inline tree
+maybe_lookup_field (tree var, omp_context *ctx)
+{
+  return maybe_lookup_field ((splay_tree_key) var, ctx);
+}
+
+static inline tree
 lookup_oacc_reduction (const char *id, omp_context *ctx)
 {
   splay_tree_node n;
@@ -1359,12 +1370,18 @@ build_outer_var_ref (tree var, omp_conte
 /* Build tree nodes to access the field for VAR on the sender side.  */
 
 static tree
-build_sender_ref (tree var, omp_context *ctx)
+build_sender_ref (splay_tree_key key, omp_context *ctx)
 {
-  tree field = lookup_sfield (var, ctx);
+  tree field = lookup_sfield (key, ctx);
   return omp_build_component_ref (ctx->sender_decl, field);
 }
 
+static tree
+build_sender_ref (tree var, omp_context *ctx)
+{
+  return build_sender_ref ((splay_tree_key) var, ctx);
+}
+
 /* Add a new field for VAR inside the structure CTX->SENDER_DECL.  */
 
 static void
@@ -1908,6 +1925,10 @@ scan_sharing_clauses (tree clauses, omp_
 	case OMP_CLAUSE_LINEAR:
 	  decl = OMP_CLAUSE_DECL (c);
 	do_private:
+	  if ((OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FIRSTPRIVATE
+	       || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IS_DEVICE_PTR)
+	      && is_gimple_omp_offloaded (ctx->stmt))
+	    install_var_field (decl, !is_reference (decl), 3, ctx);
 	  if (is_variable_sized (decl))
 	    {
 	      if (is_task_ctx (ctx))
@@ -1930,10 +1951,6 @@ scan_sharing_clauses (tree clauses, omp_
 	      else if (!global)
 		install_var_field (decl, by_ref, 3, ctx);
 	    }
-	  else if ((OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FIRSTPRIVATE
-		    || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IS_DEVICE_PTR)
-		   && is_gimple_omp_offloaded (ctx->stmt))
-	    install_var_field (decl, !is_reference (decl), 3, ctx);
 	  install_var_local (decl, ctx);
 	  if (is_gimple_omp_oacc (ctx->stmt)
 	      && OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION)
@@ -2025,6 +2042,21 @@ scan_sharing_clauses (tree clauses, omp_
 		  && !OMP_CLAUSE_MAP_ZERO_BIAS_ARRAY_SECTION (c))
 		break;
 	    }
+	  if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
+	      && OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_FIRSTPRIVATE_POINTER)
+	    {
+	      if (DECL_SIZE (decl)
+		  && TREE_CODE (DECL_SIZE (decl)) != INTEGER_CST)
+		{
+		  tree decl2 = DECL_VALUE_EXPR (decl);
+		  gcc_assert (TREE_CODE (decl2) == INDIRECT_REF);
+		  decl2 = TREE_OPERAND (decl2, 0);
+		  gcc_assert (DECL_P (decl2));
+		  install_var_local (decl2, ctx);
+		}
+	      install_var_local (decl, ctx);
+	      break;
+	    }
 	  if (DECL_P (decl))
 	    {
 	      if (DECL_SIZE (decl)
@@ -2034,7 +2066,11 @@ scan_sharing_clauses (tree clauses, omp_
 		  gcc_assert (TREE_CODE (decl2) == INDIRECT_REF);
 		  decl2 = TREE_OPERAND (decl2, 0);
 		  gcc_assert (DECL_P (decl2));
-		  install_var_field (decl2, true, 3, ctx);
+		  if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
+		      && OMP_CLAUSE_MAP_PRIVATE (c))
+		    install_var_field (decl2, true, 11, ctx);
+		  else
+		    install_var_field (decl2, true, 3, ctx);
 		  install_var_local (decl2, ctx);
 		  install_var_local (decl, ctx);
 		}
@@ -2045,6 +2081,9 @@ scan_sharing_clauses (tree clauses, omp_
 		      && !OMP_CLAUSE_MAP_ZERO_BIAS_ARRAY_SECTION (c)
 		      && TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE)
 		    install_var_field (decl, true, 7, ctx);
+		  else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
+			   && OMP_CLAUSE_MAP_PRIVATE (c))
+		    install_var_field (decl, true, 11, ctx);
 		  else
 		    install_var_field (decl, true, 3, ctx);
 		  if (is_gimple_omp_offloaded (ctx->stmt))
@@ -2151,7 +2190,19 @@ scan_sharing_clauses (tree clauses, omp_
 	case OMP_CLAUSE_IS_DEVICE_PTR:
 	  decl = OMP_CLAUSE_DECL (c);
 	  if (is_variable_sized (decl))
-	    install_var_local (decl, ctx);
+	    {
+	      if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FIRSTPRIVATE
+		  && is_gimple_omp_offloaded (ctx->stmt))
+		{
+		  tree decl2 = DECL_VALUE_EXPR (decl);
+		  gcc_assert (TREE_CODE (decl2) == INDIRECT_REF);
+		  decl2 = TREE_OPERAND (decl2, 0);
+		  gcc_assert (DECL_P (decl2));
+		  install_var_local (decl2, ctx);
+		  fixup_remapped_decl (decl2, ctx, false);
+		}
+	      install_var_local (decl, ctx);
+	    }
 	  fixup_remapped_decl (decl, ctx,
 			       OMP_CLAUSE_CODE (c) == OMP_CLAUSE_PRIVATE
 			       && OMP_CLAUSE_PRIVATE_DEBUG (c));
@@ -2201,7 +2252,8 @@ scan_sharing_clauses (tree clauses, omp_
 	    break;
 	  if (DECL_P (decl))
 	    {
-	      if (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_POINTER
+	      if ((OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_POINTER
+		   || OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_FIRSTPRIVATE_POINTER)
 		  && TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE
 		  && !COMPLETE_TYPE_P (TREE_TYPE (decl)))
 		{
@@ -3924,11 +3976,8 @@ handle_simd_reference (location_t loc, t
   tree z = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (new_vard)));
   if (TREE_CONSTANT (z))
     {
-      const char *name = NULL;
-      if (DECL_NAME (new_vard))
-	name = IDENTIFIER_POINTER (DECL_NAME (new_vard));
-
-      z = create_tmp_var_raw (TREE_TYPE (TREE_TYPE (new_vard)), name);
+      z = create_tmp_var_raw (TREE_TYPE (TREE_TYPE (new_vard)),
+			      get_name (new_vard));
       gimple_add_tmp_var (z);
       TREE_ADDRESSABLE (z) = 1;
       z = build_fold_addr_expr_loc (loc, z);
@@ -4127,9 +4176,7 @@ lower_rec_input_clauses (tree clauses, g
 	      tree type = TREE_TYPE (d);
 	      gcc_assert (TREE_CODE (type) == ARRAY_TYPE);
 	      tree v = TYPE_MAX_VALUE (TYPE_DOMAIN (type));
-	      const char *name = NULL;
-	      if (DECL_NAME (orig_var))
-		name = IDENTIFIER_POINTER (DECL_NAME (orig_var));
+	      const char *name = get_name (orig_var);
 	      if (TREE_CONSTANT (v))
 		{
 		  x = create_tmp_var_raw (type, name);
@@ -4139,7 +4186,8 @@ lower_rec_input_clauses (tree clauses, g
 		}
 	      else
 		{
-		  tree atmp = builtin_decl_explicit (BUILT_IN_ALLOCA);
+		  tree atmp
+		    = builtin_decl_explicit (BUILT_IN_ALLOCA_WITH_ALIGN);
 		  tree t = maybe_lookup_decl (v, ctx);
 		  if (t)
 		    v = t;
@@ -4152,7 +4200,8 @@ lower_rec_input_clauses (tree clauses, g
 		  t = fold_build2_loc (clause_loc, MULT_EXPR,
 				       TREE_TYPE (v), t,
 				       TYPE_SIZE_UNIT (TREE_TYPE (type)));
-		  x = build_call_expr_loc (clause_loc, atmp, 1, t);
+		  tree al = size_int (TYPE_ALIGN (TREE_TYPE (type)));
+		  x = build_call_expr_loc (clause_loc, atmp, 2, t, al);
 		}
 
 	      tree ptype = build_pointer_type (TREE_TYPE (type));
@@ -4362,8 +4411,9 @@ lower_rec_input_clauses (tree clauses, g
 		  x = TYPE_SIZE_UNIT (TREE_TYPE (new_var));
 
 		  /* void *tmp = __builtin_alloca */
-		  atmp = builtin_decl_explicit (BUILT_IN_ALLOCA);
-		  stmt = gimple_build_call (atmp, 1, x);
+		  atmp = builtin_decl_explicit (BUILT_IN_ALLOCA_WITH_ALIGN);
+		  stmt = gimple_build_call (atmp, 2, x,
+					    size_int (DECL_ALIGN (var)));
 		  tmp = create_tmp_var_raw (ptr_type_node);
 		  gimple_add_tmp_var (tmp);
 		  gimple_call_set_lhs (stmt, tmp);
@@ -4400,12 +4450,8 @@ lower_rec_input_clauses (tree clauses, g
 		    x = NULL_TREE;
 		  else
 		    {
-		      const char *name = NULL;
-		      if (DECL_NAME (var))
-			name = IDENTIFIER_POINTER (DECL_NAME (new_var));
-
 		      x = create_tmp_var_raw (TREE_TYPE (TREE_TYPE (new_var)),
-					      name);
+					      get_name (var));
 		      gimple_add_tmp_var (x);
 		      TREE_ADDRESSABLE (x) = 1;
 		      x = build_fold_addr_expr_loc (clause_loc, x);
@@ -4413,8 +4459,11 @@ lower_rec_input_clauses (tree clauses, g
 		}
 	      else
 		{
-		  tree atmp = builtin_decl_explicit (BUILT_IN_ALLOCA);
-		  x = build_call_expr_loc (clause_loc, atmp, 1, x);
+		  tree atmp
+		    = builtin_decl_explicit (BUILT_IN_ALLOCA_WITH_ALIGN);
+		  tree rtype = TREE_TYPE (TREE_TYPE (new_var));
+		  tree al = size_int (TYPE_ALIGN (rtype));
+		  x = build_call_expr_loc (clause_loc, atmp, 2, x, al);
 		}
 
 	      if (x)
@@ -5489,11 +5538,7 @@ lower_send_clauses (tree clauses, gimple
 	  /* Handle taskloop firstprivate/lastprivate, where the
 	     lastprivate on GIMPLE_OMP_TASK is represented as
 	     OMP_CLAUSE_SHARED_FIRSTPRIVATE.  */
-	  tree f
-	    = (tree)
-	      splay_tree_lookup (ctx->sfield_map
-				 ? ctx->sfield_map : ctx->field_map,
-				 (splay_tree_key) &DECL_UID (val))->value;
+	  tree f = lookup_sfield ((splay_tree_key) &DECL_UID (val), ctx);
 	  x = omp_build_component_ref (ctx->sender_decl, f);
 	  if (use_pointer_for_field (val, ctx))
 	    var = build_fold_addr_expr (var);
@@ -12883,6 +12928,7 @@ lower_omp_target (gimple_stmt_iterator *
 	  case GOMP_MAP_ALWAYS_TO:
 	  case GOMP_MAP_ALWAYS_FROM:
 	  case GOMP_MAP_ALWAYS_TOFROM:
+	  case GOMP_MAP_FIRSTPRIVATE_POINTER:
 	    break;
 	  case GOMP_MAP_FORCE_ALLOC:
 	  case GOMP_MAP_FORCE_TO:
@@ -12918,6 +12964,28 @@ lower_omp_target (gimple_stmt_iterator *
 	    var = var2;
 	  }
 
+	if (offloaded
+	    && OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_FIRSTPRIVATE_POINTER)
+	  {
+	    if (TREE_CODE (TREE_TYPE (var)) == ARRAY_TYPE)
+	      {
+		tree type = build_pointer_type (TREE_TYPE (var));
+		tree new_var = lookup_decl (var, ctx);
+		x = create_tmp_var_raw (type, get_name (new_var));
+		gimple_add_tmp_var (x);
+		x = build_simple_mem_ref (x);
+		SET_DECL_VALUE_EXPR (new_var, x);
+		DECL_HAS_VALUE_EXPR_P (new_var) = 1;
+	      }
+	    continue;
+	  }
+
+	if (offloaded && OMP_CLAUSE_MAP_PRIVATE (c))
+	  {
+	    map_cnt++;
+	    continue;
+	  }
+
 	if (!maybe_lookup_field (var, ctx))
 	  continue;
 
@@ -12925,6 +12993,7 @@ lower_omp_target (gimple_stmt_iterator *
 	  {
 	    x = build_receiver_ref (var, true, ctx);
 	    tree new_var = lookup_decl (var, ctx);
+
 	    if (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_POINTER
 		&& !OMP_CLAUSE_MAP_ZERO_BIAS_ARRAY_SECTION (c)
 		&& TREE_CODE (TREE_TYPE (var)) == ARRAY_TYPE)
@@ -12942,8 +13011,36 @@ lower_omp_target (gimple_stmt_iterator *
 	if (!is_reference (var)
 	    && !is_gimple_reg_type (TREE_TYPE (var)))
 	  {
-	    x = build_receiver_ref (var, true, ctx);
 	    tree new_var = lookup_decl (var, ctx);
+	    if (is_variable_sized (var))
+	      {
+		tree pvar = DECL_VALUE_EXPR (var);
+		gcc_assert (TREE_CODE (pvar) == INDIRECT_REF);
+		pvar = TREE_OPERAND (pvar, 0);
+		gcc_assert (DECL_P (pvar));
+		tree new_pvar = lookup_decl (pvar, ctx);
+		x = build_fold_indirect_ref (new_pvar);
+		TREE_THIS_NOTRAP (x) = 1;
+	      }
+	    else
+	      x = build_receiver_ref (var, true, ctx);
+	    SET_DECL_VALUE_EXPR (new_var, x);
+	    DECL_HAS_VALUE_EXPR_P (new_var) = 1;
+	  }
+	break;
+
+      case OMP_CLAUSE_PRIVATE:
+	var = OMP_CLAUSE_DECL (c);
+	if (is_variable_sized (var))
+	  {
+	    tree new_var = lookup_decl (var, ctx);
+	    tree pvar = DECL_VALUE_EXPR (var);
+	    gcc_assert (TREE_CODE (pvar) == INDIRECT_REF);
+	    pvar = TREE_OPERAND (pvar, 0);
+	    gcc_assert (DECL_P (pvar));
+	    tree new_pvar = lookup_decl (pvar, ctx);
+	    x = build_fold_indirect_ref (new_pvar);
+	    TREE_THIS_NOTRAP (x) = 1;
 	    SET_DECL_VALUE_EXPR (new_var, x);
 	    DECL_HAS_VALUE_EXPR_P (new_var) = 1;
 	  }
@@ -13044,6 +13141,10 @@ lower_omp_target (gimple_stmt_iterator *
 	      }
 	    else
 	      {
+		if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
+		    && OMP_CLAUSE_MAP_KIND (c)
+		       == GOMP_MAP_FIRSTPRIVATE_POINTER)
+		  break;
 		if (DECL_SIZE (ovar)
 		    && TREE_CODE (DECL_SIZE (ovar)) != INTEGER_CST)
 		  {
@@ -13053,7 +13154,14 @@ lower_omp_target (gimple_stmt_iterator *
 		    gcc_assert (DECL_P (ovar2));
 		    ovar = ovar2;
 		  }
-		if (!maybe_lookup_field (ovar, ctx))
+		if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
+		    && OMP_CLAUSE_MAP_PRIVATE (c))
+		  {
+		    if (!maybe_lookup_field ((splay_tree_key) &DECL_UID (ovar),
+					     ctx))
+		      continue;
+		  }
+		else if (!maybe_lookup_field (ovar, ctx))
 		  continue;
 	      }
 
@@ -13063,7 +13171,12 @@ lower_omp_target (gimple_stmt_iterator *
 	    if (nc)
 	      {
 		var = lookup_decl_in_outer_ctx (ovar, ctx);
-		x = build_sender_ref (ovar, ctx);
+		if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
+		    && OMP_CLAUSE_MAP_PRIVATE (c))
+		  x = build_sender_ref ((splay_tree_key) &DECL_UID (ovar),
+					ctx);
+		else
+		  x = build_sender_ref (ovar, ctx);
 		if (maybe_lookup_oacc_reduction (var, ctx))
 		  {
 		    gcc_checking_assert (offloaded
@@ -13101,7 +13214,7 @@ lower_omp_target (gimple_stmt_iterator *
 			 || map_kind == GOMP_MAP_FORCE_DEVICEPTR)
 			&& !TYPE_READONLY (TREE_TYPE (var)))
 		      {
-			x = build_sender_ref (ovar, ctx);
+			x = unshare_expr (x);
 			x = build_simple_mem_ref (x);
 			gimplify_assign (var, x, &olist);
 		      }
@@ -13239,6 +13352,7 @@ lower_omp_target (gimple_stmt_iterator *
 
   if (offloaded)
     {
+      tree prev = NULL_TREE;
       for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c))
 	switch (OMP_CLAUSE_CODE (c))
 	  {
@@ -13257,6 +13371,18 @@ lower_omp_target (gimple_stmt_iterator *
 		gimple_seq_add_stmt (&new_body,
 				     gimple_build_assign (new_var, x));
 	      }
+            else if (is_variable_sized (var))
+	      {
+		tree pvar = DECL_VALUE_EXPR (var);
+		gcc_assert (TREE_CODE (pvar) == INDIRECT_REF);
+		pvar = TREE_OPERAND (pvar, 0);
+		gcc_assert (DECL_P (pvar));
+		tree new_var = lookup_decl (pvar, ctx);
+		tree x = build_receiver_ref (var, false, ctx);
+		gimplify_expr (&x, &new_body, NULL, is_gimple_val, fb_rvalue);
+		gimple_seq_add_stmt (&new_body,
+				     gimple_build_assign (new_var, x));
+	      }
 	    break;
 	  case OMP_CLAUSE_PRIVATE:
 	    var = OMP_CLAUSE_DECL (c);
@@ -13267,20 +13393,19 @@ lower_omp_target (gimple_stmt_iterator *
 		tree x = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (new_var)));
 		if (TREE_CONSTANT (x))
 		  {
-		    const char *name = NULL;
-		    if (DECL_NAME (var))
-		      name = IDENTIFIER_POINTER (DECL_NAME (new_var));
-
 		    x = create_tmp_var_raw (TREE_TYPE (TREE_TYPE (new_var)),
-					    name);
+					    get_name (var));
 		    gimple_add_tmp_var (x);
 		    TREE_ADDRESSABLE (x) = 1;
 		    x = build_fold_addr_expr_loc (clause_loc, x);
 		  }
 		else
 		  {
-		    tree atmp = builtin_decl_explicit (BUILT_IN_ALLOCA);
-		    x = build_call_expr_loc (clause_loc, atmp, 1, x);
+		    tree atmp
+		      = builtin_decl_explicit (BUILT_IN_ALLOCA_WITH_ALIGN);
+		    tree rtype = TREE_TYPE (TREE_TYPE (new_var));
+		    tree al = size_int (TYPE_ALIGN (rtype));
+		    x = build_call_expr_loc (clause_loc, atmp, 2, x, al);
 		  }
 
 		x = fold_convert_loc (clause_loc, TREE_TYPE (new_var), x);
@@ -13290,6 +13415,110 @@ lower_omp_target (gimple_stmt_iterator *
 	      }
 	    break;
 	  }
+      /* Handle GOMP_MAP_FIRSTPRIVATE_POINTER in second pass,
+	 so that firstprivate vars holding OMP_CLAUSE_SIZE if needed
+	 are already handled.  */
+      for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c))
+	switch (OMP_CLAUSE_CODE (c))
+	  {
+	    tree var;
+	  default:
+	    break;
+	  case OMP_CLAUSE_MAP:
+	    if (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_FIRSTPRIVATE_POINTER)
+	      {
+		location_t clause_loc = OMP_CLAUSE_LOCATION (c);
+		gcc_assert (prev);
+		var = OMP_CLAUSE_DECL (c);
+		if (DECL_SIZE (var)
+		    && TREE_CODE (DECL_SIZE (var)) != INTEGER_CST)
+		  {
+		    tree var2 = DECL_VALUE_EXPR (var);
+		    gcc_assert (TREE_CODE (var2) == INDIRECT_REF);
+		    var2 = TREE_OPERAND (var2, 0);
+		    gcc_assert (DECL_P (var2));
+		    var = var2;
+		  }
+		tree new_var = lookup_decl (var, ctx), x;
+		tree type = TREE_TYPE (new_var);
+		bool is_ref = is_reference (var);
+		bool ref_to_array = false;
+		if (is_ref)
+		  {
+		    type = TREE_TYPE (type);
+		    if (TREE_CODE (type) == ARRAY_TYPE)
+		      {
+			type = build_pointer_type (type);
+			ref_to_array = true;
+		      }
+		  }
+		else if (TREE_CODE (type) == ARRAY_TYPE)
+		  {
+		    tree decl2 = DECL_VALUE_EXPR (new_var);
+		    gcc_assert (TREE_CODE (decl2) == MEM_REF);
+		    decl2 = TREE_OPERAND (decl2, 0);
+		    gcc_assert (DECL_P (decl2));
+		    new_var = decl2;
+		    type = TREE_TYPE (new_var);
+		  }
+		x = build_receiver_ref (OMP_CLAUSE_DECL (prev), false, ctx);
+		x = fold_convert_loc (clause_loc, type, x);
+		if (!integer_zerop (OMP_CLAUSE_SIZE (c)))
+		  {
+		    tree bias = OMP_CLAUSE_SIZE (c);
+		    if (DECL_P (bias))
+		      bias = lookup_decl (bias, ctx);
+		    bias = fold_convert_loc (clause_loc, sizetype, bias);
+		    bias = fold_build1_loc (clause_loc, NEGATE_EXPR, sizetype,
+					    bias);
+		    x = fold_build2_loc (clause_loc, POINTER_PLUS_EXPR,
+					 TREE_TYPE (x), x, bias);
+		  }
+		if (ref_to_array)
+		  x = fold_convert_loc (clause_loc, TREE_TYPE (new_var), x);
+		gimplify_expr (&x, &new_body, NULL, is_gimple_val, fb_rvalue);
+		if (is_ref && !ref_to_array)
+		  {
+		    tree t = create_tmp_var_raw (type, get_name (var));
+		    gimple_add_tmp_var (t);
+		    TREE_ADDRESSABLE (t) = 1;
+		    gimple_seq_add_stmt (&new_body,
+					 gimple_build_assign (t, x));
+		    x = build_fold_addr_expr_loc (clause_loc, t);
+		  }
+		gimple_seq_add_stmt (&new_body,
+				     gimple_build_assign (new_var, x));
+		prev = NULL_TREE;
+	      }
+	    else if (OMP_CLAUSE_CHAIN (c)
+		     && OMP_CLAUSE_CODE (OMP_CLAUSE_CHAIN (c))
+			== OMP_CLAUSE_MAP
+		     && OMP_CLAUSE_MAP_KIND (OMP_CLAUSE_CHAIN (c))
+			== GOMP_MAP_FIRSTPRIVATE_POINTER)
+	      prev = c;
+	    break;
+	  case OMP_CLAUSE_PRIVATE:
+	    var = OMP_CLAUSE_DECL (c);
+	    if (is_variable_sized (var))
+	      {
+		location_t clause_loc = OMP_CLAUSE_LOCATION (c);
+		tree new_var = lookup_decl (var, ctx);
+		tree pvar = DECL_VALUE_EXPR (var);
+		gcc_assert (TREE_CODE (pvar) == INDIRECT_REF);
+		pvar = TREE_OPERAND (pvar, 0);
+		gcc_assert (DECL_P (pvar));
+		tree new_pvar = lookup_decl (pvar, ctx);
+		tree atmp = builtin_decl_explicit (BUILT_IN_ALLOCA_WITH_ALIGN);
+		tree al = size_int (DECL_ALIGN (var));
+		tree x = TYPE_SIZE_UNIT (TREE_TYPE (new_var));
+		x = build_call_expr_loc (clause_loc, atmp, 2, x, al);
+		x = fold_convert_loc (clause_loc, TREE_TYPE (new_pvar), x);
+		gimplify_expr (&x, &new_body, NULL, is_gimple_val, fb_rvalue);
+		gimple_seq_add_stmt (&new_body,
+				     gimple_build_assign (new_pvar, x));
+	      }
+	    break;
+	  }
       gimple_seq_add_seq (&new_body, tgt_body);
       new_body = maybe_catch_exception (new_body);
     }
--- gcc/tree-pretty-print.c.jj	2015-07-21 09:06:42.000000000 +0200
+++ gcc/tree-pretty-print.c	2015-07-22 13:53:51.406065024 +0200
@@ -639,6 +639,9 @@ dump_omp_clause (pretty_printer *pp, tre
 	case GOMP_MAP_RELEASE:
 	  pp_string (pp, "release");
 	  break;
+	case GOMP_MAP_FIRSTPRIVATE_POINTER:
+	  pp_string (pp, "firstprivate");
+	  break;
 	default:
 	  gcc_unreachable ();
 	}
@@ -649,7 +652,9 @@ dump_omp_clause (pretty_printer *pp, tre
       if (OMP_CLAUSE_SIZE (clause))
 	{
 	  if (OMP_CLAUSE_CODE (clause) == OMP_CLAUSE_MAP
-	      && OMP_CLAUSE_MAP_KIND (clause) == GOMP_MAP_POINTER)
+	      && (OMP_CLAUSE_MAP_KIND (clause) == GOMP_MAP_POINTER
+		  || OMP_CLAUSE_MAP_KIND (clause)
+		     == GOMP_MAP_FIRSTPRIVATE_POINTER))
 	    pp_string (pp, " [pointer assign, bias: ");
 	  else if (OMP_CLAUSE_CODE (clause) == OMP_CLAUSE_MAP
 		   && OMP_CLAUSE_MAP_KIND (clause) == GOMP_MAP_TO_PSET)


	Jakub

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

* [gomp4.1] Various accelerator updates from OpenMP 4.1
  2015-07-24 20:33                       ` Jakub Jelinek
@ 2015-07-29 17:30                         ` Jakub Jelinek
  2015-09-04 18:17                           ` Ilya Verbin
  0 siblings, 1 reply; 33+ messages in thread
From: Jakub Jelinek @ 2015-07-29 17:30 UTC (permalink / raw)
  To: Ilya Verbin; +Cc: Thomas Schwinge, gcc-patches, Kirill Yukhin

On Fri, Jul 24, 2015 at 10:04:57PM +0200, Jakub Jelinek wrote:
> Another version.
> What to do with zero-length array sections vs. objects is still under heated
> debates, so target8.f90 keeps failing intermittently.

Here is a new version of the patch, with various additions (implemented
GOMP_MAP_FIRSTPRIVATE_INT I've talked about, it now handles use_device_ptr
and handles is_device_ptr with array decls (silly, but seems the accel folks
want it for some strange reason), etc.) and it special cases zero length
array sections rather than all zero length mappings.
The heated debates continue, so perhaps that part -
GOMP_MAP_ZERO_LEN_ARRAY_SECTION - will need reversion and replacement with
something else, we'll see.  This let's the testsuite pass for now except
for the two LTO ICEs, both without offloading (host fallback only) and with
Intel MIC offloading.  Committed to gomp-4_1-branch.

Ilya, I think now is the time to update your enter data/exit data patch.

2015-07-29  Jakub Jelinek  <jakub@redhat.com>

gcc/
	* tree.h (OMP_TARGET_COMBINED): Define.
	(OMP_CLAUSE_SET_MAP_KIND): Cast to unsigned int rather than unsigned
	char.
	(OMP_CLAUSE_MAP_PRIVATE,
	OMP_CLAUSE_MAP_MAYBE_ZERO_LENGTH_ARRAY_SECTION): Define.
	* tree-core.h (struct tree_omp_clause): Change type of map_kind
	from unsigned char to unsigned int.
	* gimplify.c (enum gimplify_omp_var_data): Add GOVD_MAP_0LEN_ARRAY.
	(enum omp_region_type): Add ORT_COMBINED_TARGET.
	(struct gimplify_omp_ctx): Add target_map_scalars_firstprivate,
	target_map_pointers_as_0len_arrays and
	target_firstprivatize_array_bases fields.
	(maybe_fold_stmt): Adjust check for ORT_TARGET for the addition of
	ORT_COMBINED_TARGET.
	(omp_notice_threadprivate_variable): Likewise.
	(omp_firstprivatize_variable): Likewise. 
	If ctx->target_map_scalars_firstprivate is set, firstprivatize
	as GOVD_FIRSTPRIVATE.
	(omp_add_variable): Allow map clause together with data sharing
	clauses.  For data sharing clause with VLA decl
	on omp target/target data don't add firstprivate for the pointer.
	(omp_notice_variable): Adjust check for ORT_TARGET for the addition
	of ORT_COMBINED_TARGET.  Handle implicit mapping of pointers
	as zero length array sections and
	ctx->target_map_scalars_firstprivate mapping of scalars as
	firstprivate data sharing.
	(gimplify_scan_omp_clauses): Initialize
	ctx->target_map_scalars_firstprivate,
	ctx->target_firstprivatize_array_bases and
	ctx->target_map_pointers_as_0len_arrays.  Add firstprivate for
	linear clause even to target region if combined.  Remove
	map clauses with GOMP_MAP_FIRSTPRIVATE_POINTER kind from
	OMP_TARGET_{,ENTER_,EXIT_}DATA.  For GOMP_MAP_FIRSTPRIVATE_POINTER
	map kind with non-INTEGER_CST OMP_CLAUSE_SIZE firstprivatize
	the bias.
	(gimplify_adjust_omp_clauses_1): Handle GOVD_MAP_0LEN_ARRAY.
	If gimplify_omp_ctxp->target_firstprivatize_array_bases, use
	GOMP_MAP_FIRSTPRIVATE_POINTER map kind instead of
	GOMP_MAP_POINTER.
	(gimplify_adjust_omp_clauses): Adjust check for ORT_TARGET for the
	addition of ORT_COMBINED_TARGET.  Use
	GOMP_MAP_FIRSTPRIVATE_POINTER instead of GOMP_MAP_POINTER if
	ctx->target_firstprivatize_array_bases for VLAs.  Set
	OMP_CLAUSE_MAP_PRIVATE if both data sharing and map clause
	appear together.
	(gimplify_omp_workshare): Adjust check for ORT_TARGET for the
	addition of ORT_COMBINED_TARGET.  Use ORT_COMBINED_TARGET if
	OMP_TARGET_COMBINED.
	* omp-low.c (lookup_sfield): Change first argument to
	splay_tree_key, add overload with tree first argument.
	(maybe_lookup_field): Likewise.
	(build_sender_ref): Likewise.
	(scan_sharing_clauses): Handle VLAs in target firstprivate and
	is_device_ptr clauses.  Fix up variable shadowing.  Handle
	OMP_CLAUSE_USE_DEVICE_PTR.  Handle OMP_CLAUSE_MAP_PRIVATE.  Handle
	GOMP_MAP_FIRSTPRIVATE_POINTER map kind.
	(handle_simd_reference): Use get_name.
	(lower_rec_input_clauses): Likewise.  Use BUILT_IN_ALLOCA_WITH_ALIGN
	instead of BUILT_IN_ALLOCA.
	(lower_send_clauses): Use new lookup_sfield overload.
	(lower_omp_target): Handle GOMP_MAP_FIRSTPRIVATE_POINTER map kind.
	Handle OMP_CLAUSE_PRIVATE VLAs.  Handle OMP_CLAUSE_USE_DEVICE_PTR,
	handle arrays and references to arrays in OMP_CLAUSE_IS_DEVICE_PTR
	clause.  Handle OMP_CLAUSE_MAP_MAYBE_ZERO_LENGTH_ARRAY_SECTION.
	* tree-pretty-print.c (dump_omp_clause): Handle
	GOMP_MAP_FIRSTPRIVATE_POINTER.
gcc/c/
	* c-tree.h (c_finish_omp_clauses): Add is_omp argument.
	* c-parser.c (c_parser_oacc_all_clauses, c_parser_omp_all_clauses,
	c_parser_oacc_cache, omp_split_clauses, c_parser_cilk_for): Adjust
	c_finish_omp_clauses callers.
	(c_parser_omp_target_data, c_parser_omp_target_enter_data,
	c_parser_omp_target_exit_data): Disallow GOMP_MAP_POINTER, allow
	GOMP_MAP_FIRSTPRIVATE_POINTER but don't set map_seen for it.
	(c_parser_omp_target): Set OMP_TARGET_COMBINED if combined.
	Disallow GOMP_MAP_POINTER, allow GOMP_MAP_FIRSTPRIVATE_POINTER.
	* c-typeck.c (handle_omp_array_sections): Add is_omp argument.
	Set OMP_CLAUSE_MAP_MAYBE_ZERO_LENGTH_ARRAY_SECTION if needed.
	Use GOMP_MAP_FIRSTPRIVATE_POINTER instead of GOMP_MAP_POINTER
	if is_omp.
	(c_finish_omp_clauses): Add is_omp argument, pass it down to
	handle_omp_array_sections.  Handle GOMP_MAP_FIRSTPRIVATE_POINTER.
	For is_device_ptr/use_device_ptr clauses allow ARRAY_TYPE.
gcc/cp/
	* parser.c (cp_parser_omp_target_data, cp_parser_omp_target_enter_data,
	cp_parser_omp_target_exit_data): Formatting fixes.  Disallow
	GOMP_MAP_POINTER, allow GOMP_MAP_FIRSTPRIVATE_POINTER but don't set
	map_seen for it.
	(cp_parser_omp_target): Set OMP_TARGET_COMBINED if combined.
	Disallow GOMP_MAP_POINTER, allow GOMP_MAP_FIRSTPRIVATE_POINTER.
	* semantics.c (handle_omp_array_sections): Add is_omp argument.
	Set OMP_CLAUSE_MAP_MAYBE_ZERO_LENGTH_ARRAY_SECTION if needed.
	Use GOMP_MAP_FIRSTPRIVATE_POINTER instead of GOMP_MAP_POINTER
	if is_omp.
	(finish_omp_clauses): Handle GOMP_MAP_FIRSTPRIVATE_POINTER.
	For is_device_ptr/use_device_ptr clauses allow ARRAY_TYPE
	and REFERENCE_TYPE to ARRAY_TYPE.
include/
	* gomp-constants.h (enum gomp_map_kind): Add
	GOMP_MAP_FIRSTPRIVATE_INT, GOMP_MAP_USE_DEVICE_PTR,
	GOMP_MAP_ZERO_LEN_ARRAY_SECTION and
	GOMP_MAP_FIRSTPRIVATE_POINTER.
libgomp/
	* libgomp.h (struct target_var_desc): Fix up comments
	about offset and length fields.
	* target.c (gomp_map_lookup): New function.
	(gomp_map_pointer): Use it.
	(gomp_map_vars): Handle GOMP_MAP_FIRSTPRIVATE_INT,
	GOMP_MAP_USE_DEVICE_PTR and GOMP_MAP_ZERO_LEN_ARRAY_SECTION.
	Add tgt->list[i].offset for mappings with non-NULL
	tgt->list[i].key.
	(GOMP_target_41): Handle GOMP_MAP_FIRSTPRIVATE even
	for host fallback.
	(omp_target_is_present): Use gomp_map_lookup.
	(omp_target_associate_ptr): Likewise.
	(omp_target_disassociate_ptr): Likewise.
	* testsuite/libgomp.c++/target-2.C (fn2): Add map(tofrom: s).
	* testsuite/libgomp.c++/target-7.C: New test.
	* testsuite/libgomp.c++/target-8.C: New test.
	* testsuite/libgomp.c++/target-9.C: New test.
	* testsuite/libgomp.c/target-1.c (fn2, fn3, fn4): Add
	map(tofrom:s).
	* testsuite/libgomp.c/target-2.c (fn2, fn3, fn4): Likewise.
	* testsuite/libgomp.c/target-7.c (foo): Add map(h) where needed.
	* testsuite/libgomp.c/target-15.c: New test.
	* testsuite/libgomp.c/target-16.c: New test.
	* testsuite/libgomp.c/target-17.c: New test.
	* testsuite/libgomp.c/target-18.c: New test.
	* testsuite/libgomp.c/target-19.c: New test.
	* testsuite/libgomp.c/examples-4/e.51.3.c (gramSchmidt): Add
	map(tofrom:tmp).
	* testsuite/libgomp.c/examples-4/e.53.1.c (fib_wrapper): Add
	map(from:x).
	* testsuite/libgomp.c/examples-4/e.53.4.c (accum): Add
	map(tofrom:tmp).
	* testsuite/libgomp.c/examples-4/e.53.5.c (accum): Likewise.
	* testsuite/libgomp.c/examples-4/e.54.2.c (dotprod): Add
	map(tofrom: sum).
	* testsuite/libgomp.c/examples-4/e.54.3.c (dotprod): Likewise.
	* testsuite/libgomp.c/examples-4/e.54.4.c (dotprod): Likewise.
	* testsuite/libgomp.c/examples-4/e.57.1.c (main): Add
	map(from: c) and map(from: b, d) where needed.
	* testsuite/libgomp.c/examples-4/e.57.3.c (main): Add
	map(from: res).

--- gcc/tree.h.jj	2015-07-16 17:56:41.000000000 +0200
+++ gcc/tree.h	2015-07-29 14:13:26.336307751 +0200
@@ -1341,6 +1341,11 @@ extern void protected_set_expr_location
 #define OMP_TEAMS_COMBINED(NODE) \
   (OMP_TEAMS_CHECK (NODE)->base.private_flag)
 
+/* True on an OMP_TARGET statement if it represents explicit
+   combined target teams, target parallel or target simd constructs.  */
+#define OMP_TARGET_COMBINED(NODE) \
+  (OMP_TARGET_CHECK (NODE)->base.private_flag)
+
 /* True if OMP_ATOMIC* is supposed to be sequentially consistent
    as opposed to relaxed.  */
 #define OMP_ATOMIC_SEQ_CST(NODE) \
@@ -1445,13 +1450,21 @@ extern void protected_set_expr_location
   ((enum gomp_map_kind) OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_MAP)->omp_clause.subcode.map_kind)
 #define OMP_CLAUSE_SET_MAP_KIND(NODE, MAP_KIND) \
   (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_MAP)->omp_clause.subcode.map_kind \
-   = (unsigned char) (MAP_KIND))
+   = (unsigned int) (MAP_KIND))
 
 /* 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.  */
 #define OMP_CLAUSE_MAP_ZERO_BIAS_ARRAY_SECTION(NODE) \
   (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_MAP)->base.public_flag)
+/* Nonzero if the same decl appears both in OMP_CLAUSE_MAP and either
+   OMP_CLAUSE_PRIVATE or OMP_CLAUSE_FIRSTPRIVATE.  */
+#define OMP_CLAUSE_MAP_PRIVATE(NODE) \
+  TREE_PRIVATE (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_MAP))
+/* Nonzero if this is a mapped array section, that might need special
+   treatment if OMP_CLAUSE_SIZE is zero.  */
+#define OMP_CLAUSE_MAP_MAYBE_ZERO_LENGTH_ARRAY_SECTION(NODE) \
+  TREE_PROTECTED (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_MAP))
 
 #define OMP_CLAUSE_PROC_BIND_KIND(NODE) \
   (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_PROC_BIND)->omp_clause.subcode.proc_bind_kind)
--- gcc/tree-core.h.jj	2015-07-17 09:30:44.000000000 +0200
+++ gcc/tree-core.h	2015-07-21 16:28:48.524156167 +0200
@@ -1354,7 +1354,7 @@ struct GTY(()) tree_omp_clause {
     enum omp_clause_schedule_kind  schedule_kind;
     enum omp_clause_depend_kind    depend_kind;
     /* See include/gomp-constants.h for enum gomp_map_kind's values.  */
-    unsigned char		   map_kind;
+    unsigned int		   map_kind;
     enum omp_clause_proc_bind_kind proc_bind_kind;
     enum tree_code                 reduction_code;
     enum omp_clause_linear_kind    linear_kind;
--- gcc/gimplify.c.jj	2015-07-16 17:56:41.000000000 +0200
+++ gcc/gimplify.c	2015-07-29 16:43:57.056823518 +0200
@@ -90,6 +90,8 @@ enum gimplify_omp_var_data
   /* Flag for GOVD_LINEAR or GOVD_LASTPRIVATE: no outer reference.  */
   GOVD_LINEAR_LASTPRIVATE_NO_OUTER = 16384,
 
+  GOVD_MAP_0LEN_ARRAY = 32768,
+
   GOVD_DATA_SHARE_CLASS = (GOVD_SHARED | GOVD_PRIVATE | GOVD_FIRSTPRIVATE
 			   | GOVD_LASTPRIVATE | GOVD_REDUCTION | GOVD_LINEAR
 			   | GOVD_LOCAL)
@@ -110,6 +112,7 @@ enum omp_region_type
   ORT_TARGET_DATA = 16,
   /* Data region with offloading.  */
   ORT_TARGET = 32,
+  ORT_COMBINED_TARGET = 33,
   /* Dummy OpenMP region, used to disable expansion of
      DECL_VALUE_EXPRs in taskloop pre body.  */
   ORT_NONE = 64
@@ -156,6 +159,9 @@ struct gimplify_omp_ctx
   enum omp_region_type region_type;
   bool combined_loop;
   bool distribute;
+  bool target_map_scalars_firstprivate;
+  bool target_map_pointers_as_0len_arrays;
+  bool target_firstprivatize_array_bases;
 };
 
 static struct gimplify_ctx *gimplify_ctxp;
@@ -2260,7 +2266,7 @@ maybe_fold_stmt (gimple_stmt_iterator *g
 {
   struct gimplify_omp_ctx *ctx;
   for (ctx = gimplify_omp_ctxp; ctx; ctx = ctx->outer_context)
-    if (ctx->region_type == ORT_TARGET)
+    if ((ctx->region_type & ORT_TARGET) != 0)
       return false;
   return fold_stmt (gsi);
 }
@@ -5561,8 +5567,13 @@ omp_firstprivatize_variable (struct gimp
 	  else
 	    return;
 	}
-      else if (ctx->region_type == ORT_TARGET)
-	omp_add_variable (ctx, decl, GOVD_MAP | GOVD_MAP_TO_ONLY);
+      else if ((ctx->region_type & ORT_TARGET) != 0)
+	{
+	  if (ctx->target_map_scalars_firstprivate)
+	    omp_add_variable (ctx, decl, GOVD_FIRSTPRIVATE);
+	  else
+	    omp_add_variable (ctx, decl, GOVD_MAP | GOVD_MAP_TO_ONLY);
+	}
       else if (ctx->region_type != ORT_WORKSHARE
 	       && ctx->region_type != ORT_SIMD
 	       && ctx->region_type != ORT_TARGET_DATA)
@@ -5648,7 +5659,7 @@ omp_add_variable (struct gimplify_omp_ct
     flags |= GOVD_SEEN;
 
   n = splay_tree_lookup (ctx->variables, (splay_tree_key)decl);
-  if (n != NULL && n->value != GOVD_ALIGNED)
+  if (n != NULL && (n->value & GOVD_DATA_SHARE_CLASS) != 0)
     {
       /* We shouldn't be re-adding the decl with the same data
 	 sharing class.  */
@@ -5678,6 +5689,9 @@ omp_add_variable (struct gimplify_omp_ct
 	    nflags = GOVD_MAP | GOVD_MAP_TO_ONLY | GOVD_EXPLICIT;
 	  else if (flags & GOVD_PRIVATE)
 	    nflags = GOVD_PRIVATE;
+	  else if ((ctx->region_type & (ORT_TARGET | ORT_TARGET_DATA)) != 0
+		   && (flags & GOVD_FIRSTPRIVATE))
+	    nflags = GOVD_PRIVATE | GOVD_EXPLICIT;
 	  else
 	    nflags = GOVD_FIRSTPRIVATE;
 	  nflags |= flags & GOVD_SEEN;
@@ -5746,7 +5760,7 @@ omp_notice_threadprivate_variable (struc
   struct gimplify_omp_ctx *octx;
 
   for (octx = ctx; octx; octx = octx->outer_context)
-    if (octx->region_type == ORT_TARGET)
+    if ((octx->region_type & ORT_TARGET) != 0)
       {
 	n = splay_tree_lookup (octx->variables, (splay_tree_key)decl);
 	if (n == NULL)
@@ -5810,19 +5824,66 @@ omp_notice_variable (struct gimplify_omp
     }
 
   n = splay_tree_lookup (ctx->variables, (splay_tree_key)decl);
-  if (ctx->region_type == ORT_TARGET)
+  if ((ctx->region_type & ORT_TARGET) != 0)
     {
       ret = lang_hooks.decls.omp_disregard_value_expr (decl, true);
       if (n == NULL)
 	{
-	  if (!lang_hooks.types.omp_mappable_type (TREE_TYPE (decl)))
+	  unsigned nflags = flags;
+	  if (ctx->target_map_pointers_as_0len_arrays
+	      || ctx->target_map_scalars_firstprivate)
+	    {
+	      bool is_declare_target = false;
+	      bool is_scalar = false;
+	      if (is_global_var (decl)
+		  && varpool_node::get_create (decl)->offloadable)
+		{
+		  struct gimplify_omp_ctx *octx;
+		  for (octx = ctx->outer_context;
+		       octx; octx = octx->outer_context)
+		    {
+		      n = splay_tree_lookup (octx->variables,
+					     (splay_tree_key)decl);
+		      if (n
+			  && (n->value & GOVD_DATA_SHARE_CLASS) != GOVD_SHARED
+			  && (n->value & GOVD_DATA_SHARE_CLASS) != 0)
+			break;
+		    }
+		  is_declare_target = octx == NULL;
+		}
+	      if (!is_declare_target && ctx->target_map_scalars_firstprivate)
+		{
+		  tree type = TREE_TYPE (decl);
+		  if (TREE_CODE (type) == REFERENCE_TYPE)
+		    type = TREE_TYPE (type);
+		  if (TREE_CODE (type) == COMPLEX_TYPE)
+		    type = TREE_TYPE (type);
+		  if (INTEGRAL_TYPE_P (type)
+		      || SCALAR_FLOAT_TYPE_P (type)
+		      || TREE_CODE (type) == POINTER_TYPE)
+		    is_scalar = true;
+		}
+	      if (is_declare_target)
+		;
+	      else if (ctx->target_map_pointers_as_0len_arrays
+		       && (TREE_CODE (TREE_TYPE (decl)) == POINTER_TYPE
+			   || (TREE_CODE (TREE_TYPE (decl)) == REFERENCE_TYPE
+			       && TREE_CODE (TREE_TYPE (TREE_TYPE (decl)))
+				  == POINTER_TYPE)))
+		nflags |= GOVD_MAP | GOVD_MAP_0LEN_ARRAY;
+	      else if (is_scalar)
+		nflags |= GOVD_FIRSTPRIVATE;
+	    }
+	  if (nflags == flags
+	      && !lang_hooks.types.omp_mappable_type (TREE_TYPE (decl)))
 	    {
 	      error ("%qD referenced in target region does not have "
 		     "a mappable type", decl);
-	      omp_add_variable (ctx, decl, GOVD_MAP | GOVD_EXPLICIT | flags);
+	      nflags |= GOVD_MAP | GOVD_EXPLICIT;
 	    }
-	  else
-	    omp_add_variable (ctx, decl, GOVD_MAP | flags);
+	  else if (nflags == flags)
+	    nflags |= GOVD_MAP;
+	  omp_add_variable (ctx, decl, nflags);
 	}
       else
 	{
@@ -6144,6 +6205,24 @@ gimplify_scan_omp_clauses (tree *list_p,
 
   ctx = new_omp_context (region_type);
   outer_ctx = ctx->outer_context;
+  if (code == OMP_TARGET && !lang_GNU_Fortran ())
+    {
+      ctx->target_map_pointers_as_0len_arrays = true;
+      /* FIXME: For Fortran we want to set this too, when
+	 the Fortran FE is updated to OpenMP 4.1.  */
+      ctx->target_map_scalars_firstprivate = true;
+    }
+  if (!lang_GNU_Fortran ())
+    switch (code)
+      {
+      case OMP_TARGET:
+      case OMP_TARGET_DATA:
+      case OMP_TARGET_ENTER_DATA:
+      case OMP_TARGET_EXIT_DATA:
+	ctx->target_firstprivatize_array_bases = true;
+      default:
+	break;
+      }
 
   while ((c = *list_p) != NULL)
     {
@@ -6290,11 +6369,18 @@ gimplify_scan_omp_clauses (tree *list_p,
 			   && ctx->region_type == ORT_WORKSHARE
 			   && octx == outer_ctx)
 		    flags = GOVD_SEEN | GOVD_SHARED;
+		  else if (octx
+			   && octx->region_type == ORT_COMBINED_TARGET)
+		    flags &= ~GOVD_LASTPRIVATE;
 		  else
 		    break;
-		  gcc_checking_assert (splay_tree_lookup (octx->variables,
-							  (splay_tree_key)
-							  decl) == NULL);
+		  splay_tree_node on
+		    = splay_tree_lookup (octx->variables,
+					 (splay_tree_key) decl);
+		  gcc_assert (on == NULL
+			      || (octx->region_type == ORT_COMBINED_TARGET
+				  && (on->value
+				      & GOVD_DATA_SHARE_CLASS) == 0));
 		  omp_add_variable (octx, decl, flags);
 		  if (octx->outer_context == NULL)
 		    break;
@@ -6319,10 +6405,24 @@ gimplify_scan_omp_clauses (tree *list_p,
 	case OMP_CLAUSE_MAP:
 	  decl = OMP_CLAUSE_DECL (c);
 	  if (error_operand_p (decl))
+	    remove = true;
+	  switch (code)
 	    {
-	      remove = true;
+	    case OMP_TARGET:
+	      break;
+	    case OMP_TARGET_DATA:
+	    case OMP_TARGET_ENTER_DATA:
+	    case OMP_TARGET_EXIT_DATA:
+	      if (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_FIRSTPRIVATE_POINTER)
+		/* For target {,enter ,exit }data only the array slice is
+		   mapped, but not the pointer to it.  */
+		remove = true;
+	      break;
+	    default:
 	      break;
 	    }
+	  if (remove)
+	    break;
 	  if (OMP_CLAUSE_SIZE (c) == NULL_TREE)
 	    OMP_CLAUSE_SIZE (c) = DECL_P (decl) ? DECL_SIZE_UNIT (decl)
 				  : TYPE_SIZE_UNIT (TREE_TYPE (decl));
@@ -6332,6 +6432,14 @@ gimplify_scan_omp_clauses (tree *list_p,
 	      remove = true;
 	      break;
 	    }
+	  else if (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_FIRSTPRIVATE_POINTER
+		   && TREE_CODE (OMP_CLAUSE_SIZE (c)) != INTEGER_CST)
+	    {
+	      OMP_CLAUSE_SIZE (c)
+		= get_initialized_tmp_var (OMP_CLAUSE_SIZE (c), pre_p, NULL);
+	      omp_add_variable (ctx, OMP_CLAUSE_SIZE (c),
+				GOVD_FIRSTPRIVATE | GOVD_SEEN);
+	    }
 	  if (!DECL_P (decl))
 	    {
 	      if (gimplify_expr (&OMP_CLAUSE_DECL (c), pre_p,
@@ -6643,7 +6751,10 @@ gimplify_scan_omp_clauses (tree *list_p,
 	case OMP_CLAUSE_NOGROUP:
 	case OMP_CLAUSE_THREADS:
 	case OMP_CLAUSE_SIMD:
+	  break;
+
 	case OMP_CLAUSE_DEFAULTMAP:
+	  ctx->target_map_scalars_firstprivate = false;
 	  break;
 
 	case OMP_CLAUSE_ALIGNED:
@@ -6759,6 +6870,30 @@ gimplify_adjust_omp_clauses_1 (splay_tre
     OMP_CLAUSE_PRIVATE_DEBUG (clause) = 1;
   else if (code == OMP_CLAUSE_PRIVATE && (flags & GOVD_PRIVATE_OUTER_REF))
     OMP_CLAUSE_PRIVATE_OUTER_REF (clause) = 1;
+  else if (code == OMP_CLAUSE_MAP && (flags & GOVD_MAP_0LEN_ARRAY) != 0)
+    {
+      tree nc = build_omp_clause (input_location, OMP_CLAUSE_MAP);
+      OMP_CLAUSE_DECL (nc) = decl;
+      if (TREE_CODE (TREE_TYPE (decl)) == REFERENCE_TYPE
+	  && TREE_CODE (TREE_TYPE (TREE_TYPE (decl))) == POINTER_TYPE)
+	OMP_CLAUSE_DECL (clause)
+	  = build_simple_mem_ref_loc (input_location, decl);
+      OMP_CLAUSE_DECL (clause)
+	= build2 (MEM_REF, char_type_node, OMP_CLAUSE_DECL (clause),
+		  build_int_cst (build_pointer_type (char_type_node), 0));
+      OMP_CLAUSE_SIZE (clause) = size_zero_node;
+      OMP_CLAUSE_SIZE (nc) = size_zero_node;
+      OMP_CLAUSE_SET_MAP_KIND (clause, GOMP_MAP_ALLOC);
+      OMP_CLAUSE_MAP_MAYBE_ZERO_LENGTH_ARRAY_SECTION (clause) = 1;
+      OMP_CLAUSE_SET_MAP_KIND (nc, GOMP_MAP_FIRSTPRIVATE_POINTER);
+      OMP_CLAUSE_CHAIN (nc) = *list_p;
+      OMP_CLAUSE_CHAIN (clause) = nc;
+      struct gimplify_omp_ctx *ctx = gimplify_omp_ctxp;
+      gimplify_omp_ctxp = ctx->outer_context;
+      gimplify_expr (&TREE_OPERAND (OMP_CLAUSE_DECL (clause), 0),
+		     pre_p, NULL, is_gimple_val, fb_rvalue);
+      gimplify_omp_ctxp = ctx;
+    }
   else if (code == OMP_CLAUSE_MAP)
     {
       OMP_CLAUSE_SET_MAP_KIND (clause,
@@ -6785,7 +6920,10 @@ gimplify_adjust_omp_clauses_1 (splay_tre
 				      OMP_CLAUSE_MAP);
 	  OMP_CLAUSE_DECL (nc) = decl;
 	  OMP_CLAUSE_SIZE (nc) = size_zero_node;
-	  OMP_CLAUSE_SET_MAP_KIND (nc, GOMP_MAP_POINTER);
+	  if (gimplify_omp_ctxp->target_firstprivatize_array_bases)
+	    OMP_CLAUSE_SET_MAP_KIND (nc, GOMP_MAP_FIRSTPRIVATE_POINTER);
+	  else
+	    OMP_CLAUSE_SET_MAP_KIND (nc, GOMP_MAP_POINTER);
 	  OMP_CLAUSE_CHAIN (nc) = OMP_CLAUSE_CHAIN (clause);
 	  OMP_CLAUSE_CHAIN (clause) = nc;
 	}
@@ -6910,12 +7048,14 @@ gimplify_adjust_omp_clauses (gimple_seq
 	  if (!DECL_P (decl))
 	    break;
 	  n = splay_tree_lookup (ctx->variables, (splay_tree_key) decl);
-	  if (ctx->region_type == ORT_TARGET && !(n->value & GOVD_SEEN)
+	  if ((ctx->region_type & ORT_TARGET) != 0
+	      && !(n->value & GOVD_SEEN)
 	      && !(OMP_CLAUSE_MAP_KIND (c) & GOMP_MAP_FLAG_ALWAYS))
 	    remove = true;
 	  else if (DECL_SIZE (decl)
 		   && TREE_CODE (DECL_SIZE (decl)) != INTEGER_CST
-		   && OMP_CLAUSE_MAP_KIND (c) != GOMP_MAP_POINTER)
+		   && OMP_CLAUSE_MAP_KIND (c) != GOMP_MAP_POINTER
+		   && OMP_CLAUSE_MAP_KIND (c) != GOMP_MAP_FIRSTPRIVATE_POINTER)
 	    {
 	      /* For GOMP_MAP_FORCE_DEVICEPTR, we'll never enter here, because
 		 for these, TREE_CODE (DECL_SIZE (decl)) will always be
@@ -6935,17 +7075,33 @@ gimplify_adjust_omp_clauses (gimple_seq
 		  omp_notice_variable (ctx->outer_context,
 				       OMP_CLAUSE_SIZE (c), true);
 		}
-	      tree nc = build_omp_clause (OMP_CLAUSE_LOCATION (c),
-					  OMP_CLAUSE_MAP);
-	      OMP_CLAUSE_DECL (nc) = decl;
-	      OMP_CLAUSE_SIZE (nc) = size_zero_node;
-	      OMP_CLAUSE_SET_MAP_KIND (nc, GOMP_MAP_POINTER);
-	      OMP_CLAUSE_CHAIN (nc) = OMP_CLAUSE_CHAIN (c);
-	      OMP_CLAUSE_CHAIN (c) = nc;
-	      c = nc;
+	      if (((ctx->region_type & ORT_TARGET) != 0
+		   || !ctx->target_firstprivatize_array_bases)
+		  && ((n->value & GOVD_SEEN) == 0
+		      || (n->value & (GOVD_PRIVATE | GOVD_FIRSTPRIVATE)) == 0))
+		{
+		  tree nc = build_omp_clause (OMP_CLAUSE_LOCATION (c),
+					      OMP_CLAUSE_MAP);
+		  OMP_CLAUSE_DECL (nc) = decl;
+		  OMP_CLAUSE_SIZE (nc) = size_zero_node;
+		  if (ctx->target_firstprivatize_array_bases)
+		    OMP_CLAUSE_SET_MAP_KIND (nc,
+					     GOMP_MAP_FIRSTPRIVATE_POINTER);
+		  else
+		    OMP_CLAUSE_SET_MAP_KIND (nc, GOMP_MAP_POINTER);
+		  OMP_CLAUSE_CHAIN (nc) = OMP_CLAUSE_CHAIN (c);
+		  OMP_CLAUSE_CHAIN (c) = nc;
+		  c = nc;
+		}
+	    }
+	  else
+	    {
+	      if (OMP_CLAUSE_SIZE (c) == NULL_TREE)
+		OMP_CLAUSE_SIZE (c) = DECL_SIZE_UNIT (decl);
+	      if ((n->value & GOVD_SEEN)
+		  && (n->value & (GOVD_PRIVATE | GOVD_FIRSTPRIVATE)))
+		OMP_CLAUSE_MAP_PRIVATE (c) = 1;
 	    }
-	  else if (OMP_CLAUSE_SIZE (c) == NULL_TREE)
-	    OMP_CLAUSE_SIZE (c) = DECL_SIZE_UNIT (decl);
 	  break;
 
 	case OMP_CLAUSE_TO:
@@ -7888,9 +8044,11 @@ gimplify_omp_workshare (tree *expr_p, gi
     case OMP_SINGLE:
       ort = ORT_WORKSHARE;
       break;
+    case OMP_TARGET:
+      ort = OMP_TARGET_COMBINED (expr) ? ORT_COMBINED_TARGET : ORT_TARGET;
+      break;
     case OACC_KERNELS:
     case OACC_PARALLEL:
-    case OMP_TARGET:
       ort = ORT_TARGET;
       break;
     case OACC_DATA:
@@ -7905,7 +8063,7 @@ gimplify_omp_workshare (tree *expr_p, gi
     }
   gimplify_scan_omp_clauses (&OMP_CLAUSES (expr), pre_p, ort,
 			     TREE_CODE (expr));
-  if (ort == ORT_TARGET || ort == ORT_TARGET_DATA)
+  if ((ort & (ORT_TARGET | ORT_TARGET_DATA)) != 0)
     {
       push_gimplify_context ();
       gimple g = gimplify_and_return_first (OMP_BODY (expr), &body);
--- gcc/omp-low.c.jj	2015-07-21 09:07:23.000000000 +0200
+++ gcc/omp-low.c	2015-07-29 16:13:33.209580272 +0200
@@ -1071,24 +1071,35 @@ lookup_field (tree var, omp_context *ctx
 }
 
 static inline tree
-lookup_sfield (tree var, omp_context *ctx)
+lookup_sfield (splay_tree_key key, omp_context *ctx)
 {
   splay_tree_node n;
   n = splay_tree_lookup (ctx->sfield_map
-			 ? ctx->sfield_map : ctx->field_map,
-			 (splay_tree_key) var);
+			 ? ctx->sfield_map : ctx->field_map, key);
   return (tree) n->value;
 }
 
 static inline tree
-maybe_lookup_field (tree var, omp_context *ctx)
+lookup_sfield (tree var, omp_context *ctx)
+{
+  return lookup_sfield ((splay_tree_key) var, ctx);
+}
+
+static inline tree
+maybe_lookup_field (splay_tree_key key, omp_context *ctx)
 {
   splay_tree_node n;
-  n = splay_tree_lookup (ctx->field_map, (splay_tree_key) var);
+  n = splay_tree_lookup (ctx->field_map, key);
   return n ? (tree) n->value : NULL_TREE;
 }
 
 static inline tree
+maybe_lookup_field (tree var, omp_context *ctx)
+{
+  return maybe_lookup_field ((splay_tree_key) var, ctx);
+}
+
+static inline tree
 lookup_oacc_reduction (const char *id, omp_context *ctx)
 {
   splay_tree_node n;
@@ -1359,12 +1370,18 @@ build_outer_var_ref (tree var, omp_conte
 /* Build tree nodes to access the field for VAR on the sender side.  */
 
 static tree
-build_sender_ref (tree var, omp_context *ctx)
+build_sender_ref (splay_tree_key key, omp_context *ctx)
 {
-  tree field = lookup_sfield (var, ctx);
+  tree field = lookup_sfield (key, ctx);
   return omp_build_component_ref (ctx->sender_decl, field);
 }
 
+static tree
+build_sender_ref (tree var, omp_context *ctx)
+{
+  return build_sender_ref ((splay_tree_key) var, ctx);
+}
+
 /* Add a new field for VAR inside the structure CTX->SENDER_DECL.  */
 
 static void
@@ -1908,6 +1925,17 @@ scan_sharing_clauses (tree clauses, omp_
 	case OMP_CLAUSE_LINEAR:
 	  decl = OMP_CLAUSE_DECL (c);
 	do_private:
+	  if ((OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FIRSTPRIVATE
+	       || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IS_DEVICE_PTR)
+	      && is_gimple_omp_offloaded (ctx->stmt))
+	    {
+	      if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FIRSTPRIVATE)
+		install_var_field (decl, !is_reference (decl), 3, ctx);
+	      else if (TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE)
+		install_var_field (decl, true, 3, ctx);
+	      else
+		install_var_field (decl, false, 3, ctx);
+	    }
 	  if (is_variable_sized (decl))
 	    {
 	      if (is_task_ctx (ctx))
@@ -1930,10 +1958,6 @@ scan_sharing_clauses (tree clauses, omp_
 	      else if (!global)
 		install_var_field (decl, by_ref, 3, ctx);
 	    }
-	  else if ((OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FIRSTPRIVATE
-		    || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IS_DEVICE_PTR)
-		   && is_gimple_omp_offloaded (ctx->stmt))
-	    install_var_field (decl, !is_reference (decl), 3, ctx);
 	  install_var_local (decl, ctx);
 	  if (is_gimple_omp_oacc (ctx->stmt)
 	      && OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION)
@@ -1944,9 +1968,9 @@ scan_sharing_clauses (tree clauses, omp_
 	      tree ptype = build_pointer_type (type);
 	      tree array = create_tmp_var (ptype,
 					   oacc_get_reduction_array_id (var));
-	      omp_context *c = (ctx->field_map ? ctx : ctx->outer);
-	      install_var_field (array, true, 3, c);
-	      install_var_local (array, c);
+	      omp_context *octx = (ctx->field_map ? ctx : ctx->outer);
+	      install_var_field (array, true, 3, octx);
+	      install_var_local (array, octx);
 
 	      /* Insert it into the current context.  */
 	      splay_tree_insert (ctx->reduction_map, (splay_tree_key)
@@ -1959,6 +1983,23 @@ scan_sharing_clauses (tree clauses, omp_
 	  break;
 
 	case OMP_CLAUSE_USE_DEVICE_PTR:
+	  decl = OMP_CLAUSE_DECL (c);
+	  if (TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE)
+	    install_var_field (decl, true, 3, ctx);
+	  else
+	    install_var_field (decl, false, 3, ctx);
+	  if (DECL_SIZE (decl)
+	      && TREE_CODE (DECL_SIZE (decl)) != INTEGER_CST)
+	    {
+	      tree decl2 = DECL_VALUE_EXPR (decl);
+	      gcc_assert (TREE_CODE (decl2) == INDIRECT_REF);
+	      decl2 = TREE_OPERAND (decl2, 0);
+	      gcc_assert (DECL_P (decl2));
+	      install_var_local (decl2, ctx);
+	    }
+	  install_var_local (decl, ctx);
+	  break;
+
 	case OMP_CLAUSE_IS_DEVICE_PTR:
 	  decl = OMP_CLAUSE_DECL (c);
 	  goto do_private;
@@ -2025,6 +2066,21 @@ scan_sharing_clauses (tree clauses, omp_
 		  && !OMP_CLAUSE_MAP_ZERO_BIAS_ARRAY_SECTION (c))
 		break;
 	    }
+	  if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
+	      && OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_FIRSTPRIVATE_POINTER)
+	    {
+	      if (DECL_SIZE (decl)
+		  && TREE_CODE (DECL_SIZE (decl)) != INTEGER_CST)
+		{
+		  tree decl2 = DECL_VALUE_EXPR (decl);
+		  gcc_assert (TREE_CODE (decl2) == INDIRECT_REF);
+		  decl2 = TREE_OPERAND (decl2, 0);
+		  gcc_assert (DECL_P (decl2));
+		  install_var_local (decl2, ctx);
+		}
+	      install_var_local (decl, ctx);
+	      break;
+	    }
 	  if (DECL_P (decl))
 	    {
 	      if (DECL_SIZE (decl)
@@ -2034,7 +2090,11 @@ scan_sharing_clauses (tree clauses, omp_
 		  gcc_assert (TREE_CODE (decl2) == INDIRECT_REF);
 		  decl2 = TREE_OPERAND (decl2, 0);
 		  gcc_assert (DECL_P (decl2));
-		  install_var_field (decl2, true, 3, ctx);
+		  if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
+		      && OMP_CLAUSE_MAP_PRIVATE (c))
+		    install_var_field (decl2, true, 11, ctx);
+		  else
+		    install_var_field (decl2, true, 3, ctx);
 		  install_var_local (decl2, ctx);
 		  install_var_local (decl, ctx);
 		}
@@ -2045,6 +2105,9 @@ scan_sharing_clauses (tree clauses, omp_
 		      && !OMP_CLAUSE_MAP_ZERO_BIAS_ARRAY_SECTION (c)
 		      && TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE)
 		    install_var_field (decl, true, 7, ctx);
+		  else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
+			   && OMP_CLAUSE_MAP_PRIVATE (c))
+		    install_var_field (decl, true, 11, ctx);
 		  else
 		    install_var_field (decl, true, 3, ctx);
 		  if (is_gimple_omp_offloaded (ctx->stmt))
@@ -2147,11 +2210,23 @@ scan_sharing_clauses (tree clauses, omp_
 	  /* FALLTHRU */
 	case OMP_CLAUSE_PRIVATE:
 	case OMP_CLAUSE_LINEAR:
-	case OMP_CLAUSE_USE_DEVICE_PTR:
 	case OMP_CLAUSE_IS_DEVICE_PTR:
 	  decl = OMP_CLAUSE_DECL (c);
 	  if (is_variable_sized (decl))
-	    install_var_local (decl, ctx);
+	    {
+	      if ((OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FIRSTPRIVATE
+		   || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IS_DEVICE_PTR)
+		  && is_gimple_omp_offloaded (ctx->stmt))
+		{
+		  tree decl2 = DECL_VALUE_EXPR (decl);
+		  gcc_assert (TREE_CODE (decl2) == INDIRECT_REF);
+		  decl2 = TREE_OPERAND (decl2, 0);
+		  gcc_assert (DECL_P (decl2));
+		  install_var_local (decl2, ctx);
+		  fixup_remapped_decl (decl2, ctx, false);
+		}
+	      install_var_local (decl, ctx);
+	    }
 	  fixup_remapped_decl (decl, ctx,
 			       OMP_CLAUSE_CODE (c) == OMP_CLAUSE_PRIVATE
 			       && OMP_CLAUSE_PRIVATE_DEBUG (c));
@@ -2201,7 +2276,8 @@ scan_sharing_clauses (tree clauses, omp_
 	    break;
 	  if (DECL_P (decl))
 	    {
-	      if (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_POINTER
+	      if ((OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_POINTER
+		   || OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_FIRSTPRIVATE_POINTER)
 		  && TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE
 		  && !COMPLETE_TYPE_P (TREE_TYPE (decl)))
 		{
@@ -2255,6 +2331,7 @@ scan_sharing_clauses (tree clauses, omp_
 	case OMP_CLAUSE_SIMD:
 	case OMP_CLAUSE_NOGROUP:
 	case OMP_CLAUSE_DEFAULTMAP:
+	case OMP_CLAUSE_USE_DEVICE_PTR:
 	case OMP_CLAUSE__CILK_FOR_COUNT_:
 	case OMP_CLAUSE_ASYNC:
 	case OMP_CLAUSE_WAIT:
@@ -3924,11 +4001,8 @@ handle_simd_reference (location_t loc, t
   tree z = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (new_vard)));
   if (TREE_CONSTANT (z))
     {
-      const char *name = NULL;
-      if (DECL_NAME (new_vard))
-	name = IDENTIFIER_POINTER (DECL_NAME (new_vard));
-
-      z = create_tmp_var_raw (TREE_TYPE (TREE_TYPE (new_vard)), name);
+      z = create_tmp_var_raw (TREE_TYPE (TREE_TYPE (new_vard)),
+			      get_name (new_vard));
       gimple_add_tmp_var (z);
       TREE_ADDRESSABLE (z) = 1;
       z = build_fold_addr_expr_loc (loc, z);
@@ -4127,9 +4201,7 @@ lower_rec_input_clauses (tree clauses, g
 	      tree type = TREE_TYPE (d);
 	      gcc_assert (TREE_CODE (type) == ARRAY_TYPE);
 	      tree v = TYPE_MAX_VALUE (TYPE_DOMAIN (type));
-	      const char *name = NULL;
-	      if (DECL_NAME (orig_var))
-		name = IDENTIFIER_POINTER (DECL_NAME (orig_var));
+	      const char *name = get_name (orig_var);
 	      if (TREE_CONSTANT (v))
 		{
 		  x = create_tmp_var_raw (type, name);
@@ -4139,7 +4211,8 @@ lower_rec_input_clauses (tree clauses, g
 		}
 	      else
 		{
-		  tree atmp = builtin_decl_explicit (BUILT_IN_ALLOCA);
+		  tree atmp
+		    = builtin_decl_explicit (BUILT_IN_ALLOCA_WITH_ALIGN);
 		  tree t = maybe_lookup_decl (v, ctx);
 		  if (t)
 		    v = t;
@@ -4152,7 +4225,8 @@ lower_rec_input_clauses (tree clauses, g
 		  t = fold_build2_loc (clause_loc, MULT_EXPR,
 				       TREE_TYPE (v), t,
 				       TYPE_SIZE_UNIT (TREE_TYPE (type)));
-		  x = build_call_expr_loc (clause_loc, atmp, 1, t);
+		  tree al = size_int (TYPE_ALIGN (TREE_TYPE (type)));
+		  x = build_call_expr_loc (clause_loc, atmp, 2, t, al);
 		}
 
 	      tree ptype = build_pointer_type (TREE_TYPE (type));
@@ -4362,8 +4436,9 @@ lower_rec_input_clauses (tree clauses, g
 		  x = TYPE_SIZE_UNIT (TREE_TYPE (new_var));
 
 		  /* void *tmp = __builtin_alloca */
-		  atmp = builtin_decl_explicit (BUILT_IN_ALLOCA);
-		  stmt = gimple_build_call (atmp, 1, x);
+		  atmp = builtin_decl_explicit (BUILT_IN_ALLOCA_WITH_ALIGN);
+		  stmt = gimple_build_call (atmp, 2, x,
+					    size_int (DECL_ALIGN (var)));
 		  tmp = create_tmp_var_raw (ptr_type_node);
 		  gimple_add_tmp_var (tmp);
 		  gimple_call_set_lhs (stmt, tmp);
@@ -4400,12 +4475,8 @@ lower_rec_input_clauses (tree clauses, g
 		    x = NULL_TREE;
 		  else
 		    {
-		      const char *name = NULL;
-		      if (DECL_NAME (var))
-			name = IDENTIFIER_POINTER (DECL_NAME (new_var));
-
 		      x = create_tmp_var_raw (TREE_TYPE (TREE_TYPE (new_var)),
-					      name);
+					      get_name (var));
 		      gimple_add_tmp_var (x);
 		      TREE_ADDRESSABLE (x) = 1;
 		      x = build_fold_addr_expr_loc (clause_loc, x);
@@ -4413,8 +4484,11 @@ lower_rec_input_clauses (tree clauses, g
 		}
 	      else
 		{
-		  tree atmp = builtin_decl_explicit (BUILT_IN_ALLOCA);
-		  x = build_call_expr_loc (clause_loc, atmp, 1, x);
+		  tree atmp
+		    = builtin_decl_explicit (BUILT_IN_ALLOCA_WITH_ALIGN);
+		  tree rtype = TREE_TYPE (TREE_TYPE (new_var));
+		  tree al = size_int (TYPE_ALIGN (rtype));
+		  x = build_call_expr_loc (clause_loc, atmp, 2, x, al);
 		}
 
 	      if (x)
@@ -5489,11 +5563,7 @@ lower_send_clauses (tree clauses, gimple
 	  /* Handle taskloop firstprivate/lastprivate, where the
 	     lastprivate on GIMPLE_OMP_TASK is represented as
 	     OMP_CLAUSE_SHARED_FIRSTPRIVATE.  */
-	  tree f
-	    = (tree)
-	      splay_tree_lookup (ctx->sfield_map
-				 ? ctx->sfield_map : ctx->field_map,
-				 (splay_tree_key) &DECL_UID (val))->value;
+	  tree f = lookup_sfield ((splay_tree_key) &DECL_UID (val), ctx);
 	  x = omp_build_component_ref (ctx->sender_decl, f);
 	  if (use_pointer_for_field (val, ctx))
 	    var = build_fold_addr_expr (var);
@@ -12883,6 +12953,7 @@ lower_omp_target (gimple_stmt_iterator *
 	  case GOMP_MAP_ALWAYS_TO:
 	  case GOMP_MAP_ALWAYS_FROM:
 	  case GOMP_MAP_ALWAYS_TOFROM:
+	  case GOMP_MAP_FIRSTPRIVATE_POINTER:
 	    break;
 	  case GOMP_MAP_FORCE_ALLOC:
 	  case GOMP_MAP_FORCE_TO:
@@ -12918,6 +12989,28 @@ lower_omp_target (gimple_stmt_iterator *
 	    var = var2;
 	  }
 
+	if (offloaded
+	    && OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_FIRSTPRIVATE_POINTER)
+	  {
+	    if (TREE_CODE (TREE_TYPE (var)) == ARRAY_TYPE)
+	      {
+		tree type = build_pointer_type (TREE_TYPE (var));
+		tree new_var = lookup_decl (var, ctx);
+		x = create_tmp_var_raw (type, get_name (new_var));
+		gimple_add_tmp_var (x);
+		x = build_simple_mem_ref (x);
+		SET_DECL_VALUE_EXPR (new_var, x);
+		DECL_HAS_VALUE_EXPR_P (new_var) = 1;
+	      }
+	    continue;
+	  }
+
+	if (offloaded && OMP_CLAUSE_MAP_PRIVATE (c))
+	  {
+	    map_cnt++;
+	    continue;
+	  }
+
 	if (!maybe_lookup_field (var, ctx))
 	  continue;
 
@@ -12925,6 +13018,7 @@ lower_omp_target (gimple_stmt_iterator *
 	  {
 	    x = build_receiver_ref (var, true, ctx);
 	    tree new_var = lookup_decl (var, ctx);
+
 	    if (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_POINTER
 		&& !OMP_CLAUSE_MAP_ZERO_BIAS_ARRAY_SECTION (c)
 		&& TREE_CODE (TREE_TYPE (var)) == ARRAY_TYPE)
@@ -12936,14 +13030,70 @@ lower_omp_target (gimple_stmt_iterator *
 	break;
 
       case OMP_CLAUSE_FIRSTPRIVATE:
-      case OMP_CLAUSE_IS_DEVICE_PTR:
 	map_cnt++;
 	var = OMP_CLAUSE_DECL (c);
 	if (!is_reference (var)
 	    && !is_gimple_reg_type (TREE_TYPE (var)))
 	  {
-	    x = build_receiver_ref (var, true, ctx);
 	    tree new_var = lookup_decl (var, ctx);
+	    if (is_variable_sized (var))
+	      {
+		tree pvar = DECL_VALUE_EXPR (var);
+		gcc_assert (TREE_CODE (pvar) == INDIRECT_REF);
+		pvar = TREE_OPERAND (pvar, 0);
+		gcc_assert (DECL_P (pvar));
+		tree new_pvar = lookup_decl (pvar, ctx);
+		x = build_fold_indirect_ref (new_pvar);
+		TREE_THIS_NOTRAP (x) = 1;
+	      }
+	    else
+	      x = build_receiver_ref (var, true, ctx);
+	    SET_DECL_VALUE_EXPR (new_var, x);
+	    DECL_HAS_VALUE_EXPR_P (new_var) = 1;
+	  }
+	break;
+
+      case OMP_CLAUSE_PRIVATE:
+	var = OMP_CLAUSE_DECL (c);
+	if (is_variable_sized (var))
+	  {
+	    tree new_var = lookup_decl (var, ctx);
+	    tree pvar = DECL_VALUE_EXPR (var);
+	    gcc_assert (TREE_CODE (pvar) == INDIRECT_REF);
+	    pvar = TREE_OPERAND (pvar, 0);
+	    gcc_assert (DECL_P (pvar));
+	    tree new_pvar = lookup_decl (pvar, ctx);
+	    x = build_fold_indirect_ref (new_pvar);
+	    TREE_THIS_NOTRAP (x) = 1;
+	    SET_DECL_VALUE_EXPR (new_var, x);
+	    DECL_HAS_VALUE_EXPR_P (new_var) = 1;
+	  }
+	break;
+
+      case OMP_CLAUSE_USE_DEVICE_PTR:
+      case OMP_CLAUSE_IS_DEVICE_PTR:
+	var = OMP_CLAUSE_DECL (c);
+	map_cnt++;
+	if (is_variable_sized (var))
+	  {
+	    tree new_var = lookup_decl (var, ctx);
+	    tree pvar = DECL_VALUE_EXPR (var);
+	    gcc_assert (TREE_CODE (pvar) == INDIRECT_REF);
+	    pvar = TREE_OPERAND (pvar, 0);
+	    gcc_assert (DECL_P (pvar));
+	    tree new_pvar = lookup_decl (pvar, ctx);
+	    x = build_fold_indirect_ref (new_pvar);
+	    TREE_THIS_NOTRAP (x) = 1;
+	    SET_DECL_VALUE_EXPR (new_var, x);
+	    DECL_HAS_VALUE_EXPR_P (new_var) = 1;
+	  }
+	else if (TREE_CODE (TREE_TYPE (var)) == ARRAY_TYPE)
+	  {
+	    tree new_var = lookup_decl (var, ctx);
+	    tree type = build_pointer_type (TREE_TYPE (var));
+	    x = create_tmp_var_raw (type, get_name (new_var));
+	    gimple_add_tmp_var (x);
+	    x = build_simple_mem_ref (x);
 	    SET_DECL_VALUE_EXPR (new_var, x);
 	    DECL_HAS_VALUE_EXPR_P (new_var) = 1;
 	  }
@@ -13013,7 +13163,7 @@ lower_omp_target (gimple_stmt_iterator *
       for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c))
 	switch (OMP_CLAUSE_CODE (c))
 	  {
-	    tree ovar, nc, s, purpose, var, x;
+	    tree ovar, nc, s, purpose, var, x, type;
 	    unsigned int talign;
 
 	  default:
@@ -13044,6 +13194,10 @@ lower_omp_target (gimple_stmt_iterator *
 	      }
 	    else
 	      {
+		if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
+		    && OMP_CLAUSE_MAP_KIND (c)
+		       == GOMP_MAP_FIRSTPRIVATE_POINTER)
+		  break;
 		if (DECL_SIZE (ovar)
 		    && TREE_CODE (DECL_SIZE (ovar)) != INTEGER_CST)
 		  {
@@ -13053,7 +13207,14 @@ lower_omp_target (gimple_stmt_iterator *
 		    gcc_assert (DECL_P (ovar2));
 		    ovar = ovar2;
 		  }
-		if (!maybe_lookup_field (ovar, ctx))
+		if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
+		    && OMP_CLAUSE_MAP_PRIVATE (c))
+		  {
+		    if (!maybe_lookup_field ((splay_tree_key) &DECL_UID (ovar),
+					     ctx))
+		      continue;
+		  }
+		else if (!maybe_lookup_field (ovar, ctx))
 		  continue;
 	      }
 
@@ -13063,7 +13224,12 @@ lower_omp_target (gimple_stmt_iterator *
 	    if (nc)
 	      {
 		var = lookup_decl_in_outer_ctx (ovar, ctx);
-		x = build_sender_ref (ovar, ctx);
+		if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
+		    && OMP_CLAUSE_MAP_PRIVATE (c))
+		  x = build_sender_ref ((splay_tree_key) &DECL_UID (ovar),
+					ctx);
+		else
+		  x = build_sender_ref (ovar, ctx);
 		if (maybe_lookup_oacc_reduction (var, ctx))
 		  {
 		    gcc_checking_assert (offloaded
@@ -13101,7 +13267,7 @@ lower_omp_target (gimple_stmt_iterator *
 			 || map_kind == GOMP_MAP_FORCE_DEVICEPTR)
 			&& !TYPE_READONLY (TREE_TYPE (var)))
 		      {
-			x = build_sender_ref (ovar, ctx);
+			x = unshare_expr (x);
 			x = build_simple_mem_ref (x);
 			gimplify_assign (var, x, &olist);
 		      }
@@ -13121,35 +13287,74 @@ lower_omp_target (gimple_stmt_iterator *
 	    if (TREE_CODE (s) != INTEGER_CST)
 	      TREE_STATIC (TREE_VEC_ELT (t, 1)) = 0;
 
-	    unsigned HOST_WIDE_INT tkind;
+	    unsigned HOST_WIDE_INT tkind, tkind_zero;
 	    switch (OMP_CLAUSE_CODE (c))
 	      {
 	      case OMP_CLAUSE_MAP:
 		tkind = OMP_CLAUSE_MAP_KIND (c);
+		tkind_zero = tkind;
+		if (OMP_CLAUSE_MAP_MAYBE_ZERO_LENGTH_ARRAY_SECTION (c))
+		  switch (tkind)
+		    {
+		    case GOMP_MAP_ALLOC:
+		    case GOMP_MAP_TO:
+		    case GOMP_MAP_FROM:
+		    case GOMP_MAP_TOFROM:
+		    case GOMP_MAP_ALWAYS_TO:
+		    case GOMP_MAP_ALWAYS_FROM:
+		    case GOMP_MAP_ALWAYS_TOFROM:
+		      tkind_zero = GOMP_MAP_ZERO_LEN_ARRAY_SECTION;
+		      break;
+		    default:
+		      break;
+		    }
+		if (tkind_zero != tkind)
+		  {
+		    if (integer_zerop (s))
+		      tkind = tkind_zero;
+		    else if (integer_nonzerop (s))
+		      tkind_zero = tkind;
+		  }
 		break;
 	      case OMP_CLAUSE_TO:
 		tkind = GOMP_MAP_TO;
+		tkind_zero = tkind;
 		break;
 	      case OMP_CLAUSE_FROM:
 		tkind = GOMP_MAP_FROM;
+		tkind_zero = tkind;
 		break;
 	      default:
 		gcc_unreachable ();
 	      }
 	    gcc_checking_assert (tkind
 				 < (HOST_WIDE_INT_C (1U) << talign_shift));
+	    gcc_checking_assert (tkind_zero
+				 < (HOST_WIDE_INT_C (1U) << talign_shift));
 	    talign = ceil_log2 (talign);
 	    tkind |= talign << talign_shift;
+	    tkind_zero |= talign << talign_shift;
 	    gcc_checking_assert (tkind
 				 <= tree_to_uhwi (TYPE_MAX_VALUE (tkind_type)));
-	    CONSTRUCTOR_APPEND_ELT (vkind, purpose,
-				    build_int_cstu (tkind_type, tkind));
+	    gcc_checking_assert (tkind_zero
+				 <= tree_to_uhwi (TYPE_MAX_VALUE (tkind_type)));
+	    if (tkind == tkind_zero)
+	      x = build_int_cstu (tkind_type, tkind);
+	    else
+	      {
+		TREE_STATIC (TREE_VEC_ELT (t, 2)) = 0;
+		x = build3 (COND_EXPR, tkind_type,
+			    fold_build2 (EQ_EXPR, boolean_type_node,
+					 unshare_expr (s), size_zero_node),
+			    build_int_cstu (tkind_type, tkind_zero),
+			    build_int_cstu (tkind_type, tkind));
+	      }
+	    CONSTRUCTOR_APPEND_ELT (vkind, purpose, x);
 	    if (nc && nc != c)
 	      c = nc;
 	    break;
 
 	  case OMP_CLAUSE_FIRSTPRIVATE:
-	  case OMP_CLAUSE_IS_DEVICE_PTR:
 	    ovar = OMP_CLAUSE_DECL (c);
 	    if (is_reference (ovar))
 	      talign = TYPE_ALIGN_UNIT (TREE_TYPE (TREE_TYPE (ovar)));
@@ -13157,7 +13362,24 @@ lower_omp_target (gimple_stmt_iterator *
 	      talign = DECL_ALIGN_UNIT (ovar);
 	    var = lookup_decl_in_outer_ctx (ovar, ctx);
 	    x = build_sender_ref (ovar, ctx);
-	    if (is_reference (var))
+	    tkind = GOMP_MAP_FIRSTPRIVATE;
+	    type = TREE_TYPE (ovar);
+	    if (is_reference (ovar))
+	      type = TREE_TYPE (type);
+	    if ((INTEGRAL_TYPE_P (type)
+		  && TYPE_PRECISION (type) <= POINTER_SIZE)
+		|| TREE_CODE (type) == POINTER_TYPE)
+	      {
+		tkind = GOMP_MAP_FIRSTPRIVATE_INT;
+		tree t = var;
+		if (is_reference (var))
+		  t = build_simple_mem_ref (var);
+		if (TREE_CODE (type) != POINTER_TYPE)
+		  t = fold_convert (pointer_sized_int_node, t);
+		t = fold_convert (TREE_TYPE (x), t);
+		gimplify_assign (x, t, &ilist);
+	      }
+	    else if (is_reference (var))
 	      gimplify_assign (x, var, &ilist);
 	    else if (is_gimple_reg (var))
 	      {
@@ -13172,7 +13394,9 @@ lower_omp_target (gimple_stmt_iterator *
 		var = build_fold_addr_expr (var);
 		gimplify_assign (x, var, &ilist);
 	      }
-	    if (is_reference (var))
+	    if (tkind == GOMP_MAP_FIRSTPRIVATE_INT)
+	      s = size_int (0);
+	    else if (is_reference (var))
 	      s = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (ovar)));
 	    else
 	      s = TYPE_SIZE_UNIT (TREE_TYPE (ovar));
@@ -13182,7 +13406,6 @@ lower_omp_target (gimple_stmt_iterator *
 	    if (TREE_CODE (s) != INTEGER_CST)
 	      TREE_STATIC (TREE_VEC_ELT (t, 1)) = 0;
 
-	    tkind = GOMP_MAP_FIRSTPRIVATE;
 	    gcc_checking_assert (tkind
 				 < (HOST_WIDE_INT_C (1U) << talign_shift));
 	    talign = ceil_log2 (talign);
@@ -13192,6 +13415,40 @@ lower_omp_target (gimple_stmt_iterator *
 	    CONSTRUCTOR_APPEND_ELT (vkind, purpose,
 				    build_int_cstu (tkind_type, tkind));
 	    break;
+
+	  case OMP_CLAUSE_USE_DEVICE_PTR:
+	  case OMP_CLAUSE_IS_DEVICE_PTR:
+	    ovar = OMP_CLAUSE_DECL (c);
+	    var = lookup_decl_in_outer_ctx (ovar, ctx);
+	    x = build_sender_ref (ovar, ctx);
+	    if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_USE_DEVICE_PTR)
+	      tkind = GOMP_MAP_USE_DEVICE_PTR;
+	    else
+	      tkind = GOMP_MAP_FIRSTPRIVATE_INT;
+	    type = TREE_TYPE (ovar);
+	    if (TREE_CODE (type) == ARRAY_TYPE)
+	      var = build_fold_addr_expr (var);
+	    else
+	      {
+		if (is_reference (ovar))
+		  {
+		    type = TREE_TYPE (type);
+		    if (TREE_CODE (type) != ARRAY_TYPE)
+		      var = build_simple_mem_ref (var);
+		    var = fold_convert (TREE_TYPE (x), var);
+		  }
+	      }
+	    gimplify_assign (x, var, &ilist);
+	    s = size_int (0);
+	    purpose = size_int (map_idx++);
+	    CONSTRUCTOR_APPEND_ELT (vsize, purpose, s);
+	    gcc_checking_assert (tkind
+				 < (HOST_WIDE_INT_C (1U) << talign_shift));
+	    gcc_checking_assert (tkind
+				 <= tree_to_uhwi (TYPE_MAX_VALUE (tkind_type)));
+	    CONSTRUCTOR_APPEND_ELT (vkind, purpose,
+				    build_int_cstu (tkind_type, tkind));
+	    break;
 	  }
 
       gcc_assert (map_idx == map_cnt);
@@ -13200,21 +13457,22 @@ lower_omp_target (gimple_stmt_iterator *
 	= build_constructor (TREE_TYPE (TREE_VEC_ELT (t, 1)), vsize);
       DECL_INITIAL (TREE_VEC_ELT (t, 2))
 	= build_constructor (TREE_TYPE (TREE_VEC_ELT (t, 2)), vkind);
-      if (!TREE_STATIC (TREE_VEC_ELT (t, 1)))
-	{
-	  gimple_seq initlist = NULL;
-	  force_gimple_operand (build1 (DECL_EXPR, void_type_node,
-					TREE_VEC_ELT (t, 1)),
-				&initlist, true, NULL_TREE);
-	  gimple_seq_add_seq (&ilist, initlist);
-
-	  tree clobber = build_constructor (TREE_TYPE (TREE_VEC_ELT (t, 1)),
-					    NULL);
-	  TREE_THIS_VOLATILE (clobber) = 1;
-	  gimple_seq_add_stmt (&olist,
-			       gimple_build_assign (TREE_VEC_ELT (t, 1),
-						    clobber));
-	}
+      for (int i = 1; i <= 2; i++)
+	if (!TREE_STATIC (TREE_VEC_ELT (t, i)))
+	  {
+	    gimple_seq initlist = NULL;
+	    force_gimple_operand (build1 (DECL_EXPR, void_type_node,
+					  TREE_VEC_ELT (t, i)),
+				  &initlist, true, NULL_TREE);
+	    gimple_seq_add_seq (&ilist, initlist);
+
+	    tree clobber = build_constructor (TREE_TYPE (TREE_VEC_ELT (t, i)),
+					      NULL);
+	    TREE_THIS_VOLATILE (clobber) = 1;
+	    gimple_seq_add_stmt (&olist,
+				 gimple_build_assign (TREE_VEC_ELT (t, i),
+						      clobber));
+	  }
 
       tree clobber = build_constructor (ctx->record_type, NULL);
       TREE_THIS_VOLATILE (clobber) = 1;
@@ -13237,22 +13495,64 @@ lower_omp_target (gimple_stmt_iterator *
 	  		   gimple_build_assign (ctx->receiver_decl, t));
     }
 
-  if (offloaded)
+  if (offloaded || data_region)
     {
+      tree prev = NULL_TREE;
       for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c))
 	switch (OMP_CLAUSE_CODE (c))
 	  {
-	    tree var;
+	    tree var, x;
 	  default:
 	    break;
 	  case OMP_CLAUSE_FIRSTPRIVATE:
-	  case OMP_CLAUSE_IS_DEVICE_PTR:
 	    var = OMP_CLAUSE_DECL (c);
 	    if (is_reference (var)
 		|| is_gimple_reg_type (TREE_TYPE (var)))
 	      {
 		tree new_var = lookup_decl (var, ctx);
-		tree x = build_receiver_ref (var, !is_reference (var), ctx);
+		tree type;
+		type = TREE_TYPE (var);
+		if (is_reference (var))
+		  type = TREE_TYPE (type);
+		if ((INTEGRAL_TYPE_P (type)
+		     && TYPE_PRECISION (type) <= POINTER_SIZE)
+		    || TREE_CODE (type) == POINTER_TYPE)
+		  {
+		    x = build_receiver_ref (var, false, ctx);
+		    if (TREE_CODE (type) != POINTER_TYPE)
+		      x = fold_convert (pointer_sized_int_node, x);
+		    x = fold_convert (type, x);
+		    gimplify_expr (&x, &new_body, NULL, is_gimple_val,
+				   fb_rvalue);
+		    if (is_reference (var))
+		      {
+			tree v = create_tmp_var_raw (type, get_name (var));
+			gimple_add_tmp_var (v);
+			TREE_ADDRESSABLE (v) = 1;
+			gimple_seq_add_stmt (&new_body,
+					     gimple_build_assign (v, x));
+			x = build_fold_addr_expr (v);
+		      }
+		    gimple_seq_add_stmt (&new_body,
+					 gimple_build_assign (new_var, x));
+		  }
+		else
+		  {
+		    x = build_receiver_ref (var, !is_reference (var), ctx);
+		    gimplify_expr (&x, &new_body, NULL, is_gimple_val,
+				   fb_rvalue);
+		    gimple_seq_add_stmt (&new_body,
+					 gimple_build_assign (new_var, x));
+		  }
+	      }
+	    else if (is_variable_sized (var))
+	      {
+		tree pvar = DECL_VALUE_EXPR (var);
+		gcc_assert (TREE_CODE (pvar) == INDIRECT_REF);
+		pvar = TREE_OPERAND (pvar, 0);
+		gcc_assert (DECL_P (pvar));
+		tree new_var = lookup_decl (pvar, ctx);
+		x = build_receiver_ref (var, false, ctx);
 		gimplify_expr (&x, &new_body, NULL, is_gimple_val, fb_rvalue);
 		gimple_seq_add_stmt (&new_body,
 				     gimple_build_assign (new_var, x));
@@ -13264,23 +13564,22 @@ lower_omp_target (gimple_stmt_iterator *
 	      {
 		location_t clause_loc = OMP_CLAUSE_LOCATION (c);
 		tree new_var = lookup_decl (var, ctx);
-		tree x = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (new_var)));
+		x = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (new_var)));
 		if (TREE_CONSTANT (x))
 		  {
-		    const char *name = NULL;
-		    if (DECL_NAME (var))
-		      name = IDENTIFIER_POINTER (DECL_NAME (new_var));
-
 		    x = create_tmp_var_raw (TREE_TYPE (TREE_TYPE (new_var)),
-					    name);
+					    get_name (var));
 		    gimple_add_tmp_var (x);
 		    TREE_ADDRESSABLE (x) = 1;
 		    x = build_fold_addr_expr_loc (clause_loc, x);
 		  }
 		else
 		  {
-		    tree atmp = builtin_decl_explicit (BUILT_IN_ALLOCA);
-		    x = build_call_expr_loc (clause_loc, atmp, 1, x);
+		    tree atmp
+		      = builtin_decl_explicit (BUILT_IN_ALLOCA_WITH_ALIGN);
+		    tree rtype = TREE_TYPE (TREE_TYPE (new_var));
+		    tree al = size_int (TYPE_ALIGN (rtype));
+		    x = build_call_expr_loc (clause_loc, atmp, 2, x, al);
 		  }
 
 		x = fold_convert_loc (clause_loc, TREE_TYPE (new_var), x);
@@ -13289,9 +13588,169 @@ lower_omp_target (gimple_stmt_iterator *
 				     gimple_build_assign (new_var, x));
 	      }
 	    break;
+	  case OMP_CLAUSE_USE_DEVICE_PTR:
+	  case OMP_CLAUSE_IS_DEVICE_PTR:
+	    var = OMP_CLAUSE_DECL (c);
+	    if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_USE_DEVICE_PTR)
+	      x = build_sender_ref (var, ctx);
+	    else
+	      x = build_receiver_ref (var, false, ctx);
+	    if (is_variable_sized (var))
+	      {
+		tree pvar = DECL_VALUE_EXPR (var);
+		gcc_assert (TREE_CODE (pvar) == INDIRECT_REF);
+		pvar = TREE_OPERAND (pvar, 0);
+		gcc_assert (DECL_P (pvar));
+		tree new_var = lookup_decl (pvar, ctx);
+		gimplify_expr (&x, &new_body, NULL, is_gimple_val, fb_rvalue);
+		gimple_seq_add_stmt (&new_body,
+				     gimple_build_assign (new_var, x));
+	      }
+	    else if (TREE_CODE (TREE_TYPE (var)) == ARRAY_TYPE)
+	      {
+		tree new_var = lookup_decl (var, ctx);
+		new_var = DECL_VALUE_EXPR (new_var);
+		gcc_assert (TREE_CODE (new_var) == MEM_REF);
+		new_var = TREE_OPERAND (new_var, 0);
+		gcc_assert (DECL_P (new_var));
+		gimplify_expr (&x, &new_body, NULL, is_gimple_val, fb_rvalue);
+		gimple_seq_add_stmt (&new_body,
+				     gimple_build_assign (new_var, x));
+	      }
+	    else
+	      {
+		tree type = TREE_TYPE (var);
+		tree new_var = lookup_decl (var, ctx);
+		if (is_reference (var))
+		  {
+		    type = TREE_TYPE (type);
+		    if (TREE_CODE (type) != ARRAY_TYPE)
+		      {
+			tree v = create_tmp_var_raw (type, get_name (var));
+			gimple_add_tmp_var (v);
+			TREE_ADDRESSABLE (v) = 1;
+			x = fold_convert (type, x);
+			gimplify_expr (&x, &new_body, NULL, is_gimple_val,
+				       fb_rvalue);
+			gimple_seq_add_stmt (&new_body,
+					     gimple_build_assign (v, x));
+			x = build_fold_addr_expr (v);
+		      }
+		  }
+		x = fold_convert (TREE_TYPE (new_var), x);
+		gimplify_expr (&x, &new_body, NULL, is_gimple_val, fb_rvalue);
+		gimple_seq_add_stmt (&new_body,
+				     gimple_build_assign (new_var, x));
+	      }
+	    break;
+	  }
+      /* Handle GOMP_MAP_FIRSTPRIVATE_POINTER in second pass,
+	 so that firstprivate vars holding OMP_CLAUSE_SIZE if needed
+	 are already handled.  */
+      for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c))
+	switch (OMP_CLAUSE_CODE (c))
+	  {
+	    tree var;
+	  default:
+	    break;
+	  case OMP_CLAUSE_MAP:
+	    if (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_FIRSTPRIVATE_POINTER)
+	      {
+		location_t clause_loc = OMP_CLAUSE_LOCATION (c);
+		gcc_assert (prev);
+		var = OMP_CLAUSE_DECL (c);
+		if (DECL_SIZE (var)
+		    && TREE_CODE (DECL_SIZE (var)) != INTEGER_CST)
+		  {
+		    tree var2 = DECL_VALUE_EXPR (var);
+		    gcc_assert (TREE_CODE (var2) == INDIRECT_REF);
+		    var2 = TREE_OPERAND (var2, 0);
+		    gcc_assert (DECL_P (var2));
+		    var = var2;
+		  }
+		tree new_var = lookup_decl (var, ctx), x;
+		tree type = TREE_TYPE (new_var);
+		bool is_ref = is_reference (var);
+		bool ref_to_array = false;
+		if (is_ref)
+		  {
+		    type = TREE_TYPE (type);
+		    if (TREE_CODE (type) == ARRAY_TYPE)
+		      {
+			type = build_pointer_type (type);
+			ref_to_array = true;
+		      }
+		  }
+		else if (TREE_CODE (type) == ARRAY_TYPE)
+		  {
+		    tree decl2 = DECL_VALUE_EXPR (new_var);
+		    gcc_assert (TREE_CODE (decl2) == MEM_REF);
+		    decl2 = TREE_OPERAND (decl2, 0);
+		    gcc_assert (DECL_P (decl2));
+		    new_var = decl2;
+		    type = TREE_TYPE (new_var);
+		  }
+		x = build_receiver_ref (OMP_CLAUSE_DECL (prev), false, ctx);
+		x = fold_convert_loc (clause_loc, type, x);
+		if (!integer_zerop (OMP_CLAUSE_SIZE (c)))
+		  {
+		    tree bias = OMP_CLAUSE_SIZE (c);
+		    if (DECL_P (bias))
+		      bias = lookup_decl (bias, ctx);
+		    bias = fold_convert_loc (clause_loc, sizetype, bias);
+		    bias = fold_build1_loc (clause_loc, NEGATE_EXPR, sizetype,
+					    bias);
+		    x = fold_build2_loc (clause_loc, POINTER_PLUS_EXPR,
+					 TREE_TYPE (x), x, bias);
+		  }
+		if (ref_to_array)
+		  x = fold_convert_loc (clause_loc, TREE_TYPE (new_var), x);
+		gimplify_expr (&x, &new_body, NULL, is_gimple_val, fb_rvalue);
+		if (is_ref && !ref_to_array)
+		  {
+		    tree t = create_tmp_var_raw (type, get_name (var));
+		    gimple_add_tmp_var (t);
+		    TREE_ADDRESSABLE (t) = 1;
+		    gimple_seq_add_stmt (&new_body,
+					 gimple_build_assign (t, x));
+		    x = build_fold_addr_expr_loc (clause_loc, t);
+		  }
+		gimple_seq_add_stmt (&new_body,
+				     gimple_build_assign (new_var, x));
+		prev = NULL_TREE;
+	      }
+	    else if (OMP_CLAUSE_CHAIN (c)
+		     && OMP_CLAUSE_CODE (OMP_CLAUSE_CHAIN (c))
+			== OMP_CLAUSE_MAP
+		     && OMP_CLAUSE_MAP_KIND (OMP_CLAUSE_CHAIN (c))
+			== GOMP_MAP_FIRSTPRIVATE_POINTER)
+	      prev = c;
+	    break;
+	  case OMP_CLAUSE_PRIVATE:
+	    var = OMP_CLAUSE_DECL (c);
+	    if (is_variable_sized (var))
+	      {
+		location_t clause_loc = OMP_CLAUSE_LOCATION (c);
+		tree new_var = lookup_decl (var, ctx);
+		tree pvar = DECL_VALUE_EXPR (var);
+		gcc_assert (TREE_CODE (pvar) == INDIRECT_REF);
+		pvar = TREE_OPERAND (pvar, 0);
+		gcc_assert (DECL_P (pvar));
+		tree new_pvar = lookup_decl (pvar, ctx);
+		tree atmp = builtin_decl_explicit (BUILT_IN_ALLOCA_WITH_ALIGN);
+		tree al = size_int (DECL_ALIGN (var));
+		tree x = TYPE_SIZE_UNIT (TREE_TYPE (new_var));
+		x = build_call_expr_loc (clause_loc, atmp, 2, x, al);
+		x = fold_convert_loc (clause_loc, TREE_TYPE (new_pvar), x);
+		gimplify_expr (&x, &new_body, NULL, is_gimple_val, fb_rvalue);
+		gimple_seq_add_stmt (&new_body,
+				     gimple_build_assign (new_pvar, x));
+	      }
+	    break;
 	  }
       gimple_seq_add_seq (&new_body, tgt_body);
-      new_body = maybe_catch_exception (new_body);
+      if (offloaded)
+	new_body = maybe_catch_exception (new_body);
     }
   else if (data_region)
     new_body = tgt_body;
--- gcc/tree-pretty-print.c.jj	2015-07-21 09:06:42.000000000 +0200
+++ gcc/tree-pretty-print.c	2015-07-22 13:53:51.406065024 +0200
@@ -639,6 +639,9 @@ dump_omp_clause (pretty_printer *pp, tre
 	case GOMP_MAP_RELEASE:
 	  pp_string (pp, "release");
 	  break;
+	case GOMP_MAP_FIRSTPRIVATE_POINTER:
+	  pp_string (pp, "firstprivate");
+	  break;
 	default:
 	  gcc_unreachable ();
 	}
@@ -649,7 +652,9 @@ dump_omp_clause (pretty_printer *pp, tre
       if (OMP_CLAUSE_SIZE (clause))
 	{
 	  if (OMP_CLAUSE_CODE (clause) == OMP_CLAUSE_MAP
-	      && OMP_CLAUSE_MAP_KIND (clause) == GOMP_MAP_POINTER)
+	      && (OMP_CLAUSE_MAP_KIND (clause) == GOMP_MAP_POINTER
+		  || OMP_CLAUSE_MAP_KIND (clause)
+		     == GOMP_MAP_FIRSTPRIVATE_POINTER))
 	    pp_string (pp, " [pointer assign, bias: ");
 	  else if (OMP_CLAUSE_CODE (clause) == OMP_CLAUSE_MAP
 		   && OMP_CLAUSE_MAP_KIND (clause) == GOMP_MAP_TO_PSET)
--- gcc/c/c-tree.h.jj	2015-07-01 12:50:49.000000000 +0200
+++ gcc/c/c-tree.h	2015-07-22 12:47:49.185826677 +0200
@@ -649,7 +649,7 @@ extern tree c_begin_omp_task (void);
 extern tree c_finish_omp_task (location_t, tree, tree);
 extern void c_finish_omp_cancel (location_t, tree);
 extern void c_finish_omp_cancellation_point (location_t, tree);
-extern tree c_finish_omp_clauses (tree, bool = false);
+extern tree c_finish_omp_clauses (tree, bool, bool = false);
 extern tree c_build_va_arg (location_t, tree, tree);
 extern tree c_finish_transaction (location_t, tree, int);
 extern bool c_tree_equal (tree, tree);
--- gcc/c/c-parser.c.jj	2015-07-21 09:06:42.000000000 +0200
+++ gcc/c/c-parser.c	2015-07-23 12:51:02.000000000 +0200
@@ -12435,7 +12435,7 @@ c_parser_oacc_all_clauses (c_parser *par
   c_parser_skip_to_pragma_eol (parser);
 
   if (finish_p)
-    return c_finish_omp_clauses (clauses);
+    return c_finish_omp_clauses (clauses, false);
 
   return clauses;
 }
@@ -12720,8 +12720,8 @@ c_parser_omp_all_clauses (c_parser *pars
   if (finish_p)
     {
       if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_UNIFORM)) != 0)
-	return c_finish_omp_clauses (clauses, true);
-      return c_finish_omp_clauses (clauses);
+	return c_finish_omp_clauses (clauses, true, true);
+      return c_finish_omp_clauses (clauses, true);
     }
 
   return clauses;
@@ -12755,7 +12755,7 @@ c_parser_oacc_cache (location_t loc, c_p
   tree stmt, clauses;
 
   clauses = c_parser_omp_var_list_parens (parser, OMP_CLAUSE__CACHE_, NULL);
-  clauses = c_finish_omp_clauses (clauses);
+  clauses = c_finish_omp_clauses (clauses, false);
 
   c_parser_skip_to_pragma_eol (parser);
 
@@ -13902,7 +13902,7 @@ omp_split_clauses (location_t loc, enum
   c_omp_split_clauses (loc, code, mask, clauses, cclauses);
   for (i = 0; i < C_OMP_CLAUSE_SPLIT_COUNT; i++)
     if (cclauses[i])
-      cclauses[i] = c_finish_omp_clauses (cclauses[i]);
+      cclauses[i] = c_finish_omp_clauses (cclauses[i], true);
 }
 
 /* OpenMP 4.0:
@@ -14668,9 +14668,10 @@ c_parser_omp_target_data (location_t loc
 	  case GOMP_MAP_TOFROM:
 	  case GOMP_MAP_ALWAYS_TOFROM:
 	  case GOMP_MAP_ALLOC:
-	  case GOMP_MAP_POINTER:
 	    map_seen = 3;
 	    break;
+	  case GOMP_MAP_FIRSTPRIVATE_POINTER:
+	    break;
 	  default:
 	    map_seen |= 1;
 	    error_at (OMP_CLAUSE_LOCATION (*pc),
@@ -14800,9 +14801,10 @@ c_parser_omp_target_enter_data (location
 	  case GOMP_MAP_TO:
 	  case GOMP_MAP_ALWAYS_TO:
 	  case GOMP_MAP_ALLOC:
-	  case GOMP_MAP_POINTER:
 	    map_seen = 3;
 	    break;
+	  case GOMP_MAP_FIRSTPRIVATE_POINTER:
+	    break;
 	  default:
 	    map_seen |= 1;
 	    error_at (OMP_CLAUSE_LOCATION (*pc),
@@ -14885,9 +14887,10 @@ c_parser_omp_target_exit_data (location_
 	  case GOMP_MAP_ALWAYS_FROM:
 	  case GOMP_MAP_RELEASE:
 	  case GOMP_MAP_DELETE:
-	  case GOMP_MAP_POINTER:
 	    map_seen = 3;
 	    break;
+	  case GOMP_MAP_FIRSTPRIVATE_POINTER:
+	    break;
 	  default:
 	    map_seen |= 1;
 	    error_at (OMP_CLAUSE_LOCATION (*pc),
@@ -15016,6 +15019,7 @@ c_parser_omp_target (c_parser *parser, e
 	  TREE_TYPE (stmt) = void_type_node;
 	  OMP_TARGET_CLAUSES (stmt) = cclauses[C_OMP_CLAUSE_SPLIT_TARGET];
 	  OMP_TARGET_BODY (stmt) = block;
+	  OMP_TARGET_COMBINED (stmt) = 1;
 	  add_stmt (stmt);
 	  pc = &OMP_TARGET_CLAUSES (stmt);
 	  goto check_clauses;
@@ -15078,7 +15082,7 @@ check_clauses:
 	  case GOMP_MAP_TOFROM:
 	  case GOMP_MAP_ALWAYS_TOFROM:
 	  case GOMP_MAP_ALLOC:
-	  case GOMP_MAP_POINTER:
+	  case GOMP_MAP_FIRSTPRIVATE_POINTER:
 	    break;
 	  default:
 	    error_at (OMP_CLAUSE_LOCATION (*pc),
@@ -16379,7 +16383,7 @@ c_parser_cilk_for (c_parser *parser, tre
   tree clauses = build_omp_clause (EXPR_LOCATION (grain), OMP_CLAUSE_SCHEDULE);
   OMP_CLAUSE_SCHEDULE_KIND (clauses) = OMP_CLAUSE_SCHEDULE_CILKFOR;
   OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (clauses) = grain;
-  clauses = c_finish_omp_clauses (clauses);
+  clauses = c_finish_omp_clauses (clauses, false);
 
   tree block = c_begin_compound_stmt (true);
   tree sb = push_stmt_list ();
@@ -16444,7 +16448,7 @@ c_parser_cilk_for (c_parser *parser, tre
       OMP_CLAUSE_OPERAND (c, 0)
 	= cilk_for_number_of_iterations (omp_for);
       OMP_CLAUSE_CHAIN (c) = clauses;
-      OMP_PARALLEL_CLAUSES (omp_par) = c_finish_omp_clauses (c);
+      OMP_PARALLEL_CLAUSES (omp_par) = c_finish_omp_clauses (c, true);
       add_stmt (omp_par);
     }
 
--- gcc/c/c-typeck.c.jj	2015-07-17 13:06:58.000000000 +0200
+++ gcc/c/c-typeck.c	2015-07-29 16:14:08.276065810 +0200
@@ -11850,7 +11850,7 @@ handle_omp_array_sections_1 (tree c, tre
 /* Handle array sections for clause C.  */
 
 static bool
-handle_omp_array_sections (tree c)
+handle_omp_array_sections (tree c, bool is_omp)
 {
   bool maybe_zero_len = false;
   unsigned int first_non_one = 0;
@@ -12030,9 +12030,26 @@ handle_omp_array_sections (tree c)
       if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP)
 	return false;
       gcc_assert (OMP_CLAUSE_MAP_KIND (c) != GOMP_MAP_FORCE_DEVICEPTR);
+      if (is_omp)
+	switch (OMP_CLAUSE_MAP_KIND (c))
+	  {
+	  case GOMP_MAP_ALLOC:
+	  case GOMP_MAP_TO:
+	  case GOMP_MAP_FROM:
+	  case GOMP_MAP_TOFROM:
+	  case GOMP_MAP_ALWAYS_TO:
+	  case GOMP_MAP_ALWAYS_FROM:
+	  case GOMP_MAP_ALWAYS_TOFROM:
+	    OMP_CLAUSE_MAP_MAYBE_ZERO_LENGTH_ARRAY_SECTION (c) = 1;
+	    break;
+	  default:
+	    break;
+	  }
       tree c2 = build_omp_clause (OMP_CLAUSE_LOCATION (c), OMP_CLAUSE_MAP);
-      OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_POINTER);
-      if (!c_mark_addressable (t))
+      OMP_CLAUSE_SET_MAP_KIND (c2, is_omp
+				   ? GOMP_MAP_FIRSTPRIVATE_POINTER
+				   : GOMP_MAP_POINTER);
+      if (!is_omp && !c_mark_addressable (t))
 	return false;
       OMP_CLAUSE_DECL (c2) = t;
       t = build_fold_addr_expr (first);
@@ -12097,7 +12114,7 @@ c_find_omp_placeholder_r (tree *tp, int
    Remove any elements from the list that are invalid.  */
 
 tree
-c_finish_omp_clauses (tree clauses, bool declare_simd)
+c_finish_omp_clauses (tree clauses, bool is_omp, bool declare_simd)
 {
   bitmap_head generic_head, firstprivate_head, lastprivate_head;
   bitmap_head aligned_head, map_head;
@@ -12136,7 +12153,7 @@ c_finish_omp_clauses (tree clauses, bool
 	  t = OMP_CLAUSE_DECL (c);
 	  if (TREE_CODE (t) == TREE_LIST)
 	    {
-	      if (handle_omp_array_sections (c))
+	      if (handle_omp_array_sections (c, is_omp))
 		{
 		  remove = true;
 		  break;
@@ -12496,7 +12513,7 @@ c_finish_omp_clauses (tree clauses, bool
 	    }
 	  if (TREE_CODE (t) == TREE_LIST)
 	    {
-	      if (handle_omp_array_sections (c))
+	      if (handle_omp_array_sections (c, is_omp))
 		remove = true;
 	      break;
 	    }
@@ -12519,7 +12536,7 @@ c_finish_omp_clauses (tree clauses, bool
 	  t = OMP_CLAUSE_DECL (c);
 	  if (TREE_CODE (t) == TREE_LIST)
 	    {
-	      if (handle_omp_array_sections (c))
+	      if (handle_omp_array_sections (c, is_omp))
 		remove = true;
 	      else
 		{
@@ -12556,6 +12573,8 @@ c_finish_omp_clauses (tree clauses, bool
 	  else if (!(OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
 		     && (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_POINTER
 			 || (OMP_CLAUSE_MAP_KIND (c)
+			     == GOMP_MAP_FIRSTPRIVATE_POINTER)
+			 || (OMP_CLAUSE_MAP_KIND (c)
 			     == GOMP_MAP_FORCE_DEVICEPTR)))
 		   && !lang_hooks.types.omp_mappable_type (TREE_TYPE (t)))
 	    {
@@ -12624,10 +12643,11 @@ c_finish_omp_clauses (tree clauses, bool
 	case OMP_CLAUSE_IS_DEVICE_PTR:
 	case OMP_CLAUSE_USE_DEVICE_PTR:
 	  t = OMP_CLAUSE_DECL (c);
-	  if (TREE_CODE (TREE_TYPE (t)) != POINTER_TYPE)
+	  if (TREE_CODE (TREE_TYPE (t)) != POINTER_TYPE
+	      && TREE_CODE (TREE_TYPE (t)) != ARRAY_TYPE)
 	    {
 	      error_at (OMP_CLAUSE_LOCATION (c),
-			"%qs variable is not a pointer",
+			"%qs variable is neither a pointer nor an array",
 			omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
 	      remove = true;
 	    }
--- gcc/cp/parser.c.jj	2015-07-21 09:06:42.000000000 +0200
+++ gcc/cp/parser.c	2015-07-23 12:46:22.172652420 +0200
@@ -32276,27 +32276,28 @@ cp_parser_omp_target_data (cp_parser *pa
   for (tree *pc = &clauses; *pc;)
     {
       if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_MAP)
-       switch (OMP_CLAUSE_MAP_KIND (*pc))
-	 {
-	 case GOMP_MAP_TO:
-	 case GOMP_MAP_ALWAYS_TO:
-	 case GOMP_MAP_FROM:
-	 case GOMP_MAP_ALWAYS_FROM:
-	 case GOMP_MAP_TOFROM:
-	 case GOMP_MAP_ALWAYS_TOFROM:
-	 case GOMP_MAP_ALLOC:
-	 case GOMP_MAP_POINTER:
-	   map_seen = 3;
-	   break;
-	 default:
-	   map_seen |= 1;
-	   error_at (OMP_CLAUSE_LOCATION (*pc),
-		     "%<#pragma omp target data%> with map-type other "
-		     "than %<to%>, %<from%>, %<tofrom%> or %<alloc%> "
-		     "on %<map%> clause");
-	   *pc = OMP_CLAUSE_CHAIN (*pc);
-	   continue;
-	 }
+	switch (OMP_CLAUSE_MAP_KIND (*pc))
+	  {
+	  case GOMP_MAP_TO:
+	  case GOMP_MAP_ALWAYS_TO:
+	  case GOMP_MAP_FROM:
+	  case GOMP_MAP_ALWAYS_FROM:
+	  case GOMP_MAP_TOFROM:
+	  case GOMP_MAP_ALWAYS_TOFROM:
+	  case GOMP_MAP_ALLOC:
+	    map_seen = 3;
+	    break;
+	  case GOMP_MAP_FIRSTPRIVATE_POINTER:
+	    break;
+	  default:
+	    map_seen |= 1;
+	    error_at (OMP_CLAUSE_LOCATION (*pc),
+		      "%<#pragma omp target data%> with map-type other "
+		      "than %<to%>, %<from%>, %<tofrom%> or %<alloc%> "
+		      "on %<map%> clause");
+	    *pc = OMP_CLAUSE_CHAIN (*pc);
+	    continue;
+	  }
       pc = &OMP_CLAUSE_CHAIN (*pc);
     }
 
@@ -32370,22 +32371,23 @@ cp_parser_omp_target_enter_data (cp_pars
   for (tree *pc = &clauses; *pc;)
     {
       if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_MAP)
-       switch (OMP_CLAUSE_MAP_KIND (*pc))
-	 {
-	 case GOMP_MAP_TO:
-	 case GOMP_MAP_ALWAYS_TO:
-	 case GOMP_MAP_ALLOC:
-	 case GOMP_MAP_POINTER:
-	   map_seen = 3;
-	   break;
-	 default:
-	   map_seen |= 1;
-	   error_at (OMP_CLAUSE_LOCATION (*pc),
-		     "%<#pragma omp target enter data%> with map-type other "
-		     "than %<to%> or %<alloc%> on %<map%> clause");
-	   *pc = OMP_CLAUSE_CHAIN (*pc);
-	   continue;
-	 }
+	switch (OMP_CLAUSE_MAP_KIND (*pc))
+	  {
+	  case GOMP_MAP_TO:
+	  case GOMP_MAP_ALWAYS_TO:
+	  case GOMP_MAP_ALLOC:
+	    map_seen = 3;
+	    break;
+	  case GOMP_MAP_FIRSTPRIVATE_POINTER:
+	    break;
+	  default:
+	    map_seen |= 1;
+	    error_at (OMP_CLAUSE_LOCATION (*pc),
+		      "%<#pragma omp target enter data%> with map-type other "
+		      "than %<to%> or %<alloc%> on %<map%> clause");
+	    *pc = OMP_CLAUSE_CHAIN (*pc);
+	    continue;
+	  }
       pc = &OMP_CLAUSE_CHAIN (*pc);
     }
 
@@ -32455,24 +32457,25 @@ cp_parser_omp_target_exit_data (cp_parse
   for (tree *pc = &clauses; *pc;)
     {
       if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_MAP)
-       switch (OMP_CLAUSE_MAP_KIND (*pc))
-	 {
-	 case GOMP_MAP_FROM:
-	 case GOMP_MAP_ALWAYS_FROM:
-	 case GOMP_MAP_RELEASE:
-	 case GOMP_MAP_DELETE:
-	 case GOMP_MAP_POINTER:
-	   map_seen = 3;
-	   break;
-	 default:
-	   map_seen |= 1;
-	   error_at (OMP_CLAUSE_LOCATION (*pc),
-		     "%<#pragma omp target exit data%> with map-type other "
-		     "than %<from%>, %<release%> or %<delete%> on %<map%>"
-		     " clause");
-	   *pc = OMP_CLAUSE_CHAIN (*pc);
-	   continue;
-	 }
+	switch (OMP_CLAUSE_MAP_KIND (*pc))
+	  {
+	  case GOMP_MAP_FROM:
+	  case GOMP_MAP_ALWAYS_FROM:
+	  case GOMP_MAP_RELEASE:
+	  case GOMP_MAP_DELETE:
+	    map_seen = 3;
+	    break;
+	  case GOMP_MAP_FIRSTPRIVATE_POINTER:
+	    break;
+	  default:
+	    map_seen |= 1;
+	    error_at (OMP_CLAUSE_LOCATION (*pc),
+		      "%<#pragma omp target exit data%> with map-type other "
+		      "than %<from%>, %<release%> or %<delete%> on %<map%>"
+		      " clause");
+	    *pc = OMP_CLAUSE_CHAIN (*pc);
+	    continue;
+	  }
       pc = &OMP_CLAUSE_CHAIN (*pc);
     }
 
@@ -32637,6 +32640,7 @@ cp_parser_omp_target (cp_parser *parser,
 	  TREE_TYPE (stmt) = void_type_node;
 	  OMP_TARGET_CLAUSES (stmt) = cclauses[C_OMP_CLAUSE_SPLIT_TARGET];
 	  OMP_TARGET_BODY (stmt) = body;
+	  OMP_TARGET_COMBINED (stmt) = 1;
 	  add_stmt (stmt);
 	  pc = &OMP_TARGET_CLAUSES (stmt);
 	  goto check_clauses;
@@ -32697,7 +32701,7 @@ check_clauses:
 	  case GOMP_MAP_TOFROM:
 	  case GOMP_MAP_ALWAYS_TOFROM:
 	  case GOMP_MAP_ALLOC:
-	  case GOMP_MAP_POINTER:
+	  case GOMP_MAP_FIRSTPRIVATE_POINTER:
 	    break;
 	  default:
 	    error_at (OMP_CLAUSE_LOCATION (*pc),
--- gcc/cp/semantics.c.jj	2015-07-17 13:59:27.000000000 +0200
+++ gcc/cp/semantics.c	2015-07-29 16:14:49.040467753 +0200
@@ -4650,7 +4650,7 @@ handle_omp_array_sections_1 (tree c, tre
 /* Handle array sections for clause C.  */
 
 static bool
-handle_omp_array_sections (tree c)
+handle_omp_array_sections (tree c, bool is_omp)
 {
   bool maybe_zero_len = false;
   unsigned int first_non_one = 0;
@@ -4826,10 +4826,26 @@ handle_omp_array_sections (tree c)
 	  OMP_CLAUSE_SIZE (c) = size;
 	  if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP)
 	    return false;
+	  if (is_omp)
+	    switch (OMP_CLAUSE_MAP_KIND (c))
+	      {
+	      case GOMP_MAP_ALLOC:
+	      case GOMP_MAP_TO:
+	      case GOMP_MAP_FROM:
+	      case GOMP_MAP_TOFROM:
+	      case GOMP_MAP_ALWAYS_TO:
+	      case GOMP_MAP_ALWAYS_FROM:
+	      case GOMP_MAP_ALWAYS_TOFROM:
+		OMP_CLAUSE_MAP_MAYBE_ZERO_LENGTH_ARRAY_SECTION (c) = 1;
+		break;
+	      default:
+		break;
+	      }
 	  tree c2 = build_omp_clause (OMP_CLAUSE_LOCATION (c),
 				      OMP_CLAUSE_MAP);
-	  OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_POINTER);
-	  if (!cxx_mark_addressable (t))
+	  OMP_CLAUSE_SET_MAP_KIND (c2, is_omp ? GOMP_MAP_FIRSTPRIVATE_POINTER
+					      : GOMP_MAP_POINTER);
+	  if (!is_omp && !cxx_mark_addressable (t))
 	    return false;
 	  OMP_CLAUSE_DECL (c2) = t;
 	  t = build_fold_addr_expr (first);
@@ -4847,7 +4863,8 @@ handle_omp_array_sections (tree c)
 	  OMP_CLAUSE_CHAIN (c2) = OMP_CLAUSE_CHAIN (c);
 	  OMP_CLAUSE_CHAIN (c) = c2;
 	  ptr = OMP_CLAUSE_DECL (c2);
-	  if (TREE_CODE (TREE_TYPE (ptr)) == REFERENCE_TYPE
+	  if (!is_omp
+	      && TREE_CODE (TREE_TYPE (ptr)) == REFERENCE_TYPE
 	      && POINTER_TYPE_P (TREE_TYPE (TREE_TYPE (ptr))))
 	    {
 	      tree c3 = build_omp_clause (OMP_CLAUSE_LOCATION (c),
@@ -5569,7 +5586,7 @@ finish_omp_clauses (tree clauses, bool a
 	  t = OMP_CLAUSE_DECL (c);
 	  if (TREE_CODE (t) == TREE_LIST)
 	    {
-	      if (handle_omp_array_sections (c))
+	      if (handle_omp_array_sections (c, allow_fields))
 		{
 		  remove = true;
 		  break;
@@ -6155,7 +6172,7 @@ finish_omp_clauses (tree clauses, bool a
 	    }
 	  if (TREE_CODE (t) == TREE_LIST)
 	    {
-	      if (handle_omp_array_sections (c))
+	      if (handle_omp_array_sections (c, allow_fields))
 		remove = true;
 	      break;
 	    }
@@ -6189,7 +6206,7 @@ finish_omp_clauses (tree clauses, bool a
 	  t = OMP_CLAUSE_DECL (c);
 	  if (TREE_CODE (t) == TREE_LIST)
 	    {
-	      if (handle_omp_array_sections (c))
+	      if (handle_omp_array_sections (c, allow_fields))
 		remove = true;
 	      else
 		{
@@ -6242,7 +6259,9 @@ finish_omp_clauses (tree clauses, bool a
 		   && !cxx_mark_addressable (t))
 	    remove = true;
 	  else if (!(OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
-		     && OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_POINTER)
+		     && (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_POINTER
+			 || (OMP_CLAUSE_MAP_KIND (c)
+			     == GOMP_MAP_FIRSTPRIVATE_POINTER)))
 		   && !type_dependent_expression_p (t)
 		   && !cp_omp_mappable_type ((TREE_CODE (TREE_TYPE (t))
 					      == REFERENCE_TYPE)
@@ -6428,12 +6447,14 @@ finish_omp_clauses (tree clauses, bool a
 	    {
 	      tree type = TREE_TYPE (t);
 	      if (TREE_CODE (type) != POINTER_TYPE
+		  && TREE_CODE (type) != ARRAY_TYPE
 		  && (TREE_CODE (type) != REFERENCE_TYPE
-		      || TREE_CODE (TREE_TYPE (type)) != POINTER_TYPE))
+		      || (TREE_CODE (TREE_TYPE (type)) != POINTER_TYPE
+			  && TREE_CODE (TREE_TYPE (type)) != ARRAY_TYPE)))
 		{
 		  error_at (OMP_CLAUSE_LOCATION (c),
-			    "%qs variable is not a pointer or reference "
-			    "to pointer",
+			    "%qs variable is neither a pointer, nor an array"
+			    "nor reference to pointer or array",
 			    omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
 		  remove = true;
 		}
--- include/gomp-constants.h.jj	2015-07-21 09:07:23.689851239 +0200
+++ include/gomp-constants.h	2015-07-29 16:15:20.101012063 +0200
@@ -74,6 +74,17 @@ enum gomp_map_kind
     GOMP_MAP_FORCE_DEVICEPTR =		(GOMP_MAP_FLAG_SPECIAL_1 | 0),
     /* Do not map, copy bits for firstprivate instead.  */
     GOMP_MAP_FIRSTPRIVATE =		(GOMP_MAP_FLAG_SPECIAL | 0),
+    /* Similarly, but store the value in the pointer rather than
+       pointed by the pointer.  */
+    GOMP_MAP_FIRSTPRIVATE_INT =		(GOMP_MAP_FLAG_SPECIAL | 1),
+    /* Pointer translate host address into device address and copy that
+       back to host.  */
+    GOMP_MAP_USE_DEVICE_PTR =		(GOMP_MAP_FLAG_SPECIAL | 2),
+    /* Allocate a zero length array section.  Prefer next non-zero length
+       mapping over previous non-zero length mapping over zero length mapping
+       at the address.  If not already mapped, do nothing (and pointer translate
+       to NULL).  */
+    GOMP_MAP_ZERO_LEN_ARRAY_SECTION = 	(GOMP_MAP_FLAG_SPECIAL | 3),
     /* Allocate.  */
     GOMP_MAP_FORCE_ALLOC =		(GOMP_MAP_FLAG_FORCE | GOMP_MAP_ALLOC),
     /* ..., and copy to device.  */
@@ -95,7 +106,11 @@ enum gomp_map_kind
     GOMP_MAP_DELETE =			GOMP_MAP_FORCE_DEALLOC,
     /* Decrement usage count and deallocate if zero.  */
     GOMP_MAP_RELEASE =			(GOMP_MAP_FLAG_ALWAYS
-					 | GOMP_MAP_FORCE_DEALLOC)
+					 | GOMP_MAP_FORCE_DEALLOC),
+
+    /* Internal to GCC, not used in libgomp.  */
+    /* Do not map, but pointer assign a pointer instead.  */
+    GOMP_MAP_FIRSTPRIVATE_POINTER =	(GOMP_MAP_LAST | 1)
   };
 
 #define GOMP_MAP_COPY_TO_P(X) \
--- libgomp/libgomp.h.jj	2015-07-15 13:00:32.000000000 +0200
+++ libgomp/libgomp.h	2015-07-22 21:09:39.023307107 +0200
@@ -647,11 +647,9 @@ struct target_var_desc {
   bool copy_from;
   /* True if data always should be copied from device to host at the end.  */
   bool always_copy_from;
-  /* Used for unmapping of array sections, can be nonzero only when
-     always_copy_from is true.  */
+  /* Relative offset against key host_start.  */
   uintptr_t offset;
-  /* Used for unmapping of array sections, can be less than the size of the
-     whole object only when always_copy_from is true.  */
+  /* Actual length.  */
   uintptr_t length;
 };
 
--- libgomp/target.c.jj	2015-07-21 09:07:23.690851224 +0200
+++ libgomp/target.c	2015-07-29 17:12:06.377060519 +0200
@@ -142,7 +142,26 @@ resolve_device (int device_id)
 }
 
 
-/* Handle the case where splay_tree_lookup found oldn for newn.
+static inline splay_tree_key
+gomp_map_lookup (splay_tree mem_map, splay_tree_key key)
+{
+  if (key->host_start != key->host_end)
+    return splay_tree_lookup (mem_map, key);
+
+  key->host_end++;
+  splay_tree_key n = splay_tree_lookup (mem_map, key);
+  key->host_end--;
+  if (n)
+    return n;
+  key->host_start--;
+  n = splay_tree_lookup (mem_map, key);
+  key->host_start++;
+  if (n)
+    return n;
+  return splay_tree_lookup (mem_map, key);
+}
+
+/* Handle the case where gomp_map_lookup found oldn for newn.
    Helper function of gomp_map_vars.  */
 
 static inline void
@@ -204,20 +223,8 @@ gomp_map_pointer (struct target_mem_desc
     }
   /* Add bias to the pointer value.  */
   cur_node.host_start += bias;
-  cur_node.host_end = cur_node.host_start + 1;
-  splay_tree_key n = splay_tree_lookup (mem_map, &cur_node);
-  if (n == NULL)
-    {
-      /* Could be possibly zero size array section.  */
-      cur_node.host_end--;
-      n = splay_tree_lookup (mem_map, &cur_node);
-      if (n == NULL)
-	{
-	  cur_node.host_start--;
-	  n = splay_tree_lookup (mem_map, &cur_node);
-	  cur_node.host_start++;
-	}
-    }
+  cur_node.host_end = cur_node.host_start;
+  splay_tree_key n = gomp_map_lookup (mem_map, &cur_node);
   if (n == NULL)
     {
       gomp_mutex_unlock (&devicep->lock);
@@ -271,9 +278,29 @@ gomp_map_vars (struct gomp_device_descr
   for (i = 0; i < mapnum; i++)
     {
       int kind = get_kind (short_mapkind, kinds, i);
-      if (hostaddrs[i] == NULL)
+      if (hostaddrs[i] == NULL
+	  || (kind & typemask) == GOMP_MAP_FIRSTPRIVATE_INT)
 	{
 	  tgt->list[i].key = NULL;
+	  tgt->list[i].offset = ~(uintptr_t) 0;
+	  continue;
+	}
+      else if ((kind & typemask) == GOMP_MAP_USE_DEVICE_PTR)
+	{
+	  cur_node.host_start = (uintptr_t) hostaddrs[i];
+	  cur_node.host_end = cur_node.host_start;
+	  splay_tree_key n = gomp_map_lookup (mem_map, &cur_node);
+	  if (n == NULL)
+	    {
+	      gomp_mutex_unlock (&devicep->lock);
+	      gomp_fatal ("use_device_ptr pointer wasn't mapped");
+	    }
+	  cur_node.host_start -= n->host_start;
+	  hostaddrs[i]
+	    = (void *) (n->tgt->tgt_start + n->tgt_offset
+			+ cur_node.host_start);
+	  tgt->list[i].key = NULL;
+	  tgt->list[i].offset = ~(uintptr_t) 0;
 	  continue;
 	}
       cur_node.host_start = (uintptr_t) hostaddrs[i];
@@ -293,7 +320,19 @@ gomp_map_vars (struct gomp_device_descr
 	  has_firstprivate = true;
 	  continue;
 	}
-      splay_tree_key n = splay_tree_lookup (mem_map, &cur_node);
+      splay_tree_key n;
+      if ((kind & typemask) == GOMP_MAP_ZERO_LEN_ARRAY_SECTION)
+	{
+	  n = gomp_map_lookup (mem_map, &cur_node);
+	  if (!n)
+	    {
+	      tgt->list[i].key = NULL;
+	      tgt->list[i].offset = ~(uintptr_t) 1;
+	      continue;
+	    }
+	}
+      else
+	n = splay_tree_lookup (mem_map, &cur_node);
       if (n)
 	gomp_map_vars_existing (devicep, n, &cur_node, &tgt->list[i],
 				kind & typemask);
@@ -386,6 +425,15 @@ gomp_map_vars (struct gomp_device_descr
 		tgt_size += len;
 		continue;
 	      }
+	    switch (kind & typemask)
+	      {
+	      case GOMP_MAP_FIRSTPRIVATE_INT:
+	      case GOMP_MAP_USE_DEVICE_PTR:
+	      case GOMP_MAP_ZERO_LEN_ARRAY_SECTION:
+		continue;
+	      default:
+		break;
+	      }
 	    splay_tree_key k = &array->key;
 	    k->host_start = (uintptr_t) hostaddrs[i];
 	    if (!GOMP_MAP_POINTER_P (kind & typemask))
@@ -518,15 +566,18 @@ gomp_map_vars (struct gomp_device_descr
 	{
 	  if (tgt->list[i].key == NULL)
 	    {
-	      if (hostaddrs[i] == NULL)
-		cur_node.tgt_offset = (uintptr_t) NULL;
+	      if (tgt->list[i].offset == ~(uintptr_t) 0)
+		cur_node.tgt_offset = (uintptr_t) hostaddrs[i];
+	      else if (tgt->list[i].offset == ~(uintptr_t) 1)
+		cur_node.tgt_offset = 0;
 	      else
 		cur_node.tgt_offset = tgt->tgt_start
 				      + tgt->list[i].offset;
 	    }
 	  else
 	    cur_node.tgt_offset = tgt->list[i].key->tgt->tgt_start
-				  + tgt->list[i].key->tgt_offset;
+				  + tgt->list[i].key->tgt_offset
+				  + tgt->list[i].offset;
 	  /* FIXME: see above FIXME comment.  */
 	  devicep->host2dev_func (devicep->target_id,
 				  (void *) (tgt->tgt_start
@@ -1052,7 +1103,38 @@ GOMP_target_41 (int device, void (*fn) (
 
   if (devicep == NULL
       || !(devicep->capabilities & GOMP_OFFLOAD_CAP_OPENMP_400))
-    return gomp_target_fallback (fn, hostaddrs);
+    {
+      size_t i, tgt_align = 0, tgt_size = 0;
+      char *tgt = NULL;
+      for (i = 0; i < mapnum; i++)
+	if ((kinds[i] & 0xff) == GOMP_MAP_FIRSTPRIVATE)
+	  {
+	    size_t align = (size_t) 1 << (kinds[i] >> 8);
+	    if (tgt_align < align)
+	      tgt_align = align;
+	    tgt_size = (tgt_size + align - 1) & ~(align - 1);
+	    tgt_size += sizes[i];
+	  }
+      if (tgt_align)
+	{
+	  tgt = gomp_alloca (tgt_size + tgt_align - 1);
+	  uintptr_t al = (uintptr_t) tgt & (tgt_align - 1);
+	  if (al)
+	    tgt += tgt_align - al;
+	  tgt_size = 0;
+	  for (i = 0; i < mapnum; i++)
+	    if ((kinds[i] & 0xff) == GOMP_MAP_FIRSTPRIVATE)
+	      {
+		size_t align = (size_t) 1 << (kinds[i] >> 8);
+		tgt_size = (tgt_size + align - 1) & ~(align - 1);
+		memcpy (tgt + tgt_size, hostaddrs[i], sizes[i]);
+		hostaddrs[i] = tgt + tgt_size;
+		tgt_size = tgt_size + sizes[i];
+	      }
+	}
+      gomp_target_fallback (fn, hostaddrs);
+      return;
+    }
 
   void *fn_addr = gomp_get_target_fn_addr (devicep, fn);
 
@@ -1289,20 +1371,8 @@ omp_target_is_present (void *ptr, size_t
   struct splay_tree_key_s cur_node;
 
   cur_node.host_start = (uintptr_t) ptr + offset;
-  cur_node.host_end = cur_node.host_start + 1;
-  splay_tree_key n = splay_tree_lookup (mem_map, &cur_node);
-  if (n == NULL)
-    {
-      /* Could be possibly zero size array section.  */
-      cur_node.host_end--;
-      n = splay_tree_lookup (mem_map, &cur_node);
-      if (n == NULL)
-	{
-	  cur_node.host_start--;
-	  n = splay_tree_lookup (mem_map, &cur_node);
-	  cur_node.host_start++;
-	}
-    }
+  cur_node.host_end = cur_node.host_start;
+  splay_tree_key n = gomp_map_lookup (mem_map, &cur_node);
   int ret = n != NULL;
   gomp_mutex_unlock (&devicep->lock);
   return ret;
@@ -1524,7 +1594,7 @@ omp_target_associate_ptr (void *host_ptr
 
   cur_node.host_start = (uintptr_t) host_ptr;
   cur_node.host_end = cur_node.host_start + size;
-  splay_tree_key n = splay_tree_lookup (mem_map, &cur_node);
+  splay_tree_key n = gomp_map_lookup (mem_map, &cur_node);
   if (n)
     {
       if (n->tgt->tgt_start + n->tgt_offset
@@ -1584,13 +1654,8 @@ omp_target_disassociate_ptr (void *ptr,
   int ret = EINVAL;
 
   cur_node.host_start = (uintptr_t) ptr;
-  cur_node.host_end = cur_node.host_start + 1;
-  splay_tree_key n = splay_tree_lookup (mem_map, &cur_node);
-  if (n == NULL)
-    {
-      cur_node.host_end--;
-      n = splay_tree_lookup (mem_map, &cur_node);
-    }
+  cur_node.host_end = cur_node.host_start;
+  splay_tree_key n = gomp_map_lookup (mem_map, &cur_node);
   if (n
       && n->host_start == cur_node.host_start
       && n->refcount == REFCOUNT_INFINITY
--- libgomp/testsuite/libgomp.c++/target-2.C.jj	2015-06-30 14:24:03.000000000 +0200
+++ libgomp/testsuite/libgomp.c++/target-2.C	2015-07-23 17:48:08.978674497 +0200
@@ -33,7 +33,8 @@ fn2 (int x, double (&dr) [1024], double
   int j;
   fn1 (hr + 2 * x, ir + 2 * x, x);
   #pragma omp target map(to: br[:x], cr[0:x], dr[x:x], er[x:x]) \
-		     map(to: fr[0:x], gr[0:x], hr[2 * x:x], ir[2 * x:x])
+		     map(to: fr[0:x], gr[0:x], hr[2 * x:x], ir[2 * x:x]) \
+		     map(tofrom: s)
     #pragma omp parallel for reduction(+:s)
       for (j = 0; j < x; j++)
 	s += br[j] * cr[j] + dr[x + j] + er[x + j]
--- libgomp/testsuite/libgomp.c++/target-7.C.jj	2015-07-22 11:36:53.042867520 +0200
+++ libgomp/testsuite/libgomp.c++/target-7.C	2015-07-22 11:32:00.000000000 +0200
@@ -0,0 +1,90 @@
+extern "C" void abort ();
+
+void
+foo (int *x, int *&y, int (&z)[15])
+{
+  int a[10], b[15], err, i;
+  for (i = 0; i < 10; i++)
+    a[i] = 7 * i;
+  for (i = 0; i < 15; i++)
+    b[i] = 8 * i;
+  #pragma omp target map(to:x[5:10], y[5:10], z[5:10], a[0:10], b[5:10]) map(from:err)
+  {
+    err = 0;
+    for (i = 0; i < 10; i++)
+      if (x[5 + i] != 20 + 4 * i
+	  || y[5 + i] != 25 + 5 * i
+	  || z[5 + i] != 30 + 6 * i
+	  || a[i] != 7 * i
+	  || b[5 + i] != 40 + 8 * i)
+	err = 1;
+  }
+  if (err)
+    abort ();
+}
+
+void
+bar (int n, int v)
+{
+  int a[n], b[n], c[n], d[n], e[n], err, i;
+  int (*x)[n] = &c;
+  int (*y2)[n] = &d;
+  int (*&y)[n] = y2;
+  int (&z)[n] = e;
+  for (i = 0; i < n; i++)
+    {
+      (*x)[i] = 4 * i;
+      (*y)[i] = 5 * i;
+      z[i] = 6 * i;
+      a[i] = 7 * i;
+      b[i] = 8 * i;
+    }
+  #pragma omp target map(to:x[0][5:10], y[0][5:10], z[5:10], a[0:10], b[5:10]) map(from:err)
+  {
+    err = 0;
+    for (i = 0; i < 10; i++)
+      if ((*x)[5 + i] != 20 + 4 * i
+	  || (*y)[5 + i] != 25 + 5 * i
+	  || z[5 + i] != 30 + 6 * i
+	  || a[i] != 7 * i
+	  || b[5 + i] != 40 + 8 * i)
+	err = 1;
+  }
+  if (err)
+    abort ();
+  for (i = 0; i < n; i++)
+    {
+      (*x)[i] = 9 * i;
+      (*y)[i] = 10 * i;
+      z[i] = 11 * i;
+      a[i] = 12 * i;
+      b[i] = 13 * i;
+    }
+  #pragma omp target map(to:x[0][v:v+5], y[0][v:v+5], z[v:v+5], a[v-5:v+5], b[v:v+5]) map(from:err)
+  {
+    err = 0;
+    for (i = 0; i < 10; i++)
+      if ((*x)[5 + i] != 45 + 9 * i
+	  || (*y)[5 + i] != 50 + 10 * i
+	  || z[5 + i] != 55 + 11 * i
+	  || a[i] != 12 * i
+	  || b[5 + i] != 65 + 13 * i)
+	err = 1;
+  }
+  if (err)
+    abort ();
+}
+
+int
+main ()
+{
+  int x[15], y2[15], z[15], *y = y2, i;
+  for (i = 0; i < 15; i++)
+    {
+      x[i] = 4 * i;
+      y[i] = 5 * i;
+      z[i] = 6 * i;
+    }
+  foo (x, y, z);
+  bar (15, 5);
+}
--- libgomp/testsuite/libgomp.c++/target-8.C.jj	2015-07-27 13:39:49.446401028 +0200
+++ libgomp/testsuite/libgomp.c++/target-8.C	2015-07-27 13:39:27.000000000 +0200
@@ -0,0 +1,58 @@
+extern "C" void abort ();
+struct S { int a; };
+#ifdef __SIZEOF_INT128__
+typedef __int128 T;
+#else
+typedef long long int T;
+#endif
+
+void
+foo (T a, int b, struct S c)
+{
+  int err;
+  #pragma omp target firstprivate (a, b, c) map(from:err)
+  {
+    err = 0;
+    if (a != 131 || b != 276 || c.a != 59)
+      err = 1;
+    a = 936;
+    b = 27;
+    c.a = 98;
+    if (a != 936 || b != 27 || c.a != 98)
+      err = 1;
+  }
+  if (err || a != 131 || b != 276 || c.a != 59)
+    abort ();
+}
+
+void
+bar (T &a, int &b, struct S &c)
+{
+  int err;
+  #pragma omp target firstprivate (a, b, c) map(from:err)
+  {
+    err = 0;
+    if (a != 131 || b != 276 || c.a != 59)
+      err = 1;
+    a = 936;
+    b = 27;
+    c.a = 98;
+    if (a != 936 || b != 27 || c.a != 98)
+      err = 1;
+  }
+  if (err || a != 131 || b != 276 || c.a != 59)
+    abort ();
+}
+
+int
+main ()
+{
+  T a = 131;
+  int b = 276;
+  struct S c;
+  c.a = 59;
+  foo (a, b, c);
+  bar (a, b, c);
+  if (a != 131 || b != 276 || c.a != 59)
+    abort ();
+}
--- libgomp/testsuite/libgomp.c++/target-9.C.jj	2015-07-28 16:57:29.940191999 +0200
+++ libgomp/testsuite/libgomp.c++/target-9.C	2015-07-28 20:30:05.951617430 +0200
@@ -0,0 +1,73 @@
+extern "C" void abort (void);
+
+void
+foo (int *&p, int (&s)[5], int n)
+{
+  int a[4] = { 7, 8, 9, 10 }, b[n], c[3] = { 20, 21, 22 };
+  int *r = a + 1, *q = p - 1, i, err;
+  for (i = 0; i < n; i++)
+    b[i] = 9 + i;
+  #pragma omp target data map(to:a)
+  #pragma omp target data use_device_ptr(r) map(from:err)
+  #pragma omp target is_device_ptr(r) private(i) map(from:err)
+  {
+    err = 0;
+    for (i = 0; i < 4; i++)
+      if (r[i - 1] != 7 + i)
+	err = 1;
+  }
+  if (err)
+    abort ();
+  #pragma omp target data map(to:q[:4])
+  #pragma omp target data use_device_ptr(p) map(from:err)
+  #pragma omp target is_device_ptr(p) private(i) map(from:err)
+  {
+    err = 0;
+    for (i = 0; i < 4; i++)
+      if (p[i - 1] != i)
+	err = 1;
+  }
+  if (err)
+    abort ();
+  #pragma omp target data map(to:b)
+  #pragma omp target data use_device_ptr(b) map(from:err)
+  #pragma omp target is_device_ptr(b) private(i) map(from:err)
+  {
+    err = 0;
+    for (i = 0; i < n; i++)
+      if (b[i] != 9 + i)
+	err = 1;
+  }
+  if (err)
+    abort ();
+  #pragma omp target data map(to:c)
+  #pragma omp target data use_device_ptr(c) map(from:err)
+  #pragma omp target is_device_ptr(c) private(i) map(from:err)
+  {
+    err = 0;
+    for (i = 0; i < 3; i++)
+      if (c[i] != 20 + i)
+	err = 1;
+  }
+  if (err)
+    abort ();
+  #pragma omp target data map(to:s[:5])
+  #pragma omp target data use_device_ptr(s) map(from:err)
+  #pragma omp target is_device_ptr(s) private(i) map(from:err)
+  {
+    err = 0;
+    for (i = 0; i < 5; i++)
+      if (s[i] != 17 + i)
+	err = 1;
+  }
+  if (err)
+    abort ();
+}
+
+int
+main ()
+{
+  int a[4] = { 0, 1, 2, 3 }, b[5] = { 17, 18, 19, 20, 21 };
+  int *p = a + 1;
+  foo (p, b, 9);
+}
--- libgomp/testsuite/libgomp.c/target-1.c.jj	2015-04-24 12:30:40.000000000 +0200
+++ libgomp/testsuite/libgomp.c/target-1.c	2015-07-23 17:08:32.474133124 +0200
@@ -34,7 +34,7 @@ fn2 (int x, int y, int z)
   fn1 (b, c, x);
   #pragma omp target data map(to: b)
   {
-    #pragma omp target map(tofrom: c)
+    #pragma omp target map(tofrom: c, s)
       #pragma omp teams num_teams(y) thread_limit(z) reduction(+:s) firstprivate(x)
 	#pragma omp distribute dist_schedule(static, 4) collapse(1)
 	  for (j=0; j < x; j += y)
@@ -52,7 +52,7 @@ fn3 (int x)
   double b[1024], c[1024], s = 0;
   int i;
   fn1 (b, c, x);
-  #pragma omp target map(to: b, c)
+  #pragma omp target map(to: b, c) map(tofrom:s)
     #pragma omp parallel for reduction(+:s)
       for (i = 0; i < x; i++)
 	tgt (), s += b[i] * c[i];
@@ -66,7 +66,8 @@ fn4 (int x, double *p)
   int i;
   fn1 (b, c, x);
   fn1 (d + x, p + x, x);
-  #pragma omp target map(to: b, c[0:x], d[x:x]) map(to:p[x:64 + (x & 31)])
+  #pragma omp target map(to: b, c[0:x], d[x:x]) map(to:p[x:64 + (x & 31)]) \
+		     map(tofrom: s)
     #pragma omp parallel for reduction(+:s)
       for (i = 0; i < x; i++)
 	s += b[i] * c[i] + d[x + i] + p[x + i];
--- libgomp/testsuite/libgomp.c/target-2.c.jj	2015-04-24 12:30:40.000000000 +0200
+++ libgomp/testsuite/libgomp.c/target-2.c	2015-07-23 17:09:27.987350372 +0200
@@ -23,7 +23,7 @@ fn2 (int x)
   int i;
   fn1 (b, c, x);
   fn1 (e, d + x, x);
-  #pragma omp target map(to: b, c[:x], d[x:x], e)
+  #pragma omp target map(to: b, c[:x], d[x:x], e) map(tofrom: s)
     #pragma omp parallel for reduction(+:s)
       for (i = 0; i < x; i++)
 	s += b[i] * c[i] + d[x + i] + sizeof (b) - sizeof (c);
@@ -38,7 +38,7 @@ fn3 (int x)
   int i;
   fn1 (b, c, x);
   fn1 (e, d, x);
-  #pragma omp target
+  #pragma omp target map(tofrom: s)
     #pragma omp parallel for reduction(+:s)
       for (i = 0; i < x; i++)
 	s += b[i] * c[i] + d[i];
@@ -56,7 +56,7 @@ fn4 (int x)
   #pragma omp target data map(from: b, c[:x], d[x:x], e)
     {
       #pragma omp target update to(b, c[:x], d[x:x], e)
-      #pragma omp target map(c[:x], d[x:x])
+      #pragma omp target map(c[:x], d[x:x], s)
 	#pragma omp parallel for reduction(+:s)
 	  for (i = 0; i < x; i++)
 	    {
--- libgomp/testsuite/libgomp.c/target-7.c.jj	2015-04-24 12:30:40.000000000 +0200
+++ libgomp/testsuite/libgomp.c/target-7.c	2015-07-23 17:12:33.159753962 +0200
@@ -37,63 +37,63 @@ foo (int f)
     abort ();
   #pragma omp target data device (d) map (to: h)
   {
-    #pragma omp target device (d)
+    #pragma omp target device (d) map (h)
     if (omp_get_level () != 0 || (f && !omp_is_initial_device ()) || h++ != 5)
       abort ();
     #pragma omp target update device (d) from (h)
   }
   #pragma omp target data if (v > 1) map (to: h)
   {
-    #pragma omp target if (v > 1)
+    #pragma omp target if (v > 1) map(h)
     if (omp_get_level () != 0 || !omp_is_initial_device () || h++ != 6)
       abort ();
     #pragma omp target update if (v > 1) from (h)
   }
   #pragma omp target data device (d) if (v > 1) map (to: h)
   {
-    #pragma omp target device (d) if (v > 1)
+    #pragma omp target device (d) if (v > 1) map(h)
     if (omp_get_level () != 0 || !omp_is_initial_device () || h++ != 7)
       abort ();
     #pragma omp target update device (d) if (v > 1) from (h)
   }
   #pragma omp target data if (v <= 1) map (to: h)
   {
-    #pragma omp target if (v <= 1)
+    #pragma omp target if (v <= 1) map (tofrom: h)
     if (omp_get_level () != 0 || h++ != 8)
       abort ();
     #pragma omp target update if (v <= 1) from (h)
   }
   #pragma omp target data device (d) if (v <= 1) map (to: h)
   {
-    #pragma omp target device (d) if (v <= 1)
+    #pragma omp target device (d) if (v <= 1) map (h)
     if (omp_get_level () != 0 || (f && !omp_is_initial_device ()) || h++ != 9)
       abort ();
     #pragma omp target update device (d) if (v <= 1) from (h)
   }
   #pragma omp target data if (0) map (to: h)
   {
-    #pragma omp target if (0)
+    #pragma omp target if (0) map (h)
     if (omp_get_level () != 0 || !omp_is_initial_device () || h++ != 10)
       abort ();
     #pragma omp target update if (0) from (h)
   }
   #pragma omp target data device (d) if (0) map (to: h)
   {
-    #pragma omp target device (d) if (0)
+    #pragma omp target device (d) if (0) map (h)
     if (omp_get_level () != 0 || !omp_is_initial_device () || h++ != 11)
       abort ();
     #pragma omp target update device (d) if (0) from (h)
   }
   #pragma omp target data if (1) map (to: h)
   {
-    #pragma omp target if (1)
+    #pragma omp target if (1) map (tofrom: h)
     if (omp_get_level () != 0 || h++ != 12)
       abort ();
     #pragma omp target update if (1) from (h)
   }
   #pragma omp target data device (d) if (1) map (to: h)
   {
-    #pragma omp target device (d) if (1)
+    #pragma omp target device (d) if (1) map (tofrom: h)
     if (omp_get_level () != 0 || (f && !omp_is_initial_device ()) || h++ != 13)
       abort ();
     #pragma omp target update device (d) if (1) from (h)
--- libgomp/testsuite/libgomp.c/target-15.c.jj	2015-07-22 11:37:11.655612690 +0200
+++ libgomp/testsuite/libgomp.c/target-15.c	2015-07-23 21:53:37.354632916 +0200
@@ -0,0 +1,74 @@
+extern void abort (void);
+
+void
+foo (int *x)
+{
+  int a[10], b[15], err, i;
+  for (i = 0; i < 10; i++)
+    a[i] = 7 * i;
+  for (i = 0; i < 15; i++)
+    b[i] = 8 * i;
+  #pragma omp target map(to:x[5:10], a[0:10], b[5:10]) map(from:err)
+  {
+    err = 0;
+    for (i = 0; i < 10; i++)
+      if (x[5 + i] != 20 + 4 * i
+	  || a[i] != 7 * i
+	  || b[5 + i] != 40 + 8 * i)
+	err = 1;
+  }
+  if (err)
+    abort ();
+}
+
+void
+bar (int n, int v)
+{
+  int a[n], b[n], c[n], d[n], e[n], err, i;
+  int (*x)[n] = &c;
+  for (i = 0; i < n; i++)
+    {
+      (*x)[i] = 4 * i;
+      a[i] = 7 * i;
+      b[i] = 8 * i;
+    }
+  #pragma omp target map(to:x[0][5:10], a[0:10], b[5:10]) map(from:err)
+  {
+    err = 0;
+    for (i = 0; i < 10; i++)
+      if ((*x)[5 + i] != 20 + 4 * i
+	  || a[i] != 7 * i
+	  || b[5 + i] != 40 + 8 * i)
+	err = 1;
+  }
+  if (err)
+    abort ();
+  for (i = 0; i < n; i++)
+    {
+      (*x)[i] = 9 * i;
+      a[i] = 12 * i;
+      b[i] = 13 * i;
+    }
+  #pragma omp target map(to:x[0][v:v+5], a[v-5:v+5], b[v:v+5]) map(from:err)
+  {
+    err = 0;
+    for (i = 0; i < 10; i++)
+      if ((*x)[5 + i] != 45 + 9 * i
+	  || a[i] != 12 * i
+	  || b[5 + i] != 65 + 13 * i)
+	err = 1;
+  }
+  if (err)
+    abort ();
+}
+
+int
+main ()
+{
+  int x[15], i;
+  for (i = 0; i < 15; i++)
+    x[i] = 4 * i;
+  foo (x);
+  bar (15, 5);
+  return 0;
+}
--- libgomp/testsuite/libgomp.c/target-16.c.jj	2015-07-23 21:53:28.905753778 +0200
+++ libgomp/testsuite/libgomp.c/target-16.c	2015-07-24 12:20:32.048722516 +0200
@@ -0,0 +1,45 @@
+extern void abort (void);
+
+void
+foo (int n)
+{
+  int a[n], i, err;
+  for (i = 0; i < n; i++)
+    a[i] = 7 * i;
+  #pragma omp target firstprivate (a) map(from:err) private (i)
+  {
+    err = 0;
+    for (i = 0; i < n; i++)
+      if (a[i] != 7 * i)
+	err = 1;
+  }
+  if (err)
+    abort ();
+}
+
+void
+bar (int n)
+{
+  int a[n], i, err;
+  #pragma omp target private (a) map(from:err)
+  {
+    #pragma omp parallel for
+    for (i = 0; i < n; i++)
+      a[i] = 7 * i;
+    err = 0;
+    #pragma omp parallel for reduction(|:err)
+    for (i = 0; i < n; i++)
+      if (a[i] != 7 * i)
+	err |= 1;
+  }
+  if (err)
+    abort ();
+}
+
+int
+main ()
+{
+  foo (7);
+  bar (7);
+  return 0;
+}
--- libgomp/testsuite/libgomp.c/target-17.c.jj	2015-07-24 19:50:14.275109272 +0200
+++ libgomp/testsuite/libgomp.c/target-17.c	2015-07-24 19:47:57.000000000 +0200
@@ -0,0 +1,99 @@
+extern void abort (void);
+
+void
+foo (int n)
+{
+  int a[n], i, err;
+  for (i = 0; i < n; i++)
+    a[i] = 5 * i;
+  #pragma omp target map(to:a) map(from:err) private(i)
+  {
+    err = 0;
+    for (i = 0; i < n; i++)
+      if (a[i] != 5 * i)
+	err = 1;
+  }
+  if (err)
+    abort ();
+  for (i = 0; i < n; i++)
+    a[i] += i;
+  #pragma omp target map(from:err) private(i)
+  {
+    err = 0;
+    for (i = 0; i < n; i++)
+      if (a[i] != 6 * i)
+	err = 1;
+  }
+  if (err)
+    abort ();
+  for (i = 0; i < n; i++)
+    a[i] += i;
+  #pragma omp target firstprivate (a) map(from:err) private(i)
+  {
+    err = 0;
+    for (i = 0; i < n; i++)
+      if (a[i] != 7 * i)
+	err = 1;
+  }
+  if (err)
+    abort ();
+  int on = n;
+  #pragma omp target firstprivate (n) map(tofrom: n)
+  {
+    n++;
+  }
+  if (on != n)
+    abort ();
+  #pragma omp target map(tofrom: n) private (n)
+  {
+    n = 25;
+  }
+  if (on != n)
+    abort ();
+  for (i = 0; i < n; i++)
+    a[i] += i;
+  #pragma omp target map(to:a) firstprivate (a) map(from:err) private(i)
+  {
+    err = 0;
+    for (i = 0; i < n; i++)
+      if (a[i] != 8 * i)
+	err = 1;
+  }
+  if (err)
+    abort ();
+  for (i = 0; i < n; i++)
+    a[i] += i;
+  #pragma omp target firstprivate (a) map(to:a) map(from:err) private(i)
+  {
+    err = 0;
+    for (i = 0; i < n; i++)
+      if (a[i] != 9 * i)
+	err = 1;
+  }
+  if (err)
+    abort ();
+  for (i = 0; i < n; i++)
+    a[i] += i;
+  #pragma omp target map(tofrom:a) map(from:err) private(a, i)
+  {
+    err = 0;
+    for (i = 0; i < n; i++)
+      a[i] = 7;
+    #pragma omp parallel for reduction(|:err)
+    for (i = 0; i < n; i++)
+      if (a[i] != 7)
+	err |= 1;
+  }
+  if (err)
+    abort ();
+  for (i = 0; i < n; i++)
+    if (a[i] != 10 * i)
+      abort ();
+}
+
+int
+main ()
+{
+  foo (9);
+  return 0;
+}
--- libgomp/testsuite/libgomp.c/target-18.c.jj	2015-07-28 16:50:12.139587099 +0200
+++ libgomp/testsuite/libgomp.c/target-18.c	2015-07-28 19:59:41.000000000 +0200
@@ -0,0 +1,52 @@
+extern void abort (void);
+
+void
+foo (int n)
+{
+  int a[4] = { 0, 1, 2, 3 }, b[n];
+  int *p = a + 1, i, err;
+  for (i = 0; i < n; i++)
+    b[i] = 9 + i;
+  #pragma omp target data map(to:a)
+  #pragma omp target data use_device_ptr(p) map(from:err)
+  #pragma omp target is_device_ptr(p) private(i) map(from:err)
+  {
+    err = 0;
+    for (i = 0; i < 4; i++)
+      if (p[i - 1] != i)
+	err = 1;
+  }
+  if (err)
+    abort ();
+  for (i = 0; i < 4; i++)
+    a[i] = 23 + i;
+  #pragma omp target data map(to:a)
+  #pragma omp target data use_device_ptr(a) map(from:err)
+  #pragma omp target is_device_ptr(a) private(i) map(from:err)
+  {
+    err = 0;
+    for (i = 0; i < 4; i++)
+      if (a[i] != 23 + i)
+	err = 1;
+  }
+  if (err)
+    abort ();
+  #pragma omp target data map(to:b)
+  #pragma omp target data use_device_ptr(b) map(from:err)
+  #pragma omp target is_device_ptr(b) private(i) map(from:err)
+  {
+    err = 0;
+    for (i = 0; i < 4; i++)
+      if (b[i] != 9 + i)
+	err = 1;
+  }
+  if (err)
+    abort ();
+}
+
+int
+main ()
+{
+  foo (9);
+  return 0;
+}
--- libgomp/testsuite/libgomp.c/target-19.c.jj	2015-07-29 16:28:01.783837512 +0200
+++ libgomp/testsuite/libgomp.c/target-19.c	2015-07-29 16:32:42.800714833 +0200
@@ -0,0 +1,127 @@
+extern void abort (void);
+
+void
+foo (int *p, int *q, int *r, int n, int m)
+{
+  int i, err, *s = r;
+  #pragma omp target data map(to:p[0:8])
+  {
+    /* For zero length array sections, p points to the start of
+       already mapped range, q to the end of it, and r does not point
+       to an mapped range.  */
+    #pragma omp target map(alloc:p[:0]) map(to:q[:0]) map(from:r[:0]) private(i) map(from:err) firstprivate (s)
+    {
+      err = 0;
+      for (i = 0; i < 8; i++)
+	if (p[i] != i + 1 || q[i - 8] != i + 1)
+	  err = 1;
+      if (p + 8 != q || (r != (int *) 0 && r != s))
+	err = 1;
+    }
+    if (err)
+      abort ();
+    /* Implicit mapping of pointers behaves the same way.  */
+    #pragma omp target private(i) map(from:err) firstprivate (s)
+    {
+      err = 0;
+      for (i = 0; i < 8; i++)
+	if (p[i] != i + 1 || q[i - 8] != i + 1)
+	  err = 1;
+      if (p + 8 != q || (r != (int *) 0 && r != s))
+	err = 1;
+    }
+    if (err)
+      abort ();
+    /* And zero-length array sections, though not known at compile
+       time, behave the same.  */
+    #pragma omp target map(p[:n]) map(tofrom:q[:n]) map(alloc:r[:n]) private(i) map(from:err) firstprivate (s)
+    {
+      err = 0;
+      for (i = 0; i < 8; i++)
+	if (p[i] != i + 1 || q[i - 8] != i + 1)
+	  err = 1;
+      if (p + 8 != q || (r != (int *) 0 && r != s))
+	err = 1;
+    }
+    if (err)
+      abort ();
+    /* Non-zero length array sections, though not known at compile,
+       behave differently.  */
+    #pragma omp target map(p[:m]) map(tofrom:q[:m]) map(to:r[:m]) private(i) map(from:err)
+    {
+      err = 0;
+      for (i = 0; i < 8; i++)
+	if (p[i] != i + 1)
+	  err = 1;
+      if (q[0] != 9 || r[0] != 10)
+	err = 1;
+    }
+    if (err)
+      abort ();
+    #pragma omp target data map(to:q[0:1])
+    {
+      /* For zero length array sections, p points to the start of
+	 already mapped range, q points to the start of another one,
+	 and r to the end of the second one.  */
+      #pragma omp target map(to:p[:0]) map(from:q[:0]) map(tofrom:r[:0]) private(i) map(from:err)
+      {
+	err = 0;
+	for (i = 0; i < 8; i++)
+	  if (p[i] != i + 1)
+	    err = 1;
+	if (q[0] != 9 || r != q + 1)
+	  err = 1;
+      }
+      if (err)
+	abort ();
+      /* Implicit mapping of pointers behaves the same way.  */
+      #pragma omp target private(i) map(from:err)
+      {
+	err = 0;
+	for (i = 0; i < 8; i++)
+	  if (p[i] != i + 1)
+	    err = 1;
+	if (q[0] != 9 || r != q + 1)
+	  err = 1;
+      }
+      if (err)
+	abort ();
+      /* And zero-length array sections, though not known at compile
+	 time, behave the same.  */
+      #pragma omp target map(p[:n]) map(alloc:q[:n]) map(from:r[:n]) private(i) map(from:err)
+      {
+	err = 0;
+	for (i = 0; i < 8; i++)
+	  if (p[i] != i + 1)
+	    err = 1;
+	if (q[0] != 9 || r != q + 1)
+	  err = 1;
+      }
+      if (err)
+	abort ();
+      /* Non-zero length array sections, though not known at compile,
+	 behave differently.  */
+      #pragma omp target map(p[:m]) map(alloc:q[:m]) map(tofrom:r[:m]) private(i) map(from:err)
+      {
+	err = 0;
+	for (i = 0; i < 8; i++)
+	  if (p[i] != i + 1)
+	    err = 1;
+	if (q[0] != 9 || r[0] != 10)
+	  err = 1;
+      }
+      if (err)
+	abort ();
+    }
+  }
+}
+
+int
+main ()
+{
+  int a[32], i;
+  for (i = 0; i < 32; i++)
+    a[i] = i;
+  foo (a + 1, a + 9, a + 10, 0, 1);
+  return 0;
+}
--- libgomp/testsuite/libgomp.c/examples-4/e.51.3.c.jj	2015-04-24 12:30:40.000000000 +0200
+++ libgomp/testsuite/libgomp.c/examples-4/e.51.3.c	2015-07-23 15:58:15.867779262 +0200
@@ -47,7 +47,7 @@ void gramSchmidt (int Q[][COLS], const i
       {
 	int tmp = 0;
 
-	#pragma omp target
+	#pragma omp target map(tofrom:tmp)
 	  #pragma omp parallel for reduction(+:tmp)
 	    for (i = 0; i < rows; i++)
 	      tmp += (Q[i][k] * Q[i][k]);
--- libgomp/testsuite/libgomp.c/examples-4/e.53.1.c.jj	2015-04-24 12:30:40.000000000 +0200
+++ libgomp/testsuite/libgomp.c/examples-4/e.53.1.c	2015-07-23 15:59:44.430518114 +0200
@@ -20,7 +20,7 @@ int fib_wrapper (int n)
 {
   int x = 0;
 
-  #pragma omp target if(n > THRESHOLD)
+  #pragma omp target if(n > THRESHOLD) map(from:x)
     x = fib (n);
 
   return x;
--- libgomp/testsuite/libgomp.c/examples-4/e.53.4.c.jj	2015-04-24 12:30:40.000000000 +0200
+++ libgomp/testsuite/libgomp.c/examples-4/e.53.4.c	2015-07-23 16:00:22.468976440 +0200
@@ -41,7 +41,7 @@ float accum (int k)
   int i;
   float tmp = 0.0;
 
-  #pragma omp target
+  #pragma omp target map(tofrom:tmp)
     #pragma omp parallel for reduction(+:tmp)
       for (i = 0; i < N; i++)
 	tmp += Pfun (i, k);
--- libgomp/testsuite/libgomp.c/examples-4/e.53.5.c.jj	2015-06-17 21:00:36.000000000 +0200
+++ libgomp/testsuite/libgomp.c/examples-4/e.53.5.c	2015-07-23 16:01:17.802188485 +0200
@@ -48,7 +48,7 @@ float accum ()
   int i, k;
   float tmp = 0.0;
 
-  #pragma omp target
+  #pragma omp target map(tofrom:tmp)
     #pragma omp parallel for reduction(+:tmp)
       for (i = 0; i < N; i++)
 	{
--- libgomp/testsuite/libgomp.c/examples-4/e.54.2.c.jj	2015-04-24 12:30:40.000000000 +0200
+++ libgomp/testsuite/libgomp.c/examples-4/e.54.2.c	2015-07-23 16:02:02.343554209 +0200
@@ -32,7 +32,7 @@ float dotprod (float B[], float C[], int
   int i, i0;
   float sum = 0;
 
-  #pragma omp target map(to: B[0:n], C[0:n])
+  #pragma omp target map(to: B[0:n], C[0:n]) map(tofrom: sum)
     #pragma omp teams num_teams(num_teams) thread_limit(block_threads) \
 		      reduction(+:sum)
       #pragma omp distribute
--- libgomp/testsuite/libgomp.c/examples-4/e.54.3.c.jj	2015-04-24 12:30:40.000000000 +0200
+++ libgomp/testsuite/libgomp.c/examples-4/e.54.3.c	2015-07-23 16:02:28.060187999 +0200
@@ -31,7 +31,7 @@ float dotprod (float B[], float C[], int
   int i;
   float sum = 0;
 
-  #pragma omp target teams map(to: B[0:n], C[0:n])
+  #pragma omp target teams map(to: B[0:n], C[0:n]) map(tofrom: sum)
     #pragma omp distribute parallel for reduction(+:sum)
       for (i = 0; i < n; i++)
 	sum += B[i] * C[i];
--- libgomp/testsuite/libgomp.c/examples-4/e.54.4.c.jj	2015-04-24 12:30:40.000000000 +0200
+++ libgomp/testsuite/libgomp.c/examples-4/e.54.4.c	2015-07-23 16:03:21.446427770 +0200
@@ -31,7 +31,7 @@ float dotprod (float B[], float C[], int
   int i;
   float sum = 0;
 
-  #pragma omp target map(to: B[0:n], C[0:n])
+  #pragma omp target map(to: B[0:n], C[0:n]) map(tofrom:sum)
     #pragma omp teams num_teams(8) thread_limit(16)
       #pragma omp distribute parallel for reduction(+:sum) \
 					  dist_schedule(static, 1024) \
--- libgomp/testsuite/libgomp.c/examples-4/e.57.1.c.jj	2015-04-24 12:30:40.000000000 +0200
+++ libgomp/testsuite/libgomp.c/examples-4/e.57.1.c	2015-07-23 17:37:01.880139916 +0200
@@ -10,11 +10,11 @@ int main ()
   int b = 0;
   int c, d;
 
-  #pragma omp target if(a > 200 && a < 400)
+  #pragma omp target if(a > 200 && a < 400) map(from: c)
     c = omp_is_initial_device ();
 
   #pragma omp target data map(to: b) if(a > 200 && a < 400)
-    #pragma omp target
+    #pragma omp target map(from: b, d)
       {
 	b = 100;
 	d = omp_is_initial_device ();
@@ -26,11 +26,11 @@ int main ()
   a += 200;
   b = 0;
 
-  #pragma omp target if(a > 200 && a < 400)
+  #pragma omp target if(a > 200 && a < 400) map(from: c)
     c = omp_is_initial_device ();
 
   #pragma omp target data map(to: b) if(a > 200 && a < 400)
-    #pragma omp target
+    #pragma omp target map(from: b, d)
       {
 	b = 100;
 	d = omp_is_initial_device ();
@@ -42,11 +42,11 @@ int main ()
   a += 200;
   b = 0;
 
-  #pragma omp target if(a > 200 && a < 400)
+  #pragma omp target if(a > 200 && a < 400) map(from: c)
     c = omp_is_initial_device ();
 
   #pragma omp target data map(to: b) if(a > 200 && a < 400)
-    #pragma omp target
+    #pragma omp target map(from: b, d)
       {
 	b = 100;
 	d = omp_is_initial_device ();
--- libgomp/testsuite/libgomp.c/examples-4/e.57.3.c.jj	2015-04-24 12:30:40.000000000 +0200
+++ libgomp/testsuite/libgomp.c/examples-4/e.57.3.c	2015-07-23 16:08:48.176775074 +0200
@@ -9,7 +9,7 @@ int main ()
   int res;
   int default_device = omp_get_default_device ();
 
-  #pragma omp target
+  #pragma omp target map(from: res)
     res = omp_is_initial_device ();
 
   if (res)
@@ -17,7 +17,7 @@ int main ()
 
   omp_set_default_device (omp_get_num_devices ());
 
-  #pragma omp target
+  #pragma omp target map(from: res)
     res = omp_is_initial_device ();
 
   if (!res)


	Jakub

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

* Re: [gomp4.1] Initial support for some OpenMP 4.1 construct parsing
  2015-07-20 19:40                 ` [gomp4.1] Initial support for some OpenMP 4.1 construct parsing Ilya Verbin
@ 2015-08-24 12:38                   ` Jakub Jelinek
  2015-08-24 19:10                     ` Ilya Verbin
  0 siblings, 1 reply; 33+ messages in thread
From: Jakub Jelinek @ 2015-08-24 12:38 UTC (permalink / raw)
  To: Ilya Verbin; +Cc: gcc-patches, Kirill Yukhin

On Mon, Jul 20, 2015 at 09:53:42PM +0300, Ilya Verbin wrote:
> On Fri, Jul 17, 2015 at 18:43:06 +0200, Jakub Jelinek wrote:
> > On Fri, Jul 17, 2015 at 07:31:36PM +0300, Ilya Verbin wrote:
> > > One big question is who will maintain the list of scheduled job, its
> > > dependencies, etc. - libgomp or each target plugin?
> > > 
> > > 
> > > OpenACC has async queues:
> > > #pragma acc parallel async(2) wait(1)
> > > 
> > > But it's not possible to have 2 waits like:
> > > #pragma acc parallel async(3) wait(1) wait(2)
> > > 
> > > (GOMP_OFFLOAD_openacc_async_wait_async has only one argument with the number of
> > > queue to wait)
> > > 
> > > Thomas, please correct me if I'm wrong.
> > > 
> > > In this regard, OpenMP is more complicated, since it allows e.g.:
> > > #pragma omp target nowait depend(in: a, b) depend(out: c, d)
> > 
> > If it is each plugin, then supposedly it should use (if possible) some
> > common libgomp routine to maintain the queues, duplicating the dependency
> > graph handling code in each plugins might be too ugly.
> > 
> > > Currently I'm trying to figure out what liboffloadmic can do.
> 
> Latest liboffloadmic (I'm preparing an update for trunk) can take some pointer
> *ptr* as argument of __offload_offload, which is used for execution and data
> transfer.  When given job is finished, it will call some callback in libgomp on
> host, passing *ptr* back to it, thus libgomp can distinguish which job has
> been finished.  BTW, which word to use here to avoid confusion? (task? job?)
> 
> I'm going to prototype something in libgomp using this interface.

Based on the recent largish thread on omp-lang, it seems that the intent
is that depend clause on target* constructs is for an implicit "target task"
on the host side, so sorry for understanding it as dependencies on the
implicit task on the device instead before.  As the "target task" is
supposed to be merged (i.e. sharing ICVs and variables), for
constructs without nowait and depend clauses we can do what we do right now,
perhaps later with some optimizations trying to invoke other tasks if
waiting for the hardware.

For target* constructs with nowait and/or depend clauses, we'll need to pass
in the depend info (which is a pointer to array of addresses, with first
"address" being total count and second "address" being number of out/inout
dependencies at the beginning, and whether nowait is present or not (a bit
somewhere), then create some struct gomp_task for it supposedly with a new
GOMP_TASK_TARGET kind, and handle the dependency waiting etc. like for other
tasks, except that it will not have a real body, but saved arguments from
the GOMP_target* call (at least for not immediately 
satisfied dependency my understanding from the mail thread is that
the data transfer operations are supposed to start only when the dependency
is met).

	Jakub

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

* Re: [gomp4.1] Initial support for some OpenMP 4.1 construct parsing
  2015-08-24 12:38                   ` Jakub Jelinek
@ 2015-08-24 19:10                     ` Ilya Verbin
  0 siblings, 0 replies; 33+ messages in thread
From: Ilya Verbin @ 2015-08-24 19:10 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: gcc-patches, Kirill Yukhin

On Mon, Aug 24, 2015 at 14:26:57 +0200, Jakub Jelinek wrote:
> On Mon, Jul 20, 2015 at 09:53:42PM +0300, Ilya Verbin wrote:
> > Latest liboffloadmic (I'm preparing an update for trunk) can take some pointer
> > *ptr* as argument of __offload_offload, which is used for execution and data
> > transfer.  When given job is finished, it will call some callback in libgomp on
> > host, passing *ptr* back to it, thus libgomp can distinguish which job has
> > been finished.  BTW, which word to use here to avoid confusion? (task? job?)
> > 
> > I'm going to prototype something in libgomp using this interface.
> 
> Based on the recent largish thread on omp-lang, it seems that the intent
> is that depend clause on target* constructs is for an implicit "target task"
> on the host side, so sorry for understanding it as dependencies on the
> implicit task on the device instead before.  As the "target task" is
> supposed to be merged (i.e. sharing ICVs and variables), for
> constructs without nowait and depend clauses we can do what we do right now,
> perhaps later with some optimizations trying to invoke other tasks if
> waiting for the hardware.

I just got back from vacation, and trying to understand that conversation :)

> For target* constructs with nowait and/or depend clauses, we'll need to pass
> in the depend info (which is a pointer to array of addresses, with first
> "address" being total count and second "address" being number of out/inout
> dependencies at the beginning, and whether nowait is present or not (a bit
> somewhere), then create some struct gomp_task for it supposedly with a new
> GOMP_TASK_TARGET kind, and handle the dependency waiting etc. like for other
> tasks, except that it will not have a real body, but saved arguments from
> the GOMP_target* call (at least for not immediately 
> satisfied dependency my understanding from the mail thread is that
> the data transfer operations are supposed to start only when the dependency
> is met).

So, what will happen with a target task on the host when all dependencies are
satisfied and it is ready to start?  As I understood:
* libgomp will call GOMP_OFFLOAD_run with a new 'async' argument, or a new
function GOMP_OFFLOAD_run_async, which will start target function on the device
and immediately return control to libgomp.
* The task will go into some pending state, allowing to run another tasks on the
host (I'm not very familiar with task.c yet).
* When target function is finished, the target runtime library will notify
libgomp by callback.  libgomp will remove the task and make dependent tasks (if
any) ready to start.
Is this correct?

  -- Ilya

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

* Re: [gomp4.1] Various accelerator updates from OpenMP 4.1
  2015-07-29 17:30                         ` [gomp4.1] Various accelerator updates from OpenMP 4.1 Jakub Jelinek
@ 2015-09-04 18:17                           ` Ilya Verbin
  2015-09-04 18:25                             ` Jakub Jelinek
  2015-09-07 12:48                             ` Jakub Jelinek
  0 siblings, 2 replies; 33+ messages in thread
From: Ilya Verbin @ 2015-09-04 18:17 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: gcc-patches, Kirill Yukhin

Hi!

It seems that there is a bug some here:

On Wed, Jul 29, 2015 at 19:19:07 +0200, Jakub Jelinek wrote:
> @@ -12918,6 +12989,28 @@ lower_omp_target (gimple_stmt_iterator *
>  	    var = var2;
>  	  }
>  
> +	if (offloaded
> +	    && OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_FIRSTPRIVATE_POINTER)
> +	  {
> +	    if (TREE_CODE (TREE_TYPE (var)) == ARRAY_TYPE)
> +	      {
> +		tree type = build_pointer_type (TREE_TYPE (var));
> +		tree new_var = lookup_decl (var, ctx);
> +		x = create_tmp_var_raw (type, get_name (new_var));
> +		gimple_add_tmp_var (x);
> +		x = build_simple_mem_ref (x);
> +		SET_DECL_VALUE_EXPR (new_var, x);
> +		DECL_HAS_VALUE_EXPR_P (new_var) = 1;
> +	      }
> +	    continue;
> +	  }
> +
> +	if (offloaded && OMP_CLAUSE_MAP_PRIVATE (c))
> +	  {
> +	    map_cnt++;
> +	    continue;
> +	  }
> +
>  	if (!maybe_lookup_field (var, ctx))
>  	  continue;
>  

Here is the reproducer:

#pragma omp declare target
int a[1];
#pragma omp end declare target

void foo ()
{
  #pragma omp target map(to: a[0:1])
    a;
}


lookup_decl (var, ctx) tries to lookup for 'a', but ctx->cb.decl_map->get ()
returns null-pointer.


$ gcc -fopenmp -c test.c

test.c: In function ‘foo’:
test.c:7:11: internal compiler error: Segmentation fault
   #pragma omp target map(to: a[0:1])
           ^
0xd27276 crash_signal
        gcc/toplev.c:352
0xbae3fa lookup_decl
        gcc/omp-low.c:1056
0xbe208c lower_omp_target
        gcc/omp-low.c:13362
0xbe8464 lower_omp_1
        gcc/omp-low.c:14504
0xbe8911 lower_omp
        gcc/omp-low.c:14592
0xbe8017 lower_omp_1
        gcc/omp-low.c:14436
0xbe8911 lower_omp
        gcc/omp-low.c:14592
0xbe808b lower_omp_1
        gcc/omp-low.c:14445
0xbe8911 lower_omp
        gcc/omp-low.c:14592
0xbe8ad9 execute_lower_omp
        gcc/omp-low.c:14630
0xbe8b7e execute
        gcc/omp-low.c:14667
Please submit a full bug report,
with preprocessed source if appropriate.
Please include the complete backtrace with any bug report.
See <http://gcc.gnu.org/bugs.html> for instructions.

  -- Ilya

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

* Re: [gomp4.1] Various accelerator updates from OpenMP 4.1
  2015-09-04 18:17                           ` Ilya Verbin
@ 2015-09-04 18:25                             ` Jakub Jelinek
  2015-09-07 12:48                             ` Jakub Jelinek
  1 sibling, 0 replies; 33+ messages in thread
From: Jakub Jelinek @ 2015-09-04 18:25 UTC (permalink / raw)
  To: Ilya Verbin; +Cc: gcc-patches, Kirill Yukhin

On Fri, Sep 04, 2015 at 09:07:02PM +0300, Ilya Verbin wrote:
> It seems that there is a bug some here:

Thanks, will look at it on Monday.

> Here is the reproducer:
> 
> #pragma omp declare target
> int a[1];
> #pragma omp end declare target
> 
> void foo ()
> {
>   #pragma omp target map(to: a[0:1])
>     a;
> }

	Jakub

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

* Re: [gomp4.1] Various accelerator updates from OpenMP 4.1
  2015-09-04 18:17                           ` Ilya Verbin
  2015-09-04 18:25                             ` Jakub Jelinek
@ 2015-09-07 12:48                             ` Jakub Jelinek
  1 sibling, 0 replies; 33+ messages in thread
From: Jakub Jelinek @ 2015-09-07 12:48 UTC (permalink / raw)
  To: Ilya Verbin; +Cc: gcc-patches, Kirill Yukhin

On Fri, Sep 04, 2015 at 09:07:02PM +0300, Ilya Verbin wrote:
> It seems that there is a bug some here:
> 
> Here is the reproducer:
> 
> #pragma omp declare target
> int a[1];
> #pragma omp end declare target
> 
> void foo ()
> {
>   #pragma omp target map(to: a[0:1])
>     a;
> }
> 
> 
> lookup_decl (var, ctx) tries to lookup for 'a', but ctx->cb.decl_map->get ()
> returns null-pointer.

Fixed thusly, tested on x86_64-linux, committed to gomp4.1 branch.

2015-09-07  Jakub Jelinek  <jakub@redhat.com>

	* omp-low.c (scan_sharing_clauses): Don't ignore map with
	declare target vars for GOMP_MAP_FIRSTPRIVATE_POINTER,
	unless the decl is an array.
	(lower_omp_target): Ignore GOMP_MAP_FIRSTPRIVATE_POINTER map with
	declare target var if it is an array.

	* testsuite/libgomp.c/target-26.c: New test.

--- gcc/omp-low.c.jj	2015-09-04 11:34:45.000000000 +0200
+++ gcc/omp-low.c	2015-09-07 14:10:36.198517500 +0200
@@ -2060,6 +2060,8 @@ scan_sharing_clauses (tree clauses, omp_
 	     directly.  */
 	  if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
 	      && DECL_P (decl)
+	      && (OMP_CLAUSE_MAP_KIND (c) != GOMP_MAP_FIRSTPRIVATE_POINTER
+		  || TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE)
 	      && is_global_var (maybe_lookup_decl_in_outer_ctx (decl, ctx))
 	      && varpool_node::get_create (decl)->offloadable)
 	    break;
@@ -2284,6 +2286,8 @@ scan_sharing_clauses (tree clauses, omp_
 	    break;
 	  decl = OMP_CLAUSE_DECL (c);
 	  if (DECL_P (decl)
+	      && (OMP_CLAUSE_MAP_KIND (c) != GOMP_MAP_FIRSTPRIVATE_POINTER
+		  || TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE)
 	      && is_global_var (maybe_lookup_decl_in_outer_ctx (decl, ctx))
 	      && varpool_node::get_create (decl)->offloadable)
 	    break;
@@ -13358,6 +13362,10 @@ lower_omp_target (gimple_stmt_iterator *
 	  {
 	    if (TREE_CODE (TREE_TYPE (var)) == ARRAY_TYPE)
 	      {
+		if (is_global_var (maybe_lookup_decl_in_outer_ctx (var, ctx))
+		    && varpool_node::get_create (var)->offloadable)
+		  continue;
+
 		tree type = build_pointer_type (TREE_TYPE (var));
 		tree new_var = lookup_decl (var, ctx);
 		x = create_tmp_var_raw (type, get_name (new_var));
@@ -14081,6 +14089,12 @@ lower_omp_target (gimple_stmt_iterator *
 		HOST_WIDE_INT offset = 0;
 		gcc_assert (prev);
 		var = OMP_CLAUSE_DECL (c);
+		if (DECL_P (var)
+		    && TREE_CODE (TREE_TYPE (var)) == ARRAY_TYPE
+		    && is_global_var (maybe_lookup_decl_in_outer_ctx (var,
+								      ctx))
+		    && varpool_node::get_create (var)->offloadable)
+		  break;
 		if (TREE_CODE (var) == INDIRECT_REF
 		    && TREE_CODE (TREE_OPERAND (var, 0)) == COMPONENT_REF)
 		  var = TREE_OPERAND (var, 0);
--- libgomp/testsuite/libgomp.c/target-26.c.jj	2015-09-07 11:59:08.665425993 +0200
+++ libgomp/testsuite/libgomp.c/target-26.c	2015-09-07 12:38:56.000000000 +0200
@@ -0,0 +1,36 @@
+extern void abort (void);
+#pragma omp declare target
+int a[4] = { 2, 3, 4, 5 }, *b;
+#pragma omp end declare target
+
+int
+main ()
+{
+  int err;
+  int c[3] = { 6, 7, 8 };
+  b = c;
+  #pragma omp target map(to: a[0:2], b[0:2]) map(from: err)
+  err = a[0] != 2 || a[1] != 3 || a[2] != 4 || a[3] != 5 || b[0] != 6 || b[1] != 7;
+  if (err)
+    abort ();
+  a[1] = 9;
+  a[2] = 10;
+  #pragma omp target map(always,to:a[1:2]) map(from: err)
+  err = a[0] != 2 || a[1] != 9 || a[2] != 10 || a[3] != 5;
+  if (err)
+    abort ();
+  #pragma omp parallel firstprivate(a, b, c, err) num_threads (2)
+  #pragma omp single
+  {
+    b = c + 1;
+    a[0] = 11;
+    a[2] = 13;
+    c[1] = 14;
+    int d = 0;
+    #pragma omp target map(to: a[0:3], b[d:2]) map (from: err)
+    err = a[0] != 11 || a[1] != 9 || a[2] != 13 || b[0] != 14 || b[1] != 8;
+    if (err)
+      abort ();
+  }
+  return 0;
+}

	Jakub

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

* Re: [gomp4.1] map clause parsing improvements
  2015-06-11 12:52       ` [gomp4.1] map clause parsing improvements Jakub Jelinek
@ 2015-10-19 10:34         ` Thomas Schwinge
  2015-10-19 10:46           ` Jakub Jelinek
  0 siblings, 1 reply; 33+ messages in thread
From: Thomas Schwinge @ 2015-10-19 10:34 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: gcc-patches, Kirill Yukhin, Ilya Verbin

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

Hi!

On Thu, 11 Jun 2015 14:14:20 +0200, Jakub Jelinek <jakub@redhat.com> wrote:
> On Tue, Jun 09, 2015 at 09:36:08PM +0300, Ilya Verbin wrote:
> > On Wed, Apr 29, 2015 at 14:06:44 +0200, Jakub Jelinek wrote:
> > > [...] The draft requires only alloc or to
> > > (or always, variants) for enter data and only from or delete (or always,
> > > variants) for exit data, so in theory it is possible to figure that from
> > > the call without extra args, but not so for update - enter data is supposed
> > > to increment reference counts, exit data decrement. [...]
> > 
> > TR3.pdf also says about 'release' map-type for exit data, but it is not
> > described in the document.
> 
> So, I've committed a patch to add parsing release map-kind, and fix up or add
> verification in C/C++ FE what map-kinds are used.
> 
> Furthermore, it seems the OpenMP 4.1 always modifier is something completely
> unrelated to the OpenACC force flag, in OpenMP 4.1 everything is reference
> count based, and always seems to make a difference only for from/to/tofrom,
> where it says that the copying is done unconditionally; thus the patch uses
> a different bit for that.

Aha, I see.  (The poor OpenACC/OpenMP users, having to remember so may
small yet intricate details...)

> include/
> 	* gomp-constants.h (GOMP_MAP_FLAG_ALWAYS): Define.
> 	(enum gomp_map_kind): Add GOMP_MAP_ALWAYS_TO, GOMP_MAP_ALWAYS_FROM,
> 	GOMP_MAP_ALWAYS_TOFROM, GOMP_MAP_DELETE, GOMP_MAP_RELEASE.

> --- include/gomp-constants.h.jj	2015-05-21 11:12:09.000000000 +0200
> +++ include/gomp-constants.h	2015-06-11 11:24:32.041654947 +0200
> @@ -41,6 +41,8 @@
>  #define GOMP_MAP_FLAG_SPECIAL_1		(1 << 3)
>  #define GOMP_MAP_FLAG_SPECIAL		(GOMP_MAP_FLAG_SPECIAL_1 \
>  					 | GOMP_MAP_FLAG_SPECIAL_0)
> +/* OpenMP always flag.  */
> +#define GOMP_MAP_FLAG_ALWAYS		(1 << 6)
>  /* Flag to force a specific behavior (or else, trigger a run-time error).  */
>  #define GOMP_MAP_FLAG_FORCE		(1 << 7)
>  
> @@ -77,7 +79,21 @@ enum gomp_map_kind
>      /* ..., and copy from device.  */
>      GOMP_MAP_FORCE_FROM =		(GOMP_MAP_FLAG_FORCE | GOMP_MAP_FROM),
>      /* ..., and copy to and from device.  */
> -    GOMP_MAP_FORCE_TOFROM =		(GOMP_MAP_FLAG_FORCE | GOMP_MAP_TOFROM)
> +    GOMP_MAP_FORCE_TOFROM =		(GOMP_MAP_FLAG_FORCE | GOMP_MAP_TOFROM),
> +    /* If not already present, allocate.  And unconditionally copy to
> +       device.  */
> +    GOMP_MAP_ALWAYS_TO =		(GOMP_MAP_FLAG_ALWAYS | GOMP_MAP_TO),
> +    /* If not already present, allocate.  And unconditionally copy from
> +       device.  */
> +    GOMP_MAP_ALWAYS_FROM =		(GOMP_MAP_FLAG_ALWAYS | GOMP_MAP_FROM),
> +    /* If not already present, allocate.  And unconditionally copy to and from
> +       device.  */
> +    GOMP_MAP_ALWAYS_TOFROM =		(GOMP_MAP_FLAG_ALWAYS | GOMP_MAP_TOFROM),
> +    /* OpenMP 4.1 alias for forced deallocation.  */
> +    GOMP_MAP_DELETE =			GOMP_MAP_FORCE_DEALLOC,

To avoid confusion about two different identifiers naming the same
functionality, I'd prefer to avoid such aliases ("GOMP_MAP_DELETE =
GOMP_MAP_FORCE_DEALLOC"), and instead just rename GOMP_MAP_FORCE_DEALLOC
to GOMP_MAP_DELETE, if that's the name you prefer.

By the way, looking at GCC 6 libgomp compatibility regarding
OpenACC/nvptx offloading for executables compiled with GCC 5, for the
legacy entry point libgomp/oacc-parallel.c:GOACC_parallel only supports
host-fallback execution, which doesn't pay attention to data clause at
all (sizes and kinds formal parameters), so you're free to renumber
GOMP_MAP_* if/where that makes sense.

> +    /* Decrement usage count and deallocate if zero.  */
> +    GOMP_MAP_RELEASE =			(GOMP_MAP_FLAG_ALWAYS
> +					 | GOMP_MAP_FORCE_DEALLOC)
>    };

I have not yet read the OpenMP 4.1/4.5 standard, but it's not obvious to
me here how the GOMP_MAP_FLAG_ALWAYS flag relates to the OpenMP release
clause (GOMP_MAP_RELEASE here)?  Shouldn't GOMP_MAP_RELEASE be
"(GOMP_MAP_FLAG_SPECIAL_1 | 3)" or similar?


Grüße
 Thomas

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 472 bytes --]

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

* Re: [gomp4.1] map clause parsing improvements
  2015-10-19 10:34         ` Thomas Schwinge
@ 2015-10-19 10:46           ` Jakub Jelinek
  2015-10-19 15:14             ` Thomas Schwinge
  2016-03-17 14:34             ` Thomas Schwinge
  0 siblings, 2 replies; 33+ messages in thread
From: Jakub Jelinek @ 2015-10-19 10:46 UTC (permalink / raw)
  To: Thomas Schwinge; +Cc: gcc-patches, Kirill Yukhin, Ilya Verbin

On Mon, Oct 19, 2015 at 12:20:23PM +0200, Thomas Schwinge wrote:
> > @@ -77,7 +79,21 @@ enum gomp_map_kind
> >      /* ..., and copy from device.  */
> >      GOMP_MAP_FORCE_FROM =		(GOMP_MAP_FLAG_FORCE | GOMP_MAP_FROM),
> >      /* ..., and copy to and from device.  */
> > -    GOMP_MAP_FORCE_TOFROM =		(GOMP_MAP_FLAG_FORCE | GOMP_MAP_TOFROM)
> > +    GOMP_MAP_FORCE_TOFROM =		(GOMP_MAP_FLAG_FORCE | GOMP_MAP_TOFROM),
> > +    /* If not already present, allocate.  And unconditionally copy to
> > +       device.  */
> > +    GOMP_MAP_ALWAYS_TO =		(GOMP_MAP_FLAG_ALWAYS | GOMP_MAP_TO),
> > +    /* If not already present, allocate.  And unconditionally copy from
> > +       device.  */
> > +    GOMP_MAP_ALWAYS_FROM =		(GOMP_MAP_FLAG_ALWAYS | GOMP_MAP_FROM),
> > +    /* If not already present, allocate.  And unconditionally copy to and from
> > +       device.  */
> > +    GOMP_MAP_ALWAYS_TOFROM =		(GOMP_MAP_FLAG_ALWAYS | GOMP_MAP_TOFROM),
> > +    /* OpenMP 4.1 alias for forced deallocation.  */
> > +    GOMP_MAP_DELETE =			GOMP_MAP_FORCE_DEALLOC,
> 
> To avoid confusion about two different identifiers naming the same
> functionality, I'd prefer to avoid such aliases ("GOMP_MAP_DELETE =
> GOMP_MAP_FORCE_DEALLOC"), and instead just rename GOMP_MAP_FORCE_DEALLOC
> to GOMP_MAP_DELETE, if that's the name you prefer.

If you are ok with removing GOMP_MAP_FORCE_DEALLOC and just use
GOMP_MAP_DELETE, that is ok by me, just post a patch.

> By the way, looking at GCC 6 libgomp compatibility regarding
> OpenACC/nvptx offloading for executables compiled with GCC 5, for the
> legacy entry point libgomp/oacc-parallel.c:GOACC_parallel only supports
> host-fallback execution, which doesn't pay attention to data clause at
> all (sizes and kinds formal parameters), so you're free to renumber
> GOMP_MAP_* if/where that makes sense.
> 
> > +    /* Decrement usage count and deallocate if zero.  */
> > +    GOMP_MAP_RELEASE =			(GOMP_MAP_FLAG_ALWAYS
> > +					 | GOMP_MAP_FORCE_DEALLOC)
> >    };
> 
> I have not yet read the OpenMP 4.1/4.5 standard, but it's not obvious to
> me here how the GOMP_MAP_FLAG_ALWAYS flag relates to the OpenMP release
> clause (GOMP_MAP_RELEASE here)?  Shouldn't GOMP_MAP_RELEASE be
> "(GOMP_MAP_FLAG_SPECIAL_1 | 3)" or similar?

It isn't related to always, but always really is something that affects
solely the data movement (i.e. to, from, tofrom), and while it can be
specified elsewhere, it makes no difference.  Wasting one bit just for that
is something we don't have the luxury for, which is why I've started using
that bit for other OpenMP stuff (it acts there like GOMP_MAP_FLAG_SPECIAL_2
to some extent).  It is not just release, but also the struct mapping etc.
I'll still need to make further changes, because the rules for mapping
structure element pointer/reference based array sections and structure
element references have changed again.

Some changes in the enum can be of course still be done until say mid stage3
but at least for OpenMP 4.0 we should keep backwards compatibility (so
whatever we've already used in GCC 4.9/5 should keep working).

	Jakub

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

* Re: [gomp4.1] map clause parsing improvements
  2015-10-19 10:46           ` Jakub Jelinek
@ 2015-10-19 15:14             ` Thomas Schwinge
  2015-10-20 10:10               ` Jakub Jelinek
  2016-03-17 14:34             ` Thomas Schwinge
  1 sibling, 1 reply; 33+ messages in thread
From: Thomas Schwinge @ 2015-10-19 15:14 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: gcc-patches, Kirill Yukhin, Ilya Verbin

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

Hi!

On Mon, 19 Oct 2015 12:34:08 +0200, Jakub Jelinek <jakub@redhat.com> wrote:
> On Mon, Oct 19, 2015 at 12:20:23PM +0200, Thomas Schwinge wrote:
> > > +    /* Decrement usage count and deallocate if zero.  */
> > > +    GOMP_MAP_RELEASE =			(GOMP_MAP_FLAG_ALWAYS
> > > +					 | GOMP_MAP_FORCE_DEALLOC)
> > >    };
> > 
> > I have not yet read the OpenMP 4.1/4.5 standard, but it's not obvious to
> > me here how the GOMP_MAP_FLAG_ALWAYS flag relates to the OpenMP release
> > clause (GOMP_MAP_RELEASE here)?  Shouldn't GOMP_MAP_RELEASE be
> > "(GOMP_MAP_FLAG_SPECIAL_1 | 3)" or similar?
> 
> It isn't related to always, but always really is something that affects
> solely the data movement (i.e. to, from, tofrom), and while it can be
> specified elsewhere, it makes no difference.  Wasting one bit just for that
> is something we don't have the luxury for, which is why I've started using
> that bit for other OpenMP stuff (it acts there like GOMP_MAP_FLAG_SPECIAL_2
> to some extent).  It is not just release, but also the struct mapping etc.
> I'll still need to make further changes, because the rules for mapping
> structure element pointer/reference based array sections and structure
> element references have changed again.

Hmm, I do think we should allow the luxury to use its own bit for
GOMP_MAP_FLAG_ALWAYS -- we can extend the interface later, should we
really find uses for the other two remaining bits -- or if not using a
separate bit, at least make sure that GOMP_MAP_FLAG_ALWAYS is not used as
a flag.  See, for example, the following occasions where
GOMP_MAP_FLAG_ALWAYS is used as a flag: these conditionals will also be
matched for GOMP_MAP_STRUCT, GOMP_MAP_DELETE_ZERO_LEN_ARRAY_SECTION, and
GOMP_MAP_RELEASE.  I have not analyzed whether that is erroneous or not,
but it surely is confusing?

    $ < gcc/gimplify.c grep -C3 GOMP_MAP_FLAG_ALWAYS
                          struct_map_to_clause->put (decl, *list_p);
                          list_p = &OMP_CLAUSE_CHAIN (*list_p);
                          flags = GOVD_MAP | GOVD_EXPLICIT;
                          if (OMP_CLAUSE_MAP_KIND (c) & GOMP_MAP_FLAG_ALWAYS)
                            flags |= GOVD_SEEN;
                          goto do_add_decl;
                        }
    --
                          tree *sc = NULL, *pt = NULL;
                          if (!ptr && TREE_CODE (*osc) == TREE_LIST)
                            osc = &TREE_PURPOSE (*osc);
                          if (OMP_CLAUSE_MAP_KIND (c) & GOMP_MAP_FLAG_ALWAYS)
                            n->value |= GOVD_SEEN;
                          offset_int o1, o2;
                          if (offset)
    --
              n = splay_tree_lookup (ctx->variables, (splay_tree_key) decl);
              if ((ctx->region_type & ORT_TARGET) != 0
                  && !(n->value & GOVD_SEEN)
                  && ((OMP_CLAUSE_MAP_KIND (c) & GOMP_MAP_FLAG_ALWAYS) == 0
                      || OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_STRUCT))
                {
                  remove = true;

I'd suggest turning GOMP_MAP_FLAG_ALWAYS into GOMP_MAP_FLAG_SPECIAL_2,
and then provide a GOMP_MAP_ALWAYS_P that evaluates to true just for the
three "always,to", "always,from", and "always,tofrom" cases.


Grüße,
 Thomas

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 472 bytes --]

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

* Re: [gomp4.1] map clause parsing improvements
  2015-10-19 15:14             ` Thomas Schwinge
@ 2015-10-20 10:10               ` Jakub Jelinek
  2015-10-26 13:04                 ` Ilya Verbin
  0 siblings, 1 reply; 33+ messages in thread
From: Jakub Jelinek @ 2015-10-20 10:10 UTC (permalink / raw)
  To: Thomas Schwinge; +Cc: gcc-patches, Kirill Yukhin, Ilya Verbin

On Mon, Oct 19, 2015 at 05:00:33PM +0200, Thomas Schwinge wrote:
>               n = splay_tree_lookup (ctx->variables, (splay_tree_key) decl);
>               if ((ctx->region_type & ORT_TARGET) != 0
>                   && !(n->value & GOVD_SEEN)
>                   && ((OMP_CLAUSE_MAP_KIND (c) & GOMP_MAP_FLAG_ALWAYS) == 0
>                       || OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_STRUCT))
>                 {
>                   remove = true;
> 
> I'd suggest turning GOMP_MAP_FLAG_ALWAYS into GOMP_MAP_FLAG_SPECIAL_2,
> and then provide a GOMP_MAP_ALWAYS_P that evaluates to true just for the
> three "always,to", "always,from", and "always,tofrom" cases.

Yeah, that can be done, I'll add it to my todo list.

	Jakub

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

* Re: [gomp4.1] map clause parsing improvements
  2015-10-20 10:10               ` Jakub Jelinek
@ 2015-10-26 13:04                 ` Ilya Verbin
  2015-10-26 13:17                   ` Jakub Jelinek
  0 siblings, 1 reply; 33+ messages in thread
From: Ilya Verbin @ 2015-10-26 13:04 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Thomas Schwinge, gcc-patches, Kirill Yukhin

On Tue, Oct 20, 2015 at 12:03:40 +0200, Jakub Jelinek wrote:
> On Mon, Oct 19, 2015 at 05:00:33PM +0200, Thomas Schwinge wrote:
> >               n = splay_tree_lookup (ctx->variables, (splay_tree_key) decl);
> >               if ((ctx->region_type & ORT_TARGET) != 0
> >                   && !(n->value & GOVD_SEEN)
> >                   && ((OMP_CLAUSE_MAP_KIND (c) & GOMP_MAP_FLAG_ALWAYS) == 0
> >                       || OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_STRUCT))
> >                 {
> >                   remove = true;
> > 
> > I'd suggest turning GOMP_MAP_FLAG_ALWAYS into GOMP_MAP_FLAG_SPECIAL_2,
> > and then provide a GOMP_MAP_ALWAYS_P that evaluates to true just for the
> > three "always,to", "always,from", and "always,tofrom" cases.
> 
> Yeah, that can be done, I'll add it to my todo list.

Is this what you planned?  I've replaced all 3 uses of GOMP_MAP_FLAG_ALWAYS with
GOMP_MAP_ALWAYS_P.  make check and check-target-libgomp passed, however these 2
changes in gimplify_scan_omp_clauses are not covered by the testsuite, so I'm
not entirely sure that they are correct.  OK for gomp-4_5-branch?


gcc/
	* gimplify.c (gimplify_scan_omp_clauses): Use GOMP_MAP_ALWAYS_P.
	(gimplify_adjust_omp_clauses): Likewise.
include/
	* gomp-constants.h (GOMP_MAP_FLAG_SPECIAL_2): Define.
	(GOMP_MAP_FLAG_ALWAYS): Remove.
	(enum gomp_map_kind): Use GOMP_MAP_FLAG_SPECIAL_2 instead of
	GOMP_MAP_FLAG_ALWAYS for GOMP_MAP_ALWAYS_TO, GOMP_MAP_ALWAYS_FROM,
	GOMP_MAP_ALWAYS_TOFROM, GOMP_MAP_STRUCT, GOMP_MAP_RELEASE.
	(GOMP_MAP_ALWAYS_P): Define.


diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index ee5cb95..57ab6c6 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -6613,7 +6613,7 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p,
 		      struct_map_to_clause->put (decl, *list_p);
 		      list_p = &OMP_CLAUSE_CHAIN (*list_p);
 		      flags = GOVD_MAP | GOVD_EXPLICIT;
-		      if (OMP_CLAUSE_MAP_KIND (c) & GOMP_MAP_FLAG_ALWAYS)
+		      if (GOMP_MAP_ALWAYS_P (OMP_CLAUSE_MAP_KIND (c)))
 			flags |= GOVD_SEEN;
 		      goto do_add_decl;
 		    }
@@ -6623,7 +6623,7 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p,
 		      tree *sc = NULL, *pt = NULL;
 		      if (!ptr && TREE_CODE (*osc) == TREE_LIST)
 			osc = &TREE_PURPOSE (*osc);
-		      if (OMP_CLAUSE_MAP_KIND (c) & GOMP_MAP_FLAG_ALWAYS)
+		      if (GOMP_MAP_ALWAYS_P (OMP_CLAUSE_MAP_KIND (c)))
 			n->value |= GOVD_SEEN;
 		      offset_int o1, o2;
 		      if (offset)
@@ -7363,7 +7363,7 @@ gimplify_adjust_omp_clauses (gimple_seq *pre_p, tree *list_p,
 	  n = splay_tree_lookup (ctx->variables, (splay_tree_key) decl);
 	  if ((ctx->region_type & ORT_TARGET) != 0
 	      && !(n->value & GOVD_SEEN)
-	      && ((OMP_CLAUSE_MAP_KIND (c) & GOMP_MAP_FLAG_ALWAYS) == 0
+	      && (GOMP_MAP_ALWAYS_P (OMP_CLAUSE_MAP_KIND (c)) == 0
 		  || OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_STRUCT))
 	    {
 	      remove = true;
diff --git a/include/gomp-constants.h b/include/gomp-constants.h
index f834dec..2c6f011 100644
--- a/include/gomp-constants.h
+++ b/include/gomp-constants.h
@@ -39,10 +39,9 @@
 /* Special map kinds, enumerated starting here.  */
 #define GOMP_MAP_FLAG_SPECIAL_0		(1 << 2)
 #define GOMP_MAP_FLAG_SPECIAL_1		(1 << 3)
+#define GOMP_MAP_FLAG_SPECIAL_2		(1 << 4)
 #define GOMP_MAP_FLAG_SPECIAL		(GOMP_MAP_FLAG_SPECIAL_1 \
 					 | GOMP_MAP_FLAG_SPECIAL_0)
-/* OpenMP always flag.  */
-#define GOMP_MAP_FLAG_ALWAYS		(1 << 6)
 /* Flag to force a specific behavior (or else, trigger a run-time error).  */
 #define GOMP_MAP_FLAG_FORCE		(1 << 7)
 
@@ -95,29 +94,31 @@ enum gomp_map_kind
     GOMP_MAP_FORCE_TOFROM =		(GOMP_MAP_FLAG_FORCE | GOMP_MAP_TOFROM),
     /* If not already present, allocate.  And unconditionally copy to
        device.  */
-    GOMP_MAP_ALWAYS_TO =		(GOMP_MAP_FLAG_ALWAYS | GOMP_MAP_TO),
+    GOMP_MAP_ALWAYS_TO =		(GOMP_MAP_FLAG_SPECIAL_2 | GOMP_MAP_TO),
     /* If not already present, allocate.  And unconditionally copy from
        device.  */
-    GOMP_MAP_ALWAYS_FROM =		(GOMP_MAP_FLAG_ALWAYS | GOMP_MAP_FROM),
+    GOMP_MAP_ALWAYS_FROM =		(GOMP_MAP_FLAG_SPECIAL_2
+					 | GOMP_MAP_FROM),
     /* If not already present, allocate.  And unconditionally copy to and from
        device.  */
-    GOMP_MAP_ALWAYS_TOFROM =		(GOMP_MAP_FLAG_ALWAYS | GOMP_MAP_TOFROM),
+    GOMP_MAP_ALWAYS_TOFROM =		(GOMP_MAP_FLAG_SPECIAL_2
+					 | 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
        increasing address, so it is easy to determine lowest needed address
        (address of the first adjacent entry) and highest needed address
        (address of the last adjacent entry plus its size).  */
-    GOMP_MAP_STRUCT =			(GOMP_MAP_FLAG_ALWAYS
+    GOMP_MAP_STRUCT =			(GOMP_MAP_FLAG_SPECIAL_2
 					 | GOMP_MAP_FLAG_SPECIAL | 0),
     /* Forced deallocation of zero length array section.  */
     GOMP_MAP_DELETE_ZERO_LEN_ARRAY_SECTION
-      =					(GOMP_MAP_FLAG_ALWAYS
+      =					(GOMP_MAP_FLAG_SPECIAL_2
 					 | GOMP_MAP_FLAG_SPECIAL | 3),
-    /* OpenMP 4.1 alias for forced deallocation.  */
+    /* OpenMP 4.5 alias for forced deallocation.  */
     GOMP_MAP_DELETE =			GOMP_MAP_FORCE_DEALLOC,
     /* Decrement usage count and deallocate if zero.  */
-    GOMP_MAP_RELEASE =			(GOMP_MAP_FLAG_ALWAYS
+    GOMP_MAP_RELEASE =			(GOMP_MAP_FLAG_SPECIAL_2
 					 | GOMP_MAP_FORCE_DEALLOC),
 
     /* Internal to GCC, not used in libgomp.  */
@@ -142,6 +143,10 @@ enum gomp_map_kind
 #define GOMP_MAP_ALWAYS_FROM_P(X) \
   (((X) == GOMP_MAP_ALWAYS_FROM) || ((X) == GOMP_MAP_ALWAYS_TOFROM))
 
+#define GOMP_MAP_ALWAYS_P(X) \
+  (((X) == GOMP_MAP_ALWAYS_TO) || ((X) == GOMP_MAP_ALWAYS_FROM) \
+   || ((X) == GOMP_MAP_ALWAYS_TOFROM))
+
 
 /* Asynchronous behavior.  Keep in sync with
    libgomp/{openacc.h,openacc.f90,openacc_lib.h}:acc_async_t.  */


  -- Ilya

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

* Re: [gomp4.1] map clause parsing improvements
  2015-10-26 13:04                 ` Ilya Verbin
@ 2015-10-26 13:17                   ` Jakub Jelinek
  2015-10-26 14:16                     ` Ilya Verbin
  0 siblings, 1 reply; 33+ messages in thread
From: Jakub Jelinek @ 2015-10-26 13:17 UTC (permalink / raw)
  To: Ilya Verbin; +Cc: Thomas Schwinge, gcc-patches, Kirill Yukhin

On Mon, Oct 26, 2015 at 03:53:57PM +0300, Ilya Verbin wrote:
> @@ -7363,7 +7363,7 @@ gimplify_adjust_omp_clauses (gimple_seq *pre_p, tree *list_p,
>  	  n = splay_tree_lookup (ctx->variables, (splay_tree_key) decl);
>  	  if ((ctx->region_type & ORT_TARGET) != 0
>  	      && !(n->value & GOVD_SEEN)
> -	      && ((OMP_CLAUSE_MAP_KIND (c) & GOMP_MAP_FLAG_ALWAYS) == 0
> +	      && (GOMP_MAP_ALWAYS_P (OMP_CLAUSE_MAP_KIND (c)) == 0
>  		  || OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_STRUCT))

The || OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_STRUCT part can go then too,
it was there only because (OMP_CLAUSE_MAP_KIND (c) & GOMP_MAP_FLAG_ALWAYS)
has been non-zero for GOMP_MAP_STRUCT (and the () pair around the condition
too).
We want to be able to remove all map clauses on the target construct, except
if it is always {to,from,tofrom}.
We do not want to remove release or delete, but those only exist on target
exit data and thus are handled by (ctx->region_type & ORT_TARGET) != 0.

> @@ -142,6 +143,10 @@ enum gomp_map_kind
>  #define GOMP_MAP_ALWAYS_FROM_P(X) \
>    (((X) == GOMP_MAP_ALWAYS_FROM) || ((X) == GOMP_MAP_ALWAYS_TOFROM))
>  
> +#define GOMP_MAP_ALWAYS_P(X) \
> +  (((X) == GOMP_MAP_ALWAYS_TO) || ((X) == GOMP_MAP_ALWAYS_FROM) \
> +   || ((X) == GOMP_MAP_ALWAYS_TOFROM))

You could simplify this e.g. to
  (((X) == GOMP_MAP_ALWAYS_TO) || GOMP_MAP_ALWAYS_FROM_P (X))
or
  (GOMP_MAP_ALWAYS_TO_P (X) || ((X) == GOMP_MAP_ALWAYS_FROM))

Otherwise, LGTM.

	Jakub

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

* Re: [gomp4.1] map clause parsing improvements
  2015-10-26 13:17                   ` Jakub Jelinek
@ 2015-10-26 14:16                     ` Ilya Verbin
  0 siblings, 0 replies; 33+ messages in thread
From: Ilya Verbin @ 2015-10-26 14:16 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Thomas Schwinge, gcc-patches, Kirill Yukhin

On Mon, Oct 26, 2015 at 14:07:13 +0100, Jakub Jelinek wrote:
> On Mon, Oct 26, 2015 at 03:53:57PM +0300, Ilya Verbin wrote:
> > @@ -7363,7 +7363,7 @@ gimplify_adjust_omp_clauses (gimple_seq *pre_p, tree *list_p,
> >  	  n = splay_tree_lookup (ctx->variables, (splay_tree_key) decl);
> >  	  if ((ctx->region_type & ORT_TARGET) != 0
> >  	      && !(n->value & GOVD_SEEN)
> > -	      && ((OMP_CLAUSE_MAP_KIND (c) & GOMP_MAP_FLAG_ALWAYS) == 0
> > +	      && (GOMP_MAP_ALWAYS_P (OMP_CLAUSE_MAP_KIND (c)) == 0
> >  		  || OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_STRUCT))
> 
> The || OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_STRUCT part can go then too,
> it was there only because (OMP_CLAUSE_MAP_KIND (c) & GOMP_MAP_FLAG_ALWAYS)
> has been non-zero for GOMP_MAP_STRUCT (and the () pair around the condition
> too).

Oops, missed that.

> We want to be able to remove all map clauses on the target construct, except
> if it is always {to,from,tofrom}.
> We do not want to remove release or delete, but those only exist on target
> exit data and thus are handled by (ctx->region_type & ORT_TARGET) != 0.
> 
> > @@ -142,6 +143,10 @@ enum gomp_map_kind
> >  #define GOMP_MAP_ALWAYS_FROM_P(X) \
> >    (((X) == GOMP_MAP_ALWAYS_FROM) || ((X) == GOMP_MAP_ALWAYS_TOFROM))
> >  
> > +#define GOMP_MAP_ALWAYS_P(X) \
> > +  (((X) == GOMP_MAP_ALWAYS_TO) || ((X) == GOMP_MAP_ALWAYS_FROM) \
> > +   || ((X) == GOMP_MAP_ALWAYS_TOFROM))
> 
> You could simplify this e.g. to
>   (((X) == GOMP_MAP_ALWAYS_TO) || GOMP_MAP_ALWAYS_FROM_P (X))
> or
>   (GOMP_MAP_ALWAYS_TO_P (X) || ((X) == GOMP_MAP_ALWAYS_FROM))
> 
> Otherwise, LGTM.

Done.  Here is what I committed:


gcc/
	* gimplify.c (gimplify_scan_omp_clauses): Use GOMP_MAP_ALWAYS_P.
	(gimplify_adjust_omp_clauses): Likewise.
include/
	* gomp-constants.h (GOMP_MAP_FLAG_SPECIAL_2): Define.
	(GOMP_MAP_FLAG_ALWAYS): Remove.
	(enum gomp_map_kind): Use GOMP_MAP_FLAG_SPECIAL_2 instead of
	GOMP_MAP_FLAG_ALWAYS for GOMP_MAP_ALWAYS_TO, GOMP_MAP_ALWAYS_FROM,
	GOMP_MAP_ALWAYS_TOFROM, GOMP_MAP_STRUCT, GOMP_MAP_RELEASE.
	(GOMP_MAP_ALWAYS_P): Define.


diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index ee5cb95..a308307 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -6613,7 +6613,7 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p,
 		      struct_map_to_clause->put (decl, *list_p);
 		      list_p = &OMP_CLAUSE_CHAIN (*list_p);
 		      flags = GOVD_MAP | GOVD_EXPLICIT;
-		      if (OMP_CLAUSE_MAP_KIND (c) & GOMP_MAP_FLAG_ALWAYS)
+		      if (GOMP_MAP_ALWAYS_P (OMP_CLAUSE_MAP_KIND (c)))
 			flags |= GOVD_SEEN;
 		      goto do_add_decl;
 		    }
@@ -6623,7 +6623,7 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p,
 		      tree *sc = NULL, *pt = NULL;
 		      if (!ptr && TREE_CODE (*osc) == TREE_LIST)
 			osc = &TREE_PURPOSE (*osc);
-		      if (OMP_CLAUSE_MAP_KIND (c) & GOMP_MAP_FLAG_ALWAYS)
+		      if (GOMP_MAP_ALWAYS_P (OMP_CLAUSE_MAP_KIND (c)))
 			n->value |= GOVD_SEEN;
 		      offset_int o1, o2;
 		      if (offset)
@@ -7363,8 +7363,7 @@ gimplify_adjust_omp_clauses (gimple_seq *pre_p, tree *list_p,
 	  n = splay_tree_lookup (ctx->variables, (splay_tree_key) decl);
 	  if ((ctx->region_type & ORT_TARGET) != 0
 	      && !(n->value & GOVD_SEEN)
-	      && ((OMP_CLAUSE_MAP_KIND (c) & GOMP_MAP_FLAG_ALWAYS) == 0
-		  || OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_STRUCT))
+	      && GOMP_MAP_ALWAYS_P (OMP_CLAUSE_MAP_KIND (c)) == 0)
 	    {
 	      remove = true;
 	      /* For struct element mapping, if struct is never referenced
diff --git a/include/gomp-constants.h b/include/gomp-constants.h
index f834dec..008a4a4 100644
--- a/include/gomp-constants.h
+++ b/include/gomp-constants.h
@@ -39,10 +39,9 @@
 /* Special map kinds, enumerated starting here.  */
 #define GOMP_MAP_FLAG_SPECIAL_0		(1 << 2)
 #define GOMP_MAP_FLAG_SPECIAL_1		(1 << 3)
+#define GOMP_MAP_FLAG_SPECIAL_2		(1 << 4)
 #define GOMP_MAP_FLAG_SPECIAL		(GOMP_MAP_FLAG_SPECIAL_1 \
 					 | GOMP_MAP_FLAG_SPECIAL_0)
-/* OpenMP always flag.  */
-#define GOMP_MAP_FLAG_ALWAYS		(1 << 6)
 /* Flag to force a specific behavior (or else, trigger a run-time error).  */
 #define GOMP_MAP_FLAG_FORCE		(1 << 7)
 
@@ -95,29 +94,31 @@ enum gomp_map_kind
     GOMP_MAP_FORCE_TOFROM =		(GOMP_MAP_FLAG_FORCE | GOMP_MAP_TOFROM),
     /* If not already present, allocate.  And unconditionally copy to
        device.  */
-    GOMP_MAP_ALWAYS_TO =		(GOMP_MAP_FLAG_ALWAYS | GOMP_MAP_TO),
+    GOMP_MAP_ALWAYS_TO =		(GOMP_MAP_FLAG_SPECIAL_2 | GOMP_MAP_TO),
     /* If not already present, allocate.  And unconditionally copy from
        device.  */
-    GOMP_MAP_ALWAYS_FROM =		(GOMP_MAP_FLAG_ALWAYS | GOMP_MAP_FROM),
+    GOMP_MAP_ALWAYS_FROM =		(GOMP_MAP_FLAG_SPECIAL_2
+					 | GOMP_MAP_FROM),
     /* If not already present, allocate.  And unconditionally copy to and from
        device.  */
-    GOMP_MAP_ALWAYS_TOFROM =		(GOMP_MAP_FLAG_ALWAYS | GOMP_MAP_TOFROM),
+    GOMP_MAP_ALWAYS_TOFROM =		(GOMP_MAP_FLAG_SPECIAL_2
+					 | 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
        increasing address, so it is easy to determine lowest needed address
        (address of the first adjacent entry) and highest needed address
        (address of the last adjacent entry plus its size).  */
-    GOMP_MAP_STRUCT =			(GOMP_MAP_FLAG_ALWAYS
+    GOMP_MAP_STRUCT =			(GOMP_MAP_FLAG_SPECIAL_2
 					 | GOMP_MAP_FLAG_SPECIAL | 0),
     /* Forced deallocation of zero length array section.  */
     GOMP_MAP_DELETE_ZERO_LEN_ARRAY_SECTION
-      =					(GOMP_MAP_FLAG_ALWAYS
+      =					(GOMP_MAP_FLAG_SPECIAL_2
 					 | GOMP_MAP_FLAG_SPECIAL | 3),
-    /* OpenMP 4.1 alias for forced deallocation.  */
+    /* OpenMP 4.5 alias for forced deallocation.  */
     GOMP_MAP_DELETE =			GOMP_MAP_FORCE_DEALLOC,
     /* Decrement usage count and deallocate if zero.  */
-    GOMP_MAP_RELEASE =			(GOMP_MAP_FLAG_ALWAYS
+    GOMP_MAP_RELEASE =			(GOMP_MAP_FLAG_SPECIAL_2
 					 | GOMP_MAP_FORCE_DEALLOC),
 
     /* Internal to GCC, not used in libgomp.  */
@@ -142,6 +143,9 @@ enum gomp_map_kind
 #define GOMP_MAP_ALWAYS_FROM_P(X) \
   (((X) == GOMP_MAP_ALWAYS_FROM) || ((X) == GOMP_MAP_ALWAYS_TOFROM))
 
+#define GOMP_MAP_ALWAYS_P(X) \
+  (GOMP_MAP_ALWAYS_TO_P (X) || ((X) == GOMP_MAP_ALWAYS_FROM))
+
 
 /* Asynchronous behavior.  Keep in sync with
    libgomp/{openacc.h,openacc.f90,openacc_lib.h}:acc_async_t.  */


  -- Ilya

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

* Re: [gomp4.1] map clause parsing improvements
  2015-10-19 10:46           ` Jakub Jelinek
  2015-10-19 15:14             ` Thomas Schwinge
@ 2016-03-17 14:34             ` Thomas Schwinge
  2016-03-17 14:37               ` Jakub Jelinek
  1 sibling, 1 reply; 33+ messages in thread
From: Thomas Schwinge @ 2016-03-17 14:34 UTC (permalink / raw)
  To: Jakub Jelinek, gcc-patches; +Cc: Kirill Yukhin, Ilya Verbin

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

Hi!

On Mon, 19 Oct 2015 12:34:08 +0200, Jakub Jelinek <jakub@redhat.com> wrote:
> On Mon, Oct 19, 2015 at 12:20:23PM +0200, Thomas Schwinge wrote:
> > > @@ -77,7 +79,21 @@ enum gomp_map_kind

> > > +    /* OpenMP 4.1 alias for forced deallocation.  */
> > > +    GOMP_MAP_DELETE =			GOMP_MAP_FORCE_DEALLOC,
> > 
> > To avoid confusion about two different identifiers naming the same
> > functionality, I'd prefer to avoid such aliases ("GOMP_MAP_DELETE =
> > GOMP_MAP_FORCE_DEALLOC"), and instead just rename GOMP_MAP_FORCE_DEALLOC
> > to GOMP_MAP_DELETE, if that's the name you prefer.
> 
> If you are ok with removing GOMP_MAP_FORCE_DEALLOC and just use
> GOMP_MAP_DELETE, that is ok by me, just post a patch.

That's simple enouch; OK to commit?  (I'm also including the related
change, to rename the Fortran OMP_MAP_FORCE_DEALLOC to OMP_MAP_DELETE,
because I think that's what you'd do, once starting the OpenMP 4.5
Fortran front end work.)

commit d60e36a2a935a9319602221360b1a6abf282f434
Author: Thomas Schwinge <thomas@codesourcery.com>
Date:   Wed Mar 16 18:10:26 2016 +0100

    Rename GOMP_MAP_FORCE_DEALLOC to GOMP_MAP_DELETE
    
    Also rename the Fortran OMP_MAP_FORCE_DEALLOC to OMP_MAP_DELETE.
    
    	include/
    	* gomp-constants.h (enum gomp_map_kind): Rename
    	GOMP_MAP_FORCE_DEALLOC to GOMP_MAP_DELETE.  Adjust all users.
    
    	gcc/fortran/
    	* gfortran.h (enum gfc_omp_map_op): Rename OMP_MAP_FORCE_DEALLOC
    	to OMP_MAP_DELETE.  Adjust all users.
---
 gcc/c/c-parser.c           | 2 +-
 gcc/cp/parser.c            | 2 +-
 gcc/fortran/gfortran.h     | 2 +-
 gcc/fortran/openmp.c       | 2 +-
 gcc/fortran/trans-openmp.c | 6 +++---
 gcc/gimplify.c             | 2 +-
 gcc/omp-low.c              | 2 +-
 gcc/tree-pretty-print.c    | 2 +-
 include/gomp-constants.h   | 6 ++----
 libgomp/oacc-parallel.c    | 6 +++---
 10 files changed, 15 insertions(+), 17 deletions(-)

diff --git gcc/c/c-parser.c gcc/c/c-parser.c
index 60ec996..82d6eca 100644
--- gcc/c/c-parser.c
+++ gcc/c/c-parser.c
@@ -10715,7 +10715,7 @@ c_parser_oacc_data_clause (c_parser *parser, pragma_omp_clause c_kind,
       kind = GOMP_MAP_FORCE_ALLOC;
       break;
     case PRAGMA_OACC_CLAUSE_DELETE:
-      kind = GOMP_MAP_FORCE_DEALLOC;
+      kind = GOMP_MAP_DELETE;
       break;
     case PRAGMA_OACC_CLAUSE_DEVICE:
       kind = GOMP_MAP_FORCE_TO;
diff --git gcc/cp/parser.c gcc/cp/parser.c
index 62570d4..8ba4ffe 100644
--- gcc/cp/parser.c
+++ gcc/cp/parser.c
@@ -30086,7 +30086,7 @@ cp_parser_oacc_data_clause (cp_parser *parser, pragma_omp_clause c_kind,
       kind = GOMP_MAP_FORCE_ALLOC;
       break;
     case PRAGMA_OACC_CLAUSE_DELETE:
-      kind = GOMP_MAP_FORCE_DEALLOC;
+      kind = GOMP_MAP_DELETE;
       break;
     case PRAGMA_OACC_CLAUSE_DEVICE:
       kind = GOMP_MAP_FORCE_TO;
diff --git gcc/fortran/gfortran.h gcc/fortran/gfortran.h
index 33fffd8..a0fb5fd 100644
--- gcc/fortran/gfortran.h
+++ gcc/fortran/gfortran.h
@@ -1112,8 +1112,8 @@ enum gfc_omp_map_op
   OMP_MAP_TO,
   OMP_MAP_FROM,
   OMP_MAP_TOFROM,
+  OMP_MAP_DELETE,
   OMP_MAP_FORCE_ALLOC,
-  OMP_MAP_FORCE_DEALLOC,
   OMP_MAP_FORCE_TO,
   OMP_MAP_FORCE_FROM,
   OMP_MAP_FORCE_TOFROM,
diff --git gcc/fortran/openmp.c gcc/fortran/openmp.c
index 51ab96e..a6c39cd 100644
--- gcc/fortran/openmp.c
+++ gcc/fortran/openmp.c
@@ -764,7 +764,7 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, uint64_t mask,
       if ((mask & OMP_CLAUSE_DELETE)
 	  && gfc_match ("delete ( ") == MATCH_YES
 	  && gfc_match_omp_map_clause (&c->lists[OMP_LIST_MAP],
-				       OMP_MAP_FORCE_DEALLOC))
+				       OMP_MAP_DELETE))
 	continue;
       if ((mask & OMP_CLAUSE_PRESENT)
 	  && gfc_match ("present ( ") == MATCH_YES
diff --git gcc/fortran/trans-openmp.c gcc/fortran/trans-openmp.c
index 5990202..a905ca6 100644
--- gcc/fortran/trans-openmp.c
+++ gcc/fortran/trans-openmp.c
@@ -2119,12 +2119,12 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses,
 		case OMP_MAP_TOFROM:
 		  OMP_CLAUSE_SET_MAP_KIND (node, GOMP_MAP_TOFROM);
 		  break;
+		case OMP_MAP_DELETE:
+		  OMP_CLAUSE_SET_MAP_KIND (node, GOMP_MAP_DELETE);
+		  break;
 		case OMP_MAP_FORCE_ALLOC:
 		  OMP_CLAUSE_SET_MAP_KIND (node, GOMP_MAP_FORCE_ALLOC);
 		  break;
-		case OMP_MAP_FORCE_DEALLOC:
-		  OMP_CLAUSE_SET_MAP_KIND (node, GOMP_MAP_FORCE_DEALLOC);
-		  break;
 		case OMP_MAP_FORCE_TO:
 		  OMP_CLAUSE_SET_MAP_KIND (node, GOMP_MAP_FORCE_TO);
 		  break;
diff --git gcc/gimplify.c gcc/gimplify.c
index f3e5c39..3687e7a 100644
--- gcc/gimplify.c
+++ gcc/gimplify.c
@@ -8194,7 +8194,7 @@ gimplify_oacc_declare_1 (tree clause)
       case GOMP_MAP_ALLOC:
       case GOMP_MAP_FORCE_ALLOC:
       case GOMP_MAP_FORCE_TO:
-	new_op = GOMP_MAP_FORCE_DEALLOC;
+	new_op = GOMP_MAP_DELETE;
 	ret = true;
 	break;
 
diff --git gcc/omp-low.c gcc/omp-low.c
index 82dec9d..3fd6eb3 100644
--- gcc/omp-low.c
+++ gcc/omp-low.c
@@ -15746,7 +15746,7 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx)
 	  case GOMP_MAP_TOFROM:
 	  case GOMP_MAP_POINTER:
 	  case GOMP_MAP_TO_PSET:
-	  case GOMP_MAP_FORCE_DEALLOC:
+	  case GOMP_MAP_DELETE:
 	  case GOMP_MAP_RELEASE:
 	  case GOMP_MAP_ALWAYS_TO:
 	  case GOMP_MAP_ALWAYS_FROM:
diff --git gcc/tree-pretty-print.c gcc/tree-pretty-print.c
index 9c13d84..39e3691 100644
--- gcc/tree-pretty-print.c
+++ gcc/tree-pretty-print.c
@@ -621,7 +621,7 @@ dump_omp_clause (pretty_printer *pp, tree clause, int spc, int flags)
 	case GOMP_MAP_FORCE_PRESENT:
 	  pp_string (pp, "force_present");
 	  break;
-	case GOMP_MAP_FORCE_DEALLOC:
+	case GOMP_MAP_DELETE:
 	  pp_string (pp, "delete");
 	  break;
 	case GOMP_MAP_FORCE_DEVICEPTR:
diff --git include/gomp-constants.h include/gomp-constants.h
index a8e7723..e31c2e0 100644
--- include/gomp-constants.h
+++ include/gomp-constants.h
@@ -67,7 +67,7 @@ enum gomp_map_kind
     /* Must already be present.  */
     GOMP_MAP_FORCE_PRESENT =		(GOMP_MAP_FLAG_SPECIAL_0 | 2),
     /* Deallocate a mapping, without copying from device.  */
-    GOMP_MAP_FORCE_DEALLOC =		(GOMP_MAP_FLAG_SPECIAL_0 | 3),
+    GOMP_MAP_DELETE =			(GOMP_MAP_FLAG_SPECIAL_0 | 3),
     /* Is a device pointer.  OMP_CLAUSE_SIZE for these is unused; is implicitly
        POINTER_SIZE_UNITS.  */
     GOMP_MAP_FORCE_DEVICEPTR =		(GOMP_MAP_FLAG_SPECIAL_1 | 0),
@@ -125,11 +125,9 @@ enum gomp_map_kind
     GOMP_MAP_DELETE_ZERO_LEN_ARRAY_SECTION
       =					(GOMP_MAP_FLAG_SPECIAL_2
 					 | GOMP_MAP_FLAG_SPECIAL | 3),
-    /* OpenMP 4.5 alias for forced deallocation.  */
-    GOMP_MAP_DELETE =			GOMP_MAP_FORCE_DEALLOC,
     /* Decrement usage count and deallocate if zero.  */
     GOMP_MAP_RELEASE =			(GOMP_MAP_FLAG_SPECIAL_2
-					 | GOMP_MAP_FORCE_DEALLOC),
+					 | GOMP_MAP_DELETE),
 
     /* Internal to GCC, not used in libgomp.  */
     /* Do not map, but pointer assign a pointer instead.  */
diff --git libgomp/oacc-parallel.c libgomp/oacc-parallel.c
index f795bf7..1fdb01d 100644
--- libgomp/oacc-parallel.c
+++ libgomp/oacc-parallel.c
@@ -307,7 +307,7 @@ GOACC_enter_exit_data (int device, size_t mapnum,
 	  break;
 	}
 
-      if (kind == GOMP_MAP_FORCE_DEALLOC
+      if (kind == GOMP_MAP_DELETE
 	  || kind == GOMP_MAP_FORCE_FROM)
 	break;
 
@@ -374,7 +374,7 @@ GOACC_enter_exit_data (int device, size_t mapnum,
 					 == GOMP_MAP_FORCE_FROM,
 					 async, 1);
 		break;
-	      case GOMP_MAP_FORCE_DEALLOC:
+	      case GOMP_MAP_DELETE:
 		acc_delete (hostaddrs[i], sizes[i]);
 		break;
 	      case GOMP_MAP_FORCE_FROM:
@@ -522,10 +522,10 @@ GOACC_declare (int device, size_t mapnum,
       switch (kind)
 	{
 	  case GOMP_MAP_FORCE_ALLOC:
-	  case GOMP_MAP_FORCE_DEALLOC:
 	  case GOMP_MAP_FORCE_FROM:
 	  case GOMP_MAP_FORCE_TO:
 	  case GOMP_MAP_POINTER:
+	  case GOMP_MAP_DELETE:
 	    GOACC_enter_exit_data (device, 1, &hostaddrs[i], &sizes[i],
 				   &kinds[i], 0, 0);
 	    break;


Grüße
 Thomas

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 472 bytes --]

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

* Re: [gomp4.1] map clause parsing improvements
  2016-03-17 14:34             ` Thomas Schwinge
@ 2016-03-17 14:37               ` Jakub Jelinek
  2016-03-17 14:55                 ` Jakub Jelinek
  2016-03-17 15:13                 ` Rename GOMP_MAP_FORCE_DEALLOC to GOMP_MAP_DELETE (was: [gomp4.1] map clause parsing improvements) Thomas Schwinge
  0 siblings, 2 replies; 33+ messages in thread
From: Jakub Jelinek @ 2016-03-17 14:37 UTC (permalink / raw)
  To: Thomas Schwinge, t; +Cc: gcc-patches, Kirill Yukhin, Ilya Verbin

On Thu, Mar 17, 2016 at 03:34:09PM +0100, Thomas Schwinge wrote:
> That's simple enouch; OK to commit?  (I'm also including the related
> change, to rename the Fortran OMP_MAP_FORCE_DEALLOC to OMP_MAP_DELETE,
> because I think that's what you'd do, once starting the OpenMP 4.5
> Fortran front end work.)

Ok, thanks.

	Jakub

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

* Re: [gomp4.1] map clause parsing improvements
  2016-03-17 14:37               ` Jakub Jelinek
@ 2016-03-17 14:55                 ` Jakub Jelinek
  2016-03-17 15:13                 ` Rename GOMP_MAP_FORCE_DEALLOC to GOMP_MAP_DELETE (was: [gomp4.1] map clause parsing improvements) Thomas Schwinge
  1 sibling, 0 replies; 33+ messages in thread
From: Jakub Jelinek @ 2016-03-17 14:55 UTC (permalink / raw)
  To: Thomas Schwinge; +Cc: gcc-patches, Kirill Yukhin, Ilya Verbin

On Thu, Mar 17, 2016 at 03:34:09PM +0100, Thomas Schwinge wrote:
> That's simple enouch; OK to commit?  (I'm also including the related
> change, to rename the Fortran OMP_MAP_FORCE_DEALLOC to OMP_MAP_DELETE,
> because I think that's what you'd do, once starting the OpenMP 4.5
> Fortran front end work.)

Ok, thanks.

	Jakub

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

* Rename GOMP_MAP_FORCE_DEALLOC to GOMP_MAP_DELETE (was: [gomp4.1] map clause parsing improvements)
  2016-03-17 14:37               ` Jakub Jelinek
  2016-03-17 14:55                 ` Jakub Jelinek
@ 2016-03-17 15:13                 ` Thomas Schwinge
  1 sibling, 0 replies; 33+ messages in thread
From: Thomas Schwinge @ 2016-03-17 15:13 UTC (permalink / raw)
  To: gcc-patches, Jakub Jelinek; +Cc: Kirill Yukhin, Ilya Verbin, t

Hi!

On Thu, 17 Mar 2016 15:37:04 +0100, Jakub Jelinek <jakub@redhat.com> wrote:
> On Thu, Mar 17, 2016 at 03:34:09PM +0100, Thomas Schwinge wrote:
> > That's simple enouch; OK to commit?  (I'm also including the related
> > change, to rename the Fortran OMP_MAP_FORCE_DEALLOC to OMP_MAP_DELETE,
> > because I think that's what you'd do, once starting the OpenMP 4.5
> > Fortran front end work.)
> 
> Ok, thanks.

Committed unchanged to trunk in r234294:

commit 5cb6b0b9685d5c63e87abb10abac60312dab1378
Author: tschwinge <tschwinge@138bc75d-0d04-0410-961f-82ee72b054a4>
Date:   Thu Mar 17 15:07:54 2016 +0000

    Rename GOMP_MAP_FORCE_DEALLOC to GOMP_MAP_DELETE
    
    Also rename the Fortran OMP_MAP_FORCE_DEALLOC to OMP_MAP_DELETE.
    
    	include/
    	* gomp-constants.h (enum gomp_map_kind): Rename
    	GOMP_MAP_FORCE_DEALLOC to GOMP_MAP_DELETE.  Adjust all users.
    
    	gcc/fortran/
    	* gfortran.h (enum gfc_omp_map_op): Rename OMP_MAP_FORCE_DEALLOC
    	to OMP_MAP_DELETE.  Adjust all users.
    
    git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@234294 138bc75d-0d04-0410-961f-82ee72b054a4
---
 gcc/c/c-parser.c           | 2 +-
 gcc/cp/parser.c            | 2 +-
 gcc/fortran/ChangeLog      | 5 +++++
 gcc/fortran/gfortran.h     | 2 +-
 gcc/fortran/openmp.c       | 2 +-
 gcc/fortran/trans-openmp.c | 6 +++---
 gcc/gimplify.c             | 2 +-
 gcc/omp-low.c              | 2 +-
 gcc/tree-pretty-print.c    | 2 +-
 include/ChangeLog          | 5 +++++
 include/gomp-constants.h   | 6 ++----
 libgomp/oacc-parallel.c    | 6 +++---
 12 files changed, 25 insertions(+), 17 deletions(-)

diff --git gcc/c/c-parser.c gcc/c/c-parser.c
index 60ec996..82d6eca 100644
--- gcc/c/c-parser.c
+++ gcc/c/c-parser.c
@@ -10715,7 +10715,7 @@ c_parser_oacc_data_clause (c_parser *parser, pragma_omp_clause c_kind,
       kind = GOMP_MAP_FORCE_ALLOC;
       break;
     case PRAGMA_OACC_CLAUSE_DELETE:
-      kind = GOMP_MAP_FORCE_DEALLOC;
+      kind = GOMP_MAP_DELETE;
       break;
     case PRAGMA_OACC_CLAUSE_DEVICE:
       kind = GOMP_MAP_FORCE_TO;
diff --git gcc/cp/parser.c gcc/cp/parser.c
index 62570d4..8ba4ffe 100644
--- gcc/cp/parser.c
+++ gcc/cp/parser.c
@@ -30086,7 +30086,7 @@ cp_parser_oacc_data_clause (cp_parser *parser, pragma_omp_clause c_kind,
       kind = GOMP_MAP_FORCE_ALLOC;
       break;
     case PRAGMA_OACC_CLAUSE_DELETE:
-      kind = GOMP_MAP_FORCE_DEALLOC;
+      kind = GOMP_MAP_DELETE;
       break;
     case PRAGMA_OACC_CLAUSE_DEVICE:
       kind = GOMP_MAP_FORCE_TO;
diff --git gcc/fortran/ChangeLog gcc/fortran/ChangeLog
index 9ed112e..105e7b4 100644
--- gcc/fortran/ChangeLog
+++ gcc/fortran/ChangeLog
@@ -1,3 +1,8 @@
+2016-03-17  Thomas Schwinge  <thomas@codesourcery.com>
+
+	* gfortran.h (enum gfc_omp_map_op): Rename OMP_MAP_FORCE_DEALLOC
+	to OMP_MAP_DELETE.  Adjust all users.
+
 2016-03-13  Jerry DeLisle  <jvdelisle@gcc.gnu.org>
 	    Jim MacArthur  <jim.macarthur@codethink.co.uk>
 
diff --git gcc/fortran/gfortran.h gcc/fortran/gfortran.h
index 33fffd8..a0fb5fd 100644
--- gcc/fortran/gfortran.h
+++ gcc/fortran/gfortran.h
@@ -1112,8 +1112,8 @@ enum gfc_omp_map_op
   OMP_MAP_TO,
   OMP_MAP_FROM,
   OMP_MAP_TOFROM,
+  OMP_MAP_DELETE,
   OMP_MAP_FORCE_ALLOC,
-  OMP_MAP_FORCE_DEALLOC,
   OMP_MAP_FORCE_TO,
   OMP_MAP_FORCE_FROM,
   OMP_MAP_FORCE_TOFROM,
diff --git gcc/fortran/openmp.c gcc/fortran/openmp.c
index 51ab96e..a6c39cd 100644
--- gcc/fortran/openmp.c
+++ gcc/fortran/openmp.c
@@ -764,7 +764,7 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, uint64_t mask,
       if ((mask & OMP_CLAUSE_DELETE)
 	  && gfc_match ("delete ( ") == MATCH_YES
 	  && gfc_match_omp_map_clause (&c->lists[OMP_LIST_MAP],
-				       OMP_MAP_FORCE_DEALLOC))
+				       OMP_MAP_DELETE))
 	continue;
       if ((mask & OMP_CLAUSE_PRESENT)
 	  && gfc_match ("present ( ") == MATCH_YES
diff --git gcc/fortran/trans-openmp.c gcc/fortran/trans-openmp.c
index 5990202..a905ca6 100644
--- gcc/fortran/trans-openmp.c
+++ gcc/fortran/trans-openmp.c
@@ -2119,12 +2119,12 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses,
 		case OMP_MAP_TOFROM:
 		  OMP_CLAUSE_SET_MAP_KIND (node, GOMP_MAP_TOFROM);
 		  break;
+		case OMP_MAP_DELETE:
+		  OMP_CLAUSE_SET_MAP_KIND (node, GOMP_MAP_DELETE);
+		  break;
 		case OMP_MAP_FORCE_ALLOC:
 		  OMP_CLAUSE_SET_MAP_KIND (node, GOMP_MAP_FORCE_ALLOC);
 		  break;
-		case OMP_MAP_FORCE_DEALLOC:
-		  OMP_CLAUSE_SET_MAP_KIND (node, GOMP_MAP_FORCE_DEALLOC);
-		  break;
 		case OMP_MAP_FORCE_TO:
 		  OMP_CLAUSE_SET_MAP_KIND (node, GOMP_MAP_FORCE_TO);
 		  break;
diff --git gcc/gimplify.c gcc/gimplify.c
index f3e5c39..3687e7a 100644
--- gcc/gimplify.c
+++ gcc/gimplify.c
@@ -8194,7 +8194,7 @@ gimplify_oacc_declare_1 (tree clause)
       case GOMP_MAP_ALLOC:
       case GOMP_MAP_FORCE_ALLOC:
       case GOMP_MAP_FORCE_TO:
-	new_op = GOMP_MAP_FORCE_DEALLOC;
+	new_op = GOMP_MAP_DELETE;
 	ret = true;
 	break;
 
diff --git gcc/omp-low.c gcc/omp-low.c
index 82dec9d..3fd6eb3 100644
--- gcc/omp-low.c
+++ gcc/omp-low.c
@@ -15746,7 +15746,7 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx)
 	  case GOMP_MAP_TOFROM:
 	  case GOMP_MAP_POINTER:
 	  case GOMP_MAP_TO_PSET:
-	  case GOMP_MAP_FORCE_DEALLOC:
+	  case GOMP_MAP_DELETE:
 	  case GOMP_MAP_RELEASE:
 	  case GOMP_MAP_ALWAYS_TO:
 	  case GOMP_MAP_ALWAYS_FROM:
diff --git gcc/tree-pretty-print.c gcc/tree-pretty-print.c
index 9c13d84..39e3691 100644
--- gcc/tree-pretty-print.c
+++ gcc/tree-pretty-print.c
@@ -621,7 +621,7 @@ dump_omp_clause (pretty_printer *pp, tree clause, int spc, int flags)
 	case GOMP_MAP_FORCE_PRESENT:
 	  pp_string (pp, "force_present");
 	  break;
-	case GOMP_MAP_FORCE_DEALLOC:
+	case GOMP_MAP_DELETE:
 	  pp_string (pp, "delete");
 	  break;
 	case GOMP_MAP_FORCE_DEVICEPTR:
diff --git include/ChangeLog include/ChangeLog
index c48156f..d09d548 100644
--- include/ChangeLog
+++ include/ChangeLog
@@ -1,3 +1,8 @@
+2016-03-17  Thomas Schwinge  <thomas@codesourcery.com>
+
+	* gomp-constants.h (enum gomp_map_kind): Rename
+	GOMP_MAP_FORCE_DEALLOC to GOMP_MAP_DELETE.  Adjust all users.
+
 2016-03-03  Than McIntosh <thanm@google.com>
 
 	* plugin-api.h: Add new hooks to the plugin transfer vector to
diff --git include/gomp-constants.h include/gomp-constants.h
index a8e7723..e31c2e0 100644
--- include/gomp-constants.h
+++ include/gomp-constants.h
@@ -67,7 +67,7 @@ enum gomp_map_kind
     /* Must already be present.  */
     GOMP_MAP_FORCE_PRESENT =		(GOMP_MAP_FLAG_SPECIAL_0 | 2),
     /* Deallocate a mapping, without copying from device.  */
-    GOMP_MAP_FORCE_DEALLOC =		(GOMP_MAP_FLAG_SPECIAL_0 | 3),
+    GOMP_MAP_DELETE =			(GOMP_MAP_FLAG_SPECIAL_0 | 3),
     /* Is a device pointer.  OMP_CLAUSE_SIZE for these is unused; is implicitly
        POINTER_SIZE_UNITS.  */
     GOMP_MAP_FORCE_DEVICEPTR =		(GOMP_MAP_FLAG_SPECIAL_1 | 0),
@@ -125,11 +125,9 @@ enum gomp_map_kind
     GOMP_MAP_DELETE_ZERO_LEN_ARRAY_SECTION
       =					(GOMP_MAP_FLAG_SPECIAL_2
 					 | GOMP_MAP_FLAG_SPECIAL | 3),
-    /* OpenMP 4.5 alias for forced deallocation.  */
-    GOMP_MAP_DELETE =			GOMP_MAP_FORCE_DEALLOC,
     /* Decrement usage count and deallocate if zero.  */
     GOMP_MAP_RELEASE =			(GOMP_MAP_FLAG_SPECIAL_2
-					 | GOMP_MAP_FORCE_DEALLOC),
+					 | GOMP_MAP_DELETE),
 
     /* Internal to GCC, not used in libgomp.  */
     /* Do not map, but pointer assign a pointer instead.  */
diff --git libgomp/oacc-parallel.c libgomp/oacc-parallel.c
index f795bf7..1fdb01d 100644
--- libgomp/oacc-parallel.c
+++ libgomp/oacc-parallel.c
@@ -307,7 +307,7 @@ GOACC_enter_exit_data (int device, size_t mapnum,
 	  break;
 	}
 
-      if (kind == GOMP_MAP_FORCE_DEALLOC
+      if (kind == GOMP_MAP_DELETE
 	  || kind == GOMP_MAP_FORCE_FROM)
 	break;
 
@@ -374,7 +374,7 @@ GOACC_enter_exit_data (int device, size_t mapnum,
 					 == GOMP_MAP_FORCE_FROM,
 					 async, 1);
 		break;
-	      case GOMP_MAP_FORCE_DEALLOC:
+	      case GOMP_MAP_DELETE:
 		acc_delete (hostaddrs[i], sizes[i]);
 		break;
 	      case GOMP_MAP_FORCE_FROM:
@@ -522,10 +522,10 @@ GOACC_declare (int device, size_t mapnum,
       switch (kind)
 	{
 	  case GOMP_MAP_FORCE_ALLOC:
-	  case GOMP_MAP_FORCE_DEALLOC:
 	  case GOMP_MAP_FORCE_FROM:
 	  case GOMP_MAP_FORCE_TO:
 	  case GOMP_MAP_POINTER:
+	  case GOMP_MAP_DELETE:
 	    GOACC_enter_exit_data (device, 1, &hostaddrs[i], &sizes[i],
 				   &kinds[i], 0, 0);
 	    break;


Grüße
 Thomas

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

end of thread, other threads:[~2016-03-17 15:11 UTC | newest]

Thread overview: 33+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-04-29 11:44 [gomp4.1] Initial support for some OpenMP 4.1 construct parsing Jakub Jelinek
2015-04-29 11:55 ` Thomas Schwinge
2015-04-29 12:31   ` Jakub Jelinek
2015-04-29 15:20     ` Thomas Schwinge
2015-06-09 18:39     ` Ilya Verbin
2015-06-09 20:25       ` Jakub Jelinek
2015-06-25 19:47         ` Ilya Verbin
2015-06-25 20:31           ` Jakub Jelinek
2015-07-17 16:47             ` Ilya Verbin
2015-07-17 16:54               ` Jakub Jelinek
2015-07-20 16:18                 ` Jakub Jelinek
2015-07-20 18:31                   ` Jakub Jelinek
2015-07-23  0:50                     ` Jakub Jelinek
2015-07-24 20:33                       ` Jakub Jelinek
2015-07-29 17:30                         ` [gomp4.1] Various accelerator updates from OpenMP 4.1 Jakub Jelinek
2015-09-04 18:17                           ` Ilya Verbin
2015-09-04 18:25                             ` Jakub Jelinek
2015-09-07 12:48                             ` Jakub Jelinek
2015-07-20 19:40                 ` [gomp4.1] Initial support for some OpenMP 4.1 construct parsing Ilya Verbin
2015-08-24 12:38                   ` Jakub Jelinek
2015-08-24 19:10                     ` Ilya Verbin
2015-06-11 12:52       ` [gomp4.1] map clause parsing improvements Jakub Jelinek
2015-10-19 10:34         ` Thomas Schwinge
2015-10-19 10:46           ` Jakub Jelinek
2015-10-19 15:14             ` Thomas Schwinge
2015-10-20 10:10               ` Jakub Jelinek
2015-10-26 13:04                 ` Ilya Verbin
2015-10-26 13:17                   ` Jakub Jelinek
2015-10-26 14:16                     ` Ilya Verbin
2016-03-17 14:34             ` Thomas Schwinge
2016-03-17 14:37               ` Jakub Jelinek
2016-03-17 14:55                 ` Jakub Jelinek
2016-03-17 15:13                 ` Rename GOMP_MAP_FORCE_DEALLOC to GOMP_MAP_DELETE (was: [gomp4.1] map clause parsing improvements) Thomas Schwinge

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).