diff mbox series

[gomp5] Add support for taskwait with depend clauses

Message ID 20180619070501.GQ7166@tucnak
State New
Headers show
Series [gomp5] Add support for taskwait with depend clauses | expand

Commit Message

Jakub Jelinek June 19, 2018, 7:05 a.m. UTC
Hi!

#pragma omp taskwait depend(...)
is syntactic sugar for:
#pragma omp task if(0) mergeable depend(...)
;
but we can optimize a little bit and not outline the empty body or
really construct the new task.

Tested on x86_64-linux, committed to gomp-5_0-branch.

2018-06-19  Jakub Jelinek  <jakub@redhat.com>

	* gimple.h (enum gf_mask): Add GF_OMP_TASK_TASKWAIT.
	(gimple_omp_task_taskwait_p, gimple_omp_task_set_taskwait_p): New
	inline functions.
	* gimplify.c (gimplify_omp_task): Handle taskwait with depend clauses.
	* tree-pretty-print.c (dump_generic_node): Print taskwait with depend
	clauses.
	* gimple-pretty-print.c (dump_gimple_omp_task): Likewise.
	* omp-low.c (scan_omp_task): Handle taskwait with depend clauses.
	(lower_omp_taskreg): Likewise.
	* omp-expand.c (expand_taskwait_call): New function.
	(expand_omp_taskreg): Handle taskwait with depend clauses.
	(build_omp_regions_1, omp_make_gimple_edges): Treat taskwait with
	depend clauses as a standalone directive.
	* omp-builtins.def (BUILT_IN_GOMP_TASKWAIT_DEPEND): New builtin.
gcc/c/
	* c-parser.c (OMP_TASKWAIT_CLAUSE_MASK): Define.
	(c_parser_omp_taskwait): Handle taskwait with depend clauses.
gcc/cp/
	* parser.c (OMP_TASKWAIT_CLAUSE_MASK): Define.
	(cp_parser_omp_taskwait): Handle taskwait with depend clauses.
	* pt.c (tsubst_expr): Likewise.
gcc/testsuite/
	* c-c++-common/gomp/taskwait-depend-1.c: New test.
libgomp/
	* libgomp_g.h (GOMP_taskwait_depend): Add prototype.
	* task.c (GOMP_taskwait_depend): New function.
	(gomp_task_maybe_wait_for_dependencies): Fix a function comment typo.
	* libgomp.map (GOMP_5.0): Export GOMP_taskwait_depend.
	* testsuite/libgomp.c-c++-common/taskwait-depend-1.c: New test.



	Jakub
diff mbox series

Patch

--- gcc/gimple.h.jj	2018-05-31 17:24:29.928449877 +0200
+++ gcc/gimple.h	2018-06-18 19:02:46.354895804 +0200
@@ -152,6 +152,7 @@  enum gf_mask {
     GF_OMP_PARALLEL_COMBINED	= 1 << 0,
     GF_OMP_PARALLEL_GRID_PHONY = 1 << 1,
     GF_OMP_TASK_TASKLOOP	= 1 << 0,
+    GF_OMP_TASK_TASKWAIT	= 1 << 1,
     GF_OMP_FOR_KIND_MASK	= (1 << 4) - 1,
     GF_OMP_FOR_KIND_FOR		= 0,
     GF_OMP_FOR_KIND_DISTRIBUTE	= 1,
@@ -5501,6 +5502,31 @@  gimple_omp_task_set_taskloop_p (gimple *
 }
 
 
+/* Return true if OMP task statement G has the
+   GF_OMP_TASK_TASKWAIT flag set.  */
+
+static inline bool
+gimple_omp_task_taskwait_p (const gimple *g)
+{
+  GIMPLE_CHECK (g, GIMPLE_OMP_TASK);
+  return (gimple_omp_subcode (g) & GF_OMP_TASK_TASKWAIT) != 0;
+}
+
+
+/* Set the GF_OMP_TASK_TASKWAIT field in G depending on the boolean
+   value of TASKWAIT_P.  */
+
+static inline void
+gimple_omp_task_set_taskwait_p (gimple *g, bool taskwait_p)
+{
+  GIMPLE_CHECK (g, GIMPLE_OMP_TASK);
+  if (taskwait_p)
+    g->subcode |= GF_OMP_TASK_TASKWAIT;
+  else
+    g->subcode &= ~GF_OMP_TASK_TASKWAIT;
+}
+
+
 /* Return the child function used to hold the body of OMP_TASK GS.  */
 
 static inline tree
--- gcc/gimplify.c.jj	2018-06-12 11:45:41.817981609 +0200
+++ gcc/gimplify.c	2018-06-18 19:07:09.152186493 +0200
@@ -10079,18 +10079,32 @@  gimplify_omp_task (tree *expr_p, gimple_
   gimple *g;
   gimple_seq body = NULL;
 
+  if (OMP_TASK_BODY (expr) == NULL_TREE)
+    for (tree c = OMP_TASK_CLAUSES (expr); c; c = OMP_CLAUSE_CHAIN (c))
+      if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND
+	  && OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_MUTEXINOUTSET)
+	{
+	  error_at (OMP_CLAUSE_LOCATION (c),
+		    "%<mutexinoutset%> kind in %<depend%> clause on a "
+		    "%<taskwait%> construct");
+	  break;
+	}
+
   gimplify_scan_omp_clauses (&OMP_TASK_CLAUSES (expr), pre_p,
 			     omp_find_clause (OMP_TASK_CLAUSES (expr),
 					      OMP_CLAUSE_UNTIED)
 			     ? ORT_UNTIED_TASK : ORT_TASK, OMP_TASK);
 
-  push_gimplify_context ();
+  if (OMP_TASK_BODY (expr))
+    {
+      push_gimplify_context ();
 
-  g = gimplify_and_return_first (OMP_TASK_BODY (expr), &body);
-  if (gimple_code (g) == GIMPLE_BIND)
-    pop_gimplify_context (g);
-  else
-    pop_gimplify_context (NULL);
+      g = gimplify_and_return_first (OMP_TASK_BODY (expr), &body);
+      if (gimple_code (g) == GIMPLE_BIND)
+	pop_gimplify_context (g);
+      else
+	pop_gimplify_context (NULL);
+    }
 
   gimplify_adjust_omp_clauses (pre_p, body, &OMP_TASK_CLAUSES (expr),
 			       OMP_TASK);
@@ -10099,6 +10113,8 @@  gimplify_omp_task (tree *expr_p, gimple_
 			     OMP_TASK_CLAUSES (expr),
 			     NULL_TREE, NULL_TREE,
 			     NULL_TREE, NULL_TREE, NULL_TREE);
+  if (OMP_TASK_BODY (expr) == NULL_TREE)
+    gimple_omp_task_set_taskwait_p (g, true);
   gimplify_seq_add_stmt (pre_p, g);
   *expr_p = NULL_TREE;
 }
--- gcc/tree-pretty-print.c.jj	2018-06-08 10:57:43.223983430 +0200
+++ gcc/tree-pretty-print.c	2018-06-18 19:07:09.152186493 +0200
@@ -3102,7 +3102,8 @@  dump_generic_node (pretty_printer *pp, t
       break;
 
     case OMP_TASK:
-      pp_string (pp, "#pragma omp task");
+      pp_string (pp, OMP_TASK_BODY (node) ? "#pragma omp task"
+					  : "#pragma omp taskwait");
       dump_omp_clauses (pp, OMP_TASK_CLAUSES (node), spc, flags);
       goto dump_omp_body;
 
--- gcc/gimple-pretty-print.c.jj	2018-06-04 18:19:02.139639408 +0200
+++ gcc/gimple-pretty-print.c	2018-06-18 19:07:09.152186493 +0200
@@ -2334,6 +2334,8 @@  dump_gimple_omp_task (pretty_printer *bu
       gimple_seq body;
       if (gimple_omp_task_taskloop_p (gs))
 	pp_string (buffer, "#pragma omp taskloop");
+      else if (gimple_omp_task_taskwait_p (gs))
+	pp_string (buffer, "#pragma omp taskwait");
       else
 	pp_string (buffer, "#pragma omp task");
       dump_omp_clauses (buffer, gimple_omp_task_clauses (gs), spc, flags);
--- gcc/omp-low.c.jj	2018-06-14 11:09:55.439824132 +0200
+++ gcc/omp-low.c	2018-06-19 08:24:31.960876918 +0200
@@ -1816,6 +1816,7 @@  scan_omp_task (gimple_stmt_iterator *gsi
   /* Ignore task directives with empty bodies, unless they have depend
      clause.  */
   if (optimize > 0
+      && gimple_omp_body (stmt)
       && empty_body_p (gimple_omp_body (stmt))
       && !omp_find_clause (gimple_omp_task_clauses (stmt), OMP_CLAUSE_DEPEND))
     {
@@ -1827,6 +1828,13 @@  scan_omp_task (gimple_stmt_iterator *gsi
     add_taskreg_looptemp_clauses (GF_OMP_FOR_KIND_TASKLOOP, stmt, outer_ctx);
 
   ctx = new_omp_context (stmt, outer_ctx);
+
+  if (gimple_omp_task_taskwait_p (stmt))
+    {
+      scan_sharing_clauses (gimple_omp_task_clauses (stmt), ctx);
+      return;
+    }
+
   taskreg_contexts.safe_push (ctx);
   if (taskreg_nesting_level > 1)
     ctx->is_nested = true;
@@ -7421,9 +7429,18 @@  lower_omp_taskreg (gimple_stmt_iterator
   location_t loc = gimple_location (stmt);
 
   clauses = gimple_omp_taskreg_clauses (stmt);
-  par_bind
-    = as_a <gbind *> (gimple_seq_first_stmt (gimple_omp_body (stmt)));
-  par_body = gimple_bind_body (par_bind);
+  if (gimple_code (stmt) == GIMPLE_OMP_TASK
+      && gimple_omp_task_taskwait_p (stmt))
+    {
+      par_bind = NULL;
+      par_body = NULL;
+    }
+  else
+    {
+      par_bind
+	= as_a <gbind *> (gimple_seq_first_stmt (gimple_omp_body (stmt)));
+      par_body = gimple_bind_body (par_bind);
+    }
   child_fn = ctx->cb.dst_fn;
   if (gimple_code (stmt) == GIMPLE_OMP_PARALLEL
       && !gimple_omp_parallel_combined_p (stmt))
@@ -7449,6 +7466,20 @@  lower_omp_taskreg (gimple_stmt_iterator
 			    &dep_ilist, &dep_olist);
     }
 
+  if (gimple_code (stmt) == GIMPLE_OMP_TASK
+      && gimple_omp_task_taskwait_p (stmt))
+    {
+      if (dep_bind)
+	{
+	  gsi_replace (gsi_p, dep_bind, true);
+	  gimple_bind_add_seq (dep_bind, dep_ilist);
+	  gimple_bind_add_stmt (dep_bind, stmt);
+	  gimple_bind_add_seq (dep_bind, dep_olist);
+	  pop_gimplify_context (dep_bind);
+	}
+      return;
+    }
+
   if (ctx->srecord_type)
     create_task_copyfn (as_a <gomp_task *> (stmt), ctx);
 
--- gcc/omp-expand.c.jj	2018-05-25 18:14:54.431217055 +0200
+++ gcc/omp-expand.c	2018-06-18 19:07:09.152186493 +0200
@@ -866,6 +866,29 @@  expand_task_call (struct omp_region *reg
 			    false, GSI_CONTINUE_LINKING);
 }
 
+/* Build the function call to GOMP_taskwait_depend to actually
+   generate the taskwait operation.  BB is the block where to insert the
+   code.  */
+
+static void
+expand_taskwait_call (basic_block bb, gomp_task *entry_stmt)
+{
+  tree clauses = gimple_omp_task_clauses (entry_stmt);
+  tree depend = omp_find_clause (clauses, OMP_CLAUSE_DEPEND);
+  if (depend == NULL_TREE)
+    return;
+
+  depend = OMP_CLAUSE_DECL (depend);
+
+  gimple_stmt_iterator gsi = gsi_last_nondebug_bb (bb);
+  tree t
+    = build_call_expr (builtin_decl_explicit (BUILT_IN_GOMP_TASKWAIT_DEPEND),
+		       1, depend);
+
+  force_gimple_operand_gsi (&gsi, t, true, NULL_TREE,
+			    false, GSI_CONTINUE_LINKING);
+}
+
 /* Chain all the DECLs in LIST by their TREE_CHAIN fields.  */
 
 static tree
@@ -1112,6 +1135,17 @@  expand_omp_taskreg (struct omp_region *r
   vec<tree, va_gc> *ws_args;
 
   entry_stmt = last_stmt (region->entry);
+  if (gimple_code (entry_stmt) == GIMPLE_OMP_TASK
+      && gimple_omp_task_taskwait_p (entry_stmt))
+    {
+      new_bb = region->entry;
+      gsi = gsi_last_nondebug_bb (region->entry);
+      gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_TASK);
+      gsi_remove (&gsi, true);
+      expand_taskwait_call (new_bb, as_a <gomp_task *> (entry_stmt));
+      return;
+    }
+
   child_fn = gimple_omp_taskreg_child_fn (entry_stmt);
   child_cfun = DECL_STRUCT_FUNCTION (child_fn);
 
@@ -7933,6 +7967,10 @@  build_omp_regions_1 (basic_block bb, str
 	    /* #pragma omp ordered depend is also just a stand-alone
 	       directive.  */
 	    region = NULL;
+	  else if (code == GIMPLE_OMP_TASK
+		   && gimple_omp_task_taskwait_p (stmt))
+	    /* #pragma omp taskwait depend(...) is a stand-alone directive.  */
+	    region = NULL;
 	  /* ..., this directive becomes the parent for a new region.  */
 	  if (region)
 	    parent = region;
@@ -8123,7 +8161,6 @@  omp_make_gimple_edges (basic_block bb, s
   switch (code)
     {
     case GIMPLE_OMP_PARALLEL:
-    case GIMPLE_OMP_TASK:
     case GIMPLE_OMP_FOR:
     case GIMPLE_OMP_SINGLE:
     case GIMPLE_OMP_TEAMS:
@@ -8136,6 +8173,13 @@  omp_make_gimple_edges (basic_block bb, s
       fallthru = true;
       break;
 
+    case GIMPLE_OMP_TASK:
+      cur_region = new_omp_region (bb, code, cur_region);
+      fallthru = true;
+      if (gimple_omp_task_taskwait_p (last))
+	cur_region = cur_region->outer;
+      break;
+
     case GIMPLE_OMP_ORDERED:
       cur_region = new_omp_region (bb, code, cur_region);
       fallthru = true;
--- gcc/omp-builtins.def.jj	2018-06-04 18:19:29.275682204 +0200
+++ gcc/omp-builtins.def	2018-06-18 19:02:46.415895871 +0200
@@ -75,6 +75,8 @@  DEF_GOMP_BUILTIN (BUILT_IN_GOMP_BARRIER_
 		  BT_FN_BOOL, ATTR_NOTHROW_LEAF_LIST)
 DEF_GOMP_BUILTIN (BUILT_IN_GOMP_TASKWAIT, "GOMP_taskwait",
 		  BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST)
+DEF_GOMP_BUILTIN (BUILT_IN_GOMP_TASKWAIT_DEPEND, "GOMP_taskwait_depend",
+		  BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST)
 DEF_GOMP_BUILTIN (BUILT_IN_GOMP_TASKYIELD, "GOMP_taskyield",
 		  BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST)
 DEF_GOMP_BUILTIN (BUILT_IN_GOMP_TASKGROUP_START, "GOMP_taskgroup_start",
--- gcc/c/c-parser.c.jj	2018-06-13 13:07:02.194649345 +0200
+++ gcc/c/c-parser.c	2018-06-18 19:07:09.152186493 +0200
@@ -17029,16 +17029,35 @@  c_parser_omp_task (location_t loc, c_par
 
 /* OpenMP 3.0:
    # pragma omp taskwait new-line
+
+   OpenMP 5.0:
+   # pragma omp taskwait taskwait-clause[optseq] new-line
 */
 
+#define OMP_TASKWAIT_CLAUSE_MASK					\
+	(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND)
+
 static void
 c_parser_omp_taskwait (c_parser *parser)
 {
   location_t loc = c_parser_peek_token (parser)->location;
   c_parser_consume_pragma (parser);
-  c_parser_skip_to_pragma_eol (parser);
 
-  c_finish_omp_taskwait (loc);
+  tree clauses
+    = c_parser_omp_all_clauses (parser, OMP_TASKWAIT_CLAUSE_MASK,
+				"#pragma omp taskwait");
+
+  if (clauses)
+    {
+      tree stmt = make_node (OMP_TASK);
+      TREE_TYPE (stmt) = void_node;
+      OMP_TASK_CLAUSES (stmt) = clauses;
+      OMP_TASK_BODY (stmt) = NULL_TREE;
+      SET_EXPR_LOCATION (stmt, loc);
+      add_stmt (stmt);
+    }
+  else
+    c_finish_omp_taskwait (loc);
 }
 
 /* OpenMP 3.1:
--- gcc/cp/parser.c.jj	2018-06-13 16:26:27.294958834 +0200
+++ gcc/cp/parser.c	2018-06-18 19:07:09.152186493 +0200
@@ -36471,13 +36471,32 @@  cp_parser_omp_task (cp_parser *parser, c
 }
 
 /* OpenMP 3.0:
-   # pragma omp taskwait new-line  */
+   # pragma omp taskwait new-line
+
+   OpenMP 5.0:
+   # pragma omp taskwait taskwait-clause[opt] new-line  */
+
+#define OMP_TASKWAIT_CLAUSE_MASK				\
+	(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND)
 
 static void
 cp_parser_omp_taskwait (cp_parser *parser, cp_token *pragma_tok)
 {
-  cp_parser_require_pragma_eol (parser, pragma_tok);
-  finish_omp_taskwait ();
+  tree clauses
+    = cp_parser_omp_all_clauses (parser, OMP_TASKWAIT_CLAUSE_MASK,
+				 "#pragma omp taskwait", pragma_tok);
+
+  if (clauses)
+    {
+      tree stmt = make_node (OMP_TASK);
+      TREE_TYPE (stmt) = void_node;
+      OMP_TASK_CLAUSES (stmt) = clauses;
+      OMP_TASK_BODY (stmt) = NULL_TREE;
+      SET_EXPR_LOCATION (stmt, pragma_tok->location);
+      add_stmt (stmt);
+    }
+  else
+    finish_omp_taskwait ();
 }
 
 /* OpenMP 3.1:
--- gcc/cp/pt.c.jj	2018-06-13 17:33:22.060761294 +0200
+++ gcc/cp/pt.c	2018-06-18 19:07:09.152186493 +0200
@@ -17131,6 +17131,15 @@  tsubst_expr (tree t, tree args, tsubst_f
       break;
 
     case OMP_TASK:
+      if (OMP_TASK_BODY (t) == NULL_TREE)
+	{
+	  tmp = tsubst_omp_clauses (OMP_TASK_CLAUSES (t), C_ORT_OMP, args,
+				    complain, in_decl);
+	  t = copy_node (t);
+	  OMP_TASK_CLAUSES (t) = tmp;
+	  add_stmt (t);
+	  break;
+	}
       r = push_omp_privatization_clauses (false);
       tmp = tsubst_omp_clauses (OMP_TASK_CLAUSES (t), C_ORT_OMP, args,
 				complain, in_decl);
--- gcc/testsuite/c-c++-common/gomp/taskwait-depend-1.c.jj	2018-06-18 19:39:52.596312255 +0200
+++ gcc/testsuite/c-c++-common/gomp/taskwait-depend-1.c	2018-06-18 19:08:01.694245920 +0200
@@ -0,0 +1,11 @@ 
+void
+foo (int *p)
+{
+  #pragma omp taskwait depend(iterator(i = 0:16) : in : p[i]) depend(out : p[32])
+}
+
+void
+bar (int *p)
+{
+  #pragma omp taskwait depend(mutexinoutset : p[0])	/* { dg-error "'mutexinoutset' kind in 'depend' clause on a 'taskwait' construct" } */
+}
--- libgomp/libgomp_g.h.jj	2018-04-30 13:19:47.407834551 +0200
+++ libgomp/libgomp_g.h	2018-06-18 19:02:46.477895938 +0200
@@ -251,6 +251,7 @@  extern void GOMP_taskloop_ull (void (*)
 			       unsigned long long, unsigned long long,
 			       unsigned long long);
 extern void GOMP_taskwait (void);
+extern void GOMP_taskwait_depend (void **);
 extern void GOMP_taskyield (void);
 extern void GOMP_taskgroup_start (void);
 extern void GOMP_taskgroup_end (void);
--- libgomp/task.c.jj	2018-04-30 13:21:05.605865965 +0200
+++ libgomp/task.c	2018-06-18 19:02:46.486895948 +0200
@@ -1456,6 +1456,25 @@  GOMP_taskwait (void)
     }
 }
 
+/* Called when encountering a taskwait directive with depend clause(s).
+   Wait as if it was an mergeable included task construct with empty body.  */
+
+void
+GOMP_taskwait_depend (void **depend)
+{
+  struct gomp_thread *thr = gomp_thread ();
+  struct gomp_team *team = thr->ts.team;
+
+  /* If parallel or taskgroup has been cancelled, return early.  */
+  if (team
+      && (gomp_team_barrier_cancelled (&team->barrier)
+	  || (thr->task->taskgroup && thr->task->taskgroup->cancelled)))
+    return;
+
+  if (thr->task && thr->task->depend_hash)
+    gomp_task_maybe_wait_for_dependencies (depend);
+}
+
 /* An undeferred task is about to run.  Wait for all tasks that this
    undeferred task depends on.
 
@@ -1464,7 +1483,7 @@  GOMP_taskwait (void)
    the scheduling queues.  Then we iterate through these imminently
    ready tasks (and possibly other high priority tasks), and run them.
    If we run out of ready dependencies to execute, we either wait for
-   the reamining dependencies to finish, or wait for them to get
+   the remaining dependencies to finish, or wait for them to get
    scheduled so we can run them.
 
    DEPEND is as in GOMP_task.  */
--- libgomp/libgomp.map.jj	2018-06-04 18:14:55.572250561 +0200
+++ libgomp/libgomp.map	2018-06-18 19:02:46.473895934 +0200
@@ -310,6 +310,11 @@  GOMP_4.5 {
 	GOMP_parallel_loop_nonmonotonic_guided;
 } GOMP_4.0.1;
 
+GOMP_5.0 {
+  global:
+	GOMP_taskwait_depend;
+} GOMP_4.5;
+
 OACC_2.0 {
   global:
 	acc_get_num_devices;
--- libgomp/testsuite/libgomp.c-c++-common/taskwait-depend-1.c.jj	2018-06-18 19:48:34.433871291 +0200
+++ libgomp/testsuite/libgomp.c-c++-common/taskwait-depend-1.c	2018-06-18 19:53:33.568194061 +0200
@@ -0,0 +1,29 @@ 
+#ifdef __cplusplus
+extern "C"
+#endif
+void abort (void);
+
+int
+main ()
+{
+  int a, b, c, d;
+  #pragma omp parallel num_threads (4)
+  #pragma omp single
+  {
+    #pragma omp task depend(out : a)
+    a = 6;
+    #pragma omp task depend(out : b)
+    b = 7;
+    #pragma omp task depend(out : c)
+    c = 8;
+    #pragma omp taskwait depend(in : a, c)
+    d = a + c;
+    #pragma omp task depend(out : a)
+    a = 9;
+    #pragma omp task depend(out : c)
+    c = 10;
+  }
+  if (a != 9 || b != 7 || c != 10 || d != 6 + 8)
+    abort ();
+  return 0;
+}