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

via flang-commits flang-commits at lists.llvm.org
Thu Dec 19 06:26:24 PST 2024


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

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.

>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] 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";



More information about the flang-commits mailing list