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  <ja...@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.

--- 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;
+}


        Jakub

Reply via email to