https://gcc.gnu.org/g:3560ef45c0b57d9382becf7cb0b027ada5715c91

commit 3560ef45c0b57d9382becf7cb0b027ada5715c91
Author: Paul-Antoine Arras <par...@baylibre.com>
Date:   Thu Mar 13 17:16:41 2025 +0100

    OpenMP: 'interop' construct - add ME support + target-independent libgomp
    
    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 <tbur...@baylibre.com>
    (cherry picked from commit 99e2906ae255fc7b8edb008d7cd47b28b078a809)

Diff:
---
 gcc/ChangeLog.omp                                  |  31 +++
 gcc/builtin-types.def                              |   3 +
 gcc/c/ChangeLog.omp                                |   9 +
 gcc/c/c-parser.cc                                  |   6 +-
 gcc/cp/ChangeLog.omp                               |   8 +
 gcc/cp/parser.cc                                   |   1 +
 gcc/fortran/ChangeLog.omp                          |  11 +
 gcc/fortran/trans-openmp.cc                        |  20 +-
 gcc/fortran/types.def                              |   3 +
 gcc/gimple-low.cc                                  |   1 +
 gcc/gimple-pretty-print.cc                         |  23 ++
 gcc/gimple.cc                                      |  18 ++
 gcc/gimple.def                                     |   4 +
 gcc/gimple.h                                       |  33 ++-
 gcc/gimplify.cc                                    |  23 +-
 gcc/omp-builtins.def                               |   3 +
 gcc/omp-low.cc                                     | 233 +++++++++++++++++++++
 gcc/testsuite/ChangeLog.omp                        |  14 ++
 gcc/testsuite/c-c++-common/gomp/interop-1.c        |   2 -
 gcc/testsuite/c-c++-common/gomp/interop-2.c        |   2 -
 gcc/testsuite/c-c++-common/gomp/interop-3.c        |   2 -
 gcc/testsuite/c-c++-common/gomp/interop-4.c        |  12 +-
 gcc/testsuite/c-c++-common/gomp/interop-5.c        |  69 ++++++
 gcc/testsuite/g++.dg/gomp/interop-5.C              |  12 +-
 gcc/testsuite/gfortran.dg/gomp/interop-4.f90       |  10 +-
 gcc/testsuite/gfortran.dg/gomp/interop-5.f90       |  21 ++
 include/ChangeLog.omp                              |   9 +
 include/gomp-constants.h                           |  13 +-
 libgomp/ChangeLog.omp                              |  32 +++
 libgomp/icv-device.c                               |   7 +-
 libgomp/libgomp-plugin.h                           |  44 ++++
 libgomp/libgomp.h                                  |  17 +-
 libgomp/libgomp.map                                |   1 +
 libgomp/libgomp_g.h                                |   4 +
 libgomp/target.c                                   | 213 ++++++++++++++++---
 libgomp/testsuite/libgomp.c-c++-common/interop-1.c |  43 ++++
 36 files changed, 891 insertions(+), 66 deletions(-)

diff --git a/gcc/ChangeLog.omp b/gcc/ChangeLog.omp
index 31e79a89e884..2f931af7425c 100644
--- a/gcc/ChangeLog.omp
+++ b/gcc/ChangeLog.omp
@@ -1,3 +1,34 @@
+2025-03-21  Paul-Antoine Arras  <par...@baylibre.com>
+
+       Backported from master:
+       2025-03-21  Paul-Antoine Arras  <par...@baylibre.com>
+                   Tobias Burnus  <tbur...@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  <tschwi...@baylibre.com>
 
        Backported from trunk:
diff --git a/gcc/builtin-types.def b/gcc/builtin-types.def
index 9ddc0ed33820..dac540521ef8 100644
--- a/gcc/builtin-types.def
+++ b/gcc/builtin-types.def
@@ -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)
diff --git a/gcc/c/ChangeLog.omp b/gcc/c/ChangeLog.omp
index 33b2c5b9f0d4..03a05cb7bbe2 100644
--- a/gcc/c/ChangeLog.omp
+++ b/gcc/c/ChangeLog.omp
@@ -1,3 +1,12 @@
+2025-03-21  Paul-Antoine Arras  <par...@baylibre.com>
+
+       Backported from master:
+       2025-03-21  Paul-Antoine Arras  <par...@baylibre.com>
+                   Tobias Burnus  <tbur...@baylibre.com>
+
+       * c-parser.cc (c_parser_omp_clause_destroy): Make addressable.
+       (c_parser_omp_clause_init): Make addressable.
+
 2025-03-18  Sandra Loosemore  <sloosem...@baylibre.com>
 
        Backported from master:
diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index f79131a5274f..5e3eab71b7df 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -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)
diff --git a/gcc/cp/ChangeLog.omp b/gcc/cp/ChangeLog.omp
index b8cfd32482ca..bf08763e2183 100644
--- a/gcc/cp/ChangeLog.omp
+++ b/gcc/cp/ChangeLog.omp
@@ -1,3 +1,11 @@
+2025-03-21  Paul-Antoine Arras  <par...@baylibre.com>
+
+       Backported from master:
+       2025-03-21  Paul-Antoine Arras  <par...@baylibre.com>
+                   Tobias Burnus  <tbur...@baylibre.com>
+
+       * parser.cc (cp_parser_omp_clause_init): Make addressable.
+
 2025-01-30  Tobias Burnus  <tbur...@baylibre.com>
 
        Backported from master:
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 5461719370c9..645f2f8fdcaa 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -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)
diff --git a/gcc/fortran/ChangeLog.omp b/gcc/fortran/ChangeLog.omp
index eeecc908673c..969b2f306bc2 100644
--- a/gcc/fortran/ChangeLog.omp
+++ b/gcc/fortran/ChangeLog.omp
@@ -1,3 +1,14 @@
+2025-03-21  Paul-Antoine Arras  <par...@baylibre.com>
+
+       Backported from master:
+       2025-03-21  Paul-Antoine Arras  <par...@baylibre.com>
+                   Tobias Burnus  <tbur...@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  <tbur...@baylibre.com>
 
        Backported from master:
diff --git a/gcc/fortran/trans-openmp.cc b/gcc/fortran/trans-openmp.cc
index 7eafe595d5a3..b226cf5b231b 100644
--- a/gcc/fortran/trans-openmp.cc
+++ b/gcc/fortran/trans-openmp.cc
@@ -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)
diff --git a/gcc/fortran/types.def b/gcc/fortran/types.def
index d1b11c4bfbeb..00ba8f4101ab 100644
--- a/gcc/fortran/types.def
+++ b/gcc/fortran/types.def
@@ -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)
 
diff --git a/gcc/gimple-low.cc b/gcc/gimple-low.cc
index 5b5108510286..673ddc0bc470 100644
--- a/gcc/gimple-low.cc
+++ b/gcc/gimple-low.cc
@@ -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:
diff --git a/gcc/gimple-pretty-print.cc b/gcc/gimple-pretty-print.cc
index e414cf216896..82461e837536 100644
--- a/gcc/gimple-pretty-print.cc
+++ b/gcc/gimple-pretty-print.cc
@@ -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:
diff --git a/gcc/gimple.cc b/gcc/gimple.cc
index bfe4e4c1bc24..300b50fb144a 100644
--- a/gcc/gimple.cc
+++ b/gcc/gimple.cc
@@ -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);
diff --git a/gcc/gimple.def b/gcc/gimple.def
index 3249e1cac118..d0d6ab564e1d 100644
--- a/gcc/gimple.def
+++ b/gcc/gimple.def
@@ -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)
diff --git a/gcc/gimple.h b/gcc/gimple.h
index a370a45bc877..0c8985a662aa 100644
--- a/gcc/gimple.h
+++ b/gcc/gimple.h
@@ -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:                    \
diff --git a/gcc/gimplify.cc b/gcc/gimplify.cc
index ea46c81364b3..042dd6f32fcf 100644
--- a/gcc/gimplify.cc
+++ b/gcc/gimplify.cc
@@ -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:
diff --git a/gcc/omp-builtins.def b/gcc/omp-builtins.def
index 6e3f0a65c79b..608c9af315ed 100644
--- a/gcc/omp-builtins.def
+++ b/gcc/omp-builtins.def
@@ -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,
diff --git a/gcc/omp-low.cc b/gcc/omp-low.cc
index dd4adbaeb601..d9735ff7c833 100644
--- a/gcc/omp-low.cc
+++ b/gcc/omp-low.cc
@@ -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);
diff --git a/gcc/testsuite/ChangeLog.omp b/gcc/testsuite/ChangeLog.omp
index caf883383829..ae13f4c40638 100644
--- a/gcc/testsuite/ChangeLog.omp
+++ b/gcc/testsuite/ChangeLog.omp
@@ -1,3 +1,17 @@
+2025-03-21  Paul-Antoine Arras  <par...@baylibre.com>
+
+       Backported from master:
+       2025-03-21  Paul-Antoine Arras  <par...@baylibre.com>
+                   Tobias Burnus  <tbur...@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  <tschwi...@baylibre.com>
 
        Backported from trunk:
diff --git a/gcc/testsuite/c-c++-common/gomp/interop-1.c 
b/gcc/testsuite/c-c++-common/gomp/interop-1.c
index de3a4ba4b6bc..d68611bfe9c7 100644
--- a/gcc/testsuite/c-c++-common/gomp/interop-1.c
+++ b/gcc/testsuite/c-c++-common/gomp/interop-1.c
@@ -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/  */
 
diff --git a/gcc/testsuite/c-c++-common/gomp/interop-2.c 
b/gcc/testsuite/c-c++-common/gomp/interop-2.c
index 57fd688d55fe..af81cc673608 100644
--- a/gcc/testsuite/c-c++-common/gomp/interop-2.c
+++ b/gcc/testsuite/c-c++-common/gomp/interop-2.c
@@ -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/  */
 
diff --git a/gcc/testsuite/c-c++-common/gomp/interop-3.c 
b/gcc/testsuite/c-c++-common/gomp/interop-3.c
index 42478bf760d6..51d26dd179ea 100644
--- a/gcc/testsuite/c-c++-common/gomp/interop-3.c
+++ b/gcc/testsuite/c-c++-common/gomp/interop-3.c
@@ -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/  */
 
diff --git a/gcc/testsuite/c-c++-common/gomp/interop-4.c 
b/gcc/testsuite/c-c++-common/gomp/interop-4.c
index 9b39ba0bedf7..138f293f2ac7 100644
--- a/gcc/testsuite/c-c++-common/gomp/interop-4.c
+++ b/gcc/testsuite/c-c++-common/gomp/interop-4.c
@@ -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
index 000000000000..ce4ac3a47d90
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/interop-5.c
@@ -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_inte
 rop \\(-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. 
= &o
 bj4;\[\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_GOM
 P_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++ } } }  */
+}
diff --git a/gcc/testsuite/g++.dg/gomp/interop-5.C 
b/gcc/testsuite/g++.dg/gomp/interop-5.C
index 5109dc4e4271..89396cf54379 100644
--- a/gcc/testsuite/g++.dg/gomp/interop-5.C
+++ b/gcc/testsuite/g++.dg/gomp/interop-5.C
@@ -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 }
 
diff --git a/gcc/testsuite/gfortran.dg/gomp/interop-4.f90 
b/gcc/testsuite/gfortran.dg/gomp/interop-4.f90
index 8783f4cfb5fd..43c28d696689 100644
--- a/gcc/testsuite/gfortran.dg/gomp/interop-4.f90
+++ b/gcc/testsuite/gfortran.dg/gomp/interop-4.f90
@@ -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
index 000000000000..a6a2d719189c
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/interop-5.f90
@@ -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
+
+
diff --git a/include/ChangeLog.omp b/include/ChangeLog.omp
index a80d1168a334..aca5a3a7e041 100644
--- a/include/ChangeLog.omp
+++ b/include/ChangeLog.omp
@@ -1,3 +1,12 @@
+2025-03-21  Paul-Antoine Arras  <par...@baylibre.com>
+
+       Backported from master:
+       2025-03-21  Paul-Antoine Arras  <par...@baylibre.com>
+                   Tobias Burnus  <tbur...@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  <tbur...@baylibre.com>
 
        Backported from master:
diff --git a/include/gomp-constants.h b/include/gomp-constants.h
index ed162f45cd51..965897c380ec 100644
--- a/include/gomp-constants.h
+++ b/include/gomp-constants.h
@@ -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.  */
diff --git a/libgomp/ChangeLog.omp b/libgomp/ChangeLog.omp
index 894a9f54869d..16e62694b523 100644
--- a/libgomp/ChangeLog.omp
+++ b/libgomp/ChangeLog.omp
@@ -1,3 +1,35 @@
+2025-03-21  Paul-Antoine Arras  <par...@baylibre.com>
+
+       Backported from master:
+       2025-03-21  Paul-Antoine Arras  <par...@baylibre.com>
+                   Tobias Burnus  <tbur...@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  <tbur...@baylibre.com>
 
        Backported from master:
diff --git a/libgomp/icv-device.c b/libgomp/icv-device.c
index 42ea9f5a4690..5fbf654bf091 100644
--- a/libgomp/icv-device.c
+++ b/libgomp/icv-device.c
@@ -32,8 +32,11 @@
 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)
diff --git a/libgomp/libgomp-plugin.h b/libgomp/libgomp-plugin.h
index c7561e95c9be..85e60ff61135 100644
--- a/libgomp/libgomp-plugin.h
+++ b/libgomp/libgomp-plugin.h
@@ -33,6 +33,14 @@
 #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
diff --git a/libgomp/libgomp.h b/libgomp/libgomp.h
index cf8e393544f7..43e7a068e69f 100644
--- a/libgomp/libgomp.h
+++ b/libgomp/libgomp.h
@@ -43,7 +43,14 @@
 
 #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) \
diff --git a/libgomp/libgomp.map b/libgomp/libgomp.map
index d40f8eb6eddb..bc3c2dafc21b 100644
--- a/libgomp/libgomp.map
+++ b/libgomp/libgomp.map
@@ -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;
diff --git a/libgomp/libgomp_g.h b/libgomp/libgomp_g.h
index 73c5fafb471d..83bb00da869a 100644
--- a/libgomp/libgomp_g.h
+++ b/libgomp/libgomp_g.h
@@ -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 *);
diff --git a/libgomp/target.c b/libgomp/target.c
index c9bf120ce43c..2647c3864c22 100644
--- a/libgomp/target.c
+++ b/libgomp/target.c
@@ -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
index 000000000000..149f3877b30b
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c-c++-common/interop-1.c
@@ -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;
+}

Reply via email to