]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
OpenMP: 'interop' construct - add ME support + target-independent libgomp
authorPaul-Antoine Arras <parras@baylibre.com>
Thu, 13 Mar 2025 16:16:41 +0000 (17:16 +0100)
committerPaul-Antoine Arras <parras@baylibre.com>
Fri, 21 Mar 2025 18:24:16 +0000 (19:24 +0100)
This patch partially enables use of the OpenMP interop construct by adding
middle end support, mostly in the omplower pass, and in the target-independent
part of the libgomp runtime. It follows up on previous patches for C, C++ and
Fortran front ends support. The full interop feature requires another patch to
enable foreign runtime support in libgomp plugins.

gcc/ChangeLog:

* builtin-types.def
(BT_FN_VOID_INT_INT_PTR_PTR_PTR_INT_PTR_INT_PTR_UINT_PTR): New.
* gimple-low.cc (lower_stmt): Handle GIMPLE_OMP_INTEROP.
* gimple-pretty-print.cc (dump_gimple_omp_interop): New function.
(pp_gimple_stmt_1): Handle GIMPLE_OMP_INTEROP.
* gimple.cc (gimple_build_omp_interop): New function.
(gimple_copy): Handle GIMPLE_OMP_INTEROP.
* gimple.def (GIMPLE_OMP_INTEROP): Define.
* gimple.h (gimple_build_omp_interop): Declare.
(gimple_omp_interop_clauses): New function.
(gimple_omp_interop_clauses_ptr): Likewise.
(gimple_omp_interop_set_clauses): Likewise.
(gimple_return_set_retval): Handle GIMPLE_OMP_INTEROP.
* gimplify.cc (gimplify_scan_omp_clauses): Handle OMP_CLAUSE_INIT,
OMP_CLAUSE_USE and OMP_CLAUSE_DESTROY.
(gimplify_omp_interop): New function.
(gimplify_expr): Replace sorry with call to gimplify_omp_interop.
* omp-builtins.def (BUILT_IN_GOMP_INTEROP): Define.
* omp-low.cc (scan_sharing_clauses): Handle OMP_CLAUSE_INIT,
OMP_CLAUSE_USE and OMP_CLAUSE_DESTROY.
(scan_omp_1_stmt): Handle GIMPLE_OMP_INTEROP.
(lower_omp_interop_action_clauses): New function.
(lower_omp_interop): Likewise.
(lower_omp_1): Handle GIMPLE_OMP_INTEROP.

gcc/c/ChangeLog:

* c-parser.cc (c_parser_omp_clause_destroy): Make addressable.
(c_parser_omp_clause_init): Make addressable.

gcc/cp/ChangeLog:

* parser.cc (cp_parser_omp_clause_init): Make addressable.

gcc/fortran/ChangeLog:

* trans-openmp.cc (gfc_trans_omp_clauses): Make OMP_CLAUSE_DESTROY and
OMP_CLAUSE_INIT addressable.
* types.def (BT_FN_VOID_INT_INT_PTR_PTR_PTR_INT_PTR_INT_PTR_UINT_PTR):
New.

include/ChangeLog:

* gomp-constants.h (GOMP_DEVICE_DEFAULT_OMP_61, GOMP_INTEROP_TARGET,
GOMP_INTEROP_TARGETSYNC, GOMP_INTEROP_FLAG_NOWAIT): Define.

libgomp/ChangeLog:

* icv-device.c (omp_set_default_device): Check
GOMP_DEVICE_DEFAULT_OMP_61.
* libgomp-plugin.h (struct interop_obj_t): New.
(enum gomp_interop_flag): New.
(GOMP_OFFLOAD_interop): Declare.
(GOMP_OFFLOAD_get_interop_int): Declare.
(GOMP_OFFLOAD_get_interop_ptr): Declare.
(GOMP_OFFLOAD_get_interop_str): Declare.
(GOMP_OFFLOAD_get_interop_type_desc): Declare.
* libgomp.h (_LIBGOMP_OMP_LOCK_DEFINED): Define.
(struct gomp_device_descr): Add interop_func, get_interop_int_func,
get_interop_ptr_func, get_interop_str_func, get_interop_type_desc_func.
* libgomp.map: Add GOMP_interop.
* libgomp_g.h (GOMP_interop): Declare.
* target.c (resolve_device): Handle GOMP_DEVICE_DEFAULT_OMP_61.
(omp_get_interop_int): Replace stub with actual implementation.
(omp_get_interop_ptr): Likewise.
(omp_get_interop_str): Likewise.
(omp_get_interop_type_desc): Likewise.
(struct interop_data_t): Define.
(gomp_interop_internal): New function.
(GOMP_interop): Likewise.
(gomp_load_plugin_for_device): Load symbols for get_interop_int,
get_interop_ptr, get_interop_str and get_interop_type_desc.
* testsuite/libgomp.c-c++-common/interop-1.c: New test.

gcc/testsuite/ChangeLog:

* c-c++-common/gomp/interop-1.c: Remove dg-prune-output "sorry".
* c-c++-common/gomp/interop-2.c: Likewise.
* c-c++-common/gomp/interop-3.c: Likewise.
* c-c++-common/gomp/interop-4.c: Remove dg-message "not supported".
* g++.dg/gomp/interop-5.C: Likewise.
* gfortran.dg/gomp/interop-4.f90: Likewise.
* c-c++-common/gomp/interop-5.c: New test.
* gfortran.dg/gomp/interop-5.f90: New test.

Co-authored-by: Tobias Burnus <tburnus@baylibre.com>
29 files changed:
gcc/builtin-types.def
gcc/c/c-parser.cc
gcc/cp/parser.cc
gcc/fortran/trans-openmp.cc
gcc/fortran/types.def
gcc/gimple-low.cc
gcc/gimple-pretty-print.cc
gcc/gimple.cc
gcc/gimple.def
gcc/gimple.h
gcc/gimplify.cc
gcc/omp-builtins.def
gcc/omp-low.cc
gcc/testsuite/c-c++-common/gomp/interop-1.c
gcc/testsuite/c-c++-common/gomp/interop-2.c
gcc/testsuite/c-c++-common/gomp/interop-3.c
gcc/testsuite/c-c++-common/gomp/interop-4.c
gcc/testsuite/c-c++-common/gomp/interop-5.c [new file with mode: 0644]
gcc/testsuite/g++.dg/gomp/interop-5.C
gcc/testsuite/gfortran.dg/gomp/interop-4.f90
gcc/testsuite/gfortran.dg/gomp/interop-5.f90 [new file with mode: 0644]
include/gomp-constants.h
libgomp/icv-device.c
libgomp/libgomp-plugin.h
libgomp/libgomp.h
libgomp/libgomp.map
libgomp/libgomp_g.h
libgomp/target.c
libgomp/testsuite/libgomp.c-c++-common/interop-1.c [new file with mode: 0644]

index 9b7cc9939e441dda2d60e74559e609f683262d6e..9583d30dfc05768d4d73961d1ef19d04ade352b8 100644 (file)
@@ -1015,6 +1015,9 @@ DEF_FUNCTION_TYPE_11 (BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_UINT_LONG_INT_ULL_
                      BT_PTR_FN_VOID_PTR_PTR, BT_LONG, BT_LONG,
                      BT_UINT, BT_LONG, BT_INT,
                      BT_ULONGLONG, BT_ULONGLONG, BT_ULONGLONG)
+DEF_FUNCTION_TYPE_11 (BT_FN_VOID_INT_INT_PTR_PTR_PTR_INT_PTR_INT_PTR_UINT_PTR,
+                     BT_VOID, BT_INT, BT_INT, BT_PTR, BT_PTR, BT_PTR, BT_INT,
+                     BT_PTR, BT_INT, BT_PTR, BT_UINT, BT_PTR)
 
 DEF_FUNCTION_TYPE_VAR_0 (BT_FN_VOID_VAR, BT_VOID)
 DEF_FUNCTION_TYPE_VAR_0 (BT_FN_INT_VAR, BT_INT)
index d49d5c58659fed0c4ff172fb1e9f8c9072b2d1ee..cfb1f60b2378bbd987bdf9f3f7e91ad894908ddb 100644 (file)
@@ -20519,7 +20519,10 @@ c_parser_omp_clause_detach (c_parser *parser, tree list)
 static tree
 c_parser_omp_clause_destroy (c_parser *parser, tree list)
 {
-  return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_DESTROY, list);
+  tree nl = c_parser_omp_var_list_parens (parser, OMP_CLAUSE_DESTROY, list);
+  for (tree c = nl; c != list; c = OMP_CLAUSE_CHAIN (c))
+    TREE_ADDRESSABLE (OMP_CLAUSE_DECL (c)) = 1;
+  return nl;
 }
 
 /* OpenMP 5.1:
@@ -20901,6 +20904,7 @@ c_parser_omp_clause_init (c_parser *parser, tree list)
 
   for (tree c = nl; c != list; c = OMP_CLAUSE_CHAIN (c))
     {
+      TREE_ADDRESSABLE (OMP_CLAUSE_DECL (c)) = 1;
       if (target)
        OMP_CLAUSE_INIT_TARGET (c) = 1;
       if (targetsync)
index 2fb1dc5992d4e99680d44a36d3a230a52c0fb531..57a461042bf13071b9eedf13366670333843bebf 100644 (file)
@@ -43183,6 +43183,7 @@ cp_parser_omp_clause_init (cp_parser *parser, tree list)
                                            NULL, false);
   for (tree c = nl; c != list; c = OMP_CLAUSE_CHAIN (c))
     {
+      TREE_ADDRESSABLE (OMP_CLAUSE_DECL (c)) = 1;
       if (target)
        OMP_CLAUSE_INIT_TARGET (c) = 1;
       if (targetsync)
index d1c05d0f89afc99fe8497d0b2a3541d8012613c4..bf8c34172c37de66069ad9024f17b78aaf41e0c3 100644 (file)
@@ -2790,9 +2790,6 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses,
        case OMP_LIST_USE:
          clause_code = OMP_CLAUSE_USE;
          goto add_clause;
-       case OMP_LIST_DESTROY:
-         clause_code = OMP_CLAUSE_DESTROY;
-         goto add_clause;
        case OMP_LIST_INTEROP:
          clause_code = OMP_CLAUSE_INTEROP;
          goto add_clause;
@@ -2803,6 +2800,22 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses,
                                           declare_simd);
          break;
 
+       case OMP_LIST_DESTROY:
+         for (; n != NULL; n = n->next)
+           if (n->sym->attr.referenced)
+             {
+               tree t = gfc_trans_omp_variable (n->sym, declare_simd);
+               if (t != error_mark_node)
+                 {
+                   tree node
+                     = build_omp_clause (input_location, OMP_CLAUSE_DESTROY);
+                   OMP_CLAUSE_DECL (node) = t;
+                   TREE_ADDRESSABLE (OMP_CLAUSE_DECL (node)) = 1;
+                   omp_clauses = gfc_trans_add_clause (node, omp_clauses);
+                 }
+             }
+         break;
+
        case OMP_LIST_INIT:
          {
            tree pref_type = NULL_TREE;
@@ -2816,6 +2829,7 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses,
                  tree node = build_omp_clause (input_location,
                                                OMP_CLAUSE_INIT);
                  OMP_CLAUSE_DECL (node) = t;
+                 TREE_ADDRESSABLE (OMP_CLAUSE_DECL (node)) = 1;
                  if (n->u.init.target)
                    OMP_CLAUSE_INIT_TARGET (node) = 1;
                  if (n->u.init.targetsync)
index 6447cee4ae0543775356343c0d169d4f3a5f6df2..dd9b8df59bef204bde5a8668caaa2ccc18dc968b 100644 (file)
@@ -266,6 +266,9 @@ DEF_FUNCTION_TYPE_11 (BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_UINT_LONG_INT_ULL_
                      BT_PTR_FN_VOID_PTR_PTR, BT_LONG, BT_LONG,
                      BT_UINT, BT_LONG, BT_INT,
                      BT_ULONGLONG, BT_ULONGLONG, BT_ULONGLONG)
+DEF_FUNCTION_TYPE_11 (BT_FN_VOID_INT_INT_PTR_PTR_PTR_INT_PTR_INT_PTR_UINT_PTR,
+                     BT_VOID, BT_INT, BT_INT, BT_PTR, BT_PTR, BT_PTR, BT_INT,
+                     BT_PTR, BT_INT, BT_PTR, BT_UINT, BT_PTR)
 
 DEF_FUNCTION_TYPE_VAR_0 (BT_FN_VOID_VAR, BT_VOID)
 
index 26b415c91312cc9fd9e9c880694e64ea809c75e1..b612970a55ac5b73b5e05ad60369aa8492ab495c 100644 (file)
@@ -747,6 +747,7 @@ lower_stmt (gimple_stmt_iterator *gsi, struct lower_data *data)
     case GIMPLE_OMP_FOR:
     case GIMPLE_OMP_SCOPE:
     case GIMPLE_OMP_DISPATCH:
+    case GIMPLE_OMP_INTEROP:
     case GIMPLE_OMP_SECTIONS:
     case GIMPLE_OMP_SECTIONS_SWITCH:
     case GIMPLE_OMP_SECTION:
index d1531fcd6d4a5f54a4ddcd5e75ddc1160438eb3c..4e20b4cc37145a59f4e894c603f529dbe0fa08ff 100644 (file)
@@ -1755,6 +1755,25 @@ dump_gimple_omp_dispatch (pretty_printer *buffer, const gimple *gs, int spc,
     }
 }
 
+/* Dump a GIMPLE_OMP_INTEROP tuple on the pretty_printer BUFFER.  */
+
+static void
+dump_gimple_omp_interop (pretty_printer *buffer, const gimple *gs, int spc,
+                        dump_flags_t flags)
+{
+  if (flags & TDF_RAW)
+    {
+      dump_gimple_fmt (buffer, spc, flags, "%G <CLAUSES <", gs);
+      dump_omp_clauses (buffer, gimple_omp_interop_clauses (gs), spc, flags);
+      dump_gimple_fmt (buffer, spc, flags, " >");
+    }
+  else
+    {
+      pp_string (buffer, "#pragma omp interop");
+      dump_omp_clauses (buffer, gimple_omp_interop_clauses (gs), spc, flags);
+    }
+}
+
 /* Dump a GIMPLE_OMP_TARGET tuple on the pretty_printer PP.  */
 
 static void
@@ -2838,6 +2857,10 @@ pp_gimple_stmt_1 (pretty_printer *pp, const gimple *gs, int spc,
       dump_gimple_omp_dispatch(pp, gs, spc, flags);
       break;
 
+    case GIMPLE_OMP_INTEROP:
+      dump_gimple_omp_interop (pp, gs, spc, flags);
+      break;
+
     case GIMPLE_OMP_MASTER:
     case GIMPLE_OMP_SECTION:
     case GIMPLE_OMP_STRUCTURED_BLOCK:
index 9a58a3a62d01c76bdba6229be7ac5eb616da3e9d..9acfa38ba95d56bb1f80fb96cde3493d968f42e7 100644 (file)
@@ -1278,6 +1278,19 @@ gimple_build_omp_dispatch (gimple_seq body, tree clauses)
   return p;
 }
 
+/* Build a GIMPLE_OMP_INTEROP statement.
+
+   CLAUSES are any of the OMP interop construct's clauses.  */
+
+gimple *
+gimple_build_omp_interop (tree clauses)
+{
+  gimple *p = gimple_alloc (GIMPLE_OMP_INTEROP, 0);
+  gimple_omp_interop_set_clauses (p, clauses);
+
+  return p;
+}
+
 /* Build a GIMPLE_OMP_TARGET statement.
 
    BODY is the sequence of statements that will be executed.
@@ -2205,6 +2218,11 @@ gimple_copy (gimple *stmt)
          gimple_omp_dispatch_set_clauses (copy, t);
          goto copy_omp_body;
 
+       case GIMPLE_OMP_INTEROP:
+         t = unshare_expr (gimple_omp_interop_clauses (stmt));
+         gimple_omp_interop_set_clauses (copy, t);
+         break;
+
        case GIMPLE_OMP_TARGET:
          {
            gomp_target *omp_target_stmt = as_a <gomp_target *> (stmt);
index 609c7114f7722ce140c2ae5809f4156b19104862..54248a80aa64ac809de5675d896fbb0df20d0cd2 100644 (file)
@@ -355,6 +355,10 @@ DEFGSCODE(GIMPLE_OMP_SCOPE, "gimple_omp_scope", GSS_OMP_SINGLE_LAYOUT)
    CLAUSES is an OMP_CLAUSE chain holding the associated clauses.  */
 DEFGSCODE(GIMPLE_OMP_DISPATCH, "gimple_omp_dispatch", GSS_OMP_SINGLE_LAYOUT)
 
+/* GIMPLE_OMP_INTEROP <CLAUSES> represents #pragma omp interop
+   CLAUSES is an OMP_CLAUSE chain holding the associated clauses.  */
+DEFGSCODE(GIMPLE_OMP_INTEROP, "gimple_omp_interop", GSS_OMP_SINGLE_LAYOUT)
+
 /* OMP_SECTION <BODY> represents #pragma omp section.
    BODY is the sequence of statements in the section body.  */
 DEFGSCODE(GIMPLE_OMP_SECTION, "gimple_omp_section", GSS_OMP)
index ecbd54cf28d1883741fd383c7ef5a16cb6c8b382..112e5ae472d03a54d1d51c92d3c2044d94a2f074 100644 (file)
@@ -745,7 +745,8 @@ struct GTY((tag("GSS_OMP_CONTINUE")))
 };
 
 /* GIMPLE_OMP_SINGLE, GIMPLE_OMP_ORDERED, GIMPLE_OMP_TASKGROUP,
-   GIMPLE_OMP_SCAN, GIMPLE_OMP_MASKED, GIMPLE_OMP_SCOPE, GIMPLE_OMP_DISPATCH. */
+   GIMPLE_OMP_SCAN, GIMPLE_OMP_MASKED, GIMPLE_OMP_SCOPE, GIMPLE_OMP_DISPATCH,
+   GIMPLE_OMP_INTEROP. */
 
 struct GTY((tag("GSS_OMP_SINGLE_LAYOUT")))
   gimple_statement_omp_single_layout : public gimple_statement_omp
@@ -1595,6 +1596,7 @@ gimple *gimple_build_omp_section (gimple_seq);
 gimple *gimple_build_omp_structured_block (gimple_seq);
 gimple *gimple_build_omp_scope (gimple_seq, tree);
 gimple *gimple_build_omp_dispatch (gimple_seq, tree);
+gimple *gimple_build_omp_interop (tree);
 gimple *gimple_build_omp_master (gimple_seq);
 gimple *gimple_build_omp_masked (gimple_seq, tree);
 gimple *gimple_build_omp_taskgroup (gimple_seq, tree);
@@ -5468,6 +5470,34 @@ gimple_omp_dispatch_set_clauses (gimple *gs, tree clauses)
   static_cast<gimple_statement_omp_single_layout *> (gs)->clauses = clauses;
 }
 
+/* Return the clauses associated with OMP_INTEROP statement GS.  */
+
+inline tree
+gimple_omp_interop_clauses (const gimple *gs)
+{
+  GIMPLE_CHECK (gs, GIMPLE_OMP_INTEROP);
+  return static_cast<const gimple_statement_omp_single_layout *> (gs)->clauses;
+}
+
+/* Return a pointer to the clauses associated with OMP_INTEROP statement GS.  */
+
+inline tree *
+gimple_omp_interop_clauses_ptr (gimple *gs)
+{
+  GIMPLE_CHECK (gs, GIMPLE_OMP_INTEROP);
+  return &static_cast<gimple_statement_omp_single_layout *> (gs)->clauses;
+}
+
+/* Set CLAUSES to be the clauses associated with OMP interop statement
+   GS.  */
+
+inline void
+gimple_omp_interop_set_clauses (gimple *gs, tree clauses)
+{
+  GIMPLE_CHECK (gs, GIMPLE_OMP_INTEROP);
+  static_cast<gimple_statement_omp_single_layout *> (gs)->clauses = clauses;
+}
+
 /* Return the kind of the OMP_FOR statemement G.  */
 
 inline int
@@ -6802,6 +6832,7 @@ gimple_return_set_retval (greturn *gs, tree retval)
     case GIMPLE_OMP_TEAMS:                     \
     case GIMPLE_OMP_SCOPE:                     \
     case GIMPLE_OMP_DISPATCH:                  \
+    case GIMPLE_OMP_INTEROP:                   \
     case GIMPLE_OMP_SECTION:                   \
     case GIMPLE_OMP_STRUCTURED_BLOCK:          \
     case GIMPLE_OMP_MASTER:                    \
index 5bdd970f570f881db53a6921fa3d98fd0f6cd6c8..244c4ba4b63716d4ee12fa49dc86ba520f166fc6 100644 (file)
@@ -13853,6 +13853,9 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p,
        case OMP_CLAUSE_IF_PRESENT:
        case OMP_CLAUSE_FINALIZE:
        case OMP_CLAUSE_INTEROP:
+       case OMP_CLAUSE_INIT:
+       case OMP_CLAUSE_USE:
+       case OMP_CLAUSE_DESTROY:
          break;
 
        case OMP_CLAUSE_ORDER:
@@ -18480,6 +18483,21 @@ gimplify_omp_ordered (tree expr, gimple_seq body)
   return gimple_build_omp_ordered (body, OMP_ORDERED_CLAUSES (expr));
 }
 
+/* Gimplify an OMP_INTEROP statement.  */
+
+static enum gimplify_status
+gimplify_omp_interop (tree *expr_p, gimple_seq *pre_p)
+{
+  tree expr = *expr_p;
+
+  gimplify_scan_omp_clauses (&OMP_INTEROP_CLAUSES (expr), pre_p, ORT_TASK,
+                            OMP_INTEROP);
+  gimple *stmt = gimple_build_omp_interop (OMP_INTEROP_CLAUSES (expr));
+  gimplify_seq_add_stmt (pre_p, stmt);
+  *expr_p = NULL_TREE;
+  return GS_ALL_DONE;
+}
+
 /* Callback for walk_tree to find an IFN_GOMP_DISPATCH.  */
 
 static tree
@@ -19953,9 +19971,7 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
          }
 
        case OMP_INTEROP:
-         sorry_at (EXPR_LOCATION (*expr_p),
-                   "%<#pragma omp interop%> not yet supported");
-         ret = GS_ERROR;
+         ret = gimplify_omp_interop (expr_p, pre_p);
          break;
        case OMP_ATOMIC:
        case OMP_ATOMIC_READ:
index 96de7077e79011f5b483f4dd948408e20df048ed..f73fb7b9dd88782961e45727e1399a9e9546955a 100644 (file)
@@ -402,6 +402,9 @@ DEF_GOMP_BUILTIN (BUILT_IN_GOMP_DOACROSS_ULL_POST, "GOMP_doacross_ull_post",
                  BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST)
 DEF_GOMP_BUILTIN (BUILT_IN_GOMP_DOACROSS_ULL_WAIT, "GOMP_doacross_ull_wait",
                  BT_FN_VOID_ULL_VAR, ATTR_NOTHROW_LEAF_LIST)
+DEF_GOMP_BUILTIN (BUILT_IN_GOMP_INTEROP, "GOMP_interop",
+                 BT_FN_VOID_INT_INT_PTR_PTR_PTR_INT_PTR_INT_PTR_UINT_PTR,
+                 ATTR_NOTHROW_LIST)
 DEF_GOMP_BUILTIN (BUILT_IN_GOMP_PARALLEL, "GOMP_parallel",
                  BT_FN_VOID_OMPFN_PTR_UINT_UINT, ATTR_NOTHROW_LIST)
 DEF_GOMP_BUILTIN (BUILT_IN_GOMP_PARALLEL_REDUCTIONS,
index c36ae38cf8e1f412406554147b0748c5e70ac8a2..e369df6e8f103ad4880db6c910140fb8efce010e 100644 (file)
@@ -1790,6 +1790,11 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
            install_var_local (decl, ctx);
          break;
 
+       case OMP_CLAUSE_INIT:
+       case OMP_CLAUSE_USE:
+       case OMP_CLAUSE_DESTROY:
+         break;
+
        case OMP_CLAUSE__CACHE_:
        case OMP_CLAUSE_NOHOST:
        default:
@@ -1986,6 +1991,9 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
        case OMP_CLAUSE_FINALIZE:
        case OMP_CLAUSE_FILTER:
        case OMP_CLAUSE__CONDTEMP_:
+       case OMP_CLAUSE_INIT:
+       case OMP_CLAUSE_USE:
+       case OMP_CLAUSE_DESTROY:
          break;
 
        case OMP_CLAUSE__CACHE_:
@@ -4211,6 +4219,10 @@ scan_omp_1_stmt (gimple_stmt_iterator *gsi, bool *handled_ops_p,
       scan_omp (gimple_omp_body_ptr (stmt), ctx);
       break;
 
+    case GIMPLE_OMP_INTEROP:
+      ctx = new_omp_context (stmt, ctx);
+      break;
+
     case GIMPLE_OMP_SECTIONS:
       scan_omp_sections (as_a <gomp_sections *> (stmt), ctx);
       break;
@@ -14331,6 +14343,222 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx)
     }
 }
 
+/* Generate code to implement the action-clauses (destroy, init, use) of an
+   OpenMP interop construct.  */
+
+static void
+lower_omp_interop_action_clauses (gimple_seq *seq, vec<tree> &objs,
+                                 vec<tree> *interop_types = NULL,
+                                 vec<tree> *prefer_types = NULL)
+{
+  if (objs.length () == 0)
+    return;
+
+  enum omp_clause_code action = OMP_CLAUSE_CODE (objs[0]);
+  if (action == OMP_CLAUSE_INIT)
+    gcc_checking_assert (objs.length () == interop_types->length ()
+                        && objs.length () == prefer_types->length ());
+  else
+    gcc_assert (prefer_types == NULL && interop_types == NULL);
+
+  tree ret_objs = NULL_TREE, ret_interop_types = NULL_TREE,
+       ret_prefer_types = NULL_TREE;
+
+  /* Build an array of interop objects. */
+
+  tree type_obj_pref = build_array_type_nelts (ptr_type_node, objs.length ());
+  ret_objs = create_tmp_var (type_obj_pref, "interopobjs");
+
+  bool have_pref_type = false;
+  if (action == OMP_CLAUSE_INIT)
+    {
+      for (tree pref_type : prefer_types)
+       if (pref_type != NULL_TREE)
+         {
+           have_pref_type = true;
+           break;
+         }
+      tree type_tgtsync
+       = build_array_type_nelts (integer_type_node, objs.length ());
+      ret_interop_types = create_tmp_var (type_tgtsync, "tgt_tgtsync");
+      if (have_pref_type)
+       ret_prefer_types = create_tmp_var (type_obj_pref, "pref_type");
+      else
+       {
+         ret_prefer_types = null_pointer_node;
+         prefer_types->truncate (0);
+       }
+    }
+
+  for (size_t i = 0; !objs.is_empty (); i++)
+    {
+      tree offset = build_int_cst (integer_type_node, i);
+      tree init = build4 (ARRAY_REF, ptr_type_node, ret_objs, offset, NULL_TREE,
+                         NULL_TREE);
+      tree obj = OMP_CLAUSE_DECL (objs.pop ());
+      if (TREE_CODE (TREE_TYPE (obj)) == REFERENCE_TYPE)
+       obj = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (obj)), obj);
+      if (action != OMP_CLAUSE_USE
+         && TREE_CODE (TREE_TYPE (obj)) != POINTER_TYPE)
+       /* For modifying actions, we need a pointer. */
+       obj = build_fold_addr_expr (obj);
+      else if (action == OMP_CLAUSE_USE
+              && TREE_CODE (TREE_TYPE (obj)) == POINTER_TYPE)
+       /* For use action, we need the value. */
+       obj = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (obj)), obj);
+      init = build2 (MODIFY_EXPR, ptr_type_node, init,
+                    fold_convert (ptr_type_node, obj));
+      gimplify_and_add (init, seq);
+
+      if (action == OMP_CLAUSE_INIT)
+       {
+         init = build4 (ARRAY_REF, integer_type_node, ret_interop_types,
+                        offset, NULL_TREE, NULL_TREE);
+         init = build2 (MODIFY_EXPR, integer_type_node, init,
+                        interop_types->pop ());
+         gimplify_and_add (init, seq);
+
+         if (have_pref_type)
+           {
+             tree prefer_type = prefer_types->pop ();
+             tree pref = (prefer_type == NULL_TREE
+                            ? null_pointer_node
+                            : build_fold_addr_expr (prefer_type));
+             init = build4 (ARRAY_REF, ptr_type_node, ret_prefer_types, offset,
+                            NULL_TREE, NULL_TREE);
+             init = build2 (MODIFY_EXPR, ptr_type_node, init, pref);
+             gimplify_and_add (init, seq);
+           }
+       }
+    }
+  if (action == OMP_CLAUSE_INIT)
+    {
+      if (have_pref_type)
+       ret_prefer_types = build_fold_addr_expr (ret_prefer_types);
+      ret_interop_types = build_fold_addr_expr (ret_interop_types);
+    }
+  ret_objs = build_fold_addr_expr (ret_objs);
+
+  gcc_assert (objs.is_empty ()
+             && (!interop_types || interop_types->is_empty ())
+             && (!prefer_types || prefer_types->is_empty ()));
+
+  objs.safe_push (ret_objs);
+  if (action == OMP_CLAUSE_INIT)
+    {
+      interop_types->safe_push (ret_interop_types);
+      prefer_types->safe_push (ret_prefer_types);
+    }
+}
+
+/* Lower code for an OpenMP interop directive.  */
+
+static void
+lower_omp_interop (gimple_stmt_iterator *gsi_p, omp_context *ctx)
+{
+  push_gimplify_context ();
+
+  tree block = make_node (BLOCK);
+  gbind *bind = gimple_build_bind (NULL, NULL, block);
+  gimple_seq bind_body = NULL;
+
+  /* Emit call to GOMP_interop:
+      void
+      GOMP_interop (int device_num, int n_init, omp_interop_t **init,
+                   const void *target_targetsync, const void *prefer_type,
+                   int n_use, omp_interop_t *use, int n_destroy,
+                   omp_interop_t **destroy, unsigned int flags,
+                   void **depend)  */
+
+  tree flags = NULL_TREE;
+  tree depend = null_pointer_node;
+  tree device_num = NULL_TREE;
+
+  auto_vec<tree> init_objs, use_objs, destroy_objs, prefer_type,
+    target_targetsync;
+  gimple_seq dep_ilist = NULL, dep_olist = NULL;
+  tree clauses = gimple_omp_interop_clauses (gsi_stmt (*gsi_p));
+  for (tree c = clauses; c; c = OMP_CLAUSE_CHAIN (c))
+    {
+      switch (OMP_CLAUSE_CODE (c))
+       {
+       case OMP_CLAUSE_INIT:
+         {
+           init_objs.safe_push (c);
+           int target_targetsync_bits = 0;
+           if (OMP_CLAUSE_INIT_TARGET (c))
+             target_targetsync_bits |= GOMP_INTEROP_TARGET;
+           if (OMP_CLAUSE_INIT_TARGETSYNC (c))
+             target_targetsync_bits |= GOMP_INTEROP_TARGETSYNC;
+           tree t = build_int_cst (integer_type_node, target_targetsync_bits);
+           target_targetsync.safe_push (t);
+           prefer_type.safe_push (OMP_CLAUSE_INIT_PREFER_TYPE (c));
+         }
+         break;
+       case OMP_CLAUSE_USE:
+         use_objs.safe_push (c);
+         break;
+       case OMP_CLAUSE_DESTROY:
+         destroy_objs.safe_push (c);
+         break;
+       case OMP_CLAUSE_NOWAIT:
+         flags = build_int_cst (integer_type_node, GOMP_INTEROP_FLAG_NOWAIT);
+         break;
+       case OMP_CLAUSE_DEPEND:
+         {
+           tree *cp = gimple_omp_interop_clauses_ptr (gsi_stmt (*gsi_p));
+           lower_depend_clauses (cp, &dep_ilist, &dep_olist);
+           depend = OMP_CLAUSE_DECL (*cp);
+         }
+         break;
+       case OMP_CLAUSE_DEVICE:
+         device_num = OMP_CLAUSE_DEVICE_ID (c);
+         break;
+       default:
+         gcc_unreachable ();
+       }
+    }
+
+  if (flags == NULL_TREE)
+    flags = build_int_cst (integer_type_node, 0);
+
+  if (device_num == NULL_TREE)
+    device_num = build_int_cst (integer_type_node, GOMP_DEVICE_DEFAULT_OMP_61);
+
+  tree n_init = build_int_cst (integer_type_node, init_objs.length ());
+  tree n_use = build_int_cst (integer_type_node, use_objs.length ());
+  tree n_destroy = build_int_cst (integer_type_node, destroy_objs.length ());
+
+  lower_omp_interop_action_clauses (&bind_body, init_objs, &target_targetsync,
+                                   &prefer_type);
+  lower_omp_interop_action_clauses (&bind_body, use_objs);
+  lower_omp_interop_action_clauses (&bind_body, destroy_objs);
+
+  gimple_seq_add_seq (&bind_body, dep_ilist);
+  tree fn = builtin_decl_explicit (BUILT_IN_GOMP_INTEROP);
+  tree init_arg = init_objs.length () ? init_objs.pop () : null_pointer_node;
+  tree target_targetsync_arg = target_targetsync.length ()
+                                ? target_targetsync.pop ()
+                                : null_pointer_node;
+  tree prefer_type_arg
+    = prefer_type.length () ? prefer_type.pop () : null_pointer_node;
+  tree use_arg = use_objs.length () ? use_objs.pop () : null_pointer_node;
+  tree destroy_arg
+    = destroy_objs.length () ? destroy_objs.pop () : null_pointer_node;
+  gcall *call
+    = gimple_build_call (fn, 11, device_num, n_init, init_arg,
+                        target_targetsync_arg, prefer_type_arg, n_use, use_arg,
+                        n_destroy, destroy_arg, flags, depend);
+  gimple_seq_add_stmt (&bind_body, call);
+  gimple_seq_add_seq (&bind_body, dep_olist);
+
+  gsi_replace (gsi_p, bind, true);
+  gimple_bind_set_body (bind, bind_body);
+  pop_gimplify_context (bind);
+  gimple_bind_append_vars (bind, ctx->block_vars);
+  BLOCK_VARS (block) = ctx->block_vars;
+}
+
 /* Expand code for an OpenMP teams directive.  */
 
 static void
@@ -14614,6 +14842,11 @@ lower_omp_1 (gimple_stmt_iterator *gsi_p, omp_context *ctx)
       gcc_assert (ctx);
       lower_omp_dispatch (gsi_p, ctx);
       break;
+    case GIMPLE_OMP_INTEROP:
+      ctx = maybe_lookup_ctx (stmt);
+      gcc_assert (ctx);
+      lower_omp_interop (gsi_p, ctx);
+      break;
     case GIMPLE_OMP_SINGLE:
       ctx = maybe_lookup_ctx (stmt);
       gcc_assert (ctx);
index de3a4ba4b6bc10d5601e2bed120f748666f94780..d68611bfe9c7f6a7ab17d4e3a5284a9e7eb28ddf 100644 (file)
@@ -2,8 +2,6 @@
 /* { dg-additional-options "-std=c23"  { target c } } */
 /* C++11 and C23 because of 'constexpr'.  */
 
-/* { dg-prune-output "sorry, unimplemented: '#pragma omp interop' not yet supported" }  */
-
 /* The following definitions are in omp_lib, which cannot be included
    in gcc/testsuite/  */
 
index 57fd688d55fe9d1c43b122134e6c4373a62a15de..af81cc673608b13f5e7c7a7bafe7374523b78a3e 100644 (file)
@@ -2,8 +2,6 @@
 /* { dg-additional-options "-std=c23"  { target c } } */
 /* C++11 and C23 because of 'constexpr'.  */
 
-/* { dg-prune-output "sorry, unimplemented: '#pragma omp interop' not yet supported" }  */
-
 /* The following definitions are in omp_lib, which cannot be included
    in gcc/testsuite/  */
 
index 42478bf760d6500958b0c1bd3dfd9f5b5a0e3379..51d26dd179eacd1f35237d09351048e8eed26638 100644 (file)
@@ -1,5 +1,3 @@
-/* { dg-prune-output "sorry, unimplemented: '#pragma omp interop' not yet supported" }  */
-
 /* The following definitions are in omp_lib, which cannot be included
    in gcc/testsuite/  */
 
index 1f9c987108b1e48d1d5cc33e190e989362b4055e..bb0bf312d5c23cc259e92d729dada3dd59da6a16 100644 (file)
@@ -33,18 +33,18 @@ f()
   omp_interop_t obj1, obj2, obj3, obj4, obj5, obj6, obj7;
   int x[6];
 
-  #pragma omp interop init ( obj1, obj2) use (obj3) destroy(obj4) init(obj5) destroy(obj6) use(obj7)   /* { dg-message "'#pragma omp interop' not yet supported" }  */
+  #pragma omp interop init ( obj1, obj2) use (obj3) destroy(obj4) init(obj5) destroy(obj6) use(obj7)
   /* { dg-final { scan-tree-dump-times "#pragma omp interop use\\(obj7\\) destroy\\(obj6\\) init\\(obj5\\) destroy\\(obj4\\) use\\(obj3\\) init\\(obj2\\) init\\(obj1\\)\[\r\n\]" 1 "original" } }  */
 
-  #pragma omp interop nowait init (targetsync : obj1, obj2) use (obj3) destroy(obj4) init(target, targetsync : obj5) destroy(obj6) use(obj7) depend(inout: x)  /* { dg-message "'#pragma omp interop' not yet supported" }  */
+  #pragma omp interop nowait init (targetsync : obj1, obj2) use (obj3) destroy(obj4) init(target, targetsync : obj5) destroy(obj6) use(obj7) depend(inout: x)  
   /* { dg-final { scan-tree-dump-times "#pragma omp interop depend\\(inout:x\\) use\\(obj7\\) destroy\\(obj6\\) init\\(target, targetsync: obj5\\) destroy\\(obj4\\) use\\(obj3\\) init\\(targetsync: obj2\\) init\\(targetsync: obj1\\) nowait\[\r\n\]" 1 "original" } }  */
 
-  #pragma omp interop init ( obj1, obj2) init (target: obj3) init(targetsync : obj4) init(target,targetsync: obj5)  /* { dg-message "'#pragma omp interop' not yet supported" }  */
+  #pragma omp interop init ( obj1, obj2) init (target: obj3) init(targetsync : obj4) init(target,targetsync: obj5)  
   /* { dg-final { scan-tree-dump-times "#pragma omp interop init\\(target, targetsync: obj5\\) init\\(targetsync: obj4\\) init\\(target: obj3\\) init\\(obj2\\) init\\(obj1\\)\[\r\n\]" 1 "original" } }  */
 
   /* --------------------------------------------  */
 
-  #pragma omp interop init (target, prefer_type(omp_ifr_cuda, omp_ifr_cuda+1, "hsa", "myPrivateInterop", omp_ifr_cuda-2) : obj1, obj2) init (target: obj3) init(prefer_type(omp_ifr_hip, "sycl", omp_ifr_opencl), targetsync : obj4, obj7) init(target,prefer_type("level_zero", omp_ifr_level_zero+0),targetsync: obj5)  /* { dg-message "'#pragma omp interop' not yet supported" }  */
+  #pragma omp interop init (target, prefer_type(omp_ifr_cuda, omp_ifr_cuda+1, "hsa", "myPrivateInterop", omp_ifr_cuda-2) : obj1, obj2) init (target: obj3) init(prefer_type(omp_ifr_hip, "sycl", omp_ifr_opencl), targetsync : obj4, obj7) init(target,prefer_type("level_zero", omp_ifr_level_zero+0),targetsync: obj5)  
   /*
      { dg-warning "unknown foreign runtime identifier 'myPrivateInterop' \\\[-Wopenmp\\\]" "" { target *-*-* } .-2 }
      { dg-warning "unknown foreign runtime identifier '-1' \\\[-Wopenmp\\\]" "" { target *-*-* } .-3 }
@@ -55,7 +55,7 @@ f()
 
 /* -------------------------------------------- */
 
-  #pragma omp interop init ( target, prefer_type( {fr("hip"), attr("ompx_gnu_prio:1", "ompx_gnu_debug")}, {attr("ompx_gnu_nicest"), attr("ompx_something")}) : obj1, obj2) init ( prefer_type( {fr("cuda")}, {fr(omp_ifr_cuda_driver), attr("ompx_nix")}, {fr("best")}), targetsync : obj3, obj4) nowait use(obj5)  /* { dg-message "'#pragma omp interop' not yet supported" }  */
+  #pragma omp interop init ( target, prefer_type( {fr("hip"), attr("ompx_gnu_prio:1", "ompx_gnu_debug")}, {attr("ompx_gnu_nicest"), attr("ompx_something")}) : obj1, obj2) init ( prefer_type( {fr("cuda")}, {fr(omp_ifr_cuda_driver), attr("ompx_nix")}, {fr("best")}), targetsync : obj3, obj4) nowait use(obj5)  
   /*
      { dg-warning "unknown foreign runtime identifier 'best' \\\[-Wopenmp\\\]" "" { target *-*-* } .-2 }
 
@@ -69,7 +69,7 @@ g (int *y)
 {
   omp_interop_t io1, io2, io3, io4, io5;
 
-  [[omp::directive (interop,init(prefer_type({fr("level_zero")}, {fr(omp_ifr_sycl),attr("ompx_in_order"),attr("ompx_queue:in_order")}), targetsync : io1, io2),use(io3),destroy(io4,io5),depend(inout:y),nowait)]];  /* { dg-message "'#pragma omp interop' not yet supported" }  */
+  [[omp::directive (interop,init(prefer_type({fr("level_zero")}, {fr(omp_ifr_sycl),attr("ompx_in_order"),attr("ompx_queue:in_order")}), targetsync : io1, io2),use(io3),destroy(io4,io5),depend(inout:y),nowait)]];  
 
   /* { dg-final { scan-tree-dump-times "#pragma omp interop nowait depend\\(inout:y\\) destroy\\(io5\\) destroy\\(io4\\) use\\(io3\\) init\\(prefer_type\\(\{fr\\(\"level_zero\"\\)\}, \{fr\\(\"sycl\"\\),attr\\(\"ompx_in_order\"\\),attr\\(\"ompx_queue:in_order\"\\)\}\\), targetsync: io2\\) init\\(prefer_type\\(\{fr\\(\"level_zero\"\\)\}, \{fr\\(\"sycl\"\\),attr\\(\"ompx_in_order\"\\),attr\\(\"ompx_queue:in_order\"\\)\}\\), targetsync: io1\\)\[\r\n\]" 1 "original" } }  */
 }
diff --git a/gcc/testsuite/c-c++-common/gomp/interop-5.c b/gcc/testsuite/c-c++-common/gomp/interop-5.c
new file mode 100644 (file)
index 0000000..0b9bd09
--- /dev/null
@@ -0,0 +1,68 @@
+/* { dg-additional-options "-fdump-tree-omplower" }  */
+
+/* The following definitions are in omp_lib, which cannot be included
+   in gcc/testsuite/  */
+
+#if __cplusplus >= 201103L
+# define __GOMP_UINTPTR_T_ENUM : __UINTPTR_TYPE__
+#else
+# define __GOMP_UINTPTR_T_ENUM
+#endif
+
+typedef enum omp_interop_t __GOMP_UINTPTR_T_ENUM
+{
+  omp_interop_none = 0,
+  __omp_interop_t_max__ = __UINTPTR_MAX__
+} omp_interop_t;
+
+typedef enum omp_interop_fr_t
+{
+  omp_ifr_cuda = 1,
+  omp_ifr_cuda_driver = 2,
+  omp_ifr_opencl = 3,
+  omp_ifr_sycl = 4,
+  omp_ifr_hip = 5,
+  omp_ifr_level_zero = 6,
+  omp_ifr_hsa = 7,
+  omp_ifr_last = omp_ifr_hsa
+} omp_interop_fr_t;
+
+void
+f()
+{
+  omp_interop_t obj1, obj2, obj3, obj4, obj5, obj6, obj7;
+  int x[6];
+
+  #pragma omp interop init (targetsync: obj1, obj2) use (obj3) destroy(obj4) init(target: obj5) destroy(obj6) use(obj7)   
+  /* { dg-final { scan-tree-dump-times "void \\* interopobjs\.\[0-9\]+.3.;\[\r\n\ ]*int tgt_tgtsync\\.\[0-9\]+.3.;\[\r\n\ ]*void \\* interopobjs\\.\[0-9\]+.2.;\[\r\n\ ]*omp_interop_t obj3\\.\[0-9\]+;\[\r\n\ ]*void \\* obj3\\.\[0-9\]+;\[\r\n\ ]*omp_interop_t obj7\\.\[0-9\]+;\[\r\n\ ]*void \\* obj7\\.\[0-9\]+;\[\r\n\ ]*void \\* interopobjs\\.\[0-9\]+.2.;\[\r\n\ ]*interopobjs\.\[0-9\]+.0. = &obj1;\[\r\n \]*tgt_tgtsync\.\[0-9\]+.0. = 2;\[\r\n \]*interopobjs\.\[0-9\]+.1. = &obj2;\[\r\n \]*tgt_tgtsync\.\[0-9\]+.1. = 2;\[\r\n \]*interopobjs\.\[0-9\]+.2. = &obj5;\[\r\n \]*tgt_tgtsync\.\[0-9\]+.2. = 1;\[\r\n \]*obj3\.\[0-9\]+ = obj3;\[\r\n \]*obj3\.\[0-9\]+ = \\(void \\*\\) obj3\.\[0-9\]+;\[\r\n \]*interopobjs\.\[0-9\]+.0. = obj3\.\[0-9\]+;\[\r\n \]*obj7\.\[0-9\]+ = obj7;\[\r\n \]*obj7\.\[0-9\]+ = \\(void \\*\\) obj7\.\[0-9\]+;\[\r\n \]*interopobjs\.\[0-9\]+.1. = obj7\.\[0-9\]+;\[\r\n \]*interopobjs\.\[0-9\]+.0. = &obj4;\[\r\n \]*interopobjs\.\[0-9\]+.1. = &obj6;\[\r\n \]*__builtin_GOMP_interop \\(-5, 3, &interopobjs\.\[0-9\]+, &tgt_tgtsync\.\[0-9\]+, 0B, 2, &interopobjs\.\[0-9\]+, 2, &interopobjs\.\[0-9\]+, 0, 0B\\);" 1 "omplower" { target c } } }  */
+  /* { dg-final { scan-tree-dump-times "void \\* interopobjs\.\[0-9\]+.3.;\[\r\n\ ]*int tgt_tgtsync\\.\[0-9\]+.3.;\[\r\n\ ]*void \\* interopobjs\\.\[0-9\]+.2.;\[\r\n\ ]*omp_interop_t obj3\\.\[0-9\]+;\[\r\n\ ]*void \\* obj3\\.\[0-9\]+;\[\r\n\ ]*omp_interop_t obj7\\.\[0-9\]+;\[\r\n\ ]*void \\* obj7\\.\[0-9\]+;\[\r\n\ ]*void \\* interopobjs\\.\[0-9\]+.2.;\[\r\n\ ]*omp_interop_t obj6\\.\[0-9\]+;\[\r\n\ ]*interopobjs\.\[0-9\]+.0. = &obj1;\[\r\n \]*tgt_tgtsync\.\[0-9\]+.0. = 2;\[\r\n \]*interopobjs\.\[0-9\]+.1. = &obj2;\[\r\n \]*tgt_tgtsync\.\[0-9\]+.1. = 2;\[\r\n \]*interopobjs\.\[0-9\]+.2. = &obj5;\[\r\n \]*tgt_tgtsync\.\[0-9\]+.2. = 1;\[\r\n \]*obj3\.\[0-9\]+ = obj3;\[\r\n \]*obj3\.\[0-9\]+ = \\(void \\*\\) obj3\.\[0-9\]+;\[\r\n \]*interopobjs\.\[0-9\]+.0. = obj3\.\[0-9\]+;\[\r\n \]*obj7\.\[0-9\]+ = obj7;\[\r\n \]*obj7\.\[0-9\]+ = \\(void \\*\\) obj7\.\[0-9\]+;\[\r\n \]*interopobjs\.\[0-9\]+.1. = obj7\.\[0-9\]+;\[\r\n \]*interopobjs\.\[0-9\]+.0. = &obj4;\[\r\n \]*obj6\.\[0-9\]+ = obj6;\[\r\n \]*interopobjs\.\[0-9\]+.1. = &obj6\.\[0-9\]+;\[\r\n \]*__builtin_GOMP_interop \\(-5, 3, &interopobjs\.\[0-9\]+, &tgt_tgtsync\.\[0-9\]+, 0B, 2, &interopobjs\.\[0-9\]+, 2, &interopobjs\.\[0-9\]+, 0, 0B\\);" 1 "omplower" { target c++ } } }  */
+
+  #pragma omp interop nowait init (targetsync : obj1, obj2) use (obj3) destroy(obj4) init(target, targetsync : obj5) destroy(obj6) use(obj7) depend(inout: x)  
+  /* { dg-final { scan-tree-dump-times "void \\* D\\.\[0-9\]+.3.;\[\r\n\ ]*void \\* interopobjs\\.\[0-9\]+.3.;\[\r\n\ ]*int tgt_tgtsync\\.\[0-9\]+.3.;\[\r\n\ ]*void \\* interopobjs\\.\[0-9\]+.2.;\[\r\n\ ]*omp_interop_t obj3\\.\[0-9\]+;\[\r\n\ ]*void \\* obj3\\.\[0-9\]+;\[\r\n\ ]*omp_interop_t obj7\\.\[0-9\]+;\[\r\n\ ]*void \\* obj7\\.\[0-9\]+;\[\r\n\ ]*void \\* interopobjs\\.\[0-9\]+.2.;\[\r\n\ ]*interopobjs\.\[0-9\]+.0. = &obj1;\[\r\n\ ]*tgt_tgtsync\.\[0-9\]+.0. = 2;\[\r\n\ ]*interopobjs\.\[0-9\]+.1. = &obj2;\[\r\n\ ]*tgt_tgtsync\.\[0-9\]+.1. = 2;\[\r\n\ ]*interopobjs\.\[0-9\]+.2. = &obj5;\[\r\n\ ]*tgt_tgtsync\.\[0-9\]+.2. = 3;\[\r\n\ ]*obj3\.\[0-9\]+ = obj3;\[\r\n\ ]*obj3\.\[0-9\]+ = \\(void \\*\\) obj3\.\[0-9\]+;\[\r\n\ ]*interopobjs\.\[0-9\]+.0. = obj3\.\[0-9\]+;\[\r\n\ ]*obj7\.\[0-9\]+ = obj7;\[\r\n\ ]*obj7\.\[0-9\]+ = \\(void \\*\\) obj7\.\[0-9\]+;\[\r\n\ ]*interopobjs\.\[0-9\]+.1. = obj7\.\[0-9\]+;\[\r\n\ ]*interopobjs\.\[0-9\]+.0. = &obj4;\[\r\n\ ]*interopobjs\.\[0-9\]+.1. = &obj6;\[\r\n\ ]*D\.\[0-9\]+.0. = 1B;\[\r\n\ ]*D\.\[0-9\]+.1. = 1B;\[\r\n\ ]*D\.\[0-9\]+.2. = &x;\[\r\n\ ]*__builtin_GOMP_interop \\(-5, 3, &interopobjs\.\[0-9\]+, &tgt_tgtsync\.\[0-9\]+, 0B, 2, &interopobjs\.\[0-9\]+, 2, &interopobjs\.\[0-9\]+, 1, &D\.\[0-9\]+\\);" 1 "omplower" { target c } } }  */
+  /* { dg-final { scan-tree-dump-times "void \\* D\\.\[0-9\]+.3.;\[\r\n\ ]*void \\* interopobjs\\.\[0-9\]+.3.;\[\r\n\ ]*int tgt_tgtsync\\.\[0-9\]+.3.;\[\r\n\ ]*void \\* interopobjs\\.\[0-9\]+.2.;\[\r\n\ ]*omp_interop_t obj3\\.\[0-9\]+;\[\r\n\ ]*void \\* obj3\\.\[0-9\]+;\[\r\n\ ]*omp_interop_t obj7\\.\[0-9\]+;\[\r\n\ ]*void \\* obj7\\.\[0-9\]+;\[\r\n\ ]*void \\* interopobjs\\.\[0-9\]+.2.;\[\r\n\ ]*omp_interop_t obj6\\.\[0-9\]+;\[\r\n\ ]*interopobjs\.\[0-9\]+.0. = &obj1;\[\r\n\ ]*tgt_tgtsync\.\[0-9\]+.0. = 2;\[\r\n\ ]*interopobjs\.\[0-9\]+.1. = &obj2;\[\r\n\ ]*tgt_tgtsync\.\[0-9\]+.1. = 2;\[\r\n\ ]*interopobjs\.\[0-9\]+.2. = &obj5;\[\r\n\ ]*tgt_tgtsync\.\[0-9\]+.2. = 3;\[\r\n\ ]*obj3\.\[0-9\]+ = obj3;\[\r\n\ ]*obj3\.\[0-9\]+ = \\(void \\*\\) obj3\.\[0-9\]+;\[\r\n\ ]*interopobjs\.\[0-9\]+.0. = obj3\.\[0-9\]+;\[\r\n\ ]*obj7\.\[0-9\]+ = obj7;\[\r\n\ ]*obj7\.\[0-9\]+ = \\(void \\*\\) obj7\.\[0-9\]+;\[\r\n\ ]*interopobjs\.\[0-9\]+.1. = obj7\.\[0-9\]+;\[\r\n\ ]*interopobjs\.\[0-9\]+.0. = &obj4;\[\r\n\ ]*obj6\.\[0-9\]+ = obj6;\[\r\n\ ]*interopobjs\.\[0-9\]+.1. = &obj6\.\[0-9\]+;\[\r\n\ ]*D\.\[0-9\]+.0. = 1B;\[\r\n\ ]*D\.\[0-9\]+.1. = 1B;\[\r\n\ ]*D\.\[0-9\]+.2. = &x;\[\r\n\ ]*__builtin_GOMP_interop \\(-5, 3, &interopobjs\.\[0-9\]+, &tgt_tgtsync\.\[0-9\]+, 0B, 2, &interopobjs\.\[0-9\]+, 2, &interopobjs\.\[0-9\]+, 1, &D\.\[0-9\]+\\);" 1 "omplower" { target c++ } } }  */
+
+  #pragma omp interop init (target: obj1, obj2) init (target: obj3) init(targetsync : obj4) init(target,targetsync: obj5)  
+  /* { dg-final { scan-tree-dump-times "void \\* interopobjs\\.\[0-9\]+.5.;\[\r\n\ ]*int tgt_tgtsync\\.\[0-9\]+.5.;\[\r\n\ ]*interopobjs\.\[0-9\]+.0. = &obj1;\[\r\n \]*tgt_tgtsync\.\[0-9\]+.0. = 1;\[\r\n \]*interopobjs\.\[0-9\]+.1. = &obj2;\[\r\n \]*tgt_tgtsync\.\[0-9\]+.1. = 1;\[\r\n \]*interopobjs\.\[0-9\]+.2. = &obj3;\[\r\n \]*tgt_tgtsync\.\[0-9\]+.2. = 1;\[\r\n \]*interopobjs\.\[0-9\]+.3. = &obj4;\[\r\n \]*tgt_tgtsync\.\[0-9\]+.3. = 2;\[\r\n \]*interopobjs\.\[0-9\]+.4. = &obj5;\[\r\n \]*tgt_tgtsync\.\[0-9\]+.4. = 3;\[\r\n\ ]*__builtin_GOMP_interop \\(-5, 5, &interopobjs\.\[0-9\]+, &tgt_tgtsync\.\[0-9\]+, 0B, 0, 0B, 0, 0B, 0, 0B\\);" 1 "omplower" } }  */
+
+  /* --------------------------------------------  */
+
+  #pragma omp interop init (target, prefer_type(omp_ifr_cuda, omp_ifr_cuda+1, "hsa") : obj1, obj2) init (target: obj3) init(prefer_type(omp_ifr_hip, "sycl", omp_ifr_opencl), targetsync : obj4, obj7) init(target,prefer_type("level_zero", omp_ifr_level_zero+0),targetsync: obj5)  
+  /* { dg-final { scan-tree-dump-times "void \\* interopobjs\\.\[0-9\]+.6.;\[\r\n\ ]*int tgt_tgtsync\\.\[0-9\]+.6.;\[\r\n\ ]*void \\* pref_type\.\[0-9\]+.6.;\[\r\n\ ]*interopobjs\.\[0-9\]+.0. = &obj1;\[\r\n \]*tgt_tgtsync\.\[0-9\]+.0. = 1;\[\r\n \]*pref_type\.\[0-9\]+.0. = .*;\[\r\n \]*interopobjs\.\[0-9\]+.1. = &obj2;\[\r\n \]*tgt_tgtsync\.\[0-9\]+.1. = 1;\[\r\n \]*pref_type\.\[0-9\]+.1. = .*;\[\r\n \]*interopobjs\.\[0-9\]+.2. = &obj3;\[\r\n \]*tgt_tgtsync\.\[0-9\]+.2. = 1;\[\r\n \]*pref_type\.\[0-9\]+.2. = 0B;\[\r\n \]*interopobjs\.\[0-9\]+.3. = &obj4;\[\r\n \]*tgt_tgtsync\.\[0-9\]+.3. = 2;\[\r\n \]*pref_type\.\[0-9\]+.3. = .*;\[\r\n \]*interopobjs\.\[0-9\]+.4. = &obj7;\[\r\n \]*tgt_tgtsync\.\[0-9\]+.4. = 2;\[\r\n \]*pref_type\.\[0-9\]+.4. = .*;\[\r\n \]*interopobjs\.\[0-9\]+.5. = &obj5;\[\r\n \]*tgt_tgtsync\.\[0-9\]+.5. = 3;\[\r\n \]*pref_type\.\[0-9\]+.5. = .*;\[\r\n\ ]*__builtin_GOMP_interop \\(-5, 6, &interopobjs\.\[0-9\]+, &tgt_tgtsync\.\[0-9\]+, &pref_type\.\[0-9\]+, 0, 0B, 0, 0B, 0, 0B\\);" 1 "omplower" } }  */
+
+
+  /* -------------------------------------------- */
+
+  #pragma omp interop init ( target, prefer_type( {fr("hip"), attr("ompx_gnu_prio:1", "ompx_gnu_debug")}, {attr("ompx_gnu_nicest"), attr("ompx_something")}) : obj1) destroy(obj3) nowait use(obj5)
+  /* { dg-final { scan-tree-dump-times "void \\* interopobjs\\.\[0-9\]+.1.;\[\r\n\ ]*int tgt_tgtsync\\.\[0-9\]+.1.;\[\r\n\ ]*void \\* pref_type\.\[0-9\]+.1.;\[\r\n\ ]*void \\* interopobjs\.\[0-9\]+.1.;\[\r\n\ ]*omp_interop_t obj5\.\[0-9\]+;\[\r\n\ ]*void \\* obj5\.\[0-9\]+;\[\r\n\ ]*void \\* interopobjs\.\[0-9\]+.1.;\[\r\n\ ]*interopobjs\.\[0-9\]+.0. = &obj1;\[\r\n\ ]*tgt_tgtsync\.\[0-9\]+.0. = 1;\[\r\n\ ]*pref_type\.\[0-9\]+.0. = .*;\[\r\n\ ]*obj5\.\[0-9\]+ = obj5;\[\r\n\ ]*obj5\.\[0-9\]+ = \\(void \\*\\) obj5\.\[0-9\]+;\[\r\n\ ]*interopobjs\.\[0-9\]+.0. = obj5\.\[0-9\]+;\[\r\n\ ]*interopobjs\.\[0-9\]+.0. = &obj3;\[\r\n\ ]*__builtin_GOMP_interop \\(-5, 1, &interopobjs\.\[0-9\]+, &tgt_tgtsync\.\[0-9\]+, &pref_type\.\[0-9\]+, 1, &interopobjs\.\[0-9\]+, 1, &interopobjs\.\[0-9\]+, 1, 0B\\);" 1 "omplower" } }  */
+
+}
+
+void
+g (int *y)
+{
+  omp_interop_t io1, io2, io3, io4, io5;
+
+  [[omp::directive (interop,init(prefer_type({fr("level_zero")}, {fr(omp_ifr_sycl),attr("ompx_in_order"),attr("ompx_queue:in_order")}), targetsync : io1, io2),use(io3),destroy(io4,io5),depend(inout:y),nowait)]];  
+  /* { dg-final { scan-tree-dump-times "void \\* D\.\[0-9\]+.3.;\[\r\n\ ]*void \\* interopobjs\.\[0-9\]+.2.;\[\r\n\ ]*int tgt_tgtsync\.\[0-9\]+.2.;\[\r\n\ ]*void \\* pref_type\.\[0-9\]+.2.;\[\r\n\ ]*void \\* interopobjs\.\[0-9\]+.1.;\[\r\n\ ]*void \\* io3\.\[0-9\]+;\[\r\n\ ]*void \\* interopobjs\.\[0-9\]+.2.;\[\r\n\ ]*interopobjs\.\[0-9\]+.0. = &io1;\[\r\n\ ]*tgt_tgtsync\.\[0-9\]+.0. = 2;\[\r\n\ ]*pref_type\.\[0-9\]+.0. = .*;\[\r\n\ ]*interopobjs\.\[0-9\]+.1. = &io2;\[\r\n\ ]*tgt_tgtsync\.\[0-9\]+.1. = 2;\[\r\n\ ]*pref_type\.\[0-9\]+.1. = .*;\[\r\n\ ]*io3\.\[0-9\]+ = \\(void \\*\\) io3;\[\r\n\ ]*interopobjs\.\[0-9\]+.0. = io3\.\[0-9\]+;\[\r\n\ ]*interopobjs\.\[0-9\]+.0. = &io4;\[\r\n\ ]*interopobjs\.\[0-9\]+.1. = &io5;\[\r\n\ ]*D\.\[0-9\]+.0. = 1B;\[\r\n\ ]*D\.\[0-9\]+.1. = 1B;\[\r\n\ ]*D\.\[0-9\]+.2. = &y;\[\r\n\ ]*__builtin_GOMP_interop \\(-5, 2, &interopobjs\.\[0-9\]+, &tgt_tgtsync\.\[0-9\]+, &pref_type\.\[0-9\]+, 1, &interopobjs\.\[0-9\]+, 2, &interopobjs\.\[0-9\]+, 1, &D\.\[0-9\]+\\);" 1 "omplower" { target c } } }  */
+  /* { dg-final { scan-tree-dump-times "void \\* D\.\[0-9\]+.3.;\[\r\n\ ]*void \\* interopobjs\.\[0-9\]+.2.;\[\r\n\ ]*int tgt_tgtsync\.\[0-9\]+.2.;\[\r\n\ ]*void \\* pref_type\.\[0-9\]+.2.;\[\r\n\ ]*void \\* interopobjs\.\[0-9\]+.1.;\[\r\n\ ]*void \\* io3\.\[0-9\]+;\[\r\n\ ]*void \\* interopobjs\.\[0-9\]+.2.;\[\r\n\ ]*omp_interop_t io4\.\[0-9\]+;\[\r\n\ ]*omp_interop_t io5\.\[0-9\]+;\[\r\n\ ]*interopobjs\.\[0-9\]+.0. = &io1;\[\r\n\ ]*tgt_tgtsync\.\[0-9\]+.0. = 2;\[\r\n\ ]*pref_type\.\[0-9\]+.0. = .*;\[\r\n\ ]*interopobjs\.\[0-9\]+.1. = &io2;\[\r\n\ ]*tgt_tgtsync\.\[0-9\]+.1. = 2;\[\r\n\ ]*pref_type\.\[0-9\]+.1. = .*;\[\r\n\ ]*io3\.\[0-9\]+ = \\(void \\*\\) io3;\[\r\n\ ]*interopobjs\.\[0-9\]+.0. = io3\.\[0-9\]+;\[\r\n\ ]*io4\.\[0-9\]+ = io4;\[\r\n\ ]*interopobjs\.\[0-9\]+.0. = &io4\.\[0-9\]+;\[\r\n\ ]*io5\.\[0-9\]+ = io5;\[\r\n\ ]*interopobjs\.\[0-9\]+.1. = &io5\.\[0-9\]+;\[\r\n\ ]*D\.\[0-9\]+.0. = 1B;\[\r\n\ ]*D\.\[0-9\]+.1. = 1B;\[\r\n\ ]*D\.\[0-9\]+.2. = &y;\[\r\n\ ]*__builtin_GOMP_interop \\(-5, 2, &interopobjs\.\[0-9\]+, &tgt_tgtsync\.\[0-9\]+, &pref_type\.\[0-9\]+, 1, &interopobjs\.\[0-9\]+, 2, &interopobjs\.\[0-9\]+, 1, &D\.\[0-9\]+\\);" 1 "omplower" { target c++ } } }  */
+}
index 5109dc4e427105004b5c486920d1b1d6d0c0ac08..89396cf54379d90be3c1256f6bfe92d20822a89f 100644 (file)
@@ -1,8 +1,6 @@
 /* { dg-do compile { target c++11 } } */
 /* { dg-additional-options "-fdump-tree-original" }  */
 
-/* { dg-prune-output "sorry, unimplemented: '#pragma omp interop' not yet supported" }  */
-
 /* The following definitions are in omp_lib, which cannot be included
    in gcc/testsuite/  */
 
@@ -43,13 +41,13 @@ f ()
   constexpr T3 ifr_level_zero = (T3) (omp_ifr_sycl + 2);
   constexpr T3 ifr_invalid = (T3) 99;
 
-  #pragma omp interop init ( obj1, obj2) use (obj3) destroy(obj4) init(obj5) destroy(obj6) use(obj7)   /* { dg-message "'#pragma omp interop' not yet supported" }  */
+  #pragma omp interop init ( obj1, obj2) use (obj3) destroy(obj4) init(obj5) destroy(obj6) use(obj7)   
   /* { dg-final { scan-tree-dump-times "#pragma omp interop use\\(obj7\\) destroy\\(obj6\\) init\\(obj5\\) destroy\\(obj4\\) use\\(obj3\\) init\\(obj2\\) init\\(obj1\\)\[\r\n\]" 2 "original" } }  */
 
-  #pragma omp interop nowait init (targetsync : obj1, obj2) use (obj3) destroy(obj4) init(target, targetsync : obj5) destroy(obj6) use(obj7) depend(inout: x)  /* { dg-message "'#pragma omp interop' not yet supported" }  */
+  #pragma omp interop nowait init (targetsync : obj1, obj2) use (obj3) destroy(obj4) init(target, targetsync : obj5) destroy(obj6) use(obj7) depend(inout: x)  
   /* { dg-final { scan-tree-dump-times "#pragma omp interop depend\\(inout:x\\) use\\(obj7\\) destroy\\(obj6\\) init\\(target, targetsync: obj5\\) destroy\\(obj4\\) use\\(obj3\\) init\\(targetsync: obj2\\) init\\(targetsync: obj1\\) nowait\[\r\n\]" 2 "original" } }  */
 
-  #pragma omp interop init ( obj1, obj2) init (target: obj3) init(targetsync : obj4) init(target,targetsync: obj5)  /* { dg-message "'#pragma omp interop' not yet supported" }  */
+  #pragma omp interop init ( obj1, obj2) init (target: obj3) init(targetsync : obj4) init(target,targetsync: obj5)  
   /* { dg-final { scan-tree-dump-times "#pragma omp interop init\\(target, targetsync: obj5\\) init\\(targetsync: obj4\\) init\\(target: obj3\\) init\\(obj2\\) init\\(obj1\\)\[\r\n\]" 2 "original" } }  */
 
   /* --------------------------------------------  */
@@ -64,7 +62,7 @@ f ()
      { dg-final { scan-tree-dump-times "#pragma omp interop init\\(prefer_type\\(\{fr\\(\"<unknown>\"\\)\}, \{fr\\(\"<unknown>\"\\)\}, \{fr\\(\"cuda\"\\)\}, \{fr\\(\"cuda_driver\"\\)\}, \{fr\\(\"hsa\"\\)\}, \{fr\\(\"<unknown>\"\\)\}, \{fr\\(\"<unknown>\"\\)\}\\), target: obj2\\) init\\(prefer_type\\(\{fr\\(\"<unknown>\"\\)\}, \{fr\\(\"<unknown>\"\\)\}, \{fr\\(\"cuda\"\\)\}, \{fr\\(\"cuda_driver\"\\)\}, \{fr\\(\"hsa\"\\)\}, \{fr\\(\"<unknown>\"\\)\}, \{fr\\(\"<unknown>\"\\)\}\\), target: obj1\\)\[\r\n\]" 2 "original" } }
   */
 
-  #pragma omp interop init (target, prefer_type(ifr_cuda, ifr_cuda+1, "hsa", "myPrivateInterop", ifr_cuda-2) : obj1, obj2) init (target: obj3) init(prefer_type(ifr_hip, "sycl", ifr_opencl), targetsync : obj4, obj7) init(target,prefer_type("level_zero", ifr_level_zero+0),targetsync: obj5)  /* { dg-message "'#pragma omp interop' not yet supported" }  */
+  #pragma omp interop init (target, prefer_type(ifr_cuda, ifr_cuda+1, "hsa", "myPrivateInterop", ifr_cuda-2) : obj1, obj2) init (target: obj3) init(prefer_type(ifr_hip, "sycl", ifr_opencl), targetsync : obj4, obj7) init(target,prefer_type("level_zero", ifr_level_zero+0),targetsync: obj5)  
   /*
      { dg-warning "unknown foreign runtime identifier 'myPrivateInterop' \\\[-Wopenmp\\\]" "" { target *-*-* } .-2 }
      { dg-warning "unknown foreign runtime identifier '-1' \\\[-Wopenmp\\\]" "" { target *-*-* } .-3 }
@@ -74,7 +72,7 @@ f ()
 
 /* -------------------------------------------- */
 
-  #pragma omp interop init ( target, prefer_type( {fr("hip"), attr("ompx_gnu_prio:1", "ompx_gnu_debug")}, {attr("ompx_gnu_nicest"), attr("ompx_something")}) : obj1, obj2) init ( prefer_type( {fr("cuda")}, {fr(ifr_cuda_driver), attr("ompx_nix")}, {fr("best")}), targetsync : obj3, obj4) nowait use(obj5)  /* { dg-message "'#pragma omp interop' not yet supported" }  */
+  #pragma omp interop init ( target, prefer_type( {fr("hip"), attr("ompx_gnu_prio:1", "ompx_gnu_debug")}, {attr("ompx_gnu_nicest"), attr("ompx_something")}) : obj1, obj2) init ( prefer_type( {fr("cuda")}, {fr(ifr_cuda_driver), attr("ompx_nix")}, {fr("best")}), targetsync : obj3, obj4) nowait use(obj5)  
   /*
      { dg-warning "unknown foreign runtime identifier 'best' \\\[-Wopenmp\\\]" "" { target *-*-* } .-2 }
 
index 8783f4cfb5fd521d931f16d4abf113b45fcfeef4..43c28d696689607ac58b4bfea30378a01bb0e27f 100644 (file)
@@ -26,18 +26,18 @@ implicit none
 integer(omp_interop_kind) :: obj1, obj2, obj3, obj4, obj5, obj6, obj7
 integer :: x(6)
 
-!$omp interop init ( obj1, obj2) use (obj3) destroy(obj4) init(obj5) destroy(obj6) use(obj7) ! { dg-message "'#pragma omp interop' not yet supported" }
+!$omp interop init ( obj1, obj2) use (obj3) destroy(obj4) init(obj5) destroy(obj6) use(obj7) 
 ! { dg-final { scan-tree-dump-times "#pragma omp interop init\\(obj1\\) init\\(obj2\\) init\\(obj5\\) use\\(obj3\\) use\\(obj7\\) destroy\\(obj4\\) destroy\\(obj6\\)\[\r\n\]" 1 "original" } }
 
-!$omp interop nowait init (targetsync : obj1, obj2) use (obj3) destroy(obj4) init(target, targetsync : obj5) destroy(obj6) use(obj7) depend(inout: x) ! { dg-message "'#pragma omp interop' not yet supported" }
+!$omp interop nowait init (targetsync : obj1, obj2) use (obj3) destroy(obj4) init(target, targetsync : obj5) destroy(obj6) use(obj7) depend(inout: x) 
 ! { dg-final { scan-tree-dump-times "#pragma omp interop depend\\(inout:x\\) init\\(targetsync: obj1\\) init\\(targetsync: obj2\\) init\\(target, targetsync: obj5\\) use\\(obj3\\) use\\(obj7\\) destroy\\(obj4\\) destroy\\(obj6\\) nowait\[\r\n\]" 1 "original" } }
 
-!$omp interop init ( obj1, obj2) init (target: obj3) init(targetsync : obj4) init(target,targetsync: obj5)  ! { dg-message "'#pragma omp interop' not yet supported" }
+!$omp interop init ( obj1, obj2) init (target: obj3) init(targetsync : obj4) init(target,targetsync: obj5)  
 ! { dg-final { scan-tree-dump-times "#pragma omp interop init\\(obj1\\) init\\(obj2\\) init\\(target: obj3\\) init\\(targetsync: obj4\\) init\\(target, targetsync: obj5\\)\[\r\n\]" 1 "original" } }
 
 ! --------------------------------------------
 
-!$omp interop init (target, prefer_type(omp_ifr_cuda, omp_ifr_cuda+1, "hsa", "myPrivateInterop", omp_ifr_cuda-2) : obj1, obj2) init (target: obj3) init(prefer_type(omp_ifr_hip, "sycl", omp_ifr_opencl), targetsync : obj4, obj7) init(target,prefer_type("level_zero", omp_ifr_level_zero+0),targetsync: obj5)  ! { dg-message "'#pragma omp interop' not yet supported" }
+!$omp interop init (target, prefer_type(omp_ifr_cuda, omp_ifr_cuda+1, "hsa", "myPrivateInterop", omp_ifr_cuda-2) : obj1, obj2) init (target: obj3) init(prefer_type(omp_ifr_hip, "sycl", omp_ifr_opencl), targetsync : obj4, obj7) init(target,prefer_type("level_zero", omp_ifr_level_zero+0),targetsync: obj5)  
 !
 ! { dg-warning "Unknown foreign runtime identifier 'myPrivateInterop' at \\(1\\) \\\[-Wopenmp\\\]" "" { target *-*-* } .-2 }
 ! { dg-warning "Unknown foreign runtime identifier '-1' at \\(1\\) \\\[-Wopenmp\\\]" "" { target *-*-* } .-3 }
@@ -47,7 +47,7 @@ integer :: x(6)
 
 ! --------------------------------------------
 
-!$omp interop init ( target, prefer_type( {fr(1_"hip"), attr("ompx_gnu_prio:1", 1_"ompx_gnu_debug")}, {attr("ompx_gnu_nicest"), attr("ompx_something")}) : obj1, obj2) init ( prefer_type( {fr("cuda")}, {fr(omp_ifr_cuda_driver), attr("ompx_nix")}, {fr("best")}), targetsync : obj3, obj4) nowait use(obj5)    ! { dg-message "'#pragma omp interop' not yet supported" }
+!$omp interop init ( target, prefer_type( {fr(1_"hip"), attr("ompx_gnu_prio:1", 1_"ompx_gnu_debug")}, {attr("ompx_gnu_nicest"), attr("ompx_something")}) : obj1, obj2) init ( prefer_type( {fr("cuda")}, {fr(omp_ifr_cuda_driver), attr("ompx_nix")}, {fr("best")}), targetsync : obj3, obj4) nowait use(obj5)    
 !
 ! ! { dg-warning "Unknown foreign runtime identifier 'best' at \\(1\\) \\\[-Wopenmp\\\]" "" { target *-*-* } .-2 }
 !
diff --git a/gcc/testsuite/gfortran.dg/gomp/interop-5.f90 b/gcc/testsuite/gfortran.dg/gomp/interop-5.f90
new file mode 100644 (file)
index 0000000..a6a2d71
--- /dev/null
@@ -0,0 +1,21 @@
+! { dg-additional-options "-fdump-tree-omplower" }
+
+subroutine sub1 (a1, a2, a3, a4)
+   use omp_lib, only: omp_interop_kind
+   integer(omp_interop_kind) :: a1  ! by ref
+   integer(omp_interop_kind), optional :: a2 ! as pointer
+   integer(omp_interop_kind), allocatable :: a3 ! ref to pointer
+   integer(omp_interop_kind), value :: a4
+   integer(omp_interop_kind) :: b
+
+   !$omp interop init(target : a1, a2, a3, a4, b)
+   ! { dg-final { scan-tree-dump-times "void \\* interopobjs\.\[0-9\]+\\\[5\\\];\[\r\n ]*integer\\(kind=4\\) tgt_tgtsync\.\[0-9\]+\\\[5\\\];\[\r\n ]*integer\\(kind=8\\) \\* & a3\.\[0-9\]+;\[\r\n ]*integer\\(kind=8\\) \\* D\.\[0-9\]+;\[\r\n ]*integer\\(kind=8\\) \\* a2\.\[0-9\]+;\[\r\n ]*integer\\(kind=8\\) & a1\.\[0-9\]+;\[\r\n ]*interopobjs\.\[0-9\]+\\\[0\\\] = &b;\[\r\n ]*tgt_tgtsync\.\[0-9\]+\\\[0\\\] = 1;\[\r\n ]*interopobjs\.\[0-9\]+\\\[1\\\] = &a4;\[\r\n ]*tgt_tgtsync\.\[0-9\]+\\\[1\\\] = 1;\[\r\n ]*a3\.\[0-9\]+ = a3;\[\r\n ]*D\.\[0-9\]+ = \\*a3\.\[0-9\]+;\[\r\n ]*interopobjs\.\[0-9\]+\\\[2\\\] = D\.\[0-9\]+;\[\r\n ]*tgt_tgtsync\.\[0-9\]+\\\[2\\\] = 1;\[\r\n ]*a2\.\[0-9\]+ = a2;\[\r\n ]*interopobjs\.\[0-9\]+\\\[3\\\] = a2\.\[0-9\]+;\[\r\n ]*tgt_tgtsync\.\[0-9\]+\\\[3\\\] = 1;\[\r\n ]*a1\.\[0-9\]+ = a1;\[\r\n ]*interopobjs\.\[0-9\]+\\\[4\\\] = a1\.\[0-9\]+;\[\r\n ]*tgt_tgtsync\.\[0-9\]+\\\[4\\\] = 1;\[\r\n ]*__builtin_GOMP_interop \\(-5, 5, &interopobjs\.\[0-9\]+, &tgt_tgtsync\.\[0-9\]+, 0B, 0, 0B, 0, 0B, 0, 0B\\);" 1 "omplower" } }
+
+   !$omp interop use(a1, a2, a3, a4, b)
+   ! { dg-final { scan-tree-dump-times "void \\* interopobjs\.\[0-9\]+\\\[5\\\];\[\r\n ]*integer\\(kind=8\\) b\.\[0-9\]+;\[\r\n ]*void \\* b\.\[0-9\]+;\[\r\n ]*integer\\(kind=8\\) a4\.\[0-9\]+;\[\r\n ]*void \\* a4\.\[0-9\]+;\[\r\n ]*integer\\(kind=8\\) \\* & a3\.\[0-9\]+;\[\r\n ]*integer\\(kind=8\\) \\* D\.\[0-9\]+;\[\r\n ]*integer\\(kind=8\\) D\.\[0-9\]+;\[\r\n ]*void \\* D\.\[0-9\]+;\[\r\n ]*integer\\(kind=8\\) \\* a2\.\[0-9\]+;\[\r\n ]*integer\\(kind=8\\) D\.\[0-9\]+;\[\r\n ]*void \\* D\.\[0-9\]+;\[\r\n ]*integer\\(kind=8\\) & a1\.\[0-9\]+;\[\r\n ]*integer\\(kind=8\\) D\.\[0-9\]+;\[\r\n ]*void \\* D\.\[0-9\]+;\[\r\n ]*b\.\[0-9\]+ = b;\[\r\n ]*b\.\[0-9\]+ = \\(void \\*\\) b\.\[0-9\]+;\[\r\n ]*interopobjs\.\[0-9\]+\\\[0\\\] = b\.\[0-9\]+;\[\r\n ]*a4\.\[0-9\]+ = a4;\[\r\n ]*a4\.\[0-9\]+ = \\(void \\*\\) a4\.\[0-9\]+;\[\r\n ]*interopobjs\.\[0-9\]+\\\[1\\\] = a4\.\[0-9\]+;\[\r\n ]*a3\.\[0-9\]+ = a3;\[\r\n ]*D\.\[0-9\]+ = \\*a3\.\[0-9\]+;\[\r\n ]*D\.\[0-9\]+ = \\*D\.\[0-9\]+;\[\r\n ]*D\.\[0-9\]+ = \\(void \\*\\) D\.\[0-9\]+;\[\r\n ]*interopobjs\.\[0-9\]+\\\[2\\\] = D\.\[0-9\]+;\[\r\n ]*a2\.\[0-9\]+ = a2;\[\r\n ]*D\.\[0-9\]+ = \\*a2\.\[0-9\]+;\[\r\n ]*D\.\[0-9\]+ = \\(void \\*\\) D\.\[0-9\]+;\[\r\n ]*interopobjs\.\[0-9\]+\\\[3\\\] = D\.\[0-9\]+;\[\r\n ]*a1\.\[0-9\]+ = a1;\[\r\n ]*D\.\[0-9\]+ = \\*a1\.\[0-9\]+;\[\r\n ]*D\.\[0-9\]+ = \\(void \\*\\) D\.\[0-9\]+;\[\r\n ]*interopobjs\.\[0-9\]+\\\[4\\\] = D\.\[0-9\]+;\[\r\n ]*__builtin_GOMP_interop \\(-5, 0, 0B, 0B, 0B, 5, &interopobjs\.\[0-9\]+, 0, 0B, 0, 0B\\);" 1 "omplower" } }
+
+   !$omp interop destroy(a1, a2, a3, a4, b)
+   ! { dg-final { scan-tree-dump-times "void \\* interopobjs\.\[0-9\]+\\\[5\\\];\[\r\n ]*integer\\(kind=8\\) \\* & a3\.\[0-9\]+;\[\r\n ]*integer\\(kind=8\\) \\* D\.\[0-9\]+;\[\r\n ]*integer\\(kind=8\\) \\* a2\.\[0-9\]+;\[\r\n ]*integer\\(kind=8\\) & a1\.\[0-9\]+;\[\r\n ]*interopobjs\.\[0-9\]+\\\[0\\\] = &b;\[\r\n ]*interopobjs\.\[0-9\]+\\\[1\\\] = &a4;\[\r\n ]*a3\.\[0-9\]+ = a3;\[\r\n ]*D\.\[0-9\]+ = \\*a3\.\[0-9\]+;\[\r\n ]*interopobjs\.\[0-9\]+\\\[2\\\] = D\.\[0-9\]+;\[\r\n ]*a2\.\[0-9\]+ = a2;\[\r\n ]*interopobjs\.\[0-9\]+\\\[3\\\] = a2\.\[0-9\]+;\[\r\n ]*a1\.\[0-9\]+ = a1;\[\r\n ]*interopobjs\.\[0-9\]+\\\[4\\\] = a1\.\[0-9\]+;\[\r\n ]*__builtin_GOMP_interop \\(-5, 0, 0B, 0B, 0B, 0, 0B, 5, &interopobjs\.\[0-9\]+, 0, 0B\\);" 1 "omplower" } }
+end subroutine
+
+
index ccf61ca0ae0fcae6ab9d0cdbe2d9218b3f6083c4..7d6b85f62731de9ac5dc4a92ec8752d1be158791 100644 (file)
@@ -280,10 +280,14 @@ enum gomp_map_kind
    omp_invalid_device) to -3 (so that for dev_num >= -2U we can
    subtract 1).  -4 is then what we use for omp_invalid_device,
    which unlike the other non-conforming device numbers results
-   in fatal error regardless of OMP_TARGET_OFFLOAD.  */
+   in fatal error regardless of OMP_TARGET_OFFLOAD.
+   Furthermore, OpenMP 6.1 exposes the default device to the user; hence,
+   GOMP_DEVICE_DEFAULT_OMP_61 can be used for it,
+   with and without remapped device numbers.  */
 #define GOMP_DEVICE_ICV                        -1
 #define GOMP_DEVICE_HOST_FALLBACK      -2
 #define GOMP_DEVICE_INVALID            -4
+#define GOMP_DEVICE_DEFAULT_OMP_61     -5
 
 /* GOMP_task/GOMP_taskloop* flags argument.  */
 #define GOMP_TASK_FLAG_UNTIED          (1 << 0)
@@ -406,6 +410,13 @@ enum gomp_map_kind
 #define GOMP_INTEROP_IFR_SEPARATOR ((char)(-__INT8_MAX__-1))
 #define GOMP_INTEROP_IFR_UNKNOWN ((char)(-__INT8_MAX__))
 
+/* GOMP_interop target_targetsync argument.  */
+#define GOMP_INTEROP_TARGET    (1 << 0)
+#define GOMP_INTEROP_TARGETSYNC        (1 << 1)
+
+/* GOMP_interop flags argument.  */
+#define GOMP_INTEROP_FLAG_NOWAIT       (1 << 0)
+
 /* HSA specific data structures.  */
 
 /* Identifiers of device-specific target arguments.  */
index ba06f50a7c01d30ce8672c29d62055383b7c9276..40bf7cd658a05eff2e750ddba9ed272444a2b380 100644 (file)
 void
 omp_set_default_device (int device_num)
 {
-  struct gomp_task_icv *icv = gomp_icv (true);
-  icv->default_device_var = device_num;
+  if (device_num != GOMP_DEVICE_DEFAULT_OMP_61)
+    {
+      struct gomp_task_icv *icv = gomp_icv (true);
+      icv->default_device_var = device_num;
+    }
 }
 
 ialias (omp_set_default_device)
index 62bf43da937384cdb3c80666d849b8dcfce7b321..924fc1f44b1ac8f6c36a8d36715d945d6677f030 100644 (file)
 #include <stddef.h>
 #include <stdint.h>
 
+#ifdef _LIBGOMP_PLUGIN_INCLUDE
+  /* Include 'omp.h' for the interop definitions.  */
+  #define _LIBGOMP_OMP_LOCK_DEFINED 1
+  typedef struct omp_lock_t omp_lock_t;
+  typedef struct omp_nest_lock_t omp_nest_lock_t;
+  #include "omp.h.in"
+#endif
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -101,6 +109,25 @@ struct addr_pair
   uintptr_t end;
 };
 
+
+#ifdef _LIBGOMP_OMP_LOCK_DEFINED
+/* Only define when omp.h.in was included, as in plugin/ and in libgomp.h.   */
+struct interop_obj_t
+{
+  void *stream;
+  void *device_data;
+  omp_interop_fr_t fr;
+  int device_num;
+};
+
+enum gomp_interop_flag
+{
+  gomp_interop_flag_init,
+  gomp_interop_flag_use,
+  gomp_interop_flag_destroy
+};
+#endif
+
 /* This following symbol is used to name the target side variable struct that
    holds the designated ICVs of the target device. The symbol needs to be
    available to libgomp code and the offload plugin (which in the latter case
@@ -181,6 +208,23 @@ extern int GOMP_OFFLOAD_openacc_cuda_set_stream (struct goacc_asyncqueue *,
 extern union goacc_property_value
   GOMP_OFFLOAD_openacc_get_property (int, enum goacc_property);
 
+#ifdef _LIBGOMP_OMP_LOCK_DEFINED
+/* Only define when omp.h.in was included, as in plugin/ and in libgomp.h.   */
+extern void GOMP_OFFLOAD_interop (struct interop_obj_t *, int,
+                                 enum gomp_interop_flag, bool, const char *);
+extern intptr_t GOMP_OFFLOAD_get_interop_int (struct interop_obj_t *,
+                                             omp_interop_property_t,
+                                             omp_interop_rc_t *);
+extern void *GOMP_OFFLOAD_get_interop_ptr (struct interop_obj_t *,
+                                          omp_interop_property_t,
+                                          omp_interop_rc_t *);
+extern const char *GOMP_OFFLOAD_get_interop_str (struct interop_obj_t *obj,
+                                                omp_interop_property_t,
+                                                omp_interop_rc_t *);
+extern const char *GOMP_OFFLOAD_get_interop_type_desc (struct interop_obj_t *,
+                                                      omp_interop_property_t);
+#endif
+
 #ifdef __cplusplus
 }
 #endif
index 44ad980eed74d2d9685c373769238684d2923d48..d97768f5125dca08e9dc69282c3ea2c3cf9424de 100644 (file)
 
 #include "config.h"
 #include <stdint.h>
+
+/* Include omp.h by parts.  */
+#include "omp-lock.h"
+#define _LIBGOMP_OMP_LOCK_DEFINED 1
+#include "omp.h.in"
+
 #include "libgomp-plugin.h"
+
 #include "gomp-constants.h"
 
 #ifdef HAVE_PTHREAD_H
@@ -1419,6 +1426,11 @@ struct gomp_device_descr
   __typeof (GOMP_OFFLOAD_can_run) *can_run_func;
   __typeof (GOMP_OFFLOAD_run) *run_func;
   __typeof (GOMP_OFFLOAD_async_run) *async_run_func;
+  __typeof (GOMP_OFFLOAD_interop) *interop_func;
+  __typeof (GOMP_OFFLOAD_get_interop_int) *get_interop_int_func;
+  __typeof (GOMP_OFFLOAD_get_interop_ptr) *get_interop_ptr_func;
+  __typeof (GOMP_OFFLOAD_get_interop_str) *get_interop_str_func;
+  __typeof (GOMP_OFFLOAD_get_interop_type_desc) *get_interop_type_desc_func;
 
   /* Splay tree containing information about mapped memory regions.  */
   struct splay_tree_s mem_map;
@@ -1501,11 +1513,6 @@ gomp_work_share_init_done (void)
 /* Now that we're back to default visibility, include the globals.  */
 #include "libgomp_g.h"
 
-/* Include omp.h by parts.  */
-#include "omp-lock.h"
-#define _LIBGOMP_OMP_LOCK_DEFINED 1
-#include "omp.h.in"
-
 #if !defined (HAVE_ATTRIBUTE_VISIBILITY) \
     || !defined (HAVE_ATTRIBUTE_ALIAS) \
     || !defined (HAVE_AS_SYMVER_DIRECTIVE) \
index 4530b3adc94e76706f80511b6228154d0155bfcd..eae2f53bab1f31d63aaf9ab66bf35d2c978ae097 100644 (file)
@@ -430,6 +430,7 @@ GOMP_5.1.2 {
 
 GOMP_5.1.3 {
   global:
+       GOMP_interop;
        omp_get_num_interop_properties;
        omp_get_interop_int;
        omp_get_interop_ptr;
index eed800b5cc9bd76268c8fb3efbc448c33c3984ec..8993ec610fbe16f8357d049ee592b93a60a5d0db 100644 (file)
@@ -358,6 +358,10 @@ extern void GOMP_target_enter_exit_data (int, size_t, void **, size_t *,
 extern void GOMP_teams (unsigned int, unsigned int);
 extern bool GOMP_teams4 (unsigned int, unsigned int, unsigned int, bool);
 extern void *GOMP_target_map_indirect_ptr (void *);
+struct interop_obj_t;
+extern void GOMP_interop (int, int, struct interop_obj_t ***, const int *,
+                         const char **, int, struct interop_obj_t **, int,
+                         struct interop_obj_t ***, unsigned, void **);
 
 /* teams.c */
 
index dbc4535b96f33ad97af2ba745e77b3b7c7090461..36ed797b0a9604c4fa20883dbe8ed22bedf71ea9 100644 (file)
@@ -146,7 +146,8 @@ resolve_device (int device_id, bool remapped)
      called, which must be done before using default_device_var.  */
   int num_devices = gomp_get_num_devices ();
 
-  if (remapped && device_id == GOMP_DEVICE_ICV)
+  if ((remapped && device_id == GOMP_DEVICE_ICV)
+      || device_id == GOMP_DEVICE_DEFAULT_OMP_61)
     {
       struct gomp_task_icv *icv = gomp_icv (false);
       device_id = icv->default_device_var;
@@ -5136,45 +5137,78 @@ omp_get_num_interop_properties (const omp_interop_t interop
 }
 
 omp_intptr_t
-omp_get_interop_int (const omp_interop_t interop __attribute__ ((unused)),
+omp_get_interop_int (const omp_interop_t interop,
                     omp_interop_property_t property_id,
                     omp_interop_rc_t *ret_code)
 {
-  if (ret_code == NULL)
-    return 0;
+  struct interop_obj_t *obj = (struct interop_obj_t *) interop;
+  struct gomp_device_descr *devicep;
+
   if (property_id < omp_ipr_first || property_id >= 0)
-    *ret_code = omp_irc_out_of_range;
-  else
-    *ret_code = omp_irc_empty;  /* Assume omp_interop_none.  */
-  return 0;
+    {
+      if (ret_code)
+       *ret_code = omp_irc_out_of_range;
+      return 0;
+    }
+  if (obj == NULL
+      || (devicep = resolve_device (obj->device_num, false)) == NULL
+      || devicep->get_interop_int_func == NULL)
+    {
+      if (ret_code)
+       *ret_code = omp_irc_empty;  /* Assume omp_interop_none.  */
+      return 0;
+    }
+  return devicep->get_interop_int_func (obj, property_id, ret_code);
 }
 
 void *
-omp_get_interop_ptr (const omp_interop_t interop __attribute__ ((unused)),
+omp_get_interop_ptr (const omp_interop_t interop,
                     omp_interop_property_t property_id,
                     omp_interop_rc_t *ret_code)
 {
-  if (ret_code == NULL)
-    return NULL;
+  struct interop_obj_t *obj = (struct interop_obj_t *) interop;
+  struct gomp_device_descr *devicep;
+
   if (property_id < omp_ipr_first || property_id >= 0)
-    *ret_code = omp_irc_out_of_range;
-  else
-    *ret_code = omp_irc_empty;  /* Assume omp_interop_none.  */
-  return NULL;
+    {
+      if (ret_code)
+       *ret_code = omp_irc_out_of_range;
+      return 0;
+    }
+  if (obj == NULL
+      || (devicep = resolve_device (obj->device_num, false)) == NULL
+      || devicep->get_interop_int_func == NULL)
+    {
+      if (ret_code)
+       *ret_code = omp_irc_empty;  /* Assume omp_interop_none.  */
+      return 0;
+    }
+  return devicep->get_interop_ptr_func (obj, property_id, ret_code);
 }
 
 const char *
-omp_get_interop_str (const omp_interop_t interop __attribute__ ((unused)),
+omp_get_interop_str (const omp_interop_t interop,
                     omp_interop_property_t property_id,
                     omp_interop_rc_t *ret_code)
 {
-  if (ret_code == NULL)
-    return NULL;
+  struct interop_obj_t *obj = (struct interop_obj_t *) interop;
+  struct gomp_device_descr *devicep;
+
   if (property_id < omp_ipr_first || property_id >= 0)
-    *ret_code = omp_irc_out_of_range;
-  else
-    *ret_code = omp_irc_empty;  /* Assume omp_interop_none.  */
-  return NULL;
+    {
+      if (ret_code)
+       *ret_code = omp_irc_out_of_range;
+      return 0;
+    }
+  if (obj == NULL
+      || (devicep = resolve_device (obj->device_num, false)) == NULL
+      || devicep->get_interop_int_func == NULL)
+    {
+      if (ret_code)
+       *ret_code = omp_irc_empty;  /* Assume omp_interop_none.  */
+      return 0;
+    }
+  return devicep->get_interop_str_func (obj, property_id, ret_code);
 }
 
 const char *
@@ -5194,18 +5228,24 @@ omp_get_interop_type_desc (const omp_interop_t interop,
                           omp_interop_property_t property_id)
 {
   static const char *desc[omp_ipr_fr_id - omp_ipr_device_num + 1]
-    = {"omp_interop_t",        /* fr_id */
-       "const char*",  /* fr_name */
+    = {"omp_interop_t", /* fr_id */
+       "const char *", /* fr_name */
        "int",          /* vendor */
        "const char *", /* vendor_name */
        "int"};         /* device_num */
+
+  struct interop_obj_t *obj = (struct interop_obj_t *) interop;
+  struct gomp_device_descr *devicep;
+
   if (property_id > omp_ipr_fr_id || property_id < omp_ipr_first)
     return NULL;
-  if (interop == omp_interop_none)
+  if (obj == NULL
+      || (devicep = resolve_device (obj->device_num, false)) == NULL
+      || devicep->get_interop_int_func == NULL)
     return NULL;
   if (property_id >= omp_ipr_device_num)
     return desc[omp_ipr_fr_id - property_id];
-  return NULL;  /* FIXME: Call plugin.  */
+  return devicep->get_interop_type_desc_func (obj, property_id);
 }
 
 const char *
@@ -5236,6 +5276,119 @@ ialias (omp_get_interop_name)
 ialias (omp_get_interop_type_desc)
 ialias (omp_get_interop_rc_desc)
 
+struct interop_data_t
+{
+  int device_num, n_init, n_use, n_destroy;
+  struct interop_obj_t ***init;
+  struct interop_obj_t **use;
+  struct interop_obj_t ***destroy;
+  const int *target_targetsync;
+  const char **prefer_type;
+};
+
+static void
+gomp_interop_internal (void *data)
+{
+  struct interop_data_t *args = (struct interop_data_t *) data;
+  struct gomp_device_descr *devicep;
+
+  /* Destroy objects to free resources.  */
+  for (int i = 0; i < args->n_destroy; i++)
+    {
+      struct interop_obj_t **obj = args->destroy[i];
+      if (*obj == NULL /* omp_interop_none */)
+       continue;
+      devicep = resolve_device ((*obj)->device_num, false);
+      if (devicep != NULL && devicep->interop_func)
+       devicep->interop_func (*obj, devicep->target_id,
+                              gomp_interop_flag_destroy, false, NULL);
+      free (*obj);
+      *obj = NULL;
+    }
+
+  /* Init streams next to give 'use' more time for completion.  */
+  if (args->n_init)
+    {
+      devicep = resolve_device (args->device_num, false);
+      for (int i = 0; i < args->n_init; i++)
+       {
+         struct interop_obj_t **obj = args->init[i];
+         bool targetsync
+           = (args->target_targetsync[i] & GOMP_INTEROP_TARGETSYNC);
+         const char *prefer_type
+           = (args->prefer_type ? args->prefer_type[i] : NULL);
+         if (devicep == NULL || !devicep->interop_func)
+           {
+             *obj = NULL;
+             continue;
+           }
+         *obj =
+           (struct interop_obj_t *) calloc (1, sizeof (struct interop_obj_t));
+         devicep->interop_func (*obj, devicep->target_id,
+                                gomp_interop_flag_init, targetsync,
+                                prefer_type);
+       }
+    }
+
+  for (int i = 0; i < args->n_use; i++)
+    {
+      struct interop_obj_t *obj = args->use[i];
+      if (obj == NULL)
+       continue;
+      devicep = resolve_device (obj->device_num, false);
+      if (devicep != NULL && devicep->interop_func)
+       devicep->interop_func (obj, devicep->target_id,
+                              gomp_interop_flag_use, false, NULL);
+    }
+}
+
+/* Process the OpenMP interop directive. 'init' and 'destroy' take an array
+   of 'omp_interop_t *', 'use' an array of 'omp_interop_t', where
+   'omp_interop_t' is internally 'struct interop_obj_t *';
+   'flags' is used for the 'nowait' clause.  */
+
+void
+GOMP_interop (int device_num, int n_init, struct interop_obj_t ***init,
+             const int *target_targetsync, const char **prefer_type, int n_use,
+             struct interop_obj_t **use, int n_destroy,
+             struct interop_obj_t ***destroy, unsigned int flags,
+             void **depend)
+{
+  struct interop_data_t args;
+  args.device_num = device_num;
+  args.n_init = n_init;
+  args.n_use = n_use;
+  args.n_destroy = n_destroy;
+  args.init = init;
+  args.target_targetsync = target_targetsync;
+  args.prefer_type = prefer_type;
+  args.use = use;
+  args.destroy = destroy;
+
+  /* No need to create a task for 'init' as that should be fast. */
+  bool use_task = false;
+  if (flags & GOMP_INTEROP_FLAG_NOWAIT)
+    {
+      for (int i = 0; i < n_use && !use_task; i++)
+       if (args.use[i])
+         use_task |= args.use[i]->stream != NULL;
+      for (int i = 0; i < n_destroy && !use_task; i++)
+       if (*args.destroy[i])
+         use_task |= (*args.destroy[i])->stream != NULL;
+    }
+
+  if (use_task)
+    GOMP_task (gomp_interop_internal, &args, NULL, sizeof (args),
+              __alignof__ (args), true, depend ? GOMP_TASK_FLAG_DEPEND : 0,
+              depend, 0, NULL);
+  else
+    {
+      gomp_interop_internal (&args);
+      if (depend)
+       GOMP_taskwait_depend (depend);
+    }
+}
+
 static const char *
 gomp_get_uid_for_device (struct gomp_device_descr *devicep, int device_num)
 {
@@ -5344,6 +5497,14 @@ gomp_load_plugin_for_device (struct gomp_device_descr *device,
   DLSYM (host2dev);
   DLSYM_OPT (memcpy2d, memcpy2d);
   DLSYM_OPT (memcpy3d, memcpy3d);
+  if (DLSYM_OPT (interop, interop))
+    {
+      DLSYM (get_interop_int);
+      DLSYM (get_interop_ptr);
+      DLSYM (get_interop_str);
+      DLSYM (get_interop_type_desc);
+    }
+
   device->capabilities = device->get_caps_func ();
   if (device->capabilities & GOMP_OFFLOAD_CAP_OPENMP_400)
     {
diff --git a/libgomp/testsuite/libgomp.c-c++-common/interop-1.c b/libgomp/testsuite/libgomp.c-c++-common/interop-1.c
new file mode 100644 (file)
index 0000000..149f387
--- /dev/null
@@ -0,0 +1,43 @@
+/* { dg-do run } */
+
+#include <omp.h>
+#include <stdlib.h>
+
+int
+main ()
+{
+  int dev = omp_get_num_devices ();
+  int x[6];
+  omp_interop_t obj1 = omp_interop_none;
+#pragma omp interop init(targetsync : obj1) depend(in : x) device(dev)
+  if (obj1 != omp_interop_none)
+    abort ();
+
+#pragma omp interop use(obj1)
+#pragma omp interop destroy(obj1) depend(out : x)
+  if (obj1 != omp_interop_none)
+    abort ();
+
+  omp_set_default_device (dev);
+  omp_interop_t obj2;
+
+#pragma omp interop init(                                                      \
+    target, targetsync,                                                        \
+      prefer_type({fr("hip"), attr("ompx_gnu_prio:1", "ompx_gnu_debug")},      \
+                   {attr("ompx_gnu_nicest"), attr("ompx_something")}) : obj1, \
+      obj2) nowait
+  if (obj1 != omp_interop_none || obj2 != omp_interop_none)
+    abort ();
+#pragma omp interop use(obj1, obj2) nowait
+
+  omp_interop_t obj3 = __omp_interop_t_max__;
+
+#pragma omp interop init(target : obj3) use(obj2) destroy(obj1) nowait
+  if (obj1 != omp_interop_none || obj3 != omp_interop_none)
+    abort ();
+#pragma omp interop destroy(obj3, obj2) nowait
+  if (obj2 != omp_interop_none || obj3 != omp_interop_none)
+    abort ();
+
+  return 0;
+}