[flang-commits] [flang] [llvm] [flang][openmp] Adds Parser and Semantic Support for Interop Construct, and Init and Use Clauses. (PR #120584)

via flang-commits flang-commits at lists.llvm.org
Mon Jan 6 05:19:09 PST 2025


https://github.com/swatheesh-mcw updated https://github.com/llvm/llvm-project/pull/120584

>From f26bdde8f1141846dcdd74dba28f9ac896f57bf3 Mon Sep 17 00:00:00 2001
From: swatheesh-mcw <swatheesh.muralidharan at multicorewareinc.com>
Date: Thu, 19 Dec 2024 19:51:49 +0530
Subject: [PATCH 1/2] Adds Parser and Semantic Support for the below construct
 and clauses:

- Interop Construct
- Init Clause
- Use Clause

Note:
The other clauses supported by Interop Construct such as Destroy, Use, Depend and Device are added already.
---
 flang/examples/FeatureList/FeatureList.cpp    |   9 +
 flang/include/flang/Parser/dump-parse-tree.h  |   9 +
 flang/include/flang/Parser/parse-tree.h       |  41 +++-
 flang/lib/Lower/OpenMP/OpenMP.cpp             |   7 +
 flang/lib/Parser/openmp-parsers.cpp           |  28 ++-
 flang/lib/Parser/unparse.cpp                  |  19 ++
 flang/lib/Semantics/check-omp-structure.cpp   |  85 ++++++++
 flang/lib/Semantics/check-omp-structure.h     |   2 +
 .../test/Parser/OpenMP/interop-construct.f90  | 204 ++++++++++++++++++
 .../Semantics/OpenMP/interop-construct.f90    |  30 +++
 llvm/include/llvm/Frontend/OpenMP/OMP.td      |   2 +
 11 files changed, 434 insertions(+), 2 deletions(-)
 create mode 100644 flang/test/Parser/OpenMP/interop-construct.f90
 create mode 100644 flang/test/Semantics/OpenMP/interop-construct.f90

diff --git a/flang/examples/FeatureList/FeatureList.cpp b/flang/examples/FeatureList/FeatureList.cpp
index 3a689c335c81c0..ac70de588c7d9f 100644
--- a/flang/examples/FeatureList/FeatureList.cpp
+++ b/flang/examples/FeatureList/FeatureList.cpp
@@ -525,6 +525,14 @@ struct NodeVisitor {
   READ_FEATURE(OmpScheduleClause)
   READ_FEATURE(OmpScheduleClause::Kind)
   READ_FEATURE(OmpScheduleClause::Modifier)
+  READ_FEATURE(InteropType)
+  READ_FEATURE(InteropType::Kind)
+  READ_FEATURE(InteropPreference)
+  READ_FEATURE(OmpInitClause)
+  READ_FEATURE(OmpInitClause::InteropModifier)
+  READ_FEATURE(OmpInitClause::InteropTypes)
+  READ_FEATURE(OmpInitClause::InteropVar)
+  READ_FEATURE(OmpUseClause)
   READ_FEATURE(OmpDeviceModifier)
   READ_FEATURE(OmpDeviceClause)
   READ_FEATURE(OmpDeviceClause::Modifier)
@@ -545,6 +553,7 @@ struct NodeVisitor {
   READ_FEATURE(OpenACCConstruct)
   READ_FEATURE(OpenACCDeclarativeConstruct)
   READ_FEATURE(OpenACCLoopConstruct)
+  READ_FEATURE(OpenMPInteropConstruct)
   READ_FEATURE(OpenACCRoutineConstruct)
   READ_FEATURE(OpenACCStandaloneDeclarativeConstruct)
   READ_FEATURE(OpenACCStandaloneConstruct)
diff --git a/flang/include/flang/Parser/dump-parse-tree.h b/flang/include/flang/Parser/dump-parse-tree.h
index 7821d40a644a27..5020d481dff29f 100644
--- a/flang/include/flang/Parser/dump-parse-tree.h
+++ b/flang/include/flang/Parser/dump-parse-tree.h
@@ -620,6 +620,14 @@ class ParseTreeDumper {
   NODE_ENUM(OmpDeviceModifier, Value)
   NODE(parser, OmpDeviceTypeClause)
   NODE_ENUM(OmpDeviceTypeClause, DeviceTypeDescription)
+  NODE(parser, InteropType)
+  NODE_ENUM(InteropType, Kind)
+  NODE(parser, InteropPreference)
+  NODE(parser, OmpInitClause)
+  NODE(OmpInitClause, InteropModifier)
+  NODE(OmpInitClause, InteropTypes)
+  NODE(OmpInitClause, InteropVar)
+  NODE(parser, OmpUseClause)
   NODE(parser, OmpUpdateClause)
   NODE(parser, OmpChunkModifier)
   NODE_ENUM(OmpChunkModifier, Value)
@@ -639,6 +647,7 @@ class ParseTreeDumper {
   NODE(parser, OpenACCDeclarativeConstruct)
   NODE(parser, OpenACCEndConstruct)
   NODE(parser, OpenACCLoopConstruct)
+  NODE(parser, OpenMPInteropConstruct)
   NODE(parser, OpenACCRoutineConstruct)
   NODE(parser, OpenACCStandaloneDeclarativeConstruct)
   NODE(parser, OpenACCStandaloneConstruct)
diff --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h
index 2ef593b3e50daa..3a0f41a67b01b0 100644
--- a/flang/include/flang/Parser/parse-tree.h
+++ b/flang/include/flang/Parser/parse-tree.h
@@ -4158,6 +4158,36 @@ struct OmpUpdateClause {
   std::variant<OmpDependenceType, OmpTaskDependenceType> u;
 };
 
+// REF: [5.1:217-220], [5.2:293-294]
+//
+// init-clause -> INIT ([interop-modifier,] [interop-type,]
+//                              interop-type: interop-var)
+// interop-modifier: prefer_type(preference-list)
+// interop-type: target, targetsync
+// There can be at most only two interop-type.
+struct InteropType {
+  ENUM_CLASS(Kind, Target, TargetSync)
+  WRAPPER_CLASS_BOILERPLATE(InteropType, Kind);
+};
+
+struct InteropPreference {
+  UNION_CLASS_BOILERPLATE(InteropPreference);
+  std::variant<CharLiteralConstant, ScalarIntConstantExpr> u;
+};
+
+struct OmpInitClause {
+  TUPLE_CLASS_BOILERPLATE(OmpInitClause);
+  WRAPPER_CLASS(InteropModifier, std::list<InteropPreference>);
+  WRAPPER_CLASS(InteropTypes, std::list<InteropType>);
+  WRAPPER_CLASS(InteropVar, OmpObject);
+  std::tuple<std::optional<InteropModifier>, InteropTypes, InteropVar> t;
+};
+
+// REF: [5.1:217-220], [5.2:294]
+//
+// 14.1.3 use-clause -> USE (interop-var)
+WRAPPER_CLASS(OmpUseClause, OmpObject);
+
 // OpenMP Clauses
 struct OmpClause {
   UNION_CLASS_BOILERPLATE(OmpClause);
@@ -4528,6 +4558,15 @@ struct OmpSimpleStandaloneDirective {
   CharBlock source;
 };
 
+// Ref: [5.1:217-220], [5.2:291-292]
+//
+// interop -> INTEROP clause[ [ [,] clause]...]
+struct OpenMPInteropConstruct {
+  TUPLE_CLASS_BOILERPLATE(OpenMPInteropConstruct);
+  CharBlock source;
+  std::tuple<Verbatim, OmpClauseList> t;
+};
+
 struct OpenMPSimpleStandaloneConstruct {
   TUPLE_CLASS_BOILERPLATE(OpenMPSimpleStandaloneConstruct);
   CharBlock source;
@@ -4539,7 +4578,7 @@ struct OpenMPStandaloneConstruct {
   CharBlock source;
   std::variant<OpenMPSimpleStandaloneConstruct, OpenMPFlushConstruct,
       OpenMPCancelConstruct, OpenMPCancellationPointConstruct,
-      OpenMPDepobjConstruct>
+      OpenMPDepobjConstruct, OpenMPInteropConstruct>
       u;
 };
 
diff --git a/flang/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp
index b07e89d201d198..b6328dda8441c9 100644
--- a/flang/lib/Lower/OpenMP/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP/OpenMP.cpp
@@ -2752,6 +2752,13 @@ static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
   TODO(converter.getCurrentLocation(), "OpenMPDepobjConstruct");
 }
 
+static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
+                   semantics::SemanticsContext &semaCtx,
+                   lower::pft::Evaluation &eval,
+                   const parser::OpenMPInteropConstruct &interopConstruct) {
+  TODO(converter.getCurrentLocation(), "OpenMPInteropConstruct");
+}
+
 static void
 genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
        semantics::SemanticsContext &semaCtx, lower::pft::Evaluation &eval,
diff --git a/flang/lib/Parser/openmp-parsers.cpp b/flang/lib/Parser/openmp-parsers.cpp
index 67385c03f66c80..ac9f7a45dbd77e 100644
--- a/flang/lib/Parser/openmp-parsers.cpp
+++ b/flang/lib/Parser/openmp-parsers.cpp
@@ -531,6 +531,22 @@ TYPE_PARSER(
 // OpenMPv5.2 12.5.2 detach-clause -> DETACH (event-handle)
 TYPE_PARSER(construct<OmpDetachClause>(Parser<OmpObject>{}))
 
+// InteropTypes
+TYPE_PARSER(construct<InteropType>(
+    "TARGETSYNC" >> pure(InteropType::Kind::TargetSync) ||
+    "TARGET" >> pure(InteropType::Kind::Target)))
+
+// InteropPreference
+TYPE_PARSER(construct<InteropPreference>(
+    construct<InteropPreference>(charLiteralConstant) ||
+    construct<InteropPreference>(scalarIntConstantExpr)))
+
+// init clause
+TYPE_PARSER(construct<OmpInitClause>(
+    maybe(verbatim("PREFER_TYPE"_tok) >>
+        parenthesized(nonemptyList(Parser<InteropPreference>{})) / ","),
+    nonemptyList(Parser<InteropType>{}) / ":", Parser<OmpObject>{}))
+
 // 2.8.1 ALIGNED (list: alignment)
 TYPE_PARSER(construct<OmpAlignedClause>(Parser<OmpObjectList>{},
     maybe(":" >> nonemptyList(Parser<OmpAlignedClause::Modifier>{}))))
@@ -644,6 +660,8 @@ TYPE_PARSER(
     "IF" >> construct<OmpClause>(construct<OmpClause::If>(
                 parenthesized(Parser<OmpIfClause>{}))) ||
     "INBRANCH" >> construct<OmpClause>(construct<OmpClause::Inbranch>()) ||
+    "INIT" >> construct<OmpClause>(construct<OmpClause::Init>(
+                  parenthesized(Parser<OmpInitClause>{}))) ||
     "INCLUSIVE" >> construct<OmpClause>(construct<OmpClause::Inclusive>(
                        parenthesized(Parser<OmpObjectList>{}))) ||
     "IS_DEVICE_PTR" >> construct<OmpClause>(construct<OmpClause::IsDevicePtr>(
@@ -718,6 +736,8 @@ TYPE_PARSER(
                           parenthesized(scalarIntExpr))) ||
     "TO" >> construct<OmpClause>(construct<OmpClause::To>(
                 parenthesized(Parser<OmpToClause>{}))) ||
+    "USE" >> construct<OmpClause>(construct<OmpClause::Use>(
+                 parenthesized(Parser<OmpObject>{}))) ||
     "USE_DEVICE_PTR" >> construct<OmpClause>(construct<OmpClause::UseDevicePtr>(
                             parenthesized(Parser<OmpObjectList>{}))) ||
     "USE_DEVICE_ADDR" >>
@@ -877,6 +897,10 @@ TYPE_PARSER(sourced(construct<OmpSimpleStandaloneDirective>(first(
 TYPE_PARSER(sourced(construct<OpenMPSimpleStandaloneConstruct>(
     Parser<OmpSimpleStandaloneDirective>{}, Parser<OmpClauseList>{})))
 
+// 14.1 Interop construct
+TYPE_PARSER(sourced(construct<OpenMPInteropConstruct>(
+    verbatim("INTEROP"_tok), sourced(Parser<OmpClauseList>{}))))
+
 // Standalone Constructs
 TYPE_PARSER(
     sourced(construct<OpenMPStandaloneConstruct>(
@@ -885,7 +909,9 @@ TYPE_PARSER(
         construct<OpenMPStandaloneConstruct>(Parser<OpenMPCancelConstruct>{}) ||
         construct<OpenMPStandaloneConstruct>(
             Parser<OpenMPCancellationPointConstruct>{}) ||
-        construct<OpenMPStandaloneConstruct>(Parser<OpenMPDepobjConstruct>{})) /
+        construct<OpenMPStandaloneConstruct>(Parser<OpenMPDepobjConstruct>{}) ||
+        construct<OpenMPStandaloneConstruct>(
+            Parser<OpenMPInteropConstruct>{})) /
     endOfLine)
 
 // Directives enclosing structured-block
diff --git a/flang/lib/Parser/unparse.cpp b/flang/lib/Parser/unparse.cpp
index 0a6af7435b4a22..00957c6c424019 100644
--- a/flang/lib/Parser/unparse.cpp
+++ b/flang/lib/Parser/unparse.cpp
@@ -2097,6 +2097,15 @@ class UnparseVisitor {
     Walk(std::get<std::optional<std::list<Modifier>>>(x.t), ": ");
     Walk(std::get<OmpObjectList>(x.t));
   }
+  void Unparse(const OmpInitClause::InteropTypes &x) { Walk(x.v, ","); }
+  void Unparse(const OmpInitClause::InteropModifier &x) { Walk(x.v, ","); }
+  void Unparse(const OmpInitClause &x) {
+    Walk("PREFER_TYPE(",
+        std::get<std::optional<OmpInitClause::InteropModifier>>(x.t), "),");
+    Walk(std::get<OmpInitClause::InteropTypes>(x.t));
+    Put(": ");
+    Walk(std::get<OmpInitClause::InteropVar>(x.t));
+  }
   void Unparse(const OmpMapClause &x) {
     using Modifier = OmpMapClause::Modifier;
     Walk(std::get<std::optional<std::list<Modifier>>>(x.t), ": ");
@@ -2638,6 +2647,15 @@ class UnparseVisitor {
     Put(")");
     Walk(std::get<std::optional<OmpReductionInitializerClause>>(x.t));
   }
+
+  void Unparse(const OpenMPInteropConstruct &x) {
+    BeginOpenMP();
+    Word("!$OMP INTEROP");
+    Walk(std::get<OmpClauseList>(x.t));
+    Put("\n");
+    EndOpenMP();
+  }
+
   bool Pre(const OpenMPDeclarativeConstruct &x) {
     BeginOpenMP();
     Word("!$OMP ");
@@ -2923,6 +2941,7 @@ class UnparseVisitor {
       OmpDeviceTypeClause, DeviceTypeDescription) // OMP device_type
   WALK_NESTED_ENUM(OmpReductionModifier, Value) // OMP reduction-modifier
   WALK_NESTED_ENUM(OmpExpectation, Value) // OMP motion-expectation
+  WALK_NESTED_ENUM(InteropType, Kind) // OMP InteropVar
   WALK_NESTED_ENUM(OmpCancelType, Type) // OMP cancel-type
   WALK_NESTED_ENUM(OmpOrderClause, Ordering) // OMP ordering
   WALK_NESTED_ENUM(OmpOrderModifier, Value) // OMP order-modifier
diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index 95b962f5daf57c..68a041fe6e9eeb 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -4801,6 +4801,91 @@ void OmpStructureChecker::Leave(const parser::DoConstruct &x) {
   Base::Leave(x);
 }
 
+void OmpStructureChecker::Enter(const parser::OpenMPInteropConstruct &x) {
+  bool isDependClauseOccured{false};
+  int targetCount{0}, targetSyncCount{0};
+  const auto &dir{std::get<parser::Verbatim>(x.t)};
+  std::list<std::string> ObjectNameList;
+  PushContextAndClauseSets(dir.source, llvm::omp::Directive::OMPD_interop);
+  const auto &clauseList{std::get<parser::OmpClauseList>(x.t)};
+  for (const auto &clause : clauseList.v) {
+    common::visit(
+        common::visitors{
+            [&](const parser::OmpClause::Init &InitClause) {
+              const auto &InteropTypeList{
+                  std::get<parser::OmpInitClause::InteropTypes>(
+                      InitClause.v.t)};
+              for (auto &InteropTypeVal : InteropTypeList.v) {
+                if (*(parser::Unwrap<parser::InteropType::Kind>(
+                        InteropTypeVal)) ==
+                    parser::InteropType::Kind::TargetSync) {
+                  ++targetSyncCount;
+                } else {
+                  ++targetCount;
+                }
+                if (targetCount > 1 || targetSyncCount > 1) {
+                  context_.Say(GetContext().directiveSource,
+                      "Each interop-type may be specified at most once."_err_en_US);
+                }
+              }
+              const auto &InteropVar{parser::Unwrap<parser::OmpObject>(
+                  std::get<parser::OmpInitClause::InteropVar>(InitClause.v.t))};
+              const auto *name{parser::Unwrap<parser::Name>(InteropVar)};
+              const auto ObjectName{name->ToString()};
+              if (ObjectNameList.end() !=
+                  std::find(ObjectNameList.begin(), ObjectNameList.end(),
+                      ObjectName)) {
+                context_.Say(GetContext().directiveSource,
+                    "Each interop-var may be specified for at most one action-clause of each interop construct."_err_en_US);
+              } else {
+                ObjectNameList.push_back(ObjectName);
+              }
+            },
+            [&](const parser::OmpClause::Depend &DependClause) {
+              isDependClauseOccured = true;
+            },
+            [&](const parser::OmpClause::Destroy &DestroyClause) {
+              const auto &InteropVar{
+                  parser::Unwrap<parser::OmpObject>(DestroyClause.v)};
+              const auto *name{parser::Unwrap<parser::Name>(InteropVar)};
+              const auto ObjectName{name->ToString()};
+              if (ObjectNameList.end() !=
+                  std::find(ObjectNameList.begin(), ObjectNameList.end(),
+                      ObjectName)) {
+                context_.Say(GetContext().directiveSource,
+                    "Each interop-var may be specified for at most one action-clause of each interop construct."_err_en_US);
+              } else {
+                ObjectNameList.push_back(ObjectName);
+              }
+            },
+            [&](const parser::OmpClause::Use &UseClause) {
+              const auto &InteropVar{
+                  parser::Unwrap<parser::OmpObject>(UseClause.v)};
+              const auto *name{parser::Unwrap<parser::Name>(InteropVar)};
+              const auto ObjectName{name->ToString()};
+              if (ObjectNameList.end() !=
+                  std::find(ObjectNameList.begin(), ObjectNameList.end(),
+                      ObjectName)) {
+                context_.Say(GetContext().directiveSource,
+                    "Each interop-var may be specified for at most one action-clause of each interop construct."_err_en_US);
+              } else {
+                ObjectNameList.push_back(ObjectName);
+              }
+            },
+            [&](const auto &) {},
+        },
+        clause.u);
+  }
+  if (isDependClauseOccured && !targetSyncCount) {
+    context_.Say(GetContext().directiveSource,
+        "A depend clause can only appear on the directive if the interop-type includes targetsync"_err_en_US);
+  }
+}
+
+void OmpStructureChecker::Leave(const parser::OpenMPInteropConstruct &) {
+  dirContext_.pop_back();
+}
+
 void OmpStructureChecker::CheckAllowedRequiresClause(llvmOmpClause clause) {
   CheckAllowedClause(clause);
 
diff --git a/flang/lib/Semantics/check-omp-structure.h b/flang/lib/Semantics/check-omp-structure.h
index 346a7bed9138f0..7b3d9fa3d736b8 100644
--- a/flang/lib/Semantics/check-omp-structure.h
+++ b/flang/lib/Semantics/check-omp-structure.h
@@ -73,6 +73,8 @@ class OmpStructureChecker
 
   void Enter(const parser::OpenMPConstruct &);
   void Leave(const parser::OpenMPConstruct &);
+  void Enter(const parser::OpenMPInteropConstruct &);
+  void Leave(const parser::OpenMPInteropConstruct &);
   void Enter(const parser::OpenMPLoopConstruct &);
   void Leave(const parser::OpenMPLoopConstruct &);
   void Enter(const parser::OmpEndLoopDirective &);
diff --git a/flang/test/Parser/OpenMP/interop-construct.f90 b/flang/test/Parser/OpenMP/interop-construct.f90
new file mode 100644
index 00000000000000..9fd2b3d63d5c5d
--- /dev/null
+++ b/flang/test/Parser/OpenMP/interop-construct.f90
@@ -0,0 +1,204 @@
+! RUN: %flang_fc1 -fdebug-unparse -fopenmp %s | FileCheck --ignore-case --check-prefix="UNPARSE" %s 
+! RUN: %flang_fc1 -fdebug-dump-parse-tree-no-sema -fopenmp %s | FileCheck --check-prefix="PARSE-TREE" %s
+
+subroutine test_interop_01()
+  !$omp interop device(1)
+  print *,'pass'
+end subroutine test_interop_01
+
+!UNPARSE: SUBROUTINE test_interop_01
+!UNPARSE: !$OMP INTEROP  DEVICE(1_4)
+!UNPARSE:  PRINT *, "pass"
+!UNPARSE: END SUBROUTINE test_interop_01
+
+!PARSE-TREE: | SubroutineStmt
+!PARSE-TREE: | | Name = 'test_interop_01'
+!PARSE-TREE: | SpecificationPart
+!PARSE-TREE: | | ImplicitPart -> 
+!PARSE-TREE: | ExecutionPart -> Block
+!PARSE-TREE: | | ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OpenMPStandaloneConstruct -> OpenMPInteropConstruct
+!PARSE-TREE: | | | Verbatim
+!PARSE-TREE: | | | OmpClauseList -> OmpClause -> Device -> OmpDeviceClause
+!PARSE-TREE: | | | | Scalar -> Integer -> Expr -> LiteralConstant -> IntLiteralConstant = '1'
+!PARSE-TREE: | | ExecutionPartConstruct -> ExecutableConstruct -> ActionStmt -> PrintStmt
+!PARSE-TREE: | | | Format -> Star
+!PARSE-TREE: | | | OutputItem -> Expr -> LiteralConstant -> CharLiteralConstant
+!PARSE-TREE: | | | | string = 'pass'
+!PARSE-TREE: | EndSubroutineStmt -> Name = 'test_interop_01'
+
+subroutine test_interop_02()
+  use omp_lib
+  integer(omp_interop_kind) :: obj1, obj2, obj3
+  !$omp interop init(targetsync: obj) use(obj1) destroy(obj3)
+  print *,'pass'
+end subroutine test_interop_02
+
+!UNPARSE: SUBROUTINE test_interop_02
+!UNPARSE:  USE :: omp_lib
+!UNPARSE:  INTEGER(KIND=8_4) obj1, obj2, obj3
+!UNPARSE: !$OMP INTEROP INIT(TARGETSYNC: obj) USE(obj1) DESTROY(obj3)
+!UNPARSE:  PRINT *, "pass"
+!UNPARSE: END SUBROUTINE test_interop_02
+
+!PARSE-TREE: | SubroutineStmt
+!PARSE-TREE: | | Name = 'test_interop_02'
+!PARSE-TREE: | SpecificationPart
+!PARSE-TREE: | | UseStmt
+!PARSE-TREE: | | | Name = 'omp_lib'
+!PARSE-TREE: | | ImplicitPart -> 
+!PARSE-TREE: | | DeclarationConstruct -> SpecificationConstruct -> TypeDeclarationStmt
+!PARSE-TREE: | | | DeclarationTypeSpec -> IntrinsicTypeSpec -> IntegerTypeSpec -> KindSelector -> Scalar -> Integer -> Constant -> Expr -> Designator -> DataRef -> Name = 'omp_interop_kind'
+!PARSE-TREE: | | | EntityDecl
+!PARSE-TREE: | | | | Name = 'obj1'
+!PARSE-TREE: | | | EntityDecl
+!PARSE-TREE: | | | | Name = 'obj2'
+!PARSE-TREE: | | | EntityDecl
+!PARSE-TREE: | | | | Name = 'obj3'
+!PARSE-TREE: | ExecutionPart -> Block
+!PARSE-TREE: | | ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OpenMPStandaloneConstruct -> OpenMPInteropConstruct
+!PARSE-TREE: | | | Verbatim
+!PARSE-TREE: | | | OmpClauseList -> OmpClause -> Init -> OmpInitClause
+!PARSE-TREE: | | | | InteropTypes -> InteropType -> Kind = TargetSync
+!PARSE-TREE: | | | | InteropVar -> OmpObject -> Designator -> DataRef -> Name = 'obj'
+!PARSE-TREE: | | | OmpClause -> Use -> OmpUseClause -> OmpObject -> Designator -> DataRef -> Name = 'obj1'
+!PARSE-TREE: | | | OmpClause -> Destroy -> OmpDestroyClause -> OmpObject -> Designator -> DataRef -> Name = 'obj3'
+!PARSE-TREE: | | ExecutionPartConstruct -> ExecutableConstruct -> ActionStmt -> PrintStmt
+!PARSE-TREE: | | | Format -> Star
+!PARSE-TREE: | | | OutputItem -> Expr -> LiteralConstant -> CharLiteralConstant
+!PARSE-TREE: | | | | string = 'pass'
+!PARSE-TREE: | EndSubroutineStmt -> Name = 'test_interop_02'
+
+subroutine test_interop_03()
+  use omp_lib
+  Integer(omp_interop_kind) :: obj
+  !$omp interop init(targetsync: obj) depend(inout: obj)
+  print *,'pass'
+end subroutine test_interop_03
+
+!UNPARSE: SUBROUTINE test_interop_03
+!UNPARSE:  USE :: omp_lib
+!UNPARSE:  INTEGER(KIND=8_4) obj
+!UNPARSE: !$OMP INTEROP INIT(TARGETSYNC: obj) DEPEND(INOUT: obj)
+!UNPARSE:  PRINT *, "pass"
+!UNPARSE: END SUBROUTINE test_interop_03
+
+!PARSE-TREE: | SubroutineStmt
+!PARSE-TREE: | | Name = 'test_interop_03'
+!PARSE-TREE: | SpecificationPart
+!PARSE-TREE: | | UseStmt
+!PARSE-TREE: | | | Name = 'omp_lib'
+!PARSE-TREE: | | ImplicitPart -> 
+!PARSE-TREE: | | DeclarationConstruct -> SpecificationConstruct -> TypeDeclarationStmt
+!PARSE-TREE: | | | DeclarationTypeSpec -> IntrinsicTypeSpec -> IntegerTypeSpec -> KindSelector -> Scalar -> Integer -> Constant -> Expr -> Designator -> DataRef -> Name = 'omp_interop_kind'
+!PARSE-TREE: | | | EntityDecl
+!PARSE-TREE: | | | | Name = 'obj'
+!PARSE-TREE: | ExecutionPart -> Block
+!PARSE-TREE: | | ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OpenMPStandaloneConstruct -> OpenMPInteropConstruct
+!PARSE-TREE: | | | Verbatim
+!PARSE-TREE: | | | OmpClauseList -> OmpClause -> Init -> OmpInitClause
+!PARSE-TREE: | | | | InteropTypes -> InteropType -> Kind = TargetSync
+!PARSE-TREE: | | | | InteropVar -> OmpObject -> Designator -> DataRef -> Name = 'obj'
+!PARSE-TREE: | | | OmpClause -> Depend -> OmpDependClause -> TaskDep
+!PARSE-TREE: | | | | Modifier -> OmpTaskDependenceType -> Value = Inout
+!PARSE-TREE: | | | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'obj'
+!PARSE-TREE: | | ExecutionPartConstruct -> ExecutableConstruct -> ActionStmt -> PrintStmt
+!PARSE-TREE: | | | Format -> Star
+!PARSE-TREE: | | | OutputItem -> Expr -> LiteralConstant -> CharLiteralConstant
+!PARSE-TREE: | | | | string = 'pass'
+!PARSE-TREE: | EndSubroutineStmt -> Name = 'test_interop_03'
+
+subroutine test_interop_04()
+  use omp_lib
+  integer(omp_interop_kind) :: obj
+  integer, dimension(1,10) :: arr
+  !$omp interop init(prefer_type("cuda"),targetsync,target: obj) depend(inout: arr) nowait
+  print *,'pass'
+end subroutine test_interop_04
+
+!UNPARSE: SUBROUTINE test_interop_04
+!UNPARSE:  USE :: omp_lib
+!UNPARSE:  INTEGER(KIND=8_4) obj
+!UNPARSE:  INTEGER, DIMENSION(1_4,10_4) :: arr
+!UNPARSE: !$OMP INTEROP INIT(PREFER_TYPE("cuda"),TARGETSYNC,TARGET: obj) DEPEND(INOUT: a&
+!UNPARSE: !$OMP&rr) NOWAIT
+!UNPARSE:  PRINT *, "pass"
+!UNPARSE: END SUBROUTINE test_interop_04
+
+!PARSE-TREE: | SubroutineStmt
+!PARSE-TREE: | | Name = 'test_interop_04'
+!PARSE-TREE: | SpecificationPart
+!PARSE-TREE: | | UseStmt
+!PARSE-TREE: | | | Name = 'omp_lib'
+!PARSE-TREE: | | ImplicitPart -> 
+!PARSE-TREE: | | DeclarationConstruct -> SpecificationConstruct -> TypeDeclarationStmt
+!PARSE-TREE: | | | DeclarationTypeSpec -> IntrinsicTypeSpec -> IntegerTypeSpec -> KindSelector -> Scalar -> Integer -> Constant -> Expr -> Designator -> DataRef -> Name = 'omp_interop_kind'
+!PARSE-TREE: | | | EntityDecl
+!PARSE-TREE: | | | | Name = 'obj'
+!PARSE-TREE: | | DeclarationConstruct -> SpecificationConstruct -> TypeDeclarationStmt
+!PARSE-TREE: | | | DeclarationTypeSpec -> IntrinsicTypeSpec -> IntegerTypeSpec -> 
+!PARSE-TREE: | | | AttrSpec -> ArraySpec -> ExplicitShapeSpec
+!PARSE-TREE: | | | | SpecificationExpr -> Scalar -> Integer -> Expr -> LiteralConstant -> IntLiteralConstant = '1'
+!PARSE-TREE: | | | ExplicitShapeSpec
+!PARSE-TREE: | | | | SpecificationExpr -> Scalar -> Integer -> Expr -> LiteralConstant -> IntLiteralConstant = '10'
+!PARSE-TREE: | | | EntityDecl
+!PARSE-TREE: | | | | Name = 'arr'
+!PARSE-TREE: | ExecutionPart -> Block
+!PARSE-TREE: | | ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OpenMPStandaloneConstruct -> OpenMPInteropConstruct
+!PARSE-TREE: | | | Verbatim
+!PARSE-TREE: | | | OmpClauseList -> OmpClause -> Init -> OmpInitClause
+!PARSE-TREE: | | | | InteropModifier -> InteropPreference -> CharLiteralConstant
+!PARSE-TREE: | | | | | string = 'cuda'
+!PARSE-TREE: | | | | InteropTypes -> InteropType -> Kind = TargetSync
+!PARSE-TREE: | | | | InteropType -> Kind = Target
+!PARSE-TREE: | | | | InteropVar -> OmpObject -> Designator -> DataRef -> Name = 'obj'
+!PARSE-TREE: | | | OmpClause -> Depend -> OmpDependClause -> TaskDep
+!PARSE-TREE: | | | | Modifier -> OmpTaskDependenceType -> Value = Inout
+!PARSE-TREE: | | | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'arr'
+!PARSE-TREE: | | | OmpClause -> Nowait
+!PARSE-TREE: | | ExecutionPartConstruct -> ExecutableConstruct -> ActionStmt -> PrintStmt
+!PARSE-TREE: | | | Format -> Star
+!PARSE-TREE: | | | OutputItem -> Expr -> LiteralConstant -> CharLiteralConstant
+!PARSE-TREE: | | | | string = 'pass'
+!PARSE-TREE: | EndSubroutineStmt -> Name = 'test_interop_04'
+
+
+subroutine test_interop_05()
+  use omp_lib
+  integer(omp_interop_kind) :: obj
+  !$omp interop init(prefer_type(omp_ifr_sycl), targetsync: obj) device(device_num:0)
+  print *,'pass'
+end subroutine test_interop_05
+
+!UNPARSE: SUBROUTINE test_interop_05
+!UNPARSE:  USE :: omp_lib
+!UNPARSE:  INTEGER(KIND=8_4) obj
+!UNPARSE: !$OMP INTEROP INIT(PREFER_TYPE(4_4),TARGETSYNC: obj) DEVICE(DEVICE_NUM: 0_4)
+!UNPARSE:  PRINT *, "pass"
+!UNPARSE: END SUBROUTINE test_interop_05
+
+!PARSE-TREE: | SubroutineStmt
+!PARSE-TREE: | | Name = 'test_interop_05'
+!PARSE-TREE: | SpecificationPart
+!PARSE-TREE: | | UseStmt
+!PARSE-TREE: | | | Name = 'omp_lib'
+!PARSE-TREE: | | ImplicitPart -> 
+!PARSE-TREE: | | DeclarationConstruct -> SpecificationConstruct -> TypeDeclarationStmt
+!PARSE-TREE: | | | DeclarationTypeSpec -> IntrinsicTypeSpec -> IntegerTypeSpec -> KindSelector -> Scalar -> Integer -> Constant -> Expr -> Designator -> DataRef -> Name = 'omp_interop_kind'
+!PARSE-TREE: | | | EntityDecl
+!PARSE-TREE: | | | | Name = 'obj'
+!PARSE-TREE: | ExecutionPart -> Block
+!PARSE-TREE: | | ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OpenMPStandaloneConstruct -> OpenMPInteropConstruct
+!PARSE-TREE: | | | Verbatim
+!PARSE-TREE: | | | OmpClauseList -> OmpClause -> Init -> OmpInitClause
+!PARSE-TREE: | | | | InteropModifier -> InteropPreference -> Scalar -> Integer -> Constant -> Expr -> Designator -> DataRef -> Name = 'omp_ifr_sycl'
+!PARSE-TREE: | | | | InteropTypes -> InteropType -> Kind = TargetSync
+!PARSE-TREE: | | | | InteropVar -> OmpObject -> Designator -> DataRef -> Name = 'obj'
+!PARSE-TREE: | | | OmpClause -> Device -> OmpDeviceClause
+!PARSE-TREE: | | | | Modifier -> OmpDeviceModifier -> Value = Device_Num
+!PARSE-TREE: | | | | Scalar -> Integer -> Expr -> LiteralConstant -> IntLiteralConstant = '0'
+!PARSE-TREE: | | ExecutionPartConstruct -> ExecutableConstruct -> ActionStmt -> PrintStmt
+!PARSE-TREE: | | | Format -> Star
+!PARSE-TREE: | | | OutputItem -> Expr -> LiteralConstant -> CharLiteralConstant
+!PARSE-TREE: | | | | string = 'pass'
+!PARSE-TREE: | EndSubroutineStmt -> Name = 'test_interop_05'
+
diff --git a/flang/test/Semantics/OpenMP/interop-construct.f90 b/flang/test/Semantics/OpenMP/interop-construct.f90
new file mode 100644
index 00000000000000..727455b1a369b3
--- /dev/null
+++ b/flang/test/Semantics/OpenMP/interop-construct.f90
@@ -0,0 +1,30 @@
+! REQUIRES: openmp_runtime
+
+! RUN: %python %S/../test_errors.py %s %flang -fopenmp -fopenmp-version=52
+! OpenMP Version 5.2
+! 14.1 Interop construct
+! To check various semantic errors for inteorp construct.
+
+subroutine test_interop_01()
+  use omp_lib
+  integer(omp_interop_kind) :: obj
+  !ERROR: Each interop-var may be specified for at most one action-clause of each interop construct.
+  !$omp interop init(targetsync,target: obj) use(obj)
+  print *, 'pass'
+end subroutine test_interop_01
+
+subroutine test_interop_02()
+  use omp_lib
+  integer(omp_interop_kind) :: obj
+  !ERROR: Each interop-type may be specified at most once.
+  !$omp interop init(targetsync,target,targetsync: obj)
+  print *, 'pass'
+end subroutine test_interop_02
+
+subroutine test_interop_03()
+  use omp_lib
+  integer(omp_interop_kind) :: obj
+  !ERROR: A depend clause can only appear on the directive if the interop-type includes targetsync
+  !$omp interop init(target: obj) depend(inout: obj)
+  print *, 'pass'
+end subroutine test_interop_03
\ No newline at end of file
diff --git a/llvm/include/llvm/Frontend/OpenMP/OMP.td b/llvm/include/llvm/Frontend/OpenMP/OMP.td
index e36eb77cefe7e3..099660eb6b5782 100644
--- a/llvm/include/llvm/Frontend/OpenMP/OMP.td
+++ b/llvm/include/llvm/Frontend/OpenMP/OMP.td
@@ -239,6 +239,7 @@ def OMPC_Indirect : Clause<"indirect"> {
 }
 def OMPC_Init : Clause<"init"> {
   let clangClass = "OMPInitClause";
+  let flangClass = "OmpInitClause";
 }
 def OMPC_InReduction : Clause<"in_reduction"> {
   let clangClass = "OMPInReductionClause";
@@ -507,6 +508,7 @@ def OMPC_Update : Clause<"update"> {
 }
 def OMPC_Use : Clause<"use"> {
   let clangClass = "OMPUseClause";
+  let flangClass = "OmpUseClause";
 }
 def OMPC_UsesAllocators : Clause<"uses_allocators"> {
   let clangClass = "OMPUsesAllocatorsClause";

>From 9e748a6cc5c42de4a674d0be7082738fae49b7ca Mon Sep 17 00:00:00 2001
From: swatheesh-mcw <swatheesh.muralidharan at multicorewareinc.com>
Date: Mon, 6 Jan 2025 18:48:49 +0530
Subject: [PATCH 2/2] Modified the declaration and definition of modifiers and
 addressed review comments.

---
 flang/examples/FeatureList/FeatureList.cpp    | 11 +++--
 flang/include/flang/Parser/dump-parse-tree.h  | 11 +++--
 flang/include/flang/Parser/parse-tree.h       | 44 +++++++++++++------
 .../flang/Semantics/openmp-modifiers.h        |  2 +
 flang/lib/Parser/openmp-parsers.cpp           | 31 +++++++------
 flang/lib/Parser/unparse.cpp                  | 29 +++++++++---
 flang/lib/Semantics/check-omp-structure.cpp   | 37 +++++++++-------
 flang/lib/Semantics/openmp-modifiers.cpp      | 32 ++++++++++++++
 .../test/Parser/OpenMP/interop-construct.f90  | 29 ++++++------
 9 files changed, 150 insertions(+), 76 deletions(-)

diff --git a/flang/examples/FeatureList/FeatureList.cpp b/flang/examples/FeatureList/FeatureList.cpp
index ac70de588c7d9f..443b9908e2294a 100644
--- a/flang/examples/FeatureList/FeatureList.cpp
+++ b/flang/examples/FeatureList/FeatureList.cpp
@@ -525,13 +525,12 @@ struct NodeVisitor {
   READ_FEATURE(OmpScheduleClause)
   READ_FEATURE(OmpScheduleClause::Kind)
   READ_FEATURE(OmpScheduleClause::Modifier)
-  READ_FEATURE(InteropType)
-  READ_FEATURE(InteropType::Kind)
-  READ_FEATURE(InteropPreference)
+  READ_FEATURE(OmpInteropType)
+  READ_FEATURE(OmpInteropType::Value)
+  READ_FEATURE(OmpInteropRuntimeIdentifier)
+  READ_FEATURE(OmpInteropPreference)
   READ_FEATURE(OmpInitClause)
-  READ_FEATURE(OmpInitClause::InteropModifier)
-  READ_FEATURE(OmpInitClause::InteropTypes)
-  READ_FEATURE(OmpInitClause::InteropVar)
+  READ_FEATURE(OmpInitClause::Modifier)
   READ_FEATURE(OmpUseClause)
   READ_FEATURE(OmpDeviceModifier)
   READ_FEATURE(OmpDeviceClause)
diff --git a/flang/include/flang/Parser/dump-parse-tree.h b/flang/include/flang/Parser/dump-parse-tree.h
index 5020d481dff29f..abe81c0e51af7d 100644
--- a/flang/include/flang/Parser/dump-parse-tree.h
+++ b/flang/include/flang/Parser/dump-parse-tree.h
@@ -620,13 +620,12 @@ class ParseTreeDumper {
   NODE_ENUM(OmpDeviceModifier, Value)
   NODE(parser, OmpDeviceTypeClause)
   NODE_ENUM(OmpDeviceTypeClause, DeviceTypeDescription)
-  NODE(parser, InteropType)
-  NODE_ENUM(InteropType, Kind)
-  NODE(parser, InteropPreference)
+  NODE(parser, OmpInteropType)
+  NODE_ENUM(OmpInteropType, Value)
+  NODE(parser, OmpInteropRuntimeIdentifier)
+  NODE(parser, OmpInteropPreference)
   NODE(parser, OmpInitClause)
-  NODE(OmpInitClause, InteropModifier)
-  NODE(OmpInitClause, InteropTypes)
-  NODE(OmpInitClause, InteropVar)
+  NODE(OmpInitClause, Modifier)
   NODE(parser, OmpUseClause)
   NODE(parser, OmpUpdateClause)
   NODE(parser, OmpChunkModifier)
diff --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h
index 3a0f41a67b01b0..34cbde1bba9770 100644
--- a/flang/include/flang/Parser/parse-tree.h
+++ b/flang/include/flang/Parser/parse-tree.h
@@ -3599,6 +3599,33 @@ struct OmpExpectation {
   WRAPPER_CLASS_BOILERPLATE(OmpExpectation, Value);
 };
 
+// REF: [5.1:217-220], [5.2:293-294]
+//
+// InteropType -> target || targetsync              // since 5.2
+// There can be at most only two interop-type.
+struct OmpInteropType {
+  ENUM_CLASS(Value, Target, TargetSync)
+  WRAPPER_CLASS_BOILERPLATE(OmpInteropType, Value);
+};
+
+// REF: [5.1:217-220], [5.2:293-294]
+//
+// OmpRuntimeIdentifier ->                          // since 5.2
+// CharLiteralConstant || ScalarIntConstantExpr
+struct OmpInteropRuntimeIdentifier {
+  UNION_CLASS_BOILERPLATE(OmpInteropRuntimeIdentifier);
+  std::variant<CharLiteralConstant, ScalarIntConstantExpr> u;
+};
+
+// REF: [5.1:217-220], [5.2:293-294]
+//
+// OmpInteropPreference ->                          // since 5.2
+// ([OmpRuntimeIdentifier, ...])
+struct OmpInteropPreference {
+  WRAPPER_CLASS_BOILERPLATE(
+      OmpInteropPreference, std::list<OmpInteropRuntimeIdentifier>);
+};
+
 // Ref: [5.0:47-49], [5.1:49-51], [5.2:67-69]
 //
 // iterator-modifier ->
@@ -4164,23 +4191,12 @@ struct OmpUpdateClause {
 //                              interop-type: interop-var)
 // interop-modifier: prefer_type(preference-list)
 // interop-type: target, targetsync
+// interop-var: Ompobject
 // There can be at most only two interop-type.
-struct InteropType {
-  ENUM_CLASS(Kind, Target, TargetSync)
-  WRAPPER_CLASS_BOILERPLATE(InteropType, Kind);
-};
-
-struct InteropPreference {
-  UNION_CLASS_BOILERPLATE(InteropPreference);
-  std::variant<CharLiteralConstant, ScalarIntConstantExpr> u;
-};
-
 struct OmpInitClause {
   TUPLE_CLASS_BOILERPLATE(OmpInitClause);
-  WRAPPER_CLASS(InteropModifier, std::list<InteropPreference>);
-  WRAPPER_CLASS(InteropTypes, std::list<InteropType>);
-  WRAPPER_CLASS(InteropVar, OmpObject);
-  std::tuple<std::optional<InteropModifier>, InteropTypes, InteropVar> t;
+  MODIFIER_BOILERPLATE(OmpInteropPreference, OmpInteropType);
+  std::tuple<MODIFIERS(), OmpObject> t;
 };
 
 // REF: [5.1:217-220], [5.2:294]
diff --git a/flang/include/flang/Semantics/openmp-modifiers.h b/flang/include/flang/Semantics/openmp-modifiers.h
index 5d5c5e97faf413..5c6811fe29eddb 100644
--- a/flang/include/flang/Semantics/openmp-modifiers.h
+++ b/flang/include/flang/Semantics/openmp-modifiers.h
@@ -76,6 +76,8 @@ DECLARE_DESCRIPTOR(parser::OmpDependenceType);
 DECLARE_DESCRIPTOR(parser::OmpDeviceModifier);
 DECLARE_DESCRIPTOR(parser::OmpDirectiveNameModifier);
 DECLARE_DESCRIPTOR(parser::OmpExpectation);
+DECLARE_DESCRIPTOR(parser::OmpInteropPreference);
+DECLARE_DESCRIPTOR(parser::OmpInteropType);
 DECLARE_DESCRIPTOR(parser::OmpIterator);
 DECLARE_DESCRIPTOR(parser::OmpLastprivateModifier);
 DECLARE_DESCRIPTOR(parser::OmpLinearModifier);
diff --git a/flang/lib/Parser/openmp-parsers.cpp b/flang/lib/Parser/openmp-parsers.cpp
index ac9f7a45dbd77e..cc678940fd8297 100644
--- a/flang/lib/Parser/openmp-parsers.cpp
+++ b/flang/lib/Parser/openmp-parsers.cpp
@@ -179,6 +179,10 @@ TYPE_PARSER(construct<OmpDeviceModifier>(
 TYPE_PARSER(construct<OmpExpectation>( //
     "PRESENT" >> pure(OmpExpectation::Value::Present)))
 
+TYPE_PARSER(construct<OmpInteropType>(
+    "TARGETSYNC" >> pure(OmpInteropType::Value::TargetSync) ||
+    "TARGET" >> pure(OmpInteropType::Value::Target)))
+
 TYPE_PARSER(construct<OmpIteratorSpecifier>(
     // Using Parser<TypeDeclarationStmt> or Parser<EntityDecl> has the problem
     // that they will attempt to treat what follows the '=' as initialization.
@@ -251,6 +255,10 @@ TYPE_PARSER(construct<OmpReductionModifier>(
     "TASK" >> pure(OmpReductionModifier::Value::Task) ||
     "DEFAULT" >> pure(OmpReductionModifier::Value::Default)))
 
+TYPE_PARSER(construct<OmpInteropRuntimeIdentifier>(
+    construct<OmpInteropRuntimeIdentifier>(charLiteralConstant) ||
+    construct<OmpInteropRuntimeIdentifier>(scalarIntConstantExpr)))
+
 TYPE_PARSER(construct<OmpStepComplexModifier>( //
     "STEP" >> parenthesized(scalarIntExpr)))
 
@@ -306,6 +314,14 @@ TYPE_PARSER(sourced(
 
 TYPE_PARSER(sourced(construct<OmpIfClause::Modifier>(OmpDirectiveNameParser{})))
 
+TYPE_PARSER(construct<OmpInteropPreference>(verbatim("PREFER_TYPE"_tok) >>
+    parenthesized(nonemptyList(Parser<OmpInteropRuntimeIdentifier>{}))))
+
+TYPE_PARSER(sourced(
+    construct<OmpInitClause::Modifier>(
+        construct<OmpInitClause::Modifier>(Parser<OmpInteropPreference>{})) ||
+    construct<OmpInitClause::Modifier>(Parser<OmpInteropType>{})))
+
 TYPE_PARSER(sourced(construct<OmpInReductionClause::Modifier>(
     Parser<OmpReductionIdentifier>{})))
 
@@ -531,21 +547,10 @@ TYPE_PARSER(
 // OpenMPv5.2 12.5.2 detach-clause -> DETACH (event-handle)
 TYPE_PARSER(construct<OmpDetachClause>(Parser<OmpObject>{}))
 
-// InteropTypes
-TYPE_PARSER(construct<InteropType>(
-    "TARGETSYNC" >> pure(InteropType::Kind::TargetSync) ||
-    "TARGET" >> pure(InteropType::Kind::Target)))
-
-// InteropPreference
-TYPE_PARSER(construct<InteropPreference>(
-    construct<InteropPreference>(charLiteralConstant) ||
-    construct<InteropPreference>(scalarIntConstantExpr)))
-
 // init clause
 TYPE_PARSER(construct<OmpInitClause>(
-    maybe(verbatim("PREFER_TYPE"_tok) >>
-        parenthesized(nonemptyList(Parser<InteropPreference>{})) / ","),
-    nonemptyList(Parser<InteropType>{}) / ":", Parser<OmpObject>{}))
+    maybe(nonemptyList(Parser<OmpInitClause::Modifier>{}) / ":"),
+    Parser<OmpObject>{}))
 
 // 2.8.1 ALIGNED (list: alignment)
 TYPE_PARSER(construct<OmpAlignedClause>(Parser<OmpObjectList>{},
diff --git a/flang/lib/Parser/unparse.cpp b/flang/lib/Parser/unparse.cpp
index 00957c6c424019..147bb06d9161bd 100644
--- a/flang/lib/Parser/unparse.cpp
+++ b/flang/lib/Parser/unparse.cpp
@@ -2097,14 +2097,29 @@ class UnparseVisitor {
     Walk(std::get<std::optional<std::list<Modifier>>>(x.t), ": ");
     Walk(std::get<OmpObjectList>(x.t));
   }
-  void Unparse(const OmpInitClause::InteropTypes &x) { Walk(x.v, ","); }
-  void Unparse(const OmpInitClause::InteropModifier &x) { Walk(x.v, ","); }
+  void Unparse(const OmpInteropPreference &x) { Walk(x.v, ","); }
   void Unparse(const OmpInitClause &x) {
-    Walk("PREFER_TYPE(",
-        std::get<std::optional<OmpInitClause::InteropModifier>>(x.t), "),");
-    Walk(std::get<OmpInitClause::InteropTypes>(x.t));
+    using Modifier = OmpInitClause::Modifier;
+    auto &modifiers{std::get<std::optional<std::list<Modifier>>>(x.t)};
+    bool is_type_start = true;
+    for (const Modifier &m : *modifiers) {
+      if (auto *interop_preference_mod{
+              std::get_if<parser::OmpInteropPreference>(&m.u)}) {
+        Put("PREFER_TYPE(");
+        Walk(*interop_preference_mod);
+        Put("),");
+      } else if (auto *interop_type_mod{
+                     std::get_if<parser::OmpInteropType>(&m.u)}) {
+        if (is_type_start) {
+          is_type_start = false;
+        } else {
+          Put(",");
+        }
+        Walk(*interop_type_mod);
+      }
+    }
     Put(": ");
-    Walk(std::get<OmpInitClause::InteropVar>(x.t));
+    Walk(std::get<OmpObject>(x.t));
   }
   void Unparse(const OmpMapClause &x) {
     using Modifier = OmpMapClause::Modifier;
@@ -2941,7 +2956,7 @@ class UnparseVisitor {
       OmpDeviceTypeClause, DeviceTypeDescription) // OMP device_type
   WALK_NESTED_ENUM(OmpReductionModifier, Value) // OMP reduction-modifier
   WALK_NESTED_ENUM(OmpExpectation, Value) // OMP motion-expectation
-  WALK_NESTED_ENUM(InteropType, Kind) // OMP InteropVar
+  WALK_NESTED_ENUM(OmpInteropType, Value) // OMP InteropType
   WALK_NESTED_ENUM(OmpCancelType, Type) // OMP cancel-type
   WALK_NESTED_ENUM(OmpOrderClause, Ordering) // OMP ordering
   WALK_NESTED_ENUM(OmpOrderModifier, Value) // OMP order-modifier
diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index 68a041fe6e9eeb..ac5de07aed7556 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -4812,24 +4812,31 @@ void OmpStructureChecker::Enter(const parser::OpenMPInteropConstruct &x) {
     common::visit(
         common::visitors{
             [&](const parser::OmpClause::Init &InitClause) {
-              const auto &InteropTypeList{
-                  std::get<parser::OmpInitClause::InteropTypes>(
-                      InitClause.v.t)};
-              for (auto &InteropTypeVal : InteropTypeList.v) {
-                if (*(parser::Unwrap<parser::InteropType::Kind>(
-                        InteropTypeVal)) ==
-                    parser::InteropType::Kind::TargetSync) {
-                  ++targetSyncCount;
-                } else {
-                  ++targetCount;
-                }
-                if (targetCount > 1 || targetSyncCount > 1) {
-                  context_.Say(GetContext().directiveSource,
-                      "Each interop-type may be specified at most once."_err_en_US);
+              if (OmpVerifyModifiers(InitClause.v, llvm::omp::OMPC_init,
+                      GetContext().directiveSource, context_)) {
+
+                auto &modifiers{OmpGetModifiers(InitClause.v)};
+                auto &&interopTypeModifier{
+                    OmpGetRepeatableModifier<parser::OmpInteropType>(
+                        modifiers)};
+                for (auto it{interopTypeModifier.begin()},
+                     end{interopTypeModifier.end()};
+                     it != end; ++it) {
+                  if (parser::ToUpperCaseLetters(
+                          parser::OmpInteropType::EnumToString((*it)->v)) ==
+                      "TARGETSYNC") {
+                    ++targetSyncCount;
+                  } else {
+                    ++targetCount;
+                  }
+                  if (targetCount > 1 || targetSyncCount > 1) {
+                    context_.Say(GetContext().directiveSource,
+                        "Each interop-type may be specified at most once."_err_en_US);
+                  }
                 }
               }
               const auto &InteropVar{parser::Unwrap<parser::OmpObject>(
-                  std::get<parser::OmpInitClause::InteropVar>(InitClause.v.t))};
+                  std::get<parser::OmpObject>(InitClause.v.t))};
               const auto *name{parser::Unwrap<parser::Name>(InteropVar)};
               const auto ObjectName{name->ToString()};
               if (ObjectNameList.end() !=
diff --git a/flang/lib/Semantics/openmp-modifiers.cpp b/flang/lib/Semantics/openmp-modifiers.cpp
index 9f2896229bb7ff..8a2e59ef332a58 100644
--- a/flang/lib/Semantics/openmp-modifiers.cpp
+++ b/flang/lib/Semantics/openmp-modifiers.cpp
@@ -223,6 +223,38 @@ const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpExpectation>() {
   return desc;
 }
 
+template <>
+const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpInteropPreference>() {
+  static const OmpModifierDescriptor desc{
+      /*name=*/"interop-preference",
+      /*props=*/
+      {
+          {52, {OmpProperty::Unique}},
+      },
+      /*clauses=*/
+      {
+          {52, {Clause::OMPC_init}},
+      },
+  };
+  return desc;
+}
+
+template <>
+const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpInteropType>() {
+  static const OmpModifierDescriptor desc{
+      /*name=*/"interop-type",
+      /*props=*/
+      {
+          {52, {OmpProperty::Required}},
+      },
+      /*clauses=*/
+      {
+          {52, {Clause::OMPC_init}},
+      },
+  };
+  return desc;
+}
+
 template <>
 const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpIterator>() {
   static const OmpModifierDescriptor desc{
diff --git a/flang/test/Parser/OpenMP/interop-construct.f90 b/flang/test/Parser/OpenMP/interop-construct.f90
index 9fd2b3d63d5c5d..37078f68e3e7c8 100644
--- a/flang/test/Parser/OpenMP/interop-construct.f90
+++ b/flang/test/Parser/OpenMP/interop-construct.f90
@@ -1,5 +1,5 @@
-! RUN: %flang_fc1 -fdebug-unparse -fopenmp %s | FileCheck --ignore-case --check-prefix="UNPARSE" %s 
-! RUN: %flang_fc1 -fdebug-dump-parse-tree-no-sema -fopenmp %s | FileCheck --check-prefix="PARSE-TREE" %s
+! RUN: %flang_fc1 -fdebug-unparse -fopenmp-version=52 -fopenmp %s | FileCheck --ignore-case --check-prefix="UNPARSE" %s 
+! RUN: %flang_fc1 -fdebug-dump-parse-tree-no-sema -fopenmp-version=52 -fopenmp %s | FileCheck --check-prefix="PARSE-TREE" %s
 
 subroutine test_interop_01()
   !$omp interop device(1)
@@ -7,7 +7,7 @@ subroutine test_interop_01()
 end subroutine test_interop_01
 
 !UNPARSE: SUBROUTINE test_interop_01
-!UNPARSE: !$OMP INTEROP  DEVICE(1_4)
+!UNPARSE: !$OMP INTEROP DEVICE(1_4)
 !UNPARSE:  PRINT *, "pass"
 !UNPARSE: END SUBROUTINE test_interop_01
 
@@ -58,8 +58,8 @@ end subroutine test_interop_02
 !PARSE-TREE: | | ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OpenMPStandaloneConstruct -> OpenMPInteropConstruct
 !PARSE-TREE: | | | Verbatim
 !PARSE-TREE: | | | OmpClauseList -> OmpClause -> Init -> OmpInitClause
-!PARSE-TREE: | | | | InteropTypes -> InteropType -> Kind = TargetSync
-!PARSE-TREE: | | | | InteropVar -> OmpObject -> Designator -> DataRef -> Name = 'obj'
+!PARSE-TREE: | | | | Modifier -> OmpInteropType -> Value = TargetSync
+!PARSE-TREE: | | | | OmpObject -> Designator -> DataRef -> Name = 'obj'
 !PARSE-TREE: | | | OmpClause -> Use -> OmpUseClause -> OmpObject -> Designator -> DataRef -> Name = 'obj1'
 !PARSE-TREE: | | | OmpClause -> Destroy -> OmpDestroyClause -> OmpObject -> Designator -> DataRef -> Name = 'obj3'
 !PARSE-TREE: | | ExecutionPartConstruct -> ExecutableConstruct -> ActionStmt -> PrintStmt
@@ -96,8 +96,8 @@ end subroutine test_interop_03
 !PARSE-TREE: | | ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OpenMPStandaloneConstruct -> OpenMPInteropConstruct
 !PARSE-TREE: | | | Verbatim
 !PARSE-TREE: | | | OmpClauseList -> OmpClause -> Init -> OmpInitClause
-!PARSE-TREE: | | | | InteropTypes -> InteropType -> Kind = TargetSync
-!PARSE-TREE: | | | | InteropVar -> OmpObject -> Designator -> DataRef -> Name = 'obj'
+!PARSE-TREE: | | | | Modifier -> OmpInteropType -> Value = TargetSync
+!PARSE-TREE: | | | | OmpObject -> Designator -> DataRef -> Name = 'obj'
 !PARSE-TREE: | | | OmpClause -> Depend -> OmpDependClause -> TaskDep
 !PARSE-TREE: | | | | Modifier -> OmpTaskDependenceType -> Value = Inout
 !PARSE-TREE: | | | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'obj'
@@ -146,11 +146,11 @@ end subroutine test_interop_04
 !PARSE-TREE: | | ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OpenMPStandaloneConstruct -> OpenMPInteropConstruct
 !PARSE-TREE: | | | Verbatim
 !PARSE-TREE: | | | OmpClauseList -> OmpClause -> Init -> OmpInitClause
-!PARSE-TREE: | | | | InteropModifier -> InteropPreference -> CharLiteralConstant
+!PARSE-TREE: | | | | Modifier -> OmpInteropPreference -> OmpInteropRuntimeIdentifier -> CharLiteralConstant
 !PARSE-TREE: | | | | | string = 'cuda'
-!PARSE-TREE: | | | | InteropTypes -> InteropType -> Kind = TargetSync
-!PARSE-TREE: | | | | InteropType -> Kind = Target
-!PARSE-TREE: | | | | InteropVar -> OmpObject -> Designator -> DataRef -> Name = 'obj'
+!PARSE-TREE: | | | | Modifier -> OmpInteropType -> Value = TargetSync
+!PARSE-TREE: | | | | Modifier -> OmpInteropType -> Value = Target
+!PARSE-TREE: | | | | OmpObject -> Designator -> DataRef -> Name = 'obj'
 !PARSE-TREE: | | | OmpClause -> Depend -> OmpDependClause -> TaskDep
 !PARSE-TREE: | | | | Modifier -> OmpTaskDependenceType -> Value = Inout
 !PARSE-TREE: | | | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'arr'
@@ -161,7 +161,6 @@ end subroutine test_interop_04
 !PARSE-TREE: | | | | string = 'pass'
 !PARSE-TREE: | EndSubroutineStmt -> Name = 'test_interop_04'
 
-
 subroutine test_interop_05()
   use omp_lib
   integer(omp_interop_kind) :: obj
@@ -190,9 +189,9 @@ end subroutine test_interop_05
 !PARSE-TREE: | | ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OpenMPStandaloneConstruct -> OpenMPInteropConstruct
 !PARSE-TREE: | | | Verbatim
 !PARSE-TREE: | | | OmpClauseList -> OmpClause -> Init -> OmpInitClause
-!PARSE-TREE: | | | | InteropModifier -> InteropPreference -> Scalar -> Integer -> Constant -> Expr -> Designator -> DataRef -> Name = 'omp_ifr_sycl'
-!PARSE-TREE: | | | | InteropTypes -> InteropType -> Kind = TargetSync
-!PARSE-TREE: | | | | InteropVar -> OmpObject -> Designator -> DataRef -> Name = 'obj'
+!PARSE-TREE: | | | | Modifier -> OmpInteropPreference -> OmpInteropRuntimeIdentifier -> Scalar -> Integer -> Constant -> Expr -> Designator -> DataRef -> Name = 'omp_ifr_sycl'
+!PARSE-TREE: | | | | Modifier -> OmpInteropType -> Value = TargetSync
+!PARSE-TREE: | | | | OmpObject -> Designator -> DataRef -> Name = 'obj'
 !PARSE-TREE: | | | OmpClause -> Device -> OmpDeviceClause
 !PARSE-TREE: | | | | Modifier -> OmpDeviceModifier -> Value = Device_Num
 !PARSE-TREE: | | | | Scalar -> Integer -> Expr -> LiteralConstant -> IntLiteralConstant = '0'



More information about the flang-commits mailing list