]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
openmp: Add taskwait nowait depend support [PR105378]
authorJakub Jelinek <jakub@redhat.com>
Tue, 24 May 2022 07:12:44 +0000 (09:12 +0200)
committerJakub Jelinek <jakub@redhat.com>
Tue, 24 May 2022 07:12:44 +0000 (09:12 +0200)
This patch adds support for (so far C/C++)
  #pragma omp taskwait nowait depend(...)
directive, which is like
  #pragma omp task depend(...)
  ;
but slightly optimized on the library side, so that it creates
the task only for the purpose of dependency tracking and doesn't actually
schedule it and wait for it when the dependencies are satisfied, instead
makes its dependencies satisfied right away.

2022-05-24  Jakub Jelinek  <jakub@redhat.com>

PR c/105378
gcc/
* omp-builtins.def (BUILT_IN_GOMP_TASKWAIT_DEPEND_NOWAIT): New
builtin.
* gimplify.cc (gimplify_omp_task): Diagnose taskwait with nowait
clause but no depend clauses.
* omp-expand.cc (expand_taskwait_call): Use
BUILT_IN_GOMP_TASKWAIT_DEPEND_NOWAIT rather than
BUILT_IN_GOMP_TASKWAIT_DEPEND if nowait clause is present.
gcc/c/
* c-parser.cc (OMP_TASKWAIT_CLAUSE_MASK): Add nowait clause.
gcc/cp/
* parser.cc (OMP_TASKWAIT_CLAUSE_MASK): Add nowait clause.
gcc/testsuite/
* c-c++-common/gomp/taskwait-depend-nowait-1.c: New test.
libgomp/
* libgomp_g.h (GOMP_taskwait_depend_nowait): Declare.
* libgomp.map (GOMP_taskwait_depend_nowait): Export at GOMP_5.1.1.
* task.c (empty_task): New function.
(gomp_task_run_post_handle_depend_hash): Declare earlier.
(gomp_task_run_post_handle_depend): Declare.
(GOMP_task): Optimize fn == empty_task if there is nothing to wait
for.
(gomp_task_run_post_handle_dependers): Optimize task->fn == empty_task.
(GOMP_taskwait_depend_nowait): New function.
* testsuite/libgomp.c-c++-common/taskwait-depend-nowait-1.c: New test.

gcc/c/c-parser.cc
gcc/cp/parser.cc
gcc/gimplify.cc
gcc/omp-builtins.def
gcc/omp-expand.cc
gcc/testsuite/c-c++-common/gomp/taskwait-depend-nowait-1.c [new file with mode: 0644]
libgomp/libgomp.map
libgomp/libgomp_g.h
libgomp/task.c
libgomp/testsuite/libgomp.c-c++-common/taskwait-depend-nowait-1.c [new file with mode: 0644]

index 8df8f60ef2136289e177423522376ac0652989ab..492d995a281a358d0a6d1a1d73487e2dbd385a97 100644 (file)
@@ -20453,7 +20453,8 @@ c_parser_omp_task (location_t loc, c_parser *parser, bool *if_p)
 */
 
 #define OMP_TASKWAIT_CLAUSE_MASK                                       \
-       (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND)
+       ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND)               \
+       | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT))
 
 static void
 c_parser_omp_taskwait (c_parser *parser)
index 24585c1c013ad80dbf5972d8932cc2b0cfd2c089..868b8610d6031aa567eae01b0aef7fff4a2aadc0 100644 (file)
@@ -43793,7 +43793,8 @@ cp_parser_omp_task (cp_parser *parser, cp_token *pragma_tok, bool *if_p)
    # pragma omp taskwait taskwait-clause[opt] new-line  */
 
 #define OMP_TASKWAIT_CLAUSE_MASK                               \
-       (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND)
+       ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND)       \
+       | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT))
 
 static void
 cp_parser_omp_taskwait (cp_parser *parser, cp_token *pragma_tok)
index 98f554491e26097e8aa3c3c733b04327502ed2e8..cd1796643d71a62b0344bb1bcb78c98e4a6eb60a 100644 (file)
@@ -12319,17 +12319,34 @@ gimplify_omp_task (tree *expr_p, gimple_seq *pre_p)
   tree expr = *expr_p;
   gimple *g;
   gimple_seq body = NULL;
+  bool nowait = false;
+  bool has_depend = false;
 
   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)
+    {
+      for (tree c = OMP_TASK_CLAUSES (expr); c; c = OMP_CLAUSE_CHAIN (c))
+       if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND)
+         {
+           has_depend = true;
+           if (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;
+             }
+         }
+       else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_NOWAIT)
+         nowait = true;
+      if (nowait && !has_depend)
        {
-         error_at (OMP_CLAUSE_LOCATION (c),
-                   "%<mutexinoutset%> kind in %<depend%> clause on a "
-                   "%<taskwait%> construct");
-         break;
+         error_at (EXPR_LOCATION (expr),
+                   "%<taskwait%> construct with %<nowait%> clause but no "
+                   "%<depend%> clauses");
+         *expr_p = NULL_TREE;
+         return;
        }
+    }
 
   gimplify_scan_omp_clauses (&OMP_TASK_CLAUSES (expr), pre_p,
                             omp_find_clause (OMP_TASK_CLAUSES (expr),
index cfa6483c7ae9e2b2ac461476385aa455aeef7d85..ee5213eedcf78001261f92476e63320abd737ef5 100644 (file)
@@ -89,6 +89,9 @@ 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_TASKWAIT_DEPEND_NOWAIT,
+                 "GOMP_taskwait_depend_nowait",
+                 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",
index 5729a20397dc97321dec69a05eaf27b321b28424..0821b8d06882b5ad3750046833b90b54d5091e27 100644 (file)
@@ -916,10 +916,12 @@ expand_taskwait_call (basic_block bb, gomp_task *entry_stmt)
 
   depend = OMP_CLAUSE_DECL (depend);
 
+  bool nowait = omp_find_clause (clauses, OMP_CLAUSE_NOWAIT) != NULL_TREE;
   gimple_stmt_iterator gsi = gsi_last_nondebug_bb (bb);
-  tree t
-    = build_call_expr (builtin_decl_explicit (BUILT_IN_GOMP_TASKWAIT_DEPEND),
-                      1, depend);
+  enum built_in_function f = (nowait
+                             ? BUILT_IN_GOMP_TASKWAIT_DEPEND_NOWAIT
+                             : BUILT_IN_GOMP_TASKWAIT_DEPEND);
+  tree t = build_call_expr (builtin_decl_explicit (f), 1, depend);
 
   force_gimple_operand_gsi (&gsi, t, true, NULL_TREE,
                            false, GSI_CONTINUE_LINKING);
diff --git a/gcc/testsuite/c-c++-common/gomp/taskwait-depend-nowait-1.c b/gcc/testsuite/c-c++-common/gomp/taskwait-depend-nowait-1.c
new file mode 100644 (file)
index 0000000..54df023
--- /dev/null
@@ -0,0 +1,17 @@
+void
+foo (int *p)
+{
+  #pragma omp taskwait depend(iterator(i = 0:16) , in : p[i]) nowait depend(out : p[32])
+}
+
+void
+bar (int *p)
+{
+  #pragma omp taskwait depend(mutexinoutset : p[0]) nowait     /* { dg-error "'mutexinoutset' kind in 'depend' clause on a 'taskwait' construct" } */
+}
+
+void
+baz (void)
+{
+  #pragma omp taskwait nowait  /* { dg-error "'taskwait' construct with 'nowait' clause but no 'depend' clauses" } */
+}
index 6334fdcce53f4c1eb247bbdf6b9cf57ba76cd71b..46d5f10f3e1d2da18442b88d52c6bfabd3fef192 100644 (file)
@@ -410,6 +410,11 @@ GOMP_5.1 {
        GOMP_teams4;
 } GOMP_5.0.1;
 
+GOMP_5.1.1 {
+  global:
+       GOMP_taskwait_depend_nowait;
+} GOMP_5.1;
+
 OACC_2.0 {
   global:
        acc_get_num_devices;
index 09674a1225ce4019c52f283e56005ebdefdcd8c8..84b9f2cfed601b8158ff4e3447050abcc4f5d244 100644 (file)
@@ -305,6 +305,7 @@ extern void GOMP_taskloop_ull (void (*) (void *), void *,
                               unsigned long long);
 extern void GOMP_taskwait (void);
 extern void GOMP_taskwait_depend (void **);
+extern void GOMP_taskwait_depend_nowait (void **);
 extern void GOMP_taskyield (void);
 extern void GOMP_taskgroup_start (void);
 extern void GOMP_taskgroup_end (void);
index 6b11a8f02efefa0700456be042ea26dc32fbfd97..7925e5873c416acda7ea96be1b3440c02c797d25 100644 (file)
@@ -460,6 +460,17 @@ gomp_task_handle_depend (struct gomp_task *task, struct gomp_task *parent,
     }
 }
 
+/* Body of empty task like taskwait nowait depend.  */
+
+static void
+empty_task (void *data __attribute__((unused)))
+{
+}
+
+static void gomp_task_run_post_handle_depend_hash (struct gomp_task *);
+static inline size_t gomp_task_run_post_handle_depend (struct gomp_task *,
+                                                      struct gomp_team *);
+
 /* Called when encountering an explicit task directive.  If IF_CLAUSE is
    false, then we must not delay in executing the task.  If UNTIED is true,
    then the task may be executed by any member of the team.
@@ -681,6 +692,18 @@ GOMP_task (void (*fn) (void *), void *data, void (*cpyfn) (void *, void *),
              gomp_mutex_unlock (&team->task_lock);
              return;
            }
+         /* Check for taskwait nowait depend which doesn't need to wait for
+            anything.  */
+         if (__builtin_expect (fn == empty_task, 0))
+           {
+             if (taskgroup)
+               taskgroup->num_children--;
+             gomp_task_run_post_handle_depend_hash (task);
+             gomp_mutex_unlock (&team->task_lock);
+             gomp_finish_task (task);
+             free (task);
+             return;
+           }
        }
 
       priority_queue_insert (PQ_CHILDREN, &parent->children_queue,
@@ -839,8 +862,6 @@ GOMP_PLUGIN_target_task_completion (void *data)
   gomp_mutex_unlock (&team->task_lock);
 }
 
-static void gomp_task_run_post_handle_depend_hash (struct gomp_task *);
-
 /* Called for nowait target tasks.  */
 
 bool
@@ -1357,6 +1378,18 @@ gomp_task_run_post_handle_dependers (struct gomp_task *child_task,
        continue;
 
       struct gomp_taskgroup *taskgroup = task->taskgroup;
+      if (__builtin_expect (task->fn == empty_task, 0))
+       {
+         if (!parent)
+           task->parent = NULL;
+         if (gomp_task_run_post_handle_depend (task, team))
+           ++ret;
+         if (taskgroup)
+           taskgroup->num_children--;
+         gomp_finish_task (task);
+         free (task);
+         continue;
+       }
       if (parent)
        {
          priority_queue_insert (PQ_CHILDREN, &parent->children_queue,
@@ -1832,6 +1865,16 @@ GOMP_taskwait_depend (void **depend)
     gomp_task_maybe_wait_for_dependencies (depend);
 }
 
+/* Called when encountering a taskwait directive with nowait and depend
+   clause(s).  Create a possibly deferred task construct with empty body.  */
+
+void
+GOMP_taskwait_depend_nowait (void **depend)
+{
+  ialias_call (GOMP_task) (empty_task, "", NULL, 0, 1, true,
+                          GOMP_TASK_FLAG_DEPEND, depend, 0, NULL);
+}
+
 /* An undeferred task is about to run.  Wait for all tasks that this
    undeferred task depends on.
 
diff --git a/libgomp/testsuite/libgomp.c-c++-common/taskwait-depend-nowait-1.c b/libgomp/testsuite/libgomp.c-c++-common/taskwait-depend-nowait-1.c
new file mode 100644 (file)
index 0000000..3d1519e
--- /dev/null
@@ -0,0 +1,39 @@
+#ifdef __cplusplus
+extern "C"
+#endif
+void abort (void);
+
+int
+main ()
+{
+  int a[64], b = 1;
+  #pragma omp parallel num_threads (4)
+  #pragma omp single
+  {
+    int i;
+    #pragma omp taskwait depend(in: a) nowait
+    #pragma omp taskwait depend(in: a) nowait
+    #pragma omp taskwait
+    #pragma omp taskgroup
+    {
+      #pragma omp taskwait depend(in: a) nowait
+      #pragma omp taskwait depend(in: a) nowait
+    }
+    for (i = 0; i < 64; ++i)
+      #pragma omp task depend(in: a) shared(a)
+      a[i] = i;
+    #pragma omp taskwait depend(inout: a) nowait
+    for (i = 0; i < 64; ++i)
+      #pragma omp task depend(inoutset: a) shared(a)
+      if (a[i] != i)
+       abort ();
+      else
+       a[i] = 2 * i + 1;
+    #pragma omp taskwait nowait depend(out: a) depend(in: b)
+    #pragma omp taskwait depend(inout: b)
+    for (i = 0; i < 64; ++i)
+      if (a[i] != 2 * i + 1)
+       abort ();
+  }
+  return 0;
+}