Hello

This is an updated version of the WIP patch for task detach support. Any comments would be welcome!

On 11/11/2020 7:06 pm, Kwok Cheung Yeung wrote:
- No error checking at the front-end.

The detach clause is now parsed properly in C, C++ and Fortran, and will raise an error if the syntax is incorrect or if the event variable is of the wrong type.

- The memory for the event is not mapped on the target. This means that if omp_fulfill_event is called from an 'omp target' section with a target that does not share memory with the host, the event will not be fulfilled (and a segfault will probably occur).

I was thinking of something along the lines of:

#pragma omp task detach (event)
{
}

#pragma omp target
{
  omp_fulfill_event (event);
}

Would something like this be expected to work? I cannot find many examples of the detach clause online, and none of them use any offloading constructs.

- The tasks awaiting event fulfillment currently wait until there are no other runnable tasks left. A better approach would be to poll (without blocking) the waiting tasks whenever any task completes, immediately removing any now-complete tasks and requeuing any dependent tasks.

This has now been implemented. On every iteration of the main loop in gomp_barrier_handle_tasks, it first checks to see if any tasks in the detach queue have a fulfilled completion event, and if so it will remove the task and requeue any dependent tasks.

Thanks

Kwok
From 3611024b39ea5b264ec2fd35ffa64360861052af Mon Sep 17 00:00:00 2001
From: Kwok Cheung Yeung <k...@codesourcery.com>
Date: Fri, 27 Nov 2020 11:59:12 -0800
Subject: [PATCH] openmp: Add support for the OpenMP 5.0 task detach clause

2020-11-27  Kwok Cheung Yeung  <k...@codesourcery.com>

        gcc/
        * builtin-types.def (BT_PTR_SIZED_INT): New primitive type.
        (BT_FN_PSINT_VOID): New function type.
        (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_PSINT):
        ...this.  Add extra argument.
        * gimplify.c (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_PSINT.
        (BUILT_IN_GOMP_NEW_EVENT): New.
        * omp-expand.c (expand_task_call): Add detach argument when generating
        call to GOMP_task.
        * omp-low.c (scan_sharing_clauses): Setup data environment for detach
        clause.
        (lower_detach_clause): New.
        (lower_omp_taskreg): Call lower_detach_clause for detach clause.  Add
        Gimple statements generated for detach clause.
        * tree-core.h (enum omp_clause_code): Add OMP_CLAUSE_DETACH.
        * tree-pretty-print.c (dump_omp_clause): Handle OMP_CLAUSE_DETACH.
        * tree.c (omp_clause_num_ops): Add entry for OMP_CLAUSE_DETACH.
        (omp_clause_code_name): Add entry for OMP_CLAUSE_DETACH.
        (walk_tree_1): Handle OMP_CLAUSE_DETACH.
        * tree.h (OMP_CLAUSE_DETACH_EXPR): New.

        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.

        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.
        * semantics.c (finish_omp_clauses): Handle OMP_CLAUSE_DETACH clause.

        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.
        * 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_PTR_SIZED_INT): New type.
        (BT_FN_PSINT_VOID): New function type.
        (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_PSINT):
        ...this.  Add extra argument.

        libgomp/
        * fortran.c (omp_fulfill_event_): New.
        * libgomp.h (struct gomp_allow_completion_event): New.
        (struct gomp_task): Add detach_event field.
        (struct gomp_team): Add task_detach_queue and task_detach_count
        fields.
        (gomp_finish_task): Delete detach_event.
        * libgomp.map (OMP_5.0.1): Add omp_fulfill_event and omp_fulfill_event_.
        (GOMP_5.0): Add GOMP_new_event.
        * libgomp_g.h (GOMP_new_event): New.
        (GOMP_task): Add uintptr_t 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_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_event field.
        (GOMP_new_event): New.
        (GOMP_task): Add detach argument.  Initialize detach_event field.
        Wait for detach event if task not deferred.
        (task_fulfilled_p): New.
        (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.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.
---
 gcc/builtin-types.def                              |  10 +-
 gcc/c-family/c-pragma.h                            |   3 +-
 gcc/c/c-parser.c                                   |  54 ++++++-
 gcc/c/c-typeck.c                                   |   5 +
 gcc/cp/parser.c                                    |  67 ++++++++-
 gcc/cp/semantics.c                                 |   3 +
 gcc/fortran/dump-parse-tree.c                      |   6 +
 gcc/fortran/frontend-passes.c                      |   1 +
 gcc/fortran/gfortran.h                             |   2 +
 gcc/fortran/openmp.c                               |  44 +++++-
 gcc/fortran/trans-openmp.c                         |  15 ++
 gcc/fortran/trans-types.c                          |   3 +
 gcc/fortran/types.def                              |  10 +-
 gcc/gimplify.c                                     |   5 +
 gcc/omp-builtins.def                               |   4 +-
 gcc/omp-expand.c                                   |  10 +-
 gcc/omp-low.c                                      |  35 +++++
 gcc/tree-core.h                                    |   3 +
 gcc/tree-pretty-print.c                            |   6 +
 gcc/tree.c                                         |   3 +
 gcc/tree.h                                         |   3 +
 libgomp/fortran.c                                  |   6 +
 libgomp/libgomp.h                                  |  14 ++
 libgomp/libgomp.map                                |   3 +
 libgomp/libgomp_g.h                                |   3 +-
 libgomp/omp.h.in                                   |   7 +
 libgomp/omp_lib.f90.in                             |   8 +
 libgomp/omp_lib.h.in                               |   4 +
 libgomp/priority_queue.c                           |  50 +++++++
 libgomp/priority_queue.h                           |   5 +
 libgomp/task.c                                     | 166 ++++++++++++++++++---
 libgomp/team.c                                     |   4 +
 .../testsuite/libgomp.c-c++-common/task-detach-1.c |  39 +++++
 .../testsuite/libgomp.c-c++-common/task-detach-2.c |  39 +++++
 .../testsuite/libgomp.c-c++-common/task-detach-3.c |  39 +++++
 .../testsuite/libgomp.c-c++-common/task-detach-4.c |  26 ++++
 .../testsuite/libgomp.fortran/task-detach-1.f90    |  33 ++++
 .../testsuite/libgomp.fortran/task-detach-2.f90    |  33 ++++
 .../testsuite/libgomp.fortran/task-detach-3.f90    |  33 ++++
 .../testsuite/libgomp.fortran/task-detach-4.f90    |  21 +++
 40 files changed, 786 insertions(+), 39 deletions(-)
 create mode 100644 libgomp/testsuite/libgomp.c-c++-common/task-detach-1.c
 create mode 100644 libgomp/testsuite/libgomp.c-c++-common/task-detach-2.c
 create mode 100644 libgomp/testsuite/libgomp.c-c++-common/task-detach-3.c
 create mode 100644 libgomp/testsuite/libgomp.c-c++-common/task-detach-4.c
 create mode 100644 libgomp/testsuite/libgomp.fortran/task-detach-1.f90
 create mode 100644 libgomp/testsuite/libgomp.fortran/task-detach-2.f90
 create mode 100644 libgomp/testsuite/libgomp.fortran/task-detach-3.f90
 create mode 100644 libgomp/testsuite/libgomp.fortran/task-detach-4.f90

diff --git a/gcc/builtin-types.def b/gcc/builtin-types.def
index 4a82ee4..d28ec75 100644
--- a/gcc/builtin-types.def
+++ b/gcc/builtin-types.def
@@ -79,6 +79,7 @@ DEF_PRIMITIVE_TYPE (BT_UINT128, uint128_type_node
 DEF_PRIMITIVE_TYPE (BT_WORD, (*lang_hooks.types.type_for_mode) (word_mode, 1))
 DEF_PRIMITIVE_TYPE (BT_UNWINDWORD, (*lang_hooks.types.type_for_mode)
                                    (targetm.unwind_word_mode (), 1))
+DEF_PRIMITIVE_TYPE (BT_PTR_SIZED_INT, pointer_sized_int_node)
 DEF_PRIMITIVE_TYPE (BT_FLOAT, float_type_node)
 DEF_PRIMITIVE_TYPE (BT_DOUBLE, double_type_node)
 DEF_PRIMITIVE_TYPE (BT_LONGDOUBLE, long_double_type_node)
@@ -253,6 +254,7 @@ DEF_FUNCTION_TYPE_1 (BT_FN_LONG_LONGDOUBLE, BT_LONG, 
BT_LONGDOUBLE)
 DEF_FUNCTION_TYPE_1 (BT_FN_LONGLONG_FLOAT, BT_LONGLONG, BT_FLOAT)
 DEF_FUNCTION_TYPE_1 (BT_FN_LONGLONG_DOUBLE, BT_LONGLONG, BT_DOUBLE)
 DEF_FUNCTION_TYPE_1 (BT_FN_LONGLONG_LONGDOUBLE, BT_LONGLONG, BT_LONGDOUBLE)
+DEF_FUNCTION_TYPE_1 (BT_FN_PSINT_VOID, BT_PTR_SIZED_INT, BT_VOID)
 DEF_FUNCTION_TYPE_1 (BT_FN_VOID_PTR, BT_VOID, BT_PTR)
 DEF_FUNCTION_TYPE_1 (BT_FN_SIZE_CONST_STRING, BT_SIZE, BT_CONST_STRING)
 DEF_FUNCTION_TYPE_1 (BT_FN_INT_CONST_STRING, BT_INT, BT_CONST_STRING)
@@ -756,10 +758,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)
@@ -767,6 +765,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_PSINT,
+                     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_SIZED_INT)
 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,
diff --git a/gcc/c-family/c-pragma.h b/gcc/c-family/c-pragma.h
index 5a493fe..fb784e9 100644
--- a/gcc/c-family/c-pragma.h
+++ b/gcc/c-family/c-pragma.h
@@ -94,6 +94,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,
@@ -150,7 +151,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,
diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index 7540a15..d3546d4 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -15976,6 +15976,53 @@ 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");
+      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);
+      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);
+      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.  */
 
@@ -16242,6 +16289,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";
@@ -19140,7 +19191,8 @@ c_parser_omp_single (location_t loc, c_parser *parser, 
bool *if_p)
        | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND)       \
        | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIORITY)     \
        | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE)     \
-       | (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)
diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index 286f3d9..0c2ed59 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -14942,6 +14942,11 @@ 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);
+         pc = &OMP_CLAUSE_CHAIN (c);
+         continue;
+
        case OMP_CLAUSE_IF:
        case OMP_CLAUSE_NUM_THREADS:
        case OMP_CLAUSE_NUM_TEAMS:
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 8802124..5731a29 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -36957,6 +36957,66 @@ cp_parser_omp_clause_depend_sink (cp_parser *parser, 
location_t clause_loc,
 }
 
 /* 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;
+
+  if (cp_lexer_next_token_is_not (parser->lexer, CPP_NAME))
+    {
+      cp_parser_error (parser, "expected identifier");
+      return list;
+    }
+
+  location_t id_loc = cp_lexer_peek_token (parser->lexer)->location;
+  tree t, identifier = cp_parser_identifier (parser);
+
+  if (identifier == error_mark_node)
+    t = error_mark_node;
+  else
+    {
+      t = cp_parser_lookup_name_simple
+           (parser, identifier,
+            cp_lexer_peek_token (parser->lexer)->location);
+      if (t == error_mark_node)
+       cp_parser_name_lookup_error (parser, identifier, t, NLE_NULL,
+                                    id_loc);
+      else
+       {
+         tree type = TYPE_MAIN_VARIANT (TREE_TYPE (t));
+         if (!INTEGRAL_TYPE_P (type)
+             || TREE_CODE (type) != ENUMERAL_TYPE
+             || DECL_NAME (TYPE_NAME (type))
+                  != get_identifier ("omp_event_handle_t"))
+           {
+             error_at (id_loc, "%<detach%> clause event handle "
+                           "has type %qT rather than "
+                           "%<omp_event_handle_t%>",
+                           type);
+             return list;
+           }
+       }
+    }
+
+  if (t == 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 (id_loc, OMP_CLAUSE_DETACH);
+  OMP_CLAUSE_DECL (u) = t;
+  OMP_CLAUSE_CHAIN (u) = list;
+
+  return u;
+}
+
+/* OpenMP 5.0:
    iterators ( iterators-definition )
 
    iterators-definition:
@@ -38012,6 +38072,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";
@@ -40546,7 +40610,8 @@ cp_parser_omp_single (cp_parser *parser, cp_token 
*pragma_tok, bool *if_p)
        | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND)       \
        | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIORITY)     \
        | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE)     \
-       | (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)
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 5ff70ff..38eecf5 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -7394,6 +7394,9 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type 
ort)
                }
            }
          break;
+       case OMP_CLAUSE_DETACH:
+         t = OMP_CLAUSE_DECL (c);
+         break;
 
        case OMP_CLAUSE_MAP:
        case OMP_CLAUSE_TO:
diff --git a/gcc/fortran/dump-parse-tree.c b/gcc/fortran/dump-parse-tree.c
index cab0fb2..baf1e3c 100644
--- a/gcc/fortran/dump-parse-tree.c
+++ b/gcc/fortran/dump-parse-tree.c
@@ -1700,6 +1700,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])
       {
diff --git a/gcc/fortran/frontend-passes.c b/gcc/fortran/frontend-passes.c
index 83f6fd8..699b354 100644
--- a/gcc/fortran/frontend-passes.c
+++ b/gcc/fortran/frontend-passes.c
@@ -5597,6 +5597,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;
diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h
index 6467985..fec96af 100644
--- a/gcc/fortran/gfortran.h
+++ b/gcc/fortran/gfortran.h
@@ -1414,6 +1414,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;
@@ -3102,6 +3103,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;
diff --git a/gcc/fortran/openmp.c b/gcc/fortran/openmp.c
index 68d0b65..4c58447 100644
--- a/gcc/fortran/openmp.c
+++ b/gcc/fortran/openmp.c
@@ -91,6 +91,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);
@@ -448,6 +449,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
@@ -807,6 +841,7 @@ enum omp_mask1
   OMP_CLAUSE_ATOMIC,  /* OpenMP 5.0.  */
   OMP_CLAUSE_CAPTURE,  /* OpenMP 5.0.  */
   OMP_CLAUSE_MEMORDER,  /* OpenMP 5.0.  */
+  OMP_CLAUSE_DETACH,  /* OpenMP 5.0.  */
   OMP_CLAUSE_NOWAIT,
   /* This must come last.  */
   OMP_MASK1_LAST
@@ -840,7 +875,6 @@ enum omp_mask2
   OMP_CLAUSE_IF_PRESENT,
   OMP_CLAUSE_FINALIZE,
   OMP_CLAUSE_ATTACH,
-  OMP_CLAUSE_DETACH,
   /* This must come last.  */
   OMP_MASK2_LAST
 };
@@ -1378,6 +1412,11 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const 
omp_mask mask,
                gfc_current_locus = old_loc;
            }
          if ((mask & OMP_CLAUSE_DETACH)
+             && !openacc
+             && 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,
@@ -2763,7 +2802,8 @@ 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_IN_REDUCTION)
+   | OMP_CLAUSE_DEPEND | OMP_CLAUSE_PRIORITY | OMP_CLAUSE_IN_REDUCTION \
+   | OMP_CLAUSE_DETACH)
 #define OMP_TASKLOOP_CLAUSES \
   (omp_mask (OMP_CLAUSE_PRIVATE) | OMP_CLAUSE_FIRSTPRIVATE             \
    | OMP_CLAUSE_LASTPRIVATE | OMP_CLAUSE_SHARED | OMP_CLAUSE_IF                
\
diff --git a/gcc/fortran/trans-openmp.c b/gcc/fortran/trans-openmp.c
index 6b4ad6a..314e00d 100644
--- a/gcc/fortran/trans-openmp.c
+++ b/gcc/fortran/trans-openmp.c
@@ -3667,6 +3667,21 @@ 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);
+      OMP_CLAUSE_DETACH_EXPR (c) = detach;
+      omp_clauses = gfc_trans_add_clause (c, omp_clauses);
+    }
+
   if (clauses->hint)
     {
       tree hint;
diff --git a/gcc/fortran/trans-types.c b/gcc/fortran/trans-types.c
index b7129dc..bd9ca14 100644
--- a/gcc/fortran/trans-types.c
+++ b/gcc/fortran/trans-types.c
@@ -114,6 +114,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;
 
@@ -691,6 +692,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;
 }
 
 
diff --git a/gcc/fortran/types.def b/gcc/fortran/types.def
index 5736bba..7cac4dc 100644
--- a/gcc/fortran/types.def
+++ b/gcc/fortran/types.def
@@ -53,6 +53,7 @@ DEF_PRIMITIVE_TYPE (BT_LONG, long_integer_type_node)
 DEF_PRIMITIVE_TYPE (BT_ULONGLONG, long_long_unsigned_type_node)
 DEF_PRIMITIVE_TYPE (BT_WORD, (*lang_hooks.types.type_for_mode) (word_mode, 1))
 DEF_PRIMITIVE_TYPE (BT_SIZE, size_type_node)
+DEF_PRIMITIVE_TYPE (BT_PTR_SIZED_INT, pointer_sized_int_node)
 
 DEF_PRIMITIVE_TYPE (BT_I1, builtin_type_for_size (BITS_PER_UNIT*1, 1))
 DEF_PRIMITIVE_TYPE (BT_I2, builtin_type_for_size (BITS_PER_UNIT*2, 1))
@@ -86,6 +87,7 @@ DEF_FUNCTION_TYPE_1 (BT_FN_VOID_VPTR, BT_VOID, 
BT_VOLATILE_PTR)
 DEF_FUNCTION_TYPE_1 (BT_FN_INT_INT, BT_INT, BT_INT)
 DEF_FUNCTION_TYPE_1 (BT_FN_UINT_UINT, BT_UINT, BT_UINT)
 DEF_FUNCTION_TYPE_1 (BT_FN_PTR_PTR, BT_PTR, BT_PTR)
+DEF_FUNCTION_TYPE_1 (BT_FN_PSINT_VOID, BT_PTR_SIZED_INT, BT_VOID)
 DEF_FUNCTION_TYPE_1 (BT_FN_VOID_INT, BT_VOID, BT_INT)
 DEF_FUNCTION_TYPE_1 (BT_FN_VOID_BOOL, BT_VOID, BT_BOOL)
 DEF_FUNCTION_TYPE_1 (BT_FN_BOOL_INT, BT_BOOL, BT_INT)
@@ -235,10 +237,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)
@@ -246,6 +244,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_PSINT,
+                     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_SIZED_INT)
 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,
diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index 53ec9ec..b0b3922 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -9733,6 +9733,10 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq 
*pre_p,
            }
          break;
 
+       case OMP_CLAUSE_DETACH:
+         decl = OMP_CLAUSE_DECL (c);
+         goto do_notice;
+
        case OMP_CLAUSE_IF:
          if (OMP_CLAUSE_IF_MODIFIER (c) != ERROR_MARK
              && OMP_CLAUSE_IF_MODIFIER (c) != code)
@@ -10870,6 +10874,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:
diff --git a/gcc/omp-builtins.def b/gcc/omp-builtins.def
index f9b78ed..b3bf17f 100644
--- a/gcc/omp-builtins.def
+++ b/gcc/omp-builtins.def
@@ -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_PSINT,
                  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,
@@ -451,3 +451,5 @@ DEF_GOMP_BUILTIN (BUILT_IN_GOMP_ALLOC,
                  ATTR_ALLOC_WARN_UNUSED_RESULT_SIZE_2_NOTHROW_LIST)
 DEF_GOMP_BUILTIN (BUILT_IN_GOMP_FREE,
                  "GOMP_free", BT_FN_VOID_PTR_PTRMODE, ATTR_NOTHROW_LEAF_LIST)
+DEF_GOMP_BUILTIN (BUILT_IN_GOMP_NEW_EVENT, "GOMP_new_event",
+                 BT_FN_PSINT_VOID, ATTR_NOTHROW_LEAF_LIST)
diff --git a/gcc/omp-expand.c b/gcc/omp-expand.c
index c0e94e5..533f47d 100644
--- a/gcc/omp-expand.c
+++ b/gcc/omp-expand.c
@@ -762,6 +762,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)
@@ -853,6 +854,11 @@ expand_task_call (struct omp_region *region, basic_block 
bb,
     priority = integer_zero_node;
 
   gsi = gsi_last_nondebug_bb (bb);
+
+  detach = detach
+      ? fold_convert (pointer_sized_int_node, OMP_CLAUSE_DETACH_EXPR (detach))
+      : null_pointer_node;
+
   tree t = gimple_omp_task_data_arg (entry_stmt);
   if (t == NULL)
     t2 = null_pointer_node;
@@ -875,10 +881,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);
diff --git a/gcc/omp-low.c b/gcc/omp-low.c
index 09a8cbd..3dd15d1 100644
--- a/gcc/omp-low.c
+++ b/gcc/omp-low.c
@@ -1412,6 +1412,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;
@@ -1779,6 +1780,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_ALLOCATE:
        case OMP_CLAUSE__LOOPTEMP_:
        case OMP_CLAUSE__REDUCTEMP_:
@@ -11453,6 +11455,26 @@ create_task_copyfn (gomp_task *task_stmt, omp_context 
*ctx)
 }
 
 static void
+lower_detach_clause (tree *pclauses, gimple_seq *iseq, omp_context *ctx)
+{
+  tree clause = omp_find_clause (*pclauses, OMP_CLAUSE_DETACH);
+  gcc_assert (clause);
+
+  tree event_decl = OMP_CLAUSE_DECL (clause);
+  tree event_ref = lookup_decl_in_outer_ctx (event_decl, ctx);
+  tree fn_decl = builtin_decl_explicit (BUILT_IN_GOMP_NEW_EVENT);
+  tree handle = create_tmp_var (pointer_sized_int_node);
+
+  gimple *call_stmt = gimple_build_call (fn_decl, 0);
+  gimple_call_set_lhs (call_stmt, handle);
+  gimple_seq_add_stmt (iseq, call_stmt);
+
+  gimplify_assign (event_ref,
+                  fold_convert (TREE_TYPE (event_decl), handle),
+                  iseq);
+}
+
+static void
 lower_depend_clauses (tree *pclauses, gimple_seq *iseq, gimple_seq *oseq)
 {
   tree c, clauses;
@@ -11601,6 +11623,15 @@ lower_omp_taskreg (gimple_stmt_iterator *gsi_p, 
omp_context *ctx)
       if (ws_num == 1)
        gimple_omp_parallel_set_combined_p (stmt, true);
     }
+
+  gimple_seq detach_ilist = NULL;
+  if (gimple_code (stmt) == GIMPLE_OMP_TASK
+      && omp_find_clause (clauses, OMP_CLAUSE_DETACH))
+    {
+      lower_detach_clause (gimple_omp_task_clauses_ptr (stmt), &detach_ilist,
+                          ctx);
+    }
+
   gimple_seq dep_ilist = NULL;
   gimple_seq dep_olist = NULL;
   if (gimple_code (stmt) == GIMPLE_OMP_TASK
@@ -11678,6 +11709,10 @@ lower_omp_taskreg (gimple_stmt_iterator *gsi_p, 
omp_context *ctx)
 
   gimple_seq olist = NULL;
   gimple_seq ilist = NULL;
+
+  if (detach_ilist)
+    gimple_seq_add_seq (&ilist, detach_ilist);
+
   lower_send_clauses (clauses, &ilist, &olist, ctx);
   lower_send_shared_vars (&ilist, &olist, ctx);
 
diff --git a/gcc/tree-core.h b/gcc/tree-core.h
index 313a6af..5b028da 100644
--- a/gcc/tree-core.h
+++ b/gcc/tree-core.h
@@ -301,6 +301,9 @@ enum omp_clause_code {
   /* OpenMP clause: to (variable-list).  */
   OMP_CLAUSE_TO,
 
+  /* OpenMP clause: detach (event-handle).  */
+  OMP_CLAUSE_DETACH,
+
   /* 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)}
diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c
index 5a93c4d..073d14b 100644
--- a/gcc/tree-pretty-print.c
+++ b/gcc/tree-pretty-print.c
@@ -1265,6 +1265,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_DETACH_EXPR (clause), spc, flags,
+                        false);
+      pp_right_paren (pp);
+      break;
 
     default:
       gcc_unreachable ();
diff --git a/gcc/tree.c b/gcc/tree.c
index d6ba553..921c928 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -299,6 +299,7 @@ unsigned const char omp_clause_num_ops[] =
   1, /* OMP_CLAUSE_LINK  */
   2, /* OMP_CLAUSE_FROM  */
   2, /* OMP_CLAUSE_TO  */
+  1, /* OMP_CLAUSE_DETACH  */
   2, /* OMP_CLAUSE_MAP  */
   1, /* OMP_CLAUSE_USE_DEVICE_PTR  */
   1, /* OMP_CLAUSE_USE_DEVICE_ADDR  */
@@ -384,6 +385,7 @@ const char * const omp_clause_code_name[] =
   "link",
   "from",
   "to",
+  "detach",
   "map",
   "use_device_ptr",
   "use_device_addr",
@@ -12234,6 +12236,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:
diff --git a/gcc/tree.h b/gcc/tree.h
index 078919b..c76ee74 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -1588,6 +1588,9 @@ class auto_suppress_location_wrappers
 #define OMP_CLAUSE_PRIORITY_EXPR(NODE) \
   OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_PRIORITY),0)
 
+#define OMP_CLAUSE_DETACH_EXPR(NODE) \
+  OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_DETACH),0)
+
 /* OpenACC clause expressions  */
 #define OMP_CLAUSE_EXPR(NODE, CLAUSE) \
   OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, CLAUSE), 0)
diff --git a/libgomp/fortran.c b/libgomp/fortran.c
index cd719f9..976b248 100644
--- a/libgomp/fortran.c
+++ b/libgomp/fortran.c
@@ -605,6 +605,12 @@ omp_get_max_task_priority_ (void)
 }
 
 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)
 {
   gomp_set_affinity_format (format, format_len);
diff --git a/libgomp/libgomp.h b/libgomp/libgomp.h
index 070d29c..88fc217 100644
--- a/libgomp/libgomp.h
+++ b/libgomp/libgomp.h
@@ -516,6 +516,12 @@ struct gomp_taskwait
   gomp_sem_t taskwait_sem;
 };
 
+struct gomp_allow_completion_event
+{
+  bool fulfilled;
+  gomp_sem_t completion_sem;
+};
+
 /* This structure describes a "task" to be run by a thread.  */
 
 struct gomp_task
@@ -545,6 +551,8 @@ struct gomp_task
      entries and the gomp_task in which they reside.  */
   struct priority_node pnode[3];
 
+  struct gomp_allow_completion_event *detach_event;
+
   struct gomp_task_icv icv;
   void (*fn) (void *);
   void *fn_data;
@@ -685,6 +693,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[];
 };
@@ -931,6 +943,8 @@ gomp_finish_task (struct gomp_task *task)
 {
   if (__builtin_expect (task->depend_hash != NULL, 0))
     free (task->depend_hash);
+  if (task->detach_event)
+    free (task->detach_event);
 }
 
 /* team.c */
diff --git a/libgomp/libgomp.map b/libgomp/libgomp.map
index 2c95f78..434dfc3 100644
--- a/libgomp/libgomp.map
+++ b/libgomp/libgomp.map
@@ -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 {
@@ -347,6 +349,7 @@ GOMP_5.0 {
        GOMP_loop_ull_nonmonotonic_runtime_start;
        GOMP_loop_ull_ordered_start;
        GOMP_loop_ull_start;
+       GOMP_new_event;
        GOMP_parallel_loop_maybe_nonmonotonic_runtime;
        GOMP_parallel_loop_nonmonotonic_runtime;
        GOMP_parallel_reductions;
diff --git a/libgomp/libgomp_g.h b/libgomp/libgomp_g.h
index b20e186..ca27c53 100644
--- a/libgomp/libgomp_g.h
+++ b/libgomp/libgomp_g.h
@@ -293,8 +293,9 @@ extern bool GOMP_cancellation_point (int);
 
 /* task.c */
 
+extern uintptr_t GOMP_new_event (void);
 extern void GOMP_task (void (*) (void *), void *, void (*) (void *, void *),
-                      long, long, bool, unsigned, void **, int);
+                      long, long, bool, unsigned, void **, int, uintptr_t);
 extern void GOMP_taskloop (void (*) (void *), void *,
                           void (*) (void *, void *), long, long, unsigned,
                           unsigned long, int, long, long, long);
diff --git a/libgomp/omp.h.in b/libgomp/omp.h.in
index 4424a16..62b6c0f 100644
--- a/libgomp/omp.h.in
+++ b/libgomp/omp.h.in
@@ -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;
diff --git a/libgomp/omp_lib.f90.in b/libgomp/omp_lib.f90.in
index 3b7f0cb..7b70d8b 100644
--- a/libgomp/omp_lib.f90.in
+++ b/libgomp/omp_lib.f90.in
@@ -39,6 +39,7 @@
         integer, parameter :: omp_alloctrait_val_kind = c_intptr_t
         integer, parameter :: omp_memspace_handle_kind = c_intptr_t
         integer, parameter :: omp_depend_kind = @OMP_DEPEND_KIND@
+        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
@@ -556,6 +557,13 @@
         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
           end subroutine omp_set_affinity_format
diff --git a/libgomp/omp_lib.h.in b/libgomp/omp_lib.h.in
index eb1dcc4..5b4053f 100644
--- a/libgomp/omp_lib.h.in
+++ b/libgomp/omp_lib.h.in
@@ -82,10 +82,12 @@
 
       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 = 4)
       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
@@ -245,6 +247,8 @@
       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
diff --git a/libgomp/priority_queue.c b/libgomp/priority_queue.c
index 9b8d2ff..0c6b556 100644
--- a/libgomp/priority_queue.c
+++ b/libgomp/priority_queue.c
@@ -168,6 +168,56 @@ priority_queue_verify (enum priority_queue_type type,
 }
 #endif /* _LIBGOMP_CHECKING_ */
 
+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;
+}
+
+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;
+}
+
+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.  */
 
diff --git a/libgomp/priority_queue.h b/libgomp/priority_queue.h
index 0ad78f5..c6fd80d 100644
--- a/libgomp/priority_queue.h
+++ b/libgomp/priority_queue.h
@@ -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 *);
diff --git a/libgomp/task.c b/libgomp/task.c
index a95067c..d40a42a 100644
--- a/libgomp/task.c
+++ b/libgomp/task.c
@@ -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_event = NULL;
 }
 
 /* Clean up a task, after completing it.  */
@@ -326,6 +327,21 @@ gomp_task_handle_depend (struct gomp_task *task, struct 
gomp_task *parent,
     }
 }
 
+uintptr_t
+GOMP_new_event ()
+{
+  struct gomp_allow_completion_event *event;
+
+  event = (struct gomp_allow_completion_event *)
+           gomp_malloc (sizeof (struct gomp_allow_completion_event));
+  event->fulfilled = false;
+  gomp_sem_init (&event->completion_sem, 0);
+
+  gomp_debug (0, "GOMP_new_event: %p\n", event);
+
+  return (uintptr_t) event;
+}
+
 /* 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,11 +363,14 @@ 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, uintptr_t detach)
 {
   struct gomp_thread *thr = gomp_thread ();
   struct gomp_team *team = thr->ts.team;
 
+  struct gomp_allow_completion_event *detach_event =
+    detach ? (struct gomp_allow_completion_event *) detach : NULL;
+
 #ifdef HAVE_BROKEN_POSIX_SEMAPHORES
   /* If pthread_mutex_* is used for omp_*lock*, then each task must be
      tied to one thread all the time.  This means UNTIED tasks must be
@@ -404,6 +423,10 @@ 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_event = detach_event;
+
       if (thr->task)
        {
          task.in_tied_task = thr->task->in_tied_task;
@@ -420,6 +443,10 @@ GOMP_task (void (*fn) (void *), void *data, void (*cpyfn) 
(void *, void *),
        }
       else
        fn (data);
+
+      if (detach)
+         gomp_sem_wait (&task.detach_event->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)
@@ -435,6 +462,7 @@ GOMP_task (void (*fn) (void *), void *data, void (*cpyfn) 
(void *, void *),
          gomp_clear_parent (&task.children_queue);
          gomp_mutex_unlock (&team->task_lock);
        }
+
       gomp_end_task ();
     }
   else
@@ -458,6 +486,8 @@ 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_event = detach_event;
       thr->task = task;
       if (cpyfn)
        {
@@ -1299,6 +1329,13 @@ gomp_task_run_post_remove_taskgroup (struct gomp_task 
*child_task)
     }
 }
 
+static bool
+task_fulfilled_p (struct gomp_task *task)
+{
+  return __atomic_load_n (&task->detach_event->fulfilled,
+                         __ATOMIC_RELAXED);
+}
+
 void
 gomp_barrier_handle_tasks (gomp_barrier_state_t state)
 {
@@ -1310,6 +1347,8 @@ gomp_barrier_handle_tasks (gomp_barrier_state_t state)
   int do_wake = 0;
 
   gomp_mutex_lock (&team->task_lock);
+  gomp_debug (0, "thread: %d, task_count %d\n",
+             thr->ts.team_id, team->task_count);
   if (gomp_barrier_last_thread (state))
     {
       if (team->task_count == 0)
@@ -1325,6 +1364,22 @@ 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->detach_event);
+         goto finish_cancelled;
+       }
+
       if (!priority_queue_empty_p (&team->task_queue, MEMMODEL_RELAXED))
        {
          bool ignored;
@@ -1388,34 +1443,86 @@ gomp_barrier_handle_tasks (gomp_barrier_state_t state)
          thr->task = task;
        }
       else
-       return;
-      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)
+         bool ignored;
+
+         /* If there are no tasks left, return.  */
+         gomp_mutex_lock (&team->task_lock);
+         if (priority_queue_empty_p (&team->task_detach_queue,
+                                     MEMMODEL_RELAXED))
            {
-             do_wake = team->nthreads - team->task_running_count;
-             if (do_wake > new_tasks)
-               do_wake = new_tasks;
+             gomp_mutex_unlock (&team->task_lock);
+             return;
            }
-         if (--team->task_count == 0
-             && gomp_team_barrier_waiting_for_tasks (&team->barrier))
+
+         /* Retrieve a queued detached task.  */
+         child_task
+           = priority_queue_next_task (PQ_TEAM, &team->task_detach_queue,
+                                       PQ_IGNORED, NULL,
+                                       &ignored);
+         priority_queue_remove (PQ_TEAM, &team->task_detach_queue,
+                                child_task, MEMMODEL_RELAXED);
+         --team->task_detach_count;
+         if (!task_fulfilled_p (child_task))
            {
-             gomp_team_barrier_done (&team->barrier, state);
+             /* Wait for detached task to finish.  */
              gomp_mutex_unlock (&team->task_lock);
-             gomp_team_barrier_wake (&team->barrier, 0);
+             gomp_debug (0,
+                         "thread: %d, waiting for event to be fulfilled %p\n",
+                         thr->ts.team_id, child_task->detach_event);
+             gomp_sem_wait (&child_task->detach_event->completion_sem);
              gomp_mutex_lock (&team->task_lock);
            }
+         else
+           gomp_debug (0, "thread: %d, queued event already fulfilled %p\n",
+                       thr->ts.team_id, child_task->detach_event);
+         goto finish_cancelled;
+       }
+      gomp_mutex_lock (&team->task_lock);
+      if (child_task)
+       {
+         if (child_task->detach_event
+             && !task_fulfilled_p (child_task))
+           {
+             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 detached %p\n",
+                         thr->ts.team_id, child_task->detach_event);
+             child_task = NULL;
+           }
+         else
+           {
+             if (child_task->detach_event)
+               gomp_debug (0, "thread: %d, event already fulfilled %p\n",
+                           thr->ts.team_id, child_task->detach_event);
+            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 +2433,18 @@ omp_in_final (void)
 }
 
 ialias (omp_in_final)
+
+void omp_fulfill_event(omp_event_handle_t event)
+{
+  struct gomp_allow_completion_event *ev =
+               (struct gomp_allow_completion_event *) event;
+
+  if (__atomic_load_n (&ev->fulfilled, __ATOMIC_RELAXED))
+    gomp_fatal ("omp_fulfill_enent: Event already fulfilled!\n");
+
+  gomp_debug(0, "omp_fulfill_event: %p\n", ev);
+  __atomic_store_n (&ev->fulfilled, true, __ATOMIC_RELAXED);
+  gomp_sem_post (&ev->completion_sem);
+}
+
+ialias (omp_fulfill_event)
diff --git a/libgomp/team.c b/libgomp/team.c
index cbc3aec..ee488f2 100644
--- a/libgomp/team.c
+++ b/libgomp/team.c
@@ -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
index 0000000..7f2319c
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c-c++-common/task-detach-1.c
@@ -0,0 +1,39 @@
+/* { dg-do run } */
+
+#include <omp.h>
+#include <assert.h>
+
+omp_event_handle_t detach_event1, detach_event2;
+
+int main (void)
+{
+  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);
+      }
+    }
+    #pragma omp taskwait
+  }
+
+  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
index 0000000..330c936
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c-c++-common/task-detach-2.c
@@ -0,0 +1,39 @@
+/* { dg-do run } */
+
+#include <omp.h>
+#include <assert.h>
+
+int main (void)
+{
+  int x = 0, y = 0, z = 0;
+
+  #pragma omp parallel num_threads(1)
+  {
+    #pragma omp single
+    {
+      omp_event_handle_t detach_event1, detach_event2;
+
+      #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);
+      }
+    }
+    #pragma omp taskwait
+  }
+
+  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
index 0000000..a16f5336
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c-c++-common/task-detach-3.c
@@ -0,0 +1,39 @@
+/* { dg-do run } */
+
+#include <omp.h>
+#include <assert.h>
+
+int main (void)
+{
+  int x = 0, y = 0, z = 0;
+
+  #pragma omp parallel
+  {
+    #pragma omp single
+    {
+      omp_event_handle_t detach_event;
+      int dep;
+
+      #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++;
+      }
+    }
+    #pragma omp taskwait
+  }
+
+  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
index 0000000..3d4d491
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c-c++-common/task-detach-4.c
@@ -0,0 +1,26 @@
+/* { dg-do run } */
+
+#include <omp.h>
+#include <assert.h>
+
+int main (void)
+{
+  int x = 0;
+
+  #pragma omp parallel
+  {
+    #pragma omp single
+    {
+      omp_event_handle_t detach_event;
+
+      #pragma omp task detach(detach_event)
+      {
+       x++;
+       omp_fulfill_event(detach_event);
+      }
+    }
+    #pragma omp taskwait
+  }
+
+  assert (x == 1);
+}
diff --git a/libgomp/testsuite/libgomp.fortran/task-detach-1.f90 
b/libgomp/testsuite/libgomp.fortran/task-detach-1.f90
new file mode 100644
index 0000000..20e3675
--- /dev/null
+++ b/libgomp/testsuite/libgomp.fortran/task-detach-1.f90
@@ -0,0 +1,33 @@
+! { dg-do run }
+
+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 taskwait
+  !$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
index 0000000..bd0f016
--- /dev/null
+++ b/libgomp/testsuite/libgomp.fortran/task-detach-2.f90
@@ -0,0 +1,33 @@
+! { dg-do run }
+
+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 taskwait
+  !$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
index 0000000..8a2ae48
--- /dev/null
+++ b/libgomp/testsuite/libgomp.fortran/task-detach-3.f90
@@ -0,0 +1,33 @@
+! { dg-do run }
+
+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 taskwait
+  !$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
index 0000000..a4ca3e0
--- /dev/null
+++ b/libgomp/testsuite/libgomp.fortran/task-detach-4.f90
@@ -0,0 +1,21 @@
+! { dg-do run }
+
+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 taskwait
+  !$omp end parallel
+
+  if (x /= 1) stop 1
+end program
-- 
2.8.1

Reply via email to