public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc/devel/omp/gcc-10] openmp: Add support for the OpenMP 5.0 task detach clause
@ 2021-01-22 19:51 Kwok Yeung
  0 siblings, 0 replies; only message in thread
From: Kwok Yeung @ 2021-01-22 19:51 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:de460a5faff80a2338ccd46f249c964fa34b4c16

commit de460a5faff80a2338ccd46f249c964fa34b4c16
Author: Kwok Cheung Yeung <kcy@codesourcery.com>
Date:   Sat Jan 16 12:58:13 2021 -0800

    openmp: Add support for the OpenMP 5.0 task detach clause
    
    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)

Diff:
---
 gcc/ChangeLog.omp                                  |  35 ++++++
 gcc/builtin-types.def                              |   8 +-
 gcc/c-family/ChangeLog.omp                         |   8 ++
 gcc/c-family/c-pragma.h                            |   3 +-
 gcc/c/ChangeLog.omp                                |  12 ++
 gcc/c/c-parser.c                                   |  57 ++++++++-
 gcc/c/c-typeck.c                                   |  58 ++++++++-
 gcc/cp/ChangeLog.omp                               |  13 ++
 gcc/cp/parser.c                                    |  53 ++++++++-
 gcc/cp/pt.c                                        |   1 +
 gcc/cp/semantics.c                                 |  61 +++++++++-
 gcc/fortran/ChangeLog.omp                          |  26 ++++
 gcc/fortran/dump-parse-tree.c                      |   6 +
 gcc/fortran/frontend-passes.c                      |   1 +
 gcc/fortran/gfortran.h                             |   2 +
 gcc/fortran/openmp.c                               |  59 ++++++++-
 gcc/fortran/trans-openmp.c                         |  16 +++
 gcc/fortran/trans-types.c                          |   3 +
 gcc/fortran/types.def                              |   8 +-
 gcc/gimplify.c                                     |  14 +++
 gcc/omp-builtins.def                               |   2 +-
 gcc/omp-expand.c                                   |  19 ++-
 gcc/omp-low.c                                      |  47 ++++++++
 gcc/testsuite/ChangeLog.omp                        |  10 ++
 gcc/testsuite/c-c++-common/gomp/task-detach-1.c    |  37 ++++++
 gcc/testsuite/g++.dg/gomp/task-detach-1.C          |  29 +++++
 gcc/testsuite/gcc.dg/gomp/task-detach-1.c          |  20 ++++
 gcc/testsuite/gfortran.dg/gomp/task-detach-1.f90   |  29 +++++
 gcc/tree-core.h                                    |  29 +++--
 gcc/tree-nested.c                                  |   2 +
 gcc/tree-pretty-print.c                            |   6 +
 gcc/tree.c                                         |  15 ++-
 include/ChangeLog.omp                              |   7 ++
 include/gomp-constants.h                           |   1 +
 libgomp/ChangeLog.omp                              |  48 ++++++++
 libgomp/fortran.c                                  |   6 +
 libgomp/libgomp.h                                  |   7 ++
 libgomp/libgomp.map                                |   2 +
 libgomp/libgomp_g.h                                |   2 +-
 libgomp/omp.h.in                                   |   7 ++
 libgomp/omp_lib.f90.in                             |   9 ++
 libgomp/omp_lib.h.in                               |   4 +
 libgomp/priority_queue.c                           |  57 +++++++++
 libgomp/priority_queue.h                           |   5 +
 libgomp/task.c                                     | 132 +++++++++++++++++----
 libgomp/team.c                                     |   4 +
 .../testsuite/libgomp.c-c++-common/task-detach-1.c |  36 ++++++
 .../testsuite/libgomp.c-c++-common/task-detach-2.c |  37 ++++++
 .../testsuite/libgomp.c-c++-common/task-detach-3.c |  33 ++++++
 .../testsuite/libgomp.c-c++-common/task-detach-4.c |  24 ++++
 .../testsuite/libgomp.c-c++-common/task-detach-5.c |  42 +++++++
 .../testsuite/libgomp.c-c++-common/task-detach-6.c |  46 +++++++
 .../testsuite/libgomp.fortran/task-detach-1.f90    |  33 ++++++
 .../testsuite/libgomp.fortran/task-detach-2.f90    |  34 ++++++
 .../testsuite/libgomp.fortran/task-detach-3.f90    |  33 ++++++
 .../testsuite/libgomp.fortran/task-detach-4.f90    |  22 ++++
 .../testsuite/libgomp.fortran/task-detach-5.f90    |  39 ++++++
 .../testsuite/libgomp.fortran/task-detach-6.f90    |  44 +++++++
 58 files changed, 1341 insertions(+), 62 deletions(-)

diff --git a/gcc/ChangeLog.omp b/gcc/ChangeLog.omp
index f333d3d2410..590dc27373a 100644
--- a/gcc/ChangeLog.omp
+++ b/gcc/ChangeLog.omp
@@ -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
diff --git a/gcc/builtin-types.def b/gcc/builtin-types.def
index 5e36a498f4a..249338b5723 100644
--- a/gcc/builtin-types.def
+++ b/gcc/builtin-types.def
@@ -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,
diff --git a/gcc/c-family/ChangeLog.omp b/gcc/c-family/ChangeLog.omp
index 49fa269e077..d0d7d3f08b6 100644
--- a/gcc/c-family/ChangeLog.omp
+++ b/gcc/c-family/ChangeLog.omp
@@ -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
diff --git a/gcc/c-family/c-pragma.h b/gcc/c-family/c-pragma.h
index b8d9b7a4cff..3e6e5d87fd3 100644
--- a/gcc/c-family/c-pragma.h
+++ b/gcc/c-family/c-pragma.h
@@ -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,
diff --git a/gcc/c/ChangeLog.omp b/gcc/c/ChangeLog.omp
index e520f95fd89..e9ad3a1ea6f 100644
--- a/gcc/c/ChangeLog.omp
+++ b/gcc/c/ChangeLog.omp
@@ -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
diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index b4611ee5089..6b9898a1c70 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -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)
diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index 3ee0da0ba94..651f29bb21b 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -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;
 }
diff --git a/gcc/cp/ChangeLog.omp b/gcc/cp/ChangeLog.omp
index 3dac62b4edc..f071ef61b17 100644
--- a/gcc/cp/ChangeLog.omp
+++ b/gcc/cp/ChangeLog.omp
@@ -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
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index c5192278ca8..cea6ed0b2c1 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -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)
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 041b61059ff..781b055921b 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -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);
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 0d8b1298f56..86d5d464a32 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -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
diff --git a/gcc/fortran/ChangeLog.omp b/gcc/fortran/ChangeLog.omp
index 39a3682c925..dc045ebd5d5 100644
--- a/gcc/fortran/ChangeLog.omp
+++ b/gcc/fortran/ChangeLog.omp
@@ -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:
diff --git a/gcc/fortran/dump-parse-tree.c b/gcc/fortran/dump-parse-tree.c
index b9c321469d2..fe24e9cf4d7 100644
--- a/gcc/fortran/dump-parse-tree.c
+++ b/gcc/fortran/dump-parse-tree.c
@@ -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])
       {
diff --git a/gcc/fortran/frontend-passes.c b/gcc/fortran/frontend-passes.c
index 5e768b12854..80efafd6cb9 100644
--- a/gcc/fortran/frontend-passes.c
+++ b/gcc/fortran/frontend-passes.c
@@ -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;
diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h
index bd154f42a75..ce37e72c6b1 100644
--- a/gcc/fortran/gfortran.h
+++ b/gcc/fortran/gfortran.h
@@ -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;
diff --git a/gcc/fortran/openmp.c b/gcc/fortran/openmp.c
index 334125e7f9a..8dc2871cd41 100644
--- a/gcc/fortran/openmp.c
+++ b/gcc/fortran/openmp.c
@@ -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);
 }
 
 
diff --git a/gcc/fortran/trans-openmp.c b/gcc/fortran/trans-openmp.c
index 77ecb957dfd..452e2a69baa 100644
--- a/gcc/fortran/trans-openmp.c
+++ b/gcc/fortran/trans-openmp.c
@@ -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;
diff --git a/gcc/fortran/trans-types.c b/gcc/fortran/trans-types.c
index b7712dc74d1..f90025d75cf 100644
--- a/gcc/fortran/trans-types.c
+++ b/gcc/fortran/trans-types.c
@@ -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;
 }
 
 
diff --git a/gcc/fortran/types.def b/gcc/fortran/types.def
index e5fafc5a34d..80e4fad5263 100644
--- a/gcc/fortran/types.def
+++ b/gcc/fortran/types.def
@@ -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,
diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index bf4eb8b008b..f5769403461 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -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:
diff --git a/gcc/omp-builtins.def b/gcc/omp-builtins.def
index 1d063289232..447abcdd759 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_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,
diff --git a/gcc/omp-expand.c b/gcc/omp-expand.c
index 08afaceb87e..db2ae54feab 100644
--- a/gcc/omp-expand.c
+++ b/gcc/omp-expand.c
@@ -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);
diff --git a/gcc/omp-low.c b/gcc/omp-low.c
index b4148542e7f..ddeceba2bc7 100644
--- a/gcc/omp-low.c
+++ b/gcc/omp-low.c
@@ -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)
diff --git a/gcc/testsuite/ChangeLog.omp b/gcc/testsuite/ChangeLog.omp
index ed435aff6b6..457ce6e38cf 100644
--- a/gcc/testsuite/ChangeLog.omp
+++ b/gcc/testsuite/ChangeLog.omp
@@ -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
index 00000000000..4558bc1f89c
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/task-detach-1.c
@@ -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
index 00000000000..6028cb418c7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/task-detach-1.C
@@ -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
index 00000000000..611044d8d97
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/gomp/task-detach-1.c
@@ -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
index 00000000000..4763f13ba84
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/task-detach-1.f90
@@ -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
diff --git a/gcc/tree-core.h b/gcc/tree-core.h
index 6ada13875ba..15fb1b5d2b7 100644
--- a/gcc/tree-core.h
+++ b/gcc/tree-core.h
@@ -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_,
diff --git a/gcc/tree-nested.c b/gcc/tree-nested.c
index e42f0b6a2d2..89fbcd56555 100644
--- a/gcc/tree-nested.c
+++ b/gcc/tree-nested.c
@@ -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);
diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c
index 7bd35ce8a6d..3fae181fefb 100644
--- a/gcc/tree-pretty-print.c
+++ b/gcc/tree-pretty-print.c
@@ -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 ();
diff --git a/gcc/tree.c b/gcc/tree.c
index 3ba6fee08a0..cd6a5331d4b 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -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:
diff --git a/include/ChangeLog.omp b/include/ChangeLog.omp
index 3e1bdd5e922..d500277d345 100644
--- a/include/ChangeLog.omp
+++ b/include/ChangeLog.omp
@@ -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
diff --git a/include/gomp-constants.h b/include/gomp-constants.h
index f2d15f65b67..45d553c47c2 100644
--- a/include/gomp-constants.h
+++ b/include/gomp-constants.h
@@ -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)
diff --git a/libgomp/ChangeLog.omp b/libgomp/ChangeLog.omp
index b6f565c1d28..684e09a378b 100644
--- a/libgomp/ChangeLog.omp
+++ b/libgomp/ChangeLog.omp
@@ -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
diff --git a/libgomp/fortran.c b/libgomp/fortran.c
index cd719f92fc8..976b2482743 100644
--- a/libgomp/fortran.c
+++ b/libgomp/fortran.c
@@ -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)
 {
diff --git a/libgomp/libgomp.h b/libgomp/libgomp.h
index c77a813cf32..9b1378559bc 100644
--- a/libgomp/libgomp.h
+++ b/libgomp/libgomp.h
@@ -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[];
 };
diff --git a/libgomp/libgomp.map b/libgomp/libgomp.map
index c5f52f725d0..6561721f8af 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 {
diff --git a/libgomp/libgomp_g.h b/libgomp/libgomp_g.h
index 70a27572182..b439c833d64 100644
--- a/libgomp/libgomp_g.h
+++ b/libgomp/libgomp_g.h
@@ -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);
diff --git a/libgomp/omp.h.in b/libgomp/omp.h.in
index be7df6d283f..b7c3eea171f 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 da630fa0541..776bb84f947 100644
--- a/libgomp/omp_lib.f90.in
+++ b/libgomp/omp_lib.f90.in
@@ -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
@@ -554,6 +555,14 @@
           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
diff --git a/libgomp/omp_lib.h.in b/libgomp/omp_lib.h.in
index b06e5681334..9f3d176cec7 100644
--- a/libgomp/omp_lib.h.in
+++ b/libgomp/omp_lib.h.in
@@ -80,10 +80,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 = @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
@@ -243,6 +245,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 9b8d2ff5d9f..6cc817d2dd6 100644
--- a/libgomp/priority_queue.c
+++ b/libgomp/priority_queue.c
@@ -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.  */
 
diff --git a/libgomp/priority_queue.h b/libgomp/priority_queue.h
index 0ad78f5ecb6..50269fc9ca8 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 a95067c6de9..67bff47fa0b 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 = 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)
diff --git a/libgomp/team.c b/libgomp/team.c
index cbc3aec0265..ee488f2214b 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 00000000000..8583e3761b5
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c-c++-common/task-detach-1.c
@@ -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
index 00000000000..943ac2a3f85
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c-c++-common/task-detach-2.c
@@ -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
index 00000000000..2609fb1c43d
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c-c++-common/task-detach-3.c
@@ -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
index 00000000000..eeb9554c665
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c-c++-common/task-detach-4.c
@@ -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
index 00000000000..5a0151729ef
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c-c++-common/task-detach-5.c
@@ -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
index 00000000000..b5f68ccabdc
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c-c++-common/task-detach-6.c
@@ -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
index 00000000000..217bf657506
--- /dev/null
+++ b/libgomp/testsuite/libgomp.fortran/task-detach-1.f90
@@ -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
index 00000000000..ecb4829e14b
--- /dev/null
+++ b/libgomp/testsuite/libgomp.fortran/task-detach-2.f90
@@ -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
index 00000000000..bdf93a5909a
--- /dev/null
+++ b/libgomp/testsuite/libgomp.fortran/task-detach-3.f90
@@ -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
index 00000000000..6d0843cb126
--- /dev/null
+++ b/libgomp/testsuite/libgomp.fortran/task-detach-4.f90
@@ -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
index 00000000000..955d687ca8b
--- /dev/null
+++ b/libgomp/testsuite/libgomp.fortran/task-detach-5.f90
@@ -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
index 00000000000..0fe21553494
--- /dev/null
+++ b/libgomp/testsuite/libgomp.fortran/task-detach-6.f90
@@ -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


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2021-01-22 19:51 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-01-22 19:51 [gcc/devel/omp/gcc-10] openmp: Add support for the OpenMP 5.0 task detach clause Kwok Yeung

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).