]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
openmp: Add support for the OpenMP 5.0 task detach clause
authorKwok Cheung Yeung <kcy@codesourcery.com>
Sat, 16 Jan 2021 20:58:13 +0000 (12:58 -0800)
committerKwok Cheung Yeung <kcy@codesourcery.com>
Fri, 22 Jan 2021 16:18:44 +0000 (08:18 -0800)
2021-01-16  Kwok Cheung Yeung  <kcy@codesourcery.com>

gcc/
* builtin-types.def
(BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT_PTR_INT): Rename
to...
(BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT_PTR_INT_PTR):
...this.  Add extra argument.
* gimplify.c (omp_default_clause): Ensure that event handle is
firstprivate in a task region.
(gimplify_scan_omp_clauses): Handle OMP_CLAUSE_DETACH.
(gimplify_adjust_omp_clauses): Likewise.
* omp-builtins.def (BUILT_IN_GOMP_TASK): Change function type to
BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT_PTR_INT_PTR.
* omp-expand.c (expand_task_call): Add GOMP_TASK_FLAG_DETACH to flags
if detach clause specified.  Add detach argument when generating
call to GOMP_task.
* omp-low.c (scan_sharing_clauses): Setup data environment for detach
clause.
(finish_taskreg_scan): Move field for variable containing the event
handle to the front of the struct.
* tree-core.h (enum omp_clause_code): Add OMP_CLAUSE_DETACH.  Fix
ordering.
* tree-nested.c (convert_nonlocal_omp_clauses): Handle
OMP_CLAUSE_DETACH clause.
(convert_local_omp_clauses): Handle OMP_CLAUSE_DETACH clause.
* tree-pretty-print.c (dump_omp_clause): Handle OMP_CLAUSE_DETACH.
* tree.c (omp_clause_num_ops): Add entry for OMP_CLAUSE_DETACH.
Fix ordering.
(omp_clause_code_name): Add entry for OMP_CLAUSE_DETACH.  Fix
ordering.
(walk_tree_1): Handle OMP_CLAUSE_DETACH.

gcc/c-family/
* c-pragma.h (pragma_omp_clause): Add PRAGMA_OMP_CLAUSE_DETACH.
Redefine PRAGMA_OACC_CLAUSE_DETACH.

gcc/c/
* c-parser.c (c_parser_omp_clause_detach): New.
(c_parser_omp_all_clauses): Handle PRAGMA_OMP_CLAUSE_DETACH clause.
(OMP_TASK_CLAUSE_MASK): Add mask for PRAGMA_OMP_CLAUSE_DETACH.
* c-typeck.c (c_finish_omp_clauses): Handle PRAGMA_OMP_CLAUSE_DETACH
clause.  Prevent use of detach with mergeable and overriding the
data sharing mode of the event handle.

gcc/cp/
* parser.c (cp_parser_omp_clause_detach): New.
(cp_parser_omp_all_clauses): Handle PRAGMA_OMP_CLAUSE_DETACH.
(OMP_TASK_CLAUSE_MASK): Add mask for PRAGMA_OMP_CLAUSE_DETACH.
* pt.c (tsubst_omp_clauses): Handle OMP_CLAUSE_DETACH clause.
* semantics.c (finish_omp_clauses): Handle OMP_CLAUSE_DETACH clause.
Prevent use of detach with mergeable and overriding the data sharing
mode of the event handle.

gcc/fortran/
* dump-parse-tree.c (show_omp_clauses): Handle detach clause.
* frontend-passes.c (gfc_code_walker): Walk detach expression.
* gfortran.h (struct gfc_omp_clauses): Add detach field.
(gfc_c_intptr_kind): New.
* openmp.c (gfc_free_omp_clauses): Free detach clause.
(gfc_match_omp_detach): New.
(enum omp_mask1): Add OMP_CLAUSE_DETACH.
(enum omp_mask2): Remove OMP_CLAUSE_DETACH.
(gfc_match_omp_clauses): Handle OMP_CLAUSE_DETACH for OpenMP.
(OMP_TASK_CLAUSES): Add OMP_CLAUSE_DETACH.
(resolve_omp_clauses): Prevent use of detach with mergeable and
overriding the data sharing mode of the event handle.
* trans-openmp.c (gfc_trans_omp_clauses): Handle detach clause.
* trans-types.c (gfc_c_intptr_kind): New.
(gfc_init_kinds): Initialize gfc_c_intptr_kind.
* types.def
(BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT_PTR_INT): Rename
to...
(BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT_PTR_INT_PTR):
...this.  Add extra argument.

gcc/testsuite/
* c-c++-common/gomp/task-detach-1.c: New.
* g++.dg/gomp/task-detach-1.C: New.
* gcc.dg/gomp/task-detach-1.c: New.
* gfortran.dg/gomp/task-detach-1.f90: New.

include/
* gomp-constants.h (GOMP_TASK_FLAG_DETACH): New.

libgomp/
* fortran.c (omp_fulfill_event_): New.
* libgomp.h (struct gomp_task): Add detach and completion_sem fields.
(struct gomp_team): Add task_detach_queue and task_detach_count
fields.
* libgomp.map (OMP_5.0.1): Add omp_fulfill_event and omp_fulfill_event_.
* libgomp_g.h (GOMP_task): Add extra argument.
* omp.h.in (enum omp_event_handle_t): New.
(omp_fulfill_event): New.
* omp_lib.f90.in (omp_event_handle_kind): New.
(omp_fulfill_event): New.
* omp_lib.h.in (omp_event_handle_kind): New.
(omp_fulfill_event): Declare.
* priority_queue.c (priority_tree_find): New.
(priority_list_find): New.
(priority_queue_find): New.
* priority_queue.h (priority_queue_predicate): New.
(priority_queue_find): New.
* task.c (gomp_init_task): Initialize detach field.
(task_fulfilled_p): New.
(GOMP_task): Add detach argument.  Ignore detach argument if
GOMP_TASK_FLAG_DETACH not set in flags.  Initialize completion_sem
field. Copy address of completion_sem into detach argument and
into the start of the data record.  Wait for detach event if task
not deferred.
(gomp_barrier_handle_tasks): Queue tasks with unfulfilled events.
Remove completed tasks and requeue dependent tasks.
(omp_fulfill_event): New.
* team.c (gomp_new_team): Initialize task_detach_queue and
task_detach_count fields.
(free_team): Free task_detach_queue field.
* testsuite/libgomp.c-c++-common/task-detach-1.c: New testcase.
* testsuite/libgomp.c-c++-common/task-detach-2.c: New testcase.
* testsuite/libgomp.c-c++-common/task-detach-3.c: New testcase.
* testsuite/libgomp.c-c++-common/task-detach-4.c: New testcase.
* testsuite/libgomp.c-c++-common/task-detach-5.c: New testcase.
* testsuite/libgomp.c-c++-common/task-detach-6.c: New testcase.
* testsuite/libgomp.fortran/task-detach-1.f90: New testcase.
* testsuite/libgomp.fortran/task-detach-2.f90: New testcase.
* testsuite/libgomp.fortran/task-detach-3.f90: New testcase.
* testsuite/libgomp.fortran/task-detach-4.f90: New testcase.
* testsuite/libgomp.fortran/task-detach-5.f90: New testcase.
* testsuite/libgomp.fortran/task-detach-6.f90: New testcase.

(cherry picked from commit a6d22fb21c6f1ad7e8b6b722bfc0e7e11f50cb92)

58 files changed:
gcc/ChangeLog.omp
gcc/builtin-types.def
gcc/c-family/ChangeLog.omp
gcc/c-family/c-pragma.h
gcc/c/ChangeLog.omp
gcc/c/c-parser.c
gcc/c/c-typeck.c
gcc/cp/ChangeLog.omp
gcc/cp/parser.c
gcc/cp/pt.c
gcc/cp/semantics.c
gcc/fortran/ChangeLog.omp
gcc/fortran/dump-parse-tree.c
gcc/fortran/frontend-passes.c
gcc/fortran/gfortran.h
gcc/fortran/openmp.c
gcc/fortran/trans-openmp.c
gcc/fortran/trans-types.c
gcc/fortran/types.def
gcc/gimplify.c
gcc/omp-builtins.def
gcc/omp-expand.c
gcc/omp-low.c
gcc/testsuite/ChangeLog.omp
gcc/testsuite/c-c++-common/gomp/task-detach-1.c [new file with mode: 0644]
gcc/testsuite/g++.dg/gomp/task-detach-1.C [new file with mode: 0644]
gcc/testsuite/gcc.dg/gomp/task-detach-1.c [new file with mode: 0644]
gcc/testsuite/gfortran.dg/gomp/task-detach-1.f90 [new file with mode: 0644]
gcc/tree-core.h
gcc/tree-nested.c
gcc/tree-pretty-print.c
gcc/tree.c
include/ChangeLog.omp
include/gomp-constants.h
libgomp/ChangeLog.omp
libgomp/fortran.c
libgomp/libgomp.h
libgomp/libgomp.map
libgomp/libgomp_g.h
libgomp/omp.h.in
libgomp/omp_lib.f90.in
libgomp/omp_lib.h.in
libgomp/priority_queue.c
libgomp/priority_queue.h
libgomp/task.c
libgomp/team.c
libgomp/testsuite/libgomp.c-c++-common/task-detach-1.c [new file with mode: 0644]
libgomp/testsuite/libgomp.c-c++-common/task-detach-2.c [new file with mode: 0644]
libgomp/testsuite/libgomp.c-c++-common/task-detach-3.c [new file with mode: 0644]
libgomp/testsuite/libgomp.c-c++-common/task-detach-4.c [new file with mode: 0644]
libgomp/testsuite/libgomp.c-c++-common/task-detach-5.c [new file with mode: 0644]
libgomp/testsuite/libgomp.c-c++-common/task-detach-6.c [new file with mode: 0644]
libgomp/testsuite/libgomp.fortran/task-detach-1.f90 [new file with mode: 0644]
libgomp/testsuite/libgomp.fortran/task-detach-2.f90 [new file with mode: 0644]
libgomp/testsuite/libgomp.fortran/task-detach-3.f90 [new file with mode: 0644]
libgomp/testsuite/libgomp.fortran/task-detach-4.f90 [new file with mode: 0644]
libgomp/testsuite/libgomp.fortran/task-detach-5.f90 [new file with mode: 0644]
libgomp/testsuite/libgomp.fortran/task-detach-6.f90 [new file with mode: 0644]

index f333d3d24106c6b6b0478908b1218cdde7f728f5..590dc27373af3c8cdd09ff4c6283477661696721 100644 (file)
@@ -1,3 +1,38 @@
+2021-01-22  Kwok Cheung Yeung  <kcy@codesourcery.com>
+
+       Backport from mainline
+       2021-01-16  Kwok Cheung Yeung  <kcy@codesourcery.com>
+
+       * builtin-types.def
+       (BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT_PTR_INT): Rename
+       to...
+       (BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT_PTR_INT_PTR):
+       ...this.  Add extra argument.
+       * gimplify.c (omp_default_clause): Ensure that event handle is
+       firstprivate in a task region.
+       (gimplify_scan_omp_clauses): Handle OMP_CLAUSE_DETACH.
+       (gimplify_adjust_omp_clauses): Likewise.
+       * omp-builtins.def (BUILT_IN_GOMP_TASK): Change function type to
+       BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT_PTR_INT_PTR.
+       * omp-expand.c (expand_task_call): Add GOMP_TASK_FLAG_DETACH to flags
+       if detach clause specified.  Add detach argument when generating
+       call to GOMP_task.
+       * omp-low.c (scan_sharing_clauses): Setup data environment for detach
+       clause.
+       (finish_taskreg_scan): Move field for variable containing the event
+       handle to the front of the struct.
+       * tree-core.h (enum omp_clause_code): Add OMP_CLAUSE_DETACH.  Fix
+       ordering.
+       * tree-nested.c (convert_nonlocal_omp_clauses): Handle
+       OMP_CLAUSE_DETACH clause.
+       (convert_local_omp_clauses): Handle OMP_CLAUSE_DETACH clause.
+       * tree-pretty-print.c (dump_omp_clause): Handle OMP_CLAUSE_DETACH.
+       * tree.c (omp_clause_num_ops): Add entry for OMP_CLAUSE_DETACH.
+       Fix ordering.
+       (omp_clause_code_name): Add entry for OMP_CLAUSE_DETACH.  Fix
+       ordering.
+       (walk_tree_1): Handle OMP_CLAUSE_DETACH.
+
 2020-12-18  Kwok Cheung Yeung  <kcy@codesourcery.com>
 
        Backport from mainline
index 5e36a498f4a5cfac75cca628137d127ee54ad97b..249338b572361c7c9f12ffb1cf9adf5e07636e63 100644 (file)
@@ -750,10 +750,6 @@ DEF_FUNCTION_TYPE_8 (BT_FN_BOOL_UINT_ULLPTR_LONG_ULL_ULLPTR_ULLPTR_PTR_PTR,
                     BT_BOOL, BT_UINT, BT_PTR_ULONGLONG, BT_LONG, BT_ULONGLONG,
                     BT_PTR_ULONGLONG, BT_PTR_ULONGLONG, BT_PTR, BT_PTR)
 
-DEF_FUNCTION_TYPE_9 (BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT_PTR_INT,
-                    BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR,
-                    BT_PTR_FN_VOID_PTR_PTR, BT_LONG, BT_LONG,
-                    BT_BOOL, BT_UINT, BT_PTR, BT_INT)
 DEF_FUNCTION_TYPE_9 (BT_FN_VOID_INT_OMPFN_SIZE_PTR_PTR_PTR_UINT_PTR_PTR,
                     BT_VOID, BT_INT, BT_PTR_FN_VOID_PTR, BT_SIZE, BT_PTR,
                     BT_PTR, BT_PTR, BT_UINT, BT_PTR, BT_PTR)
@@ -761,6 +757,10 @@ DEF_FUNCTION_TYPE_9 (BT_FN_BOOL_LONG_LONG_LONG_LONG_LONG_LONGPTR_LONGPTR_PTR_PTR
                     BT_BOOL, BT_LONG, BT_LONG, BT_LONG, BT_LONG, BT_LONG,
                     BT_PTR_LONG, BT_PTR_LONG, BT_PTR, BT_PTR)
 
+DEF_FUNCTION_TYPE_10 (BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT_PTR_INT_PTR,
+                     BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR,
+                     BT_PTR_FN_VOID_PTR_PTR, BT_LONG, BT_LONG,
+                     BT_BOOL, BT_UINT, BT_PTR, BT_INT, BT_PTR)
 DEF_FUNCTION_TYPE_10 (BT_FN_BOOL_BOOL_ULL_ULL_ULL_LONG_ULL_ULLPTR_ULLPTR_PTR_PTR,
                      BT_BOOL, BT_BOOL, BT_ULONGLONG, BT_ULONGLONG,
                      BT_ULONGLONG, BT_LONG, BT_ULONGLONG, BT_PTR_ULONGLONG,
index 49fa269e077a9794177f88a247937864877ef3ff..d0d7d3f08b6d692ef793daa9e0d8794180507da0 100644 (file)
@@ -1,3 +1,11 @@
+2021-01-22  Kwok Cheung Yeung  <kcy@codesourcery.com>
+
+       Backport from mainline
+       2021-01-16  Kwok Cheung Yeung  <kcy@codesourcery.com>
+
+       * c-pragma.h (pragma_omp_clause): Add PRAGMA_OMP_CLAUSE_DETACH.
+       Redefine PRAGMA_OACC_CLAUSE_DETACH.
+
 2020-09-16  Tobias Burnus  <tobias@codesourcery.com>
 
        Backport from mainline
index b8d9b7a4cff91793fa2ab752444dddb79f2737d8..3e6e5d87fd33dcf1c7cafe58c90dfe5058460ffd 100644 (file)
@@ -93,6 +93,7 @@ enum pragma_omp_clause {
   PRAGMA_OMP_CLAUSE_DEFAULT,
   PRAGMA_OMP_CLAUSE_DEFAULTMAP,
   PRAGMA_OMP_CLAUSE_DEPEND,
+  PRAGMA_OMP_CLAUSE_DETACH,
   PRAGMA_OMP_CLAUSE_DEVICE,
   PRAGMA_OMP_CLAUSE_DEVICE_TYPE,
   PRAGMA_OMP_CLAUSE_DIST_SCHEDULE,
@@ -149,7 +150,6 @@ enum pragma_omp_clause {
   PRAGMA_OACC_CLAUSE_COPYOUT,
   PRAGMA_OACC_CLAUSE_CREATE,
   PRAGMA_OACC_CLAUSE_DELETE,
-  PRAGMA_OACC_CLAUSE_DETACH,
   PRAGMA_OACC_CLAUSE_DEVICEPTR,
   PRAGMA_OACC_CLAUSE_DEVICE_RESIDENT,
   PRAGMA_OACC_CLAUSE_FINALIZE,
@@ -173,6 +173,7 @@ enum pragma_omp_clause {
   PRAGMA_OACC_CLAUSE_COPYIN = PRAGMA_OMP_CLAUSE_COPYIN,
   PRAGMA_OACC_CLAUSE_DEVICE = PRAGMA_OMP_CLAUSE_DEVICE,
   PRAGMA_OACC_CLAUSE_DEFAULT = PRAGMA_OMP_CLAUSE_DEFAULT,
+  PRAGMA_OACC_CLAUSE_DETACH = PRAGMA_OMP_CLAUSE_DETACH,
   PRAGMA_OACC_CLAUSE_FIRSTPRIVATE = PRAGMA_OMP_CLAUSE_FIRSTPRIVATE,
   PRAGMA_OACC_CLAUSE_IF = PRAGMA_OMP_CLAUSE_IF,
   PRAGMA_OACC_CLAUSE_PRIVATE = PRAGMA_OMP_CLAUSE_PRIVATE,
index e520f95fd8993ee2c2ad6a3814ea5a9c683045dc..e9ad3a1ea6f6c8c8d68f2e8cac3949c5d08145e0 100644 (file)
@@ -1,3 +1,15 @@
+2021-01-22  Kwok Cheung Yeung  <kcy@codesourcery.com>
+
+       Backport from mainline
+       2021-01-16  Kwok Cheung Yeung  <kcy@codesourcery.com>
+
+       * c-parser.c (c_parser_omp_clause_detach): New.
+       (c_parser_omp_all_clauses): Handle PRAGMA_OMP_CLAUSE_DETACH clause.
+       (OMP_TASK_CLAUSE_MASK): Add mask for PRAGMA_OMP_CLAUSE_DETACH.
+       * c-typeck.c (c_finish_omp_clauses): Handle PRAGMA_OMP_CLAUSE_DETACH
+       clause.  Prevent use of detach with mergeable and overriding the
+       data sharing mode of the event handle.
+
 2020-09-17  Tobias Burnus  <tobias@codesourcery.com>
 
        Backport from mainline
index b4611ee5089210cc9bd1c6d6d30bdbd85aea4c09..6b9898a1c7051f581d611574eb9c1d4368861314 100644 (file)
@@ -15912,6 +15912,56 @@ c_parser_omp_clause_uniform (c_parser *parser, tree list)
   return list;
 }
 
+/* OpenMP 5.0:
+   detach ( event-handle ) */
+
+static tree
+c_parser_omp_clause_detach (c_parser *parser, tree list)
+{
+  matching_parens parens;
+  location_t clause_loc = c_parser_peek_token (parser)->location;
+
+  if (!parens.require_open (parser))
+    return list;
+
+  if (c_parser_next_token_is_not (parser, CPP_NAME)
+      || c_parser_peek_token (parser)->id_kind != C_ID_ID)
+    {
+      c_parser_error (parser, "expected identifier");
+      parens.skip_until_found_close (parser);
+      return list;
+    }
+
+  tree t = lookup_name (c_parser_peek_token (parser)->value);
+  if (t == NULL_TREE)
+    {
+      undeclared_variable (c_parser_peek_token (parser)->location,
+                          c_parser_peek_token (parser)->value);
+      parens.skip_until_found_close (parser);
+      return list;
+    }
+  c_parser_consume_token (parser);
+
+  tree type = TYPE_MAIN_VARIANT (TREE_TYPE (t));
+  if (!INTEGRAL_TYPE_P (type)
+      || TREE_CODE (type) != ENUMERAL_TYPE
+      || TYPE_NAME (type) != get_identifier ("omp_event_handle_t"))
+    {
+      error_at (clause_loc, "%<detach%> clause event handle "
+                           "has type %qT rather than "
+                           "%<omp_event_handle_t%>",
+                           type);
+      parens.skip_until_found_close (parser);
+      return list;
+    }
+
+  tree u = build_omp_clause (clause_loc, OMP_CLAUSE_DETACH);
+  OMP_CLAUSE_DECL (u) = t;
+  OMP_CLAUSE_CHAIN (u) = list;
+  parens.skip_until_found_close (parser);
+  return u;
+}
+
 /* Parse all OpenACC clauses.  The set clauses allowed by the directive
    is a bitmask in MASK.  Return the list of clauses found.  */
 
@@ -16183,6 +16233,10 @@ c_parser_omp_all_clauses (c_parser *parser, omp_clause_mask mask,
          clauses = c_parser_omp_clause_default (parser, clauses, false);
          c_name = "default";
          break;
+       case PRAGMA_OMP_CLAUSE_DETACH:
+         clauses = c_parser_omp_clause_detach (parser, clauses);
+         c_name = "detach";
+         break;
        case PRAGMA_OMP_CLAUSE_FIRSTPRIVATE:
          clauses = c_parser_omp_clause_firstprivate (parser, clauses);
          c_name = "firstprivate";
@@ -19029,7 +19083,8 @@ c_parser_omp_single (location_t loc, c_parser *parser, bool *if_p)
        | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MERGEABLE)    \
        | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND)       \
        | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIORITY)     \
-       | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IN_REDUCTION))
+       | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IN_REDUCTION) \
+       | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DETACH))
 
 static tree
 c_parser_omp_task (location_t loc, c_parser *parser, bool *if_p)
index 3ee0da0ba948697c3b1f487759251bd78c8d7f87..651f29bb21ba66ea70190c878649034896a1aa08 100644 (file)
@@ -13760,6 +13760,8 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
   tree simdlen = NULL_TREE, safelen = NULL_TREE;
   bool branch_seen = false;
   bool copyprivate_seen = false;
+  bool mergeable_seen = false;
+  tree *detach_seen = NULL;
   bool linear_variable_step_check = false;
   tree *nowait_clause = NULL;
   tree ordered_clause = NULL_TREE;
@@ -14833,6 +14835,21 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
          pc = &OMP_CLAUSE_CHAIN (c);
          continue;
 
+       case OMP_CLAUSE_DETACH:
+         t = OMP_CLAUSE_DECL (c);
+         if (detach_seen)
+           {
+             error_at (OMP_CLAUSE_LOCATION (c),
+                       "too many %qs clauses on a task construct",
+                       "detach");
+             remove = true;
+             break;
+           }
+         detach_seen = pc;
+         pc = &OMP_CLAUSE_CHAIN (c);
+         c_mark_addressable (t);
+         continue;
+
        case OMP_CLAUSE_IF:
        case OMP_CLAUSE_NUM_THREADS:
        case OMP_CLAUSE_NUM_TEAMS:
@@ -14841,7 +14858,6 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
        case OMP_CLAUSE_UNTIED:
        case OMP_CLAUSE_COLLAPSE:
        case OMP_CLAUSE_FINAL:
-       case OMP_CLAUSE_MERGEABLE:
        case OMP_CLAUSE_DEVICE:
        case OMP_CLAUSE_DIST_SCHEDULE:
        case OMP_CLAUSE_PARALLEL:
@@ -14876,6 +14892,11 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
          pc = &OMP_CLAUSE_CHAIN (c);
          continue;
 
+       case OMP_CLAUSE_MERGEABLE:
+         mergeable_seen = true;
+         pc = &OMP_CLAUSE_CHAIN (c);
+         continue;
+
        case OMP_CLAUSE_NOGROUP:
          nogroup_seen = pc;
          pc = &OMP_CLAUSE_CHAIN (c);
@@ -15077,6 +15098,41 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
       *nogroup_seen = OMP_CLAUSE_CHAIN (*nogroup_seen);
     }
 
+  if (detach_seen)
+    {
+      if (mergeable_seen)
+       {
+         error_at (OMP_CLAUSE_LOCATION (*detach_seen),
+                   "%<detach%> clause must not be used together with "
+                   "%<mergeable%> clause");
+         *detach_seen = OMP_CLAUSE_CHAIN (*detach_seen);
+       }
+      else
+       {
+         tree detach_decl = OMP_CLAUSE_DECL (*detach_seen);
+
+         for (pc = &clauses, c = clauses; c ; c = *pc)
+           {
+             bool remove = false;
+             if ((OMP_CLAUSE_CODE (c) == OMP_CLAUSE_SHARED
+                  || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_PRIVATE
+                  || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FIRSTPRIVATE
+                  || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE)
+                 && OMP_CLAUSE_DECL (c) == detach_decl)
+               {
+                 error_at (OMP_CLAUSE_LOCATION (c),
+                           "the event handle of a %<detach%> clause "
+                           "should not be in a data-sharing clause");
+                 remove = true;
+               }
+             if (remove)
+               *pc = OMP_CLAUSE_CHAIN (c);
+             else
+               pc = &OMP_CLAUSE_CHAIN (c);
+           }
+       }
+    }
+
   bitmap_obstack_release (NULL);
   return clauses;
 }
index 3dac62b4edcdc29dd49d5db6f9497fabbbbcf231..f071ef61b17081c34c6b51df2b743906f8a702ba 100644 (file)
@@ -1,3 +1,16 @@
+2021-01-22  Kwok Cheung Yeung  <kcy@codesourcery.com>
+
+       Backport from mainline
+       2021-01-16  Kwok Cheung Yeung  <kcy@codesourcery.com>
+
+       * parser.c (cp_parser_omp_clause_detach): New.
+       (cp_parser_omp_all_clauses): Handle PRAGMA_OMP_CLAUSE_DETACH.
+       (OMP_TASK_CLAUSE_MASK): Add mask for PRAGMA_OMP_CLAUSE_DETACH.
+       * pt.c (tsubst_omp_clauses): Handle OMP_CLAUSE_DETACH clause.
+       * semantics.c (finish_omp_clauses): Handle OMP_CLAUSE_DETACH clause.
+       Prevent use of detach with mergeable and overriding the data sharing
+       mode of the event handle.
+
 2020-12-18  Kwok Cheung Yeung  <kcy@codesourcery.com>
 
        Backport from mainline
index c5192278ca8f449f7d4ecb380d4fc30e191744e5..cea6ed0b2c198cdd51083314c5c3316e5b964e22 100644 (file)
@@ -36404,6 +36404,52 @@ cp_parser_omp_clause_depend_sink (cp_parser *parser, location_t clause_loc,
   return list;
 }
 
+/* OpenMP 5.0:
+   detach ( event-handle ) */
+
+static tree
+cp_parser_omp_clause_detach (cp_parser *parser, tree list)
+{
+  matching_parens parens;
+
+  if (!parens.require_open (parser))
+    return list;
+
+  cp_token *token;
+  tree name, decl;
+
+  token = cp_lexer_peek_token (parser->lexer);
+  name = cp_parser_id_expression (parser, /*template_p=*/false,
+                                         /*check_dependency_p=*/true,
+                                         /*template_p=*/NULL,
+                                         /*declarator_p=*/false,
+                                         /*optional_p=*/false);
+  if (name == error_mark_node)
+    decl = error_mark_node;
+  else
+    {
+      if (identifier_p (name))
+       decl = cp_parser_lookup_name_simple (parser, name, token->location);
+      else
+       decl = name;
+      if (decl == error_mark_node)
+       cp_parser_name_lookup_error (parser, name, decl, NLE_NULL,
+                                    token->location);
+    }
+
+  if (decl == error_mark_node
+      || !parens.require_close (parser))
+    cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true,
+                                          /*or_comma=*/false,
+                                          /*consume_paren=*/true);
+
+  tree u = build_omp_clause (token->location, OMP_CLAUSE_DETACH);
+  OMP_CLAUSE_DECL (u) = decl;
+  OMP_CLAUSE_CHAIN (u) = list;
+
+  return u;
+}
+
 /* OpenMP 5.0:
    iterators ( iterators-definition )
 
@@ -37461,6 +37507,10 @@ cp_parser_omp_all_clauses (cp_parser *parser, omp_clause_mask mask,
                                                 token->location);
          c_name = "depend";
          break;
+       case PRAGMA_OMP_CLAUSE_DETACH:
+         clauses = cp_parser_omp_clause_detach (parser, clauses);
+         c_name = "detach";
+         break;
        case PRAGMA_OMP_CLAUSE_MAP:
          clauses = cp_parser_omp_clause_map (parser, clauses);
          c_name = "map";
@@ -39977,7 +40027,8 @@ cp_parser_omp_single (cp_parser *parser, cp_token *pragma_tok, bool *if_p)
        | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MERGEABLE)    \
        | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND)       \
        | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIORITY)     \
-       | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IN_REDUCTION))
+       | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IN_REDUCTION) \
+       | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DETACH))
 
 static tree
 cp_parser_omp_task (cp_parser *parser, cp_token *pragma_tok, bool *if_p)
index 041b61059ff926aed0049d538673bef9ea80d17f..781b055921b36e190656011a712316d226c38bdd 100644 (file)
@@ -17205,6 +17205,7 @@ tsubst_omp_clauses (tree clauses, enum c_omp_region_type ort,
        case OMP_CLAUSE_VECTOR:
        case OMP_CLAUSE_ASYNC:
        case OMP_CLAUSE_WAIT:
+       case OMP_CLAUSE_DETACH:
          OMP_CLAUSE_OPERAND (nc, 0)
            = tsubst_expr (OMP_CLAUSE_OPERAND (oc, 0), args, complain,
                           in_decl, /*integral_constant_expression_p=*/false);
index 0d8b1298f56f35d9590d6de18d6ac32e2620de84..86d5d464a325ceffb0e53fa1ab5decb6a1f3fadd 100644 (file)
@@ -6383,6 +6383,8 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
      has been seen, -2 if mixed inscan/normal reduction diagnosed.  */
   int reduction_seen = 0;
   bool oacc_gang_seen = false;
+  bool detach_seen = false;
+  bool mergeable_seen = false;
 
   bitmap_obstack_initialize (NULL);
   bitmap_initialize (&generic_head, &bitmap_default_obstack);
@@ -7338,6 +7340,36 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
                }
            }
          break;
+       case OMP_CLAUSE_DETACH:
+         t = OMP_CLAUSE_DECL (c);
+         if (detach_seen)
+           {
+             error_at (OMP_CLAUSE_LOCATION (c),
+                       "too many %qs clauses on a task construct",
+                       "detach");
+             remove = true;
+             break;
+           }
+         else
+           {
+             tree type = TYPE_MAIN_VARIANT (TREE_TYPE (t));
+             if (!type_dependent_expression_p (t)
+                 && (!INTEGRAL_TYPE_P (type)
+                     || TREE_CODE (type) != ENUMERAL_TYPE
+                     || (DECL_NAME (TYPE_NAME (type))
+                         != get_identifier ("omp_event_handle_t"))))
+               {
+                 error_at (OMP_CLAUSE_LOCATION (c),
+                           "%<detach%> clause event handle "
+                           "has type %qT rather than "
+                           "%<omp_event_handle_t%>",
+                           type);
+                 remove = true;
+               }
+             detach_seen = true;
+             cxx_mark_addressable (t);
+           }
+         break;
 
        case OMP_CLAUSE_MAP:
        case OMP_CLAUSE_TO:
@@ -7884,7 +7916,6 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
        case OMP_CLAUSE_DEFAULT:
        case OMP_CLAUSE_UNTIED:
        case OMP_CLAUSE_COLLAPSE:
-       case OMP_CLAUSE_MERGEABLE:
        case OMP_CLAUSE_PARALLEL:
        case OMP_CLAUSE_FOR:
        case OMP_CLAUSE_SECTIONS:
@@ -7904,6 +7935,10 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
        case OMP_CLAUSE_NOHOST:
          break;
 
+       case OMP_CLAUSE_MERGEABLE:
+         mergeable_seen = true;
+         break;
+
        case OMP_CLAUSE_TILE:
          for (tree list = OMP_CLAUSE_TILE_LIST (c); !remove && list;
               list = TREE_CHAIN (list))
@@ -8141,6 +8176,17 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
            }
          pc = &OMP_CLAUSE_CHAIN (c);
          continue;
+       case OMP_CLAUSE_DETACH:
+         if (mergeable_seen)
+           {
+             error_at (OMP_CLAUSE_LOCATION (c),
+                       "%<detach%> clause must not be used together with "
+                       "%<mergeable%> clause");
+             *pc = OMP_CLAUSE_CHAIN (c);
+             continue;
+           }
+         pc = &OMP_CLAUSE_CHAIN (c);
+         continue;
        case OMP_CLAUSE_NOWAIT:
          if (copyprivate_seen)
            {
@@ -8264,6 +8310,19 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
            }
        }
 
+      if (detach_seen
+         && (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_SHARED
+             || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_PRIVATE
+             || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FIRSTPRIVATE
+             || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE)
+         && OMP_CLAUSE_DECL (c) == t)
+       {
+         error_at (OMP_CLAUSE_LOCATION (c),
+                   "the event handle of a %<detach%> clause "
+                   "should not be in a data-sharing clause");
+         remove = true;
+       }
+
       /* We're interested in the base element, not arrays.  */
       inner_type = type = TREE_TYPE (t);
       if ((need_complete_type
index 39a3682c92581b1687dfa3fd80c11ab556af31ca..dc045ebd5d53184ff297163f4323f92cadbf996d 100644 (file)
@@ -1,3 +1,29 @@
+2021-01-22  Kwok Cheung Yeung  <kcy@codesourcery.com>
+
+       Backport from mainline
+       2021-01-16  Kwok Cheung Yeung  <kcy@codesourcery.com>
+
+       * dump-parse-tree.c (show_omp_clauses): Handle detach clause.
+       * frontend-passes.c (gfc_code_walker): Walk detach expression.
+       * gfortran.h (struct gfc_omp_clauses): Add detach field.
+       (gfc_c_intptr_kind): New.
+       * openmp.c (gfc_free_omp_clauses): Free detach clause.
+       (gfc_match_omp_detach): New.
+       (enum omp_mask1): Add OMP_CLAUSE_DETACH.
+       (enum omp_mask2): Remove OMP_CLAUSE_DETACH.
+       (gfc_match_omp_clauses): Handle OMP_CLAUSE_DETACH for OpenMP.
+       (OMP_TASK_CLAUSES): Add OMP_CLAUSE_DETACH.
+       (resolve_omp_clauses): Prevent use of detach with mergeable and
+       overriding the data sharing mode of the event handle.
+       * trans-openmp.c (gfc_trans_omp_clauses): Handle detach clause.
+       * trans-types.c (gfc_c_intptr_kind): New.
+       (gfc_init_kinds): Initialize gfc_c_intptr_kind.
+       * types.def
+       (BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT_PTR_INT): Rename
+       to...
+       (BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT_PTR_INT_PTR):
+       ...this.  Add extra argument.
+
 2021-01-04  Tobias Burnus  <tobias@codesourcery.com>
 
        Backported from master:
index b9c321469d2a83d3dd2134b301c3353e10896e29..fe24e9cf4d789f4a9dbaa47f9da490ba55c641bb 100644 (file)
@@ -1692,6 +1692,12 @@ show_omp_clauses (gfc_omp_clauses *omp_clauses)
       show_expr (omp_clauses->priority);
       fputc (')', dumpfile);
     }
+  if (omp_clauses->detach)
+    {
+      fputs (" DETACH(", dumpfile);
+      show_expr (omp_clauses->detach);
+      fputc (')', dumpfile);
+    }
   for (i = 0; i < OMP_IF_LAST; i++)
     if (omp_clauses->if_exprs[i])
       {
index 5e768b12854a4681c0f6d5f507ceca211f6a1156..80efafd6cb9c3c367f5dec273bd04ffb9d4f0a77 100644 (file)
@@ -5342,6 +5342,7 @@ gfc_code_walker (gfc_code **c, walk_code_fn_t codefn, walk_expr_fn_t exprfn,
                  WALK_SUBEXPR (co->ext.omp_clauses->hint);
                  WALK_SUBEXPR (co->ext.omp_clauses->num_tasks);
                  WALK_SUBEXPR (co->ext.omp_clauses->priority);
+                 WALK_SUBEXPR (co->ext.omp_clauses->detach);
                  for (idx = 0; idx < OMP_IF_LAST; idx++)
                    WALK_SUBEXPR (co->ext.omp_clauses->if_exprs[idx]);
                  for (idx = 0;
index bd154f42a75f1e8667a6f936b85de1049fb23c15..ce37e72c6b1efca00f040af2270cb2f1f04e859c 100644 (file)
@@ -1390,6 +1390,7 @@ typedef struct gfc_omp_clauses
   struct gfc_expr *hint;
   struct gfc_expr *num_tasks;
   struct gfc_expr *priority;
+  struct gfc_expr *detach;
   struct gfc_expr *if_exprs[OMP_IF_LAST];
   enum gfc_omp_sched_kind dist_sched_kind;
   struct gfc_expr *dist_chunk_size;
@@ -3088,6 +3089,7 @@ extern int gfc_default_character_kind;
 extern int gfc_default_logical_kind;
 extern int gfc_default_complex_kind;
 extern int gfc_c_int_kind;
+extern int gfc_c_intptr_kind;
 extern int gfc_atomic_int_kind;
 extern int gfc_atomic_logical_kind;
 extern int gfc_intio_kind;
index 334125e7f9ac00773932269ab9683e6a68d3f148..8dc2871cd41b83ebdf71af389624b19f086aa6f8 100644 (file)
@@ -92,6 +92,7 @@ gfc_free_omp_clauses (gfc_omp_clauses *c)
   gfc_free_expr (c->hint);
   gfc_free_expr (c->num_tasks);
   gfc_free_expr (c->priority);
+  gfc_free_expr (c->detach);
   for (i = 0; i < OMP_IF_LAST; i++)
     gfc_free_expr (c->if_exprs[i]);
   gfc_free_expr (c->async_expr);
@@ -449,6 +450,39 @@ cleanup:
   return MATCH_ERROR;
 }
 
+/* Match detach(event-handle).  */
+
+static match
+gfc_match_omp_detach (gfc_expr **expr)
+{
+  locus old_loc = gfc_current_locus;
+
+  if (gfc_match ("detach ( ") != MATCH_YES)
+    goto syntax_error;
+
+  if (gfc_match_variable (expr, 0) != MATCH_YES)
+    goto syntax_error;
+
+  if ((*expr)->ts.type != BT_INTEGER || (*expr)->ts.kind != gfc_c_intptr_kind)
+    {
+      gfc_error ("%qs at %L should be of type "
+                "integer(kind=omp_event_handle_kind)",
+                (*expr)->symtree->n.sym->name, &(*expr)->where);
+      return MATCH_ERROR;
+    }
+
+  if (gfc_match_char (')') != MATCH_YES)
+    goto syntax_error;
+
+  return MATCH_YES;
+
+syntax_error:
+   gfc_error ("Syntax error in OpenMP detach clause at %C");
+   gfc_current_locus = old_loc;
+   return MATCH_ERROR;
+
+}
+
 /* Match depend(sink : ...) construct a namelist from it.  */
 
 static match
@@ -803,6 +837,7 @@ enum omp_mask1
   OMP_CLAUSE_USE_DEVICE_PTR,
   OMP_CLAUSE_USE_DEVICE_ADDR,  /* OpenMP 5.0.  */
   OMP_CLAUSE_DEVICE_TYPE,  /* OpenMP 5.0.  */
+  OMP_CLAUSE_DETACH,  /* OpenMP 5.0.  */
   OMP_CLAUSE_NOWAIT,
   /* This must come last.  */
   OMP_MASK1_LAST
@@ -836,7 +871,6 @@ enum omp_mask2
   OMP_CLAUSE_IF_PRESENT,
   OMP_CLAUSE_FINALIZE,
   OMP_CLAUSE_ATTACH,
-  OMP_CLAUSE_DETACH,
   OMP_CLAUSE_NOHOST,
   /* This must come last.  */
   OMP_MASK2_LAST
@@ -1194,6 +1228,12 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask,
                gfc_current_locus = old_loc;
            }
          if ((mask & OMP_CLAUSE_DETACH)
+             && !openacc
+             && !c->detach
+             && gfc_match_omp_detach (&c->detach) == MATCH_YES)
+           continue;
+         if ((mask & OMP_CLAUSE_DETACH)
+             && openacc
              && gfc_match ("detach ( ") == MATCH_YES
              && gfc_match_omp_map_clause (&c->lists[OMP_LIST_MAP],
                                           OMP_MAP_DETACH, false,
@@ -2633,7 +2673,7 @@ cleanup:
   (omp_mask (OMP_CLAUSE_PRIVATE) | OMP_CLAUSE_FIRSTPRIVATE             \
    | OMP_CLAUSE_SHARED | OMP_CLAUSE_IF | OMP_CLAUSE_DEFAULT            \
    | OMP_CLAUSE_UNTIED | OMP_CLAUSE_FINAL | OMP_CLAUSE_MERGEABLE       \
-   | OMP_CLAUSE_DEPEND | OMP_CLAUSE_PRIORITY)
+   | OMP_CLAUSE_DEPEND | OMP_CLAUSE_PRIORITY | OMP_CLAUSE_DETACH)
 #define OMP_TASKLOOP_CLAUSES \
   (omp_mask (OMP_CLAUSE_PRIVATE) | OMP_CLAUSE_FIRSTPRIVATE             \
    | OMP_CLAUSE_LASTPRIVATE | OMP_CLAUSE_SHARED | OMP_CLAUSE_IF                \
@@ -4827,6 +4867,10 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses,
                if (n->sym->attr.associate_var)
                  gfc_error ("ASSOCIATE name %qs in SHARED clause at %L",
                             n->sym->name, &n->where);
+               if (omp_clauses->detach
+                   && n->sym == omp_clauses->detach->symtree->n.sym)
+                 gfc_error ("DETACH event handle %qs in SHARED clause at %L",
+                            n->sym->name, &n->where);
              }
            break;
          case OMP_LIST_ALIGNED:
@@ -5137,7 +5181,13 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses,
                    default:
                      break;
                    }
-
+               if (omp_clauses->detach
+                   && (list == OMP_LIST_PRIVATE
+                       || list == OMP_LIST_FIRSTPRIVATE
+                       || list == OMP_LIST_LASTPRIVATE)
+                   && n->sym == omp_clauses->detach->symtree->n.sym)
+                 gfc_error ("DETACH event handle %qs in %s clause at %L",
+                            n->sym->name, name, &n->where);
                switch (list)
                  {
                  case OMP_LIST_REDUCTION:
@@ -5420,6 +5470,9 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses,
        gfc_error ("%s must contain at least one MAP clause at %L",
                   p, &code->loc);
     }
+  if (!openacc && omp_clauses->mergeable && omp_clauses->detach)
+    gfc_error ("%<DETACH%> clause at %L must not be used together with "
+              "%<MERGEABLE%> clause", &omp_clauses->detach->where);
 }
 
 
index 77ecb957dfd805552a1948773e30295c3ef3bbc4..452e2a69baa29b3560cf944d17de430e74c6d5ca 100644 (file)
@@ -3649,6 +3649,22 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses,
       omp_clauses = gfc_trans_add_clause (c, omp_clauses);
     }
 
+  if (clauses->detach)
+    {
+      tree detach;
+
+      gfc_init_se (&se, NULL);
+      gfc_conv_expr (&se, clauses->detach);
+      gfc_add_block_to_block (block, &se.pre);
+      detach = se.expr;
+      gfc_add_block_to_block (block, &se.post);
+
+      c = build_omp_clause (gfc_get_location (&where), OMP_CLAUSE_DETACH);
+      TREE_ADDRESSABLE (detach) = 1;
+      OMP_CLAUSE_DECL (c) = detach;
+      omp_clauses = gfc_trans_add_clause (c, omp_clauses);
+    }
+
   if (clauses->hint)
     {
       tree hint;
index b7712dc74d167d1e35506c44fb0fdfb67ef1286e..f90025d75cf440bdfc8fa9a0a204137da160843d 100644 (file)
@@ -113,6 +113,7 @@ int gfc_default_character_kind;
 int gfc_default_logical_kind;
 int gfc_default_complex_kind;
 int gfc_c_int_kind;
+int gfc_c_intptr_kind;
 int gfc_atomic_int_kind;
 int gfc_atomic_logical_kind;
 
@@ -690,6 +691,8 @@ gfc_init_kinds (void)
   /* Choose atomic kinds to match C's int.  */
   gfc_atomic_int_kind = gfc_c_int_kind;
   gfc_atomic_logical_kind = gfc_c_int_kind;
+
+  gfc_c_intptr_kind = POINTER_SIZE / 8;
 }
 
 
index e5fafc5a34d7006ad2165c8c26ab800c2de2f314..80e4fad5263f936c9f648afa5da63d32e8fa1a29 100644 (file)
@@ -230,10 +230,6 @@ DEF_FUNCTION_TYPE_8 (BT_FN_BOOL_UINT_ULLPTR_LONG_ULL_ULLPTR_ULLPTR_PTR_PTR,
                     BT_BOOL, BT_UINT, BT_PTR_ULONGLONG, BT_LONG, BT_ULONGLONG,
                     BT_PTR_ULONGLONG, BT_PTR_ULONGLONG, BT_PTR, BT_PTR)
 
-DEF_FUNCTION_TYPE_9 (BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT_PTR_INT,
-                    BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR,
-                    BT_PTR_FN_VOID_PTR_PTR, BT_LONG, BT_LONG,
-                    BT_BOOL, BT_UINT, BT_PTR, BT_INT)
 DEF_FUNCTION_TYPE_9 (BT_FN_VOID_INT_OMPFN_SIZE_PTR_PTR_PTR_UINT_PTR_PTR,
                     BT_VOID, BT_INT, BT_PTR_FN_VOID_PTR, BT_SIZE, BT_PTR,
                     BT_PTR, BT_PTR, BT_UINT, BT_PTR, BT_PTR)
@@ -241,6 +237,10 @@ DEF_FUNCTION_TYPE_9 (BT_FN_BOOL_LONG_LONG_LONG_LONG_LONG_LONGPTR_LONGPTR_PTR_PTR
                     BT_BOOL, BT_LONG, BT_LONG, BT_LONG, BT_LONG, BT_LONG,
                     BT_PTR_LONG, BT_PTR_LONG, BT_PTR, BT_PTR)
 
+DEF_FUNCTION_TYPE_10 (BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT_PTR_INT_PTR,
+                     BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR,
+                     BT_PTR_FN_VOID_PTR_PTR, BT_LONG, BT_LONG,
+                     BT_BOOL, BT_UINT, BT_PTR, BT_INT, BT_PTR)
 DEF_FUNCTION_TYPE_10 (BT_FN_BOOL_BOOL_ULL_ULL_ULL_LONG_ULL_ULLPTR_ULLPTR_PTR_PTR,
                      BT_BOOL, BT_BOOL, BT_ULONGLONG, BT_ULONGLONG,
                      BT_ULONGLONG, BT_LONG, BT_ULONGLONG, BT_PTR_ULONGLONG,
index bf4eb8b008b62985366e17cb37010d78eb9fa76e..f5769403461673072e61da093f93da24564dd913 100644 (file)
@@ -7204,6 +7204,15 @@ omp_default_clause (struct gimplify_omp_ctx *ctx, tree decl,
   enum omp_clause_default_kind kind;
 
   kind = lang_hooks.decls.omp_predetermined_sharing (decl);
+  if (ctx->region_type & ORT_TASK)
+    {
+      tree detach_clause = omp_find_clause (ctx->clauses, OMP_CLAUSE_DETACH);
+
+      /* The event-handle specified by a detach clause should always be firstprivate,
+        regardless of the current default.  */
+      if (detach_clause && OMP_CLAUSE_DECL (detach_clause) == decl)
+       kind = OMP_CLAUSE_DEFAULT_FIRSTPRIVATE;
+    }
   if (kind != OMP_CLAUSE_DEFAULT_UNSPECIFIED)
     default_kind = kind;
   else if (VAR_P (decl) && TREE_STATIC (decl) && DECL_IN_CONSTANT_POOL (decl))
@@ -9793,6 +9802,10 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p,
            }
          break;
 
+       case OMP_CLAUSE_DETACH:
+         flags = GOVD_FIRSTPRIVATE | GOVD_SEEN;
+         goto do_add;
+
        case OMP_CLAUSE_IF:
          if (OMP_CLAUSE_IF_MODIFIER (c) != ERROR_MARK
              && OMP_CLAUSE_IF_MODIFIER (c) != code)
@@ -11005,6 +11018,7 @@ gimplify_adjust_omp_clauses (gimple_seq *pre_p, gimple_seq body, tree *list_p,
        case OMP_CLAUSE_DEFAULTMAP:
        case OMP_CLAUSE_ORDER:
        case OMP_CLAUSE_BIND:
+       case OMP_CLAUSE_DETACH:
        case OMP_CLAUSE_USE_DEVICE_PTR:
        case OMP_CLAUSE_USE_DEVICE_ADDR:
        case OMP_CLAUSE_IS_DEVICE_PTR:
index 1d0632892321f91c17aaaf13b3e01863cb896e65..447abcdd759297643c9218e184e9e7c5cc660001 100644 (file)
@@ -381,7 +381,7 @@ DEF_GOMP_BUILTIN (BUILT_IN_GOMP_PARALLEL_REDUCTIONS,
                  "GOMP_parallel_reductions",
                  BT_FN_UINT_OMPFN_PTR_UINT_UINT, ATTR_NOTHROW_LIST)
 DEF_GOMP_BUILTIN (BUILT_IN_GOMP_TASK, "GOMP_task",
-                 BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT_PTR_INT,
+                 BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT_PTR_INT_PTR,
                  ATTR_NOTHROW_LIST)
 DEF_GOMP_BUILTIN (BUILT_IN_GOMP_TASKLOOP, "GOMP_taskloop",
                  BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_UINT_LONG_INT_LONG_LONG_LONG,
index 08afaceb87e7f24d2f7f3e0f10302ca4ecce007c..db2ae54feab8a4dfd4ae86be384bd62a35c191aa 100644 (file)
@@ -803,6 +803,7 @@ expand_task_call (struct omp_region *region, basic_block bb,
   tree depend = omp_find_clause (clauses, OMP_CLAUSE_DEPEND);
   tree finalc = omp_find_clause (clauses, OMP_CLAUSE_FINAL);
   tree priority = omp_find_clause (clauses, OMP_CLAUSE_PRIORITY);
+  tree detach = omp_find_clause (clauses, OMP_CLAUSE_DETACH);
 
   unsigned int iflags
     = (untied ? GOMP_TASK_FLAG_UNTIED : 0)
@@ -852,8 +853,13 @@ expand_task_call (struct omp_region *region, basic_block bb,
       if (omp_find_clause (clauses, OMP_CLAUSE_REDUCTION))
        iflags |= GOMP_TASK_FLAG_REDUCTION;
     }
-  else if (priority)
-    iflags |= GOMP_TASK_FLAG_PRIORITY;
+  else
+    {
+      if (priority)
+       iflags |= GOMP_TASK_FLAG_PRIORITY;
+      if (detach)
+       iflags |= GOMP_TASK_FLAG_DETACH;
+    }
 
   tree flags = build_int_cst (unsigned_type_node, iflags);
 
@@ -894,6 +900,11 @@ expand_task_call (struct omp_region *region, basic_block bb,
     priority = integer_zero_node;
 
   gsi = gsi_last_nondebug_bb (bb);
+
+  detach = (detach
+           ? build_fold_addr_expr (OMP_CLAUSE_DECL (detach))
+           : null_pointer_node);
+
   tree t = gimple_omp_task_data_arg (entry_stmt);
   if (t == NULL)
     t2 = null_pointer_node;
@@ -916,10 +927,10 @@ expand_task_call (struct omp_region *region, basic_block bb,
                         num_tasks, priority, startvar, endvar, step);
   else
     t = build_call_expr (builtin_decl_explicit (BUILT_IN_GOMP_TASK),
-                        9, t1, t2, t3,
+                        10, t1, t2, t3,
                         gimple_omp_task_arg_size (entry_stmt),
                         gimple_omp_task_arg_align (entry_stmt), cond, flags,
-                        depend, priority);
+                        depend, priority, detach);
 
   force_gimple_operand_gsi (&gsi, t, true, NULL_TREE,
                            false, GSI_CONTINUE_LINKING);
index b4148542e7f18fb4cf8b80d1ecbbb747f80dcba0..ddeceba2bc7024f98390f8d10d50fc0a336d8219 100644 (file)
@@ -1550,6 +1550,7 @@ scan_sharing_clauses (tree clauses, omp_context *ctx,
        case OMP_CLAUSE_NUM_GANGS:
        case OMP_CLAUSE_NUM_WORKERS:
        case OMP_CLAUSE_VECTOR_LENGTH:
+       case OMP_CLAUSE_DETACH:
          if (ctx->outer)
            scan_omp_op (&OMP_CLAUSE_OPERAND (c, 0), ctx->outer);
          break;
@@ -1960,6 +1961,7 @@ scan_sharing_clauses (tree clauses, omp_context *ctx,
        case OMP_CLAUSE_SIMDLEN:
        case OMP_CLAUSE_ALIGNED:
        case OMP_CLAUSE_DEPEND:
+       case OMP_CLAUSE_DETACH:
        case OMP_CLAUSE__LOOPTEMP_:
        case OMP_CLAUSE__REDUCTEMP_:
        case OMP_CLAUSE_TO:
@@ -2521,6 +2523,9 @@ finish_taskreg_scan (omp_context *ctx)
     {
       location_t loc = gimple_location (ctx->stmt);
       tree *p, vla_fields = NULL_TREE, *q = &vla_fields;
+      tree detach_clause
+       = omp_find_clause (gimple_omp_task_clauses (ctx->stmt),
+                          OMP_CLAUSE_DETACH);
       /* Move VLA fields to the end.  */
       p = &TYPE_FIELDS (ctx->record_type);
       while (*p)
@@ -2587,6 +2592,48 @@ finish_taskreg_scan (omp_context *ctx)
              TYPE_FIELDS (ctx->srecord_type) = f1;
            }
        }
+      if (detach_clause)
+       {
+         tree c, field;
+
+         /* Look for a firstprivate clause with the detach event handle.  */
+         for (c = gimple_omp_taskreg_clauses (ctx->stmt);
+              c; c = OMP_CLAUSE_CHAIN (c))
+           {
+             if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_FIRSTPRIVATE)
+               continue;
+             if (maybe_lookup_decl_in_outer_ctx (OMP_CLAUSE_DECL (c), ctx)
+                 == OMP_CLAUSE_DECL (detach_clause))
+               break;
+           }
+
+         gcc_assert (c);
+         field = lookup_field (OMP_CLAUSE_DECL (c), ctx);
+
+         /* Move field corresponding to the detach clause first.
+            This is filled by GOMP_task and needs to be in a
+            specific position.  */
+         p = &TYPE_FIELDS (ctx->record_type);
+         while (*p)
+           if (*p == field)
+             *p = DECL_CHAIN (*p);
+           else
+             p = &DECL_CHAIN (*p);
+         DECL_CHAIN (field) = TYPE_FIELDS (ctx->record_type);
+         TYPE_FIELDS (ctx->record_type) = field;
+         if (ctx->srecord_type)
+           {
+             field = lookup_sfield (OMP_CLAUSE_DECL (detach_clause), ctx);
+             p = &TYPE_FIELDS (ctx->srecord_type);
+             while (*p)
+               if (*p == field)
+                 *p = DECL_CHAIN (*p);
+               else
+                 p = &DECL_CHAIN (*p);
+             DECL_CHAIN (field) = TYPE_FIELDS (ctx->srecord_type);
+             TYPE_FIELDS (ctx->srecord_type) = field;
+           }
+       }
       layout_type (ctx->record_type);
       fixup_child_record_type (ctx);
       if (ctx->srecord_type)
index ed435aff6b67bb7bab2293322232905a51d7bc65..457ce6e38cfe2d322041be895ceb70d073b2a30a 100644 (file)
@@ -1,3 +1,13 @@
+2021-01-22  Kwok Cheung Yeung  <kcy@codesourcery.com>
+
+       Backport from mainline
+       2021-01-16  Kwok Cheung Yeung  <kcy@codesourcery.com>
+
+       * c-c++-common/gomp/task-detach-1.c: New.
+       * g++.dg/gomp/task-detach-1.C: New.
+       * gcc.dg/gomp/task-detach-1.c: New.
+       * gfortran.dg/gomp/task-detach-1.f90: New.
+
 2021-01-04  Tobias Burnus  <tobias@codesourcery.com>
 
        Backported from master:
diff --git a/gcc/testsuite/c-c++-common/gomp/task-detach-1.c b/gcc/testsuite/c-c++-common/gomp/task-detach-1.c
new file mode 100644 (file)
index 0000000..4558bc1
--- /dev/null
@@ -0,0 +1,37 @@
+/* { dg-do compile } */
+/* { dg-options "-fopenmp" } */
+
+typedef enum omp_event_handle_t
+{
+  __omp_event_handle_t_max__ = __UINTPTR_MAX__
+} omp_event_handle_t;
+
+extern void omp_fulfill_event (omp_event_handle_t);
+
+void f (omp_event_handle_t x, omp_event_handle_t y, int z)
+{
+  #pragma omp task detach (x) detach (y) /* { dg-error "too many 'detach' clauses on a task construct" } */
+    ;
+
+  #pragma omp task mergeable detach (x) /* { dg-error "'detach' clause must not be used together with 'mergeable' clause" } */
+    ;
+
+  #pragma omp task detach (x) mergeable /* { dg-error "'detach' clause must not be used together with 'mergeable' clause" } */
+    ;
+
+  #pragma omp task detach (z) /* { dg-error "'detach' clause event handle has type 'int' rather than 'omp_event_handle_t'" } */
+    ;
+
+  #pragma omp parallel master default (none) /* { dg-message "enclosing 'parallel'" } */
+    #pragma omp task detach (x) /* { dg-error "'x' not specified in enclosing 'parallel'" } */
+      ;
+
+  #pragma omp task detach (x) default (none) /* This should work.  */
+    omp_fulfill_event (x);
+
+  #pragma omp task detach (x) firstprivate (x) /* { dg-error "the event handle of a 'detach' clause should not be in a data-sharing clause" } */
+    ;
+
+  #pragma omp task detach (x) shared (x) /* { dg-error "the event handle of a 'detach' clause should not be in a data-sharing clause" } */
+    ;
+}
diff --git a/gcc/testsuite/g++.dg/gomp/task-detach-1.C b/gcc/testsuite/g++.dg/gomp/task-detach-1.C
new file mode 100644 (file)
index 0000000..6028cb4
--- /dev/null
@@ -0,0 +1,29 @@
+// { dg-do compile }
+// { dg-options "-fopenmp" }
+
+typedef enum omp_event_handle_t
+{
+  __omp_event_handle_t_max__ = __UINTPTR_MAX__
+} omp_event_handle_t;
+
+template <typename T>
+void foo ()
+{
+  T t;
+  #pragma omp task detach (t)
+    ;
+}
+
+template <typename T>
+void bar ()
+{
+  T t;
+  #pragma omp task detach (t) // { dg-error "'detach' clause event handle has type 'int' rather than 'omp_event_handle_t'" }
+    ;
+}
+
+void f()
+{
+  foo <omp_event_handle_t> ();
+  bar <int> (); // { dg-message "required from here" }
+}
diff --git a/gcc/testsuite/gcc.dg/gomp/task-detach-1.c b/gcc/testsuite/gcc.dg/gomp/task-detach-1.c
new file mode 100644 (file)
index 0000000..611044d
--- /dev/null
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-options "-fopenmp" } */
+
+typedef enum omp_event_handle_t
+{
+  __omp_event_handle_t_max__ = __UINTPTR_MAX__
+} omp_event_handle_t;
+
+extern void omp_fulfill_event (omp_event_handle_t);
+
+void f (omp_event_handle_t x)
+{
+  void g (void)
+  {
+    #pragma omp task detach (x)
+      omp_fulfill_event (x);
+  }
+
+  g ();
+}
diff --git a/gcc/testsuite/gfortran.dg/gomp/task-detach-1.f90 b/gcc/testsuite/gfortran.dg/gomp/task-detach-1.f90
new file mode 100644 (file)
index 0000000..4763f13
--- /dev/null
@@ -0,0 +1,29 @@
+! { dg-do compile }
+! { dg-options "-fopenmp" }
+
+program task_detach_1
+  use iso_c_binding, only: c_intptr_t
+  implicit none
+  
+  integer, parameter :: omp_event_handle_kind = c_intptr_t
+  integer (kind=omp_event_handle_kind) :: x, y
+  integer :: z
+  
+  !$omp task detach(x) detach(y) ! { dg-error "Failed to match clause at \\\(1\\\)" }
+  !$omp end task ! { dg-error "Unexpected !\\\$OMP END TASK statement at \\\(1\\\)" }
+
+  !$omp task mergeable detach(x) ! { dg-error "'DETACH' clause at \\\(1\\\) must not be used together with 'MERGEABLE' clause" }
+  !$omp end task
+
+  !$omp task detach(x) mergeable ! { dg-error "'DETACH' clause at \\\(1\\\) must not be used together with 'MERGEABLE' clause" }
+  !$omp end task
+
+  !$omp task detach(z) ! { dg-error "'z' at \\\(1\\\) should be of type integer\\\(kind=omp_event_handle_kind\\\)" }
+  !$omp end task ! { dg-error "Unexpected !\\\$OMP END TASK statement at \\\(1\\\)" }
+  
+  !$omp task detach (x) firstprivate (x) ! { dg-error "DETACH event handle 'x' in FIRSTPRIVATE clause at \\\(1\\\)" }
+  !$omp end task
+
+  !$omp task detach (x) shared (x) ! { dg-error "DETACH event handle 'x' in SHARED clause at \\\(1\\\)" }
+  !$omp end task
+end program
index 6ada13875ba902d51cd6886e2a7ad058433e58fe..15fb1b5d2b7b34f6084493a14bb66a0437ec70b8 100644 (file)
@@ -294,19 +294,8 @@ enum omp_clause_code {
   /* OpenMP clause: link (variable-list).  */
   OMP_CLAUSE_LINK,
 
-  /* OpenMP clause: from (variable-list).  */
-  OMP_CLAUSE_FROM,
-
-  /* OpenMP clause: to (variable-list).  */
-  OMP_CLAUSE_TO,
-
-  /* OpenACC clauses: {copy, copyin, copyout, create, delete, deviceptr,
-     device, host (self), present, present_or_copy (pcopy), present_or_copyin
-     (pcopyin), present_or_copyout (pcopyout), present_or_create (pcreate)}
-     (variable-list).
-
-     OpenMP clause: map ({alloc:,to:,from:,tofrom:,}variable-list).  */
-  OMP_CLAUSE_MAP,
+  /* OpenMP clause: detach (event-handle).  */
+  OMP_CLAUSE_DETACH,
 
   /* OpenACC clause: use_device (variable-list).
      OpenMP clause: use_device_ptr (ptr-list).  */
@@ -324,6 +313,20 @@ enum omp_clause_code {
   /* OpenMP clause: exclusive (variable-list).  */
   OMP_CLAUSE_EXCLUSIVE,
 
+  /* OpenMP clause: from (variable-list).  */
+  OMP_CLAUSE_FROM,
+
+  /* OpenMP clause: to (variable-list).  */
+  OMP_CLAUSE_TO,
+
+  /* OpenACC clauses: {copy, copyin, copyout, create, delete, deviceptr,
+     device, host (self), present, present_or_copy (pcopy), present_or_copyin
+     (pcopyin), present_or_copyout (pcopyout), present_or_create (pcreate)}
+     (variable-list).
+
+     OpenMP clause: map ({alloc:,to:,from:,tofrom:,}variable-list).  */
+  OMP_CLAUSE_MAP,
+
   /* Internal structure to hold OpenACC cache directive's variable-list.
      #pragma acc cache (variable-list).  */
   OMP_CLAUSE__CACHE_,
index e42f0b6a2d273dac3d5820aa5918560f445a6a06..89fbcd56555b59c971b0b3dff1aadb5020b965c6 100644 (file)
@@ -1239,6 +1239,7 @@ convert_nonlocal_omp_clauses (tree *pclauses, struct walk_stmt_info *wi)
        case OMP_CLAUSE_USE_DEVICE_PTR:
        case OMP_CLAUSE_USE_DEVICE_ADDR:
        case OMP_CLAUSE_IS_DEVICE_PTR:
+       case OMP_CLAUSE_DETACH:
        do_decl_clause:
          if (pdecl == NULL)
            pdecl = &OMP_CLAUSE_DECL (clause);
@@ -2000,6 +2001,7 @@ convert_local_omp_clauses (tree *pclauses, struct walk_stmt_info *wi)
        case OMP_CLAUSE_USE_DEVICE_PTR:
        case OMP_CLAUSE_USE_DEVICE_ADDR:
        case OMP_CLAUSE_IS_DEVICE_PTR:
+       case OMP_CLAUSE_DETACH:
        do_decl_clause:
          if (pdecl == NULL)
            pdecl = &OMP_CLAUSE_DECL (clause);
index 7bd35ce8a6daa07acb510d35b55d7fb6a76276ed..3fae181fefbb70c66548a26bd2a15f8aea81124e 100644 (file)
@@ -1306,6 +1306,12 @@ dump_omp_clause (pretty_printer *pp, tree clause, int spc, dump_flags_t flags)
     case OMP_CLAUSE_FINALIZE:
       pp_string (pp, "finalize");
       break;
+    case OMP_CLAUSE_DETACH:
+      pp_string (pp, "detach(");
+      dump_generic_node (pp, OMP_CLAUSE_DECL (clause), spc, flags,
+                        false);
+      pp_right_paren (pp);
+      break;
 
     default:
       gcc_unreachable ();
index 3ba6fee08a0b8292c948bbc84b2579b699d523d7..cd6a5331d4bbd1be3543e332c7bb3decad0c56b7 100644 (file)
@@ -296,14 +296,15 @@ unsigned const char omp_clause_num_ops[] =
   1, /* OMP_CLAUSE_UNIFORM  */
   1, /* OMP_CLAUSE_TO_DECLARE  */
   1, /* OMP_CLAUSE_LINK  */
-  2, /* OMP_CLAUSE_FROM  */
-  2, /* OMP_CLAUSE_TO  */
-  2, /* OMP_CLAUSE_MAP  */
+  1, /* OMP_CLAUSE_DETACH  */
   1, /* OMP_CLAUSE_USE_DEVICE_PTR  */
   1, /* OMP_CLAUSE_USE_DEVICE_ADDR  */
   1, /* OMP_CLAUSE_IS_DEVICE_PTR  */
   1, /* OMP_CLAUSE_INCLUSIVE  */
   1, /* OMP_CLAUSE_EXCLUSIVE  */
+  2, /* OMP_CLAUSE_FROM  */
+  2, /* OMP_CLAUSE_TO  */
+  2, /* OMP_CLAUSE_MAP  */
   2, /* OMP_CLAUSE__CACHE_  */
   2, /* OMP_CLAUSE_GANG  */
   1, /* OMP_CLAUSE_ASYNC  */
@@ -382,14 +383,15 @@ const char * const omp_clause_code_name[] =
   "uniform",
   "to",
   "link",
-  "from",
-  "to",
-  "map",
+  "detach",
   "use_device_ptr",
   "use_device_addr",
   "is_device_ptr",
   "inclusive",
   "exclusive",
+  "from",
+  "to",
+  "map",
   "_cache_",
   "gang",
   "async",
@@ -12148,6 +12150,7 @@ walk_tree_1 (tree *tp, walk_tree_fn func, void *data,
        case OMP_CLAUSE_HINT:
        case OMP_CLAUSE_TO_DECLARE:
        case OMP_CLAUSE_LINK:
+       case OMP_CLAUSE_DETACH:
        case OMP_CLAUSE_USE_DEVICE_PTR:
        case OMP_CLAUSE_USE_DEVICE_ADDR:
        case OMP_CLAUSE_IS_DEVICE_PTR:
index 3e1bdd5e922898ea9d5ca2bf988003dccd225be7..d500277d345321e682ae0cd1c20fbec133a18963 100644 (file)
@@ -1,3 +1,10 @@
+2021-01-22  Kwok Cheung Yeung  <kcy@codesourcery.com>
+
+       Backport from mainline
+       2021-01-16  Kwok Cheung Yeung  <kcy@codesourcery.com>
+
+       * gomp-constants.h (GOMP_TASK_FLAG_DETACH): New.
+
 2020-09-15  Tobias Burnus  <tobias@codesourcery.com>
 
        Backport from mainline
index f2d15f65b672735eab8b20e3afada44343a40ffd..45d553c47c207fc2b298db97ef779970ebe514a4 100644 (file)
@@ -249,6 +249,7 @@ enum gomp_map_kind
 #define GOMP_TASK_FLAG_IF              (1 << 10)
 #define GOMP_TASK_FLAG_NOGROUP         (1 << 11)
 #define GOMP_TASK_FLAG_REDUCTION       (1 << 12)
+#define GOMP_TASK_FLAG_DETACH          (1 << 13)
 
 /* GOMP_target{_ext,update_ext,enter_exit_data} flags argument.  */
 #define GOMP_TARGET_FLAG_NOWAIT                (1 << 0)
index b6f565c1d28fae2249ea4462b9d1c72b1575b3af..684e09a378bd1b986461e51ae2c0381f29c2e456 100644 (file)
@@ -1,3 +1,51 @@
+2021-01-22  Kwok Cheung Yeung  <kcy@codesourcery.com>
+
+       Backport from mainline
+       2021-01-16  Kwok Cheung Yeung  <kcy@codesourcery.com>
+
+       * fortran.c (omp_fulfill_event_): New.
+       * libgomp.h (struct gomp_task): Add detach and completion_sem fields.
+       (struct gomp_team): Add task_detach_queue and task_detach_count
+       fields.
+       * libgomp.map (OMP_5.0.1): Add omp_fulfill_event and omp_fulfill_event_.
+       * libgomp_g.h (GOMP_task): Add extra argument.
+       * omp.h.in (enum omp_event_handle_t): New.
+       (omp_fulfill_event): New.
+       * omp_lib.f90.in (omp_event_handle_kind): New.
+       (omp_fulfill_event): New.
+       * omp_lib.h.in (omp_event_handle_kind): New.
+       (omp_fulfill_event): Declare.
+       * priority_queue.c (priority_tree_find): New.
+       (priority_list_find): New.
+       (priority_queue_find): New.
+       * priority_queue.h (priority_queue_predicate): New.
+       (priority_queue_find): New.
+       * task.c (gomp_init_task): Initialize detach field.
+       (task_fulfilled_p): New.
+       (GOMP_task): Add detach argument.  Ignore detach argument if
+       GOMP_TASK_FLAG_DETACH not set in flags.  Initialize completion_sem
+       field.  Copy address of completion_sem into detach argument and
+       into the start of the data record.  Wait for detach event if task
+       not deferred.
+       (gomp_barrier_handle_tasks): Queue tasks with unfulfilled events.
+       Remove completed tasks and requeue dependent tasks.
+       (omp_fulfill_event): New.
+       * team.c (gomp_new_team): Initialize task_detach_queue and
+       task_detach_count fields.
+       (free_team): Free task_detach_queue field.
+       * testsuite/libgomp.c-c++-common/task-detach-1.c: New testcase.
+       * testsuite/libgomp.c-c++-common/task-detach-2.c: New testcase.
+       * testsuite/libgomp.c-c++-common/task-detach-3.c: New testcase.
+       * testsuite/libgomp.c-c++-common/task-detach-4.c: New testcase.
+       * testsuite/libgomp.c-c++-common/task-detach-5.c: New testcase.
+       * testsuite/libgomp.c-c++-common/task-detach-6.c: New testcase.
+       * testsuite/libgomp.fortran/task-detach-1.f90: New testcase.
+       * testsuite/libgomp.fortran/task-detach-2.f90: New testcase.
+       * testsuite/libgomp.fortran/task-detach-3.f90: New testcase.
+       * testsuite/libgomp.fortran/task-detach-4.f90: New testcase.
+       * testsuite/libgomp.fortran/task-detach-5.f90: New testcase.
+       * testsuite/libgomp.fortran/task-detach-6.f90: New testcase.
+
 2021-01-05  Julian Brown  <julian@codesourcery.com>
 
        Backport from mainline
index cd719f92fc8360e4e13c4bfd83f61ad83fa6dc31..976b2482743029b4c5d6b1567ffff32585be79bf 100644 (file)
@@ -604,6 +604,12 @@ omp_get_max_task_priority_ (void)
   return omp_get_max_task_priority ();
 }
 
+void
+omp_fulfill_event_ (intptr_t event)
+{
+  omp_fulfill_event ((omp_event_handle_t) event);
+}
+
 void
 omp_set_affinity_format_ (const char *format, size_t format_len)
 {
index c77a813cf32eec6bb6edd36f4fac896ad1696014..9b1378559bcea6ed30650c42aafb49cf2a469419 100644 (file)
@@ -545,6 +545,9 @@ struct gomp_task
      entries and the gomp_task in which they reside.  */
   struct priority_node pnode[3];
 
+  bool detach;
+  gomp_sem_t completion_sem;
+
   struct gomp_task_icv icv;
   void (*fn) (void *);
   void *fn_data;
@@ -685,6 +688,10 @@ struct gomp_team
   int work_share_cancelled;
   int team_cancelled;
 
+  /* Tasks waiting for their completion event to be fulfilled.  */
+  struct priority_queue task_detach_queue;
+  unsigned int task_detach_count;
+
   /* This array contains structures for implicit tasks.  */
   struct gomp_task implicit_task[];
 };
index c5f52f725d06b498b626c93c1c8b077f3a86fd00..6561721f8af121718011c3b9cc6efb765fd8c147 100644 (file)
@@ -195,6 +195,8 @@ OMP_5.0.1 {
        omp_free;
        omp_get_supported_active_levels;
        omp_get_supported_active_levels_;
+       omp_fulfill_event;
+       omp_fulfill_event_;
 } OMP_5.0;
 
 GOMP_1.0 {
index 70a275721824019fba5595065353b2b462a6fe7a..b439c833d6468f0b8185e78b52e07320779304ba 100644 (file)
@@ -294,7 +294,7 @@ extern bool GOMP_cancellation_point (int);
 /* task.c */
 
 extern void GOMP_task (void (*) (void *), void *, void (*) (void *, void *),
-                      long, long, bool, unsigned, void **, int);
+                      long, long, bool, unsigned, void **, int, void *);
 extern void GOMP_taskloop (void (*) (void *), void *,
                           void (*) (void *, void *), long, long, unsigned,
                           unsigned long, int, long, long, long);
index be7df6d283f1c487ddd2d4e898fb050d3b7ae190..b7c3eea171f774e103d387596301814c8e62d380 100644 (file)
@@ -171,6 +171,11 @@ typedef struct omp_alloctrait_t
   omp_uintptr_t value;
 } omp_alloctrait_t;
 
+typedef enum omp_event_handle_t __GOMP_UINTPTR_T_ENUM
+{
+  __omp_event_handle_t_max__ = __UINTPTR_MAX__
+} omp_event_handle_t;
+
 #ifdef __cplusplus
 extern "C" {
 # define __GOMP_NOTHROW throw ()
@@ -245,6 +250,8 @@ extern int omp_is_initial_device (void) __GOMP_NOTHROW;
 extern int omp_get_initial_device (void) __GOMP_NOTHROW;
 extern int omp_get_max_task_priority (void) __GOMP_NOTHROW;
 
+extern void omp_fulfill_event (omp_event_handle_t) __GOMP_NOTHROW;
+
 extern void *omp_target_alloc (__SIZE_TYPE__, int) __GOMP_NOTHROW;
 extern void omp_target_free (void *, int) __GOMP_NOTHROW;
 extern int omp_target_is_present (const void *, int) __GOMP_NOTHROW;
index da630fa054104953409c3b7d5de49b99db0d568d..776bb84f947ac41db73b7d017dea4c5a89232f86 100644 (file)
@@ -38,6 +38,7 @@
         integer, parameter :: omp_alloctrait_key_kind = c_int
         integer, parameter :: omp_alloctrait_val_kind = c_intptr_t
         integer, parameter :: omp_memspace_handle_kind = c_intptr_t
+        integer, parameter :: omp_event_handle_kind = c_intptr_t
         integer (omp_sched_kind), parameter :: omp_sched_static = 1
         integer (omp_sched_kind), parameter :: omp_sched_dynamic = 2
         integer (omp_sched_kind), parameter :: omp_sched_guided = 3
           end function omp_get_max_task_priority
         end interface
 
+        interface
+          subroutine omp_fulfill_event (event)
+            use omp_lib_kinds
+            integer (kind=omp_event_handle_kind), &
+              value, intent(in) :: event
+          end subroutine omp_fulfill_event
+        end interface
+
         interface
           subroutine omp_set_affinity_format (format)
             character(len=*), intent(in) :: format
index b06e5681334969230416c1ebb5299b8243464aa5..9f3d176cec7922657bc4bbab81155017afbd0288 100644 (file)
 
       integer omp_allocator_handle_kind, omp_alloctrait_key_kind
       integer omp_alloctrait_val_kind, omp_memspace_handle_kind
+      integer omp_event_handle_kind
       parameter (omp_allocator_handle_kind = @INTPTR_T_KIND@)
       parameter (omp_alloctrait_key_kind = @INTPTR_T_KIND@)
       parameter (omp_alloctrait_val_kind = @INTPTR_T_KIND@)
       parameter (omp_memspace_handle_kind = @INTPTR_T_KIND@)
+      parameter (omp_event_handle_kind = @INTPTR_T_KIND@)
       integer (omp_alloctrait_key_kind) omp_atk_sync_hint
       integer (omp_alloctrait_key_kind) omp_atk_alignment
       integer (omp_alloctrait_key_kind) omp_atk_access
       external omp_get_max_task_priority
       integer(4) omp_get_max_task_priority
 
+      external omp_fulfill_event
+
       external omp_set_affinity_format, omp_get_affinity_format
       external omp_display_affinity, omp_capture_affinity
       integer(4) omp_get_affinity_format
index 9b8d2ff5d9fe4d4b4bc7e5c79e10edffb21e57b9..6cc817d2dd6b6c76bdd845409b3668296467244e 100644 (file)
@@ -168,6 +168,63 @@ priority_queue_verify (enum priority_queue_type type,
 }
 #endif /* _LIBGOMP_CHECKING_ */
 
+/* Tree version of priority_queue_find.  */
+
+static struct gomp_task *
+priority_tree_find (enum priority_queue_type type,
+                   prio_splay_tree_node node,
+                   priority_queue_predicate pred)
+{
+ again:
+  if (!node)
+    return NULL;
+  struct gomp_task *task = priority_tree_find (type, node->right, pred);
+  if (task)
+    return task;
+  task = priority_node_to_task (type, node->key.l.tasks);
+  if (pred (task))
+    return task;
+  node = node->left;
+  goto again;
+}
+
+/* List version of priority_queue_find.  */
+
+static struct gomp_task *
+priority_list_find (enum priority_queue_type type,
+                    struct priority_list *list,
+                    priority_queue_predicate pred)
+{
+  struct priority_node *node = list->tasks;
+  if (!node)
+    return NULL;
+
+  do
+    {
+      struct gomp_task *task = priority_node_to_task (type, node);
+      if (pred (task))
+       return task;
+      node = node->next;
+    }
+  while (node != list->tasks);
+
+  return NULL;
+}
+
+/* Return the highest priority task in the priority queue HEAD that
+   satisfies the predicate PRED.  HEAD contains tasks of type TYPE.  */
+
+struct gomp_task *
+priority_queue_find (enum priority_queue_type type,
+                    struct priority_queue *head,
+                    priority_queue_predicate pred)
+{
+  if (priority_queue_multi_p (head))
+    return priority_tree_find (type, head->t.root, pred);
+  else
+    return priority_list_find (type, &head->l, pred);
+}
+
 /* Remove NODE from priority queue HEAD, wherever it may be inside the
    tree.  HEAD contains tasks of type TYPE.  */
 
index 0ad78f5ecb6997e01bad172f3bb41caafdf819fc..50269fc9ca8033bef6916ef9c282eaeabb0a8f39 100644 (file)
@@ -113,6 +113,8 @@ enum priority_queue_type
   PQ_IGNORED = 999
 };
 
+typedef bool (*priority_queue_predicate) (struct gomp_task *);
+
 /* Priority queue implementation prototypes.  */
 
 extern bool priority_queue_task_in_queue_p (enum priority_queue_type,
@@ -122,6 +124,9 @@ extern void priority_queue_dump (enum priority_queue_type,
                                 struct priority_queue *);
 extern void priority_queue_verify (enum priority_queue_type,
                                   struct priority_queue *, bool);
+extern struct gomp_task *priority_queue_find (enum priority_queue_type,
+                                             struct priority_queue *,
+                                             priority_queue_predicate);
 extern void priority_tree_remove (enum priority_queue_type,
                                  struct priority_queue *,
                                  struct priority_node *);
index a95067c6de9e62dee2a88ac0d3285eb0fd939668..67bff47fa0b0f1074de9bfd9ea85841322a8d053 100644 (file)
@@ -86,6 +86,7 @@ gomp_init_task (struct gomp_task *task, struct gomp_task *parent_task,
   task->dependers = NULL;
   task->depend_hash = NULL;
   task->depend_count = 0;
+  task->detach = false;
 }
 
 /* Clean up a task, after completing it.  */
@@ -326,6 +327,12 @@ gomp_task_handle_depend (struct gomp_task *task, struct gomp_task *parent,
     }
 }
 
+static bool
+task_fulfilled_p (struct gomp_task *task)
+{
+  return __atomic_load_n (&task->completion_sem, __ATOMIC_RELAXED);
+}
+
 /* 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.
@@ -347,7 +354,7 @@ gomp_task_handle_depend (struct gomp_task *task, struct gomp_task *parent,
 void
 GOMP_task (void (*fn) (void *), void *data, void (*cpyfn) (void *, void *),
           long arg_size, long arg_align, bool if_clause, unsigned flags,
-          void **depend, int priority)
+          void **depend, int priority, void *detach)
 {
   struct gomp_thread *thr = gomp_thread ();
   struct gomp_team *team = thr->ts.team;
@@ -383,6 +390,9 @@ GOMP_task (void (*fn) (void *), void *data, void (*cpyfn) (void *, void *),
   else if (priority > gomp_max_task_priority_var)
     priority = gomp_max_task_priority_var;
 
+  if ((flags & GOMP_TASK_FLAG_DETACH) == 0)
+    detach = NULL;
+
   if (!if_clause || team == NULL
       || (thr->task && thr->task->final_task)
       || team->task_count > 64 * team->nthreads)
@@ -404,6 +414,18 @@ GOMP_task (void (*fn) (void *), void *data, void (*cpyfn) (void *, void *),
       task.final_task = (thr->task && thr->task->final_task)
                        || (flags & GOMP_TASK_FLAG_FINAL);
       task.priority = priority;
+
+      if (detach)
+       {
+         task.detach = true;
+         gomp_sem_init (&task.completion_sem, 0);
+         *(void **) detach = &task.completion_sem;
+         if (data)
+           *(void **) data = &task.completion_sem;
+
+         gomp_debug (0, "New event: %p\n", &task.completion_sem);
+       }
+
       if (thr->task)
        {
          task.in_tied_task = thr->task->in_tied_task;
@@ -420,6 +442,10 @@ GOMP_task (void (*fn) (void *), void *data, void (*cpyfn) (void *, void *),
        }
       else
        fn (data);
+
+      if (detach && !task_fulfilled_p (&task))
+       gomp_sem_wait (&task.completion_sem);
+
       /* Access to "children" is normally done inside a task_lock
         mutex region, but the only way this particular task.children
         can be set is if this thread's task work function (fn)
@@ -458,6 +484,16 @@ GOMP_task (void (*fn) (void *), void *data, void (*cpyfn) (void *, void *),
       task->kind = GOMP_TASK_UNDEFERRED;
       task->in_tied_task = parent->in_tied_task;
       task->taskgroup = taskgroup;
+      if (detach)
+       {
+         task->detach = true;
+         gomp_sem_init (&task->completion_sem, 0);
+         *(void **) detach = &task->completion_sem;
+         if (data)
+           *(void **) data = &task->completion_sem;
+
+         gomp_debug (0, "New event: %p\n", &task->completion_sem);
+       }
       thr->task = task;
       if (cpyfn)
        {
@@ -1325,6 +1361,28 @@ gomp_barrier_handle_tasks (gomp_barrier_state_t state)
   while (1)
     {
       bool cancelled = false;
+
+      /* Look for a queued detached task with a fulfilled completion event
+        that is ready to finish.  */
+      child_task = priority_queue_find (PQ_TEAM, &team->task_detach_queue,
+                                       task_fulfilled_p);
+      if (child_task)
+       {
+         priority_queue_remove (PQ_TEAM, &team->task_detach_queue,
+                                child_task, MEMMODEL_RELAXED);
+         --team->task_detach_count;
+         gomp_debug (0, "thread %d: found task with fulfilled event %p\n",
+                     thr->ts.team_id, &child_task->completion_sem);
+
+       if (to_free)
+         {
+           gomp_finish_task (to_free);
+           free (to_free);
+           to_free = NULL;
+         }
+         goto finish_cancelled;
+       }
+
       if (!priority_queue_empty_p (&team->task_queue, MEMMODEL_RELAXED))
        {
          bool ignored;
@@ -1392,29 +1450,43 @@ gomp_barrier_handle_tasks (gomp_barrier_state_t state)
       gomp_mutex_lock (&team->task_lock);
       if (child_task)
        {
-        finish_cancelled:;
-         size_t new_tasks
-           = gomp_task_run_post_handle_depend (child_task, team);
-         gomp_task_run_post_remove_parent (child_task);
-         gomp_clear_parent (&child_task->children_queue);
-         gomp_task_run_post_remove_taskgroup (child_task);
-         to_free = child_task;
-         child_task = NULL;
-         if (!cancelled)
-           team->task_running_count--;
-         if (new_tasks > 1)
+         if (child_task->detach && !task_fulfilled_p (child_task))
            {
-             do_wake = team->nthreads - team->task_running_count;
-             if (do_wake > new_tasks)
-               do_wake = new_tasks;
+             priority_queue_insert (PQ_TEAM, &team->task_detach_queue,
+                                    child_task, child_task->priority,
+                                    PRIORITY_INSERT_END,
+                                    false, false);
+             ++team->task_detach_count;
+             gomp_debug (0, "thread %d: queueing task with event %p\n",
+                         thr->ts.team_id, &child_task->completion_sem);
+             child_task = NULL;
            }
-         if (--team->task_count == 0
-             && gomp_team_barrier_waiting_for_tasks (&team->barrier))
+         else
            {
-             gomp_team_barrier_done (&team->barrier, state);
-             gomp_mutex_unlock (&team->task_lock);
-             gomp_team_barrier_wake (&team->barrier, 0);
-             gomp_mutex_lock (&team->task_lock);
+            finish_cancelled:;
+             size_t new_tasks
+               = gomp_task_run_post_handle_depend (child_task, team);
+             gomp_task_run_post_remove_parent (child_task);
+             gomp_clear_parent (&child_task->children_queue);
+             gomp_task_run_post_remove_taskgroup (child_task);
+             to_free = child_task;
+             child_task = NULL;
+             if (!cancelled)
+               team->task_running_count--;
+             if (new_tasks > 1)
+               {
+                 do_wake = team->nthreads - team->task_running_count;
+                 if (do_wake > new_tasks)
+                   do_wake = new_tasks;
+               }
+             if (--team->task_count == 0
+                 && gomp_team_barrier_waiting_for_tasks (&team->barrier))
+               {
+                 gomp_team_barrier_done (&team->barrier, state);
+                 gomp_mutex_unlock (&team->task_lock);
+                 gomp_team_barrier_wake (&team->barrier, 0);
+                 gomp_mutex_lock (&team->task_lock);
+               }
            }
        }
     }
@@ -2326,3 +2398,21 @@ omp_in_final (void)
 }
 
 ialias (omp_in_final)
+
+void
+omp_fulfill_event (omp_event_handle_t event)
+{
+  gomp_sem_t *sem = (gomp_sem_t *) event;
+  struct gomp_thread *thr = gomp_thread ();
+  struct gomp_team *team = thr ? thr->ts.team : NULL;
+
+  if (__atomic_load_n (sem, __ATOMIC_RELAXED))
+    gomp_fatal ("omp_fulfill_event: %p event already fulfilled!\n", sem);
+
+  gomp_debug (0, "omp_fulfill_event: %p\n", sem);
+  gomp_sem_post (sem);
+  if (team)
+    gomp_team_barrier_wake (&team->barrier, 1);
+}
+
+ialias (omp_fulfill_event)
index cbc3aec0265c7d6f15017a2645dfde09b82e0008..ee488f2214b7355aa6ecd5ba73d116026e6ae673 100644 (file)
@@ -206,6 +206,9 @@ gomp_new_team (unsigned nthreads)
   team->work_share_cancelled = 0;
   team->team_cancelled = 0;
 
+  priority_queue_init (&team->task_detach_queue);
+  team->task_detach_count = 0;
+
   return team;
 }
 
@@ -221,6 +224,7 @@ free_team (struct gomp_team *team)
   gomp_barrier_destroy (&team->barrier);
   gomp_mutex_destroy (&team->task_lock);
   priority_queue_free (&team->task_queue);
+  priority_queue_free (&team->task_detach_queue);
   team_free (team);
 }
 
diff --git a/libgomp/testsuite/libgomp.c-c++-common/task-detach-1.c b/libgomp/testsuite/libgomp.c-c++-common/task-detach-1.c
new file mode 100644 (file)
index 0000000..8583e37
--- /dev/null
@@ -0,0 +1,36 @@
+/* { dg-do run } */
+
+#include <omp.h>
+#include <assert.h>
+
+/* Test chaining of detached tasks, with each task fulfilling the
+   completion event of the previous one.  */
+
+int main (void)
+{
+  omp_event_handle_t detach_event1, detach_event2;
+  int x = 0, y = 0, z = 0;
+
+  #pragma omp parallel
+    #pragma omp single
+    {
+      #pragma omp task detach(detach_event1)
+       x++;
+
+      #pragma omp task detach(detach_event2)
+      {
+       y++;
+       omp_fulfill_event (detach_event1);
+      }
+
+      #pragma omp task
+      {
+       z++;
+       omp_fulfill_event (detach_event2);
+      }
+    }
+
+  assert (x == 1);
+  assert (y == 1);
+  assert (z == 1);
+}
diff --git a/libgomp/testsuite/libgomp.c-c++-common/task-detach-2.c b/libgomp/testsuite/libgomp.c-c++-common/task-detach-2.c
new file mode 100644 (file)
index 0000000..943ac2a
--- /dev/null
@@ -0,0 +1,37 @@
+/* { dg-do run } */
+
+#include <omp.h>
+#include <assert.h>
+
+/* Test handling of detach clause with only a single thread.  The runtime
+   should not block when a task with an unfulfilled event finishes
+   running.  */
+
+int main (void)
+{
+  omp_event_handle_t detach_event1, detach_event2;
+  int x = 0, y = 0, z = 0;
+
+  #pragma omp parallel num_threads(1)
+    #pragma omp single
+    {
+      #pragma omp task detach(detach_event1)
+       x++;
+
+      #pragma omp task detach(detach_event2)
+      {
+       y++;
+       omp_fulfill_event (detach_event1);
+      }
+
+      #pragma omp task
+      {
+       z++;
+       omp_fulfill_event (detach_event2);
+      }
+    }
+
+  assert (x == 1);
+  assert (y == 1);
+  assert (z == 1);
+}
diff --git a/libgomp/testsuite/libgomp.c-c++-common/task-detach-3.c b/libgomp/testsuite/libgomp.c-c++-common/task-detach-3.c
new file mode 100644 (file)
index 0000000..2609fb1
--- /dev/null
@@ -0,0 +1,33 @@
+/* { dg-do run } */
+
+#include <omp.h>
+#include <assert.h>
+
+/* Test the task detach clause used together with dependencies.  */
+
+int main (void)
+{
+  omp_event_handle_t detach_event;
+  int x = 0, y = 0, z = 0;
+  int dep;
+
+  #pragma omp parallel
+    #pragma omp single
+    {
+      #pragma omp task depend(out:dep) detach(detach_event)
+       x++;
+
+      #pragma omp task
+      {
+       y++;
+       omp_fulfill_event(detach_event);
+      }
+
+      #pragma omp task depend(in:dep)
+       z++;
+    }
+
+  assert (x == 1);
+  assert (y == 1);
+  assert (z == 1);
+}
diff --git a/libgomp/testsuite/libgomp.c-c++-common/task-detach-4.c b/libgomp/testsuite/libgomp.c-c++-common/task-detach-4.c
new file mode 100644 (file)
index 0000000..eeb9554
--- /dev/null
@@ -0,0 +1,24 @@
+/* { dg-do run } */
+
+#include <omp.h>
+#include <assert.h>
+
+/* Test detach clause, where a task fulfills its own completion event.  */
+
+int main (void)
+{
+  omp_event_handle_t detach_event;
+  int x = 0;
+
+  detach_event = (omp_event_handle_t) 0x123456789abcdef0;
+
+  #pragma omp parallel
+    #pragma omp single
+      #pragma omp task detach(detach_event)
+      {
+       x++;
+       omp_fulfill_event(detach_event);
+      }
+
+  assert (x == 1);
+}
diff --git a/libgomp/testsuite/libgomp.c-c++-common/task-detach-5.c b/libgomp/testsuite/libgomp.c-c++-common/task-detach-5.c
new file mode 100644 (file)
index 0000000..5a01517
--- /dev/null
@@ -0,0 +1,42 @@
+/* { dg-do run } */
+
+#include <omp.h>
+#include <assert.h>
+
+/* Test tasks with detach clause.  Each thread spawns off a chain of tasks,
+   that can then be executed by any available thread.  */
+
+int main (void)
+{
+  int x = 0, y = 0, z = 0;
+  int thread_count;
+  omp_event_handle_t detach_event1, detach_event2;
+
+  #pragma omp parallel firstprivate(detach_event1, detach_event2)
+  {
+    #pragma omp single
+      thread_count = omp_get_num_threads();
+
+    #pragma omp task detach(detach_event1) untied
+      #pragma omp atomic update
+       x++;
+
+    #pragma omp task detach(detach_event2) untied
+    {
+      #pragma omp atomic update
+       y++;
+      omp_fulfill_event (detach_event1);
+    }
+
+    #pragma omp task untied
+    {
+      #pragma omp atomic update
+       z++;
+      omp_fulfill_event (detach_event2);
+    }
+  }
+
+  assert (x == thread_count);
+  assert (y == thread_count);
+  assert (z == thread_count);
+}
diff --git a/libgomp/testsuite/libgomp.c-c++-common/task-detach-6.c b/libgomp/testsuite/libgomp.c-c++-common/task-detach-6.c
new file mode 100644 (file)
index 0000000..b5f68cc
--- /dev/null
@@ -0,0 +1,46 @@
+/* { dg-do run } */
+
+#include <omp.h>
+#include <assert.h>
+
+/* Test tasks with detach clause on an offload device.  Each device
+   thread spawns off a chain of tasks, that can then be executed by
+   any available thread.  */
+
+int main (void)
+{
+  int x = 0, y = 0, z = 0;
+  int thread_count;
+  omp_event_handle_t detach_event1, detach_event2;
+
+  #pragma omp target map(tofrom: x, y, z) map(from: thread_count)
+    #pragma omp parallel firstprivate(detach_event1, detach_event2)
+      {
+       #pragma omp single
+         thread_count = omp_get_num_threads();
+
+       #pragma omp task detach(detach_event1) untied
+         #pragma omp atomic update
+           x++;
+
+       #pragma omp task detach(detach_event2) untied
+       {
+         #pragma omp atomic update
+           y++;
+         omp_fulfill_event (detach_event1);
+       }
+
+       #pragma omp task untied
+       {
+         #pragma omp atomic update
+           z++;
+         omp_fulfill_event (detach_event2);
+       }
+
+       #pragma omp taskwait
+      }
+
+  assert (x == thread_count);
+  assert (y == thread_count);
+  assert (z == thread_count);
+}
diff --git a/libgomp/testsuite/libgomp.fortran/task-detach-1.f90 b/libgomp/testsuite/libgomp.fortran/task-detach-1.f90
new file mode 100644 (file)
index 0000000..217bf65
--- /dev/null
@@ -0,0 +1,33 @@
+! { dg-do run }
+
+! Test chaining of detached tasks, with each task fulfilling the
+! completion event of the previous one.
+
+program task_detach_1
+  use omp_lib
+
+  integer (kind=omp_event_handle_kind) :: detach_event1, detach_event2
+  integer :: x = 0, y = 0, z = 0
+
+  !$omp parallel
+    !$omp single
+      !$omp task detach(detach_event1)
+        x = x + 1
+      !$omp end task
+
+      !$omp task detach(detach_event2)
+        y = y + 1
+       call omp_fulfill_event (detach_event1)
+      !$omp end task
+
+      !$omp task
+        z = z + 1
+       call omp_fulfill_event (detach_event2)
+      !$omp end task
+    !$omp end single
+  !$omp end parallel
+
+  if (x /= 1) stop 1
+  if (y /= 1) stop 2
+  if (z /= 1) stop 3
+end program
diff --git a/libgomp/testsuite/libgomp.fortran/task-detach-2.f90 b/libgomp/testsuite/libgomp.fortran/task-detach-2.f90
new file mode 100644 (file)
index 0000000..ecb4829
--- /dev/null
@@ -0,0 +1,34 @@
+! { dg-do run }
+
+! Test handling of detach clause with only a single thread.  The runtime
+! should not block when a task with an unfulfilled event finishes
+! running.
+
+program task_detach_2
+  use omp_lib
+
+  integer (kind=omp_event_handle_kind) :: detach_event1, detach_event2
+  integer :: x = 0, y = 0, z = 0
+
+  !$omp parallel num_threads(1)
+    !$omp single
+      !$omp task detach(detach_event1)
+        x = x + 1
+      !$omp end task
+
+      !$omp task detach(detach_event2)
+        y = y + 1
+       call omp_fulfill_event (detach_event1)
+      !$omp end task
+
+      !$omp task
+        z = z + 1
+       call omp_fulfill_event (detach_event2)
+      !$omp end task
+    !$omp end single
+  !$omp end parallel
+
+  if (x /= 1) stop 1
+  if (y /= 1) stop 2
+  if (z /= 1) stop 3
+end program
diff --git a/libgomp/testsuite/libgomp.fortran/task-detach-3.f90 b/libgomp/testsuite/libgomp.fortran/task-detach-3.f90
new file mode 100644 (file)
index 0000000..bdf93a5
--- /dev/null
@@ -0,0 +1,33 @@
+! { dg-do run }
+
+! Test the task detach clause used together with dependencies.
+
+program task_detach_3
+
+  use omp_lib
+
+  integer (kind=omp_event_handle_kind) :: detach_event
+  integer :: x = 0, y = 0, z = 0
+  integer :: dep
+
+  !$omp parallel
+    !$omp single
+      !$omp task depend(out:dep) detach(detach_event)
+        x = x + 1
+      !$omp end task
+
+      !$omp task
+        y = y + 1
+       call omp_fulfill_event(detach_event)
+      !$omp end task
+
+      !$omp task depend(in:dep)
+        z = z + 1
+      !$omp end task
+    !$omp end single
+  !$omp end parallel
+
+  if (x /= 1) stop 1
+  if (y /= 1) stop 2
+  if (z /= 1) stop 3
+end program
diff --git a/libgomp/testsuite/libgomp.fortran/task-detach-4.f90 b/libgomp/testsuite/libgomp.fortran/task-detach-4.f90
new file mode 100644 (file)
index 0000000..6d0843c
--- /dev/null
@@ -0,0 +1,22 @@
+! { dg-do run }
+
+! Test detach clause, where a task fulfills its own completion event.
+
+program task_detach_4
+
+  use omp_lib
+
+  integer (kind=omp_event_handle_kind) :: detach_event
+  integer :: x = 0
+
+  !$omp parallel
+    !$omp single
+      !$omp task detach(detach_event)
+        x = x + 1
+       call omp_fulfill_event(detach_event)
+      !$omp end task
+    !$omp end single
+  !$omp end parallel
+
+  if (x /= 1) stop 1
+end program
diff --git a/libgomp/testsuite/libgomp.fortran/task-detach-5.f90 b/libgomp/testsuite/libgomp.fortran/task-detach-5.f90
new file mode 100644 (file)
index 0000000..955d687
--- /dev/null
@@ -0,0 +1,39 @@
+! { dg-do run }
+
+! Test tasks with detach clause.  Each thread spawns off a chain of tasks,
+! that can then be executed by any available thread.
+
+program task_detach_5
+  use omp_lib
+
+  integer (kind=omp_event_handle_kind) :: detach_event1, detach_event2
+  integer :: x = 0, y = 0, z = 0
+  integer :: thread_count
+
+  !$omp parallel firstprivate(detach_event1, detach_event2)
+    !$omp single
+      thread_count = omp_get_num_threads()
+    !$omp end single
+
+    !$omp task detach(detach_event1) untied
+      !$omp atomic update
+       x = x + 1
+    !$omp end task
+
+    !$omp task detach(detach_event2) untied
+      !$omp atomic update
+       y = y + 1
+      call omp_fulfill_event (detach_event1);
+    !$omp end task
+
+    !$omp task untied
+      !$omp atomic update
+       z = z + 1
+      call omp_fulfill_event (detach_event2);
+    !$omp end task
+  !$omp end parallel
+
+  if (x /= thread_count) stop 1
+  if (y /= thread_count) stop 2
+  if (z /= thread_count) stop 3
+end program
diff --git a/libgomp/testsuite/libgomp.fortran/task-detach-6.f90 b/libgomp/testsuite/libgomp.fortran/task-detach-6.f90
new file mode 100644 (file)
index 0000000..0fe2155
--- /dev/null
@@ -0,0 +1,44 @@
+! { dg-do run }
+
+! Test tasks with detach clause on an offload device.  Each device
+! thread spawns off a chain of tasks, that can then be executed by
+! any available thread.
+
+program task_detach_6
+  use omp_lib
+
+  integer (kind=omp_event_handle_kind) :: detach_event1, detach_event2
+  integer :: x = 0, y = 0, z = 0
+  integer :: thread_count
+
+  !$omp target map(tofrom: x, y, z) map(from: thread_count)
+    !$omp parallel firstprivate(detach_event1, detach_event2)
+      !$omp single
+       thread_count = omp_get_num_threads()
+      !$omp end single
+
+      !$omp task detach(detach_event1) untied
+       !$omp atomic update
+         x = x + 1
+      !$omp end task
+
+      !$omp task detach(detach_event2) untied
+       !$omp atomic update
+         y = y + 1
+       call omp_fulfill_event (detach_event1);
+      !$omp end task
+
+      !$omp task untied
+       !$omp atomic update
+         z = z + 1
+       call omp_fulfill_event (detach_event2);
+      !$omp end task
+
+      !$omp taskwait
+    !$omp end parallel
+  !$omp end target
+
+  if (x /= thread_count) stop 1
+  if (y /= thread_count) stop 2
+  if (z /= thread_count) stop 3
+end program