[flang] [llvm] [flang][OpenMP] Parser support for DEPOBJ plus DEPEND, DESTROY, UPDATE (PR #114074)

Krzysztof Parzyszek via llvm-commits llvm-commits at lists.llvm.org
Tue Oct 29 08:43:15 PDT 2024


https://github.com/kparzysz created https://github.com/llvm/llvm-project/pull/114074

Parse the DEPOBJ construct and the associated clauses, perform basic semantic checks.

>From 24e8174c47379351577cfd7b7772fee267681bf8 Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <Krzysztof.Parzyszek at amd.com>
Date: Fri, 25 Oct 2024 12:01:29 -0500
Subject: [PATCH] [flang][OpenMP] Parser support for DEPOBJ plus DEPEND,
 DESTROY, UPDATE

Parse the DEPOBJ construct and the associated clauses, perform basic
semantic checks.
---
 flang/include/flang/Parser/dump-parse-tree.h  |   3 +
 flang/include/flang/Parser/parse-tree.h       |  57 +++++--
 flang/include/flang/Semantics/symbol.h        |   2 +-
 flang/lib/Lower/OpenMP/ClauseProcessor.cpp    |   2 +
 flang/lib/Lower/OpenMP/Clauses.cpp            |  49 ++++--
 flang/lib/Lower/OpenMP/Clauses.h              |   1 +
 flang/lib/Lower/OpenMP/OpenMP.cpp             |  15 ++
 flang/lib/Parser/openmp-parsers.cpp           |  18 ++-
 flang/lib/Parser/parse-tree.cpp               |  17 ++
 flang/lib/Parser/unparse.cpp                  |  12 +-
 flang/lib/Semantics/check-omp-structure.cpp   | 152 ++++++++++++++++--
 flang/lib/Semantics/check-omp-structure.h     |   2 +
 flang/lib/Semantics/resolve-directives.cpp    |   8 +
 flang/lib/Semantics/resolve-names.cpp         |   7 +
 .../Lower/OpenMP/Todo/depobj-construct.f90    |   9 ++
 flang/test/Parser/OpenMP/depobj-construct.f90 |  64 ++++++++
 .../Semantics/OpenMP/depobj-construct-v50.f90 |  28 ++++
 .../Semantics/OpenMP/depobj-construct-v51.f90 |  13 ++
 .../Semantics/OpenMP/depobj-construct-v52.f90 |  15 ++
 llvm/include/llvm/Frontend/OpenMP/ClauseT.h   |   3 +-
 llvm/include/llvm/Frontend/OpenMP/OMP.td      |   3 +
 21 files changed, 429 insertions(+), 51 deletions(-)
 create mode 100644 flang/test/Lower/OpenMP/Todo/depobj-construct.f90
 create mode 100644 flang/test/Parser/OpenMP/depobj-construct.f90
 create mode 100644 flang/test/Semantics/OpenMP/depobj-construct-v50.f90
 create mode 100644 flang/test/Semantics/OpenMP/depobj-construct-v51.f90
 create mode 100644 flang/test/Semantics/OpenMP/depobj-construct-v52.f90

diff --git a/flang/include/flang/Parser/dump-parse-tree.h b/flang/include/flang/Parser/dump-parse-tree.h
index 31ad1b7c6ce5b5..67f7e1aac40edb 100644
--- a/flang/include/flang/Parser/dump-parse-tree.h
+++ b/flang/include/flang/Parser/dump-parse-tree.h
@@ -517,6 +517,7 @@ class ParseTreeDumper {
   NODE_ENUM(OmpTaskDependenceType, Type)
   NODE(parser, OmpDependSinkVec)
   NODE(parser, OmpDependSinkVecLength)
+  NODE(parser, OmpDestroyClause)
   NODE(parser, OmpEndAllocators)
   NODE(parser, OmpEndAtomic)
   NODE(parser, OmpEndBlockDirective)
@@ -571,6 +572,7 @@ class ParseTreeDumper {
   NODE_ENUM(OmpDeviceClause, DeviceModifier)
   NODE(parser, OmpDeviceTypeClause)
   NODE_ENUM(OmpDeviceTypeClause, Type)
+  NODE(parser, OmpUpdateClause)
   NODE(parser, OmpScheduleModifier)
   NODE(OmpScheduleModifier, Modifier1)
   NODE(OmpScheduleModifier, Modifier2)
@@ -609,6 +611,7 @@ class ParseTreeDumper {
   NODE(parser, OmpAtomicClauseList)
   NODE(parser, OmpAtomicDefaultMemOrderClause)
   NODE_ENUM(common, OmpAtomicDefaultMemOrderType)
+  NODE(parser, OpenMPDepobjConstruct)
   NODE(parser, OpenMPFlushConstruct)
   NODE(parser, OpenMPLoopConstruct)
   NODE(parser, OpenMPExecutableAllocate)
diff --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h
index 174f4c631e9d4c..13c3353512208b 100644
--- a/flang/include/flang/Parser/parse-tree.h
+++ b/flang/include/flang/Parser/parse-tree.h
@@ -3447,7 +3447,7 @@ WRAPPER_CLASS(OmpObjectList, std::list<OmpObject>);
 //    MUTEXINOUTSET | DEPOBJ |  // since 5.0
 //    INOUTSET                  // since 5.2
 struct OmpTaskDependenceType {
-  ENUM_CLASS(Type, In, Out, Inout, Source, Sink)
+  ENUM_CLASS(Type, In, Out, Inout, Source, Sink, Depobj)
   WRAPPER_CLASS_BOILERPLATE(OmpTaskDependenceType, Type);
 };
 
@@ -3527,19 +3527,6 @@ struct OmpDefaultmapClause {
   std::tuple<ImplicitBehavior, std::optional<VariableCategory>> t;
 };
 
-// device([ device-modifier :] scalar-integer-expression)
-struct OmpDeviceClause {
-  TUPLE_CLASS_BOILERPLATE(OmpDeviceClause);
-  ENUM_CLASS(DeviceModifier, Ancestor, Device_Num)
-  std::tuple<std::optional<DeviceModifier>, ScalarIntExpr> t;
-};
-
-// device_type(any | host | nohost)
-struct OmpDeviceTypeClause {
-  ENUM_CLASS(Type, Any, Host, Nohost)
-  WRAPPER_CLASS_BOILERPLATE(OmpDeviceTypeClause, Type);
-};
-
 // 2.13.9 depend-vec-length -> +/- non-negative-constant
 struct OmpDependSinkVecLength {
   TUPLE_CLASS_BOILERPLATE(OmpDependSinkVecLength);
@@ -3561,6 +3548,8 @@ struct OmpDependSinkVec {
 //
 // depend-modifier -> iterator-modifier              // since 5.0
 struct OmpDependClause {
+  OmpTaskDependenceType::Type GetDepType() const;
+
   UNION_CLASS_BOILERPLATE(OmpDependClause);
   EMPTY_CLASS(Source);
   WRAPPER_CLASS(Sink, std::list<OmpDependSinkVec>);
@@ -3573,6 +3562,26 @@ struct OmpDependClause {
   std::variant<Source, Sink, InOut> u;
 };
 
+// Ref: [5.0:254-255], [5.1:287-288], [5.2:73]
+//
+// destroy-clause ->
+//    DESTROY |             // since 5.0, until 5.2
+//    DESTROY(variable)     // since 5.2
+WRAPPER_CLASS(OmpDestroyClause, OmpObject);
+
+// device([ device-modifier :] scalar-integer-expression)
+struct OmpDeviceClause {
+  TUPLE_CLASS_BOILERPLATE(OmpDeviceClause);
+  ENUM_CLASS(DeviceModifier, Ancestor, Device_Num)
+  std::tuple<std::optional<DeviceModifier>, ScalarIntExpr> t;
+};
+
+// device_type(any | host | nohost)
+struct OmpDeviceTypeClause {
+  ENUM_CLASS(Type, Any, Host, Nohost)
+  WRAPPER_CLASS_BOILERPLATE(OmpDeviceTypeClause, Type);
+};
+
 // OMP 5.2 12.6.1 grainsize-clause -> grainsize ([prescriptiveness :] value)
 struct OmpGrainsizeClause {
   TUPLE_CLASS_BOILERPLATE(OmpGrainsizeClause);
@@ -3716,6 +3725,11 @@ struct OmpNumTasksClause {
   std::tuple<std::optional<Prescriptiveness>, ScalarIntExpr> t;
 };
 
+// Ref: [5.0:254-255], [5.1:287-288], [5.2:321-322]
+//
+// update-clause -> UPDATE(task-dependence-type)    // since 5.0
+WRAPPER_CLASS(OmpUpdateClause, OmpTaskDependenceType);
+
 // OpenMP Clauses
 struct OmpClause {
   UNION_CLASS_BOILERPLATE(OmpClause);
@@ -4023,6 +4037,18 @@ struct OpenMPCancelConstruct {
   std::tuple<Verbatim, OmpCancelType, std::optional<If>> t;
 };
 
+// Ref: [5.0:254-255], [5.1:287-288], [5.2:322-323]
+//
+// depobj-construct -> DEPOBJ(depend-object) depobj-clause  // since 5.0
+// depobj-clause -> depend-clause |                         // until 5.2
+//                  destroy-clause |
+//                  update-clause
+struct OpenMPDepobjConstruct {
+  TUPLE_CLASS_BOILERPLATE(OpenMPDepobjConstruct);
+  CharBlock source;
+  std::tuple<Verbatim, OmpObject, OmpClause> t;
+};
+
 // 2.17.8 flush -> FLUSH [memory-order-clause] [(variable-name-list)]
 struct OpenMPFlushConstruct {
   TUPLE_CLASS_BOILERPLATE(OpenMPFlushConstruct);
@@ -4047,7 +4073,8 @@ struct OpenMPStandaloneConstruct {
   UNION_CLASS_BOILERPLATE(OpenMPStandaloneConstruct);
   CharBlock source;
   std::variant<OpenMPSimpleStandaloneConstruct, OpenMPFlushConstruct,
-      OpenMPCancelConstruct, OpenMPCancellationPointConstruct>
+      OpenMPCancelConstruct, OpenMPCancellationPointConstruct,
+      OpenMPDepobjConstruct>
       u;
 };
 
diff --git a/flang/include/flang/Semantics/symbol.h b/flang/include/flang/Semantics/symbol.h
index 0767d8ea84bc6b..b9512f33eaacd5 100644
--- a/flang/include/flang/Semantics/symbol.h
+++ b/flang/include/flang/Semantics/symbol.h
@@ -755,7 +755,7 @@ class Symbol {
       OmpDeclarativeAllocateDirective, OmpExecutableAllocateDirective,
       OmpDeclareSimd, OmpDeclareTarget, OmpThreadprivate, OmpDeclareReduction,
       OmpFlushed, OmpCriticalLock, OmpIfSpecified, OmpNone, OmpPreDetermined,
-      OmpImplicit);
+      OmpImplicit, OmpDependObject);
   using Flags = common::EnumSet<Flag, Flag_enumSize>;
 
   const Scope &owner() const { return *owner_; }
diff --git a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
index 7c254ce673855a..8eb1fdb4709178 100644
--- a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
+++ b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
@@ -137,6 +137,8 @@ genDependKindAttr(fir::FirOpBuilder &firOpBuilder,
   case omp::clause::Depend::TaskDependenceType::Mutexinoutset:
   case omp::clause::Depend::TaskDependenceType::Inoutset:
   case omp::clause::Depend::TaskDependenceType::Depobj:
+  case omp::clause::Depend::TaskDependenceType::Sink:
+  case omp::clause::Depend::TaskDependenceType::Source:
     llvm_unreachable("unhandled parser task dependence type");
     break;
   }
diff --git a/flang/lib/Lower/OpenMP/Clauses.cpp b/flang/lib/Lower/OpenMP/Clauses.cpp
index 9483f643acd55a..4fc910ce4c1e78 100644
--- a/flang/lib/Lower/OpenMP/Clauses.cpp
+++ b/flang/lib/Lower/OpenMP/Clauses.cpp
@@ -338,6 +338,27 @@ ReductionOperator makeReductionOperator(const parser::OmpReductionOperator &inp,
       inp.u);
 }
 
+clause::TaskDependenceType
+makeDepType(const parser::OmpTaskDependenceType &inp) {
+  switch (inp.v) {
+    case parser::OmpTaskDependenceType::Type::Depobj:
+      return clause::TaskDependenceType::Depobj;
+    case parser::OmpTaskDependenceType::Type::In:
+      return clause::TaskDependenceType::In;
+    case parser::OmpTaskDependenceType::Type::Inout:
+      return clause::TaskDependenceType::Inout;
+    // Inoutset        // missing-in-parser
+    // Mutexinoutset   // missing-in-parser
+    case parser::OmpTaskDependenceType::Type::Out:
+      return clause::TaskDependenceType::Out;
+    case parser::OmpTaskDependenceType::Type::Sink:
+      return clause::TaskDependenceType::Sink;
+    case parser::OmpTaskDependenceType::Type::Source:
+      return clause::TaskDependenceType::Source;
+  }
+  llvm_unreachable("Unexpected dependence type");
+}
+
 // --------------------------------------------------------------------
 // Actual clauses. Each T (where tomp::T exists in ClauseT) has its "make".
 
@@ -554,18 +575,6 @@ Depend make(const parser::OmpClause::Depend &inp,
   // Iteration is the equivalent of parser::OmpDependSinkVec
   using Iteration = Doacross::Vector::value_type; // LoopIterationT
 
-  CLAUSET_ENUM_CONVERT( //
-      convert1, parser::OmpTaskDependenceType::Type, Depend::TaskDependenceType,
-      // clang-format off
-      MS(In,     In)
-      MS(Out,    Out)
-      MS(Inout,  Inout)
-      // MS(, Mutexinoutset)   // missing-in-parser
-      // MS(, Inputset)        // missing-in-parser
-      // MS(, Depobj)          // missing-in-parser
-      // clang-format on
-  );
-
   return Depend{Fortran::common::visit( //
       common::visitors{
           // Doacross
@@ -602,7 +611,7 @@ Depend make(const parser::OmpClause::Depend &inp,
 
             auto &&maybeIter = maybeApply(
                 [&](auto &&s) { return makeIterator(s, semaCtx); }, t0);
-            return Depend::DepType{{/*TaskDependenceType=*/convert1(t1.v),
+            return Depend::DepType{{/*TaskDependenceType=*/makeDepType(t1),
                                     /*Iterator=*/std::move(maybeIter),
                                     /*LocatorList=*/makeObjects(t2, semaCtx)}};
           },
@@ -614,8 +623,14 @@ Depend make(const parser::OmpClause::Depend &inp,
 
 Destroy make(const parser::OmpClause::Destroy &inp,
              semantics::SemanticsContext &semaCtx) {
-  // inp -> empty
-  llvm_unreachable("Empty: destroy");
+  // inp.v -> std::optional<OmpDestroyClause>
+  auto &&maybeObject = maybeApply(
+      [&](const parser::OmpDestroyClause &c) {
+        return makeObject(c.v, semaCtx);
+      },
+      inp.v);
+
+  return Destroy{/*DestroyVar=*/std::move(maybeObject)};
 }
 
 Detach make(const parser::OmpClause::Detach &inp,
@@ -1279,8 +1294,8 @@ Uniform make(const parser::OmpClause::Uniform &inp,
 
 Update make(const parser::OmpClause::Update &inp,
             semantics::SemanticsContext &semaCtx) {
-  // inp -> empty
-  return Update{/*TaskDependenceType=*/std::nullopt};
+  // inp.v -> parser::OmpUpdateClause
+  return Update{/*TaskDependenceType=*/makeDepType(inp.v.v)};
 }
 
 Use make(const parser::OmpClause::Use &inp,
diff --git a/flang/lib/Lower/OpenMP/Clauses.h b/flang/lib/Lower/OpenMP/Clauses.h
index 1e911a20468575..51180ebfe5745e 100644
--- a/flang/lib/Lower/OpenMP/Clauses.h
+++ b/flang/lib/Lower/OpenMP/Clauses.h
@@ -152,6 +152,7 @@ using IteratorSpecifier = tomp::type::IteratorSpecifierT<TypeTy, IdTy, ExprTy>;
 using DefinedOperator = tomp::type::DefinedOperatorT<IdTy, ExprTy>;
 using ProcedureDesignator = tomp::type::ProcedureDesignatorT<IdTy, ExprTy>;
 using ReductionOperator = tomp::type::ReductionIdentifierT<IdTy, ExprTy>;
+using TaskDependenceType = tomp::type::TaskDependenceType;
 
 // "Requires" clauses are handled early on, and the aggregated information
 // is stored in the Symbol details of modules, programs, and subprograms.
diff --git a/flang/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp
index 01a40d6e2204ef..954d6b8d122f46 100644
--- a/flang/lib/Lower/OpenMP/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP/OpenMP.cpp
@@ -2699,6 +2699,21 @@ static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
   TODO(converter.getCurrentLocation(), "OpenMPCancelConstruct");
 }
 
+static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
+                   semantics::SemanticsContext &semaCtx,
+                   lower::pft::Evaluation &eval,
+                   const parser::OpenMPDepobjConstruct &construct) {
+  // These values will be ignored until the construct itself is implemented,
+  // but run them anyway for the sake of testing (via a Todo test).
+  auto &ompObj = std::get<parser::OmpObject>(construct.t);
+  const Object &depObj = makeObject(ompObj, semaCtx);
+  Clause clause = makeClause(std::get<parser::OmpClause>(construct.t), semaCtx);
+  (void)depObj;
+  (void)clause;
+
+  TODO(converter.getCurrentLocation(), "OpenMPDepobjConstruct");
+}
+
 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 598439cbee87e6..852898c6623dc6 100644
--- a/flang/lib/Parser/openmp-parsers.cpp
+++ b/flang/lib/Parser/openmp-parsers.cpp
@@ -366,9 +366,12 @@ TYPE_PARSER(
     construct<OmpDependSinkVec>(name, maybe(Parser<OmpDependSinkVecLength>{})))
 
 TYPE_PARSER(construct<OmpTaskDependenceType>(
+    "DEPOBJ" >> pure(OmpTaskDependenceType::Type::Depobj) ||
     "IN"_id >> pure(OmpTaskDependenceType::Type::In) ||
     "INOUT" >> pure(OmpTaskDependenceType::Type::Inout) ||
-    "OUT" >> pure(OmpTaskDependenceType::Type::Out)))
+    "OUT" >> pure(OmpTaskDependenceType::Type::Out) ||
+    "SINK" >> pure(OmpTaskDependenceType::Type::Sink) ||
+    "SOURCE" >> pure(OmpTaskDependenceType::Type::Source)))
 
 TYPE_CONTEXT_PARSER("Omp Depend clause"_en_US,
     construct<OmpDependClause>(construct<OmpDependClause::Sink>(
@@ -454,6 +457,9 @@ TYPE_PARSER(
                         parenthesized(Parser<OmpDefaultmapClause>{}))) ||
     "DEPEND" >> construct<OmpClause>(construct<OmpClause::Depend>(
                     parenthesized(Parser<OmpDependClause>{}))) ||
+    "DESTROY" >> construct<OmpClause>(construct<OmpClause::Destroy>(
+                     maybe(parenthesized(construct<OmpDestroyClause>(
+                         Parser<OmpObject>{}))))) ||
     "DEVICE" >> construct<OmpClause>(construct<OmpClause::Device>(
                     parenthesized(Parser<OmpDeviceClause>{}))) ||
     "DEVICE_TYPE" >> construct<OmpClause>(construct<OmpClause::DeviceType>(
@@ -560,7 +566,9 @@ TYPE_PARSER(
         construct<OmpClause>(construct<OmpClause::UnifiedSharedMemory>()) ||
     "UNIFORM" >> construct<OmpClause>(construct<OmpClause::Uniform>(
                      parenthesized(nonemptyList(name)))) ||
-    "UNTIED" >> construct<OmpClause>(construct<OmpClause::Untied>()))
+    "UNTIED" >> construct<OmpClause>(construct<OmpClause::Untied>()) ||
+    "UPDATE" >> construct<OmpClause>(construct<OmpClause::Update>(
+                    parenthesized(Parser<OmpTaskDependenceType>{}))))
 
 // [Clause, [Clause], ...]
 TYPE_PARSER(sourced(construct<OmpClauseList>(
@@ -673,6 +681,9 @@ TYPE_PARSER(sourced(construct<OmpAtomicClause>(
 TYPE_PARSER(sourced(construct<OmpAtomicClauseList>(
     many(maybe(","_tok) >> sourced(Parser<OmpAtomicClause>{})))))
 
+TYPE_PARSER(sourced(construct<OpenMPDepobjConstruct>(verbatim("DEPOBJ"_tok),
+    parenthesized(Parser<OmpObject>{}), sourced(Parser<OmpClause>{}))))
+
 TYPE_PARSER(sourced(construct<OpenMPFlushConstruct>(verbatim("FLUSH"_tok),
     many(maybe(","_tok) >> sourced(Parser<OmpMemoryOrderClause>{})),
     maybe(parenthesized(Parser<OmpObjectList>{})))))
@@ -697,7 +708,8 @@ TYPE_PARSER(
         construct<OpenMPStandaloneConstruct>(Parser<OpenMPFlushConstruct>{}) ||
         construct<OpenMPStandaloneConstruct>(Parser<OpenMPCancelConstruct>{}) ||
         construct<OpenMPStandaloneConstruct>(
-            Parser<OpenMPCancellationPointConstruct>{})) /
+            Parser<OpenMPCancellationPointConstruct>{}) ||
+        construct<OpenMPStandaloneConstruct>(Parser<OpenMPDepobjConstruct>{})) /
     endOfLine)
 
 // Directives enclosing structured-block
diff --git a/flang/lib/Parser/parse-tree.cpp b/flang/lib/Parser/parse-tree.cpp
index 948ad04a091a8c..60aef1666e9ba7 100644
--- a/flang/lib/Parser/parse-tree.cpp
+++ b/flang/lib/Parser/parse-tree.cpp
@@ -252,6 +252,23 @@ CharBlock Variable::GetSource() const {
 llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Name &x) {
   return os << x.ToString();
 }
+
+OmpTaskDependenceType::Type OmpDependClause::GetDepType() const {
+  return common::visit(
+      common::visitors{
+          [&](const parser::OmpDependClause::Source &) {
+            return parser::OmpTaskDependenceType::Type::Source;
+          },
+          [&](const parser::OmpDependClause::Sink &) {
+            return parser::OmpTaskDependenceType::Type::Sink;
+          },
+          [&](const parser::OmpDependClause::InOut &y) {
+            return std::get<parser::OmpTaskDependenceType>(y.t).v;
+          },
+      },
+      u);
+}
+
 } // namespace Fortran::parser
 
 template <typename C> static llvm::omp::Clause getClauseIdForClass(C &&) {
diff --git a/flang/lib/Parser/unparse.cpp b/flang/lib/Parser/unparse.cpp
index 39fcb61609e33b..32fe530e16f634 100644
--- a/flang/lib/Parser/unparse.cpp
+++ b/flang/lib/Parser/unparse.cpp
@@ -2215,11 +2215,9 @@ class UnparseVisitor {
     Walk(std::get<std::optional<OmpDependSinkVecLength>>(x.t));
   }
   void Unparse(const OmpDependClause::InOut &x) {
-    Put("(");
     Walk(std::get<OmpTaskDependenceType>(x.t));
     Put(":");
     Walk(std::get<OmpObjectList>(x.t));
-    Put(")");
   }
   bool Pre(const OmpDependClause &x) {
     return common::visit(
@@ -2706,6 +2704,16 @@ class UnparseVisitor {
                   },
         x.u);
   }
+  void Unparse(const OpenMPDepobjConstruct &x) {
+    BeginOpenMP();
+    Word("!$OMP DEPOBJ");
+    Put("(");
+    Walk(std::get<OmpObject>(x.t));
+    Put(") ");
+    Walk(std::get<OmpClause>(x.t));
+    Put("\n");
+    EndOpenMP();
+  }
   void Unparse(const OpenMPFlushConstruct &x) {
     BeginOpenMP();
     Word("!$OMP FLUSH ");
diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index 8f3eb9fefee678..64c2254b277502 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -1261,6 +1261,39 @@ void OmpStructureChecker::Leave(const parser::OpenMPDeclareSimdConstruct &) {
   dirContext_.pop_back();
 }
 
+void OmpStructureChecker::Enter(const parser::OpenMPDepobjConstruct &x) {
+  const auto &dir{std::get<parser::Verbatim>(x.t)};
+  PushContextAndClauseSets(dir.source, llvm::omp::Directive::OMPD_depobj);
+
+  // [5.2:73:27-28]
+  // If the destroy clause appears on a depobj construct, destroy-var must
+  // refer to the same depend object as the depobj argument of the construct.
+  auto &clause{std::get<parser::OmpClause>(x.t)};
+  if (clause.Id() == llvm::omp::Clause::OMPC_destroy) {
+    auto getSymbol = [&](const parser::OmpObject &obj) {
+      return common::visit(
+          [&](auto &&s) { return GetLastName(s).symbol; }, obj.u);
+    };
+
+    auto &wrapper{std::get<parser::OmpClause::Destroy>(clause.u)};
+    if (const std::optional<parser::OmpDestroyClause> &destroy{wrapper.v}) {
+      const Symbol *constrSym = getSymbol(std::get<parser::OmpObject>(x.t));
+      const Symbol *clauseSym = getSymbol(destroy->v);
+      assert(constrSym && "Unresolved depobj construct symbol");
+      assert(clauseSym && "Unresolved destroy symbol on depobj construct");
+      if (constrSym != clauseSym) {
+        context_.Say(x.source,
+            "The DESTROY clause must refer to the same object as the "
+            "DEPOBJ construct"_err_en_US);
+      }
+    }
+  }
+}
+
+void OmpStructureChecker::Leave(const parser::OpenMPDepobjConstruct &x) {
+  dirContext_.pop_back();
+}
+
 void OmpStructureChecker::Enter(const parser::OpenMPRequiresConstruct &x) {
   const auto &dir{std::get<parser::Verbatim>(x.t)};
   PushContextAndClauseSets(dir.source, llvm::omp::Directive::OMPD_requires);
@@ -2476,7 +2509,6 @@ CHECK_SIMPLE_CLAUSE(Capture, OMPC_capture)
 CHECK_SIMPLE_CLAUSE(Contains, OMPC_contains)
 CHECK_SIMPLE_CLAUSE(Default, OMPC_default)
 CHECK_SIMPLE_CLAUSE(Depobj, OMPC_depobj)
-CHECK_SIMPLE_CLAUSE(Destroy, OMPC_destroy)
 CHECK_SIMPLE_CLAUSE(Detach, OMPC_detach)
 CHECK_SIMPLE_CLAUSE(DeviceType, OMPC_device_type)
 CHECK_SIMPLE_CLAUSE(DistSchedule, OMPC_dist_schedule)
@@ -2519,7 +2551,6 @@ CHECK_SIMPLE_CLAUSE(Uniform, OMPC_uniform)
 CHECK_SIMPLE_CLAUSE(Unknown, OMPC_unknown)
 CHECK_SIMPLE_CLAUSE(Untied, OMPC_untied)
 CHECK_SIMPLE_CLAUSE(UsesAllocators, OMPC_uses_allocators)
-CHECK_SIMPLE_CLAUSE(Update, OMPC_update)
 CHECK_SIMPLE_CLAUSE(Write, OMPC_write)
 CHECK_SIMPLE_CLAUSE(Init, OMPC_init)
 CHECK_SIMPLE_CLAUSE(Use, OMPC_use)
@@ -2555,6 +2586,22 @@ CHECK_REQ_CONSTANT_SCALAR_INT_CLAUSE(Simdlen, OMPC_simdlen)
 
 // Restrictions specific to each clause are implemented apart from the
 // generalized restrictions.
+
+void OmpStructureChecker::Enter(const parser::OmpClause::Destroy &x) {
+  CheckAllowedClause(llvm::omp::Clause::OMPC_destroy);
+
+  llvm::omp::Directive dir{GetContext().directive};
+  unsigned version{context_.langOptions().OpenMPVersion};
+  if (dir == llvm::omp::Directive::OMPD_depobj) {
+    if (version < 52) {
+      context_.Say(GetContext().clauseSource,
+          "The object parameter in DESTROY clause in DEPOPJ construct "
+          "was introduced in %s"_port_en_US,
+          ThisVersion(52));
+    }
+  }
+}
+
 void OmpStructureChecker::Enter(const parser::OmpClause::Reduction &x) {
   CheckAllowedClause(llvm::omp::Clause::OMPC_reduction);
   if (CheckReductionOperators(x)) {
@@ -3285,16 +3332,63 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Device &x) {
 
 void OmpStructureChecker::Enter(const parser::OmpClause::Depend &x) {
   CheckAllowedClause(llvm::omp::Clause::OMPC_depend);
-  if ((std::holds_alternative<parser::OmpDependClause::Source>(x.v.u) ||
-          std::holds_alternative<parser::OmpDependClause::Sink>(x.v.u)) &&
-      GetContext().directive != llvm::omp::OMPD_ordered) {
-    context_.Say(GetContext().clauseSource,
-        "DEPEND(SOURCE) or DEPEND(SINK : vec) can be used only with the ordered"
-        " directive. Used here in the %s construct."_err_en_US,
-        parser::ToUpperCaseLetters(getDirectiveName(GetContext().directive)));
+  llvm::omp::Directive directive{GetContext().directive};
+  unsigned version{context_.langOptions().OpenMPVersion};
+
+  using DepType = parser::OmpTaskDependenceType::Type;
+  DepType depType = x.v.GetDepType();
+
+  if (version >= 52) {
+    switch (depType) {
+    case DepType::Sink:
+    case DepType::Source:
+      context_.Say(GetContext().clauseSource,
+          "The %s task-dependence-type is deprecated in %s"_warn_en_US,
+          parser::ToUpperCaseLetters(
+              parser::OmpTaskDependenceType::EnumToString(depType)),
+          ThisVersion(version));
+      break;
+    default:
+      break;
+    }
+  }
+
+  if (directive == llvm::omp::OMPD_depobj) {
+    // [5.0:255:11], [5.1:288:3]
+    // A depend clause on a depobj construct must not have source, sink [or
+    // depobj](5.0) as dependence-type.
+    if (version >= 50) {
+      bool invalidDep{depType == DepType::Source || depType == DepType::Sink};
+      if (version == 50) {
+        invalidDep = invalidDep || depType == DepType::Depobj;
+      }
+      if (invalidDep) {
+        context_.Say(GetContext().clauseSource,
+            "A DEPEND clause on a DEPOBJ construct must not have SOURCE%s "
+            "as dependence-type"_err_en_US,
+            version == 50 ? ", SINK or DEPOBJ" : " or SINK");
+      }
+    }
+  } else if (directive != llvm::omp::OMPD_ordered) {
+    if (depType == DepType::Source || depType == DepType::Sink) {
+      context_.Say(GetContext().clauseSource,
+          "DEPEND(SOURCE) or DEPEND(SINK : vec) can be used only with the "
+          "ordered directive. Used here in the %s construct."_err_en_US,
+          parser::ToUpperCaseLetters(getDirectiveName(directive)));
+    }
   }
   if (const auto *inOut{std::get_if<parser::OmpDependClause::InOut>(&x.v.u)}) {
-    for (const auto &object : std::get<parser::OmpObjectList>(inOut->t).v) {
+    auto &objList{std::get<parser::OmpObjectList>(inOut->t)};
+    if (directive == llvm::omp::OMPD_depobj) {
+      // [5.0:255:13], [5.1:288:6], [5.2:322:26]
+      // A depend clause on a depobj construct must only specify one locator.
+      if (objList.v.size() != 1) {
+        context_.Say(GetContext().clauseSource,
+            "A DEPEND clause on a DEPOBJ construct must only specify "
+            "one locator"_err_en_US);
+      }
+    }
+    for (const auto &object : objList.v) {
       if (const auto *name{std::get_if<parser::Name>(&object.u)}) {
         context_.Say(GetContext().clauseSource,
             "Common block name ('%s') cannot appear in a DEPEND "
@@ -3313,12 +3407,18 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Depend &x) {
       }
     }
     if (std::get<std::optional<parser::OmpIteratorModifier>>(inOut->t)) {
-      unsigned version{context_.langOptions().OpenMPVersion};
       unsigned allowedInVersion{50};
       if (version < allowedInVersion) {
         context_.Say(GetContext().clauseSource,
             "Iterator modifiers are not supported in %s, %s"_warn_en_US,
             ThisVersion(version), TryVersion(allowedInVersion));
+      } else {
+        if (directive == llvm::omp::OMPD_depobj) {
+          context_.Say(GetContext().clauseSource,
+              "An iterator-modifier may specify multiple locators, "
+              "a DEPEND clause on a DEPOBJ construct must only specify "
+              "one locator"_warn_en_US);
+        }
       }
     }
   }
@@ -3433,6 +3533,34 @@ void OmpStructureChecker::CheckStructureElement(
   return;
 }
 
+void OmpStructureChecker::Enter(const parser::OmpClause::Update &x) {
+  CheckAllowedClause(llvm::omp::Clause::OMPC_update);
+  llvm::omp::Directive directive{GetContext().directive};
+  unsigned version{context_.langOptions().OpenMPVersion};
+
+  // [5.1:288:4-5]
+  // An update clause on a depobj construct must not have source, sink or depobj
+  // as dependence-type.
+  // [5.2:322:3]
+  // task-dependence-type must not be depobj.
+  if (directive == llvm::omp::OMPD_depobj) {
+    if (version >= 51) {
+      // Update -> OmpUpdateClause -> OmpTaskDependenceType -> Type
+      switch (x.v.v.v) {
+      case parser::OmpTaskDependenceType::Type::Source:
+      case parser::OmpTaskDependenceType::Type::Sink:
+      case parser::OmpTaskDependenceType::Type::Depobj:
+        context_.Say(GetContext().clauseSource,
+            "An UPDATE clause on a DEPOBJ construct must not have SOURCE, "
+            "SINK or DEPOBJ as dependence-type"_err_en_US);
+        break;
+      default:
+        break;
+      }
+    }
+  }
+}
+
 void OmpStructureChecker::Enter(const parser::OmpClause::UseDevicePtr &x) {
   CheckStructureElement(x.v, llvm::omp::Clause::OMPC_use_device_ptr);
   CheckAllowedClause(llvm::omp::Clause::OMPC_use_device_ptr);
@@ -3616,7 +3744,7 @@ void OmpStructureChecker::CheckDependList(const parser::DataRef &d) {
             context_.Say(GetContext().clauseSource,
                 "Coarrays are not supported in DEPEND clause"_err_en_US);
           },
-          [&](const parser::Name &) { return; },
+          [&](const parser::Name &) {},
       },
       d.u);
 }
diff --git a/flang/lib/Semantics/check-omp-structure.h b/flang/lib/Semantics/check-omp-structure.h
index 237569bc40c483..d5fd558cea2372 100644
--- a/flang/lib/Semantics/check-omp-structure.h
+++ b/flang/lib/Semantics/check-omp-structure.h
@@ -92,6 +92,8 @@ class OmpStructureChecker
   void Leave(const parser::OpenMPDeclarativeAllocate &);
   void Enter(const parser::OpenMPDeclareTargetConstruct &);
   void Leave(const parser::OpenMPDeclareTargetConstruct &);
+  void Enter(const parser::OpenMPDepobjConstruct &);
+  void Leave(const parser::OpenMPDepobjConstruct &);
   void Enter(const parser::OmpDeclareTargetWithList &);
   void Enter(const parser::OmpDeclareTargetWithClause &);
   void Leave(const parser::OmpDeclareTargetWithClause &);
diff --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp
index 014b7987a658bd..d85109fc9cda83 100644
--- a/flang/lib/Semantics/resolve-directives.cpp
+++ b/flang/lib/Semantics/resolve-directives.cpp
@@ -383,6 +383,14 @@ class OmpAttributeVisitor : DirectiveAttributeVisitor<llvm::omp::Directive> {
   }
   void Post(const parser::OpenMPDeclareSimdConstruct &) { PopContext(); }
 
+  bool Pre(const parser::OpenMPDepobjConstruct &x) {
+    PushContext(x.source, llvm::omp::Directive::OMPD_depobj);
+    auto &object{std::get<parser::OmpObject>(x.t)};
+    ResolveOmpObject(object, Symbol::Flag::OmpDependObject);
+    return true;
+  }
+  void Post(const parser::OpenMPDepobjConstruct &) { PopContext(); }
+
   bool Pre(const parser::OpenMPRequiresConstruct &x) {
     using Flags = WithOmpDeclarative::RequiresFlags;
     using Requires = WithOmpDeclarative::RequiresFlag;
diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index add4e4befd3a2b..e0a8246ebc752e 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -1538,6 +1538,13 @@ class OmpVisitor : public virtual DeclarationVisitor {
   void Post(const parser::OpenMPDeclarativeConstruct &) {
     messageHandler().set_currStmtSource(std::nullopt);
   }
+  bool Pre(const parser::OpenMPDepobjConstruct &x) {
+    AddOmpSourceRange(x.source);
+    return true;
+  }
+  void Post(const parser::OpenMPDepobjConstruct &x) {
+    messageHandler().set_currStmtSource(std::nullopt);
+  }
   bool Pre(const parser::OpenMPAtomicConstruct &x) {
     return common::visit(common::visitors{[&](const auto &u) -> bool {
       AddOmpSourceRange(u.source);
diff --git a/flang/test/Lower/OpenMP/Todo/depobj-construct.f90 b/flang/test/Lower/OpenMP/Todo/depobj-construct.f90
new file mode 100644
index 00000000000000..2b3c4d92c4a4f8
--- /dev/null
+++ b/flang/test/Lower/OpenMP/Todo/depobj-construct.f90
@@ -0,0 +1,9 @@
+!RUN: %not_todo_cmd bbc -emit-hlfir -fopenmp -fopenmp-version=50 -o - %s 2>&1 | FileCheck %s
+!RUN: %not_todo_cmd %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 -o - %s 2>&1 | FileCheck %s
+
+!CHECK: not yet implemented: OpenMPDepobjConstruct
+subroutine f00()
+  integer :: obj
+  integer :: x
+  !$omp depobj(obj) depend(in: x)
+end
diff --git a/flang/test/Parser/OpenMP/depobj-construct.f90 b/flang/test/Parser/OpenMP/depobj-construct.f90
new file mode 100644
index 00000000000000..7c474071bc1e67
--- /dev/null
+++ b/flang/test/Parser/OpenMP/depobj-construct.f90
@@ -0,0 +1,64 @@
+!RUN: %flang_fc1 -fdebug-unparse -fopenmp -fopenmp-version=52 %s | FileCheck --ignore-case --check-prefix="UNPARSE" %s
+!RUN: %flang_fc1 -fdebug-dump-parse-tree -fopenmp -fopenmp-version=52 %s | FileCheck --check-prefix="PARSE-TREE" %s
+
+subroutine f00
+  integer :: x, y
+  !$omp depobj(x) depend(in: y)
+end
+
+!UNPARSE: SUBROUTINE f00
+!UNPARSE:  INTEGER x, y
+!UNPARSE: !$OMP DEPOBJ(x) DEPEND(IN:y)
+!UNPARSE: END SUBROUTINE
+
+!PARSE-TREE: ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OpenMPStandaloneConstruct -> OpenMPDepobjConstruct
+!PARSE-TREE: | Verbatim
+!PARSE-TREE: | OmpObject -> Designator -> DataRef -> Name = 'x'
+!PARSE-TREE: | OmpClause -> Depend -> OmpDependClause -> InOut
+!PARSE-TREE: | | OmpTaskDependenceType -> Type = In
+!PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'y'
+
+subroutine f01
+  integer :: x
+  !$omp depobj(x) update(out)
+end
+
+!UNPARSE: SUBROUTINE f01
+!UNPARSE:  INTEGER x
+!UNPARSE: !$OMP DEPOBJ(x) UPDATE(OUT)
+!UNPARSE: END SUBROUTINE
+
+!PARSE-TREE: ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OpenMPStandaloneConstruct -> OpenMPDepobjConstruct
+!PARSE-TREE: | Verbatim
+!PARSE-TREE: | OmpObject -> Designator -> DataRef -> Name = 'x'
+!PARSE-TREE: | OmpClause -> Update -> OmpUpdateClause -> OmpTaskDependenceType -> Type = Out
+
+subroutine f02
+  integer :: x
+  !$omp depobj(x) destroy(x)
+end
+
+!UNPARSE: SUBROUTINE f02
+!UNPARSE:  INTEGER x
+!UNPARSE: !$OMP DEPOBJ(x) DESTROY(x)
+!UNPARSE: END SUBROUTINE
+
+!PARSE-TREE: ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OpenMPStandaloneConstruct -> OpenMPDepobjConstruct
+!PARSE-TREE: | Verbatim
+!PARSE-TREE: | OmpObject -> Designator -> DataRef -> Name = 'x'
+!PARSE-TREE: | OmpClause -> Destroy -> OmpDestroyClause -> OmpObject -> Designator -> DataRef -> Name = 'x'
+
+subroutine f03
+  integer :: x
+  !$omp depobj(x) destroy
+end
+
+!UNPARSE: SUBROUTINE f03
+!UNPARSE:  INTEGER x
+!UNPARSE: !$OMP DEPOBJ(x) DESTROY
+!UNPARSE: END SUBROUTINE
+
+!PARSE-TREE: ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OpenMPStandaloneConstruct -> OpenMPDepobjConstruct
+!PARSE-TREE: | Verbatim
+!PARSE-TREE: | OmpObject -> Designator -> DataRef -> Name = 'x'
+!PARSE-TREE: | OmpClause -> Destroy ->
diff --git a/flang/test/Semantics/OpenMP/depobj-construct-v50.f90 b/flang/test/Semantics/OpenMP/depobj-construct-v50.f90
new file mode 100644
index 00000000000000..e7fa24d521b63b
--- /dev/null
+++ b/flang/test/Semantics/OpenMP/depobj-construct-v50.f90
@@ -0,0 +1,28 @@
+!RUN: %python %S/../test_errors.py %s %flang -fopenmp -fopenmp-version=50
+
+subroutine f00
+  integer :: obj
+!ERROR: A DEPEND clause on a DEPOBJ construct must not have SOURCE, SINK or DEPOBJ as dependence-type
+  !$omp depobj(obj) depend(source)
+end
+
+subroutine f01
+  integer :: obj
+  integer :: x, y
+!ERROR: A DEPEND clause on a DEPOBJ construct must only specify one locator
+  !$omp depobj(obj) depend(in: x, y)
+end
+
+subroutine f02
+  integer :: obj
+  integer :: x(10)
+!WARNING: An iterator-modifier may specify multiple locators, a DEPEND clause on a DEPOBJ construct must only specify one locator
+  !$omp depobj(obj) depend(iterator(i = 1:10), in: x(i))
+end
+
+subroutine f03
+  integer :: obj, jbo
+!ERROR: The DESTROY clause must refer to the same object as the DEPOBJ construct
+!PORTABILITY: The object parameter in DESTROY clause in DEPOPJ construct was introduced in OpenMP v5.2
+  !$omp depobj(obj) destroy(jbo)
+end
diff --git a/flang/test/Semantics/OpenMP/depobj-construct-v51.f90 b/flang/test/Semantics/OpenMP/depobj-construct-v51.f90
new file mode 100644
index 00000000000000..fa0c025a110100
--- /dev/null
+++ b/flang/test/Semantics/OpenMP/depobj-construct-v51.f90
@@ -0,0 +1,13 @@
+!RUN: %python %S/../test_errors.py %s %flang -fopenmp -fopenmp-version=51
+
+subroutine f04
+  integer :: obj
+!ERROR: An UPDATE clause on a DEPOBJ construct must not have SOURCE, SINK or DEPOBJ as dependence-type
+  !$omp depobj(obj) update(source)
+end
+
+subroutine f05
+  integer :: obj
+!ERROR: An UPDATE clause on a DEPOBJ construct must not have SOURCE, SINK or DEPOBJ as dependence-type
+  !$omp depobj(obj) update(depobj)
+end
diff --git a/flang/test/Semantics/OpenMP/depobj-construct-v52.f90 b/flang/test/Semantics/OpenMP/depobj-construct-v52.f90
new file mode 100644
index 00000000000000..f2e66485c6c801
--- /dev/null
+++ b/flang/test/Semantics/OpenMP/depobj-construct-v52.f90
@@ -0,0 +1,15 @@
+!RUN: %python %S/../test_errors.py %s %flang -fopenmp -fopenmp-version=52
+
+subroutine f00
+  integer :: obj
+!WARNING: The SOURCE task-dependence-type is deprecated in OpenMP v5.2
+!ERROR: A DEPEND clause on a DEPOBJ construct must not have SOURCE or SINK as dependence-type
+  !$omp depobj(obj) depend(source)
+end
+
+subroutine f03
+  integer :: obj, jbo
+!Note: no portability message
+!ERROR: The DESTROY clause must refer to the same object as the DEPOBJ construct
+  !$omp depobj(obj) destroy(jbo)
+end
diff --git a/llvm/include/llvm/Frontend/OpenMP/ClauseT.h b/llvm/include/llvm/Frontend/OpenMP/ClauseT.h
index 2a890905dc6323..8ff15b51f1abdf 100644
--- a/llvm/include/llvm/Frontend/OpenMP/ClauseT.h
+++ b/llvm/include/llvm/Frontend/OpenMP/ClauseT.h
@@ -239,7 +239,8 @@ struct MapperT {
 ENUM(MemoryOrder, AcqRel, Acquire, Relaxed, Release, SeqCst);
 ENUM(MotionExpectation, Present);
 // V5.2: [15.9.1] `task-dependence-type` modifier
-ENUM(TaskDependenceType, In, Out, Inout, Mutexinoutset, Inoutset, Depobj);
+ENUM(TaskDependenceType, Depobj, In, Inout, Inoutset, Mutexinoutset, Out, Sink,
+     Source);
 
 template <typename I, typename E> //
 struct LoopIterationT {
diff --git a/llvm/include/llvm/Frontend/OpenMP/OMP.td b/llvm/include/llvm/Frontend/OpenMP/OMP.td
index 70179bab475779..97496d4aae5ae2 100644
--- a/llvm/include/llvm/Frontend/OpenMP/OMP.td
+++ b/llvm/include/llvm/Frontend/OpenMP/OMP.td
@@ -130,6 +130,8 @@ def OMPC_Depobj : Clause<"depobj"> {
 }
 def OMPC_Destroy : Clause<"destroy"> {
   let clangClass = "OMPDestroyClause";
+  let flangClass = "OmpDestroyClause";
+  let isValueOptional = true;
 }
 def OMPC_Detach : Clause<"detach"> {
   let clangClass = "OMPDetachClause";
@@ -481,6 +483,7 @@ def OMPC_Untied : Clause<"untied"> {
 }
 def OMPC_Update : Clause<"update"> {
   let clangClass = "OMPUpdateClause";
+  let flangClass = "OmpUpdateClause";
 }
 def OMPC_Use : Clause<"use"> {
   let clangClass = "OMPUseClause";



More information about the llvm-commits mailing list