]> 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)
committerTobias Burnus <tburnus@baylibre.com>
Fri, 21 Mar 2025 23:28:19 +0000 (00:28 +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>
(cherry picked from commit 99e2906ae255fc7b8edb008d7cd47b28b078a809)

36 files changed:
gcc/ChangeLog.omp
gcc/builtin-types.def
gcc/c/ChangeLog.omp
gcc/c/c-parser.cc
gcc/cp/ChangeLog.omp
gcc/cp/parser.cc
gcc/fortran/ChangeLog.omp
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/ChangeLog.omp
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/ChangeLog.omp
include/gomp-constants.h
libgomp/ChangeLog.omp
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 31e79a89e884a118d2117e6c7cd3b5292f41526b..2f931af7425c9ddb7afb0a17727bcacaf5282a16 100644 (file)
@@ -1,3 +1,34 @@
+2025-03-21  Paul-Antoine Arras  <parras@baylibre.com>
+
+       Backported from master:
+       2025-03-21  Paul-Antoine Arras  <parras@baylibre.com>
+                   Tobias Burnus  <tburnus@baylibre.com>
+
+       * 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.
+
 2025-03-19  Thomas Schwinge  <tschwinge@baylibre.com>
 
        Backported from trunk:
index 9ddc0ed338206102ad944f5d0b269fe88d855f4c..dac540521ef832e19e3693332dca85e9b65d7179 100644 (file)
@@ -990,6 +990,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 33b2c5b9f0d42e95d34e71fcc9a98c338635ef40..03a05cb7bbe20775c2e6ea7eaf7fd8da031c62e3 100644 (file)
@@ -1,3 +1,12 @@
+2025-03-21  Paul-Antoine Arras  <parras@baylibre.com>
+
+       Backported from master:
+       2025-03-21  Paul-Antoine Arras  <parras@baylibre.com>
+                   Tobias Burnus  <tburnus@baylibre.com>
+
+       * c-parser.cc (c_parser_omp_clause_destroy): Make addressable.
+       (c_parser_omp_clause_init): Make addressable.
+
 2025-03-18  Sandra Loosemore  <sloosemore@baylibre.com>
 
        Backported from master:
index f79131a5274f1c59bf7ae7d2c080f452df2ced70..5e3eab71b7df10d869a648f29c8d37a5db04a4fe 100644 (file)
@@ -20240,7 +20240,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:
@@ -20621,6 +20624,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 b8cfd32482ca80da8154664bfaf1ddeb7b72a67d..bf08763e2183852b82e046637d1b3f9ac82d463b 100644 (file)
@@ -1,3 +1,11 @@
+2025-03-21  Paul-Antoine Arras  <parras@baylibre.com>
+
+       Backported from master:
+       2025-03-21  Paul-Antoine Arras  <parras@baylibre.com>
+                   Tobias Burnus  <tburnus@baylibre.com>
+
+       * parser.cc (cp_parser_omp_clause_init): Make addressable.
+
 2025-01-30  Tobias Burnus  <tburnus@baylibre.com>
 
        Backported from master:
index 5461719370c9ab3e9451eba796726fa49fe1a5c4..645f2f8fdcaaff9431f4a44e1914fa9bd8850d6c 100644 (file)
@@ -43501,6 +43501,7 @@ cp_parser_omp_clause_init (cp_parser *parser, tree list)
                                            NULL);
   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 eeecc908673c64df3768aee8303e7c2bfb6468b0..969b2f306bc200871b0e67a566a063f27dca0cc4 100644 (file)
@@ -1,3 +1,14 @@
+2025-03-21  Paul-Antoine Arras  <parras@baylibre.com>
+
+       Backported from master:
+       2025-03-21  Paul-Antoine Arras  <parras@baylibre.com>
+                   Tobias Burnus  <tburnus@baylibre.com>
+
+       * 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.
+
 2025-03-18  Tobias Burnus  <tburnus@baylibre.com>
 
        Backported from master:
index 7eafe595d5a3fac8aaceb13a92ac6f97eeecb43f..b226cf5b231b935c2842a1dd90af7dab62396304 100644 (file)
@@ -4803,9 +4803,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;
@@ -4816,6 +4813,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;
@@ -4829,6 +4842,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 d1b11c4bfbebb3dfc1a8783e03092f87cd78de7b..00ba8f4101abd182f2b76e1738c9769f57b384ce 100644 (file)
@@ -272,6 +272,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 5b51085102867209bc4ccac2acbb674fb46e7a49..673ddc0bc4704bce9768736da8f889622b35d102 100644 (file)
@@ -777,6 +777,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 e414cf2168960ac731d7502ad6445a528e62c38f..82461e83753663752489710658f22af90b1f8941 100644 (file)
@@ -1752,6 +1752,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 BUFFER.  */
 
 static void
@@ -2907,6 +2926,10 @@ pp_gimple_stmt_1 (pretty_printer *buffer, const gimple *gs, int spc,
       dump_gimple_omp_dispatch(buffer, gs, spc, flags);
       break;
 
+    case GIMPLE_OMP_INTEROP:
+      dump_gimple_omp_interop (buffer, gs, spc, flags);
+      break;
+
     case GIMPLE_OMP_MASTER:
     case GIMPLE_OMP_SECTION:
     case GIMPLE_OMP_STRUCTURED_BLOCK:
index bfe4e4c1bc24baa2dd721196072565fb72c60aa9..300b50fb144a8060e889995e27cb3203896d4ffd 100644 (file)
@@ -1251,6 +1251,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.
@@ -2204,6 +2217,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 3249e1cac1186d6e28defe6b287e7ac6660630bf..d0d6ab564e1d32d6ef22346a36a9e51314dc9a70 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 a370a45bc8770ba0e784b07c977a479b888ace1e..0c8985a662aa5d5aad456ea59d60e917f074cb5c 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
@@ -1655,6 +1656,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);
@@ -5532,6 +5534,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
@@ -6920,6 +6950,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 ea46c81364b34ce44274620b71a13b1b13764464..042dd6f32fcfd7d2c7768a3f83a82237648a9489 100644 (file)
@@ -14317,6 +14317,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__OMPACC_:
@@ -19421,6 +19424,22 @@ gimplify_omp_declare_mapper (tree *expr_p)
   return GS_ALL_DONE;
 }
 
+
+/* 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;
+}
+
 /* Replace a metadirective with the candidate directive variants in
    CANDIDATES.  */
 
@@ -20840,9 +20859,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 6e3f0a65c79b71b9fe758a359928149a4e3b745d..608c9af315edd1e1bf4c2f6c879b0fd8a6a8aa45 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 dd4adbaeb60143c5488b6db348dabfd292eb7125..d9735ff7c8339ea1be42dde44f2a34b5667de3c0 100644 (file)
@@ -2162,6 +2162,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:
@@ -2365,6 +2370,9 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
        case OMP_CLAUSE__CONDTEMP_:
        case OMP_CLAUSE_USES_ALLOCATORS:
        case OMP_CLAUSE__OMPACC_:
+       case OMP_CLAUSE_INIT:
+       case OMP_CLAUSE_USE:
+       case OMP_CLAUSE_DESTROY:
          break;
 
        case OMP_CLAUSE__CACHE_:
@@ -4713,6 +4721,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;
@@ -15817,6 +15829,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
@@ -16118,6 +16346,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 caf8833838293703bf6a7fecfc7004691218bb6f..ae13f4c406380e8c12bd66afb14cca64ba743b26 100644 (file)
@@ -1,3 +1,17 @@
+2025-03-21  Paul-Antoine Arras  <parras@baylibre.com>
+
+       Backported from master:
+       2025-03-21  Paul-Antoine Arras  <parras@baylibre.com>
+                   Tobias Burnus  <tburnus@baylibre.com>
+
+       * 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.
 2025-03-19  Thomas Schwinge  <tschwinge@baylibre.com>
 
        Backported from trunk:
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 9b39ba0bedf71ad469bea276412000844ede653a..138f293f2ac7cb1fe7fc6367fef441300625b99e 100644 (file)
@@ -34,18 +34,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 }
@@ -56,7 +56,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 }
 
@@ -70,7 +70,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..ce4ac3a
--- /dev/null
@@ -0,0 +1,69 @@
+/* { dg-do compile { target { c || c++11 } } } */
+/* { 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 a80d1168a334f3bf4fc29af4e925be15909fe727..aca5a3a7e041fe2a6f1382ef3093985edbb7ff4b 100644 (file)
@@ -1,3 +1,12 @@
+2025-03-21  Paul-Antoine Arras  <parras@baylibre.com>
+
+       Backported from master:
+       2025-03-21  Paul-Antoine Arras  <parras@baylibre.com>
+                   Tobias Burnus  <tburnus@baylibre.com>
+
+       * gomp-constants.h (GOMP_DEVICE_DEFAULT_OMP_61, GOMP_INTEROP_TARGET,
+       GOMP_INTEROP_TARGETSYNC, GOMP_INTEROP_FLAG_NOWAIT): Define.
+
 2025-01-27  Tobias Burnus  <tburnus@baylibre.com>
 
        Backported from master:
index ed162f45cd51eef8046feeb0138904f69965481a..965897c380ec83c52929aa066d4a957e2bef6cf3 100644 (file)
@@ -322,10 +322,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)
@@ -436,6 +440,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 894a9f54869dd459f4bed16864712c7008ec5d8a..16e62694b523b304951f8c6d3c7577c871d2b966 100644 (file)
@@ -1,3 +1,35 @@
+2025-03-21  Paul-Antoine Arras  <parras@baylibre.com>
+
+       Backported from master:
+       2025-03-21  Paul-Antoine Arras  <parras@baylibre.com>
+                   Tobias Burnus  <tburnus@baylibre.com>
+
+       * 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.
+
 2025-03-18  Tobias Burnus  <tburnus@baylibre.com>
 
        Backported from master:
index 42ea9f5a46907a255518fdc122fb02d4c3f809a8..5fbf654bf09116ae3b8dbfccab4d039dc9d01932 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 c7561e95c9be2fbb9be538579c414562ddc1ff53..85e60ff61135862e7dd2d6bf1f18d89bb0b9babc 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
@@ -185,6 +212,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 cf8e393544f7153905964c880c3174988fca2b74..43e7a068e69f584e3a71d676fe2ab480eaff92ed 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
@@ -1440,6 +1447,11 @@ struct gomp_device_descr
   __typeof (GOMP_OFFLOAD_run) *run_func;
   __typeof (GOMP_OFFLOAD_async_run) *async_run_func;
   __typeof (GOMP_OFFLOAD_evaluate_device) *evaluate_device_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;
@@ -1523,11 +1535,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 d40f8eb6eddbacf50b0651dda03ffc559cfb8dcc..bc3c2dafc21b335666e95f42890e593b6667c932 100644 (file)
@@ -432,6 +432,7 @@ GOMP_5.1.2 {
 GOMP_5.1.3 {
   global:
        GOMP_evaluate_target_device;
+       GOMP_interop;
        omp_get_num_interop_properties;
        omp_get_interop_int;
        omp_get_interop_ptr;
index 73c5fafb471d7a224d5b058d1fc1bbcd99db6814..83bb00da869ae9b1f4a17e010bdbe7cc6cd6998e 100644 (file)
@@ -363,6 +363,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 **);
 
 extern bool GOMP_evaluate_target_device (int, const char *, const char *,
                                         const char *);
index c9bf120ce43c754d9f58fc45da5f54a871f3dedc..2647c3864c22128c349d6747150fb2bcf454128d 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;
@@ -5723,45 +5724,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 *
@@ -5781,18 +5815,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 *
@@ -5823,6 +5863,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)
 {
@@ -5934,6 +6087,14 @@ gomp_load_plugin_for_device (struct gomp_device_descr *device,
   DLSYM (evaluate_device);
   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;
+}